Merge pull request #47969 from rohitwaghchaure/fixed-support-40445
fix: do not create repeat work orders
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -2327,6 +2327,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):
|
||||
"""
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -851,22 +851,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()
|
||||
|
||||
Reference in New Issue
Block a user