From 2840260906f214af6d047427ec13958cda7c1dd6 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 18 Dec 2023 17:56:05 +0530 Subject: [PATCH] fix: not able to cancel SCR with Batch (backport #38817) (#38821) * fix: not able to cancel SCR with Batch (#38817) (cherry picked from commit fb5090fd3f23ada507fe8abc5a899f4b06e48d7e) # Conflicts: # erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py * chore: fix test case * chore: fix test case * chore: fix test case * chore: fix test case --------- Co-authored-by: rohitwaghchaure (cherry picked from commit 71e833c3f2323873953c3ad7ab4a9403ebbdeb0a) --- .../serial_and_batch_bundle.py | 2 +- .../subcontracting_receipt.py | 2 +- .../test_subcontracting_receipt.py | 85 +++++++++++++++++++ 3 files changed, 87 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py index e8c1124d9a68..7ddf1573de29 100644 --- a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py +++ b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py @@ -459,7 +459,7 @@ def validate_quantity(self, row, qty_field=None): qty_field = "qty" precision = row.precision - if self.voucher_type in ["Subcontracting Receipt"]: + if row.get("doctype") in ["Subcontracting Receipt Supplied Item"]: qty_field = "consumed_qty" if abs(abs(flt(self.total_qty, precision)) - abs(flt(row.get(qty_field), precision))) > 0.01: diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py index ac845d86fb77..fc1b697a8e02 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py @@ -167,13 +167,13 @@ def on_cancel(self): ) self.update_status_updater_args() self.update_prevdoc_status() - self.delete_auto_created_batches() self.set_consumed_qty_in_subcontract_order() self.set_subcontracting_order_status() self.update_stock_ledger() self.make_gl_entries_on_cancel() self.repost_future_sle_and_gle() self.update_status() + self.delete_auto_created_batches() def validate_items_qty(self): for item in self.items: diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py index 1d007fe3c8b3..5523c318a59c 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py @@ -953,6 +953,91 @@ def test_scrap_items_for_subcontracting_receipt(self): scr.submit() + def test_subcontracting_receipt_cancel_with_batch(self): + from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom + + # Step - 1: Set Backflush Based On as "BOM" + set_backflush_based_on("BOM") + + # Step - 2: Create FG and RM Items + fg_item = make_item( + properties={"is_stock_item": 1, "is_sub_contracted_item": 1, "has_batch_no": 1} + ).name + rm_item1 = make_item(properties={"is_stock_item": 1}).name + rm_item2 = make_item(properties={"is_stock_item": 1}).name + make_item("Subcontracted Service Item Test For Batch 1", {"is_stock_item": 0}) + + # Step - 3: Create BOM for FG Item + bom = make_bom(item=fg_item, raw_materials=[rm_item1, rm_item2]) + for rm_item in bom.items: + self.assertEqual(rm_item.rate, 0) + self.assertEqual(rm_item.amount, 0) + bom = bom.name + + # Step - 4: Create PO and SCO + service_items = [ + { + "warehouse": "_Test Warehouse - _TC", + "item_code": "Subcontracted Service Item Test For Batch 1", + "qty": 100, + "rate": 100, + "fg_item": fg_item, + "fg_item_qty": 100, + }, + ] + sco = get_subcontracting_order(service_items=service_items) + for rm_item in sco.supplied_items: + self.assertEqual(rm_item.rate, 0) + self.assertEqual(rm_item.amount, 0) + + # Step - 5: Inward Raw Materials + rm_items = get_rm_items(sco.supplied_items) + for rm_item in rm_items: + rm_item["rate"] = 100 + itemwise_details = make_stock_in_entry(rm_items=rm_items) + + # Step - 6: Transfer RM's to Subcontractor + se = make_stock_transfer_entry( + sco_no=sco.name, + rm_items=rm_items, + itemwise_details=copy.deepcopy(itemwise_details), + ) + for item in se.items: + self.assertEqual(item.qty, 100) + self.assertEqual(item.basic_rate, 100) + self.assertEqual(item.amount, item.qty * item.basic_rate) + + batch_doc = frappe.get_doc( + { + "doctype": "Batch", + "item": fg_item, + "batch_id": frappe.generate_hash(length=10), + } + ).insert(ignore_permissions=True) + + serial_batch_bundle = frappe.get_doc( + { + "doctype": "Serial and Batch Bundle", + "item_code": fg_item, + "warehouse": sco.items[0].warehouse, + "has_batch_no": 1, + "type_of_transaction": "Inward", + "voucher_type": "Subcontracting Receipt", + "entries": [{"batch_no": batch_doc.name, "qty": 100}], + } + ).insert(ignore_permissions=True) + + # Step - 7: Create Subcontracting Receipt + scr = make_subcontracting_receipt(sco.name) + scr.items[0].serial_and_batch_bundle = serial_batch_bundle.name + scr.save() + scr.submit() + scr.load_from_db() + + # Step - 8: Cancel Subcontracting Receipt + scr.cancel() + self.assertTrue(scr.docstatus == 2) + @change_settings("Buying Settings", {"auto_create_purchase_receipt": 1}) def test_auto_create_purchase_receipt(self): fg_item = "Subcontracted Item SA1"