From f7b277582940cbb5f7a427ef8250b18db773004b Mon Sep 17 00:00:00 2001 From: pandiyan Date: Sun, 9 Aug 2026 11:25:12 +0530 Subject: [PATCH 1/2] fix: tolerate floating-point drift in sales team allocated percentage the total of allocated_percentage was compared to 100 with exact float equality, so a correct allocation could be rejected when the sum drifts in binary floating point (10.0 + 58.02 + 31.98 -> 100.00000000000001). round the total to the field precision before comparing, in both SellingController.calculate_contribution and Customer.validate. --- erpnext/controllers/selling_controller.py | 2 +- erpnext/selling/doctype/customer/customer.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index 9c6dc4d9ce5..970dd8e4b48 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -254,7 +254,7 @@ class SellingController(StockController): total += sales_person.allocated_percentage - if sales_team and total != 100.0: + if sales_team and flt(total, self.precision("allocated_percentage", "sales_team")) != 100.0: throw(_("Total allocated percentage for sales team should be 100")) def validate_sales_team(self, sales_team): diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index 2d7a562715f..dd60d11301c 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -199,7 +199,8 @@ class Customer(TransactionBase): self.loyalty_program_tier = customer.loyalty_program_tier if self.sales_team: - if sum(member.allocated_percentage or 0 for member in self.sales_team) != 100: + total = sum(flt(member.allocated_percentage) for member in self.sales_team) + if flt(total, self.precision("allocated_percentage", "sales_team")) != 100: frappe.throw(_("Total contribution percentage should be equal to 100")) @frappe.whitelist(methods=["POST"]) From 4afba94d1c3dffec6cb789f69f537883b88dc32d Mon Sep 17 00:00:00 2001 From: pandiyan Date: Sun, 9 Aug 2026 11:25:24 +0530 Subject: [PATCH 2/2] test: sales team allocation totalling 100 in floating point covers the case where the percentages are correct but the accumulated sum is 100.00000000000001. two rows can never drift, since the second reconstructs exactly as 100 - first, so the case needs three rows. --- .../selling/doctype/sales_order/test_sales_order.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 0ec0f203c14..fdbc40ba235 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -3215,6 +3215,17 @@ class TestSalesOrder(ERPNextTestSuite): so.save() self.assertEqual(sum(d.allocated_percentage for d in so.sales_team), 100) + with self.subTest("floating-point drift in the total is tolerated"): + # 10.0 + 58.02 + 31.98 accumulates to 100.00000000000001 in binary floating point + so = make_sales_order(do_not_save=True) + for sales_person, percentage in ( + ("_Test Sales Person", 10.0), + ("_Test Sales Person 1", 58.02), + ("_Test Sales Person 2", 31.98), + ): + so.append("sales_team", {"sales_person": sales_person, "allocated_percentage": percentage}) + so.save() + def test_sales_team_disabled_sales_person_rejected(self): frappe.db.set_value("Sales Person", "_Test Sales Person 2", "enabled", 0) try: