Merge pull request #29736 from rohitwaghchaure/performance-issue-while-making-wo
fix: time out error while making work orders from production plan
This commit is contained in:
commit
ce79434a9b
@ -341,6 +341,7 @@ class ProductionPlan(Document):
|
|||||||
|
|
||||||
def get_production_items(self):
|
def get_production_items(self):
|
||||||
item_dict = {}
|
item_dict = {}
|
||||||
|
|
||||||
for d in self.po_items:
|
for d in self.po_items:
|
||||||
item_details = {
|
item_details = {
|
||||||
"production_item" : d.item_code,
|
"production_item" : d.item_code,
|
||||||
@ -357,12 +358,12 @@ class ProductionPlan(Document):
|
|||||||
"production_plan" : self.name,
|
"production_plan" : self.name,
|
||||||
"production_plan_item" : d.name,
|
"production_plan_item" : d.name,
|
||||||
"product_bundle_item" : d.product_bundle_item,
|
"product_bundle_item" : d.product_bundle_item,
|
||||||
"planned_start_date" : d.planned_start_date
|
"planned_start_date" : d.planned_start_date,
|
||||||
|
"project" : self.project
|
||||||
}
|
}
|
||||||
|
|
||||||
item_details.update({
|
if not item_details['project'] and d.sales_order:
|
||||||
"project": self.project or frappe.db.get_value("Sales Order", d.sales_order, "project")
|
item_details['project'] = frappe.get_cached_value("Sales Order", d.sales_order, "project")
|
||||||
})
|
|
||||||
|
|
||||||
if self.get_items_from == "Material Request":
|
if self.get_items_from == "Material Request":
|
||||||
item_details.update({
|
item_details.update({
|
||||||
@ -380,39 +381,59 @@ class ProductionPlan(Document):
|
|||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def make_work_order(self):
|
def make_work_order(self):
|
||||||
|
from erpnext.manufacturing.doctype.work_order.work_order import get_default_warehouse
|
||||||
|
|
||||||
wo_list, po_list = [], []
|
wo_list, po_list = [], []
|
||||||
subcontracted_po = {}
|
subcontracted_po = {}
|
||||||
|
default_warehouses = get_default_warehouse()
|
||||||
|
|
||||||
self.validate_data()
|
self.make_work_order_for_finished_goods(wo_list, default_warehouses)
|
||||||
self.make_work_order_for_finished_goods(wo_list)
|
self.make_work_order_for_subassembly_items(wo_list, subcontracted_po, default_warehouses)
|
||||||
self.make_work_order_for_subassembly_items(wo_list, subcontracted_po)
|
|
||||||
self.make_subcontracted_purchase_order(subcontracted_po, po_list)
|
self.make_subcontracted_purchase_order(subcontracted_po, po_list)
|
||||||
self.show_list_created_message('Work Order', wo_list)
|
self.show_list_created_message('Work Order', wo_list)
|
||||||
self.show_list_created_message('Purchase Order', po_list)
|
self.show_list_created_message('Purchase Order', po_list)
|
||||||
|
|
||||||
def make_work_order_for_finished_goods(self, wo_list):
|
def make_work_order_for_finished_goods(self, wo_list, default_warehouses):
|
||||||
items_data = self.get_production_items()
|
items_data = self.get_production_items()
|
||||||
|
|
||||||
for key, item in items_data.items():
|
for key, item in items_data.items():
|
||||||
if self.sub_assembly_items:
|
if self.sub_assembly_items:
|
||||||
item['use_multi_level_bom'] = 0
|
item['use_multi_level_bom'] = 0
|
||||||
|
|
||||||
|
set_default_warehouses(item, default_warehouses)
|
||||||
work_order = self.create_work_order(item)
|
work_order = self.create_work_order(item)
|
||||||
if work_order:
|
if work_order:
|
||||||
wo_list.append(work_order)
|
wo_list.append(work_order)
|
||||||
|
|
||||||
def make_work_order_for_subassembly_items(self, wo_list, subcontracted_po):
|
def make_work_order_for_subassembly_items(self, wo_list, subcontracted_po, default_warehouses):
|
||||||
for row in self.sub_assembly_items:
|
for row in self.sub_assembly_items:
|
||||||
if row.type_of_manufacturing == 'Subcontract':
|
if row.type_of_manufacturing == 'Subcontract':
|
||||||
subcontracted_po.setdefault(row.supplier, []).append(row)
|
subcontracted_po.setdefault(row.supplier, []).append(row)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
args = {}
|
work_order_data = {
|
||||||
self.prepare_args_for_sub_assembly_items(row, args)
|
'wip_warehouse': default_warehouses.get('wip_warehouse'),
|
||||||
work_order = self.create_work_order(args)
|
'fg_warehouse': default_warehouses.get('fg_warehouse')
|
||||||
|
}
|
||||||
|
|
||||||
|
self.prepare_data_for_sub_assembly_items(row, work_order_data)
|
||||||
|
work_order = self.create_work_order(work_order_data)
|
||||||
if work_order:
|
if work_order:
|
||||||
wo_list.append(work_order)
|
wo_list.append(work_order)
|
||||||
|
|
||||||
|
def prepare_data_for_sub_assembly_items(self, row, wo_data):
|
||||||
|
for field in ["production_item", "item_name", "qty", "fg_warehouse",
|
||||||
|
"description", "bom_no", "stock_uom", "bom_level",
|
||||||
|
"production_plan_item", "schedule_date"]:
|
||||||
|
if row.get(field):
|
||||||
|
wo_data[field] = row.get(field)
|
||||||
|
|
||||||
|
wo_data.update({
|
||||||
|
"use_multi_level_bom": 0,
|
||||||
|
"production_plan": self.name,
|
||||||
|
"production_plan_sub_assembly_item": row.name
|
||||||
|
})
|
||||||
|
|
||||||
def make_subcontracted_purchase_order(self, subcontracted_po, purchase_orders):
|
def make_subcontracted_purchase_order(self, subcontracted_po, purchase_orders):
|
||||||
if not subcontracted_po:
|
if not subcontracted_po:
|
||||||
return
|
return
|
||||||
@ -423,7 +444,7 @@ class ProductionPlan(Document):
|
|||||||
po.schedule_date = getdate(po_list[0].schedule_date) if po_list[0].schedule_date else nowdate()
|
po.schedule_date = getdate(po_list[0].schedule_date) if po_list[0].schedule_date else nowdate()
|
||||||
po.is_subcontracted = 'Yes'
|
po.is_subcontracted = 'Yes'
|
||||||
for row in po_list:
|
for row in po_list:
|
||||||
args = {
|
po_data = {
|
||||||
'item_code': row.production_item,
|
'item_code': row.production_item,
|
||||||
'warehouse': row.fg_warehouse,
|
'warehouse': row.fg_warehouse,
|
||||||
'production_plan_sub_assembly_item': row.name,
|
'production_plan_sub_assembly_item': row.name,
|
||||||
@ -433,9 +454,9 @@ class ProductionPlan(Document):
|
|||||||
|
|
||||||
for field in ['schedule_date', 'qty', 'uom', 'stock_uom', 'item_name',
|
for field in ['schedule_date', 'qty', 'uom', 'stock_uom', 'item_name',
|
||||||
'description', 'production_plan_item']:
|
'description', 'production_plan_item']:
|
||||||
args[field] = row.get(field)
|
po_data[field] = row.get(field)
|
||||||
|
|
||||||
po.append('items', args)
|
po.append('items', po_data)
|
||||||
|
|
||||||
po.set_missing_values()
|
po.set_missing_values()
|
||||||
po.flags.ignore_mandatory = True
|
po.flags.ignore_mandatory = True
|
||||||
@ -452,24 +473,9 @@ class ProductionPlan(Document):
|
|||||||
doc_list = [get_link_to_form(doctype, p) for p in doc_list]
|
doc_list = [get_link_to_form(doctype, p) for p in doc_list]
|
||||||
msgprint(_("{0} created").format(comma_and(doc_list)))
|
msgprint(_("{0} created").format(comma_and(doc_list)))
|
||||||
|
|
||||||
def prepare_args_for_sub_assembly_items(self, row, args):
|
|
||||||
for field in ["production_item", "item_name", "qty", "fg_warehouse",
|
|
||||||
"description", "bom_no", "stock_uom", "bom_level",
|
|
||||||
"production_plan_item", "schedule_date"]:
|
|
||||||
args[field] = row.get(field)
|
|
||||||
|
|
||||||
args.update({
|
|
||||||
"use_multi_level_bom": 0,
|
|
||||||
"production_plan": self.name,
|
|
||||||
"production_plan_sub_assembly_item": row.name
|
|
||||||
})
|
|
||||||
|
|
||||||
def create_work_order(self, item):
|
def create_work_order(self, item):
|
||||||
from erpnext.manufacturing.doctype.work_order.work_order import (
|
from erpnext.manufacturing.doctype.work_order.work_order import OverProductionError
|
||||||
OverProductionError,
|
|
||||||
get_default_warehouse,
|
|
||||||
)
|
|
||||||
warehouse = get_default_warehouse()
|
|
||||||
wo = frappe.new_doc("Work Order")
|
wo = frappe.new_doc("Work Order")
|
||||||
wo.update(item)
|
wo.update(item)
|
||||||
wo.planned_start_date = item.get('planned_start_date') or item.get('schedule_date')
|
wo.planned_start_date = item.get('planned_start_date') or item.get('schedule_date')
|
||||||
@ -478,11 +484,11 @@ class ProductionPlan(Document):
|
|||||||
wo.fg_warehouse = item.get("warehouse")
|
wo.fg_warehouse = item.get("warehouse")
|
||||||
|
|
||||||
wo.set_work_order_operations()
|
wo.set_work_order_operations()
|
||||||
|
wo.set_required_items()
|
||||||
|
|
||||||
if not wo.fg_warehouse:
|
|
||||||
wo.fg_warehouse = warehouse.get('fg_warehouse')
|
|
||||||
try:
|
try:
|
||||||
wo.flags.ignore_mandatory = True
|
wo.flags.ignore_mandatory = True
|
||||||
|
wo.flags.ignore_validate = True
|
||||||
wo.insert()
|
wo.insert()
|
||||||
return wo.name
|
return wo.name
|
||||||
except OverProductionError:
|
except OverProductionError:
|
||||||
@ -1023,3 +1029,8 @@ def get_sub_assembly_items(bom_no, bom_data, to_produce_qty, indent=0):
|
|||||||
|
|
||||||
if d.value:
|
if d.value:
|
||||||
get_sub_assembly_items(d.value, bom_data, stock_qty, indent=indent+1)
|
get_sub_assembly_items(d.value, bom_data, stock_qty, indent=indent+1)
|
||||||
|
|
||||||
|
def set_default_warehouses(row, default_warehouses):
|
||||||
|
for field in ['wip_warehouse', 'fg_warehouse']:
|
||||||
|
if not row.get(field):
|
||||||
|
row[field] = default_warehouses.get(field)
|
@ -76,7 +76,6 @@ class WorkOrder(Document):
|
|||||||
|
|
||||||
self.set_required_items(reset_only_qty = len(self.get("required_items")))
|
self.set_required_items(reset_only_qty = len(self.get("required_items")))
|
||||||
|
|
||||||
|
|
||||||
def validate_sales_order(self):
|
def validate_sales_order(self):
|
||||||
if self.sales_order:
|
if self.sales_order:
|
||||||
self.check_sales_order_on_hold_or_close()
|
self.check_sales_order_on_hold_or_close()
|
||||||
@ -546,7 +545,7 @@ class WorkOrder(Document):
|
|||||||
if node.is_bom:
|
if node.is_bom:
|
||||||
operations.extend(_get_operations(node.name, qty=node.exploded_qty))
|
operations.extend(_get_operations(node.name, qty=node.exploded_qty))
|
||||||
|
|
||||||
bom_qty = frappe.db.get_value("BOM", self.bom_no, "quantity")
|
bom_qty = frappe.get_cached_value("BOM", self.bom_no, "quantity")
|
||||||
operations.extend(_get_operations(self.bom_no, qty=1.0/bom_qty))
|
operations.extend(_get_operations(self.bom_no, qty=1.0/bom_qty))
|
||||||
|
|
||||||
for correct_index, operation in enumerate(operations, start=1):
|
for correct_index, operation in enumerate(operations, start=1):
|
||||||
@ -627,7 +626,7 @@ class WorkOrder(Document):
|
|||||||
frappe.delete_doc("Job Card", d.name)
|
frappe.delete_doc("Job Card", d.name)
|
||||||
|
|
||||||
def validate_production_item(self):
|
def validate_production_item(self):
|
||||||
if frappe.db.get_value("Item", self.production_item, "has_variants"):
|
if frappe.get_cached_value("Item", self.production_item, "has_variants"):
|
||||||
frappe.throw(_("Work Order cannot be raised against a Item Template"), ItemHasVariantError)
|
frappe.throw(_("Work Order cannot be raised against a Item Template"), ItemHasVariantError)
|
||||||
|
|
||||||
if self.production_item:
|
if self.production_item:
|
||||||
|
Loading…
Reference in New Issue
Block a user