---
phase: 71-attributes-import
plan: 01
type: execute
wave: 1
depends_on: []
files_modified: [src/Modules/Settings/ShopproOrderMapper.php]
autonomous: true
---
## Goal
Dodanie importu pola `attributes` z API shopPRO do personalizacji produktow w orderPRO. Obecnie importowane jest tylko `custom_fields`, a `attributes` (np. "Woreczek jutowy: Nie", "Kolor koperty: Biala") jest ignorowane.
## Purpose
Klienci nie widza pelnych danych produktu z zamowienia shopPRO. Atrybuty takie jak wariant produktu, kolor, dodatkowe opcje sa tracone przy imporcie.
## Output
Zmodyfikowany `ShopproOrderMapper::extractPersonalization()` ktory laczy `attributes` i `custom_fields` w jedno pole `personalization`.
## Project Context
@.paul/PROJECT.md
@.paul/ROADMAP.md
## Source Files
@src/Modules/Settings/ShopproOrderMapper.php (linie 590-602 - extractPersonalization)
## AC-1: Atrybuty produktu importowane do personalizacji
```gherkin
Given zamowienie w shopPRO ma produkt z polem attributes = "Woreczek jutowy: Nie"
When zamowienie jest synchronizowane do orderPRO
Then pole personalization zawiera "Woreczek jutowy: Nie"
```
## AC-2: Polaczenie attributes i custom_fields
```gherkin
Given produkt ma attributes = "Kolor tekstu: Bialy
Zakretka: Zlota" i custom_fields = "Imiona: Jan i Anna"
When zamowienie jest synchronizowane
Then personalization zawiera oba bloki oddzielone nowa linia (najpierw attributes, potem custom_fields)
```
## AC-3: Puste pola nie generuja pustych linii
```gherkin
Given produkt ma attributes = "" i custom_fields = "Imie: Jan"
When zamowienie jest synchronizowane
Then personalization zawiera tylko "Imie: Jan" (bez pustych linii na poczatku)
```
## AC-4: Oba pola puste zwracaja null
```gherkin
Given produkt ma attributes = "" i custom_fields = ""
When zamowienie jest synchronizowane
Then personalization = null (bez zmian wzgledem obecnego zachowania)
```
Task 1: Rozszerzenie extractPersonalization o pole attributes
src/Modules/Settings/ShopproOrderMapper.php
W metodzie `extractPersonalization()` (linia 590):
1. Odczytaj pole `attributes` z $row (readPath z kluczem 'attributes')
2. Odczytaj pole `custom_fields` z $row (juz istniejace)
3. Dla kazdego niepustego pola: zamien <br> na \n, strip_tags, html_entity_decode, trim
4. Polacz niepuste czesci separatorem "\n" (attributes first, potem custom_fields)
5. Zwroc polaczony tekst lub null jesli oba puste
Nie zmieniac logiki parsowania HTML (str_replace br, strip_tags, html_entity_decode) - tylko rozszerzyc o drugie pole.
Nie dodawac naglowkow "Atrybuty:" / "Personalizacja:" - traktowac dane jednorodnie.
Sprawdzenie w bazie danych po resync zamowienia 11776:
SELECT personalization FROM order_items WHERE order_id = (SELECT id FROM orders WHERE source_order_id = '11776')
Powinno zwrocic "Woreczek jutowy: Nie"
AC-1, AC-2, AC-3, AC-4 satisfied
## DO NOT CHANGE
- Logika `mapItems()` poza wywolaniem `extractPersonalization()`
- Struktura bazy danych (kolumna `personalization` juz istnieje)
- Widok wyswietlania personalizacji (show.php)
- ShopproOrdersSyncService, ShopproApiClient
## SCOPE LIMITS
- Tylko zmiana parsera - bez migracji DB
- Bez zmian w widoku (wyswietlanie juz dziala)
- Bez resyncu wszystkich zamowien (to recznie po deploy)
Before declaring plan complete:
- [ ] PHP syntax OK: `php -l src/Modules/Settings/ShopproOrderMapper.php`
- [ ] Zamowienie 11776 po resync ma personalization = "Woreczek jutowy: Nie"
- [ ] Zamowienia z samym custom_fields dzialaja jak dotychczas (brak regresji)
- [ ] Zamowienia z obu polami maja polaczone dane
- extractPersonalization() czyta zarowno attributes jak i custom_fields
- Istniejace zamowienia z custom_fields nie tracą danych
- Pole attributes jest poprawnie parsowane (HTML stripped, br -> newline)