Skip to content

Podatki i VAT (Silnik kalkulacji)

Moduł podatków stanowi centralny, wysoce precyzyjny silnik obliczeniowy i konfiguracyjny w platformie Ammonly. Odpowiada za automatyczną determinację stawek podatkowych, wielopoziomowe przeliczanie kwot netto/brutto, obsługę procedur specjalnych (VAT Marża, WHT, OSS, Reverse Charge) oraz generowanie niezmiennych snapshotów fiskalnych dla dokumentów handlowych.

Architektura Domain-Driven & API-First

Silnik podatkowy został zaprojektowany w oparciu o czystą domenę (App\Modules\Tax\Domain), pozbawioną zależności od frameworka i bazy danych. Wszystkie kalkulacje są deterministyczne, audytowalne i dostępne zarówno przez REST API (/api/v1/tax/*), jak i reaktywny interfejs HTMX w panelu administracyjnym.


Spis treści


1. Architektura i kluczowe zasady

W nowoczesnym systemie ERP/CRM zarządzanie podatkami nie może ograniczać się do prostego mnożenia ceny przez 0.23. Różnice w przepisach międzynarodowych, wymagania transakcji transgranicznych, sprzedaż towarów używanych oraz podatki u źródła wymagają zunifikowanego, elastycznego modelu danych:

mermaid
flowchart TD
    Doc[Pozycja dokumentu: Oferta / Zamówienie / Faktura] --> Matrix[Matryca Determinacji Stawek]
    Matrix -->|Klient: B2B/B2C, Strefa: PL/UE/Export, Typ: Towar/Usługa| Rate[Wybrana Stawka / Grupa Podatkowa]
    Rate --> Engine[Silnik Kalkulacji Finansowej TaxEngine]
    Engine --> Strategy{Strategia zaokrągleń}
    Strategy -->|Line-Level / Header-Level| Output[Wyliczone kwoty Netto, VAT, Brutto, WHT]
    Output --> Snapshot[(Niezmienny Snapshot JSON w rekordzie dokumentu)]

Kluczowe założenia projektowe:

  1. Niezmienność historyczna (Immutability): Zmiana stawek VAT lub usunięcie stawki w konfiguracji systemu nie wpływa na wcześniej wystawione oferty, zamówienia czy faktury. Dokument przechowuje kompletny zrzut JSON.
  2. Precyzja matematyczna: Wszystkie operacje arytmetyczne operują na wysokiej precyzji zmiennoprzecinkowej, a zaokrąglenie do 2 miejsc po przecinku (groszy) odbywa się ściśle według wybranej strategii biznesowej.
  3. Separacja profilowa (Multi-Tenant): Konfiguracja podatków jest autonomiczna dla każdej instancji klienta (App Client), przy jednoczesnym dostępie centralnym z poziomu panelu App Admin.

2. Cztery tryby kalkulacji podatku

Silnik Ammonly natywnie obsługuje 4 odrębne algorytmy wyliczania podatku, definiowane na poziomie stawki (calculation_mode):

mermaid
graph LR
    Mode[Tryb kalkulacji] --> Exc[1. Exclusive: Netto + VAT]
    Mode --> Inc[2. Inclusive: W cenie brutto]
    Mode --> Mar[3. Margin: Od marży handlowej]
    Mode --> Wht[4. WHT: Potrącenie podatku u źródła]

2.1. Exclusive — Od netto (Standard B2B)

Podstawowy tryb stosowany w transakcjach pomiędzy przedsiębiorstwami. Wprowadzana cena jednostkowa jest ceną netto, a podatek jest doliczany do wartości pozycji:

$$\text{Kwota Podatku} = \text{Kwota Netto} \times \frac{\text{Stawka}%}{100}$$ $$\text{Kwota Brutto} = \text{Kwota Netto} + \text{Kwota Podatku}$$

Przykład:

  • Cena netto: $100{,}00\text{ PLN}$, Stawka VAT: $23%$
  • Podatek VAT: $23{,}00\text{ PLN}$, Kwota brutto: $123{,}00\text{ PLN}$

2.2. Inclusive — Od brutto (Standard B2C)

Tryb dedykowany dla sprzedaży konsumenckiej (detalicznej), cenników konsumenckich oraz e-commerce, gdzie prezentowana cena zawiera już podatek VAT (kalkulacja metodą "w stu"):

$$\text{Kwota Netto} = \frac{\text{Kwota Brutto}}{1 + \frac{\text{Stawka}%}{100}}$$ $$\text{Kwota Podatku} = \text{Kwota Brutto} - \text{Kwota Netto}$$

Przykład:

  • Cena brutto: $123{,}00\text{ PLN}$, Stawka VAT: $23%$
  • Kwota netto: $100{,}00\text{ PLN}$, Podatek VAT: $23{,}00\text{ PLN}$

2.3. Procedura Marży — VAT Marża (art. 120)

Zgodnie z art. 120 ustawy o VAT, w przypadku dostawy towarów używanych, dzieł sztuki, przedmiotów kolekcjonerskich oraz usług turystycznych (biura podróży), podstawą opodatkowania jest wyłącznie marża handlowa (różnica między ceną sprzedaży a ceną nabycia), pomniejszona o kwotę podatku:

$$\text{Marża Brutto} = \max(0, \text{Cena Sprzedaży} - \text{Koszt Nabycia})$$ $$\text{Podstawa Netto Marży} = \frac{\text{Marża Brutto}}{1 + \frac{\text{Stawka}%}{100}}$$ $$\text{Kwota Podatku} = \text{Marża Brutto} - \text{Podstawa Netto Marży}$$ $$\text{Łączna Kwota Brutto do zapłaty} = \text{Cena Sprzedaży}$$

Zasada marży ujemnej

Jeżeli cena sprzedaży jest niższa lub równa kosztowi nabycia ($\text{Marża} \le 0$), podstawa opodatkowania oraz kwota podatku VAT wynoszą dokładnie $0{,}00\text{ PLN}$. Nabywca płaci cenę sprzedaży, a na dokumencie nie wykazuje się kwoty podatku dla nabywcy.

Przykład:

  • Cena sprzedaży samochodu używanego: $50,000{,}00\text{ PLN}$, Cena nabycia (zakupu): $40,000{,}00\text{ PLN}$
  • Marża brutto: $10,000{,}00\text{ PLN}$
  • Podstawa netto marży przy stawce $23%$: $8,130{,}08\text{ PLN}$
  • Podatek VAT z marży: $1,869{,}92\text{ PLN}$
  • Kwota do zapłaty na fakturze: $50,000{,}00\text{ PLN}$ (z adnotacją procedura marży - towary używane, kod fiskalny P_106E_3).

2.4. Podatek u źródła — WHT (Withholding Tax)

Mechanizm stosowany w transakcjach zakupu usług niematerialnych (np. doradczych, prawnych, marketingowych, licencji oprogramowania, hostingu) od podmiotów zagranicznych (nierezydentów podatkowych). Zgodnie z ustawami o CIT/PIT, płatnik w Polsce potrąca podatek u źródła (np. 20%) i odprowadza go do polskiego urzędu skarbowego, wypłacając kontrahentowi kwotę pomniejszoną o ten podatek:

$$\text{Kwota WHT} = \text{Kwota Netto} \times \frac{\text{Stawka WHT}%}{100}$$ $$\text{Kwota do wypłaty dla dostawcy} = \text{Kwota Brutto} - \text{Kwota WHT}$$

Przykład:

  • Zakup licencji IT z USA o wartości: $10,000{,}00\text{ PLN}$ (stawka WHT 20%)
  • Kwota podatku WHT potrącona dla US: $2,000{,}00\text{ PLN}$
  • Kwota wypłacona dostawcy zagranicznemu: $8,000{,}00\text{ PLN}$

3. Statusy prawne i integracja fiskalna (JPK_V7 / KSeF)

Każda stawka podatkowa w systemie posiada przypisany status prawny (tax_status) oraz kod fiskalny (fiscal_code), które gwarantują bezbłędne mapowanie do struktur logicznych JPK_V7 oraz Krajowego Systemu e-Faktur (KSeF):

Status prawny (tax_status)Kod fiskalny KSeF/JPKStawka %Zastosowanie biznesowePodstawa prawna / Klauzula
standardP_13_123.00%Podstawowa stawka VAT na towary i usługiArt. 41 ust. 1
standardP_13_28.00%Stawka obniżona (budownictwo, gastronomia)Art. 41 ust. 2
standardP_13_35.00%Stawka obniżona (żywność, książki)Art. 41 ust. 2a
zero_ratedP_13_6_10.00%Eksport towarów poza UE oraz WDT wewnątrz UEArt. 41 ust. 4, Art. 42
exemptP_13_6_20.00%Zwolnienie przedmiotowe lub podmiotowe (ZW)Zwolnienie na podst. art. 43 ust. 1
reverse_chargeP_13_6_30.00%Odwrotne obciążenie (NP / OO) dla usług B2B UEOdwrotne obciążenie - art. 28b
out_of_scope0.00%Transakcje niepodlegające ustawie o VATPoza zakresem ustawy o podatku VAT

4. Matryca determinacji podatków (Determination Matrix)

Matryca determinacji eliminuje błędy ludzkie operatorów, automatycznie dobierając właściwą stawkę podatku w oparciu o reguły decyzyjne oceniane według priorytetu (priority, gdzie niższa liczba = wyższy priorytet):

mermaid
sequenceDiagram
    autonumber
    actor User as Operator / System
    participant Engine as Silnik Matrycy (TaxDeterminationMatrix)
    participant Rules as Rejestr Reguł (a_mod_tax_rules_records)
    participant Rate as Wybrana Stawka VAT

    User->>Engine: Przekazuje dane: [Klient: UE B2B, Usługa IT, Strefa: eu_vat]
    Engine->>Rules: Pobiera aktywne reguły posortowane wg priorytetu rosnąco
    loop Ewaluacja reguł
        Rules->>Engine: Reguła 40: Export Goods? -> NIE PASUJE
        Rules->>Engine: Reguła 50: EU B2B Services? -> PASUJE!
    end
    Engine->>Rate: Zwraca stawkę VAT_NP (0% Odwrotne obciążenie)
    Rate-->>User: Automatycznie aplikuje stawkę do pozycji oferty/faktury

Kryteria ewaluacji:

  1. Typ kontrahenta (customer_type):
    • all — dotyczy wszystkich kontrahentów,
    • b2b — przedsiębiorcy zarejestrowani z numerem identyfikacji podatkowej (NIP / Tax ID),
    • b2c — konsumenci i osoby fizyczne nieprowadzące działalności gospodarczej.
  2. Strefa geograficzna (geo_zone):
    • domestic — transakcja krajowa (Polska),
    • eu_vat — kontrahent z kraju Unii Europejskiej z aktywnym numerem VAT-UE (VIES),
    • eu_consumer — konsument z kraju UE (obsługa procedury One Stop Shop — OSS),
    • export_world — kontrahent z kraju trzeciego poza obszarem celnym UE (eksport).
  3. Klasyfikacja pozycji (item_type):
    • all — wszystkie pozycje asortymentowe,
    • product — towary fizyczne i materiały,
    • service — usługi niematerialne, programistyczne, doradcze, licencje,
    • margin_goods — towary używane rozliczane w procedurze marży.

5. Grupy wielopodatkowe (Tax Groups)

Dla złożonych transakcji system pozwala na grupowanie wielu podatków w pojedynczą wybieralną encję (TaxGroup):

  1. Podatki równoległe (Parallel Taxes):
    • Każdy składnik grupy naliczany jest niezależnie od podstawowej kwoty netto.
    • Przykład: Podatek podstawowy VAT 23% + Opłata Cukrowa 5%.
  2. Podatki kaskadowe / złożone (Compound Taxes — is_compound = 1):
    • Składnik podatkowy naliczany jest od kwoty netto powiększonej o wartość wcześniej naliczonych podatków w grupie.
    • Stosowane m.in. w kanadyjskim systemie podatkowym (GST + PST) oraz przy akcyzach.

6. Strategie zaokrągleń i precyzja finansowa

System Ammonly oferuje pełną kontrolę nad miejscem i metodą zaokrąglania kwot podatków:

mermaid
graph TD
    Calc[Obliczenia kwot] --> Strat{Poziom zaokrągleń}
    Strat --> Line[Line Level: Pozycja po pozycji]
    Strat --> Head[Header Level: Suma baz opodatkowania]
    Line --> Math{Algorytm matematyczny}
    Head --> Math
    Math --> HalfUp[Half-Up: >= 0.005 w górę]
    Math --> HalfEven[Half-Even: Zaokrąglenie bankierskie]

Poziom strategii zaokrąglania (RoundingStrategy):

  • Line Level (Row-by-Row) — Standard: Podatek jest obliczany i zaokrąglany do 2 miejsc po przecinku na każdej pojedynczej pozycji dokumentu. Suma podatku na dokumencie stanowi sumę zaokrąglonych pozycji.
  • Header Level (Summary Table): Na poziomie pozycji zachowywana jest pełna precyzja ułamkowa. W podsumowaniu dokumentu sumowane są dokładne bazy netto dla każdej stawki, a zaokrąglenie do groszy odbywa się jednorazowo na zagregowanej sumie.

Algorytmy zaokrąglania:

  • Half-Up: Standardowa metoda handlowa — jeśli trzecia cyfra po przecinku wynosi $\ge 5$, zaokrąglenie następuje w górę (np. $10{,}005 \to 10{,}01$).
  • Half-Even (Banker's Rounding): Zaokrąglenie do najbliższej cyfry parzystej — eliminuje statystyczne przeszacowanie sum przy setkach tysięcy operacji rozliczeniowych.

7. Niezmienny zrzut podatkowy dokumentu (Snapshot JSON)

Każdy zatwierdzony dokument handlowy (oferta, zamówienie, faktura) utrwala w bazie danych pełen zrzut kalkulacji podatkowej w formacie JSON (tax_snapshot).

json
{
  "currency": "PLN",
  "defaultPriceMode": "exclusive",
  "roundingStrategy": "line_level",
  "totalNet": 100.00,
  "totalTax": 23.00,
  "totalGross": 123.00,
  "totalWht": 0.00,
  "totalPaymentDue": 123.00,
  "items": [
    {
      "id": "item-1",
      "name": "Konsultacje IT / Wdrożenie",
      "quantity": 1.00,
      "unitPrice": 100.00,
      "netAmount": 100.00,
      "taxAmount": 23.00,
      "grossAmount": 123.00,
      "taxRate": {
        "taxCode": "VAT_23",
        "taxName": "VAT 23% (Standard)",
        "ratePercent": 23.00,
        "calculationMode": "exclusive",
        "taxStatus": "standard",
        "fiscalCode": "P_13_1"
      }
    }
  ],
  "taxBreakdown": [
    {
      "taxCode": "VAT_23",
      "taxName": "VAT 23% (Standard)",
      "ratePercent": 23.00,
      "netBase": 100.00,
      "taxAmount": 23.00,
      "grossAmount": 123.00,
      "legalClause": null
    }
  ]
}

Gwarancja audytowa

Taki format zapisu gwarantuje, że wydruk faktury po 5 latach będzie w 100% zgodny z pierwotnymi wyliczeniami, nawet jeśli stawki VAT w państwie ulegną zmianie.


8. Symulator podatków (Live Tester) oraz REST API

Live Tax Tester w interfejsie

W zakładce Live Tax Tester (/settings/taxes#tab-simulator) administratorzy mogą w czasie rzeczywistym wprowadzać parametry transakcji (cena, ilość, rabat, marża, strefa geo, typ klienta) i diagnozować:

  • Która reguła matrycy decyzyjnej została zastosowana,
  • Jakie kwoty netto, VAT, brutto i WHT zostały wygenerowane,
  • Dokładną tabelę rozbicia stawek oraz podgląd snapshotu JSON.

REST API Endpoints

Wszystkie operacje kalkulacyjne są dostępne programistycznie przez REST API:

  • POST /api/v1/tax/calculate: Przelicza przekazany koszyk pozycji, zwracając podsumowanie, rozbicie stawek i snapshot JSON.
  • GET /api/v1/tax/rates: Pobiera listę aktywnych stawek podatkowych dla bieżącego kontekstu.
  • GET /api/v1/tax/rules: Pobiera listę zdefiniowanych reguł matrycy determinacji.

Ammonly Documentation System