feat(113): fakturownia integration foundation

Phase 113 complete (v3.7 Invoices):
- DB: invoices, invoice_configs, invoice_number_counters, fakturownia_integration_settings + orders.invoice_requested
- FakturowniaIntegrationRepository (multi-account via integrations.type='fakturownia')
- FakturowniaApiClient (testConnection; createInvoice/downloadPdf STUBs)
- IntegrationsRepository::updateTestResult() (reusable test-result writer)
- /settings/integrations/fakturownia (list + edit + test + delete)
- Karta Fakturownia w hubie /settings/integrations

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-10 22:11:55 +02:00
parent 322b23b7be
commit 2382018739
20 changed files with 1766 additions and 32 deletions

View File

@@ -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** | 54+ | Integration controllers, OAuth clients, API clients (Fakturownia incl.), mappers | Allegro/shopPRO/Apaczka/InPost/Fakturownia config, status mappings |
| **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 |
@@ -174,3 +174,32 @@ tests/
- `AutomationService::evaluateShipmentStatusCondition()` — bezpośrednie porównanie kluczy DB (usunięto mapping grupowy `SHIPMENT_STATUS_OPTION_MAP`)
- `AutomationService::resolveStatusFromActionKey()` — bezpośredni klucz statusu z DB jako target
- BREAKING: stare reguły z grupowymi kluczami (`registered`, `courier_pickup`, `dropped_at_point`, `unclaimed`, `picked_up_return`) nie matchują się — operator musi je odtworzyć przy użyciu nowych kluczy DB
## Phase 113 — Fakturownia Integration Foundation
### Schema (Plan 113-01)
- Tabele `invoice_configs`, `invoices`, `invoice_number_counters` (mirror `receipt_configs`/`receipts`/`receipt_number_counters` plus delegation fields: `invoice_configs.integration_id`, `is_delegated`; `invoices.external_invoice_id`, `external_pdf_url`).
- Tabela `fakturownia_integration_settings` (multi-account: `integration_id INT UNSIGNED NOT NULL UNIQUE` FK -> `integrations(id)`).
- `orders.invoice_requested TINYINT(1) NOT NULL DEFAULT 0` z indexem `idx_orders_invoice_requested`.
### FakturowniaIntegrationRepository (`src/Modules/Settings/FakturowniaIntegrationRepository.php`)
- `findAll()` JOIN `integrations` + `fakturownia_integration_settings` zwraca listę kont Fakturowni.
- `findByIntegrationId(int)` zwraca jedno konto (z resolved `api_token_encrypted` z `integrations.api_key_encrypted` z fallbackiem na settings).
- `save(?int $integrationId, array $payload)` - upsert (insert do `integrations` przez `IntegrationsRepository::ensureIntegration` gdy `$integrationId=null`; w przeciwnym razie update name/is_active). Token szyfrowany przez `IntegrationSecretCipher` i zapisywany do `integrations.api_key_encrypted` (źródło prawdy) oraz settings.api_token_encrypted (cache).
- `delete(int $integrationId)` — blokuje usunięcie gdy `invoice_configs.integration_id = X` (FK SET NULL chroniony aplikacyjnie przez `IntegrationConfigException`).
- `getDecryptedToken(int $integrationId)` — dla użycia w przyszłych planach (createInvoice/downloadPdf).
### FakturowniaApiClient (`src/Modules/Settings/FakturowniaApiClient.php`)
- `testConnection(string $prefix, string $apiToken): array` — GET `https://{prefix}.fakturownia.pl/account.json?api_token=...` z cURL + `SslCertificateResolver::resolve()`. Zwraca `['ok' => bool, 'http_code' => int, 'message' => string]`.
- `createInvoice()` i `downloadPdf()` — STUB-y rzucające `RuntimeException` do implementacji w kolejnym planie.
### IntegrationsRepository::updateTestResult()
- Nowa metoda zapisująca `last_test_status / last_test_http_code / last_test_message / last_test_at` po wywołaniu API test. Używana przez `FakturowniaIntegrationController::test()` (i będzie reuse'owana w przyszłych integracjach).
### FakturowniaIntegrationController (`src/Modules/Settings/FakturowniaIntegrationController.php`)
- Routy `/settings/integrations/fakturownia` (lista), `.../edit`, `.../save`, `.../test`, `.../delete` (POST z `_token` CSRF).
- Wykorzystuje `Flash::set('fakturownia.save'|'fakturownia.test'|'fakturownia.error')` i `RedirectPathResolver`.
### IntegrationsHubController
- Nowy parametr konstruktora `FakturowniaIntegrationRepository $fakturownia` i nowa metoda `buildFakturowniaRow()` agregująca status wszystkich kont (count instancji, configured/active counts, ostatni test).