--- 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 --- ## 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* ## 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 ## 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) ``` Task 1: Zaktualizuj IntegrationsController i App.php autoload/admin/Controllers/IntegrationsController.php, autoload/admin/App.php **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 ) ); ``` 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ń AC-1 spełnione Task 2: Zaktualizuj OrderAdminService i cron.php autoload/Domain/Order/OrderAdminService.php, cron.php **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) 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 AC-2 spełnione Task 3: Usuń metody apilo* z IntegrationsRepository + cleanup testów autoload/Domain/Integrations/IntegrationsRepository.php, tests/Unit/Domain/Integrations/IntegrationsRepositoryTest.php **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). 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 AC-3 i AC-4 spełnione ## 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) 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 - 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 After completion, create `.paul/phases/06-integrations-refactoring/06-02-SUMMARY.md`