Merge pull request #40638 from rohitwaghchaure/fixed-40578
fix: Batch No is mandatory while making manufacture entry
diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py
index e1c1069..b56e9e1 100644
--- a/erpnext/manufacturing/doctype/work_order/test_work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py
@@ -1208,6 +1208,51 @@
except frappe.MandatoryError:
self.fail("Batch generation causing failing in Work Order")
+ @change_settings("Manufacturing Settings", {"make_serial_no_batch_from_work_order": 1})
+ def test_auto_serial_no_batch_creation(self):
+ from erpnext.manufacturing.doctype.bom.test_bom import create_nested_bom
+
+ fg_item = frappe.generate_hash(length=20)
+ child_item = frappe.generate_hash(length=20)
+
+ bom_tree = {fg_item: {child_item: {}}}
+
+ create_nested_bom(bom_tree, prefix="")
+
+ item = frappe.get_doc("Item", fg_item)
+ item.update(
+ {
+ "has_serial_no": 1,
+ "has_batch_no": 1,
+ "serial_no_series": f"SN-TEST-{item.name}.#####",
+ "create_new_batch": 1,
+ "batch_number_series": f"BATCH-TEST-{item.name}.#####",
+ }
+ )
+ item.save()
+
+ try:
+ wo_order = make_wo_order_test_record(item=fg_item, batch_size=5, qty=10, skip_transfer=True)
+ serial_nos = self.get_serial_nos_for_fg(wo_order.name)
+
+ stock_entry = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 10))
+ stock_entry.set_work_order_details()
+ stock_entry.set_serial_no_batch_for_finished_good()
+ for row in stock_entry.items:
+ if row.item_code == fg_item:
+ self.assertTrue(row.serial_and_batch_bundle)
+ self.assertEqual(
+ sorted(get_serial_nos_from_bundle(row.serial_and_batch_bundle)), sorted(serial_nos)
+ )
+
+ sn_doc = frappe.get_doc("Serial and Batch Bundle", row.serial_and_batch_bundle)
+ for row in sn_doc.entries:
+ self.assertTrue(row.serial_no)
+ self.assertTrue(row.batch_no)
+
+ except frappe.MandatoryError:
+ self.fail("Batch generation causing failing in Work Order")
+
def get_serial_nos_for_fg(self, work_order):
serial_nos = []
for row in frappe.get_all("Serial No", filters={"work_order": work_order}):
@@ -2270,6 +2315,7 @@
wo_order.planned_start_date = args.planned_start_date or now()
wo_order.transfer_material_against = args.transfer_material_against or "Work Order"
wo_order.from_wip_warehouse = args.from_wip_warehouse or 0
+ wo_order.batch_size = args.batch_size or 0
if args.source_warehouse:
for item in wo_order.get("required_items"):
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index 233ca19..f897a91 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -536,6 +536,12 @@
"Item", self.production_item, ["serial_no_series", "item_name", "description"], as_dict=1
)
+ batches = []
+ if self.has_batch_no:
+ batches = frappe.get_all(
+ "Batch", filters={"reference_name": self.name}, order_by="creation", pluck="name"
+ )
+
serial_nos = []
if item_details.serial_no_series:
serial_nos = get_available_serial_nos(item_details.serial_no_series, self.qty)
@@ -556,10 +562,20 @@
"description",
"status",
"work_order",
+ "batch_no",
]
serial_nos_details = []
+ index = 0
for serial_no in serial_nos:
+ index += 1
+ batch_no = None
+ if batches and self.batch_size:
+ batch_no = batches[0]
+
+ if index % self.batch_size == 0:
+ batches.remove(batch_no)
+
serial_nos_details.append(
(
serial_no,
@@ -574,6 +590,7 @@
item_details.description,
"Inactive",
self.name,
+ batch_no,
)
)
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index ac2fe58..96a9209 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -1081,7 +1081,9 @@
cint(frappe.user_defaults?.use_serial_batch_fields) === 1
) {
this.frm.doc.items.forEach((item) => {
- frappe.model.set_value(item.doctype, item.name, "use_serial_batch_fields", 1);
+ if (!item.serial_and_batch_bundle) {
+ frappe.model.set_value(item.doctype, item.name, "use_serial_batch_fields", 1);
+ }
});
}
}
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index f554787..b75ce21 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -2541,6 +2541,7 @@
)
d.serial_and_batch_bundle = id
+ d.use_serial_batch_fields = 0
def get_available_serial_nos(self) -> List[str]:
serial_nos = []