From 0320b59ea615b372c9d627db54d272607b104878 Mon Sep 17 00:00:00 2001 From: marination Date: Mon, 20 Jun 2022 16:25:34 +0530 Subject: [PATCH 1/2] chore: Clear Progress section for completed logs & `on_submit` UX - Delete `BOM Update Batch` table on 'Completed' log, to save space - Hide Progress section on 'Completed' log - Enqueue `on_submit` for 'Update Cost' job, getting leaf boms could take time for huge DBs. Users have to wait for screen to unfreeze. - Add error handling to `process_boms_cost_level_wise` (Called via cron job and on submit, both in background) --- .../bom_update_log/bom_update_log.json | 10 ++-- .../doctype/bom_update_log/bom_update_log.py | 59 +++++++++++-------- 2 files changed, 42 insertions(+), 27 deletions(-) diff --git a/erpnext/manufacturing/doctype/bom_update_log/bom_update_log.json b/erpnext/manufacturing/doctype/bom_update_log/bom_update_log.json index c32e383b08..a926e69ee6 100644 --- a/erpnext/manufacturing/doctype/bom_update_log/bom_update_log.json +++ b/erpnext/manufacturing/doctype/bom_update_log/bom_update_log.json @@ -7,11 +7,11 @@ "editable_grid": 1, "engine": "InnoDB", "field_order": [ - "current_bom", - "new_bom", - "column_break_3", "update_type", "status", + "column_break_3", + "current_bom", + "new_bom", "error_log", "progress_section", "current_level", @@ -37,6 +37,7 @@ "options": "BOM" }, { + "depends_on": "eval:doc.update_type === \"Replace BOM\"", "fieldname": "column_break_3", "fieldtype": "Column Break" }, @@ -87,6 +88,7 @@ "options": "BOM Update Batch" }, { + "depends_on": "eval:doc.status !== \"Completed\"", "fieldname": "current_level", "fieldtype": "Int", "label": "Current Level" @@ -96,7 +98,7 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2022-06-06 15:15:23.883251", + "modified": "2022-06-20 15:43:55.696388", "modified_by": "Administrator", "module": "Manufacturing", "name": "BOM Update Log", diff --git a/erpnext/manufacturing/doctype/bom_update_log/bom_update_log.py b/erpnext/manufacturing/doctype/bom_update_log/bom_update_log.py index 9c9c24044a..af5ff8e1c2 100644 --- a/erpnext/manufacturing/doctype/bom_update_log/bom_update_log.py +++ b/erpnext/manufacturing/doctype/bom_update_log/bom_update_log.py @@ -77,7 +77,11 @@ class BOMUpdateLog(Document): now=frappe.flags.in_test, ) else: - process_boms_cost_level_wise(self) + frappe.enqueue( + method="erpnext.manufacturing.doctype.bom_update_log.bom_update_log.process_boms_cost_level_wise", + update_doc=self, + now=frappe.flags.in_test, + ) def run_replace_bom_job( @@ -112,28 +116,31 @@ def process_boms_cost_level_wise( current_boms = {} values = {} - if update_doc.status == "Queued": - # First level yet to process. On Submit. - current_level = 0 - current_boms = get_leaf_boms() - values = { - "processed_boms": json.dumps({}), - "status": "In Progress", - "current_level": current_level, - } - else: - # Resume next level. via Cron Job. - if not parent_boms: - return + try: + if update_doc.status == "Queued": + # First level yet to process. On Submit. + current_level = 0 + current_boms = get_leaf_boms() + values = { + "processed_boms": json.dumps({}), + "status": "In Progress", + "current_level": current_level, + } + else: + # Resume next level. via Cron Job. + if not parent_boms: + return - current_level = cint(update_doc.current_level) + 1 + current_level = cint(update_doc.current_level) + 1 - # Process the next level BOMs. Stage parents as current BOMs. - current_boms = parent_boms.copy() - values = {"current_level": current_level} + # Process the next level BOMs. Stage parents as current BOMs. + current_boms = parent_boms.copy() + values = {"current_level": current_level} - set_values_in_log(update_doc.name, values, commit=True) - queue_bom_cost_jobs(current_boms, update_doc, current_level) + set_values_in_log(update_doc.name, values, commit=True) + queue_bom_cost_jobs(current_boms, update_doc, current_level) + except Exception: + handle_exception(update_doc) def queue_bom_cost_jobs( @@ -199,16 +206,22 @@ def resume_bom_cost_update_jobs(): current_boms, processed_boms = get_processed_current_boms(log, bom_batches) parent_boms = get_next_higher_level_boms(child_boms=current_boms, processed_boms=processed_boms) - # Unset processed BOMs if log is complete, it is used for next level BOMs + # Unset processed BOMs (it is used for next level BOMs) & change status if log is complete + status = "Completed" if not parent_boms else "In Progress" + processed_boms = json.dumps([] if not parent_boms else processed_boms) set_values_in_log( log.name, values={ - "processed_boms": json.dumps([] if not parent_boms else processed_boms), - "status": "Completed" if not parent_boms else "In Progress", + "processed_boms": processed_boms, + "status": status, }, commit=True, ) + # clear progress section + if status == "Completed": + frappe.db.delete("BOM Update Batch", {"parent": log.name}) + if parent_boms: # there is a next level to process process_boms_cost_level_wise( update_doc=frappe.get_doc("BOM Update Log", log.name), parent_boms=parent_boms From 4cf2225a29c0d1c1a1967de20c78b411f055bf53 Mon Sep 17 00:00:00 2001 From: marination Date: Tue, 21 Jun 2022 14:03:05 +0530 Subject: [PATCH 2/2] chore: Implement Log clearing interface in BOM Update Log - Implement Log clearing interface in BOM Update Log - Add additional info in sidebar: Log clearing only happens for 'Update Cost' type logs - 'Replace BOM' logs have important info and is used in BOM timeline, so we'll let users decide if they wanna keep or discard it --- .../doctype/bom_update_log/bom_update_log.py | 13 ++++++++++++ .../bom_update_log/bom_update_log_list.js | 21 +++++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/erpnext/manufacturing/doctype/bom_update_log/bom_update_log.py b/erpnext/manufacturing/doctype/bom_update_log/bom_update_log.py index af5ff8e1c2..c3f52d4583 100644 --- a/erpnext/manufacturing/doctype/bom_update_log/bom_update_log.py +++ b/erpnext/manufacturing/doctype/bom_update_log/bom_update_log.py @@ -6,6 +6,8 @@ from typing import Any, Dict, List, Optional, Tuple, Union import frappe from frappe import _ from frappe.model.document import Document +from frappe.query_builder import DocType, Interval +from frappe.query_builder.functions import Now from frappe.utils import cint, cstr from erpnext.manufacturing.doctype.bom_update_log.bom_updation_utils import ( @@ -22,6 +24,17 @@ class BOMMissingError(frappe.ValidationError): class BOMUpdateLog(Document): + @staticmethod + def clear_old_logs(days=None): + days = days or 90 + table = DocType("BOM Update Log") + frappe.db.delete( + table, + filters=( + (table.modified < (Now() - Interval(days=days))) & (table.update_type == "Update Cost") + ), + ) + def validate(self): if self.update_type == "Replace BOM": self.validate_boms_are_specified() diff --git a/erpnext/manufacturing/doctype/bom_update_log/bom_update_log_list.js b/erpnext/manufacturing/doctype/bom_update_log/bom_update_log_list.js index e39b5637c7..bc709d8fc4 100644 --- a/erpnext/manufacturing/doctype/bom_update_log/bom_update_log_list.js +++ b/erpnext/manufacturing/doctype/bom_update_log/bom_update_log_list.js @@ -1,6 +1,6 @@ frappe.listview_settings['BOM Update Log'] = { add_fields: ["status"], - get_indicator: function(doc) { + get_indicator: (doc) => { let status_map = { "Queued": "orange", "In Progress": "blue", @@ -9,5 +9,22 @@ frappe.listview_settings['BOM Update Log'] = { }; return [__(doc.status), status_map[doc.status], "status,=," + doc.status]; - } + }, + onload: () => { + if (!frappe.model.can_write("Log Settings")) { + return; + } + + let sidebar_entry = $( + '' + ).appendTo(cur_list.page.sidebar); + let message = __("Note: Automatic log deletion only applies to logs of type Update Cost"); + $(`
${message}
`).appendTo(sidebar_entry); + + frappe.require("logtypes.bundle.js", () => { + frappe.utils.logtypes.show_log_retention_message(cur_list.doctype); + }); + + + }, }; \ No newline at end of file