Skip to content
Back to skills

Programming

ASecurity

Klasy ORM i wzorce kodu biznesowego platformy Soneta (enova365, Soneta Enterprise, Triva) — dla dodatków partnerów i dla kodu samej platformy pisanego przez zespół Soneta w repozytorium źródłowym (przestrzenie nazw `Soneta.*`, moduły standardowe). Używaj gdy użytkownik: (1) pisze, modyfikuje lub refaktoruje kod biznesowy (Row/Table/Module, sesje i transakcje, selector, typy wierszy) albo edytuje plik `.cs` z klasami `Row`/`Table`/`Module`, workerem, `[Action]`, `Session`/`Transaction`; (2) py...

  • 9 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 5, 2026
developmentgoc#bashsqlexpressawstestingapidatabasefrontend

Works with

  • cli
  • api
  • mcp

Security analysis

A100/100

Pro scans all 18 files and shows the line behind each finding

Scanned October 1, 2026

npx -y skills add soneta/soneta-erp-skills --skill programming --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Programming?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Programming
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/soneta-programming/badge)](https://www.skillsdirectory.com/skills/soneta-programming)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: programming
description: >
  Klasy ORM i wzorce kodu biznesowego platformy Soneta (enova365, Soneta Enterprise, Triva) — dla
  dodatków partnerów i dla kodu samej platformy pisanego przez zespół Soneta w repozytorium
  źródłowym (przestrzenie nazw `Soneta.*`, moduły standardowe). Używaj gdy użytkownik: (1) pisze,
  modyfikuje lub refaktoruje kod biznesowy (Row/Table/Module, sesje i transakcje, selector, typy
  wierszy) albo edytuje plik `.cs` z klasami `Row`/`Table`/`Module`, workerem, `[Action]`,
  `Session`/`Transaction`; (2) pyta o mechanizm ORM — Session, Commit/Save, optimistic lock,
  Context, RowCondition, Datapack, ViewInfo, Features, thread-safety; (3) prosi o code review kodu
  biznesowego Soneta (safe-code); (4) pisze worker, extender, akcję w menu Czynności, folder/listę;
  (5) inwentaryzuje moduły, pola, workery lub formularze/zakładki z bibliotek DLL; (6) zaczyna nowy
  dodatek — szkielet z CLI (`dotnet new soneta-addon`, Soneta.MsBuild.SDK). Sięgnij też, gdy inny
  skill potrzebuje warstwy ORM/kodu biznesowego Soneta.
---

# Soneta Programming Basics - Podstawowe klasy ORM

Skill zawiera dokumentację fundamentalnych klas logiki biznesowej platformy Soneta. Klasy te stanowią podstawę mapowania obiektowo-relacyjnego (ORM) i są niezbędne do tworzenia kodu i dodatków.

> **Code review / refaktoring:** po napisaniu nowego kodu biznesowego oraz po każdym refaktoringu, **zawsze** zweryfikuj go względem [references/safe-code.md](references/safe-code.md). Ten sam dokument służy jako lista kontrolna do review PR-ów.

## Mapa skilla

SKILL.md zawiera "duży obraz" - hierarchię klas, thread-safety, kanoniczne wzorce. Po szczegóły konkretnego tematu sięgaj do referencji:

| Temat                                                                                             | Gdzie szukać |
|---------------------------------------------------------------------------------------------------|---|
| **Nowy dodatek od zera** — wygenerowanie szkieletu źródeł przez CLI (`dotnet new soneta-addon`, Soneta.MsBuild.SDK, `global.json`/`Directory.Build.props`, solucja, debug VS Code) | [references/new-addon-cli.md](references/new-addon-cli.md) |
| Hierarchia ORM, Row / Table / Module, klucze, ISessionable                                        | sekcje poniżej |
| Implementacja klas Row/Table, konstruktory (pola readonly, `RowCreator`), selector + `[BusinessRow]`, `[NewRow]`, `[DefaultConstructor]`, jawne wartości enum'ów, **zdarzenia cyklu życia** (`OnAdded`/`OnLoaded`/`OnEditing`/`OnDeleting`/`OnDeleted`/`OnRepacked` — override z `base.OnXxx()`; alternatywa bez dziedziczenia: statyczne delegaty `XSchema`) | [references/row-types.md](references/row-types.md) |
| `AssemblyAttributes` - odczyt atrybutów z załadowanych modułów (`GetCustom<T>`, `Find`, iteracja po assembly, cache, analiza DLL w runtime) | [references/assembly-attributes.md](references/assembly-attributes.md) |
| Sesje, transakcje, Login, Database, BusApplication, optimistic locking                            | [references/session-login.md](references/session-login.md) |
| Paczki danych, Datapack, GuidedRow, ExportedRow, synchronizacja, blokady                          | [references/datapack-guidedrow.md](references/datapack-guidedrow.md) |
| Klasa Context - dane z UI, zaznaczenia, parametry workera                                         | [references/context.md](references/context.md) |
| Klasy parametrów (ContextBase) - filtry, trwałość, InvokeChanged (ta sama konstrukcja służy jako **parametry wydruków** → `/soneta:repx`) | [references/contextbase.md](references/contextbase.md) |
| Obiekty Worker i Extender - rozszerzenia modelu, akcje w menu Czynności (`[Action]` i dynamiczne `GetActions`), **rozszerzanie obiektów obcych** (property/kolekcje dodatku na obcym typie Soneta bez modyfikacji jego kodu) | [references/worker-extender.md](references/worker-extender.md) |
| Serwisy biznesowe (App / Database / Login / Session scope), **rejestracja warunkowa ServiceInitializer** (per instancja właściciela, np. per silnik bazy; kolejność po Priority) | [references/services.md](references/services.md) |
| Tłumaczenia (Translate, TranslateIgnore), ILogger, ActSource, **lokalizacja plików logów** (katalog `Soneta/Logs/` — macOS: `~/Library/Application Support/`, Windows: `%APPDATA%\`; pliki `server-*`/`dbmgr-*`/`test-*`) | [references/translations-logging.md](references/translations-logging.md) |
| Action result (rezultaty workera) zwracany przez worker / extender / Command - raporty, dialogi, nawigacja | [references/action-result.md](references/action-result.md) |
| RowCondition - serwerowe warunki LINQ, filtrowanie SubTable / View / Query                        | [references/rowcondition.md](references/rowcondition.md) |
| ViewInfo - definicja widoków list (folderów i inline jako property), CreateView, args.DataSource, klasa Params, `[Accessor(AutoChange)]`, powiązanie z viewform.xml | [references/viewinfo.md](references/viewinfo.md) |
| ChangeInfos - dziennik zmian / audyt (`session.ChangeInfos.Add`, pola Info/Data, pułapka 255 znaków, ChangeInfoType, prezentacja listy) | [references/changeinfos.md](references/changeinfos.md) |
| Cechy (Features) - tabela Features, typy cech, dostęp typowany/nietypowany, bindowanie w form.xml | [references/features.md](references/features.md) |
| Weryfikatory - walidacja spójności danych (`Verifier`, `RowVerifier<T>`, `ColVerifier<T>`, `MultiColVerifier<T>`, `RequiredVerifier`), poziomy `Error`/`Warning`/`Information`, uzbrajanie na zmianę pól-źródeł (`Session.Verifiers.Add`, `<verifier>` w business.xml), blokada `Save()` przy błędzie | [references/verifiers.md](references/verifiers.md) |
| Eventy (zdarzenia sesji) - odraczanie ciężkich obliczeń i logika w transakcji serwerowej: **sesyjne** (`Session.Events`, odpalane na `CommitUI`/`Save`/`Invoke`) vs **serwerowe** (`Session.ServerEvents`, w transakcji `Save` — numeracja). Rejestracja `Add(handler[, args])`, dedup po `Equals`/`GetHashCode`, wymuszanie `Invoke(handler)`, argumenty (`BusEventArgs`, `RowEventArgs<TRow>`, `SessionBusEventArgs`), priorytety, transakcyjność | [references/events.md](references/events.md) |
| Źródła praw (`IRightsSource`) - obiekt sterujący dostępem do danych operacyjnych, `AccessRight`, `Login.GetObjectRight`; nowe źródło domyślnie Denied, `AccessDeniedException` przy odczycie kolumn bez prawa, nadawanie praw i cache ról; prawa proste `SimpleRight`. **Miejsce tabeli w drzewie uprawnień** (pliki `*.rightstree.xml`, reguła korzenia praw, relacje `relright`/`relguided`) → skill `/soneta:business-xml` | [references/rights-source.md](references/rights-source.md) |
| Notacja klamrowa (`AccessorFormatter`) - wstawki `{ścieżka}` / `{ścieżka:format}` w captionach, szablonach, promptach; metadane modeli (`ApplicationInfo`, `TableInfo`) | [references/metadata-formatting.md](references/metadata-formatting.md) |
| Gotowe wzorce kodu end-to-end (import, CRUD, obsługa błędów)                                      | [references/examples.md](references/examples.md) |
| Receptury kodu per obiekt biznesowy (domena CRM) — `Kontrahent` (pola, kolekcje, workery, finanse, RODO, KSeF). Indeks + mapa receptur (CRM-W1–W18); rozdziały `references/domeny/crm/CRM01..CRM10` | [references/domeny/crm.md](references/domeny/crm.md) |
| Receptury kodu per obiekt biznesowy (domena Handel) — `DokumentHandlowy` (faktury/magazynowe/zamówienia/korekty, relacje `IRelacjeService`, cykl życia, magazyn/partie/obroty, VAT/waluty, płatności, KSeF/fiskal/Intrastat, wydruki). Indeks + mapa receptur (HANDEL-W1–W82); rozdziały `references/domeny/handel/HANDEL01..HANDEL14` | [references/domeny/handel.md](references/domeny/handel.md) |
| Receptury kodu per obiekt biznesowy (domena Kadry-Płace) — `Pracownik` (zatrudnienie i dane kadrowe, historia `PracHistoria`+`Etat`, dodatki, nieobecności/limity, plan pracy/RCP, umowy cywilnoprawne, naliczanie wypłat, listy płac, wydruki PDF). Indeks + mapa receptur (KADRY-A*…K*); rozdziały `references/domeny/kadry/KADRY01..KADRY11` | [references/domeny/kadry.md](references/domeny/kadry.md) |
| **Zasady bezpiecznego kodu biznesowego — checklist do review i refaktoringu**                     | [references/safe-code.md](references/safe-code.md) |
| Pola obiektów biznesowych — dane wygenerowane (`data/props/`) + skaner/regeneracja z DLL      | [references/scan-props.md](references/scan-props.md) |
| Moduły i tabele (`*Module` / `*Row` / `*Table`) — gotowy przegląd w `data/props/` (`INDEX.md` → `<Moduł>/INDEX.md`) + skaner z DLL | [references/scan-modules.md](references/scan-modules.md) |
| Inwentaryzacja workerów i extenderów (`[Worker<…>]`) z DLL                            | [references/scan-workers.md](references/scan-workers.md) |
| Zakładki, sekcje danych i pola formularzy (zasoby `*.pageform.xml`/`*.form.xml`) z DLL — katalog `data/forms/` (`INDEX.md` → `<Przestrzeń>.md`) + skaner na żądanie (`DataContext`/`EditValue`, `Include`, listy, kolejność pól pod kod i import XML) | [references/scan-forms.md](references/scan-forms.md) |
| Inwentaryzacja folderów statycznych menu (`[assembly: FolderView]`) z DLL — drzewo, listy, formularze | narzędzie `scan-folders` w skillu `/soneta:config` |
| Wydruki DevExpress (pliki `.repx`) — struktura raportu, źródło danych `BusinessDataSource`, rejestracja `[assembly: DxReport(...)]`; **kod-behind wydruku** (`ReportSnippet`/`[DxBind]`, lub generyczny `Snippet`/`[Bind]` bez licencji DevExpress) liczący dane raportu w oparciu o ORM. **Parametry wydruku konstruuje się jak parametry workerów — klasa `ContextBase` + `[Context]`** (patrz wyżej) | skill `/soneta:repx` (warstwa `.repx`) |
| **Testowanie na żywej aplikacji przez `buscall call` (CLI)** — zdalne sterowanie programem (nawigacja, formularze, gridy, edycja) i **zrzuty ekranu** do analizy wizualnej; jednorazowe wywołania CLI bez zarządzania procesem (`buscall --db <Baza> call <metoda> klucz=wartość`), plus wariant MCP `callmcp` | [references/buscall-live-testing.md](references/buscall-live-testing.md) (weryfikacja na żywo) |
| **Import/eksport XML z kodu — `SessionReader`/`SessionWriter`** — konstruktory (`Session` vs `Login`), obsługa błędów (`CollectExceptions`, zdarzenie `ReaderException`/`ReaderResponse`), mapowanie GUID-ów (`AddGuidMap`, `GuidMapPolicy`), tryby kolekcji (`RelationsImportMode`), eksport datapacku z subexports, `ImportBusinessXml` w testach; struktura samego pliku XML → artykuł *import-export-xml* w `/soneta:config` | [references/sessionreader-sessionwriter.md](references/sessionreader-sessionwriter.md) |
| **Testy integracyjne — klasa bazowa `TestBase`** — testy na realnej bazie z automatycznym rollbackiem (dwupoziomowa transakcja), wybór bazy `[TestDatabase]` (`nunit_default`/`nunit_ui`/`nunit_premiumui`), cykl życia (`ClassSetup`/`TestSetup`), `Session`/`ConfigSession`/`Context`, `InTransaction`/`SaveDispose`, podmiana DI (`ConfigureLoginServices`), asercje `AwesomeAssertions`, testy SQL (`SqlTraceInfo`), konwencje: nazewnictwo `Should_..._When_...` + prefiks grupy, `[Description]`, struktura AAA | [references/integration-tests.md](references/integration-tests.md) |

## Nowy dodatek od zera (CLI)

Gdy zaczynasz **nowy** dodatek (a nie modyfikujesz istniejący), najpierw wygeneruj szkielet źródeł
z wiersza poleceń, a dopiero potem wypełniaj go treścią. Robi to paczka szablonów **Soneta Platform
Developer** w oparciu o **Soneta.MsBuild.SDK** — jednym poleceniem powstają rozdzielone projekty
(logika biznesowa, UI, testy) już skonfigurowane pod platformę Soneta:

```bash
dotnet new install Soneta.Platform.Developer          # raz na maszynę (starsza składnia: dotnet new -i …)
dotnet new soneta-addon -n MyExtension -o ./MyExtension
# >>> obowiązkowy krok konfiguracji (patrz niżej) — nadpisz 3 pliki poprawną treścią <<<
cd ./MyExtension && dotnet build                       # weryfikacja
```

Powstaje gotowa solucja `MyExtension.sln` z projektami `MyExtension` (logika), `MyExtension.UI`,
`MyExtension.Tests` oraz pliki `global.json` (wersja SDK) i `Directory.Build.props` (wersja bibliotek
`SonetaPackageVersion`). SDK sam pobiera biblioteki Soneta i uruchamia generator
`*.business.xml → *.business.cs` przy buildzie. Dodatki celują w **`net10.0`** i są **cross-platform**
— pełny cykl (generowanie, build, testy) działa na macOS/Linux/Windows.

**Obowiązkowy krok po wygenerowaniu — nadpisz pliki konfiguracyjne poprawną treścią.** Szablon
`1.0.7` generuje konfigurację, która **nie buduje się z pudełka**, więc zaraz po `dotnet new` (a przed
`dotnet build`) doprowadź trzy pliki do poprawnej postaci — nie czekaj, aż build padnie:

1. **`global.json`** — przypnij `"Soneta.Sdk": "1.2.0"` (szablon wpisuje starszą, np. `1.1.8`).
2. **`Directory.Build.props`** — dodaj w pierwszym `PropertyGroup`
   `<SonetaTargetFramework>net10.0</SonetaTargetFramework>` (szablon zostawia tę zmienną pustą).
3. **`NuGet.Config`** — utwórz w katalogu solucji z feedem Soneta
   (`https://nuget.soneta.pl/v3/index.json`); szablon **nie generuje** tego pliku.

Gotowa treść wszystkich trzech plików: [references/new-addon-cli.md](references/new-addon-cli.md#5a-pliki-konfiguracyjne--poprawna-treść-krok-obowiązkowy).
Dopiero po tym uruchom `dotnet build` (powinien przejść z 0 ostrzeżeń, 0 błędów).

**`dotnet build` = walidator obu warstw** (generacja `business.xml → business.cs` **i** C#) — jednym
poleceniem wychodzą błędy generatora i braki klas konkretnych; to najszybsza pętla iteracji.
W raportach rozróżniaj „zweryfikowane buildem" vs „wymaga weryfikacji runtime" (żywa aplikacja /
testy) — zielony build ≠ działające runtime.

**Kryterium ukończenia:** w katalogu docelowym istnieją trzy `*.csproj`, `global.json`
i `Directory.Build.props`. Dalej wypełniasz szkielet: definicje (**soneta:business-xml**) → kod
biznesowy (ten skill) → UI (**soneta:form-xml**).

Pełna procedura — szablony, pliki konfiguracyjne, parametry MSBuild, solucja, debug w VS Code,
referencje WinForms, ręczny fallback bez szablonów i troubleshooting:
[references/new-addon-cli.md](references/new-addon-cli.md).

## Architektura warstw

```
BusApplication.Instance (singleton) - multithreaded
  └── Database
       └── Login
            └── Session - single-threaded
                 └── Module
                      └── Table
                           └── Row
```

## 3 poziomy logiki biznesowej

| Poziom | Opis | Przykłady klas |
|--------|------|----------------|
| **1. Bazowe** | Klasy wspólne dla wszystkich modułów (Soneta.Business.dll) | `Row`, `Table`, `Module`, `Session`, `Context` |
| **2. Generowane** | Klasy generowane przez BusinessGenerator z `*.business.xml` (sufiksy: Row, Table, Module) | `TowarRow`, `TowarTable`, `TowaryModule` |
| **3. Implementowane** | Klasy konkretne tworzone przez programistę | `Towar`, `Towary` (bez sufiksów) |

**BusinessGenerator** jest automatycznie uruchamiany podczas kompilacji dla plików `*.business.xml`. Szczegółowy opis definiowania business.xml znajduje się w skill **soneta:business-xml**.

Klasy poziomu 3 (`Towar`, `Towary`) pisze programista, dziedzicząc po klasach generowanych.
Gdy tabela ma pola `readonly` (w tym **selector**), klasa obiektu biznesowego wymaga
dodatkowych konstruktorów; selector pozwala też przechowywać **wiele typów obiektów w jednej
tabeli**. Wzorce implementacji (konstruktory, `[BusinessRow]`, `[NewRow]`) —
[references/row-types.md](references/row-types.md).

## Hierarchia głównych klas

```
Row (abstrakcyjna)
 └── GuidedRow (+ Guid, Attachments, ChangeInfos)
      └── ExportedRow (+ Exported flag - rozróżnia dane konfiguracyjne od operacyjnych)

Table (abstrakcyjna)
 └── GuidedTable (indeksator po Guid)
      └── ExportedTable

Module (abstrakcyjna)
 └── [NazwaModulu]Module (np. TowaryModule)
```

Szczegóły GuidedRow / ExportedRow (flaga `Exported`, atrybuty `guided` / `relguided` w business.xml, ChangeInfos, blokady) - patrz [references/datapack-guidedrow.md](references/datapack-guidedrow.md).

## Thread-safety

### Obiekty single-threaded (NIE współdzielić między wątkami)
- `Session`
- `Module`
- `Table`
- `Row`
- `Context`
- oraz wszystkie klasy pochodne

### Obiekty multi-threaded (można współdzielić)
- `BusApplication`
- `Database`
- `Login`

## Klasa Session - fundamenty

Session to kluczowa klasa do zarządzania danymi. **Każda operacja na danych wymaga sesji.** Sesja jest single-threaded i implementuje `IDisposable` - zawsze opakowuj w `using`.

```csharp
Session session = login.CreateSession(readOnly: false, config: false, name: "MojaSesja");
```

**Każda modyfikacja obiektu MUSI być w transakcji biznesowej** otwieranej przez `Session.Logout(editMode: true)` - dotyczy dodawania, modyfikacji właściwości oraz kasowania:

```csharp
using (var transaction = session.Logout(editMode: true))
{
    towar.Nazwa = "Zmieniona nazwa";
    transaction.Commit();   // Commit() w kodzie biznesowym
    // transaction.CommitUI();  // CommitUI() w kodzie UI (worker, extender, Command)
}
session.Save();   // zapis do bazy - optimistic-lock; konflikty wykrywane tu
```

**Brak Commit() = automatyczny rollback przy Dispose()** - dotyczy też transakcji tylko do odczytu.

Pełna dokumentacja (typy sesji edycyjna / readonly / konfiguracyjna, transakcje zagnieżdżone, Commit vs CommitUI, optimistic locking, mieszanie obiektów z różnych sesji przez `session.Get(obiekt)`) - patrz [references/session-login.md](references/session-login.md).

## Klasa Module

Moduł grupuje logicznie powiązane tabele. **Nie ma odwzorowania w bazie danych.**

**Preferowany odczyt modułu to metoda rozszerzająca `session.GetX()` (generowanymi z `business.xml`, także dla modułów dodatków). ** Wariant
`Module.GetInstance(ISessionable)` stosuj tylko, gdy nie masz dostępu do property `Session`.
Nie używaj ogólnego `session.Get<TModule>()` ani `session.Modules[...]` — zasada
[§14.4 w safe-code.md](references/safe-code.md).

```csharp
// Dostęp do modułu - extension method (preferowane)
var tm = session.GetTowary();
var hm = session.GetHandel();
var crm = session.GetCRM();
var bm = session.GetBusiness();

// Dostęp do tabel
Towary towary = tm.Towary;
Jednostki jednostki = tm.Jednostki;

// Moduł implementuje ISessionable
Session s = tm.Session;
```

## Klasa Table

Reprezentuje tabelę w bazie danych. Udostępnia dostęp do kolekcji wierszy.

```csharp
var towary = tm.Towary;

// Iteracja po kluczu podstawowym
foreach (Towar t in towary.WgKodu) { ... }

// Iteracja po innym kluczu
foreach (Towar t in towary.WgNazwy) { ... }

// Właściwości
Table.AccessRight      // Prawa dostępu
Table.Session          // Sesja (ISessionable)
Table.Module           // Moduł nadrzędny
Table.PrimaryKey       // Klucz podstawowy
```

## Klasa Row

Reprezentuje pojedynczy wiersz (rekord) z tabeli.

### Właściwości bazowe

```csharp
Row.ID        // int - PODSTAWOWY identyfikator obiektu w tabeli (autoincrement, Primary Key)
Row.State     // RowState - stan obiektu w sesji
Row.Table     // Table - tabela nadrzędna
Row.Module    // Module - moduł
Row.Session   // Session - sesja
```

**ID** jest automatycznie generowany przez bazę danych i stanowi klucz główny (Primary Key) tabeli.

### Stany obiektu (RowState)

| Stan | Opis |
|------|------|
| `Detached` | Nowy obiekt, nie przypisany do tabeli |
| `Unchanged` | Wczytany z bazy, bez zmian |
| `Modified` | Zmodyfikowany w sesji |
| `Added` | Nowy, dodany do tabeli, nie zapisany w bazie |
| `Deleted` | Skasowany, do usunięcia z bazy |

## Klucze i indeksy

Definiowane w *.business.xml, mapowane na indeksy w bazie danych.

```xml
<key name="WgKodu" keyunique="true" keyprimary="true">
  <keycol name="Kod"/>
</key>
```

| Atrybut | Znaczenie |
|---------|-----------|
| `keyprimary="true"` | Klucz podstawowy (domyślne sortowanie) |
| `keyunique="true"` | Wartości unikalne w tabeli |

**Uwaga:** `keyprimary` w business.xml to **nie to samo** co Primary Key w bazie (który jest zawsze na kolumnie ID).

## Interfejs ISessionable

```csharp
public interface ISessionable {
    Session Session { get; }
}
```

Implementują go: `Session`, `Module`, `Table`, `Row`, `Context`, `Key`.

Używany jako argument funkcji wymagających kontekstu sesji:

```csharp
// Metoda statyczna GetInstance - akceptuje ISessionable
public static TowaryModule GetInstance(ISessionable session)

// Extension method - wygodniejsza składnia (tylko dla Session)
public static TowaryModule GetTowary(this Session session)
```

**Zalecane użycie:**
```csharp
// Extension method (prostsze)
var tm = session.GetTowary();
var tm = context.Session.GetTowary();
var tm = towar.Session.GetTowary();

// GetInstance (gdy mamy ISessionable, ale property Session jest niedostępne)
var tm = TowaryModule.GetInstance(sessionable);
```

## Kod biznesowy vs UI

Kod biznesowy realizuje operacje logiki biznesowej (jak backend). Kod UI (frontend) jest odpowiedzialny za prezentację danych i interakcję z użytkownikiem. Kod biznesowy może być umieszczony w tej samej klasie z kodem UI.

Kod UI to np.:
- obiekty `View`, `ViewInfo`, extender
- metody sterujące `IsReadOnlyXxx`, `IsVisibleXxxx`, `GetListXxx`, `IsEnabledXxx`, `GetNameXxx`, `GetAppearanceXxx`

### Ważne zasady do stosowania w kodzie biznesowym

- Nie używaj żadnych obiektów kodu UI, w szczególności `View` - zamiast tego możesz użyć `SubTable[condition]`.
- Nie należy stosować warunków na prawa dostępu (np. `if (Table.AccessRight == AccessRights.Denied) {...}`).

Szczegóły konstruowania ViewInfo (atrybut `FolderView`, eventy `CreateView`/`InitContext`, klasa `Params`, powiązanie z `viewform.xml`) opisuje [references/viewinfo.md](references/viewinfo.md).

## Szybki start - wzorce kodu

Kanoniczny wzorzec transakcji biznesowej (`Logout → zmiana → Commit → Save`) pokazuje
sekcja [Klasa Session - fundamenty](#klasa-session---fundamenty) powyżej. Gotowe wzorce
end-to-end (odczyt, tworzenie, modyfikacja, kasowanie, obsługa błędów, pełny import) -
patrz [references/examples.md](references/examples.md).

Gotowe **receptury per obiekt biznesowy** (realne pola, kolekcje i workery) są w `references/domeny/`:
[crm.md](references/domeny/crm.md) (`Kontrahent`), [handel.md](references/domeny/handel.md)
(`DokumentHandlowy`), [kadry.md](references/domeny/kadry.md) (`Pracownik`),
[workflow.md](references/domeny/workflow.md) (procesy i zadania).

### Wymagane `using` dla metod rozszerzających

Przykłady w skillu podają wywołania bez przestrzeni nazw. Brak `using` daje `CS1061`/`CS0246`:

| Wywołanie | `using` |
|-----------|---------|
| `"…".Translate()`, `.TranslateFormat(…)` | `Soneta.Langs` |
| `tekst.IsNullOrEmpty()` (rozszerzenie `string`) | `Soneta.Tools` |
| `[Caption]`, `VerifierType` | `Soneta.Types` |

## Narzędzia pomocnicze

Skill udostępnia skrypty `dotnet script` (`scripts/`) do statycznej inwentaryzacji bibliotek Soneta — bez ładowania IL do CLR (metadane typów: Roslyn `MetadataReference.CreateFromFile`; zasoby osadzone: `System.Reflection.Metadata`):

- **Pola tabel — najpierw dane wygenerowane.** Kontrakty pól **wszystkich ~1200 tabel** są już wyeksportowane do [`data/props/`](data/props/) (plik `<Moduł>/<RowType>.md` na tabelę). Odczyt jest natychmiastowy — nie skanuj DLL, gdy tabela tam jest. Znasz `RowType`? Nie czytaj indeksów, tylko `ls data/props/*/DokumentHandlowy.md` (pełny zestaw poleceń niżej). Jak regenerować po zmianie wersji: [references/scan-props.md](references/scan-props.md).
- **Moduły i tabele — indeks dwupoziomowy.** [`data/props/INDEX.md`](data/props/INDEX.md) to **router**: statystyki, polecenia wyszukiwania i lista 37 modułów. Inwentaryzacja tabel modułu jest w `data/props/<Moduł>/INDEX.md` (`RowType | Tytuł | Tabela | Konfig | Guided | Historia | Interfaces | Selektor | Plik`; kolumna `Historia`: `historyczna → H` / `historia → P`). Podział jest celowy — monolityczny indeks (212 KB) przekraczał limit jednego odczytu.
- **Interfejsy — [`data/props/Interfaces.md`](data/props/Interfaces.md).** Wszystkie interfejsy z `[TableInfo(Interfaces=...)]` i tabele je implementujące (relacje interfejsowe w jednym miejscu, tabele linkowane do plików).
- `scan-modules.csx` — skaner **na żądanie** listujący moduły i tabele z DLL (dla innego katalogu DLL niż ten, z którego zbudowano `data/props/`). Szczegóły: [references/scan-modules.md](references/scan-modules.md).
- `export-props-all.csx` — **wsadowo** regeneruje cały `data/props/` z DLL (kompilacja budowana raz, ~1200 tabel w kilka sekund). Uruchamiaj po zmianie wersji platformy lub przebudowie dodatku. Szczegóły: [references/scan-props.md](references/scan-props.md).
- `scan-props.csx` — skaner **na żądanie** dla pojedynczej tabeli (fallback, gdy tabeli nie ma w `data/props/`). Wypisuje pola i właściwości kalkulowane klasy biznesowej, rekurencyjnie po polach typu subrow, oraz — dla tabel z **selektorem** — sekcję podtypów (`[BusinessRow]`/`[NewRow]`). Szczegóły: [references/scan-props.md](references/scan-props.md).
- `scan-workers.csx` — wypisuje na stdout **JSON** z workerami i extenderami zarejestrowanymi atrybutem assembly `[Worker<…>]`, pogrupowanymi wg `DataType`. Dla każdej klasy: parametry inicjowane z `Context` (ctor + `[Context]`, z rozwinięciem pod-property dla typów dziedziczących z `ContextBase`), property do bindowania, akcje menu Czynności. Opcjonalny drugi argument filtruje wynik do konkretnego typu danych (np. `DokumentHandlowy`) — w praktyce konieczny, bo pełne skanowanie zwraca tysiące rejestracji. Wynik łatwo przetwarzać `jq`. Szczegóły: [references/scan-workers.md](references/scan-workers.md).
- **Formularze — najpierw INDEX.** Katalog **wszystkich ~5700 zakładek** (pageform) jest wyeksportowany do [`data/forms/`](data/forms/): [`INDEX.md`](data/forms/INDEX.md) to **router** (sposoby wyszukiwania, lista 26 przestrzeni nazw, sekcja systemowa), a zakładki biznesowe leżą w `data/forms/<Przestrzeń>.md` (`Typ danych | Zakładka (plik) | Nazwa zakładki | Priority | Biblioteka | Przestrzeń`, sortowane po typie). **Nie musisz znać przestrzeni** — `rg '^\| Kontrahent \|' data/forms/*.md` przeszukuje wszystkie naraz. Typ = segment przed nazwą zakładki w `…<TYP>.<ZAKŁADKA>.pageform.xml` (albo `DataType`). Zakładki typów ogólnych (`Row`/`IRow`/…) wydzielone jako **systemowe** (osobna sekcja routera; `scan-forms` nie raportuje ich per obiekt). Odczyt natychmiastowy, bez DLL. Regeneracja: `export-forms-index.csx`. Szczegóły: [references/scan-forms.md](references/scan-forms.md).
- `scan-forms.csx` — skaner **na żądanie** dla pojedynczego obiektu: odczytuje z zasobów osadzonych (`*.pageform.xml`/`*.form.xml`) **zakładki, sekcje danych (grupy) i pola** w **kolejności wprowadzania**, rozwijając ścieżki pól przez łańcuch `DataContext`/`EditValue`, dołączane `Include` (także między bibliotekami) oraz listy (`Grid`/`Scheduler`/… → kolumny elementu kolekcji, separator `:` między wczytaniem listy a polami elementu). Argument = prefiks nazwy pliku lub `DataType`/`Namespace.Typ`. Do budowania danych kodem i importu XML `business="true"`. Szczegóły: [references/scan-forms.md](references/scan-forms.md).
- `export-forms-index.csx` — **wsadowo** generuje `data/forms/INDEX.md` i pliki przestrzeni z DLL (jeden przebieg, ~5700 zakładek w ~1 s). Uruchamiaj po zmianie wersji platformy lub przebudowie dodatku.

### Jak szukać w danych wygenerowanych

Dane w `data/` są tak zorganizowane, że **nazwa pliku niesie informację** — najczęściej
wystarczy `ls` albo jeden `rg`, bez czytania indeksów. Polecenia uruchamiaj z katalogu skilla:

```bash
# Pola tabeli, gdy znasz RowType — plik nazywa się <Moduł>/<RowType>.md
ls data/props/*/DokumentHandlowy.md          # → data/props/Handel/DokumentHandlowy.md
ls data/props/*/*Pracownik*.md               # gdy nie znasz dokładnej nazwy

# Tabela po nazwie w bazie (kolumna `Tabela`) lub po tytule
rg -l '`DokHandlowe`' data/props/*/INDEX.md

# Które tabele mają pole wskazujące na dany obiekt (relacje)
rg -l 'Soneta\.CRM\.Kontrahenci\.Kontrahent`' data/props/*/*.md

# Zakładki obiektu — bez znajomości przestrzeni nazw
rg '^\| Kontrahent \|' data/forms/*.md

# Które tabele implementują interfejs
rg '^\| `IDokument' data/props/Interfaces.md
```

**Nie czytaj `data/props/<Moduł>/INDEX.md` ani `data/forms/<Przestrzeń>.md` w całości**, gdy
szukasz jednego obiektu — to setki wierszy. Indeksy służą do przeglądu modułu, `rg`/`ls` do
trafienia w konkret.

Inwentaryzację **folderów statycznych menu** (`[assembly: FolderView]`) — drzewo pozycji menu, list i formularzy — realizuje narzędzie **`scan-folders`** przeniesione do skilla **`/soneta:config`** (komplementarne do `scan-modules`: perspektywa funkcjonalno-użytkowa zamiast danych).

## Konwencje nazewnicze

| Element | Konwencja | Przykład |
|---------|-----------|----------|
| Klasa wiersza (Row) | PascalCase, l.poj. | `Towar`, `Kontrahent` |
| Klasa tabeli | PascalCase, l.mn. | `Towary`, `Kontrahenci` |
| Klasa modułu | Nazwa + Module | `TowaryModule` |
| Klucz | Wg + nazwa kolumny | `WgKodu`, `WgNazwy` |
| Namespace | Soneta.NazwaModułu | `Soneta.Towary` |

### Język identyfikatorów

| Typ | Język | Przykłady |
|-----|-------|-----------|
| Logika biznesowa | **polski** | `Towar`, `Kontrahent`, `DokumentHandlowy`, `Faktura` |
| Identyfikatory systemowe | **angielski** | `Session`, `Context`, `Row`, `Table`, `Module` |

**Można łączyć polski i angielski** w nazwach metod i klas:

```csharp
RetrieveTowary()
UpdateKontrahent()
GetDokumentyHandlowe()
CreateFaktura()
```

Files in this skill

  • SKILL.md28.9 KB
  • data/forms/INDEX.md6.4 KB
  • data/forms/Soneta.BI.md20.2 KB
  • data/forms/Soneta.Business.md41.8 KB
  • data/forms/Soneta.CRM.md18.6 KB
  • data/forms/Soneta.Core.md40.6 KB
  • data/forms/Soneta.CzlonkowieSzkolenia.md16.2 KB
  • data/forms/Soneta.EI.md4.7 KB
  • data/forms/Soneta.Handel.md26.3 KB
  • data/forms/Soneta.Kasa.md18.8 KB
  • data/forms/Soneta.KlientBiuraRachunkowego.md1.4 KB
  • data/forms/Soneta.Ksiega.md36.2 KB
  • data/forms/Soneta.Magazyny.md3.4 KB
  • data/forms/Soneta.Net.md7.2 KB
  • data/forms/Soneta.Printer.md825 B
  • data/forms/Soneta.Produkcja.md5.1 KB
  • data/forms/Soneta.ProdukcjaPro.md18.4 KB
  • data/forms/Soneta.PulpitKontrahenta.md3.7 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.