Files

47 KiB
Raw Permalink Blame History

KADRY04 — Nieobecności i czas pracy

Wspólne fakty o typie, podstawowe typy i szablon wzorca: ../kadry.md.

KADRY-D1 — Wprowadzanie nieobecności (★)

Cel: zarejestrować nieobecność pracownika (urlop wypoczynkowy, zwolnienie chorobowe, urlop bezpłatny, opieka itp.) za wskazany okres oraz odczytać nieobecności obowiązujące w danym przedziale dat.

Fakty o typie (zweryfikowane skanem DLL):

  • Soneta.Kalend.Nieobecnosc jest klasą abstrakcyjną — tabela Nieobecnosci (GuidedRow root, child Pracownik-a). new Nieobecnosc(...) się nie skompiluje.
  • Konkretny typ do tworzenia: Soneta.Kalend.NieobecnośćPracownika (dziedziczy z Nieobecnosc), z publicznym konstruktorem new NieobecnośćPracownika(Pracownik pracownik) — ctor od razu wiąże nieobecność z pracownikiem. (Drugi konkretny typ to KorektaNieobecności — patrz KADRY-D2.)
  • Kolekcja na pracowniku: pracownik.Nieobecnosci: FromToSubTable<Soneta.Kalend.Nieobecnosc> (uporządkowana po okresie „oddo").
  • Tabela z poziomu modułu: session.GetKalend().Nieobecnosci.

Pola i typy (Nieobecnosc / NieobecnośćPracownika):

Pole Typ Rodzaj Opis
Definicja Soneta.Kalend.DefinicjaNieobecnosci bazodanowe, zapisywalne rodzaj nieobecności (słownik konfiguracyjny); decyduje o typie (urlop / zasiłek / bezpłatny)
Okres Soneta.Types.FromTo bazodanowe, zapisywalne zakres dat nieobecności „oddo"
OdGodziny, DoGodziny Soneta.Types.Time godziny (nieobecności godzinowe)
Norma, NormaNie Soneta.Types.Time bazodanowe normy czasowe
IlośćDni / Dni int kalkulowane/zapisywalne liczba dni nieobecności
Pracownik Soneta.Kadry.Pracownik tylko do odczytu właściciel (ustawiany ctorem, nie da się zmienić setterem)
Zwolnienie Soneta.Kalend.ZwolnienieZUS (subrow) bazodanowe dane ZUS dla zwolnień chorobowych (KodChoroby, Numer ZLA, PonownieUstalPodstawe…)
Urlop, Macierzynski, Wychowawczy, Okolicznosciowy subrowy bazodanowe szczegóły poszczególnych typów urlopów
Korygowana bool tylko do odczytu czy nieobecność jest korektą (patrz KADRY-D2)

Dostęp do definicji nieobecności (DefNieobecnosci):

  • session.GetKalend().DefNieobecnosci.WgNazwy[string] — pobranie po nazwie, np. WgNazwy["Urlop wypoczynkowy"], WgNazwy["Zwolnienie chorobowe"], WgNazwy["Urlop bezpłatny (art 174 kp)"]. Nazwy muszą dokładnie odpowiadać słownikowi danej bazy (w Demo nie ma wpisu „Urlop bezpłatny" — jest „Urlop bezpłatny (art 174 kp)"); WgNazwy[...] dla nieistniejącej nazwy zwraca null.
  • session.GetKalend().DefNieobecnosci[string] (indeksator domyślny po nazwie) — równoważne.
  • DefinicjaNieobecnosci ma pola Nazwa: string, Kod: string, Typ: TypNieobecnosci.

Wyszukiwanie po dacie/okresie: pracownik.Nieobecnosci.GetIntersectedRows(FromTo) zwraca IList nieobecności przecinających podany przedział.

Snippet:

var kalend    = session.GetKalend();
var pracownik = session.GetKadry().Pracownicy.WgKodu["006"];
// Nieobecność BEZ limitu (np. urlop bezpłatny) można wprowadzić wprost. Dla nieobecności
// LIMITOWANYCH (urlop wypoczynkowy) najpierw musi istnieć naliczony limit — patrz pułapki i KADRY-D7.
var defNieob  = kalend.DefNieobecnosci.WgNazwy["Urlop bezpłatny (art 174 kp)"];

using (var t = session.Logout(editMode: true))
{
    // typ konkretny; ctor wiąże nieobecność z pracownikiem
    var nieobecnosc = session.AddRow(new NieobecnośćPracownika(pracownik));
    nieobecnosc.Definicja = defNieob;                                  // rodzaj nieobecności
    nieobecnosc.Okres     = new FromTo(new Date(2026, 7, 1), new Date(2026, 7, 5));
    t.Commit();
}
session.Save();

// Odczyt nieobecności przecinających lipiec 2026:
var lipiec = new FromTo(new Date(2026, 7, 1), new Date(2026, 7, 31));
foreach (Nieobecnosc n in pracownik.Nieobecnosci.GetIntersectedRows(lipiec))
{
    // n.Definicja.Nazwa, n.Okres, n.Dni
}

Pułapki:

  • Nie rób new Nieobecnosc(...) — typ jest abstrakcyjny. Używaj new NieobecnośćPracownika(pracownik).
  • Nieobecności limitowane wymagają istniejącego limitu. Ustawienie Okres dla nieobecności powiązanej z limitem (np. „Urlop wypoczynkowy") synchronicznie przelicza limit i rzuca Soneta.Kalend.DefinicjaLimitu.LimitNotFoundException, gdy pracownik nie ma naliczonego limitu na dany rok. Dlatego: albo najpierw nalicz limit (patrz KADRY-D7), albo użyj nieobecności bez limitu (np. „Urlop bezpłatny (art 174 kp)") — jak w snippetcie powyżej.
  • Definicja jest wymagana — bez niej nieobecność nie zostanie poprawnie naliczona/zapisana. Pobieraj istniejący wpis słownika przez DefNieobecnosci.WgNazwy[...], nie twórz „w locie".
  • Pracownik jest tylko do odczytu — relację ustawia konstruktor, nie da się jej później zmienić.
  • Tabela Nieobecnosci jest operacyjna guided — przy przeglądaniu poprzecznym (po wszystkich pracownikach) filtruj zakresem czasowym (safe-code §6.3). W zakresie jednego pracownika korzystaj z pracownik.Nieobecnosci i GetIntersectedRows.
  • Nakładające się nieobecności i niepoprawne okresy wychwytują weryfikatory przy Save() (RowException) — obsłuż wyjątek.
  • Pełna transakcja w session.Logout(editMode: true); brak Commit() = rollback przy Dispose().

KADRY-D2 — Korygowanie nieobecności już wypłaconych (★)

Cel: poprawić nieobecność, która została już rozliczona w wypłacie — zmienić jej okres lub typ (definicję) i/lub wymusić ponowne ustalenie podstawy naliczania zasiłku. enova rozróżnia dwie ścieżki: (a) modyfikacja istniejącej nieobecności + ponowne ustalenie podstawy, (b) korekta jako odrębny rekord typu KorektaNieobecności.

Fakty o typie (zweryfikowane skanem DLL):

  • Pola Definicja: DefinicjaNieobecnosci i Okres: FromTo na Nieobecnosczapisywalne publicznie — można je zmienić na istniejącym rekordzie.
  • Nieobecnosc.Korygowana: bool i Nieobecnosc.Pracowniktylko do odczytu.
  • Subrow Zwolnienie: Soneta.Kalend.ZwolnienieZUS posiada flagę PonownieUstalPodstawe: bool oraz publiczną metodę SetPonownieUstalPodstawe(bool) — to ona steruje przeliczeniem podstawy zasiłku przy kolejnym naliczeniu wypłaty.
  • Worker (czynność menu, DataType = Nieobecnosc): klasa Soneta.Kalend.Nieobecnosc.UstalPonowniePodstawęNaliczaniaWorker — czynność „Ustal ponownie podstawę naliczania". Worker:
    • ma publiczny bezparametrowy ctor;
    • przyjmuje kontekst przez settowalną property [Context] public Params Nieobecność;
    • klasa …Worker.Params : ContextBase ma publiczny ctor Params(Context context), który czyta nieobecność z context[typeof(Nieobecnosc)], oraz settowalną property UstalPodstawę: bool;
    • metoda public void PonownieUstalPodstawę() jest jego akcją;
    • static bool IsEnabledPonownieUstalPodstawę(Nieobecnosc) mówi, kiedy czynność jest aktywna (dotyczy zwolnień ZUS i urlopów macierzyńskich: Zwolnienie.IsZUS || Macierzynski.IsMacierzyński, przy braku BlokadaOkresu).
  • Drugi konkretny typ nieobecności: Soneta.Kalend.KorektaNieobecności (dziedziczy Nieobecnosc), z publicznym ctor new KorektaNieobecności(NieobecnośćPracownika nieobecność) — tworzy rekord korygujący wskazaną nieobecność. Ma zapisywalne Definicja, Okres, IlośćDni, RozliczenieWDniu, RozliczenieData, a kolekcje ElementyKorygowane/ElementyKorygowaneStorno są tylko do odczytu (wyliczane).

Wariant A — zmiana okresu/typu + ponowne ustalenie podstawy (modyfikacja istniejącego rekordu):

var pracownik = session.GetKadry().Pracownicy.WgKodu["006"];
var okresStary = new FromTo(new Date(2026, 3, 2), new Date(2026, 3, 10));

// odszukaj istniejącą (już rozliczoną) nieobecność po przecięciu z okresem
var nieobecnosc = (Nieobecnosc)pracownik.Nieobecnosci.GetIntersectedRows(okresStary)[0];

using (var t = session.Logout(editMode: true))
{
    nieobecnosc.Okres = new FromTo(new Date(2026, 3, 2), new Date(2026, 3, 12));  // wydłużenie okresu
    // dla zwolnień ZUS — wymuś ponowne ustalenie podstawy przy najbliższym naliczeniu wypłaty:
    nieobecnosc.Zwolnienie.SetPonownieUstalPodstawe(true);
    t.Commit();
}
session.Save();

Wariant B — czynność „Ustal ponownie podstawę naliczania" przez worker (kontekst):

var worker = new Nieobecnosc.UstalPonowniePodstawęNaliczaniaWorker();
var ctx    = Context.Empty.Clone(session);
ctx[typeof(Nieobecnosc)] = nieobecnosc;                     // worker czyta nieobecność z kontekstu
worker.Nieobecność = new Nieobecnosc.UstalPonowniePodstawęNaliczaniaWorker.Params(ctx)
{
    UstalPodstawę = true
};
worker.PonownieUstalPodstawę();                             // wykonuje własną transakcję + Commit
session.Save();

Wariant C — odrębny rekord korekty (KorektaNieobecności):

using (var t = session.Logout(editMode: true))
{
    var nPrac = (NieobecnośćPracownika)nieobecnosc;          // korekta dotyczy NieobecnośćPracownika
    var korekta = session.AddRow(new KorektaNieobecności(nPrac));
    korekta.Definicja = nPrac.Definicja;
    // Okres korekty MUSI być podzbiorem okresu korygowanej nieobecności (tu: 2..10):
    korekta.Okres     = new FromTo(new Date(2026, 3, 3), new Date(2026, 3, 8));
    t.Commit();
}
session.Save();
// Po zapisie korygowana nieobecność ma flagę Korygowana == true.

Pułapki:

  • Faktyczne przeliczenie wartości zasiłku NIE następuje w momencie ustawienia flagi/wywołania workera — flaga PonownieUstalPodstawe jest odczytywana dopiero przy ponownym naliczeniu wypłaty (mechanizm PodstawaZasilku). Sam test korekty rekordu nieobecności (Demo, rollback) zweryfikuje zmianę Okres/Definicja/flagi, ale nie zweryfikuje przeliczonych kwot wypłaty bez pełnego scenariusza naliczenia listy płac (patrz sekcja „funkcjonalności niewykonalne").
  • IsEnabledPonownieUstalPodstawę ogranicza czynność do zwolnień ZUS / macierzyńskich — dla zwykłego urlopu wypoczynkowego worker nie ma zastosowania; tam korektę robisz przez zmianę Okres/Definicja albo rekord KorektaNieobecności.
  • Okres korekty (KorektaNieobecności.Okres) musi być podzbiorem okresu korygowanej nieobecności — wyjście poza ten zakres rzuca Nieobecnosc.KorygowanyOkresException.
  • Dla nieobecności bez skutków płacowych (np. urlop bezpłatny) KorektaNieobecności nie pojawia się jako osobny wiersz w pracownik.Nieobecnosci — obserwowalnym efektem jest flaga Korygowana == true na nieobecności pierwotnej.
  • Korekta zmienia dane operacyjne powiązane z wypłatą — trzymaj transakcję krótką i obsłuż RowConflictException / RowException z Save() (safe-code §4, §13.1).
  • Worker wykonuje własną transakcję (Session.Logout(true) + Commit) — nie zagnieżdżaj go w innej otwartej transakcji edycyjnej.

KADRY-D7 — Analiza limitów urlopowych (★)

Cel: odczytać limit nieobecności (np. urlop wypoczynkowy) pracownika za dany rok — ile przysługuje, ile wykorzystano, ile pozostało. Limity nie są tworzone ręcznie — powstają przez naliczanie.

Fakty o typie (zweryfikowane skanem DLL):

  • Soneta.Kalend.LimitNieobecnosci — tabela LimNieobecnosci, GuidedRow child pracownika (relacja przez pole Pracownik). Instancje powstają wyłącznie przez naliczanie — nie twórz ich konstruktorem.
  • Kolekcja na pracowniku: pracownik.Limity: SubTable<Soneta.Kalend.LimitNieobecnosci> (nazwa kolekcji to Limity, nie „LimityNieobecnosci").
  • Tabela z poziomu modułu: session.GetKalend().LimNieobecnosci.

Pola i typy (LimitNieobecnosci) — odczyt:

Pole Typ Rodzaj Opis
Definicja Soneta.Kalend.DefinicjaLimitu bazodanowe rodzaj limitu (urlop wypoczynkowy itd.)
Okres Soneta.Types.FromTo bazodanowe okres limitu (zwykle rok)
OkresWażności Soneta.Types.FromTo kalkulowane okres ważności limitu
Limit int bazodanowe limit (dni) wynikający z kodeksu pracy
LimitDni int kalkulowane limit w dniach
LimitGodz Soneta.Types.Time bazodanowe limit w godzinach
Razem / RazemGodz int / Time kalkulowane łączny przysługujący (limit + przeniesienia + zmiany)
Wykorzystane / WykorzystaneGodz int / Time bazodanowe wykorzystane dni/godziny
Pozostalo int kalkulowane pozostało (dni, int)
PozostaloDni double kalkulowane pozostało dni (z częścią ułamkową)
PozostaloGodz Soneta.Types.Time kalkulowane pozostało godzin
ZaleglyDni / ZaleglyGodz double / Time kalkulowane zaległy z poprzednich okresów
Przeniesienie / PrzeniesienieDni int / double kalkulowane przeniesione z poprzedniego roku
Korekta, Zmiana int bazodanowe korekty/zmiany limitu
Pracownik Soneta.Kadry.Pracownik bazodanowe (guided-parent), read-only właściciel

Wykorzystany = Razem - Pozostalo (lub bezpośrednio pole Wykorzystane). „Przysługujący" to Razem (limit kodeksowy + przeniesienia + zmiany), a nie samo Limit.

Dostęp do definicji limitów (DefinicjeLimitow):

  • session.GetKalend().DefinicjeLimitow.WgNazwy[string] — np. WgNazwy["Urlop wypoczynkowy"].
  • Skróty typowane (property zwracające DefinicjaLimitu): DefinicjeLimitow.UrlopWypoczynkowy, .UrlopDodatkowy, .OpiekaNadZdrowym, .UrlopOpiekunczy, .ZwolnienieOdPracySilaWyzsza itd.
  • DefinicjaLimitu ma pola Nazwa: string, Typ: TypLimitu.

Naliczanie limitu (by mógł istnieć do odczytu) — Soneta.Kalend.NaliczanieLimitow:

  • Klasa z publicznym bezparametrowym ctor; settowalne property:
    • Pars: NaliczanieLimitow.Params (set),
    • Pracownicy: ICollection<Pracownik> (set) albo PracownicyIdx: Pracownik[] (set).
  • Klasa NaliczanieLimitow.Params : ContextBase ma publiczny ctor Params(Context context) oraz settowalne: Definicja: DefinicjaLimitu, Okres: FromTo, KopiujKorekty: bool, ZapisPerPracownik: bool.
  • Metoda public void DodajLimit() — nalicza limit (zapisuje rekordy LimitNieobecnosci). (Jest też DodajLimitUrlopowy().)

Snippet — naliczenie + odczyt:

var kalend    = session.GetKalend();
var pracownik = session.GetKadry().Pracownicy.WgKodu["006"];
var defUrlop  = kalend.DefinicjeLimitow.WgNazwy["Urlop wypoczynkowy"];   // lub DefinicjeLimitow.UrlopWypoczynkowy
var rok       = FromTo.Year(new Date(2026, 1, 1));

using (var t = session.Logout(editMode: true))
{
    var naliczanie = new NaliczanieLimitow
    {
        Pars = new NaliczanieLimitow.Params(Context.Empty.Clone(session))
        {
            Definicja     = defUrlop,
            Okres         = rok,
            KopiujKorekty = true
        },
        Pracownicy = new Pracownik[] { pracownik }
    };
    naliczanie.DodajLimit();          // tworzy/aktualizuje LimitNieobecnosci
    t.Commit();
}
session.Save();

// Odczyt limitu urlopu wypoczynkowego za rok 2026.
// UWAGA: filtr serwerowy obejmuje TYLKO pola bazodanowe i prostych porównań — Okres (FromTo)
// NIE da się porównać serwerowo (==), więc filtrujemy serwerowo po Definicja, a rok w pamięci:
var lim = pracownik.Limity[(LimitNieobecnosci l) => l.Definicja == defUrlop]
              .Cast<LimitNieobecnosci>()
              .FirstOrDefault(l => l.Okres.From == rok.From);
if (lim != null)
{
    int przysluguje  = lim.Razem;            // przysługujący (limit + przeniesienia + zmiany)
    int pozostalo    = lim.Pozostalo;        // pozostało
    int wykorzystany = przysluguje - pozostalo;  // == lim.Wykorzystane
    // lim.PozostaloDni, lim.PozostaloGodz, lim.ZaleglyDni
}

Pułapki:

  • Nie twórz new LimitNieobecnosci(...) — limit powstaje przez naliczanie (DodajLimit). W bazie Demo limit dla danego roku może jeszcze nie istnieć — w teście trzeba go najpierw naliczyć.
  • Kolekcja na pracowniku to pracownik.Limity (nie LimityNieobecnosci).
  • Nie porównuj Okres (FromTo) w filtrze serwerowyml.Okres == rok rzuca ArgumentException („pole nieznalezione"). Filtruj serwerowo po Definicja, a okres/rok porównaj w pamięci (.FirstOrDefault(l => l.Okres.From == rok.From)).
  • Razem może wynosić 0 dla pracowników bez danych napędzających wymiar urlopu (staż, data urodzenia) — asercje opieraj na spójności (Wykorzystane == Razem - Pozostalo, Razem >= 0), a nie na założeniu Razem > 0.
  • Pracownik na limicie jest read-only (relacja guided) — naliczanie samo wiąże rekord z pracownikiem.
  • Filtruj limity serwerowo po Definicja i Okres (pracownik.Limity[condition]), nie iteruj całości z if w pamięci (safe-code §6.1). Tabela LimNieobecnosci jest operacyjna guided.
  • Context.Empty.Clone(session) daje kontekst związany z bieżącą sesją — wymagany przez ctor NaliczanieLimitow.Params(Context).
  • Naliczanie modyfikuje dane operacyjne — w transakcji edycyjnej, krótko, z obsługą wyjątków z Save().

KADRY-D3 — Import e-ZLA z PUE ZUS (zwolnienia lekarskie)

Cel: zaewidencjonować w systemie zwolnienie lekarskie pobrane z PUE ZUS (e-ZLA). Sam import to operacja sieciowa (komunikacja z PUE ZUS) — w kodzie biznesowym/teście dokumentujemy model danych nieobecności chorobowej i jej dane ZUS, a nie samo połączenie z bramką PUE.

Fakty o typie (zweryfikowane skanem DLL):

  • Zwolnienie chorobowe to Soneta.Kalend.NieobecnośćPracownika (typ konkretny z KADRY-D1) z Definicja wskazującą na rodzaj zasiłkowy (np. „Zwolnienie chorobowe").
  • Dane ZUS zwolnienia leżą w subrowie Nieobecnosc.Zwolnienie: Soneta.Kalend.ZwolnienieZUS (bazodanowy subrow na rekordzie nieobecności).
  • Dane samego dokumentu ZLA leżą w subrowie Nieobecnosc.ZLA: Soneta.Kalend.ZLA (ZLA.Data: Date, ZLA.Wersja: WersjaZLA, ZLA.Zrodlo: MemoText).

Pola i typy (Nieobecnosc.Zwolnienie: ZwolnienieZUS) — zapisywalne, bazodanowe:

Pole Typ Opis
Numer string numer dokumentu ZLA (pole tekstowe — maks. 9 znaków)
KodChoroby string kod literowy choroby (A, B, C, D, …)
Przyczyna Soneta.Kalend.PrzyczynaZwolnienia przyczyna niezdolności do pracy
Kwarantanna Soneta.Kalend.ZwolnienieKwarantanna kwarantanna/izolacja
LeczenieSzpitalne bool pobyt w szpitalu
ZwolnienieWystawione Soneta.Types.Date data wystawienia ZLA
ZwolnienieDostarczone Soneta.Types.Date data dostarczenia
PomniejszajZasilek bool obniżenie zasiłku
PonownieUstalPodstawe bool wymuszenie przeliczenia podstawy (patrz KADRY-D2/KADRY-D6)

Pola i typy (Nieobecnosc.ZLA: ZLA): Data: Date, Wersja: WersjaZLA, Zrodlo: MemoText.

Snippet — ręczne odwzorowanie e-ZLA jako nieobecności chorobowej (bez sieci):

var kalend    = session.GetKalend();
var pracownik = session.GetKadry().Pracownicy.WgKodu["006"];
var defChor   = kalend.DefNieobecnosci.WgNazwy["Zwolnienie chorobowe"];

using (var t = session.Logout(editMode: true))
{
    var nieob = session.AddRow(new NieobecnośćPracownika(pracownik));
    nieob.Definicja = defChor;
    nieob.Okres     = new FromTo(new Date(2026, 5, 4), new Date(2026, 5, 10));
    // dane ZUS z e-ZLA (subrow Zwolnienie):
    nieob.Zwolnienie.Numer      = "ZLA000001";   // pole Numer ma limit 9 znaków
    nieob.Zwolnienie.KodChoroby = "A";
    t.Commit();
}
session.Save();

Pułapki:

  • Sam import e-ZLA z PUE wymaga sieci (uwierzytelnienie + bramka ZUS) — nie da się go odtworzyć w teście jednostkowym na bazie Demo; testuj wyłącznie odwzorowanie modelu danych (subrow Zwolnienie).
  • Zwolnienie i ZLA to subrowy — nie tworzysz ich osobno, są częścią rekordu Nieobecnosc; ustawiasz ich pola po utworzeniu nieobecności.
  • Definicja zasiłkowa musi istnieć w słowniku bazy (DefNieobecnosci.WgNazwy[...]null).
  • Faktyczne kwoty zasiłku liczą się dopiero przy naliczeniu wypłaty — patrz uwaga przy KADRY-D2.

KADRY-D4 — Generowanie deklaracji Z-3 / Z-3a dla nieobecności chorobowej

Cel: wygenerować zaświadczenie płatnika składek Z-3 (pracownik etatowy) lub Z-3a (umowy/inni ubezpieczeni) dla konkretnej nieobecności zasiłkowej.

Fakty o typie (zweryfikowane skanem DLL):

  • Worker (czynność na Nieobecnosc): Soneta.Deklaracje.ZUS.ZUSZ3.Z3Worker — akcja „Generuj deklarację Z-3", metoda public object UtworzDeklaracjeZ3().
  • Analogicznie Soneta.Deklaracje.ZUS.ZUSZ3.Z3aWorker — akcja „Generuj deklarację Z-3a", metoda public object UtworzDeklaracjeZ3a().
  • Oba workery przyjmują przez [Context]:
    • KeduContext: DeklaracjaZUS.PUEContext (property Kedu: KEDU),
    • Z3ParamContext: Z3ParamContext / Z3aParamContext z polami m.in.: Nieobecnosc: INieobecnoscLubZbieg, NieobecnoscZContextu: bool, Pracownik: Pracownik, PracownikZContextu: bool, Okres: FromTo, OkresZasiłkowy: FromTo, OkresZasilkowyOd: Date, Współczynnik: Fraction, RachBank: string, KontynuacjaŚwiadczenia: bool.

Snippet — generowanie Z-3 dla nieobecności (kontekst):

var worker = new Soneta.Deklaracje.ZUS.ZUSZ3.Z3Worker();
var ctx    = Context.Empty.Clone(session);
ctx[typeof(Nieobecnosc)] = nieobChorobowa;   // worker czyta nieobecność z kontekstu

var deklaracja = worker.UtworzDeklaracjeZ3();  // zwraca obiekt deklaracji Z-3
session.Save();

Pułapki:

  • Sensowny Z-3 wymaga naliczonej wypłaty/podstawy zasiłku — bez naliczonej podstawy deklaracja powstanie z pustymi/zerowymi kwotami. W teście na czystej Demo zweryfikujesz fakt powstania obiektu i ustawienie pól nagłówkowych (pracownik, okres), ale nie kwoty zasiłku.
  • Worker przyjmuje dane przez Context (ctx[typeof(Nieobecnosc)]/ctx[typeof(Pracownik)]) — nie ma prostego ctora parametrowego; zegnij pod swój scenariusz Z3ParamContext.
  • Z-3 dotyczy etatu, Z-3a umów/innych ubezpieczonych — dobierz worker do tytułu ubezpieczenia.
  • Metody zwracają object (deklaracja KEDU) — zachowaj/odczytaj wynik, nie zakładaj typu wprost.

KADRY-D5 — Obsługa przestoju (dodanie/usunięcie, przestój ekonomiczny — % wynagrodzenia)

Cel: zaewidencjonować przestój pracownika (np. ekonomiczny) za okres oraz wskazać procent wynagrodzenia przestojowego; usunąć przestój nakładający się na nieobecność ZUS.

Fakty o typie (zweryfikowane skanem DLL):

  • Dodanie przestoju: worker Soneta.Kadry.DodajPrzestojWorker (czynność „Przestój/Dodaj przestój", metoda public void DodajPrzestoj()):
    • settowalne property: Pracownicy: Pracownik[], Pars: DodajPrzestojWorker.Params;
    • Params z polami: DefinicjaStrefy: Soneta.Kalend.DefinicjaStrefy, Okres: FromTo.
  • Procent wynagrodzenia przestojowego (przestój ekonomiczny): worker Soneta.Kadry.IndywidualnyProcentWynagrPrzestojowegoWorker (czynność „Przestój/Przestój ekonomiczny - procent wynagr.", metoda public void Aktualizuj()):
    • Pracownicy: Pracownik[], Pars.Data: Date, Pars.Procent: Soneta.Types.Percent.
  • Usunięcie przestoju podczas nieobecności ZUS: worker Soneta.Kadry.UsunPrzestojNieobecnoscWorker (czynność „Przestój/Usuń przestój podczas nieobecności ZUS", metoda public void UsunPrzestoj()): Pracownicy: Pracownik[], Pars.Okres: FromTo.
  • Procent wynagrodzenia przestojowego jest też trzymany na etacie: PracHistoria.Etat.Postojowe: Soneta.Kadry.WynagrodzeniePostojowe (Procent: Percent, Standardowe: bool).
  • DefinicjaStrefy (session.GetKalend().DefinicjeStref) — słownik konfiguracyjny stref (m.in. przestoju).

Snippet — dodanie przestoju:

var kalend     = session.GetKalend();
var pracownik  = session.GetKadry().Pracownicy.WgKodu["006"];
var defStrefa  = kalend.DefinicjeStref.WgNazwy["Przestój"];   // nazwa wg słownika danej bazy

var worker = new Soneta.Kadry.DodajPrzestojWorker
{
    Pracownicy = new[] { pracownik },
    Pars = new Soneta.Kadry.DodajPrzestojWorker.Params(Context.Empty.Clone(session))
    {
        DefinicjaStrefy = defStrefa,
        Okres           = new FromTo(new Date(2026, 6, 1), new Date(2026, 6, 5))
    }
};
worker.DodajPrzestoj();    // worker wykonuje własną transakcję
session.Save();

Snippet — przestój ekonomiczny (procent):

var worker = new Soneta.Kadry.IndywidualnyProcentWynagrPrzestojowegoWorker
{
    Pracownicy = new[] { pracownik },
    Pars = new Soneta.Kadry.IndywidualnyProcentWynagrPrzestojowegoWorker.Params(Context.Empty.Clone(session))
    {
        Data    = new Date(2026, 6, 1),
        Procent = new Percent(0.5m)   // 50% wynagrodzenia
    }
};
worker.Aktualizuj();
session.Save();

Pułapki:

  • DefinicjeStref.WgNazwy[...] zależy od słownika danej bazy — zweryfikuj nazwę przestoju w Demo (może być inna niż „Przestój"); dla nieistniejącej nazwy zwraca null.
  • Worker wykonuje własną transakcję — nie zagnieżdżaj go w otwartej transakcji edycyjnej.
  • Percent przyjmuj jako ułamek (0.5m = 50%), nie liczbę 50.
  • UsunPrzestojNieobecnoscWorker usuwa przestój kolidujący z nieobecnością ZUS — to nie generyczne „usuń przestój"; zakres działania ogranicza okres + obecność nieobecności ZUS.
  • Skutki płacowe (wynagrodzenie przestojowe) liczą się dopiero przy naliczeniu wypłaty.

KADRY-D6 — Ustalanie/zmiana parametrów okresu zasiłkowego

Cel: zmienić parametry okresu zasiłkowego nieobecności chorobowej — kontynuację/przedłużenie okresu zasiłkowego oraz wymusić ponowne ustalenie podstawy naliczania zasiłku.

Fakty o typie (zweryfikowane skanem DLL):

  • Parametry okresu zasiłkowego są w subrowie Nieobecnosc.Zwolnienie: ZwolnienieZUS (bazodanowe, zapisywalne):
    • KontynuacjaOkrZas: Soneta.Kalend.KontynuacjaOkrZas (enum: Warunkowo, Tak, Nie),
    • PrzedluzenieOkrZas: bool, PrzedluzeniaData: Soneta.Types.Date,
    • PonownieUstalPodstawe: bool + metoda SetPonownieUstalPodstawe(bool) (patrz KADRY-D2).
  • Worker korekty okresu zasiłkowego: Soneta.Kalend.Nieobecnosc.KorektaOkresuZasiłkowegoWorker (czynność „Zmień pozostałe parametry okresu zasiłkowego", metoda public void PonownieUstalPodstawę()):
    • settowalne Pars: KorektaOkresuZasiłkowegoWorker.Params z polami: KontynuacjaOkrZas: KontynuacjaOkrZas, PrzedluzenieOkrZas: bool, PrzedluzeniaData: Date.
  • BO okresu zasiłkowego (przy wdrożeniu) — patrz KADRY-D10: PracHistoria.ChorobowyBO (DniZasilkowe, ZasilekOdDnia, PrzedluzenieOZ).

Snippet — zmiana parametrów wprost na rekordzie:

using (var t = session.Logout(editMode: true))
{
    nieobChorobowa.Zwolnienie.KontynuacjaOkrZas  = KontynuacjaOkrZas.Tak;
    nieobChorobowa.Zwolnienie.PrzedluzenieOkrZas = true;
    nieobChorobowa.Zwolnienie.PrzedluzeniaData   = new Date(2026, 5, 31);
    nieobChorobowa.Zwolnienie.SetPonownieUstalPodstawe(true);
    t.Commit();
}
session.Save();

Snippet — przez worker korekty okresu zasiłkowego:

var worker = new Nieobecnosc.KorektaOkresuZasiłkowegoWorker();
var ctx    = Context.Empty.Clone(session);
ctx[typeof(Nieobecnosc)] = nieobChorobowa;
worker.Pars = new Nieobecnosc.KorektaOkresuZasiłkowegoWorker.Params(ctx)
{
    KontynuacjaOkrZas  = KontynuacjaOkrZas.Tak,
    PrzedluzenieOkrZas = true,
    PrzedluzeniaData   = new Date(2026, 5, 31)
};
worker.PonownieUstalPodstawę();   // własna transakcja + Commit
session.Save();

Pułapki:

  • Faktyczne przeliczenie kwot zasiłku następuje dopiero przy ponownym naliczeniu wypłaty — test na Demo zweryfikuje zmianę pól KontynuacjaOkrZas/PrzedluzenieOkrZas/PrzedluzeniaData/flagi, ale nie kwoty.
  • Parametry okresu zasiłkowego mają sens tylko dla nieobecności ZUS (zwolnienia chorobowe/zasiłki) — dla urlopu wypoczynkowego są bez znaczenia.
  • Worker wykonuje własną transakcję — nie zagnieżdżaj go w innej otwartej transakcji.

KADRY-D8 — Naliczanie i przeliczanie limitów nieobecności

Cel: naliczyć limit nieobecności (jak KADRY-D7 — NaliczanieLimitow.DodajLimit()) oraz przeliczyć liczbę wykorzystanych dni limitu (czynność „Przelicz wykorzystane").

Fakty o typie (zweryfikowane skanem DLL):

  • Naliczenie limitu: klasa Soneta.Kalend.NaliczanieLimitow — publiczny bezparametrowy ctor; settowalne Pars: NaliczanieLimitow.Params (Definicja: DefinicjaLimitu, Okres: FromTo, KopiujKorekty: bool, ZapisPerPracownik: bool) oraz Pracownicy: ICollection<Pracownik> / PracownicyIdx: Pracownik[]; metoda public void DodajLimit() (i DodajLimitUrlopowy()). Wariant UI per-pracownik: worker Soneta.Kalend.UI.PracownikLimityNaliczanieWorker (czynność „Nalicz limit nieobecności", metoda DodajLimit()) — Pracownik: Pracownik, Pars jak wyżej.
  • Przeliczenie wykorzystanych: worker Soneta.Kalend.LimitNieobecnosci.Pracownicy.PrzeliczWykorzystaneWorker (czynność „Limity nieobecności/Przelicz wykorzystane", metoda public void PrzeliczWykorzystane()):
    • settowalne Pracownicy: Pracownik[], Pars.Definicja: DefinicjaLimitu, Pars.Okres: FromTo.

Snippet — naliczenie + przeliczenie wykorzystanych:

var kalend    = session.GetKalend();
var pracownik = session.GetKadry().Pracownicy.WgKodu["006"];
var defUrlop  = kalend.DefinicjeLimitow.WgNazwy["Urlop wypoczynkowy"];
var rok       = FromTo.Year(new Date(2026, 1, 1));

// 1) naliczenie limitu (jak KADRY-D7)
var naliczanie = new NaliczanieLimitow
{
    Pars = new NaliczanieLimitow.Params(Context.Empty.Clone(session))
    {
        Definicja     = defUrlop,
        Okres         = rok,
        KopiujKorekty = true
    },
    Pracownicy = new[] { pracownik }
};
naliczanie.DodajLimit();
session.Save();

// 2) przeliczenie wykorzystanych
var przelicz = new LimitNieobecnosci.Pracownicy.PrzeliczWykorzystaneWorker
{
    Pracownicy = new[] { pracownik },
    Pars = new LimitNieobecnosci.Pracownicy.PrzeliczWykorzystaneWorker.Params(Context.Empty.Clone(session))
    {
        Definicja = defUrlop,
        Okres     = rok
    }
};
przelicz.PrzeliczWykorzystane();
session.Save();

Pułapki:

  • Nie twórz new LimitNieobecnosci(...) — limit powstaje przez naliczanie (jak w KADRY-D7).
  • PrzeliczWykorzystane aktualizuje pole LimitNieobecnosci.Wykorzystane na podstawie wprowadzonych nieobecności — ma sens dopiero po naliczeniu limitu i wprowadzeniu nieobecności limitowanych.
  • Razem może wynosić 0 dla pracownika bez danych napędzających wymiar — opieraj asercje na spójności (Wykorzystane == Razem - Pozostalo), nie na Razem > 0 (patrz KADRY-D7).
  • Workery wykonują własne transakcje — wywołuj poza otwartą transakcją edycyjną; obsłuż wyjątki z Save().

KADRY-D9 — Aktualizacja podstaw nieobecności ZUS / podstaw urlopu

Cel: odczytać/wprowadzić ręcznie podstawy naliczania zasiłków (chorobowe/macierzyńskie/opiekuńcze/ rehabilitacyjne) używane przy nieobecnościach ZUS — np. przy wdrożeniu lub korekcie podstawy.

Fakty o typie (zweryfikowane skanem DLL):

  • Kolekcja na pracowniku: pracownik.PodstawyNieobecności: SubTable<Soneta.Place.PodstawaNieobecnosci> (jest też PodstawyNieobecnościOkresowe: SubTable<PodstawaNieobecnosciOkresowa>).
  • Soneta.Place.PodstawaNieobecnosci — tabela PodstawyNieobec, GuidedRow child pracownika (relacja przez pole Pracownik).
  • Brak publicznego ctoraPodstawaNieobecnosci ma jedynie ctory niepubliczne ((RowCreator), (Pracownik, TypyPodstawNieobecnosci)). Rekordy powstają z naliczenia wypłaty; w kodzie biznesowym/teście realnie testowalny jest odczyt (dodawanie ręczne — patrz pułapki/spec).

Pola i typy (PodstawaNieobecnosci) — bazodanowe, zapisywalne:

Pole Typ Opis
Data Soneta.Types.Date data podstawy
Miesieczne decimal podstawa miesięczna
Kwartalne / Roczne decimal składowe
Podstawa decimal podstawa naliczania chorobowego
PodstawaM / PodstawaO / PodstawaR decimal podstawa macierzyńskiego / opiekuńczego / rehabilitacyjnego
Typ Soneta.Place.TypyPodstawNieobecnosci Chorobowa / Wypoczynkowy
Norma / NormaDni Time / int norma czasu/dni
Praca / PracaDni Time / int przepracowane
ProcentSkladki Soneta.Types.Percent procent składki

Podstawy urlopu wypoczynkowego rozróżnia pole Typ = TypyPodstawNieobecnosci.Wypoczynkowy; podstawy zasiłków ZUS → Typ = Chorobowa.

Snippet — odczyt podstaw + dodanie podstawy ręcznej:

var pracownik = session.GetKadry().Pracownicy.WgKodu["006"];

// Odczyt podstaw chorobowych (filtr serwerowy po Typ):
foreach (PodstawaNieobecnosci p in
         pracownik.PodstawyNieobecności[(PodstawaNieobecnosci x) => x.Typ == TypyPodstawNieobecnosci.Chorobowa])
{
    // p.Data, p.Podstawa, p.Miesieczne
}

// UWAGA: PodstawaNieobecnosci NIE ma publicznego ctora — normalnie powstaje z naliczenia wypłaty.
// Ręczne dodanie wymagałoby niepublicznego API → w teście testuj wyłącznie ODCZYT (powyżej).

Pułapki:

  • Kwoty (Miesieczne, Podstawa, …) są typu decimal — to dane operacyjne podstaw; normalnie podstawy powstają z naliczenia wypłaty (brak publicznego ctora — patrz wyżej).
  • Pracownik na podstawie jest read-only (guided-parent).
  • Filtruj serwerowo po Typ (PodstawyNieobecności[condition]) — nie iteruj całości z if w pamięci.
  • W teście na czystej Demo kolekcja PodstawyNieobecności może być pusta, dopóki nie naliczono wypłaty z zasiłkiem — testuj odczyt asercją na model/spójność, a scenariusz „dodaj ręcznie" oznacz [Ignore].

KADRY-D10 — Bilans otwarcia nieobecności i urlopów

Cel: wprowadzić bilans otwarcia (BO) przy wdrożeniu / starcie roku — historię chorobową (okres zasiłkowy, dni wykorzystane) oraz urlop wykorzystany u poprzednich pracodawców / w pierwszym miesiącu.

Fakty o typie (zweryfikowane skanem DLL):

  • BO leży na rekordzie historycznym Soneta.Kadry.PracHistoria w dwóch subrowach (bazodanowe, zapisywalne):
    • PracHistoria.ChorobowyBO: Soneta.Kadry.ChorobowyBO (BO chorobowy / okres zasiłkowy),
    • PracHistoria.DodatkowyBO: Soneta.Kadry.DodatkowyBO (BO urlopowy — urlop u poprzednich pracodawców).
  • BO nieobecności pojedynczej oznacza też flaga Nieobecnosc.BilansOtwarcia: bool (interfejs IBilansOtwarcia na Nieobecnosc).

Pola i typy (ChorobowyBO) — bazodanowe:

Pole Typ Opis
Data Soneta.Types.Date data BO
MiesiacPodstawy Soneta.Types.YearMonth miesiąc podstawy
Podstawa decimal podstawa BO
DniWynagrodzenia int dni zwolnienia finansowane przez pracodawcę
DniZasilkowe int dni wliczane do bieżącego okresu zasiłkowego
DniZwolnienia int dni nieprzerwanego zwolnienia dobrowolnego
ZasilekOdDnia Soneta.Types.Date zasiłek od dnia
PrzedluzenieOZ bool okres zasiłkowy przedłużony o 3 mies.

Pola i typy (DodatkowyBO) — bazodanowe:

Pole Typ Opis
UPoprzednich decimal urlop wykorzystany u poprzednich pracodawców (dni)
Wykorzystany Soneta.Types.Time wykorzystany przypadający na bieżące zatrudnienie (godz.)
BezPierwszego bool prawo do urlopu w 1. mies. nabyte u poprzedniego pracodawcy

Snippet — wprowadzenie BO chorobowego i urlopowego na zapisie historycznym:

var pracownik = session.GetKadry().Pracownicy.WgKodu["006"];
var historia  = pracownik.Historia[Date.Today];   // właściwy zapis historyczny „na dzień"

using (var t = session.Logout(editMode: true))
{
    // BO chorobowy / okres zasiłkowy
    historia.ChorobowyBO.DniZasilkowe = 33;
    historia.ChorobowyBO.ZasilekOdDnia = new Date(2026, 1, 1);
    // BO urlopowy
    historia.DodatkowyBO.UPoprzednich = 10m;
    t.Commit();
}
session.Save();

Pułapki:

  • ChorobowyBO/DodatkowyBO to subrowy zapisu PracHistoria — nie tworzysz ich osobno, edytujesz ich pola na istniejącym zapisie historycznym.
  • ChorobowyBO (DniZasilkowe, ZasilekOdDnia, PrzedluzenieOZ, …) jest zapisywalny na zwykłym zapisie historii (zweryfikowane testem KADRY-D10 na Demo).
  • DodatkowyBO (UPoprzednich, BezPierwszego, Wykorzystany) na zwykłym zapisie historii Demo rzuca ColReadOnlyException („pole w trybie tylko do odczytu") — BO urlopowy jest zapisywalny tylko na zapisie historycznym oznaczonym jako bilans otwarcia / start zatrudnienia, nie na dowolnym zapisie „na dzień". W teście na gotowych pracownikach Demo dodawanie DodatkowyBO oznacz [Ignore].
  • Pobierz właściwy zapis historyczny przez pracownik.Historia[data] (patrz KADRY-A14/KADRY-A15) — edycja BO na niewłaściwym zapisie da błędne dane „na dzień".
  • BO ma sens przy wdrożeniu — nie miesza się z normalnym naliczaniem; po wprowadzeniu wpływa na limity (KADRY-D8) i okres zasiłkowy (KADRY-D6) dopiero przy przeliczeniu/naliczeniu.

KADRY-D11 — Wnioski o urlop / delegację

Cel: zarejestrować wniosek urlopowy (lub o delegację), zmienić jego stan (akceptacja/odrzucenie/ przywrócenie) i — docelowo — przekształcić zaakceptowany wniosek w nieobecność.

Fakty o typie (zweryfikowane skanem DLL):

  • Wniosek urlopowy: Soneta.Kadry.WniosekUrlopowy — tabela WnioskiUrlopowe, GuidedRow root. Konstruktory publiczne: new WniosekUrlopowy(Pracownik pracownik) oraz new WniosekUrlopowy(Pracownik pracownik, DefinicjaNieobecnosci definicja).
  • Kolekcja na pracowniku: pracownik.WnioskiUrlopowe: SubTable<Soneta.Kadry.WniosekUrlopowy> (oraz WnioskiKierownika, WnioskiZastępcy — te same wnioski w roli kierownika/zastępcy).
  • Pola WniosekUrlopowy (bazodanowe, zapisywalne): Pracownik: Pracownik, Definicja: DefinicjaNieobecnosci, Okres: FromTo, Data: Date, DataDecyzji: Date, Kierownik: Pracownik, Opis: MemoText, Stan: Soneta.Kadry.StanWnioskuUrlopowego.
    • StanWnioskuUrlopowego: Oczekujący, Anulowany, Zaakceptowany, Odrzucony, Korygowana.
  • Wniosek o delegację jest subrowem wniosku: WniosekUrlopowy.Delegacja: Soneta.Kadry.WniosekODelegację (DataRozpoczeciaPlanowana, DataZakonczeniaPlanowana: DateShortTime, KrajDocelowy, Cel: MemoText, WnioskowanaZaliczka: Currency); samodzielny new WniosekODelegację() ma publiczny ctor bezparametrowy.
  • Planowane nieobecności (osobny model, np. plan urlopów): kolekcja pracownik.PlanowaneNieobecności: FromToSubTable<Soneta.Kalend.PlanowanaNieobecność>; typ PlanowanaNieobecność (tabela PlanNieobecnosci, root) z ctorem new PlanowanaNieobecność(Pracownik pracownik), polami Definicja, Okres: FromTo.
    • Definicja musi mieć zaznaczone pole Planowana (DefinicjaNieobecnosci.Planowana == true) — inaczej setter rzuca RowException „Wybrana definicja musi mieć zaznaczone pole 'Planowana'."; dobierz definicję dynamicznie: DefNieobecnosci.Cast<DefinicjaNieobecnosci>().First(d => d.Planowana).
    • Stan: StanPlanowanejNieobecności jest READ-ONLY (Oczekująca, Wprowadzona, Korygowana, Zatwierdzona, Anulowana) — nie przypisujesz go wprost (plan.Stan = … → błąd kompilacji „cannot be assigned to"); przejścia stanu wykonujesz metodami domenowymi StanWprowadzona() / StanZatwierdzona() / StanAnulowana() / StanOczekująca().
  • Akceptacja/odrzucenie/przywrócenie z poziomu Pulpitu: worker (UI/Net) PracownikNetWnioskiUrlopowe z akcjami „Zatwierdź wniosek"/Zatwierdz, „Odrzuć wniosek"/Odrzuc, „Przywróć wniosek"/Przywroc. W kodzie biznesowym/teście prościej ustawiać Stan wprost.

Snippet — rejestracja wniosku urlopowego + akceptacja:

var kalend    = session.GetKalend();
var pracownik = session.GetKadry().Pracownicy.WgKodu["006"];
// UWAGA: dla definicji limitowanej (np. „Urlop wypoczynkowy") akceptacja wniosku (set Stan) wyzwoli
// przeliczenie limitu → LimitNotFoundException, jeśli limit nie został wcześniej naliczony (patrz pułapki).
// Tu używamy definicji bezlimitowej (np. „Urlop bezpłatny (art 174 kp)") albo najpierw naliczamy limit (KADRY-D8).
var defUrlop  = kalend.DefNieobecnosci.WgNazwy["Urlop bezpłatny (art 174 kp)"];

using (var t = session.Logout(editMode: true))
{
    var wniosek = session.AddRow(new WniosekUrlopowy(pracownik, defUrlop));
    wniosek.Okres = new FromTo(new Date(2026, 8, 3), new Date(2026, 8, 7));
    wniosek.Data  = Date.Today;
    wniosek.Stan  = StanWnioskuUrlopowego.Oczekujący;
    t.Commit();
}
session.Save();

// Akceptacja (zmiana stanu):
using (var t = session.Logout(editMode: true))
{
    var wniosek = pracownik.WnioskiUrlopowe
        .Cast<WniosekUrlopowy>()
        .First(w => w.Stan == StanWnioskuUrlopowego.Oczekujący);
    wniosek.Stan        = StanWnioskuUrlopowego.Zaakceptowany;
    wniosek.DataDecyzji = Date.Today;
    t.Commit();
}
session.Save();

Pułapki:

  • Akceptacja wniosku na definicji limitowanej rzuca LimitNotFoundException bez wcześniej naliczonego limitu: ustawienie Stan (np. Zaakceptowany) na wniosku z definicją „Urlop wypoczynkowy" wewnętrznie ustawia Okres nieobecności i wyzwala DefinicjaLimitu.Przelicz(...), który dla pracownika bez limitu na ten dzień rzuca wyjątek. Rozwiązanie: albo nalicz limit (KADRY-D8) przed zmianą stanu, albo do scenariusza obsługi samego rekordu wniosku użyj definicji bezlimitowej (np. „Urlop bezpłatny (art 174 kp)").
  • Przekształcenie wniosku w nieobecność wymaga, by nieobecność limitowana miała naliczony limit (jak KADRY-D1) — sama akceptacja wniosku nie tworzy automatycznie rozliczonej nieobecności w teście bez naliczonego limitu/wypłaty.
  • WniosekODelegację to subrow wniosku (WniosekUrlopowy.Delegacja) — wnioskowanie o delegację ustawiasz na tym subrowie; pełne rozliczenie delegacji to moduł Soneta.Delegacje (osobny dokument handlowy PWS), poza zakresem wniosku.
  • Filtruj kolekcję wniosków przez WnioskiUrlopowe[condition] lub iteruj w zakresie jednego pracownika; nie skanuj globalnej tabeli WnioskiUrlopowe bez zakresu (tabela operacyjna guided).
  • Stan zmieniaj świadomie wg enuma StanWnioskuUrlopowego — workery Net robią to samo z dodatkową logiką workflow (powiadomienia), której w teście jednostkowym nie odtworzysz.

KADRY-D12 — Praca zdalna (wnioski, lokalizacje, ewidencja)

Cel: skonfigurować pracę zdalną pracownika (model pracy, limit pracy zdalnej okazjonalnej), zarejestrować wniosek o pracę zdalną i lokalizacje jej świadczenia oraz odczytać ewidencję.

Fakty o typie (zweryfikowane skanem DLL):

  • Parametry pracy zdalnej leżą na etacie/historii: PracHistoria.PracaZdalna: Soneta.Kadry.PracZdalna (subrow, bazodanowe, zapisywalne):
    • ModelPracy: Soneta.Kadry.ModelPracy (NieDotyczy, PracaStacjonarna, PracaHybrydowa, PracaZdalna),
    • OswiadczenieWarunki: bool (warunki lokalowe/techniczne),
    • LimitPZ: int, IndywidualnyLimitPZ: bool, TypLimituPZ: TypLimituPracyZdalnej (Roczny, Miesieczny, Tygodniowy, Kwartalny, Półroczny).
  • Lokalizacje pracy zdalnej: pracownik.LokalizacjePracyZdalnej: SubTable<Soneta.Kadry.LokalizacjaPracyZdalnej> (tabela LokPracZdalnej).
  • Wnioski o pracę zdalną: pracownik.WnioskiPracyZdalnej: SubTable<Soneta.Kalend.WniosekPracyZdalnej> (oraz WnioskiPracyZdalnejKierownika); typ WniosekPracyZdalnej ma ctor (Pracownik, DefinicjaRodzajuPracyZdalnej)ctory są niepubliczne, więc tworzenie wniosku idzie przez worker (GrupoweZleceniePracyZdalnejWorker) lub Pulpit, nie wprost new.
  • Lokalizacja pracy zdalnej: Soneta.Kadry.LokalizacjaPracyZdalnej ma publiczny ctor new LokalizacjaPracyZdalnej(Pracownik pracownik).
  • Ewidencja/odczyt limitu pracy zdalnej okazjonalnej: worker Soneta.Kadry.Pracownik.PracaZdalnaWorker — property odczytowe (bez akcji modyfikującej): DniPracyZdalnejRazem: int, DniPracyZdalnejOkazjonalnej: int, DniPracyZdalnejOkazjonalnejLimit: int, CzasPracyZdalnejRazem: Time, LimitPracaZdalnaOkazjonalna: int, PozostaloPracaZdalnaOkazjonalna: int; kontekst: Pracownik: Pracownik, Okres: FromTo.
  • Grupowe zlecenie pracy zdalnej (Pulpit/seryjne): worker Soneta.Kadry.UI.KadryNet.Workers.GrupoweZleceniePracyZdalnejWorker (akcja „Dodaj wnioski zlecenia pracy zdalnej"/DodajZleceniaPracyZdalnej): Pracownicy: Pracownik[], Pars.Okres: FromTo, Pars.Data: Date, Pars.Uwagi: string.
  • Aktualizacja podzielników kosztów na podstawie pracy hybrydowej: worker AktualizujPodzielnikowPracaZdalnaWorker (DefinicjaPodzielnika, Okres: YearMonth, …).

Snippet — ustawienie modelu pracy zdalnej + lokalizacja + wniosek:

var kadry     = session.GetKadry();
var pracownik = kadry.Pracownicy.WgKodu["006"];

using (var t = session.Logout(editMode: true))
{
    var historia = pracownik.Historia[Date.Today];
    historia.PracaZdalna.ModelPracy          = ModelPracy.PracaHybrydowa;
    historia.PracaZdalna.OswiadczenieWarunki = true;

    // lokalizacja pracy zdalnej (np. adres domowy)
    var lok = session.AddRow(new LokalizacjaPracyZdalnej(pracownik));
    // … pola adresowe lokalizacji wg LokalizacjaPracyZdalnej
    t.Commit();
}
session.Save();

// Odczyt ewidencji pracy zdalnej okazjonalnej (worker odczytowy):
// Pracownik i Okres są zwykłymi, settowalnymi property (nie trzeba przekazywać przez Context):
var pz = new Soneta.Kadry.Pracownik.PracaZdalnaWorker
{
    Pracownik = pracownik,
    Okres     = FromTo.Year(new Date(2026, 1, 1))
};
// odczyt: pz.DniPracyZdalnejRazem, pz.LimitPracaZdalnaOkazjonalna, pz.PozostaloPracaZdalnaOkazjonalna

Pułapki:

  • PracaZdalnaWorker to worker odczytowy (ma property, brak akcji modyfikującej) — służy do prezentacji ewidencji/limitu, nie do zapisu.
  • ModelPracy/OswiadczenieWarunki są na historycznym zapisie etatu (PracHistoria.PracaZdalna) — edytuj właściwy zapis „na dzień".
  • WniosekPracyZdalnej ma niepubliczne ctory — w teście jednostkowym nie utworzysz go przez new; zlecenie pracy zdalnej idzie przez worker GrupoweZleceniePracyZdalnejWorker (czynność Net/UI, wymaga Context). Testuj raczej ModelPracy/OswiadczenieWarunki na PracHistoria.PracaZdalna i LokalizacjaPracyZdalnej (ma publiczny ctor).
  • LokalizacjaPracyZdalnej ma publiczny ctor (Pracownik) — testowalna wprost.