Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright (c) 2026, efeone and contributors
// For license information, please see license.txt

frappe.ui.form.on('Incident Report', {
onload: function(frm) {
if (!frm.doc.reported_by) {
frappe.db.get_value('Employee',
{ user_id: frappe.session.user },
'name'
).then(r => {
if (r.message) {
frm.set_value('reported_by', r.message.name);
}
});
}
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
{
"actions": [],
"allow_rename": 1,
"autoname": "INC-.YYYY.-.####",
"creation": "2026-04-07 11:47:42.488696",
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
"incident_title",
"incident_type",
"reported_by",
"incident_date",
"description",
"column_break_ujev",
"assigned_to",
"resolution_date",
"resolution_notes",
"status"
],
"fields": [
{
"fieldname": "incident_title",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Incident Title",
"reqd": 1
},
{
"fieldname": "incident_type",
"fieldtype": "Select",
"label": "Incident Type",
"options": "Facility\nSecurity\nIT\nHR\nOther",
"reqd": 1
},
{
"fieldname": "reported_by",
"fieldtype": "Link",
"label": "Reported By",
"options": "Employee",
"reqd": 1
},
{
"default": "Today",
"fieldname": "incident_date",
"fieldtype": "Date",
"in_list_view": 1,
"label": "Incident Date",
"reqd": 1
},
{
"fieldname": "description",
"fieldtype": "Long Text",
"label": "Description",
"reqd": 1
},
{
"fieldname": "assigned_to",
"fieldtype": "Link",
"label": "Assigned To",
"options": "Employee"
},
{
"fieldname": "resolution_date",
"fieldtype": "Date",
"label": "Resolution Date"
},
{
"fieldname": "resolution_notes",
"fieldtype": "Long Text",
"label": "Resolution Notes"
},
{
"fieldname": "status",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Status",
"options": "Open\nIn Progress\nResolved\nClosed"
},
{
"fieldname": "column_break_ujev",
"fieldtype": "Column Break"
}
],
"grid_page_length": 50,
"index_web_pages_for_search": 1,
"links": [],
"modified": "2026-04-07 13:12:33.198131",
"modified_by": "Administrator",
"module": "General Administration Management System",
"name": "Incident Report",
"naming_rule": "Expression (old style)",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
}
],
"row_format": "Dynamic",
"rows_threshold_for_grid_search": 20,
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Copyright (c) 2026, efeone and contributors
# For license information, please see license.txt

import frappe
from frappe.model.document import Document
from frappe.utils import today, get_url_to_form


class IncidentReport(Document):

def on_update(self):
'''
Handle resolution date + email notification on Assign and Resolve actions
'''
if not self.has_value_changed("status"):
return

if self.status == "Resolved":
if not self.resolution_date:
self.db_set("resolution_date", today())

if self.status == "In Progress":
if self.resolution_date:
self.db_set("resolution_date", None)

if self.status == "In Progress" and self.assigned_to:
email = self.get_employee_email(self.assigned_to)

if email:
frappe.sendmail(
recipients=[email],
subject=f"Incident {self.name} Assigned to You",
message=self.get_assign_message(),
now=True
)

if self.status == "Resolved" and self.reported_by:
email = self.get_employee_email(self.reported_by)

if email:
frappe.sendmail(
recipients=[email],
subject=f"Incident {self.name} Resolved",
message=self.get_resolve_message(),
now=True
)

def get_employee_email(self, 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_assign_message(self):
'''
Message to be sent to the assignee when the incident is assigned to them
'''
return f"""
<p>Hello,</p>
<p>An incident has been <b>assigned</b> to you.</p>

<p><b>ID:</b> {self.name}</p>
<p><b>Title:</b> {self.incident_title}</p>

<p>
<a href="{get_url_to_form(self.doctype, self.name)}">
View Incident
</a>
</p>
"""

def get_resolve_message(self):
'''
Message to be sent to the reporter when the incident is resolved
'''
return f"""
<p>Hello,</p>
<p>Your reported incident has been <b>resolved</b>.</p>

<p><b>ID:</b> {self.name}</p>
<p><b>Resolution:</b> {self.resolution_notes or "N/A"}</p>

<p>
<a href="{get_url_to_form(self.doctype, self.name)}">
View Incident
</a>
</p>
"""
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Copyright (c) 2026, efeone and Contributors
# See license.txt

# import frappe
from frappe.tests.utils import FrappeTestCase


class TestIncidentReport(FrappeTestCase):
pass
7 changes: 6 additions & 1 deletion gams/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,15 @@
# before_install = "gams.install.before_install"
# after_install = "gams.install.after_install"
Comment thread
MhmdSinanKT marked this conversation as resolved.

# Migration
#------------

after_migrate = "gams.setup.after_migrate"

# Uninstallation
# ------------

# before_uninstall = "gams.uninstall.before_uninstall"
before_uninstall = "gams.uninstall.before_uninstall"
# after_uninstall = "gams.uninstall.after_uninstall"

# Integration Setup
Expand Down
34 changes: 34 additions & 0 deletions gams/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import frappe

def after_migrate():
create_custom_roles(get_gams_roles())

def before_migrate():
pass

def create_custom_roles(roles):
for role in roles:
if not frappe.db.exists("Role", role):
role_doc = frappe.get_doc({
"doctype": "Role",
"role_name": role
})
role_doc.insert(ignore_permissions=True)

frappe.db.commit()

def create_property_setters(property_setter_datas):
for data in property_setter_datas:
if frappe.db.exists("Property Setter", data):
continue

ps = frappe.new_doc("Property Setter")
ps.update(data)
ps.flags.ignore_permissions = True
ps.insert()

def get_gams_roles():
return [
"GAMS Manager"
]

Loading