From e4ae34f537b72a3efac4727c0a863ea4d19f579d Mon Sep 17 00:00:00 2001 From: esaLCuE Date: Fri, 21 Mar 2025 10:28:50 +0100 Subject: [PATCH 01/18] Changed item group field to multiselect and added items multiselect field --- .../itemwise_recommended_reorder_level.js | 52 ++++++++++++++++--- .../itemwise_recommended_reorder_level.py | 27 ++++++++-- .../stock/report/stock_ledger/stock_ledger.py | 17 ++++++ 3 files changed, 85 insertions(+), 11 deletions(-) diff --git a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js index 8d46b14a177..00b714553a0 100644 --- a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js +++ b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js @@ -15,18 +15,56 @@ frappe.query_reports["Itemwise Recommended Reorder Level"] = { fieldtype: "Date", default: frappe.datetime.get_today(), }, - { - fieldname: "item_group", - label: __("Item Group"), - fieldtype: "Link", - options: "Item Group", - reqd: 1, - }, { fieldname: "brand", label: __("Brand"), fieldtype: "Link", options: "Brand", }, + { + fieldname:"item_group", + label: __("Item Group"), + fieldtype: "MultiSelectList", + width: "100", + get_data: function(txt) { + return frappe.db.get_link_options('Item Group', txt); + }, + + on_change: function(report){ + let itGro = frappe.query_report.get_filter_value("item_group"); + console.log("itGro : ", itGro); + let itNam = frappe.query_report.get_filter_value("item_name"); + console.log("itNam : ", itNam); + + frappe.db.get_list("Item", { + filters: { + item_group:["in", itGro], + name:["in", itNam] + }, + fields:["name"] + }).then((items) => { + let itemNames = items.map(item=>item.name); + frappe.query_report.set_filter_value("item_name", itemNames); + }) + + report.refresh(); + } + }, + { + "fieldname":"item_name", + "label": __("Items"), + "fieldtype": "MultiSelectList", + "width": "100", + get_data: function(txt) { + let itGro = frappe.query_report.get_filter_value("item_group"); + if (itGro==""){ + return frappe.db.get_link_options('Item', txt) + } else { + return frappe.db.get_link_options('Item', txt, { + "item_group":["in", itGro] + }); + } + } + }, ], }; diff --git a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py index c4358b809fc..f8da3077267 100644 --- a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py +++ b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py @@ -1,6 +1,7 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt +from erpnext.stock.report.stock_ledger.stock_ledger import get_item_name_condition import frappe from frappe import _ from frappe.query_builder.functions import Abs, Sum @@ -69,10 +70,13 @@ def get_columns(): def get_item_info(filters): from erpnext.stock.report.stock_ledger.stock_ledger import get_item_group_condition + from pypika import Criterion item = frappe.qb.DocType("Item") + ig = frappe.qb.DocType("Item Group") query = ( frappe.qb.from_(item) + .from_(ig) .select( item.name, item.item_name, @@ -82,14 +86,29 @@ def get_item_info(filters): item.safety_stock, item.lead_time_days, ) - .where((item.is_stock_item == 1) & (item.disabled == 0)) + .where( + (item.is_stock_item == 1) + & (item.disabled == 0) + & (item.item_group == ig.name) + ) ) if brand := filters.get("brand"): query = query.where(item.brand == brand) - - if conditions := get_item_group_condition(filters.get("item_group"), item): - query = query.where(conditions) + + groups = filters.get("item_group") + conditions = [] + for group in groups: + if condition := get_item_group_condition(group, item): + conditions.append(condition) + query = query.where(Criterion.any(conditions)) + + items = filters.get("item_name") + conditions=[] + for itm in items: + if condition := get_item_name_condition(itm, item): + conditions.append(condition) + query = query.where(Criterion.any(conditions)) return query.run(as_dict=True) diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py index 391395503b0..2da1f958671 100644 --- a/erpnext/stock/report/stock_ledger/stock_ledger.py +++ b/erpnext/stock/report/stock_ledger/stock_ledger.py @@ -657,3 +657,20 @@ def check_inventory_dimension_filters_applied(filters) -> bool: return True return False + +def get_item_name_condition(itemf, item_table=None): + item_name_details = frappe.db.get_value("Item", itemf, as_dict=1) + if item_name_details: + if item_table: + itn = frappe.qb.DocType("Item") + return item_table.name.isin( + ( + frappe.qb.from_(itn) + .select(itn.name) + .where( + (itemf == itn.item_code) + ) + ) + ) + else: + return -- GitLab From 23910e28572656df5704288b75885f8f28cf8073 Mon Sep 17 00:00:00 2001 From: esaLCuE Date: Fri, 21 Mar 2025 12:18:24 +0100 Subject: [PATCH 02/18] fix: material request option checks all items have one --- .../doctype/production_plan/production_plan.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py index 6f600cc08e3..3d4d39c0e3a 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py @@ -550,6 +550,7 @@ class ProductionPlan(Document): self.db_set("status", self.status) def on_submit(self): + self.check_production_items() self.update_bin_qty() self.update_sales_order() @@ -734,6 +735,7 @@ class ProductionPlan(Document): if self.sub_assembly_items: item["use_multi_level_bom"] = 0 + self.check_production_items() set_default_warehouses(item, default_warehouses) work_order = self.create_work_order(item) if work_order: @@ -1099,6 +1101,11 @@ class ProductionPlan(Document): all_work_orders_completed = all(s == "Completed" for s in wo_status) return all_work_orders_completed + def check_production_items(self): + items_data = self.get_production_items() + for key, item in items_data.items(): + if (item["material_request"] is None and self.get_items_from=="Material Request"): + frappe.throw("Une demande de matériel est nécessaire pour chaque article") @frappe.whitelist() def download_raw_materials(doc, warehouses=None): -- GitLab From 652f8fe249df34bec05bacfedeb59b6692114bd3 Mon Sep 17 00:00:00 2001 From: esaLCuE Date: Fri, 21 Mar 2025 17:11:58 +0100 Subject: [PATCH 03/18] wip --- test.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 test.txt diff --git a/test.txt b/test.txt new file mode 100644 index 00000000000..632e4fe73c3 --- /dev/null +++ b/test.txt @@ -0,0 +1 @@ +Bonjour -- GitLab From 36b300ce2615f4b9ace3d0ff4f08b20ee6809249 Mon Sep 17 00:00:00 2001 From: esaLCuE Date: Thu, 27 Mar 2025 11:34:15 +0100 Subject: [PATCH 04/18] fixes update --- .../doctype/production_plan/production_plan.py | 4 +++- .../itemwise_recommended_reorder_level.py | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py index 3d4d39c0e3a..f375aebcde6 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py @@ -1103,9 +1103,11 @@ class ProductionPlan(Document): def check_production_items(self): items_data = self.get_production_items() + row=0 for key, item in items_data.items(): + row += 1 if (item["material_request"] is None and self.get_items_from=="Material Request"): - frappe.throw("Une demande de matériel est nécessaire pour chaque article") + frappe.throw(_("Row #{0} : This article is not related to a material request").format(row)) @frappe.whitelist() def download_raw_materials(doc, warehouses=None): diff --git a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py index f8da3077267..cad2c089b4b 100644 --- a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py +++ b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py @@ -73,10 +73,10 @@ def get_item_info(filters): from pypika import Criterion item = frappe.qb.DocType("Item") - ig = frappe.qb.DocType("Item Group") +# ig = frappe.qb.DocType("Item Group") query = ( frappe.qb.from_(item) - .from_(ig) +# .from_(ig) .select( item.name, item.item_name, @@ -89,7 +89,7 @@ def get_item_info(filters): .where( (item.is_stock_item == 1) & (item.disabled == 0) - & (item.item_group == ig.name) +# & (item.item_group == ig.name) ) ) -- GitLab From df7d7a9bc614d9137b9c525085e3c087cb77e7e9 Mon Sep 17 00:00:00 2001 From: esaLCuE Date: Fri, 4 Apr 2025 11:56:07 +0200 Subject: [PATCH 05/18] More explicit names --- .../itemwise_recommended_reorder_level.js | 10 ++++------ erpnext/stock/report/stock_ledger/stock_ledger.py | 12 ++++++------ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js index 00b714553a0..328413bdbfd 100644 --- a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js +++ b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js @@ -31,15 +31,13 @@ frappe.query_reports["Itemwise Recommended Reorder Level"] = { }, on_change: function(report){ - let itGro = frappe.query_report.get_filter_value("item_group"); - console.log("itGro : ", itGro); - let itNam = frappe.query_report.get_filter_value("item_name"); - console.log("itNam : ", itNam); + let selectedGroups = frappe.query_report.get_filter_value("item_group"); + let selectedItems = frappe.query_report.get_filter_value("item_name"); frappe.db.get_list("Item", { filters: { - item_group:["in", itGro], - name:["in", itNam] + item_group:["in", selectedGroups], + name:["in", selectedItems] }, fields:["name"] }).then((items) => { diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py index 2da1f958671..77d97ebe3ef 100644 --- a/erpnext/stock/report/stock_ledger/stock_ledger.py +++ b/erpnext/stock/report/stock_ledger/stock_ledger.py @@ -658,17 +658,17 @@ def check_inventory_dimension_filters_applied(filters) -> bool: return False -def get_item_name_condition(itemf, item_table=None): - item_name_details = frappe.db.get_value("Item", itemf, as_dict=1) +def get_item_name_condition(selectedItem, item_table=None): + item_name_details = frappe.db.get_value("Item", selectedItem, as_dict=1) if item_name_details: if item_table: - itn = frappe.qb.DocType("Item") + itm = frappe.qb.DocType("Item") return item_table.name.isin( ( - frappe.qb.from_(itn) - .select(itn.name) + frappe.qb.from_(itm) + .select(itm.name) .where( - (itemf == itn.item_code) + (selectedItem == itm.item_code) ) ) ) -- GitLab From 041e9dc7d9cc3bd2caa55633f4214a5ffae9b14e Mon Sep 17 00:00:00 2001 From: esaLCuE Date: Mon, 7 Apr 2025 11:06:56 +0200 Subject: [PATCH 06/18] Name fixes --- .../itemwise_recommended_reorder_level.js | 6 +++--- .../itemwise_recommended_reorder_level.py | 3 --- erpnext/stock/report/stock_ledger/stock_ledger.py | 12 ++++++------ 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js index 328413bdbfd..65c9b556ab0 100644 --- a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js +++ b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js @@ -54,12 +54,12 @@ frappe.query_reports["Itemwise Recommended Reorder Level"] = { "fieldtype": "MultiSelectList", "width": "100", get_data: function(txt) { - let itGro = frappe.query_report.get_filter_value("item_group"); - if (itGro==""){ + let item_groups = frappe.query_report.get_filter_value("item_group"); + if (item_groups==""){ return frappe.db.get_link_options('Item', txt) } else { return frappe.db.get_link_options('Item', txt, { - "item_group":["in", itGro] + "item_group":["in", item_groups] }); } } diff --git a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py index cad2c089b4b..e4211f827f1 100644 --- a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py +++ b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py @@ -73,10 +73,8 @@ def get_item_info(filters): from pypika import Criterion item = frappe.qb.DocType("Item") -# ig = frappe.qb.DocType("Item Group") query = ( frappe.qb.from_(item) -# .from_(ig) .select( item.name, item.item_name, @@ -89,7 +87,6 @@ def get_item_info(filters): .where( (item.is_stock_item == 1) & (item.disabled == 0) -# & (item.item_group == ig.name) ) ) diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py index 77d97ebe3ef..52f914887f7 100644 --- a/erpnext/stock/report/stock_ledger/stock_ledger.py +++ b/erpnext/stock/report/stock_ledger/stock_ledger.py @@ -658,17 +658,17 @@ def check_inventory_dimension_filters_applied(filters) -> bool: return False -def get_item_name_condition(selectedItem, item_table=None): - item_name_details = frappe.db.get_value("Item", selectedItem, as_dict=1) +def get_item_name_condition(selected_item, item_table=None): + item_name_details = frappe.db.get_value("Item", selected_item, as_dict=1) if item_name_details: if item_table: - itm = frappe.qb.DocType("Item") + item = frappe.qb.DocType("Item") return item_table.name.isin( ( - frappe.qb.from_(itm) - .select(itm.name) + frappe.qb.from_(item) + .select(item.name) .where( - (selectedItem == itm.item_code) + (selected_item == item.item_code) ) ) ) -- GitLab From 1c88de22b82b6e361b8282c3f53f46cd5051354c Mon Sep 17 00:00:00 2001 From: esaLCuE Date: Mon, 7 Apr 2025 16:50:31 +0200 Subject: [PATCH 07/18] fix test: test report --- erpnext/stock/report/test_reports.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/report/test_reports.py b/erpnext/stock/report/test_reports.py index 36e3e2d29bf..9ead7e0453a 100644 --- a/erpnext/stock/report/test_reports.py +++ b/erpnext/stock/report/test_reports.py @@ -22,7 +22,7 @@ REPORT_FILTER_TEST_CASES: list[tuple[ReportName, ReportFilters]] = [ ("Stock Balance", {"_optional": True}), ("Stock Projected Qty", {"_optional": True}), ("Batch-Wise Balance History", {}), - ("Itemwise Recommended Reorder Level", {"item_group": "All Item Groups"}), + ("Itemwise Recommended Reorder Level", {"item_group": ["All Item Groups"]}), ("COGS By Item Group", {}), ("Stock Qty vs Serial No Count", {"warehouse": "_Test Warehouse - _TC"}), ( -- GitLab From e7771e96ea4efd5b90b2518052c5cd59adca1f01 Mon Sep 17 00:00:00 2001 From: esaLCuE Date: Tue, 8 Apr 2025 10:47:19 +0200 Subject: [PATCH 08/18] cleaning --- .../manufacturing/doctype/production_plan/production_plan.py | 2 +- test.txt | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 test.txt diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py index f375aebcde6..f611f1aaf13 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py @@ -1107,7 +1107,7 @@ class ProductionPlan(Document): for key, item in items_data.items(): row += 1 if (item["material_request"] is None and self.get_items_from=="Material Request"): - frappe.throw(_("Row #{0} : This article is not related to a material request").format(row)) + frappe.throw(_("Row #{0}: This item must be linked to a Material Request").format(row)) @frappe.whitelist() def download_raw_materials(doc, warehouses=None): diff --git a/test.txt b/test.txt deleted file mode 100644 index 632e4fe73c3..00000000000 --- a/test.txt +++ /dev/null @@ -1 +0,0 @@ -Bonjour -- GitLab From c1b46b64bb92ace4d054bdb4064efbc6e40d8c4a Mon Sep 17 00:00:00 2001 From: esaLCuE Date: Wed, 9 Apr 2025 16:46:08 +0200 Subject: [PATCH 09/18] test_reports fix --- erpnext/stock/report/test_reports.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/report/test_reports.py b/erpnext/stock/report/test_reports.py index 9ead7e0453a..aa12f97704a 100644 --- a/erpnext/stock/report/test_reports.py +++ b/erpnext/stock/report/test_reports.py @@ -22,7 +22,7 @@ REPORT_FILTER_TEST_CASES: list[tuple[ReportName, ReportFilters]] = [ ("Stock Balance", {"_optional": True}), ("Stock Projected Qty", {"_optional": True}), ("Batch-Wise Balance History", {}), - ("Itemwise Recommended Reorder Level", {"item_group": ["All Item Groups"]}), + ("Itemwise Recommended Reorder Level", {"item_group": ["All Item Groups"], "items":["All Items"]}), ("COGS By Item Group", {}), ("Stock Qty vs Serial No Count", {"warehouse": "_Test Warehouse - _TC"}), ( -- GitLab From 7dfcfa271c8d4fe121104db9debde413298a9531 Mon Sep 17 00:00:00 2001 From: esaLCuE Date: Thu, 10 Apr 2025 15:46:07 +0200 Subject: [PATCH 10/18] conditional items loop --- .../itemwise_recommended_reorder_level.py | 9 +++++---- erpnext/stock/report/test_reports.py | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py index e4211f827f1..ae617395f2f 100644 --- a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py +++ b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py @@ -102,10 +102,11 @@ def get_item_info(filters): items = filters.get("item_name") conditions=[] - for itm in items: - if condition := get_item_name_condition(itm, item): - conditions.append(condition) - query = query.where(Criterion.any(conditions)) + if items: + for itm in items: + if condition := get_item_name_condition(itm, item): + conditions.append(condition) + query = query.where(Criterion.any(conditions)) return query.run(as_dict=True) diff --git a/erpnext/stock/report/test_reports.py b/erpnext/stock/report/test_reports.py index aa12f97704a..17b517a6027 100644 --- a/erpnext/stock/report/test_reports.py +++ b/erpnext/stock/report/test_reports.py @@ -22,7 +22,7 @@ REPORT_FILTER_TEST_CASES: list[tuple[ReportName, ReportFilters]] = [ ("Stock Balance", {"_optional": True}), ("Stock Projected Qty", {"_optional": True}), ("Batch-Wise Balance History", {}), - ("Itemwise Recommended Reorder Level", {"item_group": ["All Item Groups"], "items":["All Items"]}), + ("Itemwise Recommended Reorder Level", {"item_group": "All Item Groups", "items":[]}), ("COGS By Item Group", {}), ("Stock Qty vs Serial No Count", {"warehouse": "_Test Warehouse - _TC"}), ( -- GitLab From 11820a12879dc48a7073c70988cda40123a6a006 Mon Sep 17 00:00:00 2001 From: Corentin Forler Date: Mon, 14 Apr 2025 18:55:16 +0200 Subject: [PATCH 11/18] chore: fmt --- .../production_plan/production_plan.py | 11 ++-- .../itemwise_recommended_reorder_level.js | 54 +++++++++---------- .../itemwise_recommended_reorder_level.py | 18 +++---- .../stock/report/stock_ledger/stock_ledger.py | 11 ++-- 4 files changed, 44 insertions(+), 50 deletions(-) diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py index f611f1aaf13..b9460408002 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py @@ -1102,12 +1102,13 @@ class ProductionPlan(Document): return all_work_orders_completed def check_production_items(self): + if self.get_items_from != "Material Request": + return items_data = self.get_production_items() - row=0 - for key, item in items_data.items(): - row += 1 - if (item["material_request"] is None and self.get_items_from=="Material Request"): - frappe.throw(_("Row #{0}: This item must be linked to a Material Request").format(row)) + for idx, item in enumerate(items_data.values(), start=1): + if not item["material_request"]: + frappe.throw(_("Row #{0}: This item must be linked to a Material Request").format(idx)) + @frappe.whitelist() def download_raw_materials(doc, warehouses=None): diff --git a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js index 65c9b556ab0..8e39dc798c1 100644 --- a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js +++ b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js @@ -22,47 +22,47 @@ frappe.query_reports["Itemwise Recommended Reorder Level"] = { options: "Brand", }, { - fieldname:"item_group", + fieldname: "item_group", label: __("Item Group"), fieldtype: "MultiSelectList", width: "100", - get_data: function(txt) { - return frappe.db.get_link_options('Item Group', txt); + get_data(txt) { + return frappe.db.get_link_options("Item Group", txt); }, + async on_change(report) { + // TODO: Handle parent item groups + const selected_groups = frappe.query_report.get_filter_value("item_group"); + const selected_items = frappe.query_report.get_filter_value("item_name"); - on_change: function(report){ - let selectedGroups = frappe.query_report.get_filter_value("item_group"); - let selectedItems = frappe.query_report.get_filter_value("item_name"); - - frappe.db.get_list("Item", { + const items = await frappe.db.get_list("Item", { filters: { - item_group:["in", selectedGroups], - name:["in", selectedItems] + item_group: ["in", selected_groups], + name: ["in", selected_items], }, - fields:["name"] - }).then((items) => { - let itemNames = items.map(item=>item.name); - frappe.query_report.set_filter_value("item_name", itemNames); - }) + fields: ["name"], + }); + + const item_names = items.map((item) => item.name); + frappe.query_report.set_filter_value("item_name", item_names); report.refresh(); - } + }, }, { - "fieldname":"item_name", - "label": __("Items"), - "fieldtype": "MultiSelectList", - "width": "100", - get_data: function(txt) { - let item_groups = frappe.query_report.get_filter_value("item_group"); - if (item_groups==""){ - return frappe.db.get_link_options('Item', txt) + fieldname: "item_name", + label: __("Items"), + fieldtype: "MultiSelectList", + width: "100", + get_data(txt) { + const item_groups = frappe.query_report.get_filter_value("item_group"); + if (!item_groups) { + return frappe.db.get_link_options("Item", txt); } else { - return frappe.db.get_link_options('Item', txt, { - "item_group":["in", item_groups] + return frappe.db.get_link_options("Item", txt, { + item_group: ["in", item_groups], }); } - } + }, }, ], }; diff --git a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py index ae617395f2f..9013f7790d0 100644 --- a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py +++ b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py @@ -1,12 +1,13 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from erpnext.stock.report.stock_ledger.stock_ledger import get_item_name_condition import frappe from frappe import _ from frappe.query_builder.functions import Abs, Sum from frappe.utils import flt, getdate +from erpnext.stock.report.stock_ledger.stock_ledger import get_item_name_condition + def execute(filters=None): if not filters: @@ -69,9 +70,10 @@ def get_columns(): def get_item_info(filters): - from erpnext.stock.report.stock_ledger.stock_ledger import get_item_group_condition from pypika import Criterion + from erpnext.stock.report.stock_ledger.stock_ledger import get_item_group_condition + item = frappe.qb.DocType("Item") query = ( frappe.qb.from_(item) @@ -84,15 +86,12 @@ def get_item_info(filters): item.safety_stock, item.lead_time_days, ) - .where( - (item.is_stock_item == 1) - & (item.disabled == 0) - ) + .where((item.is_stock_item == 1) & (item.disabled == 0)) ) if brand := filters.get("brand"): query = query.where(item.brand == brand) - + groups = filters.get("item_group") conditions = [] for group in groups: @@ -100,9 +99,8 @@ def get_item_info(filters): conditions.append(condition) query = query.where(Criterion.any(conditions)) - items = filters.get("item_name") - conditions=[] - if items: + if items := filters.get("item_name"): + conditions = [] for itm in items: if condition := get_item_name_condition(itm, item): conditions.append(condition) diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py index 52f914887f7..df644128884 100644 --- a/erpnext/stock/report/stock_ledger/stock_ledger.py +++ b/erpnext/stock/report/stock_ledger/stock_ledger.py @@ -658,19 +658,14 @@ def check_inventory_dimension_filters_applied(filters) -> bool: return False + def get_item_name_condition(selected_item, item_table=None): - item_name_details = frappe.db.get_value("Item", selected_item, as_dict=1) + item_name_details = frappe.db.get_value("Item", selected_item, as_dict=True) if item_name_details: if item_table: item = frappe.qb.DocType("Item") return item_table.name.isin( - ( - frappe.qb.from_(item) - .select(item.name) - .where( - (selected_item == item.item_code) - ) - ) + frappe.qb.from_(item).select(item.name).where(selected_item == item.item_code) ) else: return -- GitLab From 5426d00cf5017b46c6b190793d44814288537abb Mon Sep 17 00:00:00 2001 From: Corentin Forler Date: Mon, 14 Apr 2025 18:56:09 +0200 Subject: [PATCH 12/18] fix: Handle list/str input --- .../itemwise_recommended_reorder_level.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py index 9013f7790d0..cbc36f394c7 100644 --- a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py +++ b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py @@ -93,6 +93,8 @@ def get_item_info(filters): query = query.where(item.brand == brand) groups = filters.get("item_group") + if isinstance(groups, str): + groups = [groups] conditions = [] for group in groups: if condition := get_item_group_condition(group, item): @@ -100,6 +102,8 @@ def get_item_info(filters): query = query.where(Criterion.any(conditions)) if items := filters.get("item_name"): + if isinstance(items, str): + items = [items] conditions = [] for itm in items: if condition := get_item_name_condition(itm, item): -- GitLab From d7525d3609eff84ee5f5597f88bfd980ac95e36e Mon Sep 17 00:00:00 2001 From: Corentin Forler Date: Mon, 14 Apr 2025 18:57:24 +0200 Subject: [PATCH 13/18] fix: Simplify item_name condition --- .../itemwise_recommended_reorder_level.py | 7 +------ erpnext/stock/report/stock_ledger/stock_ledger.py | 12 ------------ 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py index cbc36f394c7..2d85551cc7a 100644 --- a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py +++ b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py @@ -6,8 +6,6 @@ from frappe import _ from frappe.query_builder.functions import Abs, Sum from frappe.utils import flt, getdate -from erpnext.stock.report.stock_ledger.stock_ledger import get_item_name_condition - def execute(filters=None): if not filters: @@ -105,10 +103,7 @@ def get_item_info(filters): if isinstance(items, str): items = [items] conditions = [] - for itm in items: - if condition := get_item_name_condition(itm, item): - conditions.append(condition) - query = query.where(Criterion.any(conditions)) + query = query.where(item.name.isin(items)) return query.run(as_dict=True) diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py index df644128884..391395503b0 100644 --- a/erpnext/stock/report/stock_ledger/stock_ledger.py +++ b/erpnext/stock/report/stock_ledger/stock_ledger.py @@ -657,15 +657,3 @@ def check_inventory_dimension_filters_applied(filters) -> bool: return True return False - - -def get_item_name_condition(selected_item, item_table=None): - item_name_details = frappe.db.get_value("Item", selected_item, as_dict=True) - if item_name_details: - if item_table: - item = frappe.qb.DocType("Item") - return item_table.name.isin( - frappe.qb.from_(item).select(item.name).where(selected_item == item.item_code) - ) - else: - return -- GitLab From cf557b82407d7ee9f983fb3bb7e8bfa9addb8260 Mon Sep 17 00:00:00 2001 From: Corentin Forler Date: Mon, 14 Apr 2025 18:57:40 +0200 Subject: [PATCH 14/18] test: Add more test cases --- erpnext/stock/report/test_reports.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/report/test_reports.py b/erpnext/stock/report/test_reports.py index 17b517a6027..97e4c6fcd67 100644 --- a/erpnext/stock/report/test_reports.py +++ b/erpnext/stock/report/test_reports.py @@ -22,7 +22,9 @@ REPORT_FILTER_TEST_CASES: list[tuple[ReportName, ReportFilters]] = [ ("Stock Balance", {"_optional": True}), ("Stock Projected Qty", {"_optional": True}), ("Batch-Wise Balance History", {}), - ("Itemwise Recommended Reorder Level", {"item_group": "All Item Groups", "items":[]}), + ("Itemwise Recommended Reorder Level", {"item_group": "All Item Groups"}), + ("Itemwise Recommended Reorder Level", {"item_group": ["All Item Groups"]}), + ("Itemwise Recommended Reorder Level", {"items": ["_Test Item"]}), ("COGS By Item Group", {}), ("Stock Qty vs Serial No Count", {"warehouse": "_Test Warehouse - _TC"}), ( -- GitLab From 2536a950d130f9594f9e5c598e5117c240f31dcf Mon Sep 17 00:00:00 2001 From: Corentin Forler Date: Mon, 14 Apr 2025 19:02:34 +0200 Subject: [PATCH 15/18] perf: Don't set item_name filter based on item_group --- .../itemwise_recommended_reorder_level.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js index 8e39dc798c1..95eff2f2a1c 100644 --- a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js +++ b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js @@ -29,7 +29,7 @@ frappe.query_reports["Itemwise Recommended Reorder Level"] = { get_data(txt) { return frappe.db.get_link_options("Item Group", txt); }, - async on_change(report) { + /* async on_change(report) { // TODO: Handle parent item groups const selected_groups = frappe.query_report.get_filter_value("item_group"); const selected_items = frappe.query_report.get_filter_value("item_name"); @@ -46,7 +46,7 @@ frappe.query_reports["Itemwise Recommended Reorder Level"] = { frappe.query_report.set_filter_value("item_name", item_names); report.refresh(); - }, + }, */ }, { fieldname: "item_name", -- GitLab From 40ad948da852876eb069ddb7e908d380893ef93b Mon Sep 17 00:00:00 2001 From: Corentin Forler Date: Tue, 15 Apr 2025 15:39:42 +0200 Subject: [PATCH 16/18] fix: Ignore when item_group not set --- .../itemwise_recommended_reorder_level.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py index 2d85551cc7a..acc91a5f952 100644 --- a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py +++ b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py @@ -90,14 +90,14 @@ def get_item_info(filters): if brand := filters.get("brand"): query = query.where(item.brand == brand) - groups = filters.get("item_group") - if isinstance(groups, str): - groups = [groups] - conditions = [] - for group in groups: - if condition := get_item_group_condition(group, item): - conditions.append(condition) - query = query.where(Criterion.any(conditions)) + if groups := filters.get("item_group"): + if isinstance(groups, str): + groups = [groups] + conditions = [] + for group in groups: + if condition := get_item_group_condition(group, item): + conditions.append(condition) + query = query.where(Criterion.any(conditions)) if items := filters.get("item_name"): if isinstance(items, str): -- GitLab From 77a871a601690d83d798808082e53e8e2661ecf2 Mon Sep 17 00:00:00 2001 From: Corentin Forler Date: Thu, 17 Apr 2025 17:40:14 +0200 Subject: [PATCH 17/18] uncomment useful code --- .../itemwise_recommended_reorder_level.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js index 95eff2f2a1c..8e39dc798c1 100644 --- a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js +++ b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js @@ -29,7 +29,7 @@ frappe.query_reports["Itemwise Recommended Reorder Level"] = { get_data(txt) { return frappe.db.get_link_options("Item Group", txt); }, - /* async on_change(report) { + async on_change(report) { // TODO: Handle parent item groups const selected_groups = frappe.query_report.get_filter_value("item_group"); const selected_items = frappe.query_report.get_filter_value("item_name"); @@ -46,7 +46,7 @@ frappe.query_reports["Itemwise Recommended Reorder Level"] = { frappe.query_report.set_filter_value("item_name", item_names); report.refresh(); - }, */ + }, }, { fieldname: "item_name", -- GitLab From 3eb517e2a14dc0bd28281e2ef84ec64251dd1764 Mon Sep 17 00:00:00 2001 From: Corentin Forler Date: Thu, 17 Apr 2025 17:40:40 +0200 Subject: [PATCH 18/18] fix Check length of Arrays in JS, add comments --- .../itemwise_recommended_reorder_level.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js index 8e39dc798c1..092dcff3107 100644 --- a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js +++ b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js @@ -34,6 +34,11 @@ frappe.query_reports["Itemwise Recommended Reorder Level"] = { const selected_groups = frappe.query_report.get_filter_value("item_group"); const selected_items = frappe.query_report.get_filter_value("item_name"); + if (!selected_groups?.length) { + return; // Don't filter if no Item Group is selected + } + + // Only keep items that are in the selected Item Group const items = await frappe.db.get_list("Item", { filters: { item_group: ["in", selected_groups], @@ -55,7 +60,7 @@ frappe.query_reports["Itemwise Recommended Reorder Level"] = { width: "100", get_data(txt) { const item_groups = frappe.query_report.get_filter_value("item_group"); - if (!item_groups) { + if (!item_groups?.length) { return frappe.db.get_link_options("Item", txt); } else { return frappe.db.get_link_options("Item", txt, { -- GitLab