feat(121+122): smsplanet conversation, notifications, default footer
Phase 121 — SMSPLANET Conversation + Notifications:
- migration 20260512_000110 adds smsplanet conversation + notifications tables
- src/Modules/Sms (SmsConversationService, SmsMessageRepository, SmsplanetWebhookController)
- src/Modules/Notifications (Repository, Controller, ApiController)
- order SMS tab, notification center, sender mode, inbound webhook
- public notifications.js + layouts/app.php integration
Phase 122 — SMSPLANET Default SMS Footer:
- migration 20260512_000111 adds smsplanet_integration_settings.default_footer
- footer appended to test SMS and order SMS, validated against 918 char limit
- settings textarea + compact order SMS note when footer configured
Bundled (could not split per-phase without hunk staging):
- routes/web.php (also carries Phase 118 fakturownia redirects)
- DOCS/{ARCHITECTURE,DB_SCHEMA,TECH_CHANGELOG}.md (118 + 121 + 122 entries)
- .paul/codebase/{architecture,db_schema,tech_changelog}.md (118 + 121 + 122)
- .paul/STATE.md, ROADMAP.md, changelog/2026-05-12.md (UNIFY closure)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -19,7 +19,7 @@ HTTP Request
|
||||
| Layer | Location | Responsibility |
|
||||
|-------|----------|----------------|
|
||||
| Entry | `public/index.php` | Bootstrap only |
|
||||
| Routes | `routes/web.php` (581 lines) | All ~80 routes; manual DI wiring |
|
||||
| Routes | `routes/web.php` | All routes; manual DI wiring |
|
||||
| Core | `src/Core/` (25 files) | Framework infrastructure |
|
||||
| Controllers | `src/Modules/*/Controller.php` | Request parsing → response |
|
||||
| Services | `src/Modules/*/Service.php` | Business logic |
|
||||
@@ -40,6 +40,8 @@ HTTP Request
|
||||
| **Email** | 3 | `EmailSendingService`, `VariableResolver`, `AttachmentGenerator` | Template-based email with PDF attachments |
|
||||
| **Automation** | 6 | `AutomationService` (834 LOC), `AutomationRepository`, `AutomationExecutionLogRepository` | Event→condition→action rules, email triggers |
|
||||
| **Settings** | 51+ | Integration controllers, OAuth clients, API clients, mappers | Allegro/shopPRO/Apaczka/InPost config, status mappings |
|
||||
| **Sms** | 3 | `SmsMessageRepository`, `SmsConversationService`, `SmsplanetWebhookController` | SMSPLANET outbound order SMS, inbound webhook parsing, order matching |
|
||||
| **Notifications** | 3 | `NotificationRepository`, `NotificationController`, `NotificationApiController` | Global notification history, unread polling API, mark-read actions |
|
||||
| **Cron** | 12 | `CronRepository`, `CronHandlerFactory`, handler classes | Scheduled imports, syncs, token refresh |
|
||||
| **Printing** | 4 | `PrintApiController`, `PrintJobRepository`, `ApiKeyMiddleware` | REST API for Windows print client |
|
||||
| **Statistics** | 3 | `OrdersStatisticsController`, `OrdersStatisticsRepository`, `statistics-summary-charts.js` | Daily order statistics and monthly summary charts |
|
||||
@@ -61,6 +63,12 @@ HTTP Request
|
||||
- Chart 2 displays monthly gross order values per selected integration plus a `Razem` line.
|
||||
- The PHP view keeps table fallbacks under both charts, so the data remains visible if JavaScript fails.
|
||||
|
||||
### Notifications (`public/assets/js/modules/notifications.js`)
|
||||
- Loaded globally from `resources/views/layouts/app.php`; activates only when the topbar notification button exists.
|
||||
- Polls `/api/notifications/unread` every 30 seconds and updates the unread badge.
|
||||
- Requests browser Notification API permission only after user interaction with the notification button.
|
||||
- Shows native browser notifications for newly seen unread items when permission is granted; click navigates to `target_url`.
|
||||
|
||||
## Key Data Flows
|
||||
|
||||
### Order Lifecycle
|
||||
@@ -83,6 +91,13 @@ HTTP Request
|
||||
1. **Generate** — `ReceiptController::store()` → `ReceiptService::generateReceipt()` → `ReceiptRepository::insert()` + Dompdf PDF
|
||||
2. **Email** — `EmailSendingService::send()` → `VariableResolver::resolve()` → `AttachmentGenerator::generatePdf()` → PHPMailer SMTP
|
||||
|
||||
### SMSPLANET Conversation
|
||||
1. **Settings** — `/settings/integrations/smsplanet` stores auth, text sender, `sender_mode`, optional 2WAY `sender_phone`, and optional global `default_footer`.
|
||||
2. **Outbound from order** — `/orders/{id}/sms/send` → `OrdersController::sendSms()` → `SmsConversationService::sendFromOrder()` appends `default_footer` when configured, validates the final body against 918 characters, sends through `SmsplanetApiClient::sendSms()`, and stores the final sent body in `sms_messages`.
|
||||
3. **Inbound webhook** — public `/webhooks/smsplanet/inbound` accepts SMSPLANET 2WAY `POST application/x-www-form-urlencoded` with `message=<JSON>`, plus fallback POST/GET payloads → `SmsplanetWebhookController::inbound()` → `SmsConversationService::receiveSmsplanetWebhook()`; successful 2WAY receipt returns plain `OK`.
|
||||
4. **Order matching** — inbound sender phone is normalized and matched to the latest order by `order_addresses.phone`.
|
||||
5. **Notification** — inbound SMS creates `notifications.type='sms_inbound'` with a target URL to the order SMS tab when an order was matched.
|
||||
|
||||
### Automation Rules
|
||||
1. **Setup** — `AutomationController` → `AutomationRepository::insertRule()`
|
||||
2. **Trigger** — `AutomationService::executeForOrder()` → evaluates trigger (`order_status_changed`, `order_status_aged`) → runs action (send email, update status)
|
||||
@@ -174,7 +189,7 @@ tests/
|
||||
- Zarzadza pojedynczym rekordem `smsplanet_integration_settings` (`id=1`) i bazowym wpisem `integrations` typu `smsplanet`.
|
||||
- Obsluguje dwie metody autoryzacji: Bearer token oraz `key` + `password`.
|
||||
- Szyfruje token, klucz API i haslo przez `IntegrationSecretCipher`; formularz widzi tylko flagi `has_api_token`, `has_api_key` i `has_api_password`.
|
||||
- Udostepnia `getCredentials()` tylko dla kompletnej i aktywnej konfiguracji testowej wysylki SMS.
|
||||
- Udostepnia `getCredentials()` tylko dla kompletnej i aktywnej konfiguracji testowej wysylki SMS, razem z opcjonalna `default_footer`.
|
||||
|
||||
### SmsplanetApiClient (`src/Modules/Settings/SmsplanetApiClient.php`)
|
||||
- Wykonuje `POST https://api2.smsplanet.pl/sms` jako `application/x-www-form-urlencoded`.
|
||||
@@ -185,10 +200,35 @@ tests/
|
||||
### SmsplanetIntegrationController (`src/Modules/Settings/SmsplanetIntegrationController.php`)
|
||||
- Endpointy: `GET /settings/integrations/smsplanet`, `POST /settings/integrations/smsplanet/save`, `POST /settings/integrations/smsplanet/test`.
|
||||
- `test` realnie wysyla SMS z edytowalna trescia i zapisuje wynik w `integrations.last_test_*`.
|
||||
- Testowa wysylka dopisuje `default_footer` przed wywolaniem SMSPLANET i waliduje finalna tresc w limicie 918 znakow.
|
||||
|
||||
### IntegrationsHubController
|
||||
- Dodaje wiersz SMSPLANET do `/settings/integrations` ze statusem konfiguracji, sekretu, aktywnosci i ostatniego testu.
|
||||
|
||||
## Phase 118 - Fakturownia Single Instance
|
||||
|
||||
### FakturowniaIntegrationRepository (`src/Modules/Settings/FakturowniaIntegrationRepository.php`)
|
||||
- Zarzadza pojedynczym globalnym rekordem `fakturownia_integration_settings` (`id=1`) i jednym bazowym wpisem `integrations.type='fakturownia'`.
|
||||
- `getSettings()` zwraca dane formularza, flagi `has_api_token`, aktywnosc i wynik ostatniego testu.
|
||||
- `saveSettings()` aktualizuje globalna konfiguracje; pusty `api_token` zachowuje zapisany sekret.
|
||||
- `findAll()` zostaje jako kompatybilny wrapper zwracajacy liste z jednym elementem dla starszych wywolan.
|
||||
- `getIntegrationId()` jest zrodlem prawdy dla `invoice_configs.integration_id` przy delegacji faktur.
|
||||
|
||||
### FakturowniaIntegrationController
|
||||
- Endpointy aktywne: `GET /settings/integrations/fakturownia`, `POST /settings/integrations/fakturownia/save`, `POST /settings/integrations/fakturownia/test`.
|
||||
- Legacy `/new` i `/edit` przekierowuja na globalna konfiguracje; delete z UI nie jest oferowany.
|
||||
- Widok `resources/views/settings/fakturownia.php` pokazuje jeden formularz konfiguracji oraz panel testu polaczenia.
|
||||
|
||||
### InvoiceConfigRepository + InvoiceConfigController
|
||||
- Przy `is_delegated=1` zapis konfiguracji ignoruje wieloinstancyjny wybor konta i ustawia `integration_id` na globalny Fakturownia id.
|
||||
- Kolumna `invoice_configs.integration_id` zostaje dla kompatybilnosci z `InvoiceService` i historia wystawionych faktur.
|
||||
- Widok konfiguracji faktury pokazuje status globalnej Fakturowni zamiast selecta kont.
|
||||
|
||||
### Migration 20260512_000109
|
||||
- Wybiera aktywna instancje Fakturowni jako zachowana; fallback: najczesciej uzywana w `invoice_configs`, potem najnizsze id.
|
||||
- Przepina delegowane `invoice_configs.integration_id` na zachowana instancje i zeruje `integration_id` dla lokalnych konfiguracji.
|
||||
- Usuwa nadmiarowe rekordy `fakturownia_integration_settings` i `integrations.type='fakturownia'` po przepieciu zaleznosci.
|
||||
|
||||
## Phase 108 — Delivery Status Management
|
||||
|
||||
### DeliveryStatusRepository (`src/Modules/Shipments/DeliveryStatusRepository.php`)
|
||||
|
||||
Reference in New Issue
Block a user