From a1ffacaf0bb3e9b76f22e96708d69f9c14ea6c42 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 2 Jan 2014 16:30:16 +0530 Subject: [PATCH 01/65] Valuation related charges should only go to stock items --- controllers/accounts_controller.py | 3 --- controllers/buying_controller.py | 38 +++++++++++++++++------------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/controllers/accounts_controller.py b/controllers/accounts_controller.py index 5388ee120a..11480c9ebe 100644 --- a/controllers/accounts_controller.py +++ b/controllers/accounts_controller.py @@ -231,9 +231,6 @@ class AccountsController(TransactionBase): # tax_amount represents the amount of tax for the current step current_tax_amount = self.get_current_tax_amount(item, tax, item_tax_map) - if hasattr(self, "set_item_tax_amount"): - self.set_item_tax_amount(item, tax, current_tax_amount) - # case when net total is 0 but there is an actual type charge # in this case add the actual amount to tax.tax_amount # and tax.grand_total_for_current_item for the first such iteration diff --git a/controllers/buying_controller.py b/controllers/buying_controller.py index 35b9d25279..4aa08d6c55 100644 --- a/controllers/buying_controller.py +++ b/controllers/buying_controller.py @@ -163,30 +163,36 @@ class BuyingController(StockController): if not self.meta.get_field("item_tax_amount", parentfield=self.fname): for item in self.item_doclist: del item.fields["item_tax_amount"] - - def set_item_tax_amount(self, item, tax, current_tax_amount): + + # update valuation rate + def update_valuation_rate(self, parentfield): """ item_tax_amount is the total tax amount applied on that item stored for valuation TODO: rename item_tax_amount to valuation_tax_amount """ - if tax.category in ["Valuation", "Valuation and Total"] and \ - self.meta.get_field("item_tax_amount", parentfield=self.fname): - item.item_tax_amount += flt(current_tax_amount, self.precision("item_tax_amount", item)) - - # update valuation rate - def update_valuation_rate(self, parentfield): - for item in self.doclist.get({"parentfield": parentfield}): - item.conversion_factor = item.conversion_factor or flt(webnotes.conn.get_value( - "UOM Conversion Detail", {"parent": item.item_code, "uom": item.uom}, - "conversion_factor")) or 1 + stock_items = self.get_stock_items() + + stock_items_amount = sum([flt(d.amount) for d in + self.doclist.get({"parentfield": parentfield}) + if d.item_code and d.item_code in stock_items]) - if item.item_code and item.qty: + total_valuation_amount = sum([flt(d.tax_amount) for d in + self.doclist.get({"parentfield": "purchase_tax_details"}) + if d.category in ["Valuation", "Valuation and Total"]]) + + + for item in self.doclist.get({"parentfield": parentfield}): + if item.item_code and item.qty and item.item_code in stock_items: + item.item_tax_amount = flt(flt(item.amount) * total_valuation_amount \ + / stock_items_amount, self.precision("item_tax_amount", item)) + self.round_floats_in(item) - - # if no item code, which is sometimes the case in purchase invoice, - # then it is not possible to track valuation against it + + item.conversion_factor = item.conversion_factor or flt(webnotes.conn.get_value( + "UOM Conversion Detail", {"parent": item.item_code, "uom": item.uom}, + "conversion_factor")) or 1 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) From df07c964f74e5527d2ab1a0aaffb2cdd96807619 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Thu, 2 Jan 2014 17:42:01 +0600 Subject: [PATCH 02/65] bumped to version 3.4.4 --- config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.json b/config.json index c09c2afac9..e8955b178c 100644 --- a/config.json +++ b/config.json @@ -1,6 +1,6 @@ { "app_name": "ERPNext", - "app_version": "3.4.3", + "app_version": "3.4.4", "base_template": "app/portal/templates/base.html", "modules": { "Accounts": { @@ -74,5 +74,5 @@ "type": "module" } }, - "requires_framework_version": "==3.4.2" + "requires_framework_version": "==3.4.3" } \ No newline at end of file From 28acaeb3456e31351e3dd32c0ba6d886c70a7442 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 3 Jan 2014 11:16:16 +0530 Subject: [PATCH 03/65] Fixes in valuation rate calculation in purchase receipt --- controllers/buying_controller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/buying_controller.py b/controllers/buying_controller.py index 4aa08d6c55..f014f72ee5 100644 --- a/controllers/buying_controller.py +++ b/controllers/buying_controller.py @@ -184,7 +184,7 @@ class BuyingController(StockController): for item in self.doclist.get({"parentfield": parentfield}): - if item.item_code and item.qty and item.item_code in stock_items: + if item.item_code and item.qty and stock_items_amount and item.item_code in stock_items: item.item_tax_amount = flt(flt(item.amount) * total_valuation_amount \ / stock_items_amount, self.precision("item_tax_amount", item)) From a4db83a934eb4fefd356ae6f55d88f97e3d45af9 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 3 Jan 2014 12:13:18 +0530 Subject: [PATCH 04/65] Fixes in valuation rate calculation in purchase receipt --- .../purchase_invoice/purchase_invoice.py | 12 ------------ accounts/utils.py | 2 ++ controllers/buying_controller.py | 17 +++++++++++------ 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.py b/accounts/doctype/purchase_invoice/purchase_invoice.py index 404627af25..0b8ad46dd0 100644 --- a/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -350,7 +350,6 @@ class DocType(BuyingController): # item gl entries stock_item_and_auto_accounting_for_stock = False stock_items = self.get_stock_items() - # 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): @@ -361,11 +360,6 @@ class DocType(BuyingController): 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) - gl_entries.append( self.get_gl_dict({ "account": item.expense_head, @@ -392,12 +386,6 @@ class DocType(BuyingController): # this will balance out valuation amount included in cost of goods sold 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) for cost_center, amount in valuation_tax.items(): gl_entries.append( diff --git a/accounts/utils.py b/accounts/utils.py index 8971c80f99..a5fb390e9f 100644 --- a/accounts/utils.py +++ b/accounts/utils.py @@ -31,6 +31,8 @@ def get_fiscal_years(date=None, fiscal_year=None, label="Date", verbose=1): if not fy: error_msg = """%s %s not in any Fiscal Year""" % (label, formatdate(date)) + error_msg = """{msg}: {date}""".format(msg=_("Fiscal Year does not exist for date"), + date=formatdate(date)) if verbose: webnotes.msgprint(error_msg) raise FiscalYearError, error_msg diff --git a/controllers/buying_controller.py b/controllers/buying_controller.py index f014f72ee5..3c6981d6cb 100644 --- a/controllers/buying_controller.py +++ b/controllers/buying_controller.py @@ -174,9 +174,11 @@ class BuyingController(StockController): """ stock_items = self.get_stock_items() - stock_items_amount = sum([flt(d.amount) for d in - self.doclist.get({"parentfield": parentfield}) - if d.item_code and d.item_code in stock_items]) + stock_items_qty, stock_items_amount = 0, 0 + for d in self.doclist.get({"parentfield": parentfield}): + if d.item_code and d.item_code in stock_items: + stock_items_qty += flt(d.qty) + stock_items_amount += flt(d.amount) total_valuation_amount = sum([flt(d.tax_amount) for d in self.doclist.get({"parentfield": "purchase_tax_details"}) @@ -184,9 +186,12 @@ class BuyingController(StockController): for item in self.doclist.get({"parentfield": parentfield}): - if item.item_code and item.qty and stock_items_amount and item.item_code in stock_items: - item.item_tax_amount = flt(flt(item.amount) * total_valuation_amount \ - / stock_items_amount, self.precision("item_tax_amount", item)) + if item.item_code and item.qty and item.item_code in stock_items: + item_proportion = flt(item.amount) / stock_items_amount if stock_items_amount \ + else flt(item.qty) / stock_items_qty + + item.item_tax_amount = flt(item_proportion * total_valuation_amount, + self.precision("item_tax_amount", item)) self.round_floats_in(item) From 6472bdace2b67e023563c2ca00b41cdfb2c9683e Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 3 Jan 2014 12:30:24 +0530 Subject: [PATCH 05/65] Fixes in general ledger report --- accounts/doctype/journal_voucher/journal_voucher.js | 3 ++- accounts/doctype/purchase_invoice/purchase_invoice.js | 3 ++- accounts/doctype/sales_invoice/sales_invoice.js | 3 ++- accounts/report/general_ledger/general_ledger.py | 2 +- public/js/controllers/stock_controller.js | 3 ++- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/accounts/doctype/journal_voucher/journal_voucher.js b/accounts/doctype/journal_voucher/journal_voucher.js index 6b94ba170a..e5cea8cc79 100644 --- a/accounts/doctype/journal_voucher/journal_voucher.js +++ b/accounts/doctype/journal_voucher/journal_voucher.js @@ -120,7 +120,8 @@ cur_frm.cscript.refresh = function(doc) { "voucher_no": doc.name, "from_date": doc.posting_date, "to_date": doc.posting_date, - "company": doc.company + "company": doc.company, + group_by_voucher: 0 }; wn.set_route("query-report", "General Ledger"); }, "icon-table"); diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.js b/accounts/doctype/purchase_invoice/purchase_invoice.js index 0bdc70e13d..1055bdd25d 100644 --- a/accounts/doctype/purchase_invoice/purchase_invoice.js +++ b/accounts/doctype/purchase_invoice/purchase_invoice.js @@ -35,7 +35,8 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({ "voucher_no": doc.name, "from_date": doc.posting_date, "to_date": doc.posting_date, - "company": doc.company + "company": doc.company, + group_by_voucher: 0 }; wn.set_route("query-report", "General Ledger"); }, "icon-table"); diff --git a/accounts/doctype/sales_invoice/sales_invoice.js b/accounts/doctype/sales_invoice/sales_invoice.js index a390fb4ed7..3bdef5bb56 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.js +++ b/accounts/doctype/sales_invoice/sales_invoice.js @@ -54,7 +54,8 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte "voucher_no": doc.name, "from_date": doc.posting_date, "to_date": doc.posting_date, - "company": doc.company + "company": doc.company, + group_by_voucher: 0 }; wn.set_route("query-report", "General Ledger"); }, "icon-table"); diff --git a/accounts/report/general_ledger/general_ledger.py b/accounts/report/general_ledger/general_ledger.py index 2efc8241c0..855b7d1c7a 100644 --- a/accounts/report/general_ledger/general_ledger.py +++ b/accounts/report/general_ledger/general_ledger.py @@ -136,7 +136,7 @@ def get_accountwise_gle(filters, gl_entries, gle_map): or cstr(gle.is_advance) == "Yes"): gle_map[gle.account].opening += amount opening += amount - elif gle.posting_date < filters.to_date: + 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) diff --git a/public/js/controllers/stock_controller.js b/public/js/controllers/stock_controller.js index d2fb904419..6a4261c22a 100644 --- a/public/js/controllers/stock_controller.js +++ b/public/js/controllers/stock_controller.js @@ -28,7 +28,8 @@ erpnext.stock.StockController = wn.ui.form.Controller.extend({ 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 + company: me.frm.doc.company, + group_by_voucher: false }; wn.set_route("query-report", "General Ledger"); }, "icon-table"); From b0a9581e59c6d7c8c1148afefb26c528bd464c2d Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Fri, 3 Jan 2014 12:44:00 +0530 Subject: [PATCH 06/65] fixed accounts receivable for customer name --- .../accounts_receivable.py | 43 +++++++++++++------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/accounts/report/accounts_receivable/accounts_receivable.py b/accounts/report/accounts_receivable/accounts_receivable.py index 945bae434a..1c76f9baf1 100644 --- a/accounts/report/accounts_receivable/accounts_receivable.py +++ b/accounts/report/accounts_receivable/accounts_receivable.py @@ -18,16 +18,23 @@ class AccountsReceivableReport(object): return self.get_columns(), self.get_data() def get_columns(self): - return [ + columns = [ "Posting Date:Date:80", "Account:Link/Account:150", "Voucher Type::110", "Voucher No::120", "::30", "Due Date:Date:80", "Invoiced Amount:Currency:100", "Payment Received:Currency:100", "Outstanding Amount:Currency:100", "Age:Int:50", "0-30:Currency:100", - "30-60:Currency:100", "60-90:Currency:100", "90-Above:Currency:100", - "Customer:Link/Customer:200", "Territory:Link/Territory:80", "Remarks::200" + "30-60:Currency:100", "60-90:Currency:100", "90-Above:Currency:100" ] + naming_by = self.get_selling_settings() + if naming_by[0].value == "Naming Series": + columns += ["Customer:Link/Customer:200"] + + columns += ["Customer Name::110", "Territory:Link/Territory:80", "Remarks::200"] + + return columns + def get_data(self): data = [] future_vouchers = self.get_entries_after(self.filters.report_date) @@ -42,10 +49,15 @@ class AccountsReceivableReport(object): gle.voucher_type, gle.voucher_no, due_date, invoiced_amount, payment_received, outstanding_amount] - entry_date = due_date if self.filters.ageing_based_on=="Due Date" \ + entry_date = due_date if self.filters.ageing_based_on == "Due Date" \ else gle.posting_date row += get_ageing_data(self.age_as_on, entry_date, outstanding_amount) - row += [self.get_customer(gle.account), self.get_territory(gle.account), gle.remarks] + + naming_by = self.get_selling_settings() + if naming_by[0].value == "Naming Series": + row += [self.get_customer(gle.account)] + + row += [self.get_customer_name(gle.account), self.get_territory(gle.account), gle.remarks] data.append(row) for i in range(0,len(data)): @@ -53,7 +65,11 @@ class AccountsReceivableReport(object): % ("/".join(["#Form", data[i][2], data[i][3]]),)) return data - + + def get_selling_settings(self): + return webnotes.conn.sql("""select value from `tabSingles` where + doctype='Selling Settings' and field='cust_master_name'""", as_dict=1) + def get_entries_after(self, report_date): # returns a distinct list return list(set([(e.voucher_type, e.voucher_no) for e in self.get_gl_entries() @@ -77,18 +93,21 @@ class AccountsReceivableReport(object): return flt(gle.debit) - flt(gle.credit) - payment_received def get_customer(self, account): + return self.get_account_map().get(account).get("customer") or "" + + def get_customer_name(self, account): return self.get_account_map().get(account).get("customer_name") or "" - + def get_territory(self, account): return self.get_account_map().get(account).get("territory") or "" def get_account_map(self): if not hasattr(self, "account_map"): self.account_map = dict(((r.name, r) for r in webnotes.conn.sql("""select - account.name, customer.name as customer_name, customer.territory - from `tabAccount` account, `tabCustomer` customer - where account.master_type="Customer" - and customer.name=account.master_name""", as_dict=True))) + acc.name, cust.name as customer, cust.customer_name, cust.territory + from `tabAccount` acc, `tabCustomer` cust + where acc.master_type="Customer" + and cust.name=acc.master_name""", as_dict=True))) return self.account_map @@ -164,4 +183,4 @@ def get_ageing_data(age_as_on, entry_date, outstanding_amount): if index is None: index = 3 outstanding_range[index] = outstanding_amount - return [age] + outstanding_range + return [age] + outstanding_range \ No newline at end of file From b4eba77f7b00d92a25335d6cfc2adf454763601d Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Fri, 3 Jan 2014 12:58:04 +0530 Subject: [PATCH 07/65] fixed accounts receivable --- .../accounts_receivable/accounts_receivable.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/accounts/report/accounts_receivable/accounts_receivable.py b/accounts/report/accounts_receivable/accounts_receivable.py index 1c76f9baf1..0407039e41 100644 --- a/accounts/report/accounts_receivable/accounts_receivable.py +++ b/accounts/report/accounts_receivable/accounts_receivable.py @@ -26,9 +26,8 @@ class AccountsReceivableReport(object): "Outstanding Amount:Currency:100", "Age:Int:50", "0-30:Currency:100", "30-60:Currency:100", "60-90:Currency:100", "90-Above:Currency:100" ] - - naming_by = self.get_selling_settings() - if naming_by[0].value == "Naming Series": + + if self.get_customer_naming() == "Naming Series": columns += ["Customer:Link/Customer:200"] columns += ["Customer Name::110", "Territory:Link/Territory:80", "Remarks::200"] @@ -53,8 +52,7 @@ class AccountsReceivableReport(object): else gle.posting_date row += get_ageing_data(self.age_as_on, entry_date, outstanding_amount) - naming_by = self.get_selling_settings() - if naming_by[0].value == "Naming Series": + if self.get_customer_naming() == "Naming Series": row += [self.get_customer(gle.account)] row += [self.get_customer_name(gle.account), self.get_territory(gle.account), gle.remarks] @@ -66,9 +64,8 @@ class AccountsReceivableReport(object): return data - def get_selling_settings(self): - return webnotes.conn.sql("""select value from `tabSingles` where - doctype='Selling Settings' and field='cust_master_name'""", as_dict=1) + def get_customer_naming(self): + return webnotes.conn.get_value("Selling Settings", None, "cust_master_name") def get_entries_after(self, report_date): # returns a distinct list From 8a0b7cece13a46b1f62f1dc7a70002f24a3f6731 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Fri, 3 Jan 2014 13:21:38 +0530 Subject: [PATCH 08/65] accounts receivable fixed --- .../accounts_receivable.py | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/accounts/report/accounts_receivable/accounts_receivable.py b/accounts/report/accounts_receivable/accounts_receivable.py index 0407039e41..781db2aaf3 100644 --- a/accounts/report/accounts_receivable/accounts_receivable.py +++ b/accounts/report/accounts_receivable/accounts_receivable.py @@ -15,26 +15,28 @@ class AccountsReceivableReport(object): else self.filters.report_date def run(self): - return self.get_columns(), self.get_data() + customer_naming_by = webnotes.conn.get_value("Selling Settings", None, "cust_master_name") + return self.get_columns(customer_naming_by), self.get_data(customer_naming_by) - def get_columns(self): + def get_columns(self, customer_naming_by): columns = [ "Posting Date:Date:80", "Account:Link/Account:150", "Voucher Type::110", "Voucher No::120", "::30", "Due Date:Date:80", "Invoiced Amount:Currency:100", "Payment Received:Currency:100", "Outstanding Amount:Currency:100", "Age:Int:50", "0-30:Currency:100", - "30-60:Currency:100", "60-90:Currency:100", "90-Above:Currency:100" + "30-60:Currency:100", "60-90:Currency:100", "90-Above:Currency:100", + "Customer:Link/Customer:200" ] - if self.get_customer_naming() == "Naming Series": - columns += ["Customer:Link/Customer:200"] + if customer_naming_by == "Naming Series": + columns += ["Customer Name::110"] - columns += ["Customer Name::110", "Territory:Link/Territory:80", "Remarks::200"] + columns += ["Territory:Link/Territory:80", "Remarks::200"] return columns - def get_data(self): + def get_data(self, customer_naming_by): data = [] future_vouchers = self.get_entries_after(self.filters.report_date) for gle in self.get_entries_till(self.filters.report_date): @@ -50,23 +52,21 @@ class AccountsReceivableReport(object): outstanding_amount] entry_date = due_date if self.filters.ageing_based_on == "Due Date" \ else gle.posting_date - row += get_ageing_data(self.age_as_on, entry_date, outstanding_amount) + row += get_ageing_data(self.age_as_on, entry_date, outstanding_amount) + \ + [self.get_customer(gle.account)] - if self.get_customer_naming() == "Naming Series": - row += [self.get_customer(gle.account)] + if customer_naming_by == "Naming Series": + row += [self.get_customer_name(gle.account)] - row += [self.get_customer_name(gle.account), self.get_territory(gle.account), gle.remarks] + row += [self.get_territory(gle.account), gle.remarks] data.append(row) - for i in range(0,len(data)): + for i in range(0, len(data)): data[i].insert(4, """""" \ % ("/".join(["#Form", data[i][2], data[i][3]]),)) return data - def get_customer_naming(self): - return webnotes.conn.get_value("Selling Settings", None, "cust_master_name") - def get_entries_after(self, report_date): # returns a distinct list return list(set([(e.voucher_type, e.voucher_no) for e in self.get_gl_entries() @@ -163,7 +163,7 @@ class AccountsReceivableReport(object): def execute(filters=None): return AccountsReceivableReport(filters).run() - + def get_ageing_data(age_as_on, entry_date, outstanding_amount): # [0-30, 30-60, 60-90, 90-above] outstanding_range = [0.0, 0.0, 0.0, 0.0] From 866103bf666cd6bec9e96e478f8bf701207fb614 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Fri, 3 Jan 2014 13:57:06 +0600 Subject: [PATCH 09/65] bumped to version 3.4.5 --- config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json b/config.json index e8955b178c..89c1332005 100644 --- a/config.json +++ b/config.json @@ -1,6 +1,6 @@ { "app_name": "ERPNext", - "app_version": "3.4.4", + "app_version": "3.4.5", "base_template": "app/portal/templates/base.html", "modules": { "Accounts": { From 33f6b9d6e8079df15c32773008f7c68fadbb4715 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 3 Jan 2014 15:12:16 +0530 Subject: [PATCH 10/65] Unlinked message listing all linked entries while cancelling an accounting trandsaction --- accounts/utils.py | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/accounts/utils.py b/accounts/utils.py index a5fb390e9f..fdd57b35c2 100644 --- a/accounts/utils.py +++ b/accounts/utils.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import webnotes -from webnotes.utils import nowdate, nowtime, cstr, flt, now, getdate, add_months +from webnotes.utils import nowdate, cstr, flt, now, getdate, add_months from webnotes.model.doc import addchild from webnotes import msgprint, _ from webnotes.utils import formatdate @@ -64,7 +64,6 @@ def get_balance_on(account=None, date=None): try: year_start_date = get_fiscal_year(date, verbose=0)[1] except FiscalYearError, e: - from webnotes.utils import getdate if getdate(date) > getdate(nowdate()): # if fiscal year not found and the date is greater than today # get fiscal year for today's date and its corresponding year start date @@ -222,17 +221,26 @@ def get_cost_center_list(doctype, txt, searchfield, start, page_len, filters): tuple(filter_values + ["%%%s%%" % txt, start, page_len])) def remove_against_link_from_jv(ref_type, ref_no, against_field): - webnotes.conn.sql("""update `tabJournal Voucher Detail` set `%s`=null, - modified=%s, modified_by=%s - where `%s`=%s and docstatus < 2""" % (against_field, "%s", "%s", against_field, "%s"), - (now(), webnotes.session.user, ref_no)) + linked_jv = webnotes.conn.sql_list("""select parent from `tabJournal Voucher Detail` + where `%s`=%s and docstatus < 2""" % (against_field, "%s"), (ref_no)) + + if linked_jv: + webnotes.conn.sql("""update `tabJournal Voucher Detail` set `%s`=null, + modified=%s, modified_by=%s + where `%s`=%s and docstatus < 2""" % (against_field, "%s", "%s", against_field, "%s"), + (now(), webnotes.session.user, ref_no)) - webnotes.conn.sql("""update `tabGL Entry` - 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, '')""", - (now(), webnotes.session.user, ref_type, ref_no)) + webnotes.conn.sql("""update `tabGL Entry` + 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, '')""", + (now(), webnotes.session.user, ref_type, ref_no)) + + webnotes.msgprint("{msg} {linked_jv}".format(msg = _("""Following linked Journal Vouchers \ + made against this transaction has been unlinked. You can link them again with other \ + transactions via Payment Reconciliation Tool."""), linked_jv="\n".join(linked_jv))) + @webnotes.whitelist() def get_company_default(company, fieldname): @@ -370,4 +378,4 @@ def get_account_for(account_for_doctype, account_for): account_for_field = "account_type" return webnotes.conn.get_value("Account", {account_for_field: account_for_doctype, - "master_name": account_for}) + "master_name": account_for}) \ No newline at end of file From 7f0406f281a5d38f442244fd7373a9daf29975e4 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 3 Jan 2014 17:43:19 +0530 Subject: [PATCH 11/65] Chekc over billing validation considering tolerance --- controllers/accounts_controller.py | 35 ++++++++++++++++++------- controllers/status_updater.py | 41 ++++++++++++++++-------------- 2 files changed, 48 insertions(+), 28 deletions(-) diff --git a/controllers/accounts_controller.py b/controllers/accounts_controller.py index 11480c9ebe..1a399219e4 100644 --- a/controllers/accounts_controller.py +++ b/controllers/accounts_controller.py @@ -381,24 +381,41 @@ class AccountsController(TransactionBase): }) def validate_multiple_billing(self, ref_dt, item_ref_dn, based_on, parentfield): + from controllers.status_updater import get_tolerance_for + item_tolerance = {} + global_tolerance = None + for item in self.doclist.get({"parentfield": "entries"}): if item.fields.get(item_ref_dn): already_billed = webnotes.conn.sql("""select sum(%s) from `tab%s` where %s=%s and docstatus=1""" % (based_on, self.tname, item_ref_dn, '%s'), item.fields[item_ref_dn])[0][0] - max_allowed_amt = flt(webnotes.conn.get_value(ref_dt + " Item", - item.fields[item_ref_dn], based_on), self.precision(based_on, item)) - total_billed_amt = flt(flt(already_billed) + flt(item.fields[based_on]), self.precision(based_on, item)) + + ref_amt = flt(webnotes.conn.get_value(ref_dt + " Item", + item.fields[item_ref_dn], based_on), self.precision(based_on, item)) + + tolerance, item_tolerance, global_tolerance = get_tolerance_for(item.item_code, + item_tolerance, global_tolerance) - if max_allowed_amt and total_billed_amt - max_allowed_amt > 0.02: - webnotes.msgprint(_("Row ")+ cstr(item.idx) + ": " + cstr(item.item_code) + - _(" will be over-billed against mentioned ") + cstr(ref_dt) + - _(". Max allowed " + cstr(based_on) + ": " + cstr(max_allowed_amt)), - raise_exception=1) - + max_allowed_amt = flt(ref_amt * (100 + tolerance) / 100) + + if total_billed_amt - max_allowed_amt > 0.01: + reduce_by = total_billed_amt - max_allowed_amt + + webnotes.throw(_("Row #") + cstr(item.idx) + ": " + + _(" Max amount allowed for Item ") + cstr(item.item_code) + + _(" against ") + ref_dt + " " + + cstr(item.fields[ref_dt.lower().replace(" ", "_")]) + _(" is ") + + cstr(max_allowed_amt) + ". \n" + + _("""If you want to increase your overflow tolerance, please increase \ + tolerance % in Global Defaults or Item master. + Or, you must reduce the amount by """) + cstr(reduce_by) + "\n" + + _("""Also, please check if the order item has already been billed \ + in the Sales Order""")) + def get_company_default(self, fieldname): from accounts.utils import get_company_default return get_company_default(self.doc.company, fieldname) diff --git a/controllers/status_updater.py b/controllers/status_updater.py index b2745268f7..a285c4798d 100644 --- a/controllers/status_updater.py +++ b/controllers/status_updater.py @@ -151,7 +151,9 @@ class StatusUpdater(DocListController): """ # check if overflow is within tolerance - tolerance = self.get_tolerance_for(item['item_code']) + tolerance, self.tolerance, self.global_tolerance = get_tolerance_for(item['item_code'], + self.tolerance, self.global_tolerance) + overflow_percent = ((item[args['target_field']] - item[args['target_ref_field']]) / item[args['target_ref_field']]) * 100 @@ -170,23 +172,6 @@ class StatusUpdater(DocListController): Also, please check if the order item has already been billed in the Sales Order""" % item, raise_exception=1) - - def get_tolerance_for(self, item_code): - """ - Returns the tolerance for the item, if not set, returns global tolerance - """ - if self.tolerance.get(item_code): return self.tolerance[item_code] - - tolerance = flt(webnotes.conn.get_value('Item',item_code,'tolerance') or 0) - - if not tolerance: - if self.global_tolerance == None: - self.global_tolerance = flt(webnotes.conn.get_value('Global Defaults', None, - 'tolerance')) - tolerance = self.global_tolerance - - self.tolerance[item_code] = tolerance - return tolerance def update_qty(self, change_modified=True): @@ -245,4 +230,22 @@ class StatusUpdater(DocListController): set %(status_field)s = if(ifnull(%(target_parent_field)s,0)<0.001, 'Not %(keyword)s', if(%(target_parent_field)s>=99.99, 'Fully %(keyword)s', 'Partly %(keyword)s')) - where name='%(name)s'""" % args) \ No newline at end of file + where name='%(name)s'""" % args) + +def get_tolerance_for(item_code, item_tolerance={}, global_tolerance=None): + """ + Returns the tolerance for the item, if not set, returns global tolerance + """ + if item_tolerance.get(item_code): + return item_tolerance[item_code], item_tolerance, global_tolerance + + tolerance = flt(webnotes.conn.get_value('Item',item_code,'tolerance') or 0) + + if not tolerance: + if global_tolerance == None: + global_tolerance = flt(webnotes.conn.get_value('Global Defaults', None, + 'tolerance')) + tolerance = global_tolerance + + item_tolerance[item_code] = tolerance + return tolerance, item_tolerance, global_tolerance \ No newline at end of file From b476c989a40da3d025155311fcbc945468a860d6 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 3 Jan 2014 17:43:52 +0530 Subject: [PATCH 12/65] Fixes test cases for date and year mismatch --- accounts/doctype/sales_invoice/test_sales_invoice.py | 9 +++++---- buying/doctype/purchase_order/test_purchase_order.py | 7 ++++--- .../doctype/production_order/test_production_order.py | 3 ++- selling/doctype/quotation/test_quotation.py | 1 + selling/doctype/sales_order/test_sales_order.py | 1 + stock/doctype/material_request/test_material_request.py | 1 + 6 files changed, 14 insertions(+), 8 deletions(-) diff --git a/accounts/doctype/sales_invoice/test_sales_invoice.py b/accounts/doctype/sales_invoice/test_sales_invoice.py index 5a573f9441..e98dfdc2a0 100644 --- a/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -565,16 +565,17 @@ class TestSalesInvoice(unittest.TestCase): where against_invoice=%s""", si.doc.name)) def test_recurring_invoice(self): - from webnotes.utils import now_datetime, get_first_day, get_last_day, add_to_date - today = now_datetime().date() - + from webnotes.utils import get_first_day, get_last_day, add_to_date, nowdate, getdate + from accounts.utils import get_fiscal_year + today = nowdate() base_si = webnotes.bean(copy=test_records[0]) base_si.doc.fields.update({ "convert_into_recurring_invoice": 1, "recurring_type": "Monthly", "notification_email_address": "test@example.com, test1@example.com, test2@example.com", - "repeat_on_day_of_month": today.day, + "repeat_on_day_of_month": getdate(today).day, "posting_date": today, + "fiscal_year": get_fiscal_year(today)[0], "invoice_period_from_date": get_first_day(today), "invoice_period_to_date": get_last_day(today) }) diff --git a/buying/doctype/purchase_order/test_purchase_order.py b/buying/doctype/purchase_order/test_purchase_order.py index f6c435c6fb..e1933982c4 100644 --- a/buying/doctype/purchase_order/test_purchase_order.py +++ b/buying/doctype/purchase_order/test_purchase_order.py @@ -22,7 +22,7 @@ class TestPurchaseOrder(unittest.TestCase): pr = make_purchase_receipt(po.doc.name) pr[0]["supplier_warehouse"] = "_Test Warehouse 1 - _TC" - + pr[0]["posting_date"] = "2013-05-12" self.assertEquals(pr[0]["doctype"], "Purchase Receipt") self.assertEquals(len(pr), len(test_records[0])) @@ -52,7 +52,7 @@ class TestPurchaseOrder(unittest.TestCase): self.assertEquals(pr[0]["doctype"], "Purchase Receipt") self.assertEquals(len(pr), len(test_records[0])) - + pr[0]["posting_date"] = "2013-05-12" pr[0].naming_series = "_T-Purchase Receipt-" pr[1].qty = 4.0 pr_bean = webnotes.bean(pr) @@ -66,6 +66,7 @@ class TestPurchaseOrder(unittest.TestCase): pr1 = make_purchase_receipt(po.doc.name) pr1[0].naming_series = "_T-Purchase Receipt-" + pr1[0]["posting_date"] = "2013-05-12" pr1[1].qty = 8 pr1_bean = webnotes.bean(pr1) pr1_bean.insert() @@ -88,7 +89,7 @@ class TestPurchaseOrder(unittest.TestCase): self.assertEquals(pi[0]["doctype"], "Purchase Invoice") self.assertEquals(len(pi), len(test_records[0])) - + pi[0]["posting_date"] = "2013-05-12" pi[0].bill_no = "NA" webnotes.bean(pi).insert() diff --git a/manufacturing/doctype/production_order/test_production_order.py b/manufacturing/doctype/production_order/test_production_order.py index 52697292c8..ca28708cc1 100644 --- a/manufacturing/doctype/production_order/test_production_order.py +++ b/manufacturing/doctype/production_order/test_production_order.py @@ -34,6 +34,7 @@ class TestProductionOrder(unittest.TestCase): stock_entry = webnotes.bean(stock_entry) stock_entry.doc.fg_completed_qty = 4 + stock_entry.doc.posting_date = "2013-05-12" stock_entry.run_method("get_items") stock_entry.submit() @@ -50,7 +51,7 @@ class TestProductionOrder(unittest.TestCase): stock_entry = make_stock_entry(pro_order, "Manufacture/Repack") stock_entry = webnotes.bean(stock_entry) - + stock_entry.doc.posting_date = "2013-05-12" stock_entry.doc.fg_completed_qty = 15 stock_entry.run_method("get_items") stock_entry.insert() diff --git a/selling/doctype/quotation/test_quotation.py b/selling/doctype/quotation/test_quotation.py index 8f0e644cb9..327d72f2e0 100644 --- a/selling/doctype/quotation/test_quotation.py +++ b/selling/doctype/quotation/test_quotation.py @@ -28,6 +28,7 @@ class TestQuotation(unittest.TestCase): sales_order[0]["delivery_date"] = "2014-01-01" sales_order[0]["naming_series"] = "_T-Quotation-" + sales_order[0]["transaction_date"] = "2013-05-12" webnotes.bean(sales_order).insert() diff --git a/selling/doctype/sales_order/test_sales_order.py b/selling/doctype/sales_order/test_sales_order.py index 1549b24c89..a6fe8fb5bb 100644 --- a/selling/doctype/sales_order/test_sales_order.py +++ b/selling/doctype/sales_order/test_sales_order.py @@ -53,6 +53,7 @@ class TestSalesOrder(unittest.TestCase): self.assertEquals(len([d for d in si if d["doctype"]=="Sales Invoice Item"]), 1) si = webnotes.bean(si) + si.doc.posting_date = "2013-10-10" si.insert() si.submit() diff --git a/stock/doctype/material_request/test_material_request.py b/stock/doctype/material_request/test_material_request.py index c19bfd3928..81ae27d8c2 100644 --- a/stock/doctype/material_request/test_material_request.py +++ b/stock/doctype/material_request/test_material_request.py @@ -125,6 +125,7 @@ class TestMaterialRequest(unittest.TestCase): from stock.doctype.material_request.material_request import make_purchase_order po_doclist = make_purchase_order(mr.doc.name) po_doclist[0].supplier = "_Test Supplier" + po_doclist[0].transaction_date = "2013-07-07" po_doclist[1].qty = 27.0 po_doclist[2].qty = 1.5 po_doclist[1].schedule_date = "2013-07-09" From 5d5fe5d9d50a94403ecb52e1814f1c8afc56eb13 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 3 Jan 2014 18:28:53 +0530 Subject: [PATCH 13/65] Cost center field added in Purchase Receipt Item table --- .../purchase_receipt_item/purchase_receipt_item.txt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/stock/doctype/purchase_receipt_item/purchase_receipt_item.txt b/stock/doctype/purchase_receipt_item/purchase_receipt_item.txt index 9a641c2ba3..1d9397909d 100755 --- a/stock/doctype/purchase_receipt_item/purchase_receipt_item.txt +++ b/stock/doctype/purchase_receipt_item/purchase_receipt_item.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-24 19:29:10", "docstatus": 0, - "modified": "2013-12-18 10:38:39", + "modified": "2014-01-03 18:28:20", "modified_by": "Administrator", "owner": "Administrator" }, @@ -334,6 +334,16 @@ "report_hide": 0, "reqd": 0 }, + { + "default": ":Company", + "depends_on": "eval:sys_defaults.auto_accounting_for_stock", + "doctype": "DocField", + "fieldname": "cost_center", + "fieldtype": "Link", + "label": "Cost Center", + "options": "Cost Center", + "print_hide": 1 + }, { "doctype": "DocField", "fieldname": "project_name", From a83337a2dd0102f26fd17e2d2d7da51cf059b843 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Fri, 3 Jan 2014 19:10:11 +0600 Subject: [PATCH 14/65] bumped to version 3.4.6 --- config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json b/config.json index 89c1332005..536e5af1ba 100644 --- a/config.json +++ b/config.json @@ -1,6 +1,6 @@ { "app_name": "ERPNext", - "app_version": "3.4.5", + "app_version": "3.4.6", "base_template": "app/portal/templates/base.html", "modules": { "Accounts": { From 42db5d76a9d709749f4a0ff161cbbeff4dac48f9 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 6 Jan 2014 11:20:37 +0530 Subject: [PATCH 15/65] Fixes in overbilling validation --- controllers/accounts_controller.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/controllers/accounts_controller.py b/controllers/accounts_controller.py index 1a399219e4..778348d3cc 100644 --- a/controllers/accounts_controller.py +++ b/controllers/accounts_controller.py @@ -388,8 +388,9 @@ class AccountsController(TransactionBase): for item in self.doclist.get({"parentfield": "entries"}): if item.fields.get(item_ref_dn): already_billed = webnotes.conn.sql("""select sum(%s) from `tab%s` - where %s=%s and docstatus=1""" % (based_on, self.tname, item_ref_dn, '%s'), - item.fields[item_ref_dn])[0][0] + where %s=%s and docstatus=1 and parent != %s""" % + (based_on, self.tname, item_ref_dn, '%s', '%s'), + (item.fields[item_ref_dn], self.doc.name), debug=1)[0][0] total_billed_amt = flt(flt(already_billed) + flt(item.fields[based_on]), self.precision(based_on, item)) From b882fa14f4de7b7cc1ac8d5e946093b3ce78aa5d Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Mon, 6 Jan 2014 12:48:58 +0600 Subject: [PATCH 16/65] bumped to version 3.4.7 --- config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json b/config.json index 536e5af1ba..26fc50dbb8 100644 --- a/config.json +++ b/config.json @@ -1,6 +1,6 @@ { "app_name": "ERPNext", - "app_version": "3.4.6", + "app_version": "3.4.7", "base_template": "app/portal/templates/base.html", "modules": { "Accounts": { From 7e79f300a144a704a8f21f418aef641dbd7fcd68 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Mon, 6 Jan 2014 12:23:29 +0530 Subject: [PATCH 17/65] accounts payable fixed --- .../accounts_payable/accounts_payable.py | 61 ++++++++++++------- 1 file changed, 39 insertions(+), 22 deletions(-) diff --git a/accounts/report/accounts_payable/accounts_payable.py b/accounts/report/accounts_payable/accounts_payable.py index f9266dc9ea..1bd8a9f323 100644 --- a/accounts/report/accounts_payable/accounts_payable.py +++ b/accounts/report/accounts_payable/accounts_payable.py @@ -9,18 +9,20 @@ from accounts.report.accounts_receivable.accounts_receivable import get_ageing_d def execute(filters=None): if not filters: filters = {} - columns = get_columns() + supplier_naming_by = webnotes.conn.get_value("Buying Settings", None, "supp_master_name") + columns = get_columns(supplier_naming_by) entries = get_gl_entries(filters) - account_supplier = dict(webnotes.conn.sql("""select account.name, supplier.supplier_name - from `tabAccount` account, `tabSupplier` supplier - where account.master_type="Supplier" and supplier.name=account.master_name""")) - + account_map = dict(((r.name, r) for r in webnotes.conn.sql("""select acc.name, + supp.supplier_name, supp.name as supplier + from `tabAccount` acc, `tabSupplier` supp + where acc.master_type="Supplier" and supp.name=acc.master_name""", as_dict=1))) + entries_after_report_date = [[gle.voucher_type, gle.voucher_no] for gle in get_gl_entries(filters, before_report_date=False)] - + account_supplier_type_map = get_account_supplier_type_map() voucher_detail_map = get_voucher_details() - + # Age of the invoice on this date age_on = getdate(filters.get("report_date")) > getdate(nowdate()) \ and nowdate() or filters.get("report_date") @@ -37,9 +39,7 @@ def execute(filters=None): if abs(flt(outstanding_amount)) > 0.01: paid_amount = invoiced_amount - outstanding_amount - row = [gle.posting_date, gle.account, account_supplier.get(gle.account, ""), - gle.voucher_type, gle.voucher_no, gle.remarks, - account_supplier_type_map.get(gle.account), + row = [gle.posting_date, gle.account, gle.voucher_type, gle.voucher_no, voucher_details.get("due_date", ""), voucher_details.get("bill_no", ""), voucher_details.get("bill_date", ""), invoiced_amount, paid_amount, outstanding_amount] @@ -50,21 +50,38 @@ def execute(filters=None): else: ageing_based_on_date = gle.posting_date - row += get_ageing_data(age_on, ageing_based_on_date, outstanding_amount) + row += get_ageing_data(age_on, ageing_based_on_date, outstanding_amount) + \ + [account_map.get(gle.account).get("supplier") or ""] + + if supplier_naming_by == "Naming Series": + row += [account_map.get(gle.account).get("supplier_name") or ""] + + row += [account_supplier_type_map.get(gle.account), gle.remarks] data.append(row) - + + for i in range(0, len(data)): + data[i].insert(4, """""" \ + % ("/".join(["#Form", data[i][2], data[i][3]]),)) + return columns, data -def get_columns(): - return [ - "Posting Date:Date:80", "Account:Link/Account:150", "Supplier::150", "Voucher Type::110", - "Voucher No::120", "Remarks::150", "Supplier Type:Link/Supplier Type:120", - "Due Date:Date:80", "Bill No::80", "Bill Date:Date:80", +def get_columns(supplier_naming_by): + columns = [ + "Posting Date:Date:80", "Account:Link/Account:150", "Voucher Type::110", + "Voucher No::120", "::30", "Due Date:Date:80", "Bill No::80", "Bill Date:Date:80", "Invoiced Amount:Currency:100", "Paid Amount:Currency:100", "Outstanding Amount:Currency:100", "Age:Int:50", "0-30:Currency:100", - "30-60:Currency:100", "60-90:Currency:100", "90-Above:Currency:100" + "30-60:Currency:100", "60-90:Currency:100", "90-Above:Currency:100", + "Supplier:Link/Supplier:150" ] - + + if supplier_naming_by == "Naming Series": + columns += ["Supplier Name::110"] + + columns += ["Supplier Type:Link/Supplier Type:120", "Remarks::150"] + + return columns + def get_gl_entries(filters, before_report_date=True): conditions, supplier_accounts = get_conditions(filters, before_report_date) gl_entries = [] @@ -102,10 +119,10 @@ def get_conditions(filters, before_report_date=True): def get_account_supplier_type_map(): account_supplier_type_map = {} - for each in webnotes.conn.sql("""select t2.name, t1.supplier_type from `tabSupplier` t1, - `tabAccount` t2 where t1.name = t2.master_name group by t2.name"""): + for each in webnotes.conn.sql("""select acc.name, supp.supplier_type from `tabSupplier` supp, + `tabAccount` acc where supp.name = acc.master_name group by acc.name"""): account_supplier_type_map[each[0]] = each[1] - + return account_supplier_type_map def get_voucher_details(): From 6b66c387ad3b5d5d83144c0dd41cc951f12f5fb9 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 6 Jan 2014 16:28:17 +0530 Subject: [PATCH 18/65] Fixes in item-wise sales/purchase register --- .../item_wise_purchase_register.py | 3 ++- .../item_wise_sales_register/item_wise_sales_register.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py index 7d81308a80..7d8a358aa1 100644 --- a/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py +++ b/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py @@ -12,7 +12,8 @@ def execute(filters=None): item_list = get_items(filters) aii_account_map = get_aii_accounts() - item_tax, tax_accounts = get_tax_accounts(item_list, columns) + if item_list: + item_tax, tax_accounts = get_tax_accounts(item_list, columns) data = [] for d in item_list: diff --git a/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/accounts/report/item_wise_sales_register/item_wise_sales_register.py index dc5ecda3da..9f1fd87f70 100644 --- a/accounts/report/item_wise_sales_register/item_wise_sales_register.py +++ b/accounts/report/item_wise_sales_register/item_wise_sales_register.py @@ -11,7 +11,8 @@ def execute(filters=None): last_col = len(columns) item_list = get_items(filters) - item_tax, tax_accounts = get_tax_accounts(item_list, columns) + if item_list: + item_tax, tax_accounts = get_tax_accounts(item_list, columns) data = [] for d in item_list: @@ -39,7 +40,6 @@ def get_columns(): "Qty:Float:120", "Rate:Currency:120", "Amount:Currency:120" ] - def get_conditions(filters): conditions = "" From 01441ef37f7dbf6ca25f2197b6a08a1db5a26658 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 7 Jan 2014 11:59:36 +0530 Subject: [PATCH 19/65] Removed unwanted debug --- controllers/accounts_controller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/accounts_controller.py b/controllers/accounts_controller.py index 778348d3cc..be74fef02a 100644 --- a/controllers/accounts_controller.py +++ b/controllers/accounts_controller.py @@ -390,7 +390,7 @@ class AccountsController(TransactionBase): already_billed = webnotes.conn.sql("""select sum(%s) from `tab%s` where %s=%s and docstatus=1 and parent != %s""" % (based_on, self.tname, item_ref_dn, '%s', '%s'), - (item.fields[item_ref_dn], self.doc.name), debug=1)[0][0] + (item.fields[item_ref_dn], self.doc.name))[0][0] total_billed_amt = flt(flt(already_billed) + flt(item.fields[based_on]), self.precision(based_on, item)) From a11e14424c7e608b15c078be3547785c938b8202 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Tue, 7 Jan 2014 12:02:45 +0530 Subject: [PATCH 20/65] fix branching, pip version and mysql-python version pinning in install_erpnext --- install_erpnext.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/install_erpnext.py b/install_erpnext.py index c95a03d3e5..01de4575b9 100644 --- a/install_erpnext.py +++ b/install_erpnext.py @@ -19,7 +19,7 @@ requirements = [ "jinja2", "markdown2", "markupsafe", - "mysql-python", + "mysql-python==1.2.4", "pygeoip", "python-dateutil", "python-memcached", @@ -148,13 +148,13 @@ def install_python_modules(): print "Installing Python Modules: (This may take some time)" print "-"*80 - if not exec_in_shell("which pip"): - exec_in_shell("easy_install pip") + if not exec_in_shell("which pip-2.7"): + exec_in_shell("easy_install-2.7 pip") - exec_in_shell("pip install --upgrade pip") - exec_in_shell("pip install --upgrade setuptools") - exec_in_shell("pip install --upgrade virtualenv") - exec_in_shell("pip install {}".format(' '.join(requirements))) + exec_in_shell("pip-2.7 install --upgrade pip") + exec_in_shell("pip-2.7 install --upgrade setuptools") + exec_in_shell("pip-2.7 install --upgrade virtualenv") + exec_in_shell("pip-2.7 install {}".format(' '.join(requirements))) def install_erpnext(install_path): print @@ -200,7 +200,7 @@ def setup_folders(install_path): app = os.path.join(install_path, "app") if not os.path.exists(app): print "Cloning erpnext" - exec_in_shell("cd %s && git clone https://github.com/webnotes/erpnext.git app" % install_path) + exec_in_shell("cd %s && git clone --branch master https://github.com/webnotes/erpnext.git app" % install_path) exec_in_shell("cd app && git config core.filemode false") if not os.path.exists(app): raise Exception, "Couldn't clone erpnext repository" @@ -208,7 +208,7 @@ def setup_folders(install_path): lib = os.path.join(install_path, "lib") if not os.path.exists(lib): print "Cloning wnframework" - exec_in_shell("cd %s && git clone https://github.com/webnotes/wnframework.git lib" % install_path) + exec_in_shell("cd %s && git clone --branch master https://github.com/webnotes/wnframework.git lib" % install_path) exec_in_shell("cd lib && git config core.filemode false") if not os.path.exists(lib): raise Exception, "Couldn't clone wnframework repository" From da282d405f857ddad3dc29993a7627b665906626 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 7 Jan 2014 12:41:09 +0530 Subject: [PATCH 21/65] Fixes in overbilling validation against DN/PR --- controllers/accounts_controller.py | 51 ++++++++++++++++-------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/controllers/accounts_controller.py b/controllers/accounts_controller.py index be74fef02a..839dce0b4b 100644 --- a/controllers/accounts_controller.py +++ b/controllers/accounts_controller.py @@ -387,35 +387,38 @@ class AccountsController(TransactionBase): for item in self.doclist.get({"parentfield": "entries"}): if item.fields.get(item_ref_dn): - already_billed = webnotes.conn.sql("""select sum(%s) from `tab%s` - where %s=%s and docstatus=1 and parent != %s""" % - (based_on, self.tname, item_ref_dn, '%s', '%s'), - (item.fields[item_ref_dn], self.doc.name))[0][0] - - total_billed_amt = flt(flt(already_billed) + flt(item.fields[based_on]), - self.precision(based_on, item)) - ref_amt = flt(webnotes.conn.get_value(ref_dt + " Item", item.fields[item_ref_dn], based_on), self.precision(based_on, item)) + if not ref_amt: + webnotes.msgprint(_("As amount for item") + ": " + item.item_code + _(" in ") + + ref_dt + _(" is zero, system will not check for over-billed")) + else: + already_billed = webnotes.conn.sql("""select sum(%s) from `tab%s` + where %s=%s and docstatus=1 and parent != %s""" % + (based_on, self.tname, item_ref_dn, '%s', '%s'), + (item.fields[item_ref_dn], self.doc.name))[0][0] - tolerance, item_tolerance, global_tolerance = get_tolerance_for(item.item_code, - item_tolerance, global_tolerance) - - max_allowed_amt = flt(ref_amt * (100 + tolerance) / 100) + total_billed_amt = flt(flt(already_billed) + flt(item.fields[based_on]), + self.precision(based_on, item)) - if total_billed_amt - max_allowed_amt > 0.01: - reduce_by = total_billed_amt - max_allowed_amt + tolerance, item_tolerance, global_tolerance = get_tolerance_for(item.item_code, + item_tolerance, global_tolerance) - webnotes.throw(_("Row #") + cstr(item.idx) + ": " + - _(" Max amount allowed for Item ") + cstr(item.item_code) + - _(" against ") + ref_dt + " " + - cstr(item.fields[ref_dt.lower().replace(" ", "_")]) + _(" is ") + - cstr(max_allowed_amt) + ". \n" + - _("""If you want to increase your overflow tolerance, please increase \ - tolerance % in Global Defaults or Item master. - Or, you must reduce the amount by """) + cstr(reduce_by) + "\n" + - _("""Also, please check if the order item has already been billed \ - in the Sales Order""")) + max_allowed_amt = flt(ref_amt * (100 + tolerance) / 100) + + if total_billed_amt - max_allowed_amt > 0.01: + reduce_by = total_billed_amt - max_allowed_amt + + webnotes.throw(_("Row #") + cstr(item.idx) + ": " + + _(" Max amount allowed for Item ") + cstr(item.item_code) + + _(" against ") + ref_dt + " " + + cstr(item.fields[ref_dt.lower().replace(" ", "_")]) + _(" is ") + + cstr(max_allowed_amt) + ". \n" + + _("""If you want to increase your overflow tolerance, please increase \ + tolerance % in Global Defaults or Item master. + Or, you must reduce the amount by """) + cstr(reduce_by) + "\n" + + _("""Also, please check if the order item has already been billed \ + in the Sales Order""")) def get_company_default(self, fieldname): from accounts.utils import get_company_default From 777bff6e8df41ff6575141c54fc6d96ec5469a0e Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Tue, 7 Jan 2014 14:17:44 +0600 Subject: [PATCH 22/65] bumped to version 3.4.8 --- config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.json b/config.json index 26fc50dbb8..078ca16188 100644 --- a/config.json +++ b/config.json @@ -1,6 +1,6 @@ { "app_name": "ERPNext", - "app_version": "3.4.7", + "app_version": "3.4.8", "base_template": "app/portal/templates/base.html", "modules": { "Accounts": { @@ -74,5 +74,5 @@ "type": "module" } }, - "requires_framework_version": "==3.4.3" + "requires_framework_version": "==3.4.4" } \ No newline at end of file From 10fd91c78e0c27941164306d43fbc5d87470fa1c Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 7 Jan 2014 16:18:41 +0530 Subject: [PATCH 23/65] Close tickets automatically through scheduler --- startup/schedule_handlers.py | 4 ++++ support/doctype/support_ticket/get_support_mails.py | 5 ----- support/doctype/support_ticket/support_ticket.py | 7 ++++++- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/startup/schedule_handlers.py b/startup/schedule_handlers.py index 252a091547..0cf06026d6 100644 --- a/startup/schedule_handlers.py +++ b/startup/schedule_handlers.py @@ -53,6 +53,10 @@ def execute_daily(): # email digest from setup.doctype.email_digest.email_digest import send run_fn(send) + + # auto close support tickets + from support.doctype.support_ticket.support_ticket import auto_close_tickets + run_fn(auto_close_tickets) def execute_weekly(): from setup.doctype.backup_manager.backup_manager import take_backups_weekly diff --git a/support/doctype/support_ticket/get_support_mails.py b/support/doctype/support_ticket/get_support_mails.py index 33cb023747..67ed9f6ae8 100644 --- a/support/doctype/support_ticket/get_support_mails.py +++ b/support/doctype/support_ticket/get_support_mails.py @@ -52,11 +52,6 @@ Original Query: subject = '['+cstr(d.name)+'] ' + cstr(d.subject), \ msg = cstr(response)) - def auto_close_tickets(self): - webnotes.conn.sql("""update `tabSupport Ticket` set status = 'Closed' - where status = 'Replied' - and date_sub(curdate(),interval 15 Day) > modified""") - def get_support_mails(): if cint(webnotes.conn.get_value('Email Settings', None, 'sync_support_mails')): SupportMailbox() diff --git a/support/doctype/support_ticket/support_ticket.py b/support/doctype/support_ticket/support_ticket.py index fd79583129..3030a146fe 100644 --- a/support/doctype/support_ticket/support_ticket.py +++ b/support/doctype/support_ticket/support_ticket.py @@ -66,4 +66,9 @@ class DocType(TransactionBase): def set_status(name, status): st = webnotes.bean("Support Ticket", name) st.doc.status = status - st.save() \ No newline at end of file + st.save() + +def auto_close_tickets(): + webnotes.conn.sql("""update `tabSupport Ticket` set status = 'Closed' + where status = 'Replied' + and date_sub(curdate(),interval 15 Day) > modified""") \ No newline at end of file From 69951e5d1ca6e42f3ec735c60f525add22680f43 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Tue, 7 Jan 2014 18:24:40 +0530 Subject: [PATCH 24/65] fix installer python packages issue --- install_erpnext.py | 60 ++++++++++++++++------------------------------ 1 file changed, 20 insertions(+), 40 deletions(-) diff --git a/install_erpnext.py b/install_erpnext.py index 01de4575b9..e285d4bbfe 100644 --- a/install_erpnext.py +++ b/install_erpnext.py @@ -5,6 +5,7 @@ from __future__ import unicode_literals import os, sys import argparse +import subprocess is_redhat = is_debian = None root_password = None @@ -80,7 +81,7 @@ def validate_install(): return is_redhat, is_debian def install_using_yum(): - packages = "python python-setuptools gcc python-devel MySQL-python git memcached ntp vim-enhanced screen" + packages = "gcc MySQL-python git memcached ntp vim-enhanced screen" print "-"*80 print "Installing Packages: (This may take some time)" @@ -88,7 +89,10 @@ def install_using_yum(): print "-"*80 exec_in_shell("yum install -y %s" % packages) - if not exec_in_shell("which mysql"): + + try: + exec_in_shell("which mysql") + except subprocess.CalledProcessError: packages = "mysql mysql-server mysql-devel" print "Installing Packages:", packages exec_in_shell("yum install -y %s" % packages) @@ -101,26 +105,19 @@ def install_using_yum(): exec_in_shell('mysqladmin -u root password "%s"' % (root_password,)) print "Root password set as", root_password - # install htop - if not exec_in_shell("which htop"): - try: - exec_in_shell("cd /tmp && rpm -i --force http://packages.sw.be/rpmforge-release/rpmforge-release-0.5.2-2.el6.rf.x86_64.rpm && yum install -y htop") - except: - pass - update_config_for_redhat() def update_config_for_redhat(): import re # set to autostart on startup - for service in ("mysqld", "memcached", "ntpd"): + for service in ("mysqld", "memcached"): exec_in_shell("chkconfig --level 2345 %s on" % service) exec_in_shell("service %s restart" % service) def install_using_apt(): exec_in_shell("apt-get update") - packages = "python python-setuptools python-dev build-essential python-pip python-mysqldb git memcached ntp vim screen htop" + packages = "python python-setuptools python-dev build-essential python-mysqldb git memcached ntp vim screen htop" print "-"*80 print "Installing Packages: (This may take some time)" print packages @@ -132,7 +129,9 @@ def install_using_apt(): exec_in_shell("echo mysql-server mysql-server/root_password password %s | sudo debconf-set-selections" % root_password) exec_in_shell("echo mysql-server mysql-server/root_password_again password %s | sudo debconf-set-selections" % root_password) - if not exec_in_shell("which mysql"): + try: + exec_in_shell("which mysql") + except subprocess.CalledProcessError: packages = "mysql-server libmysqlclient-dev" print "Installing Packages:", packages exec_in_shell("apt-get install -y %s" % packages) @@ -140,7 +139,7 @@ def install_using_apt(): update_config_for_debian() def update_config_for_debian(): - for service in ("mysql", "ntpd"): + for service in ("mysql",): exec_in_shell("service %s restart" % service) def install_python_modules(): @@ -148,13 +147,14 @@ def install_python_modules(): print "Installing Python Modules: (This may take some time)" print "-"*80 - if not exec_in_shell("which pip-2.7"): + try: + exec_in_shell("which pip2.7") + except subprocess.CalledProcessError: exec_in_shell("easy_install-2.7 pip") - exec_in_shell("pip-2.7 install --upgrade pip") - exec_in_shell("pip-2.7 install --upgrade setuptools") - exec_in_shell("pip-2.7 install --upgrade virtualenv") - exec_in_shell("pip-2.7 install {}".format(' '.join(requirements))) + exec_in_shell("pip2.7 install --upgrade setuptools --no-use-wheel") + exec_in_shell("pip2.7 install --upgrade setuptools") + exec_in_shell("pip2.7 install {}".format(' '.join(requirements))) def install_erpnext(install_path): print @@ -243,28 +243,8 @@ def post_install(install_path): def exec_in_shell(cmd): # using Popen instead of os.system - as recommended by python docs - from subprocess import Popen - import tempfile - - with tempfile.TemporaryFile() as stdout: - with tempfile.TemporaryFile() as stderr: - p = Popen(cmd, shell=True, stdout=stdout, stderr=stderr) - p.wait() - - stdout.seek(0) - out = stdout.read() - if out: out = out.decode('utf-8') - - stderr.seek(0) - err = stderr.read() - if err: err = err.decode('utf-8') - - if err and any((kw in err.lower() for kw in ["traceback", "error", "exception"])): - print out - raise Exception, err - else: - print "." - + import subprocess + out = subprocess.check_output(cmd, shell=True) return out def parse_args(): From 806017c92ab7b0bc2d0f5671dc55d16c88f0766d Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Tue, 7 Jan 2014 18:37:38 +0530 Subject: [PATCH 25/65] Price List and Item Price : Validfor Buying and Selling as separate check box --- accounts/doctype/pos_setting/pos_setting.js | 2 +- .../purchase_common/purchase_common.js | 2 +- buying/doctype/supplier/supplier.js | 2 +- buying/utils.py | 12 +-- controllers/accounts_controller.py | 18 ++-- .../p03_buying_selling_for_price_list.py | 21 +--- ...ice_list_and_item_details_in_item_price.py | 4 +- patches/patch_list.py | 1 + public/js/transaction.js | 9 +- selling/doctype/customer/customer.js | 2 +- selling/sales_common.js | 2 +- selling/utils/__init__.py | 14 ++- setup/page/setup_wizard/setup_wizard.py | 3 +- stock/doctype/item_price/item_price.js | 5 +- stock/doctype/item_price/item_price.py | 11 ++- stock/doctype/item_price/item_price.txt | 40 +++++--- stock/doctype/price_list/price_list.css | 7 -- stock/doctype/price_list/price_list.py | 15 ++- stock/doctype/price_list/price_list.txt | 19 ++-- stock/doctype/price_list/test_price_list.py | 8 +- stock/report/item_prices/item_prices.py | 4 +- utilities/demo/demo_docs/Item_Price.csv | 98 +++++++++---------- 22 files changed, 147 insertions(+), 152 deletions(-) delete mode 100644 stock/doctype/price_list/price_list.css diff --git a/accounts/doctype/pos_setting/pos_setting.js b/accounts/doctype/pos_setting/pos_setting.js index 8c5f254a52..dc13bb50ca 100755 --- a/accounts/doctype/pos_setting/pos_setting.js +++ b/accounts/doctype/pos_setting/pos_setting.js @@ -7,7 +7,7 @@ cur_frm.cscript.onload = function(doc,cdt,cdn){ }); cur_frm.set_query("selling_price_list", function() { - return { filters: { buying_or_selling: "Selling" } }; + return { filters: { selling: 1 } }; }); } diff --git a/buying/doctype/purchase_common/purchase_common.js b/buying/doctype/purchase_common/purchase_common.js index 9661f6edaf..14b8279245 100644 --- a/buying/doctype/purchase_common/purchase_common.js +++ b/buying/doctype/purchase_common/purchase_common.js @@ -22,7 +22,7 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({ if(this.frm.fields_dict.buying_price_list) { this.frm.set_query("buying_price_list", function() { return{ - filters: { 'buying_or_selling': "Buying" } + filters: { 'buying': 1 } } }); } diff --git a/buying/doctype/supplier/supplier.js b/buying/doctype/supplier/supplier.js index 061861643d..ec4d3e606f 100644 --- a/buying/doctype/supplier/supplier.js +++ b/buying/doctype/supplier/supplier.js @@ -95,6 +95,6 @@ cur_frm.cscript.make_contact = function() { cur_frm.fields_dict['default_price_list'].get_query = function(doc,cdt,cdn) { return{ - filters:{'buying_or_selling': "Buying"} + filters:{'buying': 1} } } \ No newline at end of file diff --git a/buying/utils.py b/buying/utils.py index 0d9c8fa838..35d89c559d 100644 --- a/buying/utils.py +++ b/buying/utils.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals import webnotes -from webnotes import msgprint, _ +from webnotes import msgprint, _, throw from webnotes.utils import getdate, flt, add_days, cstr import json @@ -90,7 +90,7 @@ def _get_price_list_rate(args, item_bean, meta): # try fetching from price list if args.buying_price_list and args.price_list_currency: price_list_rate = webnotes.conn.sql("""select ref_rate from `tabItem Price` - where price_list=%s and item_code=%s and buying_or_selling='Buying'""", + where price_list=%s and item_code=%s and buying=1""", (args.buying_price_list, args.item_code), as_dict=1) if price_list_rate: @@ -122,14 +122,12 @@ def _validate_item_details(args, item): # validate if purchase item or subcontracted item if item.is_purchase_item != "Yes": - msgprint(_("Item") + (" %s: " % item.name) + _("not a purchase item"), - raise_exception=True) + throw(_("Item") + (" %s: " % item.name) + _("not a purchase item")) if args.is_subcontracted == "Yes" and item.is_sub_contracted_item != "Yes": - msgprint(_("Item") + (" %s: " % item.name) + + throw(_("Item") + (" %s: " % item.name) + _("not a sub-contracted item.") + - _("Please select a sub-contracted item or do not sub-contract the transaction."), - raise_exception=True) + _("Please select a sub-contracted item or do not sub-contract the transaction.")) def get_last_purchase_details(item_code, doc_name=None, conversion_rate=1.0): """returns last purchase details in stock uom""" diff --git a/controllers/accounts_controller.py b/controllers/accounts_controller.py index 1a399219e4..6660a93e4e 100644 --- a/controllers/accounts_controller.py +++ b/controllers/accounts_controller.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals import webnotes -from webnotes import _, msgprint +from webnotes import _, msgprint, throw from webnotes.utils import flt, cint, today, cstr from webnotes.model.code import get_obj from setup.utils import get_company_currency @@ -50,8 +50,8 @@ class AccountsController(TransactionBase): if accounts: if not filter(lambda x: cstr(x.freeze_account) in ["", "No"], accounts): - msgprint(_("Account for this ") + fieldname + _(" has been freezed. ") + - self.doc.doctype + _(" can not be made."), raise_exception=1) + throw(_("Account for this ") + fieldname + _(" has been freezed. ") + + self.doc.doctype + _(" can not be made.")) def set_price_list_currency(self, buying_or_selling): if self.meta.get_field("currency"): @@ -179,17 +179,17 @@ class AccountsController(TransactionBase): """ if tax.charge_type in ["On Previous Row Amount", "On Previous Row Total"] and \ (not tax.row_id or cint(tax.row_id) >= tax.idx): - msgprint((_("Row") + " # %(idx)s [%(taxes_doctype)s]: " + \ + throw((_("Row") + " # %(idx)s [%(taxes_doctype)s]: " + \ _("Please specify a valid") + " %(row_id_label)s") % { "idx": tax.idx, "taxes_doctype": tax.doctype, "row_id_label": self.meta.get_label("row_id", parentfield=self.other_fname) - }, raise_exception=True) + }) def validate_inclusive_tax(self, tax): def _on_previous_row_error(row_range): - msgprint((_("Row") + " # %(idx)s [%(doctype)s]: " + + throw((_("Row") + " # %(idx)s [%(doctype)s]: " + _("to be included in Item's rate, it is required that: ") + " [" + _("Row") + " # %(row_range)s] " + _("also be included in Item's rate")) % { "idx": tax.idx, @@ -200,12 +200,12 @@ class AccountsController(TransactionBase): parentfield=self.other_fname), "charge_type": tax.charge_type, "row_range": row_range - }, raise_exception=True) + }) if cint(tax.included_in_print_rate): if tax.charge_type == "Actual": # inclusive tax cannot be of type Actual - msgprint((_("Row") + throw((_("Row") + " # %(idx)s [%(doctype)s]: %(charge_type_label)s = \"%(charge_type)s\" " + "cannot be included in Item's rate") % { "idx": tax.idx, @@ -213,7 +213,7 @@ class AccountsController(TransactionBase): "charge_type_label": self.meta.get_label("charge_type", parentfield=self.other_fname), "charge_type": tax.charge_type, - }, raise_exception=True) + }) elif tax.charge_type == "On Previous Row Amount" and \ not cint(self.tax_doclist[tax.row_id - 1].included_in_print_rate): # referred row should also be inclusive diff --git a/patches/june_2013/p03_buying_selling_for_price_list.py b/patches/june_2013/p03_buying_selling_for_price_list.py index 2f92fe6a9e..15da085e53 100644 --- a/patches/june_2013/p03_buying_selling_for_price_list.py +++ b/patches/june_2013/p03_buying_selling_for_price_list.py @@ -8,20 +8,7 @@ from webnotes.utils import cint def execute(): webnotes.reload_doc("stock", "doctype", "price_list") webnotes.reload_doc("stock", "doctype", "item_price") - - try: - for price_list in webnotes.conn.sql_list("""select name from `tabPrice List`"""): - buying, selling = False, False - for b, s in webnotes.conn.sql("""select distinct buying, selling - from `tabItem Price` where price_list_name=%s""", price_list): - buying = buying or cint(b) - selling = selling or cint(s) - - buying_or_selling = "Selling" if selling else "Buying" - webnotes.conn.set_value("Price List", price_list, "buying_or_selling", buying_or_selling) - except webnotes.SQLError, e: - if e.args[0] == 1054: - webnotes.conn.sql("""update `tabPrice List` set buying_or_selling='Selling' - where ifnull(buying_or_selling, '')='' """) - else: - raise \ No newline at end of file + + webnotes.conn.sql("""update `tabPrice List` pl, `tabItem Price` ip + set pl.selling=ip.selling, pl.buying=ip.buying + where pl.name=ip.price_list_name""") \ No newline at end of file diff --git a/patches/october_2013/p02_update_price_list_and_item_details_in_item_price.py b/patches/october_2013/p02_update_price_list_and_item_details_in_item_price.py index 3b4ca833f1..b92f7d052a 100644 --- a/patches/october_2013/p02_update_price_list_and_item_details_in_item_price.py +++ b/patches/october_2013/p02_update_price_list_and_item_details_in_item_price.py @@ -12,9 +12,7 @@ def execute(): where ip.item_code=i.name""") webnotes.conn.sql("""update `tabItem Price` ip, `tabPrice List` pl - set ip.price_list=pl.name, ip.currency=pl.currency, - ip.buying_or_selling=pl.buying_or_selling - where ip.parent=pl.name""") + set ip.price_list=pl.name, ip.currency=pl.currency where ip.parent=pl.name""") webnotes.conn.sql("""update `tabItem Price` set parent=null, parenttype=null, parentfield=null, idx=null""") \ No newline at end of file diff --git a/patches/patch_list.py b/patches/patch_list.py index 608ba77168..d291d762c5 100644 --- a/patches/patch_list.py +++ b/patches/patch_list.py @@ -263,4 +263,5 @@ patch_list = [ "patches.1311.p08_email_digest_recipients", "execute:webnotes.delete_doc('DocType', 'Warehouse Type')", "patches.1312.p02_update_item_details_in_item_price", + "patches.1401.p01_make_buying_selling_as_check_box_in_price_list", ] \ No newline at end of file diff --git a/public/js/transaction.js b/public/js/transaction.js index 4c4a810ed2..0fe0535c6b 100644 --- a/public/js/transaction.js +++ b/public/js/transaction.js @@ -330,8 +330,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ doctype: tax.doctype, row_id_label: wn.meta.get_label(tax.doctype, "row_id", tax.name) }); - msgprint(msg); - throw msg; + wn.throw(msg); } }, @@ -347,8 +346,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ charge_type_label: wn.meta.get_label(tax.doctype, "charge_type", tax.name), charge_type: tax.charge_type }); - msgprint(msg); - throw msg; + wn.throw(msg); }; var on_previous_row_error = function(row_range) { @@ -363,8 +361,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ row_range: row_range, }); - msgprint(msg); - throw msg; + wn.throw(msg); }; if(cint(tax.included_in_print_rate)) { diff --git a/selling/doctype/customer/customer.js b/selling/doctype/customer/customer.js index 5e0ccc98f2..5d046904d3 100644 --- a/selling/doctype/customer/customer.js +++ b/selling/doctype/customer/customer.js @@ -122,6 +122,6 @@ cur_frm.fields_dict.lead_name.get_query = function(doc,cdt,cdn) { cur_frm.fields_dict['default_price_list'].get_query = function(doc,cdt,cdn) { return{ - filters:{'buying_or_selling': "Selling"} + filters:{'selling': 1} } } diff --git a/selling/sales_common.js b/selling/sales_common.js index dddc2b568d..f4f643015e 100644 --- a/selling/sales_common.js +++ b/selling/sales_common.js @@ -48,7 +48,7 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ if(this.frm.fields_dict.selling_price_list) { this.frm.set_query("selling_price_list", function() { - return { filters: { buying_or_selling: "Selling" } }; + return { filters: { selling: 1 } }; }); } diff --git a/selling/utils/__init__.py b/selling/utils/__init__.py index 5974da7d8b..85c20e86d8 100644 --- a/selling/utils/__init__.py +++ b/selling/utils/__init__.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals import webnotes -from webnotes import msgprint, _ +from webnotes import msgprint, _, throw from webnotes.utils import flt, cint, comma_and import json @@ -100,7 +100,7 @@ def _get_item_code(barcode=None, serial_no=None): where name=%s""", serial_no) if not item_code: - msgprint(_("No Item found with ") + input_type + ": %s" % (barcode or serial_no), raise_exception=True) + throw(_("No Item found with ") + input_type + ": %s" % (barcode or serial_no)) return item_code[0] @@ -111,14 +111,12 @@ def _validate_item_details(args, item): # validate if sales item or service item if args.order_type == "Maintenance": if item.is_service_item != "Yes": - msgprint(_("Item") + (" %s: " % item.name) + + throw(_("Item") + (" %s: " % item.name) + _("not a service item.") + - _("Please select a service item or change the order type to Sales."), - raise_exception=True) + _("Please select a service item or change the order type to Sales.")) elif item.is_sales_item != "Yes": - msgprint(_("Item") + (" %s: " % item.name) + _("not a sales item"), - raise_exception=True) + throw(_("Item") + (" %s: " % item.name) + _("not a sales item")) def _get_basic_details(args, item_bean, warehouse_fieldname): item = item_bean.doc @@ -147,7 +145,7 @@ def _get_basic_details(args, item_bean, warehouse_fieldname): def _get_price_list_rate(args, item_bean, meta): ref_rate = webnotes.conn.sql("""select ref_rate from `tabItem Price` - where price_list=%s and item_code=%s and buying_or_selling='Selling'""", + where price_list=%s and item_code=%s and selling=1""", (args.selling_price_list, args.item_code), as_dict=1) if not ref_rate: diff --git a/setup/page/setup_wizard/setup_wizard.py b/setup/page/setup_wizard/setup_wizard.py index c1d3571ea5..ededd472a8 100644 --- a/setup/page/setup_wizard/setup_wizard.py +++ b/setup/page/setup_wizard/setup_wizard.py @@ -98,7 +98,8 @@ def create_price_lists(args): { "doctype": "Price List", "price_list_name": "Standard " + pl_type, - "buying_or_selling": pl_type, + "buying": 1 if pl_type == "Buying" else 0, + "selling": 1 if pl_type == "Selling" else 0, "currency": args["currency"] }, { diff --git a/stock/doctype/item_price/item_price.js b/stock/doctype/item_price/item_price.js index bece26c6b5..9f38fdb18e 100644 --- a/stock/doctype/item_price/item_price.js +++ b/stock/doctype/item_price/item_price.js @@ -2,11 +2,10 @@ // License: GNU General Public License v3. See license.txt $.extend(cur_frm.cscript, { - onload: function () { - // Fetch price list details - cur_frm.add_fetch("price_list", "buying_or_selling", "buying_or_selling"); + cur_frm.add_fetch("price_list", "buying", "buying"); + cur_frm.add_fetch("price_list", "selling", "selling"); cur_frm.add_fetch("price_list", "currency", "currency"); // Fetch item details diff --git a/stock/doctype/item_price/item_price.py b/stock/doctype/item_price/item_price.py index 072d70096e..9a8e3d35fb 100644 --- a/stock/doctype/item_price/item_price.py +++ b/stock/doctype/item_price/item_price.py @@ -1,7 +1,5 @@ # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# MIT License. See license.txt - -# For license information, please see license.txt +# License: GNU General Public License v3. See license.txt from __future__ import unicode_literals import webnotes @@ -19,8 +17,11 @@ class DocType: self.update_item_details() def update_price_list_details(self): - self.doc.buying_or_selling, self.doc.currency = webnotes.conn.get_value("Price List", - self.doc.price_list, ["buying_or_selling", "currency"]) + if not self.doc.selling and not self.doc.buying: + self.doc.buying, self.doc.selling = webnotes.conn.get_value("Price List", + self.doc.price_list, ["buying", "selling"]) + + self.doc.currency = webnotes.conn.get_value("Price List", self.doc.price_list, "currency") def update_item_details(self): self.doc.item_name, self.doc.item_description = webnotes.conn.get_value("Item", diff --git a/stock/doctype/item_price/item_price.txt b/stock/doctype/item_price/item_price.txt index fc411eb1d6..b25fd30812 100644 --- a/stock/doctype/item_price/item_price.txt +++ b/stock/doctype/item_price/item_price.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-02 16:29:48", "docstatus": 0, - "modified": "2013-10-31 12:59:02", + "modified": "2014-01-07 18:11:10", "modified_by": "Administrator", "owner": "Administrator" }, @@ -43,6 +43,13 @@ "doctype": "DocType", "name": "Item Price" }, + { + "doctype": "DocField", + "fieldname": "price_list_details", + "fieldtype": "Section Break", + "label": "Price List", + "options": "icon-tags" + }, { "doctype": "DocField", "fieldname": "price_list", @@ -52,6 +59,27 @@ "options": "Price List", "reqd": 1 }, + { + "doctype": "DocField", + "fieldname": "buying", + "fieldtype": "Check", + "in_list_view": 1, + "label": "Buying" + }, + { + "doctype": "DocField", + "fieldname": "selling", + "fieldtype": "Check", + "in_list_view": 1, + "label": "Selling" + }, + { + "doctype": "DocField", + "fieldname": "item_details", + "fieldtype": "Section Break", + "label": "Item", + "options": "icon-tag" + }, { "doctype": "DocField", "fieldname": "item_code", @@ -83,16 +111,6 @@ "fieldname": "col_br_1", "fieldtype": "Column Break" }, - { - "doctype": "DocField", - "fieldname": "buying_or_selling", - "fieldtype": "Select", - "in_filter": 1, - "in_list_view": 1, - "label": "Valid for Buying or Selling?", - "options": "Selling\nBuying", - "reqd": 0 - }, { "doctype": "DocField", "fieldname": "item_name", diff --git a/stock/doctype/price_list/price_list.css b/stock/doctype/price_list/price_list.css deleted file mode 100644 index 61b069442f..0000000000 --- a/stock/doctype/price_list/price_list.css +++ /dev/null @@ -1,7 +0,0 @@ -.table-grid tbody tr { - cursor: pointer; -} - -.table-grid thead tr { - height: 50px; -} \ No newline at end of file diff --git a/stock/doctype/price_list/price_list.py b/stock/doctype/price_list/price_list.py index d0e5d2b6d4..569e759159 100644 --- a/stock/doctype/price_list/price_list.py +++ b/stock/doctype/price_list/price_list.py @@ -3,16 +3,15 @@ from __future__ import unicode_literals import webnotes -from webnotes import msgprint, _ +from webnotes import msgprint, _, throw from webnotes.utils import comma_or, cint from webnotes.model.controller import DocListController import webnotes.defaults class DocType(DocListController): def validate(self): - if self.doc.buying_or_selling not in ["Buying", "Selling"]: - msgprint(_(self.meta.get_label("buying_or_selling")) + " " + _("must be one of") + " " + - comma_or(["Buying", "Selling"]), raise_exception=True) + if not self.doc.buying and not self.doc.selling: + throw(_("Price List must be one of Buying or Selling")) if not self.doclist.get({"parentfield": "valid_for_territories"}): # if no territory, set default territory @@ -34,15 +33,15 @@ class DocType(DocListController): cart_settings.validate_price_lists() def set_default_if_missing(self): - if self.doc.buying_or_selling=="Selling": + if self.doc.selling: if not webnotes.conn.get_value("Selling Settings", None, "selling_price_list"): webnotes.set_value("Selling Settings", "Selling Settings", "selling_price_list", self.doc.name) - elif self.doc.buying_or_selling=="Buying": + elif self.doc.buying: if not webnotes.conn.get_value("Buying Settings", None, "buying_price_list"): webnotes.set_value("Buying Settings", "Buying Settings", "buying_price_list", self.doc.name) def update_item_price(self): webnotes.conn.sql("""update `tabItem Price` set currency=%s, - buying_or_selling=%s, modified=NOW() where price_list=%s""", - (self.doc.currency, self.doc.buying_or_selling, self.doc.name)) \ No newline at end of file + buying=%s, selling=%s, modified=NOW() where price_list=%s""", + (self.doc.currency, self.doc.buying, self.doc.selling, self.doc.name)) \ No newline at end of file diff --git a/stock/doctype/price_list/price_list.txt b/stock/doctype/price_list/price_list.txt index d43076bcc8..69c3ecbc4c 100644 --- a/stock/doctype/price_list/price_list.txt +++ b/stock/doctype/price_list/price_list.txt @@ -2,7 +2,7 @@ { "creation": "2013-01-25 11:35:09", "docstatus": 0, - "modified": "2013-10-31 19:24:33", + "modified": "2014-01-06 18:28:23", "modified_by": "Administrator", "owner": "Administrator" }, @@ -61,14 +61,19 @@ "reqd": 1 }, { - "default": "Selling", "doctype": "DocField", - "fieldname": "buying_or_selling", - "fieldtype": "Select", + "fieldname": "buying", + "fieldtype": "Check", "in_list_view": 1, - "label": "Valid for Buying or Selling?", - "options": "Buying\nSelling", - "reqd": 1 + "label": "Buying" + }, + { + "doctype": "DocField", + "fieldname": "selling", + "fieldtype": "Check", + "in_list_view": 1, + "label": "Selling", + "reqd": 0 }, { "doctype": "DocField", diff --git a/stock/doctype/price_list/test_price_list.py b/stock/doctype/price_list/test_price_list.py index 86dcd1a594..bdcacc3452 100644 --- a/stock/doctype/price_list/test_price_list.py +++ b/stock/doctype/price_list/test_price_list.py @@ -12,7 +12,7 @@ test_records = [ "doctype": "Price List", "price_list_name": "_Test Price List", "currency": "INR", - "buying_or_selling": "Selling" + "selling": 1 }, { "doctype": "Applicable Territory", @@ -25,7 +25,7 @@ test_records = [ "doctype": "Price List", "price_list_name": "_Test Price List 2", "currency": "INR", - "buying_or_selling": "Selling" + "selling": 1 }, { "doctype": "Applicable Territory", @@ -38,7 +38,7 @@ test_records = [ "doctype": "Price List", "price_list_name": "_Test Price List India", "currency": "INR", - "buying_or_selling": "Selling" + "selling": 1 }, { "doctype": "Applicable Territory", @@ -51,7 +51,7 @@ test_records = [ "doctype": "Price List", "price_list_name": "_Test Price List Rest of the World", "currency": "USD", - "buying_or_selling": "Selling" + "selling": 1 }, { "doctype": "Applicable Territory", diff --git a/stock/report/item_prices/item_prices.py b/stock/report/item_prices/item_prices.py index da8b5007d5..e744cc73e4 100644 --- a/stock/report/item_prices/item_prices.py +++ b/stock/report/item_prices/item_prices.py @@ -65,13 +65,13 @@ def get_price_list(): rate = {} - price_list = webnotes.conn.sql("""select item_code, buying_or_selling, + price_list = webnotes.conn.sql("""select item_code, buying, selling, concat(price_list, " - ", currency, " ", ref_rate) as price from `tabItem Price`""", as_dict=1) for j in price_list: if j.price: - rate.setdefault(j.item_code, {}).setdefault(j.buying_or_selling, []).append(j.price) + rate.setdefault(j.item_code, {}).setdefault("Buying" if j.buying else "Selling", []).append(j.price) item_rate_map = {} for item in rate: diff --git a/utilities/demo/demo_docs/Item_Price.csv b/utilities/demo/demo_docs/Item_Price.csv index d70b7b3e67..cd7a13937f 100644 --- a/utilities/demo/demo_docs/Item_Price.csv +++ b/utilities/demo/demo_docs/Item_Price.csv @@ -1,49 +1,49 @@ -Data Import Template,,,,,,, -Table:,Item Price,,,,,, -,,,,,,, -,,,,,,, -Notes:,,,,,,, -Please do not change the template headings.,,,,,,, -First data column must be blank.,,,,,,, -"If you are uploading new records, leave the ""name"""" (ID) column blank.""",,,,,,, -"If you are uploading new records, ""Naming Series"""" becomes mandatory"," if present.""",,,,,, -Only mandatory fields are necessary for new records. You can delete non-mandatory columns if you wish.,,,,,,, -"For updating, you can update only selective columns.",,,,,,, -You can only upload upto 5000 records in one go. (may be less in some cases),,,,,,, -,,,,,,, -DocType:,Item Price,,,,,, -Column Labels:,ID,Price List,Item Code,Rate,Valid for Buying or Selling?,Item Name,Item Description -Column Name:,name,price_list,item_code,ref_rate,buying_or_selling,item_name,item_description -Mandatory:,Yes,Yes,Yes,Yes,No,No,No -Type:,Data (text),Link,Link,Currency,Select,Data,Text -Info:,,Valid Price List,Valid Item,,"One of: Selling, Buying",, -Start entering data below this line,,,,,,, -,,Standard Buying,Base Bearing Plate,15,Buying,, -,,Standard Buying,Base Plate,20,Buying,, -,,Standard Buying,Bearing Block,10,Buying,, -,,Standard Buying,Bearing Collar,20,Buying,, -,,Standard Buying,Bearing Pipe,15,Buying,, -,,Standard Buying,Blade Rib,10,Buying,, -,,Standard Buying,Disc Collars,74,Buying,, -,,Standard Buying,External Disc,45,Buying,, -,,Standard Buying,Internal Disc,33,Buying,, -,,Standard Buying,Shaft,30,Buying,, -,,Standard Buying,Stand,40,Buying,, -,,Standard Buying,Upper Bearing Plate,50,Buying,, -,,Standard Buying,Wing Sheet,22,Buying,, -,,Standard Selling,Wind Turbine,21,Selling,, -,,Standard Selling,Wind Mill A Series,28,Selling,, -,,Standard Selling,Wind MIll C Series,14,Selling,, -,,Standard Selling,Base Bearing Plate,28,Selling,, -,,Standard Selling,Base Plate,21,Selling,, -,,Standard Selling,Bearing Block,14,Selling,, -,,Standard Selling,Bearing Collar,103.6,Selling,, -,,Standard Selling,Bearing Pipe,63,Selling,, -,,Standard Selling,Blade Rib,46.2,Selling,, -,,Standard Selling,Disc Collars,42,Selling,, -,,Standard Selling,External Disc,56,Selling,, -,,Standard Selling,Internal Disc,70,Selling,, -,,Standard Selling,Shaft,340,Selling,, -,,Standard Selling,Stand,400,Selling,, -,,Standard Selling,Upper Bearing Plate,300,Selling,, -,,Standard Selling,Wing Sheet,30.8,Selling,, \ No newline at end of file +Data Import Template,,,,,,,, +Table:,Item Price,,,,,,, +,,,,,,,, +,,,,,,,, +Notes:,,,,,,,, +Please do not change the template headings.,,,,,,,, +First data column must be blank.,,,,,,,, +"If you are uploading new records, leave the ""name"" (ID) column blank.",,,,,,,, +"If you are uploading new records, ""Naming Series"" becomes mandatory, if present.",,,,,,,, +Only mandatory fields are necessary for new records. You can delete non-mandatory columns if you wish.,,,,,,,, +"For updating, you can update only selective columns.",,,,,,,, +You can only upload upto 5000 records in one go. (may be less in some cases),,,,,,,, +,,,,,,,, +DocType:,Item Price,,,,,,, +Column Labels:,ID,Price List,Item Code,Rate,Buying,Selling,Item Name,Item Description +Column Name:,name,price_list,item_code,ref_rate,buying,selling,item_name,item_description +Mandatory:,Yes,Yes,Yes,Yes,No,No,No,No +Type:,Data (text),Link,Link,Currency,Check,Check,Data,Text +Info:,,Valid Price List,Valid Item,,0 or 1,0 or 1,, +Start entering data below this line,,,,,,,, +,,Standard Buying,Base Bearing Plate,15,1,,, +,,Standard Buying,Base Plate,20,1,,, +,,Standard Buying,Bearing Block,10,1,,, +,,Standard Buying,Bearing Collar,20,1,,, +,,Standard Buying,Bearing Pipe,15,1,,, +,,Standard Buying,Blade Rib,10,1,,, +,,Standard Buying,Disc Collars,74,1,,, +,,Standard Buying,External Disc,45,1,,, +,,Standard Buying,Internal Disc,33,1,,, +,,Standard Buying,Shaft,30,1,,, +,,Standard Buying,Stand,40,1,,, +,,Standard Buying,Upper Bearing Plate,50,1,,, +,,Standard Buying,Wing Sheet,22,1,,, +,,Standard Selling,Wind Turbine,21,,1,, +,,Standard Selling,Wind Mill A Series,28,,1,, +,,Standard Selling,Wind MIll C Series,14,,1,, +,,Standard Selling,Base Bearing Plate,28,,1,, +,,Standard Selling,Base Plate,21,,1,, +,,Standard Selling,Bearing Block,14,,1,, +,,Standard Selling,Bearing Collar,103.6,,1,, +,,Standard Selling,Bearing Pipe,63,,1,, +,,Standard Selling,Blade Rib,46.2,,1,, +,,Standard Selling,Disc Collars,42,,1,, +,,Standard Selling,External Disc,56,,1,, +,,Standard Selling,Internal Disc,70,,1,, +,,Standard Selling,Shaft,340,,1,, +,,Standard Selling,Stand,400,,1,, +,,Standard Selling,Upper Bearing Plate,300,,1,, +,,Standard Selling,Wing Sheet,30.8,,1,, From 029f698c657bfef53456403e920f8ab5514b4871 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Tue, 7 Jan 2014 19:43:35 +0530 Subject: [PATCH 26/65] patch for item price and price list --- .../Print Format/POS Invoice/POS Invoice.txt | 4 +-- patches/1401/__init__.py | 0 ...ying_selling_as_check_box_in_price_list.py | 29 +++++++++++++++++++ stock/doctype/item_price/item_price.py | 7 ++--- stock/doctype/item_price/item_price.txt | 8 +++-- stock/doctype/price_list/price_list.py | 16 +++++----- .../item_wise_price_list_rate/__init__.py | 0 .../item_wise_price_list_rate.txt | 22 ++++++++++++++ 8 files changed, 68 insertions(+), 18 deletions(-) create mode 100644 patches/1401/__init__.py create mode 100644 patches/1401/p01_make_buying_selling_as_check_box_in_price_list.py create mode 100644 stock/report/item_wise_price_list_rate/__init__.py create mode 100644 stock/report/item_wise_price_list_rate/item_wise_price_list_rate.txt diff --git a/accounts/Print Format/POS Invoice/POS Invoice.txt b/accounts/Print Format/POS Invoice/POS Invoice.txt index aab8e18491..4f1b20a945 100644 --- a/accounts/Print Format/POS Invoice/POS Invoice.txt +++ b/accounts/Print Format/POS Invoice/POS Invoice.txt @@ -2,14 +2,14 @@ { "creation": "2011-12-21 11:08:55", "docstatus": 0, - "modified": "2013-09-13 17:17:47", + "modified": "2014-01-07 18:46:29", "modified_by": "Administrator", "owner": "Administrator" }, { "doc_type": "Sales Invoice", "doctype": "Print Format", - "html": "\n\n\n\n\n\n\n\n\n \n \n \n \n \n \n \n
RECEIPT NO: DATE:
M/s
\n\n
\n\n\n", + "html": "\n\n\n\n\n\n\n\n\n \n \n \n \n \n \n \n
RECEIPT NO: DATE:
M/s
\n\n
\n\n\n", "module": "Accounts", "name": "__common__", "print_format_type": "Client", diff --git a/patches/1401/__init__.py b/patches/1401/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/patches/1401/p01_make_buying_selling_as_check_box_in_price_list.py b/patches/1401/p01_make_buying_selling_as_check_box_in_price_list.py new file mode 100644 index 0000000000..d5eb3e8d36 --- /dev/null +++ b/patches/1401/p01_make_buying_selling_as_check_box_in_price_list.py @@ -0,0 +1,29 @@ +# Copyright (c) 2014, 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.reload_doc("stock", "doctype", "price_list") + webnotes.reload_doc("stock", "doctype", "item_price") + + if "buying_or_selling" in webnotes.conn.get_table_columns("Price List"): + webnotes.conn.sql("""update `tabPrice List` set + selling = + case + when buying_or_selling='Selling' + then 1 + end, + buying = + case + when buying_or_selling='Buying' + then 1 + end + """) + webnotes.conn.sql("""update `tabItem Price` ip, `tabPrice List` pl + set ip.buying=pl.buying, ip.selling=pl.selling + where ip.price_list=pl.name""") + + webnotes.conn.sql("""udpate `tabItem Price` set selling=1 where ifnull(selling, 0)=0 and + ifnull(buying, 0)=0""") \ No newline at end of file diff --git a/stock/doctype/item_price/item_price.py b/stock/doctype/item_price/item_price.py index 9a8e3d35fb..e2c9f2fcb0 100644 --- a/stock/doctype/item_price/item_price.py +++ b/stock/doctype/item_price/item_price.py @@ -17,11 +17,8 @@ class DocType: self.update_item_details() def update_price_list_details(self): - if not self.doc.selling and not self.doc.buying: - self.doc.buying, self.doc.selling = webnotes.conn.get_value("Price List", - self.doc.price_list, ["buying", "selling"]) - - self.doc.currency = webnotes.conn.get_value("Price List", self.doc.price_list, "currency") + self.doc.buying, self.doc.selling, self.doc.currency = webnotes.conn.get_value("Price List", + self.doc.price_list, ["buying", "selling", "currency"]) def update_item_details(self): self.doc.item_name, self.doc.item_description = webnotes.conn.get_value("Item", diff --git a/stock/doctype/item_price/item_price.txt b/stock/doctype/item_price/item_price.txt index b25fd30812..f329a5ff07 100644 --- a/stock/doctype/item_price/item_price.txt +++ b/stock/doctype/item_price/item_price.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-02 16:29:48", "docstatus": 0, - "modified": "2014-01-07 18:11:10", + "modified": "2014-01-07 19:16:49", "modified_by": "Administrator", "owner": "Administrator" }, @@ -64,14 +64,16 @@ "fieldname": "buying", "fieldtype": "Check", "in_list_view": 1, - "label": "Buying" + "label": "Buying", + "read_only": 1 }, { "doctype": "DocField", "fieldname": "selling", "fieldtype": "Check", "in_list_view": 1, - "label": "Selling" + "label": "Selling", + "read_only": 1 }, { "doctype": "DocField", diff --git a/stock/doctype/price_list/price_list.py b/stock/doctype/price_list/price_list.py index 569e759159..40841cfaac 100644 --- a/stock/doctype/price_list/price_list.py +++ b/stock/doctype/price_list/price_list.py @@ -4,14 +4,14 @@ from __future__ import unicode_literals import webnotes from webnotes import msgprint, _, throw -from webnotes.utils import comma_or, cint +from webnotes.utils import cint from webnotes.model.controller import DocListController import webnotes.defaults class DocType(DocListController): def validate(self): - if not self.doc.buying and not self.doc.selling: - throw(_("Price List must be one of Buying or Selling")) + if not cint(self.doc.buying) and not cint(self.doc.selling): + throw(_("Price List must be applicable for Buying or Selling")) if not self.doclist.get({"parentfield": "valid_for_territories"}): # if no territory, set default territory @@ -24,24 +24,24 @@ class DocType(DocListController): else: # at least one territory self.validate_table_has_rows("valid_for_territories") - + def on_update(self): self.set_default_if_missing() self.update_item_price() cart_settings = webnotes.get_obj("Shopping Cart Settings") if cint(cart_settings.doc.enabled): cart_settings.validate_price_lists() - + def set_default_if_missing(self): - if self.doc.selling: + if cint(self.doc.selling): if not webnotes.conn.get_value("Selling Settings", None, "selling_price_list"): webnotes.set_value("Selling Settings", "Selling Settings", "selling_price_list", self.doc.name) - elif self.doc.buying: + elif cint(self.doc.buying): if not webnotes.conn.get_value("Buying Settings", None, "buying_price_list"): webnotes.set_value("Buying Settings", "Buying Settings", "buying_price_list", self.doc.name) def update_item_price(self): webnotes.conn.sql("""update `tabItem Price` set currency=%s, buying=%s, selling=%s, modified=NOW() where price_list=%s""", - (self.doc.currency, self.doc.buying, self.doc.selling, self.doc.name)) \ No newline at end of file + (self.doc.currency, cint(self.doc.buying), cint(self.doc.selling), self.doc.name)) \ No newline at end of file diff --git a/stock/report/item_wise_price_list_rate/__init__.py b/stock/report/item_wise_price_list_rate/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/stock/report/item_wise_price_list_rate/item_wise_price_list_rate.txt b/stock/report/item_wise_price_list_rate/item_wise_price_list_rate.txt new file mode 100644 index 0000000000..f4d1d67ca4 --- /dev/null +++ b/stock/report/item_wise_price_list_rate/item_wise_price_list_rate.txt @@ -0,0 +1,22 @@ +[ + { + "creation": "2013-09-25 10:21:15", + "docstatus": 0, + "modified": "2014-01-07 18:35:22", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "doctype": "Report", + "is_standard": "Yes", + "json": "{\"filters\":[[\"Item Price\",\"price_list\",\"like\",\"%\"],[\"Item Price\",\"item_code\",\"like\",\"%\"]],\"columns\":[[\"name\",\"Item Price\"],[\"price_list\",\"Item Price\"],[\"item_code\",\"Item Price\"],[\"item_name\",\"Item Price\"],[\"item_description\",\"Item Price\"],[\"ref_rate\",\"Item Price\"],[\"buying\",\"Item Price\"],[\"selling\",\"Item Price\"],[\"currency\",\"Item Price\"]],\"sort_by\":\"Item Price.modified\",\"sort_order\":\"desc\",\"sort_by_next\":\"\",\"sort_order_next\":\"desc\"}", + "name": "__common__", + "ref_doctype": "Price List", + "report_name": "Item-wise Price List Rate", + "report_type": "Report Builder" + }, + { + "doctype": "Report", + "name": "Item-wise Price List Rate" + } +] \ No newline at end of file From 8d0ef21911df9cc4daba5a10bf94f588941d4e69 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Tue, 7 Jan 2014 19:45:33 +0530 Subject: [PATCH 27/65] pos invoice print format changes --- accounts/Print Format/POS Invoice/POS Invoice.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/accounts/Print Format/POS Invoice/POS Invoice.txt b/accounts/Print Format/POS Invoice/POS Invoice.txt index 4f1b20a945..4710a4e562 100644 --- a/accounts/Print Format/POS Invoice/POS Invoice.txt +++ b/accounts/Print Format/POS Invoice/POS Invoice.txt @@ -2,14 +2,14 @@ { "creation": "2011-12-21 11:08:55", "docstatus": 0, - "modified": "2014-01-07 18:46:29", + "modified": "2014-01-07 19:44:47", "modified_by": "Administrator", "owner": "Administrator" }, { "doc_type": "Sales Invoice", "doctype": "Print Format", - "html": "\n\n\n\n\n\n\n\n\n \n \n \n \n \n \n \n
RECEIPT NO: DATE:
M/s
\n\n
\n\n\n", + "html": "\n\n\n\n\n\n\n\n\t\n\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\t\n\t\t\t\n\t\t\n\t
RECEIPT NO: DATE:
M/s
\n\t\n\t
\n\n", "module": "Accounts", "name": "__common__", "print_format_type": "Client", From 9e2358c54473501bdb6e6b0baee22ee797319c01 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Tue, 7 Jan 2014 22:15:04 +0600 Subject: [PATCH 28/65] bumped to version 3.4.9 --- config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json b/config.json index 078ca16188..d88d22438b 100644 --- a/config.json +++ b/config.json @@ -1,6 +1,6 @@ { "app_name": "ERPNext", - "app_version": "3.4.8", + "app_version": "3.4.9", "base_template": "app/portal/templates/base.html", "modules": { "Accounts": { From d659343541284611afec55a474abc3a9c555d446 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 8 Jan 2014 17:29:23 +0530 Subject: [PATCH 29/65] Payment Reconciliation: Fix for outstanding voucher query --- .../payment_to_invoice_matching_tool.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/accounts/doctype/payment_to_invoice_matching_tool/payment_to_invoice_matching_tool.py b/accounts/doctype/payment_to_invoice_matching_tool/payment_to_invoice_matching_tool.py index dea5fb59c9..fc58418245 100644 --- a/accounts/doctype/payment_to_invoice_matching_tool/payment_to_invoice_matching_tool.py +++ b/accounts/doctype/payment_to_invoice_matching_tool/payment_to_invoice_matching_tool.py @@ -140,13 +140,13 @@ def gl_entry_details(doctype, txt, searchfield, start, page_len, filters): and ifnull(gle.%(account_type)s, 0) > 0 and (select ifnull(abs(sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))), 0) from `tabGL Entry` - where against_voucher_type = '%(dt)s' + where account = '%(acc)s' + and against_voucher_type = '%(dt)s' and against_voucher = gle.voucher_no and voucher_no != gle.voucher_no) - != abs(ifnull(gle.debit, 0) - ifnull(gle.credit, 0) - ) - and if(gle.voucher_type='Sales Invoice', (select is_pos from `tabSales Invoice` - where name=gle.voucher_no), 0)=0 + != abs(ifnull(gle.debit, 0) - ifnull(gle.credit, 0)) + and if(gle.voucher_type='Sales Invoice', ifnull((select is_pos from `tabSales Invoice` + where name=gle.voucher_no), 0), 0)=0 %(mcond)s ORDER BY gle.posting_date desc, gle.voucher_no desc limit %(start)s, %(page_len)s""" % { From f7a102ffe334876fb481219a764529f318aee52d Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Wed, 8 Jan 2014 19:35:01 +0530 Subject: [PATCH 30/65] POS print format fixed --- accounts/Print Format/POS Invoice/POS Invoice.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/accounts/Print Format/POS Invoice/POS Invoice.txt b/accounts/Print Format/POS Invoice/POS Invoice.txt index aab8e18491..7f1bba4c96 100644 --- a/accounts/Print Format/POS Invoice/POS Invoice.txt +++ b/accounts/Print Format/POS Invoice/POS Invoice.txt @@ -2,14 +2,14 @@ { "creation": "2011-12-21 11:08:55", "docstatus": 0, - "modified": "2013-09-13 17:17:47", + "modified": "2014-01-08 19:32:16", "modified_by": "Administrator", "owner": "Administrator" }, { "doc_type": "Sales Invoice", "doctype": "Print Format", - "html": "\n\n\n\n\n\n\n\n\n \n \n \n \n \n \n \n
RECEIPT NO: DATE:
M/s
\n\n
\n\n\n", + "html": "\n\t\n\n\t\t\n\t\t\n\n\t\t\n\t\t\n\t\n\n\t\n\t\t\n\t\t
\n\t\t
\n\t\t
\n\t\t
\n\t\t
\n\t\n", "module": "Accounts", "name": "__common__", "print_format_type": "Client", From 102b417b52f6781e7959e5aa8849d63ba78d4fd6 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Thu, 9 Jan 2014 11:39:06 +0530 Subject: [PATCH 31/65] Fix: Typo on patch --- .../1401/p01_make_buying_selling_as_check_box_in_price_list.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patches/1401/p01_make_buying_selling_as_check_box_in_price_list.py b/patches/1401/p01_make_buying_selling_as_check_box_in_price_list.py index d5eb3e8d36..b764a7f935 100644 --- a/patches/1401/p01_make_buying_selling_as_check_box_in_price_list.py +++ b/patches/1401/p01_make_buying_selling_as_check_box_in_price_list.py @@ -25,5 +25,5 @@ def execute(): set ip.buying=pl.buying, ip.selling=pl.selling where ip.price_list=pl.name""") - webnotes.conn.sql("""udpate `tabItem Price` set selling=1 where ifnull(selling, 0)=0 and + webnotes.conn.sql("""update `tabItem Price` set selling=1 where ifnull(selling, 0)=0 and ifnull(buying, 0)=0""") \ No newline at end of file From 4bbf91bea18518d56b99e04059d346e2ba548609 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 9 Jan 2014 12:44:44 +0530 Subject: [PATCH 32/65] Added match condition in general ledger report --- accounts/report/general_ledger/general_ledger.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/accounts/report/general_ledger/general_ledger.py b/accounts/report/general_ledger/general_ledger.py index 855b7d1c7a..2f5716ece3 100644 --- a/accounts/report/general_ledger/general_ledger.py +++ b/accounts/report/general_ledger/general_ledger.py @@ -72,6 +72,11 @@ def get_conditions(filters): if filters.get("voucher_no"): conditions.append("voucher_no=%(voucher_no)s") + + + from webnotes.widgets.reportview import build_match_conditions + match_conditions = build_match_conditions("GL Entry") + if match_conditions: conditions.append(match_conditions) return "and {}".format(" and ".join(conditions)) if conditions else "" From cdbd4218a825f605ec15569ab6713683a6d112bb Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 9 Jan 2014 15:49:26 +0530 Subject: [PATCH 33/65] Accounts Receivable fix for partial payment in pos --- .../accounts_receivable/accounts_receivable.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/accounts/report/accounts_receivable/accounts_receivable.py b/accounts/report/accounts_receivable/accounts_receivable.py index 945bae434a..26e1c8cd47 100644 --- a/accounts/report/accounts_receivable/accounts_receivable.py +++ b/accounts/report/accounts_receivable/accounts_receivable.py @@ -65,15 +65,23 @@ class AccountsReceivableReport(object): if getdate(e.posting_date) <= report_date) def is_receivable(self, gle, future_vouchers): - return ((not gle.against_voucher) or (gle.against_voucher==gle.voucher_no) or - ((gle.against_voucher_type, gle.against_voucher) in future_vouchers)) + return ( + # advance + (not gle.against_voucher) or + + # sales invoice + (gle.against_voucher==gle.voucher_no and gle.debit > 0) or + + # entries adjusted with future vouchers + ((gle.against_voucher_type, gle.against_voucher) in future_vouchers) + ) def get_outstanding_amount(self, gle, report_date): payment_received = 0.0 for e in self.get_gl_entries_for(gle.account, gle.voucher_type, gle.voucher_no): if getdate(e.posting_date) <= report_date and e.name!=gle.name: payment_received += (flt(e.credit) - flt(e.debit)) - + return flt(gle.debit) - flt(gle.credit) - payment_received def get_customer(self, account): From 11bf06ad76a6c510eafa2b9d4c6066ccd9f893cd Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Thu, 9 Jan 2014 16:22:09 +0600 Subject: [PATCH 34/65] bumped to version 3.5.0 --- config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.json b/config.json index d88d22438b..65fa55c02d 100644 --- a/config.json +++ b/config.json @@ -1,6 +1,6 @@ { "app_name": "ERPNext", - "app_version": "3.4.9", + "app_version": "3.5.0", "base_template": "app/portal/templates/base.html", "modules": { "Accounts": { @@ -74,5 +74,5 @@ "type": "module" } }, - "requires_framework_version": "==3.4.4" + "requires_framework_version": "==3.5.0" } \ No newline at end of file From aeb68b28998b5261a046e5002bb391aeacba20e8 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 9 Jan 2014 15:54:18 +0530 Subject: [PATCH 35/65] Accounts Receivable fix for partial payment in pos --- accounts/report/accounts_receivable/accounts_receivable.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accounts/report/accounts_receivable/accounts_receivable.py b/accounts/report/accounts_receivable/accounts_receivable.py index 26e1c8cd47..7758b24744 100644 --- a/accounts/report/accounts_receivable/accounts_receivable.py +++ b/accounts/report/accounts_receivable/accounts_receivable.py @@ -34,7 +34,7 @@ class AccountsReceivableReport(object): for gle in self.get_entries_till(self.filters.report_date): if self.is_receivable(gle, future_vouchers): outstanding_amount = self.get_outstanding_amount(gle, self.filters.report_date) - if abs(outstanding_amount) > 0.01: + if abs(outstanding_amount) > 0.0: due_date = self.get_due_date(gle) invoiced_amount = gle.debit if (gle.debit > 0) else 0 payment_received = invoiced_amount - outstanding_amount From 3e846d19d44fb46579b8ff42d5913651bc21cbf5 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Thu, 9 Jan 2014 16:26:53 +0600 Subject: [PATCH 36/65] bumped to version 3.5.1 --- config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json b/config.json index 65fa55c02d..8499ee84d3 100644 --- a/config.json +++ b/config.json @@ -1,6 +1,6 @@ { "app_name": "ERPNext", - "app_version": "3.5.0", + "app_version": "3.5.1", "base_template": "app/portal/templates/base.html", "modules": { "Accounts": { From 68b0d54b4b814dd3781fad07c1a2bd43b46ad59f Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 9 Jan 2014 17:25:55 +0530 Subject: [PATCH 37/65] Set default accounts in company related to perpetual inventory, only it is enabled --- setup/doctype/company/company.py | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/setup/doctype/company/company.py b/setup/doctype/company/company.py index 12281b4415..88d9dcaaa5 100644 --- a/setup/doctype/company/company.py +++ b/setup/doctype/company/company.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals import webnotes from webnotes import _, msgprint -from webnotes.utils import cstr +from webnotes.utils import cstr, cint import webnotes.defaults @@ -237,21 +237,28 @@ class DocType: account.insert() def set_default_accounts(self): - accounts = { + def _set_default_accounts(accounts): + for a in accounts: + account_name = accounts[a] + " - " + self.doc.abbr + if not self.doc.fields.get(a) and webnotes.conn.exists("Account", account_name): + webnotes.conn.set(self.doc, a, account_name) + + _set_default_accounts({ "default_income_account": "Sales", "default_expense_account": "Cost of Goods Sold", "receivables_group": "Accounts Receivable", "payables_group": "Accounts Payable", - "default_cash_account": "Cash", - "stock_received_but_not_billed": "Stock Received But Not Billed", - "stock_adjustment_account": "Stock Adjustment", - "expenses_included_in_valuation": "Expenses Included In Valuation" - } + "default_cash_account": "Cash" + }) + + if cint(webnotes.conn.get_value("Accounts Settings", None, "auto_accounting_for_stock")): + _set_default_accounts({ + "stock_received_but_not_billed": "Stock Received But Not Billed", + "stock_adjustment_account": "Stock Adjustment", + "expenses_included_in_valuation": "Expenses Included In Valuation" + }) + - for a in accounts: - account_name = accounts[a] + " - " + self.doc.abbr - if not self.doc.fields.get(a) and webnotes.conn.exists("Account", account_name): - webnotes.conn.set(self.doc, a, account_name) def create_default_cost_center(self): cc_list = [ From f3ded044e0686164f7271c130d8b2ad05bef7809 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 9 Jan 2014 17:38:50 +0530 Subject: [PATCH 38/65] Monthly Salary Register: Month is now optional --- hr/report/monthly_salary_register/monthly_salary_register.js | 2 +- hr/report/monthly_salary_register/monthly_salary_register.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hr/report/monthly_salary_register/monthly_salary_register.js b/hr/report/monthly_salary_register/monthly_salary_register.js index 5d3abccde9..32b4ef35fb 100644 --- a/hr/report/monthly_salary_register/monthly_salary_register.js +++ b/hr/report/monthly_salary_register/monthly_salary_register.js @@ -7,7 +7,7 @@ wn.query_reports["Monthly Salary Register"] = { "fieldname":"month", "label": wn._("Month"), "fieldtype": "Select", - "options": "Jan\nFeb\nMar\nApr\nMay\nJun\nJul\nAug\nSep\nOct\nNov\nDec", + "options": "\nJan\nFeb\nMar\nApr\nMay\nJun\nJul\nAug\nSep\nOct\nNov\nDec", "default": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"][wn.datetime.str_to_obj(wn.datetime.get_today()).getMonth()], }, diff --git a/hr/report/monthly_salary_register/monthly_salary_register.py b/hr/report/monthly_salary_register/monthly_salary_register.py index 8bd8f36ac8..9b8a84fd91 100644 --- a/hr/report/monthly_salary_register/monthly_salary_register.py +++ b/hr/report/monthly_salary_register/monthly_salary_register.py @@ -59,8 +59,8 @@ def get_columns(salary_slips): def get_salary_slips(filters): conditions, filters = get_conditions(filters) - salary_slips = webnotes.conn.sql("""select * from `tabSalary Slip` where docstatus = 1 %s""" % - conditions, filters, as_dict=1) + salary_slips = webnotes.conn.sql("""select * from `tabSalary Slip` where docstatus = 1 %s + order by employee, month""" % conditions, filters, as_dict=1) if not salary_slips: msgprint(_("No salary slip found for month: ") + cstr(filters.get("month")) + From 371663169c7d93f294d190c2c844a0293cf0543a Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Fri, 10 Jan 2014 15:05:44 +0530 Subject: [PATCH 39/65] pos view showing inclusive taxes --- accounts/doctype/sales_invoice/pos.js | 51 +++++++++++++++------------ 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/accounts/doctype/sales_invoice/pos.js b/accounts/doctype/sales_invoice/pos.js index adbdca1b63..ce3784abd3 100644 --- a/accounts/doctype/sales_invoice/pos.js +++ b/accounts/doctype/sales_invoice/pos.js @@ -60,10 +60,16 @@ erpnext.POS = Class.extend({ \ \

\ - \ - \ +
\ +
\ + \ +
\ +
\ + \ +
\ +
\

\ \
\ @@ -82,7 +88,7 @@ erpnext.POS = Class.extend({ me.refresh(); }); - this.call_function("delete-items", function() {me.remove_selected_item();}); + this.call_function("remove-items", function() {me.remove_selected_items();}); this.call_function("make-payment", function() {me.make_payment();}); }, check_transaction_type: function() { @@ -333,7 +339,7 @@ erpnext.POS = Class.extend({ } this.disable_text_box_and_button(); - this.make_payment_button(); + this.hide_payment_button(); // If quotation to is not Customer then remove party if (this.frm.doctype == "Quotation") { @@ -370,21 +376,21 @@ erpnext.POS = Class.extend({ 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 && - flt(me.frm.doc.other_charges_total_export || - me.frm.doc.other_charges_added_import) != 0.0) ? true : false) + .toggle((taxes && taxes.length) ? true : false) .find("tbody").empty(); $.each(taxes, function(i, d) { - $(repl('\ - %(description)s %(rate)s\ - %(tax_amount)s\ - ', { - description: d.description, - rate: ((d.charge_type == "Actual") ? '' : ("(" + d.rate + "%)")), - tax_amount: format_currency(flt(d.tax_amount)/flt(me.frm.doc.conversion_rate), - me.frm.doc.currency) - })).appendTo(".tax-table tbody"); + if (d.tax_amount) { + $(repl('\ + %(description)s %(rate)s\ + %(tax_amount)s\ + ', { + description: d.description, + rate: ((d.charge_type == "Actual") ? '' : ("(" + d.rate + "%)")), + tax_amount: format_currency(flt(d.tax_amount)/flt(me.frm.doc.conversion_rate), + me.frm.doc.currency) + })).appendTo(".tax-table tbody"); + } }); }, set_totals: function() { @@ -427,7 +433,7 @@ erpnext.POS = Class.extend({ $(this.wrapper).find('input, button').each(function () { $(this).prop('disabled', true); }); - $(this.wrapper).find(".delete-items").hide(); + $(this.wrapper).find(".remove-items").hide(); $(this.wrapper).find(".make-payment").hide(); } else { @@ -437,14 +443,14 @@ erpnext.POS = Class.extend({ $(this.wrapper).find(".make-payment").show(); } }, - make_payment_button: function() { + hide_payment_button: function() { var me = this; // Show Make Payment button only in Sales Invoice if (this.frm.doctype != "Sales Invoice") $(this.wrapper).find(".make-payment").hide(); }, refresh_delete_btn: function() { - $(this.wrapper).find(".delete-items").toggle($(".item-cart .warning").length ? true : false); + $(this.wrapper).find(".remove-items").toggle($(".item-cart .warning").length ? true : false); }, add_item_thru_barcode: function() { var me = this; @@ -466,7 +472,7 @@ erpnext.POS = Class.extend({ } }); }, - remove_selected_item: function() { + remove_selected_items: function() { var me = this; var selected_items = []; var no_of_items = $(this.wrapper).find("#cart tbody tr").length; @@ -487,6 +493,7 @@ erpnext.POS = Class.extend({ } } }); + this.refresh_grid(); }, refresh_grid: function() { From 03463ef73bf373af5a2415b093018c1e978f6a9a Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 10 Jan 2014 16:28:41 +0530 Subject: [PATCH 40/65] Move related property setters to custom field property --- patches/1401/__init__.py | 0 ...elated_property_setters_to_custom_field.py | 35 +++++++++++++++++++ patches/patch_list.py | 1 + 3 files changed, 36 insertions(+) create mode 100644 patches/1401/__init__.py create mode 100644 patches/1401/p01_move_related_property_setters_to_custom_field.py diff --git a/patches/1401/__init__.py b/patches/1401/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/patches/1401/p01_move_related_property_setters_to_custom_field.py b/patches/1401/p01_move_related_property_setters_to_custom_field.py new file mode 100644 index 0000000000..6b28553977 --- /dev/null +++ b/patches/1401/p01_move_related_property_setters_to_custom_field.py @@ -0,0 +1,35 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +import webnotes +from webnotes.model.meta import get_field + +def execute(): + webnotes.reload_doc("core", "doctype", "custom_field") + + custom_fields = {} + for cf in webnotes.conn.sql("""select dt, fieldname from `tabCustom Field`""", as_dict=1): + custom_fields.setdefault(cf.dt, []).append(cf.fieldname) + + delete_list = [] + for ps in webnotes.conn.sql("""select * from `tabProperty Setter`""", as_dict=1): + if ps.field_name in custom_fields.get(ps.doc_type, []): + + if ps.property == "previous_field": + property_name = "insert_after" + + field_meta = get_field(ps.doc_type, ps.value) + property_value = field_meta.label if field_meta else "" + else: + property_name = ps.property + property_value =ps.value + + webnotes.conn.sql("""update `tabCustom Field` + set %s=%s where dt=%s and fieldname=%s""" % (property_name, '%s', '%s', '%s'), + (property_value, ps.doc_type, ps.field_name)) + + delete_list.append(ps.name) + + if delete_list: + webnotes.conn.sql("""delete from `tabProperty Setter` where name in (%s)""" % + ', '.join(['%s']*len(delete_list)), tuple(delete_list)) \ No newline at end of file diff --git a/patches/patch_list.py b/patches/patch_list.py index 608ba77168..e4d2975ea3 100644 --- a/patches/patch_list.py +++ b/patches/patch_list.py @@ -263,4 +263,5 @@ patch_list = [ "patches.1311.p08_email_digest_recipients", "execute:webnotes.delete_doc('DocType', 'Warehouse Type')", "patches.1312.p02_update_item_details_in_item_price", + "patches.1401.p01_move_related_property_setters_to_custom_field", ] \ No newline at end of file From 35a9d585b4f767c0b8447dafb6dc2b96819707bb Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 13 Jan 2014 12:24:27 +0530 Subject: [PATCH 41/65] Bank Reconciliation Statement: Show balance in debit or credit column based on account type --- .../bank_reconciliation_statement.js | 4 +- .../bank_reconciliation_statement.py | 53 ++++++++----------- 2 files changed, 26 insertions(+), 31 deletions(-) diff --git a/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js b/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js index b93f182f31..7f32e261c7 100644 --- a/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js +++ b/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js @@ -8,6 +8,7 @@ wn.query_reports["Bank Reconciliation Statement"] = { "label": wn._("Bank Account"), "fieldtype": "Link", "options": "Account", + "reqd": 1, "get_query": function() { return { "query": "accounts.utils.get_account_list", @@ -22,7 +23,8 @@ wn.query_reports["Bank Reconciliation Statement"] = { "fieldname":"report_date", "label": wn._("Date"), "fieldtype": "Date", - "default": get_today() + "default": get_today(), + "reqd": 1 }, ] } \ No newline at end of file diff --git a/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py b/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py index 431a6496d2..5672497189 100644 --- a/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py +++ b/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py @@ -3,13 +3,14 @@ from __future__ import unicode_literals import webnotes -from webnotes import _, msgprint from webnotes.utils import flt def execute(filters=None): if not filters: filters = {} - - columns = get_columns() + + debit_or_credit = webnotes.conn.get_value("Account", filters["account"], "debit_or_credit") + + columns = get_columns() data = get_entries(filters) from accounts.utils import get_balance_on @@ -20,47 +21,39 @@ def execute(filters=None): total_debit += flt(d[4]) total_credit += flt(d[5]) - if webnotes.conn.get_value("Account", filters["account"], "debit_or_credit") == 'Debit': + if debit_or_credit == 'Debit': bank_bal = flt(balance_as_per_company) - flt(total_debit) + flt(total_credit) else: bank_bal = flt(balance_as_per_company) + flt(total_debit) - flt(total_credit) data += [ - ["", "", "", "Balance as per company books", balance_as_per_company, ""], + get_balance_row("Balance as per company books", balance_as_per_company, debit_or_credit), ["", "", "", "Amounts not reflected in bank", total_debit, total_credit], - ["", "", "", "Balance as per bank", bank_bal, ""] + get_balance_row("Balance as per bank", bank_bal, debit_or_credit) ] - - return columns, data + return columns, data def get_columns(): return ["Journal Voucher:Link/Journal Voucher:140", "Posting Date:Date:100", "Clearance Date:Date:110", "Against Account:Link/Account:200", "Debit:Currency:120", "Credit:Currency:120" ] - -def get_conditions(filters): - conditions = "" - if not filters.get("account"): - msgprint(_("Please select Bank Account"), raise_exception=1) - else: - conditions += " and jvd.account = %(account)s" - - if not filters.get("report_date"): - msgprint(_("Please select Date on which you want to run the report"), raise_exception=1) - else: - conditions += """ and jv.posting_date <= %(report_date)s - and ifnull(jv.clearance_date, '4000-01-01') > %(report_date)s""" - - return conditions def get_entries(filters): - conditions = get_conditions(filters) - entries = webnotes.conn.sql("""select jv.name, jv.posting_date, jv.clearance_date, - jvd.against_account, jvd.debit, jvd.credit - from `tabJournal Voucher Detail` jvd, `tabJournal Voucher` jv - where jvd.parent = jv.name and jv.docstatus=1 and ifnull(jv.cheque_no, '')!= '' %s - order by jv.name DESC""" % conditions, filters, as_list=1) + entries = webnotes.conn.sql("""select + jv.name, jv.posting_date, jv.clearance_date, jvd.against_account, jvd.debit, jvd.credit + from + `tabJournal Voucher Detail` jvd, `tabJournal Voucher` jv + where jvd.parent = jv.name and jv.docstatus=1 and ifnull(jv.cheque_no, '')!= '' + and jvd.account = %(account)s and jv.posting_date <= %(report_date)s + and ifnull(jv.clearance_date, '4000-01-01') > %(report_date)s + order by jv.name DESC""", filters, as_list=1) - return entries \ No newline at end of file + return entries + +def get_balance_row(label, amount, debit_or_credit): + if debit_or_credit == "Debit": + return ["", "", "", label, amount, 0] + else: + return ["", "", "", label, 0, amount] \ No newline at end of file From 14bf711d04e31cc5cb45ab0799ed6dab3a8ebcf5 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 13 Jan 2014 13:28:07 +0530 Subject: [PATCH 42/65] Fixes in frozen accounts validation --- accounts/doctype/gl_entry/gl_entry.py | 3 ++- controllers/accounts_controller.py | 15 +++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/accounts/doctype/gl_entry/gl_entry.py b/accounts/doctype/gl_entry/gl_entry.py index d3c6317787..694917ffcd 100644 --- a/accounts/doctype/gl_entry/gl_entry.py +++ b/accounts/doctype/gl_entry/gl_entry.py @@ -146,11 +146,12 @@ def update_outstanding_amt(account, against_voucher_type, against_voucher, on_ca webnotes.conn.sql("update `tab%s` set outstanding_amount=%s where name='%s'" % (against_voucher_type, bal, against_voucher)) -def validate_frozen_account(account, adv_adj): +def validate_frozen_account(account, adv_adj=None): 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 \ diff --git a/controllers/accounts_controller.py b/controllers/accounts_controller.py index a65bf260ee..8d33327569 100644 --- a/controllers/accounts_controller.py +++ b/controllers/accounts_controller.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals import webnotes -from webnotes import _, msgprint, throw +from webnotes import _, throw from webnotes.utils import flt, cint, today, cstr from webnotes.model.code import get_obj from setup.utils import get_company_currency @@ -44,14 +44,13 @@ class AccountsController(TransactionBase): def validate_for_freezed_account(self): for fieldname in ["customer", "supplier"]: if self.meta.get_field(fieldname) and self.doc.fields.get(fieldname): - accounts = webnotes.conn.get_values("Account", {"master_type": fieldname.title(), - "master_name": self.doc.fields[fieldname], "company": self.doc.company}, - "freeze_account", as_dict=1) - + accounts = webnotes.conn.get_values("Account", + {"master_type": fieldname.title(), "master_name": self.doc.fields[fieldname], + "company": self.doc.company}, "name") if accounts: - if not filter(lambda x: cstr(x.freeze_account) in ["", "No"], accounts): - throw(_("Account for this ") + fieldname + _(" has been freezed. ") + - self.doc.doctype + _(" can not be made.")) + from accounts.doctype.gl_entry.gl_entry import validate_frozen_account + for account in accounts: + validate_frozen_account(account[0]) def set_price_list_currency(self, buying_or_selling): if self.meta.get_field("currency"): From 0b3c10601c6eedffcdfcbf2f91c4a238b2aa6ac9 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Mon, 13 Jan 2014 13:34:34 +0530 Subject: [PATCH 43/65] Increase and decrease quantity buttons in POS --- accounts/doctype/sales_invoice/pos.js | 39 ++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/accounts/doctype/sales_invoice/pos.js b/accounts/doctype/sales_invoice/pos.js index ce3784abd3..1d58f2d2dc 100644 --- a/accounts/doctype/sales_invoice/pos.js +++ b/accounts/doctype/sales_invoice/pos.js @@ -19,8 +19,10 @@ erpnext.POS = Class.extend({ \ \ \ - \ - \ + \ + \ + \ + \ \ \ \ @@ -357,8 +359,18 @@ erpnext.POS = Class.extend({ $(repl('\ \ - \ + \ + \ \ ', { @@ -370,6 +382,11 @@ erpnext.POS = Class.extend({ } )).appendTo($items); }); + + this.wrapper.find(".increase-qty, .decrease-qty").on("click", function() { + var item_code = $(this).closest("tr").attr("id"); + me.selected_item_qty_operation(item_code, $(this).attr("class")); + }); }, show_taxes: function() { var me = this; @@ -501,6 +518,22 @@ erpnext.POS = Class.extend({ this.frm.script_manager.trigger("calculate_taxes_and_totals"); this.refresh(); }, + selected_item_qty_operation: function(item_code, operation) { + var me = this; + 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) { + if (d.item_code == item_code) { + if (operation == "increase-qty") + d.qty += 1; + else if (operation == "decrease-qty") + d.qty != 1 ? d.qty -= 1 : d.qty = 1; + + me.refresh(); + } + }); + }, make_payment: function() { var me = this; var no_of_items = $(this.wrapper).find("#cart tbody tr").length; From c43d58ac79d6144eb6252ff611cc9605f290006d Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 13 Jan 2014 17:55:24 +0530 Subject: [PATCH 44/65] Delete Property Setters for Custom Fields, and set them inside Custom Field --- ...elated_property_setters_to_custom_field.py | 32 +++++++------------ 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/patches/1401/p01_move_related_property_setters_to_custom_field.py b/patches/1401/p01_move_related_property_setters_to_custom_field.py index 6b28553977..cf9221bcfd 100644 --- a/patches/1401/p01_move_related_property_setters_to_custom_field.py +++ b/patches/1401/p01_move_related_property_setters_to_custom_field.py @@ -2,34 +2,24 @@ # License: GNU General Public License v3. See license.txt import webnotes -from webnotes.model.meta import get_field def execute(): webnotes.reload_doc("core", "doctype", "custom_field") - custom_fields = {} - for cf in webnotes.conn.sql("""select dt, fieldname from `tabCustom Field`""", as_dict=1): - custom_fields.setdefault(cf.dt, []).append(cf.fieldname) - + cf_doclist = webnotes.get_doctype("Custom Field") + delete_list = [] - for ps in webnotes.conn.sql("""select * from `tabProperty Setter`""", as_dict=1): - if ps.field_name in custom_fields.get(ps.doc_type, []): - - if ps.property == "previous_field": - property_name = "insert_after" + for d in webnotes.conn.sql("""select cf.name as cf_name, ps.property, + ps.value, ps.name as ps_name + from `tabProperty Setter` ps, `tabCustom Field` cf + where ps.doctype_or_field = 'DocField' and ps.property != 'previous_field' + and ps.doc_type=cf.dt and ps.field_name=cf.fieldname""", as_dict=1): + if cf_doclist.get_field(d.property): + webnotes.conn.sql("""update `tabCustom Field` + set `%s`=%s where name=%s""" % (d.property, '%s', '%s'), (d.value, d.cf_name)) - field_meta = get_field(ps.doc_type, ps.value) - property_value = field_meta.label if field_meta else "" - else: - property_name = ps.property - property_value =ps.value + delete_list.append(d.ps_name) - webnotes.conn.sql("""update `tabCustom Field` - set %s=%s where dt=%s and fieldname=%s""" % (property_name, '%s', '%s', '%s'), - (property_value, ps.doc_type, ps.field_name)) - - delete_list.append(ps.name) - if delete_list: webnotes.conn.sql("""delete from `tabProperty Setter` where name in (%s)""" % ', '.join(['%s']*len(delete_list)), tuple(delete_list)) \ No newline at end of file From 1e347910d5a7e30dea13883fa5f6b651efa93146 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Mon, 13 Jan 2014 19:07:07 +0600 Subject: [PATCH 45/65] bumped to version 3.6.0 --- config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.json b/config.json index 8499ee84d3..8e033d52a2 100644 --- a/config.json +++ b/config.json @@ -1,6 +1,6 @@ { "app_name": "ERPNext", - "app_version": "3.5.1", + "app_version": "3.6.0", "base_template": "app/portal/templates/base.html", "modules": { "Accounts": { @@ -74,5 +74,5 @@ "type": "module" } }, - "requires_framework_version": "==3.5.0" + "requires_framework_version": "==3.7.0" } \ No newline at end of file From d23ae108ae4537748ac4e0aade597423c71aae5a Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 14 Jan 2014 15:52:09 +0530 Subject: [PATCH 46/65] Fixes in Comment, if comment by not mentioned, consider owner --- startup/event_handlers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/startup/event_handlers.py b/startup/event_handlers.py index f0323ea36a..b04b588505 100644 --- a/startup/event_handlers.py +++ b/startup/event_handlers.py @@ -70,6 +70,6 @@ def on_build(): def comment_added(doc): """add comment to feed""" - home.make_feed('Comment', doc.comment_doctype, doc.comment_docname, doc.comment_by, - '"' + doc.comment + '"', '#6B24B3') + home.make_feed('Comment', doc.comment_doctype, doc.comment_docname, + doc.comment_by or doc.owner, '"' + doc.comment + '"', '#6B24B3') From d91af2853eff03635fcb69f1ffff3fab847bd4f4 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 14 Jan 2014 15:56:52 +0530 Subject: [PATCH 47/65] Allowed import for customer issue --- support/doctype/customer_issue/customer_issue.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/support/doctype/customer_issue/customer_issue.txt b/support/doctype/customer_issue/customer_issue.txt index f9fbc6bd6a..76d49a8199 100644 --- a/support/doctype/customer_issue/customer_issue.txt +++ b/support/doctype/customer_issue/customer_issue.txt @@ -2,11 +2,12 @@ { "creation": "2013-01-10 16:34:30", "docstatus": 0, - "modified": "2013-11-02 16:59:22", + "modified": "2014-01-14 15:56:22", "modified_by": "Administrator", "owner": "harshada@webnotestech.com" }, { + "allow_import": 1, "autoname": "naming_series:", "doctype": "DocType", "icon": "icon-bug", From 3a193708927cee8b5c788c75221ec47a0f54e24e Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 14 Jan 2014 17:44:34 +0530 Subject: [PATCH 48/65] Rounding issue and divisional loss adjustment --- .../purchase_invoice/purchase_invoice.py | 3 +- controllers/accounts_controller.py | 28 +++++++++++------- controllers/buying_controller.py | 16 +++++++--- .../production_order/test_production_order.py | 2 ++ public/js/transaction.js | 29 ++++++++++++++----- 5 files changed, 55 insertions(+), 23 deletions(-) diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.py b/accounts/doctype/purchase_invoice/purchase_invoice.py index 0b8ad46dd0..06b7a3ad2e 100644 --- a/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -358,7 +358,8 @@ class DocType(BuyingController): # expense will be booked in sales invoice stock_item_and_auto_accounting_for_stock = True - valuation_amt = item.amount + item.item_tax_amount + item.rm_supp_cost + valuation_amt = flt(item.amount + item.item_tax_amount + item.rm_supp_cost, + self.precision("amount", item)) gl_entries.append( self.get_gl_dict({ diff --git a/controllers/accounts_controller.py b/controllers/accounts_controller.py index 8d33327569..e5b0b9d75b 100644 --- a/controllers/accounts_controller.py +++ b/controllers/accounts_controller.py @@ -223,20 +223,22 @@ class AccountsController(TransactionBase): _on_previous_row_error("1 - %d" % (tax.row_id,)) def calculate_taxes(self): - for item in self.item_doclist: + # maintain actual tax rate based on idx + actual_tax_dict = dict([[tax.idx, tax.rate] for tax in self.tax_doclist + if tax.charge_type == "Actual"]) + + for n, item in enumerate(self.item_doclist): item_tax_map = self._load_item_tax_rate(item.item_tax_rate) for i, tax in enumerate(self.tax_doclist): # tax_amount represents the amount of tax for the current step current_tax_amount = self.get_current_tax_amount(item, tax, item_tax_map) - - # case when net total is 0 but there is an actual type charge - # in this case add the actual amount to tax.tax_amount - # and tax.grand_total_for_current_item for the first such iteration - if tax.charge_type=="Actual" and \ - not (current_tax_amount or self.doc.net_total or tax.tax_amount): - zero_net_total_adjustment = flt(tax.rate, self.precision("tax_amount", tax)) - current_tax_amount += zero_net_total_adjustment + + # Adjust divisional loss to the last item + if tax.charge_type == "Actual": + actual_tax_dict[tax.idx] -= current_tax_amount + if n == len(self.item_doclist) - 1: + current_tax_amount += actual_tax_dict[tax.idx] # store tax_amount for current item as it will be used for # charge type = 'On Previous Row Amount' @@ -248,7 +250,8 @@ class AccountsController(TransactionBase): if tax.category: # if just for valuation, do not add the tax amount in total # hence, setting it as 0 for further steps - current_tax_amount = 0.0 if (tax.category == "Valuation") else current_tax_amount + current_tax_amount = 0.0 if (tax.category == "Valuation") \ + else current_tax_amount current_tax_amount *= -1.0 if (tax.add_deduct_tax == "Deduct") else 1.0 @@ -267,6 +270,11 @@ class AccountsController(TransactionBase): # in tax.total, accumulate grand total of each item tax.total += tax.grand_total_for_current_item + # set precision in the last item iteration + if n == len(self.item_doclist) - 1: + tax.total = flt(tax.total, self.precision("total", tax)) + tax.tax_amount = flt(tax.tax_amount, self.precision("tax_amount", tax)) + def get_current_tax_amount(self, item, tax, item_tax_map): tax_rate = self._get_tax_rate(tax, item_tax_map) current_tax_amount = 0.0 diff --git a/controllers/buying_controller.py b/controllers/buying_controller.py index 3c6981d6cb..7954ca0abb 100644 --- a/controllers/buying_controller.py +++ b/controllers/buying_controller.py @@ -175,23 +175,31 @@ class BuyingController(StockController): stock_items = self.get_stock_items() stock_items_qty, stock_items_amount = 0, 0 + last_stock_item_idx = 1 for d in self.doclist.get({"parentfield": parentfield}): if d.item_code and d.item_code in stock_items: stock_items_qty += flt(d.qty) stock_items_amount += flt(d.amount) + last_stock_item_idx = d.idx total_valuation_amount = sum([flt(d.tax_amount) for d in self.doclist.get({"parentfield": "purchase_tax_details"}) if d.category in ["Valuation", "Valuation and Total"]]) - - for item in self.doclist.get({"parentfield": parentfield}): + + valuation_amount_adjustment = total_valuation_amount + for i, item in enumerate(self.doclist.get({"parentfield": parentfield})): if item.item_code and item.qty and item.item_code in stock_items: item_proportion = flt(item.amount) / stock_items_amount if stock_items_amount \ else flt(item.qty) / stock_items_qty - item.item_tax_amount = flt(item_proportion * total_valuation_amount, - self.precision("item_tax_amount", item)) + if i == (last_stock_item_idx - 1): + item.item_tax_amount = flt(valuation_amount_adjustment, + self.precision("item_tax_amount", item)) + else: + item.item_tax_amount = flt(item_proportion * total_valuation_amount, + self.precision("item_tax_amount", item)) + valuation_amount_adjustment -= item.item_tax_amount self.round_floats_in(item) diff --git a/manufacturing/doctype/production_order/test_production_order.py b/manufacturing/doctype/production_order/test_production_order.py index ca28708cc1..da45a9bdb6 100644 --- a/manufacturing/doctype/production_order/test_production_order.py +++ b/manufacturing/doctype/production_order/test_production_order.py @@ -35,6 +35,7 @@ class TestProductionOrder(unittest.TestCase): stock_entry.doc.fg_completed_qty = 4 stock_entry.doc.posting_date = "2013-05-12" + stock_entry.doc.fiscal_year = "_Test Fiscal Year 2013" stock_entry.run_method("get_items") stock_entry.submit() @@ -52,6 +53,7 @@ class TestProductionOrder(unittest.TestCase): stock_entry = make_stock_entry(pro_order, "Manufacture/Repack") stock_entry = webnotes.bean(stock_entry) stock_entry.doc.posting_date = "2013-05-12" + stock_entry.doc.fiscal_year = "_Test Fiscal Year 2013" stock_entry.doc.fg_completed_qty = 15 stock_entry.run_method("get_items") stock_entry.insert() diff --git a/public/js/transaction.js b/public/js/transaction.js index 0fe0535c6b..1e03833bd6 100644 --- a/public/js/transaction.js +++ b/public/js/transaction.js @@ -540,6 +540,14 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ calculate_taxes: function() { var me = this; + var actual_tax_dict = {}; + + // maintain actual tax rate based on idx + $.each(this.frm.tax_doclist, function(i, tax) { + if (tax.charge_type == "Actual") { + actual_tax_dict[tax.idx] = flt(tax.rate); + } + }); $.each(this.frm.item_doclist, function(n, item) { var item_tax_map = me._load_item_tax_rate(item.item_tax_rate); @@ -549,15 +557,15 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ var current_tax_amount = me.get_current_tax_amount(item, tax, item_tax_map); me.set_item_tax_amount && me.set_item_tax_amount(item, tax, current_tax_amount); - - // case when net total is 0 but there is an actual type charge - // in this case add the actual amount to tax.tax_amount - // and tax.grand_total_for_current_item for the first such iteration - if(tax.charge_type == "Actual" && - !(current_tax_amount || me.frm.doc.net_total || tax.tax_amount)) { - var zero_net_total_adjustment = flt(tax.rate, precision("tax_amount", tax)); - current_tax_amount += zero_net_total_adjustment; + + // Adjust divisional loss to the last item + if (tax.charge_type == "Actual") { + actual_tax_dict[tax.idx] -= current_tax_amount; + if (n == me.frm.item_doclist.length - 1) { + current_tax_amount += actual_tax_dict[tax.idx] } + } + // store tax_amount for current item as it will be used for // charge type = 'On Previous Row Amount' @@ -589,6 +597,11 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ // in tax.total, accumulate grand total for each item tax.total += tax.grand_total_for_current_item; + + if (n == me.frm.item_doclist.length - 1) { + tax.total = flt(tax.total, precision("total", tax)); + tax.tax_amount = flt(tax.tax_amount, precision("tax_amount", tax)); + } }); }); }, From ee6200576a53ad6ca8de685b028ddb44c2b30e96 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 14 Jan 2014 18:34:10 +0530 Subject: [PATCH 49/65] Highest priority to user properties while fetching warehouse from item --- selling/utils/__init__.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/selling/utils/__init__.py b/selling/utils/__init__.py index 85c20e86d8..f495f58e44 100644 --- a/selling/utils/__init__.py +++ b/selling/utils/__init__.py @@ -3,8 +3,8 @@ from __future__ import unicode_literals import webnotes -from webnotes import msgprint, _, throw -from webnotes.utils import flt, cint, comma_and +from webnotes import _, throw +from webnotes.utils import flt, cint import json def get_customer_list(doctype, txt, searchfield, start, page_len, filters): @@ -121,10 +121,16 @@ def _validate_item_details(args, item): def _get_basic_details(args, item_bean, warehouse_fieldname): item = item_bean.doc + from webnotes.defaults import get_user_default_as_list + user_default_warehouse_list = get_user_default_as_list('warehouse') + user_default_warehouse = user_default_warehouse_list[0] \ + if len(user_default_warehouse_list)==1 else "" + out = webnotes._dict({ "item_code": item.name, "description": item.description_html or item.description, - warehouse_fieldname: item.default_warehouse or args.get(warehouse_fieldname), + warehouse_fieldname: user_default_warehouse or item.default_warehouse \ + or args.get(warehouse_fieldname), "income_account": item.default_income_account or args.income_account \ or webnotes.conn.get_value("Company", args.company, "default_income_account"), "expense_account": item.purchase_account or args.expense_account \ From f55d9414cd23612bc2e5c29907b63e0e439dfcd3 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Tue, 14 Jan 2014 19:19:14 +0600 Subject: [PATCH 50/65] bumped to version 3.6.1 --- config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.json b/config.json index 8e033d52a2..45acaf2cd3 100644 --- a/config.json +++ b/config.json @@ -1,6 +1,6 @@ { "app_name": "ERPNext", - "app_version": "3.6.0", + "app_version": "3.6.1", "base_template": "app/portal/templates/base.html", "modules": { "Accounts": { @@ -74,5 +74,5 @@ "type": "module" } }, - "requires_framework_version": "==3.7.0" + "requires_framework_version": "==3.7.1" } \ No newline at end of file From c5d4fc38aa57e4bde919d5e8e1859fcd11e3e4d3 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 15 Jan 2014 10:54:07 +0530 Subject: [PATCH 51/65] Fixes in monthly salary register --- .../monthly_salary_register/monthly_salary_register.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hr/report/monthly_salary_register/monthly_salary_register.py b/hr/report/monthly_salary_register/monthly_salary_register.py index 9b8a84fd91..42c62e474b 100644 --- a/hr/report/monthly_salary_register/monthly_salary_register.py +++ b/hr/report/monthly_salary_register/monthly_salary_register.py @@ -50,9 +50,9 @@ def get_columns(salary_slips): where ifnull(d_modified_amount, 0) != 0 and parent in (%s)""" % (', '.join(['%s']*len(salary_slips))), tuple([d.name for d in salary_slips])) - columns = columns + [(e + ":Link/Earning Type:120") for e in earning_types] + \ + columns = columns + [(e + ":Currency:120") for e in earning_types] + \ ["Arrear Amount:Currency:120", "Leave Encashment Amount:Currency:150", - "Gross Pay:Currency:120"] + [(d + ":Link/Deduction Type:120") for d in ded_types] + \ + "Gross Pay:Currency:120"] + [(d + ":Currency:120") for d in ded_types] + \ ["Total Deduction:Currency:120", "Net Pay:Currency:120"] return columns, earning_types, ded_types @@ -102,6 +102,6 @@ def get_ss_ded_map(salary_slips): ss_ded_map = {} for d in ss_deductions: ss_ded_map.setdefault(d.parent, webnotes._dict()).setdefault(d.d_type, []) - ss_ded_map[d.parent][d.e_type] = flt(d.d_modified_amount) + ss_ded_map[d.parent][d.d_type] = flt(d.d_modified_amount) return ss_ded_map \ No newline at end of file From a6df26839dea38b04a17ecf29fafd2f60bc73d8b Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 15 Jan 2014 12:21:14 +0530 Subject: [PATCH 52/65] Higher priority to user's default price list over customer's default price list --- utilities/transaction_base.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/utilities/transaction_base.py b/utilities/transaction_base.py index 5c28d8d8b6..f783faa9ec 100644 --- a/utilities/transaction_base.py +++ b/utilities/transaction_base.py @@ -79,9 +79,10 @@ class TransactionBase(StatusUpdater): """ customer_defaults = self.get_customer_defaults() - customer_defaults["selling_price_list"] = customer_defaults.get("price_list") or \ - webnotes.conn.get_value("Customer Group", self.doc.customer_group, "default_price_list") or \ - self.doc.selling_price_list + customer_defaults["selling_price_list"] = self.get_user_default_price_list("Selling") or \ + customer_defaults.get("price_list") or \ + webnotes.conn.get_value("Customer Group", self.doc.customer_group, + "default_price_list") or self.doc.selling_price_list for fieldname, val in customer_defaults.items(): if self.meta.get_field(fieldname): @@ -90,6 +91,12 @@ class TransactionBase(StatusUpdater): if self.meta.get_field("sales_team") and self.doc.customer: self.set_sales_team_for_customer() + def get_user_default_price_list(self, price_list_for): + from webnotes.defaults import get_user_default_as_list + user_default_price_list = get_user_default_as_list("selling_price_list" + if price_list_for=="Selling" else "buying_price_list") + return user_default_price_list[0] if len(user_default_price_list)==1 else "" + def set_sales_team_for_customer(self): from webnotes.model import default_fields @@ -120,8 +127,9 @@ class TransactionBase(StatusUpdater): out["supplier_name"] = supplier.supplier_name if supplier.default_currency: out["currency"] = supplier.default_currency - if supplier.default_price_list: - out["buying_price_list"] = supplier.default_price_list + + out["buying_price_list"] = self.get_user_default_price_list("Buying") or \ + supplier.default_price_list or self.doc.buying_price_list return out From 76dd468f0ed39d5bd09fb06107b7fd479e5deb02 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Wed, 15 Jan 2014 14:23:38 +0530 Subject: [PATCH 53/65] update about erpnext with version number --- public/js/conf.js | 15 ++++++++------- public/js/toolbar.js | 4 ++-- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/public/js/conf.js b/public/js/conf.js index 929bfcaa59..1fe21c7611 100644 --- a/public/js/conf.js +++ b/public/js/conf.js @@ -24,16 +24,17 @@ $(document).bind('toolbar_setup', function() { wn.provide('wn.ui.misc'); wn.ui.misc.about = function() { if(!wn.ui.misc.about_dialog) { - var d = new wn.ui.Dialog({title: wn._('About ERPNext')}) + var d = new wn.ui.Dialog({title: wn._('About')}) $(d.body).html(repl("
\ -

"+wn._("ERPNext is an open-source web based ERP made by Web Notes Technologies Pvt Ltd.\ - to provide an integrated tool to manage most processes in a small organization.\ - For more information about Web Notes, or to buy hosting servies, go to ")+ - "https://erpnext.com.

\ -

"+wn._("To report an issue, go to ")+"GitHub Issues

\ -
\ +

ERPNext

\ +

v" + wn.boot.app_version + "

\ +

"+wn._("An open source ERP made for the web.

") + + "

"+wn._("To report an issue, go to ")+"GitHub Issues

\ +

http://erpnext.org.

\

License: GNU General Public License Version 3

\ +
\ +

© 2014 Web Notes Technologies Pvt. Ltd and contributers

\
", wn.app)); wn.ui.misc.about_dialog = d; diff --git a/public/js/toolbar.js b/public/js/toolbar.js index e0affaf61d..1d6fa919b2 100644 --- a/public/js/toolbar.js +++ b/public/js/toolbar.js @@ -21,6 +21,6 @@ erpnext.toolbar.setup = function() { '+wn._('Live Chat')+''); } - $("#toolbar-tools").append('
  • \ + $("#toolbar-tools").append('
  • \ Latest Updates
  • '); -} \ No newline at end of file +} From a682d45846de23f3c03382a4d371befe2b5342f7 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Wed, 15 Jan 2014 16:39:01 +0530 Subject: [PATCH 54/65] webnotes/erpnext # 1320 - hide fields fix --- accounts/doctype/pos_setting/pos_setting.txt | 4 ++-- .../doctype/purchase_receipt_item/purchase_receipt_item.txt | 4 ++-- stock/doctype/stock_entry_detail/stock_entry_detail.txt | 6 +++--- stock/doctype/stock_reconciliation/stock_reconciliation.txt | 5 +++-- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/accounts/doctype/pos_setting/pos_setting.txt b/accounts/doctype/pos_setting/pos_setting.txt index 09a3757985..4319c268ed 100755 --- a/accounts/doctype/pos_setting/pos_setting.txt +++ b/accounts/doctype/pos_setting/pos_setting.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-24 12:15:51", "docstatus": 0, - "modified": "2013-11-02 16:58:38", + "modified": "2014-01-15 16:23:58", "modified_by": "Administrator", "owner": "Administrator" }, @@ -154,7 +154,7 @@ "reqd": 1 }, { - "depends_on": "eval:sys_defaults.auto_accounting_for_stock", + "depends_on": "eval:cint(sys_defaults.auto_accounting_for_stock)", "doctype": "DocField", "fieldname": "expense_account", "fieldtype": "Link", diff --git a/stock/doctype/purchase_receipt_item/purchase_receipt_item.txt b/stock/doctype/purchase_receipt_item/purchase_receipt_item.txt index 1d9397909d..9bc66a42da 100755 --- a/stock/doctype/purchase_receipt_item/purchase_receipt_item.txt +++ b/stock/doctype/purchase_receipt_item/purchase_receipt_item.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-24 19:29:10", "docstatus": 0, - "modified": "2014-01-03 18:28:20", + "modified": "2014-01-15 16:00:44", "modified_by": "Administrator", "owner": "Administrator" }, @@ -336,7 +336,7 @@ }, { "default": ":Company", - "depends_on": "eval:sys_defaults.auto_accounting_for_stock", + "depends_on": "eval:cint(sys_defaults.auto_accounting_for_stock)", "doctype": "DocField", "fieldname": "cost_center", "fieldtype": "Link", diff --git a/stock/doctype/stock_entry_detail/stock_entry_detail.txt b/stock/doctype/stock_entry_detail/stock_entry_detail.txt index b97928b961..25835e0bf3 100644 --- a/stock/doctype/stock_entry_detail/stock_entry_detail.txt +++ b/stock/doctype/stock_entry_detail/stock_entry_detail.txt @@ -2,7 +2,7 @@ { "creation": "2013-03-29 18:22:12", "docstatus": 0, - "modified": "2013-11-08 16:15:44", + "modified": "2014-01-15 16:08:45", "modified_by": "Administrator", "owner": "Administrator" }, @@ -165,7 +165,7 @@ "read_only": 1 }, { - "depends_on": "eval:sys_defaults.auto_accounting_for_stock", + "depends_on": "eval:cint(sys_defaults.auto_accounting_for_stock)", "doctype": "DocField", "fieldname": "expense_account", "fieldtype": "Link", @@ -175,7 +175,7 @@ }, { "default": ":Company", - "depends_on": "eval:sys_defaults.auto_accounting_for_stock", + "depends_on": "eval:cint(sys_defaults.auto_accounting_for_stock)", "doctype": "DocField", "fieldname": "cost_center", "fieldtype": "Link", diff --git a/stock/doctype/stock_reconciliation/stock_reconciliation.txt b/stock/doctype/stock_reconciliation/stock_reconciliation.txt index c9959d36e3..7d5021c89e 100644 --- a/stock/doctype/stock_reconciliation/stock_reconciliation.txt +++ b/stock/doctype/stock_reconciliation/stock_reconciliation.txt @@ -2,7 +2,7 @@ { "creation": "2013-03-28 10:35:31", "docstatus": 0, - "modified": "2013-09-24 15:35:12", + "modified": "2014-01-15 15:45:07", "modified_by": "Administrator", "owner": "Administrator" }, @@ -102,7 +102,7 @@ "reqd": 1 }, { - "depends_on": "eval:sys_defaults.auto_accounting_for_stock", + "depends_on": "eval:cint(sys_defaults.auto_accounting_for_stock)", "doctype": "DocField", "fieldname": "expense_account", "fieldtype": "Link", @@ -110,6 +110,7 @@ "options": "Account" }, { + "depends_on": "eval:cint(sys_defaults.auto_accounting_for_stock)", "doctype": "DocField", "fieldname": "cost_center", "fieldtype": "Link", From 39eb7faeb9148cb667834cbdce00eab926ac2a25 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 15 Jan 2014 17:36:18 +0530 Subject: [PATCH 55/65] Update billing percentage and status from SI/PI in SO/PO, when net total is zero --- .../accounts_settings/accounts_settings.py | 8 +++- .../purchase_invoice/purchase_invoice.py | 3 +- .../doctype/sales_invoice/sales_invoice.py | 2 + controllers/status_updater.py | 37 +++++++++++++++++++ 4 files changed, 48 insertions(+), 2 deletions(-) diff --git a/accounts/doctype/accounts_settings/accounts_settings.py b/accounts/doctype/accounts_settings/accounts_settings.py index a6e993863d..2475fdaf66 100644 --- a/accounts/doctype/accounts_settings/accounts_settings.py +++ b/accounts/doctype/accounts_settings/accounts_settings.py @@ -6,6 +6,7 @@ from __future__ import unicode_literals import webnotes from webnotes import _ +from webnotes.utils import cint class DocType: def __init__(self, d, dl): @@ -14,7 +15,12 @@ class DocType: def on_update(self): webnotes.conn.set_default("auto_accounting_for_stock", self.doc.auto_accounting_for_stock) - if self.doc.auto_accounting_for_stock: + if cint(self.doc.auto_accounting_for_stock): + # set default perpetual account in company + for company in webnotes.conn.sql("select name from tabCompany"): + webnotes.bean("Company", company[0]).save() + + # Create account head for warehouses 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: diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.py b/accounts/doctype/purchase_invoice/purchase_invoice.py index 06b7a3ad2e..fcd6846507 100644 --- a/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -302,6 +302,7 @@ class DocType(BuyingController): self.make_gl_entries() self.update_against_document_in_jv() self.update_prevdoc_status() + self.update_billing_status_for_zero_amount_refdoc("Purchase Order") def make_gl_entries(self): auto_accounting_for_stock = \ @@ -421,7 +422,7 @@ class DocType(BuyingController): remove_against_link_from_jv(self.doc.doctype, self.doc.name, "against_voucher") self.update_prevdoc_status() - + self.update_billing_status_for_zero_amount_refdoc("Purchase Order") self.make_cancel_gl_entries() def on_update(self): diff --git a/accounts/doctype/sales_invoice/sales_invoice.py b/accounts/doctype/sales_invoice/sales_invoice.py index bfba30fa1b..a39702b3fc 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.py +++ b/accounts/doctype/sales_invoice/sales_invoice.py @@ -88,6 +88,7 @@ class DocType(SellingController): self.update_status_updater_args() self.update_prevdoc_status() + self.update_billing_status_for_zero_amount_refdoc("Sales Order") # this sequence because outstanding may get -ve self.make_gl_entries() @@ -114,6 +115,7 @@ class DocType(SellingController): self.update_status_updater_args() self.update_prevdoc_status() + self.update_billing_status_for_zero_amount_refdoc("Sales Order") self.make_cancel_gl_entries() diff --git a/controllers/status_updater.py b/controllers/status_updater.py index a285c4798d..1743887bf7 100644 --- a/controllers/status_updater.py +++ b/controllers/status_updater.py @@ -232,6 +232,43 @@ class StatusUpdater(DocListController): 'Fully %(keyword)s', 'Partly %(keyword)s')) where name='%(name)s'""" % args) + + def update_billing_status_for_zero_amount_refdoc(self, ref_dt): + ref_fieldname = ref_dt.lower().replace(" ", "_") + zero_amount_refdoc = [] + all_zero_amount_refdoc = webnotes.conn.sql_list("""select name from `tab%s` + where docstatus=1 and net_total = 0""" % ref_dt) + + for item in self.doclist.get({"parentfield": "entries"}): + if item.fields.get(ref_fieldname) \ + and item.fields.get(ref_fieldname) in all_zero_amount_refdoc \ + and item.fields.get(ref_fieldname) not in zero_amount_refdoc: + zero_amount_refdoc.append(item.fields[ref_fieldname]) + + if zero_amount_refdoc: + self.update_biling_status(zero_amount_refdoc, ref_dt, ref_fieldname) + + def update_biling_status(self, zero_amount_refdoc, ref_dt, ref_fieldname): + for ref_dn in zero_amount_refdoc: + ref_doc_qty = flt(webnotes.conn.sql("""select sum(ifnull(qty, 0)) from `tab%s Item` + where parent=%s""" % (ref_dt, '%s'), (ref_dn))[0][0]) + + billed_qty = flt(webnotes.conn.sql("""select sum(ifnull(qty, 0)) + from `tab%s Item` where %s=%s and docstatus=1""" % + (self.doc.doctype, ref_fieldname, '%s'), (ref_dn))[0][0]) + + per_billed = ((ref_doc_qty if billed_qty > ref_doc_qty else billed_qty)\ + / ref_doc_qty)*100 + webnotes.conn.set_value(ref_dt, ref_dn, "per_billed", per_billed) + + from webnotes.model.meta import has_field + if has_field(ref_dt, "billing_status"): + if per_billed < 0.001: billing_status = "Not Billed" + elif per_billed >= 99.99: billing_status = "Fully Billed" + else: billing_status = "Partly Billed" + + webnotes.conn.set_value(ref_dt, ref_dn, "billing_status", billing_status) + def get_tolerance_for(item_code, item_tolerance={}, global_tolerance=None): """ Returns the tolerance for the item, if not set, returns global tolerance From 5cdb8cea135f2df03e8a662fe37be28cc5735794 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 16 Jan 2014 12:08:12 +0530 Subject: [PATCH 56/65] Reset filters in Item Price report on each route --- stock/doctype/item/item.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/stock/doctype/item/item.js b/stock/doctype/item/item.js index c9aa75e7b7..e18a0f2809 100644 --- a/stock/doctype/item/item.js +++ b/stock/doctype/item/item.js @@ -29,10 +29,7 @@ cur_frm.cscript.make_dashboard = function() { cur_frm.cscript.edit_prices_button = function() { cur_frm.add_custom_button("Add / Edit Prices", function() { - wn.route_options = { - "item_code": cur_frm.doc.name - }; - wn.set_route("Report", "Item Price"); + wn.set_route("Report", "Item Price", {"item_code": cur_frm.doc.name}); }, "icon-money"); } From e31a97f3558479d6b6a989e1d716e21351c62547 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 16 Jan 2014 14:24:32 +0530 Subject: [PATCH 57/65] Calculate taxes and charges total in server side --- .../purchase_common/purchase_common.js | 30 +++++++++++-------- controllers/buying_controller.py | 22 ++++++++++++-- controllers/selling_controller.py | 3 +- 3 files changed, 40 insertions(+), 15 deletions(-) diff --git a/buying/doctype/purchase_common/purchase_common.js b/buying/doctype/purchase_common/purchase_common.js index 14b8279245..e3957ab847 100644 --- a/buying/doctype/purchase_common/purchase_common.js +++ b/buying/doctype/purchase_common/purchase_common.js @@ -302,11 +302,11 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({ calculate_totals: function() { var tax_count = this.frm.tax_doclist.length; - this.frm.doc.grand_total = flt( - tax_count ? this.frm.tax_doclist[tax_count - 1].total : this.frm.doc.net_total, + this.frm.doc.grand_total = flt(tax_count ? + this.frm.tax_doclist[tax_count - 1].total : this.frm.doc.net_total, precision("grand_total")); - this.frm.doc.grand_total_import = flt(this.frm.doc.grand_total / this.frm.doc.conversion_rate, - precision("grand_total_import")); + this.frm.doc.grand_total_import = flt(this.frm.doc.grand_total / + this.frm.doc.conversion_rate, precision("grand_total_import")); this.frm.doc.total_tax = flt(this.frm.doc.grand_total - this.frm.doc.net_total, precision("total_tax")); @@ -321,20 +321,26 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({ } // other charges added/deducted + this.frm.doc.other_charges_added = 0.0 + this.frm.doc.other_charges_deducted = 0.0 if(tax_count) { this.frm.doc.other_charges_added = wn.utils.sum($.map(this.frm.tax_doclist, - function(tax) { return (tax.add_deduct_tax == "Add" && in_list(["Valuation and Total", "Total"], tax.category)) ? tax.tax_amount : 0.0; })); + function(tax) { return (tax.add_deduct_tax == "Add" + && in_list(["Valuation and Total", "Total"], tax.category)) ? + tax.tax_amount : 0.0; })); this.frm.doc.other_charges_deducted = wn.utils.sum($.map(this.frm.tax_doclist, - function(tax) { return (tax.add_deduct_tax == "Deduct" && in_list(["Valuation and Total", "Total"], tax.category)) ? tax.tax_amount : 0.0; })); + function(tax) { return (tax.add_deduct_tax == "Deduct" + && in_list(["Valuation and Total", "Total"], tax.category)) ? + tax.tax_amount : 0.0; })); - wn.model.round_floats_in(this.frm.doc, ["other_charges_added", "other_charges_deducted"]); - - this.frm.doc.other_charges_added_import = flt(this.frm.doc.other_charges_added / this.frm.doc.conversion_rate, - precision("other_charges_added_import")); - this.frm.doc.other_charges_deducted_import = flt(this.frm.doc.other_charges_deducted / this.frm.doc.conversion_rate, - precision("other_charges_deducted_import")); + wn.model.round_floats_in(this.frm.doc, + ["other_charges_added", "other_charges_deducted"]); } + this.frm.doc.other_charges_added_import = flt(this.frm.doc.other_charges_added / + this.frm.doc.conversion_rate, precision("other_charges_added_import")); + this.frm.doc.other_charges_deducted_import = flt(this.frm.doc.other_charges_deducted / + this.frm.doc.conversion_rate, precision("other_charges_deducted_import")); }, _cleanup: function() { diff --git a/controllers/buying_controller.py b/controllers/buying_controller.py index 7954ca0abb..bdc7327c5f 100644 --- a/controllers/buying_controller.py +++ b/controllers/buying_controller.py @@ -124,8 +124,8 @@ class BuyingController(StockController): self.round_floats_in(self.doc, ["net_total", "net_total_import"]) def calculate_totals(self): - self.doc.grand_total = flt(self.tax_doclist and \ - self.tax_doclist[-1].total or self.doc.net_total, self.precision("grand_total")) + self.doc.grand_total = flt(self.tax_doclist[-1].total if self.tax_doclist + else self.doc.net_total, self.precision("grand_total")) self.doc.grand_total_import = flt(self.doc.grand_total / self.doc.conversion_rate, self.precision("grand_total_import")) @@ -137,6 +137,24 @@ class BuyingController(StockController): if self.meta.get_field("rounded_total_import"): self.doc.rounded_total_import = _round(self.doc.grand_total_import) + + if self.meta.get_field("other_charges_added"): + self.doc.other_charges_added = flt(sum([flt(d.tax_amount) for d in self.tax_doclist + if d.add_deduct_tax=="Add" and d.category in ["Valuation and Total", "Total"]]), + self.precision("other_charges_added")) + + if self.meta.get_field("other_charges_deducted"): + self.doc.other_charges_deducted = flt(sum([flt(d.tax_amount) for d in self.tax_doclist + if d.add_deduct_tax=="Deduct" and d.category in ["Valuation and Total", "Total"]]), + self.precision("other_charges_deducted")) + + if self.meta.get_field("other_charges_added_import"): + self.doc.other_charges_added_import = flt(self.doc.other_charges_added / + self.doc.conversion_rate, self.precision("other_charges_added_import")) + + if self.meta.get_field("other_charges_deducted_import"): + self.doc.other_charges_deducted_import = flt(self.doc.other_charges_deducted / + self.doc.conversion_rate, self.precision("other_charges_deducted_import")) def calculate_outstanding_amount(self): if self.doc.doctype == "Purchase Invoice" and self.doc.docstatus < 2: diff --git a/controllers/selling_controller.py b/controllers/selling_controller.py index 67c1462662..4806c73a81 100644 --- a/controllers/selling_controller.py +++ b/controllers/selling_controller.py @@ -191,7 +191,8 @@ class SellingController(StockController): self.doc.other_charges_total = flt(self.doc.grand_total - self.doc.net_total, self.precision("other_charges_total")) - self.doc.other_charges_total_export = flt(self.doc.grand_total_export - self.doc.net_total_export, + self.doc.other_charges_total_export = flt( + self.doc.grand_total_export - self.doc.net_total_export, self.precision("other_charges_total_export")) self.doc.rounded_total = _round(self.doc.grand_total) From 6933617538236c33f1ae2c103483b4161dc1dab3 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Thu, 16 Jan 2014 16:59:22 +0600 Subject: [PATCH 58/65] bumped to version 3.6.2 --- config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.json b/config.json index 45acaf2cd3..c2524671a0 100644 --- a/config.json +++ b/config.json @@ -1,6 +1,6 @@ { "app_name": "ERPNext", - "app_version": "3.6.1", + "app_version": "3.6.2", "base_template": "app/portal/templates/base.html", "modules": { "Accounts": { @@ -74,5 +74,5 @@ "type": "module" } }, - "requires_framework_version": "==3.7.1" + "requires_framework_version": "==3.7.2" } \ No newline at end of file From f6b77479d75318ee2cfe17c68d63a40ac14e6160 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 16 Jan 2014 18:18:49 +0530 Subject: [PATCH 59/65] Patch: Update billing status for zero value order --- hr/doctype/salary_manager/salary_manager.js | 2 +- ...ate_billing_status_for_zero_value_order.py | 29 +++++++++++++++++++ patches/patch_list.py | 1 + 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 patches/1401/update_billing_status_for_zero_value_order.py diff --git a/hr/doctype/salary_manager/salary_manager.js b/hr/doctype/salary_manager/salary_manager.js index 032c29e509..ec485ca671 100644 --- a/hr/doctype/salary_manager/salary_manager.js +++ b/hr/doctype/salary_manager/salary_manager.js @@ -43,7 +43,7 @@ cur_frm.cscript.make_jv = function(doc, dt, dn) { jv = locals['Journal Voucher'][jv]; jv.voucher_type = 'Bank Voucher'; jv.user_remark = wn._('Payment of salary for the month: ') + doc.month + - wn._('and fiscal year: ') + doc.fiscal_year; + wn._(' and fiscal year: ') + doc.fiscal_year; jv.fiscal_year = doc.fiscal_year; jv.company = doc.company; jv.posting_date = dateutil.obj_to_str(new Date()); diff --git a/patches/1401/update_billing_status_for_zero_value_order.py b/patches/1401/update_billing_status_for_zero_value_order.py new file mode 100644 index 0000000000..afeed55ed4 --- /dev/null +++ b/patches/1401/update_billing_status_for_zero_value_order.py @@ -0,0 +1,29 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +import webnotes +from webnotes.utils import flt + +def execute(): + for order_type in ["Sales", "Purchase"]: + for d in webnotes.conn.sql("""select par.name, sum(ifnull(child.qty, 0)) as total_qty + from `tab%s Order` par, `tab%s Order Item` child + where par.name = child.parent and par.docstatus = 1 + and ifnull(par.net_total, 0) = 0 group by par.name""" % + (order_type, order_type), as_dict=1): + + billed_qty = flt(webnotes.conn.sql("""select sum(ifnull(qty, 0)) + from `tab%s Invoice Item` where %s=%s and docstatus=1""" % + (order_type, "sales_order" if order_type=="Sales" else "purchase_order", '%s'), + (d.name))[0][0]) + + per_billed = ((d.total_qty if billed_qty > d.total_qty else billed_qty)\ + / d.total_qty)*100 + webnotes.conn.set_value(order_type+ " Order", d.name, "per_billed", per_billed) + + if order_type == "Sales": + if per_billed < 0.001: billing_status = "Not Billed" + elif per_billed >= 99.99: billing_status = "Fully Billed" + else: billing_status = "Partly Billed" + + webnotes.conn.set_value("Sales Order", d.name, "billing_status", billing_status) \ No newline at end of file diff --git a/patches/patch_list.py b/patches/patch_list.py index 04a9288c60..2598ae8c94 100644 --- a/patches/patch_list.py +++ b/patches/patch_list.py @@ -265,4 +265,5 @@ patch_list = [ "patches.1312.p02_update_item_details_in_item_price", "patches.1401.p01_move_related_property_setters_to_custom_field", "patches.1401.p01_make_buying_selling_as_check_box_in_price_list", + "patches.1401.update_billing_status_for_zero_value_order", ] \ No newline at end of file From e1e63a91d6f4571621cf519ce9c337085b216f3a Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Fri, 17 Jan 2014 11:12:20 +0530 Subject: [PATCH 60/65] Allow renaming of campaign --- accounts/doctype/sales_invoice/sales_invoice.txt | 4 ++-- selling/doctype/campaign/campaign.js | 13 +------------ selling/doctype/campaign/campaign.txt | 3 ++- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/accounts/doctype/sales_invoice/sales_invoice.txt b/accounts/doctype/sales_invoice/sales_invoice.txt index 99bfe5cdf0..0433f31ad6 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.txt +++ b/accounts/doctype/sales_invoice/sales_invoice.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-24 19:29:05", "docstatus": 0, - "modified": "2013-11-18 15:16:50", + "modified": "2014-01-16 15:36:16", "modified_by": "Administrator", "owner": "Administrator" }, @@ -1091,7 +1091,7 @@ "fieldtype": "Select", "label": "Recurring Type", "no_copy": 1, - "options": "Monthly\nQuarterly\nHalf-yearly\nYearly", + "options": "\nMonthly\nQuarterly\nHalf-yearly\nYearly", "print_hide": 1, "read_only": 0 }, diff --git a/selling/doctype/campaign/campaign.js b/selling/doctype/campaign/campaign.js index 6271a163cb..33479579a5 100644 --- a/selling/doctype/campaign/campaign.js +++ b/selling/doctype/campaign/campaign.js @@ -1,13 +1,2 @@ // Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -// License: GNU General Public License v3. See license.txt - - - -//--------- ONLOAD ------------- -cur_frm.cscript.onload = function(doc, cdt, cdn) { - -} - -cur_frm.cscript.refresh = function(doc, cdt, cdn) { - -} \ No newline at end of file +// License: GNU General Public License v3. See license.txt \ No newline at end of file diff --git a/selling/doctype/campaign/campaign.txt b/selling/doctype/campaign/campaign.txt index 7025bf5654..7170e051d6 100644 --- a/selling/doctype/campaign/campaign.txt +++ b/selling/doctype/campaign/campaign.txt @@ -2,11 +2,12 @@ { "creation": "2013-01-10 16:34:18", "docstatus": 0, - "modified": "2013-07-05 14:29:57", + "modified": "2014-01-16 12:52:19", "modified_by": "Administrator", "owner": "Administrator" }, { + "allow_rename": 1, "autoname": "field:campaign_name", "description": "Keep Track of Sales Campaigns. Keep track of Leads, Quotations, Sales Order etc from Campaigns to gauge Return on Investment. ", "doctype": "DocType", From f32314dd0b2fbbe0d183f77ad8ac5af4ef42a223 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 17 Jan 2014 11:53:25 +0530 Subject: [PATCH 61/65] Do not set income/expense account automatically in company master --- setup/doctype/company/company.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/setup/doctype/company/company.py b/setup/doctype/company/company.py index 88d9dcaaa5..34e5ca4a59 100644 --- a/setup/doctype/company/company.py +++ b/setup/doctype/company/company.py @@ -244,8 +244,6 @@ class DocType: webnotes.conn.set(self.doc, a, account_name) _set_default_accounts({ - "default_income_account": "Sales", - "default_expense_account": "Cost of Goods Sold", "receivables_group": "Accounts Receivable", "payables_group": "Accounts Payable", "default_cash_account": "Cash" @@ -257,8 +255,6 @@ class DocType: "stock_adjustment_account": "Stock Adjustment", "expenses_included_in_valuation": "Expenses Included In Valuation" }) - - def create_default_cost_center(self): cc_list = [ From bc99c9d6e0d7871decb8b092c94bad70db520e67 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 17 Jan 2014 12:04:24 +0530 Subject: [PATCH 62/65] Priority to user's deafult price list over customer's default price list --- utilities/transaction_base.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/utilities/transaction_base.py b/utilities/transaction_base.py index f783faa9ec..6c515a52b6 100644 --- a/utilities/transaction_base.py +++ b/utilities/transaction_base.py @@ -78,8 +78,9 @@ class TransactionBase(StatusUpdater): 3. Clears existing Sales Team and fetches the one mentioned in Customer """ customer_defaults = self.get_customer_defaults() - - customer_defaults["selling_price_list"] = self.get_user_default_price_list("Selling") or \ + + customer_defaults["selling_price_list"] = \ + self.get_user_default_price_list("selling_price_list") or \ customer_defaults.get("price_list") or \ webnotes.conn.get_value("Customer Group", self.doc.customer_group, "default_price_list") or self.doc.selling_price_list @@ -91,11 +92,11 @@ class TransactionBase(StatusUpdater): if self.meta.get_field("sales_team") and self.doc.customer: self.set_sales_team_for_customer() - def get_user_default_price_list(self, price_list_for): - from webnotes.defaults import get_user_default_as_list - user_default_price_list = get_user_default_as_list("selling_price_list" - if price_list_for=="Selling" else "buying_price_list") - return user_default_price_list[0] if len(user_default_price_list)==1 else "" + def get_user_default_price_list(self, price_list): + from webnotes.defaults import get_defaults_for + user_default_price_list = get_defaults_for(webnotes.session.user).get(price_list) + return cstr(user_default_price_list) \ + if not isinstance(user_default_price_list, list) else "" def set_sales_team_for_customer(self): from webnotes.model import default_fields @@ -128,7 +129,7 @@ class TransactionBase(StatusUpdater): if supplier.default_currency: out["currency"] = supplier.default_currency - out["buying_price_list"] = self.get_user_default_price_list("Buying") or \ + out["buying_price_list"] = self.get_user_default_price_list("buying_price_list") or \ supplier.default_price_list or self.doc.buying_price_list return out From da08124df2d7cc1ba7ce47ede4b8b988ce3b7f77 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Fri, 17 Jan 2014 15:27:19 +0530 Subject: [PATCH 63/65] remove mysql-python pinning to 1.2.4 --- install_erpnext.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install_erpnext.py b/install_erpnext.py index e285d4bbfe..8e1448362b 100644 --- a/install_erpnext.py +++ b/install_erpnext.py @@ -20,7 +20,7 @@ requirements = [ "jinja2", "markdown2", "markupsafe", - "mysql-python==1.2.4", + "mysql-python", "pygeoip", "python-dateutil", "python-memcached", From 96db41d996472f7f40a8267171dd01cf51de0d44 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Fri, 17 Jan 2014 17:26:31 +0600 Subject: [PATCH 64/65] bumped to version 3.6.3 --- config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.json b/config.json index c2524671a0..450e2bca6d 100644 --- a/config.json +++ b/config.json @@ -1,6 +1,6 @@ { "app_name": "ERPNext", - "app_version": "3.6.2", + "app_version": "3.6.3", "base_template": "app/portal/templates/base.html", "modules": { "Accounts": { @@ -74,5 +74,5 @@ "type": "module" } }, - "requires_framework_version": "==3.7.2" + "requires_framework_version": "==3.7.3" } \ No newline at end of file From ed87335513986af2ba6766e331906078c830a9bd Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Fri, 17 Jan 2014 18:57:21 +0530 Subject: [PATCH 65/65] decimal places fix in item prices report --- stock/report/item_prices/item_prices.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stock/report/item_prices/item_prices.py b/stock/report/item_prices/item_prices.py index e744cc73e4..5eee7df42d 100644 --- a/stock/report/item_prices/item_prices.py +++ b/stock/report/item_prices/item_prices.py @@ -15,7 +15,7 @@ def execute(filters=None): bom_rate = get_item_bom_rate() val_rate_map = get_valuation_rate() - precision = get_currency_precision or 2 + precision = get_currency_precision() or 2 data = [] for item in sorted(item_map):
    ItemQtyItemQtyRate
    %(item_code)s%(item_name)s\ +
    \ + \ +
    \ +
    \ +
    \ + \ +
    \ +
    %(amount)s
    %(rate)s