diff --git a/accounts/doctype/cost_center/cost_center.py b/accounts/doctype/cost_center/cost_center.py index e57b6a37582..a7672452aad 100644 --- a/accounts/doctype/cost_center/cost_center.py +++ b/accounts/doctype/cost_center/cost_center.py @@ -81,7 +81,7 @@ class DocType(DocTypeNestedSet): """ Cost Center name must be unique """ - if (self.doc.__islocal or not self.doc.name) and webnotes.conn.sql("select name from `tabCost Center` where cost_center_name = %s and company_name=%s", (self.doc.cost_center_name, self.doc.company_name)): + if (self.doc.fields.get("__islocal") or not self.doc.name) and webnotes.conn.sql("select name from `tabCost Center` where cost_center_name = %s and company_name=%s", (self.doc.cost_center_name, self.doc.company_name)): msgprint("Cost Center Name already exists, please rename", raise_exception=1) self.validate_mandatory() diff --git a/accounts/doctype/gl_entry/gl_entry.py b/accounts/doctype/gl_entry/gl_entry.py index 64d84b04594..429cc104a7b 100644 --- a/accounts/doctype/gl_entry/gl_entry.py +++ b/accounts/doctype/gl_entry/gl_entry.py @@ -108,8 +108,8 @@ class DocType: 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 ret and ret[0]["company"] != self.doc.company: + + 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) @@ -124,9 +124,10 @@ class DocType: return self.cost_center_company[self.doc.cost_center] - if 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) + 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): """ diff --git a/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/accounts/doctype/purchase_invoice/test_purchase_invoice.py index 621604b96b6..a70c932d9b2 100644 --- a/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -72,7 +72,38 @@ class TestPurchaseInvoice(unittest.TestCase): ["Stock Received But Not Billed - _TC", 750.0, 0], ["_Test Account Shipping Charges - _TC", 100.0, 0], ["_Test Account VAT - _TC", 120.0, 0], - ["Expenses Included In Valuation - _TC", 0, 250.0] + ["Expenses Included In Valuation - _TC", 0, 250.0], + ]) + + for i, gle in enumerate(gl_entries): + 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_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) + + pi = webnotes.bean(copy=test_records[1]) + pi.doclist[1].item_code = "_Test Non Stock Item" + pi.doclist[1].expense_head = "_Test Account Cost for Goods Sold - _TC" + pi.doclist.pop(2) + pi.doclist.pop(3) + pi.run_method("calculate_taxes_and_totals") + pi.insert() + pi.submit() + + gl_entries = webnotes.conn.sql("""select account, debit, credit + from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s + order by account asc""", pi.doc.name, as_dict=1) + self.assertTrue(gl_entries) + + expected_values = sorted([ + ["_Test Supplier - _TC", 0, 620], + ["_Test Account Cost for Goods Sold - _TC", 500.0, 0], + ["_Test Account VAT - _TC", 120.0, 0], ]) for i, gle in enumerate(gl_entries): @@ -106,7 +137,6 @@ class TestPurchaseInvoice(unittest.TestCase): self.assertEqual(tax.account_head, expected_values[i][0]) self.assertEqual(tax.tax_amount, expected_values[i][1]) self.assertEqual(tax.total, expected_values[i][2]) - # print tax.account_head, tax.tax_amount, tax.item_wise_tax_detail expected_values = [ ["_Test Item Home Desktop 100", 90, 59], @@ -142,7 +172,6 @@ class TestPurchaseInvoice(unittest.TestCase): self.assertEqual(tax.account_head, expected_values[i][0]) self.assertEqual(tax.tax_amount, expected_values[i][1]) self.assertEqual(tax.total, expected_values[i][2]) - # print tax.account_head, tax.tax_amount, tax.item_wise_tax_detail expected_values = [ ["_Test FG Item", 90, 7059], diff --git a/accounts/page/accounts_home/accounts_home.js b/accounts/page/accounts_home/accounts_home.js index 3e9ea9243cc..6a9f91a7194 100644 --- a/accounts/page/accounts_home/accounts_home.js +++ b/accounts/page/accounts_home/accounts_home.js @@ -149,6 +149,16 @@ wn.module_page["Accounts"] = [ route: "query-report/Accounts Payable", doctype: "Purchase Invoice" }, + { + "label":wn._("Sales Register"), + route: "query-report/Sales Register", + doctype: "Sales Invoice" + }, + { + "label":wn._("Purchase Register"), + route: "query-report/Purchase Register", + doctype: "Purchase Invoice" + }, ] }, { diff --git a/accounts/page/general_ledger/general_ledger.js b/accounts/page/general_ledger/general_ledger.js index 21be3a05dd7..a462b70e93e 100644 --- a/accounts/page/general_ledger/general_ledger.js +++ b/accounts/page/general_ledger/general_ledger.js @@ -186,7 +186,6 @@ erpnext.GeneralLedger = wn.views.GridReport.extend({ var totals = this.make_summary_row("Totals", this.account); var grouped_ledgers = {}; - $.each(data, function(i, item) { if((me.is_default("company") ? true : me.apply_filter(item, "company")) && (me.account ? me.is_child_account(me.account, item.account) @@ -217,8 +216,7 @@ erpnext.GeneralLedger = wn.views.GridReport.extend({ grouped_ledgers[item.account].totals.debit += item.debit; grouped_ledgers[item.account].totals.credit += item.credit; } - - if(me.account) { + if(item.account) { item.against_account = me.voucher_accounts[item.voucher_type + ":" + item.voucher_no][(item.debit > 0 ? "credits" : "debits")].join(", "); } diff --git a/accounts/report/accounts_payable/accounts_payable.py b/accounts/report/accounts_payable/accounts_payable.py index 34c8ccd2be2..a10dc7e7e7d 100644 --- a/accounts/report/accounts_payable/accounts_payable.py +++ b/accounts/report/accounts_payable/accounts_payable.py @@ -19,7 +19,6 @@ def execute(filters=None): and nowdate() or filters.get("report_date") data = [] - total_invoiced_amount = total_paid = total_outstanding = 0 for gle in entries: if cstr(gle.against_voucher) == gle.voucher_no or not gle.against_voucher \ or [gle.against_voucher_type, gle.against_voucher] in entries_after_report_date: @@ -36,7 +35,7 @@ def execute(filters=None): paid_amount = get_paid_amount(gle, filters.get("report_date") or nowdate(), entries_after_report_date) outstanding_amount = invoiced_amount - paid_amount - + if abs(flt(outstanding_amount)) > 0.01: row = [gle.posting_date, gle.account, gle.voucher_type, gle.voucher_no, gle.remarks, account_supplier_type_map.get(gle.account), due_date, bill_no, @@ -47,16 +46,9 @@ def execute(filters=None): ageing_based_on_date = due_date else: ageing_based_on_date = gle.posting_date + row += get_ageing_data(ageing_based_on_date, age_on, outstanding_amount) - - # Add to total - total_invoiced_amount += flt(invoiced_amount) - total_paid += flt(paid_amount) - total_outstanding += flt(outstanding_amount) data.append(row) - if data: - data.append(["", "", "", "", "", "", "", "Total", "", total_invoiced_amount, total_paid, - total_outstanding, "", "", "", ""]) return columns, data diff --git a/accounts/report/accounts_payable/accounts_payable.txt b/accounts/report/accounts_payable/accounts_payable.txt index 8920a0bf2ee..6de97f64e6e 100644 --- a/accounts/report/accounts_payable/accounts_payable.txt +++ b/accounts/report/accounts_payable/accounts_payable.txt @@ -2,11 +2,12 @@ { "creation": "2013-04-22 16:16:03", "docstatus": 0, - "modified": "2013-04-23 14:54:27", + "modified": "2013-04-30 17:55:54", "modified_by": "Administrator", "owner": "Administrator" }, { + "add_total_row": 1, "doctype": "Report", "is_standard": "Yes", "name": "__common__", diff --git a/accounts/report/accounts_receivable/accounts_receivable.py b/accounts/report/accounts_receivable/accounts_receivable.py index d385b36b902..a8c6d2311eb 100644 --- a/accounts/report/accounts_receivable/accounts_receivable.py +++ b/accounts/report/accounts_receivable/accounts_receivable.py @@ -18,7 +18,6 @@ def execute(filters=None): and nowdate() or filters.get("report_date") data = [] - total_invoiced_amount = total_payment = total_outstanding = 0 for gle in entries: if cstr(gle.against_voucher) == gle.voucher_no or not gle.against_voucher \ or [gle.against_voucher_type, gle.against_voucher] in entries_after_report_date: @@ -41,17 +40,9 @@ def execute(filters=None): else: ageing_based_on_date = gle.posting_date row += get_ageing_data(ageing_based_on_date, age_on, outstanding_amount) - - # Add to total - total_invoiced_amount += flt(invoiced_amount) - total_payment += flt(payment_amount) - total_outstanding += flt(outstanding_amount) - + data.append(row) - if data: - data.append(["", "", "", "", "", "", "Total", total_invoiced_amount, total_payment, - total_outstanding, "", "", "", ""]) - + return columns, data def get_columns(): diff --git a/accounts/report/accounts_receivable/accounts_receivable.txt b/accounts/report/accounts_receivable/accounts_receivable.txt index 28f7e4f44dd..7eb344fc087 100644 --- a/accounts/report/accounts_receivable/accounts_receivable.txt +++ b/accounts/report/accounts_receivable/accounts_receivable.txt @@ -2,11 +2,12 @@ { "creation": "2013-04-16 11:31:13", "docstatus": 0, - "modified": "2013-04-16 11:31:13", + "modified": "2013-04-30 17:54:47", "modified_by": "Administrator", "owner": "Administrator" }, { + "add_total_row": 1, "doctype": "Report", "is_standard": "Yes", "name": "__common__", diff --git a/accounts/report/purchase_register/__init__.py b/accounts/report/purchase_register/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/accounts/report/purchase_register/purchase_register.js b/accounts/report/purchase_register/purchase_register.js new file mode 100644 index 00000000000..21e0547f4a5 --- /dev/null +++ b/accounts/report/purchase_register/purchase_register.js @@ -0,0 +1,42 @@ +wn.query_reports["Purchase Register"] = { + "filters": [ + { + "fieldname":"from_date", + "label": "From Date", + "fieldtype": "Date", + "default": wn.defaults.get_user_default("year_start_date"), + "width": "80" + }, + { + "fieldname":"to_date", + "label": "To Date", + "fieldtype": "Date", + "default": get_today() + }, + { + "fieldname":"account", + "label": "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": { + "is_pl_account": "No", + "debit_or_credit": "Credit", + "company": company, + "master_type": "Supplier" + } + } + } + }, + { + "fieldname":"company", + "label": "Company", + "fieldtype": "Link", + "options": "Company", + "default": sys_defaults.company + } + ] +} \ No newline at end of file diff --git a/accounts/report/purchase_register/purchase_register.py b/accounts/report/purchase_register/purchase_register.py new file mode 100644 index 00000000000..01dc93700b2 --- /dev/null +++ b/accounts/report/purchase_register/purchase_register.py @@ -0,0 +1,147 @@ +# ERPNext - web based ERP (http://erpnext.com) +# Copyright (C) 2012 Web Notes Technologies Pvt Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from __future__ import unicode_literals +import webnotes +from webnotes.utils import flt + +def execute(filters=None): + if not filters: filters = {} + columns, expense_accounts, tax_accounts = get_columns() + + invoice_list = get_invoices(filters) + invoice_expense_map = get_invoice_expense_map(invoice_list) + invoice_tax_map = get_invoice_tax_map(invoice_list) + invoice_po_pr_map = get_invoice_po_pr_map(invoice_list) + account_map = get_account_details(invoice_list) + + data = [] + for inv in invoice_list: + # invoice details + purchase_order = ", ".join(invoice_po_pr_map.get(inv.name, {}).get("purchase_order", [])) + purchase_receipt = ", ".join(invoice_po_pr_map.get(inv.name, {}).get("purchase_receipt", [])) + row = [inv.name, inv.posting_date, inv.supplier, inv.credit_to, + account_map.get(inv.credit_to), inv.project_name, inv.bill_no, inv.bill_date, + inv.remarks, purchase_order, purchase_receipt] + + # map expense values + for expense_acc in expense_accounts: + row.append(invoice_expense_map.get(inv.name, {}).get(expense_acc)) + + # net total + row.append(inv.net_total) + + # tax account + for tax_acc in tax_accounts: + row.append(invoice_tax_map.get(inv.name, {}).get(tax_acc)) + + # total tax, grand total + row += [inv.total_tax, inv.grand_total] + data.append(row) + + return columns, data + + +def get_columns(): + """return columns based on filters""" + columns = [ + "Invoice:Link/Purchase Invoice:120", "Posting Date:Date:80", "Supplier:Link/Supplier:120", + "Supplier Account:Link/Account:120", "Account Group:LInk/Account:120", + "Project:Link/Project:80", "Bill No::120", "Bill Date:Date:80", "Remarks::150", + "Purchase Order:Link/Purchase Order:100", "Purchase Receipt:Link/Purchase Receipt:100" + ] + + expense_accounts = webnotes.conn.sql_list("""select distinct expense_head + from `tabPurchase Invoice Item` where docstatus = 1 and ifnull(expense_head, '') != '' + order by expense_head""") + tax_accounts = webnotes.conn.sql_list("""select distinct account_head + from `tabPurchase Taxes and Charges` where parenttype = 'Purchase Invoice' + and docstatus = 1 and ifnull(account_head, '') != '' order by account_head""") + + columns = columns + [(account + ":Currency:120") for account in expense_accounts] + \ + ["Net Total:Currency:120"] + [(account + ":Currency:120") for account in tax_accounts] + \ + ["Total Tax:Currency:120"] + ["Grand Total:Currency:120"] + + return columns, expense_accounts, tax_accounts + +def get_conditions(filters): + conditions = "" + + if filters.get("company"): conditions += " and company=%(company)s" + if filters.get("account"): conditions += " and account = %(account)s" + + if filters.get("from_date"): conditions += " and posting_date>=%(from_date)s" + if filters.get("to_date"): conditions += " and posting_date<=%(to_date)s" + + return conditions + +def get_invoices(filters): + conditions = get_conditions(filters) + return webnotes.conn.sql("""select name, posting_date, credit_to, project_name, supplier, + bill_no, bill_date, remarks, net_total, total_tax, grand_total + from `tabPurchase Invoice` where docstatus = 1 %s + order by posting_date desc, name desc""" % conditions, filters, as_dict=1) + +def get_invoice_expense_map(invoice_list): + expense_details = webnotes.conn.sql("""select parent, expense_head, sum(amount) as amount + from `tabPurchase Invoice Item` where parent in (%s) group by parent, expense_head""" % + ', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1) + + invoice_expense_map = {} + for d in expense_details: + invoice_expense_map.setdefault(d.parent, webnotes._dict()).setdefault(d.expense_head, []) + invoice_expense_map[d.parent][d.expense_head] = flt(d.amount) + + return invoice_expense_map + +def get_invoice_tax_map(invoice_list): + tax_details = webnotes.conn.sql("""select parent, account_head, sum(tax_amount) as tax_amount + from `tabPurchase Taxes and Charges` where parent in (%s) group by parent, account_head""" % + ', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1) + + invoice_tax_map = {} + for d in tax_details: + invoice_tax_map.setdefault(d.parent, webnotes._dict()).setdefault(d.account_head, []) + invoice_tax_map[d.parent][d.account_head] = flt(d.tax_amount) + + return invoice_tax_map + +def get_invoice_po_pr_map(invoice_list): + pi_items = webnotes.conn.sql("""select parent, purchase_order, purchase_receipt + from `tabPurchase Invoice Item` where parent in (%s) + and (ifnull(purchase_order, '') != '' or ifnull(purchase_receipt, '') != '')""" % + ', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1) + + invoice_po_pr_map = {} + for d in pi_items: + if d.purchase_order: + invoice_po_pr_map.setdefault(d.parent, webnotes._dict()).setdefault( + "purchase_order", []).append(d.purchase_order) + if d.purchase_receipt: + invoice_po_pr_map.setdefault(d.parent, webnotes._dict()).setdefault( + "purchase_receipt", []).append(d.purchase_receipt) + + return invoice_po_pr_map + +def get_account_details(invoice_list): + account_map = {} + accounts = list(set([inv.credit_to for inv in invoice_list])) + for acc in webnotes.conn.sql("""select name, parent_account from tabAccount + where name in (%s)""" % ", ".join(["%s"]*len(accounts)), tuple(accounts), as_dict=1): + account_map.setdefault(acc.name, "") + account_map[acc.name] = acc.parent_account + + return account_map \ No newline at end of file diff --git a/accounts/report/purchase_register/purchase_register.txt b/accounts/report/purchase_register/purchase_register.txt new file mode 100644 index 00000000000..847f5f3b6cb --- /dev/null +++ b/accounts/report/purchase_register/purchase_register.txt @@ -0,0 +1,22 @@ +[ + { + "creation": "2013-04-29 16:13:11", + "docstatus": 0, + "modified": "2013-04-30 17:51:19", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "add_total_row": 1, + "doctype": "Report", + "is_standard": "Yes", + "name": "__common__", + "ref_doctype": "Purchase Invoice", + "report_name": "Purchase Register", + "report_type": "Script Report" + }, + { + "doctype": "Report", + "name": "Purchase Register" + } +] \ No newline at end of file diff --git a/accounts/report/sales_register/__init__.py b/accounts/report/sales_register/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/accounts/report/sales_register/sales_register.js b/accounts/report/sales_register/sales_register.js new file mode 100644 index 00000000000..82246198c95 --- /dev/null +++ b/accounts/report/sales_register/sales_register.js @@ -0,0 +1,42 @@ +wn.query_reports["Sales Register"] = { + "filters": [ + { + "fieldname":"from_date", + "label": "From Date", + "fieldtype": "Date", + "default": wn.defaults.get_user_default("year_start_date"), + "width": "80" + }, + { + "fieldname":"to_date", + "label": "To Date", + "fieldtype": "Date", + "default": get_today() + }, + { + "fieldname":"account", + "label": "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": { + "is_pl_account": "No", + "debit_or_credit": "Debit", + "company": company, + "master_type": "Customer" + } + } + } + }, + { + "fieldname":"company", + "label": "Company", + "fieldtype": "Link", + "options": "Company", + "default": sys_defaults.company + } + ] +} \ No newline at end of file diff --git a/accounts/report/sales_register/sales_register.py b/accounts/report/sales_register/sales_register.py new file mode 100644 index 00000000000..a0020c45a06 --- /dev/null +++ b/accounts/report/sales_register/sales_register.py @@ -0,0 +1,161 @@ +# ERPNext - web based ERP (http://erpnext.com) +# Copyright (C) 2012 Web Notes Technologies Pvt Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from __future__ import unicode_literals +import webnotes +from webnotes.utils import flt + +def execute(filters=None): + if not filters: filters = {} + columns, income_accounts, tax_accounts = get_columns() + + invoice_list = get_invoices(filters) + invoice_income_map = get_invoice_income_map(invoice_list) + invoice_tax_map = get_invoice_tax_map(invoice_list) + + invoice_so_dn_map = get_invoice_so_dn_map(invoice_list) + customer_map = get_customer_deatils(invoice_list) + account_map = get_account_details(invoice_list) + + data = [] + for inv in invoice_list: + # invoice details + sales_order = ", ".join(invoice_so_dn_map.get(inv.name, {}).get("sales_order", [])) + delivery_note = ", ".join(invoice_so_dn_map.get(inv.name, {}).get("delivery_note", [])) + # webnotes.errprint(customer_map.get(inv.customer, [])) + row = [inv.name, inv.posting_date, inv.customer, inv.debit_to, + account_map.get(inv.debit_to), customer_map.get(inv.customer), inv.project_name, + inv.remarks, sales_order, delivery_note] + + # map income values + for income_acc in income_accounts: + row.append(invoice_income_map.get(inv.name, {}).get(income_acc)) + + # net total + row.append(inv.net_total) + + # tax account + for tax_acc in tax_accounts: + row.append(invoice_tax_map.get(inv.name, {}).get(tax_acc)) + + # total tax, grand total + row += [inv.other_charges_total, inv.grand_total] + + data.append(row) + + return columns, data + + +def get_columns(): + """return columns based on filters""" + columns = [ + "Invoice:Link/Sales Invoice:120", "Posting Date:Date:80", "Customer:Link/Customer:120", + "Customer Account:Link/Account:120", "Account Group:LInk/Account:120", + "Territory:Link/Territory:80", "Project:Link/Project:80", + "Remarks::150", "Sales Order:Link/Sales Order:100", "Delivery Note:Link/Delivery Note:100" + ] + + income_accounts = webnotes.conn.sql_list("""select distinct income_account + from `tabSales Invoice Item` where docstatus = 1 order by income_account""") + + tax_accounts = webnotes.conn.sql_list("""select distinct account_head + from `tabSales Taxes and Charges` where parenttype = 'Sales Invoice' + and docstatus = 1 order by account_head""") + + columns = columns + [(account + ":Currency:120") for account in income_accounts] + \ + ["Net Total:Currency:120"] + [(account + ":Currency:120") for account in tax_accounts] + \ + ["Total Tax:Currency:120"] + ["Grand Total:Currency:120"] + + return columns, income_accounts, tax_accounts + +def get_conditions(filters): + conditions = "" + + if filters.get("company"): conditions += " and company=%(company)s" + if filters.get("account"): conditions += " and account = %(account)s" + + if filters.get("from_date"): conditions += " and posting_date>=%(from_date)s" + if filters.get("to_date"): conditions += " and posting_date<=%(to_date)s" + + return conditions + +def get_invoices(filters): + conditions = get_conditions(filters) + return webnotes.conn.sql("""select name, posting_date, debit_to, project_name, customer, + remarks, net_total, other_charges_total, grand_total + from `tabSales Invoice` where docstatus = 1 %s + order by posting_date desc, name desc""" % conditions, filters, as_dict=1) + +def get_invoice_income_map(invoice_list): + income_details = webnotes.conn.sql("""select parent, income_account, sum(amount) as amount + from `tabSales Invoice Item` where parent in (%s) group by parent, income_account""" % + ', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1) + + invoice_income_map = {} + for d in income_details: + invoice_income_map.setdefault(d.parent, webnotes._dict()).setdefault(d.income_account, []) + invoice_income_map[d.parent][d.income_account] = flt(d.amount) + + return invoice_income_map + +def get_invoice_tax_map(invoice_list): + tax_details = webnotes.conn.sql("""select parent, account_head, sum(tax_amount) as tax_amount + from `tabSales Taxes and Charges` where parent in (%s) group by parent, account_head""" % + ', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1) + + invoice_tax_map = {} + for d in tax_details: + invoice_tax_map.setdefault(d.parent, webnotes._dict()).setdefault(d.account_head, []) + invoice_tax_map[d.parent][d.account_head] = flt(d.tax_amount) + + return invoice_tax_map + +def get_invoice_so_dn_map(invoice_list): + si_items = webnotes.conn.sql("""select parent, sales_order, delivery_note + from `tabSales Invoice Item` where parent in (%s) + and (ifnull(sales_order, '') != '' or ifnull(delivery_note, '') != '')""" % + ', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1) + + invoice_so_dn_map = {} + for d in si_items: + if d.sales_order: + invoice_so_dn_map.setdefault(d.parent, webnotes._dict()).setdefault( + "sales_order", []).append(d.sales_order) + if d.delivery_note: + invoice_so_dn_map.setdefault(d.parent, webnotes._dict()).setdefault( + "delivery_note", []).append(d.delivery_note) + + return invoice_so_dn_map + +def get_customer_deatils(invoice_list): + customer_map = {} + customers = list(set([inv.customer for inv in invoice_list])) + for cust in webnotes.conn.sql("""select name, territory from `tabCustomer` + where name in (%s)""" % ", ".join(["%s"]*len(customers)), tuple(customers), as_dict=1): + customer_map.setdefault(cust.name, "") + customer_map[cust.name] = cust.territory + + return customer_map + +def get_account_details(invoice_list): + account_map = {} + accounts = list(set([inv.debit_to for inv in invoice_list])) + for acc in webnotes.conn.sql("""select name, parent_account from tabAccount + where name in (%s)""" % ", ".join(["%s"]*len(accounts)), tuple(accounts), as_dict=1): + account_map.setdefault(acc.name, "") + account_map[acc.name] = acc.parent_account + + return account_map \ No newline at end of file diff --git a/accounts/report/sales_register/sales_register.txt b/accounts/report/sales_register/sales_register.txt new file mode 100644 index 00000000000..dbf41af0d0d --- /dev/null +++ b/accounts/report/sales_register/sales_register.txt @@ -0,0 +1,22 @@ +[ + { + "creation": "2013-04-23 18:15:29", + "docstatus": 0, + "modified": "2013-04-30 17:53:10", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "add_total_row": 1, + "doctype": "Report", + "is_standard": "Yes", + "name": "__common__", + "ref_doctype": "Sales Invoice", + "report_name": "Sales Register", + "report_type": "Script Report" + }, + { + "doctype": "Report", + "name": "Sales Register" + } +] \ No newline at end of file diff --git a/accounts/search_criteria/bank_clearance_report/bank_clearance_report.txt b/accounts/search_criteria/bank_clearance_report/bank_clearance_report.txt index 00384386f52..8aa94bf50a0 100644 --- a/accounts/search_criteria/bank_clearance_report/bank_clearance_report.txt +++ b/accounts/search_criteria/bank_clearance_report/bank_clearance_report.txt @@ -1,29 +1,32 @@ [ { - "owner": "Administrator", + "creation": "2012-05-14 18:05:41", "docstatus": 0, - "creation": "2012-04-03 12:49:50", + "modified": "2013-04-30 14:49:06", "modified_by": "Administrator", - "modified": "2012-04-03 12:49:50" + "owner": "Administrator" }, { - "description": "Bank Clearance report", - "parent_doc_type": "Journal Voucher", - "module": "Accounts", - "standard": "Yes", - "sort_order": "DESC", - "filters": "{'Journal Voucher\u0001Submitted':1,'Journal Voucher\u0001Voucher Type':'','Journal Voucher\u0001Is Opening':'','Journal Voucher\u0001Fiscal Year':'','Journal Voucher\u0001Company':'','Journal Voucher\u0001TDS Applicable':'','Journal Voucher\u0001TDS Category':''}", - "dis_filters": "fiscal_year", - "doc_type": "Journal Voucher Detail", - "name": "__common__", - "doctype": "Search Criteria", - "sort_by": "ID", - "page_len": 50, + "columns": "Journal Voucher\u0001ID,Journal Voucher Detail\u0001Account,Journal Voucher Detail\u0001Debit,Journal Voucher Detail\u0001Credit,Journal Voucher\u0001Clearance Date,Journal Voucher\u0001Cheque No,Journal Voucher\u0001Cheque Date,Journal Voucher\u0001Voucher Date,Journal Voucher\u0001Posting Date,Journal Voucher Detail\u0001Against Payable,Journal Voucher Detail\u0001Against Receivable", "criteria_name": "Bank Clearance report", - "columns": "Journal Voucher\u0001ID,Journal Voucher Detail\u0001Account,Journal Voucher Detail\u0001Debit,Journal Voucher Detail\u0001Credit,Journal Voucher\u0001Clearance Date,Journal Voucher\u0001Cheque No,Journal Voucher\u0001Cheque Date,Journal Voucher\u0001Voucher Date,Journal Voucher\u0001Posting Date,Journal Voucher Detail\u0001Against Payable,Journal Voucher Detail\u0001Against Receivable" + "custom_query": "", + "description": "Bank Clearance report", + "dis_filters": "fiscal_year", + "disabled": 0, + "doc_type": "Journal Voucher Detail", + "doctype": "Search Criteria", + "filters": "{'Journal Voucher\u0001Submitted':1,'Journal Voucher\u0001Voucher Type':'','Journal Voucher\u0001Is Opening':'','Journal Voucher\u0001Fiscal Year':'','Journal Voucher\u0001Company':'','Journal Voucher\u0001TDS Applicable':'','Journal Voucher\u0001TDS Category':''}", + "module": "Accounts", + "name": "__common__", + "page_len": 50, + "parent_doc_type": "Journal Voucher", + "report_script": null, + "sort_by": "ID", + "sort_order": "DESC", + "standard": "Yes" }, { - "name": "bank_clearance_report", - "doctype": "Search Criteria" + "doctype": "Search Criteria", + "name": "bank_clearance_report" } ] \ No newline at end of file diff --git a/accounts/search_criteria/sales_register/sales_register.js b/accounts/search_criteria/sales_register/sales_register.js index 5a09713cd7a..872e198a35a 100644 --- a/accounts/search_criteria/sales_register/sales_register.js +++ b/accounts/search_criteria/sales_register/sales_register.js @@ -28,5 +28,5 @@ report.customize_filters = function() { this.filter_fields_dict['Sales Invoice'+FILTER_SEP +'Grand Total <='].df.filter_hide = 1; this.filter_fields_dict['Sales Invoice'+FILTER_SEP +'Fiscal Year'].df.filter_hide = 1; this.filter_fields_dict['Sales Invoice'+FILTER_SEP +'Sales Partner'].df.filter_hide = 1; - this.filter_fields_dict['Sales Invoice'+FILTER_SEP +'Is Opening'].df.filter_hide = 1; + this.filter_fields_dict['Sales Invoice'+FILTER_SEP +'Is Opening Entry'].df.filter_hide = 1; } diff --git a/controllers/buying_controller.py b/controllers/buying_controller.py index 429737e53eb..e167dc57b77 100644 --- a/controllers/buying_controller.py +++ b/controllers/buying_controller.py @@ -29,6 +29,7 @@ from controllers.stock_controller import StockController class BuyingController(StockController): def validate(self): super(BuyingController, self).validate() + self.validate_stock_or_nonstock_items() if self.meta.get_field("currency"): self.company_currency = get_company_currency(self.doc.company) self.validate_conversion_rate("currency", "conversion_rate") @@ -41,7 +42,25 @@ class BuyingController(StockController): # set total in words self.set_total_in_words() - + + def validate_stock_or_nonstock_items(self): + items = [d.item_code for d in self.doclist.get({"parentfield": self.fname})] + if self.stock_items: + nonstock_items = list(set(items) - set(self.stock_items)) + if nonstock_items: + webnotes.msgprint(_("Stock and non-stock items can not be entered in the same ") + + self.doc.doctype + _(""". You should make separate documents for them. + Stock Items: """) + ", ".join(self.stock_items) + _(""" + Non-stock Items: """) + ", ".join(nonstock_items), raise_exception=1) + + elif items and not self.stock_items: + tax_for_valuation = [d.account_head for d in + self.doclist.get({"parentfield": "purchase_tax_details"}) + if d.category in ["Valuation", "Valuation and Total"]] + if tax_for_valuation: + webnotes.msgprint(_("""Tax Category can not be 'Valuation' or 'Valuation and Total' + as all items are non-stock items"""), raise_exception=1) + def update_item_details(self): for item in self.doclist.get({"parentfield": self.fname}): ret = get_item_details({ diff --git a/home/page/latest_updates/latest_updates.js b/home/page/latest_updates/latest_updates.js index 1e35a9214a7..b768f1aa1e8 100644 --- a/home/page/latest_updates/latest_updates.js +++ b/home/page/latest_updates/latest_updates.js @@ -1,6 +1,8 @@ erpnext.updates = [ - ["10th April", ["Redesigned File Uploads and added File Manager in Setup"]], + ["18th April", ["Cost Center: Set a default Cost Center for a Company"]], ["12th April", ["Employee: List of Leave Approvers who can approve the Employee's Leave Applications"]], + ["10th April", ["Redesigned File Uploads and added File Manager in Setup"]], + ["3rd April", ["Update Manager: Open source users can update their ERPNext instance from Setup > Update Manager"]], ["27th March", ["Rename multiple items together. Go to Setup > Rename Tool"]], ["26th March", ["Added project to Stock Ledger and Balance", "Added Default Cash Account in Company."]], diff --git a/manufacturing/doctype/bom/bom.js b/manufacturing/doctype/bom/bom.js index 4e8fbc95d16..f0c15fa2a9d 100644 --- a/manufacturing/doctype/bom/bom.js +++ b/manufacturing/doctype/bom/bom.js @@ -59,27 +59,22 @@ cur_frm.fields_dict["bom_operations"].grid.on_row_delete = function(cdt, cdn){ set_operation_no(doc); } -cur_frm.cscript.item = function(doc, dt, dn) { - if (doc.item) { - get_server_fields('get_item_details', doc.item, '', doc, dt, dn, 1); - } -} +cur_frm.add_fetch("item", "description", "description"); +cur_frm.add_fetch("item", "stock_uom", "uom"); cur_frm.cscript.workstation = function(doc,dt,dn) { var d = locals[dt][dn]; - if (d.workstation) { - var callback = function(r, rt) { - calculate_op_cost(doc, dt, dn); - calculate_total(doc); - } - get_server_fields('get_workstation_details', d.workstation, - 'bom_operations', doc, dt, dn, 1, callback); - } + wn.model.with_doc("Workstation", d.workstation, function(i, v) { + d.hour_rate = v.hour_rate; + refresh_field("hour_rate"); + calculate_op_cost(doc); + calculate_total(doc); + }); } cur_frm.cscript.hour_rate = function(doc, dt, dn) { - calculate_op_cost(doc, dt, dn); + calculate_op_cost(doc); calculate_total(doc); } @@ -114,7 +109,7 @@ var get_bom_material_detail= function(doc, cdt, cdn) { $.extend(d, r.message); refresh_field("bom_materials"); doc = locals[doc.doctype][doc.name]; - calculate_rm_cost(doc, cdt, cdn); + calculate_rm_cost(doc); calculate_total(doc); }, freeze: true @@ -124,7 +119,7 @@ var get_bom_material_detail= function(doc, cdt, cdn) { cur_frm.cscript.qty = function(doc, cdt, cdn) { - calculate_rm_cost(doc, cdt, cdn); + calculate_rm_cost(doc); calculate_total(doc); } @@ -134,12 +129,12 @@ cur_frm.cscript.rate = function(doc, cdt, cdn) { msgprint("You can not change rate if BOM mentioned agianst any item"); get_bom_material_detail(doc, cdt, cdn); } else { - calculate_rm_cost(doc, cdt, cdn); + calculate_rm_cost(doc); calculate_total(doc); } } -var calculate_op_cost = function(doc, dt, dn) { +var calculate_op_cost = function(doc) { var op = getchildren('BOM Operation', doc.name, 'bom_operations'); total_op_cost = 0; for(var i=0;i 0", self.doc.name) for e in existing_qty: msgprint("%s Units exist in Warehouse %s, which is not an Asset Warehouse." % diff --git a/stock/page/stock_ageing/stock_ageing.js b/stock/page/stock_ageing/stock_ageing.js index edad9a76a18..456f5f13670 100644 --- a/stock/page/stock_ageing/stock_ageing.js +++ b/stock/page/stock_ageing/stock_ageing.js @@ -95,6 +95,8 @@ erpnext.StockAgeing = erpnext.StockGridReport.extend({ this.data = [].concat(this._data); + this.serialized_buying_rates = this.get_serialized_buying_rates(); + $.each(this.data, function(i, d) { me.reset_item_values(d); }); diff --git a/support/doctype/support_ticket/support_ticket.js b/support/doctype/support_ticket/support_ticket.js index 3da81d9efbe..4ee4c1d9684 100644 --- a/support/doctype/support_ticket/support_ticket.js +++ b/support/doctype/support_ticket/support_ticket.js @@ -29,17 +29,13 @@ $.extend(cur_frm.cscript, { erpnext.hide_naming_series(); cur_frm.cscript.make_listing(doc); if(!doc.__islocal) { - if(in_list(user_roles,'System Manager')) { - if(doc.status!='Closed') cur_frm.add_custom_button('Close Ticket', cur_frm.cscript['Close Ticket']); - if(doc.status=='Closed') cur_frm.add_custom_button('Re-Open Ticket', cur_frm.cscript['Re-Open Ticket']); - }else if(doc.allocated_to) { - cur_frm.set_df_property('status','read_only', 1); - if(user==doc.allocated_to && doc.status!='Closed') cur_frm.add_custom_button('Close Ticket', cur_frm.cscript['Close Ticket']); + if(user_roles.indexOf("Support Manager")!==-1) { + if(doc.status!='Closed') cur_frm.add_custom_button('Close Ticket', cur_frm.cscript['Close Ticket']); + if(doc.status=='Closed') cur_frm.add_custom_button('Re-Open Ticket', cur_frm.cscript['Re-Open Ticket']); } - cur_frm.set_df_property('subject','read_only', 1); - cur_frm.set_df_property('description','hidden', 1); - cur_frm.set_df_property('raised_by','read_only', 1); + cur_frm.toggle_enable(["subject", "raised_by"], false); + cur_frm.toggle_display("description", false); } refresh_field('status'); }, diff --git a/support/doctype/support_ticket/support_ticket.py b/support/doctype/support_ticket/support_ticket.py index 5625f1179cd..8a705f41c72 100644 --- a/support/doctype/support_ticket/support_ticket.py +++ b/support/doctype/support_ticket/support_ticket.py @@ -45,6 +45,10 @@ class DocType(TransactionBase): def validate(self): self.update_status() + if self.doc.status == "Closed": + from webnotes.widgets.form.assign_to import clear + clear(self.doc.doctype, self.doc.name) + def on_communication_sent(self, comm): webnotes.conn.set(self.doc, 'status', 'Waiting for Customer') if comm.lead and not self.doc.lead: diff --git a/utilities/doctype/rename_tool/rename_tool.py b/utilities/doctype/rename_tool/rename_tool.py index 2e368ced709..5accf3c6b77 100644 --- a/utilities/doctype/rename_tool/rename_tool.py +++ b/utilities/doctype/rename_tool/rename_tool.py @@ -34,7 +34,8 @@ def upload(select_doctype=None, rows=None): rename_log = [] for row in rows: - if len(row) > 2: + # if row has some content + if len(row) > 1 and row[0] and row[1]: try: if rename_doc(select_doctype, row[0], row[1]): rename_log.append(_("Successful: ") + row[0] + " -> " + row[1]) @@ -45,5 +46,5 @@ def upload(select_doctype=None, rows=None): rename_log.append("" + \ _("Failed: ") + row[0] + " -> " + row[1] + "") rename_log.append("" + repr(e) + "") - + return rename_log \ No newline at end of file