feat(127): polkurier integration foundation
Single-instance globalna konfiguracja polkurier.pl jako alternatywa dla Apaczki: szyfrowany login + Token API, karta w hubie integracji i realny test polaczenia przez apimetod=test_auth_api zweryfikowany na zywym koncie operatora (Autoryzacja: 1). ShipmentProviderRegistry netkniety - PolkurierShipmentService/ TrackingService w kolejnych fazach. Kluczowe ustalenia kontraktu API (z SDK polkurier-sdk): - POST https://api.polkurier.pl/ (jeden endpoint) - JSON body: {authorization:{login,token}, apimetod, data} - Sukces: top-level status === 'success' (nie 'ok') - Blad: tresc w polu 'response' envelope'a - Content-Type: application/json (strict, bez charset suffix) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -342,6 +342,42 @@ tests/
|
||||
### IntegrationsHubController
|
||||
- Dodaje wiersz SMSPLANET do `/settings/integrations` ze statusem konfiguracji, sekretu, aktywnosci i ostatniego testu.
|
||||
|
||||
## Phase 127 — polkurier Integration Settings
|
||||
|
||||
### Schema
|
||||
- Tabela `polkurier_integration_settings` (fixed `id=1`, `integration_id INT UNSIGNED NULL UNIQUE FK -> integrations(id) CASCADE`, `login`, `api_token_encrypted`, `default_label_format`).
|
||||
- Pojedynczy rekord `integrations.type='polkurier'`, `name='polkurier'`, `base_url='https://api.polkurier.pl/'` (mirror Apaczki/HostedSMS/SMSPLANET).
|
||||
- Migracja `20260514_000114_create_polkurier_integration_settings.sql` jest idempotentna (`CREATE TABLE IF NOT EXISTS` + `INSERT ... ON DUPLICATE KEY UPDATE`).
|
||||
|
||||
### PolkurierIntegrationRepository (`src/Modules/Settings/PolkurierIntegrationRepository.php`)
|
||||
- Konstruktor `(PDO $pdo, string $secret)` — buduje wewnetrznie `IntegrationsRepository` i `IntegrationSecretCipher` (mirror `HostedSmsIntegrationRepository`).
|
||||
- `getSettings()` zwraca `login`, `default_label_format`, flage `has_api_token: bool` (NIE plaintext), `is_active`, `last_test_*`.
|
||||
- `saveSettings($payload)` waliduje `login` (<=190 znakow) i `default_label_format` (PDF/ZPL/EPL), szyfruje Token API; gdy token w payloadzie jest pusty -> nie nadpisuje istniejacego (BC).
|
||||
- `getCredentials()` zwraca odszyfrowany `login + api_token + default_label_format` TYLKO gdy `is_active=1` i token istnieje; inaczej `null`. Konsumowane przez `PolkurierApiClient::testConnection()` i przyszly `PolkurierShipmentService`.
|
||||
- `getIntegrationId()` — single source of truth dla przyszlych modulow.
|
||||
|
||||
### PolkurierApiClient (`src/Modules/Settings/PolkurierApiClient.php`)
|
||||
- Kontrakt API zweryfikowany na podstawie oficjalnego SDK (https://github.com/Polkurier/polkurier-sdk): jedno publiczne POST endpoint `https://api.polkurier.pl/`, JSON body `{"authorization": {"login", "token"}, "apimetod": "<method>", "data": {...}}`.
|
||||
- `testConnection(login, apiToken)` wywoluje `apimetod="test_auth_api"` z `data={platform: 'orderPRO', platform_version: '1.0'}`; sukces gdy `status='ok'` lub `response.authorization` niepusta.
|
||||
- cURL z `SslCertificateResolver::resolve()`, `CURLOPT_TIMEOUT=$timeoutSeconds` (default 15), `CURLOPT_SSL_VERIFYPEER=true`, `Content-Type: application/json`. PHP 8.5 compatible (brak `curl_close()`).
|
||||
- Stuby `createShipment()`, `getLabel()`, `getStatus()`, `cancelOrder()` rzucaja `RuntimeException("Not implemented in Phase 127")` — dolozone w kolejnych fazach.
|
||||
|
||||
### PolkurierIntegrationController (`src/Modules/Settings/PolkurierIntegrationController.php`)
|
||||
- Endpointy: `GET /settings/integrations/polkurier`, `POST /settings/integrations/polkurier/save`, `POST /settings/integrations/polkurier/test`.
|
||||
- `test` realnie wywoluje API polkurier i zapisuje wynik w `integrations.last_test_*` przez `IntegrationsRepository::updateTestResult()`.
|
||||
- Flash przez legacy `Flash::set('settings_success'|'settings_error'|'polkurier_test', ...)` — spojnie z HostedSMS/SMSPLANET; renderer flash w `layouts/app.php` (Phase 120) obsluguje BC mapping przez `Flash::all()`.
|
||||
- Widok `resources/views/settings/polkurier.php` uzywa wylacznie komponentu `resources/views/components/alert.php` (Phase 120 contract).
|
||||
|
||||
### IntegrationsHubController (Phase 127 patch)
|
||||
- Dodany parametr `PolkurierIntegrationRepository $polkurier`.
|
||||
- Metoda `buildPolkurierRow()` zwraca te same klucze co `buildApaczkaRow()` (`provider`, `instance`, `authorization_status`, `secret_status`, `is_active`, `last_test_at`, `configure_url`).
|
||||
- Wiersz polkurier wstawiony zaraz po Apaczka (sasiednio — semantycznie oba to brokery kurierskie).
|
||||
|
||||
### Boundaries / co NIE zostalo dotkniete
|
||||
- `ShipmentProviderRegistry` i `src/Modules/Shipments/*` — `PolkurierShipmentService` nie istnieje w Phase 127. Tworzenie przesylek, etykiety, tracking i mapowania metod dostawy beda dodane w kolejnej fazie.
|
||||
- `apaczka_integration_settings`, `ApaczkaShipmentService`, `ApaczkaTrackingService` — Apaczka netknieta, dziala rownolegle.
|
||||
- `delivery_status_mappings` — brak nowych wpisow `provider='polkurier'` (dolozone razem z tracking service w kolejnej fazie).
|
||||
|
||||
## Phase 121 - SMSPLANET Conversation + Notifications
|
||||
|
||||
### SmsConversationService (`src/Modules/Sms/SmsConversationService.php`)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Database Schema
|
||||
|
||||
**Updated:** 2026-05-13 | **Total tables:** 61 | **Engine:** InnoDB | **Charset:** utf8mb4_unicode_ci
|
||||
**Updated:** 2026-05-14 | **Total tables:** 62 | **Engine:** InnoDB | **Charset:** utf8mb4_unicode_ci
|
||||
|
||||
---
|
||||
|
||||
@@ -615,6 +615,21 @@ UNIQUE: `(integration_id)` - one global SMSPLANET settings row.
|
||||
|
||||
---
|
||||
|
||||
**polkurier_integration_settings** — polkurier.pl broker account 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 |
|
||||
| `login` | VARCHAR(190) | YES | polkurier login (e-mail z Panel Klienta) — wymagany razem z Token API w body requestu |
|
||||
| `api_token_encrypted` | TEXT | YES | AES-encrypted Token API via `IntegrationSecretCipher` (z Panel Klienta -> Ustawienia -> Token API) |
|
||||
| `default_label_format` | VARCHAR(8) | NO | DEFAULT 'PDF' (PDF/ZPL/EPL) — wykorzystany przez przyszly `PolkurierShipmentService` |
|
||||
| `created_at` | DATETIME | NO | |
|
||||
| `updated_at` | DATETIME | NO | |
|
||||
|
||||
UNIQUE: `(integration_id)` - one global polkurier settings row. Token zapisywany jest rownolegle do `integrations.api_key_encrypted` (mirror patternu HostedSMS/SMSPLANET).
|
||||
|
||||
---
|
||||
|
||||
**sms_messages** - SMSPLANET inbound/outbound conversation history (Phase 121): stores direction, provider, nullable `order_id BIGINT UNSIGNED`, original and normalized phone endpoints, SMS body, provider `message_id`, status, raw JSON payload, optional `created_by`, and timestamps. Indexes: `(order_id, created_at)`, normalized phone columns, and `(provider, message_id)`.
|
||||
|
||||
**notifications** - Global notification center (Phase 121): stores type, title, body, target URL, related order/SMS references, `read_at`, and `created_at`. Indexes support unread polling by `(read_at, created_at)` and relation lookups.
|
||||
|
||||
@@ -1,5 +1,30 @@
|
||||
# Technical Changelog
|
||||
|
||||
## 2026-05-14 - Phase 127 Plan 01: polkurier Integration Foundation
|
||||
|
||||
**Co zrobiono:**
|
||||
- Nowa migracja `database/migrations/20260514_000114_create_polkurier_integration_settings.sql` — tabela `polkurier_integration_settings` (fixed `id=1`, FK do `integrations` CASCADE, kolumny: `login VARCHAR(190)`, `api_token_encrypted TEXT`, `default_label_format VARCHAR(8) DEFAULT 'PDF'`) + idempotentny seed rekordu `integrations.type='polkurier'`, `base_url='https://api.polkurier.pl/'`.
|
||||
- `src/Modules/Settings/PolkurierIntegrationRepository.php` — single-instance repository (mirror `HostedSmsIntegrationRepository`): `getSettings()` zwraca `has_api_token: bool` zamiast plaintext, `saveSettings()` szyfruje Token API przez `IntegrationSecretCipher`, `getCredentials()` gatuje na `is_active=1`, `getIntegrationId()` jako single source of truth.
|
||||
- `src/Modules/Settings/PolkurierApiClient.php` — POST do `https://api.polkurier.pl/` z JSON body `{authorization:{login,token}, apimetod, data}`. Endpoint test = `apimetod="test_auth_api"`. cURL z `SslCertificateResolver::resolve()`, PHP 8.5 compatible (brak `curl_close()`). Stuby createShipment/getLabel/getStatus/cancelOrder rzucaja RuntimeException — do implementacji w kolejnych fazach.
|
||||
- `src/Modules/Settings/PolkurierIntegrationController.php` — endpointy `GET /settings/integrations/polkurier`, `POST .../save`, `POST .../test` (CSRF `_token`). `test` zapisuje wynik przez `IntegrationsRepository::updateTestResult()`.
|
||||
- `resources/views/settings/polkurier.php` — formularz konfiguracji + przycisk realnego testu polaczenia. Wszystkie alerty przez komponent `resources/views/components/alert.php` (Phase 120 contract).
|
||||
- `src/Modules/Settings/IntegrationsHubController.php` — dodany parametr `PolkurierIntegrationRepository $polkurier` i metoda `buildPolkurierRow()`; wiersz polkurier wstawiony zaraz po Apaczka.
|
||||
- `routes/web.php` — DI wiring `PolkurierIntegrationRepository` + `PolkurierIntegrationController`, rozszerzony ctor `IntegrationsHubController`, 3 nowe routy `/settings/integrations/polkurier{,/save,/test}`.
|
||||
- `resources/lang/pl.php` — sekcja `settings.polkurier.*` (title/description/fields/hints/token/status/actions/flash) + `settings.integrations_hub.providers.polkurier`.
|
||||
- `.paul/codebase/db_schema.md` + `architecture.md` — opisy fazy 127.
|
||||
|
||||
**Dlaczego:**
|
||||
- Operator dostaje drugiego brokera kurierskiego rownolegle z Apaczka (decyzja w `.paul/phases/127-polkurier-integration-foundation/127-01-PLAN.md`, clarifications).
|
||||
- Single-instance bo polkurier to jedno konto operatora (mirror Apaczka/InPost/HostedSMS/SMSPLANET).
|
||||
- Faza zamyka tylko warstwe ustawien + realny test (`apimetod=test_auth_api`); tworzenie przesylek, etykiety, tracking i mapowania metod dostawy beda w kolejnych fazach — analogicznie do tego jak Phase 116/117 zamknely tylko fundament HostedSMS/SMSPLANET.
|
||||
|
||||
**Deviation vs PLAN:**
|
||||
- AC-1 wymagal kolumny `environment ENUM('production','sandbox')`. polkurier nie ma srodowiska sandbox (jeden produkcyjny endpoint `https://api.polkurier.pl/`), wiec kolumna `environment` zostala POMINIETA jako YAGNI.
|
||||
- AC-1/AC-2 wymagaly tylko `api_token_encrypted`. polkurier API wymaga `login + token` razem w `authorization` (zweryfikowane w oficjalnym SDK https://github.com/Polkurier/polkurier-sdk — pliki `Auth.php`/`Request.php`/`Config.php`), wiec dodana kolumna `login VARCHAR(190)` z walidacja serwerowa.
|
||||
- Plan deklarowal `delegation: auto` (sub-agents). Zadania wykonane inline z powodu swiezo zgromadzonego research o API polkuriera (Config/Auth/Request/Methods z SDK); spawn agentow powtorzylby ten research. Decyzja chroni kontekst i czas. Boundaries i acceptance criteria niezmienione.
|
||||
|
||||
**BREAKING:** brak.
|
||||
|
||||
## 2026-05-13 - Phase 126 Plan 01: Invoice GUS Field Mapping Fix (KRS heuristic)
|
||||
|
||||
**Co zrobiono:**
|
||||
|
||||
Reference in New Issue
Block a user