Skip to content

Migrated from Notion E2E features — https://app.notion.com/p/3d31f8eaa3ad8116a2ede6e448c8cc64

E2E features

Callout Who should read: QA writing or reviewing create/pay / desk-move journeys. Callout As of 2026-09-24 IST — reservation-browser-tests main tip 4a53eab (2026-09-08 IST). Specs on tip: admin-web-app-flow.spec.ts (Midway lifecycle), admin-buyout-flow.spec.ts (#140), admin-pay-later-create.spec.ts (#143), admin-slot-full.spec.ts (#141), venuplus-booking-flow.spec.ts / smoke (#142 Datacap gated). Nightly schedule (playwright.yml) runs only suite=admin + business_admin — buyout / pay-later / slot-full / PWA are dispatch-only. BA Midway nightly often red (outlet “Select location”). Coverage map: TEST coverage recommendations (2026-09-24). How to use: status machine + golden fixtures first; assert DocTypes not UI toasts. Do not run S-883 / update_booking unless asked. Magensa inside create_booking is a dead branch for ATP/US goldens. Guest checkout does not use apply_booking_workflow_action (Desk only). Create/pay write passes need Anil approval — Datacap on DEV can still be production.

E2E features (from reservation-api-server + venuplus-app)

Read-only mapping. Canonical terms: Booking, Outlet, Customer, Business, Venue. SYS-005: new Outlet of an existing class = zero new tests. Daily = integrative, not cartesian.

Source of truth: reservation-api-server Frappe methods. Apps only call them.

Status machine (BZBooking.booking_status)

PWA Datacap guest checkout (current code in booking_transaction.py):

  1. Cart lock: BZBookingAvailability.lock_status = Active (cart.add_to_cart / lock_slot, ~600s expiry)
  2. create_booking without a payment block → Booking Pending; cart Active locks are Confirmed here (atomic_confirm_cart_locks)
  3. External Datacap capture (venuplus /booking/[outletId]/payment) — PAN never hits Frappe
  4. finalize_booking_after_payment → Pending → Successful (amounts + confirmation). Does not insert payment rows; re-attaches Confirmed locks.

apply_booking_workflow_action is not on the PWA checkout path anymore. It remains for Desk / admin (Initiated, Holding, Wait, CheckedIn).

Create also supports idempotency_key and cart_id de-dupe.

App routes (venuplus-app)

/booking/[outletId]/ steps we treat as one party-package journey (class VP-FRAPPE-PACKAGE-VENUE-DATACAP-PWA):

Step Route Backend
Catalog /booking/{outletId}/plans-and-games (ATP; / ?outlet= redirects here) pwa.get_outlet_by_id, pwa.get_service_items, customer.get_service_item
Slot same page (not /time-selection — that redirects back) pwa.get_schedules / pwa.get_schedule, availability.get_timeslots
Lock Proceed → checkout cart.add_to_cart (CART-… Active lock). Release: cart.remove_from_cart. Not availability.lock_resources
Review /checkout customer.get_addons, pricing_engine.calculate_total
Create checkout pay booking_transaction.create_booking → Pending + Confirmed locks. No apply_booking_workflow_action
Pay /payment → POST /api/payment/process Datacap only: payment.get_webtoken_config → NetEPay tokenize → payment.process_sale → record_external_payment_transaction → finalize_booking_after_payment
Confirm same /payment page (paymentState=success) no extra method; email inside finalize. /manage is later email CTA

Out of this class: game-card-*, United Skates /plans (pwa.get_plans_catalog_for_date), Magensa MagTek (process_mppg_hardware_emv on admin BookingDetail hardware pay).

Admin (admin-web-app) — schedule move

Caller Method Lock behavior
BookingDetail / BookingEditDrawer / BookingRichEditor bookingzone.api.admin_booking.patch_booking in-place Confirmed (locks_rescheduled)
Public customer portal (customerAccount.reschedule, bookings.requestReschedule) + shims bookings.update / reschedule update_booking via shim-router #883 path. Not BookingDetail manager save. Map only, do not run
Some BookingPage writes raw frappe.updateDoc("BZBooking") bypasses lock move (different defect)

DocTypes to assert (never UI toast)

  • BZBooking.booking_status / payment fields
  • BZBookingAvailability.lock_status (Active during cart, Confirmed at create_booking, still Confirmed after Successful)
  • BZPaymentTransaction (no PAN/CVV)
  • BZResourceBlock only when the class actually uses admin blocks (VP Arnot Mall: none)

DEV fixtures (catalog)

See ecosystem/ for the full dump. Locks out of this pass.

ATP class VP-FRAPPE-PACKAGE-VENUE-DATACAP-PWA - Business: Test At The Pier bz-7c4f4061-5ad1-4d1b-a4a8-37cbfd1ced2d - Outlet: Test At The Pier - Arnot Mall bz-4f8920e9-9644-4169-acb4-ba3193083ee7 - Golden package: The Midway Play bz-3702289d-3778-4d61-9181-28120d5ec1aa (buffer 30, 8–25 guests, $17.99) - PWA: /booking/{outletId}/plans-and-games

United Skates Test Seaford (not the PWA URL Outlet) - Business: Test United Skates bz-977016bb-39ae-48b3-a8b7-66a4a6f6827f - Outlet: bz-192df4d4-cdc0-4789-ae61-4e4f8e98b74e - Plan class golden: Super Pass bz-19d6fa9b-6b0a-4931-8ea9-2d4507cdc9af - Package class golden: ULTIMATE BIRTHDAY PARTY PACKAGE bz-2c518af1-7e2d-49b0-b82f-de269142f2f6 - PWA customer link uses different Outlet bz-fbf53de2-8bae-4d9c-8599-882077fef716 (/plans)

IDOR caveat

booking.get_booking / customer.get_booking have no in-method owner check. Guest cannot call them. Cross-Customer IDOR depends on Frappe has_permission on BZBooking (UNKNOWN until those hooks are read).

Payment RPC caveat

payment.record_external_payment_transaction is defined twice in payment.py; the later definition wins. E2E must use the live signature on the deploy SHA.


Daily integrative scenarios (VP class first)

Run against DEV. Assert DocTypes. One golden path per class. No extra tests for another ATP mall.

Do not run S-883 until explicitly asked. Do not charge real cards (Datacap cert / test amount only if a write pass is approved).

Legend: R = read-only (safe now). W = mutates DEV (needs your go-ahead).

S-GP-VP — Golden party book (P0)

Class: VP-FRAPPE-PACKAGE-VENUE-DATACAP-PWA
Apps: venuplus-app → reservation-api-server
Mode: W (creates a Booking)

Steps: 1. Catalog Midway Play on Arnot Mall 2. get_timeslots — pick a slot with availableCount > 0 3. Acquire Active lock (cart.add_to_cart / lock_slot, ~600s) 4. create_booking without payment block → BZBooking.booking_status = Pending; lock Confirmed (not still Active) 5. Datacap sandbox capture (no PAN in Frappe) + record_external_payment_transaction (audit only) 6. finalize_booking_after_payment → Successful; lock still Confirmed; payment row exists

Pass: Successful Booking + ≥1 Confirmed BZBookingAvailability matching hold window (guest ± 30 min buffer). Fail if toast-only. Fail if create leaves lock Active.

S-NOTIMESLOT — No capacity

Mode: R

get_timeslots on a date with no schedule or availableCount 0.
Pass: HTTP 200 with timeSlots: [] (not 400) when no schedule / online booking off / all full. Do not create_booking.

S-LOCK-ABANDON — Cart lock dies

Mode: W (lock only, no pay)

Acquire Active lock, abandon checkout (or wait expiry).
Pass: lock Released/Expired; a second cart can lock the same Venue resource.

S-IDOR — Guest cannot read someone else's Booking

Mode: R

Using Successful bz-7f9efdd6-6ec9-4f16-be83-871a01d3a3c2 as victim.
Call get_booking as a different Customer/Guest.
Pass: 403/404, not the DocType payload. Guest must not be able to call get_booking. Cross-Customer IDOR is UNKNOWN without BZBooking permission hooks.

S-ADMIN-PATCH — In-place reschedule (safe path)

Mode: W (needs approval)

patch_booking date/time on a Successful Booking with Confirmed lock.
Pass: same availability name; still Confirmed; times moved; no Released row.

S-883 — Occupied-slot update_booking (VP only)

Mode: W forbidden until you say so
#883_lock_path=yes on this class.

Admin update_booking onto a slot covered by another Confirmed lock (e.g. 7i0ssj8s59 2026-09-15 10:00–13:00).
Assert BZBookingAvailability.lock_status, not toast.
Current develop: risk of Released with no replacement. PR 885: 400, original Confirmed intact.

S-WORKFLOW — Staff only (not daily PWA)

Mode: W (optional nightly)

apply_booking_workflow_action from Desk. Not part of guest checkout.

Explicitly not daily

  • Another ATP Outlet of this class
  • Game-card kiosk (create_gamecard_only_booking)
  • FiveStar / United Skates until those Outlet IDs are filled
  • 120 styling viewport matrix
  • Cartesian pay × day × guest count