diff --git a/.claude/hooks/index-docs.mjs b/.claude/hooks/index-docs.mjs new file mode 100644 index 0000000..66f3d4a --- /dev/null +++ b/.claude/hooks/index-docs.mjs @@ -0,0 +1,47 @@ +#!/usr/bin/env node +/** + * SessionStart hook: reminds Claude to index DOCS/*.md into context-mode. + * Scans for DOCS/ or docs/ folder and lists .md files to index. + */ +import { readdirSync, statSync, existsSync } from 'fs'; +import { join, relative } from 'path'; + +const projectRoot = process.env.PROJECT_DIR || process.cwd(); + +let docsDir = null; +for (const candidate of ['DOCS', 'docs']) { + const fullPath = join(projectRoot, candidate); + if (existsSync(fullPath)) { + docsDir = fullPath; + break; + } +} + +if (!docsDir) { + process.exit(0); +} + +function getMdFiles(dir) { + const files = []; + for (const entry of readdirSync(dir, { withFileTypes: true })) { + const fullPath = join(dir, entry.name); + if (entry.isDirectory()) { + files.push(...getMdFiles(fullPath)); + } else if (entry.name.endsWith('.md')) { + files.push(relative(projectRoot, fullPath).replace(/\\/g, '/')); + } + } + return files; +} + +const mdFiles = getMdFiles(docsDir); + +if (mdFiles.length > 0) { + const instructions = { + result: "INDEX_DOCS_REMINDER", + message: `Na starcie sesji zaindeksuj poniższe pliki dokumentacji do context-mode (ctx_index) aby oszczędzać okno kontekstu. Użyj pełnych ścieżek z PROJECT_DIR.`, + files: mdFiles, + projectDir: projectRoot.replace(/\\/g, '/') + }; + console.log(JSON.stringify(instructions)); +} diff --git a/.claude/memory/MEMORY.md b/.claude/memory/MEMORY.md new file mode 100644 index 0000000..946a6c8 --- /dev/null +++ b/.claude/memory/MEMORY.md @@ -0,0 +1,12 @@ +# Memory Index — orderPRO + +## Feedback + +- [feedback_concerns_cleanup.md](feedback_concerns_cleanup.md) — Po naprawieniu concern: usunąć go z CONCERNS.md całkowicie +- [feedback_polish_language.md](feedback_polish_language.md) — Zawsze pisz po polsku w tym projekcie +- [feedback_screenshots_dir.md](feedback_screenshots_dir.md) — Screenshoty zapisywać w .claude/screenshots/, nie w katalogu głównym + +## Reference + +- [reference_server_deploy.md](reference_server_deploy.md) — FTP deploy na hostido, vendor/ bez dev deps, usuwanie ręczne +- [reference_agent_login.md](reference_agent_login.md) — Dane logowania konta technicznego Claude Agent do panelu orderPRO diff --git a/.claude/memory/feedback_concerns_cleanup.md b/.claude/memory/feedback_concerns_cleanup.md new file mode 100644 index 0000000..f75ce81 --- /dev/null +++ b/.claude/memory/feedback_concerns_cleanup.md @@ -0,0 +1,11 @@ +--- +name: feedback_concerns_cleanup +description: Po naprawieniu buga/concern — usuwać wpis z CONCERNS.md (nie zostawiać przekreślonego ani niezmienionego) +type: feedback +--- + +Po naprawieniu każdego wpisu z `.paul/codebase/CONCERNS.md` — **usuń go całkowicie** z pliku. + +**Why:** Zostawienie naprawionego concern (nawet przekreślonego ~~jak to~~) powoduje dezorientację — user wraca do starych wpisów myśląc, że bug jest aktywny (jak "Application.php Manually Instantiates Full Object Graph" który był już fixed w Plan 02-04). + +**How to apply:** Po każdym UNIFY — sprawdź czy któryś concern z CONCERNS.md został rozwiązany w tym planie. Jeśli tak, usuń go całkowicie. Wyjątek: wpis z notatką o zmianie (jak AllegroStatusSyncService ~~przekreślony~~ z adnotacją) — można zostawić tymczasowo, ale i tak lepiej usunąć. diff --git a/.claude/memory/feedback_polish_language.md b/.claude/memory/feedback_polish_language.md new file mode 100644 index 0000000..7414719 --- /dev/null +++ b/.claude/memory/feedback_polish_language.md @@ -0,0 +1,11 @@ +--- +name: Pisz po polsku +description: Użytkownik chce, żeby Claude zawsze komunikował się po polsku w tym projekcie +type: feedback +--- + +Zawsze pisz po polsku — odpowiedzi, komentarze, statusy, pytania. + +**Why:** Użytkownik wyraźnie poprosił o komunikację po polsku. + +**How to apply:** Każda odpowiedź tekstowa ma być po polsku. Kod, nazwy klas/metod i komentarze techniczne w kodzie pozostają po angielsku (konwencja projektu). diff --git a/.claude/memory/feedback_screenshots_dir.md b/.claude/memory/feedback_screenshots_dir.md new file mode 100644 index 0000000..861ea7f --- /dev/null +++ b/.claude/memory/feedback_screenshots_dir.md @@ -0,0 +1,13 @@ +--- +name: screenshots_dir +description: Screenshoty w .claude/screenshots/ projektu, przeglądarka 1920px szerokości +type: feedback +--- + +Screenshoty z Puppeteer zapisuj w `.claude/screenshots/` **w katalogu projektu** (np. `C:\visual studio code\projekty\orderPRO\.claude\screenshots\.png`). + +Przy uruchamianiu przeglądarki Puppeteer ustawiaj viewport na szerokość **1920px**. + +**Why:** Katalog `/.claude` jest na liście ignore ftp-kr, więc pliki tam nie są wysyłane na serwer. Użytkownik pracuje na monitorze 1920px i chce widzieć realny układ. + +**How to apply:** Przy każdym `puppeteer_launch` ustawiaj `viewport.width: 1920`. Przy każdym `puppeteer_screenshot` używaj ścieżki w `C:\visual studio code\projekty\orderPRO\.claude\screenshots\`. diff --git a/.claude/memory/project_sonarqube.md b/.claude/memory/project_sonarqube.md new file mode 100644 index 0000000..de47883 --- /dev/null +++ b/.claude/memory/project_sonarqube.md @@ -0,0 +1,11 @@ +--- +name: sonarqube_setup_pending +description: Użytkownik chce skonfigurować SonarQube na serwerze Hetzner (Windows + Docker) - potrzebuje pomocy krok po kroku +type: project +--- + +Użytkownik chce skonfigurować SonarQube krok po kroku na dedykowanym serwerze Hetzner z Windows i Dockerem. + +**Why:** Integracja z Claude Code przez MCP dla analizy jakości kodu projektu orderPRO. + +**How to apply:** Przy pierwszej okazji po zakończeniu bieżącego zadania przypomnij o konfiguracji SonarQube i zaproponuj przewodnik krok po kroku (Docker Compose + reverse proxy + MCP config). diff --git a/.claude/memory/reference_agent_login.md b/.claude/memory/reference_agent_login.md new file mode 100644 index 0000000..a181812 --- /dev/null +++ b/.claude/memory/reference_agent_login.md @@ -0,0 +1,11 @@ +--- +name: agent_login +description: Dane logowania konta technicznego Claude Agent do panelu orderPRO +type: reference +--- + +Konto techniczne do logowania na stronie orderPRO: +- URL: https://orderpro.projectpro.pl/login +- Email: agent@orderpro.local +- Haslo: ClaudeAgent2026! +- User ID w bazie: 2 diff --git a/.claude/memory/reference_server_deploy.md b/.claude/memory/reference_server_deploy.md new file mode 100644 index 0000000..513ec67 --- /dev/null +++ b/.claude/memory/reference_server_deploy.md @@ -0,0 +1,20 @@ +--- +name: Deployment na serwer produkcyjny +description: FTP deploy na hostido — vendor/ musi być bez dev deps, upload automatyczny ale usuwanie ręczne +type: reference +--- + +Serwer: host700513.hostido.net.pl (FTP, port 21) +Dane w: .vscode/sftp.json +Remote path: /public_html + +Upload plików na serwer odbywa się automatycznie (VS Code SFTP plugin). +Usuwanie plików z serwera NIE jest automatyczne — trzeba ręcznie. + +**vendor/ na serwerze:** +- Użytkownik NIE ma composera na serwerze +- vendor/ musi być zbudowany lokalnie z `--no-dev` przed wrzuceniem na serwer +- Komenda: `php composer.phar install --no-dev --optimize-autoloader --ignore-platform-reqs` +- Nie wrzucaj dev dependencies (phpunit, bypass-finals) na serwer — powoduje fatal error + +**How to apply:** Przy każdej zmianie composer.json/vendor/ — pamiętaj o deploy vendor/ bez dev deps. diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 2d49647..c069d82 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -22,7 +22,24 @@ "Bash(php tmp_gs1_test.php)", "mcp__serena__write_memory", "mcp__serena__prepare_for_new_conversation", - "Bash(npx sass:*)" + "Bash(npx sass:*)", + "Bash(PROJECT_DIR=\"C:/visual studio code/projekty/orderPRO\" node .claude/hooks/index-docs.mjs)", + "mcp__plugin_context-mode_context-mode__ctx_index", + "mcp__plugin_context-mode_context-mode__ctx_search", + "mcp__plugin_context-mode_context-mode__ctx_batch_execute" + ] + }, + "hooks": { + "SessionStart": [ + { + "matcher": "", + "hooks": [ + { + "type": "command", + "command": "node .claude/hooks/index-docs.mjs" + } + ] + } ] } } diff --git a/.env b/.env index 8843917..5bb83ca 100644 --- a/.env +++ b/.env @@ -13,4 +13,6 @@ DB_USERNAME=host700513_orderpro DB_PASSWORD=hrDNtUBg9grwZ7syN77S DB_CHARSET=utf8mb4 -INTEGRATIONS_SECRET=nB3sTkXAbBLqA2Ent74R9Mi1118bAbWa \ No newline at end of file +INTEGRATIONS_SECRET=nB3sTkXAbBLqA2Ent74R9Mi1118bAbWa + +pracownia.key=9554daf4bbcbbb5e72a2b48ee7d6a7f20262713d72484b781460e2c772d813fc \ No newline at end of file diff --git a/.paul/STATE.md b/.paul/STATE.md index 92d682e..09922a3 100644 --- a/.paul/STATE.md +++ b/.paul/STATE.md @@ -216,7 +216,7 @@ PLAN ──▶ APPLY ──▶ UNIFY - **Delivery mapping "Szukaj..." layout** — JS `attachSelectFilter()` w allegro.php tworzy input search dla InPost/Apaczka selectów, wizualnie wygląda jakby należał do wiersza powyżej. Pre-existing bug, do naprawy osobno. ### Git State -Last commit: e379557 — feat(24-shipment-presets-ui): kolorowe przyciski presetów, popup, autofill +Last commit: 91963d5 — feat(25-shipment-presets-management): edycja, usuwanie, zarządzanie presetami Branch: main Feature branches merged: none diff --git a/.paul/phases/21-order-source-display/21-01-PLAN.md b/.paul/phases/21-order-source-display/21-01-PLAN.md new file mode 100644 index 0000000..c7ee7dc --- /dev/null +++ b/.paul/phases/21-order-source-display/21-01-PLAN.md @@ -0,0 +1,162 @@ +--- +phase: 21-order-source-display +plan: 01 +type: execute +wave: 1 +depends_on: [] +files_modified: + - src/Modules/Orders/OrdersRepository.php + - src/Modules/Orders/OrdersController.php + - resources/views/orders/show.php +autonomous: true +--- + + +## Goal +Poprawic wyswietlanie zrodla zamowienia na liscie zamowien i stronie szczegulow: +1. (todo #15) Upewnic sie, ze w `orders-ref__meta` kolejnosc to: zrodlo, potem ID (weryfikacja — kod juz moze byc poprawny) +2. (todo #17) Zamiast generycznego "shopPRO" wyswietlac nazwe konkretnej integracji z tabeli `integrations` (np. "Moj Sklep 1"). Dotyczy listy zamowien i strony szczegulow. Dodac prefiks "ID:" przed identyfikatorem zamowienia. + +## Purpose +Sprzedawca z wieloma sklepami shopPRO musi wiedziec, z ktorego konkretnie sklepu pochodzi zamowienie. + +## Output +Zmodyfikowane pliki: OrdersRepository.php, OrdersController.php, show.php + + + +## Project Context +@.paul/PROJECT.md +@.paul/ROADMAP.md +@.paul/STATE.md + +## Source Files +@src/Modules/Orders/OrdersRepository.php +@src/Modules/Orders/OrdersController.php +@resources/views/orders/show.php +@DOCS/todo.md + + + +No specialized flows required for this plan. + + + + +## AC-1: Integration name displayed on orders list +```gherkin +Given zamowienie pochodzi z integracji shopPRO o nazwie "Moj Sklep" +When uzytkownik otwiera liste zamowien +Then w kolumnie "Numer" w sekcji orders-ref__meta widzi "Moj Sklep" zamiast "shopPRO" + And widzi "ID: " jako drugi element +``` + +## AC-2: Integration name displayed on order detail page +```gherkin +Given zamowienie pochodzi z integracji shopPRO o nazwie "Moj Sklep" +When uzytkownik otwiera szczegoly zamowienia +Then w naglowku pod numerem zamowienia widzi "Moj Sklep" i identyfikator zamowienia +``` + +## AC-3: Allegro/Erli orders unaffected +```gherkin +Given zamowienie pochodzi z Allegro +When uzytkownik otwiera liste zamowien +Then w sekcji orders-ref__meta widzi "Allegro" jako zrodlo (bez zmian) + And widzi "ID: " jako identyfikator +``` + +## AC-4: Source first, ID second in meta +```gherkin +Given dowolne zamowienie na liscie +When uzytkownik patrzy na kolumne "Numer" +Then pierwszy span w orders-ref__meta to nazwa zrodla/integracji + And drugi span to "ID: " +``` + + + + + + + Task 1: Dodac integration name do query listy i szczegulow + src/Modules/Orders/OrdersRepository.php + + 1. W `buildListSql()`: dodac LEFT JOIN do tabeli `integrations`: + ``` + LEFT JOIN integrations ig ON ig.id = o.integration_id + ``` + Dodac kolumne `ig.name AS integration_name` do SELECT. + + 2. W `transformOrderRow()`: dodac pole `'integration_name' => (string) ($row['integration_name'] ?? '')` do zwracanej tablicy. + + 3. W `findDetails()`: dodac LEFT JOIN do `integrations` i dodac `ig.name AS integration_name` do SELECT query. + + Avoid: Nie zmieniac countSql (nie potrzebuje JOIN do integrations). Nie zmieniac istniejacych kolumn — tylko dodac nowe. + + Sprawdzic ze query nie rzuca bledu — otworzyc liste zamowien w przegladarce. + AC-1, AC-2 — dane integration_name dostepne w wynikach query + + + + Task 2: Wyswietlic integration name w UI (lista + show) + src/Modules/Orders/OrdersController.php, resources/views/orders/show.php + + 1. W `OrdersController::toTableRow()`: + - Odczytac `$integrationName = trim((string) ($row['integration_name'] ?? ''));` + - Zmienic logike wyswietlania zrodla w `orders-ref__meta`: + - Jesli `$integrationName !== ''` → uzyc `$integrationName` jako label + - W przeciwnym razie → uzyc `$this->sourceLabel($source)` (fallback dla Allegro/Erli/starych danych) + - Upewnic sie ze kolejnosc spanow to: [1] zrodlo/integracja, [2] ID: identyfikator + - Obecny kod JUZ ma poprawna kolejnosc (source first), wiec tylko dodac logike integration_name + + 2. W `resources/views/orders/show.php` linia 48: + - Zmienic wyswietlanie z `ucfirst(source) external_order_id` na: + - Uzyc `$orderRow['integration_name']` jesli niepuste, inaczej `ucfirst(source)` + - Dodac prefiks "ID:" przed identyfikatorem + - Rozdzielic na dwa oddzielne spany (jak na liscie) dla spojnosci + + 3. Metoda `sourceLabel()` — pozostawic bez zmian (fallback). + + Avoid: Nie zmieniac CSS. Nie zmieniac filtrow zrodla (dropdown). Nie zmieniac logiki statusow. + + Otworzyc liste zamowien — zamowienia shopPRO pokazuja nazwe integracji. Allegro pokazuje "Allegro". Otworzyc szczegoly zamowienia — naglowek pokazuje nazwe integracji. + AC-1, AC-2, AC-3, AC-4 satisfied + + + + + + +## DO NOT CHANGE +- resources/scss/* (zadnych zmian CSS) +- Filtry zrodla w dropdownie (sourceOptions) — poza zakresem +- Logika statusow, platnosci, przesylek +- Inne widoki niz show.php + +## SCOPE LIMITS +- Tylko wyswietlanie — bez zmian w logice importu zamowien +- Bez zmian w bazie danych (kolumna integration_id juz istnieje w orders) +- Bez nowych zaleznosci + + + + +Before declaring plan complete: +- [ ] Lista zamowien laduje sie bez bledow +- [ ] Zamowienia shopPRO pokazuja nazwe integracji (nie "shopPRO") +- [ ] Zamowienia Allegro pokazuja "Allegro" (bez regresji) +- [ ] Strona szczegulow zamowienia pokazuje nazwe integracji +- [ ] Kolejnosc w orders-ref__meta: zrodlo first, ID second +- [ ] All acceptance criteria met + + + +- Todo #15 i #17 zrealizowane +- Brak regresji na liscie zamowien i stronie szczegulow +- Kod uzywa prepared statements (medoo/PDO) — brak SQL injection + + + +After completion, create `.paul/phases/21-order-source-display/21-01-SUMMARY.md` + diff --git a/.paul/phases/21-order-source-display/21-01-SUMMARY.md b/.paul/phases/21-order-source-display/21-01-SUMMARY.md new file mode 100644 index 0000000..1c5f60d --- /dev/null +++ b/.paul/phases/21-order-source-display/21-01-SUMMARY.md @@ -0,0 +1,100 @@ +--- +phase: 21-order-source-display +plan: 01 +subsystem: ui +tags: [orders, integrations, display] + +requires: + - phase: none + provides: n/a +provides: + - integration name display on orders list + - integration name display on order detail page +affects: [] + +tech-stack: + added: [] + patterns: [integration name fallback pattern] + +key-files: + created: [] + modified: + - src/Modules/Orders/OrdersRepository.php + - src/Modules/Orders/OrdersController.php + - resources/views/orders/show.php + +key-decisions: + - "Fallback: integration_name → sourceLabel() dla Allegro/Erli/starych danych" + +patterns-established: + - "Integration name resolution: prefer integrations.name, fallback to sourceLabel(source)" + +duration: 5min +started: 2026-03-22T00:00:00Z +completed: 2026-03-22T00:00:00Z +--- + +# Phase 21 Plan 01: Order Source Display Summary + +**LEFT JOIN integrations w query zamowien — lista i szczegoly pokazuja nazwe integracji zamiast generycznego "shopPRO"** + +## Performance + +| Metric | Value | +|--------|-------| +| Duration | ~5min | +| Tasks | 2 completed | +| Files modified | 3 | + +## Acceptance Criteria Results + +| Criterion | Status | Notes | +|-----------|--------|-------| +| AC-1: Integration name on list | Pass | LEFT JOIN integrations, fallback na sourceLabel | +| AC-2: Integration name on detail | Pass | show.php uzywa integration_name z order row | +| AC-3: Allegro/Erli unaffected | Pass | Fallback na sourceLabel() gdy integration_name puste | +| AC-4: Source first, ID second | Pass | Kod listy juz mial poprawna kolejnosc; show.php poprawiony | + +## Accomplishments + +- Query listy zamowien i szczegulow dolacza tabele `integrations` (LEFT JOIN) i zwraca `integration_name` +- Lista zamowien wyswietla nazwe integracji (np. "Moj Sklep") zamiast generycznego "shopPRO" +- Strona szczegulow zamowienia rozdzielona na dwa spany z prefiksem "ID:" + +## Files Created/Modified + +| File | Change | Purpose | +|------|--------|---------| +| `src/Modules/Orders/OrdersRepository.php` | Modified | LEFT JOIN integrations w buildListSql + findDetails; integration_name w transformOrderRow | +| `src/Modules/Orders/OrdersController.php` | Modified | toTableRow uzywa integration_name z fallbackiem na sourceLabel | +| `resources/views/orders/show.php` | Modified | Naglowek: osobne spany, nazwa integracji + prefiks "ID:" | + +## Decisions Made + +| Decision | Rationale | Impact | +|----------|-----------|--------| +| Fallback na sourceLabel() gdy integration_name puste | Allegro/Erli nie maja wpisow w integrations dla kazdego zamowienia; stare zamowienia moga miec NULL integration_id | Brak regresji | + +## Deviations from Plan + +None — plan executed exactly as written. + +## Issues Encountered + +None. + +## Next Phase Readiness + +**Ready:** +- Todo #15 i #17 zrealizowane +- Milestone v0.8 gotowy do zamkniecia + +**Concerns:** +- None + +**Blockers:** +- None + +--- +*Phase: 21-order-source-display, Plan: 01* +*Completed: 2026-03-22* diff --git a/.scannerwork/report-task.txt b/.scannerwork/report-task.txt index 62ceb33..51855e3 100644 --- a/.scannerwork/report-task.txt +++ b/.scannerwork/report-task.txt @@ -2,5 +2,5 @@ projectKey=orderPRO serverUrl=https://sonar.project-pro.pl serverVersion=26.3.0.120487 dashboardUrl=https://sonar.project-pro.pl/dashboard?id=orderPRO -ceTaskId=32235c87-2f61-4232-9bc1-37cdc4234595 -ceTaskUrl=https://sonar.project-pro.pl/api/ce/task?id=32235c87-2f61-4232-9bc1-37cdc4234595 +ceTaskId=16807b34-3042-4ded-9751-89e00701d085 +ceTaskUrl=https://sonar.project-pro.pl/api/ce/task?id=16807b34-3042-4ded-9751-89e00701d085 diff --git a/.vscode/ftp-kr.sync.cache.json b/.vscode/ftp-kr.sync.cache.json index b88dc26..443b12f 100644 --- a/.vscode/ftp-kr.sync.cache.json +++ b/.vscode/ftp-kr.sync.cache.json @@ -474,9 +474,9 @@ }, "composer.json": { "type": "-", - "size": 687, - "lmtime": 1772489482442, - "modified": true + "size": 722, + "lmtime": 1773786224662, + "modified": false }, "composer.lock": { "type": "-", @@ -874,8 +874,14 @@ }, "20260316_000001_add_attachment1_to_email_templates.sql": { "type": "-", - "size": 96, - "lmtime": 1773701415069, + "size": 378, + "lmtime": 1773787052845, + "modified": false + }, + "20260318_000057_create_automation_tables.sql": { + "type": "-", + "size": 1631, + "lmtime": 1773789478088, "modified": false } }, @@ -928,14 +934,14 @@ "DOCS": { "ARCHITECTURE.md": { "type": "-", - "size": 31763, - "lmtime": 1773615416923, + "size": 32951, + "lmtime": 1773790245031, "modified": false }, "DB_SCHEMA.md": { "type": "-", - "size": 27900, - "lmtime": 1773701554836, + "size": 29737, + "lmtime": 1773789666999, "modified": false }, "ORDERS_SCHEMA_APILO_DRAFT.md": { @@ -952,15 +958,15 @@ }, "TECH_CHANGELOG.md": { "type": "-", - "size": 46908, - "lmtime": 1773615432190, + "size": 49699, + "lmtime": 1773790252961, "modified": false }, "todo.md": { "type": "-", - "size": 2051, - "lmtime": 1772997209432, - "modified": true + "size": 2129, + "lmtime": 1773790444877, + "modified": false } }, ".env": { @@ -2189,8 +2195,8 @@ "css": { "app.css": { "type": "-", - "size": 36918, - "lmtime": 1773616475105, + "size": 48246, + "lmtime": 1773789643914, "modified": false }, "app.css.map": { @@ -2228,6 +2234,12 @@ "size": 5768, "lmtime": 1771873304132, "modified": false + }, + "automation-form.js": { + "type": "-", + "size": 5053, + "lmtime": 1773789606719, + "modified": false } } } @@ -2250,8 +2262,8 @@ "lang": { "pl.php": { "type": "-", - "size": 56930, - "lmtime": 1773009492281, + "size": 62881, + "lmtime": 1773788074010, "modified": false } }, @@ -2286,8 +2298,8 @@ }, "app.scss": { "type": "-", - "size": 42386, - "lmtime": 1773616457946, + "size": 42442, + "lmtime": 1773789619255, "modified": false }, "login.css": { @@ -2308,6 +2320,20 @@ "lmtime": 1771866989000, "modified": false }, + "modules": { + "_email-send.scss": { + "type": "-", + "size": 2093, + "lmtime": 1773786622096, + "modified": false + }, + "_automation.scss": { + "type": "-", + "size": 1038, + "lmtime": 1773789611848, + "modified": false + } + }, "shared": { "_ui-components.scss": { "type": "-", @@ -2318,6 +2344,7 @@ } }, "views": { + "accounting": {}, "auth": { "login.php": { "type": "-", @@ -2351,8 +2378,8 @@ "layouts": { "app.php": { "type": "-", - "size": 8934, - "lmtime": 1773616408513, + "size": 9146, + "lmtime": 1773789621995, "modified": false }, "auth.php": { @@ -2389,10 +2416,24 @@ "lmtime": 1773004094862, "modified": false }, + "partials": { + "email-send-modal.php": { + "type": "-", + "size": 7455, + "lmtime": 1773786546755, + "modified": false + } + }, + "receipt-create.php": { + "type": "-", + "size": 4987, + "lmtime": 0, + "modified": false + }, "show.php": { "type": "-", - "size": 27463, - "lmtime": 1773359729566, + "size": 31864, + "lmtime": 1773787790160, "modified": false } }, @@ -2428,6 +2469,7 @@ "modified": false } }, + "receipts": {}, "settings": { "accounting.php": { "type": "-", @@ -2520,6 +2562,14 @@ "modified": false } }, + "shipments": { + "prepare.php": { + "type": "-", + "size": 32252, + "lmtime": 1773359733203, + "modified": false + } + }, "users": { "index.php": { "type": "-", @@ -2528,11 +2578,17 @@ "modified": false } }, - "shipments": { - "prepare.php": { + "automation": { + "index.php": { "type": "-", - "size": 32252, - "lmtime": 1773359733203, + "size": 3962, + "lmtime": 1773789562003, + "modified": false + }, + "form.php": { + "type": "-", + "size": 7536, + "lmtime": 1773789588610, "modified": false } } @@ -2541,8 +2597,8 @@ "routes": { "web.php": { "type": "-", - "size": 18920, - "lmtime": 1773616330514, + "size": 21001, + "lmtime": 1773790233968, "modified": false } }, @@ -2741,6 +2797,26 @@ } }, "Modules": { + "Accounting": { + "AccountingController.php": { + "type": "-", + "size": 10212, + "lmtime": 0, + "modified": false + }, + "ReceiptController.php": { + "type": "-", + "size": 14363, + "lmtime": 1773790208003, + "modified": false + }, + "ReceiptRepository.php": { + "type": "-", + "size": 10253, + "lmtime": 0, + "modified": false + } + }, "Auth": { "AuthController.php": { "type": "-", @@ -2859,6 +2935,26 @@ "modified": false } }, + "Email": { + "AttachmentGenerator.php": { + "type": "-", + "size": 3204, + "lmtime": 1773786316666, + "modified": false + }, + "EmailSendingService.php": { + "type": "-", + "size": 12532, + "lmtime": 1773790149417, + "modified": false + }, + "VariableResolver.php": { + "type": "-", + "size": 3023, + "lmtime": 1773786302912, + "modified": false + } + }, "GS1": { "GS1Service.php": { "type": "-", @@ -2902,14 +2998,14 @@ }, "OrdersController.php": { "type": "-", - "size": 27184, - "lmtime": 1773392942464, + "size": 32146, + "lmtime": 1773788099402, "modified": false }, "OrdersRepository.php": { "type": "-", - "size": 31275, - "lmtime": 1773401508499, + "size": 31950, + "lmtime": 1773787170333, "modified": false }, "OrderStatusSyncService.php": { @@ -3291,20 +3387,6 @@ "modified": false } }, - "Users": { - "UserRepository.php": { - "type": "-", - "size": 5346, - "lmtime": 1771691981226, - "modified": true - }, - "UsersController.php": { - "type": "-", - "size": 5179, - "lmtime": 1772491357326, - "modified": false - } - }, "Shipments": { "AllegroShipmentService.php": { "type": "-", @@ -3342,6 +3424,40 @@ "lmtime": 1772999586844, "modified": false } + }, + "Users": { + "UserRepository.php": { + "type": "-", + "size": 5346, + "lmtime": 1771691981226, + "modified": true + }, + "UsersController.php": { + "type": "-", + "size": 5179, + "lmtime": 1772491357326, + "modified": false + } + }, + "Automation": { + "AutomationController.php": { + "type": "-", + "size": 11363, + "lmtime": 1773789536055, + "modified": false + }, + "AutomationRepository.php": { + "type": "-", + "size": 8913, + "lmtime": 1773789501115, + "modified": false + }, + "AutomationService.php": { + "type": "-", + "size": 5382, + "lmtime": 1773790173434, + "modified": false + } } } }, @@ -5428,7 +5544,110 @@ "modified": false } }, - "vendor": {} + "vendor": { + "autoload.php": { + "type": "-", + "size": 748, + "lmtime": 0, + "modified": false + }, + "bin": {}, + "composer": { + "2723ec57": {}, + "autoload_classmap.php": { + "type": "-", + "size": 181999, + "lmtime": 0, + "modified": false + }, + "autoload_files.php": { + "type": "-", + "size": 8667, + "lmtime": 0, + "modified": false + }, + "autoload_namespaces.php": { + "type": "-", + "size": 139, + "lmtime": 0, + "modified": false + }, + "autoload_psr4.php": { + "type": "-", + "size": 1264, + "lmtime": 1773786223380, + "modified": false + }, + "autoload_real.php": { + "type": "-", + "size": 1622, + "lmtime": 0, + "modified": false + }, + "autoload_static.php": { + "type": "-", + "size": 206600, + "lmtime": 1773786223514, + "modified": false + }, + "ClassLoader.php": { + "type": "-", + "size": 16378, + "lmtime": 0, + "modified": false + }, + "installed.json": { + "type": "-", + "size": 110832, + "lmtime": 1773786222000, + "modified": false + }, + "installed.php": { + "type": "-", + "size": 16083, + "lmtime": 1773786222002, + "modified": false + }, + "InstalledVersions.php": { + "type": "-", + "size": 17395, + "lmtime": 0, + "modified": false + }, + "LICENSE": { + "type": "-", + "size": 1070, + "lmtime": 0, + "modified": false + }, + "pcre": {}, + "tmp-135de45491cf02a6927c90567690c94e.zip~": { + "type": "-", + "size": 0, + "lmtime": 1773786221394, + "modified": false + } + }, + "dg": {}, + "dompdf": {}, + "maennchen": {}, + "markbaker": {}, + "masterminds": {}, + "myclabs": {}, + "nikic": {}, + "phar-io": {}, + "phpoffice": {}, + "phpunit": {}, + "psr": {}, + "sabberworm": {}, + "sebastian": {}, + "staabm": {}, + "thecodingmachine": {}, + "theseer": {}, + "phpmailer": { + "phpmailer": {} + } + } } }, "$version": 1 diff --git a/DOCS/TECH_CHANGELOG.md b/DOCS/TECH_CHANGELOG.md index 764cd2f..9bed451 100644 --- a/DOCS/TECH_CHANGELOG.md +++ b/DOCS/TECH_CHANGELOG.md @@ -1,5 +1,12 @@ # Tech Changelog +## 2026-03-22 (Phase 21 — Order Source Display, Plan 01) +- `OrdersRepository::buildListSql()` — LEFT JOIN `integrations ig ON ig.id = o.integration_id`, nowa kolumna `ig.name AS integration_name`. +- `OrdersRepository::findDetails()` — analogiczny LEFT JOIN dla strony szczegolow zamowienia. +- `OrdersRepository::transformOrderRow()` — nowe pole `integration_name`. +- `OrdersController::toTableRow()` — wyswietla `integration_name` gdy niepuste, fallback na `sourceLabel()` (Allegro/Erli/default). +- `resources/views/orders/show.php` — naglowek zamowienia: dwa osobne spany (nazwa integracji + "ID: identyfikator") zamiast jednego. + ## 2026-03-18 (Phase 16 — Zadania automatyczne, Plan 02: Watcher/Executor) - Nowa klasa `App\Modules\Automation\AutomationService` — trigger + ewaluacja warunkow (AND) + wykonanie akcji. - Flow: `ReceiptController::store()` -> `AutomationService::trigger('receipt.created', orderId)` -> sprawdzenie warunkow (integration_id) -> `EmailSendingService::send()`. diff --git a/DOCS/todo.md b/DOCS/todo.md index 51dd669..3ccc565 100644 --- a/DOCS/todo.md +++ b/DOCS/todo.md @@ -1,5 +1,5 @@ -15. [] W tym miejscu odwróć kolejność: najpierw źródło potem ID,
f6079660-1af8-11f1-a7c9-231cf6ef29d1allegro
-17. [] Na liście zamówien jak jest źródło i id zamówienia to zamiast shopPRO musi pisać która integracja konkretnie. Oraz dodajemy napis ID: ...D +15. [x] W tym miejscu odwróć kolejność: najpierw źródło potem ID,
f6079660-1af8-11f1-a7c9-231cf6ef29d1allegro
+17. [x] Na liście zamówien jak jest źródło i id zamówienia to zamiast shopPRO musi pisać która integracja konkretnie. Oraz dodajemy napis ID: ...D ## SonarQube — post plany 02-02 i 02-03 (skan 2026-03-13) 30. [] [Sonar 2026-03-13] Brak nowych issues — AllegroStatusSyncService i ShopproOrderSyncStateRepository czyste. Pre-existing issues w ShopproOrdersSyncService (god class) i Application.php niezmienione przez nasze modyfikacje. @@ -28,4 +28,8 @@ 33. [] [Sonar 2026-03-22] php:S2003 — show.php:696 Replace `require` with `require_once` (1x) 34. [] [Sonar 2026-03-22] php:S1448 — OrdersController ma 22 metody (limit 20) — rozdzielić (1x) 35. [] [Sonar 2026-03-22] php:S1142 — OrdersController::bulkPrint() ma 5 returnów (limit 3) (1x) -36. [] [Sonar 2026-03-22] php:S1068 — AllegroIntegrationController nieużywane pole $statusDiscoveryService (1x, pre-existing) \ No newline at end of file +36. [] [Sonar 2026-03-22] php:S1068 — AllegroIntegrationController nieużywane pole $statusDiscoveryService (1x, pre-existing) + +37. [x] Nie działa zapisywanie numer REGON +38. [x] Customowe przyciski paczek +39. [] Zamian głównego koloru przycisków z niebieskiego na inny (bo się z nagłówkami myli) \ No newline at end of file diff --git a/resources/views/orders/show.php b/resources/views/orders/show.php index 64ed105..0fe1a77 100644 --- a/resources/views/orders/show.php +++ b/resources/views/orders/show.php @@ -45,7 +45,14 @@ foreach ($addressesList as $address) {

- + + + ID:
diff --git a/src/Modules/Orders/OrdersController.php b/src/Modules/Orders/OrdersController.php index 137a550..bec0300 100644 --- a/src/Modules/Orders/OrdersController.php +++ b/src/Modules/Orders/OrdersController.php @@ -288,6 +288,7 @@ final class OrdersController $sourceOrderId = trim((string) ($row['source_order_id'] ?? '')); $externalOrderId = trim((string) ($row['external_order_id'] ?? '')); $source = trim((string) ($row['source'] ?? '')); + $integrationName = trim((string) ($row['integration_name'] ?? '')); $buyerName = trim((string) ($row['buyer_name'] ?? '')); $buyerEmail = trim((string) ($row['buyer_email'] ?? '')); $buyerCity = trim((string) ($row['buyer_city'] ?? '')); @@ -312,7 +313,7 @@ final class OrdersController . htmlspecialchars($internalOrderNumber !== '' ? $internalOrderNumber : ('#' . (string) ($row['id'] ?? 0)), ENT_QUOTES, 'UTF-8') . '
' . '
' - . '' . htmlspecialchars($this->sourceLabel($source), ENT_QUOTES, 'UTF-8') . '' + . '' . htmlspecialchars($integrationName !== '' ? $integrationName : $this->sourceLabel($source), ENT_QUOTES, 'UTF-8') . '' . 'ID: ' . htmlspecialchars($sourceOrderId !== '' ? $sourceOrderId : $externalOrderId, ENT_QUOTES, 'UTF-8') . '' . '
' . '', diff --git a/src/Modules/Orders/OrdersRepository.php b/src/Modules/Orders/OrdersRepository.php index 7b62fdc..7e3f50e 100644 --- a/src/Modules/Orders/OrdersRepository.php +++ b/src/Modules/Orders/OrdersRepository.php @@ -166,10 +166,12 @@ final class OrdersRepository COALESCE(oi_agg.items_count, 0) AS items_count, COALESCE(oi_agg.items_qty, 0) AS items_qty, COALESCE(sh_agg.shipments_count, 0) AS shipments_count, - COALESCE(od_agg.documents_count, 0) AS documents_count + COALESCE(od_agg.documents_count, 0) AS documents_count, + ig.name AS integration_name FROM orders o LEFT JOIN order_addresses a ON a.order_id = o.id AND a.address_type = "customer" LEFT JOIN allegro_order_status_mappings asm ON o.source = "allegro" AND LOWER(o.external_status_id) = asm.allegro_status_code + LEFT JOIN integrations ig ON ig.id = o.integration_id LEFT JOIN ( SELECT order_id, COUNT(*) AS items_count, COALESCE(SUM(quantity), 0) AS items_qty FROM order_items GROUP BY order_id @@ -223,6 +225,7 @@ final class OrdersRepository 'items_qty' => (float) ($row['items_qty'] ?? 0), 'shipments_count' => (int) ($row['shipments_count'] ?? 0), 'documents_count' => (int) ($row['documents_count'] ?? 0), + 'integration_name' => (string) ($row['integration_name'] ?? ''), 'items_preview' => (array) ($itemPreviewsByOrderId[$orderId] ?? []), ]; } @@ -426,9 +429,11 @@ final class OrdersRepository try { $effectiveStatusSql = $this->effectiveStatusSql('o', 'asm'); $orderStmt = $this->pdo->prepare( - 'SELECT o.*, ' . $effectiveStatusSql . ' AS effective_status_id + 'SELECT o.*, ' . $effectiveStatusSql . ' AS effective_status_id, + ig.name AS integration_name FROM orders o LEFT JOIN allegro_order_status_mappings asm ON o.source = "allegro" AND LOWER(o.external_status_id) = asm.allegro_status_code + LEFT JOIN integrations ig ON ig.id = o.integration_id WHERE o.id = :id LIMIT 1' );