diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index 6cdcb7090d2..51c821df93f 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -253,7 +253,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 126145792dd..76495a94959 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -194,7 +194,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() diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index f45632573b0..b5e6568c82b 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -2890,6 +2890,17 @@ class TestSalesOrder(ERPNextTestSuite): so = make_sales_order(item_code=fg_item, qty=10, rate=50, warehouse=fg_warehouse, do_not_save=1) self.assertRaises(frappe.ValidationError, so.save) + def test_sales_team_allocated_percentage_tolerates_floating_point_drift(self): + # 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 compare_payment_schedules(doc, doc1, doc2): for index, schedule in enumerate(doc1.get("payment_schedule")):