diff --git a/erpnext/selling/doctype/quotation/test_quotation.py b/erpnext/selling/doctype/quotation/test_quotation.py index 769e0661b12..aa83726304f 100644 --- a/erpnext/selling/doctype/quotation/test_quotation.py +++ b/erpnext/selling/doctype/quotation/test_quotation.py @@ -302,6 +302,109 @@ class TestQuotation(unittest.TestCase): enable_calculate_bundle_price(enable=0) + def test_product_bundle_price_calculation_for_multiple_product_bundles_when_calculate_bundle_price_is_checked(self): + from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle + from erpnext.stock.doctype.item.test_item import make_item + + make_item("_Test Product Bundle 1", {"is_stock_item": 0}) + make_item("_Test Product Bundle 2", {"is_stock_item": 0}) + make_item("_Test Bundle Item 1", {"is_stock_item": 1}) + make_item("_Test Bundle Item 2", {"is_stock_item": 1}) + make_item("_Test Bundle Item 3", {"is_stock_item": 1}) + + make_product_bundle("_Test Product Bundle 1", + ["_Test Bundle Item 1", "_Test Bundle Item 2"]) + make_product_bundle("_Test Product Bundle 2", + ["_Test Bundle Item 2", "_Test Bundle Item 3"]) + + enable_calculate_bundle_price() + + item_list = [ + { + "item_code": "_Test Product Bundle 1", + "warehouse": "", + "qty": 1, + "rate": 400, + "delivered_by_supplier": 1, + "supplier": '_Test Supplier' + }, + { + "item_code": "_Test Product Bundle 2", + "warehouse": "", + "qty": 1, + "rate": 400, + "delivered_by_supplier": 1, + "supplier": '_Test Supplier' + } + ] + + quotation = make_quotation(item_list=item_list, do_not_submit=1) + quotation.packed_items[0].rate = 100 + quotation.packed_items[1].rate = 200 + quotation.packed_items[2].rate = 200 + quotation.packed_items[3].rate = 300 + quotation.save() + + expected_values = [300, 500] + + for item in quotation.items: + self.assertEqual(item.amount, expected_values[item.idx-1]) + + enable_calculate_bundle_price(enable=0) + + def test_packed_items_indices_are_reset_when_product_bundle_is_deleted_from_items_table(self): + from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle + from erpnext.stock.doctype.item.test_item import make_item + + make_item("_Test Product Bundle 1", {"is_stock_item": 0}) + make_item("_Test Product Bundle 2", {"is_stock_item": 0}) + make_item("_Test Product Bundle 3", {"is_stock_item": 0}) + make_item("_Test Bundle Item 1", {"is_stock_item": 1}) + make_item("_Test Bundle Item 2", {"is_stock_item": 1}) + make_item("_Test Bundle Item 3", {"is_stock_item": 1}) + + make_product_bundle("_Test Product Bundle 1", + ["_Test Bundle Item 1", "_Test Bundle Item 2"]) + make_product_bundle("_Test Product Bundle 2", + ["_Test Bundle Item 2", "_Test Bundle Item 3"]) + make_product_bundle("_Test Product Bundle 3", + ["_Test Bundle Item 3", "_Test Bundle Item 1"]) + + item_list = [ + { + "item_code": "_Test Product Bundle 1", + "warehouse": "", + "qty": 1, + "rate": 400, + "delivered_by_supplier": 1, + "supplier": '_Test Supplier' + }, + { + "item_code": "_Test Product Bundle 2", + "warehouse": "", + "qty": 1, + "rate": 400, + "delivered_by_supplier": 1, + "supplier": '_Test Supplier' + }, + { + "item_code": "_Test Product Bundle 3", + "warehouse": "", + "qty": 1, + "rate": 400, + "delivered_by_supplier": 1, + "supplier": '_Test Supplier' + } + ] + + quotation = make_quotation(item_list=item_list, do_not_submit=1) + del quotation.items[1] + quotation.save() + + for id, item in enumerate(quotation.packed_items): + expected_index = id + 1 + self.assertEqual(item.idx, expected_index) + test_records = frappe.get_test_records('Quotation') def enable_calculate_bundle_price(enable=1): diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 47b8ebd3485..1c2482568ff 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -925,6 +925,7 @@ def make_purchase_order(source_name, selected_items=None, target_doc=None): "supplier", "pricing_rules" ], + "condition": lambda doc: doc.parent_item in items_to_map } }, target_doc, set_missing_values) diff --git a/erpnext/stock/doctype/packed_item/packed_item.py b/erpnext/stock/doctype/packed_item/packed_item.py index 3f73093d673..e4091c40dc4 100644 --- a/erpnext/stock/doctype/packed_item/packed_item.py +++ b/erpnext/stock/doctype/packed_item/packed_item.py @@ -108,9 +108,32 @@ def cleanup_packing_list(doc, parent_items): packed_items = doc.get("packed_items") doc.set("packed_items", []) + for d in packed_items: if d not in delete_list: - doc.append("packed_items", d) + add_item_to_packing_list(doc, d) + +def add_item_to_packing_list(doc, packed_item): + doc.append("packed_items", { + 'parent_item': packed_item.parent_item, + 'item_code': packed_item.item_code, + 'item_name': packed_item.item_name, + 'uom': packed_item.uom, + 'qty': packed_item.qty, + 'rate': packed_item.rate, + 'conversion_factor': packed_item.conversion_factor, + 'description': packed_item.description, + 'warehouse': packed_item.warehouse, + 'batch_no': packed_item.batch_no, + 'actual_batch_qty': packed_item.actual_batch_qty, + 'serial_no': packed_item.serial_no, + 'target_warehouse': packed_item.target_warehouse, + 'actual_qty': packed_item.actual_qty, + 'projected_qty': packed_item.projected_qty, + 'incoming_rate': packed_item.incoming_rate, + 'prevdoc_doctype': packed_item.prevdoc_doctype, + 'parent_detail_docname': packed_item.parent_detail_docname + }) def update_product_bundle_price(doc, parent_items): """Updates the prices of Product Bundles based on the rates of the Items in the bundle.""" @@ -128,7 +151,8 @@ def update_product_bundle_price(doc, parent_items): else: update_parent_item_price(doc, parent_items[parent_items_index][0], bundle_price) - bundle_price = 0 + bundle_item_rate = bundle_item.rate if bundle_item.rate else 0 + bundle_price = bundle_item.qty * bundle_item_rate parent_items_index += 1 # for the last product bundle