---
phase: 14-custom-fields-delete-bug
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
  - admin/templates/shop-product/product-edit-custom-script.php
  - autoload/Domain/Product/ProductRepository.php
autonomous: true
delegation: off
---

<objective>
## Goal
Naprawić bug: usunięcie WSZYSTKICH dodatkowych pól produktu w panelu admina nie działa — pola pozostają po zapisie.

## Purpose
Właściciel sklepu musi mieć możliwość usunięcia wszystkich custom fields z produktu. Obecny bug blokuje tę operację.

## Output
- Poprawiony JS w szablonie — hidden field gwarantujący obecność klucza `custom_field_name` w POST
- Defensive check w repozytorium (opcjonalnie)
- Test jednostkowy potwierdzający poprawkę
</objective>

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

## Source Files
@admin/templates/shop-product/product-edit-custom-script.php
@autoload/Domain/Product/ProductRepository.php
</context>

<acceptance_criteria>

## AC-1: Usunięcie wszystkich custom fields zapisuje pusty stan
```gherkin
Given produkt ma 2 dodatkowe pola (np. "Grawerunek", "Kolor")
When admin usuwa oba pola i klika "Zatwierdź"
Then po zapisie produkt nie ma żadnych dodatkowych pól
And tabela pp_shop_products_custom_fields nie zawiera rekordów dla tego produktu
```

## AC-2: Częściowe usunięcie nadal działa
```gherkin
Given produkt ma 3 dodatkowe pola
When admin usuwa 1 pole i klika "Zatwierdź"
Then po zapisie produkt ma 2 dodatkowe pola
And usunięte pole nie istnieje w bazie
```

## AC-3: Dodawanie pól nadal działa
```gherkin
Given produkt nie ma dodatkowych pól
When admin dodaje 2 nowe pola i klika "Zatwierdź"
Then po zapisie produkt ma 2 dodatkowe pola
```

</acceptance_criteria>

<tasks>

<task type="auto">
  <name>Task 1: Dodać hidden field gwarantujący klucz custom_field_name w POST</name>
  <files>admin/templates/shop-product/product-edit-custom-script.php</files>
  <action>
    W szablonie product-edit-custom-script.php dodać ukryte pole w sekcji custom fields:
    ```html
    <input type="hidden" name="custom_field_name_present" value="1">
    ```
    To pole musi być ZAWSZE obecne w formularzu (nie wewnątrz dynamicznych wierszy pól),
    tak aby serwer wiedział, że sekcja custom fields była obecna w formularzu.

    ALTERNATYWNIE (lepsze rozwiązanie): zamiast hidden field, zmienić warunek w ProductRepository
    z `array_key_exists('custom_field_name', $d)` na sprawdzanie obecności markera
    `custom_field_name_present`.

    Podejście: dodać hidden field `custom_field_name_present` w szablonie
    + zmienić warunek w ProductRepository na:
    ```php
    if ( array_key_exists( 'custom_field_name_present', $d ) ) {
    ```
    Dzięki temu:
    - Gdy formularz jest renderowany → marker ZAWSZE w POST → saveCustomFields() ZAWSZE wywoływany
    - Gdy API partial update bez custom fields → marker BRAK → skip (backward compat)
  </action>
  <verify>
    1. Otworzyć edycję produktu z custom fields w przeglądarce
    2. Usunąć wszystkie pola → Zatwierdź → sprawdzić że pola zniknęły
    3. Otworzyć ponownie → potwierdzić brak pól
  </verify>
  <done>AC-1 satisfied: usunięcie wszystkich pól działa poprawnie</done>
</task>

<task type="auto">
  <name>Task 2: Test jednostkowy — saveCustomFields z pustą listą</name>
  <files>tests/Unit/Domain/Product/ProductRepositoryTest.php</files>
  <action>
    Dodać test weryfikujący że saveCustomFields() z pustymi tablicami
    wywołuje delete na pp_shop_products_custom_fields dla danego produktu.

    Test powinien mockować Medoo i sprawdzić:
    - Że `delete('pp_shop_products_custom_fields', ['id_product' => $productId])` jest wywoływany
    - Że żaden insert/update nie jest wywoływany

    saveCustomFields() jest private — użyć Reflection do wywołania
    lub testować przez publiczną metodę saveProduct() z odpowiednim payloadem
    zawierającym `custom_field_name_present` i puste tablice.
  </action>
  <verify>./test.ps1 --filter testSaveCustomFieldsDeletesAllWhenEmpty</verify>
  <done>AC-1 potwierdzone testem jednostkowym</done>
</task>

</tasks>

<boundaries>

## DO NOT CHANGE
- Logika saveCustomFields() dla niepustych list pól (insert/update) — działa poprawnie
- API partial update — brak markera = skip custom fields (backward compat)
- Inne sekcje formularza edycji produktu

## SCOPE LIMITS
- Tylko naprawa buga usuwania pól — żadne refactoring ani nowe feature
- Nie zmieniać struktury tabeli pp_shop_products_custom_fields

</boundaries>

<verification>
Before declaring plan complete:
- [ ] Usunięcie wszystkich custom fields → po zapisie brak pól (AC-1)
- [ ] Usunięcie części custom fields → pozostałe zachowane (AC-2)
- [ ] Dodanie nowych custom fields → poprawnie zapisane (AC-3)
- [ ] Testy przechodzą: ./test.ps1
- [ ] Brak regresji w istniejących testach
</verification>

<success_criteria>
- Wszystkie 3 AC spełnione
- Test jednostkowy przechodzi
- Zero regresji w istniejącym test suite (820+ testów)
</success_criteria>

<output>
After completion, create `.paul/phases/14-custom-fields-delete-bug/14-01-SUMMARY.md`
</output>
