Uh oh!
There was an error while loading. Please reload this page.
fix(booking): validate phone numbers on the guest and custom-field paths (backport #335) - #336
Conversation
…ths (backport #335) (cherry picked from commit 23644b7) The e2e team fixtures from the original PR are dropped: main has no Buzz Team doctype (team-based multi-tenancy, #312, is develop-only), so `ensureTestTeam` and the `team` stamps have nothing to bind to here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EePTfzyKVxj7bcpbF9roWx
Greptile SummaryThis backport adds server-side validation for guest OTP phone numbers and Phone custom fields before booking side effects, and updates the guest form to use the shared phone input with inline errors.
Confidence Score: 4/5The PR should not merge until Phone custom-field validation preserves each field's application scope, otherwise legitimate bookings can be rejected when fieldnames overlap. The new fieldname-only phone map is shared across booking and attendee payloads even though custom-field definitions and persistence are scope-specific, allowing a Phone definition in one scope to misclassify a same-named non-Phone field in another. Files Needing Attention: buzz/api/booking/services.py
|
| Filename | Overview |
|---|---|
| buzz/api/booking/guests.py | Adds phone-format validation before OTP generation while preserving the submitted identifier used by the cache key. |
| buzz/api/booking/services.py | Moves Phone custom-field validation ahead of booking side effects and validates guest phones at submission, but conflates custom-field scopes in one fieldname map. |
| buzz/api/booking/test_booking.py | Adds coverage for OTP phone validation, booking and attendee Phone fields, and preserving an OTP when early validation fails. |
| dashboard/src/components/BookingForm.vue | Uses PhoneInput for guest phone OTP entry and routes phone OTP-send failures to an inline field error. |
| dashboard/src/components/PhoneInput.vue | Adds an optional inline ErrorMessage without changing existing callers that omit the new prop. |
| e2e/tests/guest-booking.spec.ts | Adds an end-to-end assertion that a too-short guest phone is rejected without opening the OTP dialog. |
Prompt To Fix All With AI
### Issue 1
buzz/api/booking/services.py:172-175
**Custom-field scopes are conflated**
When an event has a Phone field in one scope and a same-named non-Phone field in another, the fieldname-only map applies phone validation to both booking and attendee payloads, causing a valid non-phone value to fail the booking.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Reviews (1): Last reviewed commit: "fix(booking): validate phone numbers on ..." | Re-trigger Greptile
| filters={"event": self.request.event, "enabled": 1, "fieldtype": "Phone"}, | ||
| fields=["fieldname", "label"], | ||
| ) | ||
| return {field.fieldname: field.label for field in phone_fields} |
There was a problem hiding this comment.
Custom-field scopes are conflated
When an event has a Phone field in one scope and a same-named non-Phone field in another, the fieldname-only map applies phone validation to both booking and attendee payloads, causing a valid non-phone value to fail the booking.
Prompt To Fix With AI
This is a comment left during a code review.
Path: buzz/api/booking/services.py
Line: 172-175
Comment:
**Custom-field scopes are conflated**
When an event has a Phone field in one scope and a same-named non-Phone field in another, the fieldname-only map applies phone validation to both booking and attendee payloads, causing a valid non-phone value to fail the booking.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.There was a problem hiding this comment.
Real but pre-existing, and deliberately not fixed here.
phone_field_labels is byte-identical to what is already on main — git show origin/main:buzz/api/booking/services.py has the same unfiltered query, and attendee_row already passed that map to validate_custom_fields. So an event carrying a Phone field and a same-named non-Phone field in another scope already mis-validates the attendee payload today; this PR extends the same map to the booking payload rather than introducing the conflation.
It is reachable — BuzzCustomField.validate scrubs fieldname from label with no uniqueness constraint on (event, fieldname), so two fields named "Contact Number" under different applied_to values collide. But the fix belongs on develop, where the code now lives, not in a backport whose whole job is to land #335's behaviour on main unchanged. Diverging the two branches here would make the next backport conflict for no gain.
Leaving as-is; worth a separate issue against develop if the collision is considered worth closing.
Generated by Claude Code
Uh oh!
There was an error while loading. Please reload this page.
Manual backport of #335 to
main, after the automated backport action failed to cherry-pick.Why the action failed
The squashed commit (
23644b7) touches two unrelated things: the phone-validation fix, and the E2E fixture change that stamps an explicitteamon everyBuzz Event/Event Host. That second part depends on team-based multi-tenancy (#312), which lives only ondevelop—mainhas noBuzz Teamdoctype and noensureTeamMembershiphelper.Cherry-picking the whole commit conflicts in
e2e/tests/auth.setup.tsande2e/tests/check-in.setup.ts, and the hunks that do auto-merge are worse than the conflicts: they quietly introduceensureTestTeam,teamfields and a call to a helper that does not exist onmain, so the E2E suite would fail to compile.What this PR carries
Only the fix and its tests — the E2E team fixtures are dropped, since there is nothing on
mainfor them to bind to:buzz/api/booking/guests.py— validate the phone branch ofsend_booking_otpwithvalidate_phone_number_with_country_code. Validate only, never rewrite, so the OTP cache key stays identical on both the send and verify sides.buzz/api/booking/services.py— onevalidate_phone_fields, called fromprocess()beforebuild_booking(), covering booking-level and attendee-level Phone custom fields. Running it early matters:verify_guest_otpdeletes the code from the cache with no rollback, so validating later cost the guest a valid OTP and leftAttendee Ticket Add-onrows behind.verify_guestalso validates the guest phone at submit, covering the direct-API path.dashboard/src/components/BookingForm.vue— swap the guest phoneFormControlfor the existingPhoneInput, and surface OTP-send errors under the field instead of in a toast.dashboard/src/components/PhoneInput.vue— optionalerrorprop rendering frappe-ui'sErrorMessage. Existing callers pass nothing and are unchanged.buzz/api/booking/test_booking.py—TestSendGuestBookingOtpandTestBookingPhoneCustomFields, unchanged from fix(booking): validate phone numbers on the guest and custom-field paths #335 and free of any team references.e2e/tests/guest-booking.spec.ts— the too-short-number case, which needs no team.Verification
main's version ofe2e/helpers/frappe.tsand the six*.setup.tsfixtures; the remaining diff is 6 files, +155/−11, and applies with no fuzz.python -m py_compileclean on the three changed Python files; imports the fix relies on (validate_phone_number_with_country_code,validate_custom_fields,watchinBookingForm.vue) all already exist onmain.set_event,booking_request,free_ticket_type, theAdditional Fieldchild doctype) are present onmain.bench run-testsand Playwright were not run here — this sandbox has no bench site. CI on this PR is the real check.Fixes#325 on the
mainline.Generated by Claude Code