using System;
using System.Linq;
using AwesomeAssertions;
using NUnit.Framework;
using Soneta.Handel;
using Soneta.Types;
namespace Soneta.Skills.Test.Handel.DokumentyHandlowe;
///
/// Rozdział 2 — „Wystawianie dokumentów” (wzorce W4–W11).
///
/// Testy pokazują tworzenie dokumentu handlowego od zera w różnych wariantach: faktura sprzedaży (FV),
/// faktura zakupu (FZ — numer obcy i daty), dokument magazynowy (PW/PZ), zamówienie odbiorcy (ZO),
/// dodawanie pozycji (towar/ilość/cena/rabat), dokument z usługą (MONTAZ — bez magazynu),
/// dokument w walucie obcej (W9) oraz odbiorca inny niż kontrahent (W11).
///
///
/// Reguły bazy Demo, których trzymają się testy:
///
/// Demo blokuje stan ujemny (StanUjemnyVerifier): rozchód (FV/WZ) wymaga wcześniej
/// zapisanego przyjęcia (PW/PZ) tego towaru. Obroty księgują się dopiero po Session.Save().
/// Po zapisie w środku testu sesja zamyka okno edycji — kolejna edycja rzuca wyjątek.
/// Dlatego wzorzec to: zapis przez SaveDispose() → odczyt na świeżej sesji po Guid.
///
/// Wszystko operuje wyłącznie na publicznym kontrakcie platformy (jak dodatek programisty zewnętrznego).
///
///
[TestFixture]
public class Rozdzial02_WystawianieTest : DokumentHandlowyTestBase
{
///
/// Pomocniczo: przyjmuje BIKINI na magazyn „F” dokumentem PW, zatwierdza je i zapisuje,
/// żeby zbudować stan magazynu pod późniejszy rozchód (FV/WZ). Dopiero ZATWIERDZONE i zapisane
/// przyjęcie księguje zasoby/obroty i odblokowuje rozchód na bazie Demo (kontrola stanu ujemnego).
/// Korzysta z bazowego helpera . Zwraca Guid PW.
///
private Guid PrzyjmijBikiniNaStan(double ilosc = 100, double cena = 25)
=> PrzyjmijNaStan(Towar_.Bikini, ilosc, cena);
// ============================== W4 — Faktura sprzedaży (FV) ==============================
[Test]
[Description("W4: FV krajowa od netto z pozycją BIKINI — po zapisie powstaje tabela VAT i wartość dokumentu.")]
public void FakturaSprzedazy_OdNetto_WyliczaSumeIVat()
{
// Najpierw przyjęcie na stan (zapisane) — inaczej rozchód FV zablokuje kontrola stanu ujemnego.
PrzyjmijBikiniNaStan();
Guid guidFv = Guid.Empty;
// Definicja FIRST (helper UtworzDokument), potem magazyn i kontrahent-nabywca.
var fv = UtworzDokument(
Definicje.FakturaSprzedazy,
kontrahent: Kontrahent(Kontrahent_.Abc),
magazyn: Magazyn(Magazyn_.Firma));
// FV NIE zatwierdzamy — zatwierdzenie FV w bazie testowej Demo rzuca NRE w ewidencji VAT.
// SumyVAT/Suma na świeżym dokumencie w pamięci bywają niprzeliczone — przeliczają się
// po zapisie. Dlatego zapisujemy FV w BUFORZE (bez zatwierdzania) i czytamy po Guid.
InTransaction(() =>
{
fv.Data = Date.Today; // data wystawienia
fv.DataOperacji = Date.Today; // faktyczna data sprzedaży
fv.LiczonaOd = SposobLiczeniaVAT.OdNetto; // ustaw przed pozycjami
DodajPozycje(fv, Towar(Towar_.Bikini), 2, 50); // 2 szt po 50
guidFv = fv.Guid;
});
SaveDispose();
var zapis = Get(guidFv);
zapis.Should().NotBeNull();
zapis.LiczonaOd.Should().Be(SposobLiczeniaVAT.OdNetto);
// SumyVAT i Suma są wyliczane z pozycji — wyliczone po zapisie (czytamy po Guid).
zapis.SumyVAT.Should().NotBeEmpty();
// Wartość netto jest dodatnia (kontrahent Abc ma rabat, więc netto może być < cena*ilość).
((double)zapis.Suma.Netto).Should().BeGreaterThan(0);
}
[Test]
[Description("W4: FV liczona od brutto — pole LiczonaOd przyjmuje wartość Brutto.")]
public void FakturaSprzedazy_OdBrutto_UstawiaLiczonaOdBrutto()
{
PrzyjmijBikiniNaStan();
var fv = UtworzDokument(
Definicje.FakturaSprzedazy,
kontrahent: Kontrahent(Kontrahent_.Abc),
magazyn: Magazyn(Magazyn_.Firma));
// Asercja na FV w BUFORZE (nie zatwierdzamy FV — zatwierdzenie rzuca NRE w ewidencji VAT).
InTransaction(() =>
{
// LiczonaOd ustawiamy PRZED pozycjami — zmiana po wprowadzeniu pozycji wymusza przeliczenie cen.
fv.LiczonaOd = SposobLiczeniaVAT.OdBrutto;
DodajPozycje(fv, Towar(Towar_.Bikini), 1, 50);
});
fv.LiczonaOd.Should().Be(SposobLiczeniaVAT.OdBrutto);
}
// ============================== W5 — Zakup od dostawcy (PZ) ==============================
[Test]
[Description("W5: zakup od dostawcy (PZ) z datą operacji (zakupu) różną od daty wystawienia — przyjęcie zewnętrzne, przychód.")]
public void FakturaZakupu_UstawiaNumerObcyIDatyZakupu()
{
// W bazie Demo „faktura zakupu" jako dokument handlowy nie istnieje — stronę zakupową
// reprezentuje przyjęcie zewnętrzne „PZ" (przychód, kontrahent-dostawca). PZ NIE wywołuje
// kontroli stanu ujemnego, więc nie potrzebuje wcześniejszego przyjęcia.
Guid guidPz = Guid.Empty;
var dataWystawienia = Date.Today;
var dataZakupu = Date.Today.AddDays(-2);
// PZ to dokument przychodowy — kontrahent jest dostawcą.
var pz = UtworzDokument(
Definicje.FakturaZakupu,
kontrahent: Kontrahent(Kontrahent_.Abc),
magazyn: Magazyn(Magazyn_.Firma));
InTransaction(() =>
{
pz.Data = dataWystawienia; // data wystawienia u nas
pz.DataOperacji = dataZakupu; // faktyczna data zakupu (decyduje o okresie magazynowym)
DodajPozycje(pz, Towar(Towar_.Bikini), 10, 30);
guidPz = pz.Guid;
});
// Bez zatwierdzania — sprawdzamy podstawowe pola dokumentu zakupowego (PZ).
SaveDispose();
var zapis = Get(guidPz);
zapis.Should().NotBeNull();
zapis.Definicja.Symbol.Should().Be("PZ");
zapis.Kontrahent.Kod.Should().Be(Kontrahent(Kontrahent_.Abc).Kod);
zapis.DataOperacji.Should().Be(dataZakupu);
zapis.Data.Should().Be(dataWystawienia);
// Data operacji (zakupu) różna od daty wystawienia — to dwa odrębne pola.
zapis.DataOperacji.Should().NotBe(zapis.Data);
}
[Test]
[Description("W5: zakup od dostawcy (PZ) z przyjęciem na magazyn księguje przychód — po zatwierdzeniu i Save powstają zasoby dokumentu.")]
public void FakturaZakupu_KsiegujePrzychod_TworzyZasoby()
{
Guid guidPz = Guid.Empty;
// PZ (przyjęcie zewnętrzne od dostawcy) to dokument przychodowy — kontrahent jest dostawcą.
var pz = UtworzDokument(
Definicje.FakturaZakupu,
kontrahent: Kontrahent(Kontrahent_.Abc),
magazyn: Magazyn(Magazyn_.Firma));
InTransaction(() =>
{
pz.Data = Date.Today;
pz.DataOperacji = Date.Today;
DodajPozycje(pz, Towar(Towar_.Bikini), 5, 30);
guidPz = pz.Guid;
});
// Zasoby dokumentu przychodowego księgują się DOPIERO po zatwierdzeniu + Save.
// Zatwierdzenie PZ (jak PW) jest bezpieczne — nie rzuca NRE (rzuca tylko zatwierdzenie FV).
InTransaction(() => pz.Stan = StanDokumentuHandlowego.Zatwierdzony);
SaveDispose();
var zapis = Get(guidPz);
// PZ (przyjęcie od dostawcy) jest dokumentem przychodowym → powstają zasoby magazynowe.
zapis.Zasoby.Cast