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