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
Expand Up @@ -11,7 +11,10 @@
"employee",
"user_id",
"employee_name",
"email"
"email",
"status",
"attachment",
"response"
],
"fields": [
{
Expand Down Expand Up @@ -50,7 +53,7 @@
"read_only": 1
},
{
"columns": 2,
"columns": 1,
"fetch_from": "employee.employee_name",
"fieldname": "employee_name",
"fieldtype": "Data",
Expand All @@ -63,13 +66,33 @@
"fieldtype": "Data",
"in_list_view": 1,
"label": "Email"
},
{
"fieldname": "attachment",
"fieldtype": "Attach",
"label": "Attachment",
"read_only": 1
},
{
"fieldname": "response",
"fieldtype": "Small Text",
"label": "Response",
"read_only": 1
},
{
"columns": 1,
"fieldname": "status",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Status",
"options": "\nPending\nNo Response\nResponded\nSkipped"
}
],
"grid_page_length": 50,
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2026-02-23 13:35:13.202653",
"modified": "2026-02-24 12:31:57.853058",
"modified_by": "Administrator",
"module": "Audit Management",
"name": "Audit Items",
Expand Down
17 changes: 15 additions & 2 deletions audit_management/audit_management/doctype/my_audits/my_audits.json
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@
"ceo_user_id",
"column_break_yvwil",
"ceo_mail",
"audit_items_section",
"audit_stages",
"new_request_tab",
"enter_branch_section",
"emp_branch",
Expand Down Expand Up @@ -1102,15 +1104,26 @@
"fieldtype": "Select",
"label": "send mail to all ?",
"options": "\nNo\nYes"
},
{
"fieldname": "audit_items_section",
"fieldtype": "Section Break",
"label": "Audit Items"
},
{
"fieldname": "audit_stages",
"fieldtype": "Table",
"label": "Audit Stages",
"options": "Audit Items"
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2025-11-10 12:27:27.544584",
"modified": "2026-02-23 15:45:48.381781",
"modified_by": "Administrator",
"module": "Audit Management",
"name": "My Audits",
"naming_rule": "Expression",
"naming_rule": "Expression (old style)",
"owner": "Administrator",
"permissions": [
{
Expand Down
88 changes: 88 additions & 0 deletions audit_management/audit_management/doctype/my_audits/my_audits.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,94 @@
from frappe import _
from frappe.model.document import Document
from frappe.utils import now
class MyAudits(Document):
def before_save(self):
# Call the new function to populate audit stages
populate_audit_stages_on_save(self)

@frappe.whitelist()
def populate_audit_stages_on_save(doc):
"""
Populates the 'audit_stages' child table of a My Audits document
from the linked Audit Level document.
This function is intended to be called as a DocType hook (e.g., before_save).
"""

if not doc.emp_branch:
# If no Audit Level is linked, clear the child table and return
doc.set("audit_stages", [])
return

# Define the mapping from Audit Level fields to Audit Items child table fields
# Format: (emp_id_field, mail_field, stage_number, stage_name_label)
STAGE_MAP = [
("stage_1_bm_emp_id", "stage_1_bm_mail", 1, "BM"),
("stage_2_dh_emp_id", "stage_2_dh_mail", 2, "DH"),
("stage_2_com_emp_id", "stage_2_com_mail", 2, "COM"), # Assuming COM is also stage 2
("stage_3_rm_emp_id", "stage_3_rm_mail", 3, "RM"),
("stage_3_rom_emp_id", "stage_3_rom_mail", 3, "ROM"), # Assuming ROM is also stage 3
("stage_4_zm_emp_id", "stage_4_zm_mail", 4, "ZM"),
("stage_4_zom_emp_id", "stage_4_zom_mail", 4, "ZOM"), # Assuming ZOM is also stage 4
("stage_5_gm_emp_id", "stage_5_gm_mail", 5, "GM"),
("stage_6_hr_emp_id", "stage_6_hr_mail", 6, "HR"),
("stage_7_coo_emp_id", "stage_7_coo_mail", 7, "COO"),
("stage_8_ceo_emp_id", "stage_8_ceo_mail", 8, "CEO"),
]

try:
# Check if the linked Audit Level document exists
if not frappe.db.exists("Audit Level", doc.emp_branch):
frappe.log_error(f"Audit Level document '{doc.emp_branch}' linked in 'My Audits' '{doc.name}' not found.",
"Populate Audit Stages Hook")
doc.set("audit_stages", []) # Clear child table if linked Audit Level is missing
return

audit_level_doc = frappe.get_doc("Audit Level", doc.emp_branch)

# Clear existing child table entries for idempotency
# Only clear if emp_branch has changed or if it's a new document
# if doc.has_changed("emp_branch") or doc.is_new():
doc.set("audit_stages", [])

new_audit_stages_entries = []

for emp_field_id, mail_field, stage_number, stage_name_label in STAGE_MAP:
employee_id = audit_level_doc.get(emp_field_id)
employee_mail = audit_level_doc.get(mail_field)

if employee_id:
emp_user_id_field = emp_field_id.replace("_emp_id", "_user_id")
emp_name_field = emp_field_id.replace("_emp_id", "_name")

employee_user_id = audit_level_doc.get(emp_user_id_field)
employee_name = audit_level_doc.get(emp_name_field)

new_audit_stages_entries.append({
"doctype": "Audit Items",
"stage": stage_number,
"stage_name": frappe.db.get_value("Audit Stage", {"name": stage_name_label}, "name") or stage_name_label,
"employee": employee_id,
"user_id": employee_user_id,
"employee_name": employee_name,
"email": employee_mail
})

# Sort the entries by stage number
new_audit_stages_entries = sorted(
new_audit_stages_entries,
key=lambda x: int(x.get("stage", 0))
)

# Append sorted entries to the child table and fix idx
for i, row_data in enumerate(new_audit_stages_entries, start=1):
row = doc.append("audit_stages", row_data)
row.idx = i

except Exception as e:
frappe.log_error(f"Error populating 'audit_stages' for 'My Audits' {doc.name}: {e}", "Populate Audit Stages Hook")
# Ensure child table is cleared or not populated on error
doc.set("audit_stages", [])

class MyAudits(Document):
pass

Expand Down
3 changes: 2 additions & 1 deletion audit_management/patches.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@
# Patches added in this section will be executed after doctypes are migrated
audit_management.patches.fixtures.add_audit_roles
audit_management.patches.fixtures.audit_permission_patch
audit_management.patches.migrate_audit_level_to_child
audit_management.patches.migrate_audit_level_to_child
audit_management.patches.migrate_audit_level_to_my_audits_child
116 changes: 116 additions & 0 deletions audit_management/patches/migrate_audit_level_to_my_audits_child.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import frappe

def execute():
"""
Migrates stage information from linked Audit Level documents into the
'audit_stages' child table of My Audits documents.
Ensures idempotency and proper sorting.
"""

print("=======================================================")
print("🚀 Starting Migration Patch: Audit Level to My Audits Child Table")
print("=======================================================")

# Define the mapping from Audit Level fields to Audit Items child table fields
# Format: (emp_id_field, mail_field, stage_number, stage_name_label)
STAGE_MAP = [
("stage_1_bm_emp_id", "stage_1_bm_mail", 1, "BM"),
("stage_2_dh_emp_id", "stage_2_dh_mail", 2, "DH"),
("stage_2_com_emp_id", "stage_2_com_mail", 2, "COM"), # Assuming COM is also stage 2
("stage_3_rm_emp_id", "stage_3_rm_mail", 3, "RM"),
("stage_3_rom_emp_id", "stage_3_rom_mail", 3, "ROM"), # Assuming ROM is also stage 3
("stage_4_zm_emp_id", "stage_4_zm_mail", 4, "ZM"),
("stage_4_zom_emp_id", "stage_4_zom_mail", 4, "ZOM"), # Assuming ZOM is also stage 4
("stage_5_gm_emp_id", "stage_5_gm_mail", 5, "GM"),
("stage_6_hr_emp_id", "stage_6_hr_mail", 6, "HR"),
("stage_7_coo_emp_id", "stage_7_coo_mail", 7, "COO"),
("stage_8_ceo_emp_id", "stage_8_ceo_mail", 8, "CEO"),
]

# Get all My Audits documents that have an emp_branch linked to an Audit Level
my_audits_list = frappe.get_all(
"My Audits",
filters={"emp_branch": ["is", "set"]},
fields=["name", "emp_branch"]
)

print(f"🔎 Found {len(my_audits_list)} 'My Audits' documents with linked 'Audit Level'.\n")

for my_audit_data in my_audits_list:
my_audit_name = my_audit_data.name
audit_level_name = my_audit_data.emp_branch

print(f"➡ Processing 'My Audits' document: {my_audit_name} (Linked to 'Audit Level': {audit_level_name})")

try:
# Load the My Audits document
my_audit_doc = frappe.get_doc("My Audits", my_audit_name)

# Check if the linked Audit Level document exists
if not frappe.db.exists("Audit Level", audit_level_name):
frappe.log_error(f"Audit Level document '{audit_level_name}' linked in 'My Audits' '{my_audit_name}' not found. Skipping.",
"Audit Level to My Audits Migration")
print(f" ⚠️ Audit Level '{audit_level_name}' not found. Skipping 'My Audits': {my_audit_name}\n")
continue # Skip to the next My Audits document

audit_level_doc = frappe.get_doc("Audit Level", audit_level_name)

# Clear existing child table entries for idempotency
my_audit_doc.set("audit_stages", [])

new_audit_stages_entries = []

for emp_field_id, mail_field, stage_number, stage_name_label in STAGE_MAP:
employee_id = audit_level_doc.get(emp_field_id)
employee_mail = audit_level_doc.get(mail_field)

if employee_id:
# Deriving user_id and employee_name from the Audit Level doc
# based on the fetch_from definitions in audit_level.json
emp_user_id_field = emp_field_id.replace("_emp_id", "_user_id")
emp_name_field = emp_field_id.replace("_emp_id", "_name")

employee_user_id = audit_level_doc.get(emp_user_id_field)
employee_name = audit_level_doc.get(emp_name_field)

# Create a new entry for the child table
new_audit_stages_entries.append({
"doctype": "Audit Items", # Child DocType name
"stage": stage_number,
# Link to Audit Stage if exists, otherwise just the label.
# Assuming Audit Stage DocTypes exist with these names.
"stage_name": frappe.db.get_value("Audit Stage", {"name": stage_name_label}, "name") or stage_name_label,
"employee": employee_id,
"user_id": employee_user_id,
"employee_name": employee_name,
"email": employee_mail
})

# Sort the entries by stage number
new_audit_stages_entries = sorted(
new_audit_stages_entries,
key=lambda x: int(x.get("stage", 0))
)

# Append sorted entries to the child table and fix idx
for i, row_data in enumerate(new_audit_stages_entries, start=1):
row = my_audit_doc.append("audit_stages", row_data)
row.idx = i

# Save the My Audits document, ignoring validations for migration
my_audit_doc.flags.ignore_mandatory = True
my_audit_doc.flags.ignore_validate = True
my_audit_doc.save(ignore_permissions=True)

print(f" ✅ Successfully migrated stages for 'My Audits': {my_audit_name}\n")

except Exception as e:
frappe.log_error(f"Error migrating 'My Audits' {my_audit_name}: {e}", "Audit Level to My Audits Migration")
print(f" ❌ Failed to migrate stages for 'My Audits': {my_audit_name}. Error: {e}\n")
frappe.db.rollback() # Rollback changes for this document on error

frappe.db.commit() # Final commit for all successful operations

print("=========================================================")
print("🎯 Audit Level to My Audits Child Table Migration Patch Completed")
print("=========================================================\n")
Loading