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:
rohitwaghchaure 2022-02-11 16:12:21 +05:30 committed by GitHub
commit ce79434a9b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 47 additions and 37 deletions

View File

@ -341,6 +341,7 @@ class ProductionPlan(Document):
def get_production_items(self):
item_dict = {}
for d in self.po_items:
item_details = {
"production_item" : d.item_code,
@ -357,12 +358,12 @@ class ProductionPlan(Document):
"production_plan" : self.name,
"production_plan_item" : d.name,
"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({
"project": self.project or frappe.db.get_value("Sales Order", d.sales_order, "project")
})
if not item_details['project'] and d.sales_order:
item_details['project'] = frappe.get_cached_value("Sales Order", d.sales_order, "project")
if self.get_items_from == "Material Request":
item_details.update({
@ -380,39 +381,59 @@ class ProductionPlan(Document):
@frappe.whitelist()
def make_work_order(self):
from erpnext.manufacturing.doctype.work_order.work_order import get_default_warehouse
wo_list, po_list = [], []
subcontracted_po = {}
default_warehouses = get_default_warehouse()
self.validate_data()
self.make_work_order_for_finished_goods(wo_list)
self.make_work_order_for_subassembly_items(wo_list, subcontracted_po)
self.make_work_order_for_finished_goods(wo_list, default_warehouses)
self.make_work_order_for_subassembly_items(wo_list, subcontracted_po, default_warehouses)
self.make_subcontracted_purchase_order(subcontracted_po, po_list)
self.show_list_created_message('Work Order', wo_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()
for key, item in items_data.items():
if self.sub_assembly_items:
item['use_multi_level_bom'] = 0
set_default_warehouses(item, default_warehouses)
work_order = self.create_work_order(item)
if 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:
if row.type_of_manufacturing == 'Subcontract':
subcontracted_po.setdefault(row.supplier, []).append(row)
continue
args = {}
self.prepare_args_for_sub_assembly_items(row, args)
work_order = self.create_work_order(args)
work_order_data = {
'wip_warehouse': default_warehouses.get('wip_warehouse'),
'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:
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):
if not subcontracted_po:
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.is_subcontracted = 'Yes'
for row in po_list:
args = {
po_data = {
'item_code': row.production_item,
'warehouse': row.fg_warehouse,
'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',
'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.flags.ignore_mandatory = True
@ -452,24 +473,9 @@ class ProductionPlan(Document):
doc_list = [get_link_to_form(doctype, p) for p in 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):
from erpnext.manufacturing.doctype.work_order.work_order import (
OverProductionError,
get_default_warehouse,
)
warehouse = get_default_warehouse()
from erpnext.manufacturing.doctype.work_order.work_order import OverProductionError
wo = frappe.new_doc("Work Order")
wo.update(item)
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.set_work_order_operations()
wo.set_required_items()
if not wo.fg_warehouse:
wo.fg_warehouse = warehouse.get('fg_warehouse')
try:
wo.flags.ignore_mandatory = True
wo.flags.ignore_validate = True
wo.insert()
return wo.name
except OverProductionError:
@ -1023,3 +1029,8 @@ def get_sub_assembly_items(bom_no, bom_data, to_produce_qty, indent=0):
if d.value:
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)

View File

@ -76,7 +76,6 @@ class WorkOrder(Document):
self.set_required_items(reset_only_qty = len(self.get("required_items")))
def validate_sales_order(self):
if self.sales_order:
self.check_sales_order_on_hold_or_close()
@ -546,7 +545,7 @@ class WorkOrder(Document):
if node.is_bom:
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))
for correct_index, operation in enumerate(operations, start=1):
@ -627,7 +626,7 @@ class WorkOrder(Document):
frappe.delete_doc("Job Card", d.name)
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)
if self.production_item: