From 6cc1d3a3ea72414c443404e661c1efe361bb402e Mon Sep 17 00:00:00 2001 From: vishwajeet-13 Date: Thu, 12 Mar 2026 04:05:23 +0530 Subject: [PATCH 1/3] feat: webinar plus registrations --- .../doctype/zoom_webinar/zoom_webinar.json | 25 ++++- .../doctype/zoom_webinar/zoom_webinar.py | 93 +++++++++++++++---- 2 files changed, 99 insertions(+), 19 deletions(-) diff --git a/zoom_integration/zoom_integration/doctype/zoom_webinar/zoom_webinar.json b/zoom_integration/zoom_integration/doctype/zoom_webinar/zoom_webinar.json index ac25ada..3a4f702 100644 --- a/zoom_integration/zoom_integration/doctype/zoom_webinar/zoom_webinar.json +++ b/zoom_integration/zoom_integration/doctype/zoom_webinar/zoom_webinar.json @@ -23,6 +23,10 @@ "attendance_synced", "column_break_lihm", "zoom_webinar_id", + "zoom_webinar_plus_section", + "zoom_event_id", + "column_break_oxmt", + "zoom_ticket_id", "section_break_tuka", "description" ], @@ -132,6 +136,25 @@ "fieldname": "timezone", "fieldtype": "Autocomplete", "label": "Timezone" + }, + { + "fieldname": "zoom_webinar_plus_section", + "fieldtype": "Section Break", + "label": "Zoom Webinar Plus" + }, + { + "fieldname": "zoom_event_id", + "fieldtype": "Data", + "label": "Zoom Event ID" + }, + { + "fieldname": "column_break_oxmt", + "fieldtype": "Column Break" + }, + { + "fieldname": "zoom_ticket_id", + "fieldtype": "Data", + "label": "Zoom Ticket ID" } ], "grid_page_length": 50, @@ -146,7 +169,7 @@ "link_fieldname": "webinar" } ], - "modified": "2025-12-09 13:30:38.107775", + "modified": "2026-03-11 10:25:34.016507", "modified_by": "Administrator", "module": "Zoom Integration", "name": "Zoom Webinar", diff --git a/zoom_integration/zoom_integration/doctype/zoom_webinar/zoom_webinar.py b/zoom_integration/zoom_integration/doctype/zoom_webinar/zoom_webinar.py index 02bcae1..e991ebb 100644 --- a/zoom_integration/zoom_integration/doctype/zoom_webinar/zoom_webinar.py +++ b/zoom_integration/zoom_integration/doctype/zoom_webinar/zoom_webinar.py @@ -36,7 +36,9 @@ class ZoomWebinar(Document): template: DF.Link | None timezone: DF.Autocomplete | None title: DF.Data + zoom_event_id: DF.Data | None zoom_link: DF.Data | None + zoom_ticket_id: DF.Data | None zoom_webinar_id: DF.Data | None # end: auto-generated types @@ -176,28 +178,81 @@ def add_registrant( if not additional_params: additional_params = {} - url = f"{ZOOM_API_BASE_PATH}/webinars/{self.zoom_webinar_id}/registrants" headers = get_authenticated_headers_for_zoom() - body = json.dumps( - {"email": email, "first_name": first_name, "last_name": last_name or "N/A", **additional_params} - ) - response = requests.post(url, headers=headers, data=body) - if response.status_code == 201: - data = response.json() - create_request_log( - data, is_remote_request=1, service_name="Zoom", request_headers=headers, status="Completed" + # Webinar Plus + if self.zoom_event_id and self.zoom_ticket_id: + url = f"{ZOOM_API_BASE_PATH}/zoom_events/events/{self.zoom_event_id}/tickets" + body = json.dumps( + { + "tickets": [ + { + "email": email, + "first_name": first_name, + "last_name": last_name or "N/A", + "ticket_type_id": self.zoom_ticket_id, + **additional_params, + } + ] + } ) - return data + response = requests.post(url, headers=headers, data=body) + if response.status_code in (200, 201): + data = response.json() + ticket = data.get("tickets", [{}])[0] + create_request_log( + data, + is_remote_request=1, + service_name="Zoom", + request_headers=headers, + status="Completed", + ) + return { + "registrant_id": ticket.get("ticket_id"), + "join_url": ticket.get("event_join_link"), + "email": ticket.get("email"), + } + else: + create_request_log( + response.text, + is_remote_request=1, + service_name="Zoom", + request_headers=headers, + status="Failed", + ) + frappe.throw(frappe._(f"Failed to add registrant: {response.text}")) + + # Normal Webinar else: - create_request_log( - response.text, - is_remote_request=1, - service_name="Zoom", - request_headers=headers, - status="Failed", + url = f"{ZOOM_API_BASE_PATH}/webinars/{self.zoom_webinar_id}/registrants" + body = json.dumps( + { + "email": email, + "first_name": first_name, + "last_name": last_name or "N/A", + **additional_params, + } ) - frappe.throw(frappe._(f"Failed to add registrant: {response.text}")) + response = requests.post(url, headers=headers, data=body) + if response.status_code == 201: + data = response.json() + create_request_log( + data, + is_remote_request=1, + service_name="Zoom", + request_headers=headers, + status="Completed", + ) + return data + else: + create_request_log( + response.text, + is_remote_request=1, + service_name="Zoom", + request_headers=headers, + status="Failed", + ) + frappe.throw(frappe._(f"Failed to add registrant: {response.text}")) @frappe.whitelist() def sync_attendance(self): @@ -225,7 +280,9 @@ def sync_attendance(self): for attendance in batch: registration = frappe.db.get_value( - "Zoom Webinar Registration", {"email": attendance.get("user_email", "N/A")}, "name" + "Zoom Webinar Registration", + {"email": attendance.get("user_email", "N/A")}, + "name", ) try: From 947535c1002a13cbc47b5412a5592b5b8ac8206a Mon Sep 17 00:00:00 2001 From: Hussain Nagaria Date: Fri, 13 Mar 2026 17:44:19 +0530 Subject: [PATCH 2/3] refactor: DRY up add_registrant by unifying shared request/logging logic Co-Authored-By: Claude Opus 4.6 --- .../doctype/zoom_webinar/zoom_webinar.py | 81 ++++++------------- 1 file changed, 26 insertions(+), 55 deletions(-) diff --git a/zoom_integration/zoom_integration/doctype/zoom_webinar/zoom_webinar.py b/zoom_integration/zoom_integration/doctype/zoom_webinar/zoom_webinar.py index e991ebb..d4174b2 100644 --- a/zoom_integration/zoom_integration/doctype/zoom_webinar/zoom_webinar.py +++ b/zoom_integration/zoom_integration/doctype/zoom_webinar/zoom_webinar.py @@ -179,9 +179,9 @@ def add_registrant( additional_params = {} headers = get_authenticated_headers_for_zoom() + is_webinar_plus = self.zoom_event_id and self.zoom_ticket_id - # Webinar Plus - if self.zoom_event_id and self.zoom_ticket_id: + if is_webinar_plus: url = f"{ZOOM_API_BASE_PATH}/zoom_events/events/{self.zoom_event_id}/tickets" body = json.dumps( { @@ -196,63 +196,34 @@ def add_registrant( ] } ) - response = requests.post(url, headers=headers, data=body) - if response.status_code in (200, 201): - data = response.json() - ticket = data.get("tickets", [{}])[0] - create_request_log( - data, - is_remote_request=1, - service_name="Zoom", - request_headers=headers, - status="Completed", - ) - return { - "registrant_id": ticket.get("ticket_id"), - "join_url": ticket.get("event_join_link"), - "email": ticket.get("email"), - } - else: - create_request_log( - response.text, - is_remote_request=1, - service_name="Zoom", - request_headers=headers, - status="Failed", - ) - frappe.throw(frappe._(f"Failed to add registrant: {response.text}")) - - # Normal Webinar else: url = f"{ZOOM_API_BASE_PATH}/webinars/{self.zoom_webinar_id}/registrants" body = json.dumps( - { - "email": email, - "first_name": first_name, - "last_name": last_name or "N/A", - **additional_params, - } + {"email": email, "first_name": first_name, "last_name": last_name or "N/A", **additional_params} ) - response = requests.post(url, headers=headers, data=body) - if response.status_code == 201: - data = response.json() - create_request_log( - data, - is_remote_request=1, - service_name="Zoom", - request_headers=headers, - status="Completed", - ) - return data - else: - create_request_log( - response.text, - is_remote_request=1, - service_name="Zoom", - request_headers=headers, - status="Failed", - ) - frappe.throw(frappe._(f"Failed to add registrant: {response.text}")) + + response = requests.post(url, headers=headers, data=body) + + if response.status_code not in (200, 201): + create_request_log( + response.text, is_remote_request=1, service_name="Zoom", request_headers=headers, status="Failed" + ) + frappe.throw(frappe._(f"Failed to add registrant: {response.text}")) + + data = response.json() + create_request_log( + data, is_remote_request=1, service_name="Zoom", request_headers=headers, status="Completed" + ) + + if is_webinar_plus: + ticket = data.get("tickets", [{}])[0] + return { + "registrant_id": ticket.get("ticket_id"), + "join_url": ticket.get("event_join_link"), + "email": ticket.get("email"), + } + + return data @frappe.whitelist() def sync_attendance(self): From 2471419b0f724609e60b2df1b89fecf3622b9ff2 Mon Sep 17 00:00:00 2001 From: Hussain Nagaria Date: Fri, 13 Mar 2026 17:45:53 +0530 Subject: [PATCH 3/3] chore: pre-commit --- .../doctype/zoom_webinar/zoom_webinar.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/zoom_integration/zoom_integration/doctype/zoom_webinar/zoom_webinar.py b/zoom_integration/zoom_integration/doctype/zoom_webinar/zoom_webinar.py index d4174b2..c55b5ec 100644 --- a/zoom_integration/zoom_integration/doctype/zoom_webinar/zoom_webinar.py +++ b/zoom_integration/zoom_integration/doctype/zoom_webinar/zoom_webinar.py @@ -199,14 +199,23 @@ def add_registrant( else: url = f"{ZOOM_API_BASE_PATH}/webinars/{self.zoom_webinar_id}/registrants" body = json.dumps( - {"email": email, "first_name": first_name, "last_name": last_name or "N/A", **additional_params} + { + "email": email, + "first_name": first_name, + "last_name": last_name or "N/A", + **additional_params, + } ) response = requests.post(url, headers=headers, data=body) if response.status_code not in (200, 201): create_request_log( - response.text, is_remote_request=1, service_name="Zoom", request_headers=headers, status="Failed" + response.text, + is_remote_request=1, + service_name="Zoom", + request_headers=headers, + status="Failed", ) frappe.throw(frappe._(f"Failed to add registrant: {response.text}"))