mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-31 10:49:09 +00:00
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:
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
},
|
||||
|
||||
@@ -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
|
||||
@@ -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()
|
||||
@@ -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"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
Backend scripts for Budget Management.
|
||||
@@ -1 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
@@ -1,97 +0,0 @@
|
||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
from webnotes.utils import cstr, flt, getdate
|
||||
from webnotes import msgprint
|
||||
|
||||
class DocType:
|
||||
def __init__(self,d,dl):
|
||||
self.doc, self.doclist = d, dl
|
||||
|
||||
# Get monthly budget
|
||||
#-------------------
|
||||
def get_monthly_budget(self, distribution_id, cfy, st_date, post_dt, budget_allocated):
|
||||
|
||||
# get month_list
|
||||
st_date, post_dt = getdate(st_date), getdate(post_dt)
|
||||
|
||||
if distribution_id:
|
||||
if st_date.month <= post_dt.month:
|
||||
tot_per_allocated = webnotes.conn.sql("select ifnull(sum(percentage_allocation),0) from `tabBudget Distribution Detail` where parent='%s' and idx between '%s' and '%s'" % (distribution_id, st_date.month, post_dt.month))[0][0]
|
||||
|
||||
if st_date.month > post_dt.month:
|
||||
|
||||
tot_per_allocated = flt(webnotes.conn.sql("select ifnull(sum(percentage_allocation),0) from `tabBudget Distribution Detail` where parent='%s' and idx between '%s' and '%s'" % (distribution_id, st_date.month, 12 ))[0][0])
|
||||
tot_per_allocated = flt(tot_per_allocated) + flt(webnotes.conn.sql("select ifnull(sum(percentage_allocation),0) from `tabBudget Distribution Detail` where parent='%s' and idx between '%s' and '%s'" % (distribution_id, 1, post_dt.month))[0][0])
|
||||
|
||||
return (flt(budget_allocated) * flt(tot_per_allocated)) / 100
|
||||
period_diff = webnotes.conn.sql("select PERIOD_DIFF('%s','%s')" % (post_dt.strftime('%Y%m'), st_date.strftime('%Y%m')))
|
||||
|
||||
return (flt(budget_allocated) * (flt(period_diff[0][0]) + 1)) / 12
|
||||
|
||||
def validate_budget(self, acct, cost_center, actual, budget, action):
|
||||
# action if actual exceeds budget
|
||||
if flt(actual) > flt(budget):
|
||||
msgprint("Your monthly expense "+ cstr((action == 'stop') and "will exceed" or "has exceeded") +" budget for <b>Account - "+cstr(acct)+" </b> under <b>Cost Center - "+ cstr(cost_center) + "</b>"+cstr((action == 'Stop') and ", you can not have this transaction." or "."))
|
||||
if action == 'Stop': raise Exception
|
||||
|
||||
def check_budget(self,gle,cancel):
|
||||
# get allocated budget
|
||||
|
||||
bgt = webnotes.conn.sql("""select t1.budget_allocated, t1.actual, t2.distribution_id
|
||||
from `tabBudget Detail` t1, `tabCost Center` t2
|
||||
where t1.account='%s' and t1.parent=t2.name and t2.name = '%s'
|
||||
and t1.fiscal_year='%s'""" %
|
||||
(gle['account'], gle['cost_center'], gle['fiscal_year']), as_dict =1)
|
||||
|
||||
curr_amt = flt(gle['debit']) - flt(gle['credit'])
|
||||
if cancel: curr_amt = -1 * curr_amt
|
||||
|
||||
if bgt and bgt[0]['budget_allocated']:
|
||||
# check budget flag in Company
|
||||
bgt_flag = webnotes.conn.sql("""select yearly_bgt_flag, monthly_bgt_flag
|
||||
from `tabCompany` where name = '%s'""" % gle['company'], as_dict =1)
|
||||
|
||||
if bgt_flag and bgt_flag[0]['monthly_bgt_flag'] in ['Stop', 'Warn']:
|
||||
# get start date and last date
|
||||
start_date = webnotes.conn.get_value('Fiscal Year', gle['fiscal_year'], \
|
||||
'year_start_date').strftime('%Y-%m-%d')
|
||||
end_date = webnotes.conn.sql("select LAST_DAY('%s')" % gle['posting_date'])
|
||||
|
||||
# get Actual
|
||||
actual = self.get_period_difference(gle['account'] +
|
||||
'~~~' + cstr(start_date) + '~~~' + cstr(end_date[0][0]), gle['cost_center'])
|
||||
|
||||
# Get Monthly budget
|
||||
budget = self.get_monthly_budget(bgt and bgt[0]['distribution_id'] or '' , \
|
||||
gle['fiscal_year'], start_date, gle['posting_date'], bgt[0]['budget_allocated'])
|
||||
|
||||
# validate monthly budget
|
||||
self.validate_budget(gle['account'], gle['cost_center'], \
|
||||
flt(actual) + flt(curr_amt), budget, bgt_flag[0]['monthly_bgt_flag'])
|
||||
|
||||
# update actual against budget allocated in cost center
|
||||
webnotes.conn.sql("""update `tabBudget Detail` set actual = ifnull(actual,0) + %s
|
||||
where account = '%s' and fiscal_year = '%s' and parent = '%s'""" %
|
||||
(curr_amt, gle['account'],gle['fiscal_year'], gle['cost_center']))
|
||||
|
||||
|
||||
def get_period_difference(self, arg, cost_center =''):
|
||||
# used in General Ledger Page Report
|
||||
# used for Budget where cost center passed as extra argument
|
||||
acc, f, t = arg.split('~~~')
|
||||
c, fy = '', webnotes.conn.get_defaults()['fiscal_year']
|
||||
|
||||
det = webnotes.conn.sql("select debit_or_credit, lft, rgt, is_pl_account from tabAccount where name=%s", acc)
|
||||
if f: c += (' and t1.posting_date >= "%s"' % f)
|
||||
if t: c += (' and t1.posting_date <= "%s"' % t)
|
||||
if cost_center: c += (' and t1.cost_center = "%s"' % cost_center)
|
||||
bal = webnotes.conn.sql("select sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) from `tabGL Entry` t1 where t1.account='%s' %s" % (acc, c))
|
||||
bal = bal and flt(bal[0][0]) or 0
|
||||
|
||||
if det[0][0] != 'Debit':
|
||||
bal = (-1) * bal
|
||||
|
||||
return flt(bal)
|
||||
@@ -1,19 +0,0 @@
|
||||
[
|
||||
{
|
||||
"creation": "2012-03-27 14:35:41",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-07-10 14:54:06",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "nabin@webnotestech.com"
|
||||
},
|
||||
{
|
||||
"doctype": "DocType",
|
||||
"issingle": 1,
|
||||
"module": "Accounts",
|
||||
"name": "__common__"
|
||||
},
|
||||
{
|
||||
"doctype": "DocType",
|
||||
"name": "Budget Control"
|
||||
}
|
||||
]
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"creation": "2013-03-07 11:55:04",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-07-10 14:54:06",
|
||||
"modified": "2013-08-22 17:27:59",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
@@ -20,7 +20,8 @@
|
||||
"parent": "Budget Detail",
|
||||
"parentfield": "fields",
|
||||
"parenttype": "DocType",
|
||||
"permlevel": 0
|
||||
"permlevel": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"doctype": "DocType",
|
||||
@@ -35,7 +36,6 @@
|
||||
"oldfieldname": "account",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Account",
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
@@ -45,18 +45,7 @@
|
||||
"label": "Budget Allocated",
|
||||
"oldfieldname": "budget_allocated",
|
||||
"oldfieldtype": "Currency",
|
||||
"options": "Company:company:default_currency",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "actual",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Actual",
|
||||
"oldfieldname": "actual",
|
||||
"oldfieldtype": "Currency",
|
||||
"options": "Company:company:default_currency",
|
||||
"read_only": 1
|
||||
"options": "Company:company:default_currency"
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
@@ -67,7 +56,6 @@
|
||||
"oldfieldname": "fiscal_year",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "link:Fiscal Year",
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
}
|
||||
]
|
||||
@@ -1,4 +1,70 @@
|
||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
test_records = []
|
||||
test_records = [
|
||||
[{
|
||||
"doctype": "Budget Distribution",
|
||||
"distribution_id": "_Test Distribution",
|
||||
"fiscal_year": "_Test Fiscal Year 2013",
|
||||
}, {
|
||||
"doctype": "Budget Distribution Detail",
|
||||
"parentfield": "budget_distribution_details",
|
||||
"month": "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"
|
||||
}]
|
||||
]
|
||||
@@ -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 \
|
||||
|
||||
@@ -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"
|
||||
}],
|
||||
]
|
||||
@@ -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)
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 = [
|
||||
[{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
}]
|
||||
@@ -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()
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)})
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user