fix: poprawny koszt transportu na /koszyk-podsumowanie
Na podstronie /koszyk-podsumowanie transport z flaga delivery_free=1 byl pokazywany zawsze za 0,00 zl, niezaleznie od wartosci koszyka. Teraz kontroler wylicza transport_cost_effective i free_delivery_applies uwzgledniajac prog settings.free_delivery, a szablon uzywa tych kluczy. - Nowa chroniona metoda ShopBasketController::calculateTransportCostForSummary - Dodane 6 testow jednostkowych (ShopBasketControllerSummaryViewTest) - Suita: 834 testy / 2318 assertions OK Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -14,7 +14,7 @@ Właściciel sklepu internetowego ma pełną kontrolę nad sprzedażą online -
|
|||||||
|-----------|-------|
|
|-----------|-------|
|
||||||
| Version | 0.333 |
|
| Version | 0.333 |
|
||||||
| Status | Production |
|
| Status | Production |
|
||||||
| Last Updated | 2026-04-19 |
|
| Last Updated | 2026-04-20 |
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
@@ -31,6 +31,7 @@ Właściciel sklepu internetowego ma pełną kontrolę nad sprzedażą online -
|
|||||||
- [x] Ochrona przed podwójnym składaniem zamówienia
|
- [x] Ochrona przed podwójnym składaniem zamówienia
|
||||||
- [x] Domain-Driven Architecture (migracja z legacy zakończona)
|
- [x] Domain-Driven Architecture (migracja z legacy zakończona)
|
||||||
- [x] Szybka edycja custom_label_0..4 na liscie produktow admina (toggle sesyjny + autocomplete)
|
- [x] Szybka edycja custom_label_0..4 na liscie produktow admina (toggle sesyjny + autocomplete)
|
||||||
|
- [x] Poprawna kalkulacja kosztu transportu na /koszyk-podsumowanie (fix delivery_free bez uwzglednienia progu)
|
||||||
|
|
||||||
### Active (In Progress)
|
### Active (In Progress)
|
||||||
|
|
||||||
@@ -81,12 +82,13 @@ Właściciel sklepu internetowego ma pełną kontrolę nad sprzedażą online -
|
|||||||
| Własny silnik zamiast frameworka | Pełna kontrola, brak narzutów | - | Active |
|
| Własny silnik zamiast frameworka | Pełna kontrola, brak narzutów | - | Active |
|
||||||
| `id` w tabbed FormEdit przez `hiddenFields` | Zapobiega insert zamiast update przy edycji encji | 2026-04-18 | Active |
|
| `id` w tabbed FormEdit przez `hiddenFields` | Zapobiega insert zamiast update przy edycji encji | 2026-04-18 | Active |
|
||||||
| Inline custom labels w product list przez sesyjny toggle | Szybszy workflow dla Google XML bez wejscia w edycje produktu | 2026-04-19 | Active |
|
| Inline custom labels w product list przez sesyjny toggle | Szybszy workflow dla Google XML bez wejscia w edycje produktu | 2026-04-19 | Active |
|
||||||
|
| Kalkulacja kosztu transportu na /koszyk-podsumowanie w kontrolerze (nie w szablonie) | Spojnosc logiki progu darmowej dostawy miedzy /koszyk i /koszyk-podsumowanie | 2026-04-20 | Active |
|
||||||
|
|
||||||
## Success Metrics
|
## Success Metrics
|
||||||
|
|
||||||
| Metric | Target | Current | Status |
|
| Metric | Target | Current | Status |
|
||||||
|--------|--------|---------|--------|
|
|--------|--------|---------|--------|
|
||||||
| Testy | >800 | 821 | On track |
|
| Testy | >800 | 834 | On track |
|
||||||
| Pokrycie architektury DDD | 100% | 100% | Achieved |
|
| Pokrycie architektury DDD | 100% | 100% | Achieved |
|
||||||
|
|
||||||
## Tech Stack
|
## Tech Stack
|
||||||
@@ -115,4 +117,4 @@ Quick Reference:
|
|||||||
|
|
||||||
---
|
---
|
||||||
*PROJECT.md - Updated when requirements or context change*
|
*PROJECT.md - Updated when requirements or context change*
|
||||||
*Last updated: 2026-04-19 after Phase 16*
|
*Last updated: 2026-04-20 after Phase 17*
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ Status: Planning
|
|||||||
| 8 | Apilo orders not sending — diagnoza i naprawa | 1 | Done | 2026-03-16 |
|
| 8 | Apilo orders not sending — diagnoza i naprawa | 1 | Done | 2026-03-16 |
|
||||||
| 9 | Apilo email notification + infinite retry | 1 | Done | 2026-03-19 |
|
| 9 | Apilo email notification + infinite retry | 1 | Done | 2026-03-19 |
|
||||||
| 15 | Scontainers edit saves as new record | 1 | Done | 2026-04-18 |
|
| 15 | Scontainers edit saves as new record | 1 | Done | 2026-04-18 |
|
||||||
|
| 17 | Cart summary transport cost fix | 1 | Done | 2026-04-20 |
|
||||||
|
|
||||||
## Feature
|
## Feature
|
||||||
|
|
||||||
@@ -118,5 +119,11 @@ Status: Planning
|
|||||||
|
|
||||||
**Scope:** Dodac przycisk "Pokaz etykiety niestandardowe" obok "Dodaj produkt", zapisywac jego stan w sesji, pokazac 5 pol custom label pod nazwa produktu, zapisac wartosci do bazy i zapewnic podpowiedzi z juz istniejacych wartosci.
|
**Scope:** Dodac przycisk "Pokaz etykiety niestandardowe" obok "Dodaj produkt", zapisywac jego stan w sesji, pokazac 5 pol custom label pod nazwa produktu, zapisac wartosci do bazy i zapewnic podpowiedzi z juz istniejacych wartosci.
|
||||||
|
|
||||||
|
### Phase 17 - Cart summary transport cost fix
|
||||||
|
|
||||||
|
**Problem:** Na /koszyk-podsumowanie kazdy transport z flaga `delivery_free = 1` pokazywany jest za 0,00 zl, niezaleznie od tego czy koszyk osiagnal prog darmowej dostawy `settings.free_delivery`. Szablon summary-view.php sprawdza tylko flage, nie wartosc koszyka. Suma koncowa zamowienia jest zaniżona.
|
||||||
|
|
||||||
|
**Scope:** Przekazac z `ShopBasketController::summaryView()` do szablonu wyliczony `transport_cost_effective` i flage `free_delivery_applies` uwzgledniajaca prog. Zaktualizowac summary-view.php aby uzywal tych kluczy zamiast surowej flagi `delivery_free`. Test jednostkowy dla logiki wyliczenia.
|
||||||
|
|
||||||
---
|
---
|
||||||
*Last updated: 2026-04-19 (Phase 16 complete)*
|
*Last updated: 2026-04-20 (Phase 17 complete)*
|
||||||
|
|||||||
@@ -5,19 +5,19 @@
|
|||||||
See: .paul/PROJECT.md (updated 2026-04-18)
|
See: .paul/PROJECT.md (updated 2026-04-18)
|
||||||
|
|
||||||
**Core value:** Właściciel sklepu ma pełną kontrolę nad sprzedażą online w jednym systemie pisanym od podstaw, bez narzutów zewnętrznych platform.
|
**Core value:** Właściciel sklepu ma pełną kontrolę nad sprzedażą online w jednym systemie pisanym od podstaw, bez narzutów zewnętrznych platform.
|
||||||
**Current focus:** Phase 16 complete - loop closed
|
**Current focus:** Phase 17 complete - loop closed
|
||||||
|
|
||||||
## Current Position
|
## Current Position
|
||||||
|
|
||||||
Milestone: Feature
|
Milestone: Hotfix
|
||||||
Phase: 16 of 16 (Product list custom labels quick edit) - Complete
|
Phase: 17 of 17 (Cart summary transport cost fix) - Complete
|
||||||
Plan: 16-01 complete
|
Plan: 17-01 complete
|
||||||
Status: UNIFY complete, ready for next PLAN loop
|
Status: UNIFY complete, ready for next PLAN loop (transition-phase pending)
|
||||||
Last activity: 2026-04-19 - Closed loop for .paul/phases/16-product-list-custom-labels/16-01-PLAN.md
|
Last activity: 2026-04-20 - Closed loop for .paul/phases/17-cart-summary-transport-cost-fix/17-01-PLAN.md
|
||||||
|
|
||||||
Progress:
|
Progress:
|
||||||
- Milestone: [##########] 100%
|
- Milestone: [##########] 100%
|
||||||
- Phase 16: [##########] 100%
|
- Phase 17: [##########] 100%
|
||||||
|
|
||||||
## Loop Position
|
## Loop Position
|
||||||
|
|
||||||
@@ -42,10 +42,17 @@ Phase 13: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-03-25]
|
|||||||
Phase 14: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-04-16]
|
Phase 14: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-04-16]
|
||||||
Phase 15: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-04-18]
|
Phase 15: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-04-18]
|
||||||
Phase 16: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-04-19]
|
Phase 16: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-04-19]
|
||||||
|
Phase 17: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-04-20]
|
||||||
```
|
```
|
||||||
## Accumulated Context
|
## Accumulated Context
|
||||||
|
|
||||||
### Decisions
|
### Decisions
|
||||||
|
- 2026-04-20: Phase 17 loop closed with SUMMARY at .paul/phases/17-cart-summary-transport-cost-fix/17-01-SUMMARY.md
|
||||||
|
- 2026-04-20: Transition-phase git commit for Phase 17 not executed in this UNIFY run (deferred)
|
||||||
|
- 2026-04-20: Phase 17 APPLY complete - human-verify checkpoint approved, 834 testow zielonych (6 nowych)
|
||||||
|
- 2026-04-20: Created Phase 17 plan at .paul/phases/17-cart-summary-transport-cost-fix/17-01-PLAN.md
|
||||||
|
- 2026-04-20: Phase 17 bug root cause - summary-view.php blindly shows 0 zl gdy transport.delivery_free=1 bez sprawdzenia progu settings.free_delivery
|
||||||
|
- 2026-04-20: Phase 17 fix - nowa chroniona metoda ShopBasketController::calculateTransportCostForSummary zwraca transport_cost_effective + free_delivery_applies; szablon uzywa tych kluczy zamiast delivery_free
|
||||||
- 2026-04-19: Created Phase 16 plan at .paul/phases/16-product-list-custom-labels/16-01-PLAN.md
|
- 2026-04-19: Created Phase 16 plan at .paul/phases/16-product-list-custom-labels/16-01-PLAN.md
|
||||||
- 2026-04-19: Phase 16 scope includes session toggle + inline custom_label_0..4 edit + suggestions on product list
|
- 2026-04-19: Phase 16 scope includes session toggle + inline custom_label_0..4 edit + suggestions on product list
|
||||||
- 2026-04-19: Override approved by user - proceeded without required /feature-dev skill in Phase 16 APPLY
|
- 2026-04-19: Override approved by user - proceeded without required /feature-dev skill in Phase 16 APPLY
|
||||||
@@ -90,9 +97,9 @@ None.
|
|||||||
|
|
||||||
## Session Continuity
|
## Session Continuity
|
||||||
|
|
||||||
Last session: 2026-04-19
|
Last session: 2026-04-20
|
||||||
Stopped at: Phase 16 complete, loop closed
|
Stopped at: Phase 17 complete, loop closed
|
||||||
Next action: Start next milestone or create next phase plan
|
Next action: Start next milestone or create next phase plan (transition-phase commit pending)
|
||||||
Resume file: .paul/phases/16-product-list-custom-labels/16-01-SUMMARY.md
|
Resume file: .paul/phases/17-cart-summary-transport-cost-fix/17-01-SUMMARY.md
|
||||||
---
|
---
|
||||||
*STATE.md — Updated after every significant action*
|
*STATE.md — Updated after every significant action*
|
||||||
|
|||||||
19
.paul/changelog/2026-04-20.md
Normal file
19
.paul/changelog/2026-04-20.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# 2026-04-20
|
||||||
|
|
||||||
|
## Co zrobiono
|
||||||
|
|
||||||
|
- [Phase 17, Plan 01] Naprawa kosztu transportu na /koszyk-podsumowanie — transport z flaga delivery_free=1 pokazuje teraz rzeczywisty koszt ponizej progu settings.free_delivery, a 0,00 zl dopiero po osiagnieciu progu
|
||||||
|
- Dodana chroniona metoda `ShopBasketController::calculateTransportCostForSummary` wyliczajaca `transport_cost_effective` i `free_delivery_applies`
|
||||||
|
- Szablon `templates/shop-basket/summary-view.php` uzywa tych kluczy zamiast surowej flagi `delivery_free`
|
||||||
|
- Nowy plik testow `ShopBasketControllerSummaryViewTest` (6 testow, 12 assertions)
|
||||||
|
- Pelna suita PHPUnit: 834/834 OK (2318 assertions)
|
||||||
|
|
||||||
|
## Zmienione pliki
|
||||||
|
|
||||||
|
- `autoload/front/Controllers/ShopBasketController.php`
|
||||||
|
- `templates/shop-basket/summary-view.php`
|
||||||
|
- `tests/Unit/front/Controllers/ShopBasketControllerSummaryViewTest.php`
|
||||||
|
- `.paul/phases/17-cart-summary-transport-cost-fix/17-01-PLAN.md`
|
||||||
|
- `.paul/phases/17-cart-summary-transport-cost-fix/17-01-SUMMARY.md`
|
||||||
|
- `.paul/STATE.md`
|
||||||
|
- `.paul/ROADMAP.md`
|
||||||
@@ -2,6 +2,13 @@
|
|||||||
|
|
||||||
> Chronologiczny log zmian technicznych — co i dlaczego.
|
> Chronologiczny log zmian technicznych — co i dlaczego.
|
||||||
|
|
||||||
|
## v0.349 (2026-04-20)
|
||||||
|
|
||||||
|
- Naprawiono wyswietlanie kosztu transportu na /koszyk-podsumowanie: transporty z `delivery_free=1` pokazuja teraz rzeczywisty koszt ponizej progu `settings.free_delivery`, a 0,00 zl dopiero po osiagnieciu progu (spojnie z lista na /koszyk).
|
||||||
|
- Dodano chroniona metode `ShopBasketController::calculateTransportCostForSummary()` wyliczajaca `transport_cost_effective` + `free_delivery_applies` — logika widokowa przeniesiona z szablonu do kontrolera.
|
||||||
|
- Szablon `templates/shop-basket/summary-view.php` uzywa nowych kluczy zamiast sprawdzania surowej flagi `delivery_free`.
|
||||||
|
- Dodano 6 testow jednostkowych (`ShopBasketControllerSummaryViewTest`) pokrywajacych AC + edge cases (prog rowny, prog 0, transport null). Suita: 834 testy / 2318 assertions.
|
||||||
|
|
||||||
## v0.348 (2026-04-19)
|
## v0.348 (2026-04-19)
|
||||||
|
|
||||||
- Dodano przełącznik widoczności etykiet niestandardowych na liście produktów w panelu admina, z zapisem stanu w sesji.
|
- Dodano przełącznik widoczności etykiet niestandardowych na liście produktów w panelu admina, z zapisem stanu w sesji.
|
||||||
|
|||||||
@@ -3686,3 +3686,5 @@ Dodać możliwość ustawienia limitu znaków w wiadomościach do produktu
|
|||||||
- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:971 - Rename function "generate_sku_code" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100)
|
- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:971 - Rename function "generate_sku_code" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100)
|
||||||
- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:989 - Rename function "product_combination" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100)
|
- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:989 - Rename function "product_combination" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100)
|
||||||
|
|
||||||
|
|
||||||
|
## SonarQube - v0.349 - brak nowych issues
|
||||||
|
|||||||
191
.paul/phases/17-cart-summary-transport-cost-fix/17-01-PLAN.md
Normal file
191
.paul/phases/17-cart-summary-transport-cost-fix/17-01-PLAN.md
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
---
|
||||||
|
phase: 17-cart-summary-transport-cost-fix
|
||||||
|
plan: 01
|
||||||
|
type: execute
|
||||||
|
wave: 1
|
||||||
|
depends_on: []
|
||||||
|
files_modified:
|
||||||
|
- autoload/front/Controllers/ShopBasketController.php
|
||||||
|
- templates/shop-basket/summary-view.php
|
||||||
|
- tests/Unit/front/Controllers/ShopBasketControllerSummaryViewTest.php
|
||||||
|
autonomous: false
|
||||||
|
delegation: off
|
||||||
|
---
|
||||||
|
|
||||||
|
<objective>
|
||||||
|
## Goal
|
||||||
|
Naprawic blad na stronie /koszyk-podsumowanie, gdzie wybrana forma wysylki oraz laczna kwota zamowienia pokazywane sa za 0,00 zl, mimo ze koszyk nie osiagnal progu darmowej dostawy.
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
Klient widzi nieprawidlowe podsumowanie zamowienia. Koszt transportu w szablonie summary-view.php jest redukowany do zera zawsze, gdy transport ma flage `delivery_free = 1`, bez sprawdzenia czy wartosc koszyka przekroczyla prog `$settings['free_delivery']`. W efekcie klient widzi "0,00 zl" i zaniżona sume zamowienia. Po zlozeniu zamowienia dane w bazie i ostatecznej cenie moga sie roznic, co psuje zaufanie i ksiegowosc.
|
||||||
|
|
||||||
|
## Output
|
||||||
|
- ShopBasketController::summaryView() przekazuje do szablonu koszt transportu po uwzglednieniu progu darmowej dostawy (nowy klucz `transport_cost_effective` oraz `free_delivery_applies`).
|
||||||
|
- Szablon summary-view.php pokazuje koszt transportu i sume koncowa na podstawie tych kluczy zamiast surowej flagi `delivery_free`.
|
||||||
|
- Nowy test jednostkowy potwierdza logike wyliczania kosztu w kontrolerze dla 3 scenariuszy (basket ponizej progu, basket rowny progowi, transport bez `delivery_free`).
|
||||||
|
</objective>
|
||||||
|
|
||||||
|
<context>
|
||||||
|
## Project Context
|
||||||
|
@.paul/PROJECT.md
|
||||||
|
@.paul/ROADMAP.md
|
||||||
|
@.paul/STATE.md
|
||||||
|
|
||||||
|
## Source Files
|
||||||
|
@autoload/front/Controllers/ShopBasketController.php
|
||||||
|
@autoload/Domain/Transport/TransportRepository.php
|
||||||
|
@autoload/Domain/Basket/BasketCalculator.php
|
||||||
|
@templates/shop-basket/summary-view.php
|
||||||
|
@templates/shop-basket/basket-transport-methods.php
|
||||||
|
|
||||||
|
## Powiazane pliki (do odwolania)
|
||||||
|
- settings.free_delivery w `pp_settings` (globalny prog darmowej dostawy)
|
||||||
|
- Helpers::normalize_decimal / Helpers::decimal (format kwot)
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<acceptance_criteria>
|
||||||
|
|
||||||
|
## AC-1: Transport z flaga delivery_free ponizej progu pokazuje rzeczywisty koszt
|
||||||
|
```gherkin
|
||||||
|
Given transport ma `delivery_free = 1`, cost = 15.00 zl, a `$settings['free_delivery']` = 300 zl
|
||||||
|
And wartosc koszyka (po kuponie) wynosi 150 zl
|
||||||
|
When klient wchodzi na /koszyk-podsumowanie
|
||||||
|
Then linia transportu pokazuje "15,00 zl"
|
||||||
|
And laczna kwota zamowienia zawiera te 15,00 zl
|
||||||
|
```
|
||||||
|
|
||||||
|
## AC-2: Transport z flaga delivery_free powyzej progu pokazuje 0,00 zl
|
||||||
|
```gherkin
|
||||||
|
Given transport ma `delivery_free = 1`, cost = 15.00 zl, a `$settings['free_delivery']` = 300 zl
|
||||||
|
And wartosc koszyka (po kuponie) wynosi 350 zl
|
||||||
|
When klient wchodzi na /koszyk-podsumowanie
|
||||||
|
Then linia transportu pokazuje "0,00 zl"
|
||||||
|
And laczna kwota nie zawiera kosztu transportu
|
||||||
|
```
|
||||||
|
|
||||||
|
## AC-3: Transport bez flagi delivery_free zawsze pokazuje swoj koszt
|
||||||
|
```gherkin
|
||||||
|
Given transport ma `delivery_free = 0`, cost = 25.00 zl
|
||||||
|
And wartosc koszyka wynosi 500 zl (powyzej dowolnego progu)
|
||||||
|
When klient wchodzi na /koszyk-podsumowanie
|
||||||
|
Then linia transportu pokazuje "25,00 zl"
|
||||||
|
And laczna kwota zawiera te 25,00 zl
|
||||||
|
```
|
||||||
|
|
||||||
|
## AC-4: Suma testow PHPUnit nie maleje, nowy test zielony
|
||||||
|
```gherkin
|
||||||
|
Given istniejacy zestaw testow `./test.ps1`
|
||||||
|
When uruchamiam pelna suite
|
||||||
|
Then nowy test `ShopBasketControllerSummaryViewTest` przechodzi
|
||||||
|
And zadne istniejace testy nie zaczynaja failowac
|
||||||
|
```
|
||||||
|
|
||||||
|
</acceptance_criteria>
|
||||||
|
|
||||||
|
<tasks>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 1: Przekaz wyliczony koszt transportu do summary-view z kontrolera</name>
|
||||||
|
<files>autoload/front/Controllers/ShopBasketController.php</files>
|
||||||
|
<action>
|
||||||
|
W metodzie `summaryView()` (ok. linia 270):
|
||||||
|
- Po pobraniu `$transport` (findActiveByIdCached) wylicz kwote koszyka po kuponie uzywajac `\Domain\Basket\BasketCalculator::summaryPrice( $basket, $coupon )` - tak jak robi to `transportMethodsFront`.
|
||||||
|
- Wczytaj `$settings['free_delivery']` z globala `$settings`.
|
||||||
|
- Ustaw `free_delivery_applies = false` gdy transport nie istnieje; w przeciwnym razie `true` wtedy i tylko wtedy gdy `$transport['delivery_free'] == 1` ORAZ `normalize_decimal($products_summary) >= normalize_decimal($settings['free_delivery'])`.
|
||||||
|
- Wylicz `transport_cost_effective` = `free_delivery_applies ? 0.0 : (float)$transport['cost']`.
|
||||||
|
- Do `Tpl::view` przekaz dodatkowe klucze `transport_cost_effective` i `free_delivery_applies`.
|
||||||
|
Nie zmieniaj istniejacych kluczy (transport, payment_method itd.) zeby nie zepsuc innych uzyc szablonu.
|
||||||
|
Nie modyfikuj logiki tokenu zamowienia ani guardow.
|
||||||
|
Unikaj: dodawania nowych metod do TransportRepository (kalkulacja nalezy do warstwy koszyka, nie transportu).
|
||||||
|
</action>
|
||||||
|
<verify>Recznie odczytaj plik, upewnij sie ze dane sa w tablicy Tpl::view i sa uzywane deterministycznie dla transport === null.</verify>
|
||||||
|
<done>AC-1, AC-2 i AC-3 zaspokojone po stronie danych; AC-4 kontrolera.</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 2: Zaktualizuj summary-view.php aby uzywal wyliczonych kluczy</name>
|
||||||
|
<files>templates/shop-basket/summary-view.php</files>
|
||||||
|
<action>
|
||||||
|
W bloku "basket-summary" (ok. linii 97-115):
|
||||||
|
- Zamien warunek `$this->transport['delivery_free'] == 1` na `$this->free_delivery_applies`.
|
||||||
|
- Zamiast `$this->transport['cost']` wyswietlaj `$this->transport_cost_effective` w galezi "else" oraz w kwocie koncowej.
|
||||||
|
- Linia koncowej kwoty (order-summary): `$this->free_delivery_applies ? decimal($summary) : decimal($summary + $this->transport_cost_effective)`.
|
||||||
|
- Zadbaj o poprawne wyswietlenie gdy `transport` jest `null` (skeleton: zachowaj stary fallback - brak kosztu dodawanego).
|
||||||
|
Nie modyfikuj pozostalych fragmentow (produkty, adres, GTM itd.).
|
||||||
|
Unikaj: duplikowania logiki progu w szablonie - szablon ma wyswietlac, nie liczyc.
|
||||||
|
</action>
|
||||||
|
<verify>W szablonie nie wystepuje juz `$this->transport['delivery_free']` w tym bloku; nowe klucze sa uzyte dwukrotnie (linia transportu + suma).</verify>
|
||||||
|
<done>AC-1, AC-2, AC-3 zaspokojone po stronie prezentacji.</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 3: Test jednostkowy dla logiki kontrolera</name>
|
||||||
|
<files>tests/Unit/front/Controllers/ShopBasketControllerSummaryViewTest.php</files>
|
||||||
|
<action>
|
||||||
|
Utworz nowy plik testow PHPUnit extending `PHPUnit\Framework\TestCase`.
|
||||||
|
Testuj publiczna metode pomocnicza lub kalkulacje w `summaryView()` przez refleksje/helper - preferowane: wyodrebnic wyliczenie do prywatnej metody i wyeksponowac prywatna metode przez ReflectionMethod (bez zmiany publicznego API).
|
||||||
|
Alternatywa: utworz w kontrolerze protected method `calculateTransportCostForSummary(array $transport = null, array $basket, $coupon, float $freeDeliveryThreshold): array` zwracajaca `['transport_cost_effective' => float, 'free_delivery_applies' => bool]` i pokryj ja testami bezposrednio.
|
||||||
|
Trzy scenariusze (AC-1, AC-2, AC-3) + czwarty: transport === null -> cost 0.0, applies false.
|
||||||
|
Mock `\Domain\Basket\BasketCalculator::summaryPrice` nie jest wymagany - podaj gotowa liczbe w tescie.
|
||||||
|
Test musi sie uruchamiac pod `./test.ps1`.
|
||||||
|
Unikaj: testowania na realnej bazie - stub Medoo zaslugujac na AAA.
|
||||||
|
</action>
|
||||||
|
<verify>Uruchom `./test.ps1 tests/Unit/front/Controllers/ShopBasketControllerSummaryViewTest.php` - 4 testy zielone. Potem `./test.ps1` pelna suite - liczba testow >= 825 (pelna, bez regresji).</verify>
|
||||||
|
<done>AC-4 zaspokojone.</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="checkpoint:human-verify" gate="blocking">
|
||||||
|
<what-built>
|
||||||
|
Poprawka koszt transportu na /koszyk-podsumowanie.
|
||||||
|
</what-built>
|
||||||
|
<how-to-verify>
|
||||||
|
1. W panelu admina upewnij sie, ze co najmniej jedna metoda transportu ma `delivery_free = 1` i niezerowy `cost` (np. 15 zl).
|
||||||
|
2. Ustaw `settings.free_delivery` na np. 300 zl.
|
||||||
|
3. Dodaj do koszyka produkty o wartosci PONIZEJ progu (np. 150 zl).
|
||||||
|
4. Wejdz na /koszyk, wybierz transport z `delivery_free = 1`, przejdz do /koszyk-podsumowanie.
|
||||||
|
5. Potwierdz, ze linia transportu pokazuje "15,00 zl" (nie "0,00 zl") i suma zawiera ten koszt.
|
||||||
|
6. Dolow koszyk do wartosci POWYZEJ progu (>300 zl), odswiez /koszyk-podsumowanie.
|
||||||
|
7. Potwierdz, ze linia transportu pokazuje "0,00 zl" i suma NIE zawiera kosztu transportu.
|
||||||
|
8. Wybierz transport bez `delivery_free = 1` (np. kurier 25 zl), potwierdz ze zawsze pokazuje 25,00 zl.
|
||||||
|
</how-to-verify>
|
||||||
|
<resume-signal>Wpisz "approved" aby zakonczyc, lub opisz niezgodnosc do poprawy.</resume-signal>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
</tasks>
|
||||||
|
|
||||||
|
<boundaries>
|
||||||
|
|
||||||
|
## DO NOT CHANGE
|
||||||
|
- autoload/Domain/Transport/TransportRepository.php (kalkulacja kosztu transportu juz jest w `transportMethodsFront`; nie duplikujemy logiki tam).
|
||||||
|
- autoload/Domain/Basket/BasketCalculator.php (wyliczenie wartosci koszyka pozostaje bez zmian).
|
||||||
|
- templates/shop-basket/basket-transport-methods.php (lista metod na /koszyk dziala poprawnie).
|
||||||
|
- Logika tokenu zamowienia w ShopBasketController (createOrderSubmitToken, consumeOrderSubmitToken).
|
||||||
|
- Struktura bazy danych (brak migracji).
|
||||||
|
|
||||||
|
## SCOPE LIMITS
|
||||||
|
- Plan naprawia WYLACZNIE wyswietlanie kosztu na /koszyk-podsumowanie.
|
||||||
|
- Nie refaktoryzujemy summary-view.php poza blokiem transportu.
|
||||||
|
- Nie zmieniamy mechanizmu cache transportu.
|
||||||
|
- Nie dodajemy nowych ustawien/kolumn w bazie.
|
||||||
|
|
||||||
|
</boundaries>
|
||||||
|
|
||||||
|
<verification>
|
||||||
|
Przed zamknieciem planu:
|
||||||
|
- [ ] `./test.ps1` pelna suite zielona (wszystkie >=824 + 4 nowe testy).
|
||||||
|
- [ ] Recznie zweryfikowano 3 scenariusze na /koszyk-podsumowanie (checkpoint human-verify).
|
||||||
|
- [ ] W summary-view.php nie wystepuje juz `$this->transport['delivery_free']` w sekcji podsumowania.
|
||||||
|
- [ ] Nowy plik testu istnieje i jest w strukturze `tests/Unit/front/Controllers/`.
|
||||||
|
- [ ] Kod zgodny z PHP 7.4 (brak `match`, named arguments itd.).
|
||||||
|
</verification>
|
||||||
|
|
||||||
|
<success_criteria>
|
||||||
|
- Wszystkie 4 AC zaspokojone.
|
||||||
|
- Suita PHPUnit zielona bez regresji.
|
||||||
|
- Checkpoint human-verify zaakceptowany.
|
||||||
|
- Brak nowych ostrzezen/bledow w logach.
|
||||||
|
</success_criteria>
|
||||||
|
|
||||||
|
<output>
|
||||||
|
Po zakonczeniu utworz `.paul/phases/17-cart-summary-transport-cost-fix/17-01-SUMMARY.md`
|
||||||
|
</output>
|
||||||
150
.paul/phases/17-cart-summary-transport-cost-fix/17-01-SUMMARY.md
Normal file
150
.paul/phases/17-cart-summary-transport-cost-fix/17-01-SUMMARY.md
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
---
|
||||||
|
phase: 17-cart-summary-transport-cost-fix
|
||||||
|
plan: 01
|
||||||
|
subsystem: checkout
|
||||||
|
tags: [basket, transport, free-delivery, summary-view, php74]
|
||||||
|
|
||||||
|
requires:
|
||||||
|
- phase: 13-basket-logging-ttl-token
|
||||||
|
provides: createOrderSubmitToken + TTL i logging w basketSave
|
||||||
|
provides:
|
||||||
|
- Poprawna kalkulacja kosztu transportu na /koszyk-podsumowanie
|
||||||
|
- Testowalna chroniona metoda ShopBasketController::calculateTransportCostForSummary
|
||||||
|
affects: [przyszle zmiany checkoutu, kupony, promocje darmowej dostawy]
|
||||||
|
|
||||||
|
tech-stack:
|
||||||
|
added: []
|
||||||
|
patterns:
|
||||||
|
- "Logika prezentacyjna kosztu transportu trzymana w kontrolerze, nie w szablonie"
|
||||||
|
- "Chronione metody pomocnicze testowane przez ReflectionMethod"
|
||||||
|
|
||||||
|
key-files:
|
||||||
|
created:
|
||||||
|
- tests/Unit/front/Controllers/ShopBasketControllerSummaryViewTest.php
|
||||||
|
modified:
|
||||||
|
- autoload/front/Controllers/ShopBasketController.php
|
||||||
|
- templates/shop-basket/summary-view.php
|
||||||
|
|
||||||
|
key-decisions:
|
||||||
|
- "Kalkulacja kosztu transportu zostaje w warstwie kontrolera (summaryView), nie w TransportRepository — Repository dostarcza dane, kontroler interpretuje je dla konkretnego widoku"
|
||||||
|
- "Metoda calculateTransportCostForSummary pozostaje protected i jest testowana przez Reflection (public API kontrolera bez zmian)"
|
||||||
|
|
||||||
|
patterns-established:
|
||||||
|
- "Szablon summary-view otrzymuje gotowe klucze prezentacyjne (transport_cost_effective, free_delivery_applies) zamiast liczyc progi w locie"
|
||||||
|
|
||||||
|
duration: ~25min
|
||||||
|
started: 2026-04-20T00:00:00Z
|
||||||
|
completed: 2026-04-20T00:25:00Z
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 17 Plan 01: Cart summary transport cost fix — Summary
|
||||||
|
|
||||||
|
**Na /koszyk-podsumowanie wybrany transport z flaga delivery_free=1 pokazuje teraz rzeczywisty koszt ponizej progu darmowej dostawy i 0,00 zl powyzej progu — zgodnie z logika listy transportow na /koszyk.**
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
| Metric | Value |
|
||||||
|
|--------|-------|
|
||||||
|
| Duration | ~25 min |
|
||||||
|
| Started | 2026-04-20 |
|
||||||
|
| Completed | 2026-04-20 |
|
||||||
|
| Tasks | 4 completed (3 auto + 1 checkpoint) |
|
||||||
|
| Files modified | 2 modified + 1 created |
|
||||||
|
|
||||||
|
## Acceptance Criteria Results
|
||||||
|
|
||||||
|
| Criterion | Status | Notes |
|
||||||
|
|-----------|--------|-------|
|
||||||
|
| AC-1: Transport z delivery_free ponizej progu pokazuje rzeczywisty koszt | Pass | Test `testTransportWithDeliveryFreeBelowThresholdShowsRealCost` + manualna weryfikacja |
|
||||||
|
| AC-2: Transport z delivery_free powyzej progu pokazuje 0,00 zl | Pass | Test `testTransportWithDeliveryFreeAboveThresholdShowsZero` + manualna weryfikacja |
|
||||||
|
| AC-3: Transport bez flagi delivery_free zawsze pokazuje koszt | Pass | Test `testTransportWithoutDeliveryFreeAlwaysShowsCost` + manualna weryfikacja |
|
||||||
|
| AC-4: Suita PHPUnit zielona, nowy test przechodzi | Pass | 834/834 OK, 2318 assertions (6 nowych testow) |
|
||||||
|
|
||||||
|
## Accomplishments
|
||||||
|
|
||||||
|
- Chroniona metoda `ShopBasketController::calculateTransportCostForSummary()` enkapsuluje regule progowa darmowej dostawy i jest czysto testowalna.
|
||||||
|
- Szablon `summary-view.php` pozbyty dwoch duplikatow logiki `delivery_free == 1` — uzywa teraz gotowych kluczy widokowych.
|
||||||
|
- 6 testow jednostkowych pokrywa 3 AC i 3 edge case'y (transport null, prog 0, wartosc koszyka rowna progowi).
|
||||||
|
- Pelna suita zgadza sie z docs/MEMORY.md (>800 testow, 821 -> 834 po fazie).
|
||||||
|
|
||||||
|
## Task Commits
|
||||||
|
|
||||||
|
Commit transition-phase jeszcze nie wykonany w tym UNIFY (patrz Deviations).
|
||||||
|
|
||||||
|
| Task | Commit | Type | Description |
|
||||||
|
|------|--------|------|-------------|
|
||||||
|
| Task 1: Calc effective cost w kontrolerze | (pending) | fix | ShopBasketController::summaryView + calculateTransportCostForSummary |
|
||||||
|
| Task 2: summary-view.php uzywa nowych kluczy | (pending) | fix | Usuniety odwolanie do transport.delivery_free w bloku podsumowania |
|
||||||
|
| Task 3: Nowy test jednostkowy | (pending) | test | ShopBasketControllerSummaryViewTest (6 testow) |
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
|
||||||
|
| File | Change | Purpose |
|
||||||
|
|------|--------|---------|
|
||||||
|
| `autoload/front/Controllers/ShopBasketController.php` | Modified | Dodana protected method calculateTransportCostForSummary; summaryView przekazuje transport_cost_effective + free_delivery_applies |
|
||||||
|
| `templates/shop-basket/summary-view.php` | Modified | Wiersz kosztu transportu i suma koncowa uzywaja nowych kluczy zamiast transport.delivery_free |
|
||||||
|
| `tests/Unit/front/Controllers/ShopBasketControllerSummaryViewTest.php` | Created | 6 testow jednostkowych dla logiki kalkulacji kosztu |
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
|
||||||
|
| Decision | Rationale | Impact |
|
||||||
|
|----------|-----------|--------|
|
||||||
|
| Kalkulacja w kontrolerze, nie w TransportRepository | Repository juz ma `transportMethodsFront` robiace to samo, ale dla listy metod — dla pojedynczego wybranego transportu to decyzja widokowa nalezaca do kontrolera | Brak zmiany publicznego API Repository |
|
||||||
|
| protected + Reflection do testow | Zgodne z istniejacym wzorcem `ShopBasketControllerTest` (Reflection), nie rozszerza publicznego API | Test izolowany od sesji i globali |
|
||||||
|
| Boundary na prog > 0 | Jesli `settings.free_delivery = 0`, darmowa dostawa jest wylaczona (brak progu = brak regul) | Ochrona przed niezamierzonym zerowaniem kosztu w sklepach bez tej funkcji |
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
### Summary
|
||||||
|
|
||||||
|
| Type | Count | Impact |
|
||||||
|
|------|-------|--------|
|
||||||
|
| Auto-fixed | 0 | — |
|
||||||
|
| Scope additions | 2 | 2 dodatkowe edge-case testy (boundary rowny prog + prog 0) |
|
||||||
|
| Deferred | 1 | Git commit transition-phase do wykonania w transition-phase lub rece |
|
||||||
|
|
||||||
|
**Total impact:** Bez scope creepu; dodatki to defensywne testy edge-case'ow.
|
||||||
|
|
||||||
|
### Auto-fixed Issues
|
||||||
|
|
||||||
|
None.
|
||||||
|
|
||||||
|
### Scope Additions
|
||||||
|
|
||||||
|
**1. Test dla wartosci koszyka rownej progowi**
|
||||||
|
- **Found during:** Task 3 (test jednostkowy)
|
||||||
|
- **Issue:** Plan AC-2 mowi "powyzej progu", granica rowna progowi nie byla pokryta
|
||||||
|
- **Fix:** Dodany `testTransportWithDeliveryFreeAtExactThresholdShowsZero`
|
||||||
|
- **Rationale:** Stare `transportMethodsFront` uzywa `>=` — utrzymana spojnosc
|
||||||
|
|
||||||
|
**2. Test dla settings.free_delivery = 0**
|
||||||
|
- **Found during:** Task 1 (implementacja)
|
||||||
|
- **Issue:** Sklepy bez ustawionego progu darmowej dostawy nie mogly miec zerowanych transportow; guard na > 0 wart pokrycia testem
|
||||||
|
- **Fix:** Dodany `testZeroFreeDeliveryThresholdDisablesFreeDelivery`
|
||||||
|
|
||||||
|
### Deferred Items
|
||||||
|
|
||||||
|
- Transition-phase git commit do uruchomienia w ramach `/paul:transition` lub recznego commita (spojne z historycznym wzorcem faz 15 i 16).
|
||||||
|
|
||||||
|
## Issues Encountered
|
||||||
|
|
||||||
|
| Issue | Resolution |
|
||||||
|
|-------|------------|
|
||||||
|
| `test.ps1` nie istnieje w repo (pomimo wzmianki w CLAUDE.md) | Uruchomiono phpunit.phar bezposrednio przez `C:/xampp/php/php.exe phpunit.phar -c phpunit.xml` |
|
||||||
|
|
||||||
|
## Next Phase Readiness
|
||||||
|
|
||||||
|
**Ready:**
|
||||||
|
- Logika kosztu transportu w checkoutu spojna miedzy /koszyk i /koszyk-podsumowanie.
|
||||||
|
- Pelna suita zielona.
|
||||||
|
|
||||||
|
**Concerns:**
|
||||||
|
- Git commit nie wykonany automatycznie — nalezy domknac w transition-phase.
|
||||||
|
- CLAUDE.md odwoluje sie do `./test.ps1` ktorego nie ma w repo — do rozwazenia porzadkowo.
|
||||||
|
|
||||||
|
**Blockers:**
|
||||||
|
- None.
|
||||||
|
|
||||||
|
---
|
||||||
|
*Phase: 17-cart-summary-transport-cost-fix, Plan: 01*
|
||||||
|
*Completed: 2026-04-20*
|
||||||
@@ -280,20 +280,71 @@ class ShopBasketController
|
|||||||
$client = \Shared\Helpers\Helpers::get_session( 'client' );
|
$client = \Shared\Helpers\Helpers::get_session( 'client' );
|
||||||
$orderSubmitToken = $this->createOrderSubmitToken();
|
$orderSubmitToken = $this->createOrderSubmitToken();
|
||||||
|
|
||||||
|
$basket = \Shared\Helpers\Helpers::get_session( 'basket' );
|
||||||
|
$coupon = \Shared\Helpers\Helpers::get_session( 'coupon' );
|
||||||
|
$transport = ( new \Domain\Transport\TransportRepository( $GLOBALS['mdb'] ) )->findActiveByIdCached( \Shared\Helpers\Helpers::get_session( 'basket-transport-method-id' ) );
|
||||||
|
|
||||||
|
$productsSummary = (float)\Domain\Basket\BasketCalculator::summaryPrice( $basket, $coupon );
|
||||||
|
$freeDeliveryThreshold = isset( $settings['free_delivery'] ) ? (float)$settings['free_delivery'] : 0.0;
|
||||||
|
$transportCalc = $this->calculateTransportCostForSummary( $transport, $productsSummary, $freeDeliveryThreshold );
|
||||||
|
|
||||||
return \Shared\Tpl\Tpl::view( 'shop-basket/summary-view', [
|
return \Shared\Tpl\Tpl::view( 'shop-basket/summary-view', [
|
||||||
'lang_id' => $lang_id,
|
'lang_id' => $lang_id,
|
||||||
'client' => \Shared\Helpers\Helpers::get_session( 'client' ),
|
'client' => \Shared\Helpers\Helpers::get_session( 'client' ),
|
||||||
'basket' => \Shared\Helpers\Helpers::get_session( 'basket' ),
|
'basket' => $basket,
|
||||||
'transport' => ( new \Domain\Transport\TransportRepository( $GLOBALS['mdb'] ) )->findActiveByIdCached( \Shared\Helpers\Helpers::get_session( 'basket-transport-method-id' ) ),
|
'transport' => $transport,
|
||||||
|
'transport_cost_effective' => $transportCalc['transport_cost_effective'],
|
||||||
|
'free_delivery_applies' => $transportCalc['free_delivery_applies'],
|
||||||
'payment_method' => $this->paymentMethodRepository->paymentMethodCached( (int)\Shared\Helpers\Helpers::get_session( 'basket-payment-method-id' ) ),
|
'payment_method' => $this->paymentMethodRepository->paymentMethodCached( (int)\Shared\Helpers\Helpers::get_session( 'basket-payment-method-id' ) ),
|
||||||
'addresses' => ( new \Domain\Client\ClientRepository( $GLOBALS['mdb'] ) )->clientAddresses( (int)$client['id'] ),
|
'addresses' => ( new \Domain\Client\ClientRepository( $GLOBALS['mdb'] ) )->clientAddresses( (int)$client['id'] ),
|
||||||
'settings' => $settings,
|
'settings' => $settings,
|
||||||
'coupon' => \Shared\Helpers\Helpers::get_session( 'coupon' ),
|
'coupon' => $coupon,
|
||||||
'basket_message' => \Shared\Helpers\Helpers::get_session( 'basket_message' ),
|
'basket_message' => \Shared\Helpers\Helpers::get_session( 'basket_message' ),
|
||||||
'order_submit_token' => $orderSubmitToken
|
'order_submit_token' => $orderSubmitToken
|
||||||
] );
|
] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wylicza efektywny koszt transportu dla widoku /koszyk-podsumowanie.
|
||||||
|
* Koszt spada do 0, gdy transport ma flage delivery_free=1 ORAZ wartosc koszyka
|
||||||
|
* (po kuponie) osiaga prog darmowej dostawy $freeDeliveryThreshold.
|
||||||
|
*
|
||||||
|
* @param array|null $transport Aktywny transport (lub null gdy nie wybrany)
|
||||||
|
* @param float $productsSummary Wartosc koszyka po kuponie
|
||||||
|
* @param float $freeDeliveryThreshold Prog darmowej dostawy z settings.free_delivery
|
||||||
|
* @return array{transport_cost_effective: float, free_delivery_applies: bool}
|
||||||
|
*/
|
||||||
|
protected function calculateTransportCostForSummary( $transport, $productsSummary, $freeDeliveryThreshold )
|
||||||
|
{
|
||||||
|
if ( !is_array( $transport ) )
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'transport_cost_effective' => 0.0,
|
||||||
|
'free_delivery_applies' => false,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$deliveryFree = isset( $transport['delivery_free'] ) ? (int)$transport['delivery_free'] : 0;
|
||||||
|
$cost = isset( $transport['cost'] ) ? (float)$transport['cost'] : 0.0;
|
||||||
|
|
||||||
|
$applies = false;
|
||||||
|
if ( $deliveryFree === 1 && $freeDeliveryThreshold > 0 )
|
||||||
|
{
|
||||||
|
$summaryNormalized = \Shared\Helpers\Helpers::normalize_decimal( $productsSummary );
|
||||||
|
$thresholdNormalized = \Shared\Helpers\Helpers::normalize_decimal( $freeDeliveryThreshold );
|
||||||
|
|
||||||
|
if ( $summaryNormalized >= $thresholdNormalized )
|
||||||
|
{
|
||||||
|
$applies = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'transport_cost_effective' => $applies ? 0.0 : $cost,
|
||||||
|
'free_delivery_applies' => $applies,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
public function basketSave()
|
public function basketSave()
|
||||||
{
|
{
|
||||||
$orderSubmitToken = (string)\Shared\Helpers\Helpers::get( 'order_submit_token', true );
|
$orderSubmitToken = (string)\Shared\Helpers\Helpers::get( 'order_submit_token', true );
|
||||||
|
|||||||
@@ -97,11 +97,11 @@
|
|||||||
<div class="basket-summary">
|
<div class="basket-summary">
|
||||||
<?= $this -> transport[ 'name_visible' ];?>:
|
<?= $this -> transport[ 'name_visible' ];?>:
|
||||||
|
|
||||||
<? if ( $this -> transport[ 'delivery_free' ] == 1 ):?>
|
<? if ( $this -> free_delivery_applies ):?>
|
||||||
<span>0,00 zł</span>
|
<span>0,00 zł</span>
|
||||||
<? else:?>
|
<? else:?>
|
||||||
<span>
|
<span>
|
||||||
<?= \Shared\Helpers\Helpers::decimal( $this -> transport[ 'cost' ] );?> zł
|
<?= \Shared\Helpers\Helpers::decimal( $this -> transport_cost_effective );?> zł
|
||||||
</span>
|
</span>
|
||||||
<? endif;?>
|
<? endif;?>
|
||||||
</div>
|
</div>
|
||||||
@@ -111,7 +111,7 @@
|
|||||||
$summary -= $discount;
|
$summary -= $discount;
|
||||||
?>
|
?>
|
||||||
<span id="order-summary">
|
<span id="order-summary">
|
||||||
<?= $this -> transport[ 'delivery_free' ] == 1 ? \Shared\Helpers\Helpers::decimal( $summary ) : \Shared\Helpers\Helpers::decimal( $summary + $this -> transport[ 'cost' ] );?> zł
|
<?= $this -> free_delivery_applies ? \Shared\Helpers\Helpers::decimal( $summary ) : \Shared\Helpers\Helpers::decimal( $summary + $this -> transport_cost_effective );?> zł
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="basket-summary">
|
<div class="basket-summary">
|
||||||
|
|||||||
@@ -0,0 +1,120 @@
|
|||||||
|
<?php
|
||||||
|
namespace Tests\Unit\front\Controllers;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use front\Controllers\ShopBasketController;
|
||||||
|
use Domain\Order\OrderRepository;
|
||||||
|
use Domain\PaymentMethod\PaymentMethodRepository;
|
||||||
|
|
||||||
|
class ShopBasketControllerSummaryViewTest extends TestCase
|
||||||
|
{
|
||||||
|
private $controller;
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
$orderRepository = $this->createMock(OrderRepository::class);
|
||||||
|
$paymentMethodRepository = $this->createMock(PaymentMethodRepository::class);
|
||||||
|
$this->controller = new ShopBasketController($orderRepository, $paymentMethodRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wywoluje chroniona metode calculateTransportCostForSummary przez Reflection.
|
||||||
|
*
|
||||||
|
* @param array|null $transport
|
||||||
|
* @param float $productsSummary
|
||||||
|
* @param float $freeDeliveryThreshold
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function invokeCalc($transport, $productsSummary, $freeDeliveryThreshold): array
|
||||||
|
{
|
||||||
|
$reflection = new \ReflectionClass(ShopBasketController::class);
|
||||||
|
$method = $reflection->getMethod('calculateTransportCostForSummary');
|
||||||
|
$method->setAccessible(true);
|
||||||
|
|
||||||
|
return $method->invoke($this->controller, $transport, $productsSummary, $freeDeliveryThreshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testTransportWithDeliveryFreeBelowThresholdShowsRealCost(): void
|
||||||
|
{
|
||||||
|
// AC-1: delivery_free=1, basket 150, threshold 300 -> cost 15.00
|
||||||
|
$transport = [
|
||||||
|
'id' => 4,
|
||||||
|
'cost' => 15.00,
|
||||||
|
'delivery_free' => 1,
|
||||||
|
];
|
||||||
|
|
||||||
|
$result = $this->invokeCalc($transport, 150.00, 300.00);
|
||||||
|
|
||||||
|
$this->assertFalse($result['free_delivery_applies']);
|
||||||
|
$this->assertSame(15.00, $result['transport_cost_effective']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testTransportWithDeliveryFreeAboveThresholdShowsZero(): void
|
||||||
|
{
|
||||||
|
// AC-2: delivery_free=1, basket 350, threshold 300 -> cost 0.0, applies true
|
||||||
|
$transport = [
|
||||||
|
'id' => 4,
|
||||||
|
'cost' => 15.00,
|
||||||
|
'delivery_free' => 1,
|
||||||
|
];
|
||||||
|
|
||||||
|
$result = $this->invokeCalc($transport, 350.00, 300.00);
|
||||||
|
|
||||||
|
$this->assertTrue($result['free_delivery_applies']);
|
||||||
|
$this->assertSame(0.0, $result['transport_cost_effective']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testTransportWithDeliveryFreeAtExactThresholdShowsZero(): void
|
||||||
|
{
|
||||||
|
// Boundary: basket == threshold should trigger free delivery
|
||||||
|
$transport = [
|
||||||
|
'id' => 4,
|
||||||
|
'cost' => 20.00,
|
||||||
|
'delivery_free' => 1,
|
||||||
|
];
|
||||||
|
|
||||||
|
$result = $this->invokeCalc($transport, 300.00, 300.00);
|
||||||
|
|
||||||
|
$this->assertTrue($result['free_delivery_applies']);
|
||||||
|
$this->assertSame(0.0, $result['transport_cost_effective']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testTransportWithoutDeliveryFreeAlwaysShowsCost(): void
|
||||||
|
{
|
||||||
|
// AC-3: delivery_free=0, basket 500, threshold 300 -> cost 25.00, applies false
|
||||||
|
$transport = [
|
||||||
|
'id' => 5,
|
||||||
|
'cost' => 25.00,
|
||||||
|
'delivery_free' => 0,
|
||||||
|
];
|
||||||
|
|
||||||
|
$result = $this->invokeCalc($transport, 500.00, 300.00);
|
||||||
|
|
||||||
|
$this->assertFalse($result['free_delivery_applies']);
|
||||||
|
$this->assertSame(25.00, $result['transport_cost_effective']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNullTransportReturnsZeroAndDoesNotApply(): void
|
||||||
|
{
|
||||||
|
// Scenario: no transport selected yet (findActiveByIdCached zwrocil null)
|
||||||
|
$result = $this->invokeCalc(null, 500.00, 300.00);
|
||||||
|
|
||||||
|
$this->assertFalse($result['free_delivery_applies']);
|
||||||
|
$this->assertSame(0.0, $result['transport_cost_effective']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testZeroFreeDeliveryThresholdDisablesFreeDelivery(): void
|
||||||
|
{
|
||||||
|
// Ochrona: jesli settings.free_delivery = 0, darmowa dostawa nie dziala nigdy
|
||||||
|
$transport = [
|
||||||
|
'id' => 4,
|
||||||
|
'cost' => 15.00,
|
||||||
|
'delivery_free' => 1,
|
||||||
|
];
|
||||||
|
|
||||||
|
$result = $this->invokeCalc($transport, 9999.00, 0.00);
|
||||||
|
|
||||||
|
$this->assertFalse($result['free_delivery_applies']);
|
||||||
|
$this->assertSame(15.00, $result['transport_cost_effective']);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user