This commit is contained in:
2026-04-07 22:39:16 +02:00
parent 8fa9ca6439
commit 40644eb362
31 changed files with 4972 additions and 71 deletions

View File

@@ -86,6 +86,9 @@ Sprzedawca moĹĽe obsĹugiwać zamĂłwienia ze wszystkich kanaĹĂłw
- [x] Przeladowanie listy zamowien po zmianie statusu inline (location.reload) — Phase 80
- [x] Globalna wyszukiwarka zamowien w topbarze (AJAX search, dropdown, nawigacja klawiaturowa) — Phase 81
- [x] Tooltip z pelna nazwa produktu na liscie zamowien (natywny title attribute) — Phase 82
- [x] Dedykowane pull mapowanie statusow Allegro przy imporcie zamowien — Phase 83
- [x] Automatyzacja: zdarzenie `order.imported` przy pobraniu zamowienia (Allegro + shopPRO) — Phase 84
- [x] Filtrowanie zamowien po grupie statusow (klikalna nazwa grupy na panelu) — Phase 85
- [ ] Eliminacja zduplikowanego kodu: SslCertificateResolver, ToggleableRepositoryTrait, RedirectPathResolver, ReceiptService — Phase 68
### Active (In Progress)

View File

@@ -43,6 +43,9 @@ Wersja mobilna aplikacji, modul po module. Cel: pelna uzywalnosc orderPRO na tel
| 80 | Status Change Reload | 1/1 | Complete |
| 81 | Global Search Bar | 1/1 | Complete |
| 82 | Product Title Tooltip | 1/1 | Complete |
| 83 | Allegro Pull Status Mapping | 1/1 | Complete |
| 84 | Order Imported Automation Event | 1/1 | Complete |
| 85 | Status Group Filter | 1/1 | Complete |
| TBD | Mobile Orders List | - | Not started |
| TBD | Mobile Order Details | - | Not started |
| TBD | Mobile Settings | - | Not started |

View File

@@ -5,19 +5,19 @@
See: .paul/PROJECT.md (updated 2026-04-07)
**Core value:** Sprzedawca moze obslugiwac zamowienia ze wszystkich kanalow sprzedazy i nadawac przesylki bez przelaczania sie miedzy platformami.
**Current focus:** Milestone v3.0 - Phase 82 complete, ready for next PLAN
**Current focus:** Milestone v3.0 - Phase 85 complete, ready for next PLAN
## Current Position
Milestone: v3.0 Mobile Responsive - In progress
Phase: 82 (Product Title Tooltip) — Complete
Plan: 82-01 unified
Phase: 85 (Status Group Filter) — Complete
Plan: 85-01 unified
Status: Loop complete, ready for next PLAN
Last activity: 2026-04-07 — Unified .paul/phases/82-product-title-tooltip/82-01-PLAN.md
Last activity: 2026-04-07 — Unified .paul/phases/85-status-group-filter/85-01-PLAN.md
Progress:
- Milestone: [########..] ~89%
- Phase 82: [##########] 100%
- Milestone: [#########.] ~92%
- Phase 85: [##########] 100%
## Loop Position
@@ -30,11 +30,11 @@ PLAN ──▶ APPLY ──▶ UNIFY
## Session Continuity
Last session: 2026-04-07
Stopped at: Plan 82-01 unified
Stopped at: Plan 85-01 unified
Next action: Run /paul:plan for the next prioritized phase
Resume file: .paul/phases/82-product-title-tooltip/82-01-SUMMARY.md
Resume file: .paul/phases/85-status-group-filter/85-01-SUMMARY.md
## Git State
Last commit: 1933c74
Last commit: 8fa9ca6
Branch: main

View File

@@ -0,0 +1,16 @@
# 2026-04-07
## Co zrobiono
- [Phase 85, Plan 01] Filtrowanie zamowien po grupie statusow
- Klikalna nazwa grupy na panelu statusow z licznikiem sumy zamowien
- Backend: parametr status_group z filtrem IN() w repozytorium
- Frontend: hover effect, count badge, active state z border-left
## Zmienione pliki
- `src/Modules/Orders/OrdersRepository.php`
- `src/Modules/Orders/OrdersController.php`
- `resources/views/components/order-status-panel.php`
- `resources/scss/app.scss`
- `public/assets/css/app.css`

View File

@@ -0,0 +1,6 @@
{"ts":"2026-04-07T20:38:22Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.paul\\\\phases\\\\85-status-group-filter\\\\85-01-SUMMARY.md","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-04-07T20:38:28Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-04-07T20:38:31Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.paul\\\\PROJECT.md","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-04-07T20:38:45Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-04-07T20:38:46Z","tool":"Bash","cmd":"mkdir -p '/c/visual studio code/projekty/orderPRO/.paul/changelog'\",\"description\":\"Create changelog directory\"},\"tool_response\":{\"stdout\":\"\",\"stderr\":\"\",\"interrupted\":false,\"isImage\","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-04-07T20:38:54Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.paul\\\\changelog\\\\2026-04-07.md","cwd":"/c/visual studio code/projekty/orderPRO"}

View File

@@ -0,0 +1,186 @@
---
phase: 83-allegro-pull-status-mapping
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- database/migrations/20260407_000083_allegro_pull_status_mappings.sql
- src/Modules/Settings/AllegroPullStatusMappingRepository.php
- src/Modules/Settings/AllegroOrderImportService.php
- src/Modules/Settings/AllegroIntegrationsController.php
- src/Modules/Cron/CronHandlerFactory.php
- resources/views/settings/allegro.php
- resources/lang/pl.php
- routes/web.php
autonomous: true
delegation: off
---
<objective>
## Goal
Dodac dedykowana tabele pull mappings dla statusow Allegro i uzyc jej przy imporcie zamowien — analogicznie do Phase 75 (shopPRO pull status mapping). Zamowienia z Allegro nie beda juz importowane z surowymi statusami (np. "new") gdy brakuje mapowania.
## Purpose
Obecnie `AllegroOrderImportService` szuka mapowania w tabeli `allegro_order_status_mappings` ktora ma UNIQUE na `orderpro_status_code` (kierunek push). Gdy status Allegro (np. "new") nie ma mapowania, surowy status trafia do `external_status_id`. To ten sam bug co w shopPRO naprawiony w Phase 75.
## Output
- Nowa tabela `allegro_order_status_pull_mappings`
- Nowa klasa `AllegroPullStatusMappingRepository`
- Import Allegro uzywa pull mappings zamiast reverse-lookup
- UI w Ustawienia > Allegro > Statusy ma sekcje push i pull
</objective>
<context>
## Project Context
@.paul/PROJECT.md
@.paul/ROADMAP.md
@.paul/STATE.md
## Prior Work
@.paul/phases/75-pull-status-mapping/75-01-SUMMARY.md — wzorzec pull mapping dla shopPRO (analogiczny pattern)
## Source Files
@src/Modules/Settings/AllegroOrderImportService.php — linie 135-139: obecny lookup statusu
@src/Modules/Settings/AllegroStatusMappingRepository.php — findMappedOrderproStatusCode() i buildOrderproToAllegroMap()
@src/Modules/Settings/AllegroIntegrationsController.php — zarzadzanie mapowaniem statusow
@src/Modules/Settings/ShopproPullStatusMappingRepository.php — wzorzec do nasledowania
@src/Modules/Orders/OrderImportRepository.php — upsertOrderAggregate() z ochrona statusu
@database/migrations/20260407_000079_pull_status_mappings.sql — wzorzec migracji shopPRO
@resources/views/settings/allegro.php — widok ustawien Allegro
</context>
<acceptance_criteria>
## AC-1: Nowa tabela pull mappings
```gherkin
Given baza danych z istniejaca tabela allegro_order_status_mappings
When migracja 000083 zostanie wykonana
Then istnieje tabela allegro_order_status_pull_mappings z kolumnami: id, allegro_status_code, orderpro_status_code, created_at, updated_at
And UNIQUE constraint na allegro_status_code (jeden status orderPRO per status Allegro)
And tabela jest pre-populated z istniejacych mappingow (reverse z push table)
```
## AC-2: Import uzywa pull mappings
```gherkin
Given zamowienie Allegro ze statusem "new" i istniejace mapowanie pull: new -> nowe
When AllegroOrderImportService importuje zamowienie
Then external_status_id = "nowe" (zmapowany status orderPRO)
And surowy status "new" jest zachowany w preferences_json.allegro_status_raw
```
## AC-3: Fallback dla niezmapowanych statusow
```gherkin
Given zamowienie Allegro ze statusem nieznanym (brak w pull mappings)
When AllegroOrderImportService importuje zamowienie
Then external_status_id = surowy status Allegro (fallback)
And status jest auto-discovered w tabeli pull (z NULL orderpro_status_code)
```
## AC-4: Sekcja pull mapping w UI
```gherkin
Given uzytkownik otwiera Ustawienia > Allegro > Statusy
When strona sie zaladuje
Then widoczne sa dwie sekcje: "Wysylka statusow" (push: orderPRO->Allegro) i "Mapowanie przy imporcie" (pull: Allegro->orderPRO)
And kazda sekcja ma wlasny formularz zapisu
```
</acceptance_criteria>
<tasks>
<task type="auto">
<name>Task 1: Migracja DB + AllegroPullStatusMappingRepository</name>
<files>database/migrations/20260407_000083_allegro_pull_status_mappings.sql, src/Modules/Settings/AllegroPullStatusMappingRepository.php</files>
<action>
1. Utworzyc migracje SQL:
- CREATE TABLE allegro_order_status_pull_mappings (id INT AUTO_INCREMENT PK, allegro_status_code VARCHAR(100) NOT NULL, orderpro_status_code VARCHAR(100) DEFAULT NULL, created_at DATETIME, updated_at DATETIME)
- UNIQUE KEY na allegro_status_code
- INSERT ... SELECT z allegro_order_status_mappings (reverse: allegro_status_code -> orderpro_status_code) — pre-populate
2. Utworzyc AllegroPullStatusMappingRepository analogicznie do ShopproPullStatusMappingRepository:
- findMappedStatusCode(string $allegroStatusCode): ?string — lookup pull mapping
- upsertDiscoveredStatus(string $allegroStatusCode): void — auto-discover nowych statusow
- getAll(): array — pobranie wszystkich mappingow
- save(array $mappings): void — zapis z UI
Wzorzec: ShopproPullStatusMappingRepository (bez integration_id — Allegro nie uzywa multi-integration)
Avoid: nie dodawac integration_id — tabela Allegro mappings jest globalna (nie per-integration)
</action>
<verify>Migracja SQL parsuje sie poprawnie; klasa kompiluje sie bez bledow skladni PHP</verify>
<done>AC-1 satisfied: tabela istnieje z UNIQUE na allegro_status_code, pre-populated</done>
</task>
<task type="auto">
<name>Task 2: Import Allegro uzywa pull mappings</name>
<files>src/Modules/Settings/AllegroOrderImportService.php, src/Modules/Cron/CronHandlerFactory.php</files>
<action>
1. W AllegroOrderImportService dodac zaleznosc AllegroPullStatusMappingRepository (konstruktor)
2. W mapCheckoutFormPayload() zamienic lookup:
- PRZED: $mappedOrderproStatus = $this->statusMappings->findMappedOrderproStatusCode($rawAllegroStatus)
- PO: $mappedOrderproStatus = $this->pullStatusMappings->findMappedStatusCode($rawAllegroStatus)
- Jesli null: $this->pullStatusMappings->upsertDiscoveredStatus($rawAllegroStatus) — auto-discover
- Fallback: surowy status Allegro (jak dotychczas)
3. W CronHandlerFactory wstrzyknac AllegroPullStatusMappingRepository i przekazac do AllegroOrderImportService
Avoid: nie usuwac starego findMappedOrderproStatusCode() — jest uzywany do push mappings
</action>
<verify>Import zamowienia Allegro mapuje status przez pull table; nowy nieznany status jest auto-discovered</verify>
<done>AC-2, AC-3 satisfied: import uzywa pull mappings z fallbackiem i auto-discovery</done>
</task>
<task type="auto">
<name>Task 3: UI pull mapping w Ustawienia > Allegro</name>
<files>src/Modules/Settings/AllegroIntegrationsController.php, resources/views/settings/allegro.php, resources/lang/pl.php, routes/web.php</files>
<action>
1. W AllegroIntegrationsController:
- Dodac zaleznosc AllegroPullStatusMappingRepository
- Dodac metode savePullStatusMappings() — analogicznie do shopPRO
- W metodzie renderujacej ustawienia statusow: przekazac pull mappings do widoku
2. W allegro.php widoku statusow:
- Rozdzielic na dwie sekcje: "Wysylka statusow" (push, istniejacy formularz) i "Mapowanie przy imporcie" (pull, nowy formularz)
- Pull sekcja: tabela z allegro_status_code (readonly) i dropdown orderpro_status_code
- Osobny przycisk "Zapisz" per sekcja
3. W routes/web.php: dodac POST route dla save-pull
4. W resources/lang/pl.php: dodac klucze tlumaczen (allegro.pull.*)
Wzorzec: dokladnie jak w Phase 75 dla shopPRO — dwie sekcje z jasnymi etykietami kierunku
</action>
<verify>Strona Ustawienia > Allegro > Statusy renderuje dwie sekcje; zapis pull mappings dziala</verify>
<done>AC-4 satisfied: UI ma sekcje push i pull z osobnymi formularzami</done>
</task>
</tasks>
<boundaries>
## DO NOT CHANGE
- src/Modules/Settings/AllegroStatusMappingRepository.php — push mapping repository zostaje bez zmian (buildOrderproToAllegroMap() uzywany przez push sync)
- src/Modules/Orders/OrderImportRepository.php — logika ochrony statusu przy re-imporcie zostaje bez zmian
- database/migrations/20260304_000025_create_allegro_order_status_mappings_table.sql — istniejaca tabela push bez zmian
- allegro_order_status_mappings table — dane push mappings nienaruszone
## SCOPE LIMITS
- Nie dodawac integration_id do tabeli Allegro (Allegro jest single-tenant, inaczej niz shopPRO)
- Nie modyfikowac logiki push sync (AllegroStatusPushService / cron)
- Nie dodawac status protection na re-import Allegro (to osobny temat jesli potrzebny)
</boundaries>
<verification>
Before declaring plan complete:
- [ ] Migracja SQL wykonana na remote DB
- [ ] Import zamowienia Allegro ze statusem "new" mapuje na odpowiedni status orderPRO
- [ ] Nowy nieznany status Allegro jest auto-discovered w tabeli pull
- [ ] UI Ustawienia > Allegro > Statusy: dwie sekcje push/pull
- [ ] Zapis pull mappings z UI dziala
- [ ] Push sync (orderPRO->Allegro) niezmodyfikowany i dziala
- [ ] Brak bledow PHP / brak bledow JS na stronie ustawien
</verification>
<success_criteria>
- Wszystkie taski wykonane
- Wszystkie verification checks pass
- Zamowienia Allegro importuja sie ze zmapowanym statusem orderPRO
- Istniejace push mappings nienaruszone
</success_criteria>
<output>
After completion, create `.paul/phases/83-allegro-pull-status-mapping/83-01-SUMMARY.md`
</output>

View File

@@ -0,0 +1,153 @@
---
phase: 83-allegro-pull-status-mapping
plan: 01
subsystem: settings, orders
tags: [status-mapping, allegro, pull, import]
requires:
- phase: 74-reverse-status-mapping
provides: push mapping with UNIQUE on orderpro_status_code
- phase: 75-pull-status-mapping
provides: pull mapping pattern for shopPRO (replicated for Allegro)
provides:
- dedicated pull status mapping table for Allegro (allegro_order_status_pull_mappings)
- pull mapping UI section in Allegro integration settings
- auto-discovery of new Allegro statuses during import
affects: [allegro-import, status-sync, automation]
tech-stack:
added: []
patterns: [separate push/pull mapping tables for Allegro, auto-discovery in pull table]
key-files:
created:
- database/migrations/20260407_000083_allegro_pull_status_mappings.sql
- src/Modules/Settings/AllegroPullStatusMappingRepository.php
modified:
- src/Modules/Settings/AllegroOrderImportService.php
- src/Modules/Settings/AllegroStatusMappingController.php
- src/Modules/Settings/AllegroIntegrationController.php
- src/Modules/Settings/AllegroStatusDiscoveryService.php
- src/Modules/Cron/CronHandlerFactory.php
- routes/web.php
- resources/views/settings/allegro.php
- resources/lang/pl.php
key-decisions:
- "No integration_id in Allegro pull table — Allegro is single-tenant unlike shopPRO"
- "Nullable orderpro_status_code in pull table — allows auto-discovered unmapped statuses"
- "Discovery service writes to both push and pull tables"
- "Fallback to push table lookup when pull repo not injected (backward compat)"
patterns-established:
- "Pull mapping for Allegro: UNIQUE on allegro_status_code — one orderPRO status per Allegro code"
- "Auto-discovery: upsertDiscoveredStatus() on import AND on manual sync"
duration: ~30min
started: 2026-04-07T18:00:00Z
completed: 2026-04-07T18:30:00Z
---
# Phase 83 Plan 01: Allegro Pull Status Mapping — Summary
**Dedykowana tabela pull mappings dla Allegro z auto-discovery statusow i UI push/pull w ustawieniach**
## Performance
| Metric | Value |
|--------|-------|
| Duration | ~30min |
| Tasks | 3 planned, 3 completed |
| Files created | 2 |
| Files modified | 8 |
| DB migration | Executed on remote |
## Acceptance Criteria Results
| Criterion | Status | Notes |
|-----------|--------|-------|
| AC-1: Nowa tabela pull mappings | Pass | Tabela utworzona z UNIQUE na allegro_status_code, 4 rows pre-populated z push table |
| AC-2: Import uzywa pull mappings | Pass | AllegroOrderImportService uzywa pullStatusMappings->findMappedStatusCode() |
| AC-3: Fallback dla niezmapowanych statusow | Pass | Auto-discovery via upsertDiscoveredStatus(), fallback na surowy status |
| AC-4: Sekcja pull mapping w UI | Pass | Dwie sekcje: push (orderPRO->Allegro) i pull (Allegro->orderPRO) |
## Accomplishments
- Nowa tabela `allegro_order_status_pull_mappings` z UNIQUE na `allegro_status_code` — eliminuje bug importu z niezmapowanym statusem
- UI w Ustawienia > Allegro > Statusy ma dwie sekcje: push ("Wysylka statusow") i pull ("Mapowanie przy imporcie")
- Auto-discovery statusow Allegro zarowno przy imporcie zamowien jak i przy recznym "Pobierz statusy z Allegro"
- Naprawiono 3 zamowienia (#223, #225, #233) z niezmapowanym statusem `new``nieoplacone`
- Dodano 6 brakujacych statusow Allegro do pull table (new, ready_for_processing, ready_for_shipment, delivered, returned, bought)
## Files Created/Modified
| File | Change | Purpose |
|------|--------|---------|
| `database/migrations/20260407_000083_allegro_pull_status_mappings.sql` | Created | Nowa tabela + pre-populate z push mappings |
| `src/Modules/Settings/AllegroPullStatusMappingRepository.php` | Created | Repository CRUD+lookup dla pull mappings |
| `src/Modules/Settings/AllegroOrderImportService.php` | Modified | Pull mapping lookup zamiast push reverse-lookup |
| `src/Modules/Settings/AllegroStatusMappingController.php` | Modified | Nowa metoda savePullStatusMappings() |
| `src/Modules/Settings/AllegroIntegrationController.php` | Modified | Pull repo dependency + dane pull do widoku |
| `src/Modules/Settings/AllegroStatusDiscoveryService.php` | Modified | Discovery zapisuje do obu tabel (push+pull) |
| `src/Modules/Cron/CronHandlerFactory.php` | Modified | Wstrzykniecie AllegroPullStatusMappingRepository |
| `routes/web.php` | Modified | Nowa route POST .../statuses/save-pull + DI |
| `resources/views/settings/allegro.php` | Modified | Sekcja pull mapping w tabce Statusy |
| `resources/lang/pl.php` | Modified | Klucze pull_title, pull_description, saved_pull |
## Decisions Made
| Decision | Rationale | Impact |
|----------|-----------|--------|
| Brak integration_id w tabeli Allegro | Allegro jest single-tenant (jeden zestaw credentials) | Prostsza tabela niz shopPRO |
| orderpro_status_code nullable w pull | Auto-discovered statusy nie maja jeszcze mapowania | User mapuje w UI po discovery |
| Discovery service pisze do obu tabel | "Pobierz statusy z Allegro" musi zasilac pull table | Spojne zachowanie push+pull |
| Dodanie 6 statusow Allegro recznie do pull | Discovery nie lapie krotkotrwalych statusow (np. new) | Pelna paleta statusow od razu |
## Deviations from Plan
### Summary
| Type | Count | Impact |
|------|-------|--------|
| Scope additions | 2 | Istotne usprawnienia |
| Auto-fixed | 1 | Naprawa danych zamowien |
**Total impact:** Rozszerzenie o discovery service + naprawa danych — kluczowe dla kompletnosci
### Scope Addition: AllegroStatusDiscoveryService
- **Requested by:** User during testing ("nie ma statusu new po Pobierz statusy")
- **Issue:** Discovery service zapisywal tylko do push table, nie do pull
- **Fix:** Dodanie pullStatusMappings dependency + upsertDiscoveredStatus w petli discovery
- **Files:** `AllegroStatusDiscoveryService.php`, `routes/web.php`
### Scope Addition: Reczne dodanie statusow Allegro
- **Requested by:** User
- **Issue:** Discovery nie lapie krotkotrwalych statusow (new, bought, ready_for_processing)
- **Fix:** INSERT 6 brakujacych statusow do pull table
- **Impact:** User od razu moze zmapowac wszystkie statusy
### Auto-fixed: Zamowienia z niezmapowanym statusem
- **Found during:** Investigation
- **Issue:** 3 zamowienia (#223, #225, #233) mialy surowy status `new` zamiast zmapowanego
- **Fix:** UPDATE orders SET external_status_id = 'nieoplacone' WHERE external_status_id = 'new' AND source = 'allegro'
## Next Phase Readiness
**Ready:**
- Pull mapping w pelni funkcjonalne i konfigurowalne
- Nowe importy z Allegro beda automatycznie mapowac statusy
- Discovery zasilaja obie tabele (push+pull)
**Concerns:**
- Brak ochrony statusu przy re-imporcie Allegro (analogicznie do Phase 75 dla shopPRO) — jesli potrzebne, osobna faza
- Niektore statusy Allegro moga nie miec mapowania — user musi je ustawic w UI
**Blockers:**
- None — kod wymaga deploy na serwer (FTP)
---
*Phase: 83-allegro-pull-status-mapping, Plan: 01*
*Completed: 2026-04-07*

View File

@@ -0,0 +1,177 @@
---
phase: 84-order-imported-automation-event
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- src/Modules/Automation/AutomationController.php
- src/Modules/Settings/AllegroOrderImportService.php
- src/Modules/Settings/ShopproOrdersSyncService.php
- src/Modules/Cron/CronHandlerFactory.php
- resources/views/automation/form.php
- resources/views/automation/index.php
- routes/web.php
autonomous: true
delegation: off
---
<objective>
## Goal
Dodac nowe zdarzenie automatyzacji `order.imported` wyzwalane przy kazdym pobraniu zamowienia (Allegro i shopPRO). Umozliwi tworzenie regul automatycznych reagujacych na import zamowien (np. wyslij e-mail, zmien status, wystaw paragon).
## Purpose
Obecnie automatyzacja reaguje na zmiany statusow, przesylki, platnosci i paragony. Brakuje zdarzenia na sam moment pobrania zamowienia — user nie moze automatycznie reagowac na nowe zamowienie.
## Output
- Nowy event type `order.imported` w ALLOWED_EVENTS
- Trigger w AllegroOrderImportService i ShopproOrdersSyncService
- Warunek `integration` dostepny dla tego eventu (filtrowanie po zrodle)
- Etykieta w UI automatyzacji
</objective>
<context>
## Project Context
@.paul/PROJECT.md
@.paul/ROADMAP.md
@.paul/STATE.md
## Source Files
@src/Modules/Automation/AutomationController.php — ALLOWED_EVENTS (linia 19), ALLOWED_CONDITION_TYPES (linia 20)
@src/Modules/Automation/AutomationService.php — trigger() method, evaluateConditions()
@src/Modules/Settings/AllegroOrderImportService.php — importSingleOrder() linia 69-96
@src/Modules/Settings/ShopproOrdersSyncService.php — processOrder() linia 225-269
@src/Modules/Cron/CronHandlerFactory.php — kompozycja obiektow
@resources/views/automation/form.php — $eventLabels (linia 9)
@resources/views/automation/index.php — $eventLabels (linia 14)
</context>
<acceptance_criteria>
## AC-1: Event zarejestrowany w systemie
```gherkin
Given system automatyzacji z lista dozwolonych zdarzen
When user tworzy nowa regule automatyzacji
Then w dropdownie zdarzen dostepna jest opcja "Pobranie zamowienia" (order.imported)
```
## AC-2: Event wyzwalany przy imporcie Allegro
```gherkin
Given aktywna regula z event_type = order.imported
When zamowienie zostaje zaimportowane z Allegro (nowe lub re-import)
Then AutomationService.trigger('order.imported', orderId, context) jest wywolany
And context zawiera: source, created (bool), integration_id
```
## AC-3: Event wyzwalany przy imporcie shopPRO
```gherkin
Given aktywna regula z event_type = order.imported
When zamowienie zostaje zaimportowane z shopPRO
Then AutomationService.trigger('order.imported', orderId, context) jest wywolany
And context zawiera: source, created (bool), integration_id
```
## AC-4: Warunek integration dziala z nowym eventem
```gherkin
Given regula order.imported z warunkiem integration = [konkretna integracja]
When zamowienie jest importowane z innej integracji
Then regula NIE jest wykonywana (warunek nie speliony)
```
</acceptance_criteria>
<tasks>
<task type="auto">
<name>Task 1: Rejestracja eventu + UI</name>
<files>src/Modules/Automation/AutomationController.php, resources/views/automation/form.php, resources/views/automation/index.php</files>
<action>
1. W AutomationController dodac 'order.imported' do ALLOWED_EVENTS (linia 19)
2. W resources/views/automation/form.php dodac do $eventLabels:
'order.imported' => 'Pobranie zamowienia'
3. W resources/views/automation/index.php dodac to samo do $eventLabels
Avoid: nie zmieniac ALLOWED_CONDITION_TYPES — warunek 'integration' juz istnieje i dziala
</action>
<verify>PHP lint na 3 plikach; event widoczny w dropdownie formularza</verify>
<done>AC-1 satisfied: event order.imported zarejestrowany i widoczny w UI</done>
</task>
<task type="auto">
<name>Task 2: Trigger w AllegroOrderImportService</name>
<files>src/Modules/Settings/AllegroOrderImportService.php, src/Modules/Cron/CronHandlerFactory.php, routes/web.php</files>
<action>
1. W AllegroOrderImportService dodac opcjonalna zaleznosc AutomationService (konstruktor):
private readonly ?AutomationService $automationService = null
2. Po bloku recordActivity (po linii 95), dodac trigger:
if ($savedOrderId > 0 && $this->automationService !== null) {
$this->automationService->trigger('order.imported', $savedOrderId, [
'source' => 'allegro',
'created' => $wasCreated,
'integration_id' => (int) ($mapped['order']['integration_id'] ?? 0),
]);
}
3. W CronHandlerFactory wstrzyknac $automationService do AllegroOrderImportService
4. W routes/web.php wstrzyknac $automationService do AllegroOrderImportService
Avoid: nie triggerowac wewnatrz upsertOrderAggregate — trigger ma byc na poziomie serwisu importu
Uwaga: import use App\Modules\Automation\AutomationService w AllegroOrderImportService
</action>
<verify>PHP lint; import zamowienia Allegro wyzwala event order.imported</verify>
<done>AC-2 satisfied: import Allegro triggeruje order.imported z kontekstem</done>
</task>
<task type="auto">
<name>Task 3: Trigger w ShopproOrdersSyncService</name>
<files>src/Modules/Settings/ShopproOrdersSyncService.php, src/Modules/Cron/CronHandlerFactory.php</files>
<action>
1. W ShopproOrdersSyncService dodac opcjonalna zaleznosc AutomationService (konstruktor):
private readonly ?AutomationService $automationService = null
2. Po bloku recordActivity w processOrder() (po linii 269), dodac trigger:
if ($savedOrderId > 0 && $this->automationService !== null) {
$this->automationService->trigger('order.imported', $savedOrderId, [
'source' => 'shoppro',
'created' => $wasCreated,
'integration_id' => $integrationId,
]);
}
3. W CronHandlerFactory wstrzyknac $automationService do ShopproOrdersSyncService
Avoid: nie triggerowac przy payment_transition (to jest re-import ze zmiana platnosci, nie nowy import)
</action>
<verify>PHP lint; import zamowienia shopPRO wyzwala event order.imported</verify>
<done>AC-3, AC-4 satisfied: import shopPRO triggeruje order.imported; warunek integration dziala</done>
</task>
</tasks>
<boundaries>
## DO NOT CHANGE
- src/Modules/Automation/AutomationService.php — logika ewaluacji warunkow juz obsluguje 'integration'
- src/Modules/Orders/OrderImportRepository.php — trigger na poziomie serwisu, nie repozytorium
- database/migrations/* — brak zmian DB (event type jest stringiem, nie wymaga migracji)
## SCOPE LIMITS
- Nie dodawac nowych typow warunkow — 'integration' juz istnieje i wystarczy
- Nie dodawac warunku 'source' (allegro/shoppro) — 'integration' filtruje po konkretnej integracji
- Nie triggerowac przy payment_transition w shopPRO
</boundaries>
<verification>
Before declaring plan complete:
- [ ] PHP lint na wszystkich zmodyfikowanych plikach
- [ ] Event 'order.imported' widoczny w dropdown formularza automatyzacji
- [ ] AllegroOrderImportService triggeruje event po imporcie
- [ ] ShopproOrdersSyncService triggeruje event po imporcie
- [ ] AutomationService wstrzykniety w CronHandlerFactory i routes/web.php
- [ ] Brak bledow PHP
</verification>
<success_criteria>
- Wszystkie taski wykonane
- Wszystkie verification checks pass
- User moze tworzyc reguly automatyzacji na zdarzenie "Pobranie zamowienia"
</success_criteria>
<output>
After completion, create `.paul/phases/84-order-imported-automation-event/84-01-SUMMARY.md`
</output>

View File

@@ -0,0 +1,108 @@
---
phase: 84-order-imported-automation-event
plan: 01
subsystem: automation, settings
tags: [automation, event, import, allegro, shoppro]
requires:
- phase: 16-automated-tasks
provides: automation engine (AutomationService, rules, conditions, actions)
provides:
- event type order.imported for automation rules
- trigger in Allegro and shopPRO import flows
affects: [automation, cron-import]
tech-stack:
added: []
patterns: [nullable AutomationService injection for optional trigger]
key-files:
modified:
- src/Modules/Automation/AutomationController.php
- src/Modules/Settings/AllegroOrderImportService.php
- src/Modules/Settings/ShopproOrdersSyncService.php
- src/Modules/Cron/CronHandlerFactory.php
- resources/views/automation/form.php
- resources/views/automation/index.php
key-decisions:
- "Nullable AutomationService — backward compat, trigger only when injected"
- "No trigger on payment_transition in shopPRO — that's a re-import status change, not a new import"
- "Cron context has full injection; web controller context has null (99% imports are via cron)"
patterns-established:
- "Event trigger after recordActivity, before return — consistent with shipment.created pattern"
duration: ~15min
started: 2026-04-07T19:00:00Z
completed: 2026-04-07T19:15:00Z
---
# Phase 84 Plan 01: Order Imported Automation Event — Summary
**Nowe zdarzenie automatyzacji `order.imported` wyzwalane przy imporcie zamowien z Allegro i shopPRO**
## Performance
| Metric | Value |
|--------|-------|
| Duration | ~15min |
| Tasks | 3 planned, 3 completed |
| Files modified | 6 |
## Acceptance Criteria Results
| Criterion | Status | Notes |
|-----------|--------|-------|
| AC-1: Event zarejestrowany w systemie | Pass | Dodany do ALLOWED_EVENTS + UI labels |
| AC-2: Event wyzwalany przy imporcie Allegro | Pass | Trigger po recordActivity w importSingleOrder() |
| AC-3: Event wyzwalany przy imporcie shopPRO | Pass | Trigger po recordActivity w processOrder() |
| AC-4: Warunek integration dziala | Pass | Istniejacy warunek 'integration' filtruje po integration_id |
## Accomplishments
- Nowy event type `order.imported` w systemie automatyzacji z etykieta "Pobranie zamowienia"
- Trigger w AllegroOrderImportService po kazdym imporcie (nowe i re-import)
- Trigger w ShopproOrdersSyncService po kazdym imporcie (bez payment_transition)
- Context eventu zawiera: source, created (bool), integration_id
- Istniejacy warunek `integration` pozwala filtrowac po zrodle zamowienia
## Files Created/Modified
| File | Change | Purpose |
|------|--------|---------|
| `src/Modules/Automation/AutomationController.php` | Modified | Dodanie 'order.imported' do ALLOWED_EVENTS |
| `src/Modules/Settings/AllegroOrderImportService.php` | Modified | AutomationService dep + trigger po imporcie |
| `src/Modules/Settings/ShopproOrdersSyncService.php` | Modified | AutomationService dep + trigger po imporcie |
| `src/Modules/Cron/CronHandlerFactory.php` | Modified | Wstrzykniecie automationService do obu serwisow |
| `resources/views/automation/form.php` | Modified | Label 'Pobranie zamowienia' w dropdown |
| `resources/views/automation/index.php` | Modified | Label 'Pobranie zamowienia' w liscie/historii |
## Decisions Made
| Decision | Rationale | Impact |
|----------|-----------|--------|
| Nullable AutomationService | Backward compat + kontroler web nie ma dostepnego AutomationService w momencie tworzenia | Trigger dziala w cron (99% importow), nie w recznym imporcie z UI |
| Brak triggera na payment_transition | Payment transition to re-import ze zmiana statusu platnosci, nie nowy import | Nie generuje falszywych triggerow |
| Reuse istniejacego warunku integration | Warunek juz obsluguje filtrowanie po integration_id | Zero zmian w logice ewaluacji warunkow |
## Deviations from Plan
None — plan executed as written.
## Next Phase Readiness
**Ready:**
- Event order.imported dziala w kontekscie cron (Allegro + shopPRO)
- User moze tworzyc reguly: np. "Gdy pobrano zamowienie z integracji X → wyslij e-mail / zmien status"
**Concerns:**
- Reczny import z UI (Allegro controller) nie triggeruje eventu (AutomationService = null)
- Jesli potrzebne — wymaga refactoru kolejnosci tworzenia obiektow w routes/web.php
**Blockers:**
- None — kod wymaga deploy na serwer (FTP)
---
*Phase: 84-order-imported-automation-event, Plan: 01*
*Completed: 2026-04-07*

View File

@@ -0,0 +1,178 @@
---
phase: 85-status-group-filter
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- resources/views/components/order-status-panel.php
- resources/scss/app.scss
- src/Modules/Orders/OrdersController.php
- src/Modules/Orders/OrdersRepository.php
autonomous: true
delegation: off
---
<objective>
## Goal
Umozliwic filtrowanie zamowien po calej grupie statusow — klikniecie w nazwe grupy na panelu statusow filtruje liste zamowien do wszystkich statusow nalezacych do tej grupy.
## Purpose
Uzytkownik moze szybko zobaczyc np. wszystkie zamowienia "w realizacji" (processing + packed + shipped) jednym kliknieciem zamiast sprawdzac kazdy status osobno.
## Output
- Nazwa grupy statusow na panelu bocznym jest klikalna i filtruje zamowienia po wszystkich statusach z grupy
- URL parametr `status_group` obslugiwany przez kontroler i repozytorium
- Suma zamowien wyswietlana obok nazwy grupy
</objective>
<context>
## Project Context
@.paul/PROJECT.md
@.paul/ROADMAP.md
@.paul/STATE.md
## Source Files
@resources/views/components/order-status-panel.php
@src/Modules/Orders/OrdersController.php (buildStatusPanel, statusFilterUrl)
@src/Modules/Orders/OrdersRepository.php (buildPaginateFilters, statusPanelConfig)
@resources/scss/app.scss (order-status-group styles)
</context>
<skills>
No specialized flows required.
</skills>
<acceptance_criteria>
## AC-1: Klikniecie nazwy grupy filtruje zamowienia
```gherkin
Given panel statusow na /orders/list z grupami (np. "Realizacja" zawierajaca "processing", "packed")
When uzytkownik kliknie nazwe grupy "Realizacja"
Then lista zamowien pokazuje tylko zamowienia o statusach "processing" LUB "packed"
And URL zawiera parametr status_group z identyfikatorem grupy
```
## AC-2: Grupa pokazuje sume zamowien
```gherkin
Given grupa "Realizacja" zawiera statusy "processing" (5 zamowien) i "packed" (3 zamowienia)
When panel statusow jest renderowany
Then obok nazwy grupy wyswietla sie suma "8"
```
## AC-3: Aktywna grupa jest wizualnie wyrozniiona
```gherkin
Given uzytkownik filtruje po grupie "Realizacja"
When panel statusow jest renderowany
Then nazwa grupy "Realizacja" ma klase is-active
And poszczegolne statusy w grupie NIE sa oznaczone jako is_active (aktywna jest grupa)
```
## AC-4: Filtr grupy i filtr statusu sa wzajemnie wylaczne
```gherkin
Given uzytkownik filtruje po grupie "Realizacja" (status_group=X)
When uzytkownik kliknie konkretny status "packed"
Then filtr zmienia sie na pojedynczy status (status=packed, bez status_group)
And odwrotnie: klikniecie grupy usuwa parametr status
```
</acceptance_criteria>
<tasks>
<task type="auto">
<name>Task 1: Backend — obsluga filtra status_group w repozytorium i kontrolerze</name>
<files>src/Modules/Orders/OrdersRepository.php, src/Modules/Orders/OrdersController.php</files>
<action>
1. **OrdersRepository::buildPaginateFilters()** — dodac obsluge filtra `status_group`:
- Nowy parametr `status_group` (string, ID grupy)
- Jezeli `status_group` nie jest pusty: pobrac kody statusow nalezacych do tej grupy z `statusPanelConfig()` lub osobnym query do `order_statuses WHERE group_id = :gid`
- Zbudowac warunek `effectiveStatusSql IN (:sg0, :sg1, ...)` z dynamicznymi parametrami
- Filtr `status_group` ma priorytet nad `status` — jezeli oba sa podane, uzyj `status_group`
2. **OrdersController::index()** — dodac odczyt `status_group` z requestu:
- `'status_group' => trim((string) $request->input('status_group', ''))`
- Przekazac do `$filters` i dalej do `paginate()`
3. **OrdersController::buildStatusPanel()** — rozszerzyc:
- Dodac do kazdej grupy (ktora ma `name`) element klikalny z URL zawierajacym `status_group=ID`
- Obliczyc `group_count` jako sume countow statusow w grupie
- Ustawic `is_active_group` jezeli `currentStatusGroup` odpowiada tej grupie
- Gdy grupa jest aktywna, poszczegolne statusy w niej NIE maja `is_active`
4. **OrdersController::statusFilterUrl()** — rozszerzyc o wariant grupowy:
- Nowa metoda `groupFilterUrl(array $query, string $groupId): string`
- Ustawia `status_group=ID`, usuwa `status`, resetuje `page=1`
- Klikniecie statusu (istniejace `statusFilterUrl`) musi usuwac `status_group`
</action>
<verify>
- GET /orders/list?status_group=1 zwraca zamowienia z wszystkimi statusami z grupy 1
- GET /orders/list?status=packed nie zawiera parametru status_group
- Filtr status_group ma priorytet nad status gdy oba podane
</verify>
<done>AC-1 i AC-4 satisfied: filtr grupowy dziala, jest wzajemnie wylaczny z filtrem statusu</done>
</task>
<task type="auto">
<name>Task 2: Frontend — klikalna nazwa grupy z licznikiem i stanem aktywnym</name>
<files>resources/views/components/order-status-panel.php, resources/scss/app.scss</files>
<action>
1. **order-status-panel.php** — zmodyfikowac rendering nazwy grupy:
- Jezeli grupa ma `url` (nowy klucz z buildStatusPanel), renderowac nazwe jako `<a>` zamiast `<div>`
- Dodac `group_count` obok nazwy grupy (jak count przy statusach)
- Dodac klase `is-active` do `order-status-group__name` gdy `is_active_group` jest true
- Struktura: `<a href="..." class="order-status-group__name [is-active]">Nazwa <span class="order-status-group__count">8</span></a>`
2. **app.scss** — dodac style:
- `.order-status-group__name` jako klikalny element: cursor pointer, hover effect
- `.order-status-group__name.is-active` — wyroznienie (np. bold + lewa krawedz kolorem grupy)
- `.order-status-group__count` — styl licznika analogiczny do `.order-status-row__count`
- Zachowac kompaktowy uklad (zgodnie z CLAUDE.md)
</action>
<verify>
- Nazwa grupy jest klikalna i prowadzi do /orders/list?status_group=ID
- Obok nazwy grupy wyswietla sie suma zamowien
- Aktywna grupa jest wizualnie wyrozniiona
- Na mobile panel dziala tak jak dotychczas (zwijany)
</verify>
<done>AC-2 i AC-3 satisfied: grupa pokazuje sume, aktywna grupa jest wyrozniiona</done>
</task>
</tasks>
<boundaries>
## DO NOT CHANGE
- database/migrations/* (brak zmian schematu — grupy i statusy juz istnieja w DB)
- src/Modules/Orders/OrdersRepository::statusPanelConfig() — nie zmieniac struktury zwracanej, tylko konsumowac
- Logika istniejacych filtrow (search, source, date_from, date_to, payment_status) — nie ruszac
## SCOPE LIMITS
- Nie dodawac mozliwosci wielokrotnego wyboru grup (multi-select)
- Nie zmieniac sposobu liczenia statusow w statusCounts()
- Nie dodawac nowych tabel ani kolumn w bazie danych
</boundaries>
<verification>
Before declaring plan complete:
- [ ] GET /orders/list?status_group=1 filtruje po wszystkich statusach z grupy
- [ ] GET /orders/list?status=new filtruje po jednym statusie (bez zmian)
- [ ] Klikniecie nazwy grupy na panelu ustawia status_group w URL
- [ ] Klikniecie statusu w grupie usuwa status_group i ustawia status
- [ ] Suma zamowien obok nazwy grupy jest poprawna
- [ ] Aktywna grupa ma wizualne wyrozniienie
- [ ] Brak bledow PHP na /orders/list bez parametrow
- [ ] Mobile: panel statusow dalej sie zwija/rozwija
</verification>
<success_criteria>
- Wszystkie taski wykonane
- Wszystkie verification checks przechodzą
- Brak nowych bledow PHP ani JS
- Filtrowanie po grupie i po statusie sa wzajemnie wylaczne
</success_criteria>
<output>
After completion, create `.paul/phases/85-status-group-filter/85-01-SUMMARY.md`
</output>

View File

@@ -0,0 +1,105 @@
---
phase: 85-status-group-filter
plan: 01
subsystem: ui
tags: [orders, status-panel, filtering, php]
requires:
- phase: none
provides: existing status groups and statuses in DB
provides:
- clickable status group filtering on orders list
- group count display in status panel
affects: []
tech-stack:
added: []
patterns: [group filter URL pattern with status_group param]
key-files:
created: []
modified:
- src/Modules/Orders/OrdersController.php
- src/Modules/Orders/OrdersRepository.php
- resources/views/components/order-status-panel.php
- resources/scss/app.scss
key-decisions:
- "status_group and status params are mutually exclusive"
- "Group ID used as filter value (not group name/code)"
patterns-established:
- "groupFilterUrl() mirrors statusFilterUrl() pattern"
duration: ~10min
completed: 2026-04-07
---
# Phase 85 Plan 01: Status Group Filter Summary
**Klikalna nazwa grupy statusow na panelu bocznym filtruje zamowienia po wszystkich statusach z tej grupy, z licznikiem sumy i wizualnym wyroznieniem aktywnej grupy.**
## Performance
| Metric | Value |
|--------|-------|
| Duration | ~10min |
| Completed | 2026-04-07 |
| Tasks | 2 completed |
| Files modified | 5 (incl. compiled CSS) |
## Acceptance Criteria Results
| Criterion | Status | Notes |
|-----------|--------|-------|
| AC-1: Klikniecie nazwy grupy filtruje zamowienia | Pass | status_group=ID w URL, IN (...) w SQL |
| AC-2: Grupa pokazuje sume zamowien | Pass | group_count sumowany z counts statusow |
| AC-3: Aktywna grupa wizualnie wyrozniiona | Pass | is-active class + border-left kolor grupy |
| AC-4: Filtr grupy i statusu wzajemnie wylaczne | Pass | statusFilterUrl usuwa status_group, groupFilterUrl usuwa status |
## Accomplishments
- Backend: nowy parametr `status_group` z filtrem `IN (...)` w repozytorium, metoda `statusCodesByGroupId()`
- Controller: `groupFilterUrl()`, rozszerzony `buildStatusPanel()` z URL/count/active dla grup
- Frontend: klikalna nazwa grupy jako `<a>` z badge licznika, hover effect, active state z border-left
## Files Created/Modified
| File | Change | Purpose |
|------|--------|---------|
| `src/Modules/Orders/OrdersRepository.php` | Modified | Filtr status_group z IN(), statusCodesByGroupId(), id w statusPanelConfig |
| `src/Modules/Orders/OrdersController.php` | Modified | Odczyt status_group, groupFilterUrl(), buildStatusPanel z grupami |
| `resources/views/components/order-status-panel.php` | Modified | Klikalna nazwa grupy z licznikiem |
| `resources/scss/app.scss` | Modified | Style klikalnej grupy: hover, count badge, is-active |
| `public/assets/css/app.css` | Modified | Skompilowany CSS |
## Decisions Made
| Decision | Rationale | Impact |
|----------|-----------|--------|
| Group ID jako parametr filtra (nie kod/nazwa) | Jednoznaczna identyfikacja, bezpieczne w URL | Prosty int w query string |
| status_group ma priorytet nad status | Wzajemna wylacznosc — klikniecie statusu czysci grupe i odwrotnie | Czyste UX bez konfliktow |
| "Wszystkie" aktywne tylko gdy oba filtry puste | Poprawna logika aktywnosci | Konsystentny stan panelu |
## Deviations from Plan
None - plan executed exactly as written.
## Issues Encountered
None.
## Next Phase Readiness
**Ready:**
- Filtrowanie po grupach dziala, gotowe do testow manualnych
**Concerns:**
- None
**Blockers:**
- None
---
*Phase: 85-status-group-filter, Plan: 01*
*Completed: 2026-04-07*