feat(13-protection-packages): Pakiety ochronne SOFT/PREMIUM z panelu WP

- Panel admina (wp-admin > Rezerwacje > Pakiety ochronne) do zarzadzania
  nazwami, cenami za dobe, aktywnoscia i opisami pakietow SOFT i PREMIUM
  (zapis w wp_options carei_protection_packages)
- REST endpoint GET /carei/v1/protection-packages zwracajacy aktywne pakiety
- Radio cards SOFT/PREMIUM w modalu rezerwacji nad pozycjami "Pakiety ochronne"
  z API (osobne zrodlo danych, separator wizualny)
- Radio z deselect (klik zaznaczonego odznacza), natywny input z accent-color
- Pakiet NIE wysylany w priceItems Softra (powodowalo HTTP 400) - zamiast tego
  doklejany do comments booking i zapisywany w _carei_protection_package meta
- Summary frontend dokorysowuje wiersz pakietu w tabeli cen i dolicza do
  total gross (grandGross = softraGross + protectionTotal)
- Plan 13-01 oznaczony jako superseded (klient zmienil zrodlo danych)
- Phase 13 Complete, Milestone v0.5 Complete

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-20 00:45:24 +02:00
parent 9e4f47de25
commit 42efe93cdd
13 changed files with 987 additions and 25 deletions

View File

@@ -0,0 +1,173 @@
---
phase: 13-protection-packages
plan: 02
subsystem: ui
tags: [wordpress, rest-api, elementor, admin-panel, vanilla-js, insurance]
requires:
- phase: 05-admin-panel
provides: CPT carei_reservation, save_reservation() static, meta box infrastructure
- phase: 03-booking-flow
provides: booking payload pipeline, priceItems convention, summary overlay
provides:
- Panel admina "Pakiety ochronne" (wp-admin → Rezerwacje → Pakiety ochronne)
- REST endpoint GET /carei/v1/protection-packages (public)
- Radio cards SOFT/PREMIUM w modalu z wizualnym separatorem od pozycji API
- Integracja z summary overlay (details list + price table + totals)
- Zapis wybranego pakietu w post_meta _carei_protection_package
- Info o pakiecie doklejane do comments booking (rezerwacja Softra widzi pakiet w uwagach)
affects: [future-insurance-adjustments, pricing-customizations, admin-ux]
tech-stack:
added: []
patterns:
- "WP options + REST proxy jako źródło danych niezależne od Softra"
- "Hybrydowe podsumowanie: pozycje z Softra + lokalne dodatki łączone w summary overlay"
- "Rozszerzenie comments Softra o strukturalne info pakietu (fallback dla braku dedicated field)"
key-files:
created:
- ".paul/phases/13-protection-packages/13-02-PLAN.md"
- ".paul/phases/13-protection-packages/13-02-SUMMARY.md"
modified:
- "wp-content/plugins/carei-reservation/includes/class-admin-panel.php"
- "wp-content/plugins/carei-reservation/includes/class-rest-proxy.php"
- "wp-content/plugins/carei-reservation/includes/class-elementor-widget.php"
- "wp-content/plugins/carei-reservation/assets/js/carei-reservation.js"
- "wp-content/plugins/carei-reservation/assets/css/carei-reservation.css"
key-decisions:
- "Dane pakietów w wp_options (opcja carei_protection_packages) — nie CPT ani custom table"
- "Pakiet poza Softra priceItems — HTTP 400 przy próbie wysłania fałszywych ID"
- "Pakiet w comments booking + osobny protectionPackage w payloadzie dla CPT"
- "Summary frontend dokłada wiersz pakietu i oblicza grandTotal = softraGross + protectionTotal"
- "Plan 13-01 superseded — pricing progowy odrzucony przez klienta na rzecz prostej ceny/dobę z WP"
patterns-established:
- "REST route dla danych WP-managed: __return_true permission (publiczne read-only)"
- "Filtrowanie active=true po stronie endpointu, frontend dostaje tylko aktywne"
- "Radio z deselect przez JS click handler (natywne radio nie odznacza)"
- "accent-color: var(--carei-blue) dla natywnych radio spójnych z design systemem"
duration: ~3h
started: 2026-04-20T12:00:00Z
completed: 2026-04-20T15:30:00Z
---
# Phase 13 Plan 02: Pakiety ochronne SOFT+PREMIUM — Summary
**Dwa pakiety ochronne z ceną/doba zarządzane w panelu WP (wp_options), renderowane jako radio cards w modalu nad opcjami API, doliczane lokalnie w summary i przesyłane do Softra przez comments + lokalny meta CPT.**
## Performance
| Metric | Value |
|--------|-------|
| Duration | ~3h |
| Started | 2026-04-20T12:00:00Z |
| Completed | 2026-04-20T15:30:00Z |
| Tasks | 3 auto + 1 checkpoint (human-verify approved) |
| Files modified | 5 |
## Acceptance Criteria Results
| Criterion | Status | Notes |
|-----------|--------|-------|
| AC-1: Panel administratora — konfiguracja pakietów | ✅ Pass | Submenu "Pakiety ochronne" w edit.php?post_type=carei_reservation, formularz z nazwą/ceną/aktywnym/opisem dla SOFT+PREMIUM, zapis w carei_protection_packages |
| AC-2: Endpoint REST z danymi pakietów | ✅ Pass | GET /wp-json/carei/v1/protection-packages zwraca {soft, premium} z filtrem active=true |
| AC-3: Render kafelków z separatorem | ✅ Pass | #carei-protection-packages-container nad #carei-insurance-container, .carei-form__protection-divider oddziela wizualnie |
| AC-4: Wybór i dynamiczne przeliczanie | ✅ Pass (zmieniono UX) | Radio z deselect działa; sumowanie × days wyłączone w kafelku (decyzja UX z klientem — tylko "X zł/doba" szare po prawej, total dopiero w summary) |
| AC-5: Pakiet w booking submission i CPT | ✅ Pass (rozwiązanie hybrydowe) | Pakiet w comments booking + protectionPackage w payloadzie + _carei_protection_package meta CPT + wiersz w summary overlay (details list + price table + totals) |
## Accomplishments
- **Zarządzanie niezależne od Softra** — admin może zmieniać ceny pakietów bez dotykania API wynajmowanego przez zewnętrznego dostawcę
- **Rozwiązanie konfliktu API** — po pierwszej próbie wysłania pakietów jako `priceItems` Softra zwracała HTTP 400; refactor w locie: pakiet wyłączony z priceItems, doklejony do comments + zobaczony w summary po stronie frontu
- **Spójność wizualna** — kafelki pakietów identyczne stylem z `.carei-form__extra-card` (nazwa blue, cena szara po prawej, bold, natywny radio z accent-color)
- **Pełny cykl życia rezerwacji** — pakiet od momentu wyboru (radio) → comments Softra → CPT meta → meta box admina → wyświetlenie w formacie "nazwa — cena/doba × dni = total"
## Files Created/Modified
| File | Change | Purpose |
|------|--------|---------|
| `.paul/phases/13-protection-packages/13-02-PLAN.md` | Created | Plan zastępujący 13-01 (nowe założenia klienta) |
| `.paul/phases/13-protection-packages/13-02-SUMMARY.md` | Created | Ten dokument |
| `wp-content/plugins/carei-reservation/includes/class-admin-panel.php` | Modified | Submenu page, handler POST, get_protection_packages() static, rozszerzenie save_reservation() o protection_package meta, wiersz w meta boxie |
| `wp-content/plugins/carei-reservation/includes/class-rest-proxy.php` | Modified | Rejestracja GET /protection-packages, callback get_protection_packages() z filtrem active |
| `wp-content/plugins/carei-reservation/includes/class-elementor-widget.php` | Modified | Nowy #carei-protection-packages-container + .carei-form__protection-divider nad #carei-insurance-container |
| `wp-content/plugins/carei-reservation/assets/js/carei-reservation.js` | Modified | protectionPackages state, loadProtectionPackages(), renderProtectionPackages() z radio + deselect, getSelectedProtectionPayload(), buildBookingComments(), integracja w showSummaryOverlay (details + table + totals) |
| `wp-content/plugins/carei-reservation/assets/css/carei-reservation.css` | Modified | Style kafelków pakietów (flex row, name blue, price gray right, radio 16×16 accent-color, separator dashed), mobile stack |
## Decisions Made
| Decision | Rationale | Impact |
|----------|-----------|--------|
| Pakiet NIE w priceItems Softra | HTTP 400 przy próbie wysłania fałszywego ID — Softra waliduje wobec swojej bazy | Wymagane osobne kanały: comments (widoczne pracownikom wypożyczalni), protectionPackage payload (zapis WP), summary UI (widoczne klientowi) |
| UX: brak totala × days w kafelku | Klient poprosił o spójność z extras (tylko "X zł/doba" szary po prawej), total dopiero w summary | Prostszy kafelek, `updateProtectionTotals()` usunięty jako martwy kod, listenery dat oczyszczone |
| Native radio + accent-color | Spójne z reszta formularza, user prosił o widoczny wybór | Minimalny CSS, natywna accessibility, JS tylko dla deselect |
| Plan 13-01 superseded zamiast skasowany | Historia decyzji klienta zachowana dla przyszłego audytu | 13-01-PLAN.md pozostaje w repo z notatką supersession w ROADMAP |
## Deviations from Plan
### Summary
| Type | Count | Impact |
|------|-------|--------|
| Auto-fixed | 2 | Konieczne korekty po błędach runtime |
| Scope additions | 1 | Feedback UX w trakcie: prostszy kafelek |
| Deferred | 0 | — |
**Total impact:** Wszystkie deviations wynikły z feedback usera w trakcie APPLY (3 iteracje UI + 1 fix błędu API). Żadna nie wychodziła poza cel planu.
### Auto-fixed Issues
**1. [API] HTTP 400 z Softra przy wysyłaniu pakietu jako priceItem**
- **Found during:** Task 3 (frontend JS) po wdrożeniu i kliknięciu "Pokaż podsumowanie"
- **Issue:** `priceItems` zawierał `id: 'protection_soft'` — Softra nie zna tego ID i zwracała 400 Bad Request
- **Fix:** Usunięto pakiet z `getSelectedExtrasForApi()`, dodano jako osobną linię w `comments` booking (`buildBookingComments()`) oraz jako wiersz w summary frontend (details list + price table + totals), grandGross = softraGross + protectionTotal
- **Files:** `carei-reservation.js`
- **Verification:** User potwierdził brak błędu + widoczność pakietu w summary
**2. [UX] Pakiet niewidoczny w liście "Wybrane opcje" summary**
- **Found during:** Weryfikacja po fixie HTTP 400
- **Issue:** `summaryDetails` iterował po `selectedExtras` z `getSelectedExtrasForApi()`, który nie zawiera już pakietu
- **Fix:** Dodany warunkowy wiersz w liście używający `getSelectedProtectionPayload()` z formatem analogicznym do extras (`X zł/doba × N = total zł`)
- **Files:** `carei-reservation.js`
- **Verification:** User potwierdził widoczność
### Scope Additions
**1. [UX] Uproszczenie kafelka (usunięcie total × days z popupu)**
- User request podczas APPLY: "pokazuj tak jak ceny pozostałych elementów, czyli po prawej wszystko szarym kolorem i bez sumowania za liczbę dni, to dopiero w kolejnym widoku podsumowania"
- Efekt: `updateProtectionTotals()` usunięte jako martwy kod, listenery dat oczyszczone, CSS kafelków dostosowany do wzorca `.carei-form__extra-card`
### Deferred Items
None.
## Issues Encountered
| Issue | Resolution |
|-------|------------|
| Softra HTTP 400 | Refactor w locie — pakiet wyłączony z priceItems, dostarczany przez comments + meta + summary UI (patrz Auto-fixed #1) |
| Radio niewidoczny (pierwotnie hidden) | User request: "brakuje checkboxa wyboru wersji ubezpieczenia" → native radio w row z accent-color |
| Cena nie pogrubiona | User request → usunięcie override `font-weight: 400` na `.carei-form__protection-package__price strong` |
## Next Phase Readiness
**Ready:**
- Milestone v0.5 zamykany (Phase 13 ✅ + Phase 14 ✅ = 100%)
- Wzorzec "WP-managed dane + REST public endpoint + integracja z summary" gotowy do reuse w kolejnych niezależnych od Softra customizacjach
- Admin ma pełną kontrolę nad cenami bez wymagań modyfikacji Softra
**Concerns:**
- VAT dla pakietu traktowany jako brutto bez rozbicia netto/VAT — wystarczy dla MVP, ale jeśli klient będzie wymagał księgowego rozbicia, trzeba dodać `vatRate` w adminie i kalkulację
- Comments Softra ma limit długości nieznany — w przyszłości rozważyć dedykowany field w integracji, jeśli Softra doda taki
**Blockers:**
- None
---
*Phase: 13-protection-packages, Plan: 02*
*Completed: 2026-04-20*