Files
newwalls.pl/.paul/phases/02-product-actions-fixes/02-03-SUMMARY.md
Jacek Pyziak ac03f807c1 feat(02-product-actions-fixes): Phase 02 complete — customization, price label, structure fix
Plan 02-03: Customization save + success modal (5/5 AC)
- 26-field squaremeter POST payload (verbose PL dim, qty_alt/qty_alth)
- Chain POST /module/ps_shoppingcart/ajax -> Bootstrap #blockcart-modal
- Critical fix: moved {/block} so inline script actually renders
- __p02p02InFlight re-entrancy guard

Plan 02-04: Live cena per-sqm label obok "Dodaj do koszyka" (5/5 AC)
- .p02p04-total-price label, gorna .current-price static
- Separate __p02p04Bound + setInterval reconciliation
- Poll-retry prestashop.on registration

Plan 02-05: Struktura materialu w POST payload (4/4 AC)
- Enumerate [name^="group["] spoza formy, doklej do payload
- Fix: group_5 select w .product-bar-box nie trafial do koszyka

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 00:55:05 +02:00

91 lines
5.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
phase: 02-product-actions-fixes
plan: 03
status: complete
date: 2026-04-23
---
# Plan 02-03 — Customization save + success modal (SUMMARY)
## Goal
End-to-end add-to-cart UX w nowym layoucie: customization zapisuje się w DB (widoczne w koszyku jako "Szczegóły") + success modal po dodaniu. Parzystość ze starym layoutem.
## Result
**Complete (5/5 AC pass).** Blocker na usunięcie IP gate — removed.
## AC Status (live Playwright verified 2026-04-23)
| AC | Status | Evidence |
|---|---|---|
| AC-1 Customization save | ✓ PASS | Cart items "Rain of flowers" pokazują "Szczegóły produktu" z `Wymiar: Szerokość 2.0 m, Wysokość 1.5 m, 3.00 m2`. POST payload zawiera `discretion=on, calculated_total=3.0000, product_total_price_calc=717, qty_alt=2.0, qty_alth=1.5, dim=<verbose PL>`. |
| AC-2 Success modal | ✓ PASS | Modal `#blockcart-modal.modal` rendered po add-to-cart, z "Produkt pomyślnie dodany do koszyka", nazwą produktu, ceną, "Kontynuuj zakupy" + "Przejdź do kasy" buttons. |
| AC-3 Cart "Szczegóły" | ✓ PASS | `/pl/koszyk` pokazuje "Szczegóły produktu" button, rozwija się na dimension data. |
| AC-4 Single add | ✓ PASS | Po re-entrancy guard (`window.__p02p02InFlight`): 1× POST /pl/koszyk + 1× POST /module/ps_shoppingcart/ajax. Wcześniej było 2×. |
| AC-5 OLD layout regression | ✓ PASS | Flip IP temporary → `.pp_stick_parent` present, `window.__p02p02Bound: false` (nasz handler NIE aktywowany w OLD). Structural isolation confirmed. |
## Key Discoveries (Task 1 — OLD payload capture via Playwright)
**Source of truth:** fetched live POST payload z OLD layout (IP flipped to `255.255.255.255` temporarily, restored after).
**26 fields w OLD `#add-to-cart-or-refresh` → `/pl/koszyk`:**
```
token, id_product, id_customization=0
dim="Szerokość {w}.0 m, Wysokość {h} m, {area}.00 m2, Pozycja {x} {y} <span> ,Pozycja tła {bt} {bl} ,Odbicie {r} </span>"
converted_ea={area:.4f} calculated_total={area:.4f} grand_calculated_total=""
extrafeevalue=0 wastevalue=0 fixed_price, base_price (przykład: 239)
is_crop, is_reflection, crop_pos_x, crop_pos_y, crop_width, crop_height
product_total_price_calc=<int: base_price × area>
piece_bg_top, piece_bg_left
group[5]=9 (material) group[4]=5/6/7 (wariant kolorystyczny)
qty_alt={width_m} qty_alth={height_m}
discretion=on qty=1 (cart quantity)
```
**Kluczowe insighty:**
- `dim` field jest VERBOSE Polish description, NIE "200x150" jak sugerował pierwotny plan.
- `qty` (cart quantity) ≠ `qty_alt`/`qty_alth` (dimension values). Squaremeter uses alt fields.
- `product_total_price_calc` = integer = `base_price × calculated_total` (area m²).
- Wszystkie numeric fields stored as strings, decimals z 4 miejscami po przecinku dla converted_ea/calculated_total.
**POST #2 (modal fetch):**
- Endpoint: `/module/ps_shoppingcart/ajax` (POST)
- Body: `action=add-to-cart&id_product&id_product_attribute&id_customization`
- Response: `{preview: '<blockcart HTML>', modal: '<#blockcart-modal Bootstrap HTML>'}`
- Modal uses Bootstrap `#blockcart-modal.modal.fade`. Buttons: "Kontynuuj zakupy" (`data-dismiss`) + "Przejdź do kasy" (link → `/pl/koszyk?action=show`).
## Decisions
| Data | Decyzja | Wpływ |
|---|---|---|
| 2026-04-23 | Używać verbose PL dim format (nie "200x150") | Kompatybilność z squaremeter customization hook + cart display consistency. |
| 2026-04-23 | basePrice z `meta[property="product:price:amount"]` (fallback chain) | `#product_base_price`/`#product_fixed_price` nie istnieją w NEW layout (są tylko w OLD shared partial). Meta tag reliably renders w NEW. |
| 2026-04-23 | `window.__p02p02InFlight` re-entrancy guard | Jedynie `__p02p02Bound` nie wystarczył — handler firował 2× (root cause niepotwierdzony, ale guard fix'uje skutecznie). Reset przez `complete:` callback. |
| 2026-04-23 | Move inline script INSIDE `{block name='content'}` | **Kluczowy bug fix:** template użyje `{extends file=$layout}`. Smarty renderuje TYLKO content w blockach. Stary inline script (Plan 02-02) był MIĘDZY `{/block}` a `{/if}` — NIGDY nie renderowany. Znaczy: Plan 02-02 AC-3 pass było przez custom.js alone; inline mirror był dead code. |
| 2026-04-23 | Manual FTP upload via curl | ftp-kr VSCode extension nie łapie edycji z Claude Code Edit tool. `curl -T ftp://` jako work-around. |
| 2026-04-23 | Dual-source sq fields: DOM hidden inputs + explicit appended sqFields | Defense-in-depth. `$form.serialize()` jeśli shared partial ma pola. Appended wins w PHP $_POST (last-wins) gdyby brakowało. |
## Modified Files
- `themes/ayon/assets/js/custom.js` (lines 1026-1200, ~175 new lines) — sq fields injection, modal chain, re-entrancy guard.
- `themes/ayon/templates/catalog/product.tpl` (lines 756, 768-928) — moved `{/block}` to wrap inline script; added sq fields + modal chain in inline mirror.
## Boundaries respected
-`modules/squaremeter/*` not modified
- ✓ Shared partials (`themes/ayon/templates/catalog/_partials/*`) not modified
- ✓ Old layout branch `{if != '89.69.31.86'}` unchanged
- ✓ Plan 02-01 override of `totalpriceinfospecific` / `prod` preserved (still no-op)
- ✓ No new dependencies
## Deferred (Plan 02-04+)
- **Cena per-sqm UI** (live calculation on dimension change) — scope Plan 02-04.
- **Systemowy cache-buster** `?v=<mtime>` dla `<script src=custom.js>` — scope Plan 02-05. Inline mirror z Plan 02-02 teraz faktycznie renderowany (po block-move fix), pełni swój defensywny cel.
- **Dimension input UI** (alternatywa do piece popup) — user currently uses piece popup (200×150 cm → 2.0×1.5 m conversion hardcoded).
- **Puste bloki** (`.product-protect`, `.product-installation`, `.product-order-sample`) — Plan 02-06.
- **Cleanup test carts** — kilka "Rain of flowers" items w testowym koszyku z moich Playwright runs.
## Blocker na usunięcie IP gate
**REMOVED.** Milestone v0.1 może być teraz shipped — można wyłączyć `REMOTE_ADDR == '89.69.31.86'` gate po akceptacji UAT przez usera.