Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eee22ef1c4 | ||
|
|
494cb580d3 | ||
|
|
23bd85a04a |
@@ -14,7 +14,7 @@ Właściciel sklepu internetowego ma pełną kontrolę nad sprzedażą online -
|
||||
|-----------|-------|
|
||||
| Version | 0.333 |
|
||||
| Status | Production |
|
||||
| Last Updated | 2026-04-19 |
|
||||
| Last Updated | 2026-04-20 |
|
||||
|
||||
## 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] Domain-Driven Architecture (migracja z legacy zakończona)
|
||||
- [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)
|
||||
|
||||
@@ -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 |
|
||||
| `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 |
|
||||
| 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
|
||||
|
||||
| Metric | Target | Current | Status |
|
||||
|--------|--------|---------|--------|
|
||||
| Testy | >800 | 821 | On track |
|
||||
| Testy | >800 | 834 | On track |
|
||||
| Pokrycie architektury DDD | 100% | 100% | Achieved |
|
||||
|
||||
## Tech Stack
|
||||
@@ -115,4 +117,4 @@ Quick Reference:
|
||||
|
||||
---
|
||||
*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 |
|
||||
| 9 | Apilo email notification + infinite retry | 1 | Done | 2026-03-19 |
|
||||
| 15 | Scontainers edit saves as new record | 1 | Done | 2026-04-18 |
|
||||
| 17 | Cart summary transport cost fix | 1 | Done | 2026-04-20 |
|
||||
|
||||
## 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.
|
||||
|
||||
### 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)
|
||||
|
||||
**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
|
||||
|
||||
Milestone: Feature
|
||||
Phase: 16 of 16 (Product list custom labels quick edit) - Complete
|
||||
Plan: 16-01 complete
|
||||
Status: UNIFY complete, ready for next PLAN loop
|
||||
Last activity: 2026-04-19 - Closed loop for .paul/phases/16-product-list-custom-labels/16-01-PLAN.md
|
||||
Milestone: Hotfix
|
||||
Phase: 17 of 17 (Cart summary transport cost fix) - Complete
|
||||
Plan: 17-01 complete
|
||||
Status: UNIFY complete, ready for next PLAN loop (transition-phase pending)
|
||||
Last activity: 2026-04-20 - Closed loop for .paul/phases/17-cart-summary-transport-cost-fix/17-01-PLAN.md
|
||||
|
||||
Progress:
|
||||
- Milestone: [##########] 100%
|
||||
- Phase 16: [##########] 100%
|
||||
- Phase 17: [##########] 100%
|
||||
|
||||
## 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 15: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-04-18]
|
||||
Phase 16: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-04-19]
|
||||
Phase 17: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-04-20]
|
||||
```
|
||||
## Accumulated Context
|
||||
|
||||
### 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: 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
|
||||
@@ -90,9 +97,9 @@ None.
|
||||
|
||||
## Session Continuity
|
||||
|
||||
Last session: 2026-04-19
|
||||
Stopped at: Phase 16 complete, loop closed
|
||||
Next action: Start next milestone or create next phase plan
|
||||
Resume file: .paul/phases/16-product-list-custom-labels/16-01-SUMMARY.md
|
||||
Last session: 2026-04-20
|
||||
Stopped at: Phase 17 complete, loop closed
|
||||
Next action: Start next milestone or create next phase plan (transition-phase commit pending)
|
||||
Resume file: .paul/phases/17-cart-summary-transport-cost-fix/17-01-SUMMARY.md
|
||||
---
|
||||
*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.
|
||||
|
||||
## 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)
|
||||
|
||||
- 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: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*
|
||||
File diff suppressed because one or more lines are too long
@@ -2,5 +2,5 @@ projectKey=shopPRO
|
||||
serverUrl=https://sonar.project-pro.pl
|
||||
serverVersion=26.3.0.120487
|
||||
dashboardUrl=https://sonar.project-pro.pl/dashboard?id=shopPRO
|
||||
ceTaskId=3051d3c7-50d0-4263-bdc3-12917447a707
|
||||
ceTaskUrl=https://sonar.project-pro.pl/api/ce/task?id=3051d3c7-50d0-4263-bdc3-12917447a707
|
||||
ceTaskId=646324f5-0b31-4df4-a424-9aa2e5c89d4b
|
||||
ceTaskUrl=https://sonar.project-pro.pl/api/ce/task?id=646324f5-0b31-4df4-a424-9aa2e5c89d4b
|
||||
|
||||
@@ -280,20 +280,71 @@ class ShopBasketController
|
||||
$client = \Shared\Helpers\Helpers::get_session( 'client' );
|
||||
$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', [
|
||||
'lang_id' => $lang_id,
|
||||
'client' => \Shared\Helpers\Helpers::get_session( 'client' ),
|
||||
'basket' => \Shared\Helpers\Helpers::get_session( 'basket' ),
|
||||
'transport' => ( new \Domain\Transport\TransportRepository( $GLOBALS['mdb'] ) )->findActiveByIdCached( \Shared\Helpers\Helpers::get_session( 'basket-transport-method-id' ) ),
|
||||
'basket' => $basket,
|
||||
'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' ) ),
|
||||
'addresses' => ( new \Domain\Client\ClientRepository( $GLOBALS['mdb'] ) )->clientAddresses( (int)$client['id'] ),
|
||||
'settings' => $settings,
|
||||
'coupon' => \Shared\Helpers\Helpers::get_session( 'coupon' ),
|
||||
'coupon' => $coupon,
|
||||
'basket_message' => \Shared\Helpers\Helpers::get_session( 'basket_message' ),
|
||||
'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()
|
||||
{
|
||||
$orderSubmitToken = (string)\Shared\Helpers\Helpers::get( 'order_submit_token', true );
|
||||
|
||||
@@ -97,11 +97,11 @@
|
||||
<div class="basket-summary">
|
||||
<?= $this -> transport[ 'name_visible' ];?>:
|
||||
|
||||
<? if ( $this -> transport[ 'delivery_free' ] == 1 ):?>
|
||||
<? if ( $this -> free_delivery_applies ):?>
|
||||
<span>0,00 zł</span>
|
||||
<? else:?>
|
||||
<span>
|
||||
<?= \Shared\Helpers\Helpers::decimal( $this -> transport[ 'cost' ] );?> zł
|
||||
<?= \Shared\Helpers\Helpers::decimal( $this -> transport_cost_effective );?> zł
|
||||
</span>
|
||||
<? endif;?>
|
||||
</div>
|
||||
@@ -111,7 +111,7 @@
|
||||
$summary -= $discount;
|
||||
?>
|
||||
<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>
|
||||
</div>
|
||||
<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']);
|
||||
}
|
||||
}
|
||||
BIN
updates/0.30/ver_0.348.zip
Normal file
BIN
updates/0.30/ver_0.348.zip
Normal file
Binary file not shown.
26
updates/0.30/ver_0.348_manifest.json
Normal file
26
updates/0.30/ver_0.348_manifest.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"changelog": "Dodano przełącznik i edycję etykiet niestandardowych na liście produktów.",
|
||||
"version": "0.348",
|
||||
"files": {
|
||||
"added": [
|
||||
|
||||
],
|
||||
"deleted": [
|
||||
|
||||
],
|
||||
"modified": [
|
||||
"admin/templates/shop-product/products-list-custom-script.php",
|
||||
"admin/templates/shop-product/products-list.php",
|
||||
"autoload/Domain/Product/ProductRepository.php",
|
||||
"autoload/admin/Controllers/ShopProductController.php"
|
||||
]
|
||||
},
|
||||
"checksum_zip": "sha256:3dc1557d1cd17d07ce9e406cb919571d2c3f4e829d0496343cd1210e0b45da87",
|
||||
"sql": [
|
||||
|
||||
],
|
||||
"date": "2026-04-19",
|
||||
"directories_deleted": [
|
||||
|
||||
]
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
<b>ver. 0.348 - 19.04.2026</b><br />
|
||||
Dodano przełącznik i edycję etykiet niestandardowych na liście produktów.
|
||||
<hr>
|
||||
<b>ver. 0.347 - 18.04.2026</b><br />
|
||||
Naprawa zapisu edycji kontenerow statycznych + testy regresyjne
|
||||
<hr>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?
|
||||
$current_ver = 347;
|
||||
$current_ver = 348;
|
||||
|
||||
for ($i = 1; $i <= $current_ver; $i++)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user