mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-04 20:59:11 +00:00
fix: handle cumulative breach for monthly and annual
- better method names
This commit is contained in:
@@ -4,7 +4,7 @@ import frappe
|
|||||||
from frappe import _, qb
|
from frappe import _, qb
|
||||||
from frappe.query_builder import Criterion
|
from frappe.query_builder import Criterion
|
||||||
from frappe.query_builder.functions import IfNull, Sum
|
from frappe.query_builder.functions import IfNull, Sum
|
||||||
from frappe.utils import flt, fmt_money, get_link_to_form
|
from frappe.utils import comma_and, flt, fmt_money, get_link_to_form
|
||||||
|
|
||||||
from erpnext.accounts.doctype.budget.budget import BudgetError, get_accumulated_monthly_budget
|
from erpnext.accounts.doctype.budget.budget import BudgetError, get_accumulated_monthly_budget
|
||||||
from erpnext.accounts.utils import get_fiscal_year
|
from erpnext.accounts.utils import get_fiscal_year
|
||||||
@@ -87,7 +87,8 @@ class BudgetValidation:
|
|||||||
self.get_ordered_amount(key)
|
self.get_ordered_amount(key)
|
||||||
self.get_requested_amount(key)
|
self.get_requested_amount(key)
|
||||||
|
|
||||||
self.handle_action(key, v)
|
# Pre-emptive validation before hitting ledger
|
||||||
|
self.handle_actions(key, v)
|
||||||
|
|
||||||
# Validation happens after submit for Purchase Order and
|
# Validation happens after submit for Purchase Order and
|
||||||
# Material Request and so will be included in the query
|
# Material Request and so will be included in the query
|
||||||
@@ -96,7 +97,7 @@ class BudgetValidation:
|
|||||||
v.current_actual_exp_amount = sum([x.debit - x.credit for x in v.get("gl_to_process", [])])
|
v.current_actual_exp_amount = sum([x.debit - x.credit for x in v.get("gl_to_process", [])])
|
||||||
|
|
||||||
self.get_actual_expense(key)
|
self.get_actual_expense(key)
|
||||||
self.handle_action(key, v)
|
self.handle_actions(key, v)
|
||||||
|
|
||||||
def get_child_nodes(self, budget_against, dimension):
|
def get_child_nodes(self, budget_against, dimension):
|
||||||
lft, rgt = frappe.db.get_all(
|
lft, rgt = frappe.db.get_all(
|
||||||
@@ -328,7 +329,7 @@ class BudgetValidation:
|
|||||||
)
|
)
|
||||||
self.execute_action(config.action_for_monthly, _msg)
|
self.execute_action(config.action_for_monthly, _msg)
|
||||||
|
|
||||||
def handle_action(self, key, v_map):
|
def handle_purchase_order_overlimit(self, key, v_map):
|
||||||
self.handle_individual_doctype_action(
|
self.handle_individual_doctype_action(
|
||||||
key,
|
key,
|
||||||
frappe._dict(
|
frappe._dict(
|
||||||
@@ -344,6 +345,8 @@ class BudgetValidation:
|
|||||||
v_map.current_ordered_amount,
|
v_map.current_ordered_amount,
|
||||||
v_map.accumulated_monthly_budget,
|
v_map.accumulated_monthly_budget,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def handle_material_request_overlimit(self, key, v_map):
|
||||||
self.handle_individual_doctype_action(
|
self.handle_individual_doctype_action(
|
||||||
key,
|
key,
|
||||||
frappe._dict(
|
frappe._dict(
|
||||||
@@ -359,6 +362,8 @@ class BudgetValidation:
|
|||||||
v_map.current_requested_amount,
|
v_map.current_requested_amount,
|
||||||
v_map.accumulated_monthly_budget,
|
v_map.accumulated_monthly_budget,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def handle_actual_expense_overlimit(self, key, v_map):
|
||||||
self.handle_individual_doctype_action(
|
self.handle_individual_doctype_action(
|
||||||
key,
|
key,
|
||||||
frappe._dict(
|
frappe._dict(
|
||||||
@@ -375,6 +380,49 @@ class BudgetValidation:
|
|||||||
v_map.accumulated_monthly_budget,
|
v_map.accumulated_monthly_budget,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def handle_actions(self, key, v_map):
|
||||||
|
self.handle_purchase_order_overlimit(key, v_map)
|
||||||
|
self.handle_material_request_overlimit(key, v_map)
|
||||||
|
self.handle_actual_expense_overlimit(key, v_map)
|
||||||
|
# PO + MR + Actual Expense
|
||||||
|
self.handle_cumulative_overlimit(key, v_map)
|
||||||
|
|
||||||
|
def handle_cumulative_overlimit(self, key, v_map):
|
||||||
|
self.handle_cumulative_overlimit_for_monthly(key, v_map)
|
||||||
|
self.handle_cumulative_overlimit_for_annual(key, v_map)
|
||||||
|
|
||||||
|
def budget_applicable_for(self, budget_doc) -> str:
|
||||||
|
doctypes = []
|
||||||
|
if budget_doc.applicable_on_purchase_order:
|
||||||
|
doctypes.append("Purchase Order")
|
||||||
|
if budget_doc.applicable_on_material_request:
|
||||||
|
doctypes.append("Material Request")
|
||||||
|
if budget_doc.applicable_on_booking_actual_expenses:
|
||||||
|
doctypes.append("Actual Expense")
|
||||||
|
return comma_and(doctypes)
|
||||||
|
|
||||||
|
def handle_cumulative_overlimit_for_monthly(self, key, v_map):
|
||||||
|
current_amt = (
|
||||||
|
v_map.current_ordered_amount + v_map.current_requested_amount + v_map.current_actual_exp_amount
|
||||||
|
)
|
||||||
|
monthly_diff = (
|
||||||
|
v_map.ordered_amount + v_map.requested_amount + v_map.actual_expense + current_amt
|
||||||
|
) - v_map.accumulated_monthly_budget
|
||||||
|
if monthly_diff > 0:
|
||||||
|
currency = frappe.get_cached_value("Company", self.company, "default_currency")
|
||||||
|
_msg = _(
|
||||||
|
"Accumulated Monthly Budget for Account {0} against {1} {2} is {3}. It will be collectively ({4}) exceeded by {5}"
|
||||||
|
).format(
|
||||||
|
frappe.bold(key[2]),
|
||||||
|
frappe.bold(frappe.unscrub(key[0])),
|
||||||
|
frappe.bold(key[1]),
|
||||||
|
frappe.bold(fmt_money(v_map.accumulated_montly_budget, currency=currency)),
|
||||||
|
self.budget_applicable_for(v_map.budget_doc),
|
||||||
|
frappe.bold(fmt_money(monthly_diff, currency=currency)),
|
||||||
|
)
|
||||||
|
self.stop(_msg)
|
||||||
|
|
||||||
|
def handle_cumulative_overlimit_for_annual(self, key, v_map):
|
||||||
current_amt = (
|
current_amt = (
|
||||||
v_map.current_ordered_amount + v_map.current_requested_amount + v_map.current_actual_exp_amount
|
v_map.current_ordered_amount + v_map.current_requested_amount + v_map.current_actual_exp_amount
|
||||||
)
|
)
|
||||||
@@ -384,12 +432,13 @@ class BudgetValidation:
|
|||||||
if total_diff > 0:
|
if total_diff > 0:
|
||||||
currency = frappe.get_cached_value("Company", self.company, "default_currency")
|
currency = frappe.get_cached_value("Company", self.company, "default_currency")
|
||||||
_msg = _(
|
_msg = _(
|
||||||
"Annual Budget for Account {0} against {1} {2} is {3}. It will be exceeded by {4}"
|
"Annual Budget for Account {0} against {1} {2} is {3}. It will be collectively ({4}) exceeded by {5}"
|
||||||
).format(
|
).format(
|
||||||
frappe.bold(key[2]),
|
frappe.bold(key[2]),
|
||||||
frappe.bold(frappe.unscrub(key[0])),
|
frappe.bold(frappe.unscrub(key[0])),
|
||||||
frappe.bold(key[1]),
|
frappe.bold(key[1]),
|
||||||
frappe.bold(fmt_money(v_map.budget_amount, currency=currency)),
|
frappe.bold(fmt_money(v_map.budget_amount, currency=currency)),
|
||||||
|
self.budget_applicable_for(v_map.budget_doc),
|
||||||
frappe.bold(fmt_money(total_diff, currency=currency)),
|
frappe.bold(fmt_money(total_diff, currency=currency)),
|
||||||
)
|
)
|
||||||
self.stop(_msg)
|
self.stop(_msg)
|
||||||
|
|||||||
Reference in New Issue
Block a user