using System; using System.Linq; using AwesomeAssertions; using NUnit.Framework; using Soneta.Business; using Soneta.Deklaracje; using Soneta.Kadry; using Soneta.Place; using Soneta.Types; using Prac = Soneta.Kadry.Pracownik; namespace Soneta.Skills.Test.KadryPlace.Pracownik; /// /// Rozdział J — „Deklaracje (ZUS, PIT, PFRON, PPK)" (receptury J1–J6). /// /// Testy są wykonywalną dokumentacją publicznego kontraktu modułu Deklaracje /// (Soneta.Deklaracje.DeklaracjeModule, dostęp przez Session.GetDeklaracje()). /// Wszystkie deklaracje to wiersze tabeli Deklaracje, dziedziczące po abstrakcyjnej /// Soneta.Deklaracje.Deklaracja; konkretne typy żyją w podprzestrzeniach /// Soneta.Deklaracje.{ZUS,PIT,PFRON,PPK}.*. /// /// /// Rozróżnienie kluczowe. Naliczenie/utworzenie większości deklaracji (J1–J5) to operacja /// lokalna (zapis wiersza), ale wymaga Context i — dla ZUS — obiektu KEDU (kontener /// dokumentów ZUS), którego nie da się sensownie zbudować bez środowiska modułu Deklaracje. /// E-wysyłka (KEDU/PUE/SODiR/MF) jest sieciowa/plikowa. Dlatego testy J1–J5 dokumentują /// KONTRAKT typów/workerów kompilowalnie (przez odwołania do typów typeof(...), /// ctory, metody) i są oznaczone [Ignore] z powodem. Realnie wykonujemy J6 (bilanse otwarcia /// PIT — czyste API biznesowe na pracowniku) oraz próbę naliczenia PIT-11. /// /// /// Operujemy wyłącznie na publicznym kontrakcie platformy, na bazie Demo (GoldStandard), /// z automatycznym rollbackiem po teście. /// /// [TestFixture] public class RozdzialJ_DeklaracjeTest : PracownikTestBase { /// Skrót do modułu Deklaracje bieżącej sesji operacyjnej. private DeklaracjeModule Deklaracje => Session.GetDeklaracje(); // ============================== J1 — Zgłoszenia ZUS (ZUA/ZZA, ZCNA, ZWUA) ============================== [Test] [Description("J1: zgłoszenia ZUS to wiersze deklaracji w Soneta.Deklaracje.ZUS — ZUA (społeczne+zdrowotne), " + "ZZA (zdrowotne), ZCNA (rodzina), ZWUA (wyrejestrowanie). Konkretne typy mają ctor " + "(Pracownik, KEDU): new ZUA(pracownik, kedu). Workerem zbiorczym jest " + "ZarejestrujPracownikówWorker (zagnieżdżone .Rejestracja/.Rodzina/.Wyrejestrowanie/.ZgloszenieUmow), " + "Params budowane z Context (ctor (Context)) + pole Kedu. Tu dokumentujemy KONTRAKT typów; " + "samo utworzenie wymaga Context + KEDU.")] [Ignore("wymaga Context/KEDU / e-wysyłka sieciowa — dokumentowany kontrakt typów ZUS")] public void J1_ZgloszeniaZUS_ZUA_ZZA_ZCNA_ZWUA_Kontrakt() { // Kontrakt typów zgłoszeniowych ZUS — odwołania kompilowalne (zweryfikowane z DLL). typeof(Soneta.Deklaracje.ZUS.ZUA).Should().NotBeNull("ZUA — zgłoszenie społeczne+zdrowotne"); typeof(Soneta.Deklaracje.ZUS.ZZA).Should().NotBeNull("ZZA — zgłoszenie tylko zdrowotne"); typeof(Soneta.Deklaracje.ZUS.ZCNA).Should().NotBeNull("ZCNA — zgłoszenie członków rodziny"); typeof(Soneta.Deklaracje.ZUS.ZWUA).Should().NotBeNull("ZWUA — wyrejestrowanie"); // Worker zbiorczy + jego klasy zagnieżdżone (akcje menu „Deklaracje ZUS/Przygotuj …"). typeof(Soneta.Deklaracje.ZUS.ZarejestrujPracownikówWorker.Rejestracja).Should().NotBeNull(); typeof(Soneta.Deklaracje.ZUS.ZarejestrujPracownikówWorker.Rodzina).Should().NotBeNull(); typeof(Soneta.Deklaracje.ZUS.ZarejestrujPracownikówWorker.Wyrejestrowanie).Should().NotBeNull(); // Params zgłoszeniowe mają ctor (Context); KEDU jest wymaganym kontenerem docelowym. typeof(Soneta.Deklaracje.ZUS.ZarejestrujBaseWorker.ParamsKor) .GetConstructor(new[] { typeof(Context) }) .Should().NotBeNull("ParamsKor budujemy z Context"); typeof(Soneta.Deklaracje.ZUS.KEDU) .GetConstructor(new[] { typeof(Session) }) .Should().NotBeNull("KEDU ma ctor (Session), ale realne złożenie wymaga modułu Deklaracje"); } // ============================== J2 — Deklaracje rozliczeniowe ZUS (DRA, RIA, IMIR/RMUA) ============================== [Test] [Description("J2: rozliczeniowe ZUS — DRA (deklaracja rozliczeniowa, ctor (KEDU)), RIA (raport po ustaniu, " + "ctor (Pracownik, KEDU)), RMUA (informacja miesięczna dla ubezpieczonego = IMIR, ctor " + "(Pracownik, RMUA.TypOkresuDeklaracji)). Naliczanie seryjne: NaliczanieSeryjneRIAWorker / " + "NaliczanieSeryjneRMUAWorker (ctor bezparametrowy + Pracownicy/Pars + metoda NaliczRMUA(Context)). " + "Pojedynczą deklarację przelicza DeklaracjaWorker.Przelicz() (DataType Deklaracja). " + "KEDU + Context wymagane — dokumentujemy KONTRAKT.")] [Ignore("wymaga Context/KEDU / e-wysyłka sieciowa — dokumentowany kontrakt rozliczeń ZUS")] public void J2_RozliczeniaZUS_DRA_RIA_IMIR_Kontrakt() { // DRA wiąże się z KEDU (ctor (KEDU)), RIA z pracownikiem i KEDU. typeof(Soneta.Deklaracje.ZUS.DRA).GetConstructor(new[] { typeof(Soneta.Deklaracje.ZUS.KEDU) }) .Should().NotBeNull("DRA(KEDU)"); typeof(Soneta.Deklaracje.ZUS.RIA) .GetConstructor(new[] { typeof(Prac), typeof(Soneta.Deklaracje.ZUS.KEDU) }) .Should().NotBeNull("RIA(Pracownik, KEDU)"); // IMIR w CLR nazywa się RMUA (ctor (Pracownik, RMUA.TypOkresuDeklaracji)). typeof(Soneta.Deklaracje.ZUS.RMUA).Should().NotBeNull("RMUA = informacja miesięczna (IMIR)"); typeof(Soneta.Deklaracje.ZUS.RMUA.TypOkresuDeklaracji).IsEnum .Should().BeTrue("typ okresu deklaracji RMUA jest enumem"); // Naliczanie seryjne RIA/RMUA — ctor bezparametrowy + Pracownicy/Pars (Context w props). typeof(Soneta.Deklaracje.ZUS.NaliczanieSeryjneRIAWorker).GetConstructor(Type.EmptyTypes) .Should().NotBeNull(); typeof(Soneta.Deklaracje.ZUS.NaliczanieSeryjneRMUAWorker).GetMethod("NaliczRMUA") .Should().NotBeNull("NaliczRMUA(Context) — metoda akcji naliczania IMIR"); // Przeliczenie istniejącego wiersza dowolnej deklaracji. typeof(DeklaracjaWorker).GetMethod("Przelicz").Should().NotBeNull("DeklaracjaWorker.Przelicz()"); } // ============================== J3 — Deklaracje PIT (PIT-11, 4R, 8AR, R, IFT) ============================== [Test] [Description("J3: imienne PIT (PIT-11, PIT-R, IFT-1/IFT-1R, PIT-8C) nalicza seryjnie zagnieżdżony " + "Soneta.Deklaracje.PIT.NaliczanieSeryjne.* (PIT_11Worker ma ctor (Session); Params ctor (Context)). " + "PIT-4R/PIT-8AR (PIT4/PIT8A) są zbiorcze na poziomie podmiotu/US (ctory nonpublic — tworzone " + "workerami zbiorczymi). Tu dokumentujemy KONTRAKT typów i workerów. Realne naliczenie PIT-11 " + "próbujemy w J3b.")] [Ignore("wymaga Context / dane źródłowe (wypłaty + BO PIT) — dokumentowany kontrakt PIT")] public void J3_DeklaracjePIT_Kontrakt() { // Typy deklaracji PIT (wiersze tabeli Deklaracje). typeof(Soneta.Deklaracje.PIT.PIT11).Should().NotBeNull("PIT-11"); typeof(Soneta.Deklaracje.PIT.PIT4).Should().NotBeNull("PIT-4R (zaliczki)"); typeof(Soneta.Deklaracje.PIT.PIT8A).Should().NotBeNull("PIT-8AR (zryczałtowany)"); typeof(Soneta.Deklaracje.PIT.PITR).Should().NotBeNull("PIT-R"); typeof(Soneta.Deklaracje.PIT.IFT1).Should().NotBeNull("IFT-1/IFT-1R"); // Workery naliczania seryjnego PIT (zagnieżdżone w NaliczanieSeryjne). typeof(Soneta.Deklaracje.PIT.NaliczanieSeryjne.PIT_11Worker) .GetConstructor(new[] { typeof(Session) }) .Should().NotBeNull("PIT_11Worker(Session)"); typeof(Soneta.Deklaracje.PIT.NaliczanieSeryjne.PIT_RWorker).Should().NotBeNull(); typeof(Soneta.Deklaracje.PIT.NaliczanieSeryjne.IFT_1Worker).Should().NotBeNull(); typeof(Soneta.Deklaracje.PIT.NaliczanieSeryjne.IFT_1RWorker).Should().NotBeNull(); typeof(Soneta.Deklaracje.PIT.NaliczanieSeryjne.PIT_8CWorker).Should().NotBeNull(); // Params PIT mają ctor (Context). typeof(Soneta.Deklaracje.PIT.NaliczanieSeryjne.PIT_11Worker.Params) .GetConstructor(new[] { typeof(Context) }) .Should().NotBeNull("PIT_11Worker.Params(Context)"); } [Test] [Description("J3b: próba realnego naliczenia PIT-11 dla pracownika Demo workerem " + "NaliczanieSeryjne.PIT_11Worker(Session) { Pracownicy = [...] }, ustawiając Pars.Okres (rok) " + "i Pars.Data, a następnie wywołując Nalicz_PIT_11(). Worker wymaga środowiska Context/danych " + "źródłowych — w razie wyjątku oznaczamy [Ignore].")] [Ignore("PIT_11Worker wymaga Context/KEDU oraz danych źródłowych (naliczone wypłaty + BO PIT); " + "naliczenie w izolacji testu rzuca — dokumentowany kontrakt wywołania")] public void J3b_NaliczeniePIT11_ProbaRealna() { var pracownik = Pracownik(Pracownik_.Andrzejewski); pracownik.Should().NotBeNull(); var worker = new Soneta.Deklaracje.PIT.NaliczanieSeryjne.PIT_11Worker(Session) { Pracownicy = new[] { pracownik }, }; worker.Pars.Okres = FromTo.Year(2025); // rok podatkowy worker.Pars.Data = Date.Today; worker.Nalicz_PIT_11(); // tworzy wiersze PIT11 w tabeli Deklaracje SaveDispose(); } // ============================== J4 — Deklaracje PFRON (Wn-D, INF-2, DEK-R, INF-D-P) ============================== [Test] [Description("J4: PFRON to wiersze deklaracji w Soneta.Deklaracje.PFRON — WN_D (Wn-D), INF_2 (informacja " + "roczna), DEK_R (deklaracja roczna wpłat), INF_D_P (załącznik o pracowniku niepełnosprawnym). " + "PFRON nie ma seryjnego naliczania na Pracownicy — deklarację tworzy się w module Deklaracje, " + "a przelicza DeklaracjaWorker.Przelicz() (DataType Deklaracja). Dane źródłowe pochodzą z " + "PracHistoria.PFRON (A13). Tworzenie/edycja wymaga Context — dokumentujemy KONTRAKT.")] [Ignore("wymaga Context / e-wysyłka SODiR — dokumentowany kontrakt typów PFRON")] public void J4_DeklaracjePFRON_Kontrakt() { typeof(Soneta.Deklaracje.PFRON.WN_D).Should().NotBeNull("Wn-D — wniosek o dofinansowanie"); typeof(Soneta.Deklaracje.PFRON.INF_2).Should().NotBeNull("INF-2 — informacja roczna"); typeof(Soneta.Deklaracje.PFRON.DEK_R).Should().NotBeNull("DEK-R — deklaracja roczna wpłat"); typeof(Soneta.Deklaracje.PFRON.INF_D_P).Should().NotBeNull("INF-D-P — załącznik o pracowniku"); // Wszystkie PFRON dziedziczą po Deklaracja, więc przelicza je wspólny DeklaracjaWorker. typeof(Soneta.Deklaracje.PFRON.WN_D).IsSubclassOf(typeof(Deklaracja)) .Should().BeTrue("PFRON to wiersze tabeli Deklaracje"); typeof(DeklaracjaWorker).GetMethod("Przelicz").Should().NotBeNull(); } // ============================== J5 — Operacje PPK ============================== [Test] [Description("J5: dokumenty PPK to wiersze deklaracji w Soneta.Deklaracje.PPK (RejestracjaUczestnikaPPK, " + "DeklaracjaUczestnikaPPK, ZakończenieZatrudnieniaUczestnikaPPK, RozliczenieSkładekPPK, …). " + "Operacje zbiorcze na Pracownicy realizuje DeklaracjePPKPracownikówWorker (zagnieżdżone " + ".Rejestracja/.Rezygnacja/.Wznowienie/.ZakończenieZatrudnienia/.ZmianaDanychIdentyfikacyjnych); " + "wspólny Params = DeklaracjePPKBaseWorker.Params (ctor (Context), pole DokumentPPK). " + "Kwalifikacja/auto-zapis to workery na pracowniku (PPKWorker/AutoZapisPPKWorker, ctor (Context)). " + "Dokumentujemy KONTRAKT — operacje wymagają Context i zwykle DokumentyPracodawcyPPK.")] [Ignore("wymaga Context / DokumentyPracodawcyPPK — dokumentowany kontrakt operacji PPK")] public void J5_OperacjePPK_Kontrakt() { // Typy dokumentów PPK. typeof(Soneta.Deklaracje.PPK.RejestracjaUczestnikaPPK).Should().NotBeNull(); // Workery zbiorcze operacji PPK (zagnieżdżone w DeklaracjePPKPracownikówWorker). typeof(Soneta.Deklaracje.PPK.DeklaracjePPKPracownikówWorker.Rejestracja).Should().NotBeNull(); typeof(Soneta.Deklaracje.PPK.DeklaracjePPKPracownikówWorker.Rezygnacja).Should().NotBeNull(); typeof(Soneta.Deklaracje.PPK.DeklaracjePPKPracownikówWorker.Wznowienie).Should().NotBeNull(); typeof(Soneta.Deklaracje.PPK.DeklaracjePPKPracownikówWorker.ZakończenieZatrudnienia).Should().NotBeNull(); typeof(Soneta.Deklaracje.PPK.DeklaracjePPKPracownikówWorker.ZmianaDanychIdentyfikacyjnych).Should().NotBeNull(); // Wspólny Params ma ctor (Context). typeof(Soneta.Deklaracje.PPK.DeklaracjePPKBaseWorker.Params) .GetConstructor(new[] { typeof(Context) }) .Should().NotBeNull("DeklaracjePPKBaseWorker.Params(Context)"); } // ============================== J6 — Bilanse otwarcia PIT (REALNIE TESTOWALNE) ============================== [Test] [Description("J6: bilans otwarcia PIT to kolekcja na pracowniku (pracownik.BilansyOtwarciaPIT, " + "SubTable). Tworzymy czystym API biznesowym (BEZ Context/KEDU): " + "Session.AddRow(new BilansOtwarciaPIT_29(pracownik)) w trybie edycji; ustawiamy Data oraz kwoty " + "(PrzychodUlgaEtat, Spoleczne). UWAGA: bazowy BilansOtwarciaPIT jest ABSTRAKCYJNY — instancjonujemy " + "konkretną wersję BilansOtwarciaPIT_29 (Wersja=PIT11_29) lub BilansOtwarciaPIT_11 (PIT11_11), " + "ctor (Pracownik); brak ctora bezparametrowego, Pracownik read-only. Odczyt przez " + "pracownik.BilansyOtwarciaPIT.")] public void J6_BilansOtwarciaPIT_TworzenieIOdczyt() { var pracownik = Pracownik(Pracownik_.Andrzejewski); pracownik.Should().NotBeNull(); // Stan początkowy kolekcji bilansów otwarcia PIT. int przed = pracownik.BilansyOtwarciaPIT.Cast().Count(); var data = new Date(2026, 1, 1); Guid guidBO = Guid.Empty; // Tworzenie danych operacyjnych MUSI być w trybie edycji (InTransaction), // inaczej AddRow rzuca CannotEditException. InTransaction(() => { // Bazowy BilansOtwarciaPIT jest abstrakcyjny — tworzymy konkretną wersję (_29 => PIT11_29). BilansOtwarciaPIT bo = Session.AddRow(new BilansOtwarciaPIT_29(pracownik)); bo.Data = data; bo.PrzychodUlgaEtat = 12000m; bo.Spoleczne = 1645.20m; guidBO = bo.Guid; }); SaveDispose(); // utrwalenie (rollback po teście i tak wycofa) // Odczyt: bilans jest dopięty do pracownika i ma ustawione wartości. var boWczytany = Get(guidBO); boWczytany.Should().NotBeNull("bilans otwarcia PIT został zapisany"); boWczytany.Pracownik.Guid.Should().Be(pracownik.Guid, "bilans jest powiązany z pracownikiem"); boWczytany.Data.Should().Be(data); boWczytany.PrzychodUlgaEtat.Should().Be(12000m); boWczytany.Spoleczne.Should().Be(1645.20m); boWczytany.Wersja.Should().Be(WersjaBilansuOtwarciaPIT.PIT11_29, "wersja ustawiana w ctor"); // Odczyt przez kolekcję pracownika — bilans jest widoczny. var pracownik2 = Pracownik(Pracownik_.Andrzejewski); var bilanse = pracownik2.BilansyOtwarciaPIT.Cast().ToList(); bilanse.Should().HaveCount(przed + 1, "doszedł jeden bilans otwarcia PIT"); bilanse.Should().Contain(b => b.Guid == guidBO); } [Test] [Description("J6b: pozostałe kolekcje wdrożeniowe ERP-7 na pracowniku — pracownik.WynagrodzeniaERP7 " + "(SubTable) i pracownik.NieobecnosciERP7 " + "(SubTable). Dokumentujemy KONTRAKT (kolekcje istnieją i są " + "iterowalne czystym API, bez Context); sam druk Z-3/ERP-7 to generowanie w module Deklaracje.")] public void J6b_KolekcjeERP7_Odczyt() { var pracownik = Pracownik(Pracownik_.Andrzejewski); pracownik.Should().NotBeNull(); // Kolekcje istnieją i są iterowalne (na Demo zwykle puste — sprawdzamy sam kontrakt). System.Action odczytWynagrodzen = () => pracownik.WynagrodzeniaERP7.Cast().ToList(); System.Action odczytNieobecnosci = () => pracownik.NieobecnosciERP7.Cast().ToList(); odczytWynagrodzen.Should().NotThrow("kolekcja WynagrodzeniaERP7 jest dostępna czystym API"); odczytNieobecnosci.Should().NotThrow("kolekcja NieobecnosciERP7 jest dostępna czystym API"); } }