diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index d69924f469aea921a29d9f3a3e58ee4fbe538aa4..233ffcbbaea0b7934651abf729303393e0c9c0db 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -540,7 +540,9 @@ class BuyingController(SubcontractingController): "actual_qty": flt(pr_qty), "serial_and_batch_bundle": ( d.serial_and_batch_bundle - if not self.is_internal_transfer() or self.is_return + if not self.is_internal_transfer() + or self.is_return + or (self.is_internal_transfer() and self.docstatus == 2) else self.get_package_for_target_warehouse( d, type_of_transaction=type_of_transaction ) @@ -579,6 +581,14 @@ class BuyingController(SubcontractingController): (not cint(self.is_return) and self.docstatus == 2) or (cint(self.is_return) and self.docstatus == 1) ): + serial_and_batch_bundle = None + if self.is_internal_transfer() and self.docstatus == 2: + serial_and_batch_bundle = frappe.db.get_value( + "Stock Ledger Entry", + {"voucher_detail_no": d.name, "warehouse": d.warehouse}, + "serial_and_batch_bundle", + ) + from_warehouse_sle = self.get_sl_entries( d, { @@ -588,7 +598,7 @@ class BuyingController(SubcontractingController): "serial_and_batch_bundle": ( self.get_package_for_target_warehouse(d, d.from_warehouse, "Inward") if self.is_internal_transfer() and self.is_return - else None + else serial_and_batch_bundle ), }, ) diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index d2e387c1f4d3ea5b653d2aa01ef9ac6235c0d698..2fadf90560921214e72ddbfc3d412c42c0cd3057 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -536,7 +536,9 @@ class SellingController(StockController): self.make_sl_entries(sl_entries) def get_sle_for_source_warehouse(self, item_row): - serial_and_batch_bundle = item_row.serial_and_batch_bundle + serial_and_batch_bundle = ( + item_row.serial_and_batch_bundle if not self.is_internal_transfer() else None + ) if serial_and_batch_bundle and self.is_internal_transfer() and self.is_return: if self.docstatus == 1: serial_and_batch_bundle = self.make_package_for_transfer( diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index 3427cf937e0eee2594e9ffdb982b8bc62f9d49b5..8b21949f026cc064181a2f1a2f6bdc2e9cf4b5a9 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -3298,6 +3298,138 @@ class TestPurchaseReceipt(FrappeTestCase): doc.flags.ignore_validate = True doc.save() + def test_status_mapping(self): + item_code = "item_for_status" + create_item(item_code) + create_item("item_for_status") + warehouse = create_warehouse("Stores") + supplier = "Test Supplier" + create_supplier(supplier_name=supplier) + pr = make_purchase_receipt( + item_code=item_code, + warehouse=warehouse, + qty=1, + rate=0, + ) + self.assertEqual(pr.grand_total, 0.0) + self.assertEqual(pr.status, "Completed") + + def test_internal_transfer_for_batch_items_with_cancel(self): + from erpnext.controllers.sales_and_purchase_return import make_return_doc + from erpnext.stock.doctype.delivery_note.delivery_note import make_inter_company_purchase_receipt + from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note + + frappe.db.set_single_value("Stock Settings", "use_serial_batch_fields", 0) + + prepare_data_for_internal_transfer() + + customer = "_Test Internal Customer 2" + company = "_Test Company with perpetual inventory" + + batch_item_doc = make_item( + "_Test Batch Item For Stock Transfer Cancel Case", + {"has_batch_no": 1, "create_new_batch": 1, "batch_number_series": "USBF-BT-CANBIFST-.####"}, + ) + + serial_item_doc = make_item( + "_Test Serial No Item For Stock Transfer Cancel Case", + {"has_serial_no": 1, "serial_no_series": "USBF-BT-CANBIFST-.####"}, + ) + + inward_entry = make_purchase_receipt( + item_code=batch_item_doc.name, + qty=10, + rate=150, + warehouse="Stores - TCP1", + company="_Test Company with perpetual inventory", + use_serial_batch_fields=0, + do_not_submit=1, + ) + + inward_entry.append( + "items", + { + "item_code": serial_item_doc.name, + "qty": 15, + "rate": 250, + "item_name": serial_item_doc.item_name, + "conversion_factor": 1.0, + "uom": serial_item_doc.stock_uom, + "stock_uom": serial_item_doc.stock_uom, + "warehouse": "Stores - TCP1", + "use_serial_batch_fields": 0, + }, + ) + + inward_entry.submit() + inward_entry.reload() + + for row in inward_entry.items: + self.assertTrue(row.serial_and_batch_bundle) + + inter_transfer_dn = create_delivery_note( + item_code=inward_entry.items[0].item_code, + company=company, + customer=customer, + cost_center="Main - TCP1", + expense_account="Cost of Goods Sold - TCP1", + qty=10, + rate=500, + warehouse="Stores - TCP1", + target_warehouse="Work In Progress - TCP1", + batch_no=get_batch_from_bundle(inward_entry.items[0].serial_and_batch_bundle), + use_serial_batch_fields=0, + do_not_submit=1, + ) + + inter_transfer_dn.append( + "items", + { + "item_code": serial_item_doc.name, + "qty": 15, + "rate": 350, + "item_name": serial_item_doc.item_name, + "conversion_factor": 1.0, + "uom": serial_item_doc.stock_uom, + "stock_uom": serial_item_doc.stock_uom, + "warehouse": "Stores - TCP1", + "target_warehouse": "Work In Progress - TCP1", + "serial_no": "\n".join( + get_serial_nos_from_bundle(inward_entry.items[1].serial_and_batch_bundle) + ), + "use_serial_batch_fields": 0, + }, + ) + + inter_transfer_dn.submit() + inter_transfer_dn.reload() + for row in inter_transfer_dn.items: + if row.item_code == batch_item_doc.name: + self.assertEqual(row.rate, 150.0) + else: + self.assertEqual(row.rate, 250.0) + + self.assertTrue(row.serial_and_batch_bundle) + + inter_transfer_pr = make_inter_company_purchase_receipt(inter_transfer_dn.name) + for row in inter_transfer_pr.items: + row.from_warehouse = "Work In Progress - TCP1" + row.warehouse = "Stores - TCP1" + inter_transfer_pr.submit() + + for row in inter_transfer_pr.items: + if row.item_code == batch_item_doc.name: + self.assertEqual(row.rate, 150.0) + else: + self.assertEqual(row.rate, 250.0) + + self.assertTrue(row.serial_and_batch_bundle) + + inter_transfer_pr.cancel() + inter_transfer_dn.cancel() + + frappe.db.set_single_value("Stock Settings", "use_serial_batch_fields", 1) + def prepare_data_for_internal_transfer(): from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier