# KADRY09 — Listy płac, przelewy, wydruki > Wspólne fakty o typie, podstawowe typy i szablon wzorca: [../kadry.md](../kadry.md). > **Model.** Lista płac to dokument operacyjny `Soneta.Place.ListaPlac` (root `GuidedRow`, > tabela `ListyPlac`, `session.GetPlace().ListyPlac`). Trzyma kolekcję wypłat > `ListaPlac.Wyplaty: SubTable`. Każda `Wyplata` (root `GuidedRow`, tabela `Wyplaty`) > wskazuje wstecz listę (`Wyplata.ListaPlac: IRow`) i pracownika (`Wyplata.Pracownik: IRow`). > Wzorzec listy to `DefinicjaListyPlac` (tabela konfiguracyjna `DefListPlac`, > `session.GetPlace().DefListPlac`, dostęp `WgSymbolu`/`WgNazwy`). > > **`Wyplata` jest abstrakcyjna** — konkretne typy: `WyplataEtat`, `WyplataUmowa`, `WyplataInne` > (ctor `(ListaPlac listaplac, Pracownik pracownik)` oraz wariant z `IPowiązanieWypłaty`). > W praktyce wypłat **nie tworzy się ręcznie** — robi to worker naliczania. ### KADRY-I1 — Naliczanie/generowanie list płac (★) **Cel:** utworzyć listę płac dla wybranego okresu i naliczyć na niej wypłaty pracowników (etat/umowy), tak by `ListaPlac.Wyplaty` zawierała policzone `Wyplata`. **Warianty:** | Wariant | Mechanizm | Uwaga | |---|---|---| | Ręczne utworzenie pustej listy | `new ListaPlac()` + `ListyPlac.AddRow(lp)` + pola | sterujesz wszystkim sam | | Naliczanie wypłat na istniejącej liście | worker `Soneta.Place.NaliczanieWypłat` (akcja `Nalicz`) | tworzy `Wyplata*` i liczy elementy | | Naliczanie planowanych list (zbiorczo) | worker `Soneta.Place.NaliczaniePlanowanychListPłacWorker` (akcja `Nalicz`) | wg `DefinicjaPlanowanejListyPłac` | **Pola i typy (`ListaPlac`, kolejność ustawiania jest istotna):** | Pole | Typ | Uwaga | |---|---|---| | `Definicja` | `Soneta.Place.DefinicjaListyPlac` | wzorzec listy; ustawić **pierwsze** po `AddRow` | | `Wydzial` | `Soneta.Kadry.Wydzial` | tylko gdy `Definicja.Wydzial == true` | | `Seria` | `string` | tylko gdy `Definicja.Seria == true` | | `Data` | `Soneta.Types.Date` | data naliczania listy | | `Naliczanie` | `Soneta.Place.TypNaliczenia` | wartości: `PłatnaZGóry`/`PłatnaZDołu`; **nie ustawiaj** — setter rzuca bez licencji „PL Złoty" | | `DataWyplaty` | `Soneta.Types.Date` | data postawienia środków; wyznacza mies./rok | | `MiesiacZUS` | `Soneta.Types.YearMonth` | miesiąc rozliczenia ZUS | | `Okres` | `Soneta.Types.FromTo` | okres listy; **po** `DataWyplaty` i `Naliczanie` | | `MiesWstecz` | `int` | | | `Wyplaty` | `SubTable` | wypełniana przez worker naliczania | | `Numer` | `Soneta.Core.NumerDokumentu` | nadawany automatycznie | | `Bufor` / `Zatwierdzona` | `bool` | stan dokumentu | **Worker `Soneta.Place.NaliczanieWypłat`** — `[Context]`: `Context`, `ListaPłac: ListaPlac`, `Pracownik: Soneta.Kadry.Pracownik`; akcja `NaliczanieWypłat Nalicz()`; właściwości wynikowe m.in. `Wypłaty: IList`, `Nienaliczeni: IEnumerable`, `DataWypłaty/DataListy/DataZUS: Date`, `Okres: FromTo`, `Naliczanie: TypNaliczenia`. **Worker `Soneta.Place.NaliczaniePlanowanychListPłacWorker`** — `[Context]`: `Pracownik: Pracownik[]`; `Params Pars` z polami `Definicja: DefinicjaPlanowanejListyPłac`, `DataWypłaty: Date`, `Okres: FromTo`, `Naliczanie: TypNaliczenia`, `TypWypłaty: TypWyplaty`, `MiesiącZUS/MiesiącDeklaracji: YearMonth`, `Seria: string`, `MiesWstecz: int`, `UwzgledniajNieZatwierdzoneListyPlac/EdycjaMiesiącaZUS: bool`; akcja `NaliczaniePlanowanychListPłac Nalicz()`. **Snippet (ręczne utworzenie listy + naliczenie wypłaty pracownika):** ```csharp using Soneta.Business; using Soneta.Place; using Soneta.Kadry; using Soneta.Types; var place = session.GetPlace(); // 1. Wzorzec listy płac (definicja konfiguracyjna). var def = place.DefListPlac.WgSymbolu["ETAT"] ?? throw new BusException("Brak definicji listy płac".Translate()); // 2. Pusta lista płac — KOLEJNOŚĆ: AddRow → Definicja → daty/naliczanie → Okres. var lp = new ListaPlac(); place.ListyPlac.AddRow(lp); lp.Definicja = def; // pierwsze po AddRow lp.Data = new Date(2026, 6, 30); lp.DataWyplaty = new Date(2026, 6, 30); // wyznacza miesiąc/rok lp.MiesiacZUS = new YearMonth(2026, 6); lp.Okres = new FromTo(new Date(2026, 6, 1), new Date(2026, 6, 30)); // po DataWyplaty // Uwaga: NIE ustawiaj lp.Naliczanie — setter rzuca bez licencji „PL Złoty"; getter ma sensowny domyślny. // 3. Naliczenie wypłaty pracownika — sprawdzona ścieżka to NaliczanieSeryjne (patrz sekcja H); // naliczona wypłata zostaje automatycznie powiązana z bieżącą listą płac. var pracownik = session.GetKadry().Pracownicy.WgKodu["006"]; var pars = new NaliczanieSeryjne.PracownikParams(context) // context: w UI z workera, w teście z TestBase { DataWypłaty = new Date(2026, 6, 30), DataListy = new Date(2026, 6, 30), TypWypłaty = TypWyplaty.Etat, }; var wynik = new NaliczanieSeryjne.Pracownika(pars) { Pracownik = pracownik }.Nalicz(); // 4. Powiązanie wypłaty z listą jest dwukierunkowe (Wyplata.ListaPlac / Wyplata.Pracownik): foreach (Wyplata w in wynik.WszystkieWypłaty) { // w.ListaPlac, w.Pracownik } session.Save(); ``` **Pułapki:** - **Kolejność pól krytyczna:** `Okres` i `MiesWstecz` ustaw **po** `DataWyplaty` i `Naliczanie` (wzajemne zależności wyliczeń) — patrz wzorzec w kodzie naliczania list. - `Wydzial`/`Seria` ustawiaj **warunkowo** wg `Definicja.Wydzial`/`Definicja.Seria` — inaczej ryzyko niespójności klucza `WgDefinicja`. - Wypłat **nie twórz przez `new WyplataEtat(...)` ręcznie** — naliczaj. Sprawdzoną ścieżką naliczania jest **`NaliczanieSeryjne.Pracownika(...).Nalicz()`** (sekcja H); sam worker `NaliczanieWypłat { ListaPłac, Pracownik }.Nalicz()` w bazie Demo potrafi zwrócić pustą listę. - `Wyplata.ListaPlac`/`Wyplata.Pracownik` to relacje **tylko do odczytu** — powiązania nie ustawisz setterem; powstają w trakcie naliczania. - `ListyPlac` to tabela operacyjna guided — przy odczycie filtruj zakresem (`WgDatyWyplaty`, `WgOkresu`, `WgDefinicja`), nie skanuj całości (safe-code §6.3). - `Wyplata.ListaPlac`/`Wyplata.Pracownik` to `IRow` (relacje interfejsowe) — porównuj/rzutuj świadomie. ### KADRY-I2 — Drukowanie/PDF kwitków (pasków) wypłaty (★) **Cel:** wygenerować pasek (kwitek) wypłaty pracownika do PDF. **Mechanizm.** Wydruk realizuje serwis **`IReportService`** (namespace `Soneta.Business.UI`, identycznie jak wydruki handlowe — patrz `handel.md` rozdz. 12). Wzorce pasków to szablony `*.repx` zarejestrowane atrybutem `[DxReport]` w assembly **`Soneta.KadryPlace.Reports`** dla `DataType = typeof(Soneta.Place.Wyplata)`: | Wzorzec (ReportName) | Plik szablonu (`TemplateFileName`) | `DataType` | |---|---|---| | „Pasek wypłaty" | `PasekWyplaty.repx` | `Soneta.Place.Wyplata` | | „Duży pasek wypłaty" | `DuzyPasekWyplaty.repx` | `Soneta.Place.Wyplata` | | „Paski wypłat" (zbiorczy) | `PaskiWyplaty.repx` | `Soneta.Place.ListaPlac` | **API (`IReportService` / `ReportResult` — `Soneta.Business.UI`):** `Stream GenerateReport(ReportResult rr)`, `ReportResult.TemplateFileName: string`, `.DataType: Type`, `.OutputFormat: ReportFormats` (`PDF`), `.Context: Context`, `.Target: ReportTargets`. **Snippet (pasek jednej wypłaty do strumienia PDF):** ```csharp using Soneta.Business.UI; // IReportService, ReportResult, ReportFormats using Soneta.Place; var raporty = session.GetRequiredService(); var context = new Context(session.Context); context.Set(wyplata); // pojedyncza Wyplata var rr = new ReportResult { TemplateFileName = "PasekWyplaty.repx", DataType = typeof(Wyplata), OutputFormat = ReportFormats.PDF, Context = context, }; using Stream pdf = raporty.GenerateReport(rr); // pierwsze 4 bajty == "%PDF" ``` **Pułapki:** - `IReportService` pobierasz z kontenera: `session.GetRequiredService()` (potrzebne `using Microsoft.Extensions.DependencyInjection;`). Serwis i silnik raportów (DevExpress) oraz szablony pasków z `Soneta.KadryPlace.Reports` są dostępne **transytywnie** — generowanie PDF działa bez dodatkowych referencji (wzorzec jak w `handel.md` rozdz. 12). - Poprawny PDF zaczyna się od bajtów `"%PDF"` — to wygodna asercja w teście. - Druk na fizyczną drukarkę (`Target = Printer`, `PrintReport`) wymaga sprzętu — NIE testować. ### KADRY-I3 — Drukowanie/PDF list płac (★) **Cel:** wygenerować wydruk całej listy płac (pełna lista, zestawienie wypłat) do PDF. **Mechanizm.** Identyczny jak KADRY-I2 — `IReportService.GenerateReport`, szablony `[DxReport]` w `Soneta.KadryPlace.Reports`, dla `DataType = typeof(Soneta.Place.ListaPlac)` / `typeof(Soneta.Place.ListyPlac)`: | Wzorzec (ReportName) | Plik szablonu | `DataType` | |---|---|---| | „Pełna lista płac" | `PelnaListaPlac.repx` | `Soneta.Place.ListaPlac` | | „Wspólna pełna lista płac" | `Wspolnapelnalistaplac.repx` | `Soneta.Place.ListyPlac` (zbiór) | | „Paski wypłat" | `PaskiWyplaty.repx` | `Soneta.Place.ListaPlac` | | Zestawienie wypłat | `ZestawienieWyplat.repx` | `Soneta.Place.ListaPlac` | **Snippet (pełna lista płac → PDF):** ```csharp using Soneta.Business.UI; using Soneta.Place; var raporty = session.GetRequiredService(); var context = new Context(session.Context); context.Set(listaPlac); // ListaPlac var rr = new ReportResult { TemplateFileName = "PelnaListaPlac.repx", DataType = typeof(ListaPlac), OutputFormat = ReportFormats.PDF, Context = context, }; using Stream pdf = raporty.GenerateReport(rr); ``` **Pułapki:** - Mechanizm i dostępność serwisu — jak w KADRY-I2 (działa transytywnie, bez dodatkowych referencji). - Lista musi być policzona (mieć `Wyplaty`) — inaczej wydruk będzie pusty. - **Niektóre szablony list wymagają pełnego kontekstu danych.** W bazie Demo wzorzec `PelnaListaPlac.repx` potrafi rzucić `InvalidOperationException` („Problem z przygotowaniem raportu") na sztucznie utworzonej liście — to ograniczenie konkretnego szablonu/kontekstu, nie brak referencji (pasek wypłaty `PasekWyplaty.repx` z KADRY-I2 generuje się poprawnie). - Do wydruku zbiorczego wielu list ustaw `DataType = typeof(Soneta.Place.ListyPlac)` i przekaż zbiór przez `Context.Set(...)` / `ReportResult.Rows`. ### KADRY-I4 — Generowanie przelewów wynagrodzeń (przygotowanie przelewów) (★) **Cel:** z naliczonej, zatwierdzonej listy płac wygenerować dokumenty przelewu wynagrodzeń (do paczki przelewów), tak by wypłaty pracowników trafiły do zapłaty/preliminarza i mogły zostać wyeksportowane do banku (KADRY-I5). > **Dwie różne klasy `Wyplata` — nie myl ich.** W domenie współistnieją: > - **`Soneta.Place.Wyplata`** (moduł `PlaceModule`, tabela `Wyplaty`) — *naliczona wypłata > pracownika* (wynik naliczania z sekcji H/KADRY-I1); to dokument **płacowy** ze składnikami > (`Elementy`), powiązany z listą płac (`Wyplata.ListaPlac`). > - **`Soneta.Kasa.Wyplata`** (moduł `KasaModule`, tabela `Wyplaty`/`Zaplaty`) — *zapłata kasowa* > (rozchód środków). To **ona** implementuje `IDokumentPlatny`/`IDokumentKsiegowalny`, ma pola > rozliczeniowe (`DoRozliczenia`, `Stan`, `StanRozliczenia`, `KwotaRozliczona`, `Rozliczono`, > `Rozrachunki`, `Zaplaty`, `PreliminarzPoz`, `PozycjePrzelewu`, `BlokadaPrzelewow`). > > Mechanizm „z wypłaty do przelewu” łączy oba światy: worker płacowy czyta `Place.Wyplata` z listy > płac i tworzy dokumenty przelewu w module Kasa (`Soneta.Kasa.PrzelewBase`, w paczce `PaczkaPrzelewow`). **Mechanizm (publiczny kontrakt — worker płacowy):** sprawdzoną ścieżką tworzenia przelewów z wynagrodzeń jest worker **`Soneta.Place.ListaPlac.PrzygotujPrzelewyWorker`** (assembly `Soneta.KadryPlace`, akcja menu *„Przygotuj przelewy”* na liście/listach płac). Kontekstem działania jest **lista płac** (`Soneta.Place.ListaPlac`) — przygotowuje przelewy dla zatwierdzonych wypłat tej listy. **Parametry — `PrzygotujPrzelewyWorker.Params`:** | Pole | Typ | Uwaga | |---|---|---| | `Data` | `Soneta.Types.Date` | data dokumentów przelewu | | `Paczka` | `Soneta.Kasa.PaczkaPrzelewow` | istniejąca paczka, do której trafią przelewy (opcjonalnie) | | `DefinicjaPaczki` | `Soneta.Kasa.DefinicjaPaczkiPrzelewu` | definicja, wg której utworzyć nową paczkę (gdy `Paczka == null`) | | `ZRachunku` | `Soneta.Kasa.RachunekBankowyFirmy` | rachunek firmy obciążany przelewami | | `Łączone` | `bool` | łączenie przelewów do jednego podmiotu w jeden dokument | | `ListyPłac` | `string` | opis/oznaczenie list płac (informacyjnie w tytule) | | `ModyfikacjaTytułów` | `bool` | czy nadpisać tytuły przelewu (`Tytułem1`/`Tytułem2`) | | `Tytułem1`, `Tytułem2` | `string` | tytuł przelewu (gdy `ModyfikacjaTytułów == true`) | | `ZEwidencjiZrodlowej` | `bool` | bierz dane rachunku z ewidencji źródłowej | **Akcja:** `object PrzygotujPrzelewy()` — tworzy w sesji dokumenty `Soneta.Kasa.PrzelewBase` (tabela `Przelewy`) w paczce `PaczkaPrzelewow`; utrwalenie w bazie wymaga `session.Save()`. **Model dokumentu przelewu (`Soneta.Kasa.PrzelewBase`, tabela `Przelewy`, root `GuidedRow`):** | Pole | Typ | Opis | |---|---|---| | `Kwota` | `Soneta.Types.Currency` | kwota przelewu | | `Podmiot` | `Soneta.Kasa.IPodmiotKasowy` | odbiorca (m.in. `Pracownik`, `ZUS`, `UrzadSkarbowy`, `Bank`, `Kontrahent`) | | `Rachunek` | `Soneta.Kasa.RachunekBankowyPodmiotu` | rachunek odbiorcy | | `RachunekZleceniodawcy` | `Soneta.Kasa.NumerRachunku` | rachunek firmy (obciążany) | | `Data` | `Soneta.Types.Date` | data przelewu | | `Definicja` | `Soneta.Core.DefinicjaDokumentu` | definicja dokumentu | | `Numer` | `Soneta.Core.NumerDokumentu` | numer (nadawany automatycznie) | | `Tytulem1`, `Tytulem2` | `string` | tytuł przelewu | | `Typ2` | `Soneta.Kasa.TypPrzelewu2` | wariant przelewu (zwykły / **MPP** / itp.) | | `PaczkaPrzelewow` | `Soneta.Kasa.PaczkaPrzelewow` | paczka, do której należy przelew | | `Bufor` / `Zatwierdzony` | `bool` | stan dokumentu | | `Exported` | `bool` | czy wyeksportowany (po KADRY-I5 — `true`, blokuje edycję) | **Przelewy okresowe / MPP:** - **MPP (mechanizm podzielonej płatności)** to *wariant* przelewu — wyrażany przez `PrzelewBase.Typ2: Soneta.Kasa.TypPrzelewu2` (oraz na `Kasa.Wyplata` polem `KwotaMPP`, `MozliweMechanizmyMPP`). Dla wynagrodzeń MPP zwykle nie dotyczy (to mechanizm faktur VAT), ale kontrakt go przewiduje. - **Przelewy okresowe** (cykliczne płatności np. składek z list) realizuje osobny worker księgowy `Soneta.Ksiega.Kasowe.NaliczaniePrzelewowOkresowych` (poza zakresem płac pracownika). **Powiązanie z wypłatą / preliminarzem (publiczne kolekcje na `Pracownik`):** | Kolekcja na `Pracownik` | Typ | Zawiera | |---|---|---| | `Pracownik.Przelewy` | `SubTable` | przelewy pracownika | | `Pracownik.DokumentyPreliminarza` | `SubTable` | dokumenty preliminarza | | `Pracownik.DokumentyRozliczeniowe` | `SubTable` | dokumenty rozliczeniowe | | `Pracownik.Rozrachunki` | `SubTable` | rozrachunki | | `Pracownik.Rachunki` | `SubTable` | rachunki bankowe pracownika | > **Korekta (zweryfikowane kompilacją + skanem DLL):** `Pracownik.Platnosci` **nie istnieje** w publicznym > kontrakcie kartoteki pracownika — kolekcja `Platnosci` występuje tylko na interfejsie > `Soneta.Kasa.IDokumentPlatny` (np. `Kasa.Wyplata.Platnosci`), nie na `Pracownik`. Płatności podmiotu > czytaj przez `Pracownik.Rozrachunki` / `Pracownik.DokumentyRozliczeniowe`. **Snippet (worker — w UI/teście z dostępnym `Context`):** ```csharp using Soneta.Business; using Soneta.Place; // ListaPlac, ListaPlac.PrzygotujPrzelewyWorker using Soneta.Kasa; // PaczkaPrzelewow, PrzelewBase, RachunekBankowyFirmy using Soneta.Types; // listaPlac: zatwierdzona lista płac z naliczonymi wypłatami (sekcja KADRY-I1) var pars = new ListaPlac.PrzygotujPrzelewyWorker.Params { Data = Date.Today, // Paczka = istniejacaPaczka, // albo nowa wg DefinicjaPaczki: // DefinicjaPaczki = session.GetKasa().DefPaczekPrzelewow.WgSymbolu["..."], // ZRachunku = rachunekFirmy, // RachunekBankowyFirmy Łączone = false, }; var worker = new ListaPlac.PrzygotujPrzelewyWorker { Pars = pars }; // kontekstem workera jest lista płac; uruchomienie akcji: worker.PrzygotujPrzelewy(); session.Save(); // utrwalenie dokumentów przelewu w bazie ``` **Pułapki / ograniczenia (bądź szczery):** - **`Place.Wyplata` ≠ `Kasa.Wyplata`** — pola rozliczeniowe (`DoRozliczenia`, `Stan`, `StanRozliczenia`, `Rozrachunki`, `BlokadaPrzelewow`) są na **kasowej** `Soneta.Kasa.Wyplata` (`IDokumentPlatny`), nie na płacowej. Skanując „Wyplata” trafia się na kasową. - **Lista płac musi być zatwierdzona i naliczona** — `PrzygotujPrzelewy` na pustej/niezatwierdzonej liście nie ma czego przelać. - **Wymaga konfiguracji modułu Kasa** — definicji paczki przelewów (`DefinicjaPaczkiPrzelewu`), rachunku firmy (`RachunekBankowyFirmy`) oraz rachunku pracownika (`Pracownik.Rachunki`). Brak rachunku odbiorcy → przelew nie powstanie albo będzie niekompletny. **W bazie Demo te elementy mogą nie być skonfigurowane**, dlatego generowanie przelewów w teście jednostkowym jest niepewne (patrz spec testowy). - Worker **sam zatwierdza zmiany w sesji** (otwiera transakcję) — nie owijaj w dodatkowy `session.Logout(true)`; do bazy idą w `Save()`. - `PrzelewBase.Podmiot`/`Powiazanie` to relacje **interfejsowe** (`IRow`/`IPodmiotKasowy`) — rzutuj świadomie. - `Przelewy` to tabela operacyjna guided — przy odczycie filtruj zakresem (safe-code §6.3). --- ### KADRY-I5 — Eksport wynagrodzeń do banku / pliku przelewów (★) > **UWAGA — operacja plikowa/integracyjna.** Eksport zapisuje **fizyczny plik** w formacie > bankowym (Elixir, MT940-pochodne, formaty walutowe). To wejście/wyjście do systemu zewnętrznego — > **nie jest to przedmiot testu jednostkowego** (zależy od ścieżki na dysku, formatu banku, > sterownika eksportu i — przy wysyłce online — od sieci). Dokumentujemy **model i publiczny > kontrakt**, a sam eksport pliku oznaczamy jako nietestowalny jednostkowo. **Cel:** wyeksportować przygotowane przelewy (KADRY-I4) do pliku przelewów dla systemu bankowości elektronicznej. **Mechanizm (publiczny kontrakt — worker Kasa):** worker **`Soneta.Kasa.EksportPrzelewowWorker`** (akcja menu *„Eksport przelewów”*, metoda `Eksport()`), sterowany przez `Soneta.Kasa.EksportPrzelewowParams`. > **Korekta (zweryfikowane kompilacją):** `EksportPrzelewowParams` **nie ma konstruktora > bezparametrowego** — wymaga `EksportPrzelewowParams(Context ctx, RachunekBankowyFirmy rachunek, PrzelewBase[] przelewy)`. > Co więcej, **sam konstruktor waliduje rachunek** i rzuca `System.ApplicationException` > („Eksport niemożliwy. Nie wskazano rachunku w filtrach listy.”), gdy `rachunek == null`. Dlatego nie da się > utworzyć parametrów samym inicjalizatorem obiektu. W teście jednostkowym kontrakt API weryfikuj **refleksją** > (istnienie typu, sygnatura konstruktora, property `FileName`/`Params`, metoda `Eksport`), bez instancjonowania. **Parametry — `Soneta.Kasa.EksportPrzelewowParams`:** | Pole | Typ | Uwaga | |---|---|---| | `FileName` | `string` | **ścieżka pliku wyjściowego** — operacja na dysku | | `AppendToFile` | `bool` | dopisanie do istniejącego pliku | | `PrzelewyZgodne` | `IList` | przelewy do wyeksportowania | | `Rachunek` | `Soneta.Kasa.RachunekBankowyFirmy` | rachunek firmy (zleceniodawca) | | `PrmDataPrzelewow` | `Soneta.Types.Date` | data realizacji | | `PrmNumerPaczki` | `string` | numer paczki | | `PrmZakres` | `Soneta.Kasa.ZakresEksportuPrzelewow` | zakres (wszystkie / wg paczki / zaznaczone) | | `EksportujWBuforze` | `bool` | uwzględnij przelewy w buforze | | `InfoBank`, `InfoFormatKraj`, `InfoFormatWalutowy`, `InfoRachunekBankowy` | `string` | parametry formatu/banku | | `WithoutHelper` | `bool` | tryb bez kreatora | **Akcja:** `object Eksport()` — zapisuje plik wg `FileName`. Po eksporcie przelewy są oznaczane jako wyeksportowane (`PrzelewBase.Exported == true`, blokada dalszej edycji). **Powiązane (kontekst):** - Eksport całych **paczek**: worker `Soneta.Kasa.EksportPaczekPrzelewowWorker`. - Eksport przelewów PPK z pulpitu KBR: `Soneta.EI.UI.PulpitKBR.Workers.PulpitKBEksportPrzelewowWorker`. **Snippet (kontrakt — w realnej integracji, nie w teście jednostkowym):** ```csharp using Soneta.Kasa; // EksportPrzelewowWorker, EksportPrzelewowParams, PrzelewBase using System.Collections.Generic; PrzelewBase[] przelewy = /* przelewy z KADRY-I4, np. z paczki */; // Konstruktor jest WYMAGANY (brak ctora bezparametrowego) i waliduje rachunek (rzuca, gdy null): var par = new EksportPrzelewowParams(context, rachunekFirmy, przelewy) // rachunekFirmy: RachunekBankowyFirmy { FileName = @"C:\przelewy\wynagrodzenia.txt", // ŚCIEŻKA PLIKU — operacja I/O PrmDataPrzelewow = Date.Today, EksportujWBuforze = false, }; var worker = new EksportPrzelewowWorker { Params = par }; worker.Eksport(); // zapis pliku na dysk — efekt uboczny poza sesją ``` **Pułapki / ograniczenia (bądź szczery):** - **Eksport pliku NIE nadaje się do testu jednostkowego** — pisze na dysk, zależy od formatu banku i sterownika eksportu; w teście co najwyżej dokumentujemy istnienie API (`EksportPrzelewowWorker`, `EksportPrzelewowParams.FileName`), bez wywołania `Eksport()`. - Format pliku zależy od **konfiguracji formatu eksportu** danego banku — nie ma jednego uniwersalnego formatu; `InfoFormat*`/`InfoBank` parametryzują wynik. - Wysyłka online (bankowość elektroniczna / API banku) to dodatkowo operacja **sieciowa** — poza zakresem testów jednostkowych. - Po eksporcie `PrzelewBase.Exported = true` blokuje edycję — ponowny eksport wymaga `EksportujWBuforze`/zmiany stanu. --- ### KADRY-I6 — Wystawienie faktury / faktury zbiorczej z zapłaty (rozliczenia) (★) > **Zakres i szczerość.** Faktura jest dokumentem **handlowym** (`Soneta.Handel.DokumentHandlowy`), > nie płacowym — to nie jest funkcja kartoteki pracownika ani list płac. Powiązanie „z zapłaty” > dotyczy **rozrachunków/rozliczeń** (moduł Kasa): zapłata (`Soneta.Kasa.Wyplata`/`Wplata` — > `IDokumentPlatny`) jest **rozliczana** z dokumentem płatnym (np. fakturą) przez rozrachunki. > Wystawianie faktury z poziomu pracownika/płac w publicznym kontrakcie **nie istnieje**; > tutaj dokumentujemy model rozliczeń, który łączy zapłatę z fakturą. **Cel:** powiązać zapłatę z dokumentem płatnym (fakturą) na poziomie rozrachunków/rozliczeń — oraz wskazać, gdzie w publicznym API leży rozliczanie należności/zobowiązań pracownika. **Model rozliczeń (publiczny kontrakt, moduł `KasaModule`):** | Element | Typ / kolekcja | Rola | |---|---|---| | Zapłata (rozchód/wpływ) | `Soneta.Kasa.Wyplata` / `Soneta.Kasa.Wplata` | dokument płatny (`IDokumentPlatny`) | | Płatność (zobowiązanie/należność) | `Soneta.Kasa.Platnosc` (tabela `Platnosci`, `IRozliczalny`) | to z nią rozlicza się zapłatę | | Rozliczenie (powiązanie SP) | `Soneta.Kasa.RozliczenieSP` (tabela `RozliczeniaSP`, `IRozliczenie`) | wiąże zapłatę z płatnością/dokumentem | | Rozrachunek | `Soneta.Kasa.RozrachunekIdx` (tabela `RozrachunkiIdx`) | indeks rozrachunkowy podmiotu | | Stan rozliczenia zapłaty | `Wyplata.StanRozliczenia: Soneta.Kasa.StanRozliczenia`, `Wyplata.DoRozliczenia`, `Wyplata.KwotaRozliczona`, `Wyplata.Rozliczono` | ile pozostało / czy rozliczono | **Kolekcje na zapłacie (`Soneta.Kasa.Wyplata`):** - `Wyplata.Zaplaty: SubTable` oraz `Wyplata.Dokumenty: SubTable` — rozliczenia, - `Wyplata.Rozrachunki: SubTable` — rozrachunki, - `Wyplata.PreliminarzPoz: PreliminarzPozycja` — pozycja preliminarza. **Kolekcje na `Pracownik` (rozrachunki/faktury podmiotu):** - `Pracownik.Rozrachunki`, `Pracownik.DokumentyRozliczeniowe`, `Pracownik.DokumentyPreliminarza` (jak w tabeli KADRY-I4). **Uwaga:** `Pracownik.Platnosci` **nie istnieje** — kolekcja `Platnosci` jest tylko na `IDokumentPlatny` (np. `Kasa.Wyplata.Platnosci`). **Workery rozliczeniowe (publiczny kontrakt, akcje menu):** | Worker | Rola | |---|---| | `Soneta.Kasa.RozliczWgPrzelewowWyplataWorker` | rozliczenie zapłaty wg przelewów | | `Soneta.Kasa.RozliczPreliminarzIdxWorker` / `...TblWorker` / `...FrmWorker` | rozliczenie z preliminarzem | | `Soneta.Kasa.PreliminarzPozycja.DodajRozliczenieWorker` | dodanie rozliczenia do pozycji preliminarza | | `Soneta.Ksiega.UtworzPlatnoscZZapisuWorker` | utworzenie płatności z zapisu (księga) | **Faktura zbiorcza:** powstaje po stronie **handlowej** — z wielu zapłat/płatności tworzy się jeden dokument handlowy (faktura) zbiorąc je jako rozliczenia. To domena `handel.md` (wystawianie i rozliczanie faktur), nie kartoteki pracownika. Z poziomu rozliczeń pracownika publiczny kontrakt udostępnia **odczyt i rozliczanie** rozrachunków, a nie „wystaw fakturę”. **Snippet (odczyt stanu rozliczenia zapłat — publiczny kontrakt):** ```csharp using Soneta.Kasa; // Wyplata, StanRozliczenia using Soneta.Types; // Zapłaty pracownika rozliczane z dokumentami (np. fakturami) — odczyt stanu rozliczeń. // Iteruj zawsze w zakresie/okresie (tabela operacyjna guided — safe-code §6.3). foreach (RozrachunekIdx r in pracownik.Rozrachunki) { // r — pozycja rozrachunkowa pracownika (powiązanie zapłata ↔ dokument) } // Stan rozliczenia konkretnej zapłaty kasowej: // Wyplata zaplata = ...; // var doRozl = zaplata.DoRozliczenia; // ile pozostało do rozliczenia (Currency) // var stan = zaplata.StanRozliczenia; // StanRozliczenia (enum) // var czyRozl = zaplata.Rozliczono; // bool ``` **Pułapki / ograniczenia (bądź szczery):** - **„Wystaw fakturę z pracownika/płac” nie istnieje w publicznym kontrakcie.** Faktura to dokument handlowy; powiązanie z zapłatą realizują **rozrachunki/rozliczenia** (moduł Kasa), nie kartoteka pracownika. To zadanie jest z pogranicza domen — opis kierujemy do `handel.md`. - Pola rozliczeniowe (`DoRozliczenia`, `Stan`, `StanRozliczenia`, `KwotaRozliczona`, `Rozliczono`, `Rozrachunki`) są na **`Soneta.Kasa.Wyplata`** (`IDokumentPlatny`), a nie na płacowej `Soneta.Place.Wyplata`. - Rozliczanie/tworzenie faktury zbiorczej **wymaga skonfigurowanego modułu Kasa/Handel** (definicje dokumentów, rachunki, płatności). W bazie Demo część konfiguracji może nie być gotowa — operacje zapisujące są niepewne w teście (patrz spec testowy). - `Platnosc`/`RozliczenieSP`/`RozrachunekIdx` to obiekty operacyjne — przy odczycie filtruj zakresem i nie skanuj całych tabel (safe-code §6.3). --- #### Spec testowy (zwarty) — KADRY-I4 / KADRY-I5 / KADRY-I6 Konwencja: `Soneta.Skills.Test/KadryPlace/Pracownik/`, klasa `RozdzialI_ListyWydrukiTest` (lub nowa `RozdzialI_PrzelewyRozliczeniaTest : PracownikTestBase`); baza Demo + rollback; operujemy wyłącznie na publicznym kontrakcie. **KADRY-I4 — `I4_PrzygotujPrzelewy_ZListyPlac`** - *Co testowalne:* naliczenie wypłaty etatowej (`NaliczanieSeryjne.Pracownika`, jak KADRY-I1b) → uzyskanie `ListaPlac` z `Wyplata.ListaPlac`; **konstrukcja** `ListaPlac.PrzygotujPrzelewyWorker` z `Params` (asercja, że worker i typ `Params` istnieją w publicznym API; że pola `Data`/`Paczka`/`ZRachunku` są dostępne). Odczyt kolekcji `Pracownik.Przelewy`, `Pracownik.DokumentyPreliminarza`, `Pracownik.Rozrachunki` (asercja: kolekcje dostępne, iterowalne). - *Niepewne / `[Ignore]`/`Assert.Ignore`:* faktyczne **wywołanie** `worker.PrzygotujPrzelewy()` i powstanie dokumentów `PrzelewBase` — zależy od konfiguracji modułu Kasa (definicja paczki, `RachunekBankowyFirmy`, rachunek pracownika `Pracownik.Rachunki`), której baza Demo nie gwarantuje. Owinąć w `try/catch` + `Assert.Ignore` z opisem (wzorzec jak KADRY-I2/KADRY-I3) i asercję na powstaniu przelewu robić tylko, gdy się udało. **KADRY-I5 — `I5_EksportPrzelewow_KontraktApi`** - *Co testowalne:* **istnienie publicznego API** — weryfikacja **refleksją** (NIE instancjonuj!): typ `EksportPrzelewowParams`, konstruktor `(Context, RachunekBankowyFirmy, PrzelewBase[])`, property `FileName`; typ `EksportPrzelewowWorker`, property `Params`, metoda `Eksport`. **Nie używaj inicjalizatora `new EksportPrzelewowParams { ... }`** — nie ma ctora bezparametrowego, a ctor `(ctx, rachunek, przelewy)` rzuca `ApplicationException`, gdy `rachunek == null` (brak konfiguracji w Demo). - *Niewykonalne w teście jednostkowym → `[Ignore]`:* wywołanie `worker.Eksport()` — **operacja plikowa** (zapis na dysk wg `FileName`), zależna od formatu banku/sterownika; wysyłka online = operacja sieciowa. **Nie wołać `Eksport()`** w teście; udokumentować jako `[Ignore("operacja plikowa/sieciowa — poza testem jednostkowym")]`. **KADRY-I6 — `I6_Rozliczenia_OdczytStanu`** - *Co testowalne:* odczyt kolekcji rozliczeniowych pracownika — `Pracownik.Rozrachunki`, `Pracownik.DokumentyRozliczeniowe`, `Pracownik.DokumentyPreliminarza` (asercja: dostępne, iterowalne, typy zgodne — `RozrachunekIdx`, `DokRozliczBase`, `PreliminarzDokument`). **`Pracownik.Platnosci` NIE istnieje** — pomiń (kolekcja `Platnosci` jest tylko na `IDokumentPlatny`); odczyt pól rozliczeniowych z `Soneta.Kasa.Wyplata` (`DoRozliczenia`, `Stan`, `StanRozliczenia`, `Rozliczono`) — gdy istnieje zapłata kasowa w Demo. - *Niewykonalne / `[Ignore]`:* **wystawienie faktury (zbiorczej) z zapłaty** — funkcja handlowa, brak w kontrakcie pracownika; rozliczanie zapisujące (`RozliczWgPrzelewowWyplataWorker`, `RozliczPreliminarz*Worker`) wymaga konfiguracji Kasa/Handel → `Assert.Ignore` przy braku danych. Dla wystawiania faktur kierować do testów domeny handlowej (`handel.md`). **Dokładne nazwy (do użycia w testach):** - Worker płacowy: `Soneta.Place.ListaPlac.PrzygotujPrzelewyWorker` (+ zagn. `.Params`; akcja `PrzygotujPrzelewy`). - Worker eksportu: `Soneta.Kasa.EksportPrzelewowWorker` + `Soneta.Kasa.EksportPrzelewowParams` (akcja `Eksport`); paczki: `Soneta.Kasa.EksportPaczekPrzelewowWorker`. - Dokumenty: `Soneta.Kasa.PrzelewBase` (tabela `Przelewy`), `Soneta.Kasa.PaczkaPrzelewow` (tabela `PaczkiPrzelewow`), `Soneta.Kasa.DefinicjaPaczkiPrzelewu`, `Soneta.Kasa.RachunekBankowyFirmy`. - Rozliczenia: `Soneta.Kasa.Platnosc`, `Soneta.Kasa.RozliczenieSP`, `Soneta.Kasa.RozrachunekIdx`, `Soneta.Kasa.PreliminarzDokument`, `Soneta.Kasa.PreliminarzPozycja`. - Zapłata kasowa (`IDokumentPlatny`): `Soneta.Kasa.Wyplata` (NIE `Soneta.Place.Wyplata`). - Kolekcje na `Pracownik`: `Przelewy`, `Rozrachunki`, `DokumentyPreliminarza`, `DokumentyRozliczeniowe`, `Rachunki` (**bez `Platnosci`** — ta kolekcja jest tylko na `IDokumentPlatny`).