diff --git a/DATABASE_STRUCTURE.md b/DATABASE_STRUCTURE.md index 6cacc26..69ed2b1 100644 --- a/DATABASE_STRUCTURE.md +++ b/DATABASE_STRUCTURE.md @@ -320,6 +320,32 @@ Tlumaczenia kontenerow statycznych (per jezyk). **Aktualizacja 2026-02-12 (ver. 0.260):** modul `/admin/articles_archive` korzysta z `Domain\Article\ArticleRepository` (`listArchivedForAdmin`, `restore`, `deletePermanently`) przez `admin\Controllers\ArticlesArchiveController`. +## pp_shop_promotion +Promocje sklepu (modul `/admin/shop_promotion`). + +| Kolumna | Opis | +|---------|------| +| id | PK | +| name | Nazwa promocji | +| status | Status: 1 = aktywna, 0 = nieaktywna | +| condition_type | Typ warunku promocji (slownik w `shop\Promotion::$condition_type`) | +| discount_type | Typ rabatu (slownik w `shop\Promotion::$discount_type`) | +| amount | Wartosc rabatu (np. procent) | +| date_from | Data startu promocji (NULL = aktywna od razu) | +| date_to | Data konca promocji (NULL = bez daty konca) | +| categories | JSON z ID kategorii grupy I | +| condition_categories | JSON z ID kategorii grupy II | +| include_coupon | Czy laczyc z kuponami rabatowymi (0/1) | +| include_product_promo | Czy uwzgledniac produkty przecenione (0/1) | +| min_product_count | Minimalna liczba produktow (dla wybranych warunkow) | +| price_cheapest_product | Cena najtanszego produktu (dla wybranych warunkow) | + +**Uzywane w:** `Domain\Promotion\PromotionRepository`, `admin\Controllers\ShopPromotionController`, `shop\Promotion`, `front\factory\ShopPromotion` + +**Aktualizacja 2026-02-13:** modul `/admin/shop_promotion` korzysta z `Domain\Promotion\PromotionRepository` przez `admin\Controllers\ShopPromotionController`. Usunieto legacy klasy `admin\controls\ShopPromotion` i `admin\factory\ShopPromotion`. + +**Aktualizacja 2026-02-13 (ver. 0.265):** dodano obsluge `date_from` (repozytorium, formularz admin, lista admin, filtr aktywnych promocji na froncie) oraz poprawke zapisu edycji promocji po `id`. + ## pp_shop_apilo_settings Ustawienia integracji Apilo (key-value). diff --git a/PROJECT_STRUCTURE.md b/PROJECT_STRUCTURE.md index ce15768..819c691 100644 --- a/PROJECT_STRUCTURE.md +++ b/PROJECT_STRUCTURE.md @@ -475,3 +475,20 @@ Aktualnie w suite są też testy modułów `Dictionaries`, `Articles` i `Users` - CLEANUP: **usunieto integracje Sellasist i Baselinker z calego projektu** - kontrolery, factory, szablony, referencje w cron.php, Order, ShopStatuses, ShopTransport, ShopPaymentMethod, ShopProduct, config.php, front/factory/*. - CLEANUP: usuniete pliki: `autoload/admin/controls/class.Integrations.php`, `autoload/admin/controls/class.Baselinker.php`, `autoload/admin/factory/class.Baselinker.php`, `autoload/front/factory/class.Shop.php`, `autoload/shop/class.ShopStatus.php`, szablony sellasist/baselinker. - Testy: **OK (212 tests, 577 assertions)**. + +## Aktualizacja 2026-02-13 (ShopPromotion refactor, ver. 0.264) +- NOWE: `Domain\Promotion\PromotionRepository` (listForAdmin, find, save, delete, categoriesTree + invalidacja cache aktywnych promocji). +- NOWE: `admin\Controllers\ShopPromotionController` (DI) dla akcji `list`, `edit`, `save`, `delete`. +- UPDATE: modul `/admin/shop_promotion/*` przepiety z legacy `grid/gridEdit` na `components/table-list` i `components/form-edit`. +- NOWE: widoki `admin/templates/shop-promotion/promotions-list.php`, `admin/templates/shop-promotion/promotion-edit.php`. +- NOWE: partiale drzewa kategorii: `admin/templates/shop-promotion/promotion-categories-selector.php`, `admin/templates/shop-promotion/promotion-categories-tree.php`. +- NOWE: `admin/templates/shop-promotion/promotion-edit-custom-script.php` (logika warunkow promocji + drzewo kategorii). +- CLEANUP: usuniete legacy klasy/pliki `autoload/admin/controls/class.ShopPromotion.php`, `autoload/admin/factory/class.ShopPromotion.php`, `admin/templates/shop-promotion/view-list.php`. +- UPDATE: menu admin wskazuje kanoniczny URL `/admin/shop_promotion/list/`. +- Testy: **OK (222 tests, 609 assertions)**. + +## Aktualizacja 2026-02-13 (ShopPromotion poprawki, ver. 0.265) +- UPDATE: dodano pole `Data od` (`date_from`) w module `/admin/shop_promotion` (repozytorium, formularz i lista). +- UPDATE: `shop\Promotion::get_active_promotions()` uwzglednia `date_from` (`NULL` lub `<= dzisiaj`) obok `date_to`. +- FIX: edycja promocji zapisuje update zamiast insert (stabilne przekazanie `id` przez hidden field + fallback `id` z URL w `save()`). +- Testy: **OK (222 tests, 614 assertions)**. diff --git a/REFACTORING_PLAN.md b/REFACTORING_PLAN.md index dd34300..c0118bf 100644 --- a/REFACTORING_PLAN.md +++ b/REFACTORING_PLAN.md @@ -725,3 +725,60 @@ Gdy `persist = true`: - Wyczyszczone referencje w: `cron.php`, `cron/cron-xml.php`, `shop\Order`, `admin\controls\ShopStatuses`, `admin\controls\ShopTransport`, `admin\controls\ShopPaymentMethod`, `admin\controls\ShopProduct`, `admin\factory\ShopStatuses`, `admin\factory\ShopTransport`, `admin\factory\ShopProduct`, `front\factory\ShopStatuses`, `front\factory\ShopTransport`, `front\factory\ShopPaymentMethod`, `front\factory\ShopProduct`, `front\factory\ShopOrder`, `shop\Product`, `config.php` - Wyczyszczone szablony: `shop-statuses/*`, `shop-transport/*`, `shop-payment-method/*`, `shop-product/*`, `site/main-layout.php` - Testy: **OK (212 tests, 577 assertions)**. + +## Plan 2026-02-13 - Refaktoryzacja `/admin/shop_promotion/` (HITL) +- [x] Etap 1 (analiza i kontrakt): potwierdzic docelowy kontrakt URL i kompatybilnosc wsteczna: + - kontrakt docelowy: tylko `/admin/shop_promotion/list/`, `/admin/shop_promotion/edit/`, `/admin/shop_promotion/save/`, `/admin/shop_promotion/delete/` + - brak kompatybilnosci ze starymi URL i aliasami akcji (`view_list`, `promotion_delete`) +- [x] Etap 2 (Domain): dodac `Domain\Promotion\PromotionRepository`: + - `listForAdmin(filters, sort, dir, page, perPage)` z whitelist sortowania i bind params + - `find(int $id)` + domyslne dane dla nowego formularza + - `save(array $data): ?int` (insert/update, normalizacja switchy, JSON dla kategorii) + - `delete(int $id): bool` + - `categoriesTree(?int $parentId): array` (drzewo kategorii z tlumaczeniami, bez zaleznosci od `admin\factory\ShopCategory`) +- [x] Etap 3 (Admin Controller + routing DI): dodac `admin\Controllers\ShopPromotionController` i przepiac routing: + - rejestracja factory w `admin\Site::$newControllers` pod modulem `ShopPromotion` + - akcje: `list`, `edit`, `save`, `delete` + - zachowac obsluge legacy payload (`values` JSON) oraz obsluge `form-edit` (`$_POST`) +- [x] Etap 4 (widoki): przepiac modul z `grid/gridEdit` na nowe komponenty: + - nowy widok listy oparty o `components/table-list` (filtry: nazwa, aktywny) + - nowy widok edycji oparty o `components/form-edit` (+ pola custom dla drzew kategorii) + - nowe partiale dla drzewa kategorii w module `shop-promotion` (usuniecie zaleznosci od `shop-product/subcategories-list`) + - nowy `shop-promotion/promotion-edit-custom-script.php` (warunkowe pola po `condition_type`, obsluga drzewa kategorii) +- [x] Etap 5 (zaleznosci i cleanup): przeszukac i odpiac legacy zaleznosci: + - menu admin: link kanoniczny na `/admin/shop_promotion/list/` + - usunac legacy pliki po pelnym przepieciu: + - `autoload/admin/controls/class.ShopPromotion.php` + - `autoload/admin/factory/class.ShopPromotion.php` + - `admin/templates/shop-promotion/view-list.php` (grid) + - `admin/templates/shop-promotion/promotion-edit.php` (gridEdit) + - sprawdzic pozostale odwolania `ShopPromotion` i `shop_promotion/view_list` w calym repo +- [x] Etap 6 (testy): dodac/uzupelnic testy: + - `tests/Unit/Domain/Promotion/PromotionRepositoryTest.php` + - `tests/Unit/admin/Controllers/ShopPromotionControllerTest.php` + - uruchomic minimum: nowe testy modulu + pelny `composer test` +- [x] Etap 7 (dokumentacja po wdrozeniu): zaktualizowac: + - `DATABASE_STRUCTURE.md` (dodac `pp_shop_promotion`, jesli nadal brak) + - `PROJECT_STRUCTURE.md` + - `REFACTORING_PLAN.md` (sekcja "Aktualizacja ...") + - `TESTING.md` (nowy wynik suite) + +## Aktualizacja 2026-02-13 (ver. 0.264) +- **ShopPromotion** - migracja `/admin/shop_promotion` na Domain + DI + nowe widoki + - NOWE: `Domain\Promotion\PromotionRepository` (`listForAdmin`, `find`, `save`, `delete`, `categoriesTree`, invalidacja cache aktywnych promocji) + - NOWE: `admin\Controllers\ShopPromotionController` (DI) z akcjami `list`, `edit`, `save`, `delete` + - UPDATE: routing DI (`admin\Site`) rozszerzony o modul `ShopPromotion` + - UPDATE: modul `/admin/shop_promotion/*` dziala na `components/table-list` i `components/form-edit` + - NOWE: widoki/partiale `shop-promotion/promotions-list`, `shop-promotion/promotion-edit`, `shop-promotion/promotion-categories-selector`, `shop-promotion/promotion-categories-tree`, `shop-promotion/promotion-edit-custom-script` + - CLEANUP: usuniete legacy `autoload/admin/controls/class.ShopPromotion.php`, `autoload/admin/factory/class.ShopPromotion.php`, `admin/templates/shop-promotion/view-list.php` + - UPDATE: menu admin przepiete na kanoniczny URL `/admin/shop_promotion/list/` +- Testy po zmianie: **OK (222 tests, 609 assertions)**. + +## Aktualizacja 2026-02-13 (ver. 0.265) +- **ShopPromotion** - stabilizacja po migracji + - UPDATE: dodane `date_from` w `Domain\Promotion\PromotionRepository` (save/find/list/sort) + - UPDATE: `admin\Controllers\ShopPromotionController` rozszerzony o pole `Data od` na formularzu i kolumne `Data od` na liscie + - UPDATE: `shop\Promotion::get_active_promotions()` filtruje aktywnosc po `date_from` i `date_to` + - FIX: zapis edycji promocji nie tworzy nowego rekordu (hidden `id` + fallback `id` z URL) + - TEST: rozszerzono `PromotionRepositoryTest` o asercje `date_from` +- Testy po zmianie: **OK (222 tests, 614 assertions)**. diff --git a/TESTING.md b/TESTING.md index 5e0ed91..11d99f9 100644 --- a/TESTING.md +++ b/TESTING.md @@ -297,3 +297,24 @@ Nowe testy dodane 2026-02-13: Zaktualizowane pliki: - `tests/bootstrap.php` (dodany stub `S::remove_special_chars()`) + +## Aktualizacja suite (ShopPromotion refactor, ver. 0.264) +Ostatnio zweryfikowano: 2026-02-13 + +```text +OK (222 tests, 609 assertions) +``` + +Nowe testy dodane 2026-02-13: +- `tests/Unit/Domain/Promotion/PromotionRepositoryTest.php` (6 testow: find default, save insert, delete, whitelist sortowania, drzewo kategorii) +- `tests/Unit/admin/Controllers/ShopPromotionControllerTest.php` (4 testy: kontrakty metod i DI konstruktora) + +## Aktualizacja suite (ShopPromotion fix + date_from, ver. 0.265) +Ostatnio zweryfikowano: 2026-02-13 + +```text +OK (222 tests, 614 assertions) +``` + +Zmiany testowe 2026-02-13: +- rozszerzenie `tests/Unit/Domain/Promotion/PromotionRepositoryTest.php` o asercje `date_from` diff --git a/admin/templates/shop-promotion/promotion-categories-selector.php b/admin/templates/shop-promotion/promotion-categories-selector.php new file mode 100644 index 0000000..88652ae --- /dev/null +++ b/admin/templates/shop-promotion/promotion-categories-selector.php @@ -0,0 +1,19 @@ +label ?? 'Kategorie')); +$inputName = trim((string)($this->inputName ?? 'categories[]')); +$categories = is_array($this->categories ?? null) ? $this->categories : []; +$selectedIds = is_array($this->selectedIds ?? null) ? $this->selectedIds : []; +?> +
+ +
+
+ $categories, + 'selectedIds' => $selectedIds, + 'inputName' => $inputName, + ]); ?> +
+
+
+ diff --git a/admin/templates/shop-promotion/promotion-categories-tree.php b/admin/templates/shop-promotion/promotion-categories-tree.php new file mode 100644 index 0000000..34114f4 --- /dev/null +++ b/admin/templates/shop-promotion/promotion-categories-tree.php @@ -0,0 +1,68 @@ +categories ?? null) ? $this->categories : []; +$inputName = trim((string)($this->inputName ?? 'categories[]')); +$selectedRaw = is_array($this->selectedIds ?? null) ? $this->selectedIds : []; +$selected = []; +foreach ($selectedRaw as $value) { + $id = (int)$value; + if ($id > 0) { + $selected[$id] = true; + } +} +?> + +
    + + +
  1. +
    + + + + + + + + + + + +
    + + + $children, + 'selectedIds' => array_keys($selected), + 'inputName' => $inputName, + ]); ?> + +
  2. + +
+ + diff --git a/admin/templates/shop-promotion/promotion-edit-custom-script.php b/admin/templates/shop-promotion/promotion-edit-custom-script.php new file mode 100644 index 0000000..69e0189 --- /dev/null +++ b/admin/templates/shop-promotion/promotion-edit-custom-script.php @@ -0,0 +1,115 @@ + + + + diff --git a/admin/templates/shop-promotion/promotion-edit.php b/admin/templates/shop-promotion/promotion-edit.php index 44bce00..1b557e2 100644 --- a/admin/templates/shop-promotion/promotion-edit.php +++ b/admin/templates/shop-promotion/promotion-edit.php @@ -1,257 +1,3 @@ - - -
- -
-
- 'Nazwa', - 'name' => 'name', - 'id' => 'name', - 'value' => $this -> promotion['name'] - ] ); - ?> - 'Aktywna', - 'name' => 'status', - 'checked' => $this -> promotion['status'] == 1 ? true : false - ] ); - ?> - 'Łącz z kuponami rabatowymi', - 'name' => 'include_coupon', - 'checked' => $this -> promotion['include_coupon'] == 1 ? true : false - ] ); - ?> - 'Uwzględnij produkty przecenione', - 'name' => 'include_product_promo', - 'checked' => $this -> promotion['include_product_promo'] == 1 ? true : false - ] ); - ?> - 'Warunki promocji', - 'id' => 'condition_type', - 'name' => 'condition_type', - 'values' => \shop\Promotion::$condition_type, - 'value' => $this -> promotion['condition_type'], - ] ); - ?> - 'Typ rabatu', - 'id' => 'discount_type', - 'name' => 'discount_type', - 'values' => \shop\Promotion::$discount_type, - 'value' => $this -> promotion['discount_type'], - ] ); - ?> - 'Min. ilość produktów z danej kategorii', - 'class' => 'int-format', - 'name' => 'min_product_count', - 'id' => 'min_product_count', - 'value' => $this -> promotion['min_product_count'] - ] );?> - 'Cena najtańszego produktu', - 'class' => 'number-format', - 'name' => 'price_cheapest_product', - 'id' => 'price_cheapest_product', - 'value' => $this -> promotion['price_cheapest_product'] - ] ); - ?> - 'Wartość', - 'class' => 'number-format', - 'name' => 'amount', - 'id' => 'amount', - 'value' => $this -> promotion['amount'] - ] ); - ?> - 'Data do', - 'class' => 'date', - 'name' => 'date_to', - 'id' => 'date_to', - 'value' => $this -> promotion['date_to'] - ] ); - ?> -
- -
- -
-
-
-
- -
- -
-
-
-
-
- $this->form]); ?> + -$grid = new \gridEdit; -$grid -> id = 'promotion-edit'; -$grid -> gdb_opt = $gdb; -$grid -> include_plugins = true; -$grid -> title = $this -> promotion['id'] ? 'Edycja promocji: ' . $this -> promotion['name'] . '' : 'Nowa promocja'; -$grid -> fields = [ - [ - 'db' => 'id', - 'type' => 'hidden', - 'value' => $this -> promotion['id'] - ] -]; -$grid -> actions = [ - 'save' => [ 'url' => '/admin/shop_promotion/save/', 'back_url' => '/admin/shop_promotion/view_list/' ], - 'cancel' => [ 'url' => '/admin/shop_promotion/view_list/' ] -]; -$grid -> external_code = $out; -$grid -> persist_edit = true; -$grid -> id_param = 'id'; - -echo $grid -> draw(); -?> - - - - - - - \ No newline at end of file diff --git a/admin/templates/shop-promotion/promotions-list.php b/admin/templates/shop-promotion/promotions-list.php new file mode 100644 index 0000000..b336124 --- /dev/null +++ b/admin/templates/shop-promotion/promotions-list.php @@ -0,0 +1,2 @@ + $this->viewModel]); ?> + diff --git a/admin/templates/shop-promotion/view-list.php b/admin/templates/shop-promotion/view-list.php deleted file mode 100644 index 6938a65..0000000 --- a/admin/templates/shop-promotion/view-list.php +++ /dev/null @@ -1,59 +0,0 @@ - gdb_opt = $gdb; -$grid -> debug = true; -$grid -> order = [ 'column' => 'id', 'type' => 'DESC' ]; -$grid -> search = [ - [ 'name' => 'Nazwa', 'db' => 'name', 'type' => 'text' ], - [ 'name' => 'Aktywny', 'db' => 'status', 'type' => 'select', 'replace' => [ 'array' => [ 0 => 'nie', 1 => 'tak' ] ] ] -]; -$grid -> columns_view = [ - [ - 'name' => 'Lp.', - 'th' => [ 'class' => 'g-lp' ], - 'td' => [ 'class' => 'g-center' ], - 'autoincrement' => true - ], [ - 'name' => 'Aktywny', - 'db' => 'status', - 'replace' => [ 'array' => [ 0 => 'nie', 1 => 'tak' ] ], - 'td' => [ 'class' => 'g-center' ], - 'th' => [ 'class' => 'g-center', 'style' => 'width: 150px;' ], - 'sort' => true - ], [ - 'name' => 'Nazwa', - 'db' => 'name', - 'sort' => true, - 'php' => 'echo "[name]";' - ], [ - 'name' => 'Typ kuponu', - 'db' => 'condition_type', - 'replace' => [ 'array' => \shop\Promotion::$condition_type ] - ], [ - 'name' => 'Data do', - 'db' => 'date_to', - 'td' => [ 'class' => 'g-center' ], - 'th' => [ 'class' => 'g-center', 'style' => 'width: 150px;' ] - ], [ - 'name' => 'Edytuj', - 'action' => [ 'type' => 'edit', 'url' => '/admin/shop_promotion/edit/id=[id]' ], - 'th' => [ 'class' => 'g-center', 'style' => 'width: 70px;' ], - 'td' => [ 'class' => 'g-center' ] - ], [ - 'name' => 'Usuń', - 'action' => [ 'type' => 'delete', 'url' => '/admin/shop_promotion/promotion_delete/id=[id]' ], - 'th' => [ 'class' => 'g-center', 'style' => 'width: 70px;' ], - 'td' => [ 'class' => 'g-center' ] - ] -]; -$grid -> buttons = [ - [ - 'label' => 'Dodaj promocję', - 'url' => '/admin/shop_promotion/edit/', - 'icon' => 'fa-plus-circle', - 'class' => 'btn-success' - ] -]; -echo $grid -> draw(); diff --git a/admin/templates/site/main-layout.php b/admin/templates/site/main-layout.php index fc02fed..aeeb88d 100644 --- a/admin/templates/site/main-layout.php +++ b/admin/templates/site/main-layout.php @@ -76,7 +76,7 @@ Statusy zamówień
  • Kody rabatowe
  • -
  • Promocje
  • +
  • Promocje
  • Zawartość