# KADRY03 — Dodatki, potrącenia, akordy > Wspólne fakty o typie, podstawowe typy i szablon wzorca: [../kadry.md](../kadry.md). ### KADRY-C1 — Dodatki / stałe elementy wynagrodzenia (★) **Cel:** przypisać pracownikowi stały element wynagrodzenia (dodatek — np. premia, dodatek funkcyjny), oparty o definicję elementu płacowego, z okresem obowiązywania i parametrami (podstawa/procent/czas). W UI: menu czynności *Dodatki i potrącenia → Dodaj nowy*. **Klasa i model:** `Soneta.Kadry.Dodatek` — `GuidedRow` root, tabela `Dodatki`, obiekt **historyczny** (kolekcja `Dodatek.Historia: HistorySubTable`, parametry „od–do" siedzą w zapisach `DodHistoria`). Dodatek jest childem pracownika i pojawia się w `pracownik.Dodatki: SubTable`. **Tworzenie:** `new Dodatek(pracownik)` + `session.GetKadry().Dodatki.AddRow(d)`. Dodanie do tabeli tworzy **pierwszy zapis** `DodHistoria` — dostępny od razu jako `d.Last`. Parametry ustawiamy na `d.Last`. **Pola i typy (`DodHistoria` — `d.Last`):** | Pole | Typ | Uwaga | |---|---|---| | `Element` | `Soneta.Place.DefinicjaElementu` | definicja elementu wynagrodzenia (wymagana); pobierz istniejącą z `session.GetPlace().DefElementow.WgNazwy[nazwa]` | | `Okres` | `Soneta.Types.FromTo` | okres obowiązywania dodatku | | `Podstawa` | `Soneta.Types.Currency` | kwota podstawy (gdy algorytm definicji jej wymaga) | | `Procent` | `Soneta.Types.Percent` | procent (gdy algorytm definicji go wymaga) | | `Czas` | `Soneta.Types.Time` | czas (gdy algorytm definicji go wymaga) | | `Ulamek` | `Soneta.Types.Fraction` | ułamek (zależnie od definicji) | | `Dni` | `int` | liczba dni (zależnie od definicji) | | `Aktualnosc` | `Soneta.Types.FromTo` | okres zapisu historycznego (zarządzany przez historię — nie ustawiaj ręcznie) | **Pola na rootcie `Dodatek`:** `Nazwa: string`, `Pracownik: Soneta.Kadry.Pracownik` (właściciel, ustawiany ctorem), `DataZakonczeniaWyplaty: Date`, `Last: DodHistoria`, `Historia: HistorySubTable`, `Dodatki` (tabela: `session.GetKadry().Dodatki`). **Pobranie definicji elementu:** słownik `session.GetPlace().DefElementow` (kolekcja konfiguracyjna). Indeksowanie po nazwie: `DefElementow.WgNazwy["Premia"]`. Definicje dodatków mają `RodzajZrodla == Soneta.Place.RodzajŹródłaWypłaty.Dodatek` — można nimi filtrować dostępne definicje. W bazie Demo istnieją gotowe definicje, m.in. `"Premia"`, `"Premia procentowa"`. **Pułapki:** - **`new Dodatek(pracownik)` + `Dodatki.AddRow(d)` to para** — sam konstruktor nie włącza dodatku do sesji ani nie tworzy zapisu historii. Pierwszy `DodHistoria` powstaje przy `AddRow`; dopiero potem istnieje `d.Last`. - `Podstawa`/`Procent`/`Czas` **mogą być tylko-do-odczytu** w zależności od algorytmu wskazanej `DefinicjaElementu` — element kwotowy udostępnia `Podstawa`, element procentowy `Procent` itd. Ustawiaj tylko te pola, których wymaga definicja (próba zapisu pola read-only rzuci wyjątek). - `Element` jest **wymagany** — bez wskazania definicji elementu dodatek nie ma sensu płacowego. Definicję pobierasz z istniejącego słownika (`DefElementow`), nie tworzysz „w locie" w tym scenariuszu. - Zmiana parametrów dodatku **od konkretnego dnia** to nowy zapis historii dodatku (`d.Historia.Update(date)` + `Dodatki.Module.DodHistorie.AddRow(nowy)`), analogicznie do KADRY-A14 — nie nadpisuj bieżącego zapisu, jeśli chcesz zachować poprzedni okres. - `DodHistoria.Aktualnosc` (okres zapisu) zarządza mechanizm historii — sam ustawiasz `Okres`, `Aktualnosc` zostaw historii. **Snippet:** ```csharp var kadry = session.GetKadry(); var pracownik = kadry.Pracownicy.WgKodu["006"]; // Definicja elementu wynagrodzenia ze słownika konfiguracyjnego (po nazwie): var definicjaPremii = session.GetPlace().DefElementow.WgNazwy["Premia"]; using (var t = session.Logout(editMode: true)) { // new Dodatek(pracownik) + AddRow — AddRow tworzy pierwszy zapis DodHistoria (d.Last): var dodatek = new Dodatek(pracownik); kadry.Dodatki.AddRow(dodatek); var h = dodatek.Last; // pierwszy zapis historii dodatku h.Element = definicjaPremii; // definicja elementu (wymagana) h.Okres = new FromTo(new Date(2026, 1, 1), Date.MaxValue); h.Podstawa = (Currency)500m; // gdy algorytm definicji wymaga podstawy t.Commit(); } session.Save(); // Odczyt dodatków pracownika i ich definicji elementu (kolekcja childów): foreach (Dodatek d in pracownik.Dodatki) { DefinicjaElementu element = d.Last.Element; FromTo okres = d.Last.Okres; } ``` ### KADRY-C2 — Potrącenia (stałe i jednorazowe) (★) **Cel:** przypisać pracownikowi potrącenie z wynagrodzenia (np. składka związkowa, spłata rozliczana ręcznie, potrącenie dobrowolne). W modelu płacowym **potrącenie nie ma osobnej klasy** — to **`Soneta.Kadry.Dodatek`** (jak KADRY-C1), tyle że oparty o **definicję elementu o charakterze potrącenia**. O „minusowym" charakterze decyduje wyłącznie wskazana `DefinicjaElementu` (jej algorytm), a nie typ obiektu po stronie pracownika. **Jak rozpoznać definicję potrącenia (`Soneta.Place.DefinicjaElementu`, słownik `DefElementow`):** | Pole definicji | Typ | Znaczenie dla potrącenia | |---|---|---| | `Algorytm.Potracenie` | `bool` | **kluczowy znacznik** — `true` dla elementu potrącającego (element pomniejsza wynagrodzenie) | | `Algorytm.LimitPotracenia` | `Soneta.Place.TypLimituPotrącenia` | rodzaj limitu (np. do kwoty wolnej) — gdy potrącenie limitowane | | `Algorytm.TylkoPelnePotracenie` | `bool` | potrącać tylko w pełnej kwocie (bez częściowego) | | `RodzajZrodla` | `Soneta.Place.RodzajŹródłaWypłaty` | dla potrącenia przez dodatek **musi być** `Dodatek` (= `6`); enum **nie ma** wartości „Potrącenie" (ma natomiast m.in. `ZajęcieKomornicze` = 23, `Świadczenie` = 12, `Pożyczka` = 18, `PożyczkaSpłata` = 19). Minus realizuje algorytm, ale `DodHistoria.Element` **odrzuca** definicje o `RodzajZrodla != Dodatek` (np. „Alimenty" jako `ZajęcieKomornicze`) — patrz pułapki | **Mechanizm — identyczny jak KADRY-C1 (Dodatek + DodHistoria):** - `new Dodatek(pracownik)` + `session.GetKadry().Dodatki.AddRow(d)` → powstaje pierwszy `DodHistoria` (`d.Last`). - Na `d.Last` ustawiamy `Element` (definicja potrącenia), `Okres` oraz `Podstawa`/`Procent`/`Kwota` zależnie od algorytmu definicji. - **Potrącenie stałe**: `Okres` otwarty (do `Date.MaxValue`) lub na czas określony — naliczane w każdej wypłacie z okresu. - **Potrącenie jednorazowe**: `Okres` zawężony do jednego miesiąca rozliczeniowego (tylko ten miesiąc obejmie naliczenie). - Zakończenie potrącenia: `d.DataZakonczeniaWyplaty` + ewentualnie `d.PrzyczynaZakonczenia`, albo nowy zapis historii „od daty" (`d.Historia.Update(date)`), analogicznie do KADRY-C1/KADRY-A14. **Pułapki:** - Nie szukaj klasy „Potrącenie" — jej **nie ma**. Potrącenie = `Dodatek` z definicją, w której `Algorytm.Potracenie == true`. Dobór definicji jest jedynym wyróżnikiem. - **Filtruj po DWÓCH warunkach** (zweryfikowane testem): `d.Algorytm.Potracenie && d.RodzajZrodla == RodzajŹródłaWypłaty.Dodatek`. Sam `Algorytm.Potracenie` **nie wystarcza** — przy ustawianiu `DodHistoria.Element` definicja o innym `RodzajZrodla` (np. „Alimenty" jako `ZajęcieKomornicze`) rzuca `System.Exception: "Zły rodzaj źródła wypłaty elementu …"`. Element zajęcia komorniczego ma `RodzajZrodla == ZajęcieKomornicze` i podpinasz go pod `ZajęcieKomornicze`, nie pod `Dodatek` (KADRY-C4). - `Podstawa`/`Procent`/`Czas` na `DodHistoria` bywają tylko-do-odczytu zależnie od algorytmu definicji (jak w KADRY-C1) — ustawiaj tylko te, których definicja wymaga. - `Element` wymagany; pobierany z istniejącego słownika `DefElementow`, nie tworzony „w locie". **Snippet:** ```csharp var kadry = session.GetKadry(); var pracownik = kadry.Pracownicy.WgKodu["006"]; // Definicja potrącenia ze słownika — DWA warunki: Potracenie ORAZ RodzajZrodla == Dodatek: var def = session.GetPlace().DefElementow.Cast() .First(d => d.RodzajZrodla == RodzajŹródłaWypłaty.Dodatek && d.Algorytm != null && d.Algorytm.Potracenie); using (var t = session.Logout(editMode: true)) { var potracenie = new Dodatek(pracownik); kadry.Dodatki.AddRow(potracenie); // tworzy pierwszy DodHistoria var h = potracenie.Last; h.Element = def; // definicja o Algorytm.Potracenie == true h.Okres = new FromTo(new Date(2026, 1, 1), Date.MaxValue); // stałe h.Podstawa = (Currency)50m; // gdy algorytm definicji wymaga kwoty t.Commit(); } session.Save(); ``` --- ### KADRY-C3 — Akordy (★) **Cel:** przypisać pracownikowi pracę akordową (rozliczaną wg ilości/strefy), z okresem i definicją akordu; zakończyć akord. W UI: menu czynności *Akordy → Dodaj nowy / Zakończ*. **Klasa i model:** `Soneta.Kadry.Akord` — `GuidedRow` root, tabela `Akordy`, obiekt **historyczny** (`Akord.Historia: HistorySubTable`; parametry „od–do" w zapisach `AkordHistoria`, dostęp do bieżącego przez `Akord.Last`). Akord jest childem pracownika: `pracownik.Akordy: SubTable`. **Pola root `Akord`:** | Pole | Typ | Uwaga | |---|---|---| | `Pracownik` | `Soneta.Kadry.Pracownik` | właściciel (relacja) | | `Definicja` | `Soneta.Kadry.DefinicjaAkordu` | definicja akordu (słownik `DefinicjeAkordow`) | | `Okres` | `Soneta.Types.FromTo` | okres obowiązywania akordu | | `Typ` | `Soneta.Kadry.TypAkordu` | typ akordu | | `Wydzial` | `Soneta.Kadry.Wydzial` | jednostka organizacyjna realizacji | | `Last` | `Soneta.Kadry.AkordHistoria` | bieżący zapis historii | | `Dni` | `DateSubTable` | dzienna realizacja akordu | **Pola `AkordHistoria` (`Akord.Last`):** `Okres: FromTo`, `Algorytm: Soneta.Kadry.AlgorytmAkordu` (subrow z `Algorytm.Element: DefinicjaElementu`, `Algorytm.Wspolczynnik`, `Algorytm.Progi`, `Algorytm.WgCzasu`/`Progresywny` itd.), `Jednostka: string`, `Aktualnosc: FromTo` (zarządzane przez historię), `Progi: SubTable`. **Tworzenie — brak publicznego konstruktora `Akord(pracownik)`.** Akord dodaje się **workerem** operacyjnym (kanonicznie), nie `new`. Konstruktor `Akord` jest niepubliczny (poza `RowCreator`). Worker jest „jak z UI" (`Params` dziedziczy z `ContextBase`, ctor wymaga `Context`) — uruchamiaj go w transakcji `CommitUI`. **Workery (zagnieżdżone w `Pracownik`):** ctor `(Session)`, parametry przez właściwości `Pars`/`Pracownicy`; `Params` ma ctor `(Context)`. | Worker | Metoda | Wzorzec użycia | |---|---|---| | `Soneta.Kadry.Pracownik.DodajAkordWorker` | `DodajAkord` | `new Params(ctx) { Definicja, OdDnia, DoDnia, DodajKolejny }`; `new DodajAkordWorker(session) { Pars = par, Pracownicy = tab }` | | `Soneta.Kadry.Pracownik.ZakończAkordWorker` | `ZakończAkord` | `new Params(ctx) { Definicja, DoDnia, ZakończWszystkie }`; `new ZakończAkordWorker(session) { Pars = par, Pracownicy = tab }` | **Pułapki:** - Akordu **nie twórz przez `new Akord(...)`** — kanoniczna ścieżka to `DodajAkordWorker` (analogicznie `ZakończAkordWorker` do zakończenia). Workery przyjmują **tablicę pracowników**, więc nadają się też do operacji grupowej. - `Definicja` (akordu) to rekord słownika `DefinicjeAkordow` — pobierz istniejący, nie twórz „w locie". Sam akord wiąże dopiero z `DefinicjaElementu` (płacowym) przez `Algorytm.Element` definicji akordu. - Akord jest historyczny — zmiana parametrów „od daty" to nowy zapis `AkordHistoria` (`Historia.Update(date)`), analogicznie do KADRY-C1/KADRY-A14. - Tabela `Akordy` to dane operacyjne — przy przeglądaniu poprzecznym filtruj zakresem (safe-code §6.3); w zakresie jednego pracownika korzystaj z `pracownik.Akordy`. **Snippet:** ```csharp var kadry = session.GetKadry(); var pracownik = kadry.Pracownicy.WgKodu["006"]; var defAkordu = kadry.DefinicjeAkordow.WgNazwa["Akord prosty"]; // klucz WgNazwa (l.poj.) var context = login.CreateEmptyContext().Clone(session); using (var t = session.Logout(editMode: true)) { var par = new Pracownik.DodajAkordWorker.Params(context) // Params: ctor (Context) { Definicja = defAkordu, OdDnia = new Date(2026, 1, 1), DoDnia = new Date(2026, 12, 31), }; // ctor (Session); parametry przez właściwości Pars/Pracownicy: new Pracownik.DodajAkordWorker(session) { Pars = par, Pracownicy = new[] { pracownik } }.DodajAkord(); t.CommitUI(); } session.Save(); // Odczyt akordów pracownika: foreach (Akord a in pracownik.Akordy) { DefinicjaAkordu def = a.Definicja; FromTo okres = a.Okres; DefinicjaElementu element = a.Last.Algorytm.Element; } ``` --- ### KADRY-C4 — Zajęcia wynagrodzenia (komornicze, alimentacyjne) (★) **Cel:** zarejestrować zajęcie wynagrodzenia (egzekucja komornicza lub alimentacyjna) z numerem sprawy, kwotą, priorytetem i wierzycielem (komornikiem/rachunkiem odbiorcy); anulować/przywrócić zajęcie. **Klasa i model:** `Soneta.Kadry.ZajęcieKomornicze` — `GuidedRow` root, tabela `ZajKomornicze`, obiekt **historyczny** (`Historia: HistorySubTable`; limity i kwoty „od–do" w zapisach historii, bieżący przez `Last`). Child pracownika: `pracownik.ZajęciaKomornicze: SubTable`. **Konstruktor publiczny:** `new ZajęcieKomornicze(pracownik)`. **Pola root `ZajęcieKomornicze`:** | Pole | Typ | Uwaga | |---|---|---| | `Pracownik` | `Soneta.Kadry.Pracownik` | właściciel | | `Rodzaj` | `Soneta.Kadry.RodzajeZajęciaWynagrodzenia` | enum: `Kwota = 0`, `KwotaMiesięczna = 1` (jednorazowa kwota vs miesięczna) | | `Element` | `Soneta.Place.DefinicjaElementu` | element płacowy zajęcia — **wymagany**; musi mieć `RodzajZrodla == ZajęcieKomornicze` (= 23) | | `NumerSprawy` | `string` | numer sprawy egzekucyjnej | | `Data` | `Soneta.Types.Date` | data zajęcia | | `DataSplaty` | `Soneta.Types.Date` | data spłaty/zakończenia | | `Rozliczenie.Odbiorca` | `Soneta.Kasa.IPodmiotKasowy` | **wierzyciel** — komornik/odbiorca (iface; może być `Kontrahent`, `Bank`, `Pracownik`, `UrzadSkarbowy`…) | | `Rozliczenie.RachunekOdbiorcy` | `Soneta.Kasa.RachunekBankowyPodmiotu` | rachunek wierzyciela do przelewu | | `Splacono` | `Soneta.Types.Currency` | kwota spłacona (kalkulowane/narastające) | | `Pozostało` | `Soneta.Types.Currency` | kwota pozostała (kalkulowane) | | `SplataZakonczona` | `bool` | spłata zakończona | | `Anulowane` | `bool` | zajęcie anulowane (patrz workery) | | `Korekty` | `SubTable` | korekty zajęcia | | `OpisPrzelewu` | `string` | tytuł przelewu | **Limity i kwoty — na zapisie `ZajęcieKomorniczeHistoria` (`Last`):** kwota do potrącenia, limity procentowe i kwotowe, zawieszenie spłaty, priorytet, ustawienia potrąceń z zasiłków/świadczeń (zmiana „od daty" = nowy zapis historii). **Workery (zagnieżdżone w `ZajęcieKomornicze`):** ctor **bezparametrowy**, parametr przez właściwość `Zajęcie`. | Worker | Metoda | Wzorzec użycia | |---|---|---| | `Soneta.Kadry.ZajęcieKomornicze.AnulujWorker` | `Anuluj` | `new ZajęcieKomornicze.AnulujWorker { Zajęcie = zaj }.Anuluj()` | | `Soneta.Kadry.ZajęcieKomornicze.PrzywrócWorker` | `Przywróć` | `new ZajęcieKomornicze.PrzywrócWorker { Zajęcie = zaj }.Przywróć()` | **Pułapki:** - **Pole `Priorytet` NIE istnieje** na `ZajęcieKomornicze` (sprostowanie). **Alimentacyjne vs niealimentacyjne** rozstrzyga konfiguracja: wskazana `DefinicjaElementu` (`RodzajZrodla == ZajęcieKomornicze`) i parametry zapisu historii (limity), nie osobny typ klasy — to **jedna klasa** `ZajęcieKomornicze`. - `Anulowane` jest **tylko-do-odczytu** (brak publicznego settera) — anuluj **workerem** `AnulujWorker`. - `Rozliczenie.Odbiorca` jest **interfejsem** `IPodmiotKasowy` — wskaż istniejący podmiot (zwykle `Kontrahent`-komornik); nie twórz odbiorcy „w locie" w tym scenariuszu. - Faktyczne **kwoty potrącenia (`Splacono`, `Pozostało`) wyliczają się przy naliczeniu wypłaty** — po samym dodaniu zajęcia są zerowe/wyjściowe. Pełne rozliczenie wymaga naliczonej wypłaty (patrz sekcja „niewykonalne publicznym API bez naliczenia"). - Anulowanie/przywracanie realizuj **workerami** (`AnulujWorker`/`PrzywrócWorker`), nie ręcznym ustawianiem `Anulowane` — workery dbają o storna i spójność rozliczenia. - Tabela operacyjna — przegląd poprzeczny z filtrem (safe-code §6.3). **Snippet:** ```csharp var kadry = session.GetKadry(); var pracownik = kadry.Pracownicy.WgKodu["006"]; // Element zajęcia — definicja o RodzajZrodla == ZajęcieKomornicze (nie zwykłe potrącenie-Dodatek): var elementZajecia = session.GetPlace().DefElementow.Cast() .First(d => d.RodzajZrodla == RodzajŹródłaWypłaty.ZajęcieKomornicze); var komornik = session.GetCRM().Kontrahenci.WgKodu["KOMORNIK1"]; // wierzyciel (IPodmiotKasowy) using (var t = session.Logout(editMode: true)) { var zajecie = new ZajęcieKomornicze(pracownik); // ctor publiczny kadry.ZajKomornicze.AddRow(zajecie); zajecie.Rodzaj = RodzajeZajęciaWynagrodzenia.KwotaMiesięczna; zajecie.Element = elementZajecia; // wymagany (RodzajZrodla == ZajęcieKomornicze) zajecie.NumerSprawy = "KM 123/2026"; zajecie.Data = new Date(2026, 1, 1); zajecie.Rozliczenie.Odbiorca = komornik; // wierzyciel zajecie.Rozliczenie.RachunekOdbiorcy = komornik.Rachunki.WgKodu["GŁÓWNY"]; t.Commit(); } session.Save(); // Anulowanie zajęcia (worker bezparametrowy + property Zajęcie, nie ręczna flaga): using (var t = session.Logout(editMode: true)) { var zaj = pracownik.ZajęciaKomornicze.First(); new ZajęcieKomornicze.AnulujWorker { Zajęcie = zaj }.Anuluj(); t.CommitUI(); } session.Save(); ``` --- ### KADRY-C5 — Operacje seryjne na dodatkach (moduł Przeszeregowania) (★) **Cel:** dodać / zmienić / zakończyć dodatek (oraz zmienić stawkę) dla **grupy pracowników** jedną operacją. Realizuje to moduł **`Soneta.Przeszeregowania.PrzeszeregowaniaModule`**. Dokumentem zbiorczym jest `Przeszeregowanie` (tabela `Przeszeregowania`, root) z pozycjami `ElementPrzeszeregowania` (tabela `ElementyPrzeszer`, child). Pracownik widzi swoje pozycje przez `pracownik.ElementyPrzeszeregowania`. **Workery operacyjne** — ctor **bezparametrowy**, parametry przez właściwości `Pars` (typu `Params`, ctor `(Context)`) i `Pracownicy: Pracownik[]`. Uruchamiaj w transakcji `CommitUI`. **Uwaga:** workery te w bezgłowym hoście testowym (bez operatora/kontekstu UI) rzucają `NullReferenceException` — wymagają realnego środowiska aplikacji. | Worker | Metoda | Params (publiczne pola) | Działanie | |---|---|---|---| | `Soneta.Przeszeregowania.NowyDodatekWorker` | `NowyDodatek` | `Definicja: DefinicjaElementu, Podstawa: Currency, Procent: Percent` | wypłata/nadanie nowego dodatku grupie | | `Soneta.Przeszeregowania.ZmianaDodatkuWorker` | `ZmianaDodatku` | `Definicja, Podstawa, ZmianaPodstawy: Currency, ProcentowaZmianaPodstawy: Percent, Procent, ZmianaProcentu: Percent, DataStawki: Date, PodstawaPrecyzja, PodstawaSposob` | zmiana parametrów istniejącego dodatku | | `Soneta.Przeszeregowania.ZakończDodatekWorker` | `ZakończDodatek` | `Definicja: DefinicjaElementu` | zakończenie wypłaty dodatku | | `Soneta.Przeszeregowania.DodajZmienDodatekWorker` | `DodajZmienDodatek` | `Params` (dodanie lub zmiana łącznie) | dodanie albo zmiana dodatku | | `Soneta.Przeszeregowania.DodajNagrodęWorker` | (nagroda) | — | seryjne nagrody | | `Soneta.Przeszeregowania.ZmianaStawkiWorker` | `ZmianaStawki` | — | seryjna zmiana stawki zaszeregowania | **Dokument `Przeszeregowanie` (alternatywa: zbuduj dokument i wykonaj).** Tworzenie: `new Przeszeregowanie()` + `session.GetPrzeszeregowania().Przeszeregowania.AddRow(doc)` (kolekcja **nie ma** `AddNew` — to standardowy `GuidedRow` root z publicznym ctorem bezparametrowym). | Pole | Typ | |---|---| | `Data` | `Soneta.Types.Date` (data przeszeregowania) | | `DataWykonania` | `Soneta.Types.Date` | | `Nazwa` | `string` | | `Realizacja` | `Soneta.Przeszeregowania.RealizacjaPrzeszeregowania` (stan) | | `Pracownicy` | `ICollection` | | `Elementy` | `SubTable` | | `ZarzadzaneWnioskiem` | `bool` | `ElementPrzeszeregowania` (child) niesie zmianę per pracownik: `Definicja: DefinicjaElementu`, `Kwota`/`ZmianaKwoty`/`ProcentowaZmianaKwoty`, `Procent`/`ZmianaProcentu`, `Grupa: GrupaZaszeregowania`, `Krotnosc`/`ZmianaKrotnosci`, `RodzajPrzeszergowania`, `Pracownik`, `PracHistoria`. **Wykonanie dokumentu:** `Soneta.Przeszeregowania.Przeszeregowanie.WykonajWorker` (metoda `Wykonaj`, `Params { Wykonaj: bool }`) — materializuje dokument na danych pracowników (tworzy/zmienia dodatki). `ElementPrzeszeregowania.Wykonaj(Log)` realizuje pojedynczą pozycję. **Pułapki:** - To **operacja seryjna na danych operacyjnych** — trzymaj transakcje krótkie, duże grupy dziel na paczki (safe-code §13.1). Workery przyjmują tablicę pracowników — przekaż przefiltrowaną listę (po stronie serwera, safe-code §6). - Workery `NowyDodatek`/`ZmianaDodatku`/`ZakończDodatek` operują na **definicji elementu** (`Definicja`), więc wybór właściwej `DefinicjaElementu` jest kluczowy (po nazwie / `RodzajZrodla == Dodatek`). - Sam dokument `Przeszeregowanie` **nie zmienia danych** dopóki nie zostanie wykonany (`WykonajWorker`); do tego momentu to plan. Po `Wykonaj` zmiany trafiają w dodatki/etat pracowników. - Indywidualne (jednostkowe) odpowiedniki to workery z KADRY-C2/KADRY-C1 na pojedynczym pracowniku (`Pracownik.DodajDodatekWorker`/`ZmieńDodatekWorker`/`ZabierzDodatekWorker`); moduł Przeszeregowania jest dla **grupy**. **Snippet (operacja seryjna — nowy dodatek dla grupy):** ```csharp var kadry = session.GetKadry(); var def = session.GetPlace().DefElementow.WgNazwy["Premia"]; // Grupa pracowników — filtr serwerowy (np. po wydziale), nie pełny skan: Pracownik[] grupa = kadry.Pracownicy[(Pracownik p) => p.Last.Etat.Okres.Contains(Date.Today)] .Cast().ToArray(); var context = login.CreateEmptyContext().Clone(session); using (var t = session.Logout(editMode: true)) { var par = new NowyDodatekWorker.Params(context) // Params: ctor (Context) { Definicja = def, Podstawa = (Currency)300m, }; // ctor bezparametrowy; parametry przez właściwości Pars/Pracownicy: new NowyDodatekWorker { Pars = par, Pracownicy = grupa }.NowyDodatek(); t.CommitUI(); } session.Save(); ``` --- ### KADRY-C6 — Świadczenia socjalne (ZFŚS) i ich rozliczenie (★) **Cel:** przyznać pracownikowi świadczenie socjalne z ZFŚS (zapomoga, dopłata do wypoczynku, paczka) i ustawić jego rozliczenie płacowe (element, kwota, okres). **Klasa i model:** `Soneta.Kadry.SwiadczSocjalne` — `GuidedRow` root, tabela `SwiadczeniaSoc`. Child pracownika: `pracownik.Swiadczenia: SubTable`. **Konstruktor publiczny:** `new SwiadczSocjalne(pracownik)`. **Pola `SwiadczSocjalne`:** | Pole | Typ | Uwaga | |---|---|---| | `Pracownik` | `Soneta.Kadry.Pracownik` | właściciel | | `Definicja` | `Soneta.Kadry.DefinicjaŚwiadczeniaSocjalnego` | rodzaj świadczenia (słownik `DefSwiadczSocjal`) | | `Data` | `Soneta.Types.Date` | data przyznania | | `Nazwa` | `string` | nazwa | | `Opis` | `Soneta.Business.MemoText` | opis | | `Rozliczenie` | `Soneta.Kadry.RozliczenieSwiadczenia` (subrow) | dane rozliczeniowe (poniżej) | **Subrow `Rozliczenie` (`RozliczenieSwiadczenia`):** | Pole | Typ | Uwaga | |---|---|---| | `Rozliczenie.Element` | `Soneta.Place.DefinicjaElementu` | element płacowy do rozliczenia świadczenia | | `Rozliczenie.Kwota` | `Soneta.Types.Currency` | kwota świadczenia | | `Rozliczenie.Okres` | `Soneta.Types.FromTo` | okres rozliczenia | | `Rozliczenie.Data` | `Soneta.Types.Date` | data rozliczenia | | `Rozliczenie.Rozliczone` | `bool` | czy rozliczone (po naliczeniu wypłaty) | **Definicja (`DefinicjaŚwiadczeniaSocjalnego`, słownik `DefSwiadczSocjal`):** `Nazwa: string`, `Element: DefinicjaElementu` (domyślny element rozliczenia), `Kwota: Currency` (domyślna kwota). Z niej dziedziczy świadczenie domyślny element i kwotę. **Worker seryjny:** `Soneta.Kadry.SwiadczSocjalne.DodajŚwiadczenieWorker` (metoda `DodajŚwiadczenie`) — ctor **bezparametrowy**, parametry przez właściwości `Pars` i `Pracownicy: Pracownik[]`; `Params` ma ctor `(Context)`: `Params { Definicja: DefinicjaŚwiadczeniaSocjalnego, DataPrzyznania: Date, Kwota: Currency, Element: DefinicjaElementu, DataRozliczenia: Date }` — nadaje świadczenie grupie (menu *Operacje seryjne / Dodaj świadczenia socjalne*). Wzorzec: `new DodajŚwiadczenieWorker { Pars = new …Params(ctx){…}, Pracownicy = tab }.DodajŚwiadczenie()`. **Pułapki:** - `Definicja` (świadczenia) pobierana ze słownika `DefSwiadczSocjal`; jej `Element`/`Kwota` są domyślne — na konkretnym świadczeniu nadpisujesz przez `Rozliczenie.Element`/`Rozliczenie.Kwota`. - **Faktyczne rozliczenie (wypłata świadczenia, `Rozliczenie.Rozliczone == true`) następuje przy naliczeniu wypłaty** — samo dodanie świadczenia tworzy tylko zlecenie rozliczenia. - Dla grupy używaj `DodajŚwiadczenieWorker`; pojedynczo — `new SwiadczSocjalne(pracownik)` + `AddRow`. **Snippet:** ```csharp var kadry = session.GetKadry(); var pracownik = kadry.Pracownicy.WgKodu["006"]; var defSwiadcz = kadry.DefSwiadczSocjal.WgNazwy["Dopłata do wypoczynku"]; var element = session.GetPlace().DefElementow.WgNazwy["Świadczenie socjalne"]; using (var t = session.Logout(editMode: true)) { var sw = new SwiadczSocjalne(pracownik); kadry.SwiadczeniaSoc.AddRow(sw); sw.Definicja = defSwiadcz; sw.Data = new Date(2026, 6, 1); sw.Rozliczenie.Element = element; // element płacowy rozliczenia sw.Rozliczenie.Kwota = (Currency)1000m; sw.Rozliczenie.Okres = FromTo.Month(new YearMonth(2026, 6)); t.Commit(); } session.Save(); // Odczyt świadczeń pracownika: foreach (SwiadczSocjalne s in pracownik.Swiadczenia) { Currency kwota = s.Rozliczenie.Kwota; bool rozliczone = s.Rozliczenie.Rozliczone; } ``` --- ### KADRY-C7 — Pożyczki (KZP / ZFM) (★) **Cel:** zarejestrować członkostwo pracownika w funduszu pożyczkowym, udzielić pożyczki, zbudować harmonogram rat i potrącać raty z wynagrodzenia. **Hierarchia obiektów (wszystkie `GuidedRow` root, childy pracownika):** - `Soneta.Kadry.FundPozyczkowy` (tabela `FundPozyczkowe`) — **członkostwo** w funduszu; `pracownik.FunduszePozyczkowe: SubTable`. Ctor: `new FundPozyczkowy(pracownik, definicja)`. - `Soneta.Kadry.Pozyczka` (tabela `Pozyczki`) — **pożyczka** udzielona w ramach funduszu; kolekcja `fundusz.Pozyczki: SubTable`. Ctor: `new Pozyczka(fundusz)`. - `Soneta.Kadry.RataPozyczki` (tabela `RatyPozyczek`) — **rata** harmonogramu; `pozyczka.Raty: SubTable`. Raty pracownik widzi przez `pracownik.SplacaneRaty` (oraz `ZyrowaneRaty` jako żyrant). Ctor: `new RataPozyczki(pozyczka)`. - `Soneta.Kadry.DefinicjaFunduszuPozyczkowego` (słownik `DefFundPozycz`, konfiguracyjny) — zasady funduszu (oprocentowanie, elementy płacowe wpisowego/składki/wycofania). **Pola `Pozyczka` (kluczowe):** | Pole | Typ | Uwaga | |---|---|---| | `Fundusz` | `Soneta.Kadry.FundPozyczkowy` | fundusz, w ramach którego udzielono | | `Data` | `Soneta.Types.Date` | data udzielenia | | `Kwota` | `Soneta.Types.Currency` | kwota pożyczki | | `Element` | `Soneta.Place.DefinicjaElementu` | element wypłaty pożyczki | | `ElementRaty` | `Soneta.Place.DefinicjaElementu` | element potrącenia raty | | `IloscRat` | `int` | liczba rat | | `KwotaRaty` | `Soneta.Types.Currency` | kwota raty | | `SplatyOd` | `Soneta.Types.YearMonth` | miesiąc rozpoczęcia spłat | | `Procent` | `Soneta.Types.Percent` | oprocentowanie | | `Sposob` | `Soneta.Kadry.SposóbSpłatyOdsetek` | sposób spłaty odsetek | | `AlgorytmRaty` | `Soneta.Kadry.AlgorytmRatyPożyczki` | algorytm wyliczania raty | | `Raty` | `SubTable` | harmonogram rat | | `Stan` | `Soneta.Kadry.StanSpłat` | enum: `NieSpłacona = 0`, `Częściowo = 1`, `Całkowicie = 2` | | `Splacona` | `bool` | spłacona w całości | **Pola `RataPozyczki`:** `Pozyczka`, `Data: Date`, `Miesiąc: YearMonth`, `Kapital: Currency`, `Odsetki: Currency`, `Element: DefinicjaElementu` (potrącenie raty), `Stan: StanSpłat`, `Pozostaje`/`PozostajeKapitał`/`PozostajeOdsetki` (kalkulowane), `Zyrant: Pracownik`, `Splacajacy: Pracownik`. **Generowanie harmonogramu (workery):** | Worker | Metoda | Params / sygnatura | |---|---|---| | `Soneta.Kadry.Pozyczka.UzgodnijRatyWorker` | `UzgodnijRaty` | ctor bezparam.; `Pars = new Params(ctx) { UzgodnijRaty = true }` (uwaga: `PrzeliczRaty` jest **tylko-do-odczytu**), `Pożyczka = pozyczka` — **buduje/przelicza harmonogram rat** wg `IloscRat`/`KwotaRaty`/`SplatyOd` | | `Soneta.Kadry.Pozyczka.PożyczkaWorker` | `Pożyczka` | podsumowanie spłat (props: `Razem`, `Spłaty`, `Pozostaje`, `RazemOdsetki`…) | | `Soneta.Kadry.Pozyczka.ElementWypłatyWorker` | `Pokaż` | podgląd elementu wypłaty pożyczki | Metody na samym `Pozyczka`: `pozyczka.UpdatePozyczka()` (przelicz), `pozyczka.Rata(YearMonth, DefinicjaElementu)`, `pozyczka.RatyZaMiesiąc(YearMonth)`, `pozyczka.SąRaty(YearMonth)`. **Pułapki:** - Ścieżka tworzenia jest **trzystopniowa**: `FundPozyczkowy(pracownik, definicja)` → `Pozyczka(fundusz)` → harmonogram. Pożyczki **nie da się** utworzyć bez funduszu (ctor wymaga `FundPozyczkowy`). - Harmonogram rat generuj **workerem** `UzgodnijRatyWorker` (albo `UpdatePozyczka()`), nie ręcznym dodawaniem `RataPozyczki` — worker rozkłada kapitał/odsetki wg algorytmu. - `Element` (wypłaty) i `ElementRaty` (potrącenia) to **różne** definicje elementów — `ElementRaty` realizuje potrącenie raty w wypłacie. - **Faktyczne potrącenie raty następuje przy naliczeniu wypłaty** — `Stan`/`Splacono`/`Pozostaje` aktualizują się po naliczeniu. Samo udzielenie pożyczki ich nie zmienia. - `DefinicjaFunduszuPozyczkowego` to słownik konfiguracyjny — pobierz istniejący wpis, nie twórz „w locie". **Snippet:** ```csharp var kadry = session.GetKadry(); var pracownik = kadry.Pracownicy.WgKodu["006"]; var defFunduszu = kadry.DefFundPozycz.WgNazwy["KZP"]; var elWyplata = session.GetPlace().DefElementow.WgNazwy["Pożyczka"]; var elRata = session.GetPlace().DefElementow.WgNazwy["Spłata pożyczki"]; using (var t = session.Logout(editMode: true)) { // 1) Członkostwo w funduszu var fundusz = new FundPozyczkowy(pracownik, defFunduszu); kadry.FundPozyczkowe.AddRow(fundusz); fundusz.Okres = new FromTo(new Date(2026, 1, 1), Date.MaxValue); // 2) Pożyczka w ramach funduszu var pozyczka = new Pozyczka(fundusz); kadry.Pozyczki.AddRow(pozyczka); pozyczka.Data = new Date(2026, 1, 10); pozyczka.Kwota = (Currency)12000m; pozyczka.Element = elWyplata; pozyczka.ElementRaty = elRata; pozyczka.IloscRat = 12; pozyczka.SplatyOd = new YearMonth(2026, 2); // 3) Harmonogram rat (worker bezparametrowy; Params: ctor (Context); PrzeliczRaty read-only) var context = login.CreateEmptyContext().Clone(session); var par = new Pozyczka.UzgodnijRatyWorker.Params(context) { UzgodnijRaty = true }; new Pozyczka.UzgodnijRatyWorker { Pars = par, Pożyczka = pozyczka }.UzgodnijRaty(); t.CommitUI(); } session.Save(); // Odczyt harmonogramu: foreach (FundPozyczkowy f in pracownik.FunduszePozyczkowe) foreach (Pozyczka p in f.Pozyczki) foreach (RataPozyczki r in p.Raty) { YearMonth m = r.Miesiąc; Currency kapital = r.Kapital, odsetki = r.Odsetki; StanSpłat stan = r.Stan; } ```