fix: do not create repeat work orders

This commit is contained in:
Rohit Waghchaure
2025-06-09 17:44:39 +05:30
parent a61f065660
commit 384f4e120a
6 changed files with 117 additions and 10 deletions

View File

@@ -126,7 +126,9 @@ frappe.ui.form.on("Production Plan", {
);
}
if (frm.doc.po_items && frm.doc.status !== "Closed") {
let items = frm.events.get_items_for_work_order(frm);
if (items?.length && frm.doc.status !== "Closed") {
frm.add_custom_button(
__("Work Order / Subcontract PO"),
() => {
@@ -207,6 +209,24 @@ frappe.ui.form.on("Production Plan", {
set_field_options("projected_qty_formula", projected_qty_formula);
},
get_items_for_work_order(frm) {
let items = frm.doc.po_items;
if (frm.doc.sub_assembly_items?.length) {
items = [...items, ...frm.doc.sub_assembly_items];
}
let has_items =
items.filter((item) => {
if (item.pending_qty) {
return item.pending_qty > item.ordered_qty;
} else {
return item.qty > (item.received_qty || item.ordered_qty);
}
}) || [];
return has_items;
},
has_unreserved_stock(frm, table, qty_field = "required_qty") {
let has_unreserved_stock = frm.doc[table].some(
(item) => flt(item[qty_field]) > flt(item.stock_reserved_qty)

View File

@@ -778,7 +778,14 @@ class ProductionPlan(Document):
"company": self.get("company"),
}
if flt(row.qty) <= flt(row.ordered_qty):
continue
self.prepare_data_for_sub_assembly_items(row, work_order_data)
if work_order_data.get("qty") <= 0:
continue
work_order = self.create_work_order(work_order_data)
if work_order:
wo_list.append(work_order)
@@ -798,6 +805,8 @@ class ProductionPlan(Document):
if row.get(field):
wo_data[field] = row.get(field)
wo_data["qty"] = flt(row.get("qty")) - flt(row.get("ordered_qty"))
wo_data.update(
{
"use_multi_level_bom": 0,

View File

@@ -2336,6 +2336,63 @@ class TestProductionPlan(IntegrationTestCase):
self.assertTrue(len(reserved_entries) == 0)
frappe.db.set_single_value("Stock Settings", "enable_stock_reservation", 0)
def test_production_plan_for_partial_sub_assembly_items(self):
from erpnext.controllers.status_updater import OverAllowanceError
from erpnext.manufacturing.doctype.bom.test_bom import create_nested_bom
from erpnext.subcontracting.doctype.subcontracting_bom.test_subcontracting_bom import (
create_subcontracting_bom,
)
frappe.flags.test_print = False
fg_wo_item = "Test Motherboard 11"
bom_tree_1 = {"Test Laptop 11": {fg_wo_item: {"Test Motherboard Wires 11": {}}}}
create_nested_bom(bom_tree_1, prefix="")
plan = create_production_plan(
item_code="Test Laptop 11",
planned_qty=10,
use_multi_level_bom=1,
do_not_submit=True,
company="_Test Company",
skip_getting_mr_items=True,
)
plan.get_sub_assembly_items()
plan.submit()
plan.make_work_order()
work_order = frappe.db.get_value("Work Order", {"production_plan": plan.name, "docstatus": 0}, "name")
wo_doc = frappe.get_doc("Work Order", work_order)
wo_doc.qty = 5.0
wo_doc.skip_transfer = 1
wo_doc.from_wip_warehouse = 1
wo_doc.wip_warehouse = "_Test Warehouse - _TC"
wo_doc.fg_warehouse = "_Test Warehouse - _TC"
wo_doc.submit()
plan.reload()
for row in plan.sub_assembly_items:
self.assertEqual(row.ordered_qty, 5.0)
plan.make_work_order()
work_order = frappe.db.get_value("Work Order", {"production_plan": plan.name, "docstatus": 0}, "name")
wo_doc = frappe.get_doc("Work Order", work_order)
self.assertEqual(wo_doc.qty, 5.0)
wo_doc.skip_transfer = 1
wo_doc.from_wip_warehouse = 1
wo_doc.wip_warehouse = "_Test Warehouse - _TC"
wo_doc.fg_warehouse = "_Test Warehouse - _TC"
wo_doc.submit()
plan.reload()
for row in plan.sub_assembly_items:
self.assertEqual(row.ordered_qty, 10.0)
def create_production_plan(**args):
"""

View File

@@ -26,6 +26,7 @@
"wo_produced_qty",
"stock_reserved_qty",
"column_break_7",
"ordered_qty",
"received_qty",
"indent",
"section_break_19",
@@ -231,13 +232,20 @@
"no_copy": 1,
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "ordered_qty",
"fieldtype": "Float",
"label": "Ordered Qty",
"no_copy": 1,
"read_only": 1
}
],
"grid_page_length": 50,
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2025-05-01 14:28:35.979941",
"modified": "2025-06-10 13:36:24.759101",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Production Plan Sub Assembly Item",

View File

@@ -22,6 +22,7 @@ class ProductionPlanSubAssemblyItem(Document):
fg_warehouse: DF.Link | None
indent: DF.Int
item_name: DF.Data | None
ordered_qty: DF.Float
parent: DF.Data
parent_item_code: DF.Link | None
parentfield: DF.Data

View File

@@ -845,22 +845,34 @@ class WorkOrder(Document):
)
def update_ordered_qty(self):
if self.production_plan and self.production_plan_item and not self.production_plan_sub_assembly_item:
if self.production_plan and (self.production_plan_item or self.production_plan_sub_assembly_item):
table = frappe.qb.DocType("Work Order")
query = (
frappe.qb.from_(table)
.select(Sum(table.qty))
.where(
(table.production_plan == self.production_plan)
& (table.production_plan_item == self.production_plan_item)
& (table.docstatus == 1)
)
).run()
.where((table.production_plan == self.production_plan) & (table.docstatus == 1))
)
if self.production_plan_item:
query = query.where(table.production_plan_item == self.production_plan_item)
elif self.production_plan_sub_assembly_item:
query = query.where(
table.production_plan_sub_assembly_item == self.production_plan_sub_assembly_item
)
query = query.run()
qty = flt(query[0][0]) if query else 0
frappe.db.set_value("Production Plan Item", self.production_plan_item, "ordered_qty", qty)
if self.production_plan_item:
frappe.db.set_value("Production Plan Item", self.production_plan_item, "ordered_qty", qty)
elif self.production_plan_sub_assembly_item:
frappe.db.set_value(
"Production Plan Sub Assembly Item",
self.production_plan_sub_assembly_item,
"ordered_qty",
qty,
)
doc = frappe.get_doc("Production Plan", self.production_plan)
doc.set_status()