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>
This commit is contained in:
90
.paul/phases/02-product-actions-fixes/02-03-SUMMARY.md
Normal file
90
.paul/phases/02-product-actions-fixes/02-03-SUMMARY.md
Normal file
@@ -0,0 +1,90 @@
|
||||
---
|
||||
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.
|
||||
Reference in New Issue
Block a user