mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-02 19:59:12 +00:00
[minor] fixed conflict
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 and account:
|
||||
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)
|
||||
@@ -452,4 +452,4 @@ def get_outstanding(args):
|
||||
return {
|
||||
"debit": flt(webnotes.conn.get_value("Purchase Invoice", args["docname"],
|
||||
"outstanding_amount"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -8,6 +8,7 @@ cur_frm.cscript.other_fname = "purchase_tax_details";
|
||||
wn.provide("erpnext.accounts");
|
||||
wn.require('app/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js');
|
||||
wn.require('app/buying/doctype/purchase_common/purchase_common.js');
|
||||
wn.require('app/accounts/doctype/sales_invoice/pos.js');
|
||||
|
||||
erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
|
||||
onload: function() {
|
||||
|
||||
@@ -61,19 +61,23 @@ class DocType(BuyingController):
|
||||
"purchase_receipt_details")
|
||||
|
||||
def get_credit_to(self):
|
||||
acc_head = webnotes.conn.sql("""select name, credit_days from `tabAccount`
|
||||
where (name = %s or (master_name = %s and master_type = 'supplier'))
|
||||
and docstatus != 2 and company = %s""",
|
||||
(cstr(self.doc.supplier) + " - " + self.company_abbr,
|
||||
self.doc.supplier, self.doc.company))
|
||||
|
||||
ret = {}
|
||||
if acc_head and acc_head[0][0]:
|
||||
ret['credit_to'] = acc_head[0][0]
|
||||
if not self.doc.due_date:
|
||||
ret['due_date'] = add_days(cstr(self.doc.posting_date), acc_head and cint(acc_head[0][1]) or 0)
|
||||
elif not acc_head:
|
||||
msgprint("%s does not have an Account Head in %s. You must first create it from the Supplier Master" % (self.doc.supplier, self.doc.company))
|
||||
if self.doc.supplier:
|
||||
acc_head = webnotes.conn.sql("""select name, credit_days from `tabAccount`
|
||||
where (name = %s or (master_name = %s and master_type = 'supplier'))
|
||||
and docstatus != 2 and company = %s""",
|
||||
(cstr(self.doc.supplier) + " - " + self.company_abbr,
|
||||
self.doc.supplier, self.doc.company))
|
||||
|
||||
if acc_head and acc_head[0][0]:
|
||||
ret['credit_to'] = acc_head[0][0]
|
||||
if not self.doc.due_date:
|
||||
ret['due_date'] = add_days(cstr(self.doc.posting_date),
|
||||
acc_head and cint(acc_head[0][1]) or 0)
|
||||
elif not acc_head:
|
||||
msgprint("%s does not have an Account Head in %s. \
|
||||
You must first create it from the Supplier Master" % \
|
||||
(self.doc.supplier, self.doc.company))
|
||||
return ret
|
||||
|
||||
def set_supplier_defaults(self):
|
||||
@@ -84,14 +88,6 @@ class DocType(BuyingController):
|
||||
super(DocType, self).get_advances(self.doc.credit_to,
|
||||
"Purchase Invoice Advance", "advance_allocation_details", "debit")
|
||||
|
||||
def get_rate(self,arg):
|
||||
return get_obj('Purchase Common').get_rate(arg,self)
|
||||
|
||||
def get_rate1(self,acc):
|
||||
rate = webnotes.conn.sql("select tax_rate from `tabAccount` where name='%s'"%(acc))
|
||||
ret={'add_tax_rate' :rate and flt(rate[0][0]) or 0 }
|
||||
return ret
|
||||
|
||||
def check_active_purchase_items(self):
|
||||
for d in getlist(self.doclist, 'entries'):
|
||||
if d.item_code: # extra condn coz item_code is not mandatory in PV
|
||||
@@ -211,28 +207,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 +310,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 = []
|
||||
|
||||
@@ -333,7 +329,7 @@ class DocType(BuyingController):
|
||||
)
|
||||
|
||||
# tax table gl entries
|
||||
valuation_tax = 0
|
||||
valuation_tax = {}
|
||||
for tax in self.doclist.get({"parentfield": "purchase_tax_details"}):
|
||||
if tax.category in ("Total", "Valuation and Total") and flt(tax.tax_amount):
|
||||
gl_entries.append(
|
||||
@@ -348,21 +344,22 @@ class DocType(BuyingController):
|
||||
)
|
||||
|
||||
# accumulate valuation tax
|
||||
if tax.category in ("Valuation", "Valuation and Total") and flt(tax.tax_amount):
|
||||
valuation_tax += (tax.add_deduct_tax == "Add" and 1 or -1) * flt(tax.tax_amount)
|
||||
if tax.category in ("Valuation", "Valuation and Total") and flt(tax.tax_amount) \
|
||||
and tax.cost_center:
|
||||
valuation_tax.setdefault(tax.cost_center, 0)
|
||||
valuation_tax[tax.cost_center] += \
|
||||
(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 +367,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,18 +386,22 @@ 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"),
|
||||
"against": self.doc.credit_to,
|
||||
"credit": valuation_tax,
|
||||
"remarks": self.doc.remarks or "Accounting Entry for Stock"
|
||||
})
|
||||
)
|
||||
expenses_included_in_valuation = \
|
||||
self.get_company_default("expenses_included_in_valuation")
|
||||
|
||||
for cost_center, amount in valuation_tax.items():
|
||||
gl_entries.append(
|
||||
self.get_gl_dict({
|
||||
"account": expenses_included_in_valuation,
|
||||
"cost_center": cost_center,
|
||||
"against": self.doc.credit_to,
|
||||
"credit": amount,
|
||||
"remarks": self.doc.remarks or "Accounting Entry for Stock"
|
||||
})
|
||||
)
|
||||
|
||||
# writeoff account includes petty difference in the invoice amount
|
||||
# and the amount that is paid
|
||||
@@ -416,6 +417,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 +457,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)})
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
{
|
||||
"creation": "2013-05-21 16:16:39",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-08-09 14:45:35",
|
||||
"modified": "2013-10-02 14:24:55",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
{
|
||||
"allow_attach": 1,
|
||||
"allow_import": 1,
|
||||
"autoname": "naming_series:",
|
||||
"doctype": "DocType",
|
||||
"icon": "icon-file-text",
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
//
|
||||
|
||||
//--------- ONLOAD -------------
|
||||
wn.require("app/js/controllers/accounts.js");
|
||||
|
||||
cur_frm.cscript.onload = function(doc, cdt, cdn) {
|
||||
|
||||
}
|
||||
@@ -134,20 +136,6 @@ cur_frm.fields_dict['purchase_tax_details'].grid.get_field("cost_center").get_qu
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.cscript.account_head = function(doc, cdt, cdn) {
|
||||
var d = locals[cdt][cdn];
|
||||
if(!d.charge_type && d.account_head){
|
||||
alert("Please select Charge Type first");
|
||||
validated = false;
|
||||
d.account_head = '';
|
||||
}
|
||||
else if(d.account_head && d.charge_type) {
|
||||
arg = "{'charge_type' : '" + d.charge_type + "', 'account_head' : '" + d.account_head + "'}";
|
||||
return get_server_fields('get_rate', arg, 'purchase_tax_details', doc, cdt, cdn, 1);
|
||||
}
|
||||
refresh_field('account_head',d.name,'purchase_tax_details');
|
||||
}
|
||||
|
||||
cur_frm.cscript.rate = function(doc, cdt, cdn) {
|
||||
var d = locals[cdt][cdn];
|
||||
if(!d.charge_type && d.rate) {
|
||||
|
||||
@@ -14,9 +14,4 @@ from webnotes.model.code import get_obj
|
||||
class DocType:
|
||||
def __init__(self, doc, doclist=[]):
|
||||
self.doc = doc
|
||||
self.doclist = doclist
|
||||
|
||||
# Get Tax Rate if account type is Tax
|
||||
# ===================================================================
|
||||
def get_rate(self, arg):
|
||||
return get_obj('Purchase Common').get_rate(arg, self)
|
||||
self.doclist = doclist
|
||||
@@ -7,7 +7,7 @@ erpnext.POS = Class.extend({
|
||||
this.frm = frm;
|
||||
this.wrapper.html('<div class="container">\
|
||||
<div class="row">\
|
||||
<div class="customer-area col-sm-3 col-xs-6"></div>\
|
||||
<div class="party-area col-sm-3 col-xs-6"></div>\
|
||||
<div class="barcode-area col-sm-3 col-xs-6"></div>\
|
||||
<div class="search-area col-sm-3 col-xs-6"></div>\
|
||||
<div class="item-group-area col-sm-3 col-xs-6"></div>\
|
||||
@@ -71,7 +71,18 @@ erpnext.POS = Class.extend({
|
||||
</div>\
|
||||
</div>\
|
||||
</div></div>');
|
||||
|
||||
|
||||
if (wn.meta.has_field(cur_frm.doc.doctype, "customer")) {
|
||||
this.party = "Customer";
|
||||
this.price_list = this.frm.doc.selling_price_list;
|
||||
this.sales_or_purchase = "Sales";
|
||||
}
|
||||
else if (wn.meta.has_field(cur_frm.doc.doctype, "supplier")) {
|
||||
this.party = "Supplier";
|
||||
this.price_list = this.frm.doc.buying_price_list;
|
||||
this.sales_or_purchase = "Purchase";
|
||||
}
|
||||
|
||||
this.make();
|
||||
|
||||
var me = this;
|
||||
@@ -88,28 +99,29 @@ erpnext.POS = Class.extend({
|
||||
});
|
||||
},
|
||||
make: function() {
|
||||
this.make_customer();
|
||||
this.make_party();
|
||||
this.make_item_group();
|
||||
this.make_search();
|
||||
this.make_barcode();
|
||||
this.make_item_list();
|
||||
},
|
||||
make_customer: function() {
|
||||
make_party: function() {
|
||||
var me = this;
|
||||
this.customer = wn.ui.form.make_control({
|
||||
this.party_field = wn.ui.form.make_control({
|
||||
df: {
|
||||
"fieldtype": "Link",
|
||||
"options": "Customer",
|
||||
"label": "Customer",
|
||||
"fieldname": "pos_customer",
|
||||
"placeholder": "Customer"
|
||||
"options": this.party,
|
||||
"label": this.party,
|
||||
"fieldname": "pos_party",
|
||||
"placeholder": this.party
|
||||
},
|
||||
parent: this.wrapper.find(".customer-area")
|
||||
parent: this.wrapper.find(".party-area")
|
||||
});
|
||||
this.customer.make_input();
|
||||
this.customer.$input.on("change", function() {
|
||||
if(!me.customer.autocomplete_open)
|
||||
wn.model.set_value("Sales Invoice", me.frm.docname, "customer", this.value);
|
||||
this.party_field.make_input();
|
||||
this.party_field.$input.on("change", function() {
|
||||
if(!me.party_field.autocomplete_open)
|
||||
wn.model.set_value(me.frm.doctype, me.frm.docname,
|
||||
me.party.toLowerCase(), this.value);
|
||||
});
|
||||
},
|
||||
make_item_group: function() {
|
||||
@@ -120,7 +132,7 @@ erpnext.POS = Class.extend({
|
||||
"options": "Item Group",
|
||||
"label": "Item Group",
|
||||
"fieldname": "pos_item_group",
|
||||
"placeholder": "Filter by Item Group"
|
||||
"placeholder": "Item Group"
|
||||
},
|
||||
parent: this.wrapper.find(".item-group-area")
|
||||
});
|
||||
@@ -138,7 +150,7 @@ erpnext.POS = Class.extend({
|
||||
"options": "Item",
|
||||
"label": "Item",
|
||||
"fieldname": "pos_item",
|
||||
"placeholder": "Select Item"
|
||||
"placeholder": "Item"
|
||||
},
|
||||
parent: this.wrapper.find(".search-area")
|
||||
});
|
||||
@@ -155,7 +167,7 @@ erpnext.POS = Class.extend({
|
||||
"fieldtype": "Data",
|
||||
"label": "Barcode",
|
||||
"fieldname": "pos_barcode",
|
||||
"placeholder": "Select Barcode"
|
||||
"placeholder": "Barcode"
|
||||
},
|
||||
parent: this.wrapper.find(".barcode-area")
|
||||
});
|
||||
@@ -171,7 +183,8 @@ erpnext.POS = Class.extend({
|
||||
wn.call({
|
||||
method: 'accounts.doctype.sales_invoice.pos.get_items',
|
||||
args: {
|
||||
price_list: cur_frm.doc.selling_price_list,
|
||||
sales_or_purchase: this.sales_or_purchase,
|
||||
price_list: this.price_list,
|
||||
item_group: this.item_group.$input.val(),
|
||||
item: this.search.$input.val()
|
||||
},
|
||||
@@ -200,15 +213,18 @@ erpnext.POS = Class.extend({
|
||||
});
|
||||
|
||||
// if form is local then allow this function
|
||||
if (cur_frm.doc.docstatus===0) {
|
||||
$("div.pos-item").on("click", function() {
|
||||
if(!cur_frm.doc.customer) {
|
||||
msgprint("Please select customer first.");
|
||||
$(me.wrapper).find("div.pos-item").on("click", function() {
|
||||
if(me.frm.doc.docstatus==0) {
|
||||
if(!me.frm.doc[me.party.toLowerCase()] && ((me.frm.doctype == "Quotation" &&
|
||||
me.frm.doc.quotation_to == "Customer")
|
||||
|| me.frm.doctype != "Quotation")) {
|
||||
msgprint("Please select " + me.party + " first.");
|
||||
return;
|
||||
}
|
||||
me.add_to_cart($(this).attr("data-item_code"));
|
||||
});
|
||||
}
|
||||
else
|
||||
me.add_to_cart($(this).attr("data-item_code"));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
@@ -217,12 +233,12 @@ erpnext.POS = Class.extend({
|
||||
var caught = false;
|
||||
|
||||
// get no_of_items
|
||||
no_of_items = me.wrapper.find("#cart tbody").length;
|
||||
|
||||
var no_of_items = me.wrapper.find("#cart tbody tr").length;
|
||||
|
||||
// check whether the item is already added
|
||||
if (no_of_items != 0) {
|
||||
$.each(wn.model.get_children("Sales Invoice Item", this.frm.doc.name, "entries",
|
||||
"Sales Invoice"), function(i, d) {
|
||||
$.each(wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name,
|
||||
this.frm.cscript.fname, this.frm.doctype), function(i, d) {
|
||||
if (d.item_code == item_code)
|
||||
caught = true;
|
||||
});
|
||||
@@ -233,15 +249,16 @@ erpnext.POS = Class.extend({
|
||||
me.update_qty(item_code, 1);
|
||||
}
|
||||
else {
|
||||
var child = wn.model.add_child(me.frm.doc, "Sales Invoice Item", "entries");
|
||||
var child = wn.model.add_child(me.frm.doc, this.frm.doctype + " Item",
|
||||
this.frm.cscript.fname);
|
||||
child.item_code = item_code;
|
||||
me.frm.cscript.item_code(me.frm.doc, child.doctype, child.name);
|
||||
}
|
||||
},
|
||||
update_qty: function(item_code, qty, textbox_qty) {
|
||||
var me = this;
|
||||
$.each(wn.model.get_children("Sales Invoice Item", this.frm.doc.name, "entries",
|
||||
"Sales Invoice"), function(i, d) {
|
||||
$.each(wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name,
|
||||
this.frm.cscript.fname, this.frm.doctype), function(i, d) {
|
||||
if (d.item_code == item_code) {
|
||||
if (textbox_qty) {
|
||||
if (qty == 0 && d.item_code == item_code)
|
||||
@@ -259,14 +276,24 @@ erpnext.POS = Class.extend({
|
||||
},
|
||||
refresh: function() {
|
||||
var me = this;
|
||||
this.customer.set_input(this.frm.doc.customer);
|
||||
this.party_field.set_input(this.frm.doc[this.party.toLowerCase()]);
|
||||
this.barcode.set_input("");
|
||||
|
||||
// add items
|
||||
var $items = me.wrapper.find("#cart tbody").empty();
|
||||
|
||||
$.each(wn.model.get_children("Sales Invoice Item", this.frm.doc.name, "entries",
|
||||
"Sales Invoice"), function(i, d) {
|
||||
$.each(wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name,
|
||||
this.frm.cscript.fname, this.frm.doctype), function(i, d) {
|
||||
|
||||
if (me.sales_or_purchase == "Sales") {
|
||||
item_amount = d.export_amount;
|
||||
rate = d.export_rate;
|
||||
}
|
||||
else {
|
||||
item_amount = d.import_amount;
|
||||
rate = d.import_rate;
|
||||
}
|
||||
|
||||
$(repl('<tr id="%(item_code)s" data-selected="false">\
|
||||
<td>%(item_code)s%(item_name)s</td>\
|
||||
<td><input type="text" value="%(qty)s" \
|
||||
@@ -277,16 +304,16 @@ erpnext.POS = Class.extend({
|
||||
item_code: d.item_code,
|
||||
item_name: d.item_name===d.item_code ? "" : ("<br>" + d.item_name),
|
||||
qty: d.qty,
|
||||
rate: format_currency(d.ref_rate, cur_frm.doc.price_list_currency),
|
||||
amount: format_currency(d.export_amount, cur_frm.doc.price_list_currency)
|
||||
rate: format_currency(rate, me.frm.doc.currency),
|
||||
amount: format_currency(item_amount, me.frm.doc.currency)
|
||||
}
|
||||
)).appendTo($items);
|
||||
});
|
||||
|
||||
// taxes
|
||||
var taxes = wn.model.get_children("Sales Taxes and Charges", this.frm.doc.name, "other_charges",
|
||||
"Sales Invoice");
|
||||
$(".tax-table")
|
||||
var taxes = wn.model.get_children(this.sales_or_purchase + " Taxes and Charges",
|
||||
this.frm.doc.name, this.frm.cscript.other_fname, this.frm.doctype);
|
||||
$(this.wrapper).find(".tax-table")
|
||||
.toggle((taxes && taxes.length) ? true : false)
|
||||
.find("tbody").empty();
|
||||
|
||||
@@ -297,30 +324,39 @@ erpnext.POS = Class.extend({
|
||||
<tr>', {
|
||||
description: d.description,
|
||||
rate: d.rate,
|
||||
tax_amount: format_currency(d.tax_amount, me.frm.doc.price_list_currency)
|
||||
tax_amount: format_currency(flt(d.tax_amount)/flt(me.frm.doc.conversion_rate),
|
||||
me.frm.doc.currency)
|
||||
})).appendTo(".tax-table tbody");
|
||||
});
|
||||
|
||||
// set totals
|
||||
this.wrapper.find(".net-total").text(format_currency(this.frm.doc.net_total_export,
|
||||
cur_frm.doc.price_list_currency));
|
||||
this.wrapper.find(".grand-total").text(format_currency(this.frm.doc.grand_total_export,
|
||||
cur_frm.doc.price_list_currency));
|
||||
if (this.sales_or_purchase == "Sales") {
|
||||
this.wrapper.find(".net-total").text(format_currency(this.frm.doc.net_total_export,
|
||||
me.frm.doc.currency));
|
||||
this.wrapper.find(".grand-total").text(format_currency(this.frm.doc.grand_total_export,
|
||||
me.frm.doc.currency));
|
||||
}
|
||||
else {
|
||||
this.wrapper.find(".net-total").text(format_currency(this.frm.doc.net_total_import,
|
||||
me.frm.doc.currency));
|
||||
this.wrapper.find(".grand-total").text(format_currency(this.frm.doc.grand_total_import,
|
||||
me.frm.doc.currency));
|
||||
}
|
||||
|
||||
// if form is local then only run all these functions
|
||||
if (cur_frm.doc.docstatus===0) {
|
||||
$("input.qty").on("focus", function() {
|
||||
if (this.frm.doc.docstatus===0) {
|
||||
$(this.wrapper).find("input.qty").on("focus", function() {
|
||||
$(this).select();
|
||||
});
|
||||
|
||||
// append quantity to the respective item after change from input box
|
||||
$("input.qty").on("change", function() {
|
||||
$(this.wrapper).find("input.qty").on("change", function() {
|
||||
var item_code = $(this).closest("tr")[0].id;
|
||||
me.update_qty(item_code, $(this).val(), true);
|
||||
});
|
||||
|
||||
// on td click toggle the highlighting of row
|
||||
$("#cart tbody tr td").on("click", function() {
|
||||
$(this.wrapper).find("#cart tbody tr td").on("click", function() {
|
||||
var row = $(this).closest("tr");
|
||||
if (row.attr("data-selected") == "false") {
|
||||
row.attr("class", "warning");
|
||||
@@ -335,20 +371,37 @@ erpnext.POS = Class.extend({
|
||||
});
|
||||
|
||||
me.refresh_delete_btn();
|
||||
cur_frm.pos.barcode.$input.focus();
|
||||
this.barcode.$input.focus();
|
||||
}
|
||||
|
||||
// if form is submitted & cancelled then disable all input box & buttons
|
||||
if (cur_frm.doc.docstatus>=1 && cint(cur_frm.doc.is_pos)) {
|
||||
me.wrapper.find('input, button').each(function () {
|
||||
if (this.frm.doc.docstatus>=1) {
|
||||
$(this.wrapper).find('input, button').each(function () {
|
||||
$(this).prop('disabled', true);
|
||||
});
|
||||
$(".delete-items").hide();
|
||||
$(".make-payment").hide();
|
||||
$(this.wrapper).find(".delete-items").hide();
|
||||
$(this.wrapper).find(".make-payment").hide();
|
||||
}
|
||||
else {
|
||||
$(this.wrapper).find('input, button').each(function () {
|
||||
$(this).prop('disabled', false);
|
||||
});
|
||||
$(this.wrapper).find(".make-payment").show();
|
||||
}
|
||||
|
||||
// Show Make Payment button only in Sales Invoice
|
||||
if (this.frm.doctype != "Sales Invoice")
|
||||
$(this.wrapper).find(".make-payment").hide();
|
||||
|
||||
// If quotation to is not Customer then remove party
|
||||
if (this.frm.doctype == "Quotation") {
|
||||
this.party_field.$wrapper.remove();
|
||||
if (this.frm.doc.quotation_to == "Customer")
|
||||
this.make_party();
|
||||
}
|
||||
},
|
||||
refresh_delete_btn: function() {
|
||||
$(".delete-items").toggle($(".item-cart .warning").length ? true : false);
|
||||
$(this.wrapper).find(".delete-items").toggle($(".item-cart .warning").length ? true : false);
|
||||
},
|
||||
add_item_thru_barcode: function() {
|
||||
var me = this;
|
||||
@@ -370,32 +423,32 @@ erpnext.POS = Class.extend({
|
||||
remove_selected_item: function() {
|
||||
var me = this;
|
||||
var selected_items = [];
|
||||
var no_of_items = $("#cart tbody tr").length;
|
||||
var no_of_items = $(this.wrapper).find("#cart tbody tr").length;
|
||||
for(var x=0; x<=no_of_items - 1; x++) {
|
||||
var row = $("#cart tbody tr:eq(" + x + ")");
|
||||
var row = $(this.wrapper).find("#cart tbody tr:eq(" + x + ")");
|
||||
if(row.attr("data-selected") == "true") {
|
||||
selected_items.push(row.attr("id"));
|
||||
}
|
||||
}
|
||||
|
||||
var child = wn.model.get_children("Sales Invoice Item", this.frm.doc.name, "entries",
|
||||
"Sales Invoice");
|
||||
|
||||
var child = wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name,
|
||||
this.frm.cscript.fname, this.frm.doctype);
|
||||
|
||||
$.each(child, function(i, d) {
|
||||
for (var i in selected_items) {
|
||||
if (d.item_code == selected_items[i]) {
|
||||
// cur_frm.fields_dict["entries"].grid.grid_rows[d.idx].remove();
|
||||
wn.model.clear_doc(d.doctype, d.name);
|
||||
}
|
||||
}
|
||||
});
|
||||
cur_frm.fields_dict["entries"].grid.refresh();
|
||||
cur_frm.script_manager.trigger("calculate_taxes_and_totals");
|
||||
this.frm.fields_dict[this.frm.cscript.fname].grid.refresh();
|
||||
this.frm.script_manager.trigger("calculate_taxes_and_totals");
|
||||
me.frm.dirty();
|
||||
me.refresh();
|
||||
},
|
||||
make_payment: function() {
|
||||
var me = this;
|
||||
var no_of_items = $("#cart tbody tr").length;
|
||||
var no_of_items = $(this.wrapper).find("#cart tbody tr").length;
|
||||
var mode_of_payment = [];
|
||||
|
||||
if (no_of_items == 0)
|
||||
@@ -423,15 +476,15 @@ erpnext.POS = Class.extend({
|
||||
"total_amount": $(".grand-total").text()
|
||||
});
|
||||
dialog.show();
|
||||
cur_frm.pos.barcode.$input.focus();
|
||||
me.barcode.$input.focus();
|
||||
|
||||
dialog.get_input("total_amount").prop("disabled", true);
|
||||
|
||||
dialog.fields_dict.pay.input.onclick = function() {
|
||||
cur_frm.set_value("mode_of_payment", dialog.get_values().mode_of_payment);
|
||||
cur_frm.set_value("paid_amount", dialog.get_values().total_amount);
|
||||
cur_frm.cscript.mode_of_payment(cur_frm.doc);
|
||||
cur_frm.save();
|
||||
me.frm.set_value("mode_of_payment", dialog.get_values().mode_of_payment);
|
||||
me.frm.set_value("paid_amount", dialog.get_values().total_amount);
|
||||
me.frm.cscript.mode_of_payment(me.frm.doc);
|
||||
me.frm.save();
|
||||
dialog.hide();
|
||||
me.refresh();
|
||||
};
|
||||
|
||||
@@ -3,17 +3,21 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
from webnotes import msgprint
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get_items(price_list, item=None, item_group=None):
|
||||
def get_items(price_list, sales_or_purchase, item=None, item_group=None):
|
||||
condition = ""
|
||||
|
||||
if sales_or_purchase == "Sales":
|
||||
condition = "i.is_sales_item='Yes'"
|
||||
else:
|
||||
condition = "i.is_purchase_item='Yes'"
|
||||
|
||||
if item_group and item_group != "All Item Groups":
|
||||
condition = "and i.item_group='%s'" % item_group
|
||||
condition += " and i.item_group='%s'" % item_group
|
||||
|
||||
if item:
|
||||
condition = "and i.name='%s'" % item
|
||||
condition += " and i.name='%s'" % item
|
||||
|
||||
return webnotes.conn.sql("""select i.name, i.item_name, i.image,
|
||||
pl_items.ref_rate, pl_items.currency
|
||||
@@ -24,13 +28,18 @@ def get_items(price_list, item=None, item_group=None):
|
||||
ON
|
||||
pl_items.item_code=i.name
|
||||
where
|
||||
i.is_sales_item='Yes'%s""" % ('%s', condition), (price_list), as_dict=1)
|
||||
%s""" % ('%s', condition), (price_list), as_dict=1)
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get_item_from_barcode(barcode):
|
||||
return webnotes.conn.sql("""select name from `tabItem` where barcode=%s""",
|
||||
(barcode), as_dict=1)
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get_item_from_serial_no(serial_no):
|
||||
return webnotes.conn.sql("""select name, item_code from `tabSerial No` where
|
||||
name=%s""", (serial_no), as_dict=1)
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get_mode_of_payment():
|
||||
return webnotes.conn.sql("""select name from `tabMode of Payment`""", as_dict=1)
|
||||
@@ -1,15 +0,0 @@
|
||||
.pos-item {
|
||||
height: 200px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
padding-left: 5px !important;
|
||||
padding-right: 5px !important;
|
||||
}
|
||||
|
||||
.pos-bill {
|
||||
padding: 20px 5px;
|
||||
font-family: Monospace;
|
||||
border: 1px solid #eee;
|
||||
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
|
||||
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
|
||||
}
|
||||
@@ -29,9 +29,10 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
// toggle to pos view if is_pos is 1 in user_defaults
|
||||
if ((cint(wn.defaults.get_user_defaults("is_pos"))===1 || cur_frm.doc.is_pos) &&
|
||||
cint(wn.defaults.get_user_defaults("fs_pos_view"))===1) {
|
||||
this.frm.set_value("is_pos", 1);
|
||||
this.is_pos();
|
||||
cur_frm.cscript.toggle_pos(true);
|
||||
if(this.frm.doc.__islocal && !this.frm.doc.amended_from) {
|
||||
this.frm.set_value("is_pos", 1);
|
||||
this.is_pos(function() {cur_frm.cscript.toggle_pos(true);});
|
||||
}
|
||||
}
|
||||
|
||||
// if document is POS then change default print format to "POS Invoice"
|
||||
@@ -78,14 +79,11 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
cur_frm.add_custom_button('Make Payment Entry', cur_frm.cscript.make_bank_voucher);
|
||||
}
|
||||
|
||||
if (doc.docstatus===0) {
|
||||
// Show buttons only when pos view is active
|
||||
if (doc.docstatus===0 && !this.pos_active) {
|
||||
cur_frm.cscript.sales_order_btn();
|
||||
cur_frm.cscript.delivery_note_btn();
|
||||
}
|
||||
|
||||
// Show POS button only if it enabled from features setup
|
||||
if(cint(sys_defaults.fs_pos_view)===1)
|
||||
cur_frm.cscript.pos_btn();
|
||||
},
|
||||
|
||||
sales_order_btn: function() {
|
||||
@@ -124,62 +122,13 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
pos_btn: function() {
|
||||
if(cur_frm.$pos_btn)
|
||||
cur_frm.$pos_btn.remove();
|
||||
|
||||
if(!cur_frm.pos_active) {
|
||||
var btn_label = wn._("POS View"),
|
||||
icon = "icon-desktop";
|
||||
|
||||
cur_frm.cscript.sales_order_btn();
|
||||
cur_frm.cscript.delivery_note_btn();
|
||||
} else {
|
||||
var btn_label = wn._("Invoice View"),
|
||||
icon = "icon-file-text";
|
||||
|
||||
if (cur_frm.doc.docstatus===0) {
|
||||
this.$delivery_note_btn.remove();
|
||||
this.$sales_order_btn.remove();
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.$pos_btn = cur_frm.add_custom_button(btn_label, function() {
|
||||
cur_frm.cscript.toggle_pos();
|
||||
cur_frm.cscript.pos_btn();
|
||||
}, icon);
|
||||
},
|
||||
|
||||
toggle_pos: function(show) {
|
||||
if (!this.frm.doc.selling_price_list)
|
||||
msgprint(wn._("Please select Price List"))
|
||||
else {
|
||||
if((show===true && cur_frm.pos_active) || (show===false && !cur_frm.pos_active)) return;
|
||||
|
||||
// make pos
|
||||
if(!cur_frm.pos) {
|
||||
cur_frm.layout.add_view("pos");
|
||||
cur_frm.pos = new erpnext.POS(cur_frm.layout.views.pos, cur_frm);
|
||||
}
|
||||
|
||||
// toggle view
|
||||
cur_frm.layout.set_view(cur_frm.pos_active ? "" : "pos");
|
||||
cur_frm.pos_active = !cur_frm.pos_active;
|
||||
|
||||
// refresh
|
||||
if(cur_frm.pos_active)
|
||||
cur_frm.pos.refresh();
|
||||
}
|
||||
},
|
||||
|
||||
tc_name: function() {
|
||||
this.get_terms();
|
||||
},
|
||||
|
||||
is_pos: function() {
|
||||
is_pos: function(callback_fn) {
|
||||
cur_frm.cscript.hide_fields(this.frm.doc);
|
||||
|
||||
if(cint(this.frm.doc.is_pos)) {
|
||||
if(!this.frm.doc.company) {
|
||||
this.frm.set_value("is_pos", 0);
|
||||
@@ -192,11 +141,13 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
callback: function(r) {
|
||||
if(!r.exc) {
|
||||
me.frm.script_manager.trigger("update_stock");
|
||||
if(callback_fn) callback_fn()
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
debit_to: function() {
|
||||
@@ -385,7 +336,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,15 +82,13 @@ class DocType(SellingController):
|
||||
|
||||
def on_submit(self):
|
||||
if cint(self.doc.update_stock) == 1:
|
||||
self.update_stock_ledger(update_stock=1)
|
||||
self.update_serial_nos()
|
||||
self.update_stock_ledger()
|
||||
else:
|
||||
# Check for Approving Authority
|
||||
if not self.doc.recurring_id:
|
||||
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,8 +109,7 @@ class DocType(SellingController):
|
||||
|
||||
def on_cancel(self):
|
||||
if cint(self.doc.update_stock) == 1:
|
||||
self.update_stock_ledger(update_stock = -1)
|
||||
self.update_serial_nos(cancel = True)
|
||||
self.update_stock_ledger()
|
||||
|
||||
sales_com_obj = get_obj(dt = 'Sales Common')
|
||||
sales_com_obj.check_stop_sales_order(self)
|
||||
@@ -196,9 +193,7 @@ class DocType(SellingController):
|
||||
pos = get_pos_settings(self.doc.company)
|
||||
|
||||
if pos:
|
||||
self.doc.conversion_rate = flt(pos.conversion_rate)
|
||||
|
||||
if not for_validate:
|
||||
if not for_validate and not self.doc.customer:
|
||||
self.doc.customer = pos.customer
|
||||
self.set_customer_defaults()
|
||||
|
||||
@@ -269,13 +264,7 @@ class DocType(SellingController):
|
||||
|
||||
def get_adj_percent(self, arg=''):
|
||||
"""Fetch ref rate from item master as per selected price list"""
|
||||
get_obj('Sales Common').get_adj_percent(self)
|
||||
|
||||
|
||||
def get_rate(self,arg):
|
||||
"""Get tax rate if account type is tax"""
|
||||
get_obj('Sales Common').get_rate(arg)
|
||||
|
||||
get_obj('Sales Common').get_adj_percent(self)
|
||||
|
||||
def get_comm_rate(self, sales_partner):
|
||||
"""Get Commission rate of Sales Partner"""
|
||||
@@ -526,41 +515,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 +550,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 +595,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:
|
||||
@@ -993,8 +957,7 @@ def make_delivery_note(source_name, target_doclist=None):
|
||||
"doctype": "Delivery Note Item",
|
||||
"field_map": {
|
||||
"name": "prevdoc_detail_docname",
|
||||
"parent": "prevdoc_docname",
|
||||
"parenttype": "prevdoc_doctype",
|
||||
"parent": "against_sales_invoice",
|
||||
"serial_no": "serial_no"
|
||||
},
|
||||
"postprocess": update_item
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
{
|
||||
"creation": "2013-05-24 19:29:05",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-09-01 05:26:13",
|
||||
"modified": "2013-10-03 18:54:31",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
{
|
||||
"allow_attach": 1,
|
||||
"allow_import": 1,
|
||||
"autoname": "naming_series:",
|
||||
"default_print_format": "Standard",
|
||||
"doctype": "DocType",
|
||||
@@ -411,7 +412,7 @@
|
||||
"doctype": "DocField",
|
||||
"fieldname": "other_charges",
|
||||
"fieldtype": "Table",
|
||||
"label": "Taxes and Charges1",
|
||||
"label": "Sales Taxes and Charges",
|
||||
"oldfieldname": "other_charges",
|
||||
"oldfieldtype": "Table",
|
||||
"options": "Sales Taxes and Charges",
|
||||
|
||||
@@ -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 \
|
||||
@@ -642,14 +641,19 @@ 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
|
||||
# if yearly, test 1 repetition, else test 5 repetitions
|
||||
count = 1 if (no_of_months == 12) else 5
|
||||
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
|
||||
from stock.doctype.stock_ledger_entry.stock_ledger_entry import get_serial_nos
|
||||
from stock.doctype.serial_no.serial_no import get_serial_nos
|
||||
|
||||
se = make_serialized_item()
|
||||
serial_nos = get_serial_nos(se.doclist[1].serial_no)
|
||||
@@ -670,7 +674,7 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
return si
|
||||
|
||||
def test_serialized_cancel(self):
|
||||
from stock.doctype.stock_ledger_entry.stock_ledger_entry import get_serial_nos
|
||||
from stock.doctype.serial_no.serial_no import get_serial_nos
|
||||
si = self.test_serialized()
|
||||
si.cancel()
|
||||
|
||||
@@ -682,7 +686,7 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
"delivery_document_no"))
|
||||
|
||||
def test_serialize_status(self):
|
||||
from stock.doctype.stock_ledger_entry.stock_ledger_entry import SerialNoStatusError, get_serial_nos
|
||||
from stock.doctype.serial_no.serial_no import SerialNoStatusError, get_serial_nos
|
||||
from stock.doctype.stock_entry.test_stock_entry import make_serialized_item
|
||||
|
||||
se = 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",
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
// License: GNU General Public License v3. See license.txt
|
||||
|
||||
//--------- ONLOAD -------------
|
||||
|
||||
wn.require("app/js/controllers/accounts.js");
|
||||
|
||||
cur_frm.cscript.onload = function(doc, cdt, cdn) {
|
||||
if(doc.doctype === "Sales Taxes and Charges Master")
|
||||
erpnext.add_for_territory();
|
||||
@@ -142,21 +145,6 @@ cur_frm.fields_dict['other_charges'].grid.get_field("cost_center").get_query = f
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cur_frm.cscript.account_head = function(doc, cdt, cdn) {
|
||||
var d = locals[cdt][cdn];
|
||||
if(!d.charge_type && d.account_head){
|
||||
alert("Please select Charge Type first");
|
||||
validated = false;
|
||||
d.account_head = '';
|
||||
}
|
||||
else if(d.account_head && d.charge_type) {
|
||||
arg = "{'charge_type' : '" + d.charge_type +"', 'account_head' : '" + d.account_head + "'}";
|
||||
return get_server_fields('get_rate', arg, 'other_charges', doc, cdt, cdn, 1);
|
||||
}
|
||||
refresh_field('account_head',d.name,'other_charges');
|
||||
}
|
||||
|
||||
cur_frm.cscript.rate = function(doc, cdt, cdn) {
|
||||
var d = locals[cdt][cdn];
|
||||
if(!d.charge_type && d.rate) {
|
||||
|
||||
@@ -6,11 +6,7 @@ import webnotes
|
||||
from webnotes.utils import cint
|
||||
from webnotes.model.controller import DocListController
|
||||
|
||||
class DocType(DocListController):
|
||||
def get_rate(self, arg):
|
||||
from webnotes.model.code import get_obj
|
||||
return get_obj('Sales Common').get_rate(arg)
|
||||
|
||||
class DocType(DocListController):
|
||||
def validate(self):
|
||||
if self.doc.is_default == 1:
|
||||
webnotes.conn.sql("""update `tabSales Taxes and Charges Master` set is_default = 0
|
||||
|
||||
@@ -5,17 +5,35 @@ from __future__ import unicode_literals
|
||||
import webnotes
|
||||
from webnotes.utils import flt, cstr, now
|
||||
from webnotes.model.doc import Document
|
||||
from webnotes import msgprint, _
|
||||
from accounts.utils import validate_expense_against_budget
|
||||
|
||||
|
||||
class StockAccountInvalidTransaction(webnotes.ValidationError): pass
|
||||
|
||||
def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True,
|
||||
update_outstanding='Yes'):
|
||||
if gl_map:
|
||||
if not cancel:
|
||||
gl_map = process_gl_map(gl_map, merge_entries)
|
||||
save_entries(gl_map, adv_adj, update_outstanding)
|
||||
else:
|
||||
delete_gl_entries(gl_map, adv_adj=adv_adj, update_outstanding=update_outstanding)
|
||||
|
||||
def process_gl_map(gl_map, merge_entries=True):
|
||||
if merge_entries:
|
||||
gl_map = merge_similar_entries(gl_map)
|
||||
|
||||
if cancel:
|
||||
set_as_cancel(gl_map[0]["voucher_type"], gl_map[0]["voucher_no"])
|
||||
for entry in gl_map:
|
||||
# round off upto 2 decimal
|
||||
entry.debit = flt(entry.debit, 2)
|
||||
entry.credit = flt(entry.credit, 2)
|
||||
|
||||
# toggle debit, credit if negative entry
|
||||
if flt(entry.debit) < 0 or flt(entry.credit) < 0:
|
||||
entry.debit, entry.credit = abs(flt(entry.credit)), abs(flt(entry.debit))
|
||||
|
||||
check_budget(gl_map, cancel)
|
||||
save_entries(gl_map, cancel, adv_adj, update_outstanding)
|
||||
return gl_map
|
||||
|
||||
def merge_similar_entries(gl_map):
|
||||
merged_gl_map = []
|
||||
@@ -24,79 +42,86 @@ def merge_similar_entries(gl_map):
|
||||
# to that entry
|
||||
same_head = check_if_in_list(entry, merged_gl_map)
|
||||
if same_head:
|
||||
same_head['debit'] = flt(same_head['debit']) + flt(entry['debit'])
|
||||
same_head['credit'] = flt(same_head['credit']) + flt(entry['credit'])
|
||||
same_head.debit = flt(same_head.debit) + flt(entry.debit)
|
||||
same_head.credit = flt(same_head.credit) + flt(entry.credit)
|
||||
else:
|
||||
merged_gl_map.append(entry)
|
||||
|
||||
|
||||
# filter zero debit and credit entries
|
||||
merged_gl_map = filter(lambda x: flt(x.debit)!=0 or flt(x.credit)!=0, merged_gl_map)
|
||||
return merged_gl_map
|
||||
|
||||
def check_if_in_list(gle, gl_mqp):
|
||||
for e in gl_mqp:
|
||||
if e['account'] == gle['account'] and \
|
||||
def check_if_in_list(gle, gl_map):
|
||||
for e in gl_map:
|
||||
if e.account == gle.account and \
|
||||
cstr(e.get('against_voucher'))==cstr(gle.get('against_voucher')) \
|
||||
and cstr(e.get('against_voucher_type')) == \
|
||||
cstr(gle.get('against_voucher_type')) \
|
||||
and cstr(e.get('cost_center')) == cstr(gle.get('cost_center')):
|
||||
return e
|
||||
|
||||
def check_budget(gl_map, cancel):
|
||||
for gle in gl_map:
|
||||
if gle.get('cost_center'):
|
||||
#check budget only if account is expense account
|
||||
acc_details = webnotes.conn.get_value("Account", gle['account'],
|
||||
['is_pl_account', 'debit_or_credit'])
|
||||
if acc_details[0]=="Yes" and acc_details[1]=="Debit":
|
||||
webnotes.get_obj('Budget Control').check_budget(gle, cancel)
|
||||
|
||||
def save_entries(gl_map, cancel, adv_adj, update_outstanding):
|
||||
def save_entries(gl_map, adv_adj, update_outstanding):
|
||||
validate_account_for_auto_accounting_for_stock(gl_map)
|
||||
|
||||
total_debit = total_credit = 0.0
|
||||
def _swap(gle):
|
||||
gle.debit, gle.credit = abs(flt(gle.credit)), abs(flt(gle.debit))
|
||||
|
||||
for entry in gl_map:
|
||||
gle = Document('GL Entry', fielddata=entry)
|
||||
make_entry(entry, adv_adj, update_outstanding)
|
||||
# check against budget
|
||||
validate_expense_against_budget(entry)
|
||||
|
||||
# round off upto 2 decimal
|
||||
gle.debit = flt(gle.debit, 2)
|
||||
gle.credit = flt(gle.credit, 2)
|
||||
|
||||
# toggle debit, credit if negative entry
|
||||
if flt(gle.debit) < 0 or flt(gle.credit) < 0:
|
||||
_swap(gle)
|
||||
|
||||
# toggled debit/credit in two separate condition because
|
||||
# both should be executed at the
|
||||
# time of cancellation when there is negative amount (tax discount)
|
||||
if cancel:
|
||||
_swap(gle)
|
||||
|
||||
gle_obj = webnotes.get_obj(doc=gle)
|
||||
# validate except on_cancel
|
||||
if not cancel:
|
||||
gle_obj.validate()
|
||||
|
||||
# save
|
||||
gle.save(1)
|
||||
gle_obj.on_update(adv_adj, cancel, update_outstanding)
|
||||
|
||||
# update total debit / credit
|
||||
total_debit += flt(gle.debit)
|
||||
total_credit += flt(gle.credit)
|
||||
total_debit += flt(entry.debit)
|
||||
total_credit += flt(entry.credit)
|
||||
|
||||
# print gle.account, gle.debit, gle.credit, total_debit, total_credit
|
||||
|
||||
if not cancel:
|
||||
validate_total_debit_credit(total_debit, total_credit)
|
||||
validate_total_debit_credit(total_debit, total_credit)
|
||||
|
||||
def make_entry(args, adv_adj, update_outstanding):
|
||||
args.update({"doctype": "GL Entry"})
|
||||
gle = webnotes.bean([args])
|
||||
gle.ignore_permissions = 1
|
||||
gle.insert()
|
||||
gle.run_method("on_update_with_args", adv_adj, update_outstanding)
|
||||
gle.submit()
|
||||
|
||||
def validate_total_debit_credit(total_debit, total_credit):
|
||||
if abs(total_debit - total_credit) > 0.005:
|
||||
webnotes.msgprint("""Debit and Credit not equal for
|
||||
this voucher: Diff (Debit) is %s""" %
|
||||
(total_debit - total_credit), raise_exception=1)
|
||||
|
||||
def set_as_cancel(voucher_type, voucher_no):
|
||||
webnotes.conn.sql("""update `tabGL Entry` set is_cancelled='Yes',
|
||||
modified=%s, modified_by=%s
|
||||
where voucher_type=%s and voucher_no=%s""",
|
||||
(now(), webnotes.session.user, voucher_type, voucher_no))
|
||||
webnotes.throw(_("Debit and Credit not equal for this voucher: Diff (Debit) is ") +
|
||||
cstr(total_debit - total_credit))
|
||||
|
||||
def validate_account_for_auto_accounting_for_stock(gl_map):
|
||||
if gl_map[0].voucher_type=="Journal Voucher":
|
||||
aii_accounts = [d[0] for d in webnotes.conn.sql("""select name from tabAccount
|
||||
where account_type = 'Warehouse' and ifnull(master_name, '')!=''""")]
|
||||
|
||||
for entry in gl_map:
|
||||
if entry.account in aii_accounts:
|
||||
webnotes.throw(_("Account") + ": " + entry.account +
|
||||
_(" can only be debited/credited through Stock transactions"),
|
||||
StockAccountInvalidTransaction)
|
||||
|
||||
|
||||
def delete_gl_entries(gl_entries=None, voucher_type=None, voucher_no=None,
|
||||
adv_adj=False, update_outstanding="Yes"):
|
||||
|
||||
from accounts.doctype.gl_entry.gl_entry import check_negative_balance, \
|
||||
check_freezing_date, update_outstanding_amt, validate_frozen_account
|
||||
|
||||
if not gl_entries:
|
||||
gl_entries = webnotes.conn.sql("""select * from `tabGL Entry`
|
||||
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no), as_dict=True)
|
||||
if gl_entries:
|
||||
check_freezing_date(gl_entries[0]["posting_date"], adv_adj)
|
||||
|
||||
webnotes.conn.sql("""delete from `tabGL Entry` where voucher_type=%s and voucher_no=%s""",
|
||||
(voucher_type or gl_entries[0]["voucher_type"], voucher_no or gl_entries[0]["voucher_no"]))
|
||||
|
||||
for entry in gl_entries:
|
||||
validate_frozen_account(entry["account"], adv_adj)
|
||||
check_negative_balance(entry["account"], adv_adj)
|
||||
validate_expense_against_budget(entry)
|
||||
|
||||
if entry.get("against_voucher") and entry.get("against_voucher_type") != "POS" \
|
||||
and update_outstanding == 'Yes':
|
||||
update_outstanding_amt(entry["account"], entry.get("against_voucher_type"),
|
||||
entry.get("against_voucher"), on_cancel=True)
|
||||
@@ -15,7 +15,7 @@ def get_companies():
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get_children():
|
||||
args = webnotes.form_dict
|
||||
args = webnotes.local.form_dict
|
||||
ctype, company = args['ctype'], args['comp']
|
||||
|
||||
# root
|
||||
|
||||
@@ -64,10 +64,10 @@ def upload():
|
||||
|
||||
data, start_idx = get_data(rows, company_abbr, rows[0][0])
|
||||
except Exception, e:
|
||||
err_msg = webnotes.message_log and "<br>".join(webnotes.message_log) or cstr(e)
|
||||
err_msg = webnotes.local.message_log and "<br>".join(webnotes.local.message_log) or cstr(e)
|
||||
messages.append("""<p style='color: red'>%s</p>""" % (err_msg or "No message"))
|
||||
webnotes.errprint(webnotes.getTraceback())
|
||||
webnotes.message_log = []
|
||||
webnotes.local.message_log = []
|
||||
return messages
|
||||
|
||||
return import_vouchers(common_values, data, start_idx, rows[0][0])
|
||||
@@ -104,7 +104,7 @@ def import_vouchers(common_values, data, start_idx, import_type):
|
||||
|
||||
if account.master_name:
|
||||
map_fields(["against_sales_invoice:against_invoice",
|
||||
"against_purhase_invoice:against_voucher",
|
||||
"against_purchase_invoice:against_voucher",
|
||||
"against_journal_voucher:against_jv"], d, detail.fields)
|
||||
|
||||
webnotes.conn.commit()
|
||||
@@ -117,11 +117,11 @@ def import_vouchers(common_values, data, start_idx, import_type):
|
||||
|
||||
d = data[i][0]
|
||||
if import_type == "Voucher Import: Two Accounts" and flt(d.get("amount")) == 0:
|
||||
webnotes.message_log = ["Amount not specified"]
|
||||
webnotes.local.message_log = ["Amount not specified"]
|
||||
raise Exception
|
||||
elif import_type == "Voucher Import: Multiple Accounts" and \
|
||||
(flt(d.get("total_debit")) == 0 or flt(d.get("total_credit")) == 0):
|
||||
webnotes.message_log = ["Total Debit and Total Credit amount can not be zero"]
|
||||
webnotes.local.message_log = ["Total Debit and Total Credit amount can not be zero"]
|
||||
raise Exception
|
||||
else:
|
||||
d.posting_date = parse_date(d.posting_date)
|
||||
@@ -174,7 +174,7 @@ def import_vouchers(common_values, data, start_idx, import_type):
|
||||
details.append(detail)
|
||||
|
||||
if not details:
|
||||
webnotes.message_log = ["""No accounts found.
|
||||
webnotes.local.message_log = ["""No accounts found.
|
||||
If you entered accounts correctly, please check template once"""]
|
||||
raise Exception
|
||||
|
||||
@@ -193,12 +193,12 @@ def import_vouchers(common_values, data, start_idx, import_type):
|
||||
webnotes.conn.commit()
|
||||
except Exception, e:
|
||||
webnotes.conn.rollback()
|
||||
err_msg = webnotes.message_log and "<br>".join(webnotes.message_log) or cstr(e)
|
||||
err_msg = webnotes.local.message_log and "<br>".join(webnotes.local.message_log) or cstr(e)
|
||||
messages.append("""<p style='color: red'>[row #%s] %s failed: %s</p>"""
|
||||
% ((start_idx + 1) + i, jv.name or "", err_msg or "No message"))
|
||||
messages.append("<p style='color: red'>All transactions rolled back</p>")
|
||||
webnotes.errprint(webnotes.getTraceback())
|
||||
webnotes.message_log = []
|
||||
webnotes.local.message_log = []
|
||||
|
||||
return messages
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ def get_gl_entries(filters, before_report_date=True):
|
||||
conditions, supplier_accounts = get_conditions(filters, before_report_date)
|
||||
gl_entries = []
|
||||
gl_entries = webnotes.conn.sql("""select * from `tabGL Entry`
|
||||
where ifnull(is_cancelled, 'No') = 'No' %s order by posting_date, account""" %
|
||||
where docstatus < 2 %s order by posting_date, account""" %
|
||||
(conditions), tuple(supplier_accounts), as_dict=1)
|
||||
return gl_entries
|
||||
|
||||
@@ -126,7 +126,7 @@ def get_outstanding_amount(gle, report_date):
|
||||
select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))
|
||||
from `tabGL Entry`
|
||||
where account = %s and posting_date <= %s and against_voucher_type = %s
|
||||
and against_voucher = %s and name != %s and ifnull(is_cancelled, 'No') = 'No'""",
|
||||
and against_voucher = %s and name != %s""",
|
||||
(gle.account, report_date, gle.voucher_type, gle.voucher_no, gle.name))[0][0]
|
||||
|
||||
outstanding_amount = flt(gle.credit) - flt(gle.debit) - flt(payment_amount)
|
||||
|
||||
@@ -65,7 +65,7 @@ def get_columns():
|
||||
def get_gl_entries(filters, upto_report_date=True):
|
||||
conditions, customer_accounts = get_conditions(filters, upto_report_date)
|
||||
return webnotes.conn.sql("""select * from `tabGL Entry`
|
||||
where ifnull(is_cancelled, 'No') = 'No' %s order by posting_date, account""" %
|
||||
where docstatus < 2 %s order by posting_date, account""" %
|
||||
(conditions), tuple(customer_accounts), as_dict=1)
|
||||
|
||||
def get_conditions(filters, upto_report_date=True):
|
||||
@@ -116,7 +116,7 @@ def get_outstanding_amount(gle, report_date):
|
||||
select sum(ifnull(credit, 0)) - sum(ifnull(debit, 0))
|
||||
from `tabGL Entry`
|
||||
where account = %s and posting_date <= %s and against_voucher_type = %s
|
||||
and against_voucher = %s and name != %s and ifnull(is_cancelled, 'No') = 'No'""",
|
||||
and against_voucher = %s and name != %s""",
|
||||
(gle.account, report_date, gle.voucher_type, gle.voucher_no, gle.name))[0][0]
|
||||
|
||||
return flt(gle.debit) - flt(gle.credit) - flt(payment_amount)
|
||||
@@ -130,7 +130,7 @@ def get_payment_amount(gle, report_date, entries_after_report_date):
|
||||
payment_amount = webnotes.conn.sql("""
|
||||
select sum(ifnull(credit, 0)) - sum(ifnull(debit, 0)) from `tabGL Entry`
|
||||
where account = %s and posting_date <= %s and against_voucher_type = %s
|
||||
and against_voucher = %s and name != %s and ifnull(is_cancelled, 'No') = 'No'""",
|
||||
and against_voucher = %s and name != %s""",
|
||||
(gle.account, report_date, gle.voucher_type, gle.voucher_no, gle.name))[0][0]
|
||||
|
||||
return flt(payment_amount)
|
||||
|
||||
@@ -87,7 +87,7 @@ def get_actual_details(filters):
|
||||
return webnotes.conn.sql("""select gl.account, gl.debit, gl.credit,
|
||||
gl.cost_center, MONTHNAME(gl.posting_date) as month_name
|
||||
from `tabGL Entry` gl, `tabBudget Detail` bd
|
||||
where gl.fiscal_year=%s and company=%s and is_cancelled='No'
|
||||
where gl.fiscal_year=%s and company=%s
|
||||
and bd.account=gl.account""" % ('%s', '%s'),
|
||||
(filters.get("fiscal_year"), filters.get("company")), as_dict=1)
|
||||
|
||||
|
||||
@@ -52,11 +52,10 @@ def get_stock_ledger_entries(filters):
|
||||
query = """select item_code, voucher_type, voucher_no,
|
||||
voucher_detail_no, posting_date, posting_time, stock_value,
|
||||
warehouse, actual_qty as qty
|
||||
from `tabStock Ledger Entry`
|
||||
where ifnull(`is_cancelled`, "No") = "No" """
|
||||
from `tabStock Ledger Entry`"""
|
||||
|
||||
if filters.get("company"):
|
||||
query += """ and company=%(company)s"""
|
||||
query += """ where company=%(company)s"""
|
||||
|
||||
query += " order by item_code desc, warehouse desc, posting_date desc, posting_time desc, name desc"
|
||||
|
||||
|
||||
@@ -81,12 +81,12 @@ def get_tax_accounts(item_list, columns):
|
||||
if account_head not in tax_accounts:
|
||||
tax_accounts.append(account_head)
|
||||
|
||||
invoice = item_tax.setdefault(parent, {})
|
||||
if item_wise_tax_detail:
|
||||
try:
|
||||
item_wise_tax_detail = json.loads(item_wise_tax_detail)
|
||||
for item, tax_amount in item_wise_tax_detail.items():
|
||||
invoice.setdefault(item, {})[account_head] = flt(tax_amount)
|
||||
item_tax.setdefault(parent, {}).setdefault(item, {})[account_head] = \
|
||||
flt(tax_amount[1])
|
||||
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
@@ -9,7 +9,7 @@ def execute(filters=None):
|
||||
if not filters: filters = {}
|
||||
columns = get_columns()
|
||||
last_col = len(columns)
|
||||
|
||||
|
||||
item_list = get_items(filters)
|
||||
item_tax, tax_accounts = get_tax_accounts(item_list, columns)
|
||||
|
||||
@@ -21,7 +21,7 @@ def execute(filters=None):
|
||||
|
||||
for tax in tax_accounts:
|
||||
row.append(item_tax.get(d.parent, {}).get(d.item_code, {}).get(tax, 0))
|
||||
|
||||
|
||||
total_tax = sum(row[last_col:])
|
||||
row += [total_tax, d.amount + total_tax]
|
||||
|
||||
@@ -71,19 +71,19 @@ def get_tax_accounts(item_list, columns):
|
||||
tax_details = webnotes.conn.sql("""select parent, account_head, item_wise_tax_detail
|
||||
from `tabSales Taxes and Charges` where parenttype = 'Sales Invoice'
|
||||
and docstatus = 1 and ifnull(account_head, '') != ''
|
||||
and parent in (%s)""" % ', '.join(['%s']*len(item_list)), tuple([item.parent for item in item_list]))
|
||||
and parent in (%s)""" % ', '.join(['%s']*len(item_list)),
|
||||
tuple([item.parent for item in item_list]))
|
||||
|
||||
for parent, account_head, item_wise_tax_detail in tax_details:
|
||||
if account_head not in tax_accounts:
|
||||
tax_accounts.append(account_head)
|
||||
|
||||
invoice = item_tax.setdefault(parent, {})
|
||||
|
||||
if item_wise_tax_detail:
|
||||
try:
|
||||
item_wise_tax_detail = json.loads(item_wise_tax_detail)
|
||||
for item, tax_amount in item_wise_tax_detail.items():
|
||||
invoice.setdefault(item, {})[account_head] = flt(tax_amount)
|
||||
|
||||
item_tax.setdefault(parent, {}).setdefault(item, {})[account_head] = \
|
||||
flt(tax_amount[1])
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import webnotes
|
||||
from webnotes.utils import nowdate, cstr, flt, now
|
||||
from webnotes.utils import nowdate, nowtime, cstr, flt, now, getdate, add_months
|
||||
from webnotes.model.doc import addchild
|
||||
from webnotes import msgprint, _
|
||||
from webnotes.utils import formatdate
|
||||
@@ -12,6 +12,8 @@ from utilities import build_filter_conditions
|
||||
|
||||
|
||||
class FiscalYearError(webnotes.ValidationError): pass
|
||||
class BudgetError(webnotes.ValidationError): pass
|
||||
|
||||
|
||||
def get_fiscal_year(date=None, fiscal_year=None, label="Date", verbose=1):
|
||||
return get_fiscal_years(date, fiscal_year, label, verbose=1)[0]
|
||||
@@ -91,15 +93,10 @@ def get_balance_on(account=None, date=None):
|
||||
else:
|
||||
cond.append("""gle.account = "%s" """ % (account, ))
|
||||
|
||||
# join conditional conditions
|
||||
cond = " and ".join(cond)
|
||||
if cond:
|
||||
cond += " and "
|
||||
|
||||
bal = webnotes.conn.sql("""
|
||||
SELECT sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))
|
||||
FROM `tabGL Entry` gle
|
||||
WHERE %s ifnull(is_cancelled, 'No') = 'No' """ % (cond, ))[0][0]
|
||||
WHERE %s""" % " and ".join(cond))[0][0]
|
||||
|
||||
# if credit account, it should calculate credit - debit
|
||||
if bal and acc.debit_or_credit == 'Credit':
|
||||
@@ -111,7 +108,7 @@ def get_balance_on(account=None, date=None):
|
||||
@webnotes.whitelist()
|
||||
def add_ac(args=None):
|
||||
if not args:
|
||||
args = webnotes.form_dict
|
||||
args = webnotes.local.form_dict
|
||||
args.pop("cmd")
|
||||
|
||||
ac = webnotes.bean(args)
|
||||
@@ -124,7 +121,7 @@ def add_ac(args=None):
|
||||
@webnotes.whitelist()
|
||||
def add_cc(args=None):
|
||||
if not args:
|
||||
args = webnotes.form_dict
|
||||
args = webnotes.local.form_dict
|
||||
args.pop("cmd")
|
||||
|
||||
cc = webnotes.bean(args)
|
||||
@@ -236,8 +233,7 @@ def remove_against_link_from_jv(ref_type, ref_no, against_field):
|
||||
set against_voucher_type=null, against_voucher=null,
|
||||
modified=%s, modified_by=%s
|
||||
where against_voucher_type=%s and against_voucher=%s
|
||||
and voucher_no != ifnull(against_voucher, "")
|
||||
and ifnull(is_cancelled, "No")="No" """,
|
||||
and voucher_no != ifnull(against_voucher, '')""",
|
||||
(now(), webnotes.session.user, ref_type, ref_no))
|
||||
|
||||
@webnotes.whitelist()
|
||||
@@ -250,79 +246,6 @@ def get_company_default(company, fieldname):
|
||||
_("' in Company: ") + company), raise_exception=True)
|
||||
|
||||
return value
|
||||
|
||||
def create_stock_in_hand_jv(reverse=False):
|
||||
from webnotes.utils import nowdate
|
||||
today = nowdate()
|
||||
fiscal_year = get_fiscal_year(today)[0]
|
||||
jv_list = []
|
||||
|
||||
for company in webnotes.conn.sql_list("select name from `tabCompany`"):
|
||||
stock_rbnb_value = get_stock_rbnb_value(company)
|
||||
stock_rbnb_value = reverse and -1*stock_rbnb_value or stock_rbnb_value
|
||||
if stock_rbnb_value:
|
||||
jv = webnotes.bean([
|
||||
{
|
||||
"doctype": "Journal Voucher",
|
||||
"naming_series": "JV-AUTO-",
|
||||
"company": company,
|
||||
"posting_date": today,
|
||||
"fiscal_year": fiscal_year,
|
||||
"voucher_type": "Journal Entry",
|
||||
"user_remark": (_("Auto Inventory Accounting") + ": " +
|
||||
(_("Disabled") if reverse else _("Enabled")) + ". " +
|
||||
_("Journal Entry for inventory that is received but not yet invoiced"))
|
||||
},
|
||||
{
|
||||
"doctype": "Journal Voucher Detail",
|
||||
"parentfield": "entries",
|
||||
"account": get_company_default(company, "stock_received_but_not_billed"),
|
||||
(stock_rbnb_value > 0 and "credit" or "debit"): abs(stock_rbnb_value)
|
||||
},
|
||||
{
|
||||
"doctype": "Journal Voucher Detail",
|
||||
"parentfield": "entries",
|
||||
"account": get_company_default(company, "stock_adjustment_account"),
|
||||
(stock_rbnb_value > 0 and "debit" or "credit"): abs(stock_rbnb_value),
|
||||
"cost_center": get_company_default(company, "stock_adjustment_cost_center")
|
||||
},
|
||||
])
|
||||
jv.insert()
|
||||
|
||||
jv_list.append(jv.doc.name)
|
||||
|
||||
if jv_list:
|
||||
msgprint(_("Following Journal Vouchers have been created automatically") + \
|
||||
":\n%s" % ("\n".join([("<a href=\"#Form/Journal Voucher/%s\">%s</a>" % (jv, jv)) for jv in jv_list]),))
|
||||
|
||||
msgprint(_("""These adjustment vouchers book the difference between \
|
||||
the total value of received items and the total value of invoiced items, \
|
||||
as a required step to use Auto Inventory Accounting.
|
||||
This is an approximation to get you started.
|
||||
You will need to submit these vouchers after checking if the values are correct.
|
||||
For more details, read: \
|
||||
<a href="http://erpnext.com/auto-inventory-accounting" target="_blank">\
|
||||
Auto Inventory Accounting</a>"""))
|
||||
|
||||
webnotes.msgprint("""Please refresh the system to get effect of Auto Inventory Accounting""")
|
||||
|
||||
|
||||
def get_stock_rbnb_value(company):
|
||||
total_received_amount = webnotes.conn.sql("""select sum(valuation_rate*qty*conversion_factor)
|
||||
from `tabPurchase Receipt Item` pr_item where docstatus=1
|
||||
and exists(select name from `tabItem` where name = pr_item.item_code
|
||||
and is_stock_item='Yes')
|
||||
and exists(select name from `tabPurchase Receipt`
|
||||
where name = pr_item.parent and company = %s)""", company)
|
||||
|
||||
total_billed_amount = webnotes.conn.sql("""select sum(valuation_rate*qty*conversion_factor)
|
||||
from `tabPurchase Invoice Item` pi_item where docstatus=1
|
||||
and exists(select name from `tabItem` where name = pi_item.item_code
|
||||
and is_stock_item='Yes')
|
||||
and exists(select name from `tabPurchase Invoice`
|
||||
where name = pi_item.parent and company = %s)""", company)
|
||||
return flt(total_received_amount[0][0]) - flt(total_billed_amount[0][0])
|
||||
|
||||
|
||||
def fix_total_debit_credit():
|
||||
vouchers = webnotes.conn.sql("""select voucher_type, voucher_no,
|
||||
@@ -338,4 +261,91 @@ def fix_total_debit_credit():
|
||||
webnotes.conn.sql("""update `tabGL Entry` set %s = %s + %s
|
||||
where voucher_type = %s and voucher_no = %s and %s > 0 limit 1""" %
|
||||
(dr_or_cr, dr_or_cr, '%s', '%s', '%s', dr_or_cr),
|
||||
(d.diff, d.voucher_type, d.voucher_no))
|
||||
(d.diff, d.voucher_type, d.voucher_no))
|
||||
|
||||
def get_stock_and_account_difference(account_list=None, posting_date=None):
|
||||
from stock.utils import get_stock_balance_on
|
||||
|
||||
if not posting_date: posting_date = nowdate()
|
||||
|
||||
difference = {}
|
||||
|
||||
account_warehouse = dict(webnotes.conn.sql("""select name, master_name from tabAccount
|
||||
where account_type = 'Warehouse' and ifnull(master_name, '') != ''
|
||||
and name in (%s)""" % ', '.join(['%s']*len(account_list)), account_list))
|
||||
|
||||
for account, warehouse in account_warehouse.items():
|
||||
account_balance = get_balance_on(account, posting_date)
|
||||
stock_value = get_stock_balance_on(warehouse, posting_date)
|
||||
if abs(flt(stock_value) - flt(account_balance)) > 0.005:
|
||||
difference.setdefault(account, flt(stock_value) - flt(account_balance))
|
||||
|
||||
return difference
|
||||
|
||||
def validate_expense_against_budget(args):
|
||||
args = webnotes._dict(args)
|
||||
if webnotes.conn.get_value("Account", {"name": args.account, "is_pl_account": "Yes",
|
||||
"debit_or_credit": "Debit"}):
|
||||
budget = webnotes.conn.sql("""
|
||||
select bd.budget_allocated, cc.distribution_id
|
||||
from `tabCost Center` cc, `tabBudget Detail` bd
|
||||
where cc.name=bd.parent and cc.name=%s and account=%s and bd.fiscal_year=%s
|
||||
""", (args.cost_center, args.account, args.fiscal_year), as_dict=True)
|
||||
|
||||
if budget and budget[0].budget_allocated:
|
||||
yearly_action, monthly_action = webnotes.conn.get_value("Company", args.company,
|
||||
["yearly_bgt_flag", "monthly_bgt_flag"])
|
||||
action_for = action = ""
|
||||
|
||||
if monthly_action in ["Stop", "Warn"]:
|
||||
budget_amount = get_allocated_budget(budget[0].distribution_id,
|
||||
args.posting_date, args.fiscal_year, budget[0].budget_allocated)
|
||||
|
||||
args["month_end_date"] = webnotes.conn.sql("select LAST_DAY(%s)",
|
||||
args.posting_date)[0][0]
|
||||
action_for, action = "Monthly", monthly_action
|
||||
|
||||
elif yearly_action in ["Stop", "Warn"]:
|
||||
budget_amount = budget[0].budget_allocated
|
||||
action_for, action = "Monthly", yearly_action
|
||||
|
||||
if action_for:
|
||||
actual_expense = get_actual_expense(args)
|
||||
if actual_expense > budget_amount:
|
||||
webnotes.msgprint(action_for + _(" budget ") + cstr(budget_amount) +
|
||||
_(" for account ") + args.account + _(" against cost center ") +
|
||||
args.cost_center + _(" will exceed by ") +
|
||||
cstr(actual_expense - budget_amount) + _(" after this transaction.")
|
||||
, raise_exception=BudgetError if action=="Stop" else False)
|
||||
|
||||
def get_allocated_budget(distribution_id, posting_date, fiscal_year, yearly_budget):
|
||||
if distribution_id:
|
||||
distribution = {}
|
||||
for d in webnotes.conn.sql("""select bdd.month, bdd.percentage_allocation
|
||||
from `tabBudget Distribution Detail` bdd, `tabBudget Distribution` bd
|
||||
where bdd.parent=bd.name and bd.fiscal_year=%s""", fiscal_year, as_dict=1):
|
||||
distribution.setdefault(d.month, d.percentage_allocation)
|
||||
|
||||
dt = webnotes.conn.get_value("Fiscal Year", fiscal_year, "year_start_date")
|
||||
budget_percentage = 0.0
|
||||
|
||||
while(dt <= getdate(posting_date)):
|
||||
if distribution_id:
|
||||
budget_percentage += distribution.get(getdate(dt).strftime("%B"), 0)
|
||||
else:
|
||||
budget_percentage += 100.0/12
|
||||
|
||||
dt = add_months(dt, 1)
|
||||
|
||||
return yearly_budget * budget_percentage / 100
|
||||
|
||||
def get_actual_expense(args):
|
||||
args["condition"] = " and posting_date<='%s'" % args.month_end_date \
|
||||
if args.get("month_end_date") else ""
|
||||
|
||||
return webnotes.conn.sql("""
|
||||
select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))
|
||||
from `tabGL Entry`
|
||||
where account='%(account)s' and cost_center='%(cost_center)s'
|
||||
and fiscal_year='%(fiscal_year)s' and company='%(company)s' %(condition)s
|
||||
""" % (args))[0][0]
|
||||
Reference in New Issue
Block a user