fix: calculate weighted average rate for customer provided items in subcontracting inward order

(cherry picked from commit 37ee560eae)
This commit is contained in:
ljain112
2026-01-20 18:48:59 +05:30
committed by Mergify
parent be9112b6fc
commit 7120fbd14b
2 changed files with 54 additions and 3 deletions

View File

@@ -720,6 +720,7 @@ class SubcontractingInwardController:
item.db_set("scio_detail", scio_rm.name)
if data:
precision = self.precision("customer_provided_item_cost", "items")
result = frappe.get_all(
"Subcontracting Inward Order Received Item",
filters={
@@ -734,10 +735,17 @@ class SubcontractingInwardController:
table = frappe.qb.DocType("Subcontracting Inward Order Received Item")
case_expr_qty, case_expr_rate = Case(), Case()
for d in result:
d.received_qty += (
data[d.name].transfer_qty if self._action == "submit" else -data[d.name].transfer_qty
current_qty = flt(data[d.name].transfer_qty) * (1 if self._action == "submit" else -1)
current_rate = flt(data[d.name].rate)
# Calculate weighted average rate
old_total = d.rate * d.received_qty
current_total = current_rate * current_qty
d.received_qty = d.received_qty + current_qty
d.rate = (
flt((old_total + current_total) / d.received_qty, precision) if d.received_qty else 0.0
)
d.rate += data[d.name].rate if self._action == "submit" else -data[d.name].rate
if not d.required_qty and not d.received_qty:
deleted_docs.append(d.name)

View File

@@ -51,6 +51,49 @@ class IntegrationTestSubcontractingInwardOrder(IntegrationTestCase):
for item in rm_in.get("items"):
self.assertEqual(item.customer_provided_item_cost, 15)
def test_customer_provided_item_cost_with_multiple_receipts(self):
"""
Validate that rate is calculated correctly (Weighted Average) when multiple receipts
occur for the same SCIO Received Item.
"""
so, scio = create_so_scio()
rm_item = "Basic RM"
# Receipt 1: 5 Qty @ Unit Cost 10
rm_in_1 = frappe.new_doc("Stock Entry").update(scio.make_rm_stock_entry_inward())
rm_in_1.items = [item for item in rm_in_1.items if item.item_code == rm_item]
rm_in_1.items[0].qty = 5
rm_in_1.items[0].basic_rate = 10
rm_in_1.items[0].transfer_qty = 5
rm_in_1.submit()
scio.reload()
received_item = next(item for item in scio.received_items if item.rm_item_code == rm_item)
self.assertEqual(received_item.rate, 10)
# Receipt 2: 5 Qty @ Unit Cost 20
rm_in_2 = frappe.new_doc("Stock Entry").update(scio.make_rm_stock_entry_inward())
rm_in_2.items = [item for item in rm_in_2.items if item.item_code == rm_item]
rm_in_2.items[0].qty = 5
rm_in_2.items[0].basic_rate = 20
rm_in_2.items[0].transfer_qty = 5
rm_in_2.save()
rm_in_2.submit()
# Check 2: Rate should be Weighted Average
# (5 * 10 + 5 * 20) / 10 = 150 / 10 = 15
scio.reload()
received_item = next(item for item in scio.received_items if item.rm_item_code == rm_item)
self.assertEqual(received_item.rate, 15)
# Cancel Receipt 2: Rate should revert to original
# (15 * 10 - 20 * 5) / 5 = 50 / 5 = 10
rm_in_2.cancel()
scio.reload()
received_item = next(item for item in scio.received_items if item.rm_item_code == rm_item)
self.assertEqual(received_item.received_qty, 5)
self.assertEqual(received_item.rate, 10)
def test_add_extra_customer_provided_item(self):
so, scio = create_so_scio()