SKILL: Uporządkowanie skills domenowych - podział na mniejsze pliki i wspólna numeracja

This commit is contained in:
Marcin Wojas
2026-06-07 08:31:37 +02:00
parent fb2f2695a3
commit 5605ad2915
42 changed files with 13500 additions and 13526 deletions
@@ -0,0 +1,479 @@
# KADRY07 — Umowy cywilnoprawne
> Wspólne fakty o typie, podstawowe typy i szablon wzorca: [../kadry.md](../kadry.md).
### KADRY-G1 — Dodawanie umów cywilnoprawnych (zlecenie, o dzieło) (★)
**Cel:** utworzyć dla pracownika umowę cywilnoprawną (zlecenie / o dzieło / ryczałtowa) z kompletem
danych pozwalającym na `Session.Save()`: definicja elementu płacowego (rodzaj umowy), okres, wartość,
sposób rozliczenia i typ wartości (brutto/netto).
**Mechanizm (kluczowy):** `Soneta.Kadry.Umowa` to **root historyczny** (tabela `Umowy`), child
pracownika. Dodanie umowy do tabeli (`Module.Umowy.AddRow(umowa)`) w `OnAdded` **automatycznie tworzy
pierwszy zapis** `Soneta.Kadry.UmowaHistoria` (tabela `UmowaHistorie`) oraz domyślną definicję
elementu, okres, datę i numerację. Dlatego **nie tworzymy `UmowaHistoria` ręcznie** — bezpośrednio po
`AddRow` istnieje już `umowa.Last` (pierwszy zapis), na którym ustawiamy **wartość umowy**.
> **Gdzie co siedzi.** Dane „nagłówkowe" umowy (definicja elementu, okres, sposób rozliczenia, typ
> wartości) są na **roocie** `Umowa`. **Kwota/wartość umowy** jest **historyczna** i siedzi na
> `UmowaHistoria.Wartosc` — ustawiasz ją przez `umowa.Last.Wartosc`. Property `umowa.Brutto`/
> `umowa.Wartosc` na roocie oraz `UmowaHistoria.Brutto` są **wyliczane** (read-only).
**Warianty (rodzaj umowy = `DefinicjaElementu`):**
| Rodzaj umowy | Jak wskazać definicję |
|---|---|
| Zlecenie | `DefElementow[DefinicjaElementu.UmowaZlecenie]` (to też wartość domyślna konfiguracji) |
| O dzieło (20% KUP) | `DefElementow[DefinicjaElementu.Umowa20]` |
| Ryczałtowa | `DefElementow[DefinicjaElementu.UmowaRyczałtowa]` |
| Inna (po kodzie/nazwie) | `DefElementow["<kod>"]` (indeksator string = wg kodu) — pod warunkiem że jej `RodzajZrodla == RodzajŹródłaWypłaty.Umowa` |
**Pola i typy:**
| Pole | Gdzie | Typ | Uwaga |
|---|---|---|---|
| `Element` | `Umowa` (root) | `Soneta.Place.DefinicjaElementu` | definicja elementu = rodzaj umowy; akceptowana tylko gdy `RodzajZrodla == RodzajŹródłaWypłaty.Umowa` |
| `Data` | `Umowa` (root) | `Soneta.Types.Date` | data zawarcia/dokumentu |
| `Okres` | `Umowa` (root) | `Soneta.Types.FromTo` | okres obowiązywania umowy |
| `Tytul` | `Umowa` (root) | `string` | tytuł/temat umowy |
| `RodzajRozliczenia` | `Umowa` (root) | `Soneta.Kadry.RodzajeRozliczeniaUmowy` | `KwotaDoWypłaty` / `StawkaZaOkres` / `StawkaZaGodzinę` |
| `TypWartosci` | `Umowa` (root) | `Soneta.Kadry.TypWartosciUmowy` | `Brutto` / `Netto` |
| `Wydzial` | `Umowa` (root) | `Soneta.Kadry.Wydzial` | jednostka organizacyjna — **wymagana** (weryfikator przy `Save()`); ustaw `kadry.Wydzialy.Firma` |
| `Wartosc` | `UmowaHistoria` (`Last`) | `Soneta.Types.Currency` | **kwota/wartość umowy** — ustawiana na zapisie historycznym |
**Snippet:**
```csharp
var kadry = session.GetKadry();
var place = session.GetPlace();
var pracownik = kadry.Pracownicy.WgKodu["006"];
using (var t = session.Logout(editMode: true))
{
// 1) Utworzenie umowy + dodanie do tabeli; w OnAdded powstaje pierwszy UmowaHistoria.
var umowa = session.AddRow(new Umowa(pracownik));
// 2) Definicja elementu = rodzaj umowy (tu: zlecenie). Indeksator Guid + stała publiczna.
umowa.Element = place.DefElementow[DefinicjaElementu.UmowaZlecenie];
// 3) Dane nagłówkowe na roocie:
umowa.Data = new Date(2026, 1, 1);
umowa.Okres = new FromTo(new Date(2026, 1, 1), new Date(2026, 12, 31));
umowa.Tytul = "Umowa zlecenie - obsługa projektu";
umowa.RodzajRozliczenia = RodzajeRozliczeniaUmowy.KwotaDoWypłaty;
umowa.TypWartosci = TypWartosciUmowy.Brutto;
umowa.Wydzial = kadry.Wydzialy.Firma; // wymagane przy Save()
// 4) KWOTA umowy — na zapisie historycznym Last (UmowaHistoria.Wartosc):
umowa.Last.Wartosc = new Currency(5000m);
t.Commit(); // Commit() w kodzie biznesowym; CommitUI() w workerze/UI
}
session.Save(); // tu wykrywane konflikty/duplikaty
```
**Pułapki:**
- **Nie** twórz ręcznie pierwszego `UmowaHistoria` — robi to `OnAdded` przy `AddRow`. Ręczny nowy
zapis dotyczy dopiero *zmiany/aneksu* „od daty" (KADRY-G2).
- **Kwotę ustawiaj na `umowa.Last.Wartosc`**, nie na roocie — `umowa.Brutto`/`umowa.Wartosc` oraz
`Last.Brutto` są wyliczane (read-only). `Wartosc` to `Soneta.Types.Currency`, nie `decimal`
(safe-code §10.1).
- `Element` przyjmie tylko definicję o `RodzajZrodla == RodzajŹródłaWypłaty.Umowa`. Definicje
„etatowe" (np. `EtatMies`) zostaną zignorowane (umowa dostanie domyślną definicję z konfiguracji).
- Jeśli `Element` **nie** zostanie ustawiony, umowa przyjmuje
`Module.Config.Ogólne.DomyślnaDefinicjaUmowy` (domyślnie = `UmowaZlecenie`).
- Dodanie umowy do pracownika **w archiwum** rzuca wyjątek (`WArchiwumException`) z `OnAdded`.
- `RodzajRozliczenia`/`TypWartosci` bywają w UI tylko-do-odczytu zależnie od definicji elementu —
w kodzie biznesowym ustawiasz je wprost (nie używaj `IsReadOnlyXxx`, safe-code §7.1).
- Całość w transakcji (`session.Logout(editMode: true)`); brak `Commit()` = rollback przy `Dispose()`.
### KADRY-G2 — Zmiana/aneks umowy (★)
**Cel:** zmienić warunki istniejącej umowy. Trzy rozłączne przypadki: **(a) korekta** danych
nagłówkowych w bieżącym okresie; **(b) aneks „od daty"** — nowy zapis historyczny `UmowaHistoria`
obowiązujący od wskazanego dnia (analogicznie do `PracHistoria`, sekcja KADRY-A14); **(c) seryjna
aktualizacja stawki** workerem.
**Mechanizm `HistorySubTable<UmowaHistoria>`** (`umowa.Historia`):
| Operacja | API | Efekt |
|---|---|---|
| Odczyt zapisu na dzień | `umowa[date]` (== `(UmowaHistoria)Historia[date]`) | zapis, którego `Aktualnosc` zawiera `date` |
| Ostatni (bieżący) zapis | `umowa.Last` (== `Historia.GetPrev()`) | najświeższy zapis |
| Pierwszy zapis | `umowa.Historia.GetFirst()` | najstarszy zapis |
| **Nowy zapis „od daty"** | `(UmowaHistoria)umowa.Historia.Update(date)` | **klonuje** zapis aktualny na `date`, skraca stary do `date-1`, zwraca **nowy** klon (okres od `date`); klon trzeba dodać do tabeli |
| Okres obowiązywania | `UmowaHistoria.Aktualnosc: FromTo` | „oddo" zapisu (zarządzany przez historię) |
**(a) Korekta danych nagłówkowych umowy (bez nowego okresu):**
```csharp
var umowa = pracownik.Umowy.First(); // lub wyszukanie po polu/numerze
using (var t = session.Logout(editMode: true))
{
umowa.Tytul = "Umowa zlecenie - aneks zakresu prac";
umowa.Okres = new FromTo(umowa.Okres.From, new Date(2027, 6, 30)); // przedłużenie
t.Commit();
}
session.Save();
```
**(b) Aneks „od daty" — zmiana wartości umowy nowym zapisem historycznym:**
```csharp
var odDnia = new Date(2026, 7, 1);
using (var t = session.Logout(editMode: true))
{
// 1) Update klonuje zapis aktualny na `odDnia` i zwraca nowy klon (okres od `odDnia`);
// stary zapis zostaje skrócony do dnia poprzedniego.
var nowy = (UmowaHistoria)umowa.Historia.Update(odDnia);
// 2) Klon trzeba dodać do tabeli zapisów historii umowy.
umowa.Module.UmowaHistorie.AddRow(nowy);
// 3) Na nowym zapisie ustawiamy zmienioną wartość (od `odDnia`):
nowy.Wartosc = new Currency(6000m);
// Uwaga: UmowaHistoria.PowodAktualizacji jest tylko do odczytu (ustawiane wewnętrznie) — nie przypisuj.
t.Commit();
}
session.Save();
```
**(c) Seryjna aktualizacja stawki — worker `Umowa.AktualizacjaStawkiWorker`:**
```csharp
var worker = new Umowa.AktualizacjaStawkiWorker
{
Umowy = new[] { umowa },
Pars = ... // Umowa.AktualizacjaStawkiWorker.Params: Data: Date, Wartosc: Currency
};
// uruchomienie zgodnie z konwencją workerów (patrz worker-extender.md)
```
> Pokrewne workery (wywoływane jak każdy worker enova): `Umowa.KopiujUmowe2Worker`
> (`Umowa Umowa` — kopiuje umowę), `Umowa.WyrejestrujUmoweWorker` (wyrejestrowanie umowy).
**Pułapki:**
- **`Update(date)` + `UmowaHistorie.AddRow(nowy)` to nierozłączna para.** Sam `Update` tworzy
„odpięty" klon — bez `AddRow` zmiana nie zostanie zapisana.
- `Update(date)` rzuca wyjątek duplikatu, gdy na `date` już zaczyna się zapis (`Aktualnosc.From == date`)
— nie da się „aktualizować" dwa razy tego samego dnia; wtedy modyfikuj istniejący zapis (`umowa[date]`).
- **Korekta** (`umowa.Last.Wartosc = …` lub modyfikacja `umowa[date]`) zmienia dane w **całym** okresie
tego zapisu — używaj jej do poprawy błędu, nie do „zmiany od dnia"; do zmiany od dnia → wariant (b).
- `Aktualnosc` (okres zapisu) jest zarządzany przez historię — **nie ustawiaj go ręcznie**; do
skrócenia/wstawienia okresu służy `Update`.
- Wartość zawsze jako `Soneta.Types.Currency`, nie `decimal` (safe-code §10.1); daty jako
`Soneta.Types.Date`/`Date.Today` (§10.2).
- Obsłuż `RowConflictException` z `Save()` (safe-code §4); transakcje trzymaj krótkie (§13.1).
### KADRY-G3 — Operacja seryjna „Dodaj umowy" dla grupy osób (★)
**Cel:** dodać jednakową umowę cywilnoprawną (zlecenie / o dzieło / ryczałtowa) **naraz dla wielu
zaznaczonych pracowników** — operacja seryjna z listy osób. W UI: menu *Operacje seryjne → Dodaj
umowy…*. Każdej osobie z zaznaczenia tworzona jest osobna `Umowa` z tymi samymi danymi nagłówkowymi
(definicja elementu, okres, wartość, sposób rozliczenia), analogicznie do KADRY-G1.
**Worker (publiczny kontrakt):** `Soneta.Kadry.Pracownik.DodajUmowęWorker` — worker **przypisany do
`Pracownik`** (`DataType = Pracownik`). Udostępnia akcję `DodajUmowę` w menu czynności listy
pracowników.
| Składowa | Typ / sygnatura | Uwaga |
|---|---|---|
| Konstruktor | `DodajUmowęWorker(Session session)` | worker ma **ctor z `Session`** (nie bezparametrowy) |
| Zaznaczone osoby | `DodajUmowęWorker.Pracownicy: Pracownik[]` | `[Context]` — tablica pracowników z zaznaczenia listy |
| Parametry | `DodajUmowęWorker.Pars: DodajUmowęWorker.Params` | `[Context]` — okno parametrów operacji; `Params(Context)` |
| Akcja | `void DodajUmowę()` | tworzy umowy dla wszystkich `Pracownicy` (zwraca **`void`**, nie `object`) |
**Parametry operacji (`DodajUmowęWorker.Params`):**
| Pole | Typ | Odpowiednik na `Umowa` (KADRY-G1) |
|---|---|---|
| `Definicja` | `Soneta.Core.DefinicjaDokumentu` | definicja dokumentu umowy (numeracja/seria) |
| `Seria` | `string` | seria numeracji |
| `Wydział` | `Soneta.Kadry.Wydzial` | `Umowa.Wydzial` (wymagany) |
| `Data` | `Soneta.Types.Date` | `Umowa.Data` (data zawarcia) |
| `Okres` | `Soneta.Types.FromTo` | `Umowa.Okres` |
| `Tytuł` | `string` | `Umowa.Tytul` |
| `Element` | `Soneta.Place.DefinicjaElementu` | `Umowa.Element` (rodzaj umowy) |
| `RodzajRozliczenia` | `Soneta.Kadry.RodzajeRozliczeniaUmowy` | `Umowa.RodzajRozliczenia` |
| `Wartość` | `Soneta.Types.Currency` | `umowa.Last.Wartosc` (kwota umowy) |
| `TypWartości` | `Soneta.Kadry.TypWartosciUmowy` | `Umowa.TypWartosci` (`Brutto`/`Netto`) |
**Wariant A — wywołanie workera platformy (zalecane):** zainicjuj `DodajUmowęWorker`, ustaw
`Pracownicy` i `Pars`, wywołaj `DodajUmowę()` (worker uruchamia się jak każdy worker — patrz
[`worker-extender.md`](../worker-extender.md), sekcja *Programowe użycie workera*).
```csharp
var kadry = session.GetKadry();
var place = session.GetPlace();
// Grupa osób (np. z zaznaczenia listy). Tu: kilku pracowników po kodzie:
var osoby = new[]
{
kadry.Pracownicy.WgKodu["006"],
kadry.Pracownicy.WgKodu["007"],
kadry.Pracownicy.WgKodu["008"],
};
var pars = new Pracownik.DodajUmowęWorker.Params(context);
pars.Element = place.DefElementow[DefinicjaElementu.UmowaZlecenie];
pars.Okres = new FromTo(new Date(2026, 1, 1), new Date(2026, 12, 31));
pars.Data = new Date(2026, 1, 1);
pars.Tytuł = "Umowa zlecenie - projekt grupowy";
pars.RodzajRozliczenia = RodzajeRozliczeniaUmowy.KwotaDoWypłaty;
pars.TypWartości = TypWartosciUmowy.Brutto;
pars.Wartość = new Currency(4000m);
pars.Wydział = kadry.Wydzialy.Firma; // wymagany
// Worker ma konstruktor z Session (nie bezparametrowy); Pracownicy/Pars przez inicjalizator:
var worker = new Pracownik.DodajUmowęWorker(session) { Pracownicy = osoby, Pars = pars };
worker.DodajUmowę(); // void
session.Save();
```
**Wariant B — pętla po pracownikach (jawne tworzenie, jak KADRY-G1):** gdy nie chcesz przechodzić przez
worker — dla każdej osoby twórz `new Umowa(p)` i ustaw te same pola co w KADRY-G1. To jawnie pokazuje, że
operacja seryjna = KADRY-G1 powtórzone w pętli.
```csharp
var kadry = session.GetKadry();
var place = session.GetPlace();
var defElementu = place.DefElementow[DefinicjaElementu.UmowaZlecenie];
var okres = new FromTo(new Date(2026, 1, 1), new Date(2026, 12, 31));
using (var t = session.Logout(editMode: true))
{
foreach (var p in osoby)
{
var umowa = session.AddRow(new Umowa(p)); // OnAdded tworzy pierwszy UmowaHistoria
umowa.Element = defElementu;
umowa.Data = okres.From;
umowa.Okres = okres;
umowa.Tytul = "Umowa zlecenie - projekt grupowy";
umowa.RodzajRozliczenia = RodzajeRozliczeniaUmowy.KwotaDoWypłaty;
umowa.TypWartosci = TypWartosciUmowy.Brutto;
umowa.Wydzial = kadry.Wydzialy.Firma; // wymagany przy Save()
umowa.Last.Wartosc = new Currency(4000m); // kwota na zapisie historycznym
}
t.Commit(); // Commit() w kodzie biznesowym; CommitUI() w workerze/UI
}
session.Save();
```
**Pułapki:**
- `Pracownik.DodajUmowęWorker` jest workerem na typie `Pracownik`, a tworzy obiekty `Umowa` — nie myl
go z workerami na `Umowa` (KADRY-G2: `AktualizacjaStawkiWorker`, `KopiujUmowe2Worker`).
- W wariancie B obowiązują wszystkie pułapki KADRY-G1: kwota na `umowa.Last.Wartosc` (root `Brutto`/`Wartosc`
są wyliczane), `Element` tylko o `RodzajZrodla == RodzajŹródłaWypłaty.Umowa`, `Wydzial` wymagany,
dodanie umowy pracownikowi **w archiwum** rzuca `WArchiwumException`.
- Pętlę edycyjną trzymaj krótką (safe-code §13.1); konflikty/duplikaty wykrywane w `Save()` (§4).
- Wartość zawsze jako `Soneta.Types.Currency`, daty jako `Date`/`FromTo`, nie `decimal`/`DateTime`
(safe-code §10).
---
### KADRY-G4 — Rachunek do umowy zlecenia (★)
**Cel:** wystawić **rachunek do umowy zlecenia** — czyli rozliczyć (naliczyć i wypłacić) umowę
cywilnoprawną. W modelu Soneta „rachunek do umowy zlecenia" **nie jest osobnym rekordem** na `Umowa`
ani w `pracownik.Rachunki` — to **wypłata z umowy** typu `Soneta.Place.WyplataUmowa`, naliczana
mechanizmem płac (jak KADRY-H2). `pracownik.Rachunki: SubTable<Soneta.Kasa.RachunekBankowyPodmiotu>` to
**rachunki bankowe** pracownika (numer konta), a nie rachunki do umów — nie myl tych pojęć.
> **Gdzie to siedzi.** Każda umowa ma wstecz powiązane rozliczenia/wypłaty:
> - `Umowa.RozliczeniaWynagrodzenia: LpSubTable<Soneta.Place.RozliczenieWynagrodzenia>` — rozliczenia
> wynagrodzenia z umowy,
> - `Umowa.Elementy: SubTable<Soneta.Place.WypElement>` — naliczone składniki wypłat tej umowy,
> - sama wypłata to `Soneta.Place.WyplataUmowa` (konkretny typ `Wyplata`), z polem zwrotnym
> `WyplataUmowa.Umowa: Soneta.Kadry.Umowa`.
> Stan rozliczenia umowy odczytasz z `Umowa.Stan: Soneta.Kadry.StanUmowy`
> (`Niewypłacona` / `WypłaconaCzęściowo` / `WypłaconaCałkowicie` / `Anulowana`) oraz z
> `Umowa.Splacono`, `Umowa.Pozostało` (`Soneta.Types.Currency`).
**Tworzenie rachunku (wypłaty) do umowy — wykonawca naliczania `NaliczanieSeryjne.Umowy` (jak KADRY-H2):**
| Element | Typ / sygnatura | Uwaga |
|---|---|---|
| Parametry | `new NaliczanieSeryjne.UmowaParams(context)` | `Naliczanie` na sztywno `PłatnaZDołu` (setter rzuca `NotSupportedException`) |
| Data rachunku / listy | `UmowaParams.DataWypłaty`, `.DataListy` | daty rachunku |
| Wykonawca | `new NaliczanieSeryjne.Umowy(UmowaParams) { Umowa = umowa }` | ustawienie `Umowa` ustawia też `Pracownik` z `umowa.Pracownik` |
| Uruchomienie | `Umowy.Nalicz(): NaliczanieWypłat` | tworzy `WyplataUmowa` i liczy składniki |
| Wynik | `NaliczanieWypłat.WszystkieWypłaty: IList` | elementy `Wyplata` (tu `WyplataUmowa`) |
```csharp
var kadry = session.GetKadry();
var pracownik = kadry.Pracownicy.WgKodu["006"];
// Umowa zlecenie pracownika (np. utworzona w KADRY-G1):
Umowa umowa = pracownik.Umowy.Cast<Umowa>()
.First(u => u.Element == session.GetPlace().DefElementow[DefinicjaElementu.UmowaZlecenie]);
var pars = new NaliczanieSeryjne.UmowaParams(context);
pars.DataWypłaty = new Date(2026, 2, 10); // data wystawienia rachunku
pars.DataListy = pars.DataWypłaty;
var naliczanie = new NaliczanieSeryjne.Umowy(pars) { Umowa = umowa };
NaliczanieWypłat wynik = naliczanie.Nalicz(); // tworzy WyplataUmowa (rachunek)
foreach (Wyplata w in wynik.WszystkieWypłaty)
{
// w.Typ == TypWyplaty.Umowa; w to WyplataUmowa; w.Elementy = składniki rachunku
}
session.Save();
// Po naliczeniu — stan rozliczenia umowy:
StanUmowy stan = umowa.Stan; // np. WypłaconaCałkowicie
Currency splacono = umowa.Splacono; // kwota rozliczona
Currency pozostalo = umowa.Pozostało; // pozostała do wypłaty
```
**Odczyt rachunków (wypłat) wystawionych do umowy:**
```csharp
// Wypłaty (rachunki) tej umowy — przez wypłaty pracownika filtrowane po umowie:
foreach (WyplataUmowa w in pracownik.Wyplaty.OfType<WyplataUmowa>().Where(x => x.Umowa == umowa))
{
// w.Data, w.Elementy (WypElement.Wartosc / .Netto / .Podatki.*)
}
// Składniki naliczone bezpośrednio z umowy:
foreach (WypElement e in umowa.Elementy)
{
// e.Wartosc, e.Netto
}
```
**Pułapki:**
- „Rachunek do umowy zlecenia" = `WyplataUmowa`, a nie rekord w `pracownik.Rachunki` (to rachunki
bankowe). Tworzysz go naliczaniem (`NaliczanieSeryjne.Umowy.Nalicz()`), nie `AddRow` po wypłacie.
- **Nie ustawiaj `UmowaParams.Naliczanie`** — umowy są zawsze „płatne z dołu" (setter rzuca
`NotSupportedException`).
- Ustawienie `Umowy.Umowa` nadpisuje `Pracownik` właścicielem umowy — nie ustawiaj `Pracownik` ręcznie.
- `Nalicz()` wewnętrznie otwiera własną transakcję i zatwierdza zmiany w sesji — po nim wołasz tylko
`Session.Save()`; nie owijaj go w dodatkowy `Logout(editMode: true)`.
- `Wyplata` nie ma agregatów `Brutto`/`Netto` — sumuj składniki z `Wyplata.Elementy` (jak w KADRY-H2/KADRY-H4).
- Kwoty jako `Soneta.Types.Currency`, daty jako `Date` (safe-code §10).
---
### KADRY-G5 — Zgłoszenia ZUS zleceniobiorców (ZUA / ZZA na podstawie umowy) (★)
**Cel:** przygotować zgłoszenie zleceniobiorcy do ZUS — **ZUA** (zgłoszenie do ubezpieczeń
społecznych + zdrowotnego) albo **ZZA** (tylko zdrowotne) — **na podstawie schematu ubezpieczeń
umowy**, oraz wyrejestrowanie (**ZWUA**) po jej zakończeniu. O tym, czy powstaje ZUA czy ZZA, decyduje
**schemat ubezpieczeń zapisu umowy**, a nie odrębne pole „rodzaj zgłoszenia".
> **Schemat ubezpieczeń umowy — gdzie siedzi.** Ubezpieczenia umowy są **historyczne** i leżą na
> zapisie `UmowaHistoria.Ubezpieczenia: Soneta.Kadry.Ubezpieczenia` (analogicznie do
> `PracHistoria.Etat.Ubezpieczenia` z KADRY-A7; ta sama struktura `Spoleczne`/`Zdrowotne`). Z roota dostępne
> przez `umowa.Last.Ubezpieczenia` (oraz `umowa.Ubezpieczenia` jako delegat). Kluczowe pola:
> - `Ubezpieczenia.Tyub4: Soneta.Kadry.TytulUbezpieczenia4` — **tytuł ubezpieczenia** (decyduje o ZUA
> vs ZZA); pobierany ze słownika `session.GetKadry().TytulyUbezpiecz4.WgKodu[int]`,
> - `Ubezpieczenia.ObowiazkoweOd: Date` — data objęcia ubezpieczeniami społecznymi obowiązkowymi,
> - `Ubezpieczenia.Emerytalne` / `Rentowe` / `Chorobowe` / `Wypadkowe : Soneta.Kadry.Spoleczne` —
> poszczególne społeczne (`Obowiazkowe`, `Dobrowolne`, `DobrowolneOd`, `Do`; `Od` read-only),
> - `Ubezpieczenia.Zdrowotne: Soneta.Kadry.Zdrowotne` — zdrowotne (`ObowiazkoweOd` zapisywalne).
>
> **Reguła ZUA vs ZZA:** zleceniobiorca podlegający ubezpieczeniom **społecznym** (emerytalne/rentowe
> obowiązkowe) → **ZUA**; podlegający **tylko zdrowotnemu** (np. uczeń/student do 26 r.ż., zbieg
> tytułów) → **ZZA**. Worker rozpoznaje to automatycznie po schemacie `UmowaHistoria.Ubezpieczenia`.
>
> **Uwaga (zweryfikowane testem):** świeży zapis ubezpieczeń umowy zlecenie ma **domyślnie**
> `Emerytalne.Obowiazkowe == true` i `Rentowe.Obowiazkowe == true` (schemat ZUA). Aby uzyskać **ZZA**,
> trzeba je **jawnie wyłączyć** (`ub.Emerytalne.Obowiazkowe = false; ub.Rentowe.Obowiazkowe = false;`)
> — samo ustawienie `Zdrowotne.ObowiazkoweOd` nie wystarcza.
**Worker (publiczny kontrakt):** `Soneta.Deklaracje.ZUS.ZarejestrujUmowyWorker` — worker
**przypisany do `Umowa`** (`DataType = Umowa`). Operuje na zaznaczonych umowach i generuje deklaracje
zgłoszeniowe ZUS. W UI: menu czynności listy umów *Deklaracje ZUS → Przygotuj ZUA i ZZA* (oraz
wyrejestrowanie).
| Składowa | Typ / sygnatura | Uwaga |
|---|---|---|
| Worker | `ZarejestrujUmowyWorker()` | ctor **bezparametrowy**; `Umowy: Umowa[]` jest **set-only** (ustaw przez inicjalizator) |
| Zaznaczone umowy | `ZarejestrujUmowyWorker.Umowy: Umowa[]` | `[Context]` — umowy do zgłoszenia (write-only) |
| Akcja: zgłoszenie | `object ZarejestrujUmowyWorker.Rejestracja.ZarejestrujUmowy()` | tworzy ZUA/ZZA (i ZCNA dla rodziny — `Pars.ZarejestrujRodzinę`); `Rejestracja()` ctor bezparam. |
| Akcja: wyrejestrowanie | `object ZarejestrujUmowyWorker.Wyrejestrowanie.WyrejestrujUmowy()` | tworzy ZWUA |
| Parametry zgłoszenia | `Rejestracja.Pars: ParamsZ` | **set-only**; `ParamsZ(Context)`; pola bazowe `Okres`/`DataDokumentu`/`DataWypełnienia`/`Kedu` (write-only) + własne `ZarejestrujRodzinę: bool` |
| Parametry wyrejestrowania | `Wyrejestrowanie.Pars: ParamsW` | **set-only**; `ParamsW(Context)`; `Okres`/`DataDokumentu`/`DataWypełnienia`/`Kedu` + `WyrejestrujRodzinę: bool` |
**Wspólny kontrakt bazowy `ZarejestrujBaseWorker`** (do odczytu wyniku i sterowania okresem):
| Pole / metoda | Typ / sygnatura | Uwaga |
|---|---|---|
| `Okres` | `Soneta.Types.FromTo` | okres deklaracji |
| `DataDokumentu`, `DataWypełnienia` | `Soneta.Types.Date` | daty na dokumencie |
| `KEDU` | `Soneta.Deklaracje.ZUS.KEDU` | zestaw dokumentów ZUS, do którego trafiają wygenerowane bloki |
| `Deklaracje` | `System.Collections.Generic.IList` | wygenerowane deklaracje (do odczytu po akcji) |
| `CzyJestZUA()`, `CzyJestZZA()` | — | rozpoznanie typu zgłoszenia ze schematu ubezpieczeń |
**Schemat ubezpieczeń umowy + zgłoszenie ZUA/ZZA:**
```csharp
var kadry = session.GetKadry();
var pracownik = kadry.Pracownicy.WgKodu["006"];
Umowa umowa = pracownik.Umowy.Cast<Umowa>().First();
// 1) Schemat ubezpieczeń umowy (historyczny) — ZUA: społeczne obowiązkowe + zdrowotne:
using (var t = session.Logout(editMode: true))
{
var ub = umowa.Last.Ubezpieczenia; // UmowaHistoria.Ubezpieczenia
ub.Tyub4 = kadry.TytulyUbezpiecz4.WgKodu[kodTytulu]; // tytuł zleceniobiorcy (klucz int, ze słownika)
ub.ObowiazkoweOd = umowa.Okres.From; // data objęcia społecznymi
ub.Emerytalne.Obowiazkowe = true;
ub.Rentowe.Obowiazkowe = true;
ub.Zdrowotne.ObowiazkoweOd = umowa.Okres.From;
// (ZZA = tylko zdrowotne: JAWNIE ustaw Emerytalne.Obowiazkowe = false i Rentowe.Obowiazkowe = false
// — domyślnie są true; samo zdrowotne nie wystarcza)
t.Commit();
}
session.Save();
// 2) Zgłoszenie ZUA/ZZA na podstawie umowy — worker (DataType Umowa):
// Uwaga: Umowy oraz Pars są SET-ONLY (brak gettera) — ustawiamy je przez inicjalizator,
// a parametry budujemy jako osobny obiekt ParamsZ(context) i przypisujemy do Pars.
var worker = new Soneta.Deklaracje.ZUS.ZarejestrujUmowyWorker { Umowy = new[] { umowa } };
var pars = new Soneta.Deklaracje.ZUS.ZarejestrujBaseWorker.ParamsZ(context);
pars.Okres = new FromTo(umowa.Okres.From, Date.MaxValue);
pars.DataDokumentu = umowa.Okres.From;
pars.DataWypełnienia = Date.Today;
pars.ZarejestrujRodzinę = false;
var rejestracja = new Soneta.Deklaracje.ZUS.ZarejestrujUmowyWorker.Rejestracja { Pars = pars };
rejestracja.ZarejestrujUmowy(); // generuje ZUA lub ZZA wg schematu ubezpieczeń umowy
session.Save();
```
**Wyrejestrowanie po zakończeniu umowy (ZWUA):**
```csharp
var parsW = new Soneta.Deklaracje.ZUS.ZarejestrujBaseWorker.ParamsW(context);
parsW.Okres = new FromTo(umowa.Okres.To, umowa.Okres.To);
parsW.DataDokumentu = umowa.Okres.To;
parsW.DataWypełnienia = Date.Today;
var wyrej = new Soneta.Deklaracje.ZUS.ZarejestrujUmowyWorker.Wyrejestrowanie { Pars = parsW };
wyrej.WyrejestrujUmowy(); // generuje ZWUA
session.Save();
```
**Pułapki:**
- **Typ zgłoszenia (ZUA vs ZZA) wynika ze schematu `UmowaHistoria.Ubezpieczenia`**, nie z parametru
workera — ustaw poprawnie `Tyub4` + flagi `Spoleczne.Obowiazkowe`/`Zdrowotne` **przed** zgłoszeniem.
- `Ubezpieczenia` jest **historyczne** — zmiana schematu „od daty" to nowy zapis `UmowaHistoria`
(`umowa.Historia.Update(date)` + `UmowaHistorie.AddRow`, jak KADRY-G2/KADRY-A14), nie nadpisywanie bieżącego.
- `Spoleczne.Od` jest **tylko do odczytu** (wyliczane) — datę objęcia społecznymi obowiązkowymi
ustawiasz zbiorczo przez `Ubezpieczenia.ObowiazkoweOd`; na `Zdrowotne` `ObowiazkoweOd` jest
zapisywalne wprost (asymetria — jak w KADRY-A7).
- `Tyub4` to rekord **konfiguracyjnego** słownika `TytulyUbezpiecz4`, klucz `WgKodu[int]` — pobierz
istniejący tytuł zleceniobiorcy, nie twórz „w locie".
- `ZarejestrujUmowyWorker` jest na `Umowa` (umowy), a `ZarejestrujPracownikówWorker` na `Pracownik`
(etatowi) — do zleceniobiorców używaj wersji „Umowy".
- Workery deklaracji uruchamiaj jak każdy worker enova (Context z tej samej sesji); po akcji wołasz
`Session.Save()`. Obsłuż `RowConflictException` z `Save()` (safe-code §4).
- `ZarejestrujRodzinę`/`WyrejestrujRodzinę` sterują dołączeniem ZCNA dla członków rodziny
(`pracownik.Rodzina`, KADRY-A9) — dla zleceniobiorcy zgłoszenie rodziny działa analogicznie do etatu.