Merge pull request #62780 from mihir-kandoi/fix/issue-62778

fix(manufacturing): use remaining sub assembly stock across production plan rows
This commit is contained in:
mergify[bot]
2026-10-28 06:56:59 +00:00
committed by GitHub
3 changed files with 38 additions and 13 deletions
@@ -48,7 +48,6 @@ class SubAssemblyService:
bom_data = []
get_sub_assembly_items(
[item.production_item for item in sub_assembly_items_store],
bin_details,
row.bom_no,
bom_data,
@@ -17,7 +17,6 @@ from erpnext.manufacturing.doctype.production_plan.services.planning_queries imp
def get_sub_assembly_items(
sub_assembly_items,
bin_details,
bom_no,
bom_data,
@@ -39,7 +38,6 @@ def get_sub_assembly_items(
parent_item_code,
bom_no,
bom_data,
sub_assembly_items,
bin_details,
to_produce_qty,
company,
@@ -50,7 +48,6 @@ def get_sub_assembly_items(
)
if d.value:
get_sub_assembly_items(
sub_assembly_items,
bin_details,
d.value,
bom_data,
@@ -67,7 +64,6 @@ def _add_sub_assembly_child(
parent_item_code,
bom_no,
bom_data,
sub_assembly_items,
bin_details,
to_produce_qty,
company,
@@ -78,7 +74,7 @@ def _add_sub_assembly_child(
):
required_qty = (d.stock_qty / d.parent_bom_qty) * flt(to_produce_qty)
stock_qty = _resolve_available_sub_assembly(
d, required_qty, sub_assembly_items, bin_details, company, warehouse, skip_available
d, required_qty, bin_details, company, warehouse, skip_available
)
if not d.is_phantom_item:
bom_data.append(
@@ -89,19 +85,17 @@ def _add_sub_assembly_child(
return stock_qty
def _resolve_available_sub_assembly(
d, stock_qty, sub_assembly_items, bin_details, company, warehouse, skip_available
):
def _resolve_available_sub_assembly(d, stock_qty, bin_details, company, warehouse, skip_available):
if warehouse and d.item_code not in bin_details:
bins = get_bin_details(d, company, for_warehouse=warehouse)
bin_details[d.item_code] = frappe._dict(aggregate_bin_details(bins))
if skip_available and d.item_code not in sub_assembly_items:
return _consume_projected_qty(d, stock_qty, sub_assembly_items, bin_details)
if skip_available:
return _consume_projected_qty(d, stock_qty, bin_details)
return stock_qty
def _consume_projected_qty(d, stock_qty, sub_assembly_items, bin_details):
def _consume_projected_qty(d, stock_qty, bin_details):
bin_dict = bin_details[d.item_code]
available_qty = bin_dict.get("available_qty", bin_dict.projected_qty)
if available_qty <= 0:
@@ -112,7 +106,6 @@ def _consume_projected_qty(d, stock_qty, sub_assembly_items, bin_details):
return 0
bin_dict.available_qty = 0
sub_assembly_items.append(d.item_code)
return stock_qty - available_qty
@@ -4202,6 +4202,39 @@ class TestProductionPlan(ERPNextTestSuite):
shared_rows = [row for row in pln.sub_assembly_items if row.production_item == shared_item]
self.assertEqual([row.qty for row in shared_rows], [0, 50])
def test_remaining_sub_assembly_stock_consumed_across_finished_goods(self):
rm_item = make_item(properties={"is_stock_item": 1}).name
shared_item = make_item(properties={"is_stock_item": 1}).name
fg_a = make_item(properties={"is_stock_item": 1}).name
fg_b = make_item(properties={"is_stock_item": 1}).name
make_bom(item=shared_item, raw_materials=[rm_item])
make_bom(item=fg_a, raw_materials=[shared_item])
make_bom(item=fg_b, raw_materials=[shared_item])
make_stock_entry(item_code=shared_item, qty=6, target="_Test Warehouse - _TC", rate=100)
pln = create_production_plan(
item_code=fg_a,
planned_qty=5,
warehouse="_Test Warehouse - _TC",
sub_assembly_warehouse="_Test Warehouse - _TC",
skip_available_sub_assembly_item=1,
do_not_save=1,
skip_getting_mr_items=1,
)
pln.append(
"po_items",
{
"item_code": fg_b,
"bom_no": frappe.db.get_value("Item", fg_b, "default_bom"),
"planned_qty": 10,
"stock_uom": "Nos",
"warehouse": "_Test Warehouse - _TC",
},
)
pln.get_sub_assembly_items()
self.assertEqual([row.qty for row in pln.sub_assembly_items], [0, 9])
def test_calculation_of_sub_assembly_items(self):
make_item("Sub Assembly Item ", properties={"is_stock_item": 1})
make_item("Sub Assembly Item 2", properties={"is_stock_item": 1})