Skip to content

Commit 7120fbd

Browse files
ljain112mergify[bot]
authored andcommitted
fix: calculate weighted average rate for customer provided items in subcontracting inward order
(cherry picked from commit 37ee560)
1 parent be9112b commit 7120fbd

2 files changed

Lines changed: 54 additions & 3 deletions

File tree

erpnext/controllers/subcontracting_inward_controller.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,7 @@ def update_inward_order_received_items_for_raw_materials_receipt(self):
720720
item.db_set("scio_detail", scio_rm.name)
721721

722722
if data:
723+
precision = self.precision("customer_provided_item_cost", "items")
723724
result = frappe.get_all(
724725
"Subcontracting Inward Order Received Item",
725726
filters={
@@ -734,10 +735,17 @@ def update_inward_order_received_items_for_raw_materials_receipt(self):
734735
table = frappe.qb.DocType("Subcontracting Inward Order Received Item")
735736
case_expr_qty, case_expr_rate = Case(), Case()
736737
for d in result:
737-
d.received_qty += (
738-
data[d.name].transfer_qty if self._action == "submit" else -data[d.name].transfer_qty
738+
current_qty = flt(data[d.name].transfer_qty) * (1 if self._action == "submit" else -1)
739+
current_rate = flt(data[d.name].rate)
740+
741+
# Calculate weighted average rate
742+
old_total = d.rate * d.received_qty
743+
current_total = current_rate * current_qty
744+
745+
d.received_qty = d.received_qty + current_qty
746+
d.rate = (
747+
flt((old_total + current_total) / d.received_qty, precision) if d.received_qty else 0.0
739748
)
740-
d.rate += data[d.name].rate if self._action == "submit" else -data[d.name].rate
741749

742750
if not d.required_qty and not d.received_qty:
743751
deleted_docs.append(d.name)

erpnext/subcontracting/doctype/subcontracting_inward_order/test_subcontracting_inward_order.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,49 @@ def test_customer_provided_item_cost_field(self):
5151
for item in rm_in.get("items"):
5252
self.assertEqual(item.customer_provided_item_cost, 15)
5353

54+
def test_customer_provided_item_cost_with_multiple_receipts(self):
55+
"""
56+
Validate that rate is calculated correctly (Weighted Average) when multiple receipts
57+
occur for the same SCIO Received Item.
58+
"""
59+
so, scio = create_so_scio()
60+
rm_item = "Basic RM"
61+
62+
# Receipt 1: 5 Qty @ Unit Cost 10
63+
rm_in_1 = frappe.new_doc("Stock Entry").update(scio.make_rm_stock_entry_inward())
64+
rm_in_1.items = [item for item in rm_in_1.items if item.item_code == rm_item]
65+
rm_in_1.items[0].qty = 5
66+
rm_in_1.items[0].basic_rate = 10
67+
rm_in_1.items[0].transfer_qty = 5
68+
rm_in_1.submit()
69+
70+
scio.reload()
71+
received_item = next(item for item in scio.received_items if item.rm_item_code == rm_item)
72+
self.assertEqual(received_item.rate, 10)
73+
74+
# Receipt 2: 5 Qty @ Unit Cost 20
75+
rm_in_2 = frappe.new_doc("Stock Entry").update(scio.make_rm_stock_entry_inward())
76+
rm_in_2.items = [item for item in rm_in_2.items if item.item_code == rm_item]
77+
rm_in_2.items[0].qty = 5
78+
rm_in_2.items[0].basic_rate = 20
79+
rm_in_2.items[0].transfer_qty = 5
80+
rm_in_2.save()
81+
rm_in_2.submit()
82+
83+
# Check 2: Rate should be Weighted Average
84+
# (5 * 10 + 5 * 20) / 10 = 150 / 10 = 15
85+
scio.reload()
86+
received_item = next(item for item in scio.received_items if item.rm_item_code == rm_item)
87+
self.assertEqual(received_item.rate, 15)
88+
89+
# Cancel Receipt 2: Rate should revert to original
90+
# (15 * 10 - 20 * 5) / 5 = 50 / 5 = 10
91+
rm_in_2.cancel()
92+
scio.reload()
93+
received_item = next(item for item in scio.received_items if item.rm_item_code == rm_item)
94+
self.assertEqual(received_item.received_qty, 5)
95+
self.assertEqual(received_item.rate, 10)
96+
5497
def test_add_extra_customer_provided_item(self):
5598
so, scio = create_so_scio()
5699

0 commit comments

Comments
 (0)