---
phase: 06-integrations-refactoring
plan: 02
type: execute
wave: 1
depends_on: ["06-01"]
files_modified:
  - autoload/admin/Controllers/IntegrationsController.php
  - autoload/admin/App.php
  - autoload/Domain/Order/OrderAdminService.php
  - cron.php
  - autoload/Domain/Integrations/IntegrationsRepository.php
  - tests/Unit/Domain/Integrations/IntegrationsRepositoryTest.php
autonomous: true
---

<objective>
## Goal
Zmigrować wszystkich konsumentów metod `apilo*` z `IntegrationsRepository` na nowy `ApiloRepository`, a następnie usunąć metody Apilo z `IntegrationsRepository` (cleanup).

## Purpose
Po tym planie `IntegrationsRepository` będzie lean (~225 linii): tylko settings, logi, product linking, ShopPRO import. `ApiloRepository` jest jedynym miejscem logiki Apilo.

## Output
- IntegrationsController: używa obu repozytoriów (IntegrationsRepository dla settings/logi, ApiloRepository dla apilo*)
- OrderAdminService: 3 metody używają ApiloRepository dla apiloGetAccessToken
- cron.php: apilo* wywołania przez $apiloRepository
- IntegrationsRepository: usunięte metody apilo* (~650 linii mniej)
- IntegrationsRepositoryTest: oczyszczony z duplikatów testów apilo*
</objective>

<context>
## Project Context
@.paul/PROJECT.md
@.paul/STATE.md

## Prior Work
@.paul/phases/06-integrations-refactoring/06-01-SUMMARY.md

## Source Files
@autoload/admin/Controllers/IntegrationsController.php
@autoload/admin/App.php
@autoload/Domain/Order/OrderAdminService.php
@autoload/Domain/Integrations/IntegrationsRepository.php
@tests/Unit/Domain/Integrations/IntegrationsRepositoryTest.php
</context>

<acceptance_criteria>

## AC-1: IntegrationsController używa ApiloRepository dla apilo*
```gherkin
Given IntegrationsController ma dwa repozytoria: $repository i $apiloRepository
When wywoływana jest dowolna metoda apilo* (apilo_settings, apilo_authorization, itp.)
Then używa $this->apiloRepository->apilo*() a nie $this->repository->apilo*()
```

## AC-2: OrderAdminService i cron.php używają ApiloRepository dla apiloGetAccessToken
```gherkin
Given OrderAdminService::resendToApilo, syncApiloPayment, syncApiloStatus
  oraz cron.php potrzebują access tokenu
When wywoływana jest metoda apiloGetAccessToken()
Then używają new ApiloRepository($db) lub $apiloRepository, nie IntegrationsRepository
```

## AC-3: IntegrationsRepository nie zawiera metod apilo*
```gherkin
Given plik IntegrationsRepository.php po cleanup
When sprawdzamy publiczne metody klasy
Then metody apilo* NIE ISTNIEJĄ, pozostają tylko:
     getSettings, getSetting, saveSetting,
     getLogs, deleteLog, clearLogs,
     linkProduct, unlinkProduct, getProductSku,
     shopproImportProduct
```

## AC-4: Pełna suite testów green
```gherkin
Given wszystkie zmiany wprowadzone
When uruchamiane jest php phpunit.phar
Then wszystkie testy green (826+ testów, zero regresji)
```

</acceptance_criteria>

<tasks>

<task type="auto">
  <name>Task 1: Zaktualizuj IntegrationsController i App.php</name>
  <files>autoload/admin/Controllers/IntegrationsController.php, autoload/admin/App.php</files>
  <action>
    **IntegrationsController.php:**

    1. Dodaj import: `use Domain\Integrations\ApiloRepository;`
    2. Dodaj property: `private ApiloRepository $apiloRepository;`
    3. Zmień konstruktor na:
       ```php
       public function __construct( IntegrationsRepository $repository, ApiloRepository $apiloRepository )
       {
           $this->repository = $repository;
           $this->apiloRepository = $apiloRepository;
       }
       ```
    4. Zamień wszystkie wywołania `$this->repository->apilo*()` na `$this->apiloRepository->apilo*()`:
       - linia ~128: `$this->repository->apiloIntegrationStatus()` → `$this->apiloRepository->apiloIntegrationStatus()`
       - linia ~150: `$this->repository->apiloAuthorize(...)` → `$this->apiloRepository->apiloAuthorize(...)`
       - linia ~159: `$this->repository->apiloIntegrationStatus()` → `$this->apiloRepository->apiloIntegrationStatus()`
       - linia ~194: `$this->repository->apiloCreateProduct(...)` → `$this->apiloRepository->apiloCreateProduct(...)`
       - linia ~211: `$this->repository->apiloProductSearch(...)` → `$this->apiloRepository->apiloProductSearch(...)`
       - linia ~270: `$this->repository->apiloFetchListResult(...)` → `$this->apiloRepository->apiloFetchListResult(...)`

    Pozostaw bez zmian: getLogs, clearLogs, getSettings, saveSetting, getProductSku,
    linkProduct, unlinkProduct, getSettings('shoppro'), saveSetting('shoppro'), shopproImportProduct
    — wszystkie przez `$this->repository`.

    **App.php:**

    W fabryce 'Integrations' (linia ~384) zmień:
    ```php
    return new \admin\Controllers\IntegrationsController(
        new \Domain\Integrations\IntegrationsRepository( $mdb )
    );
    ```
    na:
    ```php
    return new \admin\Controllers\IntegrationsController(
        new \Domain\Integrations\IntegrationsRepository( $mdb ),
        new \Domain\Integrations\ApiloRepository( $mdb )
    );
    ```
  </action>
  <verify>
    php -l autoload/admin/Controllers/IntegrationsController.php — no syntax errors
    php -l autoload/admin/App.php — no syntax errors
    grep "apiloRepository" autoload/admin/Controllers/IntegrationsController.php — pokazuje 6+ wystąpień
  </verify>
  <done>AC-1 spełnione</done>
</task>

<task type="auto">
  <name>Task 2: Zaktualizuj OrderAdminService i cron.php</name>
  <files>autoload/Domain/Order/OrderAdminService.php, cron.php</files>
  <action>
    **OrderAdminService.php** — 3 metody tworzą IntegrationsRepository i wołają apiloGetAccessToken().
    Zmień tylko te 3 miejsca (linie ~422, ~678, ~751):

    ```php
    // PRZED (w każdym z 3 miejsc):
    $integrationsRepository = new \Domain\Integrations\IntegrationsRepository($db);
    // lub: new \Domain\Integrations\IntegrationsRepository( $mdb );
    $accessToken = $integrationsRepository->apiloGetAccessToken();

    // PO (w każdym z 3 miejsc):
    $apiloRepository = new \Domain\Integrations\ApiloRepository($db);
    // lub z $mdb gdzie używano $mdb
    $accessToken = $apiloRepository->apiloGetAccessToken();
    ```

    POZOSTAW BEZ ZMIAN (linie ~579, ~628) — te tworzą IntegrationsRepository
    i wołają tylko getSettings('apilo') — to metoda generyczna, zostaje w IntegrationsRepository.

    **cron.php** — linia ~133:
    Po linii `$integrationsRepository = new \Domain\Integrations\IntegrationsRepository( $mdb );`
    dodaj:
    ```php
    $apiloRepository = new \Domain\Integrations\ApiloRepository( $mdb );
    ```

    Zamień wywołania apilo* przez `$integrationsRepository` na `$apiloRepository`:
    - linia ~191: `$integrationsRepository->apiloKeepalive(300)` → `$apiloRepository->apiloKeepalive(300)`
    - linia ~279: `$integrationsRepository->apiloGetAccessToken()` → `$apiloRepository->apiloGetAccessToken()`
    - linia ~560: `$integrationsRepository->apiloGetAccessToken()` → `$apiloRepository->apiloGetAccessToken()`
    - linia ~589: `$integrationsRepository->apiloGetAccessToken()` → `$apiloRepository->apiloGetAccessToken()`
    - linia ~642: `$integrationsRepository->apiloGetAccessToken()` → `$apiloRepository->apiloGetAccessToken()`

    POZOSTAW BEZ ZMIAN w cron.php:
    - `$integrationsRepository->getSettings('apilo')` (linie ~188, ~198, ~553, ~586, ~632)
    - `$integrationsRepository->saveSetting('apilo', ...)` (linia ~625)
  </action>
  <verify>
    php -l autoload/Domain/Order/OrderAdminService.php — no syntax errors
    php -l cron.php — no syntax errors
    grep "integrationsRepository->apilo" cron.php — brak wyników (wszystkie apilo przeniesione)
    grep "integrationsRepository->apilo" autoload/Domain/Order/OrderAdminService.php — brak wyników
  </verify>
  <done>AC-2 spełnione</done>
</task>

<task type="auto">
  <name>Task 3: Usuń metody apilo* z IntegrationsRepository + cleanup testów</name>
  <files>autoload/Domain/Integrations/IntegrationsRepository.php, tests/Unit/Domain/Integrations/IntegrationsRepositoryTest.php</files>
  <action>
    **IntegrationsRepository.php:**

    Usuń następujące bloki (cały kod między komentarzami sekcji a kolejną sekcją):

    1. Sekcję "// ── Apilo OAuth" z metodami:
       - `apiloAuthorize()`
       - `apiloGetAccessToken()`
       - `apiloKeepalive()`
       - `refreshApiloAccessToken()` (private)
       - `shouldRefreshAccessToken()` (private)
       - `isFutureDate()` (private)

    2. Stałe klasy:
       - `private const APILO_ENDPOINTS = [...]`
       - `private const APILO_SETTINGS_KEYS = [...]`

    3. Sekcję "// ── Apilo API fetch lists" z metodami:
       - `apiloFetchList()`
       - `apiloFetchListResult()`
       - `normalizeApiloMapList()` (private)
       - `isMapListShape()` (private)
       - `extractApiloErrorMessage()` (private)

    4. Z sekcji "// ── Apilo product operations" usuń tylko:
       - `apiloProductSearch()`
       - `apiloCreateProduct()`
       (ZACHOWAJ `getProductSku()` — jest generyczna, używana też przez ShopProductController)

    Po usunięciu IntegrationsRepository powinna zawierać:
    - settings (settingsTable, getSettings, getSetting, saveSetting)
    - logs (getLogs, deleteLog, clearLogs)
    - product linking (linkProduct, unlinkProduct, getProductSku)
    - ShopPRO import (shopproImportProduct, missingShopproSetting, shopproDb)

    **IntegrationsRepositoryTest.php:**

    Usuń następujące metody testowe (zostały już przeniesione do ApiloRepositoryTest):
    - `testApiloGetAccessTokenReturnsNullWithoutSettings()`
    - `testShouldRefreshAccessTokenReturnsFalseForFarFutureDate()`
    - `testShouldRefreshAccessTokenReturnsTrueForNearExpiryDate()`
    - `testApiloFetchListThrowsForInvalidType()`
    - `testApiloFetchListResultReturnsDetailedErrorWhenConfigMissing()`
    - `testApiloIntegrationStatusReturnsMissingConfigMessage()`
    - `testNormalizeApiloMapListRejectsErrorPayload()`
    - `testNormalizeApiloMapListAcceptsIdNameList()`

    W metodzie `testAllPublicMethodsExist()` usuń z tablicy `$expectedMethods` wpisy apilo*:
    - `'apiloAuthorize'`, `'apiloGetAccessToken'`, `'apiloKeepalive'`, `'apiloIntegrationStatus'`
    - `'apiloFetchList'`, `'apiloFetchListResult'`, `'apiloProductSearch'`, `'apiloCreateProduct'`
    (Pozostaw: `'getSettings'`, `'getSetting'`, `'saveSetting'`, `'linkProduct'`, `'unlinkProduct'`,
     `'getProductSku'`, `'shopproImportProduct'`, `'getLogs'`, `'deleteLog'`, `'clearLogs'`)

    Usuń też `testSettingsTableMapping()` i `testShopproProviderWorks()` tylko jeśli są duplikatami
    (sprawdź przed usunięciem — jeśli nie mają odpowiedników, zostaw).
  </action>
  <verify>
    php -l autoload/Domain/Integrations/IntegrationsRepository.php — no syntax errors
    grep "apilo" autoload/Domain/Integrations/IntegrationsRepository.php — brak wyników (lub tylko komentarze)
    php phpunit.phar — wszystkie testy green (826+, zero regresji)
    php phpunit.phar tests/Unit/Domain/Integrations/ — oba pliki testów green
  </verify>
  <done>AC-3 i AC-4 spełnione</done>
</task>

</tasks>

<boundaries>

## DO NOT CHANGE
- `autoload/Domain/Integrations/ApiloRepository.php` — gotowy, nie modyfikować
- `tests/Unit/Domain/Integrations/ApiloRepositoryTest.php` — gotowy, nie modyfikować
- `autoload/admin/Controllers/ShopProductController.php` — używa tylko getSetting(), nie apilo*
- `autoload/admin/Controllers/ShopStatusesController.php` — używa tylko getSetting(), nie apilo*
- `autoload/admin/Controllers/ShopTransportController.php` — używa tylko getSetting(), nie apilo*
- `autoload/admin/Controllers/ShopPaymentMethodController.php` — używa tylko getSetting(), nie apilo*
- Logika biznesowa nie zmienia się — czysta migracja wywołań

## SCOPE LIMITS
- Nie refaktoryzujemy OrderAdminService poza zmianą 3 instancji na ApiloRepository
- Nie zmieniamy sygnatury metod ani logiki
- Nie przenosimy ShopPRO import do osobnej klasy (to nie ten plan)

</boundaries>

<verification>
Before declaring plan complete:
- [ ] php -l na wszystkich zmodyfikowanych plikach — no syntax errors
- [ ] grep "apiloRepository->apilo" w IntegrationsController — 6 wystąpień (apilo metody)
- [ ] grep "this->repository->apilo" w IntegrationsController — brak wyników
- [ ] grep "integrationsRepository->apilo" w cron.php — brak wyników
- [ ] grep "integrationsRepository->apilo" w OrderAdminService — brak wyników
- [ ] grep "public function apilo" w IntegrationsRepository — brak wyników
- [ ] php phpunit.phar — 826+ testów green
</verification>

<success_criteria>
- IntegrationsController używa ApiloRepository dla wszystkich metod apilo*
- OrderAdminService i cron.php używają ApiloRepository dla apiloGetAccessToken
- IntegrationsRepository nie zawiera żadnych metod apilo*
- Pełna suite testów green bez regresji
</success_criteria>

<output>
After completion, create `.paul/phases/06-integrations-refactoring/06-02-SUMMARY.md`
</output>
