159 lines
8.3 KiB
Markdown
159 lines
8.3 KiB
Markdown
---
|
|
phase: 105-orders-statistics
|
|
plan: 01
|
|
subsystem: statistics
|
|
tags: [statistics, orders, reporting, filters, ui, mysql-collation, vat-fallback]
|
|
|
|
requires:
|
|
- phase: none
|
|
provides: existing orders + status dictionaries
|
|
provides:
|
|
- new menu section Statistics -> Orders
|
|
- daily orders report by channel with totals
|
|
- filters: date range, channels multiselect, status groups multiselect
|
|
- net amount fallback (23% VAT) when source channel does not expose net
|
|
affects: [orders analytics workflow]
|
|
|
|
tech-stack:
|
|
added: []
|
|
patterns:
|
|
- daily SQL aggregation with dynamic channel columns
|
|
- explicit COLLATE utf8mb4_unicode_ci on CAST expressions to avoid collation mix in mixed-charset schemas
|
|
- brutto->netto deterministic fallback (/ 1.23) as last resort when source net is missing
|
|
|
|
key-files:
|
|
created:
|
|
- src/Modules/Statistics/OrdersStatisticsController.php
|
|
- src/Modules/Statistics/OrdersStatisticsRepository.php
|
|
- resources/views/statistics/orders.php
|
|
- .paul/TODO.md
|
|
modified:
|
|
- routes/web.php
|
|
- resources/views/layouts/app.php
|
|
- resources/lang/pl.php
|
|
- resources/scss/app.scss
|
|
- public/assets/css/app.css
|
|
- .paul/docs/ARCHITECTURE.md
|
|
- .paul/docs/DB_SCHEMA.md
|
|
- .paul/docs/TECH_CHANGELOG.md
|
|
|
|
key-decisions:
|
|
- "Channel split: allegro as one channel, shopPRO by integration_id (shoppro:{id})"
|
|
- "Default status groups: all active except group normalized to 'anulowane'"
|
|
- "No DB migration - feature based on existing schema"
|
|
- "Net fallback: gross / 1.23 when orders.total_without_tax is NULL or 0 (shopPRO does not send net)"
|
|
- "Explicit COLLATE utf8mb4_unicode_ci on channel CASE (avoids 1271 Illegal mix of collations with CAST integer->CHAR)"
|
|
|
|
patterns-established:
|
|
- "Statistics module pattern (Controller + Repository + dedicated view)"
|
|
- "Filter presence hidden flags to distinguish defaults from explicit empty multiselect"
|
|
- "Post-APPLY hotfix pattern: collation bug caught by catching Throwable in repo → silently empty response; require explicit COLLATE on any CAST(int AS CHAR) used in IN clauses"
|
|
|
|
completed: 2026-04-19
|
|
---
|
|
|
|
# Phase 105 Plan 01: Orders Statistics Summary
|
|
|
|
Dodano nowa sekcje `Statystyki -> Zamowienia` z dziennym raportem ilosci/netto/brutto, filtrami (daty, kanaly multiselect, grupy statusow multiselect) oraz stopka `Podsumowanie`. Po poczatkowym wdrozeniu poprawiono bug kolizji collation w MySQL (widok zwracal pusta tabele) oraz dodano fallback wyliczania netto z brutto dla zrodel (shopPRO) ktore nie wysylaja kwoty netto.
|
|
|
|
## Acceptance Criteria Results
|
|
|
|
| Criterion | Status | Notes |
|
|
|-----------|--------|-------|
|
|
| AC-1: Nowa pozycja menu i routing | Pass | `/statistics/orders` + nowy blok menu |
|
|
| AC-2: Filtry dat/kanalow/grup statusow | Pass | Date range + multiselect + domyslne wykluczenie `anulowane` |
|
|
| AC-3: Tabela dzienna + wiersz podsumowania | Pass | Dynamiczne kolumny per kanal, stopka `Podsumowanie` |
|
|
| AC-4: Rozbicie na Allegro i shopPRO per integracja | Pass | `allegro` i `shoppro:{integration_id}` |
|
|
|
|
## Files Created/Modified
|
|
|
|
| File | Change | Purpose |
|
|
|------|--------|---------|
|
|
| `src/Modules/Statistics/OrdersStatisticsController.php` | Created | Parsowanie filtrow, budowa view-modelu, render strony |
|
|
| `src/Modules/Statistics/OrdersStatisticsRepository.php` | Created | Agregacja dzienna SQL + diagnostics + fallback netto |
|
|
| `resources/views/statistics/orders.php` | Created | Widok formularza filtrow i tabeli dziennej |
|
|
| `routes/web.php` | Modified | Route `GET /statistics/orders` za `AuthMiddleware` |
|
|
| `resources/views/layouts/app.php` | Modified | Sidebar: grupa `Statystyki -> Zamowienia` |
|
|
| `resources/lang/pl.php` | Modified | Klucze `navigation.statistics*`, `statistics.orders.*` |
|
|
| `resources/scss/app.scss` | Modified | Kompaktowy layout filtrow i tabeli statystyk |
|
|
| `public/assets/css/app.css` | Modified | Build SCSS |
|
|
| `.paul/docs/ARCHITECTURE.md` | Modified | Opis modulu Statistics + endpoint |
|
|
| `.paul/docs/DB_SCHEMA.md` | Modified | Adnotacja: feature bez migracji |
|
|
| `.paul/docs/TECH_CHANGELOG.md` | Modified | Wpis + hotfix collation + hotfix fallback netto |
|
|
| `.paul/TODO.md` | Created | Tag `STAT-NET`: docelowy netto z shopPRO / order_items.tax_rate |
|
|
|
|
## Decisions Made
|
|
|
|
| Decision | Rationale | Impact |
|
|
|----------|-----------|--------|
|
|
| Explicit `COLLATE utf8mb4_unicode_ci` na CASE zwracajacym `channel_key` | `CAST(integration_id AS CHAR)` zwracal `utf8mb4_bin`, przez co `IN (...)` z parametrami (`utf8mb4_general_ci`) rzucal `1271 Illegal mix of collations`. Repo lapalo `Throwable` i zwracalo `[]`, widok byl pusty. | Statystyki dzialaja; pattern udokumentowany dla przyszlych agregacji po `integration_id` |
|
|
| Fallback netto `ROUND(gross / 1.23, 2)` gdy `total_without_tax` puste | shopPRO nie przesyla netto ani na poziomie zamowienia, ani pozycji (`order_items.original_price_without_tax` = NULL); bez fallbacku kolumna `Netto` pokazywala 0 | Kolumna `Netto` pokazuje sensowne wartosci; docelowe rozwiazanie (STAT-NET) zapisane w TODO |
|
|
| Status codes pozostaja `order_statuses.code` (LOWER-normalized) | Mapping Allegro zachowuje zgodnosc z `OrdersRepository` dzieki `allegro_order_status_mappings` | Spojna semantyka statusow w module Orders i Statistics |
|
|
|
|
## Deviations from Plan
|
|
|
|
### Summary
|
|
|
|
| Type | Count | Impact |
|
|
|------|-------|--------|
|
|
| Auto-fixed | 1 | Essential — zerowe wyniki zanim hotfix |
|
|
| Scope additions | 1 | Uzasadnione — brak fallback netto byl pokazywany jako bug |
|
|
| Deferred | 1 | `STAT-NET` w `.paul/TODO.md` |
|
|
|
|
### Auto-fixed Issues
|
|
|
|
**1. [SQL] Kolizja collation w channelSql() — statystyki zwracaly pusta tabele**
|
|
- **Found during:** Post-APPLY walidacja — user zglosil "strona statystyk nie pokazuje zamowien"
|
|
- **Issue:** `CAST(o.integration_id AS CHAR)` daje `utf8mb4_bin`, `CONCAT("shoppro:", ...)` + `IN (:ch0,:ch1)` rzuca `SQLSTATE[HY000] 1271`. `try/catch(Throwable)` polykal blad → puste dane.
|
|
- **Fix:** `COLLATE utf8mb4_unicode_ci` na `CAST(...)` oraz na calym wyrazeniu CASE zwracajacym `channel_key`.
|
|
- **Files:** `src/Modules/Statistics/OrdersStatisticsRepository.php` (`channelSql`)
|
|
- **Verification:** End-to-end test na produkcyjnym DB (host700513) — 41 wierszy zagregowanych dla 2026-04-01..30, kanaly: `allegro, shoppro:5, shoppro:6, shoppro:7`.
|
|
|
|
### Scope Additions
|
|
|
|
**1. [Feature] Fallback netto 23% VAT**
|
|
- **Why:** shopPRO nie wysyla `total_without_tax`; `order_items.original_price_without_tax` rowniez NULL. Bez fallbacku kolumna Netto byla bezuzyteczna (same zera).
|
|
- **Scope:** `netAmountSql()` rozszerzony o `CASE ... WHEN total_without_tax > 0 THEN total_without_tax ... WHEN total_with_tax > 0 THEN ROUND(total_with_tax/1.23, 2) ELSE 0 END`.
|
|
- **Files:** `src/Modules/Statistics/OrdersStatisticsRepository.php`, `.paul/docs/TECH_CHANGELOG.md`, `.paul/TODO.md`
|
|
|
|
### Deferred Items
|
|
|
|
- **STAT-NET:** Pobieranie netto z shopPRO (API) lub dokladne wyliczanie z `order_items.tax_rate` (unikniecie sztywnego 23%). Backfill historycznych rekordow. Zapisane w `.paul/TODO.md`.
|
|
|
|
## Verification Executed
|
|
|
|
- `php -l src/Modules/Statistics/OrdersStatisticsRepository.php`
|
|
- `php -l src/Modules/Statistics/OrdersStatisticsController.php`
|
|
- `php -l routes/web.php`
|
|
- `php -l resources/views/layouts/app.php`
|
|
- `php -l resources/views/statistics/orders.php`
|
|
- `php -l resources/lang/pl.php`
|
|
- `npm run build:css`
|
|
- End-to-end on production DB (post-hotfix): 41 agregowanych wierszy dla 2026-04, netto/brutto zgodne (np. shoppro:7 2026-04-19: orders=17, net=989.45, gross=1217.05).
|
|
|
|
## Skill Audit
|
|
|
|
| Expected | Invoked | Notes |
|
|
|----------|---------|-------|
|
|
| `sonar-scanner` (required) | o | Gap — nie uruchomiony podczas tej sesji UNIFY. `.scannerwork/report-task.txt` pokazuje modyfikacje wczesniej; skan dedykowany do tej zmiany nie wykonany. |
|
|
| /feature-dev (optional) | o | Nie uzywany |
|
|
| /frontend-design (optional) | o | Nie uzywany |
|
|
| /code-review (optional) | o | Nie uzywany |
|
|
| /simplify (optional) | o | Nie uzywany |
|
|
|
|
## Next Phase Readiness
|
|
|
|
**Ready:**
|
|
- Modul Statistics dziala; schemat patternu dla kolejnych raportow (per-kanalowych).
|
|
- TODO `STAT-NET` przechowane z konkretnym planem realizacji.
|
|
|
|
**Concerns:**
|
|
- Kolumna `Netto` na kanalach shopPRO jest obecnie estymatem (sztywne 23% VAT). Jesli pojawia sie produkty o innej stawce (5%, 8%, 0%), agregat bedzie zawyzal netto dla tych pozycji.
|
|
|
|
**Blockers:**
|
|
- None.
|
|
|
|
---
|
|
*Phase: 105-orders-statistics, Plan: 01*
|
|
*Completed: 2026-04-19*
|