---
phase: 113-fakturownia-integration
plan: 01
subsystem: integrations
tags: [fakturownia, invoices, settings, integration, api, encryption]

requires:
  - phase: 08-receipts-foundation
    provides: receipt_configs/receipts/receipt_number_counters schema patterns mirrored for invoices
  - phase: 35-inpost-settings
    provides: IntegrationsRepository + IntegrationSecretCipher patterns

provides:
  - DB: invoices, invoice_configs, invoice_number_counters, fakturownia_integration_settings, orders.invoice_requested
  - FakturowniaIntegrationRepository (multi-account CRUD)
  - FakturowniaApiClient (testConnection + STUBs for createInvoice/downloadPdf)
  - IntegrationsRepository::updateTestResult() (reusable test-result writer)
  - /settings/integrations/fakturownia (list + edit + test + delete UI)
  - Fakturownia card in integrations hub

affects: [114-invoice-configs, 115-invoice-issuance, 116-invoice-list, importers Allegro/shopPRO (invoice_requested flag)]

tech-stack:
  added: [Fakturownia REST API (app.fakturownia.pl)]
  patterns:
    - "Multi-account integration via integrations.type='fakturownia' + dedicated settings table with UNIQUE integration_id"
    - "Local snapshot pattern reused: seller/buyer/items as JSON in invoices (mirroring receipts)"
    - "is_delegated flag in invoice_configs - local-vs-API generation toggle"

key-files:
  created:
    - database/migrations/20260510_000104_create_invoices_tables.sql
    - database/migrations/20260510_000105_add_invoice_requested_to_orders.sql
    - database/migrations/20260510_000106_seed_fakturownia_integration_type.sql
    - src/Modules/Settings/FakturowniaIntegrationRepository.php
    - src/Modules/Settings/FakturowniaApiClient.php
    - src/Modules/Settings/FakturowniaIntegrationController.php
    - resources/views/settings/fakturownia.php
    - resources/views/settings/fakturownia-edit.php
  modified:
    - src/Modules/Settings/IntegrationsHubController.php
    - src/Modules/Settings/IntegrationsRepository.php
    - routes/web.php
    - .paul/codebase/db_schema.md
    - .paul/codebase/architecture.md
    - .paul/codebase/tech_changelog.md

key-decisions:
  - "Multi-account przez integrations.type='fakturownia' (zamiast singletona jak InPost/Apaczka) - spojnosc z shopPRO + przyszla obsluga wielu marek/oddzialow"
  - "is_delegated flag w invoice_configs - default lokalna numeracja+PDF, opcjonalnie delegacja do Fakturowni"
  - "Brak osobnego eventu invoice.created - receipt.created pozostaje wylacznie dla paragonow (zero ryzyka cross-matching regul automatyzacji)"
  - "orders.invoice_requested z importera + manual override (UI checkbox w kolejnym planie)"
  - "Migracja 106 jako DDL no-op (ALTER TABLE COMMENT) zamiast SELECT 1 - SELECT zwraca result set i blokuje kolejne zapytania pod PDO unbuffered"

patterns-established:
  - "Token API szyfrowany przez IntegrationSecretCipher; integrations.api_key_encrypted = zrodlo prawdy, settings.api_token_encrypted = cache"
  - "ApiClient::testConnection() zwraca array ['ok', 'http_code', 'message']; controller mapuje na IntegrationsRepository::updateTestResult()"
  - "Widoki list integracji: section.card + table-wrap + table.table + badge.badge--{success,muted,info}; usun przez js-confirm-delete + js-delete-btn (window.OrderProAlerts)"
  - "STUB-y metod API rzucaja RuntimeException z czytelnym komunikatem 'Not implemented in Phase X' zamiast cichego no-op"

duration: 90min
started: 2026-05-10T19:00:00Z
completed: 2026-05-10T20:30:00Z
---

# Phase 113 Plan 01: Fakturownia Integration Foundation Summary

**Fundament v3.7 Invoices gotowy: schema DB (4 tabele + kolumna `orders.invoice_requested`), CRUD kont Fakturowni z testem polaczenia API i kartą w hubie integracji. Numeracja lokalna z opcja delegacji do Fakturowni (flag `is_delegated` w `invoice_configs`).**

## Performance

| Metric | Value |
|--------|-------|
| Duration | ~90min |
| Started | 2026-05-10T19:00:00Z |
| Completed | 2026-05-10T20:30:00Z |
| Tasks | 3 completed (auto, inline) |
| Files created | 8 |
| Files modified | 6 |

## Acceptance Criteria Results

| Criterion | Status | Notes |
|-----------|--------|-------|
| AC-1: Schema DB dla faktur i Fakturowni | Pass | 4 nowe tabele + `orders.invoice_requested`, FK + UNIQUE wlasciwe. Migracje przeszly po naprawie `AFTER notes` (kolumna nie istnieje w `orders`) i zamianie `SELECT 1;` na `ALTER TABLE ... COMMENT` w migracji 106. |
| AC-2: Repozytorium i klient API Fakturowni | Pass | `FakturowniaIntegrationRepository::save()` szyfruje token przez `IntegrationSecretCipher` przed zapisem. `FakturowniaApiClient::testConnection()` wykonuje GET `account.json` z cURL + SslCertificateResolver. `IntegrationsRepository::updateTestResult()` (nowa metoda) zapisuje wynik testu. |
| AC-3: UI ustawien integracji Fakturownia | Pass | Lista `/settings/integrations/fakturownia` + edycja `/edit` + nowy `/new` + test + delete; CSRF `_token`; flash `fakturownia.save/.test/.error`; karta w hubie `/settings/integrations` z agregowanym statusem. Po pierwszej iteracji widok przepisany w stylu istniejacych list (`table.table` + `table-wrap` + `badge`). |

## Accomplishments

- Schema DB v3.7 Invoices gotowe: `invoices/invoice_configs/invoice_number_counters/fakturownia_integration_settings` plus `orders.invoice_requested` (multi-account przez `integrations.type='fakturownia'`).
- Pelen flow CRUD kont Fakturowni z szyfrowanym tokenem API i testem polaczenia (GET `account.json`) - operator moze dodawac/edytowac/usuwac konta i weryfikowac credentialsy bez restartu aplikacji.
- `IntegrationsRepository::updateTestResult()` jako reusable wzorzec dla przyszlych integracji (eliminuje inline UPDATE w kazdym controllerze).
- Dokumentacja techniczna zaktualizowana: `db_schema.md` (total tables 55 -> 59), `architecture.md` (sekcja Phase 113), `tech_changelog.md` (wpis 2026-05-10).

## Task Commits

Inline execution (delegation: off) - bez atomowych commits per task. Calosc do jednego git commit:

| Task | Status | Type | Description |
|------|--------|------|-------------|
| Task 1: Migracje DB | Done | feat | 3 migracje SQL + db_schema.md (4 nowe tabele, kolumna `orders.invoice_requested`) |
| Task 2: Repository + ApiClient + updateTestResult | Done | feat | FakturowniaIntegrationRepository, FakturowniaApiClient, IntegrationsRepository::updateTestResult, architecture.md |
| Task 3: Controller + views + routes + hub | Done | feat | FakturowniaIntegrationController, 2 widoki, 6 routes, hub card, tech_changelog.md |

## Files Created/Modified

| File | Change | Purpose |
|------|--------|---------|
| `database/migrations/20260510_000104_create_invoices_tables.sql` | Created | 4 tabele v3.7 Invoices |
| `database/migrations/20260510_000105_add_invoice_requested_to_orders.sql` | Created | Kolumna `orders.invoice_requested` + index |
| `database/migrations/20260510_000106_seed_fakturownia_integration_type.sql` | Created | DDL no-op stamp dla type='fakturownia' |
| `src/Modules/Settings/FakturowniaIntegrationRepository.php` | Created | CRUD kont Fakturowni (multi-account) |
| `src/Modules/Settings/FakturowniaApiClient.php` | Created | testConnection + STUB createInvoice/downloadPdf |
| `src/Modules/Settings/FakturowniaIntegrationController.php` | Created | Index/edit/save/test/delete |
| `resources/views/settings/fakturownia.php` | Created | Lista integracji (table.table + badge) |
| `resources/views/settings/fakturownia-edit.php` | Created | Form edycji integracji |
| `src/Modules/Settings/IntegrationsHubController.php` | Modified | Nowy param konstruktora + buildFakturowniaRow() |
| `src/Modules/Settings/IntegrationsRepository.php` | Modified | Nowa metoda updateTestResult() |
| `routes/web.php` | Modified | 3 use'y + DI wiring + 6 routes |
| `.paul/codebase/db_schema.md` | Modified | Sekcja Invoices + fakturownia_integration_settings + orders.invoice_requested |
| `.paul/codebase/architecture.md` | Modified | Sekcja Phase 113 + reorg Phase 108 + Module Inventory bump |
| `.paul/codebase/tech_changelog.md` | Modified | Wpis 2026-05-10 |

## Decisions Made

| Decision | Rationale | Impact |
|----------|-----------|--------|
| Multi-account przez `integrations.type='fakturownia'` (nie singleton) | Klient moze miec wiele kont Fakturowni (rozne marki/oddzialy); spojne z shopPRO | `FakturowniaIntegrationRepository::findAll()` zwraca liste; hub agreguje status; `invoice_configs.integration_id` wskazuje konkretne konto |
| `is_delegated` flag w `invoice_configs` (zamiast osobnej tabeli `invoice_delegations`) | Jeden config = jeden tryb (lokalny vs delegowany); operator wybiera per config | Kolejny plan: w `InvoiceService::generate()` rozgalez logike po `config.is_delegated` |
| Brak eventu `invoice.created` (decyzja z clarifications) | `receipt.created` pozostaje czysty - regula wysylki paragonu mailem nie zostanie odpalona dla faktury | Bezpieczenstwo automatyzacji; mozliwe rozszerzenie w przyszlosci jako osobny plan |
| Migracja 106 jako `ALTER TABLE ... COMMENT` (nie SELECT 1) | `SELECT 1;` zwraca result set i blokuje kolejne zapytania pod PDO unbuffered (`SQLSTATE[HY000] 2014`) | Wzorzec: migracje no-op zawsze jako DDL (ALTER COMMENT) - nie SELECT |
| `AFTER notes` usuniete z migracji 105 | Kolumna `notes` w `orders` nie istnieje (notatki w osobnej tabeli `order_notes`); db_schema.md byl stale | Naprawione + dodana adnotacja w db_schema.md |
| Widoki list - `table.table` + `table-wrap` + `badge.badge--*` (po feedbacku) | Spojnosc z `email-mailboxes.php`/`integrations.php`; brak inline styles strukturalnych | Wzorzec dla przyszlych list integracji |

## Deviations from Plan

### Summary

| Type | Count | Impact |
|------|-------|--------|
| Auto-fixed | 3 | Drobne, naprawione w czasie APPLY |
| Scope additions | 1 | Reusable helper (updateTestResult) - korzysc dla przyszlych integracji |
| Deferred | 0 | - |

**Total impact:** Bez scope creep. Trzy drobne fixy w czasie APPLY (kolumna `notes`, `SELECT 1`, styl widoku), wszystkie naprawione w jednym przebiegu.

### Auto-fixed Issues

**1. [Migration] Brak kolumny `notes` w `orders`**
- **Found during:** Task 1 verify (pierwsze uruchomienie `php bin/migrate.php`)
- **Issue:** Migracja 105 uzywala `ADD COLUMN ... AFTER notes`. Kolumna `notes` byla zadeklarowana w pierwotnej migracji 18, ale w nieznanym momencie zostala usunieta (notatki migrowane do `order_notes`). `db_schema.md` byl stale i pokazywal `notes` jako kolumne `orders`.
- **Fix:** Usunieto `AFTER notes` z migracji 105 (kolumna trafia na koniec tabeli). Zaktualizowano `db_schema.md` (usunieto wiersz `notes`, dodano notke "Order notes are stored in the separate `order_notes` table").
- **Files:** `database/migrations/20260510_000105_add_invoice_requested_to_orders.sql`, `.paul/codebase/db_schema.md`
- **Verification:** `php bin/migrate.php` po naprawie - migracja przeszla.

**2. [Migration] SELECT 1 w migracji 106 blokuje runner**
- **Found during:** Task 1 verify (drugie uruchomienie `php bin/migrate.php`)
- **Issue:** `SELECT 1;` zwraca result set ktory pozostawal otwarty przy PDO unbuffered queries -> `SQLSTATE[HY000] 2014: Cannot execute queries while other unbuffered queries are active`.
- **Fix:** Zastapiono `SELECT 1;` przez `ALTER TABLE integrations COMMENT = '...';` - bezpieczny DDL no-op ktory nie zwraca result setu i jest idempotentny.
- **Files:** `database/migrations/20260510_000106_seed_fakturownia_integration_type.sql`
- **Verification:** Migracja przeszla.

**3. [UI] Lista integracji Fakturownia z zlym stylem**
- **Found during:** User smoke test po wdrozeniu
- **Issue:** Pierwsza wersja widoku `fakturownia.php` uzywala `class="data-table"` (nie istniejace) i inline'owych stylow strukturalnych - tabela wygladala obco wzgledem reszty UI.
- **Fix:** Przepisano widok w stylu `email-mailboxes.php`: `section.card` + `table-wrap` + `table.table` + `badge.badge--{success,muted,info}` + przyciski usun przez `js-confirm-delete`/`js-delete-btn` (`window.OrderProAlerts`).
- **Files:** `resources/views/settings/fakturownia.php`
- **Verification:** User potwierdzil "Teraz jest ok".

### Scope Addition

**1. [Helper] `IntegrationsRepository::updateTestResult()`**
- **Context:** Plan zakladal "after teście `integrations.last_test_status/last_test_http_code/last_test_at` są zaktualizowane (przez `IntegrationsRepository::updateTestResult()`)" - ale metoda nie istniala w `IntegrationsRepository`.
- **Decision:** Dodano publiczna metode `updateTestResult(int $integrationId, string $status, ?int $httpCode, string $message)` zamiast inline'owego UPDATE w `FakturowniaIntegrationController::test()`.
- **Korzysc:** Reusable wzorzec dla przyszlych integracji (np. STAT-NET czy nowe API) - jeden punkt zapisu wynikow testow.

### Deferred Items

Brak. Plan wykonany w pelnym zakresie (z auto-fixami w czasie APPLY).

## Issues Encountered

| Issue | Resolution |
|-------|------------|
| MySQL/XAMPP offline przy pierwszym `php -l + bin/migrate.php` | Uruchomione po stronie usera; po naprawach 105/106 migracje przeszly. |
| Stary `notes` w `db_schema.md` | Usuniety; dodana adnotacja o `order_notes`. |
| SonarQube scan nie uruchomiony | XAMPP env; gap odnotowany do nastepnego planu (kontynuacja z Phase 108/110 gap). |

## Next Phase Readiness

**Ready:**
- Schema DB v3.7 Invoices kompletna - kolejne plany moga budowac `InvoiceService`, `InvoiceRepository`, `InvoiceConfigController` bez migracji DB.
- `FakturowniaIntegrationRepository::getDecryptedToken(int)` gotowy do uzycia przez `InvoiceService` w trybie `is_delegated=1`.
- `FakturowniaApiClient` ma STUB-y `createInvoice/downloadPdf` z jasnym RuntimeException - kolejny plan tylko implementuje cialo.
- `orders.invoice_requested` gotowe do (a) importera Allegro/shopPRO, (b) toggle w UI szczegolow zamowienia.

**Concerns:**
- Operator musi recznie utworzyc pierwszy `invoice_config` przed kolejnym planem (CRUD `invoice_configs`). Alternatywnie: kolejny plan moze dodac seed migracji z default config (`name='Domyslny VAT'`, `numbering_type='monthly'`, `is_delegated=0`).
- Refaktor edycji `receipt_configs` na osobna podstrone (z planu pierwotnego, poza zakresem 113-01) musi zostac zaplanowany - obecnie zarzadzanie `receipt_configs` jest pod tabela na `/settings/accounting`. User zaznaczyl ze chce ten sam refaktor zrobic dla paragonow przy okazji wprowadzania faktur.

**Blockers:**
- Brak.

---
*Phase: 113-fakturownia-integration, Plan: 01*
*Completed: 2026-05-10*
