Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
36315db
feat: UPI/QR payment support (manual verification)
rehanrehman389 Jan 27, 2026
e242a26
chore: replace UPI with generic off-platform payments
rehanrehman389 Feb 3, 2026
e8a16e2
fix: add optional payment proof upload
rehanrehman389 Feb 3, 2026
b1ae6d1
feat: payment and booking status field
rehanrehman389 Feb 3, 2026
9bac883
feat: add custom fields support for off-platform payments
rehanrehman389 Feb 3, 2026
90788ad
feat: add custom labels for off-platform payments
rehanrehman389 Feb 3, 2026
3ab0471
fix: resolve issues after rebase
rehanrehman389 Feb 9, 2026
eba3963
refactor: replace off-platform payment fields with HTML editor
rehanrehman389 Feb 9, 2026
cacd63c
Merge branch 'main' into upi-payment
rehanrehman389 Feb 9, 2026
4cafa50
fix: resolve conflict
rehanrehman389 Feb 9, 2026
0c5e89c
feat: off-platform unit test cases
rehanrehman389 Feb 10, 2026
f7dfaf5
test: Buzz-specific tests
rehanrehman389 Feb 10, 2026
8c7e79e
test: add e2e tests for off-platform payment
rehanrehman389 Feb 10, 2026
734f11e
chore: format code using pre-commit
rehanrehman389 Feb 10, 2026
230f626
fix: add missing translations
rehanrehman389 Feb 10, 2026
7eed975
refactor: use Text Editor for off-platform payment details
rehanrehman389 Feb 11, 2026
469c489
fix: ensure OTP verification before off-platform payment dialog
rehanrehman389 Feb 11, 2026
0d3bdff
Merge branch 'main' into upi-payment
NagariaHussain Feb 11, 2026
50f695e
refactor: clean up off-platform payment code for DRY, security, and c…
NagariaHussain Feb 11, 2026
3680ec9
fix: show payment gateway selection dialog for logged-in users with m…
NagariaHussain Feb 11, 2026
5fba404
fix: align payment details text and add spacing to upload label
NagariaHussain Feb 11, 2026
00a90f0
fix: show original filename after payment proof upload
NagariaHussain Feb 11, 2026
e86c89e
fix: remove top padding in payment details and use Lucide check icon
NagariaHussain Feb 11, 2026
8893bfa
refactor: rename "off-platform payment" to "offline payment" across c…
NagariaHussain Feb 11, 2026
48f0f69
fix: improve offline payment section description and upload UX
NagariaHussain Feb 11, 2026
ca9ec9e
fix: disable confetti for offline payment bookings pending approval
NagariaHussain Feb 11, 2026
aacdc67
fix: keep offline payment bookings in draft until approved
NagariaHussain Feb 11, 2026
bbbac22
fix: block manual submission of offline bookings and extract approve/…
NagariaHussain Feb 11, 2026
75c7b8d
fix: buttons
NagariaHussain Feb 11, 2026
2e876b6
fix: discard booking on rejection instead of keeping as draft
NagariaHussain Feb 11, 2026
dfa9ec9
fix: use inline refresh icon for payment proof replace action
NagariaHussain Feb 11, 2026
a6b9f62
chore: add nosemgrep comment for process_booking guest whitelist
NagariaHussain Feb 11, 2026
55918b9
fix: show actual payment status in booking financial summary
NagariaHussain Feb 11, 2026
338bc19
fix: add patch to set payment status for existing submitted bookings
NagariaHussain Feb 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 62 additions & 2 deletions buzz/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
from buzz.payments import get_payment_gateways_for_event, get_payment_link_for_booking
from buzz.utils import is_app_installed

OFFLINE_PAYMENT_METHOD = "Offline"
OFFLINE_PAYMENT_DEFAULT_LABEL = "Offline Payment"


@frappe.whitelist(allow_guest=True)
@rate_limit(key="identifier", limit=5, seconds=3600)
Expand Down Expand Up @@ -307,12 +310,28 @@ def get_event_booking_data(event_route: str) -> dict:
data.custom_fields = custom_fields

# Payment Gateways
data.payment_gateways = get_payment_gateways_for_event(event_doc.name)
payment_gateways = get_payment_gateways_for_event(event_doc.name)

# If offline payment is enabled, add it to the payment gateways list
if event_doc.enable_offline_payments:
offline_label = event_doc.offline_payment_label or OFFLINE_PAYMENT_DEFAULT_LABEL
payment_gateways.append(offline_label)

data.payment_gateways = payment_gateways

# Offline Payment Settings
data.offline_payment_enabled = event_doc.enable_offline_payments
if event_doc.enable_offline_payments:
data.offline_settings = {
"payment_details": event_doc.offline_payment_details,
"collect_payment_proof": event_doc.collect_payment_proof,
"label": event_doc.offline_payment_label or OFFLINE_PAYMENT_DEFAULT_LABEL,
}

return data


@frappe.whitelist(allow_guest=True)
@frappe.whitelist(allow_guest=True) # nosemgrep: frappe-semgrep-rules.rules.security.guest-whitelisted-method
def process_booking(
attendees: list[dict],
event: str,
Expand All @@ -324,6 +343,8 @@ def process_booking(
guest_full_name: str | None = None,
otp: str | None = None,
guest_phone: str | None = None,
payment_proof: str | None = None,
is_offline: bool = False,
) -> dict:
event_doc = frappe.get_cached_doc("Buzz Event", event)
is_guest = frappe.session.user == "Guest"
Expand Down Expand Up @@ -423,6 +444,45 @@ def process_booking(
booking.submit()
return {"booking_name": booking.name}

# Check if offline payment is explicitly requested and enabled
if is_offline:
if not event_doc.enable_offline_payments:
frappe.throw(_("Offline payment is not enabled for this event"))

booking.append(
"additional_fields",
{
"fieldname": "payment_method",
"value": OFFLINE_PAYMENT_METHOD,
"label": "Payment Method",
"fieldtype": "Data",
},
)

# Keep booking in draft until approved — don't submit
booking.status = "Approval Pending"
booking.payment_status = "Verification Pending"
booking.flags.ignore_permissions = True
booking.save()

# Attach payment proof if provided
if payment_proof:
try:
file_doc = frappe.get_doc(
{
"doctype": "File",
"file_url": payment_proof,
"attached_to_doctype": "Event Booking",
"attached_to_name": booking.name,
"is_private": 1,
}
)
file_doc.insert(ignore_permissions=True)
except Exception as e:
frappe.log_error(f"Failed to attach payment proof: {e}")

return {"booking_name": booking.name, "offline_payment": True}

return {
"payment_link": get_payment_link_for_booking(
booking.name,
Expand Down
14 changes: 7 additions & 7 deletions buzz/buzz/doctype/buzz_custom_field/buzz_custom_field.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,6 @@
"fieldname": "column_break_fpgn",
"fieldtype": "Column Break"
},
{
"default": "Booking",
"fieldname": "applied_to",
"fieldtype": "Select",
"label": "Applied To",
"options": "Booking\nTicket"
},
{
"fieldname": "label",
"fieldtype": "Data",
Expand Down Expand Up @@ -93,6 +86,13 @@
"fieldname": "default_value",
"fieldtype": "Data",
"label": "Default Value"
},
{
"default": "Booking",
"fieldname": "applied_to",
"fieldtype": "Select",
"label": "Applied To",
"options": "Booking\nTicket\nOffline Payment Form"
}
],
"grid_page_length": 50,
Expand Down
2 changes: 1 addition & 1 deletion buzz/buzz/doctype/buzz_custom_field/buzz_custom_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class BuzzCustomField(Document):
if TYPE_CHECKING:
from frappe.types import DF

applied_to: DF.Literal["Booking", "Ticket"]
applied_to: DF.Literal["Booking", "Ticket", "Offline Payment Form"]
default_value: DF.Data | None
enabled: DF.Check
event: DF.Link
Expand Down
43 changes: 41 additions & 2 deletions buzz/events/doctype/buzz_event/buzz_event.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,18 @@
"card_image",
"section_break_rmtj",
"allow_guest_booking",
"column_break_mijz",
"guest_verification_method",
"section_break_kwlt",
"featured_speakers",
"payments_tab",
"section_break_owtc",
"payment_gateways",
"offline_payment_section",
"enable_offline_payments",
"offline_payment_label",
"collect_payment_proof",
"column_break_xgh",
"offline_payment_details",
"tax_settings_section",
"apply_tax",
"tax_inclusive",
Expand Down Expand Up @@ -377,6 +382,40 @@
"fieldtype": "Section Break",
"label": "Tax Settings"
},
{
"description": "Allow attendees to pay offline (e.g. bank transfer, UPI) and submit proof for verification",
"fieldname": "offline_payment_section",
"fieldtype": "Section Break",
"label": "Offline Payment Settings"
},
{
"default": "0",
"fieldname": "enable_offline_payments",
"fieldtype": "Check",
"label": "Enable Offline Payments"
},
{
"depends_on": "eval:doc.enable_offline_payments==1",
"description": "Add payment details, instructions, QR codes, bank details, etc. Users can paste images and format content as needed.",
"fieldname": "offline_payment_details",
"fieldtype": "Text Editor",
"label": "Payment Details"
},
{
"default": "Offline Payment",
"depends_on": "eval:doc.enable_offline_payments==1",
"description": "Label displayed to users when selecting payment method (e.g., UPI Payment, Bank Transfer, etc.)",
"fieldname": "offline_payment_label",
"fieldtype": "Data",
"label": "Payment Method Label"
},
{
"default": "0",
"depends_on": "eval:doc.enable_offline_payments==1",
"fieldname": "collect_payment_proof",
"fieldtype": "Check",
"label": "Collect Proof of Payment"
},
{
"default": "0",
"fieldname": "apply_tax",
Expand Down Expand Up @@ -458,7 +497,7 @@
"fieldtype": "Section Break"
},
{
"fieldname": "column_break_mijz",
"fieldname": "column_break_xgh",
"fieldtype": "Column Break"
}
],
Expand Down
4 changes: 4 additions & 0 deletions buzz/events/doctype/buzz_event/buzz_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ class BuzzEvent(Document):
banner_image: DF.AttachImage | None
card_image: DF.AttachImage | None
category: DF.Link
collect_payment_proof: DF.Check
default_ticket_type: DF.Link | None
enable_offline_payments: DF.Check
end_date: DF.Date | None
end_time: DF.Time
external_registration_page: DF.Check
Expand All @@ -46,6 +48,8 @@ class BuzzEvent(Document):
medium: DF.Literal["In Person", "Online"]
meta_image: DF.AttachImage | None
name: DF.Int | None
offline_payment_details: DF.TextEditor | None
offline_payment_label: DF.Data | None
payment_gateways: DF.Table[EventPaymentGateway]
proposal: DF.Link | None
registration_url: DF.Data | None
Expand Down
3 changes: 2 additions & 1 deletion buzz/patches.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ buzz.patches.migrate_to_multi_payment_gateway
[post_model_sync]
# Patches added in this section will be executed after doctypes are migrated
buzz.patches.populate_slug_in_event_category
buzz.patches.set_applies_to_for_existing_coupons
buzz.patches.set_applies_to_for_existing_coupons
buzz.patches.set_payment_status_for_existing_bookings
13 changes: 13 additions & 0 deletions buzz/patches/set_payment_status_for_existing_bookings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import frappe


def execute():
EventBooking = frappe.qb.DocType("Event Booking")

# Set payment_status to "Paid" and status to "Confirmed" for all submitted bookings
(
frappe.qb.update(EventBooking)
.set(EventBooking.payment_status, "Paid")
.set(EventBooking.status, "Confirmed")
.where(EventBooking.docstatus == 1)
).run()
19 changes: 19 additions & 0 deletions buzz/ticketing/doctype/event_booking/event_booking.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,24 @@ frappe.ui.form.on("Event Booking", {
},
};
});

// Add Approve/Reject buttons for pending bookings
if (frappe.user.has_role("Event Manager") && frm.doc.status === "Approval Pending") {
frm.add_custom_button(__("Approve and Submit"), function () {
frappe.confirm("Are you sure you want to approve this booking?", function () {
frm.call("approve_booking").then(() => {
frm.refresh();
});
});
});

frm.add_custom_button(__("Reject"), function () {
frappe.confirm("Are you sure you want to reject this booking?", function () {
frm.call("reject_booking").then(() => {
frm.refresh();
});
});
});
}
},
});
33 changes: 32 additions & 1 deletion buzz/ticketing/doctype/event_booking/event_booking.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
"column_break_cjxu",
"user",
"naming_series",
"section_break_status",
"payment_status",
"column_break_status",
"status",
"section_break_xvkp",
"attendees",
"section_break_suav",
Expand Down Expand Up @@ -167,6 +171,33 @@
"label": "Discount Amount",
"options": "currency",
"read_only": 1
},
{
"fieldname": "section_break_status",
"fieldtype": "Section Break",
"label": "Status"
},
{
"default": "Unpaid",
"fieldname": "payment_status",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Payment Status",
"options": "Unpaid\nPaid\nVerification Pending",
"read_only": 1
},
{
"fieldname": "column_break_status",
"fieldtype": "Column Break"
},
{
"default": "Approval Pending",
"fieldname": "status",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Status",
"options": "Confirmed\nApproval Pending\nApproved\nRejected",
"read_only": 1
}
],
"grid_page_length": 50,
Expand All @@ -182,7 +213,7 @@
"link_fieldname": "reference_docname"
}
],
"modified": "2026-01-03 17:29:18.102192",
"modified": "2026-02-05 09:10:22.542973",
"modified_by": "Administrator",
"module": "Ticketing",
"name": "Event Booking",
Expand Down
Loading
Loading