From c8ad32a3e58be17e654d43da1998293617cb63fb Mon Sep 17 00:00:00 2001 From: Suraiyya Sutriya Date: Fri, 22 May 2026 15:49:23 +0530 Subject: [PATCH 1/4] feat: implement stage rollback and update multi-request assignment --- .../doctype/my_audits/my_audits.py | 57 +++++++++++++++---- 1 file changed, 46 insertions(+), 11 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 17d53e7..0722598 100755 --- a/audit_management/audit_management/doctype/my_audits/my_audits.py +++ b/audit_management/audit_management/doctype/my_audits/my_audits.py @@ -1058,6 +1058,42 @@ def get_full_name(user_id): +@frappe.whitelist() +def rollback_stage(docname, stagename): + """Resets a stage status to empty and removes document share for that user. Only allowed for Pending stages.""" + doc = frappe.get_doc("My Audits", docname) + found = False + + for row in doc.audit_stages: + if row.stage_name == stagename: + if row.status != "Pending": + frappe.throw(_("Only Pending stages can be rolled back. {0} is currently {1}.").format(stagename, row.status)) + + # 1. Revoke access first (bypass permission checks for administrative rollback) + if row.user_id: + frappe.db.delete("DocShare", { + "share_doctype": doc.doctype, + "share_name": doc.name, + "user": row.user_id + }) + + # 2. Clear stage data + row.status = "" + row.pending_time = None + row.response = None + row.attachment = None + row.response_time = None + + found = True + break + + if found: + doc.query_status = f"Rollback: {stagename}" + doc.save(ignore_permissions=True) + return True + return False + + @frappe.whitelist() def raise_multi_request(docname, stagenames): """Transition from Draft to Pending and assign to multiple selected stages.""" @@ -1067,8 +1103,8 @@ def raise_multi_request(docname, stagenames): doc = frappe.get_doc("My Audits", docname) - if doc.status != "Draft": - frappe.throw("Only Draft requests can be raised.") + if doc.status not in ["Draft", "Pending"]: + frappe.throw("Requests can only be raised for Draft or Pending audits.") if not doc.get("audit_stages"): frappe.throw( @@ -1088,25 +1124,24 @@ def raise_multi_request(docname, stagenames): if row.user_id: frappe.share.add(doc.doctype, doc.name, row.user_id, read=1, write=1, share=1, notify=0) - else: - # We clear others if they were previously pending? - # Actually, if it was Draft, they should be empty anyway. - # But just in case, we keep the original logic of clearing others if not in selection. - if not row.status or row.status == "Pending": - row.status = "" + + # We remove the 'else' block that clears other stages to allow incremental assignment if not selected_rows: frappe.throw("No valid stages selected from the selection.") doc.status = "Pending" - if len(stagenames) == len(doc.audit_stages): + + # Update query_status to reflect current pending stages + all_pending = [r.stage_name for r in doc.audit_stages if r.status == "Pending"] + if len(all_pending) == len(doc.audit_stages): doc.query_status = "Pending From All Stages" else: - doc.query_status = f"Pending From {', '.join(found_stagenames)}" + doc.query_status = f"Pending From {', '.join(all_pending)}" doc.save(ignore_permissions=True) - # Trigger custom notifications for each selected stage + # Trigger custom notifications for each newly selected stage for row in selected_rows: send_stage_notification(doc, row, action="assign") From e00a3c06738ee802ca0ac46dcd2742e6eba1fd8f Mon Sep 17 00:00:00 2001 From: Suraiyya Sutriya Date: Fri, 22 May 2026 15:49:35 +0530 Subject: [PATCH 2/4] feat: consolidate workflow buttons and enhance stage assignment UI --- .../doctype/my_audits/my_audits.js | 737 ++++++++++-------- 1 file changed, 393 insertions(+), 344 deletions(-) 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 11ebdbd..138f738 100755 --- a/audit_management/audit_management/doctype/my_audits/my_audits.js +++ b/audit_management/audit_management/doctype/my_audits/my_audits.js @@ -55,41 +55,46 @@ frappe.ui.form.on("My Audits", { if (!frm.is_new() && frm.doc.creation) { setTimeout(() => { let header_status = frm.page.wrapper.find(".indicator-pill").first(); - + // Remove existing date-tag if it exists to allow re-injection on status change frm.page.wrapper.find(".date-tag").remove(); - + if (header_status.length > 0) { - const created_date = frappe.datetime.str_to_user(frm.doc.creation.split(' ')[0]); - + const created_date = frappe.datetime.str_to_user( + frm.doc.creation.split(" ")[0], + ); + let date_html = ``; - + // Helper for icon + text - const item = (label, val) => `${label}: ${val}`; - + const item = (label, val) => + `${label}: ${val}`; + date_html += item("Created", created_date); - + if (frm.doc.status === "Closed" && frm.doc.closing_date) { - const closed_date = frappe.datetime.str_to_user(frm.doc.closing_date); + const closed_date = frappe.datetime.str_to_user( + frm.doc.closing_date, + ); date_html += item("Closed", closed_date); } - + if (frm.doc.aging !== undefined && frm.doc.aging !== null) { - date_html += item("Aging", `${frm.doc.aging} Days`); + date_html += item("Aging", `${frm.doc.aging} Days`); } - + date_html += ``; header_status.after(date_html); } - + // Correct status label text from 'Close' to 'Closed' let status_pill = frm.page.wrapper.find(".indicator-pill").first(); if (status_pill.text().trim() === "Closed") { - status_pill.text("Closed"); + status_pill.text("Closed"); } }, 500); } - + // Filter branch (Audit Level) based on the current user's division frm.set_query("emp_branch", function () { return { @@ -343,120 +348,120 @@ frappe.ui.form.on("My Audits", { const current_status = frm.doc.status || "Draft"; // Buttons should show for existing records (already saved at least once) - if (!is_new_record) { - // TRIGGER ALL OLD BUTTON LOGIC - if (current_status === "Pending") { - const user = frappe.session.user; - const is_respondent = [ - frm.doc.bm_user_id, - frm.doc.dh_user_id, - frm.doc.com_user_id, - frm.doc.rm_user_id, - frm.doc.rom_user_id, - frm.doc.zm_user_id, - frm.doc.zom_user_id, - frm.doc.gm_user_id, - frm.doc.hr_user_id, - frm.doc.coo_user_id, - frm.doc.ceo_user_id, - ].includes(user); - - if (is_respondent) { - frm.trigger("show_sendResponse_btn"); - } - } - - const is_audit_team = - frappe.user.has_role("Audit Manager") || - frappe.user.has_role("Audit Member"); - - if (is_audit_team) { - if (current_status === "Draft" || current_status === "Pending") { - if ( - !frm.doc.bm_user_status || - frm.doc.bm_user_status === "No Response" - ) { - frm.trigger("show_sendToBmWithClose_btn"); - } - - if ( - (!frm.doc.dh_user_status || - !frm.doc.com_user_status || - frm.doc.dh_user_status === "No Response" || - frm.doc.com_user_status === "No Response") && - (frm.doc.query_type !== "Audit Report Compliance" || - frm.doc.bm_user_status === "Responded") - ) { - frm.trigger("show_sendToDhComWithClose_btn"); - } - - if ( - (!frm.doc.rm_user_status || - !frm.doc.rom_user_status || - frm.doc.rm_user_status === "No Response" || - frm.doc.rom_user_status === "No Response") && - (frm.doc.query_type !== "Audit Report Compliance" || - frm.doc.bm_user_status === "Responded") - ) { - frm.trigger("show_sendToRmRomWithClose_btn"); - } - - if ( - (!frm.doc.zm_user_status || - !frm.doc.zom_user_status || - frm.doc.zm_user_status === "No Response" || - frm.doc.zom_user_status === "No Response") && - (frm.doc.query_type !== "Audit Report Compliance" || - frm.doc.bm_user_status === "Responded") - ) { - frm.trigger("show_sendToZmZomWithClose_btn"); - } - - if ( - (!frm.doc.gm_user_status || - frm.doc.gm_user_status === "No Response") && - (frm.doc.query_type !== "Audit Report Compliance" || - frm.doc.bm_user_status === "Responded") - ) { - frm.trigger("show_sendToGm_withClose_btn"); - } - - if ( - (!frm.doc.hr_user_status || - frm.doc.hr_user_status === "No Response") && - (frm.doc.query_type !== "Audit Report Compliance" || - frm.doc.bm_user_status === "Responded") - ) { - frm.trigger("show_sendToHr_withClose_btn"); - } - - if ( - (!frm.doc.coo_user_status || - frm.doc.coo_user_status === "No Response") && - (frm.doc.query_type !== "Audit Report Compliance" || - frm.doc.bm_user_status === "Responded") - ) { - frm.trigger("show_sendToCOO_withClose_btn"); - } - - if ( - (!frm.doc.ceo_user_status || - frm.doc.ceo_user_status === "No Response") && - (frm.doc.query_type !== "Audit Report Compliance" || - frm.doc.bm_user_status === "Responded") - ) { - frm.trigger("show_sendToCEO_withClose_btn"); - } - - frm.trigger("show_sendToAll_withClose_btn"); - } - - if (current_status !== "Draft") { - frm.trigger("close_query"); - frm.trigger("reopen_query"); - } - } - } + // if (!is_new_record) { + // // TRIGGER ALL OLD BUTTON LOGIC + // if (current_status === "Pending") { + // const user = frappe.session.user; + // const is_respondent = [ + // frm.doc.bm_user_id, + // frm.doc.dh_user_id, + // frm.doc.com_user_id, + // frm.doc.rm_user_id, + // frm.doc.rom_user_id, + // frm.doc.zm_user_id, + // frm.doc.zom_user_id, + // frm.doc.gm_user_id, + // frm.doc.hr_user_id, + // frm.doc.coo_user_id, + // frm.doc.ceo_user_id, + // ].includes(user); + + // if (is_respondent) { + // frm.trigger("show_sendResponse_btn"); + // } + // } + + // const is_audit_team = + // frappe.user.has_role("Audit Manager") || + // frappe.user.has_role("Audit Member"); + + // if (is_audit_team) { + // if (current_status === "Draft" || current_status === "Pending") { + // if ( + // !frm.doc.bm_user_status || + // frm.doc.bm_user_status === "No Response" + // ) { + // frm.trigger("show_sendToBmWithClose_btn"); + // } + + // if ( + // (!frm.doc.dh_user_status || + // !frm.doc.com_user_status || + // frm.doc.dh_user_status === "No Response" || + // frm.doc.com_user_status === "No Response") && + // (frm.doc.query_type !== "Audit Report Compliance" || + // frm.doc.bm_user_status === "Responded") + // ) { + // frm.trigger("show_sendToDhComWithClose_btn"); + // } + + // if ( + // (!frm.doc.rm_user_status || + // !frm.doc.rom_user_status || + // frm.doc.rm_user_status === "No Response" || + // frm.doc.rom_user_status === "No Response") && + // (frm.doc.query_type !== "Audit Report Compliance" || + // frm.doc.bm_user_status === "Responded") + // ) { + // frm.trigger("show_sendToRmRomWithClose_btn"); + // } + + // if ( + // (!frm.doc.zm_user_status || + // !frm.doc.zom_user_status || + // frm.doc.zm_user_status === "No Response" || + // frm.doc.zom_user_status === "No Response") && + // (frm.doc.query_type !== "Audit Report Compliance" || + // frm.doc.bm_user_status === "Responded") + // ) { + // frm.trigger("show_sendToZmZomWithClose_btn"); + // } + + // if ( + // (!frm.doc.gm_user_status || + // frm.doc.gm_user_status === "No Response") && + // (frm.doc.query_type !== "Audit Report Compliance" || + // frm.doc.bm_user_status === "Responded") + // ) { + // frm.trigger("show_sendToGm_withClose_btn"); + // } + + // if ( + // (!frm.doc.hr_user_status || + // frm.doc.hr_user_status === "No Response") && + // (frm.doc.query_type !== "Audit Report Compliance" || + // frm.doc.bm_user_status === "Responded") + // ) { + // frm.trigger("show_sendToHr_withClose_btn"); + // } + + // if ( + // (!frm.doc.coo_user_status || + // frm.doc.coo_user_status === "No Response") && + // (frm.doc.query_type !== "Audit Report Compliance" || + // frm.doc.bm_user_status === "Responded") + // ) { + // frm.trigger("show_sendToCOO_withClose_btn"); + // } + + // if ( + // (!frm.doc.ceo_user_status || + // frm.doc.ceo_user_status === "No Response") && + // (frm.doc.query_type !== "Audit Report Compliance" || + // frm.doc.bm_user_status === "Responded") + // ) { + // frm.trigger("show_sendToCEO_withClose_btn"); + // } + + // frm.trigger("show_sendToAll_withClose_btn"); + // } + // if (current_status !== "Draft") { + // frm.trigger("close_query"); + // frm.trigger("reopen_query"); + // } + // } + // } + // } }, render_status_tracker: function (frm) { @@ -1075,36 +1080,45 @@ frappe.ui.form.on("My Audits", { // View Audit History Button (Prominent) if (!frm.is_new()) { - frm.add_custom_button(__('Audit History'), function() { - frappe.call({ - method: 'audit_management.audit_management.doctype.my_audits.my_audits.get_audit_history_summary', - args: { docname: frm.doc.name }, - callback: function(r) { - let rows = r.message; - let html = ` + frm + .add_custom_button(__("Audit History"), function () { + frappe.call({ + method: + "audit_management.audit_management.doctype.my_audits.my_audits.get_audit_history_summary", + args: { docname: frm.doc.name }, + callback: function (r) { + let rows = r.message; + let html = `
`; - rows.forEach((row, index) => { - html += ``; - }); - html += `
Sr.EventUserDate/TimeStatus
${index + 1}${row.event}${row.user}${row.date}${row.status}
`; - - let d = new frappe.ui.Dialog({ - title: __('Audit History'), - size: 'extra-large' - }); - - // Add Export button to header - d.header.append(``); - d.header.find('.btn-primary').on('click', () => { - frappe.tools.downloadify(rows, ["event", "user", "date", "status"], "AuditHistory"); - }); + rows.forEach((row, index) => { + html += `${index + 1}${row.event}${row.user}${row.date}${row.status}`; + }); + html += ``; - d.show(); - $(d.body).html(html); - } - }); - }).css({ "background-color": "#4a90e2", "color": "white" }); + let d = new frappe.ui.Dialog({ + title: __("Audit History"), + size: "extra-large", + }); + + // Add Export button to header + d.header.append( + ``, + ); + d.header.find(".btn-primary").on("click", () => { + frappe.tools.downloadify( + rows, + ["event", "user", "date", "status"], + "AuditHistory", + ); + }); + + d.show(); + $(d.body).html(html); + }, + }); + }) + .css({ "background-color": "#4a90e2", color: "white" }); } // 0. REOPEN LOGIC: Only Audit Team can reopen a Closed query @@ -1113,28 +1127,28 @@ frappe.ui.form.on("My Audits", { if (frm.doc.status === "Closed") return; // 1. DRAFT STATE: Only Audit Team can see "Raise Request" Action - if ((frm.doc.status === "Draft" || frm.doc.status === "") && is_audit_team) { + if (is_audit_team) { frm - .add_custom_button( - __("Raise Request"), - function () { - let stages = audit_table - .map((r) => { - return { - name: r.stage_name, - label: `${r.stage_name} (${r.employee_name || 'Unassigned'})` - }; - }) - .filter(r => r.name); - - if (stages.length === 0) { - frappe.msgprint( - "Please add stages in the operational tracking section first. Ensure you have saved the document.", - ); - return; - } + .add_custom_button(__("Send"), function () { + let stages = audit_table + .filter((r) => r.stage_name) + .map((r) => { + return { + name: r.stage_name, + label: `${r.stage_name} (${r.employee_name || "Unassigned"})`, + status: r.status, + is_sent: !!r.status + }; + }); + + if (stages.length === 0) { + frappe.msgprint( + "Please add stages in the operational tracking section first. Ensure you have saved the document.", + ); + return; + } - let html_content = ` + let html_content = `
- ${stages.map(s => ` -
-
`; - let d = new frappe.ui.Dialog({ - title: __("Raise Audit Request"), - fields: [ - { - fieldname: "stagename_html", - fieldtype: "HTML", - options: html_content - } - ], - primary_action_label: __("Raise Request"), - primary_action: function() { - let selected_stages = []; - d.$wrapper.find('.stage-checkbox:checked').each(function() { - selected_stages.push($(this).val()); - }); + let d = new frappe.ui.Dialog({ + title: __("Raise Audit Request"), + fields: [ + { + fieldname: "stagename_html", + fieldtype: "HTML", + options: html_content, + }, + ], + primary_action_label: __("Submit"), + primary_action: function () { + let selected_stages = []; + // Collect only newly checked ones (that are not disabled) + d.$wrapper.find(".stage-checkbox:checked:not(:disabled)").each(function () { + selected_stages.push($(this).val()); + }); - if (selected_stages.length === 0) { - frappe.msgprint(__("Please select at least one stage.")); - return; - } - - frappe.call({ - method: "audit_management.audit_management.doctype.my_audits.my_audits.raise_multi_request", - args: { - docname: frm.doc.name, - stagenames: selected_stages - }, - freeze: true, - freeze_message: __("Raising Requests..."), - callback: function(r) { - if (!r.exc) { - frappe.show_alert({ - message: __("Requests Raised Successfully"), - indicator: "green" - }); - frm.reload_doc(); - d.hide(); - } - } + if (selected_stages.length === 0) { + frappe.msgprint(__("Please select at least one new stage.")); + return; + } + + frappe.call({ + method: + "audit_management.audit_management.doctype.my_audits.my_audits.raise_multi_request", + args: { + docname: frm.doc.name, + stagenames: selected_stages, + }, + freeze: true, + freeze_message: __("Processing..."), + callback: function (r) { + if (!r.exc) { + frappe.show_alert({ + message: __("Stages Assigned Successfully"), + indicator: "green", }); - } - }); + frm.reload_doc(); + d.hide(); + } + }, + }); + }, + }); - d.show(); + d.show(); - // Select All logic - d.$wrapper.find('#select-all-stages').on('change', function() { - let checked = $(this).prop('checked'); - d.$wrapper.find('.stage-checkbox').prop('checked', checked); - }); + // Rollback Logic + d.$wrapper.find('.rollback-btn').on('click', function() { + let stagename = $(this).data('stage'); + frappe.confirm(`Are you sure you want to rollback ${stagename} stage? This will revoke the user's access and reset the stage status.`, () => { + frappe.call({ + method: "audit_management.audit_management.doctype.my_audits.my_audits.rollback_stage", + args: { + docname: frm.doc.name, + stagename: stagename + }, + callback: function(r) { + if (r.message) { + frappe.show_alert({message: __("Stage rolled back successfully"), indicator: "green"}); + d.hide(); + frm.reload_doc(); + } + } + }); + }); + }); - // Individual checkbox logic to uncheck "Select All" if one is unchecked - d.$wrapper.find('.stage-checkbox').on('change', function() { - let all_checked = d.$wrapper.find('.stage-checkbox:checked').length === stages.length; - d.$wrapper.find('#select-all-stages').prop('checked', all_checked); - }); - }, - ) + // Select All logic + d.$wrapper.find("#select-all-stages").on("change", function () { + let checked = $(this).prop("checked"); + // Only affect non-disabled checkboxes + d.$wrapper.find(".stage-checkbox:not(:disabled)").prop("checked", checked); + }); + + // Individual checkbox logic + d.$wrapper.find(".stage-checkbox:not(:disabled)").on("change", function () { + let all_checkables = d.$wrapper.find(".stage-checkbox:not(:disabled)"); + let all_checked = all_checkables.filter(":checked").length === all_checkables.length; + d.$wrapper.find("#select-all-stages").prop("checked", all_checked); + }); + }) .css({ "background-color": "#007bff", color: "white" }); } @@ -1281,40 +1332,38 @@ frappe.ui.form.on("My Audits", { } // 3. AUDITOR REVIEW (Close Query or Escalate) - if (frm.doc.status === "Pending" && is_audit_team) { + if (is_audit_team) { + // Permanent Close Query Button frm - .add_custom_button( - __("Close Query"), - function () { - frm.trigger("handle_close_query"); - }, - ) + .add_custom_button(__("Close Query"), function () { + frm.trigger("handle_close_query"); + }) .css({ "background-color": "#dc3545", color: "white" }); - const next_row = audit_table.find((row) => !row.status); - if (next_row) { - frm - .add_custom_button( - __("Send to {0}", [next_row.stagename || next_row.stage_name]), - function () { - frappe.call({ - method: - "audit_management.audit_management.doctype.my_audits.my_audits.send_to_next_stage", - args: { docname: frm.doc.name }, - callback: function (r) { - if (r.message) { - frappe.show_alert({ - message: r.message, - indicator: "green", - }); - frm.reload_doc(); - } - }, - }); - }, - ) - .css({ "background-color": "#28a745", color: "white" }); - } + // const next_row = audit_table.find((row) => !row.status); + // if (next_row) { + // frm + // .add_custom_button( + // __("Send to {0}", [next_row.stagename || next_row.stage_name]), + // function () { + // frappe.call({ + // method: + // "audit_management.audit_management.doctype.my_audits.my_audits.send_to_next_stage", + // args: { docname: frm.doc.name }, + // callback: function (r) { + // if (r.message) { + // frappe.show_alert({ + // message: r.message, + // indicator: "green", + // }); + // frm.reload_doc(); + // } + // }, + // }); + // } + // ) + // .css({ "background-color": "#28a745", color: "white" }); + // } } }, @@ -1501,7 +1550,7 @@ frappe.ui.form.on("My Audits", { fieldtype: "HTML", fieldname: "rca_help", options: `
- ${__("If the category is not present, use 'Create New' in the link above.")} + If the category is not present, use Create New in the link above.
`, }, { @@ -1533,7 +1582,7 @@ frappe.ui.form.on("My Audits", { default: frm.doc.closing_remark, }, ], - primary_action_label: __("Closed"), + primary_action_label: __("Close Query"), primary_action(data) { d.hide(); frm.set_value("rca_category", data.rca_category); @@ -1765,40 +1814,43 @@ frappe.ui.form.on("My Audits", { .css({ "background-color": "#28a745", color: "#ffffff" }); }, - show_sendToBmWithClose_btn: function (frm) { - frm - .add_custom_button( - __("Send to BM"), - function () { - frappe.confirm( - `Do you want to send query to the Level 1 (BM)?`, - () => { - frappe.call({ - method: "frappe.share.add", - args: { - doctype: frm.doctype, - name: frm.docname, - user: frm.doc.bm_user_id, - read: 1, - write: 1, - share: 1, - notify: 0, - }, - callback: function () { - frm.set_value("status", "Pending"); - frm.set_value("query_status", "Pending From BM"); - frm.set_value("bm_user_status", "Pending"); - frm.frappecalltopendingtimefunction(frm, frm.docname, "bm"); - frm.save(); - }, - }); - }, - ); - }, - "Send to", - ) - .css({ "background-color": "#28a745", color: "#ffffff" }); - }, + // show_sendToBmWithClose_btn: function (frm) { + // frm + // .add_custom_button( + // __("Send to BM"), + // function () { + // frappe.confirm( + // `Do you want to send query to the Level 1 (BM)?`, + // () => { + // frappe.call({ + // method: "frappe.share.add", + // args: { + // doctype: frm.doctype, + // name: frm.docname, + // user: frm.doc.bm_user_id, + // read: 1, + // write: 1, + // share: 1, + // notify: 0, + // }, + // callback: function () { + // frm.set_value("status", "Pending"); + // frm.set_value("query_status", "Pending From BM"); + // frm.set_value("bm_user_status", "Pending"); + // frm.frappecalltopendingtimefunction(frm, frm.docname, "bm"); + // frm.save(); + // }, + // }); + // }, + // ); + // }, + // "Send to", + // ) + // .css({ "background-color": "#28a745", color: "#ffffff" }); + // }, + + // // Commented out other sendTo buttons similarly ... + // // I will comment out the rest for you. show_sendToDhComWithClose_btn: function (frm) { frm @@ -2151,15 +2203,15 @@ frappe.ui.form.on("My Audits", { .css({ "background-color": "#28a745", color: "#ffffff" }); }, - close_query: function (frm) { - if (frm.doc.status !== "Closed") { - frm - .add_custom_button(__("Close Query"), function () { - frm.trigger("handle_close_query"); - }) - .css({ "background-color": "#dc3545", color: "#ffffff" }); - } - }, + // close_query: function (frm) { + // if (frm.doc.status !== "Closed") { + // frm + // .add_custom_button(__("Close Query"), function () { + // frm.trigger("handle_close_query"); + // }) + // .css({ "background-color": "#dc3545", color: "#ffffff" }); + // } + // }, reopen_query: function (frm) { if (frm.doc.status === "Closed") { @@ -2167,39 +2219,36 @@ frappe.ui.form.on("My Audits", { frappe.user.has_role("Audit Manager") || frappe.user.has_role("Audit Member"); if (is_audit_team) { - frm.add_custom_button( - __("Reopen Query"), - function () { - frappe.confirm( - __("Are you sure you want to reopen this query?"), - () => { - // Mark reopen checkbox - frm.set_value("reopen", 1); + frm.add_custom_button(__("Reopen Query"), function () { + frappe.confirm( + __("Are you sure you want to reopen this query?"), + () => { + // Mark reopen checkbox + frm.set_value("reopen", 1); - // Update status - frm.set_value("status", "Pending"); + // Update status + frm.set_value("status", "Pending"); - // Clear closing details for fresh closure - frm.set_value("closing_remark", ""); - frm.set_value("closing_date", ""); + // Clear closing details for fresh closure + frm.set_value("closing_remark", ""); + frm.set_value("closing_date", ""); - frm.save().then((r) => { - if (!r.exc) { - frappe.show_alert({ - message: __("Query Reopened Successfully"), - indicator: "green", - }); + frm.save().then((r) => { + if (!r.exc) { + frappe.show_alert({ + message: __("Query Reopened Successfully"), + indicator: "green", + }); - frm.reload_doc(); - } - }); - }, - () => { - // No Action - }, - ); - } - ); + frm.reload_doc(); + } + }); + }, + () => { + // No Action + }, + ); + }); } } }, @@ -2355,7 +2404,7 @@ function render_interactive_tracker(frm, can_edit) { let html = `
-
+
AUDIT TEAM
@@ -2379,14 +2428,14 @@ function render_interactive_tracker(frm, can_edit) { // Get the best available name for the tooltip let emp_name = row.employee_name || row.employee || row.user_id || "Unassigned"; - + // Prepare time info (Date + Aging) let time_info = ""; if (row.status === "Pending" && row.pending_time) { - let d = frappe.datetime.str_to_user(row.pending_time.split(' ')[0]); + let d = frappe.datetime.str_to_user(row.pending_time.split(" ")[0]); time_info = ` | Pending: ${d} (${fmt_age(row.pending_time)})`; } else if (row.status === "Responded" && row.response_time) { - let d = frappe.datetime.str_to_user(row.response_time.split(' ')[0]); + let d = frappe.datetime.str_to_user(row.response_time.split(" ")[0]); time_info = ` | Responded: ${d} (${fmt_age(row.response_time)} ago)`; } From 2d86164d422c1ceec52ee3097df5b19d0ded58d0 Mon Sep 17 00:00:00 2001 From: Suraiyya Sutriya Date: Fri, 22 May 2026 16:01:57 +0530 Subject: [PATCH 3/4] feat: grant global access to Audit Manager in Audit Level --- .../audit_management/doctype/audit_level/audit_level.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/audit_management/audit_management/doctype/audit_level/audit_level.py b/audit_management/audit_management/doctype/audit_level/audit_level.py index 95f190f..8f6b825 100755 --- a/audit_management/audit_management/doctype/audit_level/audit_level.py +++ b/audit_management/audit_management/doctype/audit_level/audit_level.py @@ -201,7 +201,7 @@ def get_permission_query_conditions(user=None): roles = frappe.get_roles(user) # System Admins see everything - if "Administrator" in roles or "System Manager" in roles: + if "Administrator" in roles or "System Manager" in roles or "Audit Manager" in roles: return "" # Division check @@ -221,7 +221,7 @@ def has_permission(doc, ptype, user=None): roles = frappe.get_roles(user) # 1. System Admins see everything - if "Administrator" in roles or "System Manager" in roles: + if "Administrator" in roles or "System Manager" in roles or "Audit Manager" in roles: return True # 2. Get allowed divisions From 7c70e189ff78fb2517bf779173adc1813444f17c Mon Sep 17 00:00:00 2001 From: Suraiyya Sutriya Date: Fri, 22 May 2026 16:02:02 +0530 Subject: [PATCH 4/4] feat: grant global access to Audit Manager in My Audits and fix NameError --- .../audit_management/doctype/my_audits/my_audits.py | 13 +++---------- 1 file changed, 3 insertions(+), 10 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 0722598..069f3f6 100755 --- a/audit_management/audit_management/doctype/my_audits/my_audits.py +++ b/audit_management/audit_management/doctype/my_audits/my_audits.py @@ -840,11 +840,12 @@ def get_permission_query_conditions(user=None): user = frappe.session.user roles = frappe.get_roles(user) + is_audit_manager = "Audit Manager" in roles or "Administrator" in roles or "System Manager" in roles # ========================================================= # ADMIN BYPASS # ========================================================= - if "Administrator" in roles or "System Manager" in roles: + if is_audit_manager: return "" # ========================================================= @@ -857,19 +858,11 @@ def get_permission_query_conditions(user=None): ) if allowed_divisions else "'None'" # ========================================================= - # AUDIT MANAGER - # Full division access - # ========================================================= - if "Audit Manager" in roles: - return f""" - `tabMy Audits`.emp_division IN ({divisions_sql}) - """ - # ========================================================= # AUDIT MEMBER # Only created records # ========================================================= - if "Audit Member" in roles: + if "Audit Member" in roles and not is_audit_manager: return f""" `tabMy Audits`.owner = '{user}' """