297 lines
13 KiB
Markdown
297 lines
13 KiB
Markdown
---
|
|
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>
|