feat(117): smsplanet integration settings

This commit is contained in:
2026-05-12 13:18:41 +02:00
parent 09f9ca798d
commit bcbb35bc6b
22 changed files with 1392 additions and 22 deletions

View File

@@ -13,7 +13,7 @@ Sprzedawca moĹĽe obsĹugiwać zamĂłwienia ze wszystkich kanaĹĂłw
| Attribute | Value |
|-----------|-------|
| Version | 3.7.0-dev |
| Status | v3.7 in progress — Phases 113-116 shipped (Fakturownia + HostedSMS settings/test SMS) |
| Status | v3.7 in progress — Phases 113-117 shipped (Fakturownia + HostedSMS/SMSPLANET settings/test SMS) |
| Last Updated | 2026-05-12 |
## Requirements
@@ -120,6 +120,7 @@ Sprzedawca moĹĽe obsĹugiwać zamĂłwienia ze wszystkich kanaĹĂłw
- [x] Ksiegowosc: refaktor `/settings/accounting` na hub-rozdroze + osobne podstrony `/receipts` i `/invoices` + edycja na osobnym widoku; pelen CRUD `invoice_configs` z opcja delegacji do Fakturowni (conditional integration_id, serwerowa walidacja); seed `Domyslny VAT`; globalny modul `confirm-delete.js` — Phase 114
- [x] Wystawianie faktury z zamowienia: toggle `orders.invoice_requested` w zakladce Platnosci + auto-set z importu (Allegro `invoice.required` / shopPRO 5-key parser); formularz z auto-fillem NIP przez MF Biala Liste (publiczne API); dual flow lokalny (Dompdf + atomowy `invoice_number_counters`) / delegowany (POST do Fakturowni przed INSERT, redirect 302 do natywnego PDF); lista `/settings/accounting/invoices/issued` z filtrami; snapshot pattern w `invoices` JSON; PHP 8.5-compatible (curl_close removed) — Phase 115
- [x] Integracja HostedSMS: pojedyncza globalna konfiguracja w `/settings/integrations/hostedsms`, szyfrowane haslo, karta w hubie integracji i realna wysylka testowego SMS z edytowalna trescia oraz czytelnym statusem MessageId — Phase 116
- [x] Integracja SMSPLANET: pojedyncza globalna konfiguracja w `/settings/integrations/smsplanet`, szyfrowane sekrety, autoryzacja Bearer token albo key + password, karta w hubie integracji i realna wysylka testowego SMS — Phase 117
### Deferred
@@ -128,7 +129,7 @@ Sprzedawca moĹĽe obsĹugiwać zamĂłwienia ze wszystkich kanaĹĂłw
### Active (In Progress)
- [ ] v3.7 Invoices / operational integrations — Phases 113 + 114 + 115 + 116 shipped; ewentualne kolejne fazy (np. eksport XLSX faktur, invoice.created event, idempotencja Fakturowni, automatyzacje SMS, odbior SMS po aktywacji HostedSMS) w kolejce.
- [ ] v3.7 Invoices / operational integrations — Phases 113 + 114 + 115 + 116 + 117 shipped; ewentualne kolejne fazy (np. eksport XLSX faktur, invoice.created event, idempotencja Fakturowni, automatyzacje SMS, odbior SMS po aktywacji HostedSMS) w kolejce.
### Planned (Next)
@@ -198,6 +199,9 @@ PHP (XAMPP/Laravel), integracje z API marketplace'Ăłw (Allegro, Erli) oraz API
| Push waybilla do Allegro checkout forms wykonywany tylko dla zamowien source=allegro i jest niekrytyczny dla lokalnego tworzenia paczki | Eliminacja recznego kroku po stronie Allegro bez ryzyka utraty lokalnie utworzonej przesylki przy bledzie API | 2026-03-28 | Active |
| HostedSMS startuje jako jedna globalna konfiguracja z realnym testowym SMS | Operator potrzebowal na start tylko ustawien i potwierdzenia dzialania; SimpleAPI nie ma osobnego ping endpointu | 2026-05-12 | Active |
| Odbior odpowiedzi SMS z HostedSMS odlozony do osobnej fazy | Dokumentacja przewiduje metody odbioru SMS, ale wymagaja aktywacji interfejsu po stronie DCS/HostedSMS | 2026-05-12 | Deferred |
| SMSPLANET startuje jako jedna globalna konfiguracja z realnym testowym SMS | Operator potrzebowal drugiej bramki porownywalnej z HostedSMS, bez automatyzacji SMS w tej fazie | 2026-05-12 | Active |
| SMSPLANET obsluguje Bearer token oraz key + password | Dokumentacja SMSPLANET rekomenduje Bearer, ale API wspiera tez klucz i haslo; UI pozwala przetestowac oba warianty | 2026-05-12 | Active |
| Test SMSPLANET nie uzywa parametru `test=1` | Wymaganie UAT: test ma realnie wysylac SMS i zapisac wynik API w hubie integracji | 2026-05-12 | Active |
| Event `order.imported` emitowany tylko przy pierwszym imporcie zamowienia | Unikniecie duplikatow reakcji automatyzacji przy kolejnych synchronizacjach | 2026-04-15 | Active |
| Preset przesylek nadpisuje wylacznie wymiary+wage + auto-submit po autofill | Single responsibility preseta + szybszy flow operatora | 2026-04-17 | Active |
| Re-import istniejacego zamowienia jest delta-only — `replaceAddresses/Items/Notes` tylko przy `created=true`; `updateOrderDelta()` zawezony do payment_status/total_paid/status_code/is_canceled_by_buyer/source_updated_at/payload_json/fetched_at | Zamowienia zarzadzane sa w orderPRO (nie w zrodle), wiec re-import nie powinien nadpisywac stanu lokalnego ani lamac stabilnosci `order_items.id` (case #882: znikajace `project_generated`) | 2026-05-07 | Active |
@@ -255,6 +259,6 @@ Quick Reference:
---
*PROJECT.md — Updated when requirements or context change*
*Last updated: 2026-05-12 after Phase 116 (HostedSMS Integration Settings + Test SMS) completion; v3.7 milestone in progress*
*Last updated: 2026-05-12 after Phase 117 (SMSPLANET Integration Settings + Test SMS) completion; v3.7 milestone in progress*

View File

@@ -16,12 +16,14 @@ Wystawianie faktur dla klientow z NIP poprzez integracje z Fakturownia (app.fakt
| 114 | Accounting Configs Refactor (hub + osobne podstrony receipts/invoices) | 1/1 | Complete (2026-05-10) |
| 115 | Wystawianie faktury z zamowienia (lokalne + delegacja Fakturownia + NIP lookup MF Biala Lista) | 1/1 | Complete (2026-05-10) |
| 116 | HostedSMS Integration Settings + Test SMS | 1/1 | Complete (2026-05-12) |
| 117 | SMSPLANET Integration Settings + Test SMS | 1/1 | Complete (2026-05-12; migration/manual SMS verification pending) |
Planowane kolejne fazy v3.7 (kandydaci, do rozplanowania):
- Eksport XLSX listy wystawionych faktur (analogicznie do paragonow)
- Idempotencja podwojnego POST do Fakturowni (INVOICE-IDEMP-115)
- Event automatyzacji `invoice.created` (jezeli operator chce wysylac faktury mailem)
- Automatyzacje SMS / odbior odpowiedzi SMS po aktywacji HostedSMS
- Manualne potwierdzenie SMSPLANET na zywej bazie i danych produkcyjnych
- Backfill `curl_close()` w `ShopproIntegrationsRepository` (PHP 8.5 compat, poza zakresem 115)
## Next Milestone
@@ -496,4 +498,4 @@ Archive: `.paul/milestones/v0.1-ROADMAP.md`
---
*Roadmap created: 2026-03-12*
*Last updated: 2026-05-12 - Phase 116 (HostedSMS Integration Settings + Test SMS) complete; v3.7 milestone in progress*
*Last updated: 2026-05-12 - Phase 117 (SMSPLANET Integration Settings + Test SMS) complete with environment verification gaps; v3.7 milestone in progress*

View File

@@ -5,38 +5,38 @@
See: .paul/PROJECT.md (updated 2026-05-07)
**Core value:** Sprzedawca moze obslugiwac zamowienia ze wszystkich kanalow sprzedazy i nadawac przesylki bez przelaczania sie miedzy platformami.
**Current focus:** v3.7 Invoices + operational integrations - Phase 116 HostedSMS settings/test SMS complete.
**Current focus:** v3.7 Invoices + operational integrations - Phase 117 SMSPLANET settings/test SMS unified; migration/live SMS verification remains environment-dependent.
## Current Position
Milestone: v3.7 Invoices (Fakturownia integration) - In progress
Phase: 117 of TBD (next candidate) - Not started
Plan: pending
Status: Phase 116 complete; ready to plan next phase
Last activity: 2026-05-12 - UNIFY 116-01 complete and transition done
Phase: 117 of TBD (SMSPLANET Integration Settings + Test SMS) - Complete
Plan: 117-01 unified
Status: Phase 117 complete; migration/manual SMS test pending because local DB is unavailable
Last activity: 2026-05-12 - Unified SMSPLANET settings/test integration
Progress:
- Milestone v3.7: [########--] ~75% (Phase 113 + 114 + 115 + 116 closed)
- Phase 116: [##########] 100% - Complete
- Milestone v3.7: [########--] ~80% (Phase 113 + 114 + 115 + 116 + 117 closed; environment verification gaps documented)
- Phase 117: [##########] 100% - Implementation unified; migration/live SMS verification pending externally
## Loop Position
Current loop state:
```
PLAN -> APPLY -> UNIFY
done done done [Loop complete - ready for next PLAN]
done done done [Phase 117 closed with environment gaps documented]
```
## Session Continuity
Last session: 2026-05-12
Stopped at: Phase 116 complete, ready to plan next phase
Next action: $paul-plan for next v3.7 candidate or next milestone
Resume file: .paul/phases/116-hostedsms-integration/116-01-SUMMARY.md
Stopped at: Phase 117 unified; local migration/manual SMS verification pending
Next action: Start local MySQL, run `C:\xampp\php\php.exe bin\migrate.php`, verify SMSPLANET settings/test SMS, then plan the next v3.7 candidate or close the milestone.
Resume file: .paul/phases/117-smsplanet-integration/117-01-SUMMARY.md
## Git State
Last phase commit: bc2ed2c feat(116): hostedsms integration settings
Last phase commit: feat(117): smsplanet integration settings
Branch: main
## Pending Actions
@@ -46,6 +46,7 @@ Branch: main
- Uruchom migracje gdy XAMPP online: `php bin/migrate.php` (delivery_statuses).
- Recznie odtworzyc istniejace reguly automatyzacji z grupowymi kluczami (BREAKING z 108-02).
- HostedSMS inbound replies: requires DCS/HostedSMS activation before implementation.
- Phase 117 follow-up: run migration when XAMPP MySQL is online and manually test real SMSPLANET sends for Bearer token and key + password.
## Deferred to Next Milestones
@@ -56,4 +57,4 @@ Branch: main
## Skill Requirements
- `sonar-scanner` required after APPLY; Phase 116 gap documented because CLI was not available in PATH.
- `sonar-scanner` required after APPLY; Phase 116 and Phase 117 gaps documented because CLI was not available in PATH.

View File

@@ -7,6 +7,10 @@
- Poprawiono prezentacje ostatniego testu HostedSMS: status, HTTP i osobny identyfikator wiadomosci.
- Potwierdzono test na zywo: `2026-05-12 12:03:22 OK HTTP 200`, MessageId `d935d71a-d9a0-4cfb-be06-03fe36c71150`.
- Odnotowano przyszly zakres: odbior odpowiedzi SMS wymaga aktywacji interfejsu po stronie DCS/HostedSMS.
- [Phase 117, Plan 01] Dodano integracje SMSPLANET: globalne ustawienia konta, dwie metody autoryzacji, szyfrowane sekrety, karta w hubie integracji i realna wysylka testowego SMS.
- Dodano klienta SMSPLANET (`POST https://api2.smsplanet.pl/sms`) z obsluga Bearer token oraz `key` + `password`, bez parametru `test=1` dla testow realnych.
- Poprawiono uklad checkboxow i radio buttonow na ekranie integracji SMSPLANET przez wspolny komponent SCSS.
- Odnotowano blokery weryfikacji: lokalny MySQL odmawial polaczenia, `vendor\bin\phpunit` i `sonar-scanner` nie byly dostepne.
## Zmienione pliki
@@ -18,14 +22,23 @@
- `.paul/codebase/tech_changelog.md`
- `.paul/phases/116-hostedsms-integration/116-01-PLAN.md`
- `.paul/phases/116-hostedsms-integration/116-01-SUMMARY.md`
- `.paul/phases/117-smsplanet-integration/117-01-PLAN.md`
- `.paul/phases/117-smsplanet-integration/117-01-SUMMARY.md`
- `DOCS/ARCHITECTURE.md`
- `DOCS/DB_SCHEMA.md`
- `DOCS/TECH_CHANGELOG.md`
- `database/migrations/20260512_000107_create_hostedsms_integration_settings.sql`
- `database/migrations/20260512_000108_create_smsplanet_integration_settings.sql`
- `resources/lang/pl.php`
- `resources/scss/app.scss`
- `resources/views/settings/hostedsms.php`
- `resources/views/settings/smsplanet.php`
- `routes/web.php`
- `src/Modules/Settings/HostedSmsApiClient.php`
- `src/Modules/Settings/HostedSmsIntegrationController.php`
- `src/Modules/Settings/HostedSmsIntegrationRepository.php`
- `src/Modules/Settings/IntegrationSecretCipher.php`
- `src/Modules/Settings/IntegrationsHubController.php`
- `src/Modules/Settings/SmsplanetApiClient.php`
- `src/Modules/Settings/SmsplanetIntegrationController.php`
- `src/Modules/Settings/SmsplanetIntegrationRepository.php`

View File

@@ -281,6 +281,27 @@ tests/
### IntegrationsHubController
- Dodaje wiersz HostedSMS do `/settings/integrations` ze statusem konfiguracji, sekretu, aktywnosci i ostatniego testu.
## Phase 117 - SMSPLANET Integration Settings
### SmsplanetIntegrationRepository (`src/Modules/Settings/SmsplanetIntegrationRepository.php`)
- 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.
### SmsplanetApiClient (`src/Modules/Settings/SmsplanetApiClient.php`)
- Wykonuje `POST https://api2.smsplanet.pl/sms` jako `application/x-www-form-urlencoded`.
- Dla Bearer token wysyla naglowek `Authorization: Bearer ...`; dla `key_password` wysyla parametry `key` i `password`.
- Wysyla `from`, `to`, `msg` oraz opcjonalnie `clear_polish` i `transactional`; test nie ustawia `test=1`, wiec wysyla realny SMS.
- Traktuje `messageId` jako sukces, a `errorMsg`/`errorCode` jako blad biznesowy.
### 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_*`.
### IntegrationsHubController
- Dodaje wiersz SMSPLANET do `/settings/integrations` ze statusem konfiguracji, sekretu, aktywnosci i ostatniego testu.
## Phase 114 — Accounting Configs Refactor
### Sekcja Ksiegowosc — struktura URL

View File

@@ -1,6 +1,6 @@
# Database Schema
**Updated:** 2026-05-10 | **Total tables:** 59 | **Engine:** InnoDB | **Charset:** utf8mb4_unicode_ci
**Updated:** 2026-05-12 | **Total tables:** 60 | **Engine:** InnoDB | **Charset:** utf8mb4_unicode_ci
---
@@ -591,6 +591,25 @@ UNIQUE: `(integration_id)` - one global HostedSMS settings row.
---
**smsplanet_integration_settings** - SMSPLANET account credentials (Phase 117; fixed 1 row)
| Column | Type | Nullable | Notes |
|--------|------|----------|-------|
| `id` | TINYINT UNSIGNED | NO | PK, always 1 |
| `integration_id` | INT UNSIGNED | YES | UNIQUE, FK -> integrations(id) CASCADE |
| `auth_method` | VARCHAR(32) | NO | `token` or `key_password`, DEFAULT `token` |
| `api_token_encrypted` | TEXT | YES | AES-encrypted Bearer token via `IntegrationSecretCipher` |
| `api_key_encrypted` | TEXT | YES | AES-encrypted API key via `IntegrationSecretCipher` |
| `api_password_encrypted` | TEXT | YES | AES-encrypted API password via `IntegrationSecretCipher` |
| `sender` | VARCHAR(32) | YES | SMSPLANET `from` sender |
| `clear_polish` | TINYINT(1) | NO | DEFAULT 0 |
| `transactional` | TINYINT(1) | NO | DEFAULT 0 |
| `created_at` | DATETIME | NO | |
| `updated_at` | DATETIME | NO | |
UNIQUE: `(integration_id)` - one global SMSPLANET settings row.
---
## Accounting / Receipts
**receipt_configs** — Receipt generation configurations

View File

@@ -1,5 +1,21 @@
# Technical Changelog
## 2026-05-12 - Phase 117 Plan 01: SMSPLANET Integration Settings + Test SMS
**Co zrobiono:**
- Dodano migracje `20260512_000108_create_smsplanet_integration_settings.sql` z pojedyncza konfiguracja `smsplanet_integration_settings` i bazowym wpisem `integrations` typu `smsplanet`.
- Dodano `SmsplanetIntegrationRepository` z obsluga metod autoryzacji `token` oraz `key_password` i szyfrowaniem sekretow przez `IntegrationSecretCipher`.
- Dodano `SmsplanetApiClient` dla SMSPLANET (`POST https://api2.smsplanet.pl/sms`) z obsluga Bearer token oraz `key` + `password`.
- Dodano `SmsplanetIntegrationController` i trasy `/settings/integrations/smsplanet`, `/save`, `/test`.
- Dodano widok `resources/views/settings/smsplanet.php` z konfiguracja i realna wysylka testowego SMS z edytowalna trescia oraz panelem ostatniego testu (`OK`, HTTP, `messageId`).
- Dodano SMSPLANET do hubu integracji `/settings/integrations`.
- Poprawiono import `IntegrationSecretCipher`, aby rzucal istniejacy `App\Core\Exceptions\IntegrationConfigException`.
**Dlaczego:**
- Operator potrzebuje drugiej bramki SMS analogicznej do HostedSMS, ale bez uruchamiania jeszcze automatyzacji lub historii wysylek.
- SMSPLANET wspiera dwa warianty autoryzacji, wiec konfiguracja przechowuje wszystkie sekrety w formie szyfrowanej i waliduje wymagania zalezne od wyboru operatora.
- Test uzywa rzeczywistej wysylki, bo celem tej fazy jest potwierdzenie realnej sciezki API.
## 2026-05-12 - Phase 116 Plan 01: HostedSMS Integration Settings + Test SMS
**Co zrobiono:**

View File

@@ -0,0 +1,230 @@
---
phase: 117-smsplanet-integration
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- database/migrations/20260512_000108_create_smsplanet_integration_settings.sql
- src/Modules/Settings/SmsplanetApiClient.php
- src/Modules/Settings/SmsplanetIntegrationRepository.php
- src/Modules/Settings/SmsplanetIntegrationController.php
- src/Modules/Settings/IntegrationsHubController.php
- routes/web.php
- resources/views/settings/smsplanet.php
- resources/lang/pl.php
- DOCS/DB_SCHEMA.md
- DOCS/ARCHITECTURE.md
- DOCS/TECH_CHANGELOG.md
- .paul/codebase/db_schema.md
- .paul/codebase/architecture.md
- .paul/codebase/tech_changelog.md
autonomous: true
delegation: auto
---
<objective>
## Goal
Dodac pierwsza wersje integracji SMSPLANET: jedna globalna konfiguracja konta oraz formularz realnej wysylki testowego SMS-a.
## Purpose
Operator ma moc porownac i zweryfikowac druga bramke SMS bez naruszania istniejacej integracji HostedSMS ani dodawania jeszcze automatyzacji SMS.
## Output
Nowa podstrona `/settings/integrations/smsplanet`, zapis konfiguracji w DB, klient API SMSPLANET, akcja testowej wysylki SMS i wpis w hubie integracji.
</objective>
<context>
<clarifications>
- **Zakres** - Czy SMSPLANET ma w tej fazie dostac tylko ekran konfiguracji i realny test SMS, analogicznie do HostedSMS?
-> Odpowiedz: Na razie tylko konfiguracja + test.
- **Autoryzacja** - Ktory sposob autoryzacji SMSPLANET przyjmujemy jako podstawowy w UI?
-> Odpowiedz: Obie wersje, czyli Bearer token oraz key + password.
- **Konto** - Czy SMSPLANET ma byc jedna globalna konfiguracja tak jak HostedSMS?
-> Odpowiedz: Jedna.
- **Test** - Czy test SMSPLANET ma realnie wysylac SMS, czy uzywac parametru `test=1` z API SMSPLANET?
-> Odpowiedz: Realnie.
</clarifications>
## Project Context
@.paul/PROJECT.md
@.paul/ROADMAP.md
@.paul/STATE.md
@AGENTS.md
@DOCS/DB_SCHEMA.md
@DOCS/ARCHITECTURE.md
## API Context
SMSPLANET API docs: `https://smsplanet.pl/doc/slate/index.html#introduction`
- API version documented as `2.3.0`, UTF-8, `POST` content type `application/x-www-form-urlencoded`.
- Recommended SMS endpoint: `POST https://api2.smsplanet.pl/sms`.
- Recommended authorization: `Authorization: Bearer <token>`.
- Alternative authorization: request params `key` and `password`.
- Required send params: `from`, `to`, `msg`.
- Optional params useful for first version: `clear_polish` (`0`/`1`), `transactional` (`0`/`1`), `test` (`0`/`1`). This plan uses real SMS, so do not set `test=1` in the test action.
- Success response contains `messageId`; business failure contains `errorMsg` and `errorCode`.
- Accepted recipient formats include `600111222`, `48600111222`, `+48600111222`; normalize only whitespace/separators, do not force country prefix beyond validation.
## Prior Work
@.paul/phases/116-hostedsms-integration/116-01-SUMMARY.md
@.paul/phases/116-hostedsms-integration/116-01-PLAN.md
## Source Files
@routes/web.php
@src/Modules/Settings/HostedSmsApiClient.php
@src/Modules/Settings/HostedSmsIntegrationRepository.php
@src/Modules/Settings/HostedSmsIntegrationController.php
@src/Modules/Settings/IntegrationsRepository.php
@src/Modules/Settings/IntegrationSecretCipher.php
@src/Modules/Settings/IntegrationsHubController.php
@resources/views/settings/hostedsms.php
@resources/views/settings/integrations.php
@resources/lang/pl.php
</context>
<skills>
## Required Skills (from SPECIAL-FLOWS.md)
| Skill | Priority | When to Invoke | Loaded? |
|-------|----------|----------------|---------|
| sonar-scanner | required | Po APPLY, przed UNIFY | o |
## Skill Invocation Checklist
- [ ] Uruchomic `sonar-scanner` po implementacji, jezeli CLI i SonarQube sa dostepne.
</skills>
<acceptance_criteria>
## AC-1: Zapis konfiguracji SMSPLANET
```gherkin
Given zalogowany operator jest na stronie ustawien SMSPLANET
When wybierze metode autoryzacji, uzupelni wymagane pola, nadpis nadawcy, opcje wysylki i zapisze formularz z poprawnym CSRF
Then konfiguracja zostanie zapisana jako jedna globalna integracja, sekrety beda zaszyfrowane przez IntegrationSecretCipher, a zapisane sekrety nie beda widoczne w formularzu
```
## AC-2: Dwie metody autoryzacji
```gherkin
Given operator konfiguruje SMSPLANET
When wybierze Bearer token
Then aplikacja wymaga tokenu przy pierwszym zapisie i wysyla test z naglowkiem Authorization Bearer
And gdy wybierze key + password, aplikacja wymaga obu sekretow przy pierwszym zapisie i wysyla test z parametrami key/password
```
## AC-3: Walidacja konfiguracji i testu
```gherkin
Given operator probuje zapisac lub testowac SMSPLANET
When brakuje pol wymaganych dla wybranej metody autoryzacji, brakuje nadpisu albo numer/tresc testu sa niepoprawne
Then aplikacja pokazuje czytelny blad i nie wykonuje wysylki testowej bez kompletnych danych
```
## AC-4: Realny test wysylki SMSPLANET
```gherkin
Given konfiguracja SMSPLANET jest zapisana z poprawnymi danymi
When operator poda numer testowy i tresc testowa oraz kliknie wysylke testowa
Then aplikacja wykona realny POST do SMSPLANET bez parametru test=1, zapisze wynik w polach last_test_* integracji i pokaze messageId albo errorMsg/errorCode z API
```
## AC-5: Widocznosc w panelu integracji
```gherkin
Given operator otwiera Ustawienia > Integracje
When integracja SMSPLANET istnieje albo jeszcze nie jest skonfigurowana
Then hub pokazuje wiersz SMSPLANET ze statusem konfiguracji, sekretu, aktywnosci, ostatniego testu i linkiem do ustawien
```
## AC-6: Dokumentacja i zgodnosc projektu
```gherkin
Given funkcja zostala wdrozona
When sprawdzane sa dokumenty techniczne i testy
Then DOCS oraz .paul/codebase opisuja nowa tabele, klasy, endpointy i przeplyw, a testy/lint nie wykazuja regresji
```
</acceptance_criteria>
<tasks>
<task type="auto">
<name>Task 1: Dodac model konfiguracji SMSPLANET</name>
<files>database/migrations/20260512_000108_create_smsplanet_integration_settings.sql, src/Modules/Settings/SmsplanetIntegrationRepository.php</files>
<action>
Utworz migracje dla pojedynczej tabeli `smsplanet_integration_settings` z rekordem `id=1`, `integration_id` jako UNIQUE FK do `integrations`, polami `auth_method`, `api_token_encrypted`, `api_key`, `api_password_encrypted`, `sender`, `clear_polish`, `transactional`, `created_at`, `updated_at`.
Seeduj bazowy rekord `integrations` typu `smsplanet`, nazwa `SMSPLANET`, base_url `https://api2.smsplanet.pl/sms`, timeout 15, aktywny.
Repozytorium ma zapewniac bazowy rekord i settings row, zwracac flagi `has_api_token` oraz `has_api_password`, nigdy nie zwracac sekretow w `getSettings()`, zapisywac nowe sekrety tylko gdy pola formularza nie sa puste, wymagac odpowiednich sekretow przy pierwszym zapisie i uzywac `IntegrationSecretCipher` oraz prepared statements.
`getCredentials()` ma zwracac tylko kompletna, aktywna konfiguracje z odszyfrowanymi sekretami dla wybranej metody autoryzacji.
</action>
<verify>C:\xampp\php\php.exe -l src/Modules/Settings/SmsplanetIntegrationRepository.php</verify>
<done>AC-1, AC-2 i AC-3 spelnione dla warstwy zapisu konfiguracji.</done>
</task>
<task type="auto">
<name>Task 2: Dodac klienta API i kontroler ustawien</name>
<files>src/Modules/Settings/SmsplanetApiClient.php, src/Modules/Settings/SmsplanetIntegrationController.php, routes/web.php</files>
<action>
Utworz `SmsplanetApiClient` wykonujacy POST form-urlencoded do `https://api2.smsplanet.pl/sms` z `Accept: application/json`, SSL verification, CA z `SslCertificateResolver`, `User-Agent: orderPRO/1.0` i bez `curl_close()`.
Klient ma obslugiwac dwie metody autoryzacji: dla `token` dodaje naglowek `Authorization: Bearer ...`; dla `key_password` dodaje do payloadu `key` i `password`.
Payload testu zawiera `from`, `to`, `msg`, opcjonalnie `clear_polish=1` i `transactional=1`; test realny nie ustawia `test=1`.
Parsuj odpowiedz JSON: `messageId` przy HTTP 2xx oznacza sukces; `errorMsg`/`errorCode` to blad biznesowy; niepoprawny JSON, cURL i HTTP bez messageId maja dac czytelny komunikat.
Utworz `SmsplanetIntegrationController` z akcjami `index`, `save`, `test`. `save` waliduje CSRF i przekazuje payload do repozytorium. `test` waliduje CSRF, numer telefonu po usunieciu spacji, plusa, myslnikow i nawiasow (`^\d{8,15}$`), tresc niepusta i maks. 918 znakow (6 SMS po 153 znaki dla bezpiecznego limitu pierwszej wersji), pobiera credentials i zapisuje `last_test_status`, `last_test_http_code`, `last_test_message` przez `IntegrationsRepository::updateTestResult`.
Podlacz DI i trasy: GET `/settings/integrations/smsplanet`, POST `/settings/integrations/smsplanet/save`, POST `/settings/integrations/smsplanet/test`.
</action>
<verify>C:\xampp\php\php.exe -l src/Modules/Settings/SmsplanetApiClient.php; C:\xampp\php\php.exe -l src/Modules/Settings/SmsplanetIntegrationController.php; C:\xampp\php\php.exe -l routes/web.php</verify>
<done>AC-2, AC-3 i AC-4 spelnione dla backendu oraz realnej wysylki testowej.</done>
</task>
<task type="auto">
<name>Task 3: Dodac UI, hub integracji i dokumentacje</name>
<files>resources/views/settings/smsplanet.php, resources/lang/pl.php, src/Modules/Settings/IntegrationsHubController.php, DOCS/DB_SCHEMA.md, DOCS/ARCHITECTURE.md, DOCS/TECH_CHANGELOG.md, .paul/codebase/db_schema.md, .paul/codebase/architecture.md, .paul/codebase/tech_changelog.md</files>
<action>
Dodaj kompaktowy widok ustawien SMSPLANET wzorowany na HostedSMS, bez inline CSS. Formularz konfiguracji ma pokazac: wybor metody autoryzacji (`token` / `key_password`), token Bearer, key, password, sender (`from`), checkbox `clear_polish`, checkbox `transactional`, aktywnosc.
Zastosuj proste progressive enhancement tylko jesli potrzebne: pola niewybranej metody moga pozostac widoczne z opisem, ale walidacja serwerowa decyduje o wymaganiach. Nie dodawaj nowego natywnego `alert()`/`confirm()`.
Sekcja testu ma miec numer telefonu i edytowalna tresc z domyslna wartoscia `Test orderPRO SMSPLANET`.
Ostatni test pokazuje status, HTTP, `messageId` albo komunikat `errorCode: errorMsg`.
Dodaj SMSPLANET do hubu integracji oraz tlumaczenia PL.
Zaktualizuj dokumentacje techniczna: tabela `smsplanet_integration_settings`, nowe klasy, trasy, dwie metody autoryzacji i przeplyw testowej wysylki.
</action>
<verify>C:\xampp\php\php.exe -l resources/views/settings/smsplanet.php; C:\xampp\php\php.exe -l src/Modules/Settings/IntegrationsHubController.php; npm run build --if-present</verify>
<done>AC-5 i AC-6 spelnione dla UI, hubu i dokumentacji.</done>
</task>
</tasks>
<boundaries>
## DO NOT CHANGE
- Nie podpinac `DB_HOST_REMOTE` do runtime aplikacji.
- Nie modyfikowac zachowania HostedSMS poza ewentualnym wspoldzielonym wzorcem tylko wtedy, gdy jest to absolutnie potrzebne.
- Nie dodawac automatyzacji SMS, szablonow SMS, wysylki z zamowien ani historii wyslanych SMS w tym planie.
- Nie dodawac natywnych `alert()` / `confirm()`.
- Nie refaktoryzowac istniejacych integracji poza minimalnym dopieciem SMSPLANET do hubu i routes.
## SCOPE LIMITS
- Tylko jedna globalna konfiguracja SMSPLANET.
- Tylko realna wysylka testowa SMS z ustawien.
- Obslugiwane metody auth w pierwszej wersji: Bearer token oraz key + password.
- Bez raportow doreczen, webhookow, sender-field management, czarnej listy, link shortenera, sprawdzania salda i odbierania SMS.
- Bez parametryzowanych kampanii masowych; test wysyla pojedynczy SMS do jednego numeru.
</boundaries>
<verification>
Before declaring plan complete:
- [ ] `C:\xampp\php\php.exe bin/migrate.php`
- [ ] `C:\xampp\php\php.exe -l` dla nowych/zmienionych plikow PHP
- [ ] `npm run build --if-present`
- [ ] Manualnie: zapis konfiguracji SMSPLANET dla Bearer token, realna wysylka testowego SMS, komunikat z `messageId`
- [ ] Manualnie lub kodowo: walidacja `key_password` wymaga key+password i buduje payload z tymi parametrami
- [ ] `sonar-scanner` po APPLY, jezeli CLI i SonarQube sa dostepne
- [ ] DOCS i `.paul/codebase` zaktualizowane
- [ ] All acceptance criteria met
</verification>
<success_criteria>
- Operator moze zapisac jedna konfiguracje SMSPLANET bez ujawniania sekretow.
- Operator moze wybrac Bearer token albo key + password i walidacja odpowiada wybranej metodzie.
- Operator moze wyslac realny testowy SMS z edytowalna trescia.
- Wynik testu jest widoczny w ekranie SMSPLANET i hubie integracji.
- Migracje, lint i build przechodza albo blokery srodowiskowe sa jasno opisane w SUMMARY.
</success_criteria>
<output>
After completion, create `.paul/phases/117-smsplanet-integration/117-01-SUMMARY.md`
</output>

View File

@@ -0,0 +1,71 @@
---
phase: 117-smsplanet-integration
plan: 01
completed: 2026-05-12
status: complete-with-environment-gaps
---
# Summary: SMSPLANET Integration Settings + Test SMS
## Result
Implemented the first SMSPLANET integration slice: one global configuration screen, encrypted credentials, support for Bearer token and key + password authorization, hub visibility, and a real test SMS flow using `POST https://api2.smsplanet.pl/sms`.
The implementation also fixes the integration settings checkbox/radio layout reported during UAT by moving the options into the existing compact SCSS component.
## Acceptance Criteria
| AC | Status | Notes |
|----|--------|-------|
| AC-1 Configuration save | PASS | `SmsplanetIntegrationRepository` stores one global row, encrypts token/key/password, and never returns secrets to the view. |
| AC-2 Two auth methods | PASS | Bearer token sends `Authorization: Bearer ...`; key + password sends credentials in form payload. First save requires complete credentials for the selected method. |
| AC-3 Validation | PASS | Save/test validate CSRF, sender, selected auth method, phone number and message length before API calls. |
| AC-4 Real test SMS | IMPLEMENTED, MANUAL PENDING | API client performs real send and does not set `test=1`. Manual live send is pending because local DB/migration verification was blocked. |
| AC-5 Hub visibility | PASS | `IntegrationsHubController` includes SMSPLANET with configuration, secret, active and last-test status. |
| AC-6 Docs/compliance | PASS WITH TOOLING GAPS | DOCS and `.paul/codebase` updated. PHP lint/build passed. Migration, PHPUnit and Sonar were blocked by local tooling/environment. |
## Verification
Passed:
- `C:\xampp\php\php.exe -l` for all new/modified PHP files in this phase.
- `npm run build --if-present`.
- `git diff --check`.
Blocked or unavailable:
- `C:\xampp\php\php.exe bin\migrate.php` failed because local MySQL refused the connection: `SQLSTATE[HY000] [2002]`.
- `vendor\bin\phpunit` was not available: `Could not open input file`.
- `sonar-scanner` was not available in PATH.
- Manual real SMSPLANET send remains pending until the migration is applied and valid SMSPLANET credentials are tested.
## Deviations
- `api_key` is stored as `api_key_encrypted` rather than plaintext. This is stricter than the draft task and consistent with the requirement that credentials are secrets.
- `IntegrationSecretCipher` had an invalid namespace import and was fixed because SMSPLANET and existing integrations depend on it at runtime.
- Checkbox/radio UI was adjusted in `resources/scss/app.scss` after the UAT screenshot showed inconsistent native control sizing/alignment.
## Files Changed
- `.paul/codebase/architecture.md`
- `.paul/codebase/db_schema.md`
- `.paul/codebase/tech_changelog.md`
- `.paul/phases/117-smsplanet-integration/117-01-PLAN.md`
- `.paul/phases/117-smsplanet-integration/117-01-SUMMARY.md`
- `DOCS/ARCHITECTURE.md`
- `DOCS/DB_SCHEMA.md`
- `DOCS/TECH_CHANGELOG.md`
- `database/migrations/20260512_000108_create_smsplanet_integration_settings.sql`
- `resources/lang/pl.php`
- `resources/scss/app.scss`
- `resources/views/settings/smsplanet.php`
- `routes/web.php`
- `src/Modules/Settings/IntegrationSecretCipher.php`
- `src/Modules/Settings/IntegrationsHubController.php`
- `src/Modules/Settings/SmsplanetApiClient.php`
- `src/Modules/Settings/SmsplanetIntegrationController.php`
- `src/Modules/Settings/SmsplanetIntegrationRepository.php`
## Follow-Up
- Start local MySQL/XAMPP and run `C:\xampp\php\php.exe bin\migrate.php`.
- Save real SMSPLANET credentials and run both manual test paths: Bearer token and key + password.
- Run Sonar once `sonar-scanner` is available.