Redesigned budgets

This commit is contained in:
Nabin Hait 2016-05-18 12:22:42 +05:30
parent b9bc7d6df3
commit ca90963d5b
29 changed files with 501 additions and 745 deletions

View File

@ -15,7 +15,8 @@ frappe.ui.form.on('Budget', {
return {
filters: {
company: frm.doc.company,
report_type: "Profit and Loss"
report_type: "Profit and Loss",
is_group: 0
}
}
})

View File

@ -112,7 +112,7 @@
"unique": 0
},
{
"allow_on_submit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"default": "Stop",
@ -139,7 +139,7 @@
"unique": 0
},
{
"allow_on_submit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"default": "Warn",
@ -277,7 +277,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2016-05-16 13:12:10.439375",
"modified": "2016-05-16 15:00:40.233685",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Budget",

View File

@ -17,54 +17,80 @@ class Budget(Document):
def validate(self):
self.validate_duplicate()
self.validate_accounts()
def validate_duplicate(self):
existing_budget = frappe.db.get_value("Budget", {"cost_center": self.cost_center,
"fiscal_year": self.fiscal_year, "name": ["!=", self.name], "docstatus": ["!=", 2]})
"fiscal_year": self.fiscal_year, "company": self.company,
"name": ["!=", self.name], "docstatus": ["!=", 2]})
if existing_budget:
frappe.throw(_("Another Budget record {0} already exists against {1} for fiscal year {2}")
.format(existing_budget, self.cost_center, self.fiscal_year))
def validate_accounts(self):
account_list = []
for d in self.get('accounts'):
if d.account:
account_details = frappe.db.get_value("Account", d.account,
["is_group", "company", "report_type"], as_dict=1)
if account_details.is_group:
frappe.throw(_("Budget cannot be assigned against Group Account {0}").format(d.account))
elif account_details.company != self.company:
frappe.throw(_("Account {0} does not belongs to company {1}")
.format(d.account, self.company))
elif account_details.report_type != "Profit and Loss":
frappe.throw(_("Budget cannot be assigned against {0}, as it's not an Income or Expense account")
.format(d.account))
if d.account in account_list:
frappe.throw(_("Account {0} has been entered multiple times").format(d.account))
else:
account_list.append(d.account)
def validate_expense_against_budget(args):
args = frappe._dict(args)
if frappe.db.get_value("Account", {"name": args.account, "root_type": "Expense"}):
budget = frappe.db.sql("""
select ba.budget_amount, b.monthly_distribution,
b.action_if_annual_budget_exceeded, b.action_if_accumulated_monthly_budget_exceeded
from `tabBudget` b, `tabBudget Account` ba
where b.name=ba.parent and b.cost_center=%s and b.fiscal_year=%s and ba.account=%s
""", (args.cost_center, args.fiscal_year, args.account), as_dict=True)
cc_lft, cc_rgt = frappe.db.get_value("Cost Center", args.cost_center, ["lft", "rgt"])
budget_records = frappe.db.sql("""
select ba.budget_amount, b.monthly_distribution, b.cost_center,
b.action_if_annual_budget_exceeded, b.action_if_accumulated_monthly_budget_exceeded
from `tabBudget` b, `tabBudget Account` ba
where
b.name=ba.parent and b.fiscal_year=%s and ba.account=%s
and exists(select name from `tabCost Center` where lft<=%s and rgt>=%s and name=b.cost_center)
""", (args.fiscal_year, args.account, cc_lft, cc_rgt), as_dict=True)
for budget in budget_records:
if budget.budget_amount:
yearly_action = budget.action_if_annual_budget_exceeded
monthly_action = budget.action_if_accumulated_monthly_budget_exceeded
if budget and budget[0].budget_amount:
yearly_action = budget[0].action_if_annual_budget_exceeded
monthly_action = budget[0].action_if_accumulated_monthly_budget_exceeded
action_for = action = ""
if monthly_action in ["Stop", "Warn"]:
budget_amount = get_accumulated_monthly_budget(budget[0].monthly_distribution,
args.posting_date, args.fiscal_year, budget[0].budget_amount)
budget_amount = get_accumulated_monthly_budget(budget.monthly_distribution,
args.posting_date, args.fiscal_year, budget.budget_amount)
args["month_end_date"] = get_last_day(args.posting_date)
action_for, action = _("Accumulated Monthly"), monthly_action
compare_expense_with_budget(args, budget.cost_center,
budget_amount, _("Accumulated Monthly"), monthly_action)
elif yearly_action in ["Stop", "Warn"]:
budget_amount = flt(budget[0].budget_amount)
action_for, action = _("Annual"), yearly_action
if action_for:
actual_expense = get_actual_expense(args)
if actual_expense > budget_amount:
diff = actual_expense - budget_amount
msg = _("{0} Budget for Account {1} against Cost Center {2} is {3}. It will exceed by {4}").format(_(action_for), args.account, args.cost_center, budget_amount, diff)
if action=="Stop":
frappe.throw(msg, BudgetError)
else:
frappe.msgprint(msg)
compare_expense_with_budget(args, budget.cost_center,
flt(budget.budget_amount), _("Annual"), yearly_action)
def compare_expense_with_budget(args, cost_center, budget_amount, action_for, action):
actual_expense = get_actual_expense(args, cost_center)
if actual_expense > budget_amount:
diff = actual_expense - budget_amount
msg = _("{0} Budget for Account {1} against Cost Center {2} is {3}. It will exceed by {4}").format(_(action_for), args.account, cost_center, budget_amount, diff)
if action=="Stop":
frappe.throw(msg, BudgetError)
else:
frappe.msgprint(msg)
def get_accumulated_monthly_budget(monthly_distribution, posting_date, fiscal_year, annual_budget):
distribution = {}
@ -87,13 +113,20 @@ def get_accumulated_monthly_budget(monthly_distribution, posting_date, fiscal_ye
return annual_budget * accumulated_percentage / 100
def get_actual_expense(args):
args["condition"] = " and posting_date <= '%s'" % \
args.month_end_date if args.get("month_end_date") else ""
def get_actual_expense(args, cost_center):
lft_rgt = frappe.db.get_value("Cost Center", cost_center, ["lft", "rgt"], as_dict=1)
args.update(lft_rgt)
condition = " and gle.posting_date <= %(month_end_date)s" if args.get("month_end_date") else ""
return flt(frappe.db.sql("""
select sum(debit) - sum(credit)
from `tabGL Entry`
where account='%(account)s' and cost_center='%(cost_center)s'
and fiscal_year='%(fiscal_year)s' and company='%(company)s' and docstatus=1 %(condition)s
""" % (args))[0][0])
select sum(gle.debit) - sum(gle.credit)
from `tabGL Entry` gle
where gle.account=%(account)s
and exists(select name from `tabCost Center`
where lft>=%(lft)s and rgt<=%(rgt)s and name=gle.cost_center)
and gle.fiscal_year=%(fiscal_year)s
and gle.company=%(company)s
and gle.docstatus=1
{condition}
""".format(condition=condition), (args))[0][0])

View File

@ -5,8 +5,111 @@ from __future__ import unicode_literals
import frappe
import unittest
from erpnext.accounts.doctype.budget.budget import get_actual_expense, BudgetError
from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
# test_records = frappe.get_test_records('Budget')
class TestBudget(unittest.TestCase):
def test_monthly_budget_crossed_ignore(self):
budget = make_budget()
frappe.db.set_value("Budget", budget, "action_if_accumulated_monthly_budget_exceeded", "Ignore")
class TestBudget(unittest.TestCase):
pass
set_total_expense_zero("2013-02-28")
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", submit=True)
self.assertTrue(frappe.db.get_value("GL Entry",
{"voucher_type": "Journal Entry", "voucher_no": jv.name}))
def test_monthly_budget_crossed_stop(self):
budget = make_budget()
frappe.db.set_value("Budget", budget, "action_if_accumulated_monthly_budget_exceeded", "Stop")
set_total_expense_zero("2013-02-28")
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 40000, "_Test Cost Center - _TC")
self.assertRaises(BudgetError, jv.submit)
def test_yearly_budget_crossed_stop(self):
self.test_monthly_budget_crossed_ignore()
set_total_expense_zero("2013-02-28")
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 150000, "_Test Cost Center - _TC")
self.assertRaises(BudgetError, jv.submit)
def test_monthly_budget_on_cancellation(self):
budget = make_budget()
frappe.db.set_value("Budget", budget, "action_if_accumulated_monthly_budget_exceeded", "Ignore")
set_total_expense_zero("2013-02-28")
jv1 = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", submit=True)
self.assertTrue(frappe.db.get_value("GL Entry",
{"voucher_type": "Journal Entry", "voucher_no": jv1.name}))
jv2 = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", submit=True)
self.assertTrue(frappe.db.get_value("GL Entry",
{"voucher_type": "Journal Entry", "voucher_no": jv2.name}))
frappe.db.set_value("Budget", budget, "action_if_accumulated_monthly_budget_exceeded", "Stop")
self.assertRaises(BudgetError, jv1.cancel)
def test_monthly_budget_against_group_cost_center(self):
budget = make_budget("_Test Company - _TC")
frappe.db.set_value("Budget", budget, "action_if_accumulated_monthly_budget_exceeded", "Stop")
set_total_expense_zero("2013-02-28")
set_total_expense_zero("2013-02-28", "_Test Cost Center 2 - _TC")
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 40000, "_Test Cost Center 2 - _TC")
self.assertRaises(BudgetError, jv.submit)
def set_total_expense_zero(posting_date, cost_center=None):
existing_expense = get_actual_expense({
"account": "_Test Account Cost for Goods Sold - _TC",
"cost_center": cost_center or "_Test Cost Center - _TC",
"monthly_end_date": posting_date,
"company": "_Test Company",
"fiscal_year": "_Test Fiscal Year 2013"
}, cost_center or "_Test Cost Center - _TC")
make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", submit=True)
def make_budget(cost_center=None):
existing_budget = frappe.db.get_value("Budget",
{"cost_center": cost_center or "_Test Cost Center - _TC",
"fiscal_year": "_Test Fiscal Year 2013", "company": "_Test Company"})
if not existing_budget:
budget = frappe.new_doc("Budget")
budget.cost_center = cost_center or "_Test Cost Center - _TC"
budget.fiscal_year = "_Test Fiscal Year 2013"
budget.monthly_distribution = "_Test Distribution"
budget.company = "_Test Company"
budget.action_if_annual_budget_exceeded = "Stop"
budget.action_if_accumulated_monthly_budget_exceeded = "Stop"
budget.append("accounts", {
"account": "_Test Account Cost for Goods Sold - _TC",
"budget_amount": 100000
})
budget.insert()
budget.submit()
return budget.name
else:
return existing_budget

View File

@ -1 +0,0 @@
Budget amounts for year and distribution for parent Cost Center.

View File

@ -1 +0,0 @@
from __future__ import unicode_literals

View File

@ -1,106 +0,0 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "hash",
"creation": "2013-03-07 11:55:04",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 1,
"in_list_view": 1,
"label": "Account",
"length": 0,
"no_copy": 0,
"oldfieldname": "account",
"oldfieldtype": "Link",
"options": "Account",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 1,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "budget_allocated",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Budget Allocated",
"length": 0,
"no_copy": 0,
"oldfieldname": "budget_allocated",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "fiscal_year",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 1,
"in_list_view": 1,
"label": "Fiscal Year",
"length": 0,
"no_copy": 0,
"oldfieldname": "fiscal_year",
"oldfieldtype": "Select",
"options": "Fiscal Year",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 1,
"set_only_once": 0,
"unique": 0
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 1,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2015-11-16 06:29:43.050558",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Budget Detail",
"owner": "Administrator",
"permissions": [],
"read_only": 0,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC"
}

View File

@ -1,9 +0,0 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
class BudgetDetail(Document):
pass

View File

@ -5,36 +5,19 @@ frappe.provide("erpnext.accounts");
cur_frm.list_route = "Accounts Browser/Cost Center";
erpnext.accounts.CostCenterController = frappe.ui.form.Controller.extend({
onload: function() {
this.setup_queries();
},
setup_queries: function() {
var me = this;
if(this.frm.fields_dict["budgets"].grid.get_field("account")) {
this.frm.set_query("account", "budgets", function() {
return {
filters:[
['Account', 'company', '=', me.frm.doc.company],
['Account', 'is_group', '=', '0']
]
}
});
}
this.frm.set_query("parent_cost_center", function() {
frappe.ui.form.on('Cost Center', {
onload: function(frm) {
frm.set_query("parent_cost_center", function() {
return {
filters:[
['Cost Center', 'is_group', '=', '1'],
['Cost Center', 'company', '=', me.frm.doc.company],
]
filters: {
company: frm.doc.company,
is_group: 1
}
}
});
})
}
});
$.extend(cur_frm.cscript, new erpnext.accounts.CostCenterController({frm: cur_frm}));
})
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
var intro_txt = '';

View File

@ -3,6 +3,7 @@
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:cost_center_name",
"beta": 0,
"creation": "2013-01-23 19:57:17",
"custom": 0,
"description": "Track separate Income and Expense for product verticals or divisions.",
@ -164,87 +165,6 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"description": "Define Budget for this Cost Center. To set budget action, see \"Company List\"",
"fieldname": "sb1",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Budget",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"description": "Select Monthly Distribution, if you want to track based on seasonality.",
"fieldname": "distribution_id",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Distribution Id",
"length": 0,
"no_copy": 0,
"oldfieldname": "distribution_id",
"oldfieldtype": "Link",
"options": "Monthly Distribution",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"description": "Add rows to set annual budgets on Accounts.",
"fieldname": "budgets",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Budgets",
"length": 0,
"no_copy": 0,
"oldfieldname": "budget_details",
"oldfieldtype": "Table",
"options": "Budget Detail",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@ -336,7 +256,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2016-03-14 15:59:51.508268",
"modified": "2016-05-16 15:23:14.770933",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Cost Center",
@ -443,8 +363,11 @@
"write": 0
}
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"search_fields": "parent_cost_center, is_group",
"sort_order": "ASC",
"track_seen": 0,
"version": 0
}

View File

@ -16,36 +16,12 @@ class CostCenter(NestedSet):
def validate(self):
self.validate_mandatory()
self.validate_accounts()
def validate_mandatory(self):
if self.cost_center_name != self.company and not self.parent_cost_center:
frappe.throw(_("Please enter parent cost center"))
elif self.cost_center_name == self.company and self.parent_cost_center:
frappe.throw(_("Root cannot have a parent cost center"))
def validate_accounts(self):
if self.is_group==1 and self.get("budgets"):
frappe.throw(_("Budget cannot be set for Group Cost Center"))
check_acc_list = []
for d in self.get('budgets'):
if d.account:
account_details = frappe.db.get_value("Account", d.account,
["is_group", "company", "report_type"], as_dict=1)
if account_details.is_group:
frappe.throw(_("Budget cannot be assigned against Group Account {0}").format(d.account))
elif account_details.company != self.company:
frappe.throw(_("Account {0} does not belongs to company {1}").format(d.account, self.company))
elif account_details.report_type != "Profit and Loss":
frappe.throw(_("Budget cannot be assigned against {0}, as it's not an Income or Expense account")
.format(d.account))
if [d.account, d.fiscal_year] in check_acc_list:
frappe.throw(_("Account {0} has been entered more than once for fiscal year {1}")
.format(d.account, d.fiscal_year))
else:
check_acc_list.append([d.account, d.fiscal_year])
def convert_group_to_ledger(self):
if self.check_if_child_exists():

View File

@ -1,17 +1,7 @@
[
{
"budgets": [
{
"account": "_Test Account Cost for Goods Sold - _TC",
"budget_allocated": 100000,
"doctype": "Budget Detail",
"fiscal_year": "_Test Fiscal Year 2013",
"parentfield": "budgets"
}
],
"company": "_Test Company",
"cost_center_name": "_Test Cost Center",
"distribution_id": "_Test Distribution",
"doctype": "Cost Center",
"is_group": 0,
"parent_cost_center": "_Test Company - _TC"

View File

@ -4,7 +4,6 @@
from __future__ import unicode_literals
import unittest, frappe
from frappe.utils import flt
from erpnext.accounts.doctype.budget.budget import get_actual_expense, BudgetError, get_fiscal_year
from erpnext.exceptions import InvalidAccountCurrency
@ -96,78 +95,6 @@ class TestJournalEntry(unittest.TestCase):
set_perpetual_inventory(0)
def test_monthly_budget_crossed_ignore(self):
frappe.db.set_value("Company", "_Test Company", "monthly_bgt_flag", "Ignore")
self.set_total_expense_zero("2013-02-28")
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", submit=True)
self.assertTrue(frappe.db.get_value("GL Entry",
{"voucher_type": "Journal Entry", "voucher_no": jv.name}))
def test_monthly_budget_crossed_stop(self):
frappe.db.set_value("Company", "_Test Company", "monthly_bgt_flag", "Stop")
self.set_total_expense_zero("2013-02-28")
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 40000, "_Test Cost Center - _TC")
self.assertRaises(BudgetError, jv.submit)
frappe.db.set_value("Company", "_Test Company", "monthly_bgt_flag", "Ignore")
def test_yearly_budget_crossed_stop(self):
self.test_monthly_budget_crossed_ignore()
frappe.db.set_value("Company", "_Test Company", "yearly_bgt_flag", "Stop")
self.set_total_expense_zero("2013-02-28")
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 150000, "_Test Cost Center - _TC")
self.assertRaises(BudgetError, jv.submit)
frappe.db.set_value("Company", "_Test Company", "yearly_bgt_flag", "Ignore")
def test_monthly_budget_on_cancellation(self):
self.set_total_expense_zero("2013-02-28")
jv1 = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", submit=True)
self.assertTrue(frappe.db.get_value("GL Entry",
{"voucher_type": "Journal Entry", "voucher_no": jv1.name}))
jv2 = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", submit=True)
self.assertTrue(frappe.db.get_value("GL Entry",
{"voucher_type": "Journal Entry", "voucher_no": jv2.name}))
frappe.db.set_value("Company", "_Test Company", "monthly_bgt_flag", "Stop")
self.assertRaises(BudgetError, jv1.cancel)
frappe.db.set_value("Company", "_Test Company", "monthly_bgt_flag", "Ignore")
def get_actual_expense(self, monthly_end_date):
return get_actual_expense({
"account": "_Test Account Cost for Goods Sold - _TC",
"cost_center": "_Test Cost Center - _TC",
"monthly_end_date": monthly_end_date,
"company": "_Test Company",
"fiscal_year": get_fiscal_year(monthly_end_date)[0]
})
def set_total_expense_zero(self, posting_date):
existing_expense = self.get_actual_expense(posting_date)
make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", submit=True)
def test_multi_currency(self):
jv = make_journal_entry("_Test Bank USD - _TC",
"_Test Bank - _TC", 100, exchange_rate=50, save=False)

View File

@ -1,156 +1,159 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "field:distribution_id",
"creation": "2013-01-10 16:34:05",
"custom": 0,
"description": "**Monthly Distribution** helps you distribute your budget across months if you have seasonality in your business.\n\nTo distribute a budget using this distribution, set this **Monthly Distribution** in the **Cost Center**",
"docstatus": 0,
"doctype": "DocType",
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "field:distribution_id",
"beta": 0,
"creation": "2013-01-10 16:34:05",
"custom": 0,
"description": "**Monthly Distribution** helps you distribute the Budget/Target across months if you have seasonality in your business.",
"docstatus": 0,
"doctype": "DocType",
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"description": "Name of the Monthly Distribution",
"fieldname": "distribution_id",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Distribution Name",
"length": 0,
"no_copy": 0,
"oldfieldname": "distribution_id",
"oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"description": "Name of the Monthly Distribution",
"fieldname": "distribution_id",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Distribution Name",
"length": 0,
"no_copy": 0,
"oldfieldname": "distribution_id",
"oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "fiscal_year",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1,
"in_list_view": 1,
"label": "Fiscal Year",
"length": 0,
"no_copy": 0,
"oldfieldname": "fiscal_year",
"oldfieldtype": "Select",
"options": "Fiscal Year",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "fiscal_year",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1,
"in_list_view": 1,
"label": "Fiscal Year",
"length": 0,
"no_copy": 0,
"oldfieldname": "fiscal_year",
"oldfieldtype": "Select",
"options": "Fiscal Year",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
"unique": 0
},
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "percentages",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Monthly Distribution Percentages",
"length": 0,
"no_copy": 0,
"oldfieldname": "budget_distribution_details",
"oldfieldtype": "Table",
"options": "Monthly Distribution Percentage",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "percentages",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Monthly Distribution Percentages",
"length": 0,
"no_copy": 0,
"oldfieldname": "budget_distribution_details",
"oldfieldtype": "Table",
"options": "Monthly Distribution Percentage",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "icon-bar-chart",
"idx": 1,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2016-03-03 02:46:44.493857",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Monthly Distribution",
"name_case": "Title Case",
"owner": "Administrator",
],
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "icon-bar-chart",
"idx": 1,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2016-05-16 16:35:20.349194",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Monthly Distribution",
"name_case": "Title Case",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 0,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 2,
"print": 0,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 0,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 2,
"print": 0,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
}
],
"read_only": 0,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC"
}
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_seen": 0
}

View File

@ -8,7 +8,8 @@ frappe.query_reports["Budget Variance Report"] = {
label: __("Fiscal Year"),
fieldtype: "Link",
options: "Fiscal Year",
default: sys_defaults.fiscal_year
default: sys_defaults.fiscal_year,
reqd: 1
},
{
fieldname: "period",
@ -20,14 +21,16 @@ frappe.query_reports["Budget Variance Report"] = {
{ "value": "Half-Yearly", "label": __("Half-Yearly") },
{ "value": "Yearly", "label": __("Yearly") }
],
default: "Monthly"
default: "Monthly",
reqd: 1
},
{
fieldname: "company",
label: __("Company"),
fieldtype: "Link",
options: "Company",
default: frappe.defaults.get_user_default("Company")
},
default: frappe.defaults.get_user_default("Company"),
reqd: 1
}
]
}

View File

@ -3,48 +3,43 @@
from __future__ import unicode_literals
import frappe
from frappe import _, msgprint
from frappe import _
from frappe.utils import flt
from frappe.utils import formatdate
import time
from erpnext.accounts.utils import get_fiscal_year
from erpnext.controllers.trends import get_period_date_ranges, get_period_month_ranges
def execute(filters=None):
if not filters: filters = {}
columns = get_columns(filters)
cost_centers = get_cost_centers(filters.company)
period_month_ranges = get_period_month_ranges(filters["period"], filters["fiscal_year"])
cam_map = get_costcenter_account_month_map(filters)
cam_map = get_cost_center_account_month_map(filters)
data = []
for cost_center, cost_center_items in cam_map.items():
for account, monthwise_data in cost_center_items.items():
row = [cost_center, account]
totals = [0, 0, 0]
for relevant_months in period_month_ranges:
period_data = [0, 0, 0]
for month in relevant_months:
month_data = monthwise_data.get(month, {})
for i, fieldname in enumerate(["target", "actual", "variance"]):
value = flt(month_data.get(fieldname))
period_data[i] += value
totals[i] += value
period_data[2] = period_data[0] - period_data[1]
row += period_data
totals[2] = totals[0] - totals[1]
row += totals
data.append(row)
for cost_center in cost_centers:
cost_center_items = cam_map.get(cost_center)
if cost_center_items:
for account, monthwise_data in cost_center_items.items():
row = [cost_center, account]
totals = [0, 0, 0]
for relevant_months in period_month_ranges:
period_data = [0, 0, 0]
for month in relevant_months:
month_data = monthwise_data.get(month, {})
for i, fieldname in enumerate(["target", "actual", "variance"]):
value = flt(month_data.get(fieldname))
period_data[i] += value
totals[i] += value
period_data[2] = period_data[0] - period_data[1]
row += period_data
totals[2] = totals[0] - totals[1]
row += totals
data.append(row)
return columns, sorted(data, key=lambda x: (x[0], x[1]))
return columns, data
def get_columns(filters):
for fieldname in ["fiscal_year", "period", "company"]:
if not filters.get(fieldname):
label = (" ".join(fieldname.split("_"))).title()
msgprint(_("Please specify") + ": " + label,
raise_exception=True)
columns = [_("Cost Center") + ":Link/Cost Center:120", _("Account") + ":Link/Account:120"]
group_months = False if filters["period"] == "Monthly" else True
@ -52,7 +47,7 @@ def get_columns(filters):
for from_date, to_date in get_period_date_ranges(filters["period"], filters["fiscal_year"]):
for label in [_("Target") + " (%s)", _("Actual") + " (%s)", _("Variance") + " (%s)"]:
if group_months:
label = label % (formatdate(from_date, format_string="MMM") + " - " + formatdate(from_date, format_string="MMM"))
label = label % (formatdate(from_date, format_string="MMM") + " - " + formatdate(to_date, format_string="MMM"))
else:
label = label % formatdate(from_date, format_string="MMM")
@ -60,20 +55,21 @@ def get_columns(filters):
return columns + [_("Total Target") + ":Float:120", _("Total Actual") + ":Float:120",
_("Total Variance") + ":Float:120"]
def get_cost_centers(company):
return frappe.db.sql_list("select name from `tabCost Center` where company=%s order by lft", company)
#Get cost center & target details
def get_costcenter_target_details(filters):
return frappe.db.sql("""select cc.name, cc.distribution_id,
cc.parent_cost_center, bd.account, bd.budget_allocated
from `tabCost Center` cc, `tabBudget Detail` bd
where bd.parent=cc.name and bd.fiscal_year=%s and
cc.company=%s order by cc.name""" % ('%s', '%s'),
(filters.get("fiscal_year"), filters.get("company")), as_dict=1)
def get_cost_center_target_details(filters):
return frappe.db.sql("""
select b.cost_center, b.monthly_distribution, ba.account, ba.budget_amount
from `tabBudget` b, `tabBudget Account` ba
where b.name=ba.parent and b.fiscal_year=%s and b.company=%s
""", (filters.fiscal_year, filters.company), as_dict=True)
#Get target distribution details of accounts of cost center
def get_target_distribution_details(filters):
target_details = {}
for d in frappe.db.sql("""select md.name, mdp.month, mdp.percentage_allocation
from `tabMonthly Distribution Percentage` mdp, `tabMonthly Distribution` md
where mdp.parent=md.name and md.fiscal_year=%s""", (filters["fiscal_year"]), as_dict=1):
@ -82,45 +78,51 @@ def get_target_distribution_details(filters):
return target_details
#Get actual details from gl entry
def get_actual_details(filters):
def get_actual_details(cost_center, fiscal_year):
cc_lft, cc_rgt = frappe.db.get_value("Cost Center", cost_center, ["lft", "rgt"])
ac_details = frappe.db.sql("""select gl.account, gl.debit, gl.credit,
gl.cost_center, MONTHNAME(gl.posting_date) as month_name
from `tabGL Entry` gl, `tabBudget Detail` bd
where gl.fiscal_year=%s and company=%s
and bd.account=gl.account and bd.parent=gl.cost_center""" % ('%s', '%s'),
(filters.get("fiscal_year"), filters.get("company")), as_dict=1)
MONTHNAME(gl.posting_date) as month_name, b.cost_center
from `tabGL Entry` gl, `tabBudget Account` ba, `tabBudget` b
where
b.name = ba.parent
and ba.account=gl.account
and gl.fiscal_year=%s
and b.cost_center=%s
and exists(select name from `tabCost Center` where name=gl.cost_center and lft>=%s and rgt<=%s)
""", (fiscal_year, cost_center, cc_lft, cc_rgt), as_dict=1)
cc_actual_details = {}
for d in ac_details:
cc_actual_details.setdefault(d.cost_center, {}).setdefault(d.account, []).append(d)
cc_actual_details.setdefault(d.account, []).append(d)
return cc_actual_details
def get_costcenter_account_month_map(filters):
def get_cost_center_account_month_map(filters):
import datetime
costcenter_target_details = get_costcenter_target_details(filters)
cost_center_target_details = get_cost_center_target_details(filters)
tdd = get_target_distribution_details(filters)
actual_details = get_actual_details(filters)
cam_map = {}
for ccd in costcenter_target_details:
for ccd in cost_center_target_details:
actual_details = get_actual_details(ccd.cost_center, filters.fiscal_year)
for month_id in range(1, 13):
month = datetime.date(2013, month_id, 1).strftime('%B')
cam_map.setdefault(ccd.name, {}).setdefault(ccd.account, {})\
cam_map.setdefault(ccd.cost_center, {}).setdefault(ccd.account, {})\
.setdefault(month, frappe._dict({
"target": 0.0, "actual": 0.0
}))
tav_dict = cam_map[ccd.name][ccd.account][month]
tav_dict = cam_map[ccd.cost_center][ccd.account][month]
month_percentage = tdd.get(ccd.monthly_distribution, {}).get(month, 0) \
if ccd.monthly_distribution else 100.0/12
month_percentage = tdd.get(ccd.distribution_id, {}).get(month, 0) \
if ccd.distribution_id else 100.0/12
tav_dict.target = flt(ccd.budget_allocated) * month_percentage / 100
for ad in actual_details.get(ccd.name, {}).get(ccd.account, []):
tav_dict.target = flt(ccd.budget_amount) * month_percentage / 100
for ad in actual_details.get(ccd.account, []):
if ad.month_name == month:
tav_dict.actual += flt(ad.debit) - flt(ad.credit)

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

View File

@ -69,11 +69,11 @@ Since Project's Cost Center is updated in both sales and purchase entries, you c
#### 3.2 Projectwise Budgeting
If you have also define budgets in the Cost Center of a Project, you will get Budget Variance Report for a Cost Center of a Project.
You can define budgets against the Cost Center associated with a Project. At any point of time, you can refer Budget Variance Report to analysis the expense vs budget against a cost center.
To check Budget Variance report, go to:
`Accounts > Standard Reports > Budget Variance Report`
`Accounts > Budget and Cost Center > Budget Variance Report`
[Click here to learn how to do budgeting from Cost Center]({{docs_base_url}}/user/manual/en/accounts/budgeting.html).

View File

@ -1,45 +1,29 @@
ERPNext will help you set and manage budgets on your Cost Centers. This is
useful when, for example, you are doing online sales. You have a budget for
search ads, and you want ERPNext to stop or warn you from over spending, based
on that budget.
In ERPNext, you can set and manage budgets against a Cost Center. This is useful when, for example, you are doing online sales. You have a budget for search ads, and you want ERPNext to stop or warn you from over spending, based on that budget.
Budgets are also great for planning purposes. When you are making plans for
the next financial year, you would typically target a revenue based on which
you would set your expenses. Setting a budget will ensure that your expenses
do not get out of hand, at any point, as per your plans.
Budgets are also great for planning purposes. When you are making plans for the next financial year, you would typically target a revenue based on which you would set your expenses. Setting a budget will ensure that your expenses do not get out of hand, at any point, as per your plans.
You can define it in the Cost Center. If you have seasonal sales you can also
define a budget distribution that the budget will follow.
To allocate budget, go to:
In order to allocate budget, go to:
> Accounts > Budget and Cost Center > Budget
> Accounts > Setup > Chart of Cost Centers
In the Budget form, you can select a Cost Center and for that cost center you can define budgets against any Expense / Income accounts. Budgets can be defined against any Cost Center whether it is a Group / Leaf node in the Chart of Cost Centers.
and click on Chart of Cost Center. Select a Cost Center and click on Open.
<img class="screenshot" alt="Budget" src="{{docs_base_url}}/assets/img/accounts/budget.png">
#### Step 1: Click on Edit.
<img alt="Cost Center" class="screenshot" src="{{docs_base_url}}/assets/img/accounts/cost-center-1.gif">
#### Step 3:Add New Row and select budget account.
<img alt="Cost Center Account" class="screenshot" src="{{docs_base_url}}/assets/img/accounts/cost-center-2.png">
#### Step 3: Enter Monthly Distribution (optional)
<img alt="Cost Center" class="screenshot" src="{{docs_base_url}}/assets/img/accounts/cost-center-distribution.gif">
If you leave the** **distribution ID blank, ERPNext will calculate on a yearly
If you have seasonal business, you can also define a Monthly Distribution record, to distribute the budget between months. If you don't set the monthly distribution, ERPNext will calculate the budget on yearly
basis or in equal proportion for every month.
### To Create New Distribution ID
<img class="screenshot" alt="Monthly Distribution" src="{{docs_base_url}}/assets/img/accounts/monthly-distribution.png">
ERPNext allows you to take a few budget actions. It signifies whether to stop, warn or Ignore if you exceed budgets.
While setting budget, you can also define the actions when expenses will exceed the allocated budget for a period. You can set separate action for monthly and annual budgets. There are 3 types of actions: Stop, Warn and Ignore. If Stop, system will not allow to book expenses more than allocated budget. In Case of Warn, it will just warn the user that expenses has been exceeded from the allocated budget. And Ignore will do nothing.
These can be defined from the Company record.
<img alt="Cost Center" class="screenshot" src="{{docs_base_url}}/assets/img/accounts/cost-center-company.gif">
At any point of time, user can check Budget Variance Report to analysis the expense vs budget against a cost center.
Even if you choose to “ignore” budget overruns, you will get a wealth of information from the “Budget vs Actual” variance report. This report shows month wise actual expenses as compared to the budgeted expenses.
To check Budget Variance report, go to:
Accounts > Budget and Cost Center > Budget Variance Report
<img class="screenshot" alt="Budget Variance Report" src="{{docs_base_url}}/assets/img/accounts/budget-variance-report.png">
{next}

View File

@ -34,45 +34,4 @@ To setup your Chart of Cost Centers go to:
![Chart of Cost Center]({{docs_base_url}}/assets/old_images/erpnext/chart-of-cost-centers.png)
Cost centers help you in one more activity, budgeting.
### Budgeting
ERPNext will help you set and manage budgets on your Cost Centers. This is
useful when, for example, you are doing online sales. You have a budget for
search ads, and you want ERPNext to stop or warn you from over spending, based
on that budget.
Budgets are also great for planning purposes. When you are making plans for
the next financial year, you would typically target a revenue based on which
you would set your expenses. Setting a budget will ensure that your expenses
do not get out of hand, at any point, as per your plans.
You can define it in the Cost Center. If you have seasonal sales you can also
define a budget distribution that the budget will follow.
> Accounts > Setup > Budget Distribution > New Budget Distribution
![Budget Distribution]({{docs_base_url}}/assets/old_images/erpnext/budgeting.png)
#### Budget Actions
ERPNext allows you to either:
* Stop.
* Warn or,
* Ignore
if you exceed budgets.
These can be defined from the Company record.
Even if you choose to “ignore” budget overruns, you will get a wealth of
information from the “Budget vs Actual” variance report.
> Note: When you set a budget, it has to be set as per Account under the Cost
Center. For example if you have a Cost Center “Online Sales”, you can restrict
“Advertising Budget” by creating a row with that Account and defining the
amount.
{next}

View File

@ -20,7 +20,7 @@ In this table, you should select Item Group, Fiscal Year, Target Qty and Amount.
####1.3 Target Distribution
If you wish to spread allocated target across months, then you shoult setup Target Distribution master, and select it in the Sales Person master. Considering our example, target for the month of December will be set as 5 qty (10% of total allocation).
If you wish to spread allocated target across months, then you should setup Monthly Distribution master, and select it in the Sales Person master. Considering our example, target for the month of December will be set as 5 qty (10% of total allocation).
![Sales Person Target Distribution]({{docs_base_url}}/assets/old_images/erpnext/sales-person-target-distribution.png)
@ -52,11 +52,11 @@ In the Territory master, you will find field to select Territory Manager. This f
####2.2 Allocating Target
Allocation Target in the Territory master is same as in Sales Person master. You can follow same steps as given above to specify target in the Territory master as well.
Target Allocation in the Territory master is same as in Sales Person master. You can follow same steps as given above to specify target in the Territory master as well.
####2.3 Target Distribution
Using this master, you can divide target Qty or Amount across various months.
Using this Monthly Distribution document, you can divide target Qty or Amount across various months.
####2.4 Report - Territory Target Variance Item Groupwise
@ -68,15 +68,15 @@ This report will provide you variance between target and actual performance of S
###3. Target Distribution
Target Distribution master allows you to divide allocated target across multiple months. If your product and services is seasonal, you can distribute the sales target accordingly. For example, if you are into umbrella business, then target allocated in the monsoon seasion will be higher than in other months.
Target Distribution document allows you to divide allocated target across multiple months. If your product and services is seasonal, you can distribute the sales target accordingly. For example, if you are into umbrella business, then target allocated in the monsoon seasion will be higher than in other months.
To create new Budget Distriibution master, go to:
To create new Monthly Distriibution, go to:
`Accounts > Setup > Budget Distributon`
`Accounts > Monthly Distributon`
![Target Distribution]({{docs_base_url}}/assets/old_images/erpnext/target-distribution.png)
You can link target distribution while allocation targets in Sales Person as well as in Territory master.
You can link Monthly Distribution while allocating targets in Sales Person as well as in Territory master.
###See Also

View File

@ -264,4 +264,5 @@ erpnext.patches.v7_0.update_party_status
erpnext.patches.v7_0.update_item_projected
erpnext.patches.v7_0.fix_duplicate_icons
erpnext.patches.v7_0.remove_features_setup
erpnext.patches.v7_0.update_home_page
erpnext.patches.v7_0.update_home_page
erpnext.patches.v7_0.create_budget_record

View File

@ -86,9 +86,6 @@ rename_map = {
"Bank Reconciliation": [
["entries", "journal_entries"]
],
"Cost Center": [
["budget_details", "budgets"]
],
"C-Form": [
["invoice_details", "invoices"]
],

View File

@ -0,0 +1,46 @@
import frappe
def execute():
existing_budgets = frappe.db.sql("""
select
cc.name, cc.company, cc.distribution_id,
budget.account, budget.budget_allocated, budget.fiscal_year
from
`tabCost Center` cc, `tabBudget Detail` budget
where
cc.name=budget.parent
""", as_dict=1)
actions = {}
for d in frappe.db.sql("select name, yearly_bgt_flag, monthly_bgt_flag from tabCompany", as_dict=1):
actions.setdefault(d.name, d)
budget_records = []
for d in existing_budgets:
budget = frappe.db.get_value("Budget",
{"cost_center": d.name, "fiscal_year": d.fiscal_year, "company": d.company})
if not budget:
budget = frappe.new_doc("Budget")
budget.cost_center = d.name
budget.fiscal_year = d.fiscal_year
budget.monthly_distribution = d.distribution_id
budget.company = d.company
budget.action_if_annual_budget_exceeded = actions[d.company]["yearly_bgt_flag"]
budget.action_if_accumulated_monthly_budget_exceeded = actions[d.company]["monthly_bgt_flag"]
else:
budget = frappe.get_doc("Budget", budget)
budget.append("accounts", {
"account": d.account,
"budget_amount": d.budget_allocated
})
budget.insert()
budget_records.append(budget)
for budget in budget_records:
budget.submit()
if frappe.db.get_value("DocType", "Budget Detail"):
frappe.delete_doc("DocType", "Budget Detail")

View File

@ -3,6 +3,7 @@
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:company_name",
"beta": 0,
"creation": "2013-04-10 08:35:39",
"custom": 0,
"description": "Legal Entity / Subsidiary with a separate Chart of Accounts belonging to the Organization.",
@ -661,7 +662,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Cost Center",
"label": "Deafult Cost Center",
"length": 0,
"no_copy": 1,
"options": "Cost Center",
@ -675,59 +676,6 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "credit_days_based_on",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Credit Days Based On",
"length": 0,
"no_copy": 0,
"options": "\nFixed Days\nLast Day of the Next Month",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"depends_on": "eval:(!doc.__islocal && doc.credit_days_based_on=='Fixed Days')",
"fieldname": "credit_days",
"fieldtype": "Int",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Credit Days",
"length": 0,
"no_copy": 0,
"oldfieldname": "credit_days",
"oldfieldtype": "Int",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@ -784,21 +732,19 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"depends_on": "eval:!doc.__islocal",
"fieldname": "yearly_bgt_flag",
"fieldname": "credit_days_based_on",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "If Yearly Budget Exceeded (for expense account)",
"label": "Credit Days Based On",
"length": 0,
"no_copy": 0,
"oldfieldname": "yearly_bgt_flag",
"oldfieldtype": "Select",
"options": "\nWarn\nIgnore\nStop",
"options": "\nFixed Days\nLast Day of the Next Month",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
@ -812,20 +758,19 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"depends_on": "eval:!doc.__islocal",
"fieldname": "monthly_bgt_flag",
"fieldtype": "Select",
"depends_on": "eval:(!doc.__islocal && doc.credit_days_based_on=='Fixed Days')",
"fieldname": "credit_days",
"fieldtype": "Int",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "If Monthly Budget Exceeded (for expense account)",
"label": "Credit Days",
"length": 0,
"no_copy": 0,
"oldfieldname": "monthly_bgt_flag",
"oldfieldtype": "Select",
"options": "\nWarn\nIgnore\nStop",
"oldfieldname": "credit_days",
"oldfieldtype": "Int",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
@ -1387,7 +1332,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2016-03-10 04:34:43.440914",
"modified": "2016-05-16 15:24:47.178826",
"modified_by": "Administrator",
"module": "Setup",
"name": "Company",
@ -1534,7 +1479,9 @@
"write": 0
}
],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"sort_order": "ASC"
"sort_order": "ASC",
"track_seen": 0
}

View File

@ -194,17 +194,11 @@ class Company(Document):
rec = frappe.db.sql("SELECT name from `tabGL Entry` where company = %s", self.name)
if not rec:
# delete Account
frappe.db.sql("delete from `tabAccount` where company = %s", self.name)
# delete cost center child table - budget detail
frappe.db.sql("""delete bd.* from `tabBudget Detail` bd, `tabCost Center` cc
where bd.parent = cc.name and cc.company = %s""", self.name)
#delete cost center
frappe.db.sql("delete from `tabCost Center` WHERE company = %s", self.name)
# delete account from customer and supplier
frappe.db.sql("delete from `tabParty Account` where company=%s", self.name)
frappe.db.sql("""delete from `tabBudget Account` b
where exists(select name from tabBudget where name=b.parent and company = %s)""", self.name)
for doctype in ["Account", "Cost Center", "Budget", "Party Account"]:
frappe.db.sql("delete from `tab{0}` where company = %s".format(doctype), self.name)
if not frappe.db.get_value("Stock Ledger Entry", {"company": self.name}):
frappe.db.sql("""delete from `tabWarehouse` where company=%s""", self.name)

View File

@ -14,7 +14,8 @@ def delete_company_transactions(company_name):
doc = frappe.get_doc("Company", company_name)
if frappe.session.user != doc.owner:
frappe.throw(_("Transactions can only be deleted by the creator of the Company"), frappe.PermissionError)
frappe.throw(_("Transactions can only be deleted by the creator of the Company"),
frappe.PermissionError)
delete_bins(company_name)
delete_time_logs(company_name)
@ -22,7 +23,7 @@ def delete_company_transactions(company_name):
for doctype in frappe.db.sql_list("""select parent from
tabDocField where fieldtype='Link' and options='Company'"""):
if doctype not in ("Account", "Cost Center", "Warehouse", "Budget Detail",
if doctype not in ("Account", "Cost Center", "Warehouse", "Budget",
"Party Account", "Employee", "Sales Taxes and Charges Template",
"Purchase Taxes and Charges Template", "POS Profile", 'BOM'):
delete_for_doctype(doctype, company_name)