fix: Fix Budget Variance Report
This commit fixes a bug in Budget Variance Report where it combines the actual expense amounts across different fiscal years. This was fixed by updating the function and queries for computing the actual expense amounts.
This commit is contained in:
parent
52189cba86
commit
b3ee6314f9
@ -2,12 +2,12 @@
|
|||||||
# License: GNU General Public License v3. See license.txt
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
import datetime
|
||||||
from six import iteritems
|
from six import iteritems
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import flt
|
from frappe.utils import flt, formatdate
|
||||||
from frappe.utils import formatdate
|
|
||||||
|
|
||||||
from erpnext.controllers.trends import get_period_date_ranges, get_period_month_ranges
|
from erpnext.controllers.trends import get_period_date_ranges, get_period_month_ranges
|
||||||
|
|
||||||
@ -126,8 +126,8 @@ def get_cost_centers(filters):
|
|||||||
from
|
from
|
||||||
`tab{tab}`
|
`tab{tab}`
|
||||||
where
|
where
|
||||||
company = %s
|
company=%s
|
||||||
{order_by};
|
{order_by}
|
||||||
""".format(
|
""".format(
|
||||||
tab=filters.get("budget_against"), order_by=order_by
|
tab=filters.get("budget_against"), order_by=order_by
|
||||||
),
|
),
|
||||||
@ -153,11 +153,11 @@ def get_dimension_target_details(filters):
|
|||||||
cond = ""
|
cond = ""
|
||||||
if filters.get("budget_against_filter"):
|
if filters.get("budget_against_filter"):
|
||||||
cond += """
|
cond += """
|
||||||
and
|
and
|
||||||
b.{budget_against} in (
|
b.{budget_against} in (
|
||||||
%s
|
%s
|
||||||
)
|
)
|
||||||
""".format(
|
""".format(
|
||||||
budget_against=budget_against
|
budget_against=budget_against
|
||||||
) % ", ".join(
|
) % ", ".join(
|
||||||
["%s"] * len(filters.get("budget_against_filter"))
|
["%s"] * len(filters.get("budget_against_filter"))
|
||||||
@ -165,7 +165,7 @@ def get_dimension_target_details(filters):
|
|||||||
|
|
||||||
return frappe.db.sql(
|
return frappe.db.sql(
|
||||||
"""
|
"""
|
||||||
select
|
select distinct
|
||||||
b.{budget_against} as name
|
b.{budget_against} as name
|
||||||
from
|
from
|
||||||
`tabBudget` b
|
`tabBudget` b
|
||||||
@ -198,19 +198,19 @@ def get_target_distribution_details(filters):
|
|||||||
target_details = {}
|
target_details = {}
|
||||||
for d in frappe.db.sql(
|
for d in frappe.db.sql(
|
||||||
"""
|
"""
|
||||||
select
|
select
|
||||||
md.name,
|
md.name,
|
||||||
mdp.month,
|
mdp.month,
|
||||||
mdp.percentage_allocation
|
mdp.percentage_allocation
|
||||||
from
|
from
|
||||||
`tabMonthly Distribution Percentage` mdp,
|
`tabMonthly Distribution Percentage` mdp,
|
||||||
`tabMonthly Distribution` md
|
`tabMonthly Distribution` md
|
||||||
where
|
where
|
||||||
mdp.parent = md.name
|
mdp.parent = md.name
|
||||||
and md.fiscal_year between %s
|
and md.fiscal_year between %s
|
||||||
and %s
|
and %s
|
||||||
order by md.fiscal_year
|
order by md.fiscal_year
|
||||||
""",
|
""",
|
||||||
(filters.from_fiscal_year, filters.to_fiscal_year),
|
(filters.from_fiscal_year, filters.to_fiscal_year),
|
||||||
as_dict=1,
|
as_dict=1,
|
||||||
):
|
):
|
||||||
@ -229,8 +229,8 @@ def get_actual_details(name, filters):
|
|||||||
if filters.get("budget_against") == "Cost Center":
|
if filters.get("budget_against") == "Cost Center":
|
||||||
cc_lft, cc_rgt = frappe.db.get_value("Cost Center", name, ["lft", "rgt"])
|
cc_lft, cc_rgt = frappe.db.get_value("Cost Center", name, ["lft", "rgt"])
|
||||||
cond = """
|
cond = """
|
||||||
and lft >= '{lft}'
|
and lft >= \'{lft}\'
|
||||||
and rgt <= '{rgt}'
|
and rgt <= \'{rgt}\'
|
||||||
""".format(
|
""".format(
|
||||||
lft=cc_lft, rgt=cc_rgt
|
lft=cc_lft, rgt=cc_rgt
|
||||||
)
|
)
|
||||||
@ -282,37 +282,44 @@ def get_actual_details(name, filters):
|
|||||||
|
|
||||||
|
|
||||||
def get_dimension_account_month_map(filters):
|
def get_dimension_account_month_map(filters):
|
||||||
import datetime
|
|
||||||
|
|
||||||
dimension_target_details = get_dimension_target_details(filters)
|
dimension_target_details = get_dimension_target_details(filters)
|
||||||
tdd = get_target_distribution_details(filters)
|
tdd = get_target_distribution_details(filters)
|
||||||
|
|
||||||
cam_map = {}
|
cam_map = {}
|
||||||
|
|
||||||
for ccd in dimension_target_details:
|
for ccd in dimension_target_details:
|
||||||
actual_details = get_actual_details(ccd.budget_against, filters)
|
accounts = get_accounts(ccd.name, filters)
|
||||||
|
actual_details = get_actual_details(ccd.name, filters)
|
||||||
|
|
||||||
for month_id in range(1, 13):
|
for year in get_fiscal_years(filters):
|
||||||
month = datetime.date(2013, month_id, 1).strftime("%B")
|
year = year[0]
|
||||||
cam_map.setdefault(ccd.budget_against, {}).setdefault(
|
monthly_distribution = get_monthly_distribution(ccd.name, year, filters)
|
||||||
ccd.account, {}
|
for month_id in range(1, 13):
|
||||||
).setdefault(ccd.fiscal_year, {}).setdefault(
|
month = datetime.date(2013, month_id, 1).strftime(
|
||||||
month, frappe._dict({"target": 0.0, "actual": 0.0})
|
"%B"
|
||||||
)
|
) # Get month string
|
||||||
|
|
||||||
tav_dict = cam_map[ccd.budget_against][ccd.account][ccd.fiscal_year][month]
|
for account in accounts:
|
||||||
month_percentage = (
|
account = account[0]
|
||||||
tdd.get(ccd.monthly_distribution, {}).get(month, 0)
|
cam_map.setdefault(ccd.name, {}).setdefault(account, {}).setdefault(
|
||||||
if ccd.monthly_distribution
|
year, {}
|
||||||
else 100.0 / 12
|
).setdefault(month, frappe._dict({"target": 0.0, "actual": 0.0}))
|
||||||
)
|
|
||||||
|
|
||||||
tav_dict.target = flt(ccd.budget_amount) * month_percentage / 100
|
tav_dict = cam_map[ccd.name][account][year][month]
|
||||||
|
|
||||||
for ad in actual_details.get(ccd.account, []):
|
month_percentage = (
|
||||||
if ad.month_name == month:
|
tdd.get(monthly_distribution, {}).get(month, 0)
|
||||||
tav_dict.actual += flt(ad.debit) - flt(ad.credit)
|
if monthly_distribution
|
||||||
|
else 100.0 / 12
|
||||||
|
)
|
||||||
|
|
||||||
|
budget_amount = get_budget_amount(ccd.name, year, account, filters)
|
||||||
|
|
||||||
|
tav_dict.target = flt(budget_amount) * month_percentage / 100
|
||||||
|
|
||||||
|
for ad in actual_details.get(account, []):
|
||||||
|
if ad.month_name == month and ad.fiscal_year == year:
|
||||||
|
tav_dict.actual += flt(ad.debit) - flt(ad.credit)
|
||||||
return cam_map
|
return cam_map
|
||||||
|
|
||||||
|
|
||||||
@ -336,3 +343,78 @@ def get_fiscal_years(filters):
|
|||||||
)
|
)
|
||||||
|
|
||||||
return fiscal_year
|
return fiscal_year
|
||||||
|
|
||||||
|
|
||||||
|
def get_accounts(name, filters):
|
||||||
|
budget_against = frappe.scrub(filters.get("budget_against"))
|
||||||
|
|
||||||
|
accounts = frappe.db.sql(
|
||||||
|
"""
|
||||||
|
select
|
||||||
|
distinct(ba.account)
|
||||||
|
from
|
||||||
|
`tabBudget Account` ba
|
||||||
|
join
|
||||||
|
`tabBudget` b
|
||||||
|
on b.name = ba.parent
|
||||||
|
where
|
||||||
|
b.docstatus = 1
|
||||||
|
and b.fiscal_year between %s and %s
|
||||||
|
and b.{budget_against} = %s
|
||||||
|
order by
|
||||||
|
ba.account
|
||||||
|
""".format(
|
||||||
|
budget_against=budget_against
|
||||||
|
),
|
||||||
|
(filters.from_fiscal_year, filters.to_fiscal_year, name),
|
||||||
|
)
|
||||||
|
|
||||||
|
return accounts
|
||||||
|
|
||||||
|
|
||||||
|
def get_monthly_distribution(name, year, filters):
|
||||||
|
budget_against = frappe.scrub(filters.get("budget_against"))
|
||||||
|
|
||||||
|
monthly_distribution = frappe.db.sql(
|
||||||
|
"""
|
||||||
|
select
|
||||||
|
monthly_distribution
|
||||||
|
from
|
||||||
|
`tabBudget`
|
||||||
|
where
|
||||||
|
docstatus = 1
|
||||||
|
and {budget_against} = %s
|
||||||
|
and fiscal_year = %s
|
||||||
|
""".format(
|
||||||
|
budget_against=budget_against
|
||||||
|
),
|
||||||
|
(name, year),
|
||||||
|
)
|
||||||
|
|
||||||
|
return monthly_distribution[0][0] if monthly_distribution else None
|
||||||
|
|
||||||
|
|
||||||
|
def get_budget_amount(name, year, account, filters):
|
||||||
|
budget_against = frappe.scrub(filters.get("budget_against"))
|
||||||
|
|
||||||
|
budget_amount = frappe.db.sql(
|
||||||
|
"""
|
||||||
|
select
|
||||||
|
ba.budget_amount
|
||||||
|
from
|
||||||
|
`tabBudget Account` ba
|
||||||
|
join
|
||||||
|
`tabBudget` b
|
||||||
|
on b.name = ba.parent
|
||||||
|
where
|
||||||
|
b.docstatus = 1
|
||||||
|
and b.{budget_against} = %s
|
||||||
|
and b.fiscal_year = %s
|
||||||
|
and ba.account = %s
|
||||||
|
""".format(
|
||||||
|
budget_against=budget_against
|
||||||
|
),
|
||||||
|
(name, year, account),
|
||||||
|
)
|
||||||
|
|
||||||
|
return budget_amount[0][0] if budget_amount else 0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user