feat(127): erli integration foundation
Phase 127 complete: - add global Erli settings schema and encrypted API key repository - add real read-only Erli API connection test and settings UI - expose Erli in integrations hub and update PAUL/docs state
This commit is contained in:
@@ -39,7 +39,7 @@ HTTP Request
|
||||
| **Accounting** | 5 | `AccountingController`, `ReceiptService`, `ReceiptRepository` | Receipts, invoices, PDF, Excel export |
|
||||
| **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 |
|
||||
| **Settings** | 57+ | Integration controllers, OAuth clients, API clients, mappers | Allegro/shopPRO/Erli/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 |
|
||||
@@ -117,6 +117,13 @@ HTTP Request
|
||||
| `OrderStatusAgedHandler` | Trigger automation for stuck statuses |
|
||||
| `AutomationHistoryCleanupHandler` | Purge old automation logs |
|
||||
|
||||
### Erli Integration Foundation
|
||||
|
||||
1. **Settings** - `/settings/integrations/erli` stores one global Erli API key encrypted via `IntegrationSecretCipher`, an optional account label, active flag, and last connection-test result.
|
||||
2. **Connection test** - `ErliIntegrationController::test()` loads active credentials, calls `ErliApiClient::testConnection()`, performs a real authenticated `GET https://erli.pl/svc/shop-api/inbox`, and stores the result in `integrations.last_test_*`.
|
||||
3. **Hub** - `IntegrationsHubController::buildErliRow()` adds Erli to `/settings/integrations` with configured/missing secret status, active status, last test timestamp, and configure URL.
|
||||
4. **Deferred** - Phase 127 does not import orders, sync statuses, create labels, or track shipments. Those flows are planned for v3.8 Phases 128-131.
|
||||
|
||||
## Dependency Injection
|
||||
|
||||
Manual constructor injection in `routes/web.php` — no DI container library. Example:
|
||||
@@ -164,6 +171,30 @@ tests/
|
||||
bootstrap.php PSR-4 autoloader for tests
|
||||
```
|
||||
|
||||
## Phase 127 - Erli Integration Foundation
|
||||
|
||||
### ErliIntegrationRepository (`src/Modules/Settings/ErliIntegrationRepository.php`)
|
||||
- Zarzadza pojedynczym rekordem `erli_integration_settings` (`id=1`) i bazowym wpisem `integrations.type='erli'`.
|
||||
- Szyfruje klucz API przez `IntegrationSecretCipher`; formularz widzi tylko flage `has_api_key`.
|
||||
- `getCredentials()` zwraca aktywna konfiguracje z `base_url='https://erli.pl/svc/shop-api'` i odszyfrowanym Bearer API key.
|
||||
- Pusty input `api_key` podczas edycji zachowuje zapisany sekret.
|
||||
|
||||
### ErliApiClient (`src/Modules/Settings/ErliApiClient.php`)
|
||||
- `testConnection()` wykonuje realny `GET /inbox` do Erli z naglowkiem `Authorization: Bearer ...`.
|
||||
- Wysyla `Accept: application/json` i `User-Agent: orderPRO/1.0 (erli-integration)`.
|
||||
- Traktuje HTTP 2xx jako sukces; 401/403 jako blad autoryzacji, 429 jako limit zapytan, pozostale bledy jako czytelny komunikat z odpowiedzi.
|
||||
- Uzywa `SslCertificateResolver` i nie wywoluje `curl_close()` (PHP 8.5 compatible).
|
||||
|
||||
### ErliIntegrationController (`src/Modules/Settings/ErliIntegrationController.php`)
|
||||
- Endpointy: `GET /settings/integrations/erli`, `POST /settings/integrations/erli/save`, `POST /settings/integrations/erli/test`.
|
||||
- `save` zapisuje label, aktywnosc i sekret; `test` wykonuje realny test API i zapisuje wynik przez `IntegrationsRepository::updateTestResult()`.
|
||||
|
||||
### IntegrationsHubController
|
||||
- Dodaje wiersz Erli do `/settings/integrations` ze statusem konfiguracji, sekretu, aktywnosci i ostatniego testu.
|
||||
|
||||
### Scope Boundary
|
||||
- Phase 127 nie dodaje importu zamowien, mapowania/synchronizacji statusow, etykiet ani trackingu Erli. Te obszary sa odlozone do Phases 128-131.
|
||||
|
||||
## Phase 116 - HostedSMS Integration Settings
|
||||
|
||||
### HostedSmsIntegrationRepository (`src/Modules/Settings/HostedSmsIntegrationRepository.php`)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Database Schema
|
||||
|
||||
**Updated:** 2026-05-12 | **Total tables:** 62 | **Engine:** InnoDB | **Charset:** utf8mb4_unicode_ci
|
||||
**Updated:** 2026-05-15 | **Total tables:** 63 | **Engine:** InnoDB | **Charset:** utf8mb4_unicode_ci
|
||||
|
||||
---
|
||||
|
||||
@@ -613,6 +613,20 @@ UNIQUE: `(integration_id)` - one global SMSPLANET settings row.
|
||||
|
||||
---
|
||||
|
||||
**erli_integration_settings** - Erli marketplace API credentials (Phase 127; fixed 1 row)
|
||||
| Column | Type | Nullable | Notes |
|
||||
|--------|------|----------|-------|
|
||||
| `id` | TINYINT UNSIGNED | NO | PK, always 1 |
|
||||
| `integration_id` | INT UNSIGNED | YES | UNIQUE, FK -> integrations(id) CASCADE; single `integrations.type='erli'` row |
|
||||
| `api_key_encrypted` | TEXT | YES | AES-encrypted Bearer API key via `IntegrationSecretCipher` |
|
||||
| `account_label` | VARCHAR(128) | YES | Optional display label for the integrations hub |
|
||||
| `created_at` | DATETIME | NO | DEFAULT CURRENT_TIMESTAMP |
|
||||
| `updated_at` | DATETIME | NO | DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP |
|
||||
|
||||
UNIQUE: `(integration_id)` - one global Erli settings row. Base integration uses `base_url='https://erli.pl/svc/shop-api'`. Phase 127 only stores configuration and test results; order import, status sync, shipments and tracking are deferred to later v3.8 phases.
|
||||
|
||||
---
|
||||
|
||||
**sms_messages** - SMSPLANET inbound/outbound conversation history (Phase 121)
|
||||
| Column | Type | Nullable | Notes |
|
||||
|--------|------|----------|-------|
|
||||
|
||||
@@ -1,5 +1,22 @@
|
||||
# Technical Changelog
|
||||
|
||||
## 2026-05-15 - Phase 127 Plan 01: Erli Integration Foundation
|
||||
|
||||
**Co zrobiono:**
|
||||
- Dodano migracje `20260515_000114_create_erli_integration_settings.sql` z pojedyncza globalna konfiguracja `erli_integration_settings` i bazowym wpisem `integrations.type='erli'`.
|
||||
- Dodano `ErliIntegrationRepository` z szyfrowaniem klucza API przez `IntegrationSecretCipher` i zachowaniem sekretu przy pustym polu edycji.
|
||||
- Dodano `ErliApiClient`, ktory testuje polaczenie realnym `GET https://erli.pl/svc/shop-api/inbox` z naglowkiem `Authorization: Bearer ...` i `User-Agent`.
|
||||
- Dodano `ErliIntegrationController`, routes `/settings/integrations/erli`, `/save`, `/test` oraz widok `resources/views/settings/erli.php`.
|
||||
- Dodano Erli do hubu integracji `/settings/integrations` z informacja o konfiguracji, aktywnosci i ostatnim tescie.
|
||||
|
||||
**Dlaczego:**
|
||||
- Erli ma byc trzecim kanalem sprzedazy, ale potrzebuje najpierw bezpiecznego fundamentu konfiguracji i potwierdzenia dostepu do API.
|
||||
- Na podstawie decyzji operatora integracja startuje jako jedna globalna konfiguracja, bez przelacznika sandbox.
|
||||
- Test polaczenia realnie odpytuje API, ale nie importuje zamowien i nie oznacza inboxa jako przeczytanego.
|
||||
|
||||
**BREAKING / migracja:**
|
||||
- Brak breaking changes. Nowa tabela i nowy wpis integracji sa dodatkiem. Import zamowien, synchronizacja statusow, etykiety i tracking Erli sa odlozone do kolejnych faz v3.8.
|
||||
|
||||
## 2026-05-12 - SMSPLANET Inbound Webhook Fix
|
||||
|
||||
**Co zrobiono:**
|
||||
|
||||
Reference in New Issue
Block a user