From e52b1d6cff1229c525f173b7876088581c2340b9 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Sun, 5 Jul 2026 15:09:49 +0530 Subject: [PATCH] fix(controllers): compute budget requested amount per row get_requested_amount multiplied the pooled pending qty of all matching Material Request items by a single Max(rate), fabricating the total whenever rates differ and biasing it upward - making false Budget Exceeded stops more likely. Sum (stock_qty - ordered_qty) * rate per row instead, matching get_ordered_amount. --- erpnext/controllers/budget_controller.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/erpnext/controllers/budget_controller.py b/erpnext/controllers/budget_controller.py index eee9eca7f11..6c437c00248 100644 --- a/erpnext/controllers/budget_controller.py +++ b/erpnext/controllers/budget_controller.py @@ -3,7 +3,7 @@ from collections import OrderedDict import frappe from frappe import _, qb from frappe.query_builder import Criterion -from frappe.query_builder.functions import IfNull, Max, Sum +from frappe.query_builder.functions import IfNull, Sum from frappe.utils import fmt_money from erpnext.accounts.doctype.budget.budget import BudgetError, get_accumulated_monthly_budget @@ -260,10 +260,10 @@ class BudgetValidation: qb.from_(mr) .inner_join(mri) .on(mr.name == mri.parent) - # rate is outside the Sum (no GROUP BY -> implicit aggregate); Max() keeps it valid on - # postgres and matches MySQL's arbitrary single-rate choice for this aggregate. .select( - (Sum(IfNull(mri.stock_qty, 0) - IfNull(mri.ordered_qty, 0)) * Max(mri.rate)).as_("amount") + Sum((IfNull(mri.stock_qty, 0) - IfNull(mri.ordered_qty, 0)) * IfNull(mri.rate, 0)).as_( + "amount" + ) ) .where(Criterion.all(conditions)) .run(as_dict=True)