mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-27 17:04:47 +00:00
Merge pull request #52721 from aerele/backport-52626
fix(manufacturing): add sales order fields in subassembly child table (backport #52626)
This commit is contained in:
@@ -790,6 +790,8 @@ class ProductionPlan(Document):
|
|||||||
"stock_uom",
|
"stock_uom",
|
||||||
"bom_level",
|
"bom_level",
|
||||||
"schedule_date",
|
"schedule_date",
|
||||||
|
"sales_order",
|
||||||
|
"sales_order_item",
|
||||||
]:
|
]:
|
||||||
if row.get(field):
|
if row.get(field):
|
||||||
wo_data[field] = row.get(field)
|
wo_data[field] = row.get(field)
|
||||||
@@ -829,6 +831,8 @@ class ProductionPlan(Document):
|
|||||||
"qty",
|
"qty",
|
||||||
"description",
|
"description",
|
||||||
"production_plan_item",
|
"production_plan_item",
|
||||||
|
"sales_order",
|
||||||
|
"sales_order_item",
|
||||||
]:
|
]:
|
||||||
po_data[field] = row.get(field)
|
po_data[field] = row.get(field)
|
||||||
|
|
||||||
@@ -1015,6 +1019,10 @@ class ProductionPlan(Document):
|
|||||||
if not is_group_warehouse:
|
if not is_group_warehouse:
|
||||||
data.fg_warehouse = self.sub_assembly_warehouse
|
data.fg_warehouse = self.sub_assembly_warehouse
|
||||||
|
|
||||||
|
if not self.combine_sub_items:
|
||||||
|
data.sales_order = row.sales_order
|
||||||
|
data.sales_order_item = row.sales_order_item
|
||||||
|
|
||||||
def set_default_supplier_for_subcontracting_order(self):
|
def set_default_supplier_for_subcontracting_order(self):
|
||||||
items = [
|
items = [
|
||||||
d.production_item for d in self.sub_assembly_items if d.type_of_manufacturing == "Subcontract"
|
d.production_item for d in self.sub_assembly_items if d.type_of_manufacturing == "Subcontract"
|
||||||
|
|||||||
@@ -565,6 +565,90 @@ class TestProductionPlan(FrappeTestCase):
|
|||||||
self.assertEqual(po_doc.items[0].fg_item, fg_item)
|
self.assertEqual(po_doc.items[0].fg_item, fg_item)
|
||||||
self.assertEqual(po_doc.items[0].item_code, service_item)
|
self.assertEqual(po_doc.items[0].item_code, service_item)
|
||||||
|
|
||||||
|
def test_sales_order_references_for_sub_assembly_items(self):
|
||||||
|
"""
|
||||||
|
Test that Sales Order and Sales Order Item references in Work Order and Purchase Order
|
||||||
|
are correctly propagated from the Production Plan.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from erpnext.manufacturing.doctype.bom.test_bom import create_nested_bom
|
||||||
|
|
||||||
|
# Setup Test Items & BOM
|
||||||
|
fg_item = "Test FG Good Item"
|
||||||
|
sub_assembly_item1 = "Test Sub Assembly Item 1"
|
||||||
|
sub_assembly_item2 = "Test Sub Assembly Item 2"
|
||||||
|
|
||||||
|
bom_tree = {
|
||||||
|
fg_item: {
|
||||||
|
sub_assembly_item1: {"Test Raw Material 1": {}},
|
||||||
|
sub_assembly_item2: {"Test Raw Material 2": {}},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
create_nested_bom(bom_tree, prefix="")
|
||||||
|
|
||||||
|
# Create Sales Order
|
||||||
|
so = make_sales_order(item_code=fg_item, qty=10)
|
||||||
|
so_item_row = so.items[0].name
|
||||||
|
|
||||||
|
# Create Production Plan from Sales Order
|
||||||
|
production_plan = frappe.new_doc("Production Plan")
|
||||||
|
production_plan.company = so.company
|
||||||
|
production_plan.get_items_from = "Sales Order"
|
||||||
|
production_plan.item_code = fg_item
|
||||||
|
|
||||||
|
production_plan.get_open_sales_orders()
|
||||||
|
self.assertEqual(production_plan.sales_orders[0].sales_order, so.name)
|
||||||
|
|
||||||
|
production_plan.get_so_items()
|
||||||
|
|
||||||
|
production_plan.skip_available_sub_assembly_item = 0
|
||||||
|
production_plan.get_sub_assembly_items()
|
||||||
|
|
||||||
|
self.assertEqual(len(production_plan.sub_assembly_items), 2)
|
||||||
|
|
||||||
|
# Validate Sales Order references in Sub Assembly Items
|
||||||
|
for row in production_plan.sub_assembly_items:
|
||||||
|
if row.production_item == sub_assembly_item1:
|
||||||
|
row.supplier = "_Test Supplier"
|
||||||
|
row.type_of_manufacturing = "Subcontract"
|
||||||
|
|
||||||
|
self.assertEqual(row.sales_order, so.name)
|
||||||
|
self.assertEqual(row.sales_order_item, so_item_row)
|
||||||
|
|
||||||
|
# Submit Production Plan
|
||||||
|
production_plan.save()
|
||||||
|
production_plan.submit()
|
||||||
|
production_plan.make_work_order()
|
||||||
|
|
||||||
|
# Validate Purchase Order (Subcontracted Item)
|
||||||
|
po_items = frappe.get_all(
|
||||||
|
"Purchase Order Item",
|
||||||
|
{
|
||||||
|
"production_plan": production_plan.name,
|
||||||
|
"fg_item": sub_assembly_item1,
|
||||||
|
},
|
||||||
|
["sales_order", "sales_order_item"],
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertTrue(po_items)
|
||||||
|
self.assertEqual(po_items[0].sales_order, so.name)
|
||||||
|
self.assertEqual(po_items[0].sales_order_item, so_item_row)
|
||||||
|
|
||||||
|
# Validate Work Order (In-house Item)
|
||||||
|
work_orders = frappe.get_all(
|
||||||
|
"Work Order",
|
||||||
|
{
|
||||||
|
"production_plan": production_plan.name,
|
||||||
|
"production_item": sub_assembly_item2,
|
||||||
|
},
|
||||||
|
["sales_order", "sales_order_item"],
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertTrue(work_orders)
|
||||||
|
self.assertEqual(work_orders[0].sales_order, so.name)
|
||||||
|
self.assertEqual(work_orders[0].sales_order_item, so_item_row)
|
||||||
|
|
||||||
def test_production_plan_combine_subassembly(self):
|
def test_production_plan_combine_subassembly(self):
|
||||||
"""
|
"""
|
||||||
Test combining Sub assembly items belonging to the same BOM in Prod Plan.
|
Test combining Sub assembly items belonging to the same BOM in Prod Plan.
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
"fg_warehouse",
|
"fg_warehouse",
|
||||||
"parent_item_code",
|
"parent_item_code",
|
||||||
"schedule_date",
|
"schedule_date",
|
||||||
|
"sales_order",
|
||||||
|
"sales_order_item",
|
||||||
"column_break_3",
|
"column_break_3",
|
||||||
"qty",
|
"qty",
|
||||||
"bom_no",
|
"bom_no",
|
||||||
@@ -212,20 +214,36 @@
|
|||||||
"label": "Ordered Qty",
|
"label": "Ordered Qty",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "sales_order",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Sales Order",
|
||||||
|
"options": "Sales Order",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "sales_order_item",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"hidden": 1,
|
||||||
|
"label": "Sales Order Item",
|
||||||
|
"no_copy": 1,
|
||||||
|
"print_hide": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2025-06-10 13:36:24.759101",
|
"modified": "2026-02-17 12:06:02.309032",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Manufacturing",
|
"module": "Manufacturing",
|
||||||
"name": "Production Plan Sub Assembly Item",
|
"name": "Production Plan Sub Assembly Item",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [],
|
"permissions": [],
|
||||||
"quick_entry": 1,
|
"quick_entry": 1,
|
||||||
|
"row_format": "Dynamic",
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"states": [],
|
"states": [],
|
||||||
"track_changes": 1
|
"track_changes": 1
|
||||||
}
|
}
|
||||||
@@ -33,6 +33,8 @@ class ProductionPlanSubAssemblyItem(Document):
|
|||||||
purchase_order: DF.Link | None
|
purchase_order: DF.Link | None
|
||||||
qty: DF.Float
|
qty: DF.Float
|
||||||
received_qty: DF.Float
|
received_qty: DF.Float
|
||||||
|
sales_order: DF.Link | None
|
||||||
|
sales_order_item: DF.Data | None
|
||||||
schedule_date: DF.Datetime | None
|
schedule_date: DF.Datetime | None
|
||||||
stock_uom: DF.Link | None
|
stock_uom: DF.Link | None
|
||||||
supplier: DF.Link | None
|
supplier: DF.Link | None
|
||||||
|
|||||||
Reference in New Issue
Block a user