mirror of
https://github.com/frappe/erpnext.git
synced 2026-02-18 17:15:04 +00:00
Merge pull request #40639 from frappe/mergify/bp/version-15-hotfix/pr-40638
fix: Batch No is mandatory while making manufacture entry (backport #40638)
This commit is contained in:
@@ -1207,6 +1207,51 @@ class TestWorkOrder(FrappeTestCase):
|
||||
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}):
|
||||
@@ -2269,6 +2314,7 @@ def make_wo_order_test_record(**args):
|
||||
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"):
|
||||
|
||||
@@ -536,6 +536,12 @@ class WorkOrder(Document):
|
||||
"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 @@ class WorkOrder(Document):
|
||||
"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 @@ class WorkOrder(Document):
|
||||
item_details.description,
|
||||
"Inactive",
|
||||
self.name,
|
||||
batch_no,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -1081,7 +1081,9 @@ erpnext.stock.StockEntry = class StockEntry extends erpnext.stock.StockControlle
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2536,6 +2536,7 @@ class StockEntry(StockController):
|
||||
)
|
||||
|
||||
d.serial_and_batch_bundle = id
|
||||
d.use_serial_batch_fields = 0
|
||||
|
||||
def get_available_serial_nos(self) -> List[str]:
|
||||
serial_nos = []
|
||||
|
||||
Reference in New Issue
Block a user