diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json index ae4adfa8a67..8acb821b1e5 100644 --- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json +++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json @@ -86,7 +86,9 @@ "legacy_section", "ignore_is_opening_check_for_reporting", "payment_request_settings", - "create_pr_in_draft_status" + "create_pr_in_draft_status", + "budget_settings", + "use_new_budget_controller" ], "fields": [ { @@ -565,6 +567,17 @@ "fieldname": "legacy_section", "fieldtype": "Section Break", "label": "Legacy Fields" + }, + { + "fieldname": "budget_settings", + "fieldtype": "Tab Break", + "label": "Budget" + }, + { + "default": "1", + "fieldname": "use_new_budget_controller", + "fieldtype": "Check", + "label": "Use New Budget Controller" } ], "grid_page_length": 50, @@ -573,7 +586,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2025-05-05 12:29:38.302027", + "modified": "2025-05-16 11:08:00.796886", "modified_by": "Administrator", "module": "Accounts", "name": "Accounts Settings", diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py index bbf1c2ef060..2735653bb45 100644 --- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py +++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py @@ -67,6 +67,7 @@ class AccountsSettings(Document): submit_journal_entries: DF.Check unlink_advance_payment_on_cancelation_of_order: DF.Check unlink_payment_on_cancellation_of_invoice: DF.Check + use_new_budget_controller: DF.Check use_sales_invoice_in_pos: DF.Check # end: auto-generated types diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py index 6d123308a6d..edf8c2e3581 100644 --- a/erpnext/accounts/general_ledger.py +++ b/erpnext/accounts/general_ledger.py @@ -33,7 +33,10 @@ def make_gl_entries( from_repost=False, ): if gl_map: - if gl_map[0].voucher_type != "Period Closing Voucher": + if ( + frappe.db.get_single_value("Accounts Settings", "use_new_budget_controller") + and gl_map[0].voucher_type != "Period Closing Voucher" + ): bud_val = BudgetValidation(gl_map=gl_map) bud_val.validate() @@ -196,12 +199,11 @@ def distribute_gl_based_on_cost_center_allocation(gl_map, precision=None, from_r for d in gl_map: cost_center = d.get("cost_center") - # TODO: is a separate validation on cost center allocation required? # Validate budget against main cost center - # if not from_repost: - # validate_expense_against_budget( - # d, expense_amount=flt(d.debit, precision) - flt(d.credit, precision) - # ) + if not from_repost: + validate_expense_against_budget( + d, expense_amount=flt(d.debit, precision) - flt(d.credit, precision) + ) cost_center_allocation = get_cost_center_allocation_data( gl_map[0]["company"], gl_map[0]["posting_date"], cost_center @@ -403,8 +405,8 @@ def make_entry(args, adv_adj, update_outstanding, from_repost=False): gle.flags.notify_update = False gle.submit() - # if not from_repost and gle.voucher_type != "Period Closing Voucher": - # validate_expense_against_budget(args) + if not from_repost and gle.voucher_type != "Period Closing Voucher": + validate_expense_against_budget(args) def validate_cwip_accounts(gl_map): diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index ed2d98f3469..c296850428f 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -775,28 +775,28 @@ class BuyingController(SubcontractingController): self.update_fixed_asset(field, delete_asset=True) def validate_budget(self): - from erpnext.controllers.budget_controller import BudgetValidation + if frappe.db.get_single_value("Accounts Settings", "use_new_budget_controller"): + from erpnext.controllers.budget_controller import BudgetValidation - val = BudgetValidation(doc=self) - val.validate() - return + val = BudgetValidation(doc=self) + val.validate() + else: + if self.docstatus == 1: + for data in self.get("items"): + args = data.as_dict() + args.update( + { + "doctype": self.doctype, + "company": self.company, + "posting_date": ( + self.schedule_date + if self.doctype == "Material Request" + else self.transaction_date + ), + } + ) - if self.docstatus == 1: - for data in self.get("items"): - args = data.as_dict() - args.update( - { - "doctype": self.doctype, - "company": self.company, - "posting_date": ( - self.schedule_date - if self.doctype == "Material Request" - else self.transaction_date - ), - } - ) - - validate_expense_against_budget(args) + validate_expense_against_budget(args) def process_fixed_asset(self): if self.doctype == "Purchase Invoice" and not self.update_stock: