Production Order fixes (#11951)
* Production Order from Sales Order fixes: Validate SO and set required items on save
* Codacy fixes
diff --git a/erpnext/manufacturing/doctype/production_order/production_order.js b/erpnext/manufacturing/doctype/production_order/production_order.js
index c3e6f20..68a5dc4 100644
--- a/erpnext/manufacturing/doctype/production_order/production_order.js
+++ b/erpnext/manufacturing/doctype/production_order/production_order.js
@@ -157,6 +157,7 @@
item: frm.doc.production_item,
project: frm.doc.project
},
+ freeze: true,
callback: function(r) {
if(r.message) {
erpnext.in_production_item_onchange = true;
@@ -184,6 +185,7 @@
return frm.call({
doc: frm.doc,
method: "get_items_and_operations_from_bom",
+ freeze: true,
callback: function(r) {
if(r.message["set_scrap_wh_mandatory"]){
frm.toggle_reqd("scrap_warehouse", true);
diff --git a/erpnext/manufacturing/doctype/production_order/production_order.py b/erpnext/manufacturing/doctype/production_order/production_order.py
index 34ade10..891e6dc 100644
--- a/erpnext/manufacturing/doctype/production_order/production_order.py
+++ b/erpnext/manufacturing/doctype/production_order/production_order.py
@@ -43,10 +43,7 @@
validate_uom_is_integer(self, "stock_uom", ["qty", "produced_qty"])
- if not self.get("required_items"):
- self.set_required_items()
- else:
- self.set_available_qty()
+ self.set_required_items(reset_only_qty = len(self.get("required_items")))
def validate_sales_order(self):
if self.sales_order:
@@ -57,6 +54,19 @@
and so.docstatus = 1 and so_item.item_code=%s
""", (self.sales_order, self.production_item), as_dict=1)
+ if not so:
+ so = frappe.db.sql("""
+ select
+ so.name, so_item.delivery_date, so.project
+ from
+ `tabSales Order` so, `tabSales Order Item` so_item, `tabPacked Item` packed_item
+ where so.name=%s
+ and so.name=so_item.parent
+ and so.name=packed_item.parent
+ and so_item.item_code = packed_item.parent_item
+ and so.docstatus = 1 and packed_item.item_code=%s
+ """, (self.sales_order, self.production_item), as_dict=1)
+
if len(so):
if not self.expected_delivery_date:
self.expected_delivery_date = so[0].delivery_date
@@ -431,21 +441,27 @@
if self.wip_warehouse:
d.available_qty_at_wip_warehouse = get_latest_stock_qty(d.item_code, self.wip_warehouse)
- def set_required_items(self):
+ def set_required_items(self, reset_only_qty=False):
'''set required_items for production to keep track of reserved qty'''
- self.required_items = []
+ if not reset_only_qty:
+ self.required_items = []
+
if self.bom_no and self.qty:
item_dict = get_bom_items_as_dict(self.bom_no, self.company, qty=self.qty,
fetch_exploded = self.use_multi_level_bom)
- for item in sorted(item_dict.values(), key=lambda d: d['idx']):
- self.append('required_items', {
- 'item_code': item.item_code,
- 'item_name': item.item_name,
- 'description': item.description,
- 'required_qty': item.qty,
- 'source_warehouse': item.source_warehouse or item.default_warehouse
- })
+ if reset_only_qty:
+ for d in self.get("required_items"):
+ d.required_qty = item_dict.get(d.item_code).get("qty")
+ else:
+ for item in sorted(item_dict.values(), key=lambda d: d['idx']):
+ self.append('required_items', {
+ 'item_code': item.item_code,
+ 'item_name': item.item_name,
+ 'description': item.description,
+ 'required_qty': item.qty,
+ 'source_warehouse': item.source_warehouse or item.default_warehouse
+ })
self.set_available_qty()
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 51e6c61..d928405 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -762,10 +762,15 @@
out = []
for i in items:
+ if not i.get("bom"):
+ frappe.throw(_("Please select BOM against item {0}").format(i.get("item_code")))
+ if not i.get("pending_qty"):
+ frappe.throw(_("Please select Qty against item {0}").format(i.get("item_code")))
+
production_order = frappe.get_doc(dict(
doctype='Production Order',
production_item=i['item_code'],
- bom_no=i['bom'],
+ bom_no=i.get('bom'),
qty=i['pending_qty'],
company=company,
sales_order=sales_order,