Skip to content

Commit f1fa359

Browse files
committed
feat: Added approval validation and email notifications for Travel Request
1 parent 771dfc0 commit f1fa359

2 files changed

Lines changed: 114 additions & 7 deletions

File tree

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# Copyright (c) 2026, efeone and contributors
2+
# For license information, please see license.txt
3+
import frappe
4+
from frappe.utils import get_url_to_form
5+
6+
7+
def before_save(doc, method):
8+
'''
9+
Prevent self-approval of Travel Requests
10+
'''
11+
if doc.workflow_state == "Approved":
12+
13+
if doc.owner == frappe.session.user:
14+
frappe.throw("You cannot approve your own Travel Request.")
15+
16+
if doc.employee:
17+
user = frappe.db.get_value("Employee", doc.employee, "user_id")
18+
19+
if user and user == frappe.session.user:
20+
frappe.throw("You cannot approve your own Travel Request.")
21+
22+
def on_update(doc, method):
23+
'''
24+
Send email notifications on Travel Request submission and status changes
25+
'''
26+
if doc.workflow_state == "Submitted":
27+
emails = get_manager_emails()
28+
29+
if emails:
30+
frappe.sendmail(
31+
recipients=emails,
32+
subject=f"Travel Request {doc.name} Submitted",
33+
message=get_submit_message(doc),
34+
now=True
35+
)
36+
37+
if doc.workflow_state in ["Approved", "Rejected"]:
38+
email = get_employee_email(doc.employee)
39+
40+
if email:
41+
frappe.sendmail(
42+
recipients=[email],
43+
subject=f"Travel Request {doc.workflow_state}: {doc.name}",
44+
message=get_status_message(doc),
45+
now=True
46+
)
47+
48+
def get_employee_email(employee):
49+
'''
50+
Get the email of the employee
51+
'''
52+
user = frappe.db.get_value("Employee", employee, "user_id")
53+
if user:
54+
return frappe.db.get_value("User", user, "email")
55+
return None
56+
57+
def get_manager_emails():
58+
'''
59+
Get the emails of all GAMS Managers
60+
'''
61+
managers = frappe.get_all(
62+
"Has Role",
63+
filters={"role": "GAMS Manager"},
64+
fields=["parent"]
65+
)
66+
67+
emails = [frappe.db.get_value("User", m.parent, "email") for m in managers]
68+
return list(set(filter(None, emails)))
69+
70+
def get_submit_message(doc):
71+
'''
72+
Message to be sent to GAMS Managers when a Travel Request is submitted
73+
'''
74+
return f"""
75+
<p>Hello,</p>
76+
77+
<p>A new <b>Travel Request</b> has been submitted for your approval.</p>
78+
79+
<p><b>Request ID:</b> {doc.name}</p>
80+
<p><b>Employee:</b> {doc.employee_name}</p>
81+
<p><b>Purpose:</b> {doc.purpose_of_travel}</p>
82+
83+
<p>
84+
<a href="{get_url_to_form(doc.doctype, doc.name)}">
85+
View Travel Request
86+
</a>
87+
</p>
88+
"""
89+
90+
def get_status_message(doc):
91+
'''
92+
Message to be sent to the employee when their Travel Request is approved or rejected
93+
'''
94+
return f"""
95+
<p>Hello,</p>
96+
97+
<p>Your <b>Travel Request</b> has been
98+
<b>{doc.workflow_state}</b>.</p>
99+
100+
<p><b>Request ID:</b> {doc.name}</p>
101+
<p><b>Purpose:</b> {doc.purpose_of_travel}</p>
102+
103+
<p>
104+
<a href="{get_url_to_form(doc.doctype, doc.name)}">
105+
View Travel Request
106+
</a>
107+
</p>
108+
"""

gams/hooks.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -142,13 +142,12 @@
142142
# ---------------
143143
# Hook on document methods and events
144144

145-
# doc_events = {
146-
# "*": {
147-
# "on_update": "method",
148-
# "on_cancel": "method",
149-
# "on_trash": "method"
150-
# }
151-
# }
145+
doc_events = {
146+
"Travel Request": {
147+
"before_save": "gams.general_administration_management_system.custom_scripts.travel_request.travel_request.before_save",
148+
"on_update": "gams.general_administration_management_system.custom_scripts.travel_request.travel_request.on_update"
149+
},
150+
}
152151

153152
# Scheduled Tasks
154153
# ---------------

0 commit comments

Comments
 (0)