using System.Linq;
using AwesomeAssertions;
using NUnit.Framework;
using Soneta.Business;
using Soneta.Handel;
using Soneta.Types;
namespace Soneta.Skills.Test.Handel.DokumentyHandlowe;
///
/// Rozdział 7 — Cechy (Features) na dokumencie handlowym (wzorce W40–W42).
///
/// Cechy () to definiowalne informacje przypisane do Row —
/// tu: do dokumentu () i pozycji ().
/// Cecha jest adresowana po nazwie definicji (FeatureDefinition), a samo jej istnienie
/// zależy od konfiguracji wdrożenia — nie jest gwarantowane w bazie Demo.
///
///
/// Z tego powodu testy w tym rozdziale celują w bezpieczną ścieżkę: dostępność kolekcji
/// Features. Jednocześnie dokumentują kontraktowe rzucanie wyjątku przy odwołaniu do
/// cechy bez FeatureSetDefinition: zarówno Features.Exists(nazwa), jak i warunek
/// serwerowy po string-path "Features.Nazwa" (FieldCondition) dla NIEZDEFINIOWANEJ
/// cechy rzucają — NIE zwracają false ani pustego zbioru.
/// Testy zapisu wartości cech (W41) oraz filtrowania zwracającego rekordy (W42) są pominięte,
/// bo wymagałyby wcześniej utworzonej definicji cechy, której Demo nie gwarantuje.
///
///
[TestFixture]
public class Rozdzial07_CechyTest : DokumentHandlowyTestBase
{
// Nazwa cechy gwarantowanie niezdefiniowana w Demo — używana do testów bezpiecznej ścieżki.
// (Losowy, mało prawdopodobny identyfikator, by uniknąć kolizji z realną definicją wdrożenia.)
private const string NieistniejacaCecha = "SkillTestCechaXyz";
// ---------------------------------------------------------------------------------------------
// W41 — Odczyt i zapis cech (Features)
// ---------------------------------------------------------------------------------------------
[Test]
[Description("W41: property Features dokumentu jest dostępna (nie-null) zaraz po utworzeniu dokumentu.")]
public void Features_NaDokumencie_JestDostepna()
{
// Tworzymy minimalny dokument przychodowy (PW) na magazynie Firma — bez kontrahenta.
var dok = UtworzDokument(Definicje.PrzyjecieWewnetrzne, magazyn: Magazyn(Magazyn_.Firma));
// Kolekcja Features istnieje zawsze, niezależnie od tego, czy zdefiniowano jakiekolwiek cechy.
dok.Features.Should().NotBeNull();
// Definicje cech to obiekt FeatureDefinitions (może być pusty, ale dostępny).
dok.Features.Definitions.Should().NotBeNull();
// Features.Row wskazuje z powrotem na dokument-właściciela.
dok.Features.Row.Should().BeSameAs(dok);
}
[Test]
[Description("W41: property Features pozycji dokumentu jest dostępna (nie-null) po dodaniu pozycji.")]
public void Features_NaPozycji_JestDostepna()
{
var dok = UtworzDokument(Definicje.PrzyjecieWewnetrzne, magazyn: Magazyn(Magazyn_.Firma));
// Pozycję dodajemy w transakcji edycyjnej (każde tworzenie/edycja Row tego wymaga).
PozycjaDokHandlowego poz = null;
InTransaction(() => poz = DodajPozycje(dok, Towar(Towar_.Bikini), ilosc: 1, cena: 5));
// Kolekcja Features pozycji jest dostępna analogicznie do dokumentu.
poz.Features.Should().NotBeNull();
poz.Features.Row.Should().BeSameAs(poz);
}
[Test]
[Description("W41: Features.Exists(nazwa) dla NIEZDEFINIOWANEJ cechy RZUCA ArgumentException " +
"(odwołanie do cechy bez FeatureSetDefinition nie jest bezpieczne — nie zwraca false).")]
public void Features_Exists_DlaNiezdefiniowanejCechy_RzucaArgumentException()
{
var dok = UtworzDokument(Definicje.PrzyjecieWewnetrzne, magazyn: Magazyn(Magazyn_.Firma));
// Kolekcja Features jest dostępna zawsze — niezależnie od konfiguracji cech.
dok.Features.Should().NotBeNull();
// UWAGA: Exists NIE jest bezpiecznym sprawdzeniem istnienia dla cechy, której nikt nie
// zdefiniował (brak FeatureSetDefinition). Odwołanie do takiej cechy rzuca ArgumentException
// ("nie znaleziono definicji cechy") — Exists NIE zwraca false dla nieznanej cechy.
Assert.Throws(() => dok.Features.Exists(NieistniejacaCecha));
}
// --- POMINIĘTE (W41 zapis): ustawienie wartości cechy ---
// Powód: zapis dok["Nazwa"] = wartość wymaga istniejącej definicji cechy (FeatureDefinition)
// zarejestrowanej dla tabeli DokHandlowe / PozycjeDokHan. Baza Demo nie gwarantuje żadnej
// takiej definicji, a tworzenie nowych definicji cech wykracza poza zakres tego rozdziału
// (i poza bezpieczną ścieżkę dla dodatku zewnętrznego). Odwołanie do niezdefiniowanej cechy
// rzuciłoby wyjątek, więc testu zapisu świadomie NIE piszemy.
// ---------------------------------------------------------------------------------------------
// W42 — Filtrowanie / wyszukiwanie po wartości cechy (serwerowo)
// ---------------------------------------------------------------------------------------------
[Test]
[Description("W42: warunek serwerowy FieldCondition.Equal po string-path 'Features.Nazwa' " +
"dla NIEZDEFINIOWANEJ cechy RZUCA ArgumentException przy aplikacji na indeksie dokumentów.")]
public void FiltrPoCesze_NaIndeksieDokumentow_DlaNiezdefiniowanejCechy_RzucaArgumentException()
{
// Cechy adresuje się STRING-PATHEM "Features.Nazwa" — Features.X nie jest typowaną property
// Row, więc nie da się jej użyć w wyrażeniu LINQ. Warunek budujemy jako FieldCondition.
var warunek = new FieldCondition.Equal($"Features.{NieistniejacaCecha}", "dowolna");
// Filtr serwerowy po cesze BEZ FeatureSetDefinition nie zwraca pustego zbioru — rzuca
// ArgumentException ("nie znaleziono definicji cechy") już przy budowaniu/aplikacji zapytania.
// Demo nie gwarantuje żadnej zdefiniowanej cechy, więc to zachowanie jest deterministyczne.
Assert.Throws(() =>
Handel.DokHandlowe.WgDaty[warunek].Cast().ToArray());
}
[Test]
[Description("W42: złożony warunek RowCondition.And/FieldCondition po NIEZDEFINIOWANEJ cesze " +
"RZUCA ArgumentException przy wykonaniu serwerowym (brak FeatureSetDefinition).")]
public void FiltrPoCesze_WarunekZlozony_DlaNiezdefiniowanejCechy_RzucaArgumentException()
{
// Składanie warunków serwerowych: cecha-bool ORAZ cecha-data >= dziś.
// Wartości podajemy w typie zgodnym z typem cechy (bool dla Bool, Date dla Date) — zgodnie
// z W42. Sam warunek się składa, ale wykonanie na indeksie wymaga definicji cechy.
var warunek = new RowCondition.And(
new FieldCondition.Equal($"Features.{NieistniejacaCecha}", true),
new FieldCondition.GreaterEqual($"Features.{NieistniejacaCecha}Data", Date.Today));
// Brak FeatureSetDefinition dla cechy → ArgumentException przy aplikacji warunku na indeksie
// (nie pusty zbiór). Deterministyczne w Demo, które nie gwarantuje żadnej zdefiniowanej cechy.
Assert.Throws(() =>
Handel.DokHandlowe.WgDaty[warunek].Cast().ToArray());
}
[Test]
[Description("W42: filtr po cesze na kolekcji SubTable pozycji dokumentu (dok.Pozycje[condition]) " +
"wykonuje się bez błędu i dla nieistniejącej cechy zwraca pusty zbiór.")]
public void FiltrPoCesze_NaPozycjachDokumentu_WykonujeSieBezBledu()
{
// Tworzymy dokument z jedną pozycją — sam dokument istnieje, ale żadna pozycja nie ma
// ustawionej (ani zdefiniowanej) testowej cechy.
var dok = UtworzDokument(Definicje.PrzyjecieWewnetrzne, magazyn: Magazyn(Magazyn_.Firma));
InTransaction(() => DodajPozycje(dok, Towar(Towar_.Bikini), ilosc: 1, cena: 5));
// Filtr na kolekcji SubTable (dok.Pozycje[condition]) również wykonuje się serwerowo.
var warunek = new FieldCondition.Equal($"Features.{NieistniejacaCecha}", "S-2026-001");
var pozycje = dok.Pozycje[warunek].Cast().ToArray();
// Brak pozycji o takiej cesze — zbiór pusty, bez wyjątku.
pozycje.Should().BeEmpty();
}
// --- POMINIĘTE (W42 z trafieniami): filtr po cesze zwracający rekordy ---
// Powód: aby warunek FieldCondition.Equal("Features.Nazwa", wartość) zwrócił jakikolwiek
// dokument/pozycję, musi istnieć definicja cechy ORAZ zapisana wartość tej cechy na rekordzie.
// Oba elementy wymagałyby zdefiniowania własnej cechy (FeatureDefinition) i zapisu jej wartości,
// czego Demo nie gwarantuje. Testujemy więc jedynie, że konstrukcja i wykonanie warunku
// serwerowego są poprawne (powyżej), nie zaś zawartość zwróconego zbioru.
// --- POMINIĘTE (W40): przenoszenie cech z partii / dokumentu nadrzędnego ---
// Powód: przenoszenie cech to mechanizm KONFIGURACYJNY (flagi DefDokHandlowego.KopiujCechyDostawy,
// KopiujCechyDokumentu/KopiujCechyPozycji na definicji relacji), a faktyczne skopiowanie cechy
// wymaga: (1) istniejącej definicji cechy zarejestrowanej dla pozycji/partii, (2) zapisanego
// przyjęcia z ustawioną cechą i (3) rozchodu ze wskazaniem partii. Bez gwarantowanej definicji
// cechy w Demo nie da się zweryfikować przeniesienia wartości bezpieczną ścieżką, więc W40
// pomijamy w testach (pozostaje udokumentowany w skillu jako konfiguracja, nie API).
}