From bde6b7983e3ddb1540f773edbb91b5000a28fddc Mon Sep 17 00:00:00 2001 From: Suraiyya Sutriya Date: Thu, 21 May 2026 14:07:44 +0530 Subject: [PATCH 1/3] fix:fix audit history to track close and reopen query --- .../doctype/my_audits/my_audits.py | 68 ++++++++++++++----- 1 file changed, 52 insertions(+), 16 deletions(-) diff --git a/audit_management/audit_management/doctype/my_audits/my_audits.py b/audit_management/audit_management/doctype/my_audits/my_audits.py index 5f39689..4f7d7f3 100755 --- a/audit_management/audit_management/doctype/my_audits/my_audits.py +++ b/audit_management/audit_management/doctype/my_audits/my_audits.py @@ -829,6 +829,9 @@ def get_permission_query_conditions(user=None): from frappe.utils import now, time_diff_in_seconds, time_diff_in_hours, getdate, nowdate, format_datetime +from frappe.utils import now, time_diff_in_seconds, time_diff_in_hours, getdate, nowdate, format_datetime +import json + @frappe.whitelist() def get_audit_history_summary(docname): doc = frappe.get_doc("My Audits", docname) @@ -838,18 +841,18 @@ def get_full_name(user_id): if user_id == "System/Audit Team": return "System/Audit Team" return frappe.db.get_value("User", user_id, "full_name") or user_id - # Formatted History List history = [] - # Creator Info + # 1. Capture Creation history.append({ "event": "Query Created", "user": doc.query_generated_by_name or get_full_name(doc.owner), "date": format_datetime(doc.creation, "dd-MM-yyyy hh:mm a"), - "status": "Created" + "status": "Created", + "timestamp": doc.creation }) - # Stages Info + # 2. Capture Stage Assignments and Responses from child table creator_name = doc.query_generated_by_name or get_full_name(doc.owner) for row in doc.audit_stages: if row.status or row.pending_time: @@ -857,26 +860,59 @@ def get_full_name(user_id): "event": f"Assigned to {row.stage_name} ({row.employee_name})", "user": creator_name, "date": format_datetime(row.pending_time, "dd-MM-yyyy hh:mm a") if row.pending_time else "", - "status": "Pending" + "status": "Pending", + "timestamp": row.pending_time if row.pending_time else doc.creation }) if row.status == "Responded": history.append({ "event": f"Response from {row.stage_name}", "user": row.employee_name, "date": format_datetime(row.response_time, "dd-MM-yyyy hh:mm a") if row.response_time else "", - "status": "Responded" + "status": "Responded", + "timestamp": row.response_time if row.response_time else doc.creation }) - # Closure Info - if doc.status == "Closed": - # Attempt to find who closed it - closed_by_id = frappe.db.get_value("Version", {"ref_doctype": "My Audits", "docname": doc.name, "data": ["like", "%status%Closed%"]}, "owner") - history.append({ - "event": "Query Closed", - "user": get_full_name(closed_by_id) or "System/Audit Team", - "date": format_datetime(str(doc.closing_date) + " 00:00:00", "dd-MM-yyyy hh:mm a") if doc.closing_date else "", - "status": "Closed" - }) + # 3. Capture status transitions (Closed/Reopened) from Version history + versions = frappe.get_all( + "Version", + filters={"ref_doctype": "My Audits", "docname": docname}, + fields=["data", "owner", "creation"], + order_by="creation asc" + ) + + for version in versions: + try: + version_data = json.loads(version.data) + # Some versions contain a list of changed fields in 'changed' key + changed_fields = version_data.get("changed", []) + + for field in changed_fields: + # field is usually a list: [fieldname, old_value, new_value] + if len(field) == 3 and field[0] == "status": + old_val = field[1] + new_val = field[2] + + if new_val == "Closed": + history.append({ + "event": "Query Closed", + "user": get_full_name(version.owner), + "date": format_datetime(version.creation, "dd-MM-yyyy hh:mm a"), + "status": "Closed", + "timestamp": version.creation + }) + elif old_val == "Closed" and new_val != "Closed": + history.append({ + "event": "Query Reopened", + "user": get_full_name(version.owner), + "date": format_datetime(version.creation, "dd-MM-yyyy hh:mm a"), + "status": "Reopened", + "timestamp": version.creation + }) + except Exception: + pass + + # Sort history by timestamp + history.sort(key=lambda x: x["timestamp"]) return history From 3d06eedc93b11588ef8a0bd3e8e9d252b2b2cc6a Mon Sep 17 00:00:00 2001 From: Suraiyya Sutriya Date: Thu, 21 May 2026 15:41:00 +0530 Subject: [PATCH 2/3] fix:fixed email fetching issue for stage users --- .../doctype/my_audits/my_audits.js | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/audit_management/audit_management/doctype/my_audits/my_audits.js b/audit_management/audit_management/doctype/my_audits/my_audits.js index 31967a5..c61a853 100755 --- a/audit_management/audit_management/doctype/my_audits/my_audits.js +++ b/audit_management/audit_management/doctype/my_audits/my_audits.js @@ -2554,6 +2554,12 @@ function open_stages_modal(frm) { label: "Employee Name", read_only: 1, }, + { + fieldtype: "Data", + fieldname: "email", + in_list_view: 1, + label: "Email", + }, ], }, ], @@ -2593,6 +2599,7 @@ function open_stages_modal(frm) { target_row.stage_name = row.stage_name; target_row.employee = row.employee; target_row.employee_name = row.employee_name; + target_row.email = row.email; target_row.stage = idx + 1; target_row.idx = idx + 1; // Required by Frappe for sequence tracking @@ -2617,6 +2624,49 @@ function open_stages_modal(frm) { }, }); + // Fetch logic for employee field in the modal + d.fields_dict.temp_stages.grid.get_field("employee").get_query = function () { + return { + filters: { + status: "Active", + }, + }; + }; + + // 🌟 FIX: Fetch Email and Employee Name when Employee is selected in the modal + d.fields_dict.temp_stages.grid.on_row_add = function (doc, cdt, cdn) { + let row = locals[cdt][cdn]; + }; + + // We use the grid's change trigger + d.fields_dict.temp_stages.grid.on_row_add = function (doc, cdt, cdn) { + // Optional: logic on row add + }; + + // Use model events if doctype is set, or grid events + // Since temp_stages doesn't have a doctype, we use the grid's control events + let grid = d.fields_dict.temp_stages.grid; + grid.wrapper.on("change", 'input[data-fieldname="employee"]', function (e) { + let $input = $(e.currentTarget); + let name = $input.closest(".grid-row").attr("data-name"); + let row = grid.get_row(name).doc; + + if (row.employee) { + frappe.call({ + method: + "audit_management.audit_management.doctype.my_audits.my_audits.fetch_employee_data", + args: { employee_id: row.employee }, + callback: function (r) { + if (r.message) { + row.employee_name = r.message.employee_name; + row.email = r.message.company_email; + grid.refresh(); + } + }, + }); + } + }); + // Populate the modal with data, binding the exact Database ID to 'stage_id' let existing_data = (frm.doc.audit_stages || []).map((row) => { return { @@ -2624,6 +2674,7 @@ function open_stages_modal(frm) { stage_name: row.stage_name, employee: row.employee, employee_name: row.employee_name, + email: row.email, }; }); From f2d4acd2379ccac4c4133e9915d8ebadf5777395 Mon Sep 17 00:00:00 2001 From: Suraiyya Sutriya Date: Thu, 21 May 2026 15:41:38 +0530 Subject: [PATCH 3/3] fix:fixed email fetching issue in my audits --- audit_management/audit_management/doctype/my_audits/my_audits.py | 1 + 1 file changed, 1 insertion(+) diff --git a/audit_management/audit_management/doctype/my_audits/my_audits.py b/audit_management/audit_management/doctype/my_audits/my_audits.py index 4f7d7f3..e26fdbb 100755 --- a/audit_management/audit_management/doctype/my_audits/my_audits.py +++ b/audit_management/audit_management/doctype/my_audits/my_audits.py @@ -248,6 +248,7 @@ def sync_new_to_old(self): self.set(f"{prefix}_user_status", row.status) self.set(f"{prefix}_response_box", row.response) self.set(f"{prefix}_attach_box", row.attachment) + self.set(f"{prefix}_mail", row.email) if row.pending_time: self.set(f"{prefix}_pending_time", row.pending_time)