---
phase: 06-sonarqube-quality
plan: 05
type: execute
wave: 3
depends_on: ["06-04"]
files_modified:
  - src/Modules/Settings/ShopproOrdersSyncService.php
  - src/Modules/Settings/ShopproOrderMapper.php
  - src/Modules/Settings/ShopproProductImageResolver.php
  - src/Modules/Settings/AllegroIntegrationController.php
  - src/Modules/Settings/AllegroStatusMappingController.php
  - src/Modules/Settings/AllegroDeliveryMappingController.php
autonomous: false
---

<objective>
## Goal
Rozdzielić 2 z 3 god classes przekraczające 20 metod — eliminacja naruszeń SonarQube php:S1448.
- `ShopproOrdersSyncService` (39 metod) → 3 klasy
- `AllegroIntegrationController` (30 metod) → 3 kontrolery

## Purpose
God classes naruszają SRP i S1448. `ShopproOrdersSyncService` z 39 metodami i 1192 liniami jest najtrudniejszą do testowania klasą w projekcie. Podział ułatwia izolowane modyfikacje integracji Shoppro bez ryzyka regresi w całym module.

## Output
5 nowych klas/kontrolerów, `ShopproOrdersSyncService` spada do ~15 metod, `AllegroIntegrationController` do ~12. S1448 spada z 6x do 1x (ShopproIntegrationsController pozostaje na następny plan).
</objective>

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

## Source Files
@src/Modules/Settings/ShopproOrdersSyncService.php
@src/Modules/Settings/AllegroIntegrationController.php
@routes/web.php
</context>

<skills>
## Required Skills (from SPECIAL-FLOWS.md)

| Skill | Priority | When to Invoke | Loaded? |
|-------|----------|----------------|---------|
| sonar-scanner | required | Po APPLY, przed UNIFY | ○ |
| /code-review | optional | Po implementacji, przed UNIFY | ○ |

## Skill Invocation Checklist
- [ ] sonar-scanner uruchomiony po zakończeniu APPLY
- [ ] /code-review rozważyć (duże zmiany strukturalne)
</skills>

<acceptance_criteria>

## AC-1: ShopproOrderMapper wydzielony
```gherkin
Given ShopproOrdersSyncService zawiera 15+ metod mapujących (mapOrderAggregate, mapAddresses, mapItems, etc.)
When wydzielasz je do src/Modules/Settings/ShopproOrderMapper.php
Then ShopproOrderMapper zawiera wszystkie metody mapowania; ShopproOrdersSyncService wstrzykuje go przez konstruktor
```

## AC-2: ShopproProductImageResolver wydzielony
```gherkin
Given ShopproOrdersSyncService zawiera resolveProductImagesForOrder() i fetchPrimaryProductImageUrl()
When wydzielasz je do src/Modules/Settings/ShopproProductImageResolver.php
Then ShopproProductImageResolver obsługuje image fetching; ShopproOrdersSyncService używa go przez konstruktor
```

## AC-3: ShopproOrdersSyncService ma ≤20 metod
```gherkin
Given ShopproOrdersSyncService ma 39 metod
When wydzielono ShopproOrderMapper i ShopproProductImageResolver
Then ShopproOrdersSyncService ma ≤20 metod (sync + orchestration + state management)
```

## AC-4: AllegroIntegrationController podzielony
```gherkin
Given AllegroIntegrationController ma 30 metod (status mapping, delivery mapping, main settings)
When wydzielasz AllegroStatusMappingController i AllegroDeliveryMappingController
Then każdy kontroler ma ≤15 metod; routes/web.php zaktualizowane
```

## AC-5: Brak regresji
```gherkin
Given Shoppro sync i Allegro integration działają przed podziałem
When podział jest czysto strukturalny (move method, nie zmiana logiki)
Then sync Shoppro importuje zamówienia; mapowania Allegro zapisują się; OAuth działa
```

</acceptance_criteria>

<tasks>

<task type="auto">
  <name>Task 1: Wydziel ShopproOrderMapper z ShopproOrdersSyncService</name>
  <files>
    src/Modules/Settings/ShopproOrderMapper.php,
    src/Modules/Settings/ShopproOrdersSyncService.php
  </files>
  <action>
    Przeczytaj ShopproOrdersSyncService dokładnie. Zidentyfikuj metody mapujące dane zamówień.

    **Metody do przeniesienia do ShopproOrderMapper:**
    Przenieś wszystkie private metody których jedynym zadaniem jest konwersja danych API → struktury wewnętrzne:
    - mapOrderAggregate() — główna metoda mapowania
    - mapAddresses() — mapowanie adresów
    - mapItems() — mapowanie pozycji
    - mapPayments() — mapowanie płatności
    - mapShipments() — mapowanie wysyłek
    - mapNotes() — mapowanie notatek
    - buildInvoiceAddress() — budowanie adresu faktury
    - normalizeOrderId(), normalizePaidFlag(), mapPaymentStatus(), sanitizePlainText()
    - buildDeliveryMethodLabel(), formatMoneyCompact(), normalizeMediaUrl()
    - toFloatOrNull(), toFloatOrDefault(), readPath(), readSinglePath(), composeName()
    - hasAddressData(), resolveInvoiceRequested(), parsePickupPoint()

    **ShopproOrderMapper (nowy plik):**
    - namespace App\Modules\Settings
    - class ShopproOrderMapper
    - Konstruktor przyjmuje zależności potrzebne metodom (np. ShopproOrderSyncStateRepository jeśli potrzebne)
    - Przenieś metody bez zmiany logiki (tylko zmień z private na public te, które sync() wywołuje bezpośrednio)

    **ShopproOrdersSyncService (aktualizacja):**
    - Dodaj private ShopproOrderMapper $mapper; w konstruktorze
    - CronHandlerFactory tworzy ShopproOrdersSyncService — sprawdź src/Modules/Cron/CronHandlerFactory.php i zaktualizuj kompozycję
    - Zastąp wywołania $this->mapOrderAggregate() → $this->mapper->mapOrderAggregate()
    - Usuń przeniesione metody z ShopproOrdersSyncService

    UWAGA: Sprawdź CronHandlerFactory.php — musi przekazać nowy ShopproOrderMapper do konstruktora.
  </action>
  <verify>
    php -l src/Modules/Settings/ShopproOrderMapper.php
    php -l src/Modules/Settings/ShopproOrdersSyncService.php
    php -l src/Modules/Cron/CronHandlerFactory.php
    grep -c "function " src/Modules/Settings/ShopproOrdersSyncService.php — powinno być ≤25 (po Task 1, przed Task 2)
  </verify>
  <done>AC-1 satisfied: ShopproOrderMapper istnieje z metodami mapowania; ShopproOrdersSyncService go używa</done>
</task>

<task type="auto">
  <name>Task 2: Wydziel ShopproProductImageResolver i finalizuj ShopproOrdersSyncService</name>
  <files>
    src/Modules/Settings/ShopproProductImageResolver.php,
    src/Modules/Settings/ShopproOrdersSyncService.php,
    src/Modules/Cron/CronHandlerFactory.php
  </files>
  <action>
    **ShopproProductImageResolver (nowy plik):**
    - Przenieś z ShopproOrdersSyncService:
      - resolveProductImagesForOrder()
      - fetchPrimaryProductImageUrl()
    - Konstruktor przyjmuje ShopproApiClient (potrzebny do fetch)
    - namespace App\Modules\Settings

    **ShopproOrdersSyncService (finalizacja):**
    - Dodaj private ShopproProductImageResolver $imageResolver;
    - Zastąp $this->resolveProductImagesForOrder() → $this->imageResolver->resolveProductImagesForOrder()
    - Po Task 1 + Task 2 ShopproOrdersSyncService powinien mieć ≤20 metod

    **CronHandlerFactory.php (aktualizacja):**
    - Sprawdź gdzie tworzona jest instancja ShopproOrdersSyncService
    - Dodaj nowe zależności: new ShopproOrderMapper(...), new ShopproProductImageResolver($shopproApiClient)
    - Przekaż do konstruktora ShopproOrdersSyncService

    Sprawdź czy ShopproOrderMapper też potrzebuje ShopproApiClient lub innych zależności — jeśli tak, przekaż z CronHandlerFactory.
  </action>
  <verify>
    php -l src/Modules/Settings/ShopproProductImageResolver.php
    php -l src/Modules/Settings/ShopproOrdersSyncService.php
    php -l src/Modules/Cron/CronHandlerFactory.php
    grep -c "function " src/Modules/Settings/ShopproOrdersSyncService.php — ≤20
  </verify>
  <done>AC-2, AC-3 satisfied: ShopproProductImageResolver wydzielony; ShopproOrdersSyncService ≤20 metod</done>
</task>

<task type="checkpoint:human-verify" gate="blocking">
  <what-built>
    ShopproOrdersSyncService podzielony na 3 klasy:
    - ShopproOrderMapper (metody mapowania danych)
    - ShopproProductImageResolver (pobieranie zdjęć produktów)
    - ShopproOrdersSyncService (orchestrator, ≤20 metod)
    CronHandlerFactory zaktualizowany z nowymi zależnościami.
  </what-built>
  <how-to-verify>
    1. Uruchom aplikację (XAMPP)
    2. Przejdź do Ustawień → Integracje → ShopPRO
    3. Uruchom ręczny import zamówień (jeśli dostępny) lub uruchom cron
    4. Sprawdź logi crona: importy Shoppro działają bez błędów
    5. Sprawdź że zamówienia pojawiają się / nie ma regresji
  </how-to-verify>
  <resume-signal>Wpisz "approved" aby kontynuować do podziału AllegroIntegrationController, lub opisz błędy</resume-signal>
</task>

<task type="auto">
  <name>Task 3: Podziel AllegroIntegrationController na 3 kontrolery</name>
  <files>
    src/Modules/Settings/AllegroIntegrationController.php,
    src/Modules/Settings/AllegroStatusMappingController.php,
    src/Modules/Settings/AllegroDeliveryMappingController.php,
    routes/web.php
  </files>
  <action>
    Przeczytaj AllegroIntegrationController i routes/web.php dokładnie.

    **Podział metod:**

    AllegroStatusMappingController (nowy):
    - saveStatusMapping()
    - saveStatusMappingsBulk()
    - deleteStatusMapping()
    - syncStatusesFromAllegro()
    - buildImportImageWarningMessage() (private helper)
    - reasonLabel() (private helper)

    AllegroDeliveryMappingController (nowy):
    - saveDeliveryMappings()
    - loadDeliveryServices()
    - (prywatne helpery potrzebne tym metodom)

    AllegroIntegrationController (zostaje z):
    - index()
    - save()
    - saveImportSettings()
    - startOAuth()
    - oauthCallback()
    - refreshOAuthToken()
    - importSingleOrder()
    - (prywatne walidatory i helpery potrzebne tym metodom)

    **Nowe pliki kontrolerów:**
    - Skopiuj konstruktor i zależności z AllegroIntegrationController
    - namespace App\Modules\Settings
    - Przenieś metody bez zmiany logiki

    **routes/web.php:**
    - Utwórz instancje nowych kontrolerów (ten sam wzorzec co istniejące)
    - Przepnij route definicje dla:
      - status mapping routes → AllegroStatusMappingController
      - delivery mapping routes → AllegroDeliveryMappingController
    - AllegroIntegrationController obsługuje resztę

    Sprawdź które zależności ($this->repository, $this->translator etc.) są potrzebne każdemu kontrolerowi.
  </action>
  <verify>
    php -l src/Modules/Settings/AllegroIntegrationController.php
    php -l src/Modules/Settings/AllegroStatusMappingController.php
    php -l src/Modules/Settings/AllegroDeliveryMappingController.php
    php -l routes/web.php
    grep -c "function " src/Modules/Settings/AllegroIntegrationController.php — ≤15
  </verify>
  <done>AC-4, AC-5 satisfied: AllegroIntegrationController ≤15 metod; nowe kontrolery poprawne; routes zaktualizowane</done>
</task>

</tasks>

<boundaries>

## DO NOT CHANGE
- Logika biznesowa w żadnej z przenoszonych metod
- Publiczne sygnatury metod (nazwy, parametry)
- Pliki widoków i SCSS
- ShopproIntegrationsController — zakres następnego planu (06-06 jeśli powstanie)
- Inne moduły (Orders, Shipments, Auth, etc.)

## SCOPE LIMITS
- Podział 2 klas (ShopproOrdersSyncService + AllegroIntegrationController)
- ShopproIntegrationsController pomijamy w tym planie (30 metod — podobny refactoring)
- Nie zmieniaj publicznych URL routes — tylko który controller je obsługuje
- CronHandlerFactory — tylko minimalne zmiany potrzebne dla nowych dependencies

</boundaries>

<verification>
Przed zamknięciem planu:
- [ ] php -l na wszystkich nowych i zmodyfikowanych plikach
- [ ] ShopproOrdersSyncService: grep -c "function " ≤20
- [ ] AllegroIntegrationController: grep -c "function " ≤15
- [ ] ShopproOrderMapper.php istnieje z metodami mapowania
- [ ] ShopproProductImageResolver.php istnieje
- [ ] AllegroStatusMappingController.php i AllegroDeliveryMappingController.php istnieją
- [ ] routes/web.php poprawny składniowo
- [ ] Checkpoint human-verify zaliczony (Shoppro sync działa)
- [ ] sonar-scanner — S1448 violations zmalały
</verification>

<success_criteria>
- 4 nowe pliki PHP
- ShopproOrdersSyncService ≤20 metod
- AllegroIntegrationController ≤15 metod
- Zero błędów składniowych
- Shoppro import działa (human-verify passed)
- SonarQube S1448 spada z 6 do ≤2
</success_criteria>

<output>
Po zakończeniu utwórz `.paul/phases/06-sonarqube-quality/06-05-SUMMARY.md`
</output>
