SKILL: Uporządkowanie skills domenowych - podział na mniejsze pliki i wspólna numeracja
This commit is contained in:
@@ -0,0 +1,333 @@
|
||||
# HANDEL08 — VAT, wartości i waluty
|
||||
|
||||
> Wspólne fakty o typie, podstawowe typy i szablon wzorca: [../handel.md](../handel.md).
|
||||
|
||||
Rozdział opisuje publiczny kontrakt dokumentu handlowego w zakresie tabeli VAT, podsumowań
|
||||
wartości, ręcznej korekty VAT, sposobu liczenia VAT oraz zmiany waluty dokumentu i cen. Cały kod
|
||||
jest zgodny z **C# 10** i operuje wyłącznie na **publicznych** typach i workerach platformy.
|
||||
|
||||
> **Wartości pieniężne** na pozycjach tabeli VAT i podsumowaniach mają dwie reprezentacje:
|
||||
> `BruttoNetto` — kwoty w walucie systemowej jako `decimal` (`Netto`, `VAT`, `Brutto`); `BruttoNettoCy`
|
||||
> — kwoty w walucie dokumentu jako `Currency` (`NettoCy`, `VATCy`, `BruttoCy`). Nie operuj na
|
||||
> niezaokrąglonych `decimal` — platforma weryfikuje zaokrąglenie (safe-code §10).
|
||||
|
||||
---
|
||||
|
||||
### HANDEL-W43 — Odczytanie tabeli VAT (`SumyVAT`)
|
||||
|
||||
**Cel:** odczytać rozbicie wartości dokumentu na stawki VAT (netto / VAT / brutto wg stawki) — np.
|
||||
do wydruku, eksportu lub kontroli sumy podatku.
|
||||
|
||||
**Warianty:**
|
||||
|
||||
| Wariant | Źródło | Uwaga |
|
||||
|---|---|---|
|
||||
| Tabela VAT dokumentu | `dok.SumyVAT` (`SubTable<SumaVAT>`) | po jednej pozycji na stawkę |
|
||||
| Kwoty w walucie systemowej | `suma.Suma` (`BruttoNetto`) | `Netto`/`VAT`/`Brutto` jako `decimal` |
|
||||
| Kwoty w walucie dokumentu | `suma.SumaCy` (`BruttoNettoCy`) | `NettoCy`/`VATCy`/`BruttoCy` jako `Currency` |
|
||||
| Procent / opis stawki | `suma.Stawka`, `suma.DefinicjaStawki` | `StawkaVat.Procent: Percent` |
|
||||
| Sumy z dokumentów nadrzędnych | `dok.NadrzędneSumyVAT` (`IList`) | scalone stawki nadrzędnych |
|
||||
|
||||
**Pola i typy:** `dok.SumyVAT: SubTable<SumaVAT>`. `SumaVAT` udostępnia: `DefinicjaStawki:
|
||||
DefinicjaStawkiVat`, `Stawka: StawkaVat` (`Stawka.Procent: Percent`), `Suma: BruttoNetto`
|
||||
(`Netto`, `VAT`, `Brutto` — `decimal`), `SumaCy: BruttoNettoCy` (`NettoCy`, `VATCy`, `BruttoCy` —
|
||||
`Currency`), `Dokument: DokumentHandlowy`.
|
||||
|
||||
**Snippet:**
|
||||
|
||||
```csharp
|
||||
var dok = session.GetHandel().DokHandlowe.WgDaty[...]; // lub po Guid
|
||||
|
||||
// Iteracja po tabeli VAT — jedna pozycja (SumaVAT) na każdą stawkę dokumentu:
|
||||
foreach (SumaVAT s in dok.SumyVAT)
|
||||
{
|
||||
Percent stawka = s.Stawka.Procent; // np. 23%
|
||||
decimal netto = s.Suma.Netto; // kwota netto w walucie systemowej
|
||||
decimal vat = s.Suma.VAT; // kwota podatku VAT
|
||||
decimal brutto = s.Suma.Brutto; // kwota brutto
|
||||
|
||||
// Kwoty w walucie dokumentu (Currency = wartość + symbol waluty):
|
||||
Currency vatCy = s.SumaCy.VATCy;
|
||||
|
||||
Console.WriteLine($"{stawka}: netto={netto} VAT={vat} brutto={brutto}");
|
||||
}
|
||||
|
||||
// Łączna kwota VAT dokumentu z tabeli VAT:
|
||||
decimal vatRazem = dok.SumyVAT.Sum(s => s.Suma.VAT);
|
||||
```
|
||||
|
||||
**Pułapki:**
|
||||
- `dok.SumyVAT` to `SubTable<SumaVAT>` — kolekcja serwerowa; iteruj po niej, nie materializuj do listy,
|
||||
jeśli wystarczy przebieg jednorazowy. Tabela VAT jest mała (kilka stawek), więc `.Sum(...)` jest
|
||||
akceptowalne.
|
||||
- Rozróżniaj `Suma` (`BruttoNetto`, `decimal` w walucie systemowej) od `SumaCy` (`BruttoNettoCy`,
|
||||
`Currency` w walucie dokumentu). Dla dokumentu walutowego do prezentacji używaj `SumaCy`.
|
||||
- `Stawka` to `StawkaVat` (typ stawki), `Procent` zwraca `Percent` — nie myl z `decimal`.
|
||||
- Tabela VAT jest **wyliczana z pozycji** dokumentu (chyba że włączono `KorektaVAT` — patrz HANDEL-W45). Nie
|
||||
modyfikuj jej, gdy chcesz tylko odczytać wartości.
|
||||
|
||||
---
|
||||
|
||||
### HANDEL-W44 — Odczyt podsumowań wartości dokumentu
|
||||
|
||||
**Cel:** odczytać zsumowane wartości netto / VAT / brutto całego dokumentu oraz proponowany rabat —
|
||||
bez ręcznego sumowania pozycji.
|
||||
|
||||
**Warianty:**
|
||||
|
||||
| Wariant | Pole | Typ | Uwaga |
|
||||
|---|---|---|---|
|
||||
| Podsumowanie dokumentu | `dok.Suma` | `BruttoNetto` | `Netto`/`VAT`/`Brutto` (`decimal`, waluta systemowa) |
|
||||
| Wartość brutto w walucie | `dok.BruttoCy` | `Currency` | brutto w walucie dokumentu |
|
||||
| Suma wyliczona z pozycji | `dok.SumaPozycji` | `BruttoNettoPozycji` | `Netto`/`VAT`/`Brutto` (read-only) |
|
||||
| Suma pozycji tow./prod. | `dok.SumaPozycjiTowProd` | `BruttoNettoPozycji` | tylko towary i produkty |
|
||||
| Proponowany rabat | `dok.Rabat` | `Percent` | przepisywany do pozycji |
|
||||
|
||||
**Pola i typy:** `dok.Suma: BruttoNetto` (podsumowana wartość dokumentu), `dok.BruttoCy: Currency`,
|
||||
`dok.SumaPozycji: BruttoNettoPozycji` (`Netto`/`VAT`/`Brutto` — `decimal`, **tylko do odczytu**,
|
||||
liczone na bieżąco z pozycji), `dok.Rabat: Percent`.
|
||||
|
||||
**Snippet:**
|
||||
|
||||
```csharp
|
||||
var dok = session.GetHandel().DokHandlowe.WgDaty[...];
|
||||
|
||||
// Podsumowanie całego dokumentu (waluta systemowa):
|
||||
decimal netto = dok.Suma.Netto;
|
||||
decimal vat = dok.Suma.VAT;
|
||||
decimal brutto = dok.Suma.Brutto;
|
||||
|
||||
// Brutto w walucie dokumentu (dla dokumentów walutowych):
|
||||
Currency bruttoCy = dok.BruttoCy;
|
||||
|
||||
// Suma wyliczana z pozycji (przydatne do kontroli spójności z dok.Suma):
|
||||
var sp = dok.SumaPozycji;
|
||||
Console.WriteLine($"Pozycje: netto={sp.Netto} VAT={sp.VAT} brutto={sp.Brutto}");
|
||||
|
||||
// Proponowany rabat dokumentu (przepisywany do nowych pozycji):
|
||||
Percent rabat = dok.Rabat;
|
||||
```
|
||||
|
||||
**Pułapki:**
|
||||
- `dok.Suma` to **stan zapisany** podsumowania, a `dok.SumaPozycji` jest **wyliczane na bieżąco**
|
||||
z pozycji za każdym odczytem. Dla dokumentu w buforze, przed ponownym przeliczeniem, mogą się
|
||||
chwilowo różnić.
|
||||
- `SumaPozycji`/`SumaPozycjiTowProd` zwracają `BruttoNettoPozycji` — typ **tylko do odczytu** (brak
|
||||
setterów); nie próbuj przez nie modyfikować wartości.
|
||||
- `dok.Rabat` to `Percent` — proponowany rabat dokumentu, przepisywany do nowo dodawanych pozycji;
|
||||
ustawienie nie przelicza wstecznie pozycji już istniejących.
|
||||
- Wartości brutto/netto na poziomie dokumentu zależą od `LiczonaOd` (HANDEL-W46) i ewentualnej korekty
|
||||
tabeli VAT (`KorektaVAT`, HANDEL-W45).
|
||||
|
||||
---
|
||||
|
||||
### HANDEL-W45 — Ręczna korekta tabeli VAT (`KorektaVAT`)
|
||||
|
||||
**Cel:** ręcznie skorygować kwoty w tabeli VAT (gdy wyliczenie z pozycji nie odpowiada wartości
|
||||
docelowej — np. zaokrąglenia faktury źródłowej), włączając flagę `KorektaVAT` i edytując wiersze
|
||||
`SumyVAT`.
|
||||
|
||||
**Warianty:**
|
||||
|
||||
| Wariant | Operacja |
|
||||
|---|---|
|
||||
| Włączenie trybu korekty | `dok.KorektaVAT = true` |
|
||||
| Ręczna zmiana kwoty stawki | edycja `suma.Suma.Netto` / `.VAT` / `.Brutto` na wierszu `SumaVAT` |
|
||||
| Dostępność korekty | `dok.IsReadOnlyKorektaVAT()`, `dok.IsReadOnlySumyVAT()` (sterowanie UI) |
|
||||
| Powrót do automatu | `dok.KorektaVAT = false` (tabela liczona ponownie z pozycji) |
|
||||
|
||||
**Pola i typy:** `dok.KorektaVAT: bool` (czy sumy VAT zmieniono ręcznie i nie zależą od pozycji),
|
||||
`SumaVAT.Suma: BruttoNetto` (`Netto`/`VAT`/`Brutto` — `decimal`). Wiersze tabeli VAT są edytowalne
|
||||
**tylko gdy** `KorektaVAT == true` (`SumaVAT.IsReadOnly()` zwraca `true` przy wyłączonej fladze).
|
||||
|
||||
> **Worker `KorektaTabeliVATWorker` jest `internal`** — nie da się go zainstancjonować z dodatku
|
||||
> zewnętrznego. Publiczny tor korekty prowadzi przez flagę `dok.KorektaVAT` i bezpośrednią edycję
|
||||
> pól wierszy `dok.SumyVAT`.
|
||||
|
||||
**Snippet:**
|
||||
|
||||
```csharp
|
||||
var dok = session.GetHandel().DokHandlowe.WgDaty[...];
|
||||
|
||||
using (var t = session.Logout(editMode: true)) // CommitUI() w workerze/extenderze
|
||||
{
|
||||
// 1. Włącz ręczną korektę — odblokowuje edycję wierszy tabeli VAT:
|
||||
dok.KorektaVAT = true;
|
||||
|
||||
// 2. Skoryguj kwoty na wybranej stawce (np. wyrównanie groszowe na 23%):
|
||||
foreach (SumaVAT s in dok.SumyVAT)
|
||||
{
|
||||
if (s.Stawka.Procent == new Percent(0.23))
|
||||
{
|
||||
s.Suma.VAT = 230.01m; // wartości MUSZĄ być zaokrąglone do grosza
|
||||
s.Suma.Brutto = 1230.01m;
|
||||
}
|
||||
}
|
||||
t.Commit();
|
||||
}
|
||||
session.Save();
|
||||
```
|
||||
|
||||
**Pułapki:**
|
||||
- Edycja wierszy `SumyVAT` bez `dok.KorektaVAT = true` zostanie zablokowana — `SumaVAT` jest wtedy
|
||||
read-only (sumy zależą od pozycji).
|
||||
- Przypisywane kwoty muszą być **zaokrąglone do grosza** — w trybie DEBUG ustawienie
|
||||
niezaokrąglonej wartości `Netto`/`VAT`/`Brutto` rzuca `ArgumentException`. Zaokrąglaj wejście
|
||||
(`Soneta.Tools.Math.RoundCy(...)`).
|
||||
- `KorektaVAT` jest dostępna tylko, gdy definicja dokumentu na to pozwala
|
||||
(`Definicja.SumyVAT` w trybie korekty) — sprawdzaj `dok.IsReadOnlyKorektaVAT()` zanim ustawisz
|
||||
flagę z poziomu UI.
|
||||
- Po włączeniu korekty tabela VAT **przestaje** śledzić zmiany pozycji. Wyłączenie
|
||||
(`KorektaVAT = false`) przywraca wyliczanie z pozycji i nadpisuje ręczne kwoty.
|
||||
- `DefinicjaStawki` na wierszu `SumaVAT` można zmieniać tylko przy włączonej korekcie
|
||||
(`IsReadOnlyDefinicjaStawki()` zależy od `KorektaVAT`).
|
||||
|
||||
---
|
||||
|
||||
### HANDEL-W46 — Sposób liczenia VAT (`LiczonaOd`) i przeliczenie procedur VAT
|
||||
|
||||
**Cel:** ustawić, czy dokument jest liczony od netto czy od brutto (`LiczonaOd`), oraz przeliczyć
|
||||
procedury VAT (JPK) na dokumencie zatwierdzonym/zaksięgowanym przy użyciu publicznego workera.
|
||||
|
||||
**Warianty:**
|
||||
|
||||
| Wariant | Mechanizm |
|
||||
|---|---|
|
||||
| Liczenie od netto | `dok.LiczonaOd = SposobLiczeniaVAT.OdNetto` |
|
||||
| Liczenie od brutto | `dok.LiczonaOd = SposobLiczeniaVAT.OdBrutto` |
|
||||
| Od brutto minus netto | `dok.LiczonaOd = SposobLiczeniaVAT.OdBruttoMinusNetto` |
|
||||
| Wg ustawień kontrahenta | `dok.LiczonaOd = SposobLiczeniaVAT.ZależyOdKontrahenta` |
|
||||
| Przeliczenie procedur VAT | worker `PrzeliczProceduryVATWorker` (publiczny) |
|
||||
|
||||
**Pola i typy:** `dok.LiczonaOd: SposobLiczeniaVAT` — enum `Soneta.Handel.SposobLiczeniaVAT`:
|
||||
`OdNetto=1`, `OdBrutto=2`, `OdBruttoMinusNetto=3`, `ZależyOdKontrahenta=4` (wartość `0` jest
|
||||
niedozwolona — rzuca `RequiredException`). Worker `PrzeliczProceduryVATWorker` ma publiczną klasę
|
||||
parametrów `PrzeliczProceduryVATParams : ContextBase` (`Zatwierdzone: bool = true`,
|
||||
`Zaksiegowane: bool = false`) oraz właściwości `[Context]`: `Dokument: DokumentHandlowy`,
|
||||
`Params: PrzeliczProceduryVATParams`.
|
||||
|
||||
**Snippet:**
|
||||
|
||||
```csharp
|
||||
var dok = session.GetHandel().DokHandlowe.WgDaty[...];
|
||||
|
||||
// 1. Zmiana sposobu liczenia VAT (dokument w buforze):
|
||||
using (var t = session.Logout(editMode: true))
|
||||
{
|
||||
dok.LiczonaOd = SposobLiczeniaVAT.OdBrutto; // 0 jest niedozwolone
|
||||
t.Commit();
|
||||
}
|
||||
session.Save();
|
||||
|
||||
// 2. Przeliczenie procedur VAT (JPK) workerem publicznym.
|
||||
// Worker działa tylko dla dokumentu zatwierdzonego (Params.Zatwierdzone)
|
||||
// lub zablokowanego/zaksięgowanego (Params.Zaksiegowane):
|
||||
var p = new PrzeliczProceduryVATWorker.PrzeliczProceduryVATParams(context)
|
||||
{
|
||||
Zatwierdzone = true,
|
||||
Zaksiegowane = false,
|
||||
};
|
||||
var worker = new PrzeliczProceduryVATWorker
|
||||
{
|
||||
Dokument = dok,
|
||||
Params = p,
|
||||
};
|
||||
worker.PrzeliczProceduryVAT(); // sam otwiera transakcję i Commit
|
||||
session.Save();
|
||||
```
|
||||
|
||||
**Pułapki:**
|
||||
- `LiczonaOd` nie przyjmuje wartości `0` (`RequiredException`). Zawsze ustaw konkretny wariant enuma.
|
||||
- Zmiana `LiczonaOd` na dokumencie z pozycjami wpływa na sposób przeliczenia netto↔brutto pozycji
|
||||
i tabeli VAT — rób to przed wprowadzeniem cen lub świadomie po przeliczeniu.
|
||||
- `PrzeliczProceduryVATWorker.PrzeliczProceduryVAT()` **nic nie zrobi**, jeśli dokument jest w
|
||||
buforze albo stan nie pasuje do flag `Params` (`Zatwierdzone`/`Zaksiegowane`). Worker sam otwiera
|
||||
transakcję (`Logout(true)` + `Commit`) — nie owijaj go w dodatkową transakcję edycyjną.
|
||||
- Worker jest widoczny tylko, gdy definicja liczy sumy VAT i ma definicję ewidencji
|
||||
(`IsVisiblePrzeliczProceduryVAT`); z poziomu kodu i tak sprawdź stan dokumentu przed wywołaniem.
|
||||
- `PrzeliczProceduryVATParams` dziedziczy po `ContextBase` — przy ręcznym tworzeniu przekaż `Context`
|
||||
do konstruktora.
|
||||
|
||||
---
|
||||
|
||||
### HANDEL-W47 — Zmiana waluty dokumentu i cen
|
||||
|
||||
**Cel:** zmienić walutę dokumentu handlowego (i opcjonalnie przeliczyć ceny pozycji) — np. wystawić
|
||||
fakturę w EUR zamiast PLN, z kursem z wybranej tabeli kursowej.
|
||||
|
||||
**Warianty:**
|
||||
|
||||
| Wariant | Mechanizm |
|
||||
|---|---|
|
||||
| Zmiana waluty z przeliczeniem cen | parametry `DokumentHandlowyZmianaWalutyWorkerParams` + akcja „Zmień walutę dokumentu i cen..." |
|
||||
| Zmiana waluty bez cen | te same parametry z `ZmienCeny = false` |
|
||||
| Ręczne ustawienie waluty/kursu | `dok.TabelaKursowa`, `dok.KursWaluty`, `dok.DataOgłoszeniaKursu`, `dok.BruttoCy` |
|
||||
|
||||
**Pola i typy:** klasa parametrów (publiczna) `DokumentHandlowyZmianaWalutyWorkerParams :
|
||||
PozycjaDokHandlowegoZmianaWalutyCenyWorkerParams` (ctor `(Context, [Context] DokumentHandlowy)`)
|
||||
udostępnia: `Waluta: Waluta` („na walutę"), `WalutaBazowa: Waluta` (read-only, „z waluty"),
|
||||
`TabelaKursowa: TabelaKursowa`, `Data: Date`, `KursWaluty: double`, `ZmienCeny: bool`. Pola
|
||||
dokumentu: `dok.TabelaKursowa: TabelaKursowa`, `dok.KursWaluty: double`, `dok.BruttoCy: Currency`.
|
||||
Moduł walut (jest `internal` jako extension): `Soneta.Waluty.WalutyModule.GetInstance(session)` →
|
||||
`.Waluty.WgSymbolu["EUR"]`, `.TabeleKursowe`.
|
||||
|
||||
> **Worker `DokumentHandlowyZmianaWalutyWorker` jest `internal`** — nie da się go zainstancjonować
|
||||
> bezpośrednio z dodatku zewnętrznego. Jest jednak zarejestrowany jako akcja menu Czynności („Zmień
|
||||
> walutę dokumentu i cen...", `Shift+F11`) i przyjmuje publiczne parametry
|
||||
> `DokumentHandlowyZmianaWalutyWorkerParams`. Z poziomu kodu dodatku zewnętrznego dostępne tory to:
|
||||
> (1) uruchomienie akcji przez mechanizm Czynności z przygotowanym `Context`, albo (2) bezpośrednie
|
||||
> ustawienie pól waluty/kursu na dokumencie i pozycjach.
|
||||
|
||||
**Snippet:**
|
||||
|
||||
```csharp
|
||||
using Microsoft.Extensions.DependencyInjection; // jeśli korzystasz z serwisów
|
||||
using Soneta.Waluty;
|
||||
|
||||
var dok = session.GetHandel().DokHandlowe.WgDaty[...];
|
||||
|
||||
// --- Tor 1: przygotowanie parametrów workera (do uruchomienia przez akcję Czynności) ---
|
||||
// Worker jest internal — z dodatku przygotowujemy publiczne Params i uruchamiamy akcję
|
||||
// przez mechanizm menu Czynności (Context z zaznaczonym dokumentem).
|
||||
var wm = WalutyModule.GetInstance(session);
|
||||
var p = new DokumentHandlowyZmianaWalutyWorkerParams(context, dok)
|
||||
{
|
||||
Waluta = wm.Waluty.WgSymbolu["EUR"], // waluta docelowa
|
||||
TabelaKursowa = wm.TabeleKursowe.NBP,
|
||||
Data = Date.Today,
|
||||
ZmienCeny = true, // przelicz też ceny pozycji
|
||||
};
|
||||
// KursWaluty wylicza się automatycznie po ustawieniu Waluta/TabelaKursowa/Data;
|
||||
// w razie potrzeby można nadpisać: p.KursWaluty = 4.30;
|
||||
|
||||
// --- Tor 2: ręczne ustawienie waluty i kursu na dokumencie (bez workera) ---
|
||||
using (var t = session.Logout(editMode: true))
|
||||
{
|
||||
dok.TabelaKursowa = wm.TabeleKursowe.NBP;
|
||||
dok.KursWaluty = 4.30;
|
||||
// dok.BruttoCy = new Currency(..., "EUR"); // kwoty w walucie dokumentu
|
||||
t.Commit();
|
||||
}
|
||||
session.Save();
|
||||
```
|
||||
|
||||
**Pułapki:**
|
||||
- Worker `DokumentHandlowyZmianaWalutyWorker` jest `internal` — **nie** wywołasz `new ...Worker(...)`
|
||||
ani `.ZmienWalute()` z dodatku zewnętrznego. Używaj publicznych `Params` + akcji Czynności lub
|
||||
bezpośredniej edycji pól dokumentu.
|
||||
- `session.GetWaluty()` jest **internal** — moduł walut pobieraj przez
|
||||
`WalutyModule.GetInstance(session)` (namespace `Soneta.Waluty`).
|
||||
- Jeśli w bazie **brak kursu** na żądaną datę (np. Demo nie ma kursu EUR „na dziś"), platforma rzuci
|
||||
`KursWalutyNotFoundException`. `KursWaluty` w parametrach wylicza się automatycznie tylko, gdy kurs
|
||||
istnieje; w przeciwnym razie ustaw `KursWaluty` ręcznie.
|
||||
- Zmiana waluty ma sens tylko dla dokumentu w **buforze** (`IsVisibleZmienWalute` wymaga
|
||||
`dok.Bufor`); dla dokumentu zatwierdzonego operacja jest niedostępna.
|
||||
- `WalutaBazowa` jest read-only — wyznaczana z bieżącej waluty dokumentu (`dok.BruttoCy.Symbol`).
|
||||
Ustawiasz tylko `Waluta` (docelową).
|
||||
- Kwoty pieniężne to `Currency` (wartość + symbol), nie `decimal`/`double`. Sam `KursWaluty` jest
|
||||
`double`.
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user