Compare commits
49 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
39a3f50732 | ||
|
|
ba7221c332 | ||
|
|
6a45588a2c | ||
|
|
ab9d755e4d | ||
|
|
1cf8bd8767 | ||
|
|
a4f99428d7 | ||
|
|
e761fe89e2 | ||
|
|
d51f805b78 | ||
|
|
9a064e9ced | ||
|
|
9dc1b00d87 | ||
|
|
9373ba96d5 | ||
|
|
a402079cd4 | ||
|
|
2ca388b0a5 | ||
|
|
6ebcc5c006 | ||
|
|
6a2edee914 | ||
|
|
de69ad0a48 | ||
|
|
25a4bd02f4 | ||
|
|
a3d058938e | ||
|
|
4cae8a0d54 | ||
|
|
454b6f9f8a | ||
|
|
9f1b59dfc6 | ||
|
|
74f64b67db | ||
|
|
2117afba07 | ||
|
|
e409d0d70b | ||
|
|
50125b35d2 | ||
|
|
c38527ef5f | ||
|
|
facde47c6c | ||
|
|
20dc79ac99 | ||
|
|
61da43f793 | ||
|
|
af30c3fdfd | ||
|
|
68888a21ec | ||
|
|
7d7661c9ed | ||
|
|
fbda00eef0 | ||
|
|
a0212d8014 | ||
|
|
c8d2604afc | ||
|
|
861453279d | ||
|
|
be96600c1c | ||
|
|
8709c51e84 | ||
|
|
6fc0262cb6 | ||
|
|
4b5ced03ec | ||
|
|
a888e29b0a | ||
|
|
ae2e8996b0 | ||
|
|
1c2bbd77a0 | ||
|
|
2ffba327ac | ||
|
|
4764f3ea1d | ||
|
|
104deeebb5 | ||
|
|
2a9e4e9a32 | ||
|
|
a38a7b8e76 | ||
|
|
88eedb7397 |
@@ -95,9 +95,10 @@ cur_frm.cscript.add_toolbar_buttons = function(doc) {
|
||||
wn.route_options = {
|
||||
"account": doc.name,
|
||||
"from_date": sys_defaults.year_start_date,
|
||||
"to_date": sys_defaults.year_end_date
|
||||
"to_date": sys_defaults.year_end_date,
|
||||
"company": doc.company
|
||||
};
|
||||
wn.set_route("general-ledger");
|
||||
wn.set_route("query-report", "General Ledger");
|
||||
}, "icon-table");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,6 +211,9 @@ class DocType:
|
||||
|
||||
# Validate properties before merging
|
||||
if merge:
|
||||
if not webnotes.conn.exists("Account", new):
|
||||
webnotes.throw(_("Account ") + new +_(" does not exists"))
|
||||
|
||||
val = list(webnotes.conn.get_value("Account", new_account,
|
||||
["group_or_ledger", "debit_or_credit", "is_pl_account"]))
|
||||
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
from webnotes.utils import cint, cstr
|
||||
from webnotes import msgprint, _
|
||||
from webnotes import _
|
||||
|
||||
class DocType:
|
||||
def __init__(self, d, dl):
|
||||
@@ -16,6 +15,11 @@ class DocType:
|
||||
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])
|
||||
warehouse_list = webnotes.conn.sql("select name, company from tabWarehouse", as_dict=1)
|
||||
warehouse_with_no_company = [d.name for d in warehouse_list if not d.company]
|
||||
if warehouse_with_no_company:
|
||||
webnotes.throw(_("Company is missing in following warehouses") + ": \n" +
|
||||
"\n".join(warehouse_with_no_company))
|
||||
for wh in warehouse_list:
|
||||
wh_bean = webnotes.bean("Warehouse", wh.name)
|
||||
wh_bean.save()
|
||||
@@ -120,8 +120,9 @@ cur_frm.cscript.refresh = function(doc) {
|
||||
"voucher_no": doc.name,
|
||||
"from_date": doc.posting_date,
|
||||
"to_date": doc.posting_date,
|
||||
"company": doc.company
|
||||
};
|
||||
wn.set_route("general-ledger");
|
||||
wn.set_route("query-report", "General Ledger");
|
||||
}, "icon-table");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,8 +35,9 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
|
||||
"voucher_no": doc.name,
|
||||
"from_date": doc.posting_date,
|
||||
"to_date": doc.posting_date,
|
||||
"company": doc.company
|
||||
};
|
||||
wn.set_route("general-ledger");
|
||||
wn.set_route("query-report", "General Ledger");
|
||||
}, "icon-table");
|
||||
}
|
||||
|
||||
|
||||
@@ -350,7 +350,7 @@ class DocType(BuyingController):
|
||||
# item gl entries
|
||||
stock_item_and_auto_accounting_for_stock = False
|
||||
stock_items = self.get_stock_items()
|
||||
rounding_diff = 0.0
|
||||
# rounding_diff = 0.0
|
||||
for item in self.doclist.get({"parentfield": "entries"}):
|
||||
if auto_accounting_for_stock and item.item_code in stock_items:
|
||||
if flt(item.valuation_rate):
|
||||
@@ -359,13 +359,12 @@ class DocType(BuyingController):
|
||||
# expense will be booked in sales invoice
|
||||
stock_item_and_auto_accounting_for_stock = True
|
||||
|
||||
valuation_amt = flt(flt(item.valuation_rate) * flt(item.qty) * \
|
||||
flt(item.conversion_factor), self.precision("valuation_rate", item))
|
||||
valuation_amt = item.amount + item.item_tax_amount + item.rm_supp_cost
|
||||
|
||||
rounding_diff += (flt(item.amount, self.precision("amount", item)) +
|
||||
flt(item.item_tax_amount, self.precision("item_tax_amount", item)) +
|
||||
flt(item.rm_supp_cost, self.precision("rm_supp_cost", item)) -
|
||||
valuation_amt)
|
||||
# rounding_diff += (flt(item.amount, self.precision("amount", item)) +
|
||||
# flt(item.item_tax_amount, self.precision("item_tax_amount", item)) +
|
||||
# flt(item.rm_supp_cost, self.precision("rm_supp_cost", item)) -
|
||||
# valuation_amt)
|
||||
|
||||
gl_entries.append(
|
||||
self.get_gl_dict({
|
||||
@@ -394,11 +393,11 @@ class DocType(BuyingController):
|
||||
expenses_included_in_valuation = \
|
||||
self.get_company_default("expenses_included_in_valuation")
|
||||
|
||||
if rounding_diff:
|
||||
import operator
|
||||
cost_center_with_max_value = max(valuation_tax.iteritems(),
|
||||
key=operator.itemgetter(1))[0]
|
||||
valuation_tax[cost_center_with_max_value] -= flt(rounding_diff)
|
||||
# if rounding_diff:
|
||||
# import operator
|
||||
# cost_center_with_max_value = max(valuation_tax.iteritems(),
|
||||
# key=operator.itemgetter(1))[0]
|
||||
# valuation_tax[cost_center_with_max_value] -= flt(rounding_diff)
|
||||
|
||||
for cost_center, amount in valuation_tax.items():
|
||||
gl_entries.append(
|
||||
|
||||
@@ -54,8 +54,9 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
"voucher_no": doc.name,
|
||||
"from_date": doc.posting_date,
|
||||
"to_date": doc.posting_date,
|
||||
"company": doc.company
|
||||
};
|
||||
wn.set_route("general-ledger");
|
||||
wn.set_route("query-report", "General Ledger");
|
||||
}, "icon-table");
|
||||
|
||||
var percent_paid = cint(flt(doc.grand_total - doc.outstanding_amount) / flt(doc.grand_total) * 100);
|
||||
|
||||
@@ -364,7 +364,6 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
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)
|
||||
# print gl_entries
|
||||
|
||||
stock_in_hand = webnotes.conn.get_value("Account", {"master_name": "_Test Warehouse - _TC"})
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ def merge_similar_entries(gl_map):
|
||||
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
|
||||
|
||||
@@ -175,9 +175,10 @@ erpnext.AccountsChart = Class.extend({
|
||||
wn.route_options = {
|
||||
"account": node.data('label'),
|
||||
"from_date": sys_defaults.year_start_date,
|
||||
"to_date": sys_defaults.year_end_date
|
||||
"to_date": sys_defaults.year_end_date,
|
||||
"company": me.company
|
||||
};
|
||||
wn.set_route("general-ledger");
|
||||
wn.set_route("query-report", "General Ledger");
|
||||
},
|
||||
rename: function() {
|
||||
var node = this.selected_node();
|
||||
|
||||
@@ -11,26 +11,6 @@ wn.query_reports["General Ledger"] = {
|
||||
"default": wn.defaults.get_user_default("company"),
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname":"account",
|
||||
"label": wn._("Account"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Account"
|
||||
},
|
||||
{
|
||||
"fieldname":"voucher_no",
|
||||
"label": wn._("Voucher No"),
|
||||
"fieldtype": "Data",
|
||||
},
|
||||
{
|
||||
"fieldname":"group_by",
|
||||
"label": wn._("Group by"),
|
||||
"fieldtype": "Select",
|
||||
"options": "\nGroup by Account\nGroup by Voucher"
|
||||
},
|
||||
{
|
||||
"fieldtype": "Break",
|
||||
},
|
||||
{
|
||||
"fieldname":"from_date",
|
||||
"label": wn._("From Date"),
|
||||
@@ -46,6 +26,40 @@ wn.query_reports["General Ledger"] = {
|
||||
"default": wn.datetime.get_today(),
|
||||
"reqd": 1,
|
||||
"width": "60px"
|
||||
},
|
||||
{
|
||||
"fieldtype": "Break",
|
||||
},
|
||||
{
|
||||
"fieldname":"account",
|
||||
"label": wn._("Account"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Account",
|
||||
"get_query": function() {
|
||||
var company = wn.query_report.filters_by_name.company.get_value();
|
||||
return {
|
||||
"query": "accounts.utils.get_account_list",
|
||||
"filters": {
|
||||
"company": company,
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"fieldname":"voucher_no",
|
||||
"label": wn._("Voucher No"),
|
||||
"fieldtype": "Data",
|
||||
},
|
||||
{
|
||||
"fieldname":"group_by_voucher",
|
||||
"label": wn._("Group by Voucher"),
|
||||
"fieldtype": "Check",
|
||||
"default": 1
|
||||
},
|
||||
{
|
||||
"fieldname":"group_by_account",
|
||||
"label": wn._("Group by Account"),
|
||||
"fieldtype": "Check",
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -3,77 +3,170 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
from webnotes.utils import flt
|
||||
from webnotes.utils import cstr, flt
|
||||
from webnotes import _
|
||||
|
||||
def execute(filters=None):
|
||||
validate_filters(filters)
|
||||
account_details = {}
|
||||
for acc in webnotes.conn.sql("""select name, debit_or_credit, group_or_ledger
|
||||
from tabAccount""", as_dict=1):
|
||||
account_details.setdefault(acc.name, acc)
|
||||
|
||||
validate_filters(filters, account_details)
|
||||
|
||||
columns = get_columns()
|
||||
|
||||
if filters.get("group_by"):
|
||||
data = get_grouped_gle(filters)
|
||||
else:
|
||||
data = get_gl_entries(filters)
|
||||
if data:
|
||||
data.append(get_total_row(data))
|
||||
res = get_result(filters, account_details)
|
||||
|
||||
return columns, data
|
||||
return columns, res
|
||||
|
||||
def validate_filters(filters):
|
||||
if filters.get("account") and filters.get("group_by") == "Group by Account":
|
||||
def validate_filters(filters, account_details):
|
||||
if filters.get("account") and filters.get("group_by_account") \
|
||||
and account_details[filters.account].group_or_ledger == "Ledger":
|
||||
webnotes.throw(_("Can not filter based on Account, if grouped by Account"))
|
||||
|
||||
if filters.get("voucher_no") and filters.get("group_by") == "Group by Voucher":
|
||||
if filters.get("voucher_no") and filters.get("group_by_voucher"):
|
||||
webnotes.throw(_("Can not filter based on Voucher No, if grouped by Voucher"))
|
||||
|
||||
if filters.from_date > filters.to_date:
|
||||
webnotes.throw(_("From Date must be before To Date"))
|
||||
|
||||
def get_columns():
|
||||
return ["Posting Date:Date:100", "Account:Link/Account:200", "Debit:Currency:100",
|
||||
"Credit:Currency:100", "Voucher Type::120", "Voucher No::160",
|
||||
"Cost Center:Link/Cost Center:100", "Remarks::200"]
|
||||
return ["Posting Date:Date:100", "Account:Link/Account:200", "Debit:Float:100",
|
||||
"Credit:Float:100", "Voucher Type::120", "Voucher No::160", "Link::20",
|
||||
"Against Account::120", "Cost Center:Link/Cost Center:100", "Remarks::200"]
|
||||
|
||||
def get_result(filters, account_details):
|
||||
gl_entries = get_gl_entries(filters)
|
||||
|
||||
data = get_data_with_opening_closing(filters, account_details, gl_entries)
|
||||
|
||||
result = get_result_as_list(data)
|
||||
|
||||
return result
|
||||
|
||||
def get_gl_entries(filters):
|
||||
return webnotes.conn.sql("""select
|
||||
posting_date, account, debit, credit, voucher_type, voucher_no, cost_center, remarks
|
||||
group_by_condition = "group by voucher_type, voucher_no, account" \
|
||||
if filters.get("group_by_voucher") else "group by name"
|
||||
|
||||
gl_entries = webnotes.conn.sql("""select posting_date, account,
|
||||
sum(ifnull(debit, 0)) as debit, sum(ifnull(credit, 0)) as credit,
|
||||
voucher_type, voucher_no, cost_center, remarks, is_advance, against
|
||||
from `tabGL Entry`
|
||||
where company=%(company)s
|
||||
and posting_date between %(from_date)s and %(to_date)s
|
||||
{conditions}
|
||||
where company=%(company)s {conditions}
|
||||
{group_by_condition}
|
||||
order by posting_date, account"""\
|
||||
.format(conditions=get_conditions(filters)), filters, as_list=1)
|
||||
|
||||
.format(conditions=get_conditions(filters), group_by_condition=group_by_condition),
|
||||
filters, as_dict=1)
|
||||
|
||||
return gl_entries
|
||||
|
||||
def get_conditions(filters):
|
||||
conditions = []
|
||||
if filters.get("account"):
|
||||
conditions.append("account=%(account)s")
|
||||
lft, rgt = webnotes.conn.get_value("Account", filters["account"], ["lft", "rgt"])
|
||||
conditions.append("""account in (select name from tabAccount
|
||||
where lft>=%s and rgt<=%s and docstatus<2)""" % (lft, rgt))
|
||||
else:
|
||||
conditions.append("posting_date between %(from_date)s and %(to_date)s")
|
||||
|
||||
if filters.get("voucher_no"):
|
||||
conditions.append("voucher_no=%(voucher_no)s")
|
||||
|
||||
return "and {}".format(" and ".join(conditions)) if conditions else ""
|
||||
|
||||
def get_grouped_gle(filters):
|
||||
gle_map = {}
|
||||
gle = get_gl_entries(filters)
|
||||
for d in gle:
|
||||
gle_map.setdefault(d[1 if filters["group_by"]=="Group by Account" else 5], []).append(d)
|
||||
|
||||
|
||||
def get_data_with_opening_closing(filters, account_details, gl_entries):
|
||||
data = []
|
||||
for entries in gle_map.values():
|
||||
subtotal_debit = subtotal_credit = 0.0
|
||||
for entry in entries:
|
||||
data.append(entry)
|
||||
subtotal_debit += flt(entry[2])
|
||||
subtotal_credit += flt(entry[3])
|
||||
|
||||
data.append(["", "Total", subtotal_debit, subtotal_credit, "", "", ""])
|
||||
gle_map = initialize_gle_map(gl_entries)
|
||||
|
||||
opening, total_debit, total_credit, gle_map = get_accountwise_gle(filters, gl_entries, gle_map)
|
||||
|
||||
# Opening for filtered account
|
||||
if filters.get("account"):
|
||||
data += [get_balance_row("Opening", account_details[filters.account].debit_or_credit,
|
||||
opening), {}]
|
||||
|
||||
for acc, acc_dict in gle_map.items():
|
||||
if acc_dict.entries:
|
||||
# Opening for individual ledger, if grouped by account
|
||||
if filters.get("group_by_account"):
|
||||
data.append(get_balance_row("Opening", account_details[acc].debit_or_credit,
|
||||
acc_dict.opening))
|
||||
|
||||
data += acc_dict.entries
|
||||
|
||||
# Totals and closing for individual ledger, if grouped by account
|
||||
if filters.get("group_by_account"):
|
||||
data += [{"account": "Totals", "debit": acc_dict.total_debit,
|
||||
"credit": acc_dict.total_credit},
|
||||
get_balance_row("Closing (Opening + Totals)",
|
||||
account_details[acc].debit_or_credit, (acc_dict.opening
|
||||
+ acc_dict.total_debit - acc_dict.total_credit)), {}]
|
||||
|
||||
# Total debit and credit between from and to date
|
||||
if total_debit or total_credit:
|
||||
data.append({"account": "Totals", "debit": total_debit, "credit": total_credit})
|
||||
|
||||
# Closing for filtered account
|
||||
if filters.get("account"):
|
||||
data.append(get_balance_row("Closing (Opening + Totals)",
|
||||
account_details[filters.account].debit_or_credit,
|
||||
(opening + total_debit - total_credit)))
|
||||
|
||||
if data:
|
||||
data.append(get_total_row(gle))
|
||||
return data
|
||||
|
||||
def initialize_gle_map(gl_entries):
|
||||
gle_map = webnotes._dict()
|
||||
for gle in gl_entries:
|
||||
gle_map.setdefault(gle.account, webnotes._dict({
|
||||
"opening": 0,
|
||||
"entries": [],
|
||||
"total_debit": 0,
|
||||
"total_credit": 0,
|
||||
"closing": 0
|
||||
}))
|
||||
return gle_map
|
||||
|
||||
def get_accountwise_gle(filters, gl_entries, gle_map):
|
||||
opening, total_debit, total_credit = 0, 0, 0
|
||||
|
||||
def get_total_row(gle):
|
||||
total_debit = total_credit = 0.0
|
||||
for d in gle:
|
||||
total_debit += flt(d[2])
|
||||
total_credit += flt(d[3])
|
||||
for gle in gl_entries:
|
||||
amount = flt(gle.debit) - flt(gle.credit)
|
||||
if filters.get("account") and (gle.posting_date < filters.from_date
|
||||
or cstr(gle.is_advance) == "Yes"):
|
||||
gle_map[gle.account].opening += amount
|
||||
opening += amount
|
||||
elif gle.posting_date < filters.to_date:
|
||||
gle_map[gle.account].entries.append(gle)
|
||||
gle_map[gle.account].total_debit += flt(gle.debit)
|
||||
gle_map[gle.account].total_credit += flt(gle.credit)
|
||||
|
||||
total_debit += flt(gle.debit)
|
||||
total_credit += flt(gle.credit)
|
||||
|
||||
return opening, total_debit, total_credit, gle_map
|
||||
|
||||
def get_balance_row(label, debit_or_credit, balance):
|
||||
return {
|
||||
"account": label,
|
||||
"debit": balance if debit_or_credit=="Debit" else 0,
|
||||
"credit": -1*balance if debit_or_credit=="Credit" else 0,
|
||||
}
|
||||
|
||||
def get_result_as_list(data):
|
||||
result = []
|
||||
for d in data:
|
||||
result.append([d.get("posting_date"), d.get("account"), d.get("debit"),
|
||||
d.get("credit"), d.get("voucher_type"), d.get("voucher_no"),
|
||||
get_voucher_link(d.get("voucher_type"), d.get("voucher_no")),
|
||||
d.get("against"), d.get("cost_center"), d.get("remarks")])
|
||||
|
||||
return result
|
||||
|
||||
def get_voucher_link(voucher_type, voucher_no):
|
||||
icon = ""
|
||||
if voucher_type and voucher_no:
|
||||
icon = """<a href="%s"><i class="icon icon-share" style="cursor: pointer;">
|
||||
</i></a>""" % ("/".join(["#Form", voucher_type, voucher_no]))
|
||||
|
||||
return ["", "Total Debit/Credit", total_debit, total_credit, "", "", ""]
|
||||
return icon
|
||||
@@ -16,7 +16,7 @@ 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]
|
||||
return get_fiscal_years(date, fiscal_year, label, verbose)[0]
|
||||
|
||||
def get_fiscal_years(date=None, fiscal_year=None, label="Date", verbose=1):
|
||||
# if year start date is 2012-04-01, year end date should be 2013-03-31 (hence subdate)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"app_name": "ERPNext",
|
||||
"app_version": "3.3.3",
|
||||
"app_version": "3.4.1",
|
||||
"base_template": "app/portal/templates/base.html",
|
||||
"modules": {
|
||||
"Accounts": {
|
||||
@@ -74,5 +74,5 @@
|
||||
"type": "module"
|
||||
}
|
||||
},
|
||||
"requires_framework_version": "==3.3.1"
|
||||
"requires_framework_version": "==3.4.1"
|
||||
}
|
||||
@@ -108,10 +108,11 @@ class BuyingController(StockController):
|
||||
item.import_amount = flt(item.import_rate * item.qty,
|
||||
self.precision("import_amount", item))
|
||||
item.item_tax_amount = 0.0;
|
||||
|
||||
|
||||
self._set_in_company_currency(item, "import_amount", "amount")
|
||||
self._set_in_company_currency(item, "import_ref_rate", "purchase_ref_rate")
|
||||
self._set_in_company_currency(item, "import_rate", "rate")
|
||||
self._set_in_company_currency(item, "import_amount", "amount")
|
||||
|
||||
|
||||
def calculate_net_total(self):
|
||||
self.doc.net_total = self.doc.net_total_import = 0.0
|
||||
@@ -183,14 +184,12 @@ class BuyingController(StockController):
|
||||
|
||||
if item.item_code and item.qty:
|
||||
self.round_floats_in(item)
|
||||
|
||||
purchase_rate = item.rate if self.doc.doctype == "Purchase Invoice" else item.purchase_rate
|
||||
|
||||
|
||||
# if no item code, which is sometimes the case in purchase invoice,
|
||||
# then it is not possible to track valuation against it
|
||||
item.valuation_rate = flt((purchase_rate +
|
||||
(item.item_tax_amount + item.rm_supp_cost) / item.qty) / item.conversion_factor,
|
||||
self.precision("valuation_rate", item))
|
||||
qty_in_stock_uom = flt(item.qty * item.conversion_factor)
|
||||
item.valuation_rate = ((item.amount + item.item_tax_amount + item.rm_supp_cost)
|
||||
/ qty_in_stock_uom)
|
||||
else:
|
||||
item.valuation_rate = 0.0
|
||||
|
||||
|
||||
10
patches/1312/p02_update_item_details_in_item_price.py
Normal file
10
patches/1312/p02_update_item_details_in_item_price.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
|
||||
def execute():
|
||||
webnotes.conn.sql("""update `tabItem Price` ip INNER JOIN `tabItem` i
|
||||
ON (ip.item_code = i.name)
|
||||
set ip.item_name = i.item_name, ip.item_description = i.description""")
|
||||
@@ -5,7 +5,8 @@ from __future__ import unicode_literals
|
||||
|
||||
def execute():
|
||||
import webnotes
|
||||
webnotes.reload_doc('stock', 'doctype', 'packed_item')
|
||||
for si in webnotes.conn.sql("""select name from `tabSales Invoice` where docstatus = 1"""):
|
||||
webnotes.get_obj("Sales Invoice", si[0],
|
||||
with_children=1).update_qty(change_modified=False)
|
||||
webnotes.conn.commit()
|
||||
webnotes.conn.commit()
|
||||
|
||||
@@ -262,4 +262,5 @@ patch_list = [
|
||||
"patches.1311.p07_scheduler_errors_digest",
|
||||
"patches.1311.p08_email_digest_recipients",
|
||||
"execute:webnotes.delete_doc('DocType', 'Warehouse Type')",
|
||||
"patches.1312.p02_update_item_details_in_item_price",
|
||||
]
|
||||
@@ -28,7 +28,7 @@ class DocType:
|
||||
})
|
||||
|
||||
def validate_time_log_is_submitted(self, tl):
|
||||
if tl.status != "Submitted":
|
||||
if tl.status != "Submitted" and self.doc.docstatus == 0:
|
||||
webnotes.msgprint(_("Time Log must have status 'Submitted'") + \
|
||||
" :" + tl.name + " (" + _(tl.status) + ")", raise_exception=True)
|
||||
|
||||
@@ -57,7 +57,4 @@ class DocType:
|
||||
tl = webnotes.bean("Time Log", d.time_log)
|
||||
tl.doc.time_log_batch = time_log_batch
|
||||
tl.doc.sales_invoice = self.doc.sales_invoice
|
||||
tl.update_after_submit()
|
||||
|
||||
|
||||
|
||||
tl.update_after_submit()
|
||||
@@ -26,9 +26,10 @@ erpnext.AccountTreeGrid = wn.views.TreeGridReport.extend({
|
||||
show: true,
|
||||
parent_field: "parent_account",
|
||||
formatter: function(item) {
|
||||
return repl('<a href="#general-ledger/account=%(enc_value)s">%(value)s</a>', {
|
||||
return repl("<a \
|
||||
onclick='wn.cur_grid_report.show_general_ledger(\"%(value)s\")'>\
|
||||
%(value)s</a>", {
|
||||
value: item.name,
|
||||
enc_value: encodeURIComponent(item.name)
|
||||
});
|
||||
}
|
||||
},
|
||||
@@ -211,4 +212,14 @@ erpnext.AccountTreeGrid = wn.views.TreeGridReport.extend({
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
show_general_ledger: function(account) {
|
||||
wn.route_options = {
|
||||
account: account,
|
||||
company: this.company,
|
||||
from_date: this.from_date,
|
||||
to_date: this.to_date
|
||||
};
|
||||
wn.set_route("query-report", "General Ledger");
|
||||
}
|
||||
});
|
||||
@@ -11,9 +11,10 @@ erpnext.stock.StockController = wn.ui.form.Controller.extend({
|
||||
wn.route_options = {
|
||||
voucher_no: me.frm.doc.name,
|
||||
from_date: me.frm.doc.posting_date,
|
||||
to_date: me.frm.doc.posting_date
|
||||
to_date: me.frm.doc.posting_date,
|
||||
company: me.frm.doc.company
|
||||
};
|
||||
wn.set_route('stock-ledger');
|
||||
wn.set_route("query-report", "Stock Ledger");
|
||||
}, "icon-bar-chart");
|
||||
}
|
||||
|
||||
@@ -24,11 +25,12 @@ erpnext.stock.StockController = wn.ui.form.Controller.extend({
|
||||
if(this.frm.doc.docstatus===1 && cint(wn.defaults.get_default("auto_accounting_for_stock"))) {
|
||||
cur_frm.appframe.add_button(wn._('Accounting Ledger'), function() {
|
||||
wn.route_options = {
|
||||
"voucher_no": me.frm.doc.name,
|
||||
"from_date": me.frm.doc.posting_date,
|
||||
"to_date": me.frm.doc.posting_date,
|
||||
voucher_no: me.frm.doc.name,
|
||||
from_date: me.frm.doc.posting_date,
|
||||
to_date: me.frm.doc.posting_date,
|
||||
company: me.frm.doc.company
|
||||
};
|
||||
wn.set_route("general-ledger");
|
||||
wn.set_route("query-report", "General Ledger");
|
||||
}, "icon-table");
|
||||
}
|
||||
},
|
||||
|
||||
@@ -17,10 +17,10 @@ erpnext.StockAnalytics = erpnext.StockGridReport.extend({
|
||||
parent_field: "parent_item_group",
|
||||
formatter: function(item) {
|
||||
if(!item.is_group) {
|
||||
return repl('<a href="#stock-ledger/item_code=%(enc_value)s">%(value)s</a>',
|
||||
{
|
||||
return repl("<a \
|
||||
onclick='wn.cur_grid_report.show_stock_ledger(\"%(value)s\")'>\
|
||||
%(value)s</a>", {
|
||||
value: item.name,
|
||||
enc_value: encodeURIComponent(item.name)
|
||||
});
|
||||
} else {
|
||||
return item.name;
|
||||
@@ -183,5 +183,13 @@ erpnext.StockAnalytics = erpnext.StockGridReport.extend({
|
||||
},
|
||||
get_plot_points: function(item, col, idx) {
|
||||
return [[dateutil.user_to_obj(col.name).getTime(), item[col.field]]]
|
||||
},
|
||||
show_stock_ledger: function(item_code) {
|
||||
wn.route_options = {
|
||||
item_code: item_code,
|
||||
from_date: this.from_date,
|
||||
to_date: this.to_date
|
||||
};
|
||||
wn.set_route("query-report", "Stock Ledger");
|
||||
}
|
||||
});
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"creation": "2013-06-11 14:26:44",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-11-03 14:01:33",
|
||||
"modified": "2013-12-25 11:15:05",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
@@ -16,7 +16,7 @@
|
||||
"icon": "icon-user",
|
||||
"module": "Selling",
|
||||
"name": "__common__",
|
||||
"search_fields": "customer_name,customer_group,country,territory"
|
||||
"search_fields": "customer_name,customer_group,territory"
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
|
||||
@@ -9,6 +9,7 @@ from webnotes.utils import fmt_money, formatdate, now_datetime, cstr, esc, \
|
||||
from webnotes.utils.dateutils import datetime_in_user_format
|
||||
from datetime import timedelta
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from webnotes.utils.email_lib import sendmail
|
||||
|
||||
content_sequence = [
|
||||
["Income / Expenses", ["income_year_to_date", "bank_balance",
|
||||
@@ -80,15 +81,15 @@ class DocType(DocListController):
|
||||
for user_id in recipients:
|
||||
msg_for_this_receipient = self.get_msg_html(self.get_user_specific_content(user_id) + \
|
||||
common_msg)
|
||||
from webnotes.utils.email_lib import sendmail
|
||||
sendmail(recipients=user_id,
|
||||
subject="[ERPNext] [{frequency} Digest] {name}".format(
|
||||
frequency=self.doc.frequency, name=self.doc.name),
|
||||
msg=msg_for_this_receipient)
|
||||
if msg_for_this_receipient:
|
||||
sendmail(recipients=user_id,
|
||||
subject="[ERPNext] [{frequency} Digest] {name}".format(
|
||||
frequency=self.doc.frequency, name=self.doc.name),
|
||||
msg=msg_for_this_receipient)
|
||||
|
||||
def get_digest_msg(self):
|
||||
return self.get_msg_html(self.get_user_specific_content(webnotes.session.user) + \
|
||||
self.get_common_content())
|
||||
self.get_common_content(), send_only_if_updates=False)
|
||||
|
||||
def get_common_content(self):
|
||||
out = []
|
||||
@@ -119,14 +120,19 @@ class DocType(DocListController):
|
||||
|
||||
return out
|
||||
|
||||
def get_msg_html(self, out):
|
||||
def get_msg_html(self, out, send_only_if_updates=True):
|
||||
with_value = [o[1] for o in out if o[0]]
|
||||
|
||||
if with_value:
|
||||
has_updates = True
|
||||
with_value = "\n".join(with_value)
|
||||
else:
|
||||
has_updates = False
|
||||
with_value = "<p>There were no updates in the items selected for this digest.</p><hr>"
|
||||
|
||||
if not has_updates and send_only_if_updates:
|
||||
return
|
||||
|
||||
# seperate out no value items
|
||||
no_value = [o[1] for o in out if not o[0]]
|
||||
if no_value:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"creation": "2012-12-20 12:50:49",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-11-03 14:20:18",
|
||||
"modified": "2013-12-24 11:40:19",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
@@ -90,7 +90,7 @@
|
||||
"doctype": "DocField",
|
||||
"fieldname": "fs_packing_details",
|
||||
"fieldtype": "Check",
|
||||
"label": "Packing Detials"
|
||||
"label": "Packing Details"
|
||||
},
|
||||
{
|
||||
"description": "To get Item Group in details table",
|
||||
|
||||
@@ -58,11 +58,6 @@ class TestDeliveryNote(unittest.TestCase):
|
||||
self.assertEqual(stock_value, 0)
|
||||
self.assertEqual(stock_value_difference, -375)
|
||||
|
||||
|
||||
gl_entries = webnotes.conn.sql("""select account, debit, credit
|
||||
from `tabGL Entry` where voucher_type='Delivery Note' and voucher_no=%s
|
||||
order by account desc""", dn.doc.name, as_dict=1)
|
||||
|
||||
self.assertFalse(get_gl_entries("Delivery Note", dn.doc.name))
|
||||
|
||||
def test_delivery_note_gl_entry(self):
|
||||
@@ -111,8 +106,8 @@ class TestDeliveryNote(unittest.TestCase):
|
||||
gl_entries = get_gl_entries("Delivery Note", dn.doc.name)
|
||||
self.assertTrue(gl_entries)
|
||||
expected_values = {
|
||||
stock_in_hand_account: [0.0, 666.65],
|
||||
"Cost of Goods Sold - _TC": [666.65, 0.0]
|
||||
stock_in_hand_account: [0.0, 666.67],
|
||||
"Cost of Goods Sold - _TC": [666.67, 0.0]
|
||||
}
|
||||
for i, gle in enumerate(gl_entries):
|
||||
self.assertEquals([gle.debit, gle.credit], expected_values.get(gle.account))
|
||||
|
||||
@@ -49,6 +49,7 @@ class DocType(DocListController, WebsiteGenerator):
|
||||
def on_update(self):
|
||||
self.validate_name_with_item_group()
|
||||
self.update_website()
|
||||
self.update_item_price()
|
||||
|
||||
def check_warehouse_is_set_for_stock_item(self):
|
||||
if self.doc.is_stock_item=="Yes" and not self.doc.default_warehouse:
|
||||
@@ -210,6 +211,11 @@ class DocType(DocListController, WebsiteGenerator):
|
||||
|
||||
WebsiteGenerator.on_update(self)
|
||||
|
||||
def update_item_price(self):
|
||||
webnotes.conn.sql("""update `tabItem Price` set item_name=%s,
|
||||
item_description=%s, modified=NOW() where item_code=%s""",
|
||||
(self.doc.item_name, self.doc.description, self.doc.name))
|
||||
|
||||
def get_page_title(self):
|
||||
if self.doc.name==self.doc.item_name:
|
||||
page_name_from = self.doc.name
|
||||
@@ -246,6 +252,9 @@ class DocType(DocListController, WebsiteGenerator):
|
||||
def before_rename(self, olddn, newdn, merge=False):
|
||||
if merge:
|
||||
# Validate properties before merging
|
||||
if not webnotes.conn.exists("Item", newdn):
|
||||
webnotes.throw(_("Item ") + newdn +_(" does not exists"))
|
||||
|
||||
field_list = ["stock_uom", "is_stock_item", "has_serial_no", "has_batch_no"]
|
||||
new_properties = [cstr(d) for d in webnotes.conn.get_value("Item", newdn, field_list)]
|
||||
if new_properties != [cstr(self.doc.fields[fld]) for fld in field_list]:
|
||||
|
||||
@@ -44,5 +44,5 @@ class DocType(DocListController):
|
||||
|
||||
def update_item_price(self):
|
||||
webnotes.conn.sql("""update `tabItem Price` set currency=%s,
|
||||
buying_or_selling=%s where price_list=%s""",
|
||||
buying_or_selling=%s, modified=NOW() where price_list=%s""",
|
||||
(self.doc.currency, self.doc.buying_or_selling, self.doc.name))
|
||||
@@ -287,9 +287,16 @@ class DocType(StockController):
|
||||
# validate quantity <= ref item's qty - qty already returned
|
||||
ref_item = ref.doclist.getone({"item_code": item.item_code})
|
||||
returnable_qty = ref_item.qty - flt(already_returned_item_qty.get(item.item_code))
|
||||
self.validate_value("transfer_qty", "<=", returnable_qty, item,
|
||||
raise_exception=StockOverReturnError)
|
||||
|
||||
if not returnable_qty:
|
||||
webnotes.throw("{item}: {item_code} {returned}".format(
|
||||
item=_("Item"), item_code=item.item_code,
|
||||
returned=_("already returned though some other documents")),
|
||||
StockOverReturnError)
|
||||
elif item.transfer_qty > returnable_qty:
|
||||
webnotes.throw("{item}: {item_code}, {returned}: {qty}".format(
|
||||
item=_("Item"), item_code=item.item_code,
|
||||
returned=_("Max Returnable Qty"), qty=returnable_qty), StockOverReturnError)
|
||||
|
||||
def get_already_returned_item_qty(self, ref_fieldname):
|
||||
return dict(webnotes.conn.sql("""select item_code, sum(transfer_qty) as qty
|
||||
from `tabStock Entry Detail` where parent in (
|
||||
|
||||
@@ -20,6 +20,19 @@ class DocType:
|
||||
if self.doc.email_id and not validate_email_add(self.doc.email_id):
|
||||
msgprint("Please enter valid Email Id", raise_exception=1)
|
||||
|
||||
self.update_parent_account()
|
||||
|
||||
def update_parent_account(self):
|
||||
if not self.doc.__islocal and (self.doc.create_account_under !=
|
||||
webnotes.conn.get_value("Warehouse", self.doc.name, "create_account_under")):
|
||||
warehouse_account = webnotes.conn.get_value("Account",
|
||||
{"account_type": "Warehouse", "company": self.doc.company,
|
||||
"master_name": self.doc.name}, ["name", "parent_account"])
|
||||
if warehouse_account and warehouse_account[1] != self.doc.create_account_under:
|
||||
acc_bean = webnotes.bean("Account", warehouse_account[0])
|
||||
acc_bean.doc.parent_account = self.doc.create_account_under
|
||||
acc_bean.save()
|
||||
|
||||
def on_update(self):
|
||||
self.create_account_head()
|
||||
|
||||
@@ -84,6 +97,9 @@ class DocType:
|
||||
new_warehouse = get_name_with_abbr(newdn, self.doc.company)
|
||||
|
||||
if merge:
|
||||
if not webnotes.conn.exists("Warehouse", newdn):
|
||||
webnotes.throw(_("Warehouse ") + newdn +_(" does not exists"))
|
||||
|
||||
if self.doc.company != webnotes.conn.get_value("Warehouse", new_warehouse, "company"):
|
||||
webnotes.throw(_("Both Warehouse must belong to same Company"))
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ def execute(filters=None):
|
||||
bom_rate = get_item_bom_rate()
|
||||
val_rate_map = get_valuation_rate()
|
||||
|
||||
precision = webnotes.conn.get_value("Global Defaults", None, "float_precision") or 2
|
||||
|
||||
precision = get_currency_precision or 2
|
||||
|
||||
data = []
|
||||
for item in sorted(item_map):
|
||||
data.append([item, item_map[item]["item_name"],
|
||||
@@ -30,6 +30,14 @@ def execute(filters=None):
|
||||
])
|
||||
|
||||
return columns, data
|
||||
|
||||
def get_currency_precision():
|
||||
company_currency = webnotes.conn.get_value("Company",
|
||||
webnotes.conn.get_default("company"), "default_currency")
|
||||
currency_format = webnotes.conn.get_value("Currency", company_currency, "number_format")
|
||||
|
||||
from webnotes.utils import get_number_format_info
|
||||
return get_number_format_info(currency_format)[2]
|
||||
|
||||
def get_columns(filters):
|
||||
"""return columns based on filters"""
|
||||
|
||||
@@ -67,7 +67,7 @@ def get_stock_ledger_entries(filters):
|
||||
item.name, item.item_name, item_group, brand, description, item.stock_uom,
|
||||
actual_qty, posting_date
|
||||
from `tabStock Ledger Entry` sle,
|
||||
(select name, item_name, description, stock_uom, brand
|
||||
(select name, item_name, description, stock_uom, brand, item_group
|
||||
from `tabItem` {item_conditions}) item
|
||||
where item_code = item.name and
|
||||
company = %(company)s and
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
from webnotes import _
|
||||
|
||||
def execute(filters=None):
|
||||
columns = get_columns()
|
||||
@@ -13,10 +12,14 @@ def execute(filters=None):
|
||||
data = []
|
||||
for sle in sl_entries:
|
||||
item_detail = item_details[sle.item_code]
|
||||
voucher_link_icon = """<a href="%s"><i class="icon icon-share"
|
||||
style="cursor: pointer;"></i></a>""" \
|
||||
% ("/".join(["#Form", sle.voucher_type, sle.voucher_no]),)
|
||||
|
||||
data.append([sle.date, sle.item_code, item_detail.item_name, item_detail.item_group,
|
||||
item_detail.brand, item_detail.description, sle.warehouse, item_detail.stock_uom,
|
||||
sle.actual_qty, sle.qty_after_transaction, sle.stock_value, sle.voucher_type,
|
||||
sle.voucher_no, sle.batch_no, sle.serial_no, sle.company])
|
||||
sle.voucher_no, voucher_link_icon, sle.batch_no, sle.serial_no, sle.company])
|
||||
|
||||
return columns, data
|
||||
|
||||
@@ -25,17 +28,10 @@ def get_columns():
|
||||
"Item Group:Link/Item Group:100", "Brand:Link/Brand:100",
|
||||
"Description::200", "Warehouse:Link/Warehouse:100",
|
||||
"Stock UOM:Link/UOM:100", "Qty:Float:50", "Balance Qty:Float:80",
|
||||
"Balance Value:Currency:100", "Voucher Type::100", "Voucher #::100",
|
||||
"Balance Value:Currency:100", "Voucher Type::100", "Voucher #::100", "Link::30",
|
||||
"Batch:Link/Batch:100", "Serial #:Link/Serial No:100", "Company:Link/Company:100"]
|
||||
|
||||
def get_stock_ledger_entries(filters):
|
||||
if not filters.get("company"):
|
||||
webnotes.throw(_("Company is mandatory"))
|
||||
if not filters.get("from_date"):
|
||||
webnotes.throw(_("From Date is mandatory"))
|
||||
if not filters.get("to_date"):
|
||||
webnotes.throw(_("To Date is mandatory"))
|
||||
|
||||
return webnotes.conn.sql("""select concat_ws(" ", posting_date, posting_time) as date,
|
||||
item_code, warehouse, actual_qty, qty_after_transaction,
|
||||
stock_value, voucher_type, voucher_no, batch_no, serial_no, company
|
||||
@@ -66,6 +62,10 @@ def get_item_conditions(filters):
|
||||
|
||||
def get_sle_conditions(filters):
|
||||
conditions = []
|
||||
item_conditions=get_item_conditions(filters)
|
||||
if item_conditions:
|
||||
conditions.append("""item_code in (select name from tabItem
|
||||
{item_conditions})""".format(item_conditions=item_conditions))
|
||||
if filters.get("warehouse"):
|
||||
conditions.append("warehouse=%(warehouse)s")
|
||||
if filters.get("voucher_no"):
|
||||
|
||||
@@ -7,9 +7,7 @@ wn.query_reports["Stock Projected Qty"] = {
|
||||
"fieldname":"company",
|
||||
"label": wn._("Company"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Company",
|
||||
"default": wn.defaults.get_user_default("company"),
|
||||
"reqd": 1
|
||||
"options": "Company"
|
||||
},
|
||||
{
|
||||
"fieldname":"warehouse",
|
||||
|
||||
@@ -13,14 +13,14 @@ def execute(filters=None):
|
||||
projected_qty, item.re_order_level, item.re_order_qty
|
||||
from `tabBin` bin,
|
||||
(select name, company from tabWarehouse
|
||||
where company=%(company)s {warehouse_conditions}) wh,
|
||||
{warehouse_conditions}) wh,
|
||||
(select name, item_name, description, stock_uom, item_group,
|
||||
brand, re_order_level, re_order_qty
|
||||
from `tabItem` {item_conditions}) item
|
||||
where item_code = item.name and warehouse = wh.name
|
||||
order by item.name, wh.name"""\
|
||||
.format(item_conditions=get_item_conditions(filters),
|
||||
warehouse_conditions=get_warehouse_conditions(filters)), filters, debug=1)
|
||||
warehouse_conditions=get_warehouse_conditions(filters)), filters)
|
||||
|
||||
return columns, data
|
||||
|
||||
@@ -41,4 +41,10 @@ def get_item_conditions(filters):
|
||||
return "where {}".format(" and ".join(conditions)) if conditions else ""
|
||||
|
||||
def get_warehouse_conditions(filters):
|
||||
return " and name=%(warehouse)s" if filters.get("warehouse") else ""
|
||||
conditions = []
|
||||
if filters.get("company"):
|
||||
conditions.append("company=%(company)s")
|
||||
if filters.get("warehouse"):
|
||||
conditions.append("name=%(warehouse)s")
|
||||
|
||||
return "where {}".format(" and ".join(conditions)) if conditions else ""
|
||||
@@ -113,7 +113,14 @@ def update_entries_after(args, verbose=1):
|
||||
(qty_after_transaction * valuation_rate) or 0
|
||||
else:
|
||||
stock_value = sum((flt(batch[0]) * flt(batch[1]) for batch in stock_queue))
|
||||
|
||||
|
||||
# rounding as per precision
|
||||
from webnotes.model.meta import get_field_precision
|
||||
meta = webnotes.get_doctype("Stock Ledger Entry")
|
||||
|
||||
stock_value = flt(stock_value, get_field_precision(meta.get_field("stock_value"),
|
||||
webnotes._dict({"fields": sle})))
|
||||
|
||||
stock_value_difference = stock_value - prev_stock_value
|
||||
prev_stock_value = stock_value
|
||||
|
||||
|
||||
Reference in New Issue
Block a user