---
phase: 79-personalization-message-field
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
  - src/Modules/Settings/ShopproOrderMapper.php
  - DOCS/ARCHITECTURE.md
  - DOCS/TECH_CHANGELOG.md
autonomous: true
---

<objective>
## Goal
Dodanie pola `message` z API shopPRO do personalizacji produktow w zamowieniach. Aktualnie `extractPersonalization()` sprawdza tylko `attributes` i `custom_fields`, a shopPRO zwraca rowniez pole `message` z wiadomoscia personalizacji klienta (np. "Milenie na pamiatke I Komunii Swietej").

## Purpose
Klienci wpisuja wiadomosci personalizacji przy zamowieniach w shopPRO. Te dane sa kluczowe dla realizacji zamowien (np. grawerunki, dedykacje). Bez ich importu pracownik musi reczne sprawdzac dane w shopPRO.

## Output
- Zaktualizowany `extractPersonalization()` w ShopproOrderMapper — obsluguje pole `message`
- Istniejace zamowienia z `message` w payload_json — backfill personalizacji
- Zaktualizowana dokumentacja
</objective>

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

## Source Files
@src/Modules/Settings/ShopproOrderMapper.php (metoda extractPersonalization, linia ~590)
</context>

<skills>
No specialized flows required for this plan.
</skills>

<acceptance_criteria>

## AC-1: Pole message importowane do personalizacji
```gherkin
Given zamowienie shopPRO z pozycja majaca pole "message" w odpowiedzi API
When pozycja jest importowana/aktualizowana przez ShopproOrderMapper
Then wartosc pola "message" jest zapisana w kolumnie personalization tabeli order_items
```

## AC-2: Laczenie message z attributes i custom_fields
```gherkin
Given pozycja shopPRO majaca zarowno "attributes" jak i "message"
When extractPersonalization przetwarza dane
Then oba pola sa polaczone w personalization oddzielone nowa linia
  And pole "message" jest poprzedzone etykieta "Wiadomosc:"
```

## AC-3: Backfill istniejacych zamowien
```gherkin
Given istniejace pozycje zamowien z polem "message" w payload_json ale pustym personalization
When uruchomiona jest migracja/skrypt backfill
Then kolumna personalization zostaje wypelniona danymi z payload_json.message
```

</acceptance_criteria>

<tasks>

<task type="auto">
  <name>Task 1: Dodanie pola message do extractPersonalization</name>
  <files>src/Modules/Settings/ShopproOrderMapper.php</files>
  <action>
    W metodzie `extractPersonalization()` (linia ~590):
    1. Dodac pole `message` do listy sprawdzanych pol OSOBNO po petli attributes/custom_fields
    2. Wartosc message powinna byc poprzedzona etykieta "Wiadomosc: " (z dwukropkiem i spacja)
    3. Zachowac istniejaca logike czyszczenia HTML (strip_tags, html_entity_decode, trim)
    4. Jesli message jest jedynym polem — zwrocic "Wiadomosc: {tresc}"
    5. Jesli sa tez attributes/custom_fields — dodac message na koncu po nowej linii

    Logika:
    ```
    // Po istniejącej pętli attributes/custom_fields:
    $message = $this->readPath($row, ['message']);
    if ($message !== null && $message !== '' && $message !== false) {
        $text = str_replace(['<br>', '<br/>', '<br />'], "\n", (string) $message);
        $text = html_entity_decode(strip_tags($text), ENT_QUOTES | ENT_HTML5, 'UTF-8');
        $text = trim($text);
        if ($text !== '') {
            $parts[] = 'Wiadomość: ' . $text;
        }
    }
    ```
  </action>
  <verify>
    Sprawdzic w kodzie ze extractPersonalization obsluguje 3 pola: attributes, custom_fields, message.
    Zweryfikowac ze message jest poprzedzony etykieta "Wiadomosc:".
  </verify>
  <done>AC-1 i AC-2 satisfied: pole message jest importowane do personalizacji z etykieta</done>
</task>

<task type="auto">
  <name>Task 2: Migracja backfill personalizacji z payload_json</name>
  <files>database/migrations/20260407_000080_backfill_personalization_message.sql</files>
  <action>
    Utworzyc migracje SQL ktora:
    1. Aktualizuje kolumne personalization dla pozycji majacych message w payload_json
    2. Warunek: personalization IS NULL AND payload_json zawiera niepuste pole message
    3. Uzyc JSON_UNQUOTE(JSON_EXTRACT(payload_json, '$.message')) do wyciagniecia wartosci
    4. Ustawic personalization = CONCAT('Wiadomość: ', extracted_message)
    5. Jesli personalization juz istnieje (nie NULL) — nie nadpisywac (dodac do WHERE)
    
    Uwaga: Jezeli pozycja ma tez attributes/custom_fields w payload_json, sam SQL nie zbuduje pelnej personalizacji.
    Dla prostoty: backfill dotyczy TYLKO pozycji z pustym personalization.
    Pozycje z istniejacym personalization (z attributes/custom_fields) i brakujacym message — pomijamy 
    (przyszly re-import uzupelni je poprawnie dzieki Task 1).
  </action>
  <verify>
    Uruchomic migracje na bazie i sprawdzic ze pozycje zamowienia #217 maja wypelniona personalizacje z polem Wiadomosc.
  </verify>
  <done>AC-3 satisfied: istniejace zamowienia maja uzupelniona personalizacje</done>
</task>

<task type="auto">
  <name>Task 3: Aktualizacja dokumentacji</name>
  <files>DOCS/ARCHITECTURE.md, DOCS/TECH_CHANGELOG.md</files>
  <action>
    1. W ARCHITECTURE.md — zaktualizowac opis ShopproOrderMapper::extractPersonalization o pole message
    2. W TECH_CHANGELOG.md — dodac wpis o rozszerzeniu importu personalizacji o pole message
  </action>
  <verify>Sprawdzic ze dokumenty sa aktualne</verify>
  <done>Dokumentacja zaktualizowana</done>
</task>

</tasks>

<boundaries>

## DO NOT CHANGE
- Logika importu zamowien (OrderImportRepository) — zmiana tylko w mapperze
- Widok show.php — juz obsluguje personalizacje (nl2br), nie wymaga zmian
- Struktura tabeli order_items — kolumna personalization juz istnieje

## SCOPE LIMITS
- Nie zmieniamy sposobu wyswietlania personalizacji w widoku (juz dziala)
- Nie dodajemy nowych kolumn do bazy
- Backfill tylko dla pozycji z pustym personalization (nie nadpisujemy istniejacych)

</boundaries>

<verification>
Before declaring plan complete:
- [ ] extractPersonalization obsluguje pola: attributes, custom_fields, message
- [ ] Pole message jest poprzedzone etykieta "Wiadomosc:"
- [ ] Migracja backfill wykonana pomyslnie
- [ ] Zamowienie #217 wyswietla personalizacje z wiadomosciami
- [ ] Dokumentacja zaktualizowana
</verification>

<success_criteria>
- Nowe zamowienia shopPRO z polem message importuja personalizacje
- Istniejace zamowienia z message w payload_json maja uzupelniona personalizacje
- Brak regresji w imporcie zamowien
</success_criteria>

<output>
After completion, create `.paul/phases/79-personalization-message-field/79-01-SUMMARY.md`
</output>
