# KADRY08 — Płace — naliczanie wypłat > Wspólne fakty o typie, podstawowe typy i szablon wzorca: [../kadry.md](../kadry.md). > **Model danych.** `Wyplata` (`Soneta.Place.Wyplata`) jest klasą **abstrakcyjną**, root `GuidedRow`, > tabela `Wyplaty`. Konkretne typy: `WyplataEtat` (etat), `WyplataUmowa` (umowy), `WyplataInne` > (pozostałe). Każda wypłata należy do jednej **listy płac** (`ListaPlac`, tabela `ListyPlac`) i do > jednego pracownika. Składniki wynagrodzenia to **elementy** (`WypElement`, tabela `WypElementy`, > root guided) w kolekcji `Wyplata.Elementy: SubTable`. > > **Naliczanie** realizuje publiczny worker `Soneta.Place.NaliczanieSeryjne` (klasa abstrakcyjna > `partial`) z zagnieżdżonymi klasami: > - parametry: `NaliczanieSeryjne.Params` (bazowa), `NaliczanieSeryjne.PracownikParams : Params` > (etat + pozostałe), `NaliczanieSeryjne.UmowaParams : Params` (umowy); > - wykonawcy: `NaliczanieSeryjne.Pracownika : NaliczanieSeryjne` (wypłaty pracownika), > `NaliczanieSeryjne.Umowy : NaliczanieSeryjne` (wypłaty z umów). > > Wynik to obiekt `Soneta.Place.NaliczanieWypłat` z kolekcją `WszystkieWypłaty: IList` (elementy są > typu `Wyplata`). **Naliczanie samo zatwierdza zmiany w sesji** (`Nalicz()` wewnętrznie otwiera i > commituje transakcję edycyjną na sesji pracownika) — utrwalenie w bazie wymaga osobnego > `session.Save()`. ### KADRY-H1 — Naliczanie wypłat etatowych (★) **Cel:** naliczyć wypłatę etatową (wynagrodzenie zasadnicze etatu + dodatki/potrącenia) dla jednego pracownika za wskazany okres rozliczeniowy. **Klasy, pola i typy:** | Element | Typ / sygnatura | Uwaga | |---|---|---| | Parametry | `new NaliczanieSeryjne.PracownikParams(Context)` | ctor przyjmuje `Context` (sesja operacyjna) | | Data wypłaty | `PracownikParams.DataWypłaty: Date` | ustawienie **automatycznie** wylicza `Okres` (z konfiguracji listy) i `MiesiącDeklaracji` | | Data listy | `PracownikParams.DataListy: Date` | data dokumentu listy płac | | Okres naliczania | `PracownikParams.Okres: FromTo` | zwykle wyliczony z `DataWypłaty`; można nadpisać | | Typ naliczenia | `PracownikParams.Naliczanie: TypNaliczenia` | `PłatnaZGóry`/`PłatnaZDołu`; **domyślnie `PłatnaZDołu`** — patrz Pułapki (licencja) | | Filtr typu wypłaty | `PracownikParams.TypWypłaty: TypWyplaty` | `Wszystkie`/`Etat`/`Umowa`/`Inne` — dla etatu `Etat` lub `Wszystkie` | | Wykonawca | `new NaliczanieSeryjne.Pracownika(PracownikParams)` | | | Pracownik | `NaliczanieSeryjne.Pracownika.Pracownik: Pracownik` | komu naliczamy (z tej samej sesji co `Context`) | | Uruchomienie | `NaliczanieSeryjne.Pracownika.Nalicz(): NaliczanieWypłat` | nalicza i zatwierdza w sesji | | Wynik | `NaliczanieWypłat.WszystkieWypłaty: IList` (elementy `Wyplata`) | naliczone wypłaty | | Błędy naliczania | `NaliczanieWypłat.Nienaliczeni: IEnumerable` | pracownicy, dla których się nie udało | `TypNaliczenia` (`Soneta.Place`): `PłatnaZGóry = 1`, `PłatnaZDołu = 2`. `TypWyplaty` (`Soneta.Place`): `Wszystkie = 0`, `Etat = 1`, `Umowa = 2`, `Inne = 3`. **Snippet:** ```csharp var place = session.GetPlace(); var pracownik = session.GetKadry().Pracownicy.WgKodu["006"]; // Parametry naliczania — Context z tej samej sesji co pracownik: var pars = new NaliczanieSeryjne.PracownikParams(context); pars.DataWypłaty = new Date(2024, 6, 28); // ustawia Okres i MiesiącDeklaracji automatycznie pars.DataListy = pars.DataWypłaty; // pars.Naliczanie pozostaje domyślnie PłatnaZDołu (nie ustawiamy — patrz Pułapki) pars.TypWypłaty = TypWyplaty.Etat; // tylko wypłaty etatowe var naliczanie = new NaliczanieSeryjne.Pracownika(pars) { Pracownik = pracownik }; NaliczanieWypłat wynik = naliczanie.Nalicz(); // nalicza + commit w sesji foreach (Wyplata w in wynik.WszystkieWypłaty) { // w.Pracownik, w.ListaPlac, w.Data, w.MiesiacDeklaracji, w.Wartosc (Currency, do wypłaty) } session.Save(); // utrwalenie w bazie (opcjonalne — bez tego zmiany żyją tylko w sesji) ``` **Pułapki:** - **`Context` musi pochodzić z tej samej sesji co pracownik.** `PracownikParams(Context)` wiąże się z `Context.Session`; pracownik pobrany z innej sesji spowoduje niespójność. - **Nie ustawiaj `Naliczanie` jawnie, jeśli nie masz pewności co do licencji.** Setter `Params.Naliczanie` rzuca wyjątek, gdy licencja nie jest „PL Złoty/Platynowy" — getter wtedy i tak zwraca `PłatnaZDołu`. Pozostawienie wartości domyślnej (`PłatnaZDołu`) jest bezpieczne. - `Nalicz()` **otwiera własną transakcję** na sesji pracownika i commituje ją — **nie owijaj** wywołania w dodatkowy `session.Logout(true)`. Po naliczeniu zmiany są w sesji; do bazy idą dopiero w `Save()`. - `WszystkieWypłaty` to `IList` nietypowana — iteruj jako `foreach (Wyplata w in ...)`. - Pracownik w archiwum (`Pracownik.ArchiwumInfo == InformacjeOArchiwum.WArchiwum`) jest pomijany — `WszystkieWypłaty` będzie puste, bez wyjątku. - Naliczanie to operacja na danych operacyjnych — sprawdź `wynik.Nienaliczeni` zamiast łapać ogólny wyjątek; przy `KontynacjaNaliczenia` (tryb seryjny) błędy lądują tam, a nie w `throw`. ### KADRY-H2 — Naliczanie wypłat z umów (★) **Cel:** naliczyć wypłatę z konkretnej umowy cywilnoprawnej (`Soneta.Kadry.Umowa`). **Klasy, pola i typy:** | Element | Typ / sygnatura | Uwaga | |---|---|---| | Parametry | `new NaliczanieSeryjne.UmowaParams(Context)` | jak `PracownikParams`, ale `Naliczanie` jest na sztywno `PłatnaZDołu` (setter rzuca `NotSupportedException`) | | Data wypłaty / listy / okres | `UmowaParams.DataWypłaty`, `.DataListy`, `.Okres` | jak w KADRY-H1 | | Wykonawca | `new NaliczanieSeryjne.Umowy(UmowaParams)` | w ctorze ustawia `TypWypłaty = Umowa` | | Umowa | `NaliczanieSeryjne.Umowy.Umowa: Umowa` | ustawienie umowy ustawia też `Pracownik` z `umowa.Pracownik` | | Uruchomienie | `NaliczanieSeryjne.Umowy.Nalicz(): NaliczanieWypłat` | | **Snippet:** ```csharp var pracownik = session.GetKadry().Pracownicy.WgKodu["006"]; Umowa umowa = pracownik.Umowy.Cast().First(); // przykładowa umowa pracownika var pars = new NaliczanieSeryjne.UmowaParams(context); pars.DataWypłaty = new Date(2024, 6, 28); pars.DataListy = pars.DataWypłaty; var naliczanie = new NaliczanieSeryjne.Umowy(pars) { Umowa = umowa }; NaliczanieWypłat wynik = naliczanie.Nalicz(); foreach (Wyplata w in wynik.WszystkieWypłaty) { // w.Typ == TypWyplaty.Umowa; w.Wartosc; w.Elementy } session.Save(); ``` **Pułapki:** - **Nie ustawiaj `UmowaParams.Naliczanie`** — setter rzuca `NotSupportedException` (umowy zawsze „płatne z dołu"). - Ustawienie `Umowy.Umowa` nadpisuje `Pracownik` na właściciela umowy — nie ustawiaj `Pracownik` ręcznie. - Pozostałe pułapki jak w KADRY-H1 (Context z tej samej sesji, własna transakcja w `Nalicz()`, `Save()`). ### KADRY-H3 — Naliczanie pozostałych wypłat (★) **Cel:** naliczyć wypłaty „pozostałe" — pojedynczy dodatek/potrącenie (np. premia, zasiłek jednorazowy) poza zasadniczym wynagrodzeniem etatu, bądź wypłaty typu `Inne`. **Mechanizm:** używamy tego samego wykonawcy co KADRY-H1 — `NaliczanieSeryjne.Pracownika` — sterując zakresem przez `PracownikParams`: - `PracownikParams.TypWypłaty = TypWyplaty.Inne` — naliczanie tylko składników typu „inne", - `PracownikParams.Dodatek: DefinicjaElementu` — **zawężenie do jednej definicji** dodatku/potrącenia (naliczany jest tylko wskazany składnik). **Pola i typy:** | Element | Typ / sygnatura | Uwaga | |---|---|---| | Filtr typu | `PracownikParams.TypWypłaty: TypWyplaty` | `Inne` — pozostałe; `Wszystkie` — łącznie z etatem | | Pojedynczy składnik | `PracownikParams.Dodatek: DefinicjaElementu` | definicja konkretnego dodatku/potrącenia; `null` = bez zawężenia | **Snippet:** ```csharp var place = session.GetPlace(); var pracownik = session.GetKadry().Pracownicy.WgKodu["006"]; // Definicja konkretnego dodatku/potrącenia (rekord konfiguracyjny): DefinicjaElementu defDodatku = place.DefElementow.WgKodu["PREMIA"]; // przykładowy kod var pars = new NaliczanieSeryjne.PracownikParams(context); pars.DataWypłaty = new Date(2024, 6, 28); pars.DataListy = pars.DataWypłaty; pars.TypWypłaty = TypWyplaty.Inne; // pozostałe wypłaty pars.Dodatek = defDodatku; // tylko ten składnik var naliczanie = new NaliczanieSeryjne.Pracownika(pars) { Pracownik = pracownik }; NaliczanieWypłat wynik = naliczanie.Nalicz(); foreach (Wyplata w in wynik.WszystkieWypłaty) { foreach (WypElement e in w.Elementy) { // e.Definicja, e.Nazwa, e.Wartosc (decimal), e.Okres } } session.Save(); ``` **Pułapki:** - `Dodatek` to rekord **konfiguracyjny** `DefinicjaElementu` — pobierz istniejącą definicję (np. przez klucz kodu w `place.DefElementow`), nie twórz „w locie". - `TypWyplaty.Inne` i `TypWyplaty.Etat` są rozłączne — by naliczyć etat + dodatki łącznie użyj `Wszystkie`. - Pozostałe pułapki jak w KADRY-H1. ### KADRY-H4 — Przeglądanie/odczyt wypłat za rok (★) **Cel:** odczytać naliczone wypłaty pracownika za dany rok i zagregować wartości (suma do wypłaty, brutto/netto/składki/podatek, sumy składników). **Dostęp do wypłat (publiczny kontrakt):** | Punkt wejścia | Typ | Uwaga | |---|---|---| | `pracownik.Wyplaty` | `SubTable` | wszystkie wypłaty pracownika (klucz `WgPracownik`) | | `session.GetPlace().Wyplaty.WgPracownik[pracownik]` | `SubTable` | równoważnie z modułu | | `session.GetPlace().Wyplaty.WgData[date]` | `SubTable` | wypłaty z datą `date` | | `listaPlac.Wyplaty` | `SubTable` | wypłaty danej listy płac | **Pola wypłaty (`Wyplata`) do odczytu:** | Pole | Typ | Opis | |---|---|---| | `Pracownik` | `Pracownik` | właściciel | | `ListaPlac` | `ListaPlac` | lista płac (`ListaPlac.Okres: FromTo`, `ListaPlac.DataWyplaty: Date`, `ListaPlac.Zatwierdzona: bool`) | | `Data` | `Date` | data wypłaty (klucz `WgData`) | | `MiesiacDeklaracji` | `YearMonth` | miesiąc rozliczenia PIT | | `MiesiacZUS` | `YearMonth` | miesiąc rozliczenia ZUS | | `Wartosc` | `Currency` | kwota **do wypłaty** (netto) w PLN | | `Numer` | `NumerDokumentu` | numer dokumentu (`Numer.NumerPelny`) | | `Typ` | `TypWyplaty` | etat / umowa / inne | | `Bufor` | `bool` | wypłata w buforze (niezatwierdzona) | | `Elementy` | `SubTable` | składniki wynagrodzenia | **Kwoty na poziomie wypłaty (`Soneta.Place.Wyplata`, typ `Soneta.Types.Currency`):** `Wartosc` (kwota **do wypłaty**, PLN), `WartoscCy` (w walucie listy), `DoWypłaty`, `Gotówka`, `Inne`. Aby otrzymać `decimal`, użyj **`.Value`** (`w.Wartosc.Value`) — `Currency` nie ma jawnego rzutowania na `decimal`. > **Uwaga:** `Wyplata`/`WyplataEtat` **nie udostępnia** publicznych agregatów typu `Brutto`, `Netto`, > `SkładkiZUS`, `Podatek` jako gotowych właściwości. Brutto/netto/składki/podatek **liczymy sumując > składniki** z kolekcji `Wyplata.Elementy` (`WypElement.Wartosc`, `WypElement.Netto`, `WypElement.Podatki.*`). **Składniki (`WypElement`) i ich struktura podatkowo-składkowa:** | Pole | Typ | Opis | |---|---|---| | `Definicja` | `DefinicjaElementu` | definicja składnika | | `Nazwa` | `string` | nazwa składnika | | `Wartosc` | `decimal` | wartość składnika | | `Okres` | `FromTo` | okres, za który naliczono | | `Podatki` | `Podatki` (subrow) | struktura podatków/składek | | `Podatki.PodstawaZUS` | `decimal` | podstawa ZUS | | `Podatki.Emerytalna` / `Rentowa` / `Chorobowa` / `Wypadkowa` / `Zdrowotna` | `SkladkaZUS` (subrow) | każda z polami `Podstawa`, `Prac`, `Firma: decimal` | | `Podatki.Koszty`, `Podatki.Ulga`, `Podatki.ZalFIS` | `decimal` | koszty, ulga, zaliczka PIT | **Snippet:** ```csharp var place = session.GetPlace(); var pracownik = session.GetKadry().Pracownicy.WgKodu["006"]; int rok = 2024; var od = new Date(rok, 1, 1); var doD = new Date(rok, 12, 31); // Filtr serwerowy po dacie wypłaty (zakres roku) — bez pełnego skanu: decimal sumaDoWypłaty = 0m; decimal sumaBrutto = 0m; foreach (Wyplata w in pracownik.Wyplaty[(Wyplata x) => x.Data >= od && x.Data <= doD]) { sumaDoWypłaty += w.Wartosc.Value; // kwota do wypłaty (Currency -> decimal przez .Value) // brutto/składki/podatek liczymy z elementów (nie ma gotowych agregatów na wypłacie): foreach (WypElement e in w.Elementy) { sumaBrutto += e.Wartosc; // WypElement.Wartosc to decimal decimal netto = e.Netto; decimal podstawaZUS = e.Podatki.PodstawaZUS; decimal zaliczkaPit = e.Podatki.ZalFIS; } } ``` **Pułapki:** - `Wyplaty` to tabela **operacyjna guided** — zawsze ograniczaj zakresem czasowym (rok), nie iteruj całości (`safe-code §6.3`). Filtruj serwerowo przez `SubTable[condition]` po `Data`, nie w pamięci. - `Wartosc` to `Currency` (kwota do wypłaty); konwersja na `decimal` przez `.Value`. Składnik `WypElement.Wartosc`/`WypElement.Netto` to już `decimal` — nie myl typów ani znaczeń. - **Nie ma** gotowych właściwości agregujących (`Brutto`/`Netto`/`SkładkiZUS`/`Podatek`) na `Wyplata` ani `WyplataEtat` — sumuj składniki z `Wyplata.Elementy` (i ich `Podatki.*`). - `SkladkaZUS` ma pola `Podstawa`, `Prac`, `Firma` (część pracownika i pracodawcy) oraz właściwość pomocniczą `Składka` (suma) — wybierz właściwą do potrzeb. - Filtruj po `Data` (data wypłaty) lub `MiesiacDeklaracji`/`MiesiacZUS` zależnie od potrzeby raportowej — to różne pojęcia roku (rok wypłaty vs rok deklaracji). ### KADRY-H5 — Odczyt elementów wypłaty (brutto/składki/podatek/netto) (★) **Cel:** odczytać składniki konkretnej **naliczonej** wypłaty (`Soneta.Place.Wyplata`) i wyliczyć agregaty: brutto, składki ZUS (część pracownika i firmy), zaliczka PIT, netto. **Model.** Składniki to `Wyplata.Elementy: SubTable` (`Soneta.Place.WypElement`, tabela operacyjna guided `WypElementy`). `Wyplata` **nie** ma gotowych agregatów `Brutto`/`Netto`/`SkładkiZUS`/ `Podatek` — liczymy je z elementów albo przez worker `Wyplata.PITInfoWorker` (patrz niżej). **Pola składnika `WypElement` (do odczytu):** | Pole | Typ | Opis | |---|---|---| | `Definicja` | `DefinicjaElementu` | definicja składnika (konfiguracja) | | `Nazwa` | `string` | nazwa składnika | | `Wartosc` | `decimal` | wartość brutto składnika (kwota elementu) | | `Netto` | `decimal` | wartość netto składnika | | `DoWypłaty` | `decimal` | kwota do wypłaty z tego składnika | | `Okres` | `FromTo` | okres, za który naliczono | | `MiesiacDeklaracji` | `YearMonth` | miesiąc rozliczenia PIT | | `MiesiacZUS` | `YearMonth` | miesiąc rozliczenia ZUS | | `Podatki` | `Podatki` (subrow) | struktura podatkowo-składkowa | **Subrow `WypElement.Podatki` (`Soneta.Place.Podatki`) — pola istotne:** | Pole | Typ | Opis | |---|---|---| | `PodstawaZUS` | `decimal` | podstawa wymiaru składek ZUS | | `Emerytalna` / `Rentowa` / `Chorobowa` / `Wypadkowa` / `Zdrowotna` | `SkladkaZUS` (subrow) | każda z polami `Podstawa`, `Prac`, `Firma: decimal` oraz wyliczanym `Składka` (suma) | | `Koszty` | `decimal` | koszty uzyskania przychodu | | `Ulga` | `decimal` | ulga podatkowa (kwota wolna) | | `ZalFIS` | `decimal` | zaliczka na podatek dochodowy (fiskus) | | `ZdrowotneDoOdliczenia` | `decimal` | składka zdrowotna do odliczenia | Subrow `SkladkaZUS` (`Soneta.Place.SkladkaZUS`): `Podstawa` (podstawa), `Prac` (część pracownika, `decimal`), `Firma` (część pracodawcy, `decimal`), wyliczane `Składka` (suma) i `JestMinus` (`bool`). **Worker-agregator `Wyplata.PITInfoWorker`** (klasa publiczna, `[Context] Wypłata`) — udostępnia gotowe sumy podatkowe dla wypłaty: | Właściwość | Typ | Opis | |---|---|---| | `DoOpodatkowania` | `Currency` | suma elementów opodatkowanych (brutto opodatkowane) | | `Nieopodatkowane` | `Currency` | suma elementów nieopodatkowanych | | `Razem` | `decimal` | opodatkowane + nieopodatkowane (przychód razem) | | `NettoRazem` | `decimal` | wynagrodzenie netto razem | | `NettoOpodat` | `Currency` | netto opodatkowane | | `SkładkiZUS` | `decimal` | suma składek ZUS pracownika | | `SkładkaZdrow` | `decimal` | składka zdrowotna | | `Koszty` | `decimal` | koszty uzyskania razem | | `Ulga` | `decimal` | ulga podatkowa | | `ZalFIS` | `decimal` | zaliczka PIT | | `Dochód_Bez26` / `Dochód_26` | `decimal` | dochód (z podziałem na ulgę „do 26 lat") | > `PITInfoWorker.Brutto` i `PITInfoWorker.Netto` są oznaczone `[Obsolete]` — używaj `DoOpodatkowania`, > `Nieopodatkowane`, `Razem`, `NettoRazem`. Worker przyjmuje też kolekcję `Elementy: IEnumerable` > (zamiast `Wypłata`) i `WykluczoneElementy: DefinicjaElementu[]`. **Snippet (agregacja ręczna z elementów):** ```csharp var pracownik = session.GetKadry().Pracownicy.WgKodu["006"]; decimal brutto = 0m, netto = 0m, zusPrac = 0m, zusFirma = 0m, zalPit = 0m; // jedna konkretna wypłata pracownika (np. ostatnia z czerwca): var od = new Date(2024, 6, 1); var doD = new Date(2024, 6, 30); Wyplata wyplata = pracownik.Wyplaty[(Wyplata x) => x.Data >= od && x.Data <= doD].Cast().First(); foreach (WypElement e in wyplata.Elementy) { brutto += e.Wartosc; // WypElement.Wartosc to decimal netto += e.Netto; zalPit += e.Podatki.ZalFIS; zusPrac += e.Podatki.Emerytalna.Prac + e.Podatki.Rentowa.Prac + e.Podatki.Chorobowa.Prac + e.Podatki.Zdrowotna.Prac; zusFirma += e.Podatki.Emerytalna.Firma + e.Podatki.Rentowa.Firma + e.Podatki.Wypadkowa.Firma; } decimal doWyplaty = wyplata.Wartosc.Value; // Currency -> decimal przez .Value ``` **Snippet (przez worker — gotowe agregaty):** ```csharp var pit = new Wyplata.PITInfoWorker { Wypłata = wyplata }; decimal brutto = pit.Razem; // przychód razem decimal nettoR = pit.NettoRazem; decimal zus = pit.SkładkiZUS; decimal zdrow = pit.SkładkaZdrow; decimal zaliczka = pit.ZalFIS; ``` **Pułapki:** - `WypElement.Wartosc`/`Netto`/`DoWypłaty` to `decimal`; `Wyplata.Wartosc` (do wypłaty) to `Currency` — konwersja przez `.Value` (§10.1). - `SkladkaZUS.Prac` to część pracownika, `SkladkaZUS.Firma` to część pracodawcy — wybierz właściwą zależnie od potrzeby (koszt pracownika vs koszt pracodawcy). - `Wyplaty`/`WypElementy` to tabele operacyjne guided — pobieraj zakresem czasowym (§6.3), nie iteruj całości. - Pomijaj elementy stornowane przy sumowaniu, jeśli liczysz stan bieżący — patrz `WypElement.RozliczenieStorna` (KADRY-H10); naliczona wypłata po korekcie zawiera zarówno element pierwotny (`Wystornowany`) jak i `Stornujący`. --- ### KADRY-H6 — Wypłata zaliczki / dołączenie zaliczki (★) **Cel:** naliczyć i wypłacić zaliczkę (wypłata środków „na poczet" przyszłego wynagrodzenia), tworząc dokument `Soneta.Place.Zaliczka` i element realizacji zaliczki na wypłacie. **Model.** Zaliczka to rekord operacyjny `Soneta.Place.Zaliczka` (root guided, tabela `Zaliczki`, `session.GetPlace().Zaliczki`), implementuje `IBazaZrodlaWyplaty` i `IPowiązanieWypłaty`. Element realizujący zaliczkę to `WypElementZaliczka.Realizacja : WypElementZaliczka : WypElement`, spłata to `WypElementZaliczka.Spłata`. Powiązanie elementu z zaliczką: `WypElement.BazaZrodla = Zaliczka`, `RodzajŹródłaWypłaty.Zaliczka`. **Ścieżka publiczna — worker `Soneta.Place.WypłaćZaliczkęWorker`** (na `Soneta.Kadry.Pracownicy`): | Element | Typ / sygnatura | Uwaga | |---|---|---| | Parametry | `WypłaćZaliczkęWorker.ZalParams : WypElement.Params` | ctor `(Context)`; `Rodzaj == RodzajŹródłaWypłaty.Zaliczka` | | Definicja | `ZalParams.Definicja: DefinicjaElementu` | definicja elementu zaliczki (z `WypElement.Params`); **musi mieć** `DefinicjaElementu.RodzajZrodla == RodzajŹródłaWypłaty.Zaliczka` — inaczej worker rzuca `WypElement.RodzajDefinicjiException` (np. „Korekta zaliczki podatku" ma `Dodatek`) | | Data | `ZalParams.Data: Date` | data wypłaty zaliczki (wymagana) | | Kwota | `ZalParams.Kwota: Currency` | kwota zaliczki (wymagana) | | Pracownicy | `WypłaćZaliczkęWorker.Pracownicy: Pracownik[]` | dla kogo | | Akcja | `[Action("Wypłać zaliczkę")] object WypłataZaliczki()` | tworzy `Zaliczka`, nalicza element realizacji | **Stan zaliczki (`Zaliczka`):** `Wartosc: Currency`, `Splacono: Currency`, `Pozostaje: Currency` (`= Wartosc - Splacono`), `Stan: StanZaliczki` (`NieSpłacona`/`CzęściowoSpłacona`/`CałkowicieSpłacona`), `Realizacje: SubTable` (elementy realizacji), `Spłaty: SubTable` (elementy spłaty). **Mechanizm naliczenia** (realizowany przez worker): dla każdego pracownika tworzony jest `new Zaliczka(pracownik)`, dodawany przez `Zaliczki.AddRow(zaliczka)`, a następnie niskopoziomowy obiekt `Soneta.Place.NaliczanieWypłat` z `NaliczŹródłoWypłaty = zaliczka` wykonuje `Nalicz()`. Dołączenie/spłata zaliczki w kolejnej wypłacie etatowej dzieje się automatycznie podczas zwykłego naliczania (KADRY-H1) — naliczanie wyszukuje niespłacone zaliczki pracownika i generuje element `WypElementZaliczka.Spłata`. **Snippet (uruchomienie workera zaliczki):** ```csharp var pracownik = session.GetKadry().Pracownicy.WgKodu["006"]; // definicję zaliczki rozpoznajemy po RodzajZrodla (nie po Kodzie/Nazwie — „Korekta zaliczki podatku" // to RodzajZrodla.Dodatek, którego worker NIE przyjmie): DefinicjaElementu defZaliczki = session.GetPlace().DefElementow.Cast() .First(d => d.RodzajZrodla == RodzajŹródłaWypłaty.Zaliczka); var pars = new WypłaćZaliczkęWorker.ZalParams(context) { Data = new Date(2024, 6, 15), Kwota = new Currency(1000m, Currency.SystemSymbol), }; pars.Definicja = defZaliczki; var worker = new WypłaćZaliczkęWorker { Params = pars, Pracownicy = new[] { pracownik } }; object wynik = worker.WypłataZaliczki(); // tworzy Zaliczka + nalicza; otwiera własną transakcję session.Save(); ``` **Pułapki:** - `ZalParams.Definicja` to **istniejąca** definicja elementu o `RodzajZrodla == RodzajŹródłaWypłaty.Zaliczka` — pobierz z `place.DefElementow` (filtruj po `RodzajZrodla`, nie po `Kod`/`Nazwa`), nie twórz w locie. - Baza Demo może nie zawierać definicji o `RodzajZrodla == Zaliczka` — wtedy worker jest niewykonalny (w teście: `Assert.Ignore`). - `Zaliczka.SetWartość(...)` jest `internal` — wartości nie ustawiaj ręcznie; przekaż `ZalParams.Kwota` do workera. - `Zaliczka` nie kasuje się bezpośrednio, gdy ma realizacje/spłaty (`OnDeleting` rzuca `RowException`). - Worker otwiera własną transakcję (`Session.Logout(true)` + `CommitUI`) — nie owijaj dodatkowo; utrwalenie w bazie przez `Save()`. --- ### KADRY-H7 — Korekta podatków i składek; „Przelicz składki ZUS i podatki" (★) **Cel:** ponownie przeliczyć (skorygować) składki ZUS i zaliczki PIT na już naliczonych elementach wypłat pracownika za dany miesiąc deklaracji — np. po zmianie progu, tytułu ubezpieczenia, korekcie danych kadrowych. **Worker `Soneta.Place.NaliczaniePodatkówMiesięcznie`** (na `Pracownik`/`PracHistoria`): | Element | Typ / sygnatura | Uwaga | |---|---|---| | Miesiąc | publiczny ctor `(YearMonth miesiącDeklaracji)` (atrybut `[Context(typeof(MiesiącDeklaracji),"Miesiąc")]`) | przy ręcznym wywołaniu przekaż `YearMonth` (np. `pars.Miesiąc`); property odczytu `MiesiącDeklaracji: YearMonth` (get) | | Klasa parametru | `Soneta.Place.MiesiącDeklaracji : ContextBase` | `MiesiącDeklaracji.Miesiąc: YearMonth` (domyślnie `YearMonth.Today`) | | Pracownik | `NaliczaniePodatkówMiesięcznie.Pracownik: Pracownik` | `[Context]` | | `NoTrace` | `bool` | wyłączenie śladu (logu) operacji | | Akcja | `[Action("Przelicz składki ZUS i podatki")] void PrzeliczPodatki()` | przelicza elementy z danego miesiąca | **Mechanizm:** worker iteruje elementy (`WypElementy.WgDaty`) wszystkich pracowników powiązanych (`Pracownik.PracownicyPowiązani`) w okresie `MiesiącDeklaracji.ToFromTo()`, dla niezablokowanych (`!element.Podatki.Korekta && element.Wyplata.Bufor`) wykonuje przeliczenie flag i naliczenie podatków (`NaliczaniePodatków.NaliczRozrzuć()`). Wszystko w transakcji `Session.Logout(true)` + `Commit()`. **Snippet:** ```csharp var pracownik = session.GetKadry().Pracownicy.WgKodu["006"]; var pars = new MiesiącDeklaracji(context) { Miesiąc = new YearMonth(2024, 6) }; var worker = new NaliczaniePodatkówMiesięcznie(pars.Miesiąc) { Pracownik = pracownik }; worker.PrzeliczPodatki(); // przelicza składki ZUS i zaliczki PIT za czerwiec 2024 session.Save(); ``` **Pułapki:** - Elementy z ręczną korektą podatków (`element.Podatki.Korekta == true`) oraz elementy z wypłat zatwierdzonych (`!Wyplata.Bufor`) są **pomijane** — przeliczane są tylko elementy z bufora. - `MiesiącDeklaracji.Miesiąc` to `YearMonth` — to miesiąc deklaracji, nie data wypłaty. - Worker przelicza także pracowników powiązanych (`PracownicyPowiązani`) — operacja może objąć więcej niż jedną kartotekę. --- ### KADRY-H8 — Rozliczenie pracownika; dochód / roczny dochód (★) **Cel:** odczytać dochód z naliczonej wypłaty oraz (dla właścicieli) pobrać roczny dochód do rozliczeń; opcjonalnie uruchomić rozliczenie pracownika. **A. Dochód z wypłaty — `Wyplata.PITInfoWorker`** (publiczny, jak w KADRY-H5). Dochód podatkowy: | Właściwość | Typ | Opis | |---|---|---| | `Dochód_Bez26` | `decimal` | dochód poza ulgą „do 26 lat" (`= przychód + przychód50 − koszty − koszty50`) | | `Dochód_26` | `decimal` | dochód objęty ulgą „do 26 lat" | | `DoOpodatkowania` | `Currency` | podstawa opodatkowania (brutto opodatkowane) | | `Podstawa` | `decimal` | podstawa naliczenia zaliczki | | `ZalFIS` | `decimal` | zaliczka PIT | Dochód roczny pracownika sumuje się iterując wypłaty roku (KADRY-H4/KADRY-H5) i sumując `Dochód_Bez26 + Dochód_26` (lub `DoOpodatkowania`) z `PITInfoWorker` każdej wypłaty. **B. „Pobierz roczny dochód" — worker `Soneta.Kadry.PobierzDochodRocznyWorker`** (na `Pracownik`/ `PracHistoria`) — **tylko dla właściciela** (`Pracownik is Wlasciciel`): | Element | Typ / sygnatura | Uwaga | |---|---|---| | Parametry | property `PobierzDochodRocznyWorker.Pars : PobierzDochodRocznyWorker.Params` | `Pars.Rok: int` (domyślnie rok ubiegły) | | Pracownik | `PobierzDochodRocznyWorker.Pracownik: Pracownik` | `[Context]` | | Akcja | `[Action("Pobierz roczny dochód")] void Pobierz()` | zapisuje `PrzychodRyczalt` (RoczDochSkala/RoczDochLiniowy/RoczDochRyczalt) za rok | Korzysta z serwisu `IDochódWłaściciela.KwotaDochoduStraty(pracownik, YearMonth, FormaOpodatkowania)`. **C. „Rozlicz pracownika" — worker `Soneta.Place.RozliczaniePracownikowWorker`** (na `Pracownik`) — **tylko dla folderu pracowników zewnętrznych** (`KadryIPlace/Kadry/PracownicyZewnetrzni`): | Element | Typ / sygnatura | Uwaga | |---|---|---| | Parametry | `RozliczeniePracownikowParams : RozliczanieUmowZewnetrznychParams` | `Okres: FromTo`, `Data: Date` | | Akcja | `[Action("Rozlicz pracownika")] RozliczanieUmowZewnetrznych Rozlicz()` | rozlicza umowy zewnętrzne pracownika | **Snippet (dochód roczny z wypłat):** ```csharp var pracownik = session.GetKadry().Pracownicy.WgKodu["006"]; var od = new Date(2024, 1, 1); var doD = new Date(2024, 12, 31); decimal dochodRoczny = 0m; foreach (Wyplata w in pracownik.Wyplaty[(Wyplata x) => x.Data >= od && x.Data <= doD]) { var pit = new Wyplata.PITInfoWorker { Wypłata = w }; dochodRoczny += pit.Dochód_Bez26 + pit.Dochód_26; } ``` **Pułapki:** - `PobierzDochodRocznyWorker` działa wyłącznie dla `Wlasciciel` i form opodatkowania ogólnych/ryczałtu — dla zwykłego pracownika nie ma zastosowania (zwraca bez efektu). - „Rozlicz pracownika" (`RozliczaniePracownikowWorker`) dotyczy **pracowników zewnętrznych** (umowy zewnętrzne), nie standardowego rozliczenia płacowego. - Wewnętrzny `Wyplata.RozliczenieManager` (rozliczanie płatności/należności) jest **niepubliczny** — rozliczenie płatności inicjuje setter `Wyplata.Bufor` (zejście z bufora), nie wywołuj go bezpośrednio. --- ### KADRY-H9 — Kalkulator wynagrodzeń (brutto↔netto, koszt pracodawcy) (★) **Cel:** wyliczyć netto z brutto (lub odwrotnie) oraz całkowity koszt pracodawcy. **Brak dedykowanej publicznej klasy „kalkulatora wynagrodzeń"** w publicznym kontrakcie (patrz sekcja „niewykonalne"). Wyliczenie realizujemy przez **naliczenie próbne** (KADRY-H1/KADRY-H3 — `NaliczanieSeryjne`) i odczyt agregatów workera `Wyplata.PITInfoWorker` oraz `Wyplata.KosztyUzyskaniaPrzychoduWorker`. **Koszt pracodawcy — `Wyplata.PITInfoWorker` + składki firmy z elementów:** - brutto: `pit.Razem` / `pit.DoOpodatkowania`, - netto: `pit.NettoRazem`, - składki pracownika: `pit.SkładkiZUS`, `pit.SkładkaZdrow`, - zaliczka PIT: `pit.ZalFIS`, - składki firmy (narzuty pracodawcy): suma `WypElement.Podatki.{Emerytalna,Rentowa,Wypadkowa}.Firma` (plus FP/FGŚP/FEP) — patrz `WyplataSkładkiWorker` niżej. **Agregator składek — `Soneta.Place.WyplataSkładkiWorker`** (publiczny, `[Context] Wypłata` lub `Elementy: IEnumerable`): udostępnia `Razem: ZestawienieSkładek` z m.in.: | Właściwość `ZestawienieSkładek` | Typ | Opis | |---|---|---| | `KosztyZUS` | `decimal` | składki ZUS pracownika (emer.+rent.+chor.+wyp., część `Prac`) | | `FirmaZUS` | `decimal` | składki ZUS pracodawcy (część `Firma`) | | `Narzuty` | `decimal` | narzuty pracodawcy (`FirmaZUS` + FP.Firma + FGSP.Firma + FEP.Firma) | | `ZUS` | `decimal` | `KosztyZUS + FirmaZUS` | | `Emerytalna`/`Rentowa`/… | `ISkładka` | pojedyncze składki (`Podstawa`/`Prac`/`Firma`/`Składka`) | Koszt pracodawcy ≈ brutto (`pit.DoOpodatkowania`/`Razem`) + `skladki.Razem.Narzuty`. **Snippet (kalkulacja przez naliczenie próbne):** ```csharp var pracownik = session.GetKadry().Pracownicy.WgKodu["006"]; var pars = new NaliczanieSeryjne.PracownikParams(context); pars.DataWypłaty = new Date(2024, 6, 28); pars.DataListy = pars.DataWypłaty; pars.TypWypłaty = TypWyplaty.Etat; var nal = new NaliczanieSeryjne.Pracownika(pars) { Pracownik = pracownik }; NaliczanieWypłat wynik = nal.Nalicz(); Wyplata w = (Wyplata)wynik.WszystkieWypłaty[0]; var pit = new Wyplata.PITInfoWorker { Wypłata = w }; var skl = new WyplataSkładkiWorker { Wypłata = w }; decimal brutto = pit.Razem; decimal netto = pit.NettoRazem; decimal kosztPracod = brutto + skl.Razem.Narzuty; // brutto + narzuty pracodawcy // (jeśli to tylko kalkulacja — nie wywołuj Save(), wynik istnieje w sesji) ``` **Pułapki:** - Brak osobnego „kalkulatora" — wynik zawsze powstaje przez naliczenie i workery agregujące. - Kalkulacja brutto↔netto zależy od pełnej konfiguracji pracownika (etat, ulgi, koszty, PPK) — nie ma bezstanowej funkcji „brutto→netto" w publicznym API. - Jeśli naliczenie ma być tylko próbne, nie wywołuj `Save()` (zmiany zostaną w sesji i znikną z `Dispose`), albo wykonaj na osobnej sesji „brudnopisowej". --- ### KADRY-H10 — Stornowanie elementów wypłaty; obsługa elementów stornowanych (★) **Cel:** zastornować (wycofać/skorygować) element już zatwierdzonej wypłaty i poprawnie odczytać stan storna. **Model.** Storno opisuje rekord `Soneta.Place.StornoElementu` (tabela `StornaElementow`). Element ma stan `WypElement.StanStorna: StanStornaElementu` oraz dostęp do storna `WypElement.Storno: StornoElementu`. Enum `Soneta.Place.StanStornaElementu`: `NieDotyczy=0`, `DoStornowania=1`, `Wystornowany=2`, `Stornujący=3`, `WycofaneStorno=10` (tylko wyliczany). Enum `Soneta.Place.RodzajStornaElementu`: `NieDotyczy=0`, `Anulowanie=1`, `Przeliczenie=2`. **Pola `WypElement` związane ze storno:** | Pole | Typ | Opis | |---|---|---| | `StanStorna` | `StanStornaElementu` | bieżący stan storna elementu | | `StanStornaEx` | `StanStornaElementu` | jw. + `WycofaneStorno` gdy `Wystornowany` historyczny | | `Storno` | `StornoElementu` | powiązany rekord storna (lub `null`) | | `RozliczenieStorna` | `bool` | `true` gdy `Wystornowany` lub `Stornujący` (element nie liczy się do bieżącego stanu) | | `Wystornowany` | `bool` | do elementu naliczono element stornujący | | `Stornowane` / `Stornujące` | `SubTable` | relacje storn | | `Korekta` | `bool` | element zmodyfikowany ręcznie przez operatora | | `UtwórzStorno()` | `WypElement` | (wirtualna) tworzy element stornujący danego typu | **Workery oznaczania (publiczne, na `WypElement` / `Wyplata`):** - `StornoElementu.ElementDoPrzeliczeniaWorker` (na `WypElement`): - `[Action("Oznacz element do przeliczenia")] ZaznaczElementDoPrzeliczenia()` — `RodzajStornaElementu.Przeliczenie`, - `[Action("Oznacz element do anulowania")] ZaznaczElementDoAnulowania()` — `RodzajStornaElementu.Anulowanie`, - `[Action("Wycofaj oznaczenie anulowania lub przeliczenia")] WycofajZaznaczenie()` — kasuje `Storno`. - `StornoElementu.WypłataDoPrzeliczeniaWorker` (na `Wyplata`): - `ZaznaczElementyDoPrzeliczenia()` / `WycofajZaznaczenie()` — dla wszystkich elementów wypłaty. - `StornoElementu.ListaPłacDoPrzeliczeniaWorker` (na `ListaPlac`, z `Params.Definicja` / `WszystkieElementy`). **Mechanizm.** Oznaczenie tworzy `StornoElementu` i ustawia element na `DoStornowania`. Właściwe wytworzenie elementu stornującego (`UtwórzStornujący()`, stan `Wystornowany` na pierwotnym + `Stornujący` na nowym) następuje przy ponownym naliczeniu wypłaty (KADRY-H1) lub przeliczeniu. Wymagane: wypłata zatwierdzona (`Wyplata.Zatwierdzona`) i element w stanie `NieDotyczy`. **Snippet (oznaczenie do anulowania + przeliczenie):** ```csharp Wyplata w = ...; // zatwierdzona wypłata pracownika 006 WypElement element = w.Elementy.Cast().First(e => e.Definicja.Kod == "PREMIA"); // oznacz element do anulowania: var worker = new StornoElementu.ElementDoPrzeliczeniaWorker { Element = element }; worker.ZaznaczElementDoAnulowania(); // otwiera własną transakcję // element.StanStorna == StanStornaElementu.DoStornowania, element.Storno.RodzajStorna == Anulowanie // ponowne naliczenie wypłaty (KADRY-H1) wygeneruje element stornujący: var pars = new NaliczanieSeryjne.PracownikParams(context) { DataWypłaty = w.Data, DataListy = w.Data }; new NaliczanieSeryjne.Pracownika(pars) { Pracownik = w.Pracownik }.Nalicz(); session.Save(); ``` **Odczyt elementów stornowanych:** ```csharp foreach (WypElement e in w.Elementy) { if (e.RozliczenieStorna) continue; // pomiń wystornowane i stornujące przy sumowaniu stanu bieżącego // ... e to element „żywy" } ``` **Pułapki:** - Oznaczać można tylko elementy wypłaty **zatwierdzonej** i w stanie `NieDotyczy` (`IsEnabled...` to egzekwuje); na buforze storno nie ma sensu. - Storno samo w sobie tylko **oznacza** (`DoStornowania`) — wystornowanie (`Wystornowany`/`Stornujący`) powstaje dopiero przy ponownym naliczeniu/przeliczeniu. - Przy sumowaniu kwot bieżących pomijaj `RozliczenieStorna == true`, inaczej policzysz element pierwotny i jego storno podwójnie. - Nie można przenieść do bufora wypłaty z elementami `DoStornowania`/`Wystornowany` (rzuca `RowException` — patrz KADRY-H11). --- ### KADRY-H11 — Anulowanie/usunięcie naliczonej wypłaty (bufor, ponowne naliczenie) (★) **Cel:** „cofnąć" naliczoną i zatwierdzoną wypłatę do edycji (bufor) lub usunąć, by naliczyć ponownie. **Model.** Wypłata ma flagi `Wyplata.Bufor: bool` (niezatwierdzona/edytowalna) oraz `Wyplata.Zatwierdzona: bool` (odwrotność `Bufor`). Zejście z bufora = zatwierdzenie; powrót do bufora = otwarcie do edycji. **Workery (publiczne, na `Wyplata`):** | Worker / akcja | Sygnatura | Efekt | |---|---|---| | `Wyplata.ZatwierdźWorker` | property `Lista: Wyplata`; `[Action("Zatwierdź wypłatę")] void Zatwierdź()` | `Zatwierdzona = true` (zejście z bufora) | | `Wyplata.OtwórzWorker` | property `Wypłata: Wyplata`; `[Action("Przenieś do bufora")] void Otwórz()` | `Zatwierdzona = false` (powrót do bufora) | Obie akcje działają w transakcji `Session.Logout(true)` + `Commit()`. **Uwaga na nazwy property:** worker zatwierdzania przypina wypłatę przez `ZatwierdźWorker.Lista`, a otwierania — przez `OtwórzWorker.Wypłata`. `IsEnabled...` wymaga `Wyplata.CanBufor` — ale `CanBufor` jest **`protected`** (niedostępny z dodatku); stan czytaj przez publiczne `Wyplata.Bufor` / `Wyplata.Zatwierdzona`. **Bezpośrednia flaga `Wyplata.Bufor`:** - setter `Bufor` rzuca `ColReadOnlyException`, gdy `!CanBufor`; - zejście z bufora (`Bufor=false`) wyzwala rozliczenie płatności (wewnętrzny `RozliczenieManager`); - `IsReadOnlyBufor()` true gdy brak praw / `!CanBufor` / wyłączone „ZatwierdzanieFlagą" / lista zatwierdzona. **Usunięcie / ponowne naliczenie.** Aby przeliczyć od nowa: przenieś wypłatę do bufora (`OtwórzWorker.Otwórz()`), a następnie wykonaj ponowne naliczenie (KADRY-H1 — `NaliczanieSeryjne`), które nadpisze elementy. Usunięcie samej wypłaty realizuje standardowe `Row.Delete()` w transakcji (gdy dozwolone — wypłata w buforze, bez powiązań blokujących). **Snippet (powrót do bufora + ponowne naliczenie):** ```csharp Wyplata w = ...; // zatwierdzona wypłata pracownika 006 // 1) przenieś do bufora: new Wyplata.OtwórzWorker { Wypłata = w }.Otwórz(); // Zatwierdzona = false // 2) ponowne naliczenie (KADRY-H1): var pars = new NaliczanieSeryjne.PracownikParams(context) { DataWypłaty = w.Data, DataListy = w.Data, TypWypłaty = TypWyplaty.Etat, }; new NaliczanieSeryjne.Pracownika(pars) { Pracownik = w.Pracownik }.Nalicz(); session.Save(); ``` **Snippet (usunięcie wypłaty z bufora):** ```csharp using (ITransaction t = session.Logout(true)) { w.Bufor = true; // upewnij się, że w buforze (lub OtwórzWorker) w.Delete(); t.Commit(); } session.Save(); ``` **Pułapki:** - `Otwórz()` rzuca `RowException`, gdy wypłata nie jest zatwierdzona; `Zatwierdź()` — gdy już zatwierdzona. Sprawdzaj `IsEnabled...` / stan przed wywołaniem. - `UpdateBufor()` rzuca `RowException`, gdy na wypłacie są elementy `DoStornowania`/`Wystornowany` — najpierw wycofaj oznaczenia storna (KADRY-H10) lub dokończ przeliczenie. - Zejście z bufora wykonuje rozliczenie płatności i kopiowanie kursu — nie traktuj go jak zwykłej zmiany pola. - Operacje płacowe to dane operacyjne — łap `RowException`/`RowConflictException` z `Save()` (§4, §9), nie ogólny `Exception`.