diff --git a/.paul/PROJECT.md b/.paul/PROJECT.md index b836251..fd58b94 100644 --- a/.paul/PROJECT.md +++ b/.paul/PROJECT.md @@ -73,6 +73,7 @@ Sprzedawca moĹĽe obsĹ‚ugiwać zamĂłwienia ze wszystkich kanałów - [x] Ochrona danych lokalnych przy re-imporcie + rozroznienie import/aktualizacja w activity log shopPRO — Phase 62 - [x] Import i wyswietlanie personalizacji produktow z shopPRO (custom_fields) + naprawa daty zamowienia — Phase 63 - [x] Data wystawienia paragonu z dokladnoscia do godziny i minuty (DATE -> DATETIME) — Phase 64 +- [x] Koszt wysylki jako pozycja paragonu (bugfix buildItemsSnapshot + delivery_price) — Phase 70 - [ ] Eliminacja zduplikowanego kodu: SslCertificateResolver, ToggleableRepositoryTrait, RedirectPathResolver, ReceiptService — Phase 68 ### Active (In Progress) diff --git a/.paul/ROADMAP.md b/.paul/ROADMAP.md index 8c4e68d..229b1aa 100644 --- a/.paul/ROADMAP.md +++ b/.paul/ROADMAP.md @@ -30,6 +30,7 @@ Wersja mobilna aplikacji, modul po module. Cel: pelna uzywalnosc orderPRO na tel | 67 | PAUL Codex Executor | 1/1 | Complete | | 68 | Code Deduplication Refactor | 0/2 | Planning | | 69 | Allegro Tracking English Statuses | 1/1 | Complete | +| 70 | Receipt Shipping Cost | 1/1 | Complete | | TBD | Mobile Orders List | - | Not started | | TBD | Mobile Order Details | - | Not started | | TBD | Mobile Settings | - | Not started | @@ -353,4 +354,4 @@ Archive: `.paul/milestones/v0.1-ROADMAP.md` --- *Roadmap created: 2026-03-12* -*Last updated: 2026-04-04 - phase 69 unified (Allegro Tracking English Statuses)* +*Last updated: 2026-04-06 - phase 70 unified (Receipt Shipping Cost bugfix)* diff --git a/.paul/STATE.md b/.paul/STATE.md index 78306a6..f3bc290 100644 --- a/.paul/STATE.md +++ b/.paul/STATE.md @@ -5,34 +5,34 @@ See: .paul/PROJECT.md (updated 2026-04-04) **Core value:** Sprzedawca moze obslugiwac zamowienia ze wszystkich kanalow sprzedazy i nadawac przesylki bez przelaczania sie miedzy platformami. -**Current focus:** Milestone v3.0 - Phase 69 plan 01 unified, ready for next PLAN +**Current focus:** Milestone v3.0 - Phase 70 complete, ready for next PLAN ## Current Position Milestone: v3.0 Mobile Responsive - In progress -Phase: 69 (Allegro Tracking English Statuses) - Complete -Plan: 69-01 unified +Phase: 70 (Receipt Shipping Cost) — Complete +Plan: 70-01 unified Status: Loop complete, ready for next PLAN -Last activity: 2026-04-04 - Unified .paul/phases/69-allegro-tracking-english-statuses/69-01-PLAN.md +Last activity: 2026-04-06 — Unified .paul/phases/70-receipt-shipping-cost/70-01-PLAN.md Progress: -- Milestone: [#######...] ~70% -- Phase 69: [##########] 100% +- Milestone: [#######...] ~72% +- Phase 70: [##########] 100% ## Loop Position Current loop state: ``` PLAN --> APPLY --> UNIFY - ✓ ✓ ✓ [Loop complete - ready for next PLAN] + ✓ ✓ ✓ [Loop complete - ready for next PLAN] ``` ## Session Continuity -Last session: 2026-04-04 -Stopped at: Plan 69-01 unified -Next action: Run $paul-plan for the next prioritized phase -Resume file: .paul/phases/69-allegro-tracking-english-statuses/69-01-SUMMARY.md +Last session: 2026-04-06 +Stopped at: Plan 70-01 unified +Next action: Run /paul:plan for the next prioritized phase +Resume file: .paul/phases/70-receipt-shipping-cost/70-01-SUMMARY.md ## Git State diff --git a/.paul/phases/70-receipt-shipping-cost/70-01-PLAN.md b/.paul/phases/70-receipt-shipping-cost/70-01-PLAN.md new file mode 100644 index 0000000..c249948 --- /dev/null +++ b/.paul/phases/70-receipt-shipping-cost/70-01-PLAN.md @@ -0,0 +1,145 @@ +--- +phase: 70-receipt-shipping-cost +plan: 01 +type: execute +wave: 1 +depends_on: [] +files_modified: + - src/Modules/Accounting/ReceiptService.php + - src/Modules/Accounting/ReceiptController.php + - resources/views/orders/receipt-create.php +autonomous: true +delegation: off +--- + + +## Goal +Naprawic brak pozycji kosztu wysylki na paragonach. Aktualnie `buildItemsSnapshot()` iteruje tylko po produktach zamowienia, pomijajac `delivery_price` z tabeli orders. + +## Purpose +Paragony musza zawierac wszystkie pozycje kosztowe zamowienia, w tym koszt dostawy, aby byly zgodne z rzeczywista kwota zamowienia. + +## Output +- `ReceiptService::buildItemsSnapshot()` dodaje pozycje "Koszt wysylki" gdy `delivery_price > 0` +- `ReceiptService::calculateTotalGross()` uwzglednia `delivery_price` +- `ReceiptController::create()` przekazuje `delivery_price` do widoku i wlicza do `totalGross` +- Widok `receipt-create.php` wyswietla wiersz kosztu wysylki w tabeli pozycji + + + +## Project Context +@.paul/PROJECT.md +@.paul/ROADMAP.md +@.paul/STATE.md + +## Source Files +@src/Modules/Accounting/ReceiptService.php +@src/Modules/Accounting/ReceiptController.php +@resources/views/orders/receipt-create.php +@src/Modules/Orders/OrdersRepository.php (findDetails zwraca SELECT o.* wiec delivery_price jest dostepne) + + + + +## AC-1: Koszt wysylki jako pozycja paragonu +```gherkin +Given zamowienie z delivery_price = 15.00 i produktami +When uzytkownik wystawia paragon +Then paragon zawiera dodatkowa pozycje "Koszt wysylki" z cena 15.00 i iloscia 1 +And total_gross paragonu zawiera sume produktow + 15.00 +``` + +## AC-2: Brak pozycji wysylki gdy delivery_price = 0 lub NULL +```gherkin +Given zamowienie z delivery_price = 0 lub NULL +When uzytkownik wystawia paragon +Then paragon NIE zawiera pozycji "Koszt wysylki" +And total_gross paragonu zawiera tylko sume produktow +``` + +## AC-3: Podglad formularza wystawienia paragonu +```gherkin +Given zamowienie z delivery_price > 0 +When uzytkownik otwiera formularz wystawienia paragonu +Then tabela pozycji wyswietla wiersz "Koszt wysylki" z prawidlowa kwota +And suma w stopce tabeli zawiera koszt wysylki +``` + + + + + + + Task 1: Dodac koszt wysylki do buildItemsSnapshot i calculateTotalGross + src/Modules/Accounting/ReceiptService.php + + 1. Zmienic sygnature `buildItemsSnapshot()` na `buildItemsSnapshot(array $items, array $order)` — dodac parametr `$order` + 2. Po petli foreach nad produktami, sprawdzic `$order['delivery_price']`: + - Jesli `delivery_price` istnieje i jest > 0, dodac pozycje do `$itemsSnapshot`: + - name: "Koszt wysylki" + - quantity: 1 + - price: (float) delivery_price + - total: (float) delivery_price + - sku: '' + - ean: '' + - Dodac wartosc do `$totalGross` + 3. Zaktualizowac wywolanie w `issue()` linia 64: `$this->buildItemsSnapshot($items, $order)` + 4. Zmienic `calculateTotalGross()` — dodac opcjonalny parametr `float $deliveryPrice = 0.0` i dodac go do sumy + + Przegladnac kod — buildItemsSnapshot przyjmuje $order i dodaje wiersz wysylki + AC-1 i AC-2 satisfied: paragon zawiera/nie zawiera pozycji wysylki w zaleznosci od delivery_price + + + + Task 2: Zaktualizowac kontroler i widok formularza + src/Modules/Accounting/ReceiptController.php, resources/views/orders/receipt-create.php + + 1. W `ReceiptController::create()`: + - Pobrac delivery_price: `$deliveryPrice = (float) ($order['delivery_price'] ?? 0);` + - Przekazac do `calculateTotalGross()`: `$totalGross = $this->receiptService->calculateTotalGross($items, $deliveryPrice);` + - Przekazac `deliveryPrice` do widoku w tablicy render + 2. W `receipt-create.php`: + - Po petli `foreach ($itemsList ...)` a przed zamknieciem ``: + - Dodac warunek: `if ($deliveryPrice > 0)` + - Wyswietlic wiersz: Lp = count($itemsList)+1, nazwa "Koszt wysylki", qty 1, cena i suma = deliveryPrice + - Na gorze widoku dodac: `$deliveryPrice = (float) ($deliveryPrice ?? 0);` + + Otworzyc formularz wystawienia paragonu dla zamowienia z kosztem wysylki — wiersz "Koszt wysylki" widoczny w tabeli + AC-3 satisfied: formularz wyswietla pozycje kosztu wysylki + + + + + + +## DO NOT CHANGE +- database/migrations/* (schemat bazy danych) +- src/Modules/Orders/OrdersRepository.php (findDetails juz zwraca delivery_price) +- resources/views/receipts/show.php, receipts/print.php (wyswietlaja dane z items_json — automatycznie pokaza nowa pozycje) + +## SCOPE LIMITS +- Nie dodawac obslugi VAT dla pozycji wysylki (paragony nie rozdzielajaja netto/brutto) +- Nie zmieniac widokow podgladu/wydruku paragonu — one czytaja z items_json i automatycznie pokaza nowy wiersz + + + + +Before declaring plan complete: +- [ ] buildItemsSnapshot przyjmuje $order i dodaje pozycje wysylki gdy delivery_price > 0 +- [ ] calculateTotalGross uwzglednia delivery_price +- [ ] Kontroler przekazuje deliveryPrice do widoku +- [ ] Widok wyswietla wiersz "Koszt wysylki" warunkow +- [ ] Brak bledow skladni PHP +- [ ] Istniejace paragony (bez wysylki) nie sa naruszone + + + +- Paragon wystawiony dla zamowienia z delivery_price zawiera pozycje "Koszt wysylki" +- Paragon wystawiony dla zamowienia bez delivery_price nie zawiera dodatkowej pozycji +- Formularz wystawienia paragonu pokazuje koszt wysylki w tabeli +- Total paragonu = suma produktow + koszt wysylki + + + +After completion, create `.paul/phases/70-receipt-shipping-cost/70-01-SUMMARY.md` + diff --git a/.paul/phases/70-receipt-shipping-cost/70-01-SUMMARY.md b/.paul/phases/70-receipt-shipping-cost/70-01-SUMMARY.md new file mode 100644 index 0000000..0266bf3 --- /dev/null +++ b/.paul/phases/70-receipt-shipping-cost/70-01-SUMMARY.md @@ -0,0 +1,97 @@ +--- +phase: 70-receipt-shipping-cost +plan: 01 +subsystem: accounting +tags: [receipts, delivery, shipping-cost] + +requires: + - phase: 10-receipt-issuing + provides: ReceiptService, buildItemsSnapshot, receipt creation flow +provides: + - Shipping cost included as receipt line item + - delivery_price reflected in receipt total +affects: [] + +tech-stack: + added: [] + patterns: [] + +key-files: + created: [] + modified: + - src/Modules/Accounting/ReceiptService.php + - src/Modules/Accounting/ReceiptController.php + - resources/views/orders/receipt-create.php + +key-decisions: + - "Shipping cost added as regular line item in items_json (same structure as product items)" + +patterns-established: [] + +duration: 5min +started: 2026-04-06T00:00:00Z +completed: 2026-04-06T00:05:00Z +--- + +# Phase 70 Plan 01: Receipt Shipping Cost Summary + +**Bugfix: paragony zawieraja teraz pozycje "Koszt wysylki" gdy zamowienie ma delivery_price > 0** + +## Performance + +| Metric | Value | +|--------|-------| +| Duration | ~5min | +| Tasks | 2 completed | +| Files modified | 3 | + +## Acceptance Criteria Results + +| Criterion | Status | Notes | +|-----------|--------|-------| +| AC-1: Koszt wysylki jako pozycja paragonu | Pass | buildItemsSnapshot dodaje wiersz gdy delivery_price > 0 | +| AC-2: Brak pozycji wysylki gdy delivery_price = 0/NULL | Pass | Warunek `if ($deliveryPrice > 0)` chroni | +| AC-3: Podglad formularza wystawienia paragonu | Pass | Widok wyswietla wiersz "Koszt wysylki" warunkowo | + +## Accomplishments + +- `buildItemsSnapshot()` rozszerzony o parametr `$order` — dodaje pozycje "Koszt wysylki" do snapshot i total +- `calculateTotalGross()` rozszerzony o opcjonalny `$deliveryPrice` — kontroler przekazuje wartosc do widoku +- Widok `receipt-create.php` wyswietla wiersz kosztu wysylki w tabeli pozycji + +## Files Created/Modified + +| File | Change | Purpose | +|------|--------|---------| +| `src/Modules/Accounting/ReceiptService.php` | Modified | buildItemsSnapshot($items, $order) + calculateTotalGross($items, $deliveryPrice) | +| `src/Modules/Accounting/ReceiptController.php` | Modified | Przekazuje deliveryPrice do widoku i calculateTotalGross | +| `resources/views/orders/receipt-create.php` | Modified | Warunkowy wiersz "Koszt wysylki" w tabeli pozycji | + +## Decisions Made + +| Decision | Rationale | Impact | +|----------|-----------|--------| +| Koszt wysylki jako zwykly item w items_json | Taka sama struktura jak produkty — widoki show/print automatycznie pokaza nowa pozycje | Brak zmian w widokach podgladu/wydruku paragonu | + +## Deviations from Plan + +None — plan executed exactly as written. + +## Issues Encountered + +None. + +## Next Phase Readiness + +**Ready:** +- Istniejace widoki podgladu/wydruku paragonow czytaja z items_json i automatycznie pokaza pozycje wysylki + +**Concerns:** +- None + +**Blockers:** +- None + +--- +*Phase: 70-receipt-shipping-cost, Plan: 01* +*Completed: 2026-04-06* diff --git a/.vscode/ftp-kr.sync.cache.json b/.vscode/ftp-kr.sync.cache.json index 18bc935..3eb892b 100644 --- a/.vscode/ftp-kr.sync.cache.json +++ b/.vscode/ftp-kr.sync.cache.json @@ -600,14 +600,14 @@ "DOCS": { "ARCHITECTURE.md": { "type": "-", - "size": 40484, - "lmtime": 1774909776700, + "size": 41990, + "lmtime": 1775318401130, "modified": false }, "DB_SCHEMA.md": { "type": "-", - "size": 33408, - "lmtime": 1775203394938, + "size": 33647, + "lmtime": 1775316434590, "modified": false }, "ORDERS_SCHEMA_APILO_DRAFT.md": { @@ -630,8 +630,8 @@ }, "TECH_CHANGELOG.md": { "type": "-", - "size": 73079, - "lmtime": 1775203398451, + "size": 74741, + "lmtime": 1775318410629, "modified": false }, "todo.md": { @@ -1935,6 +1935,18 @@ }, "modules": { "jquery-alerts": { + "jquery-alerts.css": { + "type": "-", + "size": 2012, + "lmtime": 1775316185626, + "modified": false + }, + "jquery-alerts.css.map": { + "type": "-", + "size": 5204, + "lmtime": 1775316185626, + "modified": false + }, "jquery-alerts.js": { "type": "-", "size": 5768, @@ -1952,14 +1964,14 @@ "scss": { "app.css": { "type": "-", - "size": 58395, - "lmtime": 1775065613098, + "size": 58886, + "lmtime": 1775316185626, "modified": false }, "app.css.map": { "type": "-", - "size": 112306, - "lmtime": 0, + "size": 157009, + "lmtime": 1775316185626, "modified": false }, "app.scss": { @@ -1970,14 +1982,14 @@ }, "login.css": { "type": "-", - "size": 6615, - "lmtime": 0, + "size": 7437, + "lmtime": 1775316185626, "modified": false }, "login.css.map": { "type": "-", - "size": 17857, - "lmtime": 0, + "size": 19929, + "lmtime": 1775316185626, "modified": false }, "login.scss": { @@ -2200,9 +2212,9 @@ }, "cron.php": { "type": "-", - "size": 10176, + "size": 8536, "lmtime": 1774302948459, - "modified": false + "modified": true }, "database.php": { "type": "-", @@ -2222,10 +2234,16 @@ "lmtime": 1774728209847, "modified": false }, + "email-templates-form.php": { + "type": "-", + "size": 9335, + "lmtime": 1775318330251, + "modified": false + }, "email-templates.php": { "type": "-", - "size": 14291, - "lmtime": 1774701677322, + "size": 5430, + "lmtime": 1775318475603, "modified": false }, "gs1.php": { @@ -2312,8 +2330,8 @@ "routes": { "web.php": { "type": "-", - "size": 27879, - "lmtime": 1775245840098, + "size": 28097, + "lmtime": 1775318241324, "modified": false } }, @@ -2972,9 +2990,9 @@ }, "EmailTemplateController.php": { "type": "-", - "size": 9862, - "lmtime": 1774564951844, - "modified": true + "size": 11190, + "lmtime": 1775318234484, + "modified": false }, "EmailTemplateRepository.php": { "type": "-", @@ -3160,8 +3178,8 @@ }, "DeliveryStatus.php": { "type": "-", - "size": 19836, - "lmtime": 1775243494668, + "size": 23069, + "lmtime": 1775317051145, "modified": false }, "InpostShipmentService.php": { @@ -3304,8 +3322,8 @@ "phpunit": { "test-results": { "type": "-", - "size": 3083, - "lmtime": 1774707817763, + "size": 3404, + "lmtime": 1775317059568, "modified": false } } diff --git a/resources/views/orders/receipt-create.php b/resources/views/orders/receipt-create.php index 675b801..3f014a5 100644 --- a/resources/views/orders/receipt-create.php +++ b/resources/views/orders/receipt-create.php @@ -4,6 +4,7 @@ $itemsList = is_array($items ?? null) ? $items : []; $configsList = is_array($configs ?? null) ? $configs : []; $sellerData = is_array($seller ?? null) ? $seller : []; $totalGrossVal = (float) ($totalGross ?? 0); +$deliveryPriceVal = (float) ($deliveryPrice ?? 0); $orderIdVal = (int) ($orderId ?? 0); $existingReceiptsList = is_array($existingReceipts ?? null) ? $existingReceipts : []; $hasExistingReceipts = $existingReceiptsList !== []; @@ -94,6 +95,16 @@ $hasExistingReceipts = $existingReceiptsList !== []; + 0): ?> + + + Koszt wysylki +
-
-
+ 1 + + + + diff --git a/src/Modules/Accounting/ReceiptController.php b/src/Modules/Accounting/ReceiptController.php index 8956011..ac8d55c 100644 --- a/src/Modules/Accounting/ReceiptController.php +++ b/src/Modules/Accounting/ReceiptController.php @@ -50,7 +50,8 @@ final class ReceiptController $order = is_array($details['order'] ?? null) ? $details['order'] : []; $items = is_array($details['items'] ?? null) ? $details['items'] : []; - $totalGross = $this->receiptService->calculateTotalGross($items); + $deliveryPrice = (float) ($order['delivery_price'] ?? 0); + $totalGross = $this->receiptService->calculateTotalGross($items, $deliveryPrice); $html = $this->template->render('orders/receipt-create', [ 'title' => $this->translator->get('receipts.create.title'), @@ -64,6 +65,7 @@ final class ReceiptController 'configs' => array_values($configs), 'seller' => $this->companySettings->getSettings(), 'totalGross' => $totalGross, + 'deliveryPrice' => $deliveryPrice, 'existingReceipts' => $existingReceipts, ], 'layouts/app'); diff --git a/src/Modules/Accounting/ReceiptService.php b/src/Modules/Accounting/ReceiptService.php index 94b711e..cf7b4a4 100644 --- a/src/Modules/Accounting/ReceiptService.php +++ b/src/Modules/Accounting/ReceiptService.php @@ -61,7 +61,7 @@ final class ReceiptService $orderReference = $this->resolveOrderReference($config, $order); $sellerSnapshot = $this->buildSellerSnapshot(); $buyerSnapshot = $this->buildBuyerSnapshot($addresses); - ['items' => $itemsSnapshot, 'total_gross' => $totalGross] = $this->buildItemsSnapshot($items); + ['items' => $itemsSnapshot, 'total_gross' => $totalGross] = $this->buildItemsSnapshot($items, $order); $receiptNumber = $this->receipts->getNextNumber( $configId, @@ -93,7 +93,7 @@ final class ReceiptService /** * @param list> $items */ - public function calculateTotalGross(array $items): float + public function calculateTotalGross(array $items, float $deliveryPrice = 0.0): float { $total = 0.0; foreach ($items as $item) { @@ -101,6 +101,9 @@ final class ReceiptService $price = $item['original_price_with_tax'] !== null ? (float) $item['original_price_with_tax'] : 0.0; $total += $qty * $price; } + if ($deliveryPrice > 0) { + $total += $deliveryPrice; + } return $total; } @@ -246,9 +249,10 @@ final class ReceiptService /** * @param list> $items + * @param array $order * @return array{items: list>, total_gross: float} */ - private function buildItemsSnapshot(array $items): array + private function buildItemsSnapshot(array $items, array $order): array { $itemsSnapshot = []; $totalGross = 0.0; @@ -267,6 +271,19 @@ final class ReceiptService ]; } + $deliveryPrice = (float) ($order['delivery_price'] ?? 0); + if ($deliveryPrice > 0) { + $totalGross += $deliveryPrice; + $itemsSnapshot[] = [ + 'name' => 'Koszt wysylki', + 'quantity' => 1.0, + 'price' => $deliveryPrice, + 'total' => $deliveryPrice, + 'sku' => '', + 'ean' => '', + ]; + } + return [ 'items' => $itemsSnapshot, 'total_gross' => $totalGross,