[cleanup] [minor] deprecated budget control and rewritten budget related code
This commit is contained in:
parent
4212180804
commit
2b06aaa291
@ -1 +0,0 @@
|
||||
Backend scripts for Budget Management.
|
@ -1 +0,0 @@
|
||||
from __future__ import unicode_literals
|
@ -1,97 +0,0 @@
|
||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
from webnotes.utils import cstr, flt, getdate
|
||||
from webnotes import msgprint
|
||||
|
||||
class DocType:
|
||||
def __init__(self,d,dl):
|
||||
self.doc, self.doclist = d, dl
|
||||
|
||||
# Get monthly budget
|
||||
#-------------------
|
||||
def get_monthly_budget(self, distribution_id, cfy, st_date, post_dt, budget_allocated):
|
||||
|
||||
# get month_list
|
||||
st_date, post_dt = getdate(st_date), getdate(post_dt)
|
||||
|
||||
if distribution_id:
|
||||
if st_date.month <= post_dt.month:
|
||||
tot_per_allocated = webnotes.conn.sql("select ifnull(sum(percentage_allocation),0) from `tabBudget Distribution Detail` where parent='%s' and idx between '%s' and '%s'" % (distribution_id, st_date.month, post_dt.month))[0][0]
|
||||
|
||||
if st_date.month > post_dt.month:
|
||||
|
||||
tot_per_allocated = flt(webnotes.conn.sql("select ifnull(sum(percentage_allocation),0) from `tabBudget Distribution Detail` where parent='%s' and idx between '%s' and '%s'" % (distribution_id, st_date.month, 12 ))[0][0])
|
||||
tot_per_allocated = flt(tot_per_allocated) + flt(webnotes.conn.sql("select ifnull(sum(percentage_allocation),0) from `tabBudget Distribution Detail` where parent='%s' and idx between '%s' and '%s'" % (distribution_id, 1, post_dt.month))[0][0])
|
||||
|
||||
return (flt(budget_allocated) * flt(tot_per_allocated)) / 100
|
||||
period_diff = webnotes.conn.sql("select PERIOD_DIFF('%s','%s')" % (post_dt.strftime('%Y%m'), st_date.strftime('%Y%m')))
|
||||
|
||||
return (flt(budget_allocated) * (flt(period_diff[0][0]) + 1)) / 12
|
||||
|
||||
def validate_budget(self, acct, cost_center, actual, budget, action):
|
||||
# action if actual exceeds budget
|
||||
if flt(actual) > flt(budget):
|
||||
msgprint("Your monthly expense "+ cstr((action == 'stop') and "will exceed" or "has exceeded") +" budget for <b>Account - "+cstr(acct)+" </b> under <b>Cost Center - "+ cstr(cost_center) + "</b>"+cstr((action == 'Stop') and ", you can not have this transaction." or "."))
|
||||
if action == 'Stop': raise Exception
|
||||
|
||||
def check_budget(self,gle,cancel):
|
||||
# get allocated budget
|
||||
|
||||
bgt = webnotes.conn.sql("""select t1.budget_allocated, t1.actual, t2.distribution_id
|
||||
from `tabBudget Detail` t1, `tabCost Center` t2
|
||||
where t1.account='%s' and t1.parent=t2.name and t2.name = '%s'
|
||||
and t1.fiscal_year='%s'""" %
|
||||
(gle['account'], gle['cost_center'], gle['fiscal_year']), as_dict =1)
|
||||
|
||||
curr_amt = flt(gle['debit']) - flt(gle['credit'])
|
||||
if cancel: curr_amt = -1 * curr_amt
|
||||
|
||||
if bgt and bgt[0]['budget_allocated']:
|
||||
# check budget flag in Company
|
||||
bgt_flag = webnotes.conn.sql("""select yearly_bgt_flag, monthly_bgt_flag
|
||||
from `tabCompany` where name = '%s'""" % gle['company'], as_dict =1)
|
||||
|
||||
if bgt_flag and bgt_flag[0]['monthly_bgt_flag'] in ['Stop', 'Warn']:
|
||||
# get start date and last date
|
||||
start_date = webnotes.conn.get_value('Fiscal Year', gle['fiscal_year'], \
|
||||
'year_start_date').strftime('%Y-%m-%d')
|
||||
end_date = webnotes.conn.sql("select LAST_DAY('%s')" % gle['posting_date'])
|
||||
|
||||
# get Actual
|
||||
actual = self.get_period_difference(gle['account'] +
|
||||
'~~~' + cstr(start_date) + '~~~' + cstr(end_date[0][0]), gle['cost_center'])
|
||||
|
||||
# Get Monthly budget
|
||||
budget = self.get_monthly_budget(bgt and bgt[0]['distribution_id'] or '' , \
|
||||
gle['fiscal_year'], start_date, gle['posting_date'], bgt[0]['budget_allocated'])
|
||||
|
||||
# validate monthly budget
|
||||
self.validate_budget(gle['account'], gle['cost_center'], \
|
||||
flt(actual) + flt(curr_amt), budget, bgt_flag[0]['monthly_bgt_flag'])
|
||||
|
||||
# update actual against budget allocated in cost center
|
||||
webnotes.conn.sql("""update `tabBudget Detail` set actual = ifnull(actual,0) + %s
|
||||
where account = '%s' and fiscal_year = '%s' and parent = '%s'""" %
|
||||
(curr_amt, gle['account'],gle['fiscal_year'], gle['cost_center']))
|
||||
|
||||
|
||||
def get_period_difference(self, arg, cost_center =''):
|
||||
# used in General Ledger Page Report
|
||||
# used for Budget where cost center passed as extra argument
|
||||
acc, f, t = arg.split('~~~')
|
||||
c, fy = '', webnotes.conn.get_defaults()['fiscal_year']
|
||||
|
||||
det = webnotes.conn.sql("select debit_or_credit, lft, rgt, is_pl_account from tabAccount where name=%s", acc)
|
||||
if f: c += (' and t1.posting_date >= "%s"' % f)
|
||||
if t: c += (' and t1.posting_date <= "%s"' % t)
|
||||
if cost_center: c += (' and t1.cost_center = "%s"' % cost_center)
|
||||
bal = webnotes.conn.sql("select sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) from `tabGL Entry` t1 where t1.account='%s' %s" % (acc, c))
|
||||
bal = bal and flt(bal[0][0]) or 0
|
||||
|
||||
if det[0][0] != 'Debit':
|
||||
bal = (-1) * bal
|
||||
|
||||
return flt(bal)
|
@ -1,19 +0,0 @@
|
||||
[
|
||||
{
|
||||
"creation": "2012-03-27 14:35:41",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-07-10 14:54:06",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "nabin@webnotestech.com"
|
||||
},
|
||||
{
|
||||
"doctype": "DocType",
|
||||
"issingle": 1,
|
||||
"module": "Accounts",
|
||||
"name": "__common__"
|
||||
},
|
||||
{
|
||||
"doctype": "DocType",
|
||||
"name": "Budget Control"
|
||||
}
|
||||
]
|
@ -2,7 +2,7 @@
|
||||
{
|
||||
"creation": "2013-03-07 11:55:04",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-07-10 14:54:06",
|
||||
"modified": "2013-08-22 17:27:59",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
@ -20,7 +20,8 @@
|
||||
"parent": "Budget Detail",
|
||||
"parentfield": "fields",
|
||||
"parenttype": "DocType",
|
||||
"permlevel": 0
|
||||
"permlevel": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"doctype": "DocType",
|
||||
@ -35,7 +36,6 @@
|
||||
"oldfieldname": "account",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Account",
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
@ -45,18 +45,7 @@
|
||||
"label": "Budget Allocated",
|
||||
"oldfieldname": "budget_allocated",
|
||||
"oldfieldtype": "Currency",
|
||||
"options": "Company:company:default_currency",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "actual",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Actual",
|
||||
"oldfieldname": "actual",
|
||||
"oldfieldtype": "Currency",
|
||||
"options": "Company:company:default_currency",
|
||||
"read_only": 1
|
||||
"options": "Company:company:default_currency"
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
@ -67,7 +56,6 @@
|
||||
"oldfieldname": "fiscal_year",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "link:Fiscal Year",
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
}
|
||||
]
|
@ -1,4 +1,70 @@
|
||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
test_records = []
|
||||
test_records = [
|
||||
[{
|
||||
"doctype": "Budget Distribution",
|
||||
"distribution_id": "_Test Distribution",
|
||||
"fiscal_year": "_Test Fiscal Year 2013",
|
||||
}, {
|
||||
"doctype": "Budget Distribution Detail",
|
||||
"parentfield": "budget_distribution_details",
|
||||
"month": "April",
|
||||
"percentage_allocation": "8"
|
||||
}, {
|
||||
"doctype": "Budget Distribution Detail",
|
||||
"parentfield": "budget_distribution_details",
|
||||
"month": "May",
|
||||
"percentage_allocation": "8"
|
||||
}, {
|
||||
"doctype": "Budget Distribution Detail",
|
||||
"parentfield": "budget_distribution_details",
|
||||
"month": "June",
|
||||
"percentage_allocation": "8"
|
||||
}, {
|
||||
"doctype": "Budget Distribution Detail",
|
||||
"parentfield": "budget_distribution_details",
|
||||
"month": "July",
|
||||
"percentage_allocation": "8"
|
||||
}, {
|
||||
"doctype": "Budget Distribution Detail",
|
||||
"parentfield": "budget_distribution_details",
|
||||
"month": "August",
|
||||
"percentage_allocation": "8"
|
||||
}, {
|
||||
"doctype": "Budget Distribution Detail",
|
||||
"parentfield": "budget_distribution_details",
|
||||
"month": "September",
|
||||
"percentage_allocation": "8"
|
||||
}, {
|
||||
"doctype": "Budget Distribution Detail",
|
||||
"parentfield": "budget_distribution_details",
|
||||
"month": "October",
|
||||
"percentage_allocation": "8"
|
||||
}, {
|
||||
"doctype": "Budget Distribution Detail",
|
||||
"parentfield": "budget_distribution_details",
|
||||
"month": "November",
|
||||
"percentage_allocation": "8"
|
||||
}, {
|
||||
"doctype": "Budget Distribution Detail",
|
||||
"parentfield": "budget_distribution_details",
|
||||
"month": "December",
|
||||
"percentage_allocation": "8"
|
||||
}, {
|
||||
"doctype": "Budget Distribution Detail",
|
||||
"parentfield": "budget_distribution_details",
|
||||
"month": "January",
|
||||
"percentage_allocation": "8"
|
||||
}, {
|
||||
"doctype": "Budget Distribution Detail",
|
||||
"parentfield": "budget_distribution_details",
|
||||
"month": "February",
|
||||
"percentage_allocation": "10"
|
||||
}, {
|
||||
"doctype": "Budget Distribution Detail",
|
||||
"parentfield": "budget_distribution_details",
|
||||
"month": "March",
|
||||
"percentage_allocation": "10"
|
||||
}]
|
||||
]
|
@ -7,6 +7,13 @@ test_records = [
|
||||
"cost_center_name": "_Test Cost Center",
|
||||
"parent_cost_center": "_Test Company - _TC",
|
||||
"company": "_Test Company",
|
||||
"group_or_ledger": "Ledger"
|
||||
"group_or_ledger": "Ledger",
|
||||
"distribution_id": "_Test Distribution",
|
||||
}, {
|
||||
"doctype": "Budget Detail",
|
||||
"parentfield": "budget_details",
|
||||
"account": "_Test Account Cost for Goods Sold - _TC",
|
||||
"budget_allocated": 100000,
|
||||
"fiscal_year": "_Test Fiscal Year 2013"
|
||||
}],
|
||||
]
|
@ -2,7 +2,7 @@
|
||||
{
|
||||
"creation": "2013-01-10 16:34:06",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-07-05 14:39:07",
|
||||
"modified": "2013-08-22 17:12:13",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
@ -171,17 +171,6 @@
|
||||
"oldfieldtype": "Text",
|
||||
"search_index": 0
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "is_cancelled",
|
||||
"fieldtype": "Select",
|
||||
"in_filter": 1,
|
||||
"label": "Is Cancelled",
|
||||
"oldfieldname": "is_cancelled",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "No\nYes",
|
||||
"search_index": 0
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "is_opening",
|
||||
|
@ -31,6 +31,21 @@ class TestJournalVoucher(unittest.TestCase):
|
||||
|
||||
self.assertTrue(not webnotes.conn.sql("""select name from `tabJournal Voucher Detail`
|
||||
where against_jv=%s""", jv_invoice.doc.name))
|
||||
|
||||
def test_budget(self):
|
||||
from accounts.utils import BudgetError
|
||||
webnotes.conn.set_value("Company", "_Test Company", "monthly_bgt_flag", "Stop")
|
||||
|
||||
jv1 = webnotes.bean(copy=test_records[0])
|
||||
jv1.doc.posting_date = "2013-02-12"
|
||||
jv1.doclist[2].account = "_Test Account Cost for Goods Sold - _TC"
|
||||
jv1.doclist[2].cost_center = "_Test Cost Center - _TC"
|
||||
jv1.doclist[2].debit = 20000.0
|
||||
jv1.doclist[1].credit = 20000.0
|
||||
jv1.insert()
|
||||
|
||||
self.assertRaises(BudgetError, jv1.submit)
|
||||
|
||||
|
||||
test_records = [
|
||||
[{
|
||||
|
@ -5,6 +5,7 @@ from __future__ import unicode_literals
|
||||
import webnotes
|
||||
from webnotes.utils import flt, cstr, now
|
||||
from webnotes.model.doc import Document
|
||||
from accounts.utils import validate_expense_against_budget
|
||||
|
||||
def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True,
|
||||
update_outstanding='Yes'):
|
||||
@ -12,7 +13,6 @@ def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True,
|
||||
if merge_entries:
|
||||
gl_map = merge_similar_entries(gl_map)
|
||||
|
||||
check_budget(gl_map, cancel)
|
||||
save_entries(gl_map, adv_adj, update_outstanding)
|
||||
else:
|
||||
delete_gl_entries(gl_map, adv_adj, update_outstanding)
|
||||
@ -54,20 +54,21 @@ def check_budget(gl_map, cancel):
|
||||
|
||||
def save_entries(gl_map, adv_adj, update_outstanding):
|
||||
total_debit = total_credit = 0.0
|
||||
def _swap(gle):
|
||||
gle.debit, gle.credit = abs(flt(gle.credit)), abs(flt(gle.debit))
|
||||
def _swap(entry):
|
||||
entry["debit"], entry["credit"] = abs(flt(entry["credit"])), abs(flt(entry["debit"]))
|
||||
|
||||
for entry in gl_map:
|
||||
gle = Document('GL Entry', fielddata=entry)
|
||||
|
||||
# round off upto 2 decimal
|
||||
gle.debit = flt(gle.debit, 2)
|
||||
gle.credit = flt(gle.credit, 2)
|
||||
entry["debit"] = flt(entry["debit"], 2)
|
||||
entry["credit"] = flt(entry["credit"], 2)
|
||||
|
||||
# toggle debit, credit if negative entry
|
||||
if flt(gle.debit) < 0 or flt(gle.credit) < 0:
|
||||
_swap(gle)
|
||||
if flt(entry["debit"]) < 0 or flt(entry["credit"]) < 0:
|
||||
_swap(entry)
|
||||
|
||||
validate_expense_against_budget(entry)
|
||||
|
||||
gle = Document('GL Entry', fielddata=entry)
|
||||
gle_obj = webnotes.get_obj(doc=gle)
|
||||
gle_obj.validate()
|
||||
gle.save(1)
|
||||
@ -96,10 +97,9 @@ def delete_gl_entries(gl_entries, adv_adj, update_outstanding):
|
||||
for entry in gl_entries:
|
||||
validate_freezed_account(entry["account"], adv_adj)
|
||||
check_negative_balance(entry["account"], adv_adj)
|
||||
validate_expense_against_budget(entry)
|
||||
|
||||
if entry.get("against_voucher") and entry.get("against_voucher_type") != "POS" \
|
||||
and update_outstanding == 'Yes':
|
||||
update_outstanding_amt(entry["account"], entry.get("against_voucher_type"),
|
||||
entry.get("against_voucher"))
|
||||
|
||||
# To-do
|
||||
# Check and update budget for expense account
|
||||
entry.get("against_voucher"))
|
@ -4,7 +4,7 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import webnotes
|
||||
from webnotes.utils import nowdate, nowtime, cstr, flt, now
|
||||
from webnotes.utils import nowdate, nowtime, cstr, flt, now, getdate, add_months
|
||||
from webnotes.model.doc import addchild
|
||||
from webnotes import msgprint, _
|
||||
from webnotes.utils import formatdate
|
||||
@ -12,6 +12,8 @@ from utilities import build_filter_conditions
|
||||
|
||||
|
||||
class FiscalYearError(webnotes.ValidationError): pass
|
||||
class BudgetError(webnotes.ValidationError): pass
|
||||
|
||||
|
||||
def get_fiscal_year(date=None, fiscal_year=None, label="Date", verbose=1):
|
||||
return get_fiscal_years(date, fiscal_year, label, verbose=1)[0]
|
||||
@ -373,7 +375,6 @@ def get_stock_and_account_difference(warehouse_list=None):
|
||||
|
||||
return difference
|
||||
|
||||
|
||||
def validate_expense_against_budget(args):
|
||||
args = webnotes._dict(args)
|
||||
if webnotes.conn.get_value("Account", {"name": args.account, "is_pl_account": "Yes",
|
||||
@ -385,18 +386,60 @@ def validate_expense_against_budget(args):
|
||||
""", (args.cost_center, args.account, args.fiscal_year), as_dict=True)
|
||||
|
||||
if budget and budget[0].budget_allocated:
|
||||
action = webnotes.conn.get_value("Company", args.company,
|
||||
yearly_action, monthly_action = webnotes.conn.get_value("Company", args.company,
|
||||
["yearly_bgt_flag", "monthly_bgt_flag"])
|
||||
action_for = action = ""
|
||||
|
||||
if monthly_action in ["Stop", "Warn"]:
|
||||
budget_amount = get_allocated_budget(budget[0].distribution_id,
|
||||
args.posting_date, args.fiscal_year, budget[0].budget_allocated)
|
||||
|
||||
args["month_end_date"] = webnotes.conn.sql("select LAST_DAY(%s)", args.posting_date)
|
||||
|
||||
expense_upto_date = get_actual_expense(args)
|
||||
month_end_date = webnotes.conn.sql("select LAST_DAY(%s)", args.posting_date)
|
||||
args["condition"] = " and posting_date<='%s'" % month_end_date
|
||||
action_for, action = "Monthly", monthly_action
|
||||
|
||||
elif yearly_action in ["Stop", "Warn"]:
|
||||
budget_amount = budget[0].budget_allocated
|
||||
action_for, action = "Monthly", yearly_action
|
||||
print budget_amount
|
||||
if action_for:
|
||||
actual_expense = get_actual_expense(args)
|
||||
print actual_expense
|
||||
if actual_expense > budget_amount:
|
||||
webnotes.msgprint(action_for + _(" budget ") + cstr(budget_amount) +
|
||||
_(" for account ") + args.account + _(" against cost center ") +
|
||||
args.cost_center + _(" will exceed by ") +
|
||||
cstr(actual_expense - budget_amount) + _(" after this transaction.")
|
||||
, raise_exception=BudgetError if action=="Stop" else False)
|
||||
|
||||
def get_allocated_budget(distribution_id, posting_date, fiscal_year, yearly_budget):
|
||||
if distribution_id:
|
||||
distribution = {}
|
||||
for d in webnotes.conn.sql("""select bdd.month, bdd.percentage_allocation
|
||||
from `tabBudget Distribution Detail` bdd, `tabBudget Distribution` bd
|
||||
where bdd.parent=bd.name and bd.fiscal_year=%s""", fiscal_year, as_dict=1):
|
||||
distribution.setdefault(d.month, d.percentage_allocation)
|
||||
print distribution
|
||||
dt = webnotes.conn.get_value("Fiscal Year", fiscal_year, "year_start_date")
|
||||
budget_percentage = 0.0
|
||||
|
||||
while(dt <= getdate(posting_date)):
|
||||
print dt, posting_date
|
||||
if distribution_id:
|
||||
print getdate(dt).month
|
||||
print distribution.get(getdate(dt).month)
|
||||
budget_percentage += distribution.get(getdate(dt).month, 0)
|
||||
else:
|
||||
budget_percentage += 100.0/12
|
||||
|
||||
dt = add_months(dt, 1)
|
||||
|
||||
return yearly_budget * budget_percentage / 100
|
||||
|
||||
def get_actual_expense(args):
|
||||
return webnotes.conn.sql("""
|
||||
select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))
|
||||
from `tabGL Entry`
|
||||
where account=%(account)s and cost_center=%(cost_center)s
|
||||
and posting_date<=%(month_end_date)s
|
||||
and fiscal_year=%(fiscal_year)s and company=%(company)s
|
||||
and fiscal_year=%(fiscal_year)s and company=%(company)s %(condition)s
|
||||
""", (args))[0][0]
|
@ -5,4 +5,7 @@ def execute():
|
||||
webnotes.reload_doc("stock", "report", "stock_ledger")
|
||||
|
||||
webnotes.conn.sql("""delete from `tabStock Ledger Entry`
|
||||
where ifnull(is_cancelled, 'No') = 'Yes'""")
|
||||
where ifnull(is_cancelled, 'No') = 'Yes'""")
|
||||
|
||||
webnotes.reload_doc("stock", "doctype", "gl_entry")
|
||||
webnotes.conn.sql("""delete from `tabGL Entry` where ifnull(is_cancelled, 'No') = 'Yes'""")
|
@ -260,4 +260,6 @@ patch_list = [
|
||||
"patches.august_2013.p06_deprecate_cancelled_sl_entry",
|
||||
"patches.august_2013.p06_fix_sle_against_stock_entry",
|
||||
"execute:webnotes.bean('Style Settings').save() #2013-08-20",
|
||||
"patches.august_2013.p06_deprecate_is_cancelled",
|
||||
"execute:webnotes.delete_doc('DocType', 'Budget Control')",
|
||||
]
|
Loading…
x
Reference in New Issue
Block a user