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
32 changes: 26 additions & 6 deletions audit_management/audit_management/doctype/my_audits/my_audits.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,16 @@ frappe.ui.form.on("My Audits", {
date_html += item("Closed", closed_date);
}

if (frm.doc.aging !== undefined && frm.doc.aging !== null) {
date_html += item("Aging", `${frm.doc.aging} Days`);
if (frm.doc.creation) {
const created_date = frappe.datetime.str_to_user(frm.doc.creation.split(" ")[0]);

// Calculate dynamic aging: today - creation date
const creation_date_obj = frappe.datetime.str_to_obj(frm.doc.creation);
const today = new Date();
const time_diff = today - creation_date_obj;
const dynamic_aging = Math.floor(time_diff / (1000 * 60 * 60 * 24));

date_html += item("Aging", `${dynamic_aging} Days`);
}

date_html += `</span>`;
Expand Down Expand Up @@ -483,11 +491,14 @@ frappe.ui.form.on("My Audits", {
args: { docname: frm.doc.name },
callback: function (r) {
if (r.message) {
// Check again if it's already there to be absolutely sure
if (frm.page.wrapper.find(".custom-status-tracker").length === 0) {
frm.set_intro(
`<div class="custom-status-tracker">${r.message}</div>`,
);
// Initialize Bootstrap tooltips
setTimeout(() => {
frm.page.wrapper.find('[data-toggle="tooltip"]').tooltip();
}, 300);
}
} else {
frm.is_intro_set = false;
Expand Down Expand Up @@ -2327,6 +2338,7 @@ function render_interactive_tracker(frm, can_edit) {
.pill-pending { background-color: #fef2f2; border: 1px solid #fecaca; color: #b91c1c; }
.pill-responded { background-color: #f0fdf4; border: 1px solid #bbf7d0; color: #15803d; }
.pill-skipped { background-color: #faf5ff; border: 1px solid #e9d5ff; color: #6b21a8; }
.pill-no-response { background-color: #fff7ed; border: 1px solid #fdba74; color: #c2410c; }
.pill-default { background-color: #f3f4f6; border: 1px solid #e5e7eb; color: #374151; }
.pill-audit-team { background-color: #eff6ff; border: 1px solid #bfdbfe; color: #1d4ed8; }

Expand Down Expand Up @@ -2437,17 +2449,25 @@ function render_interactive_tracker(frm, can_edit) {
? "pill-responded"
: row.status === "Skipped"
? "pill-skipped"
: "pill-default";
: row.status === "No Response"
? "pill-no-response"
: "pill-default";

// 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) {
if (
(row.status === "Pending" || row.status === "No Response") &&
row.pending_time
) {
let d = frappe.datetime.str_to_user(row.pending_time.split(" ")[0]);
time_info = ` | Pending: ${d} (${fmt_age(row.pending_time)})`;
time_info =
row.status === "No Response"
? ` | No Response Since: ${d} (${fmt_age(row.pending_time)})`
: ` | 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]);
time_info = ` | Responded: ${d} (${fmt_age(row.response_time)} ago)`;
Expand Down
86 changes: 77 additions & 9 deletions audit_management/audit_management/doctype/my_audits/my_audits.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -249,11 +249,7 @@ def sync_new_to_old(self):
prefix = m["prefix"]
break

# Debugging log
frappe.log_error(
title="Stage Mapping Debug",
message=f"Stage Name: {row.stage_name} | Found Prefix: {prefix}"
)


if prefix:
self.set(f"{prefix}_name", row.employee_name)
Expand Down Expand Up @@ -348,30 +344,48 @@ def populate_audit_stages(doc):
@frappe.whitelist()
def get_status_tracker_html(docname):
audit_doc = frappe.get_doc("My Audits", docname)

from frappe.utils import getdate, nowdate
creation_date = getdate(audit_doc.creation)
today = getdate(nowdate())
dynamic_aging = (today - creation_date).days

def create_status_box(text, color, title):
return f"<div style='display:inline-block; padding: 2px 6px; border-radius: 10px; border: 2px solid {color}; color: {color}; cursor: pointer;' title='{title}'>{text}</div>"
return f"<div style='display:inline-block; padding: 2px 6px; border-radius: 10px; border: 2px solid {color} !important; color: {color} !important; cursor: pointer;' title='{title}'>{text}</div>"

html_output = create_status_box(
"AUDIT TEAM", '#1E6EB2', 'Stage 0 : Audit Query') + " <b>--></b> "
"AUDIT TEAM", '#1E6EB2', f'Stage 0 : Audit Query (Aging: {dynamic_aging} days)') + " <b>--></b> "

for i, row in enumerate(audit_doc.audit_stages):
color = "grey"
title = f"Stage {row.stage} : {row.stage_name} - {row.status or 'Waiting'}"
# Include aging in tooltip
title = f"Stage {row.stage} : {row.stage_name} - {row.status or 'Waiting'} (Aging: {dynamic_aging} days)"

if row.status == "Pending":
color = "red"
elif row.status == "Responded":
color = "green"
elif row.status == "No Response":
color = "#4b0a7d"
color = "#4b0a7d"
elif row.status == "Skipped":
color = "#ffbe0b"
else:
color = "grey"

# Constructing Title with specific check for No Response details
status_text = row.status or 'Waiting'
title = f"Stage {row.stage} : {row.stage_name} - {status_text} (Aging: {dynamic_aging} days)"
if row.status == "No Response" and row.pending_time:
from frappe.utils import format_datetime
title += f" | Last Attempt: {format_datetime(row.pending_time, 'dd-MM-yyyy')}"

html_output += create_status_box(row.stage_name, color, title)
if i < len(audit_doc.audit_stages) - 1:
html_output += " <b>--></b> "

# Log for debugging
frappe.log_error(title="Tracker HTML Output", message=html_output)

return html_output


Expand Down Expand Up @@ -1251,3 +1265,57 @@ def check_pending_tat():
doc.query_status = "Unresolved - Escalation Exhausted"

doc.save(ignore_permissions=True)
import frappe
from frappe.utils import getdate, nowdate, format_datetime
import html

@frappe.whitelist()
def get_status_tracker_html(docname):
try:
audit_doc = frappe.get_doc("My Audits", docname)

creation_date = getdate(audit_doc.creation)
today = getdate(nowdate())
dynamic_aging = (today - creation_date).days

html_output = """
<style>
.status-tracker-container { display:flex; align-items:center; flex-wrap:wrap; gap:5px; }
.tracker-pill { padding:2px 8px; border-radius:10px; display:inline-block; margin-left:5px; cursor:pointer; font-weight:600; border:2px solid; }
.tracker-red { color:#ef4444 !important; border-color:#ef4444 !important; }
.tracker-green { color:#22c55e !important; border-color:#22c55e !important; }
.tracker-purple { color:#4b0a7d !important; border-color:#4b0a7d !important; }
.tracker-yellow { color:#ffbe0b !important; border-color:#ffbe0b !important; }
.tracker-grey { color:#6b7280 !important; border-color:#6b7280 !important; }
.tracker-blue { color:#1E6EB2 !important; border-color:#1E6EB2 !important; }
</style>
<div class='status-tracker-container'>
"""

# Base Node
html_output += f"<span class='tracker-pill tracker-blue' data-toggle='tooltip' title='Stage 0: Audit Query (Aging: {dynamic_aging} days)'>AUDIT TEAM</span>"

for row in audit_doc.audit_stages:
status = (row.status or "").strip()
status_class_map = {
"Pending": "tracker-red",
"Responded": "tracker-green",
"No Response": "tracker-purple",
"Skipped": "tracker-yellow",
}
css_class = status_class_map.get(status, "tracker-grey")

# Tooltip details
title = f"{row.stage_name} : {status or 'Waiting'} (Aging: {dynamic_aging} days)"
if status == "No Response" and row.pending_time:
title += f" | Last Attempt: {format_datetime(row.pending_time, 'dd-MM-yyyy')}"

safe_title = html.escape(title)

html_output += f"<span class='tracker-pill {css_class}' data-toggle='tooltip' title='{safe_title}'>{row.stage_name}</span>"

html_output += "</div>"
return html_output
except Exception as e:
frappe.log_error(f"Tracker Error: {str(e)}")
return f"Error: {str(e)}"
Original file line number Diff line number Diff line change
Expand Up @@ -3,136 +3,65 @@
/* eslint-disable */

frappe.query_reports["My Audits Report"] = {
filters: [
{
fieldname: "from_date",
label: "From Date",
fieldtype: "Date",
},
{
fieldname: "to_date",
label: "To Date",
fieldtype: "Date",
},
{
fieldname: "emp_branch",
label: "Branch",
fieldtype: "Link",
options: "Audit Level",
},
{
fieldname: "query_generated_by_empid",
label: "Generated By (Emp ID)",
fieldtype: "Link",
options: "Employee",
get_query: () => {
return {
filters: {
status: "Active",
department: "Audit",
},
};
},
},
{
fieldname: "query_generated_by_name",
label: "Generated By (Name)",
fieldtype: "Link",
options: "Employee",
get_query: () => {
return {
filters: {
status: "Active",
department: "Audit",
},
};
},
},
{
fieldname: "query_type",
label: "Query Type",
fieldtype: "Select",
options: "\nAudit Report Compliance\nCritical Compliance",
},
{
fieldname: "status",
label: "Query Status",
fieldtype: "Select",
options: "\nDraft\nPending\nClosed",
},
{
fieldname: "bm_user_status",
label: "BM Response Status",
fieldtype: "Select",
options: "\nResponded\nNo response",
},
{
fieldname: "dh_user_status",
label: "DH Response Status",
fieldtype: "Select",
options: "\nResponded\nNo response",
},
{
fieldname: "com_user_status",
label: "COM Response Status",
fieldtype: "Select",
options: "\nResponded\nNo response",
},
{
fieldname: "rm_user_status",
label: "RM Response Status",
fieldtype: "Select",
options: "\nResponded\nNo response",
},
{
fieldname: "rom_user_status",
label: "ROM Response Status",
fieldtype: "Select",
options: "\nResponded\nNo response",
},
{
fieldname: "zm_user_status",
label: "ZM Response Status",
fieldtype: "Select",
options: "\nResponded\nNo response",
},
{
fieldname: "zom_user_status",
label: "ZOM Response Status",
fieldtype: "Select",
options: "\nResponded\nNo response",
},
{
fieldname: "gm_user_status",
label: "GM Response Status",
fieldtype: "Select",
options: "\nResponded\nNo response",
},
{
fieldname: "hr_user_status",
label: "HR Response Status",
fieldtype: "Select",
options: "\nResponded\nNo response",
},
{
fieldname: "coo_user_status",
label: "COO Response Status",
fieldtype: "Select",
options: "\nResponded\nNo response",
},
{
fieldname: "ceo_user_status",
label: "CEO Response Status",
fieldtype: "Select",
options: "\nResponded\nNo response",
},
],
filters: [
{
fieldname: "from_date",
label: __("From Date"),
fieldtype: "Date",
},
{
fieldname: "to_date",
label: __("To Date"),
fieldtype: "Date",
},
{
fieldname: "emp_branch",
label: __("Branch"),
fieldtype: "Link",
options: "Audit Level",
},
{
fieldname: "query_generated_by_empid",
label: __("Generated By Employee"),
fieldtype: "Link",
options: "Employee",
},
{
fieldname: "query_type",
label: __("Query Type"),
fieldtype: "Link",
options: "Audit Query Type",
},
{
fieldname: "status",
label: __("Query Status"),
fieldtype: "Select",
options: "\nDraft\nPending\nClosed",
},
{
fieldname: "stage_name",
label: __("Audit Stage"),
fieldtype: "Link",
options: "Audit Stage",
},
{
fieldname: "stage_status",
label: __("Stage Response Status"),
fieldtype: "Select",
options: "\nPending\nResponded\nNo response\nSkipped",
},
{
fieldname: "stage_employee",
label: __("Stage Employee"),
fieldtype: "Link",
options: "Employee",
},
],

// clear filters button
onload: function (report) {
report.page.add_inner_button(__("Clear Filters"), function () {
report.filters.forEach((f) => f.set_value(""));
report.refresh();
});
},
onload: function (report) {
report.page.add_inner_button(__("Clear Filters"), function () {
report.filters.forEach((f) => f.set_value(""));
report.refresh();
});
},
};
Loading
Loading