--- phase: 15-email-sending plan: 01 subsystem: email tags: [phpmailer, smtp, dompdf, quill, activity-log] requires: - phase: 13-email-mailboxes provides: email_mailboxes table, SMTP credentials, IntegrationSecretCipher - phase: 14-email-templates provides: email_templates table, Quill.js editor, VARIABLE_GROUPS, ATTACHMENT_TYPES provides: - EmailSendingService (send + preview via SMTP) - VariableResolver (template variable substitution) - AttachmentGenerator (receipt PDF in-memory) - Send email modal on order detail view - Activity log integration for email events affects: [] tech-stack: added: [phpmailer/phpmailer v7.0.2] patterns: [activity-log-based email history, in-memory PDF attachments] key-files: created: - src/Modules/Email/EmailSendingService.php - src/Modules/Email/VariableResolver.php - src/Modules/Email/AttachmentGenerator.php - resources/views/orders/partials/email-send-modal.php - resources/scss/modules/_email-send.scss modified: - src/Modules/Orders/OrdersController.php - routes/web.php - resources/views/orders/show.php - resources/lang/pl.php key-decisions: - "PHPMailer v7.0.2 jako SMTP transport (nie natywny mail())" - "Email history jako wpisy w order_activity_log (nie osobna sekcja UI)" - "VariableResolver wydzielony jako osobna klasa (reuse poza kontrolerem szablonow)" - "Zalaczniki in-memory (addStringAttachment) bez plikow tymczasowych" patterns-established: - "Activity log integration: nowe typy zdarzen (email_sent/email_failed) z tlumaczeniami w pl.php" - "Email modul (App\\Modules\\Email) jako oddzielny namespace od Settings" duration: ~90min started: 2026-03-17T10:00:00Z completed: 2026-03-17T11:30:00Z --- # Phase 15 Plan 01: Wysylka e-mail z zamowien — Summary **Pelny flow wysylki e-mail z widoku zamowienia: wybor szablonu, podglad ze zmiennymi, wysylka SMTP z zalacznikiem paragon PDF, logowanie w historii zamowienia.** ## Performance | Metric | Value | |--------|-------| | Duration | ~90min | | Tasks | 2 auto + 1 checkpoint | | Files created | 5 | | Files modified | 9 | ## Acceptance Criteria Results | Criterion | Status | Notes | |-----------|--------|-------| | AC-1: Wysylka e-mail z zamowienia | Pass | Szablon + zmienne + SMTP wysylka dziala end-to-end | | AC-2: Zalacznik paragon PDF | Pass | Dompdf generuje PDF in-memory, dolaczany przez addStringAttachment | | AC-3: Logowanie wysylek | Pass | Wpis w email_logs + order_activity_log (widoczny w zakladce Historia) | | AC-4: Podglad przed wysylka | Pass | AJAX preview z rozwiazanymi zmiennymi + lista zalacznikow | | AC-5: Walidacja i obsluga bledow | Pass | Brak konfiguracji → btn disabled; blad SMTP → status failed + komunikat | ## Accomplishments - Modul `App\Modules\Email` z 3 klasami: EmailSendingService, VariableResolver, AttachmentGenerator - Modal wysylki na widoku zamowienia z wyborem szablonu, skrzynki, podgladem i wysylka AJAX - Integracja z order_activity_log — wysylka maila pojawia sie jako zdarzenie w historii zamowienia - PHPMailer v7.0.2 jako zaleznosc composer ## Files Created/Modified | File | Change | Purpose | |------|--------|---------| | `src/Modules/Email/EmailSendingService.php` | Created | Glowna klasa wysylki: send(), preview(), SMTP transport, logowanie | | `src/Modules/Email/VariableResolver.php` | Created | Zamiana {{grupa.zmienna}} na dane zamowienia/kupujacego/firmy | | `src/Modules/Email/AttachmentGenerator.php` | Created | Generowanie PDF paragonu in-memory przez dompdf | | `resources/views/orders/partials/email-send-modal.php` | Created | Modal: wybor szablonu/skrzynki, podglad, wysylka AJAX | | `resources/scss/modules/_email-send.scss` | Created | Style modala i podgladu | | `src/Modules/Orders/OrdersController.php` | Modified | Dodano sendEmail(), emailPreview(), email deps w konstruktorze | | `routes/web.php` | Modified | Nowe route'y POST send-email/email-preview, wiring EmailSendingService | | `resources/views/orders/show.php` | Modified | Przycisk "Wyslij e-mail", include modala | | `resources/lang/pl.php` | Modified | Tlumaczenia email_sent, email_failed | | `resources/scss/app.scss` | Modified | Import modules/email-send | | `composer.json` | Modified | phpmailer/phpmailer v7.0.2 | | `DOCS/DB_SCHEMA.md` | Modified | Wpis o PHPMailer i module Email | | `DOCS/ARCHITECTURE.md` | Modified | Nowy modul + route'y | | `DOCS/TECH_CHANGELOG.md` | Modified | Changelog Phase 15 | ## Decisions Made | Decision | Rationale | Impact | |----------|-----------|--------| | PHPMailer v7.0.2 (nie natywny mail()) | Pelna kontrola SMTP, auth, TLS, zalaczniki | Nowa zaleznosc composer | | Email history w activity_log (nie osobna sekcja) | Spojnosc UX — jeden timeline zdarzen | Prostszy widok, mniej kodu | | VariableResolver jako osobna klasa | Reuse logiki zmiennych poza kontrolerem szablonow | Czystsza architektura | | In-memory PDF (addStringAttachment) | Brak plikow tymczasowych na dysku | Prostsze, bezpieczniejsze | ## Deviations from Plan ### Summary | Type | Count | Impact | |------|-------|--------| | Scope change | 1 | Email history przeniesiona z Dokumentow do activity_log | | Auto-fixed | 3 | Bugfixy odkryte podczas pracy | **Total impact:** Istotna zmiana UX (lepsza), plus naprawione 3 bugi. ### Scope Change **1. Email history w activity_log zamiast osobnej sekcji w Dokumentach** - **Zmiana:** User zażądał przeniesienia historii e-maili z zakładki Dokumenty do zakładki Historia jako wpisy w activity_log - **Wpływ:** Usunięto loadEmailLogs(), emailLogsList z widoku; dodano recordActivity() w EmailSendingService ### Auto-fixed Issues **1. Search duplicate :search parameter (OrdersRepository)** - **Found during:** Testowanie UI - **Issue:** PDO named parameter `:search` użyty 5x w jednym zapytaniu — wyszukiwanie po nazwisku klienta nie działało - **Fix:** Osobne nazwy parametrów `:s1` do `:s5` - **Files:** `src/Modules/Orders/OrdersRepository.php` **2. Migration idempotency (attachment_1)** - **Found during:** Uruchomienie migracji - **Issue:** `ALTER TABLE ADD COLUMN attachment_1` nie miała warunku IF NOT EXISTS - **Fix:** Dodano sprawdzenie information_schema + PREPARE/EXECUTE - **Files:** `database/migrations/20260316_000001_add_attachment1_to_email_templates.sql` **3. ReceiptController actor name** - **Found during:** Review activity_log entries - **Issue:** Używał `$user['username']` (nieistniejące pole) zamiast `$user['name']` - **Fix:** Zmieniono na `$user['name'] ?? $user['email']` - **Files:** `src/Modules/Accounting/ReceiptController.php` ## Next Phase Readiness **Ready:** - Milestone v0.4 Modul E-mail kompletny (Phase 13 + 14 + 15) - Pelny flow: skrzynki SMTP → szablony z Quill.js → wysylka z zamowien **Concerns:** - Brak kolejki/retry dla nieudanych wysylek (synchroniczna wysylka) - Brak bulk email z listy zamowien **Blockers:** - None --- *Phase: 15-email-sending, Plan: 01* *Completed: 2026-03-17*