From d42c3e0f484d71b834b98bc9e829d02bd6e5056e Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 15 Nov 2013 23:38:09 +0530 Subject: [PATCH 01/10] [fix] [minor] fixes in patch --- patches/october_2013/p01_fix_serial_no_status.py | 1 - 1 file changed, 1 deletion(-) diff --git a/patches/october_2013/p01_fix_serial_no_status.py b/patches/october_2013/p01_fix_serial_no_status.py index 9f58593c26..e7bf52abc8 100644 --- a/patches/october_2013/p01_fix_serial_no_status.py +++ b/patches/october_2013/p01_fix_serial_no_status.py @@ -11,7 +11,6 @@ def execute(): try: sr_bean = webnotes.bean("Serial No", sr[0]) sr_bean.make_controller().via_stock_ledger = True - sr_bean.run_method("validate") sr_bean.save() webnotes.conn.commit() except: From 0b3a8477b0db13f660a544b455c34bcb276d5dab Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Mon, 18 Nov 2013 11:21:04 +0530 Subject: [PATCH 02/10] [fix] [minor] stock related report fixed --- public/js/stock_grid_report.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/public/js/stock_grid_report.js b/public/js/stock_grid_report.js index e87228fde7..2cd38c0971 100644 --- a/public/js/stock_grid_report.js +++ b/public/js/stock_grid_report.js @@ -112,9 +112,11 @@ erpnext.StockGridReport = wn.views.TreeGridReport.extend({ get_serialized_buying_rates: function() { var serialized_buying_rates = {}; - $.each(wn.report_dump.data["Serial No"], function(i, sn) { - serialized_buying_rates[sn.name.toLowerCase()] = flt(sn.incoming_rate); - }); + if (wn.report_dump.data["Serial No"]) { + $.each(wn.report_dump.data["Serial No"], function(i, sn) { + serialized_buying_rates[sn.name.toLowerCase()] = flt(sn.incoming_rate); + }); + } return serialized_buying_rates; }, From 6ca0548231f4c813d7d46b9ed10ec2181fd0ce4d Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Mon, 18 Nov 2013 12:16:48 +0530 Subject: [PATCH 03/10] [fix] [minor] stock related reports fixed for serialized item --- public/js/stock_analytics.js | 2 +- public/js/stock_grid_report.js | 12 +++++------- stock/page/stock_ageing/stock_ageing.js | 4 ++-- stock/page/stock_ledger/stock_ledger.js | 2 +- stock/page/stock_level/stock_level.js | 2 +- 5 files changed, 10 insertions(+), 12 deletions(-) diff --git a/public/js/stock_analytics.js b/public/js/stock_analytics.js index 5b58113046..f704a86b25 100644 --- a/public/js/stock_analytics.js +++ b/public/js/stock_analytics.js @@ -11,7 +11,7 @@ erpnext.StockAnalytics = erpnext.StockGridReport.extend({ parent: $(wrapper).find('.layout-main'), appframe: wrapper.appframe, doctypes: ["Item", "Item Group", "Warehouse", "Stock Ledger Entry", "Brand", - "Fiscal Year"], + "Fiscal Year", "Serial No"], tree_grid: { show: true, parent_field: "parent_item_group", diff --git a/public/js/stock_grid_report.js b/public/js/stock_grid_report.js index 2cd38c0971..bfe364bfab 100644 --- a/public/js/stock_grid_report.js +++ b/public/js/stock_grid_report.js @@ -14,7 +14,7 @@ erpnext.StockGridReport = wn.views.TreeGridReport.extend({ // value if(sl.qty > 0) { // incoming - rate is given - var rate = sl.incoming_rate; + var rate = sl.incoming_rate; var add_qty = sl.qty; if(wh.balance_qty < 0) { // negative valuation @@ -34,11 +34,14 @@ erpnext.StockGridReport = wn.views.TreeGridReport.extend({ if(add_qty) wh.fifo_stack.push([add_qty, sl.incoming_rate, sl.posting_date]); } else { + // called everytime for maintaining fifo stack + var fifo_value_diff = this.get_fifo_value_diff(wh, sl); + // outgoing if(sl.serial_no) { var value_diff = -1 * this.get_serialized_value_diff(sl); } else if(is_fifo) { - var value_diff = this.get_fifo_value_diff(wh, sl); + var value_diff = fifo_value_diff; } else { // average rate for weighted average var rate = (wh.balance_qty.toFixed(2) == 0.00 ? 0 : @@ -84,11 +87,6 @@ erpnext.StockGridReport = wn.views.TreeGridReport.extend({ qty = qty - batch[0]; } } - if(qty) { - // msgprint("Negative values not allowed for FIFO valuation!\ - // Item " + sl.item_code.bold() + " on " + dateutil.str_to_user(sl.posting_datetime).bold() + - // " becomes negative. Values computed will not be accurate."); - } // reset the updated stack wh.fifo_stack = fifo_stack.reverse(); diff --git a/stock/page/stock_ageing/stock_ageing.js b/stock/page/stock_ageing/stock_ageing.js index 920ac848d0..a83573ed8d 100644 --- a/stock/page/stock_ageing/stock_ageing.js +++ b/stock/page/stock_ageing/stock_ageing.js @@ -25,7 +25,7 @@ erpnext.StockAgeing = erpnext.StockGridReport.extend({ page: wrapper, parent: $(wrapper).find('.layout-main'), appframe: wrapper.appframe, - doctypes: ["Item", "Warehouse", "Stock Ledger Entry", "Item Group", "Brand"], + doctypes: ["Item", "Warehouse", "Stock Ledger Entry", "Item Group", "Brand", "Serial No"], }) }, setup_columns: function() { @@ -175,7 +175,7 @@ erpnext.StockAgeing = erpnext.StockGridReport.extend({ grid: { hoverable: true, clickable: true }, xaxis: { ticks: $.map(me.data, function(item, idx) { return [[idx+1, item.name]] }), - max: 20 + max: 15 }, series: { downsample: { threshold: 1000 } } } diff --git a/stock/page/stock_ledger/stock_ledger.js b/stock/page/stock_ledger/stock_ledger.js index c83fc0ec12..0aa8a1fe6a 100644 --- a/stock/page/stock_ledger/stock_ledger.js +++ b/stock/page/stock_ledger/stock_ledger.js @@ -21,7 +21,7 @@ erpnext.StockLedger = erpnext.StockGridReport.extend({ page: wrapper, parent: $(wrapper).find('.layout-main'), appframe: wrapper.appframe, - doctypes: ["Item", "Item Group", "Warehouse", "Stock Ledger Entry", "Brand"], + doctypes: ["Item", "Item Group", "Warehouse", "Stock Ledger Entry", "Brand", "Serial No"], }) }, diff --git a/stock/page/stock_level/stock_level.js b/stock/page/stock_level/stock_level.js index df7c8c5d4d..62ae6c75ae 100644 --- a/stock/page/stock_level/stock_level.js +++ b/stock/page/stock_level/stock_level.js @@ -27,7 +27,7 @@ erpnext.StockLevel = erpnext.StockGridReport.extend({ parent: $(wrapper).find('.layout-main'), appframe: wrapper.appframe, doctypes: ["Item", "Warehouse", "Stock Ledger Entry", "Production Order", - "Material Request Item", "Purchase Order Item", "Sales Order Item", "Brand"], + "Material Request Item", "Purchase Order Item", "Sales Order Item", "Brand", "Serial No"], }); this.wrapper.bind("make", function() { From 48bd4a1deddaeb3d6faf7af8a3de49c82488eb38 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 18 Nov 2013 12:42:55 +0530 Subject: [PATCH 04/10] [fix] [minor] stock value difference rounding issue --- controllers/stock_controller.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/controllers/stock_controller.py b/controllers/stock_controller.py index e07e752c7e..229c035a34 100644 --- a/controllers/stock_controller.py +++ b/controllers/stock_controller.py @@ -48,7 +48,7 @@ class StockController(AccountsController): "against": detail.expense_account, "cost_center": detail.cost_center, "remarks": self.doc.remarks or "Accounting Entry for Stock", - "debit": sle.stock_value_difference + "debit": flt(sle.stock_value_difference, 2) })) # to target warehouse / expense account @@ -57,7 +57,7 @@ class StockController(AccountsController): "against": warehouse_account[sle.warehouse], "cost_center": detail.cost_center, "remarks": self.doc.remarks or "Accounting Entry for Stock", - "credit": sle.stock_value_difference + "credit": flt(sle.stock_value_difference, 2) })) elif sle.warehouse not in warehouse_with_no_account: warehouse_with_no_account.append(sle.warehouse) From 510a73a0de26db8eb8c10e2b6ed61010a16ae323 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Mon, 18 Nov 2013 15:29:36 +0530 Subject: [PATCH 05/10] [fix] [minor] product search box fixed --- stock/doctype/item/templates/includes/product_search_box.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stock/doctype/item/templates/includes/product_search_box.html b/stock/doctype/item/templates/includes/product_search_box.html index b4fa3e8783..55e6377781 100644 --- a/stock/doctype/item/templates/includes/product_search_box.html +++ b/stock/doctype/item/templates/includes/product_search_box.html @@ -22,7 +22,7 @@ return false; }); $("#product-search").keypress(function(e) { - if(e.which==13) $("#product-search-btn").click(); + if(e.which==13) $("#btn-product-search").click(); }) }) From ca471f41a132b081d06a9cb08bad34dff6974b77 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 20 Nov 2013 13:14:12 +0530 Subject: [PATCH 06/10] [fix] Rename and merge rewrite --- accounts/doctype/account/account.py | 35 ++++---- accounts/doctype/cost_center/cost_center.py | 32 +++---- buying/doctype/supplier/supplier.py | 20 ++--- buying/utils.py | 9 +- selling/doctype/customer/customer.py | 14 +-- setup/doctype/company/company.py | 32 ++++--- stock/doctype/item/item.py | 44 ++++++++-- stock/doctype/serial_no/serial_no.py | 11 +-- stock/doctype/warehouse/warehouse.js | 14 +-- stock/doctype/warehouse/warehouse.py | 96 +++++++++++---------- stock/doctype/warehouse/warehouse.txt | 49 +---------- utilities/repost_stock.py | 14 ++- 12 files changed, 180 insertions(+), 190 deletions(-) diff --git a/accounts/doctype/account/account.py b/accounts/doctype/account/account.py index 37e165a97b..f525b327d4 100644 --- a/accounts/doctype/account/account.py +++ b/accounts/doctype/account/account.py @@ -193,41 +193,40 @@ class DocType: if self.check_gle_exists(): msgprint("""Account with existing transaction (Sales Invoice / Purchase Invoice / \ - Journal Voucher) can not be trashed""", raise_exception=1) + Journal Voucher) can not be deleted""", raise_exception=1) if self.check_if_child_exists(): - msgprint("Child account exists for this account. You can not trash this account.", + msgprint("Child account exists for this account. You can not delete this account.", raise_exception=1) def on_trash(self): self.validate_trash() self.update_nsm_model() - - def on_rename(self, new, old, merge=False): - company_abbr = webnotes.conn.get_value("Company", self.doc.company, "abbr") - parts = new.split(" - ") - - if parts[-1].lower() != company_abbr.lower(): - parts.append(company_abbr) - # rename account name - new_account_name = " - ".join(parts[:-1]) - sql("update `tabAccount` set account_name = %s where name = %s", (new_account_name, old)) + def before_rename(self, old, new, merge=False): + # Add company abbr if not provided + from setup.doctype.company.company import get_name_with_abbr + new_account = get_name_with_abbr(new, self.doc.company) + # Validate properties before merging if merge: - new_name = " - ".join(parts) - val = list(webnotes.conn.get_value("Account", new_name, + val = list(webnotes.conn.get_value("Account", new_account, ["group_or_ledger", "debit_or_credit", "is_pl_account"])) if val != [self.doc.group_or_ledger, self.doc.debit_or_credit, self.doc.is_pl_account]: - msgprint(_("""Merging is only possible if following \ + webnotes.throw(_("""Merging is only possible if following \ properties are same in both records. - Group or Ledger, Debit or Credit, Is PL Account"""), raise_exception=1) + Group or Ledger, Debit or Credit, Is PL Account""")) + + return new_account + def after_rename(self, old, new, merge=False): + if not merge: + webnotes.conn.set_value("Account", new, "account_name", + " - ".join(new.split(" - ")[:-1])) + else: from webnotes.utils.nestedset import rebuild_tree rebuild_tree("Account", "parent_account") - return " - ".join(parts) - def get_master_name(doctype, txt, searchfield, start, page_len, filters): conditions = (" and company='%s'"% filters["company"]) if doctype == "Warehouse" else "" diff --git a/accounts/doctype/cost_center/cost_center.py b/accounts/doctype/cost_center/cost_center.py index 4b18aae4e8..d89cef0cfd 100644 --- a/accounts/doctype/cost_center/cost_center.py +++ b/accounts/doctype/cost_center/cost_center.py @@ -16,7 +16,7 @@ class DocType(DocTypeNestedSet): def autoname(self): company_abbr = webnotes.conn.sql("select abbr from tabCompany where name=%s", self.doc.company)[0][0] - self.doc.name = self.doc.cost_center_name.strip() + ' - ' + company_abbr + self.doc.name = self.doc.cost_center_name.strip() + ' - ' + company_abbr def validate_mandatory(self): if not self.doc.group_or_ledger: @@ -73,18 +73,20 @@ class DocType(DocTypeNestedSet): self.validate_mandatory() self.validate_budget_details() - def on_rename(self, new, old, merge=False): - company_abbr = webnotes.conn.get_value("Company", self.doc.company, "abbr") - parts = new.split(" - ") - - if parts[-1].lower() != company_abbr.lower(): - parts.append(company_abbr) - - # rename account name - cost_center_name = " - ".join(parts[:-1]) - webnotes.conn.sql("update `tabCost Center` set cost_center_name = %s where name = %s", \ - (cost_center_name, old)) + def before_rename(self, olddn, newdn, merge=False): + # Add company abbr if not provided + from setup.doctype.company.company import get_name_with_abbr + new_cost_center = get_name_with_abbr(newdn, self.doc.company) + + # Validate properties before merging + super(DocType, self).before_rename(olddn, new_cost_center, merge, "group_or_ledger") + + return new_cost_center + + def after_rename(self, olddn, newdn, merge=False): + if not merge: + webnotes.conn.set_value("Cost Center", newdn, "cost_center_name", + " - ".join(newdn.split(" - ")[:-1])) + else: + super(DocType, self).after_rename(olddn, newdn, merge) - super(DocType, self).on_rename(new, old, merge, "group_or_ledger") - - return " - ".join(parts) diff --git a/buying/doctype/supplier/supplier.py b/buying/doctype/supplier/supplier.py index 15e1d625f9..afad61aeba 100644 --- a/buying/doctype/supplier/supplier.py +++ b/buying/doctype/supplier/supplier.py @@ -149,29 +149,21 @@ class DocType(TransactionBase): self.delete_supplier_contact() self.delete_supplier_account() - def on_rename(self, new, old, merge=False): + def after_rename(self, old, new, merge=False): #update supplier_name if not naming series if webnotes.defaults.get_global_default('supp_master_name') == 'Supplier Name': - update_fields = [ - ('Supplier', 'name'), - ('Address', 'supplier'), - ('Contact', 'supplier'), - ('Purchase Invoice', 'supplier'), - ('Purchase Order', 'supplier'), - ('Purchase Receipt', 'supplier'), - ('Serial No', 'supplier')] - for rec in update_fields: - sql("update `tab%s` set supplier_name = %s where `%s` = %s" % \ - (rec[0], '%s', rec[1], '%s'), (new, old)) + webnotes.conn.set(self.doc, "supplier_name", new) for account in webnotes.conn.sql("""select name, account_name from tabAccount where master_name=%s and master_type='Supplier'""", old, as_dict=1): if account.account_name != new: - webnotes.rename_doc("Account", account.name, new, merge=merge) + merge_account = True if merge and webnotes.conn.get_value("Account", + {"master_name": new, "master_type": "Supplier"}) else False + webnotes.rename_doc("Account", account.name, new, merge=merge_account) #update master_name in doctype account webnotes.conn.sql("""update `tabAccount` set master_name = %s, - master_type = 'Supplier' where master_name = %s""" , (new,old)) + master_type = 'Supplier' where master_name = %s""" , (new, old)) @webnotes.whitelist() def get_dashboard_info(supplier): diff --git a/buying/utils.py b/buying/utils.py index 385a8c7b51..85cb8566f7 100644 --- a/buying/utils.py +++ b/buying/utils.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import webnotes from webnotes import msgprint, _ -from webnotes.utils import getdate, flt, add_days +from webnotes.utils import getdate, flt, add_days, cstr import json @webnotes.whitelist() @@ -94,7 +94,6 @@ def _get_price_list_rate(args, item_bean, meta): (args.buying_price_list, args.item_code), as_dict=1) if price_list_rate: - from utilities.transaction_base import validate_currency validate_currency(args, item_bean.doc, meta) out.import_ref_rate = flt(price_list_rate[0].ref_rate) * \ @@ -132,7 +131,7 @@ def _validate_item_details(args, item): _("Please select a sub-contracted item or do not sub-contract the transaction."), raise_exception=True) -def get_last_purchase_details(item_code, doc_name, conversion_rate=1.0): +def get_last_purchase_details(item_code, doc_name=None, conversion_rate=1.0): """returns last purchase details in stock uom""" # get last purchase order item details last_purchase_order = webnotes.conn.sql("""\ @@ -143,7 +142,7 @@ def get_last_purchase_details(item_code, doc_name, conversion_rate=1.0): where po.docstatus = 1 and po_item.item_code = %s and po.name != %s and po.name = po_item.parent order by po.transaction_date desc, po.name desc - limit 1""", (item_code, doc_name), as_dict=1) + limit 1""", (item_code, cstr(doc_name)), as_dict=1) # get last purchase receipt item details last_purchase_receipt = webnotes.conn.sql("""\ @@ -154,7 +153,7 @@ def get_last_purchase_details(item_code, doc_name, conversion_rate=1.0): where pr.docstatus = 1 and pr_item.item_code = %s and pr.name != %s and pr.name = pr_item.parent order by pr.posting_date desc, pr.posting_time desc, pr.name desc - limit 1""", (item_code, doc_name), as_dict=1) + limit 1""", (item_code, cstr(doc_name)), as_dict=1) purchase_order_date = getdate(last_purchase_order and last_purchase_order[0].transaction_date \ or "1900-01-01") diff --git a/selling/doctype/customer/customer.py b/selling/doctype/customer/customer.py index 2b57da972c..206e28d274 100644 --- a/selling/doctype/customer/customer.py +++ b/selling/doctype/customer/customer.py @@ -4,7 +4,6 @@ from __future__ import unicode_literals import webnotes -from webnotes.utils import cstr from webnotes.model.doc import Document, make_autoname from webnotes import msgprint, _ import webnotes.defaults @@ -145,20 +144,21 @@ class DocType(TransactionBase): if self.doc.lead_name: sql("update `tabLead` set status='Interested' where name=%s",self.doc.lead_name) - def on_rename(self, new, old, merge=False): + def after_rename(self, old, new, merge=False): #update customer_name if not naming series if webnotes.defaults.get_global_default('cust_master_name') == 'Customer Name': - webnotes.conn.sql("""update `tabCustomer` set customer_name = %s where name = %s""", - (new, old)) + webnotes.conn.set(self.doc, "customer_name", new) for account in webnotes.conn.sql("""select name, account_name from tabAccount where master_name=%s and master_type='Customer'""", old, as_dict=1): if account.account_name != new: - webnotes.rename_doc("Account", account.name, new, merge=merge) + merge_account = True if merge and webnotes.conn.get_value("Account", + {"master_name": new, "master_type": "Customer"}) else False + webnotes.rename_doc("Account", account.name, new, merge=merge_account) - #update master_name in doctype account + #update master_name in account record webnotes.conn.sql("""update `tabAccount` set master_name = %s, - master_type = 'Customer' where master_name = %s""", (new,old)) + master_type = 'Customer' where master_name = %s""", (new, old)) @webnotes.whitelist() def get_dashboard_info(customer): diff --git a/setup/doctype/company/company.py b/setup/doctype/company/company.py index 7da231031e..d3f4b22803 100644 --- a/setup/doctype/company/company.py +++ b/setup/doctype/company/company.py @@ -303,18 +303,17 @@ class DocType: where doctype='Global Defaults' and field='default_company' and value=%s""", self.doc.name) - def on_rename(self,newdn,olddn, merge=False): + def before_rename(self, olddn, newdn, merge=False): if merge: - msgprint(_("Sorry. Companies cannot be merged"), raise_exception=True) - - webnotes.conn.sql("""update `tabCompany` set company_name=%s - where name=%s""", (newdn, olddn)) - - webnotes.conn.sql("""update `tabSingles` set value=%s - where doctype='Global Defaults' and field='default_company' - and value=%s""", (newdn, olddn)) - - webnotes.defaults.clear_default("company", value=olddn) + webnotes.throw(_("Sorry, companies cannot be merged")) + + def after_rename(self, olddn, newdn, merge=False): + webnotes.conn.set(self.doc, "company_name", newdn) + + webnotes.conn.sql("""update `tabDefaultValue` set defvalue=%s + where defkey='Company' and defvalue=%s""", (newdn, olddn)) + + webnotes.defaults.clear_cache() @webnotes.whitelist() def replace_abbr(company, old, new): @@ -329,4 +328,13 @@ def replace_abbr(company, old, new): for dt in ["Account", "Cost Center", "Warehouse"]: _rename_record(dt) - webnotes.conn.commit() \ No newline at end of file + webnotes.conn.commit() + +def get_name_with_abbr(name, company): + company_abbr = webnotes.conn.get_value("Company", company, "abbr") + parts = name.split(" - ") + + if parts[-1].lower() != company_abbr.lower(): + parts.append(company_abbr) + + return " - ".join(parts) \ No newline at end of file diff --git a/stock/doctype/item/item.py b/stock/doctype/item/item.py index aedb71c2c2..ca03089395 100644 --- a/stock/doctype/item/item.py +++ b/stock/doctype/item/item.py @@ -264,15 +264,45 @@ class DocType(DocListController): if self.doc.page_name: from webnotes.webutils import clear_cache clear_cache(self.doc.page_name) + + def before_rename(self, olddn, newdn, merge=False): + if merge: + # Validate properties before merging + field_list = ["stock_uom", "is_stock_item", "has_serial_no", "has_batch_no"] + new_properties = [cstr(d) for d in webnotes.conn.get_value("Item", newdn, field_list)] + if new_properties != [cstr(self.doc.fields[fld]) for fld in field_list]: + webnotes.throw(_("To merge, following properties must be same for both items") + + ": \n" + ", ".join([self.meta.get_label(fld) for fld in field_list])) - def on_rename(self, newdn, olddn, merge=False): - webnotes.conn.sql("update tabItem set item_code = %s where name = %s", (newdn, olddn)) + webnotes.conn.sql("delete from `tabBin` where item_code=%s", olddn) + + def after_rename(self, olddn, newdn, merge): + webnotes.conn.set_value("Item", newdn, "item_code", newdn) + self.update_website_page_name() + + if merge: + self.set_last_purchase_rate(newdn) + self.recalculate_bin_qty(newdn) + + def update_website_page_name(self): if self.doc.page_name: + self.update_website() from webnotes.webutils import clear_cache clear_cache(self.doc.page_name) - if merge: - from stock.stock_ledger import update_entries_after - for wh in webnotes.conn.sql("""select warehouse from `tabBin` - where item_code=%s""", newdn): - update_entries_after({"item_code": newdn, "warehouse": wh[0]}) + def set_last_purchase_rate(self, newdn): + from buying.utils import get_last_purchase_details + last_purchase_rate = get_last_purchase_details(newdn).get("purchase_rate", 0) + webnotes.conn.set_value("Item", newdn, "last_purchase_rate", last_purchase_rate) + + def recalculate_bin_qty(self, newdn): + from utilities.repost_stock import repost_stock + webnotes.conn.auto_commit_on_many_writes = 1 + webnotes.conn.set_default("allow_negative_stock", 1) + + for warehouse in webnotes.conn.sql("select name from `tabWarehouse`"): + repost_stock(newdn, warehouse[0]) + + webnotes.conn.set_default("allow_negative_stock", + webnotes.conn.get_value("Stock Settings", None, "allow_negative_stock")) + webnotes.conn.auto_commit_on_many_writes = 0 \ No newline at end of file diff --git a/stock/doctype/serial_no/serial_no.py b/stock/doctype/serial_no/serial_no.py index 15edf8b369..db32ca0608 100644 --- a/stock/doctype/serial_no/serial_no.py +++ b/stock/doctype/serial_no/serial_no.py @@ -6,7 +6,7 @@ import webnotes from webnotes.utils import cint, getdate, cstr, flt, add_days import datetime -from webnotes import msgprint, _, ValidationError +from webnotes import _, ValidationError from controllers.stock_controller import StockController @@ -158,11 +158,12 @@ class DocType(StockController): webnotes.throw(_("Cannot delete Serial No in warehouse. \ First remove from warehouse, then delete.") + ": " + self.doc.name) - def on_rename(self, new, old, merge=False): - """rename serial_no text fields""" + def before_rename(self, old, new, merge=False): if merge: - msgprint(_("Sorry. Serial Nos. cannot be merged"), raise_exception=True) - + webnotes.throw(_("Sorry, Serial Nos cannot be merged")) + + def after_rename(self, old, new, merge=False): + """rename serial_no text fields""" for dt in webnotes.conn.sql("""select parent from tabDocField where fieldname='serial_no' and fieldtype='Text'"""): diff --git a/stock/doctype/warehouse/warehouse.js b/stock/doctype/warehouse/warehouse.js index 2a58a387f8..f566bcf9fa 100644 --- a/stock/doctype/warehouse/warehouse.js +++ b/stock/doctype/warehouse/warehouse.js @@ -5,18 +5,6 @@ cur_frm.cscript.refresh = function(doc) { cur_frm.toggle_display('warehouse_name', doc.__islocal); } -cur_frm.cscript.merge = function(doc, cdt, cdn) { - if (!doc.merge_with) { - msgprint("Please enter the warehouse to which you want to merge?"); - return; - } - var check = confirm("Are you sure you want to merge this warehouse into " - + doc.merge_with + "?"); - if (check) { - return $c_obj(make_doclist(cdt, cdn), 'merge_warehouses', '', ''); - } -} - cur_frm.set_query("create_account_under", function() { return { filters: { @@ -25,4 +13,4 @@ cur_frm.set_query("create_account_under", function() { 'group_or_ledger': "Group" } } -}) +}) \ No newline at end of file diff --git a/stock/doctype/warehouse/warehouse.py b/stock/doctype/warehouse/warehouse.py index cfa278278d..ba36f3198c 100644 --- a/stock/doctype/warehouse/warehouse.py +++ b/stock/doctype/warehouse/warehouse.py @@ -58,38 +58,6 @@ class DocType: else: webnotes.throw(_("Please enter account group under which account \ for warehouse ") + self.doc.name +_(" will be created")) - - - def merge_warehouses(self): - webnotes.conn.auto_commit_on_many_writes = 1 - - # get items which dealt with current warehouse - items = webnotes.conn.sql("select item_code from tabBin where warehouse=%s" , self.doc.name) - # delete old bins - webnotes.conn.sql("delete from tabBin where warehouse=%s", self.doc.name) - - # replace link fields - from webnotes.model import rename_doc - link_fields = rename_doc.get_link_fields('Warehouse') - rename_doc.update_link_field_values(link_fields, self.doc.name, self.doc.merge_with) - - account_link_fields = rename_doc.get_link_fields('Account') - old_warehouse_account = webnotes.conn.get_value("Account", {"master_name": self.doc.name}) - new_warehouse_account = webnotes.conn.get_value("Account", - {"master_name": self.doc.merge_with}) - rename_doc.update_link_field_values(account_link_fields, old_warehouse_account, - new_warehouse_account) - - webnotes.conn.delete_doc("Account", old_warehouse_account) - - from utilities.repost_stock import repost - for item_code in items: - repost(item_code[0], self.doc.merge_with) - - webnotes.conn.auto_commit_on_many_writes = 0 - - msgprint("Warehouse %s merged into %s. Now you can delete warehouse: %s" - % (self.doc.name, self.doc.merge_with, self.doc.name)) def on_trash(self): # delete bin @@ -103,24 +71,62 @@ class DocType: sql("delete from `tabBin` where name = %s", d['name']) warehouse_account = webnotes.conn.get_value("Account", - {"account_type": "Warehosue", "master_name": self.doc.name}) + {"account_type": "Warehouse", "master_name": self.doc.name}) if warehouse_account: webnotes.delete_doc("Account", warehouse_account) # delete cancelled sle if sql("""select name from `tabStock Ledger Entry` where warehouse = %s""", self.doc.name): - msgprint("""Warehosue can not be deleted as stock ledger entry + msgprint("""Warehouse can not be deleted as stock ledger entry exists for this warehouse.""", raise_exception=1) - else: - sql("delete from `tabStock Ledger Entry` where warehouse = %s", self.doc.name) - - def on_rename(self, newdn, olddn, merge=False): - account = webnotes.conn.get_value("Account", {"account_type": "Warehouse", - "master_name": olddn}) - webnotes.conn.set_value("Account", account, "master_name", newdn) + def before_rename(self, olddn, newdn, merge=False): + # Add company abbr if not provided + from setup.doctype.company.company import get_name_with_abbr + new_warehouse = get_name_with_abbr(newdn, self.doc.company) + if merge: - from stock.stock_ledger import update_entries_after - for item_code in webnotes.conn.sql("""select item_code from `tabBin` - where warehouse=%s""", newdn): - update_entries_after({"item_code": item_code, "warehouse": newdn}) + if self.doc.company != webnotes.conn.get_value("Warehouse", new_warehouse, "company"): + webnotes.throw(_("Both Warehouse must belong to same Company")) + + webnotes.conn.sql("delete from `tabBin` where warehouse=%s", olddn) + + self.rename_account(olddn, new_warehouse, merge) + + return new_warehouse + + def after_rename(self, olddn, newdn, merge=False): + if merge: + self.recalculate_bin_qty(newdn) + + def recalculate_bin_qty(self, newdn): + from utilities.repost_stock import repost_stock + webnotes.conn.auto_commit_on_many_writes = 1 + webnotes.conn.set_default("allow_negative_stock", 1) + + for item in webnotes.conn.sql("""select distinct item_code from ( + select name as item_code from `tabItem` where ifnull(is_stock_item, 'Yes')='Yes' + union + select distinct item_code from tabBin) a"""): + repost_stock(item[0], newdn) + + webnotes.conn.set_default("allow_negative_stock", + webnotes.conn.get_value("Stock Settings", None, "allow_negative_stock")) + webnotes.conn.auto_commit_on_many_writes = 0 + + def rename_account(self, olddn, newdn, merge): + old_account = webnotes.conn.get_value("Account", + {"account_type": "Warehouse", "master_name": olddn}) + if old_account: + new_account = None + if not merge: + if old_account == olddn: + new_account = webnotes.rename_doc("Account", olddn, newdn) + else: + existing_new_account = webnotes.conn.get_value("Account", + {"account_type": "Warehouse", "master_name": newdn}) + new_account = webnotes.rename_doc("Account", old_account, + existing_new_account or newdn, merge=True if existing_new_account else False) + + if new_account: + webnotes.conn.set_value("Account", new_account, "master_name", newdn) \ No newline at end of file diff --git a/stock/doctype/warehouse/warehouse.txt b/stock/doctype/warehouse/warehouse.txt index 76ddac7930..8c75247cae 100644 --- a/stock/doctype/warehouse/warehouse.txt +++ b/stock/doctype/warehouse/warehouse.txt @@ -2,7 +2,7 @@ { "creation": "2013-03-07 18:50:32", "docstatus": 0, - "modified": "2013-09-16 10:45:49", + "modified": "2013-11-19 12:12:33", "modified_by": "Administrator", "owner": "Administrator" }, @@ -20,7 +20,8 @@ "name": "__common__", "parent": "Warehouse", "parentfield": "fields", - "parenttype": "DocType" + "parenttype": "DocType", + "permlevel": 0 }, { "doctype": "DocPerm", @@ -42,7 +43,6 @@ "fieldtype": "Section Break", "label": "Warehouse Detail", "oldfieldtype": "Section Break", - "permlevel": 0, "read_only": 0 }, { @@ -52,7 +52,6 @@ "label": "Warehouse Name", "oldfieldname": "warehouse_name", "oldfieldtype": "Data", - "permlevel": 0, "read_only": 0, "reqd": 1 }, @@ -65,7 +64,6 @@ "oldfieldname": "company", "oldfieldtype": "Link", "options": "Company", - "permlevel": 0, "read_only": 0, "reqd": 1, "search_index": 1 @@ -77,14 +75,12 @@ "fieldname": "create_account_under", "fieldtype": "Link", "label": "Create Account Under", - "options": "Account", - "permlevel": 0 + "options": "Account" }, { "doctype": "DocField", "fieldname": "column_break_4", "fieldtype": "Section Break", - "permlevel": 0, "read_only": 0 }, { @@ -94,7 +90,6 @@ "fieldtype": "Table", "label": "Warehouse Users", "options": "Warehouse User", - "permlevel": 0, "read_only": 0 }, { @@ -103,7 +98,6 @@ "fieldname": "warehouse_contact_info", "fieldtype": "Section Break", "label": "Warehouse Contact Info", - "permlevel": 0, "read_only": 0 }, { @@ -114,7 +108,6 @@ "label": "Email Id", "oldfieldname": "email_id", "oldfieldtype": "Data", - "permlevel": 0, "print_hide": 0, "read_only": 0 }, @@ -126,7 +119,6 @@ "oldfieldname": "phone_no", "oldfieldtype": "Int", "options": "Phone", - "permlevel": 0, "read_only": 0 }, { @@ -137,7 +129,6 @@ "oldfieldname": "mobile_no", "oldfieldtype": "Int", "options": "Phone", - "permlevel": 0, "read_only": 0 }, { @@ -145,7 +136,6 @@ "fieldname": "column_break0", "fieldtype": "Column Break", "oldfieldtype": "Column Break", - "permlevel": 0, "read_only": 0 }, { @@ -155,7 +145,6 @@ "label": "Address Line 1", "oldfieldname": "address_line_1", "oldfieldtype": "Data", - "permlevel": 0, "read_only": 0 }, { @@ -165,7 +154,6 @@ "label": "Address Line 2", "oldfieldname": "address_line_2", "oldfieldtype": "Data", - "permlevel": 0, "read_only": 0 }, { @@ -176,7 +164,6 @@ "label": "City", "oldfieldname": "city", "oldfieldtype": "Data", - "permlevel": 0, "read_only": 0, "reqd": 0 }, @@ -188,7 +175,6 @@ "oldfieldname": "state", "oldfieldtype": "Select", "options": "Suggest", - "permlevel": 0, "read_only": 0 }, { @@ -198,33 +184,6 @@ "label": "PIN", "oldfieldname": "pin", "oldfieldtype": "Int", - "permlevel": 0, - "read_only": 0 - }, - { - "description": "This feature is for merging duplicate warehouses. It will replace all the links of this warehouse by \"Merge Into\" warehouse. After merging you can delete this warehouse, as stock level for this warehouse will be zero.", - "doctype": "DocField", - "fieldname": "merge_warehouses_section", - "fieldtype": "Section Break", - "label": "Merge Warehouses", - "permlevel": 2, - "read_only": 0 - }, - { - "doctype": "DocField", - "fieldname": "merge_with", - "fieldtype": "Link", - "label": "Merge Into", - "options": "Warehouse", - "permlevel": 2, - "read_only": 0 - }, - { - "doctype": "DocField", - "fieldname": "merge", - "fieldtype": "Button", - "label": "Merge", - "permlevel": 2, "read_only": 0 }, { diff --git a/utilities/repost_stock.py b/utilities/repost_stock.py index 536df81e8b..a3a5d28f3c 100644 --- a/utilities/repost_stock.py +++ b/utilities/repost_stock.py @@ -7,18 +7,24 @@ import webnotes from webnotes.utils import flt -def repost(): +def repost(allow_negative_stock=False): """ Repost everything! """ webnotes.conn.auto_commit_on_many_writes = 1 + if allow_negative_stock: + webnotes.conn.set_default("allow_negative_stock", 1) + for d in webnotes.conn.sql("""select distinct item_code, warehouse from (select item_code, warehouse from tabBin union select item_code, warehouse from `tabStock Ledger Entry`) a"""): - repost_stock(d[0], d[1]) - + repost_stock(d[0], d[1], allow_negative_stock) + + if allow_negative_stock: + webnotes.conn.set_default("allow_negative_stock", + webnotes.conn.get_value("Stock Settings", None, "allow_negative_stock")) webnotes.conn.auto_commit_on_many_writes = 0 def repost_stock(item_code, warehouse): @@ -38,7 +44,7 @@ def repost_actual_qty(item_code, warehouse): update_entries_after({ "item_code": item_code, "warehouse": warehouse }) except: pass - + def get_reserved_qty(item_code, warehouse): reserved_qty = webnotes.conn.sql(""" select From 20f93546eb6c5df0605061c945a58a688050d904 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Wed, 20 Nov 2013 13:25:04 +0530 Subject: [PATCH 07/10] [fix] [minor] all variance related reports fixed --- .../budget_variance_report/budget_variance_report.py | 11 ++++++----- .../sales_person_target_variance_item_group_wise.py | 6 +++--- .../territory_target_variance_item_group_wise.py | 6 +++--- .../item/templates/includes/product_search_box.html | 2 +- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/accounts/report/budget_variance_report/budget_variance_report.py b/accounts/report/budget_variance_report/budget_variance_report.py index 0e241dea1d..652c1851a6 100644 --- a/accounts/report/budget_variance_report/budget_variance_report.py +++ b/accounts/report/budget_variance_report/budget_variance_report.py @@ -73,10 +73,10 @@ def get_costcenter_target_details(filters): def get_target_distribution_details(filters): target_details = {} - for d in webnotes.conn.sql("""select bd.name, bdd.month, bdd.percentage_allocation \ + for d in webnotes.conn.sql("""select bd.name, bdd.month, bdd.percentage_allocation from `tabBudget Distribution Detail` bdd, `tabBudget Distribution` bd where bdd.parent=bd.name and bd.fiscal_year=%s""", (filters["fiscal_year"]), as_dict=1): - target_details.setdefault(d.name, {}).setdefault(d.month, d.percentage_allocation) + target_details.setdefault(d.name, {}).setdefault(d.month, flt(d.percentage_allocation)) return target_details @@ -113,10 +113,11 @@ def get_costcenter_account_month_map(filters): })) tav_dict = cam_map[ccd.name][ccd.account][month] - month_percentage = ccd.distribution_id and \ - tdd.get(ccd.distribution_id, {}).get(month, 0) or 100.0/12 + + month_percentage = tdd.get(ccd.distribution_id, {}).get(month, 0) \ + if ccd.distribution_id else 100.0/12 - tav_dict.target = flt(ccd.budget_allocated) * month_percentage /100 + tav_dict.target = flt(ccd.budget_allocated) * month_percentage / 100 for ad in actual_details.get(ccd.name, {}).get(ccd.account, []): if ad.month_name == month: diff --git a/selling/report/sales_person_target_variance_item_group_wise/sales_person_target_variance_item_group_wise.py b/selling/report/sales_person_target_variance_item_group_wise/sales_person_target_variance_item_group_wise.py index ebb2d9f96f..8a4b9530f3 100644 --- a/selling/report/sales_person_target_variance_item_group_wise/sales_person_target_variance_item_group_wise.py +++ b/selling/report/sales_person_target_variance_item_group_wise/sales_person_target_variance_item_group_wise.py @@ -76,7 +76,7 @@ def get_target_distribution_details(filters): for d in webnotes.conn.sql("""select bd.name, bdd.month, bdd.percentage_allocation from `tabBudget Distribution Detail` bdd, `tabBudget Distribution` bd where bdd.parent=bd.name and bd.fiscal_year=%s""", (filters["fiscal_year"]), as_dict=1): - target_details.setdefault(d.name, {}).setdefault(d.month, d.percentage_allocation) + target_details.setdefault(d.name, {}).setdefault(d.month, flt(d.percentage_allocation)) return target_details @@ -115,8 +115,8 @@ def get_salesperson_item_month_map(filters): })) tav_dict = sim_map[sd.name][sd.item_group][month] - month_percentage = sd.distribution_id and \ - tdd.get(sd.distribution_id, {}).get(month, 0) or 100.0/12 + month_percentage = tdd.get(sd.distribution_id, {}).get(month, 0) \ + if sd.distribution_id else 100.0/12 for ad in achieved_details.get(sd.name, {}).get(sd.item_group, []): if (filters["target_on"] == "Quantity"): diff --git a/selling/report/territory_target_variance_item_group_wise/territory_target_variance_item_group_wise.py b/selling/report/territory_target_variance_item_group_wise/territory_target_variance_item_group_wise.py index 2aafe3c6bd..f3b480c206 100644 --- a/selling/report/territory_target_variance_item_group_wise/territory_target_variance_item_group_wise.py +++ b/selling/report/territory_target_variance_item_group_wise/territory_target_variance_item_group_wise.py @@ -73,7 +73,7 @@ def get_target_distribution_details(filters): for d in webnotes.conn.sql("""select bd.name, bdd.month, bdd.percentage_allocation from `tabBudget Distribution Detail` bdd, `tabBudget Distribution` bd where bdd.parent=bd.name and bd.fiscal_year=%s""", (filters["fiscal_year"]), as_dict=1): - target_details.setdefault(d.name, {}).setdefault(d.month, d.percentage_allocation) + target_details.setdefault(d.name, {}).setdefault(d.month, flt(d.percentage_allocation)) return target_details @@ -113,8 +113,8 @@ def get_territory_item_month_map(filters): })) tav_dict = tim_map[td.name][td.item_group][month] - month_percentage = td.distribution_id and \ - tdd.get(td.distribution_id, {}).get(month, 0) or 100.0/12 + month_percentage = tdd.get(td.distribution_id, {}).get(month, 0) \ + if td.distribution_id else 100.0/12 for ad in achieved_details.get(td.name, {}).get(td.item_group, []): if (filters["target_on"] == "Quantity"): diff --git a/stock/doctype/item/templates/includes/product_search_box.html b/stock/doctype/item/templates/includes/product_search_box.html index 55e6377781..96e571f21f 100644 --- a/stock/doctype/item/templates/includes/product_search_box.html +++ b/stock/doctype/item/templates/includes/product_search_box.html @@ -22,7 +22,7 @@ return false; }); $("#product-search").keypress(function(e) { - if(e.which==13) $("#btn-product-search").click(); + if(e.which==13) $("#btn-product-search").click(); }) }) From 1d35c444b6579f1f31f5b64c5b15a753bf6620d2 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 20 Nov 2013 16:24:11 +0530 Subject: [PATCH 08/10] [fix] [minor] check print hide property to show net total and grand total in purchase cycle standard print format --- .../purchase_taxes_and_charges_master.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js b/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js index 423c4e49b9..72d2864cff 100644 --- a/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js +++ b/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js @@ -36,18 +36,21 @@ cur_frm.pformat.purchase_tax_details= function(doc){ // main table out +='' - +make_row('Net Total',convert_rate(doc.net_total),1); - + if(!print_hide('net_total')) { + out += make_row('Net Total', convert_rate(doc.net_total), 1); + } + // add rows if(cl.length){ for(var i=0;i Date: Thu, 21 Nov 2013 10:39:43 +0530 Subject: [PATCH 09/10] [fix] [minor] check print hide properties in purchase standard print format --- .../purchase_taxes_and_charges_master.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js b/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js index 72d2864cff..b70e669d55 100644 --- a/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js +++ b/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js @@ -27,6 +27,11 @@ cur_frm.pformat.purchase_tax_details= function(doc){ var new_val = flt(val)/flt(doc.conversion_rate); return new_val; } + + function print_hide(fieldname) { + var doc_field = wn.meta.get_docfield(doc.doctype, fieldname, doc.name); + return doc_field.print_hide; + } var cl = getchildren('Purchase Taxes and Charges',doc.name,'purchase_tax_details'); From 0ec4bdfcb82fecad2771d62d44f5ce1dd9bef5cd Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Thu, 21 Nov 2013 11:55:54 +0530 Subject: [PATCH 10/10] [fix] [minor] send sms fixed for purchase module --- buying/doctype/purchase_order/purchase_order.js | 2 +- stock/doctype/purchase_receipt/purchase_receipt.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/buying/doctype/purchase_order/purchase_order.js b/buying/doctype/purchase_order/purchase_order.js index 9967f15a50..d35072d09e 100644 --- a/buying/doctype/purchase_order/purchase_order.js +++ b/buying/doctype/purchase_order/purchase_order.js @@ -24,7 +24,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend( doc.per_billed); - cur_frm.add_custom_button('Send SMS', cur_frm.cscript['Send SMS']); + cur_frm.add_custom_button('Send SMS', cur_frm.cscript.send_sms); if(flt(doc.per_received, 2) < 100) cur_frm.add_custom_button('Make Purchase Receipt', this.make_purchase_receipt); if(flt(doc.per_billed, 2) < 100) diff --git a/stock/doctype/purchase_receipt/purchase_receipt.js b/stock/doctype/purchase_receipt/purchase_receipt.js index 5333c21be0..9f9aa15de1 100644 --- a/stock/doctype/purchase_receipt/purchase_receipt.js +++ b/stock/doctype/purchase_receipt/purchase_receipt.js @@ -20,7 +20,7 @@ erpnext.stock.PurchaseReceiptController = erpnext.buying.BuyingController.extend cur_frm.add_custom_button('Make Purchase Invoice', this.make_purchase_invoice); } - cur_frm.add_custom_button('Send SMS', cur_frm.cscript['Send SMS']); + cur_frm.add_custom_button('Send SMS', cur_frm.cscript.send_sms); this.show_stock_ledger(); this.show_general_ledger();