Skip to content

feat(registrations): approval-required registrations for free events - #663

Draft
harshtandiya wants to merge 11 commits into
developfrom
claude/elegant-fermat-tca4th
Draft

harshtandiya wants to merge 11 commits into
developfrom
claude/elegant-fermat-tca4th

Conversation

@harshtandiya

@harshtandiya harshtandiya commented Oct 25, 2026 •

Copy link
Copy Markdown
Collaborator

What changed

Organizers can review registrations before guests get a ticket, as on Luma.

How it works

  • Turn on Requires approval for a ticket type (ticket type drawer), or for every ticket with the Approval tile in the Registration page's quick actions.
  • A guest's registration becomes a request: a draft booking with status Approval Pending. No tickets are issued and no capacity is used. The guest sees "pending approval" and gets a pending email. The event's team gets an in-app notification.
  • Requests appear under Guests → Pending (N) as normal guest rows, with Approve and Decline icon buttons. Opening a row shows the guest drawer with the request's answers, attendees, request time and a "Previously declined" tag. An alert in the drawer holds the Approve and Decline buttons. Declining takes an optional message.
    • Approve submits the booking: tickets are issued and a "You're in" email is sent. Capacity is checked at this point, so approving into a sold-out ticket type fails and the request stays pending.
    • Decline discards the booking and emails the guest. The guest can request again.
  • Guests can withdraw a pending request. A daily job expires requests whose event has ended.
  • Turning approval off while requests are waiting asks whether to keep them pending, approve them all, or decline them all.
  • Bookings that an organizer adds skip approval.
  • Also removes the "Copy check-in link" quick action from the Guests page.

Limits

  • Free events only. Approval can't be turned on while any ticket type or add-on has a price, and a price can't be added while approval is on. Paid support is tracked in Approval-required registrations for paid events (payment link on approval) #662.
  • Approval covers a whole booking, not individual attendees.
  • There is no multi-select in the Pending list. Bulk approve or decline happens only when approval is turned off.
  • The Pending tab shows the 100 oldest requests. Its count includes all of them.
  • The pending email and the decline email use built-in templates; there is no per-event override yet. The approval email uses the event's custom confirmation template when one is set.
  • Offline-payment approvals still happen in Desk. There is no waitlist yet.

Demo

These screenshots were rendered from the dashboard with a mocked API.

Guests → Pending
Pending tab

Request in the guest drawer
Request drawer

Registration → Approval quick action
Approval tile

Turning approval off with requests waiting
Turn-off dialog

Guest booking page while pending
Guest pending

Testing

  • Backend: buzz/api/booking/test_approvals.py and buzz/ticketing/doctype/event_booking/test_approval_booking.py cover the lifecycle, emails, the free-only rule, turn-off actions and permissions.
  • Dashboard: unit tests in bookingApproval.test.ts.
  • E2E: e2e/tests/approval-registration.spec.ts covers request → approve, decline with a message, and turn-off with "Keep them pending".

🤖 Generated with Claude Code

https://claude.ai/code/session_012a5qiK2oG4vUEFh3y5ybNC

Organizers can require approval per ticket type, or for every ticket on
the event. A registration that needs approval stays a draft booking with
status Approval Pending: no tickets, no capacity taken. The organizer
approves or declines it from a Pending tab on the Guests page, one at a
time or in bulk.

- Approving submits the booking. Capacity is checked then, so approving
  into a sold-out ticket type fails and the request stays pending.
- Declining discards the booking. An optional message goes in the email.
- Pending, approved and declined emails are always sent.
- Guests can withdraw a pending request. A daily job expires requests
  whose event has ended.
- Hosts get an in-app notification for each new request.
- Turning approval off with requests waiting asks the organizer to keep,
  approve or decline them.
- Approval is refused while the event has any priced ticket type or
  add-on.
- Bookings that an organizer adds skip approval.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012a5qiK2oG4vUEFh3y5ybNC

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@github-actions

github-actions Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

⏸️ UI Demo Check — paused while this is a draft.

@github-actions

github-actions Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Backend test coverage: 93%

Commit 83f0268. Test modules are excluded.

Coverage by file
Name Stmts Miss Cover
buzz/__init__.py 5 5 0%
buzz/analytics.py 32 2 94%
buzz/api/account/__init__.py 32 2 94%
buzz/api/account/exceptions.py 8 0 100%
buzz/api/account/schemas.py 7 0 100%
buzz/api/account/services.py 15 1 93%
buzz/api/auth/__init__.py 11 0 100%
buzz/api/auth/schemas.py 3 0 100%
buzz/api/booking/__init__.py 48 2 96%
buzz/api/booking/approvals.py 128 4 97%
buzz/api/booking/coupons.py 25 0 100%
buzz/api/booking/details.py 98 6 94%
buzz/api/booking/downloads.py 37 0 100%
buzz/api/booking/event_data.py 49 4 92%
buzz/api/booking/exceptions.py 46 0 100%
buzz/api/booking/guests.py 71 10 86%
buzz/api/booking/holds.py 64 1 98%
buzz/api/booking/my_bookings.py 9 3 67%
buzz/api/booking/schemas.py 57 0 100%
buzz/api/booking/services.py 249 18 93%
buzz/api/campaigns/__init__.py 34 19 44%
buzz/api/campaigns/exceptions.py 11 0 100%
buzz/api/campaigns/schemas.py 2 0 100%
buzz/api/checkin/__init__.py 21 0 100%
buzz/api/checkin/exceptions.py 20 0 100%
buzz/api/checkin/schemas.py 12 0 100%
buzz/api/checkin/services.py 107 2 98%
buzz/api/comments/__init__.py 29 0 100%
buzz/api/comments/activity.py 55 1 98%
buzz/api/comments/email_content.py 90 1 99%
buzz/api/comments/exceptions.py 17 0 100%
buzz/api/comments/schemas.py 17 0 100%
buzz/api/comments/services.py 85 3 96%
buzz/api/communications/__init__.py 16 0 100%
buzz/api/communications/exceptions.py 11 0 100%
buzz/api/communications/schemas.py 6 0 100%
buzz/api/communications/services.py 64 1 98%
buzz/api/communities/__init__.py 62 1 98%
buzz/api/communities/creation.py 26 1 96%
buzz/api/communities/exceptions.py 19 0 100%
buzz/api/communities/notifications.py 34 2 94%
buzz/api/communities/queries.py 36 0 100%
buzz/api/communities/reviews.py 39 1 97%
buzz/api/communities/schemas.py 14 0 100%
buzz/api/communities/submissions.py 54 1 98%
buzz/api/events/__init__.py 52 0 100%
buzz/api/events/collaborators.py 100 4 96%
buzz/api/events/coupons.py 41 0 100%
buzz/api/events/exceptions.py 44 0 100%
buzz/api/events/guest_zones.py 48 0 100%
buzz/api/events/schemas.py 107 0 100%
buzz/api/events/services.py 237 10 96%
buzz/api/events/taxes.py 19 0 100%
buzz/api/events/ticket_types.py 53 0 100%
buzz/api/events/zoom.py 15 1 93%
buzz/api/exceptions.py 23 0 100%
buzz/api/filters/conditions.py 106 2 98%
buzz/api/filters/exceptions.py 5 0 100%
buzz/api/filters/schemas.py 6 0 100%
buzz/api/forms/__init__.py 24 0 100%
buzz/api/forms/answers.py 77 14 82%
buzz/api/forms/exceptions.py 27 0 100%
buzz/api/forms/fields.py 82 3 96%
buzz/api/forms/schemas.py 7 0 100%
buzz/api/forms/services.py 119 1 99%
buzz/api/imports/__init__.py 13 0 100%
buzz/api/imports/exceptions.py 20 0 100%
buzz/api/imports/schemas.py 28 0 100%
buzz/api/imports/services.py 65 5 92%
buzz/api/imports/sponsors.py 165 2 99%
buzz/api/imports/spreadsheet.py 41 3 93%
buzz/api/listings/__init__.py 9 0 100%
buzz/api/listings/exceptions.py 4 0 100%
buzz/api/listings/schemas.py 3 0 100%
buzz/api/listings/services.py 33 0 100%
buzz/api/maps/__init__.py 20 0 100%
buzz/api/maps/exceptions.py 11 0 100%
buzz/api/maps/schemas.py 9 0 100%
buzz/api/maps/services.py 65 0 100%
buzz/api/notifications/__init__.py 12 0 100%
buzz/api/notifications/schemas.py 9 0 100%
buzz/api/notifications/services.py 50 0 100%
buzz/api/payments/__init__.py 10 1 90%
buzz/api/payments/currencies.py 7 2 71%
buzz/api/payments/schemas.py 2 0 100%
buzz/api/playground/__init__.py 24 1 96%
buzz/api/playground/exceptions.py 9 0 100%
buzz/api/playground/schemas.py 6 0 100%
buzz/api/playground/services.py 91 5 95%
buzz/api/proposals/__init__.py 18 0 100%
buzz/api/proposals/exceptions.py 5 0 100%
buzz/api/proposals/schemas.py 26 0 100%
buzz/api/proposals/services.py 106 1 99%
buzz/api/schemas.py 13 0 100%
buzz/api/sponsorships/__init__.py 41 0 100%
buzz/api/sponsorships/enquiries.py 74 2 97%
buzz/api/sponsorships/exceptions.py 22 0 100%
buzz/api/sponsorships/forms.py 64 2 97%
buzz/api/sponsorships/manage.py 22 1 95%
buzz/api/sponsorships/schemas.py 21 0 100%
buzz/api/sponsorships/services.py 67 1 99%
buzz/api/sponsorships/sponsors.py 29 0 100%
buzz/api/tags/__init__.py 9 0 100%
buzz/api/tags/desk.py 35 9 74%
buzz/api/tags/exceptions.py 8 0 100%
buzz/api/tags/schemas.py 2 0 100%
buzz/api/tags/services.py 56 0 100%
buzz/api/teams/__init__.py 51 2 96%
buzz/api/teams/calendar.py 28 0 100%
buzz/api/teams/exceptions.py 26 0 100%
buzz/api/teams/invitations.py 34 0 100%
buzz/api/teams/public_page.py 26 8 69%
buzz/api/teams/schemas.py 14 0 100%
buzz/api/teams/services.py 105 1 99%
buzz/api/tickets/__init__.py 15 0 100%
buzz/api/tickets/emails.py 14 9 36%
buzz/api/tickets/exceptions.py 29 0 100%
buzz/api/tickets/schemas.py 4 0 100%
buzz/api/tickets/services.py 85 0 100%
buzz/api/tickets/windows.py 12 0 100%
buzz/booking_permissions.py 47 3 94%
buzz/buzz/doctype/buzz_custom_field/buzz_custom_field.py 20 4 80%
buzz/buzz/doctype/buzz_notification_subscription/buzz_notification_subscription.py 3 0 100%
buzz/buzz/web_form/apply_for_sponsorship/apply_for_sponsorship.py 3 3 0%
buzz/buzz/web_form/propose_a_talk/propose_a_talk.py 3 3 0%
buzz/buzz_marketing/doctype/buzz_campaign/buzz_campaign.py 21 7 67%
buzz/comments.py 81 4 95%
buzz/emails.py 19 0 100%
buzz/events/banner_pattern.py 35 0 100%
buzz/events/buzz_events_listing.py 52 11 79%
buzz/events/countdown.py 13 0 100%
buzz/events/doctype/additional_event_page/additional_event_page.py 9 0 100%
buzz/events/doctype/buzz_event/buzz_event.py 288 22 92%
buzz/events/doctype/buzz_event_collaborator/buzz_event_collaborator.py 47 2 96%
buzz/events/doctype/buzz_event_form/buzz_event_form.py 11 4 64%
buzz/events/doctype/buzz_form_field/buzz_form_field.py 3 0 100%
buzz/events/doctype/buzz_price/buzz_price.py 10 0 100%
buzz/events/doctype/buzz_settings/buzz_settings.py 26 4 85%
buzz/events/doctype/buzz_tag/buzz_tag.py 30 2 93%
buzz/events/doctype/buzz_tag_link/buzz_tag_link.py 14 2 86%
buzz/events/doctype/buzz_team/buzz_team.py 102 3 97%
buzz/events/doctype/buzz_team/team_map.py 23 0 100%
buzz/events/doctype/buzz_team/team_page.py 99 2 98%
buzz/events/doctype/buzz_team_membership/buzz_team_membership.py 93 1 99%
buzz/events/doctype/buzz_team_settings/buzz_team_settings.py 45 0 100%
buzz/events/doctype/buzz_theme/buzz_theme.py 50 3 94%
buzz/events/doctype/buzz_theme/tokens.py 29 1 97%
buzz/events/doctype/buzz_theme_token/buzz_theme_token.py 3 0 100%
buzz/events/doctype/community_event_request/community_event_request.py 59 13 78%
buzz/events/doctype/event_category/event_category.py 9 0 100%
buzz/events/doctype/event_check_in/event_check_in.py 19 2 89%
buzz/events/doctype/event_check_in_zone/event_check_in_zone.py 40 0 100%
buzz/events/doctype/event_check_in_zone_ticket_type/event_check_in_zone_ticket_type.py 3 0 100%
buzz/events/doctype/event_cohost/event_cohost.py 4 0 100%
buzz/events/doctype/event_communication/event_communication.py 16 0 100%
buzz/events/doctype/event_external_link/event_external_link.py 4 0 100%
buzz/events/doctype/event_featured_speaker/event_featured_speaker.py 4 0 100%
buzz/events/doctype/event_feedback/event_feedback.py 4 0 100%
buzz/events/doctype/event_host/event_host.py 4 0 100%
buzz/events/doctype/event_payment_gateway/event_payment_gateway.py 4 0 100%
buzz/events/doctype/event_sponsor/event_sponsor.py 15 2 87%
buzz/events/doctype/event_talk/event_talk.py 8 0 100%
buzz/events/doctype/event_template/event_template.py 43 4 91%
buzz/events/doctype/event_template_add_on/event_template_add_on.py 4 0 100%
buzz/events/doctype/event_template_custom_field/event_template_custom_field.py 4 0 100%
buzz/events/doctype/event_template_ticket_category/event_template_ticket_category.py 4 0 100%
buzz/events/doctype/event_template_ticket_type/event_template_ticket_type.py 4 0 100%
buzz/events/doctype/event_topic/event_topic.py 18 5 72%
buzz/events/doctype/event_topic/topic_page.py 32 32 0%
buzz/events/doctype/event_topic_link/event_topic_link.py 3 0 100%
buzz/events/doctype/event_track/event_track.py 4 0 100%
buzz/events/doctype/event_user_preferences/event_user_preferences.py 4 4 0%
buzz/events/doctype/event_venue/details.py 37 1 97%
buzz/events/doctype/event_venue/event_venue.py 95 1 99%
buzz/events/doctype/event_venue/geocode.py 72 9 88%
buzz/events/doctype/event_venue/map_link.py 106 5 95%
buzz/events/doctype/event_venue_location/event_venue_location.py 3 0 100%
buzz/events/doctype/offline_payment_method/offline_payment_method.py 11 0 100%
buzz/events/doctype/schedule_item/schedule_item.py 4 0 100%
buzz/events/doctype/social_media_link/social_media_link.py 3 0 100%
buzz/events/doctype/speaker_profile/speaker_profile.py 8 0 100%
buzz/events/doctype/sponsor_enquiry_form/sponsor_enquiry_form.py 54 5 91%
buzz/events/doctype/sponsorship_tier/sponsorship_tier.py 27 1 96%
buzz/events/doctype/talk_speaker/talk_speaker.py 3 0 100%
buzz/events/doctype/utm_parameter/utm_parameter.py 4 0 100%
buzz/events/og_image.py 141 7 95%
buzz/events/og_text.py 66 1 98%
buzz/events/online_meeting.py 42 0 100%
buzz/events/report/event_attendance_summary/event_attendance_summary.py 65 32 51%
buzz/events/report/event_overview/event_overview.py 27 0 100%
buzz/hooks.py 41 0 100%
buzz/html_lines.py 66 1 98%
buzz/install.py 66 32 52%
buzz/integrations/zoom.py 3 3 0%
buzz/islands.py 9 1 89%
buzz/payments.py 96 33 66%
buzz/permissions.py 182 13 93%
buzz/playground/__init__.py 32 9 72%
buzz/playground/checklist.py 64 43 33%
buzz/playground/cleanup.py 43 5 88%
buzz/playground/demo_data.py 95 3 97%
buzz/playground/doctype/playground_email/playground_email.py 4 0 100%
buzz/playground/doctype/playground_sandbox/playground_sandbox.py 6 0 100%
buzz/playground/inbox.py 67 9 87%
buzz/proposals/description.py 68 0 100%
buzz/proposals/doctype/event_proposal/event_proposal.py 71 5 93%
buzz/proposals/doctype/proposal_speaker/proposal_speaker.py 4 0 100%
buzz/proposals/doctype/sponsorship_deck_item/sponsorship_deck_item.py 4 0 100%
buzz/proposals/doctype/sponsorship_enquiry/sponsorship_enquiry.py 81 5 94%
buzz/proposals/doctype/talk_proposal/talk_proposal.py 96 5 95%
buzz/proposals/doctype/talk_proposal_status/talk_proposal_status.py 4 0 100%
buzz/subscriptions.py 45 1 98%
buzz/tasks.py 17 3 82%
buzz/telemetry.py 46 0 100%
buzz/telemetry_scan.py 55 8 85%
buzz/ticketing/approval.py 35 1 97%
buzz/ticketing/doctype/additional_field/additional_field.py 4 0 100%
buzz/ticketing/doctype/attendee_ticket_add_on/attendee_ticket_add_on.py 3 0 100%
buzz/ticketing/doctype/buzz_coupon_code/buzz_coupon_code.py 153 2 99%
buzz/ticketing/doctype/buzz_coupon_ticket_type/buzz_coupon_ticket_type.py 4 0 100%
buzz/ticketing/doctype/event_booking/event_booking.py 394 19 95%
buzz/ticketing/doctype/event_booking_attendee/event_booking_attendee.py 20 7 65%
buzz/ticketing/doctype/event_booking_refund/event_booking_refund.py 56 0 100%
buzz/ticketing/doctype/event_booking_refund_ticket/event_booking_refund_ticket.py 4 0 100%
buzz/ticketing/doctype/event_payment/event_payment.py 4 0 100%
buzz/ticketing/doctype/event_ticket/event_ticket.py 73 7 90%
buzz/ticketing/doctype/event_ticket_category/event_ticket_category.py 27 0 100%
buzz/ticketing/doctype/event_ticket_type/event_ticket_type.py 95 0 100%
buzz/ticketing/doctype/ticket_add_on/ticket_add_on.py 11 1 91%
buzz/ticketing/doctype/ticket_add_on_value/ticket_add_on_value.py 3 0 100%
buzz/ticketing/doctype/ticket_cancellation_item/ticket_cancellation_item.py 4 0 100%
buzz/ticketing/doctype/ticket_cancellation_request/ticket_cancellation_request.py 19 1 95%
buzz/ticketing/doctype/ticket_hold/ticket_hold.py 44 1 98%
buzz/ticketing/report/detailed_event_registrations/detailed_event_registrations.py 113 5 96%
buzz/ticketing/report/event_add_ons_overview/event_add_ons_overview.py 22 3 86%
buzz/uninstall.py 10 2 80%
buzz/utils.py 139 22 84%
buzz/www/community.py 24 0 100%
buzz/www/dashboard.py 27 3 89%
buzz/www/event/banner_color.py 20 6 70%
buzz/www/event/date_range.py 42 5 88%
buzz/www/event/dot_map.py 38 2 95%
buzz/www/event/index.py 163 6 96%
buzz/www/event/link_icons.py 1 0 100%
buzz/www/event/meta.py 64 5 92%
buzz/www/event/registration.py 84 15 82%
buzz/www/event/venue_map.py 35 1 97%
buzz/www/events.py 102 9 91%
buzz/www/events_sitemap.py 11 0 100%
buzz/www/site_header.py 40 1 98%
buzz/www/user_profile.py 36 0 100%
TOTAL 10283 689 93%

106 empty files skipped.

- Refuse a direct submit of a pending request. Frappe sets docstatus to
  1 before before_submit runs, so the old guard never fired.
- set_approval also needs ticketing write, since it saves the event or
  ticket type.
- Approving still works after a ticket type stops selling, and is
  refused once the request carries a price.
- A bulk decline skips requests that are no longer pending.
- withdraw_booking doesn't reveal whether a booking exists.
- A failed host notification or a failed expiry is logged and does not
  roll back the booking or the rest of the run.
- The pending list is capped at 100, and its total counts every request.
- Ticket rows show a "Requires approval" badge, and answers line up in a
  grid.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012a5qiK2oG4vUEFh3y5ybNC

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

- Set the approval switch to a target state instead of toggling it, so a
  retried test doesn't turn approval back off.
- Skip a new request when one is already pending.
- Drop a label check that ran before the final step.
- ensureTestTeam only writes Buzz Team Settings when the paid-events
  flag is off. Setups run in parallel, and their concurrent writes to the
  same row deadlocked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012a5qiK2oG4vUEFh3y5ybNC

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

…e ticket type cache

Buzz Price.parent is a text column, so an integer filter made MariaDB
compare numerically and fail on hash-named rows. The price was also
changed in the database without refreshing the cached ticket type.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012a5qiK2oG4vUEFh3y5ybNC
The server redirects every free booking, approval requests included, to
/booking-success, which shows the pending notice.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012a5qiK2oG4vUEFh3y5ybNC

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@harshtandiya
harshtandiya marked this pull request as draft October 25, 2026 20:56
…equests

frappe-ui TabButtons renders a radio group. A retried test now declines
the requester's earlier pending request first, since a guest can have
only one pending request per event.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012a5qiK2oG4vUEFh3y5ybNC
…alog opens

The dialog that asks about waiting requests rendered behind the open
drawer, so an organizer turning approval off for a ticket type could not
see or click it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012a5qiK2oG4vUEFh3y5ybNC
…equests

- A pending request renders as a normal guest row, with Approve and
  Decline icon buttons at its end. The custom card, its inline answers
  and the bulk selection bar are removed.
- The guest drawer shows a request's answers, attendees and request time.
  A bordered section in it holds the Approve and Decline buttons.
- The event-wide approval switch moves from the main column to an
  Approval tile in the Registration page's quick actions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012a5qiK2oG4vUEFh3y5ybNC
- The drawer's approve/decline section is a frappe-ui Alert, with Approve
  and Decline as its actions.
- The Pending row buttons are subtle green and red.
- The "Copy check-in link" quick action is removed from the Guests page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012a5qiK2oG4vUEFh3y5ybNC
…a string

The row's 'Open Approved Requester' button also matched 'Approve' as a
substring, and decline_bookings rejects an integer event name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012a5qiK2oG4vUEFh3y5ybNC
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants