From fe38c9998088ecf89a2321aaa4d87943ea6f2ca4 Mon Sep 17 00:00:00 2001 From: NaseeraVP Date: Wed, 8 Apr 2026 15:44:27 +0530 Subject: [PATCH] feat: Added approval validation and email notifications for Travel Request --- .../travel_request/travel_request.py | 107 ++++++++++++++++++ gams/hooks.py | 13 +-- 2 files changed, 113 insertions(+), 7 deletions(-) create mode 100644 gams/general_administration_management_system/custom_scripts/travel_request/travel_request.py diff --git a/gams/general_administration_management_system/custom_scripts/travel_request/travel_request.py b/gams/general_administration_management_system/custom_scripts/travel_request/travel_request.py new file mode 100644 index 0000000..56141f1 --- /dev/null +++ b/gams/general_administration_management_system/custom_scripts/travel_request/travel_request.py @@ -0,0 +1,107 @@ +# Copyright (c) 2026, efeone and contributors +# For license information, please see license.txt +import frappe +from frappe.utils import get_url_to_form + +def before_save(doc, method): + ''' + Prevent self-approval of Travel Requests + ''' + if doc.workflow_state == "Approved": + + if doc.owner == frappe.session.user: + frappe.throw("You cannot approve your own Travel Request.") + + if doc.employee: + user = frappe.db.get_value("Employee", doc.employee, "user_id") + + if user and user == frappe.session.user: + frappe.throw("You cannot approve your own Travel Request.") + +def on_update(doc, method): + ''' + Send email notifications on Travel Request submission and status changes + ''' + if doc.workflow_state == "Submitted": + emails = get_manager_emails() + + if emails: + frappe.sendmail( + recipients=emails, + subject=f"Travel Request {doc.name} Submitted", + message=get_submit_message(doc), + now=True + ) + + if doc.workflow_state in ["Approved", "Rejected"]: + email = get_employee_email(doc.employee) + + if email: + frappe.sendmail( + recipients=[email], + subject=f"Travel Request {doc.workflow_state}: {doc.name}", + message=get_status_message(doc), + now=True + ) + +def get_employee_email(employee): + ''' + Get the email of the employee + ''' + user = frappe.db.get_value("Employee", employee, "user_id") + if user: + return frappe.db.get_value("User", user, "email") + return None + +def get_manager_emails(): + ''' + Get the emails of all GAMS Managers + ''' + managers = frappe.get_all( + "Has Role", + filters={"role": "GAMS Manager"}, + fields=["parent"] + ) + + emails = [frappe.db.get_value("User", m.parent, "email") for m in managers] + return list(set(filter(None, emails))) + +def get_submit_message(doc): + ''' + Message to be sent to GAMS Managers when a Travel Request is submitted + ''' + return f""" +

Hello,

+ +

A new Travel Request has been submitted for your approval.

+ +

Request ID: {doc.name}

+

Employee: {doc.employee_name}

+

Purpose: {doc.purpose_of_travel}

+ +

+ + View Travel Request + +

+ """ + +def get_status_message(doc): + ''' + Message to be sent to the employee when their Travel Request is approved or rejected + ''' + return f""" +

Hello,

+ +

Your Travel Request has been + {doc.workflow_state}.

+ +

Request ID: {doc.name}

+

Purpose: {doc.purpose_of_travel}

+ +

+ + View Travel Request + +

+ """ diff --git a/gams/hooks.py b/gams/hooks.py index df87a72..925eddd 100644 --- a/gams/hooks.py +++ b/gams/hooks.py @@ -142,13 +142,12 @@ # --------------- # Hook on document methods and events -# doc_events = { -# "*": { -# "on_update": "method", -# "on_cancel": "method", -# "on_trash": "method" -# } -# } +doc_events = { + "Travel Request": { + "before_save": "gams.general_administration_management_system.custom_scripts.travel_request.travel_request.before_save", + "on_update": "gams.general_administration_management_system.custom_scripts.travel_request.travel_request.on_update", + }, +} # Scheduled Tasks # ---------------