From 5dcd8061761b95c1e01bdaff5d019a2ab66615c4 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Wed, 22 Nov 2023 15:22:42 +0530 Subject: [PATCH 1/8] fix: skip fixed assets in parent (cherry picked from commit f9713eeb5690f9e71e01c6c570012f561a633c73) --- .../doctype/product_bundle/product_bundle.py | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/erpnext/selling/doctype/product_bundle/product_bundle.py b/erpnext/selling/doctype/product_bundle/product_bundle.py index ac83c0f0462..4b401e7e67d 100644 --- a/erpnext/selling/doctype/product_bundle/product_bundle.py +++ b/erpnext/selling/doctype/product_bundle/product_bundle.py @@ -59,6 +59,8 @@ class ProductBundle(Document): """Validates, main Item is not a stock item""" if frappe.db.get_value("Item", self.new_item_code, "is_stock_item"): frappe.throw(_("Parent Item {0} must not be a Stock Item").format(self.new_item_code)) + if frappe.db.get_value("Item", self.new_item_code, "is_fixed_asset"): + frappe.throw(_("Parent Item {0} must not be a Fixed Asset").format(self.new_item_code)) def validate_child_items(self): for item in self.items: @@ -73,12 +75,17 @@ class ProductBundle(Document): @frappe.whitelist() @frappe.validate_and_sanitize_search_inputs def get_new_item_code(doctype, txt, searchfield, start, page_len, filters): - from erpnext.controllers.queries import get_match_cond - - return frappe.db.sql( - """select name, item_name, description from tabItem - where is_stock_item=0 and name not in (select name from `tabProduct Bundle`) - and %s like %s %s limit %s offset %s""" - % (searchfield, "%s", get_match_cond(doctype), "%s", "%s"), - ("%%%s%%" % txt, page_len, start), - ) + product_bundles = frappe.db.get_list("Product Bundle", pluck="name") + item = frappe.qb.DocType("Item") + return ( + frappe.qb.from_(item) + .select("*") + .where( + (item.is_stock_item == 0) + & (item.is_fixed_asset == 0) + & (item.name.notin(product_bundles)) + & (item[searchfield].like(f"%{txt}%")) + ) + .limit(page_len) + .offset(start) + ).run() From 8d5efc901d1f454348efba7c94cc167362d0a16f Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Wed, 22 Nov 2023 15:23:17 +0530 Subject: [PATCH 2/8] feat: add disabled field in product bundle (cherry picked from commit ee76af76812fe04d86653fd1955ad133c8cb5df8) --- .../product_bundle/product_bundle.json | 398 +++++------------- 1 file changed, 101 insertions(+), 297 deletions(-) diff --git a/erpnext/selling/doctype/product_bundle/product_bundle.json b/erpnext/selling/doctype/product_bundle/product_bundle.json index 56155fb750a..c4f21b61b9e 100644 --- a/erpnext/selling/doctype/product_bundle/product_bundle.json +++ b/erpnext/selling/doctype/product_bundle/product_bundle.json @@ -1,315 +1,119 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 0, - "beta": 0, - "creation": "2013-06-20 11:53:21", - "custom": 0, - "description": "Aggregate group of **Items** into another **Item**. This is useful if you are bundling a certain **Items** into a package and you maintain stock of the packed **Items** and not the aggregate **Item**. \n\nThe package **Item** will have \"Is Stock Item\" as \"No\" and \"Is Sales Item\" as \"Yes\".\n\nFor Example: If you are selling Laptops and Backpacks separately and have a special price if the customer buys both, then the Laptop + Backpack will be a new Product Bundle Item.\n\nNote: BOM = Bill of Materials", - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 0, + "actions": [], + "allow_import": 1, + "creation": "2013-06-20 11:53:21", + "description": "Aggregate group of **Items** into another **Item**. This is useful if you are bundling a certain **Items** into a package and you maintain stock of the packed **Items** and not the aggregate **Item**. \n\nThe package **Item** will have \"Is Stock Item\" as \"No\" and \"Is Sales Item\" as \"Yes\".\n\nFor Example: If you are selling Laptops and Backpacks separately and have a special price if the customer buys both, then the Laptop + Backpack will be a new Product Bundle Item.\n\nNote: BOM = Bill of Materials", + "doctype": "DocType", + "engine": "InnoDB", + "field_order": [ + "basic_section", + "new_item_code", + "description", + "column_break_eonk", + "disabled", + "item_section", + "items", + "section_break_4", + "about" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "basic_section", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "basic_section", + "fieldtype": "Section Break" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "", - "fieldname": "new_item_code", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 1, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Parent Item", - "length": 0, - "no_copy": 1, - "oldfieldname": "new_item_code", - "oldfieldtype": "Data", - "options": "Item", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "new_item_code", + "fieldtype": "Link", + "in_global_search": 1, + "in_list_view": 1, + "label": "Parent Item", + "no_copy": 1, + "oldfieldname": "new_item_code", + "oldfieldtype": "Data", + "options": "Item", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "description", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Description", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "description", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Description" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "List items that form the package.", - "fieldname": "item_section", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Items", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "description": "List items that form the package.", + "fieldname": "item_section", + "fieldtype": "Section Break", + "label": "Items" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "items", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Items", - "length": 0, - "no_copy": 0, - "oldfieldname": "sales_bom_items", - "oldfieldtype": "Table", - "options": "Product Bundle Item", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "items", + "fieldtype": "Table", + "label": "Items", + "oldfieldname": "sales_bom_items", + "oldfieldtype": "Table", + "options": "Product Bundle Item", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break_4", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "section_break_4", + "fieldtype": "Section Break" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "about", - "fieldtype": "HTML", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "", - "length": 0, - "no_copy": 0, - "options": "

About Product Bundle

\n\n

Aggregate group of Items into another Item. This is useful if you are bundling a certain Items into a package and you maintain stock of the packed Items and not the aggregate Item.

\n

The package Item will have Is Stock Item as No and Is Sales Item as Yes.

\n

Example:

\n

If you are selling Laptops and Backpacks separately and have a special price if the customer buys both, then the Laptop + Backpack will be a new Product Bundle Item.

", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 + "fieldname": "about", + "fieldtype": "HTML", + "options": "

About Product Bundle

\n\n

Aggregate group of Items into another Item. This is useful if you are bundling a certain Items into a package and you maintain stock of the packed Items and not the aggregate Item.

\n

The package Item will have Is Stock Item as No and Is Sales Item as Yes.

\n

Example:

\n

If you are selling Laptops and Backpacks separately and have a special price if the customer buys both, then the Laptop + Backpack will be a new Product Bundle Item.

" + }, + { + "default": "0", + "fieldname": "disabled", + "fieldtype": "Check", + "label": "Disabled" + }, + { + "fieldname": "column_break_eonk", + "fieldtype": "Column Break" } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "icon": "fa fa-sitemap", - "idx": 1, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2020-09-18 17:26:09.703215", - "modified_by": "Administrator", - "module": "Selling", - "name": "Product Bundle", - "owner": "Administrator", + ], + "icon": "fa fa-sitemap", + "idx": 1, + "links": [], + "modified": "2023-11-22 15:20:46.805114", + "modified_by": "Administrator", + "module": "Selling", + "name": "Product Bundle", + "owner": "Administrator", "permissions": [ { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Stock Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "create": 1, + "delete": 1, + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Stock Manager", + "share": 1, "write": 1 - }, + }, { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Stock User", - "set_user_permissions": 0, - "share": 0, - "submit": 0, - "write": 0 - }, + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Stock User" + }, { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Sales User", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "create": 1, + "delete": 1, + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Sales User", + "share": 1, "write": 1 } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "sort_order": "ASC", - "track_changes": 0, - "track_seen": 0 + ], + "sort_field": "modified", + "sort_order": "ASC", + "states": [] } \ No newline at end of file From 8a3a0688ba1a3c38837e2f1ec4a822b1139b14f3 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Wed, 22 Nov 2023 15:24:56 +0530 Subject: [PATCH 3/8] fix: filter bundle items based on disabled check (cherry picked from commit 874774fe6c81c854fb3ade03e93f003c0fc8dd8a) --- erpnext/stock/doctype/packed_item/packed_item.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/packed_item/packed_item.py b/erpnext/stock/doctype/packed_item/packed_item.py index a9e9ad1a639..8b6f7158e04 100644 --- a/erpnext/stock/doctype/packed_item/packed_item.py +++ b/erpnext/stock/doctype/packed_item/packed_item.py @@ -111,7 +111,7 @@ def get_product_bundle_items(item_code): product_bundle_item.uom, product_bundle_item.description, ) - .where(product_bundle.new_item_code == item_code) + .where((product_bundle.new_item_code == item_code) & (product_bundle.disabled == 0)) .orderby(product_bundle_item.idx) ) return query.run(as_dict=True) From fd19ac55e3e5f3a9a2b9c8d212ac39dd29986b1b Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Wed, 22 Nov 2023 16:04:05 +0530 Subject: [PATCH 4/8] fix: has_product_bundle util to only check for enabled bundles (cherry picked from commit 3543f86c639cf7383c37a5ed9a61d5787c9ebad4) --- erpnext/controllers/selling_controller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index f005a7f7a39..3f77a7114a3 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -346,7 +346,7 @@ class SellingController(StockController): def has_product_bundle(self, item_code): return frappe.db.sql( """select name from `tabProduct Bundle` - where new_item_code=%s and docstatus != 2""", + where new_item_code=%s and disabled=0""", item_code, ) From ae960e735aa76bd3f76c65450576b0d72e609355 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Wed, 22 Nov 2023 16:10:49 +0530 Subject: [PATCH 5/8] fix: validation for existing bundles (cherry picked from commit 67f43d37df9e77c3e59562117fa44ea76273a536) --- erpnext/selling/doctype/product_bundle/product_bundle.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/selling/doctype/product_bundle/product_bundle.py b/erpnext/selling/doctype/product_bundle/product_bundle.py index 4b401e7e67d..2fd9cc13012 100644 --- a/erpnext/selling/doctype/product_bundle/product_bundle.py +++ b/erpnext/selling/doctype/product_bundle/product_bundle.py @@ -64,7 +64,7 @@ class ProductBundle(Document): def validate_child_items(self): for item in self.items: - if frappe.db.exists("Product Bundle", item.item_code): + if frappe.db.exists("Product Bundle", {"name": item.item_code, "disabled": 0}): frappe.throw( _( "Row #{0}: Child Item should not be a Product Bundle. Please remove Item {1} and Save" @@ -75,7 +75,7 @@ class ProductBundle(Document): @frappe.whitelist() @frappe.validate_and_sanitize_search_inputs def get_new_item_code(doctype, txt, searchfield, start, page_len, filters): - product_bundles = frappe.db.get_list("Product Bundle", pluck="name") + product_bundles = frappe.db.get_list("Product Bundle", {"disabled": 0}, pluck="name") item = frappe.qb.DocType("Item") return ( frappe.qb.from_(item) From e96ef7338ed4fb3eacef1da702d8211ecb7c9e4b Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Wed, 22 Nov 2023 16:17:23 +0530 Subject: [PATCH 6/8] fix: condition in other bundle utils (cherry picked from commit 8bdb61cb87802723a0db1aaa29c30c15c740ec6b) --- erpnext/accounts/doctype/pos_invoice/pos_invoice.py | 2 +- erpnext/selling/doctype/sales_order/sales_order.py | 8 +++++--- erpnext/stock/get_item_details.py | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py index d3058e44509..df5e221e195 100644 --- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py +++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py @@ -659,7 +659,7 @@ def get_stock_availability(item_code, warehouse): return bin_qty - pos_sales_qty, is_stock_item else: is_stock_item = True - if frappe.db.exists("Product Bundle", item_code): + if frappe.db.exists("Product Bundle", {"name": item_code, "disabled": 0}): return get_bundle_availability(item_code, warehouse), is_stock_item else: is_stock_item = False diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 914adbb7906..c7c7e526f4c 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -613,7 +613,9 @@ def make_material_request(source_name, target_doc=None): "Sales Order Item": { "doctype": "Material Request Item", "field_map": {"name": "sales_order_item", "parent": "sales_order"}, - "condition": lambda item: not frappe.db.exists("Product Bundle", item.item_code) + "condition": lambda item: not frappe.db.exists( + "Product Bundle", {"name": item.item_code, "disabled": 0} + ) and get_remaining_qty(item) > 0, "postprocess": update_item, }, @@ -1163,7 +1165,7 @@ def set_delivery_date(items, sales_order): def is_product_bundle(item_code): - return frappe.db.exists("Product Bundle", item_code) + return frappe.db.exists("Product Bundle", {"name": item_code, "disabled": 0}) @frappe.whitelist() @@ -1362,7 +1364,7 @@ def get_work_order_items(sales_order, for_raw_material_request=0): product_bundle_parents = [ pb.new_item_code for pb in frappe.get_all( - "Product Bundle", {"new_item_code": ["in", item_codes]}, ["new_item_code"] + "Product Bundle", {"new_item_code": ["in", item_codes], "disabled": 0}, ["new_item_code"] ) ] diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 990e03daa1b..daa7becc1f4 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -182,7 +182,7 @@ def update_stock(args, out): def set_valuation_rate(out, args): - if frappe.db.exists("Product Bundle", args.item_code, cache=True): + if frappe.db.exists("Product Bundle", {"name": args.item_code, "disabled": 0}, cache=True): valuation_rate = 0.0 bundled_items = frappe.get_doc("Product Bundle", args.item_code) From 445e9c90413db00d1edf22c3edd1616e8a380c92 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Wed, 22 Nov 2023 16:26:09 +0530 Subject: [PATCH 7/8] fix: skip disabled bundles for non-report utils (cherry picked from commit 362f377f6127e9262ab7829a427d0a2051a77b2f) --- erpnext/stock/doctype/delivery_note/delivery_note.py | 4 ++-- erpnext/stock/doctype/item/item.py | 8 ++++++-- erpnext/stock/doctype/packed_item/packed_item.py | 2 +- erpnext/stock/doctype/pick_list/pick_list.py | 8 ++++++-- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py index b18ee9943c7..571e0ea5d7a 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/delivery_note.py @@ -412,7 +412,7 @@ class DeliveryNote(SellingController): items_list = [item.item_code for item in self.items] return frappe.db.get_all( "Product Bundle", - filters={"new_item_code": ["in", items_list]}, + filters={"new_item_code": ["in", items_list], "disabled": 0}, pluck="name", ) @@ -761,7 +761,7 @@ def make_packing_slip(source_name, target_doc=None): }, "postprocess": update_item, "condition": lambda item: ( - not frappe.db.exists("Product Bundle", {"new_item_code": item.item_code}) + not frappe.db.exists("Product Bundle", {"new_item_code": item.item_code, "disabled": 0}) and flt(item.packed_qty) < flt(item.qty) ), }, diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index e1dd481b075..96cec1dd0a2 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -542,8 +542,12 @@ class Item(Document): def validate_duplicate_product_bundles_before_merge(self, old_name, new_name): "Block merge if both old and new items have product bundles." - old_bundle = frappe.get_value("Product Bundle", filters={"new_item_code": old_name}) - new_bundle = frappe.get_value("Product Bundle", filters={"new_item_code": new_name}) + old_bundle = frappe.get_value( + "Product Bundle", filters={"new_item_code": old_name, "disabled": 0} + ) + new_bundle = frappe.get_value( + "Product Bundle", filters={"new_item_code": new_name, "disabled": 0} + ) if old_bundle and new_bundle: bundle_link = get_link_to_form("Product Bundle", old_bundle) diff --git a/erpnext/stock/doctype/packed_item/packed_item.py b/erpnext/stock/doctype/packed_item/packed_item.py index 8b6f7158e04..35701c90deb 100644 --- a/erpnext/stock/doctype/packed_item/packed_item.py +++ b/erpnext/stock/doctype/packed_item/packed_item.py @@ -55,7 +55,7 @@ def make_packing_list(doc): def is_product_bundle(item_code: str) -> bool: - return bool(frappe.db.exists("Product Bundle", {"new_item_code": item_code})) + return bool(frappe.db.exists("Product Bundle", {"new_item_code": item_code, "disabled": 0})) def get_indexed_packed_items_table(doc): diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py index 99246774aa1..e89e22ab336 100644 --- a/erpnext/stock/doctype/pick_list/pick_list.py +++ b/erpnext/stock/doctype/pick_list/pick_list.py @@ -267,7 +267,9 @@ class PickList(Document): frappe.throw("Row #{0}: Item Code is Mandatory".format(item.idx)) if not cint( frappe.get_cached_value("Item", item.item_code, "is_stock_item") - ) and not frappe.db.exists("Product Bundle", {"new_item_code": item.item_code}): + ) and not frappe.db.exists( + "Product Bundle", {"new_item_code": item.item_code, "disabled": 0} + ): continue item_code = item.item_code reference = item.sales_order_item or item.material_request_item @@ -405,7 +407,9 @@ class PickList(Document): # bundle_item_code: Dict[component, qty] product_bundle_qty_map = {} for bundle_item_code in bundles: - bundle = frappe.get_last_doc("Product Bundle", {"new_item_code": bundle_item_code}) + bundle = frappe.get_last_doc( + "Product Bundle", {"new_item_code": bundle_item_code, "disabled": 0} + ) product_bundle_qty_map[bundle_item_code] = {item.item_code: item.qty for item in bundle.items} return product_bundle_qty_map From d7d5317b0eef53e840104cdf29a060511f6e95a0 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Wed, 22 Nov 2023 16:45:14 +0530 Subject: [PATCH 8/8] chore: linting issues (cherry picked from commit 16573378870bb9c6e80f39e80fa43e5b2cc0a69f) --- erpnext/controllers/selling_controller.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index 3f77a7114a3..7cef623148e 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -344,11 +344,12 @@ class SellingController(StockController): return il def has_product_bundle(self, item_code): - return frappe.db.sql( - """select name from `tabProduct Bundle` - where new_item_code=%s and disabled=0""", - item_code, - ) + product_bundle = frappe.qb.DocType("Product Bundle") + return ( + frappe.qb.from_(product_bundle) + .select(product_bundle.name) + .where((product_bundle.new_item_code == item_code) & (product_bundle.disabled == 0)) + ).run() def get_already_delivered_qty(self, current_docname, so, so_detail): delivered_via_dn = frappe.db.sql(