diff --git a/accounts/doctype/budget_control/README.md b/accounts/doctype/budget_control/README.md
deleted file mode 100644
index 28210156c0..0000000000
--- a/accounts/doctype/budget_control/README.md
+++ /dev/null
@@ -1 +0,0 @@
-Backend scripts for Budget Management.
\ No newline at end of file
diff --git a/accounts/doctype/budget_control/__init__.py b/accounts/doctype/budget_control/__init__.py
deleted file mode 100644
index baffc48825..0000000000
--- a/accounts/doctype/budget_control/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-from __future__ import unicode_literals
diff --git a/accounts/doctype/budget_control/budget_control.py b/accounts/doctype/budget_control/budget_control.py
deleted file mode 100644
index 0aa64c86fc..0000000000
--- a/accounts/doctype/budget_control/budget_control.py
+++ /dev/null
@@ -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 Account - "+cstr(acct)+" under Cost Center - "+ cstr(cost_center) + ""+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)
\ No newline at end of file
diff --git a/accounts/doctype/budget_control/budget_control.txt b/accounts/doctype/budget_control/budget_control.txt
deleted file mode 100644
index 13adf4b406..0000000000
--- a/accounts/doctype/budget_control/budget_control.txt
+++ /dev/null
@@ -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"
- }
-]
\ No newline at end of file
diff --git a/accounts/doctype/budget_detail/budget_detail.txt b/accounts/doctype/budget_detail/budget_detail.txt
index f16190d0bd..f53ff52e58 100644
--- a/accounts/doctype/budget_detail/budget_detail.txt
+++ b/accounts/doctype/budget_detail/budget_detail.txt
@@ -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
}
]
\ No newline at end of file
diff --git a/accounts/doctype/budget_distribution/test_budget_distribution.py b/accounts/doctype/budget_distribution/test_budget_distribution.py
index 7ac835db7d..629fd87530 100644
--- a/accounts/doctype/budget_distribution/test_budget_distribution.py
+++ b/accounts/doctype/budget_distribution/test_budget_distribution.py
@@ -1,4 +1,70 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
# License: GNU General Public License v3. See license.txt
-test_records = []
\ No newline at end of file
+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"
+ }]
+]
\ No newline at end of file
diff --git a/accounts/doctype/cost_center/test_cost_center.py b/accounts/doctype/cost_center/test_cost_center.py
index 7c63d7c5dd..056755e463 100644
--- a/accounts/doctype/cost_center/test_cost_center.py
+++ b/accounts/doctype/cost_center/test_cost_center.py
@@ -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"
}],
]
\ No newline at end of file
diff --git a/accounts/doctype/gl_entry/gl_entry.txt b/accounts/doctype/gl_entry/gl_entry.txt
index 2f20a350a4..90b2ed4aff 100644
--- a/accounts/doctype/gl_entry/gl_entry.txt
+++ b/accounts/doctype/gl_entry/gl_entry.txt
@@ -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",
diff --git a/accounts/doctype/journal_voucher/test_journal_voucher.py b/accounts/doctype/journal_voucher/test_journal_voucher.py
index 30e3ada60a..2065232efa 100644
--- a/accounts/doctype/journal_voucher/test_journal_voucher.py
+++ b/accounts/doctype/journal_voucher/test_journal_voucher.py
@@ -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 = [
[{
diff --git a/accounts/general_ledger.py b/accounts/general_ledger.py
index 4b7e4256f3..f2dc748a39 100644
--- a/accounts/general_ledger.py
+++ b/accounts/general_ledger.py
@@ -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
\ No newline at end of file
+ entry.get("against_voucher"))
\ No newline at end of file
diff --git a/accounts/utils.py b/accounts/utils.py
index d91c4db62e..4110c995e3 100644
--- a/accounts/utils.py
+++ b/accounts/utils.py
@@ -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]
\ No newline at end of file
diff --git a/patches/august_2013/p06_deprecate_cancelled_sl_entry.py b/patches/august_2013/p06_deprecate_is_cancelled.py
similarity index 57%
rename from patches/august_2013/p06_deprecate_cancelled_sl_entry.py
rename to patches/august_2013/p06_deprecate_is_cancelled.py
index abb9d6839e..693a1ae159 100644
--- a/patches/august_2013/p06_deprecate_cancelled_sl_entry.py
+++ b/patches/august_2013/p06_deprecate_is_cancelled.py
@@ -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'""")
\ No newline at end of file
+ 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'""")
\ No newline at end of file
diff --git a/patches/patch_list.py b/patches/patch_list.py
index 46a40ac807..8dd4c972bb 100644
--- a/patches/patch_list.py
+++ b/patches/patch_list.py
@@ -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')",
]
\ No newline at end of file