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

5.9 KiB
Raw Blame History

phase, plan, status, date
phase plan status date
02-product-actions-fixes 03 complete 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.