feat(123): receipts export xlsx VAT breakdown

- AccountingController::export(): new headers (Numer | Data wystawienia | Kwota brutto | Kwota netto | Stawka VAT | Kwota VAT), removed Data sprzedazy/Konfiguracja/Nr zamowienia/Nr referencyjny
- buildVatBreakdown() helper groups items_json by vat rate, emits one XLSX row per (receipt x rate); legacy receipts (no `vat` in snapshot) fallback to net=brutto/1.23
- ReceiptService::buildItemsSnapshot(): writes `vat` per item from order_items.tax_rate (fallback 23.0); shipping cost item gets vat=23.0
- RECEIPT-NET-FIX deferred (.paul/codebase/todo.md): ReceiptService::issue() still saves total_net=total_gross

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-12 21:06:53 +02:00
parent a4ed4531dc
commit 0227f2d072
12 changed files with 491 additions and 17 deletions

View File

@@ -339,6 +339,20 @@ tests/
- `/api/notifications/unread` zasila topbar badge oraz `public/assets/js/modules/notifications.js`.
- Browser Notification API jest progresywne: brak zgody nie blokuje strony ani pollingu.
## Phase 123 — Receipts Export VAT Breakdown
### ReceiptService::buildItemsSnapshot (`src/Modules/Accounting/ReceiptService.php`)
- Snapshot pozycji w `receipts.items_json` ma teraz pole `vat` (procent jako float). Zrodlo: `order_items.tax_rate` (fallback `item.vat`, ostatecznie 23.0).
- Pozycja "Koszt wysylki" (gdy `delivery_price > 0`) dostaje `vat = 23.0`.
- Stary kontrakt (`name`, `quantity`, `price`, `total`, `sku`, `ean`) zachowany — tylko dodatek pola `vat`. Widoki paragonu (print/preview) nie wymagaja zmian.
### AccountingController::export (`src/Modules/Accounting/AccountingController.php`)
- Naglowki XLSX: `Numer | Data wystawienia | Kwota brutto | Kwota netto | Stawka VAT | Kwota VAT`. Usunieto: Data sprzedazy, Konfiguracja, Nr zamowienia, Nr referencyjny.
- `buildVatBreakdown(itemsJson, totalNet, totalGross)` grupuje pozycje `items_json` po `vat`, oblicza per-grupa `net = round(gross / (1 + rate/100), 2)` i `vat = gross - net`. Zwraca liste `[{rate_label, net, vat}, ...]` posortowana malejaco po stawce.
- Legacy fallback: gdy zaden item nie ma klucza `vat`, zwraca pojedynczy wiersz `[{rate_label: '23%', net: total_net, vat: total_gross - total_net}]`.
- Multi-rate paragon = wiele wierszy w XLSX (ten sam Numer, Data wystawienia i Kwota brutto powtarzane).
- Helper `formatVatRate()` formatuje stawke (23.0 -> "23%", 7.5 -> "7.5%").
## Phase 120 — Alert Component Unification
### Alert component (`resources/views/components/alert.php`)

View File

@@ -1,5 +1,20 @@
# Technical Changelog
## 2026-05-12 - Phase 123 Plan 01: Receipts Export VAT Breakdown
**Co zrobiono:**
- `ReceiptService::buildItemsSnapshot()` zapisuje `vat` (procent) per pozycja w `items_json` (z `order_items.tax_rate`, fallback 23.0). Pozycja "Koszt wysylki" dostaje `vat=23.0`.
- `AccountingController::export()`: nowe naglowki XLSX `Numer | Data wystawienia | Kwota brutto | Kwota netto | Stawka VAT | Kwota VAT` (usunieto `Data sprzedazy`, `Konfiguracja`, `Nr zamowienia`, `Nr referencyjny`).
- Eksport emituje osobny wiersz na kazda stawke VAT wystepujaca w paragonie (multi-rate breakdown z grupowania `items_json` po `vat`).
- Legacy paragony (snapshot bez `vat`) zwracaja jeden wiersz ze stawka 23%, `Kwota netto = total_net`, `Kwota VAT = total_gross - total_net`.
- Dodany prywatny helper `AccountingController::buildVatBreakdown()` + `formatVatRate()` (np. 23.0 -> "23%", 7.5 -> "7.5%").
**Dlaczego:**
- Ksiegowy potrzebuje arkusza z rozbiciem VAT per stawka do zaczytania do ksiegowosci. Stary eksport zawieral pola operacyjne (data sprzedazy, konfiguracja, ref) bez podstawowych pol VAT.
**Weryfikacja:**
- `php -l` na obu plikach OK; manualny eksport XLSX dla mieszanej listy paragonow po wdrozeniu.
## 2026-05-12 - SMSPLANET Inbound Webhook Fix
**Co zrobiono:**

View File

@@ -2,6 +2,20 @@
> Lista nieformalnych zadan do zrobienia pozniej. Kazdy wpis ma wlasny tag (np. `STAT-NET`) zeby mozna go bylo zlinkowac z komentarzy w kodzie.
## RECEIPT-NET-FIX — `receipts.total_net` powinno byc realnym netto (data: 2026-05-12)
### Kontekst
- Phase 123-01 — eksport paragonow XLSX z VAT breakdown.
- `ReceiptService::issue()` (linie 81-82) zapisuje `total_net = total_gross` (kopia, nie realne netto). To znany bug, ale nie poprawiany w 123 (poza zakresem).
- Phase 123 fallback dla legacy paragonow musi liczyc `net = brutto/1.23` zamiast brac z `total_net`, bo inaczej VAT = 0.
### Zadania
1. W `ReceiptService::buildItemsSnapshot()` agreguj `total_net` z pozycji (per stawka) — `lineTotal / (1 + vat/100)`.
2. Zwroc oba: `total_net` (suma netto per pozycja) i `total_gross` (suma brutto). Uzyj `total_net` w INSERT zamiast kopii brutto.
3. Po deploy mozna uproscic legacy fallback w `AccountingController::buildVatBreakdown()` zeby brak `vat` -> uzywal `total_net` z bazy.
4. Backfill historycznych paragonow opcjonalny (eksport teraz dziala bez tego).
## INVOICE-IDEMP-115 — idempotencja podwojnego POST do Fakturowni (data: 2026-05-10)
### Kontekst