feat: Combine Sub-assembly items in Production Plan
- Combine subassembly rows if same Item, Warehouse, Inhouse/Outhouse Manu.g, BOM No.
This commit is contained in:
parent
4d8d4acec4
commit
6d72aa377f
@ -918,7 +918,7 @@ def validate_bom_no(item, bom_no):
|
||||
frappe.throw(_("BOM {0} does not belong to Item {1}").format(bom_no, item))
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_children(doctype, parent=None, is_root=False, **filters):
|
||||
def get_children(parent=None, is_root=False, **filters):
|
||||
if not parent or parent=="BOM":
|
||||
frappe.msgprint(_('Please select a BOM'))
|
||||
return
|
||||
|
@ -232,7 +232,7 @@ frappe.ui.form.on('Production Plan', {
|
||||
});
|
||||
},
|
||||
combine_items: function (frm) {
|
||||
frm.clear_table('prod_plan_references');
|
||||
frm.clear_table("prod_plan_references");
|
||||
|
||||
frappe.call({
|
||||
method: "get_items",
|
||||
@ -247,6 +247,13 @@ frappe.ui.form.on('Production Plan', {
|
||||
});
|
||||
},
|
||||
|
||||
combine_sub_items: (frm) => {
|
||||
if (frm.doc.sub_assembly_items.length > 0) {
|
||||
frm.clear_table("sub_assembly_items");
|
||||
frm.trigger("get_sub_assembly_items");
|
||||
}
|
||||
},
|
||||
|
||||
get_sub_assembly_items: function(frm) {
|
||||
frm.dirty();
|
||||
|
||||
|
@ -36,6 +36,7 @@
|
||||
"prod_plan_references",
|
||||
"section_break_24",
|
||||
"get_sub_assembly_items",
|
||||
"combine_sub_items",
|
||||
"sub_assembly_items",
|
||||
"material_request_planning",
|
||||
"include_non_stock_items",
|
||||
@ -340,7 +341,6 @@
|
||||
{
|
||||
"fieldname": "prod_plan_references",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 1,
|
||||
"label": "Production Plan Item Reference",
|
||||
"options": "Production Plan Item Reference"
|
||||
},
|
||||
@ -370,16 +370,23 @@
|
||||
"fieldname": "to_delivery_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "To Delivery Date"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "combine_sub_items",
|
||||
"fieldtype": "Check",
|
||||
"label": "Consolidate Sub Assembly Items"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-calendar",
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2021-09-06 18:35:59.642232",
|
||||
"modified": "2022-02-23 17:16:10.629378",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Production Plan",
|
||||
"naming_rule": "By \"Naming Series\" field",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
|
@ -21,7 +21,8 @@ from frappe.utils import (
|
||||
)
|
||||
from frappe.utils.csvutils import build_csv_response
|
||||
|
||||
from erpnext.manufacturing.doctype.bom.bom import get_children, validate_bom_no
|
||||
from erpnext.manufacturing.doctype.bom.bom import get_children as get_bom_children
|
||||
from erpnext.manufacturing.doctype.bom.bom import validate_bom_no
|
||||
from erpnext.manufacturing.doctype.work_order.work_order import get_item_details
|
||||
from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
|
||||
|
||||
@ -570,17 +571,28 @@ class ProductionPlan(Document):
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_sub_assembly_items(self, manufacturing_type=None):
|
||||
"Fetch sub assembly items and optionally combine them."
|
||||
self.sub_assembly_items = []
|
||||
sub_assembly_items_store = [] # temporary store to process all subassembly items
|
||||
|
||||
for row in self.po_items:
|
||||
bom_data = []
|
||||
get_sub_assembly_items(row.bom_no, bom_data, row.planned_qty)
|
||||
self.set_sub_assembly_items_based_on_level(row, bom_data, manufacturing_type)
|
||||
sub_assembly_items_store.extend(bom_data)
|
||||
|
||||
self.sub_assembly_items.sort(key= lambda d: d.bom_level, reverse=True)
|
||||
for idx, row in enumerate(self.sub_assembly_items, start=1):
|
||||
row.idx = idx
|
||||
if self.combine_sub_items:
|
||||
# Combine subassembly items
|
||||
sub_assembly_items_store = self.combine_subassembly_items(sub_assembly_items_store)
|
||||
|
||||
sub_assembly_items_store.sort(key= lambda d: d.bom_level, reverse=True) # sort by bom level
|
||||
|
||||
for idx, row in enumerate(sub_assembly_items_store):
|
||||
row.idx = idx + 1
|
||||
self.append("sub_assembly_items", row)
|
||||
|
||||
def set_sub_assembly_items_based_on_level(self, row, bom_data, manufacturing_type=None):
|
||||
"Modify bom_data, set additional details."
|
||||
for data in bom_data:
|
||||
data.qty = data.stock_qty
|
||||
data.production_plan_item = row.name
|
||||
@ -589,7 +601,32 @@ class ProductionPlan(Document):
|
||||
data.type_of_manufacturing = manufacturing_type or ("Subcontract" if data.is_sub_contracted_item
|
||||
else "In House")
|
||||
|
||||
self.append("sub_assembly_items", data)
|
||||
def combine_subassembly_items(self, sub_assembly_items_store):
|
||||
"Aggregate if same: Item, Warehouse, Inhouse/Outhouse Manu.g, BOM No."
|
||||
key_wise_data = {}
|
||||
for row in sub_assembly_items_store:
|
||||
key = (
|
||||
row.get("production_item"), row.get("fg_warehouse"),
|
||||
row.get("bom_no"), row.get("type_of_manufacturing")
|
||||
)
|
||||
if key not in key_wise_data:
|
||||
# intialise (item, wh, bom no, man.g type) wise dict
|
||||
key_wise_data[key] = row
|
||||
continue
|
||||
|
||||
existing_row = key_wise_data[key]
|
||||
if existing_row:
|
||||
# if row with same (item, wh, bom no, man.g type) key, merge
|
||||
existing_row.qty += flt(row.qty)
|
||||
existing_row.stock_qty += flt(row.stock_qty)
|
||||
existing_row.bom_level = max(existing_row.bom_level, row.bom_level)
|
||||
continue
|
||||
else:
|
||||
# add row with key
|
||||
key_wise_data[key] = row
|
||||
|
||||
sub_assembly_items_store = [key_wise_data[key] for key in key_wise_data] # unpack into single level list
|
||||
return sub_assembly_items_store
|
||||
|
||||
def all_items_completed(self):
|
||||
all_items_produced = all(flt(d.planned_qty) - flt(d.produced_qty) < 0.000001
|
||||
@ -1031,7 +1068,7 @@ def get_item_data(item_code):
|
||||
}
|
||||
|
||||
def get_sub_assembly_items(bom_no, bom_data, to_produce_qty, indent=0):
|
||||
data = get_children('BOM', parent = bom_no)
|
||||
data = get_bom_children(parent=bom_no)
|
||||
for d in data:
|
||||
if d.expandable:
|
||||
parent_item_code = frappe.get_cached_value("BOM", bom_no, "item")
|
||||
|
Loading…
x
Reference in New Issue
Block a user