Soneta.Skills.Test

This commit is contained in:
Marcin Wojas
2026-06-06 22:33:15 +02:00
parent d42ca3e825
commit fb2f2695a3
38 changed files with 10644 additions and 0 deletions
@@ -0,0 +1,224 @@
using System;
using System.Collections;
using System.Linq;
using AwesomeAssertions;
using NUnit.Framework;
using Soneta.Kasa; // EksportPrzelewowWorker, EksportPrzelewowParams, PrzelewBase, PaczkaPrzelewow, RachunekBankowyFirmy, RozrachunekIdx, ...
using Soneta.Place; // ListaPlac (+ ListaPlac.PrzygotujPrzelewyWorker)
using Prac = Soneta.Kadry.Pracownik;
namespace Soneta.Skills.Test.KadryPlace.Pracownik;
/// <summary>
/// Rozdział I (część rozliczeniowa) — „Przelewy wynagrodzeń, eksport do banku, rozliczenia/faktury”
/// (receptury I4, I5, I6).
/// <para>
/// Testy są <b>wykonywalną dokumentacją</b> publicznego kontraktu mechanizmu „z wypłaty do przelewu”
/// i rozliczeń pracownika. Operujemy wyłącznie na <b>publicznym kontrakcie</b> platformy Soneta
/// (jak dodatek programisty zewnętrznego), na bazie Demo (GoldStandard) z automatycznym rollbackiem.
/// </para>
/// <list type="bullet">
/// <item><b>I4</b> — przygotowanie przelewów wynagrodzeń workerem
/// <c>Soneta.Place.ListaPlac.PrzygotujPrzelewyWorker</c> (akcja <c>PrzygotujPrzelewy()</c>).
/// Testowalny jest <b>kontrakt</b> (istnienie workera i jego <c>Params</c> z polami
/// <c>Data</c>/<c>Paczka</c>/<c>ZRachunku</c>) oraz <b>odczyt</b> kolekcji rozliczeniowych pracownika
/// (<c>Przelewy</c>, <c>DokumentyPreliminarza</c>, <c>Rozrachunki</c>). Samo
/// <c>worker.PrzygotujPrzelewy()</c> wymaga skonfigurowanego modułu Kasa (definicja paczki, rachunek
/// firmy, rachunek pracownika), czego baza Demo nie gwarantuje → <c>[Ignore]</c>.</item>
/// <item><b>I5</b> — eksport przelewów do pliku bankowego workerem
/// <c>Soneta.Kasa.EksportPrzelewowWorker</c> (akcja <c>Eksport()</c>) sterowanym
/// <c>Soneta.Kasa.EksportPrzelewowParams</c>. Testowalne jest <b>istnienie publicznego API</b>
/// (konstrukcja workera i parametrów, pole <c>FileName</c>). Wywołanie <c>Eksport()</c> to operacja
/// plikowa/sieciowa → <c>[Ignore]</c>.</item>
/// <item><b>I6</b> — rozliczenia/faktura: odczyt kolekcji rozrachunkowych pracownika
/// (<c>Rozrachunki</c>, <c>DokumentyRozliczeniowe</c>, <c>DokumentyPreliminarza</c>) — asercja, że są
/// dostępne, iterowalne i zwracają typy zgodne z kontraktem. Wystawienie faktury (zbiorczej) z zapłaty
/// to domena handlowa (<c>DokumentHandlowy</c>), poza kontraktem pracownika → <c>[Ignore]</c>.</item>
/// </list>
/// </summary>
[TestFixture]
public class RozdzialIrest_PrzelewyTest : PracownikTestBase
{
// ===================================================================================
// I4 — Przygotowanie przelewów wynagrodzeń (kontrakt workera + odczyt kolekcji)
// ===================================================================================
[Test]
[Description("I4 (kontrakt): worker przygotowania przelewów z listy płac istnieje w publicznym API — " +
"Soneta.Place.ListaPlac.PrzygotujPrzelewyWorker z zagnieżdżonym typem Params. " +
"Asercja przez refleksję publicznego kontraktu: typ workera i Params istnieją, Params ma " +
"pola Data/Paczka/DefinicjaPaczki/ZRachunku, a worker ma metodę PrzygotujPrzelewy(). " +
"Faktyczne wywołanie PrzygotujPrzelewy() jest [Ignore] (osobny test) wymaga konfiguracji Kasa.")]
public void I4_PrzygotujPrzelewy_KontraktWorkera()
{
// Worker płacowy jest typem zagnieżdżonym w ListaPlac (assembly Soneta.KadryPlace, namespace Soneta.Place).
Type workerType = typeof(ListaPlac.PrzygotujPrzelewyWorker);
workerType.Should().NotBeNull("worker przygotowania przelewów istnieje w publicznym kontrakcie");
// Typ parametrów workera (zagnieżdżony Params).
Type paramsType = workerType.GetNestedType("Params");
paramsType.Should().NotBeNull("PrzygotujPrzelewyWorker udostępnia publiczny typ Params");
// Kluczowe pola/właściwości parametrów wg dokumentacji I4.
var skladowe = paramsType.GetMembers()
.Select(m => m.Name)
.ToList();
skladowe.Should().Contain("Data", "Params.Data — data dokumentów przelewu");
skladowe.Should().Contain("Paczka", "Params.Paczka — istniejąca paczka przelewów");
skladowe.Should().Contain("ZRachunku", "Params.ZRachunku — rachunek firmy obciążany przelewami");
// Akcja workera: PrzygotujPrzelewy().
workerType.GetMethod("PrzygotujPrzelewy")
.Should().NotBeNull("worker udostępnia akcję PrzygotujPrzelewy()");
// Dokument przelewu, który powstaje w wyniku akcji, to Soneta.Kasa.PrzelewBase (tabela Przelewy).
typeof(PrzelewBase).Should().NotBeNull("dokument przelewu to Soneta.Kasa.PrzelewBase");
}
[Test]
[Description("I4 (odczyt): kolekcje rozliczeniowe pracownika są dostępne i iterowalne — " +
"Pracownik.Przelewy (PrzelewBase), Pracownik.DokumentyPreliminarza (PreliminarzDokument), " +
"Pracownik.Rozrachunki (RozrachunekIdx). Asercja: iteracja nie rzuca, a elementy (jeśli są) " +
"mają typy zgodne z kontraktem. Bez wywołania PrzygotujPrzelewy — sam odczyt stanu.")]
public void I4_KolekcjeRozliczeniowePracownika_OdczytTypyZgodne()
{
var pracownik = Pracownik(Pracownik_.Andrzejewski);
pracownik.Should().NotBeNull();
// Przelewy — odczyt nie rzuca; elementy (jeśli są) to PrzelewBase.
Action czytajPrzelewy = () => IterujISprawdzTyp<PrzelewBase>(pracownik.Przelewy);
czytajPrzelewy.Should().NotThrow("odczyt kolekcji Pracownik.Przelewy jest bezpieczny");
// Dokumenty preliminarza — elementy to PreliminarzDokument.
Action czytajPreliminarz = () => IterujISprawdzTyp<PreliminarzDokument>(pracownik.DokumentyPreliminarza);
czytajPreliminarz.Should().NotThrow("odczyt kolekcji Pracownik.DokumentyPreliminarza jest bezpieczny");
// Rozrachunki — elementy to RozrachunekIdx.
Action czytajRozrachunki = () => IterujISprawdzTyp<RozrachunekIdx>(pracownik.Rozrachunki);
czytajRozrachunki.Should().NotThrow("odczyt kolekcji Pracownik.Rozrachunki jest bezpieczny");
}
[Test]
[Ignore("I4: faktyczne wywołanie ListaPlac.PrzygotujPrzelewyWorker.PrzygotujPrzelewy() wymaga " +
"skonfigurowanego modułu Kasa (definicja paczki przelewów DefinicjaPaczkiPrzelewu, rachunek firmy " +
"RachunekBankowyFirmy oraz rachunek odbiorcy Pracownik.Rachunki). Baza Demo nie gwarantuje tej " +
"konfiguracji, więc generowanie dokumentów PrzelewBase jest niepewne. Test I4_PrzygotujPrzelewy_KontraktWorkera " +
"pokrywa publiczny kontrakt; samo przygotowanie przelewów dokumentujemy bez uruchamiania.")]
[Description("I4 (wykonanie — pominięte): naliczenie wypłaty etatowej (jak H1/I1b) → ListaPlac z Wyplata.ListaPlac → " +
"new ListaPlac.PrzygotujPrzelewyWorker { Pars = new Params { Data = Date.Today, ... } }.PrzygotujPrzelewy() → " +
"session.Save(). Powstają dokumenty Soneta.Kasa.PrzelewBase w paczce PaczkaPrzelewow.")]
public void I4_PrzygotujPrzelewy_Wykonanie()
{
// Pominięte — patrz powód w [Ignore]. Operacja zapisująca zależna od konfiguracji modułu Kasa.
}
// ===================================================================================
// I5 — Eksport przelewów do pliku bankowego (istnienie API; eksport pliku → Ignore)
// ===================================================================================
[Test]
[Description("I5 (kontrakt API): eksport przelewów to worker Soneta.Kasa.EksportPrzelewowWorker " +
"sterowany Soneta.Kasa.EksportPrzelewowParams. UWAGA: EksportPrzelewowParams NIE ma " +
"konstruktora bezparametrowego — wymaga (Context, RachunekBankowyFirmy, PrzelewBase[]), a sam " +
"konstruktor RZUCA ApplicationException, gdy nie wskazano rachunku firmy (walidacja w ctorze). " +
"Dlatego kontrakt weryfikujemy REFLEKSJĄ (bez instancjonowania): istnienie typów, sygnatura " +
"konstruktora parametrów, publiczne pole FileName, worker + property Params i metoda Eksport().")]
public void I5_EksportPrzelewow_KontraktApi()
{
// Typ parametrów eksportu istnieje w publicznym kontrakcie.
Type paramsType = typeof(EksportPrzelewowParams);
paramsType.Should().NotBeNull("EksportPrzelewowParams istnieje w publicznym kontrakcie");
// Konstruktor parametrów wymaga (Context, RachunekBankowyFirmy, PrzelewBase[]) — sygnatura wg kontraktu.
// (NIE wołamy go: ctor waliduje rachunek i rzuca ApplicationException przy braku konfiguracji.)
var ctor = paramsType.GetConstructor(new[]
{
typeof(Soneta.Business.Context), typeof(RachunekBankowyFirmy), typeof(PrzelewBase[]),
});
ctor.Should().NotBeNull(
"EksportPrzelewowParams wymaga konstruktora (Context, RachunekBankowyFirmy, PrzelewBase[])");
// Publiczne pole ścieżki pliku wyjściowego.
paramsType.GetProperty("FileName")
.Should().NotBeNull("Params.FileName — ścieżka pliku wyjściowego (operacja na dysku)");
// Worker eksportu i jego property Params (sterowanie parametrami).
Type workerType = typeof(EksportPrzelewowWorker);
workerType.Should().NotBeNull("EksportPrzelewowWorker istnieje w publicznym kontrakcie");
workerType.GetProperty("Params")
.Should().NotBeNull("worker przyjmuje parametry przez właściwość Params");
// Akcja eksportu istnieje w kontrakcie (ale jej NIE wołamy — patrz I5_EksportPrzelewow_Eksport).
workerType.GetMethod("Eksport")
.Should().NotBeNull("worker udostępnia akcję Eksport() — w teście jednostkowym nie wywoływaną");
}
[Test]
[Ignore("I5: EksportPrzelewowWorker.Eksport() zapisuje fizyczny plik bankowy na dysk (wg Params.FileName) " +
"i zależy od formatu/sterownika eksportu danego banku; wysyłka online to dodatkowo operacja sieciowa. " +
"To wejście/wyjście do systemu zewnętrznego — poza zakresem testu jednostkowego. Kontrakt API " +
"pokrywa test I5_EksportPrzelewow_KontraktApi (bez wywołania Eksport()).")]
[Description("I5 (wykonanie — pominięte): worker.Eksport() — zapis pliku przelewów wg FileName; po eksporcie " +
"PrzelewBase.Exported = true blokuje dalszą edycję.")]
public void I5_EksportPrzelewow_Eksport()
{
// Pominięte — patrz powód w [Ignore]. Operacja plikowa/sieciowa.
}
// ===================================================================================
// I6 — Rozliczenia / faktura (odczyt rozrachunków; wystawienie faktury → Ignore)
// ===================================================================================
[Test]
[Description("I6 (odczyt): kolekcje rozliczeniowe pracownika są dostępne i iterowalne, a elementy mają " +
"typy zgodne z kontraktem — Pracownik.Rozrachunki (RozrachunekIdx), " +
"Pracownik.DokumentyRozliczeniowe (DokRozliczBase), Pracownik.DokumentyPreliminarza " +
"(PreliminarzDokument). Asercja: iteracja nie rzuca; bez operacji zapisujących.")]
public void I6_Rozliczenia_OdczytStanu()
{
var pracownik = Pracownik(Pracownik_.Bednarek);
pracownik.Should().NotBeNull();
// Rozrachunki — indeksy rozrachunkowe podmiotu (RozrachunekIdx).
Action czytajRozrachunki = () => IterujISprawdzTyp<RozrachunekIdx>(pracownik.Rozrachunki);
czytajRozrachunki.Should().NotThrow("odczyt kolekcji Pracownik.Rozrachunki jest bezpieczny");
// Dokumenty rozliczeniowe — DokRozliczBase.
Action czytajRozliczeniowe = () => IterujISprawdzTyp<DokRozliczBase>(pracownik.DokumentyRozliczeniowe);
czytajRozliczeniowe.Should().NotThrow("odczyt kolekcji Pracownik.DokumentyRozliczeniowe jest bezpieczny");
// Dokumenty preliminarza — PreliminarzDokument.
Action czytajPreliminarz = () => IterujISprawdzTyp<PreliminarzDokument>(pracownik.DokumentyPreliminarza);
czytajPreliminarz.Should().NotThrow("odczyt kolekcji Pracownik.DokumentyPreliminarza jest bezpieczny");
}
[Test]
[Ignore("I6: „Wystaw fakturę (zbiorczą) z zapłaty” NIE istnieje w publicznym kontrakcie pracownika/płac — " +
"faktura to dokument handlowy (Soneta.Handel.DokumentHandlowy). Powiązanie zapłaty z fakturą realizują " +
"rozrachunki/rozliczenia (moduł Kasa), a operacje zapisujące (np. RozliczWgPrzelewowWyplataWorker) wymagają " +
"skonfigurowanego modułu Kasa/Handel, którego baza Demo nie gwarantuje. Wystawianie faktur należy do testów " +
"domeny handlowej (dokument-handlowy.md). Odczyt rozrachunków pokrywa test I6_Rozliczenia_OdczytStanu.")]
[Description("I6 (wykonanie — pominięte): wystawienie faktury zbiorczej z zapłat/rozliczeń (domena handlowa) " +
"oraz rozliczanie zapisujące przez workery rozliczeniowe Kasa.")]
public void I6_WystawienieFaktury_Rozliczenie()
{
// Pominięte — patrz powód w [Ignore]. Domena handlowa + konfiguracja Kasa/Handel.
}
// ===================================================================================
// Pomocniki lokalne
// ===================================================================================
/// <summary>
/// Iteruje kolekcję (np. <c>SubTable&lt;T&gt;</c> z kartoteki pracownika) i sprawdza, że każdy
/// element jest przypisywalny do oczekiwanego typu kontraktu. Sama iteracja po kolekcji
/// rozliczeniowej pracownika jest bezpieczna (zakres = jeden podmiot), więc nie skanujemy całej
/// tabeli operacyjnej (safe-code §6.3). Pusta kolekcja jest poprawna (brak danych w Demo).
/// </summary>
private static void IterujISprawdzTyp<T>(IEnumerable kolekcja)
{
kolekcja.Should().NotBeNull("kolekcja rozliczeniowa pracownika jest dostępna w kontrakcie");
foreach (var element in kolekcja)
element.Should().BeAssignableTo<T>($"elementy kolekcji są typu {typeof(T).Name} (zgodnie z kontraktem)");
}
}