Skip to content

Commit

Permalink
feat: provision to skip available sub assembly items in the productio…
Browse files Browse the repository at this point in the history
…n plan

(cherry picked from commit 64751ec)
  • Loading branch information
rohitwaghchaure authored and mergify[bot] committed May 23, 2023
1 parent 1b827f6 commit ce601af
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 12 deletions.
32 changes: 28 additions & 4 deletions erpnext/manufacturing/doctype/production_plan/production_plan.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,12 @@
"section_break_25",
"prod_plan_references",
"section_break_24",
"get_sub_assembly_items",
"combine_sub_items",
"section_break_ucc4",
"skip_available_sub_assembly_item",
"column_break_igxl",
"get_sub_assembly_items",
"section_break_g4ip",
"sub_assembly_items",
"download_materials_request_plan_section_section",
"download_materials_required",
Expand Down Expand Up @@ -351,12 +355,12 @@
{
"fieldname": "section_break_24",
"fieldtype": "Section Break",
"hide_border": 1
"hide_border": 1,
"label": "Sub Assembly Items"
},
{
"fieldname": "sub_assembly_items",
"fieldtype": "Table",
"label": "Sub Assembly Items",
"no_copy": 1,
"options": "Production Plan Sub Assembly Item"
},
Expand Down Expand Up @@ -392,13 +396,33 @@
"fieldname": "download_materials_request_plan_section_section",
"fieldtype": "Section Break",
"label": "Download Materials Request Plan Section"
},
{
"default": "0",
"description": "System consider the projected quantity to check available or will be available sub-assembly items ",
"fieldname": "skip_available_sub_assembly_item",
"fieldtype": "Check",
"label": "Skip Available Sub Assembly Items"
},
{
"fieldname": "section_break_ucc4",
"fieldtype": "Column Break",
"hide_border": 1
},
{
"fieldname": "section_break_g4ip",
"fieldtype": "Section Break"
},
{
"fieldname": "column_break_igxl",
"fieldtype": "Column Break"
}
],
"icon": "fa fa-calendar",
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2023-03-31 10:30:48.118932",
"modified": "2023-05-22 23:36:31.770517",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Production Plan",
Expand Down
111 changes: 105 additions & 6 deletions erpnext/manufacturing/doctype/production_plan/production_plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,9 @@ def get_sub_assembly_items(self, manufacturing_type=None):
frappe.throw(_("Row #{0}: Please select Item Code in Assembly Items").format(row.idx))

bom_data = []
get_sub_assembly_items(row.bom_no, bom_data, row.planned_qty)

warehouse = row.warehouse if self.skip_available_sub_assembly_item else None
get_sub_assembly_items(row.bom_no, bom_data, row.planned_qty, self.company, warehouse=warehouse)
self.set_sub_assembly_items_based_on_level(row, bom_data, manufacturing_type)
sub_assembly_items_store.extend(bom_data)

Expand Down Expand Up @@ -894,7 +896,9 @@ def download_raw_materials(doc, warehouses=None):
build_csv_response(item_list, doc.name)


def get_exploded_items(item_details, company, bom_no, include_non_stock_items, planned_qty=1):
def get_exploded_items(
item_details, company, bom_no, include_non_stock_items, planned_qty=1, doc=None
):
bei = frappe.qb.DocType("BOM Explosion Item")
bom = frappe.qb.DocType("BOM")
item = frappe.qb.DocType("Item")
Expand Down Expand Up @@ -1271,6 +1275,12 @@ def get_items_for_material_requests(doc, warehouses=None, get_parent_warehouse_d
include_safety_stock = doc.get("include_safety_stock")

so_item_details = frappe._dict()

sub_assembly_items = {}
if doc.get("skip_available_sub_assembly_item"):
for d in doc.get("sub_assembly_items"):
sub_assembly_items.setdefault((d.get("production_item"), d.get("bom_no")), d.get("qty"))

for data in po_items:
if not data.get("include_exploded_items") and doc.get("sub_assembly_items"):
data["include_exploded_items"] = 1
Expand All @@ -1296,10 +1306,24 @@ def get_items_for_material_requests(doc, warehouses=None, get_parent_warehouse_d
frappe.throw(_("For row {0}: Enter Planned Qty").format(data.get("idx")))

if bom_no:
if data.get("include_exploded_items") and include_subcontracted_items:
if (
data.get("include_exploded_items")
and doc.get("sub_assembly_items")
and doc.get("skip_available_sub_assembly_item")
):
item_details = get_raw_materials_of_sub_assembly_items(
item_details,
company,
bom_no,
include_non_stock_items,
sub_assembly_items,
planned_qty=planned_qty,
)

elif data.get("include_exploded_items") and include_subcontracted_items:
# fetch exploded items from BOM
item_details = get_exploded_items(
item_details, company, bom_no, include_non_stock_items, planned_qty=planned_qty
item_details, company, bom_no, include_non_stock_items, planned_qty=planned_qty, doc=doc
)
else:
item_details = get_subitems(
Expand Down Expand Up @@ -1456,12 +1480,22 @@ def get_item_data(item_code):
}


def get_sub_assembly_items(bom_no, bom_data, to_produce_qty, indent=0):
def get_sub_assembly_items(bom_no, bom_data, to_produce_qty, company, warehouse=None, indent=0):
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")
stock_qty = (d.stock_qty / d.parent_bom_qty) * flt(to_produce_qty)

if warehouse:
bin_dict = get_bin_details(d, company, for_warehouse=warehouse)

if bin_dict and bin_dict[0].projected_qty > 0:
if bin_dict[0].projected_qty > stock_qty:
continue
else:
stock_qty = stock_qty - bin_dict[0].projected_qty

bom_data.append(
frappe._dict(
{
Expand All @@ -1481,7 +1515,7 @@ 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)
get_sub_assembly_items(d.value, bom_data, stock_qty, company, warehouse, indent=indent + 1)


def set_default_warehouses(row, default_warehouses):
Expand Down Expand Up @@ -1519,3 +1553,68 @@ def get_reserved_qty_for_production_plan(item_code, warehouse):
)

return reserved_qty_for_production_plan - reserved_qty_for_production


def get_raw_materials_of_sub_assembly_items(
item_details, company, bom_no, include_non_stock_items, sub_assembly_items, planned_qty=1
):

bei = frappe.qb.DocType("BOM Item")
bom = frappe.qb.DocType("BOM")
item = frappe.qb.DocType("Item")
item_default = frappe.qb.DocType("Item Default")
item_uom = frappe.qb.DocType("UOM Conversion Detail")

items = (
frappe.qb.from_(bei)
.join(bom)
.on(bom.name == bei.parent)
.join(item)
.on(item.name == bei.item_code)
.left_join(item_default)
.on((item_default.parent == item.name) & (item_default.company == company))
.left_join(item_uom)
.on((item.name == item_uom.parent) & (item_uom.uom == item.purchase_uom))
.select(
(IfNull(Sum(bei.stock_qty / IfNull(bom.quantity, 1)), 0) * planned_qty).as_("qty"),
item.item_name,
item.name.as_("item_code"),
bei.description,
bei.stock_uom,
bei.bom_no,
item.min_order_qty,
bei.source_warehouse,
item.default_material_request_type,
item.min_order_qty,
item_default.default_warehouse,
item.purchase_uom,
item_uom.conversion_factor,
item.safety_stock,
)
.where(
(bei.docstatus == 1)
& (bom.name == bom_no)
& (item.is_stock_item.isin([0, 1]) if include_non_stock_items else item.is_stock_item == 1)
)
.groupby(bei.item_code, bei.stock_uom)
).run(as_dict=True)

for item in items:
key = (item.item_code, item.bom_no)
if item.bom_no and key in sub_assembly_items:
planned_qty = flt(sub_assembly_items[key])
get_raw_materials_of_sub_assembly_items(
item_details,
company,
item.bom_no,
include_non_stock_items,
sub_assembly_items,
planned_qty=planned_qty,
)
else:
if not item.conversion_factor and item.purchase_uom:
item.conversion_factor = get_uom_conversion_factor(item.item_code, item.purchase_uom)

item_details.setdefault(item.get("item_code"), item)

return item_details
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@
"uom",
"stock_uom",
"column_break_22",
"description"
"description",
"section_break_4rxf",
"actual_qty",
"column_break_xfhm",
"projected_qty"
],
"fields": [
{
Expand Down Expand Up @@ -183,12 +187,34 @@
"fieldtype": "Datetime",
"in_list_view": 1,
"label": "Schedule Date"
},
{
"fieldname": "section_break_4rxf",
"fieldtype": "Section Break"
},
{
"fieldname": "actual_qty",
"fieldtype": "Float",
"label": "Actual Qty",
"no_copy": 1,
"read_only": 1
},
{
"fieldname": "column_break_xfhm",
"fieldtype": "Column Break"
},
{
"fieldname": "projected_qty",
"fieldtype": "Float",
"label": "Projected Qty",
"no_copy": 1,
"read_only": 1
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2022-11-28 13:50:15.116082",
"modified": "2023-05-22 17:52:34.708879",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Production Plan Sub Assembly Item",
Expand Down

0 comments on commit ce601af

Please sign in to comment.