Merge branch 'master' of github.com:webnotes/erpnext into wsgi

Conflicts:
	accounts/doctype/account/account.py
	accounts/doctype/gl_entry/gl_entry.py
	accounts/doctype/period_closing_voucher/period_closing_voucher.py
	stock/doctype/delivery_note/delivery_note.py
	stock/doctype/landed_cost_wizard/landed_cost_wizard.py
	stock/doctype/purchase_receipt/purchase_receipt.py
	stock/doctype/stock_ledger/stock_ledger.py
	stock/doctype/warehouse/warehouse.py
	stock/stock_ledger.py
This commit is contained in:
Anand Doshi
2013-09-25 19:55:41 +05:30
242 changed files with 3879 additions and 3910 deletions

View File

@@ -18,12 +18,22 @@ cur_frm.cscript.refresh = function(doc, cdt, cdn) {
cur_frm.toggle_display('account_name', doc.__islocal);
// hide fields if group
cur_frm.toggle_display(['account_type', 'master_type', 'master_name', 'freeze_account',
cur_frm.toggle_display(['account_type', 'master_type', 'master_name',
'credit_days', 'credit_limit', 'tax_rate'], doc.group_or_ledger=='Ledger')
// disable fields
cur_frm.toggle_enable(['account_name', 'debit_or_credit', 'group_or_ledger',
'is_pl_account', 'company'], false);
if(doc.group_or_ledger=='Ledger') {
wn.model.with_doc("Accounts Settings", "Accounts Settings", function (name) {
var accounts_settings = wn.model.get_doc("Accounts Settings", name);
var display = accounts_settings["frozen_accounts_modifier"]
&& in_list(user_roles, accounts_settings["frozen_accounts_modifier"]);
cur_frm.toggle_display('freeze_account', display);
});
}
// read-only for root accounts
if(!doc.parent_account) {
@@ -32,10 +42,10 @@ cur_frm.cscript.refresh = function(doc, cdt, cdn) {
} else {
// credit days and type if customer or supplier
cur_frm.set_intro(null);
cur_frm.toggle_display(['credit_days', 'credit_limit', 'master_name'],
in_list(['Customer', 'Supplier'], doc.master_type));
// hide tax_rate
cur_frm.toggle_display(['credit_days', 'credit_limit'], in_list(['Customer', 'Supplier'],
doc.master_type));
cur_frm.cscript.master_type(doc, cdt, cdn);
cur_frm.cscript.account_type(doc, cdt, cdn);
// show / hide convert buttons
@@ -44,7 +54,10 @@ cur_frm.cscript.refresh = function(doc, cdt, cdn) {
}
cur_frm.cscript.master_type = function(doc, cdt, cdn) {
cur_frm.toggle_display(['credit_days', 'credit_limit', 'master_name'],
cur_frm.toggle_display(['credit_days', 'credit_limit'], in_list(['Customer', 'Supplier'],
doc.master_type));
cur_frm.toggle_display('master_name', doc.account_type=='Warehouse' ||
in_list(['Customer', 'Supplier'], doc.master_type));
}
@@ -58,10 +71,10 @@ cur_frm.add_fetch('parent_account', 'is_pl_account', 'is_pl_account');
// -----------------------------------------
cur_frm.cscript.account_type = function(doc, cdt, cdn) {
if(doc.group_or_ledger=='Ledger') {
cur_frm.toggle_display(['tax_rate'],
doc.account_type == 'Tax');
cur_frm.toggle_display(['master_type', 'master_name'],
cstr(doc.account_type)=='');
cur_frm.toggle_display(['tax_rate'], doc.account_type == 'Tax');
cur_frm.toggle_display('master_type', cstr(doc.account_type)=='');
cur_frm.toggle_display('master_name', doc.account_type=='Warehouse' ||
in_list(['Customer', 'Supplier'], doc.master_type));
}
}
@@ -109,11 +122,15 @@ cur_frm.cscript.convert_to_group = function(doc, cdt, cdn) {
}
cur_frm.fields_dict['master_name'].get_query = function(doc) {
if (doc.master_type) {
if (doc.master_type || doc.account_type=="Warehouse") {
var dt = doc.master_type || "Warehouse";
return {
doctype: doc.master_type,
doctype: dt,
query: "accounts.doctype.account.account.get_master_name",
filters: { "master_type": doc.master_type }
filters: {
"master_type": dt,
"company": doc.company
}
}
}
}

View File

@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import webnotes
from webnotes.utils import flt, fmt_money
from webnotes.utils import flt, fmt_money, cstr, cint
from webnotes import msgprint, _
get_value = webnotes.conn.get_value
@@ -15,13 +15,25 @@ class DocType:
self.nsm_parent_field = 'parent_account'
def autoname(self):
"""Append abbreviation to company on naming"""
self.doc.name = self.doc.account_name.strip() + ' - ' + \
webnotes.conn.get_value("Company", self.doc.company, "abbr")
def get_address(self):
address = webnotes.conn.get_value(self.doc.master_type, self.doc.master_name, "address")
return {'address': address}
return {
'address': webnotes.conn.get_value(self.doc.master_type,
self.doc.master_name, "address")
}
def validate(self):
self.validate_master_name()
self.validate_parent()
self.validate_duplicate_account()
self.validate_root_details()
self.validate_mandatory()
self.validate_frozen_accounts_modifier()
if not self.doc.parent_account:
self.doc.parent_account = ''
def validate_master_name(self):
"""Remind to add master name"""
@@ -70,6 +82,15 @@ class DocType:
if webnotes.conn.exists("Account", self.doc.name):
if not webnotes.conn.get_value("Account", self.doc.name, "parent_account"):
webnotes.msgprint("Root cannot be edited.", raise_exception=1)
def validate_frozen_accounts_modifier(self):
old_value = webnotes.conn.get_value("Account", self.doc.name, "freeze_account")
if old_value and old_value != self.doc.freeze_account:
frozen_accounts_modifier = webnotes.conn.get_value( 'Accounts Settings', None,
'frozen_accounts_modifier')
if not frozen_accounts_modifier or \
frozen_accounts_modifier not in webnotes.user.get_roles():
webnotes.throw(_("You are not authorized to set Frozen value"))
def convert_group_to_ledger(self):
if self.check_if_child_exists():
@@ -97,9 +118,7 @@ class DocType:
# Check if any previous balance exists
def check_gle_exists(self):
exists = webnotes.conn.sql("""select name from `tabGL Entry` where account = %s
and ifnull(is_cancelled, 'No') = 'No'""", self.doc.name)
return exists and exists[0][0] or ''
return webnotes.conn.get_value("GL Entry", {"account": self.doc.name})
def check_if_child_exists(self):
return webnotes.conn.sql("""select name from `tabAccount` where parent_account = %s
@@ -110,16 +129,25 @@ class DocType:
msgprint("Debit or Credit field is mandatory", raise_exception=1)
if not self.doc.is_pl_account:
msgprint("Is PL Account field is mandatory", raise_exception=1)
def validate(self):
self.validate_master_name()
self.validate_parent()
self.validate_duplicate_account()
self.validate_root_details()
self.validate_mandatory()
if not self.doc.parent_account:
self.doc.parent_account = ''
def validate_warehouse_account(self):
if not cint(webnotes.defaults.get_global_default("auto_accounting_for_stock")):
return
if self.doc.account_type == "Warehouse":
old_warehouse = cstr(webnotes.conn.get_value("Account", self.doc.name, "master_name"))
if old_warehouse != cstr(self.doc.master_name):
if old_warehouse:
self.validate_warehouse(old_warehouse)
if self.doc.master_name:
self.validate_warehouse(self.doc.master_name)
else:
webnotes.throw(_("Master Name is mandatory if account type is Warehouse"))
def validate_warehouse(self, warehouse):
if webnotes.conn.get_value("Stock Ledger Entry", {"warehouse": warehouse}):
webnotes.throw(_("Stock transactions exist against warehouse ") + warehouse +
_(" .You can not assign / modify / remove Master Name"))
def update_nsm_model(self):
"""update lft, rgt indices for nested set model"""
@@ -172,10 +200,6 @@ class DocType:
self.validate_trash()
self.update_nsm_model()
# delete all cancelled gl entry of this account
webnotes.conn.sql("""delete from `tabGL Entry` where account = %s and
ifnull(is_cancelled, 'No') = 'Yes'""", self.doc.name)
def on_rename(self, new, old, merge=False):
company_abbr = webnotes.conn.get_value("Company", self.doc.company, "abbr")
parts = new.split(" - ")
@@ -203,9 +227,11 @@ class DocType:
return " - ".join(parts)
def get_master_name(doctype, txt, searchfield, start, page_len, filters):
return webnotes.conn.sql("""select name from `tab%s` where %s like %s
conditions = (" and company='%s'"% filters["company"]) if doctype == "Warehouse" else ""
return webnotes.conn.sql("""select name from `tab%s` where %s like %s %s
order by name limit %s, %s""" %
(filters["master_type"], searchfield, "%s", "%s", "%s"),
(filters["master_type"], searchfield, "%s", conditions, "%s", "%s"),
("%%%s%%" % txt, start, page_len), as_list=1)
def get_parent_account(doctype, txt, searchfield, start, page_len, filters):

View File

@@ -2,7 +2,7 @@
{
"creation": "2013-01-30 12:49:46",
"docstatus": 0,
"modified": "2013-07-05 14:23:30",
"modified": "2013-09-24 11:22:18",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -23,7 +23,8 @@
"name": "__common__",
"parent": "Account",
"parentfield": "fields",
"parenttype": "DocType"
"parenttype": "DocType",
"permlevel": 0
},
{
"amend": 0,
@@ -45,14 +46,12 @@
"fieldname": "properties",
"fieldtype": "Section Break",
"label": "Account Details",
"oldfieldtype": "Section Break",
"permlevel": 0
"oldfieldtype": "Section Break"
},
{
"doctype": "DocField",
"fieldname": "column_break0",
"fieldtype": "Column Break",
"permlevel": 0,
"width": "50%"
},
{
@@ -64,7 +63,6 @@
"no_copy": 1,
"oldfieldname": "account_name",
"oldfieldtype": "Data",
"permlevel": 0,
"read_only": 1,
"reqd": 1,
"search_index": 1
@@ -77,7 +75,6 @@
"label": "Level",
"oldfieldname": "level",
"oldfieldtype": "Int",
"permlevel": 0,
"print_hide": 1,
"read_only": 1
},
@@ -91,7 +88,6 @@
"oldfieldname": "group_or_ledger",
"oldfieldtype": "Select",
"options": "\nLedger\nGroup",
"permlevel": 0,
"read_only": 1,
"reqd": 1,
"search_index": 1
@@ -104,7 +100,6 @@
"label": "Debit or Credit",
"oldfieldname": "debit_or_credit",
"oldfieldtype": "Data",
"permlevel": 0,
"read_only": 1,
"search_index": 1
},
@@ -117,7 +112,6 @@
"oldfieldname": "is_pl_account",
"oldfieldtype": "Select",
"options": "Yes\nNo",
"permlevel": 0,
"read_only": 1,
"search_index": 1
},
@@ -130,7 +124,6 @@
"oldfieldname": "company",
"oldfieldtype": "Link",
"options": "Company",
"permlevel": 0,
"read_only": 1,
"reqd": 1,
"search_index": 1
@@ -139,7 +132,6 @@
"doctype": "DocField",
"fieldname": "column_break1",
"fieldtype": "Column Break",
"permlevel": 0,
"width": "50%"
},
{
@@ -150,7 +142,6 @@
"oldfieldname": "parent_account",
"oldfieldtype": "Link",
"options": "Account",
"permlevel": 0,
"search_index": 1
},
{
@@ -162,7 +153,7 @@
"label": "Account Type",
"oldfieldname": "account_type",
"oldfieldtype": "Select",
"options": "\nFixed Asset Account\nBank or Cash\nExpense Account\nTax\nIncome Account\nChargeable",
"options": "\nFixed Asset Account\nBank or Cash\nExpense Account\nTax\nIncome Account\nChargeable\nWarehouse",
"permlevel": 0,
"search_index": 0
},
@@ -175,19 +166,17 @@
"label": "Rate",
"oldfieldname": "tax_rate",
"oldfieldtype": "Currency",
"permlevel": 0,
"reqd": 0
},
{
"description": "If the account is frozen, entries are allowed for the \"Account Manager\" only.",
"description": "If the account is frozen, entries are allowed to restricted users.",
"doctype": "DocField",
"fieldname": "freeze_account",
"fieldtype": "Select",
"label": "Frozen",
"oldfieldname": "freeze_account",
"oldfieldtype": "Select",
"options": "No\nYes",
"permlevel": 2
"options": "No\nYes"
},
{
"doctype": "DocField",
@@ -197,7 +186,6 @@
"label": "Credit Days",
"oldfieldname": "credit_days",
"oldfieldtype": "Int",
"permlevel": 0,
"print_hide": 1
},
{
@@ -209,7 +197,6 @@
"oldfieldname": "credit_limit",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"permlevel": 0,
"print_hide": 1
},
{
@@ -220,8 +207,7 @@
"label": "Master Type",
"oldfieldname": "master_type",
"oldfieldtype": "Select",
"options": "\nSupplier\nCustomer\nEmployee",
"permlevel": 0
"options": "\nSupplier\nCustomer\nEmployee"
},
{
"doctype": "DocField",
@@ -230,8 +216,7 @@
"label": "Master Name",
"oldfieldname": "master_name",
"oldfieldtype": "Link",
"options": "[Select]",
"permlevel": 0
"options": "[Select]"
},
{
"default": "1",
@@ -239,8 +224,7 @@
"doctype": "DocField",
"fieldname": "allow_negative_balance",
"fieldtype": "Check",
"label": "Allow Negative Balance",
"permlevel": 0
"label": "Allow Negative Balance"
},
{
"doctype": "DocField",
@@ -248,7 +232,6 @@
"fieldtype": "Int",
"hidden": 1,
"label": "Lft",
"permlevel": 0,
"print_hide": 1,
"read_only": 1
},
@@ -258,7 +241,6 @@
"fieldtype": "Int",
"hidden": 1,
"label": "Rgt",
"permlevel": 0,
"print_hide": 1,
"read_only": 1
},
@@ -268,7 +250,6 @@
"fieldtype": "Data",
"hidden": 1,
"label": "Old Parent",
"permlevel": 0,
"print_hide": 1,
"read_only": 1
},

View File

@@ -9,36 +9,38 @@ def make_test_records(verbose):
accounts = [
# [account_name, parent_account, group_or_ledger]
["_Test Account Bank Account", "Bank Accounts - _TC", "Ledger"],
["_Test Account Bank Account", "Bank Accounts", "Ledger"],
["_Test Account Stock Expenses", "Direct Expenses - _TC", "Group"],
["_Test Account Shipping Charges", "_Test Account Stock Expenses - _TC", "Ledger"],
["_Test Account Customs Duty", "_Test Account Stock Expenses - _TC", "Ledger"],
["_Test Account Stock Expenses", "Direct Expenses", "Group"],
["_Test Account Shipping Charges", "_Test Account Stock Expenses", "Ledger"],
["_Test Account Customs Duty", "_Test Account Stock Expenses", "Ledger"],
["_Test Account Tax Assets", "Current Assets - _TC", "Group"],
["_Test Account VAT", "_Test Account Tax Assets - _TC", "Ledger"],
["_Test Account Service Tax", "_Test Account Tax Assets - _TC", "Ledger"],
["_Test Account Tax Assets", "Current Assets", "Group"],
["_Test Account VAT", "_Test Account Tax Assets", "Ledger"],
["_Test Account Service Tax", "_Test Account Tax Assets", "Ledger"],
["_Test Account Reserves and Surplus", "Current Liabilities", "Ledger"],
["_Test Account Cost for Goods Sold", "Expenses - _TC", "Ledger"],
["_Test Account Excise Duty", "_Test Account Tax Assets - _TC", "Ledger"],
["_Test Account Education Cess", "_Test Account Tax Assets - _TC", "Ledger"],
["_Test Account S&H Education Cess", "_Test Account Tax Assets - _TC", "Ledger"],
["_Test Account CST", "Direct Expenses - _TC", "Ledger"],
["_Test Account Discount", "Direct Expenses - _TC", "Ledger"],
["_Test Account Cost for Goods Sold", "Expenses", "Ledger"],
["_Test Account Excise Duty", "_Test Account Tax Assets", "Ledger"],
["_Test Account Education Cess", "_Test Account Tax Assets", "Ledger"],
["_Test Account S&H Education Cess", "_Test Account Tax Assets", "Ledger"],
["_Test Account CST", "Direct Expenses", "Ledger"],
["_Test Account Discount", "Direct Expenses", "Ledger"],
# related to Account Inventory Integration
["_Test Account Stock In Hand", "Current Assets - _TC", "Ledger"],
["_Test Account Stock In Hand", "Current Assets", "Ledger"],
["_Test Account Fixed Assets", "Current Assets", "Ledger"],
]
test_objects = make_test_objects("Account", [[{
"doctype": "Account",
"account_name": account_name,
"parent_account": parent_account,
"company": "_Test Company",
"group_or_ledger": group_or_ledger
}] for account_name, parent_account, group_or_ledger in accounts])
webnotes.conn.set_value("Company", "_Test Company", "stock_in_hand_account",
"_Test Account Stock In Hand - _TC")
for company, abbr in [["_Test Company", "_TC"], ["_Test Company 1", "_TC1"]]:
test_objects = make_test_objects("Account", [[{
"doctype": "Account",
"account_name": account_name,
"parent_account": parent_account + " - " + abbr,
"company": company,
"group_or_ledger": group_or_ledger
}] for account_name, parent_account, group_or_ledger in accounts])
return test_objects

View File

@@ -5,23 +5,17 @@
from __future__ import unicode_literals
import webnotes
from webnotes.utils import cint
from webnotes.utils import cint, cstr
from webnotes import msgprint, _
class DocType:
def __init__(self, d, dl):
self.doc, self.doclist = d, dl
def validate(self):
self.make_adjustment_jv_for_auto_inventory()
def make_adjustment_jv_for_auto_inventory(self):
previous_auto_inventory_accounting = cint(webnotes.conn.get_value("Accounts Settings",
None, "auto_inventory_accounting"))
if cint(self.doc.auto_inventory_accounting) != previous_auto_inventory_accounting:
from accounts.utils import create_stock_in_hand_jv
create_stock_in_hand_jv(reverse = \
cint(self.doc.auto_inventory_accounting) < previous_auto_inventory_accounting)
def on_update(self):
for key in ["auto_inventory_accounting"]:
webnotes.conn.set_default(key, self.doc.fields.get(key, ''))
webnotes.conn.set_default("auto_accounting_for_stock", self.doc.auto_accounting_for_stock)
if self.doc.auto_accounting_for_stock:
for wh in webnotes.conn.sql("select name from `tabWarehouse`"):
wh_bean = webnotes.bean("Warehouse", wh[0])
wh_bean.save()

View File

@@ -2,7 +2,7 @@
{
"creation": "2013-06-24 15:49:57",
"docstatus": 0,
"modified": "2013-07-05 14:23:40",
"modified": "2013-09-24 11:52:58",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -39,11 +39,12 @@
"name": "Accounts Settings"
},
{
"default": "1",
"description": "If enabled, the system will post accounting entries for inventory automatically.",
"doctype": "DocField",
"fieldname": "auto_inventory_accounting",
"fieldname": "auto_accounting_for_stock",
"fieldtype": "Check",
"label": "Enable Auto Inventory Accounting"
"label": "Make Accounting Entry For Every Stock Movement"
},
{
"description": "Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.",
@@ -53,11 +54,19 @@
"label": "Accounts Frozen Upto"
},
{
"description": "Users with this role are allowed to do / modify accounting entry before frozen date",
"description": "Users with this role are allowed to create / modify accounting entry before frozen date",
"doctype": "DocField",
"fieldname": "bde_auth_role",
"fieldtype": "Link",
"label": "Allow Editing of Frozen Accounts For",
"label": "Allowed Role to Edit Entries Before Frozen Date",
"options": "Role"
},
{
"description": "Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts",
"doctype": "DocField",
"fieldname": "frozen_accounts_modifier",
"fieldtype": "Link",
"label": "Frozen Accounts Modifier",
"options": "Role"
},
{

View File

@@ -1 +0,0 @@
Backend scripts for Budget Management.

View File

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

View File

@@ -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)

View File

@@ -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"
}
]

View File

@@ -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
}
]

View File

@@ -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": "January",
"percentage_allocation": "8"
}, {
"doctype": "Budget Distribution Detail",
"parentfield": "budget_distribution_details",
"month": "February",
"percentage_allocation": "8"
}, {
"doctype": "Budget Distribution Detail",
"parentfield": "budget_distribution_details",
"month": "March",
"percentage_allocation": "8"
}, {
"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": "10"
}, {
"doctype": "Budget Distribution Detail",
"parentfield": "budget_distribution_details",
"month": "December",
"percentage_allocation": "10"
}]
]

View File

@@ -46,8 +46,7 @@ class DocType(DocTypeNestedSet):
return 1
def check_gle_exists(self):
return webnotes.conn.sql("select name from `tabGL Entry` where cost_center = %s and \
ifnull(is_cancelled, 'No') = 'No'", (self.doc.name))
return webnotes.conn.get_value("GL Entry", {"cost_center": self.doc.name})
def check_if_child_exists(self):
return webnotes.conn.sql("select name from `tabCost Center` where \

View File

@@ -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"
}],
]

View File

@@ -7,50 +7,49 @@ import webnotes
from webnotes.utils import flt, fmt_money, getdate
from webnotes.model.code import get_obj
from webnotes import msgprint, _
class DocType:
def __init__(self,d,dl):
self.doc, self.doclist = d, dl
def validate(self): # not called on cancel
def validate(self):
self.check_mandatory()
self.pl_must_have_cost_center()
self.validate_posting_date()
self.doc.is_cancelled = 'No' # will be reset by GL Control if cancelled
self.check_credit_limit()
self.check_pl_account()
def on_update(self, adv_adj, cancel, update_outstanding = 'Yes'):
self.validate_account_details(adv_adj)
self.validate_cost_center()
self.check_freezing_date(adv_adj)
self.check_negative_balance(adv_adj)
def on_update_with_args(self, adv_adj, update_outstanding = 'Yes'):
self.validate_account_details(adv_adj)
validate_frozen_account(self.doc.account, adv_adj)
check_freezing_date(self.doc.posting_date, adv_adj)
check_negative_balance(self.doc.account, adv_adj)
# Update outstanding amt on against voucher
if self.doc.against_voucher and self.doc.against_voucher_type != "POS" \
and update_outstanding == 'Yes':
self.update_outstanding_amt()
update_outstanding_amt(self.doc.account, self.doc.against_voucher_type,
self.doc.against_voucher)
def check_mandatory(self):
mandatory = ['account','remarks','voucher_type','voucher_no','fiscal_year','company']
for k in mandatory:
if not self.doc.fields.get(k):
msgprint(k + _(" is mandatory for GL Entry"), raise_exception=1)
webnotes.throw(k + _(" is mandatory for GL Entry"))
# Zero value transaction is not allowed
if not (flt(self.doc.debit) or flt(self.doc.credit)):
msgprint(_("GL Entry: Debit or Credit amount is mandatory for ") + self.doc.account,
raise_exception=1)
webnotes.throw(_("GL Entry: Debit or Credit amount is mandatory for ") +
self.doc.account)
def pl_must_have_cost_center(self):
if webnotes.conn.get_value("Account", self.doc.account, "is_pl_account") == "Yes":
if not self.doc.cost_center and self.doc.voucher_type != 'Period Closing Voucher':
msgprint(_("Cost Center must be specified for PL Account: ") + self.doc.account,
raise_exception=1)
else:
if self.doc.cost_center:
self.doc.cost_center = ""
webnotes.throw(_("Cost Center must be specified for PL Account: ") +
self.doc.account)
elif self.doc.cost_center:
self.doc.cost_center = None
def validate_posting_date(self):
from accounts.utils import validate_fiscal_year
@@ -64,7 +63,7 @@ class DocType:
if (self.doc.voucher_type=='Journal Voucher' or self.doc.voucher_type=='Sales Invoice') \
and (master_type =='Customer' and master_name):
dbcr = webnotes.conn.sql("""select sum(debit), sum(credit) from `tabGL Entry`
where account = '%s' and is_cancelled='No'""" % self.doc.account)
where account = %s""", self.doc.account)
if dbcr:
tot_outstanding = flt(dbcr[0][0]) - flt(dbcr[0][1]) + \
flt(self.doc.debit) - flt(self.doc.credit)
@@ -74,30 +73,23 @@ class DocType:
def check_pl_account(self):
if self.doc.is_opening=='Yes' and \
webnotes.conn.get_value("Account", self.doc.account, "is_pl_account") == "Yes":
msgprint(_("For opening balance entry account can not be a PL account"),
raise_exception=1)
webnotes.throw(_("For opening balance entry account can not be a PL account"))
def validate_account_details(self, adv_adj):
"""Account must be ledger, active and not freezed"""
ret = webnotes.conn.sql("""select group_or_ledger, docstatus, freeze_account, company
from tabAccount where name=%s""", self.doc.account, as_dict=1)
ret = webnotes.conn.sql("""select group_or_ledger, docstatus, company
from tabAccount where name=%s""", self.doc.account, as_dict=1)[0]
if ret and ret[0]["group_or_ledger"]=='Group':
msgprint(_("Account") + ": " + self.doc.account + _(" is not a ledger"), raise_exception=1)
if ret.group_or_ledger=='Group':
webnotes.throw(_("Account") + ": " + self.doc.account + _(" is not a ledger"))
if ret and ret[0]["docstatus"]==2:
msgprint(_("Account") + ": " + self.doc.account + _(" is not active"), raise_exception=1)
if ret.docstatus==2:
webnotes.throw(_("Account") + ": " + self.doc.account + _(" is not active"))
# Account has been freezed for other users except account manager
if ret and ret[0]["freeze_account"]== 'Yes' and not adv_adj \
and not 'Accounts Manager' in webnotes.user.get_roles():
msgprint(_("Account") + ": " + self.doc.account + _(" has been freezed. \
Only Accounts Manager can do transaction against this account"), raise_exception=1)
if self.doc.is_cancelled in ("No", None) and ret and ret[0]["company"] != self.doc.company:
msgprint(_("Account") + ": " + self.doc.account + _(" does not belong to the company") \
+ ": " + self.doc.company, raise_exception=1)
if ret.company != self.doc.company:
webnotes.throw(_("Account") + ": " + self.doc.account +
_(" does not belong to the company") + ": " + self.doc.company)
def validate_cost_center(self):
if not hasattr(self, "cost_center_company"):
@@ -105,70 +97,80 @@ class DocType:
def _get_cost_center_company():
if not self.cost_center_company.get(self.doc.cost_center):
self.cost_center_company[self.doc.cost_center] = webnotes.conn.get_value("Cost Center",
self.doc.cost_center, "company")
self.cost_center_company[self.doc.cost_center] = webnotes.conn.get_value(
"Cost Center", self.doc.cost_center, "company")
return self.cost_center_company[self.doc.cost_center]
if self.doc.is_cancelled in ("No", None) and \
self.doc.cost_center and _get_cost_center_company() != self.doc.company:
msgprint(_("Cost Center") + ": " + self.doc.cost_center \
+ _(" does not belong to the company") + ": " + self.doc.company, raise_exception=True)
def check_freezing_date(self, adv_adj):
"""
Nobody can do GL Entries where posting date is before freezing date
except authorized person
"""
if not adv_adj:
acc_frozen_upto = webnotes.conn.get_value('Accounts Settings', None, 'acc_frozen_upto')
if acc_frozen_upto:
bde_auth_role = webnotes.conn.get_value( 'Accounts Settings', None,'bde_auth_role')
if getdate(self.doc.posting_date) <= getdate(acc_frozen_upto) \
and not bde_auth_role in webnotes.user.get_roles():
msgprint(_("You are not authorized to do/modify back dated entries before ") +
getdate(acc_frozen_upto).strftime('%d-%m-%Y'), raise_exception=1)
if self.doc.cost_center and _get_cost_center_company() != self.doc.company:
webnotes.throw(_("Cost Center") + ": " + self.doc.cost_center +
_(" does not belong to the company") + ": " + self.doc.company)
def check_negative_balance(self, adv_adj):
if not adv_adj:
account = webnotes.conn.get_value("Account", self.doc.account,
["allow_negative_balance", "debit_or_credit"], as_dict=True)
if not account["allow_negative_balance"]:
balance = webnotes.conn.sql("""select sum(debit) - sum(credit) from `tabGL Entry`
where account = %s and ifnull(is_cancelled, 'No') = 'No'""", self.doc.account)
balance = account["debit_or_credit"] == "Debit" and \
flt(balance[0][0]) or -1*flt(balance[0][0])
if flt(balance) < 0:
msgprint(_("Negative balance is not allowed for account ") + self.doc.account,
raise_exception=1)
def check_negative_balance(account, adv_adj=False):
if not adv_adj:
account_details = webnotes.conn.get_value("Account", account,
["allow_negative_balance", "debit_or_credit"], as_dict=True)
if not account_details["allow_negative_balance"]:
balance = webnotes.conn.sql("""select sum(debit) - sum(credit) from `tabGL Entry`
where account = %s""", account)
balance = account_details["debit_or_credit"] == "Debit" and \
flt(balance[0][0]) or -1*flt(balance[0][0])
if flt(balance) < 0:
webnotes.throw(_("Negative balance is not allowed for account ") + account)
def update_outstanding_amt(self):
# get final outstanding amt
bal = flt(webnotes.conn.sql("""select sum(debit) - sum(credit) from `tabGL Entry`
where against_voucher=%s and against_voucher_type=%s and account = %s
and ifnull(is_cancelled,'No') = 'No'""", (self.doc.against_voucher,
self.doc.against_voucher_type, self.doc.account))[0][0] or 0.0)
def check_freezing_date(posting_date, adv_adj=False):
"""
Nobody can do GL Entries where posting date is before freezing date
except authorized person
"""
if not adv_adj:
acc_frozen_upto = webnotes.conn.get_value('Accounts Settings', None, 'acc_frozen_upto')
if acc_frozen_upto:
bde_auth_role = webnotes.conn.get_value( 'Accounts Settings', None,'bde_auth_role')
if getdate(posting_date) <= getdate(acc_frozen_upto) \
and not bde_auth_role in webnotes.user.get_roles():
webnotes.throw(_("You are not authorized to do/modify back dated entries before ")
+ getdate(acc_frozen_upto).strftime('%d-%m-%Y'))
if self.doc.against_voucher_type == 'Purchase Invoice':
def update_outstanding_amt(account, against_voucher_type, against_voucher, on_cancel=False):
# get final outstanding amt
bal = flt(webnotes.conn.sql("""select sum(debit) - sum(credit) from `tabGL Entry`
where against_voucher_type=%s and against_voucher=%s and account = %s""",
(against_voucher_type, against_voucher, account))[0][0] or 0.0)
if against_voucher_type == 'Purchase Invoice':
bal = -bal
elif against_voucher_type == "Journal Voucher":
against_voucher_amount = flt(webnotes.conn.sql("""select sum(debit) - sum(credit)
from `tabGL Entry` where voucher_type = 'Journal Voucher' and voucher_no = %s
and account = %s""", (against_voucher, account))[0][0])
bal = against_voucher_amount + bal
if against_voucher_amount < 0:
bal = -bal
elif self.doc.against_voucher_type == "Journal Voucher":
against_voucher_amount = flt(webnotes.conn.sql("""select sum(debit) - sum(credit)
from `tabGL Entry` where voucher_type = 'Journal Voucher' and voucher_no = %s
and account = %s""", (self.doc.against_voucher, self.doc.account))[0][0])
# Validation : Outstanding can not be negative
if bal < 0 and not on_cancel:
webnotes.throw(_("Outstanding for Voucher ") + against_voucher + _(" will become ") +
fmt_money(bal) + _(". Outstanding cannot be less than zero. \
Please match exact outstanding."))
# Update outstanding amt on against voucher
if against_voucher_type in ["Sales Invoice", "Purchase Invoice"]:
webnotes.conn.sql("update `tab%s` set outstanding_amount=%s where name='%s'" %
(against_voucher_type, bal, against_voucher))
bal = against_voucher_amount + bal
if against_voucher_amount < 0:
bal = -bal
# Validation : Outstanding can not be negative
if bal < 0 and self.doc.is_cancelled == 'No':
msgprint(_("Outstanding for Voucher ") + self.doc.against_voucher +
_(" will become ") + fmt_money(bal) + _(". Outstanding cannot be less than zero. \
Please match exact outstanding."), raise_exception=1)
# Update outstanding amt on against voucher
if self.doc.against_voucher_type in ["Sales Invoice", "Purchase Invoice"]:
webnotes.conn.sql("update `tab%s` set outstanding_amount=%s where name='%s'"%
(self.doc.against_voucher_type, bal, self.doc.against_voucher))
def validate_frozen_account(account, adv_adj):
frozen_account = webnotes.conn.get_value("Account", account, "freeze_account")
if frozen_account == 'Yes' and not adv_adj:
frozen_accounts_modifier = webnotes.conn.get_value( 'Accounts Settings', None,
'frozen_accounts_modifier')
if not frozen_accounts_modifier:
webnotes.throw(account + _(" is a frozen account. \
Either make the account active or assign role in Accounts Settings \
who can create / modify entries against this account"))
elif frozen_accounts_modifier not in webnotes.user.get_roles():
webnotes.throw(account + _(" is a frozen account. ") +
_("To create / edit transactions against this account, you need role") + ": " +
frozen_accounts_modifier)

View File

@@ -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",

View File

@@ -7,7 +7,7 @@ import webnotes
from webnotes.utils import cint, cstr, flt, fmt_money, formatdate, getdate
from webnotes.model.doc import addchild
from webnotes.model.bean import getlist
from webnotes import msgprint
from webnotes import msgprint, _
from setup.utils import get_company_currency
from controllers.accounts_controller import AccountsController
@@ -49,7 +49,7 @@ class DocType(AccountsController):
from accounts.utils import remove_against_link_from_jv
remove_against_link_from_jv(self.doc.doctype, self.doc.name, "against_jv")
self.make_gl_entries(cancel=1)
self.make_gl_entries(1)
def on_trash(self):
pass
@@ -255,7 +255,7 @@ class DocType(AccountsController):
"against_voucher": d.against_voucher or d.against_invoice or d.against_jv,
"remarks": self.doc.remark,
"cost_center": d.cost_center
}, cancel)
})
)
if gl_map:
make_gl_entries(gl_map, cancel=cancel, adv_adj=adv_adj)

View File

@@ -8,6 +8,7 @@ import webnotes
class TestJournalVoucher(unittest.TestCase):
def test_journal_voucher_with_against_jv(self):
self.clear_account_balance()
jv_invoice = webnotes.bean(copy=test_records[2])
jv_invoice.insert()
jv_invoice.submit()
@@ -31,6 +32,101 @@ 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_jv_against_stock_account(self):
from stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
set_perpetual_inventory()
jv = webnotes.bean(copy=test_records[0])
jv.doclist[1].account = "_Test Warehouse - _TC"
jv.insert()
from accounts.general_ledger import StockAccountInvalidTransaction
self.assertRaises(StockAccountInvalidTransaction, jv.submit)
set_perpetual_inventory(0)
def test_monthly_budget_crossed_ignore(self):
webnotes.conn.set_value("Company", "_Test Company", "monthly_bgt_flag", "Ignore")
self.clear_account_balance()
jv = webnotes.bean(copy=test_records[0])
jv.doclist[2].account = "_Test Account Cost for Goods Sold - _TC"
jv.doclist[2].cost_center = "_Test Cost Center - _TC"
jv.doclist[2].debit = 20000.0
jv.doclist[1].credit = 20000.0
jv.insert()
jv.submit()
self.assertTrue(webnotes.conn.get_value("GL Entry",
{"voucher_type": "Journal Voucher", "voucher_no": jv.doc.name}))
def test_monthly_budget_crossed_stop(self):
from accounts.utils import BudgetError
webnotes.conn.set_value("Company", "_Test Company", "monthly_bgt_flag", "Stop")
self.clear_account_balance()
jv = webnotes.bean(copy=test_records[0])
jv.doclist[2].account = "_Test Account Cost for Goods Sold - _TC"
jv.doclist[2].cost_center = "_Test Cost Center - _TC"
jv.doclist[2].debit = 20000.0
jv.doclist[1].credit = 20000.0
jv.insert()
self.assertRaises(BudgetError, jv.submit)
webnotes.conn.set_value("Company", "_Test Company", "monthly_bgt_flag", "Ignore")
def test_yearly_budget_crossed_stop(self):
from accounts.utils import BudgetError
self.clear_account_balance()
self.test_monthly_budget_crossed_ignore()
webnotes.conn.set_value("Company", "_Test Company", "yearly_bgt_flag", "Stop")
jv = webnotes.bean(copy=test_records[0])
jv.doc.posting_date = "2013-08-12"
jv.doclist[2].account = "_Test Account Cost for Goods Sold - _TC"
jv.doclist[2].cost_center = "_Test Cost Center - _TC"
jv.doclist[2].debit = 150000.0
jv.doclist[1].credit = 150000.0
jv.insert()
self.assertRaises(BudgetError, jv.submit)
webnotes.conn.set_value("Company", "_Test Company", "yearly_bgt_flag", "Ignore")
def test_monthly_budget_on_cancellation(self):
from accounts.utils import BudgetError
webnotes.conn.set_value("Company", "_Test Company", "monthly_bgt_flag", "Stop")
self.clear_account_balance()
jv = webnotes.bean(copy=test_records[0])
jv.doclist[1].account = "_Test Account Cost for Goods Sold - _TC"
jv.doclist[1].cost_center = "_Test Cost Center - _TC"
jv.doclist[1].credit = 30000.0
jv.doclist[2].debit = 30000.0
jv.submit()
self.assertTrue(webnotes.conn.get_value("GL Entry",
{"voucher_type": "Journal Voucher", "voucher_no": jv.doc.name}))
jv1 = webnotes.bean(copy=test_records[0])
jv1.doclist[2].account = "_Test Account Cost for Goods Sold - _TC"
jv1.doclist[2].cost_center = "_Test Cost Center - _TC"
jv1.doclist[2].debit = 40000.0
jv1.doclist[1].credit = 40000.0
jv1.submit()
self.assertTrue(webnotes.conn.get_value("GL Entry",
{"voucher_type": "Journal Voucher", "voucher_no": jv1.doc.name}))
self.assertRaises(BudgetError, jv.cancel)
webnotes.conn.set_value("Company", "_Test Company", "monthly_bgt_flag", "Ignore")
def clear_account_balance(self):
webnotes.conn.sql("""delete from `tabGL Entry`""")
test_records = [
[{

View File

@@ -21,7 +21,7 @@ class DocType:
def get_voucher_details(self):
total_amount = webnotes.conn.sql("""select sum(%s) from `tabGL Entry`
where voucher_type = %s and voucher_no = %s
and account = %s and ifnull(is_cancelled, 'No') = 'No'""" %
and account = %s""" %
(self.doc.account_type, '%s', '%s', '%s'),
(self.doc.voucher_type, self.doc.voucher_no, self.doc.account))
@@ -29,7 +29,7 @@ class DocType:
reconciled_payment = webnotes.conn.sql("""
select sum(ifnull(%s, 0)) - sum(ifnull(%s, 0)) from `tabGL Entry` where
against_voucher = %s and voucher_no != %s
and account = %s and ifnull(is_cancelled, 'No') = 'No'""" %
and account = %s""" %
((self.doc.account_type == 'debit' and 'credit' or 'debit'), self.doc.account_type,
'%s', '%s', '%s'), (self.doc.voucher_no, self.doc.voucher_no, self.doc.account))
@@ -135,7 +135,6 @@ def gl_entry_details(doctype, txt, searchfield, start, page_len, filters):
where gle.account = '%(acc)s'
and gle.voucher_type = '%(dt)s'
and gle.voucher_no like '%(txt)s'
and ifnull(gle.is_cancelled, 'No') = 'No'
and (ifnull(gle.against_voucher, '') = ''
or ifnull(gle.against_voucher, '') = gle.voucher_no )
and ifnull(gle.%(account_type)s, 0) > 0
@@ -143,8 +142,7 @@ def gl_entry_details(doctype, txt, searchfield, start, page_len, filters):
from `tabGL Entry`
where against_voucher_type = '%(dt)s'
and against_voucher = gle.voucher_no
and voucher_no != gle.voucher_no
and ifnull(is_cancelled, 'No') = 'No')
and voucher_no != gle.voucher_no)
!= abs(ifnull(gle.debit, 0) - ifnull(gle.credit, 0)
)
%(mcond)s

View File

@@ -3,178 +3,101 @@
from __future__ import unicode_literals
import webnotes
from webnotes.utils import cstr, flt, getdate
from webnotes.model import db_exists
from webnotes.model.doc import Document
from webnotes.model.bean import copy_doclist
from webnotes.model.code import get_obj
from webnotes import msgprint
from webnotes import msgprint, _
from controllers.accounts_controller import AccountsController
class DocType:
class DocType(AccountsController):
def __init__(self,d,dl):
self.doc, self.doclist = d, dl
self.td, self.tc = 0, 0
self.year_start_date = ''
self.year_end_date = ''
def validate(self):
self.validate_account_head()
self.validate_posting_date()
self.validate_pl_balances()
def on_submit(self):
self.make_gl_entries()
def on_cancel(self):
webnotes.conn.sql("""delete from `tabGL Entry`
where voucher_type = 'Period Closing Voucher' and voucher_no=%s""", self.doc.name)
def validate_account_head(self):
acc_det = webnotes.conn.sql("select debit_or_credit, is_pl_account, group_or_ledger, company \
from `tabAccount` where name = '%s'" % (self.doc.closing_account_head))
# Account should be under liability
if cstr(acc_det[0][0]) != 'Credit' or cstr(acc_det[0][1]) != 'No':
msgprint("Account: %s must be created under 'Source of Funds'" % self.doc.closing_account_head)
raise Exception
# Account must be a ledger
if cstr(acc_det[0][2]) != 'Ledger':
msgprint("Account %s must be a ledger" % self.doc.closing_account_head)
raise Exception
# Account should belong to company selected
if cstr(acc_det[0][3]) != self.doc.company:
msgprint("Account %s does not belong to Company %s ." % (self.doc.closing_account_head, self.doc.company))
raise Exception
debit_or_credit, is_pl_account = webnotes.conn.get_value("Account",
self.doc.closing_account_head, ["debit_or_credit", "is_pl_account"])
if debit_or_credit != 'Credit' or is_pl_account != 'No':
webnotes.throw(_("Account") + ": " + self.doc.closing_account_head +
_("must be a Liability account"))
def validate_posting_date(self):
yr = webnotes.conn.sql("""select year_start_date, adddate(year_start_date, interval 1 year)
from `tabFiscal Year` where name=%s""", (self.doc.fiscal_year, ))
self.year_start_date = yr and yr[0][0] or ''
self.year_end_date = yr and yr[0][1] or ''
# Posting Date should be within closing year
if getdate(self.doc.posting_date) < getdate(self.year_start_date) or getdate(self.doc.posting_date) > getdate(self.year_end_date):
msgprint("Posting Date should be within Closing Fiscal Year")
raise Exception
from accounts.utils import get_fiscal_year
self.year_start_date = get_fiscal_year(self.doc.posting_date)[1]
# Period Closing Entry
pce = webnotes.conn.sql("select name from `tabPeriod Closing Voucher` \
where posting_date > '%s' and fiscal_year = '%s' and docstatus = 1" \
% (self.doc.posting_date, self.doc.fiscal_year))
pce = webnotes.conn.sql("""select name from `tabPeriod Closing Voucher`
where posting_date > %s and fiscal_year = %s and docstatus = 1""",
(self.doc.posting_date, self.doc.fiscal_year))
if pce and pce[0][0]:
msgprint("Another Period Closing Entry: %s has been made after posting date: %s"\
% (cstr(pce[0][0]), self.doc.posting_date))
raise Exception
webnotes.throw(_("Another Period Closing Entry") + ": " + cstr(pce[0][0]) +
_("has been made after posting date") + ": " + self.doc.posting_date)
def validate_pl_balances(self):
income_bal = webnotes.conn.sql("select sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) \
from `tabGL Entry` t1, tabAccount t2 where t1.account = t2.name \
and t1.posting_date between '%s' and '%s' and t2.debit_or_credit = 'Credit' \
and t2.group_or_ledger = 'Ledger' and t2.is_pl_account = 'Yes' and t2.docstatus < 2 \
and t2.company = '%s'" % (self.year_start_date, self.doc.posting_date, self.doc.company))
income_bal = webnotes.conn.sql("""
select sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0))
from `tabGL Entry` t1, tabAccount t2
where t1.account = t2.name and t1.posting_date between %s and %s
and t2.debit_or_credit = 'Credit' and t2.is_pl_account = 'Yes'
and t2.docstatus < 2 and t2.company = %s""",
(self.year_start_date, self.doc.posting_date, self.doc.company))
expense_bal = webnotes.conn.sql("select sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) \
from `tabGL Entry` t1, tabAccount t2 where t1.account = t2.name \
and t1.posting_date between '%s' and '%s' and t2.debit_or_credit = 'Debit' \
and t2.group_or_ledger = 'Ledger' and t2.is_pl_account = 'Yes' and t2.docstatus < 2 \
and t2.company = '%s'" % (self.year_start_date, self.doc.posting_date, self.doc.company))
expense_bal = webnotes.conn.sql("""
select sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0))
from `tabGL Entry` t1, tabAccount t2
where t1.account = t2.name and t1.posting_date between %s and %s
and t2.debit_or_credit = 'Debit' and t2.is_pl_account = 'Yes'
and t2.docstatus < 2 and t2.company=%s""",
(self.year_start_date, self.doc.posting_date, self.doc.company))
income_bal = income_bal and income_bal[0][0] or 0
expense_bal = expense_bal and expense_bal[0][0] or 0
if not income_bal and not expense_bal:
msgprint("Both Income and Expense balances are zero. No Need to make Period Closing Entry.")
raise Exception
webnotes.throw(_("Both Income and Expense balances are zero. \
No Need to make Period Closing Entry."))
def get_pl_balances(self, d_or_c):
"""Get account (pl) specific balance"""
acc_bal = webnotes.conn.sql("select t1.account, sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) \
from `tabGL Entry` t1, `tabAccount` t2 where t1.account = t2.name and t2.group_or_ledger = 'Ledger' \
and ifnull(t2.is_pl_account, 'No') = 'Yes' and ifnull(is_cancelled, 'No') = 'No' \
and t2.debit_or_credit = '%s' and t2.docstatus < 2 and t2.company = '%s' \
and t1.posting_date between '%s' and '%s' group by t1.account " \
% (d_or_c, self.doc.company, self.year_start_date, self.doc.posting_date))
return acc_bal
def get_pl_balances(self):
"""Get balance for pl accounts"""
return webnotes.conn.sql("""
select t1.account, sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) as balance
from `tabGL Entry` t1, `tabAccount` t2
where t1.account = t2.name and ifnull(t2.is_pl_account, 'No') = 'Yes'
and t2.docstatus < 2 and t2.company = %s
and t1.posting_date between %s and %s
group by t1.account
""", (self.doc.company, self.year_start_date, self.doc.posting_date), as_dict=1)
def make_gl_entries(self, acc_det):
for a in acc_det:
if flt(a[1]):
fdict = {
'account': a[0],
'cost_center': '',
'against': '',
'debit': flt(a[1]) < 0 and -1*flt(a[1]) or 0,
'credit': flt(a[1]) > 0 and flt(a[1]) or 0,
'remarks': self.doc.remarks,
'voucher_type': self.doc.doctype,
'voucher_no': self.doc.name,
'transaction_date': self.doc.transaction_date,
'posting_date': self.doc.posting_date,
'fiscal_year': self.doc.fiscal_year,
'against_voucher': '',
'against_voucher_type': '',
'company': self.doc.company,
'is_opening': 'No',
'aging_date': self.doc.posting_date
}
def make_gl_entries(self):
gl_entries = []
net_pl_balance = 0
pl_accounts = self.get_pl_balances()
for acc in pl_accounts:
if flt(acc.balance):
gl_entries.append(self.get_gl_dict({
"account": acc.account,
"debit": abs(flt(acc.balance)) if flt(acc.balance) < 0 else 0,
"credit": abs(flt(acc.balance)) if flt(acc.balance) > 0 else 0,
}))
self.save_entry(fdict)
net_pl_balance += flt(acc.balance)
def save_entry(self, fdict, is_cancel = 'No'):
# Create new GL entry object and map values
le = Document('GL Entry')
for k in fdict:
le.fields[k] = fdict[k]
le_obj = get_obj(doc=le)
# validate except on_cancel
if is_cancel == 'No':
le_obj.validate()
if net_pl_balance:
gl_entries.append(self.get_gl_dict({
"account": self.doc.closing_account_head,
"debit": abs(net_pl_balance) if net_pl_balance > 0 else 0,
"credit": abs(net_pl_balance) if net_pl_balance < 0 else 0
}))
# update total debit / credit except on_cancel
self.td += flt(le.credit)
self.tc += flt(le.debit)
# save
le.save(1)
le_obj.on_update(adv_adj = '', cancel = '')
def validate(self):
# validate account head
self.validate_account_head()
# validate posting date
self.validate_posting_date()
# check if pl balance:
self.validate_pl_balances()
def on_submit(self):
# Makes closing entries for Expense Account
in_acc_det = self.get_pl_balances('Credit')
self.make_gl_entries(in_acc_det)
# Makes closing entries for Expense Account
ex_acc_det = self.get_pl_balances('Debit')
self.make_gl_entries(ex_acc_det)
# Makes Closing entry for Closing Account Head
bal = self.tc - self.td
self.make_gl_entries([[self.doc.closing_account_head, flt(bal)]])
def on_cancel(self):
# get all submit entries of current closing entry voucher
gl_entries = webnotes.conn.sql("select account, debit, credit from `tabGL Entry` where voucher_type = 'Period Closing Voucher' and voucher_no = '%s' and ifnull(is_cancelled, 'No') = 'No'" % (self.doc.name))
# Swap Debit & Credit Column and make gl entry
for gl in gl_entries:
fdict = {'account': gl[0], 'cost_center': '', 'against': '', 'debit': flt(gl[2]), 'credit' : flt(gl[1]), 'remarks': "cancelled", 'voucher_type': self.doc.doctype, 'voucher_no': self.doc.name, 'transaction_date': self.doc.transaction_date, 'posting_date': self.doc.posting_date, 'fiscal_year': self.doc.fiscal_year, 'against_voucher': '', 'against_voucher_type': '', 'company': self.doc.company, 'is_opening': 'No', 'aging_date': 'self.doc.posting_date'}
self.save_entry(fdict, is_cancel = 'Yes')
# Update is_cancelled = 'Yes' to all gl entries for current voucher
webnotes.conn.sql("update `tabGL Entry` set is_cancelled = 'Yes' where voucher_type = '%s' and voucher_no = '%s'" % (self.doc.doctype, self.doc.name))
from accounts.general_ledger import make_gl_entries
make_gl_entries(gl_entries)

View File

@@ -0,0 +1,53 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import unittest
import webnotes
class TestPeriodClosingVoucher(unittest.TestCase):
def test_closing_entry(self):
from accounts.doctype.journal_voucher.test_journal_voucher import test_records as jv_records
jv = webnotes.bean(copy=jv_records[2])
jv.insert()
jv.submit()
jv1 = webnotes.bean(copy=jv_records[0])
jv1.doclist[2].account = "_Test Account Cost for Goods Sold - _TC"
jv1.doclist[2].debit = 600.0
jv1.doclist[1].credit = 600.0
jv1.insert()
jv1.submit()
pcv = webnotes.bean(copy=test_record)
pcv.insert()
pcv.submit()
gl_entries = webnotes.conn.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Period Closing Voucher' and voucher_no=%s
order by account asc, debit asc""", pcv.doc.name, as_dict=1)
self.assertTrue(gl_entries)
expected_gl_entries = sorted([
["_Test Account Reserves and Surplus - _TC", 200.0, 0.0],
["_Test Account Cost for Goods Sold - _TC", 0.0, 600.0],
["Sales - _TC", 400.0, 0.0]
])
for i, gle in enumerate(gl_entries):
self.assertEquals(expected_gl_entries[i][0], gle.account)
self.assertEquals(expected_gl_entries[i][1], gle.debit)
self.assertEquals(expected_gl_entries[i][2], gle.credit)
test_dependencies = ["Customer", "Cost Center"]
test_record = [{
"doctype": "Period Closing Voucher",
"closing_account_head": "_Test Account Reserves and Surplus - _TC",
"company": "_Test Company",
"fiscal_year": "_Test Fiscal Year 2013",
"posting_date": "2013-03-31",
"remarks": "test"
}]

View File

@@ -35,7 +35,7 @@ class DocType:
(res[0][0], self.doc.company), raise_exception=1)
def validate_expense_account(self):
if cint(webnotes.defaults.get_global_default("auto_inventory_accounting")) \
if cint(webnotes.defaults.get_global_default("auto_accounting_for_stock")) \
and not self.doc.expense_account:
msgprint(_("Expense Account is mandatory"), raise_exception=1)
@@ -61,4 +61,4 @@ class DocType:
webnotes.defaults.set_global_default("is_pos", 1)
def on_trash(self):
self.on_update()
self.on_update()

View File

@@ -2,7 +2,7 @@
{
"creation": "2013-05-24 12:15:51",
"docstatus": 0,
"modified": "2013-08-09 16:35:03",
"modified": "2013-08-28 19:13:42",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -163,7 +163,7 @@
"reqd": 1
},
{
"depends_on": "eval:sys_defaults.auto_inventory_accounting",
"depends_on": "eval:sys_defaults.auto_accounting_for_stock",
"doctype": "DocField",
"fieldname": "expense_account",
"fieldtype": "Link",

View File

@@ -211,28 +211,29 @@ class DocType(BuyingController):
raise Exception
def set_against_expense_account(self):
auto_inventory_accounting = \
cint(webnotes.defaults.get_global_default("auto_inventory_accounting"))
auto_accounting_for_stock = cint(webnotes.defaults.get_global_default("auto_accounting_for_stock"))
if auto_inventory_accounting:
if auto_accounting_for_stock:
stock_not_billed_account = self.get_company_default("stock_received_but_not_billed")
against_accounts = []
stock_items = self.get_stock_items()
for item in self.doclist.get({"parentfield": "entries"}):
if auto_inventory_accounting and item.item_code in self.stock_items:
if auto_accounting_for_stock and item.item_code in stock_items:
# in case of auto inventory accounting, against expense account is always
# Stock Received But Not Billed for a stock item
item.expense_head = item.cost_center = None
item.expense_head = stock_not_billed_account
item.cost_center = None
if stock_not_billed_account not in against_accounts:
against_accounts.append(stock_not_billed_account)
elif not item.expense_head:
msgprint(_("""Expense account is mandatory for item: """) + (item.item_code or item.item_name),
raise_exception=1)
msgprint(_("Expense account is mandatory for item") + ": " +
(item.item_code or item.item_name), raise_exception=1)
elif item.expense_head not in against_accounts:
# if no auto_inventory_accounting or not a stock item
# if no auto_accounting_for_stock or not a stock item
against_accounts.append(item.expense_head)
self.doc.against_expense_account = ",".join(against_accounts)
@@ -313,9 +314,8 @@ class DocType(BuyingController):
self.update_prevdoc_status()
def make_gl_entries(self):
from accounts.general_ledger import make_gl_entries
auto_inventory_accounting = \
cint(webnotes.defaults.get_global_default("auto_inventory_accounting"))
auto_accounting_for_stock = \
cint(webnotes.defaults.get_global_default("auto_accounting_for_stock"))
gl_entries = []
@@ -352,17 +352,15 @@ class DocType(BuyingController):
valuation_tax += (tax.add_deduct_tax == "Add" and 1 or -1) * flt(tax.tax_amount)
# item gl entries
stock_item_and_auto_inventory_accounting = False
if auto_inventory_accounting:
stock_account = self.get_company_default("stock_received_but_not_billed")
stock_item_and_auto_accounting_for_stock = False
stock_items = self.get_stock_items()
for item in self.doclist.get({"parentfield": "entries"}):
if auto_inventory_accounting and item.item_code in self.stock_items:
if auto_accounting_for_stock and item.item_code in stock_items:
if flt(item.valuation_rate):
# if auto inventory accounting enabled and stock item,
# then do stock related gl entries
# expense will be booked in sales invoice
stock_item_and_auto_inventory_accounting = True
stock_item_and_auto_accounting_for_stock = True
valuation_amt = (flt(item.amount, self.precision("amount", item)) +
flt(item.item_tax_amount, self.precision("item_tax_amount", item)) +
@@ -370,7 +368,7 @@ class DocType(BuyingController):
gl_entries.append(
self.get_gl_dict({
"account": stock_account,
"account": item.expense_head,
"against": self.doc.credit_to,
"debit": valuation_amt,
"remarks": self.doc.remarks or "Accounting Entry for Stock"
@@ -389,13 +387,13 @@ class DocType(BuyingController):
})
)
if stock_item_and_auto_inventory_accounting and valuation_tax:
if stock_item_and_auto_accounting_for_stock and valuation_tax:
# credit valuation tax amount in "Expenses Included In Valuation"
# this will balance out valuation amount included in cost of goods sold
gl_entries.append(
self.get_gl_dict({
"account": self.get_company_default("expenses_included_in_valuation"),
"cost_center": self.get_company_default("stock_adjustment_cost_center"),
"cost_center": self.get_company_default("cost_center"),
"against": self.doc.credit_to,
"credit": valuation_tax,
"remarks": self.doc.remarks or "Accounting Entry for Stock"
@@ -416,6 +414,7 @@ class DocType(BuyingController):
)
if gl_entries:
from accounts.general_ledger import make_gl_entries
make_gl_entries(gl_entries, cancel=(self.doc.docstatus == 2))
def on_cancel(self):
@@ -455,4 +454,4 @@ def get_expense_account(doctype, txt, searchfield, start, page_len, filters):
and tabAccount.company = '%(company)s'
and tabAccount.%(key)s LIKE '%(txt)s'
%(mcond)s""" % {'company': filters['company'], 'key': searchfield,
'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype, searchfield)})
'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype, searchfield)})

View File

@@ -9,14 +9,15 @@ import webnotes.model
import json
from webnotes.utils import cint
import webnotes.defaults
from stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
test_dependencies = ["Item", "Cost Center"]
test_ignore = ["Serial No"]
class TestPurchaseInvoice(unittest.TestCase):
def test_gl_entries_without_auto_inventory_accounting(self):
webnotes.defaults.set_global_default("auto_inventory_accounting", 0)
self.assertTrue(not cint(webnotes.defaults.get_global_default("auto_inventory_accounting")))
def test_gl_entries_without_auto_accounting_for_stock(self):
set_perpetual_inventory(0)
self.assertTrue(not cint(webnotes.defaults.get_global_default("auto_accounting_for_stock")))
wrapper = webnotes.bean(copy=test_records[0])
wrapper.run_method("calculate_taxes_and_totals")
@@ -41,9 +42,9 @@ class TestPurchaseInvoice(unittest.TestCase):
for d in gl_entries:
self.assertEqual([d.debit, d.credit], expected_gl_entries.get(d.account))
def test_gl_entries_with_auto_inventory_accounting(self):
webnotes.defaults.set_global_default("auto_inventory_accounting", 1)
self.assertEqual(cint(webnotes.defaults.get_global_default("auto_inventory_accounting")), 1)
def test_gl_entries_with_auto_accounting_for_stock(self):
set_perpetual_inventory(1)
self.assertEqual(cint(webnotes.defaults.get_global_default("auto_accounting_for_stock")), 1)
pi = webnotes.bean(copy=test_records[1])
pi.run_method("calculate_taxes_and_totals")
@@ -68,11 +69,11 @@ class TestPurchaseInvoice(unittest.TestCase):
self.assertEquals(expected_values[i][1], gle.debit)
self.assertEquals(expected_values[i][2], gle.credit)
webnotes.defaults.set_global_default("auto_inventory_accounting", 0)
set_perpetual_inventory(0)
def test_gl_entries_with_aia_for_non_stock_items(self):
webnotes.defaults.set_global_default("auto_inventory_accounting", 1)
self.assertEqual(cint(webnotes.defaults.get_global_default("auto_inventory_accounting")), 1)
set_perpetual_inventory()
self.assertEqual(cint(webnotes.defaults.get_global_default("auto_accounting_for_stock")), 1)
pi = webnotes.bean(copy=test_records[1])
pi.doclist[1].item_code = "_Test Non Stock Item"
@@ -98,8 +99,7 @@ class TestPurchaseInvoice(unittest.TestCase):
self.assertEquals(expected_values[i][0], gle.account)
self.assertEquals(expected_values[i][1], gle.debit)
self.assertEquals(expected_values[i][2], gle.credit)
webnotes.defaults.set_global_default("auto_inventory_accounting", 0)
set_perpetual_inventory(0)
def test_purchase_invoice_calculation(self):
wrapper = webnotes.bean(copy=test_records[0])

View File

@@ -384,7 +384,7 @@ cur_frm.set_query("income_account", "entries", function(doc) {
});
// expense account
if (sys_defaults.auto_inventory_accounting) {
if (sys_defaults.auto_accounting_for_stock) {
cur_frm.fields_dict['entries'].grid.get_field('expense_account').get_query = function(doc) {
return {
filters: {

View File

@@ -82,7 +82,7 @@ class DocType(SellingController):
def on_submit(self):
if cint(self.doc.update_stock) == 1:
self.update_stock_ledger(update_stock=1)
self.update_stock_ledger()
self.update_serial_nos()
else:
# Check for Approving Authority
@@ -90,7 +90,6 @@ class DocType(SellingController):
get_obj('Authorization Control').validate_approving_authority(self.doc.doctype,
self.doc.company, self.doc.grand_total, self)
self.set_buying_amount()
self.check_prev_docstatus()
self.update_status_updater_args()
@@ -111,7 +110,7 @@ class DocType(SellingController):
def on_cancel(self):
if cint(self.doc.update_stock) == 1:
self.update_stock_ledger(update_stock = -1)
self.update_stock_ledger()
self.update_serial_nos(cancel = True)
sales_com_obj = get_obj(dt = 'Sales Common')
@@ -196,8 +195,6 @@ class DocType(SellingController):
pos = get_pos_settings(self.doc.company)
if pos:
self.doc.conversion_rate = flt(pos.conversion_rate)
if not for_validate:
self.doc.customer = pos.customer
self.set_customer_defaults()
@@ -526,41 +523,18 @@ class DocType(SellingController):
msgprint("Delivery Note : "+ cstr(d.delivery_note) +" is not submitted")
raise Exception , "Validation Error."
def make_sl_entry(self, d, wh, qty, in_value, update_stock):
st_uom = webnotes.conn.sql("select stock_uom from `tabItem` where name = '%s'"%d['item_code'])
self.values.append({
'item_code' : d['item_code'],
'warehouse' : wh,
'posting_date' : self.doc.posting_date,
'posting_time' : self.doc.posting_time,
'voucher_type' : 'Sales Invoice',
'voucher_no' : cstr(self.doc.name),
'voucher_detail_no' : cstr(d['name']),
'actual_qty' : qty,
'stock_uom' : st_uom and st_uom[0][0] or '',
'incoming_rate' : in_value,
'company' : self.doc.company,
'fiscal_year' : self.doc.fiscal_year,
'is_cancelled' : (update_stock==1) and 'No' or 'Yes',
'batch_no' : cstr(d['batch_no']),
'serial_no' : d['serial_no'],
"project" : self.doc.project_name
})
def update_stock_ledger(self, update_stock):
self.values = []
def update_stock_ledger(self):
sl_entries = []
items = get_obj('Sales Common').get_item_list(self)
for d in items:
if webnotes.conn.get_value("Item", d['item_code'], "is_stock_item") == "Yes":
if not d['warehouse']:
msgprint("Message: Please enter Warehouse for item %s as it is stock item." \
% d['item_code'], raise_exception=1)
# Reduce actual qty from warehouse
self.make_sl_entry( d, d['warehouse'], - flt(d['qty']) , 0, update_stock)
if webnotes.conn.get_value("Item", d.item_code, "is_stock_item") == "Yes" \
and d.warehouse:
sl_entries.append(self.get_sl_entries(d, {
"actual_qty": -1*flt(d.qty),
"stock_uom": webnotes.conn.get_value("Item", d.item_code, "stock_uom")
}))
get_obj('Stock Ledger', 'Stock Ledger').update_stock(self.values)
self.make_sl_entries(sl_entries)
def make_gl_entries(self):
from accounts.general_ledger import make_gl_entries, merge_similar_entries
@@ -584,6 +558,10 @@ class DocType(SellingController):
make_gl_entries(gl_entries, cancel=(self.doc.docstatus == 2),
update_outstanding=update_outstanding, merge_entries=False)
if cint(webnotes.defaults.get_global_default("auto_accounting_for_stock")) \
and cint(self.doc.update_stock):
self.update_gl_entries_after()
def make_customer_gl_entry(self, gl_entries):
if self.doc.grand_total:
gl_entries.append(
@@ -625,15 +603,9 @@ class DocType(SellingController):
)
# expense account gl entries
if cint(webnotes.defaults.get_global_default("auto_inventory_accounting")) \
if cint(webnotes.defaults.get_global_default("auto_accounting_for_stock")) \
and cint(self.doc.update_stock):
for item in self.doclist.get({"parentfield": "entries"}):
self.check_expense_account(item)
if item.buying_amount:
gl_entries += self.get_gl_entries_for_stock(item.expense_account,
-1*item.buying_amount, cost_center=item.cost_center)
gl_entries += self.get_gl_entries_for_stock()
def make_pos_gl_entries(self, gl_entries):
if cint(self.doc.is_pos) and self.doc.cash_bank_account and self.doc.paid_amount:

View File

@@ -5,10 +5,13 @@ import webnotes
import unittest, json
from webnotes.utils import flt, cint
from webnotes.model.bean import DocstatusTransitionError, TimestampMismatchError
from accounts.utils import get_stock_and_account_difference
from stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
class TestSalesInvoice(unittest.TestCase):
def make(self):
w = webnotes.bean(copy=test_records[0])
w.doc.is_pos = 0
w.insert()
w.submit()
return w
@@ -92,7 +95,6 @@ class TestSalesInvoice(unittest.TestCase):
si.doclist[1].ref_rate = 1
si.doclist[2].export_rate = 3
si.doclist[2].ref_rate = 3
si.run_method("calculate_taxes_and_totals")
si.insert()
expected_values = {
@@ -299,8 +301,8 @@ class TestSalesInvoice(unittest.TestCase):
"Batched for Billing")
def test_sales_invoice_gl_entry_without_aii(self):
webnotes.defaults.set_global_default("auto_inventory_accounting", 0)
self.clear_stock_account_balance()
set_perpetual_inventory(0)
si = webnotes.bean(copy=test_records[1])
si.insert()
si.submit()
@@ -308,6 +310,7 @@ class TestSalesInvoice(unittest.TestCase):
gl_entries = webnotes.conn.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
order by account asc""", si.doc.name, as_dict=1)
self.assertTrue(gl_entries)
expected_values = sorted([
@@ -325,19 +328,14 @@ class TestSalesInvoice(unittest.TestCase):
# cancel
si.cancel()
gle_count = webnotes.conn.sql("""select count(name) from `tabGL Entry`
where voucher_type='Sales Invoice' and voucher_no=%s
and ifnull(is_cancelled, 'No') = 'Yes'
order by account asc""", si.doc.name)
gle = webnotes.conn.sql("""select * from `tabGL Entry`
where voucher_type='Sales Invoice' and voucher_no=%s""", si.doc.name)
self.assertEquals(gle_count[0][0], 8)
self.assertFalse(gle)
def test_pos_gl_entry_with_aii(self):
webnotes.conn.sql("delete from `tabStock Ledger Entry`")
webnotes.defaults.set_global_default("auto_inventory_accounting", 1)
old_default_company = webnotes.conn.get_default("company")
webnotes.conn.set_default("company", "_Test Company")
self.clear_stock_account_balance()
set_perpetual_inventory()
self._insert_purchase_receipt()
self._insert_pos_settings()
@@ -362,20 +360,19 @@ class TestSalesInvoice(unittest.TestCase):
["_Test Item", "_Test Warehouse - _TC", -1.0])
# check gl entries
stock_in_hand_account = webnotes.conn.get_value("Company", "_Test Company",
"stock_in_hand_account")
gl_entries = webnotes.conn.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
order by account asc, debit asc""", si.doc.name, as_dict=1)
self.assertTrue(gl_entries)
stock_in_hand = webnotes.conn.get_value("Account", {"master_name": "_Test Warehouse - _TC"})
expected_gl_entries = sorted([
[si.doc.debit_to, 630.0, 0.0],
[pos[1]["income_account"], 0.0, 500.0],
[pos[2]["account_head"], 0.0, 80.0],
[pos[3]["account_head"], 0.0, 50.0],
[stock_in_hand_account, 0.0, 75.0],
[stock_in_hand, 0.0, 75.0],
[pos[1]["expense_account"], 75.0, 0.0],
[si.doc.debit_to, 0.0, 600.0],
["_Test Account Bank Account - _TC", 600.0, 0.0]
@@ -385,20 +382,22 @@ class TestSalesInvoice(unittest.TestCase):
self.assertEquals(expected_gl_entries[i][1], gle.debit)
self.assertEquals(expected_gl_entries[i][2], gle.credit)
# cancel
si.cancel()
gl_count = webnotes.conn.sql("""select count(name)
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
and ifnull(is_cancelled, 'No') = 'Yes'
order by account asc, name asc""", si.doc.name)
gle = webnotes.conn.sql("""select * from `tabGL Entry`
where voucher_type='Sales Invoice' and voucher_no=%s""", si.doc.name)
self.assertEquals(gl_count[0][0], 16)
webnotes.defaults.set_global_default("auto_inventory_accounting", 0)
webnotes.conn.set_default("company", old_default_company)
self.assertFalse(gle)
def test_sales_invoice_gl_entry_with_aii_no_item_code(self):
webnotes.defaults.set_global_default("auto_inventory_accounting", 1)
self.assertFalse(get_stock_and_account_difference([stock_in_hand]))
set_perpetual_inventory(0)
def test_sales_invoice_gl_entry_with_aii_no_item_code(self):
self.clear_stock_account_balance()
set_perpetual_inventory()
si_copy = webnotes.copy_doclist(test_records[1])
si_copy[1]["item_code"] = None
@@ -421,12 +420,12 @@ class TestSalesInvoice(unittest.TestCase):
self.assertEquals(expected_values[i][0], gle.account)
self.assertEquals(expected_values[i][1], gle.debit)
self.assertEquals(expected_values[i][2], gle.credit)
webnotes.defaults.set_global_default("auto_inventory_accounting", 0)
def test_sales_invoice_gl_entry_with_aii_non_stock_item(self):
webnotes.defaults.set_global_default("auto_inventory_accounting", 1)
set_perpetual_inventory(0)
def test_sales_invoice_gl_entry_with_aii_non_stock_item(self):
self.clear_stock_account_balance()
set_perpetual_inventory()
si_copy = webnotes.copy_doclist(test_records[1])
si_copy[1]["item_code"] = "_Test Non Stock Item"
si = webnotes.bean(si_copy)
@@ -449,7 +448,7 @@ class TestSalesInvoice(unittest.TestCase):
self.assertEquals(expected_values[i][1], gle.debit)
self.assertEquals(expected_values[i][2], gle.credit)
webnotes.defaults.set_global_default("auto_inventory_accounting", 0)
set_perpetual_inventory(0)
def _insert_purchase_receipt(self):
from stock.doctype.purchase_receipt.test_purchase_receipt import test_records \
@@ -643,9 +642,14 @@ class TestSalesInvoice(unittest.TestCase):
return new_si
# if yearly, test 3 repetitions, else test 13 repetitions
count = no_of_months == 12 and 3 or 13
count = 3 if no_of_months == 12 else 13
for i in xrange(count):
base_si = _test(i)
def clear_stock_account_balance(self):
webnotes.conn.sql("delete from `tabStock Ledger Entry`")
webnotes.conn.sql("delete from tabBin")
webnotes.conn.sql("delete from `tabGL Entry`")
def test_serialized(self):
from stock.doctype.stock_entry.test_stock_entry import make_serialized_item

View File

@@ -2,7 +2,7 @@
{
"creation": "2013-06-04 11:02:19",
"docstatus": 0,
"modified": "2013-07-25 16:32:10",
"modified": "2013-08-29 16:58:56",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -416,17 +416,6 @@
"print_hide": 1,
"read_only": 1
},
{
"doctype": "DocField",
"fieldname": "buying_amount",
"fieldtype": "Currency",
"hidden": 1,
"label": "Buying Amount",
"no_copy": 1,
"options": "Company:company:default_currency",
"print_hide": 1,
"read_only": 1
},
{
"allow_on_submit": 1,
"doctype": "DocField",