@@ -194,12 +194,18 @@ def validate_expense_against_budget(args, expense_amount=0):
|
|||||||
def validate_budget_records(args, budget_records, expense_amount):
|
def validate_budget_records(args, budget_records, expense_amount):
|
||||||
for budget in budget_records:
|
for budget in budget_records:
|
||||||
if flt(budget.budget_amount):
|
if flt(budget.budget_amount):
|
||||||
amount = expense_amount or get_amount(args, budget)
|
|
||||||
yearly_action, monthly_action = get_actions(args, budget)
|
yearly_action, monthly_action = get_actions(args, budget)
|
||||||
|
args["for_material_request"] = budget.for_material_request
|
||||||
|
args["for_purchase_order"] = budget.for_purchase_order
|
||||||
|
|
||||||
if yearly_action in ("Stop", "Warn"):
|
if yearly_action in ("Stop", "Warn"):
|
||||||
compare_expense_with_budget(
|
compare_expense_with_budget(
|
||||||
args, flt(budget.budget_amount), _("Annual"), yearly_action, budget.budget_against, amount
|
args,
|
||||||
|
flt(budget.budget_amount),
|
||||||
|
_("Annual"),
|
||||||
|
yearly_action,
|
||||||
|
budget.budget_against,
|
||||||
|
expense_amount,
|
||||||
)
|
)
|
||||||
|
|
||||||
if monthly_action in ["Stop", "Warn"]:
|
if monthly_action in ["Stop", "Warn"]:
|
||||||
@@ -215,18 +221,28 @@ def validate_budget_records(args, budget_records, expense_amount):
|
|||||||
_("Accumulated Monthly"),
|
_("Accumulated Monthly"),
|
||||||
monthly_action,
|
monthly_action,
|
||||||
budget.budget_against,
|
budget.budget_against,
|
||||||
amount,
|
expense_amount,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def compare_expense_with_budget(args, budget_amount, action_for, action, budget_against, amount=0):
|
def compare_expense_with_budget(args, budget_amount, action_for, action, budget_against, amount=0):
|
||||||
actual_expense = get_actual_expense(args)
|
args.actual_expense = get_actual_expense(args)
|
||||||
total_expense = actual_expense + amount
|
args.requested_amount, args.ordered_amount = 0, 0
|
||||||
|
if not amount:
|
||||||
|
args.requested_amount, args.ordered_amount = get_requested_amount(args), get_ordered_amount(args)
|
||||||
|
|
||||||
|
if args.get("doctype") == "Material Request" and args.for_material_request:
|
||||||
|
amount = args.requested_amount + args.ordered_amount
|
||||||
|
|
||||||
|
elif args.get("doctype") == "Purchase Order" and args.for_purchase_order:
|
||||||
|
amount = args.ordered_amount
|
||||||
|
|
||||||
|
total_expense = args.actual_expense + amount
|
||||||
|
|
||||||
if total_expense > budget_amount:
|
if total_expense > budget_amount:
|
||||||
if actual_expense > budget_amount:
|
if args.actual_expense > budget_amount:
|
||||||
error_tense = _("is already")
|
error_tense = _("is already")
|
||||||
diff = actual_expense - budget_amount
|
diff = args.actual_expense - budget_amount
|
||||||
else:
|
else:
|
||||||
error_tense = _("will be")
|
error_tense = _("will be")
|
||||||
diff = total_expense - budget_amount
|
diff = total_expense - budget_amount
|
||||||
@@ -243,6 +259,8 @@ def compare_expense_with_budget(args, budget_amount, action_for, action, budget_
|
|||||||
frappe.bold(fmt_money(diff, currency=currency)),
|
frappe.bold(fmt_money(diff, currency=currency)),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
msg += get_expense_breakup(args, currency, budget_against)
|
||||||
|
|
||||||
if frappe.flags.exception_approver_role and frappe.flags.exception_approver_role in frappe.get_roles(
|
if frappe.flags.exception_approver_role and frappe.flags.exception_approver_role in frappe.get_roles(
|
||||||
frappe.session.user
|
frappe.session.user
|
||||||
):
|
):
|
||||||
@@ -254,6 +272,85 @@ def compare_expense_with_budget(args, budget_amount, action_for, action, budget_
|
|||||||
frappe.msgprint(msg, indicator="orange", title=_("Budget Exceeded"))
|
frappe.msgprint(msg, indicator="orange", title=_("Budget Exceeded"))
|
||||||
|
|
||||||
|
|
||||||
|
def get_expense_breakup(args, currency, budget_against):
|
||||||
|
msg = "<hr>Total Expenses booked through - <ul>"
|
||||||
|
|
||||||
|
common_filters = frappe._dict(
|
||||||
|
{
|
||||||
|
args.budget_against_field: budget_against,
|
||||||
|
"account": args.account,
|
||||||
|
"company": args.company,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
msg += (
|
||||||
|
"<li>"
|
||||||
|
+ frappe.utils.get_link_to_report(
|
||||||
|
"General Ledger",
|
||||||
|
label="Actual Expenses",
|
||||||
|
filters=common_filters.copy().update(
|
||||||
|
{
|
||||||
|
"from_date": frappe.get_cached_value("Fiscal Year", args.fiscal_year, "year_start_date"),
|
||||||
|
"to_date": frappe.get_cached_value("Fiscal Year", args.fiscal_year, "year_end_date"),
|
||||||
|
"is_cancelled": 0,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
+ " - "
|
||||||
|
+ frappe.bold(fmt_money(args.actual_expense, currency=currency))
|
||||||
|
+ "</li>"
|
||||||
|
)
|
||||||
|
|
||||||
|
msg += (
|
||||||
|
"<li>"
|
||||||
|
+ frappe.utils.get_link_to_report(
|
||||||
|
"Material Request",
|
||||||
|
label="Material Requests",
|
||||||
|
report_type="Report Builder",
|
||||||
|
doctype="Material Request",
|
||||||
|
filters=common_filters.copy().update(
|
||||||
|
{
|
||||||
|
"status": [["!=", "Stopped"]],
|
||||||
|
"docstatus": 1,
|
||||||
|
"material_request_type": "Purchase",
|
||||||
|
"schedule_date": [["fiscal year", "2023-2024"]],
|
||||||
|
"item_code": args.item_code,
|
||||||
|
"per_ordered": [["<", 100]],
|
||||||
|
}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
+ " - "
|
||||||
|
+ frappe.bold(fmt_money(args.requested_amount, currency=currency))
|
||||||
|
+ "</li>"
|
||||||
|
)
|
||||||
|
|
||||||
|
msg += (
|
||||||
|
"<li>"
|
||||||
|
+ frappe.utils.get_link_to_report(
|
||||||
|
"Purchase Order",
|
||||||
|
label="Unbilled Orders",
|
||||||
|
report_type="Report Builder",
|
||||||
|
doctype="Purchase Order",
|
||||||
|
filters=common_filters.copy().update(
|
||||||
|
{
|
||||||
|
"status": [["!=", "Closed"]],
|
||||||
|
"docstatus": 1,
|
||||||
|
"transaction_date": [["fiscal year", "2023-2024"]],
|
||||||
|
"item_code": args.item_code,
|
||||||
|
"per_billed": [["<", 100]],
|
||||||
|
}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
+ " - "
|
||||||
|
+ frappe.bold(fmt_money(args.ordered_amount, currency=currency))
|
||||||
|
+ "</li>"
|
||||||
|
)
|
||||||
|
|
||||||
|
msg += "</ul>"
|
||||||
|
|
||||||
|
return msg
|
||||||
|
|
||||||
|
|
||||||
def get_actions(args, budget):
|
def get_actions(args, budget):
|
||||||
yearly_action = budget.action_if_annual_budget_exceeded
|
yearly_action = budget.action_if_annual_budget_exceeded
|
||||||
monthly_action = budget.action_if_accumulated_monthly_budget_exceeded
|
monthly_action = budget.action_if_accumulated_monthly_budget_exceeded
|
||||||
@@ -269,21 +366,9 @@ def get_actions(args, budget):
|
|||||||
return yearly_action, monthly_action
|
return yearly_action, monthly_action
|
||||||
|
|
||||||
|
|
||||||
def get_amount(args, budget):
|
def get_requested_amount(args):
|
||||||
amount = 0
|
|
||||||
|
|
||||||
if args.get("doctype") == "Material Request" and budget.for_material_request:
|
|
||||||
amount = get_requested_amount(args, budget) + get_ordered_amount(args, budget)
|
|
||||||
|
|
||||||
elif args.get("doctype") == "Purchase Order" and budget.for_purchase_order:
|
|
||||||
amount = get_ordered_amount(args, budget)
|
|
||||||
|
|
||||||
return amount
|
|
||||||
|
|
||||||
|
|
||||||
def get_requested_amount(args, budget):
|
|
||||||
item_code = args.get("item_code")
|
item_code = args.get("item_code")
|
||||||
condition = get_other_condition(args, budget, "Material Request")
|
condition = get_other_condition(args, "Material Request")
|
||||||
|
|
||||||
data = frappe.db.sql(
|
data = frappe.db.sql(
|
||||||
""" select ifnull((sum(child.stock_qty - child.ordered_qty) * rate), 0) as amount
|
""" select ifnull((sum(child.stock_qty - child.ordered_qty) * rate), 0) as amount
|
||||||
@@ -297,9 +382,9 @@ def get_requested_amount(args, budget):
|
|||||||
return data[0][0] if data else 0
|
return data[0][0] if data else 0
|
||||||
|
|
||||||
|
|
||||||
def get_ordered_amount(args, budget):
|
def get_ordered_amount(args):
|
||||||
item_code = args.get("item_code")
|
item_code = args.get("item_code")
|
||||||
condition = get_other_condition(args, budget, "Purchase Order")
|
condition = get_other_condition(args, "Purchase Order")
|
||||||
|
|
||||||
data = frappe.db.sql(
|
data = frappe.db.sql(
|
||||||
f""" select ifnull(sum(child.amount - child.billed_amt), 0) as amount
|
f""" select ifnull(sum(child.amount - child.billed_amt), 0) as amount
|
||||||
@@ -313,7 +398,7 @@ def get_ordered_amount(args, budget):
|
|||||||
return data[0][0] if data else 0
|
return data[0][0] if data else 0
|
||||||
|
|
||||||
|
|
||||||
def get_other_condition(args, budget, for_doc):
|
def get_other_condition(args, for_doc):
|
||||||
condition = "expense_account = '%s'" % (args.expense_account)
|
condition = "expense_account = '%s'" % (args.expense_account)
|
||||||
budget_against_field = args.get("budget_against_field")
|
budget_against_field = args.get("budget_against_field")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user