Compare commits

...

1 Commits

Author SHA1 Message Date
Nabin Hait
6f9ad833d0 fix: guard BOM get_routing against a zero conversion rate 2026-07-02 15:09:05 +05:30
2 changed files with 36 additions and 1 deletions

View File

@@ -498,7 +498,11 @@ class BOM(WebsiteGenerator):
order_by="sequence_id, idx",
):
child = self.append("operations", row)
child.hour_rate = flt(row.hour_rate / self.conversion_rate, child.precision("hour_rate"))
# guard against a 0/unset conversion rate (e.g. a foreign-currency BOM with no
# exchange-rate record), mirroring the fallback used elsewhere in this file
child.hour_rate = flt(
row.hour_rate / (flt(self.conversion_rate) or 1), child.precision("hour_rate")
)
@staticmethod
def _get_routing_fields():

View File

@@ -85,6 +85,37 @@ class TestRouting(ERPNextTestSuite):
self.assertEqual(bom_doc.operations[0].time_in_mins, 30)
self.assertEqual(bom_doc.operations[1].time_in_mins, 20)
def test_get_routing_survives_zero_conversion_rate(self):
# A foreign-currency BOM with no exchange-rate record leaves conversion_rate at 0.
# get_routing() divides the operation hour rate by it and used to raise
# ZeroDivisionError; it must now fall back to a rate of 1.
operations = [
{
"operation": "Test Operation A",
"workstation": "_Test Workstation A",
"hour_rate_rent": 300,
"hour_rate_labour": 750,
"time_in_mins": 30,
},
]
setup_operations(operations)
routing_doc = create_routing(
routing_name="Zero Rate Route",
operations=[
{"operation": "Test Operation A", "workstation": "_Test Workstation A", "time_in_mins": 30}
],
)
bom = frappe.new_doc("BOM")
bom.routing = routing_doc.name
bom.conversion_rate = 0
bom.get_routing() # must not raise ZeroDivisionError
self.assertTrue(bom.operations)
# with the 0 rate falling back to 1, the hour rate is carried over unchanged
self.assertEqual(bom.operations[0].hour_rate, routing_doc.operations[0].hour_rate)
def setup_operations(rows):
from erpnext.manufacturing.doctype.operation.test_operation import make_operation