From cdc9e2cd6fe3a5639fc18ad7bcb8ae143c08426e Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 25 Apr 2013 11:06:17 +0530 Subject: [PATCH 01/38] [patch] [file data] reset permissions --- patches/patch_list.py | 1 + 1 file changed, 1 insertion(+) diff --git a/patches/patch_list.py b/patches/patch_list.py index abee4f0cbc..a6dd0a217b 100644 --- a/patches/patch_list.py +++ b/patches/patch_list.py @@ -246,4 +246,5 @@ patch_list = [ "execute:webnotes.delete_doc('DocType Mapper', 'Delivery Note-Packing Slip')", "execute:webnotes.reload_doc('Stock', 'DocType', 'Delivery Note Item')", "patches.april_2013.p06_default_cost_center", + "execute:webnotes.reset_perms('File Data')", ] \ No newline at end of file From 04c1f94b4e53a19bde20efe687aac6eab3b7959a Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 26 Apr 2013 16:27:51 +0530 Subject: [PATCH 02/38] [DN][usability] copy cost center in each row --- controllers/buying_controller.py | 2 +- stock/doctype/delivery_note/delivery_note.js | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/controllers/buying_controller.py b/controllers/buying_controller.py index 85d8b9d9ea..94e3d56ddc 100644 --- a/controllers/buying_controller.py +++ b/controllers/buying_controller.py @@ -47,7 +47,7 @@ class BuyingController(StockController): items = [d.item_code for d in self.doclist.get({"parentfield": self.fname})] if self.stock_items and len(items) > len(self.stock_items): nonstock_items = list(set(items) - set(self.stock_items)) - webnotes.msgprint(_("Stock and non-stock items can not be entered at the same ") + + webnotes.msgprint(_("Stock and non-stock items can not be entered in the same ") + self.doc.doctype + _(""". You should make separate documents for them. Stock Items: """) + ", ".join(self.stock_items) + _(""" Non-stock Items: """) + ", ".join(nonstock_items), raise_exception=1) diff --git a/stock/doctype/delivery_note/delivery_note.js b/stock/doctype/delivery_note/delivery_note.js index 8d09cbd676..0a31dfe80e 100644 --- a/stock/doctype/delivery_note/delivery_note.js +++ b/stock/doctype/delivery_note/delivery_note.js @@ -326,6 +326,17 @@ if (sys_defaults.auto_inventory_accounting) { } // cost center + cur_frm.cscript.cost_center = function(doc, cdt, cdn){ + var d = locals[cdt][cdn]; + if(d.cost_center) { + var cl = getchildren('Delivery Note Item', doc.name, cur_frm.cscript.fname, doc.doctype); + for(var i = 0; i < cl.length; i++){ + if(!cl[i].cost_center) cl[i].cost_center = d.cost_center; + } + } + refresh_field(cur_frm.cscript.fname); + } + cur_frm.fields_dict.delivery_note_details.grid.get_field("cost_center").get_query = function(doc) { return { query: "accounts.utils.get_cost_center_list", From 612424776535c588163bc0146a93160f366ed285 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 26 Apr 2013 16:29:06 +0530 Subject: [PATCH 03/38] [bom] set fetched values at server side --- manufacturing/doctype/bom/bom.js | 37 +++++++++----------- manufacturing/doctype/bom/bom.py | 58 ++++++++++++++++++-------------- 2 files changed, 48 insertions(+), 47 deletions(-) diff --git a/manufacturing/doctype/bom/bom.js b/manufacturing/doctype/bom/bom.js index 4e8fbc95d1..f0c15fa2a9 100644 --- a/manufacturing/doctype/bom/bom.js +++ b/manufacturing/doctype/bom/bom.js @@ -59,27 +59,22 @@ cur_frm.fields_dict["bom_operations"].grid.on_row_delete = function(cdt, cdn){ set_operation_no(doc); } -cur_frm.cscript.item = function(doc, dt, dn) { - if (doc.item) { - get_server_fields('get_item_details', doc.item, '', doc, dt, dn, 1); - } -} +cur_frm.add_fetch("item", "description", "description"); +cur_frm.add_fetch("item", "stock_uom", "uom"); cur_frm.cscript.workstation = function(doc,dt,dn) { var d = locals[dt][dn]; - if (d.workstation) { - var callback = function(r, rt) { - calculate_op_cost(doc, dt, dn); - calculate_total(doc); - } - get_server_fields('get_workstation_details', d.workstation, - 'bom_operations', doc, dt, dn, 1, callback); - } + wn.model.with_doc("Workstation", d.workstation, function(i, v) { + d.hour_rate = v.hour_rate; + refresh_field("hour_rate"); + calculate_op_cost(doc); + calculate_total(doc); + }); } cur_frm.cscript.hour_rate = function(doc, dt, dn) { - calculate_op_cost(doc, dt, dn); + calculate_op_cost(doc); calculate_total(doc); } @@ -114,7 +109,7 @@ var get_bom_material_detail= function(doc, cdt, cdn) { $.extend(d, r.message); refresh_field("bom_materials"); doc = locals[doc.doctype][doc.name]; - calculate_rm_cost(doc, cdt, cdn); + calculate_rm_cost(doc); calculate_total(doc); }, freeze: true @@ -124,7 +119,7 @@ var get_bom_material_detail= function(doc, cdt, cdn) { cur_frm.cscript.qty = function(doc, cdt, cdn) { - calculate_rm_cost(doc, cdt, cdn); + calculate_rm_cost(doc); calculate_total(doc); } @@ -134,12 +129,12 @@ cur_frm.cscript.rate = function(doc, cdt, cdn) { msgprint("You can not change rate if BOM mentioned agianst any item"); get_bom_material_detail(doc, cdt, cdn); } else { - calculate_rm_cost(doc, cdt, cdn); + calculate_rm_cost(doc); calculate_total(doc); } } -var calculate_op_cost = function(doc, dt, dn) { +var calculate_op_cost = function(doc) { var op = getchildren('BOM Operation', doc.name, 'bom_operations'); total_op_cost = 0; for(var i=0;i Date: Fri, 26 Apr 2013 17:25:44 +0530 Subject: [PATCH 04/38] validation for stock and nonstock items in purchase cycle --- controllers/buying_controller.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/controllers/buying_controller.py b/controllers/buying_controller.py index 94e3d56ddc..e167dc57b7 100644 --- a/controllers/buying_controller.py +++ b/controllers/buying_controller.py @@ -45,12 +45,13 @@ class BuyingController(StockController): def validate_stock_or_nonstock_items(self): items = [d.item_code for d in self.doclist.get({"parentfield": self.fname})] - if self.stock_items and len(items) > len(self.stock_items): + if self.stock_items: nonstock_items = list(set(items) - set(self.stock_items)) - webnotes.msgprint(_("Stock and non-stock items can not be entered in the same ") + - self.doc.doctype + _(""". You should make separate documents for them. - Stock Items: """) + ", ".join(self.stock_items) + _(""" - Non-stock Items: """) + ", ".join(nonstock_items), raise_exception=1) + if nonstock_items: + webnotes.msgprint(_("Stock and non-stock items can not be entered in the same ") + + self.doc.doctype + _(""". You should make separate documents for them. + Stock Items: """) + ", ".join(self.stock_items) + _(""" + Non-stock Items: """) + ", ".join(nonstock_items), raise_exception=1) elif items and not self.stock_items: tax_for_valuation = [d.account_head for d in From 6198c28fd352f597194c2cea460b9830b417f11f Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 26 Apr 2013 17:29:05 +0530 Subject: [PATCH 05/38] validation for stock and nonstock items in purchase cycle --- manufacturing/doctype/bom/bom.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/manufacturing/doctype/bom/bom.py b/manufacturing/doctype/bom/bom.py index 1408a3ad5c..5f42f4da5d 100644 --- a/manufacturing/doctype/bom/bom.py +++ b/manufacturing/doctype/bom/bom.py @@ -89,7 +89,7 @@ class DocType: "qty": item.qty }) for r in ret: - if not item.fields[r]: + if not item.fields.get(r): item.fields[r] = ret[r] def get_bom_material_detail(self, args=None): @@ -117,7 +117,7 @@ class DocType: def get_rm_rate(self, arg): """ Get raw material rate as per selected method, if bom exists takes bom cost """ - + rate = 0 if arg['bom_no']: rate = self.get_bom_unitcost(arg['bom_no']) elif arg and (arg['is_purchase_item'] == 'Yes' or arg['is_sub_contracted_item'] == 'Yes'): From 319e0f43da2d8f6168408067c3aabaddd69a1f68 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Mon, 29 Apr 2013 08:53:12 +0530 Subject: [PATCH 06/38] [latest updates] added default cost center and update manager --- home/page/latest_updates/latest_updates.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/home/page/latest_updates/latest_updates.js b/home/page/latest_updates/latest_updates.js index 949849d8f1..a4d99f69e4 100644 --- a/home/page/latest_updates/latest_updates.js +++ b/home/page/latest_updates/latest_updates.js @@ -1,5 +1,7 @@ erpnext.updates = [ + ["18th April", ["Cost Center: Set a default Cost Center for a Company"]], ["12th April", ["Employee: List of Leave Approvers who can approve the Employee's Leave Applications"]], + ["3rd April", ["Update Manager: Open source users can update their ERPNext instance from Setup > Update Manager"]], ["27th March", ["Rename multiple items together. Go to Setup > Rename Tool"]], ["26th March", ["Added project to Stock Ledger and Balance", "Added Default Cash Account in Company."]], From 4cbeda1ec7ced13f5227948641467f2c66db148d Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Mon, 29 Apr 2013 10:48:45 +0530 Subject: [PATCH 07/38] [patch] [fix] commented out export_to_files call in p05_update_file_data patch --- patches/april_2013/p05_update_file_data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patches/april_2013/p05_update_file_data.py b/patches/april_2013/p05_update_file_data.py index a5540cc3cd..986e5b9b53 100644 --- a/patches/april_2013/p05_update_file_data.py +++ b/patches/april_2013/p05_update_file_data.py @@ -26,7 +26,7 @@ def execute(): webnotes.conn.sql("""delete from tabDocField where fieldname='file_list' and parent=%s""", doctype) - export_to_files([["DocType", doctype]]) + # export_to_files([["DocType", doctype]]) def update_for_doc(doctype, doc): for filedata in doc.file_list.split("\n"): From e81b0e2d669d766e685d6859400172a211da0d23 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 29 Apr 2013 11:45:22 +0530 Subject: [PATCH 08/38] [stock ageing][fixes] for serialized items --- stock/page/stock_ageing/stock_ageing.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/stock/page/stock_ageing/stock_ageing.js b/stock/page/stock_ageing/stock_ageing.js index edad9a76a1..456f5f1367 100644 --- a/stock/page/stock_ageing/stock_ageing.js +++ b/stock/page/stock_ageing/stock_ageing.js @@ -95,6 +95,8 @@ erpnext.StockAgeing = erpnext.StockGridReport.extend({ this.data = [].concat(this._data); + this.serialized_buying_rates = this.get_serialized_buying_rates(); + $.each(this.data, function(i, d) { me.reset_item_values(d); }); From 99883420e78c6f6e54df7dc205e5eaf866449e56 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 29 Apr 2013 12:15:35 +0530 Subject: [PATCH 09/38] [general ledger][fixes] for against_account value --- accounts/page/general_ledger/general_ledger.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/accounts/page/general_ledger/general_ledger.js b/accounts/page/general_ledger/general_ledger.js index 21be3a05dd..a462b70e93 100644 --- a/accounts/page/general_ledger/general_ledger.js +++ b/accounts/page/general_ledger/general_ledger.js @@ -186,7 +186,6 @@ erpnext.GeneralLedger = wn.views.GridReport.extend({ var totals = this.make_summary_row("Totals", this.account); var grouped_ledgers = {}; - $.each(data, function(i, item) { if((me.is_default("company") ? true : me.apply_filter(item, "company")) && (me.account ? me.is_child_account(me.account, item.account) @@ -217,8 +216,7 @@ erpnext.GeneralLedger = wn.views.GridReport.extend({ grouped_ledgers[item.account].totals.debit += item.debit; grouped_ledgers[item.account].totals.credit += item.credit; } - - if(me.account) { + if(item.account) { item.against_account = me.voucher_accounts[item.voucher_type + ":" + item.voucher_no][(item.debit > 0 ? "credits" : "debits")].join(", "); } From ce3296fc87298466c32b6de471d9b1f78aa31ccc Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Mon, 29 Apr 2013 12:28:19 +0530 Subject: [PATCH 10/38] [rename tool] [fix] condition to validate that content exists in a row of the uploaded file --- utilities/doctype/rename_tool/rename_tool.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/utilities/doctype/rename_tool/rename_tool.py b/utilities/doctype/rename_tool/rename_tool.py index 2e368ced70..5accf3c6b7 100644 --- a/utilities/doctype/rename_tool/rename_tool.py +++ b/utilities/doctype/rename_tool/rename_tool.py @@ -34,7 +34,8 @@ def upload(select_doctype=None, rows=None): rename_log = [] for row in rows: - if len(row) > 2: + # if row has some content + if len(row) > 1 and row[0] and row[1]: try: if rename_doc(select_doctype, row[0], row[1]): rename_log.append(_("Successful: ") + row[0] + " -> " + row[1]) @@ -45,5 +46,5 @@ def upload(select_doctype=None, rows=None): rename_log.append("" + \ _("Failed: ") + row[0] + " -> " + row[1] + "") rename_log.append("" + repr(e) + "") - + return rename_log \ No newline at end of file From 457cd7d1f446b7a823eef77c4df5c53c1e90d8c6 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Mon, 29 Apr 2013 13:01:44 +0530 Subject: [PATCH 11/38] [gl entry] [validation] company match validation should be done only for is_cancelled = No --- accounts/doctype/gl_entry/gl_entry.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/accounts/doctype/gl_entry/gl_entry.py b/accounts/doctype/gl_entry/gl_entry.py index 64d84b0459..429cc104a7 100644 --- a/accounts/doctype/gl_entry/gl_entry.py +++ b/accounts/doctype/gl_entry/gl_entry.py @@ -108,8 +108,8 @@ class DocType: and not 'Accounts Manager' in webnotes.user.get_roles(): msgprint(_("Account") + ": " + self.doc.account + _(" has been freezed. \ Only Accounts Manager can do transaction against this account"), raise_exception=1) - - if ret and ret[0]["company"] != self.doc.company: + + if self.doc.is_cancelled in ("No", None) and ret and ret[0]["company"] != self.doc.company: msgprint(_("Account") + ": " + self.doc.account + _(" does not belong to the company") \ + ": " + self.doc.company, raise_exception=1) @@ -124,9 +124,10 @@ class DocType: return self.cost_center_company[self.doc.cost_center] - if self.doc.cost_center and _get_cost_center_company() != self.doc.company: - msgprint(_("Cost Center") + ": " + self.doc.cost_center \ - + _(" does not belong to the company") + ": " + self.doc.company, raise_exception=True) + if self.doc.is_cancelled in ("No", None) and \ + self.doc.cost_center and _get_cost_center_company() != self.doc.company: + msgprint(_("Cost Center") + ": " + self.doc.cost_center \ + + _(" does not belong to the company") + ": " + self.doc.company, raise_exception=True) def check_freezing_date(self, adv_adj): """ From e5a36a287f8069025d13b7b2547f580965d69525 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Mon, 29 Apr 2013 14:12:27 +0530 Subject: [PATCH 12/38] [patch] [file data] patch for custom fields with name file_list --- patches/april_2013/p05_update_file_data.py | 40 +++++++++++++--------- patches/patch_list.py | 1 + 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/patches/april_2013/p05_update_file_data.py b/patches/april_2013/p05_update_file_data.py index 986e5b9b53..1ff48fa60e 100644 --- a/patches/april_2013/p05_update_file_data.py +++ b/patches/april_2013/p05_update_file_data.py @@ -5,28 +5,36 @@ def execute(): webnotes.reload_doc("core", "doctype", "file_data") webnotes.reset_perms("File Data") - singles = webnotes.conn.sql_list("""select name from tabDocType - where ifnull(issingle,0)=1""") + singles = get_single_doctypes() + for doctype in webnotes.conn.sql_list("""select parent from tabDocField where fieldname='file_list' and fieldtype='Text'"""): - if doctype in singles: - doc = webnotes.doc(doctype, doctype) - if doc.file_list: - update_for_doc(doctype, doc) - webnotes.conn.set_value(doctype, None, "file_list", None) - else: - try: - for doc in webnotes.conn.sql("""select name, file_list from `tab%s` where - ifnull(file_list, '')!=''""" % doctype, as_dict=True): - update_for_doc(doctype, doc) - webnotes.conn.commit() - webnotes.conn.sql("""alter table `tab%s` drop column file_list""" % doctype) - except Exception, e: - if e.args[0]!=1054: raise e + update_file_list(doctype, singles) webnotes.conn.sql("""delete from tabDocField where fieldname='file_list' and parent=%s""", doctype) + # export_to_files([["DocType", doctype]]) + +def get_single_doctypes(): + return webnotes.conn.sql_list("""select name from tabDocType + where ifnull(issingle,0)=1""") + +def update_file_list(doctype, singles): + if doctype in singles: + doc = webnotes.doc(doctype, doctype) + if doc.file_list: + update_for_doc(doctype, doc) + webnotes.conn.set_value(doctype, None, "file_list", None) + else: + try: + for doc in webnotes.conn.sql("""select name, file_list from `tab%s` where + ifnull(file_list, '')!=''""" % doctype, as_dict=True): + update_for_doc(doctype, doc) + webnotes.conn.commit() + webnotes.conn.sql("""alter table `tab%s` drop column file_list""" % doctype) + except Exception, e: + if e.args[0]!=1054: raise e def update_for_doc(doctype, doc): for filedata in doc.file_list.split("\n"): diff --git a/patches/patch_list.py b/patches/patch_list.py index a6dd0a217b..096fec80ab 100644 --- a/patches/patch_list.py +++ b/patches/patch_list.py @@ -247,4 +247,5 @@ patch_list = [ "execute:webnotes.reload_doc('Stock', 'DocType', 'Delivery Note Item')", "patches.april_2013.p06_default_cost_center", "execute:webnotes.reset_perms('File Data')", + "patches.april_2013.p07_update_file_data_custom_field", ] \ No newline at end of file From 123f59dc89cf3858678ba8a71bfd72e9a3b9438b Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Mon, 29 Apr 2013 14:21:42 +0530 Subject: [PATCH 13/38] [patches] [file data] fixes in file data patch --- patches/april_2013/p05_update_file_data.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/patches/april_2013/p05_update_file_data.py b/patches/april_2013/p05_update_file_data.py index 1ff48fa60e..d3877417e2 100644 --- a/patches/april_2013/p05_update_file_data.py +++ b/patches/april_2013/p05_update_file_data.py @@ -53,10 +53,17 @@ def update_for_doc(doctype, doc): exists = False if exists: - webnotes.conn.sql("""update `tabFile Data` - set attached_to_doctype=%s, attached_to_name=%s - where name=%s""", (doctype, doc.name, fileid)) - + if webnotes.conn.exists("File Data", fileid): + fd = webnotes.bean("File Data", fileid) + if not (fd.doc.attached_to_doctype and fd.doc.attached_to_name): + fd.doc.attached_to_doctype = doctype + fd.doc.attached_to_name = doc.name + fd.save() + else: + fd = webnotes.bean("File Data", copy=fd.doclist) + fd.doc.attached_to_doctype = doctype + fd.doc.attached_to_name = doc.name + fd.insert() else: webnotes.conn.sql("""delete from `tabFile Data` where name=%s""", - fileid) \ No newline at end of file + fileid) \ No newline at end of file From 7bd7c8769ef6eb472b9b0dde5653859ccaa7150d Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Mon, 29 Apr 2013 14:21:58 +0530 Subject: [PATCH 14/38] [patch] [file data] files in update file data patch --- .../april_2013/p07_update_file_data_custom_field.py | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 patches/april_2013/p07_update_file_data_custom_field.py diff --git a/patches/april_2013/p07_update_file_data_custom_field.py b/patches/april_2013/p07_update_file_data_custom_field.py new file mode 100644 index 0000000000..909df0554d --- /dev/null +++ b/patches/april_2013/p07_update_file_data_custom_field.py @@ -0,0 +1,11 @@ +import webnotes +def execute(): + from patches.april_2013.p05_update_file_data import update_file_list, get_single_doctypes + singles = get_single_doctypes() + for doctype in webnotes.conn.sql("""select parent from `tabCustom Field` where + fieldname='file_list' and fieldtype='Text'"""): + update_file_list(doctype, singles) + + webnotes.conn.sql("""delete from `tabCustom Field` where fieldname='file_list' + and parent=%s""", doctype) + \ No newline at end of file From 345c8fbfa29dd51e7f0a637ec50818dd7b975b16 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 29 Apr 2013 14:35:11 +0530 Subject: [PATCH 15/38] [patch] rebuild sales browser --- patches/april_2013/rebuild_sales_browser.py | 4 ++++ patches/patch_list.py | 1 + 2 files changed, 5 insertions(+) create mode 100644 patches/april_2013/rebuild_sales_browser.py diff --git a/patches/april_2013/rebuild_sales_browser.py b/patches/april_2013/rebuild_sales_browser.py new file mode 100644 index 0000000000..917ae68467 --- /dev/null +++ b/patches/april_2013/rebuild_sales_browser.py @@ -0,0 +1,4 @@ +import webnotes +def execute(): + from patches.january_2013 import rebuild_tree + rebuild_tree.execute() \ No newline at end of file diff --git a/patches/patch_list.py b/patches/patch_list.py index a6dd0a217b..1b874d63ff 100644 --- a/patches/patch_list.py +++ b/patches/patch_list.py @@ -247,4 +247,5 @@ patch_list = [ "execute:webnotes.reload_doc('Stock', 'DocType', 'Delivery Note Item')", "patches.april_2013.p06_default_cost_center", "execute:webnotes.reset_perms('File Data')", + "patches.april_2013.rebuild_sales_browser", ] \ No newline at end of file From 7ee7eae3ae8848eb597bcab6557dc278fbb6784b Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 29 Apr 2013 15:10:39 +0530 Subject: [PATCH 16/38] [item][validation] some validation only after saving --- stock/doctype/item/item.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/stock/doctype/item/item.py b/stock/doctype/item/item.py index 4767742e3e..fce6f32543 100644 --- a/stock/doctype/item/item.py +++ b/stock/doctype/item/item.py @@ -55,12 +55,13 @@ class DocType(DocListController): ch.conversion_factor = 1 def check_stock_uom_with_bin(self): - bin = webnotes.conn.sql("select stock_uom from `tabBin` where item_code = %s", - self.doc.item_code) - if self.doc.stock_uom and bin and cstr(bin[0][0]) \ - and cstr(bin[0][0]) != cstr(self.doc.stock_uom): - msgprint(_("Please Update Stock UOM with the help of Stock UOM Replace Utility."), - raise_exception=1) + if not self.doc.__islocal: + bin = webnotes.conn.sql("select stock_uom from `tabBin` where item_code = %s", + self.doc.name) + if self.doc.stock_uom and bin and cstr(bin[0][0]) \ + and cstr(bin[0][0]) != cstr(self.doc.stock_uom): + msgprint(_("Please Update Stock UOM with the help of Stock UOM Replace Utility."), + raise_exception=1) def validate_conversion_factor(self): check_list = [] @@ -154,13 +155,14 @@ class DocType(DocListController): def validate_barcode(self): if self.doc.barcode: - duplicate = webnotes.conn.sql("select name from tabItem where barcode = %s and name != %s", (self.doc.barcode, self.doc.name)) + duplicate = webnotes.conn.sql("""select name from tabItem where barcode = %s + and name != %s""", (self.doc.barcode, self.doc.name)) if duplicate: msgprint("Barcode: %s already used in item: %s" % (self.doc.barcode, cstr(duplicate[0][0])), raise_exception = 1) def check_non_asset_warehouse(self): - if self.doc.is_asset_item == "Yes": + if not self.doc.__islocal and self.doc.is_asset_item == "Yes": existing_qty = webnotes.conn.sql("select t1.warehouse, t1.actual_qty from tabBin t1, tabWarehouse t2 where t1.item_code=%s and (t2.warehouse_type!='Fixed Asset' or t2.warehouse_type is null) and t1.warehouse=t2.name and t1.actual_qty > 0", self.doc.name) for e in existing_qty: msgprint("%s Units exist in Warehouse %s, which is not an Asset Warehouse." % From eda17eb20a7808f24faae12b612e40f101059557 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Mon, 29 Apr 2013 15:21:30 +0530 Subject: [PATCH 17/38] [patch] [fiel data] new patch p07_update_file_data_2 --- patches/april_2013/p05_update_file_data.py | 20 ++++++++++++------- patches/april_2013/p07_update_file_data_2.py | 15 ++++++++++++++ .../p07_update_file_data_custom_field.py | 11 ---------- patches/patch_list.py | 2 +- 4 files changed, 29 insertions(+), 19 deletions(-) create mode 100644 patches/april_2013/p07_update_file_data_2.py delete mode 100644 patches/april_2013/p07_update_file_data_custom_field.py diff --git a/patches/april_2013/p05_update_file_data.py b/patches/april_2013/p05_update_file_data.py index d3877417e2..a5d2f7a07a 100644 --- a/patches/april_2013/p05_update_file_data.py +++ b/patches/april_2013/p05_update_file_data.py @@ -8,7 +8,7 @@ def execute(): singles = get_single_doctypes() for doctype in webnotes.conn.sql_list("""select parent from tabDocField where - fieldname='file_list' and fieldtype='Text'"""): + fieldname='file_list'"""): update_file_list(doctype, singles) webnotes.conn.sql("""delete from tabDocField where fieldname='file_list' @@ -32,9 +32,11 @@ def update_file_list(doctype, singles): ifnull(file_list, '')!=''""" % doctype, as_dict=True): update_for_doc(doctype, doc) webnotes.conn.commit() - webnotes.conn.sql("""alter table `tab%s` drop column file_list""" % doctype) + webnotes.conn.sql("""alter table `tab%s` drop column `file_list`""" % doctype) except Exception, e: - if e.args[0]!=1054: raise e + print webnotes.getTraceback() + if (e.args and e.args[0]!=1054) or not e.args: + raise e def update_for_doc(doctype, doc): for filedata in doc.file_list.split("\n"): @@ -60,10 +62,14 @@ def update_for_doc(doctype, doc): fd.doc.attached_to_name = doc.name fd.save() else: - fd = webnotes.bean("File Data", copy=fd.doclist) - fd.doc.attached_to_doctype = doctype - fd.doc.attached_to_name = doc.name - fd.insert() + try: + fd = webnotes.bean("File Data", copy=fd.doclist) + fd.doc.attached_to_doctype = doctype + fd.doc.attached_to_name = doc.name + fd.doc.name = None + fd.insert() + except webnotes.DuplicateEntryError: + pass else: webnotes.conn.sql("""delete from `tabFile Data` where name=%s""", fileid) \ No newline at end of file diff --git a/patches/april_2013/p07_update_file_data_2.py b/patches/april_2013/p07_update_file_data_2.py new file mode 100644 index 0000000000..7b89a9de77 --- /dev/null +++ b/patches/april_2013/p07_update_file_data_2.py @@ -0,0 +1,15 @@ +import webnotes +def execute(): + from patches.april_2013.p05_update_file_data import update_file_list, get_single_doctypes + + singles = get_single_doctypes() + for doctype in webnotes.conn.sql_list("""select table_name from `information_schema`.`columns` + where table_schema=%s and column_name='file_list'""", webnotes.conn.cur_db_name): + doctype = doctype[3:] + update_file_list(doctype, singles) + + webnotes.conn.sql("""delete from `tabCustom Field` where fieldname='file_list' + and parent=%s""", doctype) + webnotes.conn.sql("""delete from `tabDocField` where fieldname='file_list' + and parent=%s""", doctype) + \ No newline at end of file diff --git a/patches/april_2013/p07_update_file_data_custom_field.py b/patches/april_2013/p07_update_file_data_custom_field.py deleted file mode 100644 index 909df0554d..0000000000 --- a/patches/april_2013/p07_update_file_data_custom_field.py +++ /dev/null @@ -1,11 +0,0 @@ -import webnotes -def execute(): - from patches.april_2013.p05_update_file_data import update_file_list, get_single_doctypes - singles = get_single_doctypes() - for doctype in webnotes.conn.sql("""select parent from `tabCustom Field` where - fieldname='file_list' and fieldtype='Text'"""): - update_file_list(doctype, singles) - - webnotes.conn.sql("""delete from `tabCustom Field` where fieldname='file_list' - and parent=%s""", doctype) - \ No newline at end of file diff --git a/patches/patch_list.py b/patches/patch_list.py index 096fec80ab..70aeb4a6ff 100644 --- a/patches/patch_list.py +++ b/patches/patch_list.py @@ -247,5 +247,5 @@ patch_list = [ "execute:webnotes.reload_doc('Stock', 'DocType', 'Delivery Note Item')", "patches.april_2013.p06_default_cost_center", "execute:webnotes.reset_perms('File Data')", - "patches.april_2013.p07_update_file_data_custom_field", + "patches.april_2013.p07_update_file_data_2", ] \ No newline at end of file From 28eae6e9ff1d002e8232a60bcfc9c451a11fa745 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Mon, 29 Apr 2013 15:25:52 +0530 Subject: [PATCH 18/38] [patch] [file data] fix --- patches/april_2013/p07_update_file_data_2.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/patches/april_2013/p07_update_file_data_2.py b/patches/april_2013/p07_update_file_data_2.py index 7b89a9de77..2405e80d65 100644 --- a/patches/april_2013/p07_update_file_data_2.py +++ b/patches/april_2013/p07_update_file_data_2.py @@ -6,6 +6,9 @@ def execute(): for doctype in webnotes.conn.sql_list("""select table_name from `information_schema`.`columns` where table_schema=%s and column_name='file_list'""", webnotes.conn.cur_db_name): doctype = doctype[3:] + + if not webnotes.conn.exists("DocType", doctype): continue + update_file_list(doctype, singles) webnotes.conn.sql("""delete from `tabCustom Field` where fieldname='file_list' From fe5fb33cc2e8c7f9a59e1f9d6d859b16623c93ec Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Mon, 29 Apr 2013 15:27:57 +0530 Subject: [PATCH 19/38] [patch] [file data] fix --- patches/april_2013/p05_update_file_data.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/patches/april_2013/p05_update_file_data.py b/patches/april_2013/p05_update_file_data.py index a5d2f7a07a..787991251e 100644 --- a/patches/april_2013/p05_update_file_data.py +++ b/patches/april_2013/p05_update_file_data.py @@ -56,20 +56,20 @@ def update_for_doc(doctype, doc): if exists: if webnotes.conn.exists("File Data", fileid): - fd = webnotes.bean("File Data", fileid) - if not (fd.doc.attached_to_doctype and fd.doc.attached_to_name): - fd.doc.attached_to_doctype = doctype - fd.doc.attached_to_name = doc.name - fd.save() - else: - try: + try: + fd = webnotes.bean("File Data", fileid) + if not (fd.doc.attached_to_doctype and fd.doc.attached_to_name): + fd.doc.attached_to_doctype = doctype + fd.doc.attached_to_name = doc.name + fd.save() + else: fd = webnotes.bean("File Data", copy=fd.doclist) fd.doc.attached_to_doctype = doctype fd.doc.attached_to_name = doc.name fd.doc.name = None fd.insert() - except webnotes.DuplicateEntryError: - pass + except webnotes.DuplicateEntryError: + pass else: webnotes.conn.sql("""delete from `tabFile Data` where name=%s""", fileid) \ No newline at end of file From fe9c1eb5df29b744016844c67f9ceb682034cdc1 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Mon, 29 Apr 2013 16:36:59 +0530 Subject: [PATCH 20/38] [support ticket] clear assign to on closing ticket --- support/doctype/support_ticket/support_ticket.js | 14 +++++--------- support/doctype/support_ticket/support_ticket.py | 4 ++++ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/support/doctype/support_ticket/support_ticket.js b/support/doctype/support_ticket/support_ticket.js index 3da81d9efb..4ee4c1d968 100644 --- a/support/doctype/support_ticket/support_ticket.js +++ b/support/doctype/support_ticket/support_ticket.js @@ -29,17 +29,13 @@ $.extend(cur_frm.cscript, { erpnext.hide_naming_series(); cur_frm.cscript.make_listing(doc); if(!doc.__islocal) { - if(in_list(user_roles,'System Manager')) { - if(doc.status!='Closed') cur_frm.add_custom_button('Close Ticket', cur_frm.cscript['Close Ticket']); - if(doc.status=='Closed') cur_frm.add_custom_button('Re-Open Ticket', cur_frm.cscript['Re-Open Ticket']); - }else if(doc.allocated_to) { - cur_frm.set_df_property('status','read_only', 1); - if(user==doc.allocated_to && doc.status!='Closed') cur_frm.add_custom_button('Close Ticket', cur_frm.cscript['Close Ticket']); + if(user_roles.indexOf("Support Manager")!==-1) { + if(doc.status!='Closed') cur_frm.add_custom_button('Close Ticket', cur_frm.cscript['Close Ticket']); + if(doc.status=='Closed') cur_frm.add_custom_button('Re-Open Ticket', cur_frm.cscript['Re-Open Ticket']); } - cur_frm.set_df_property('subject','read_only', 1); - cur_frm.set_df_property('description','hidden', 1); - cur_frm.set_df_property('raised_by','read_only', 1); + cur_frm.toggle_enable(["subject", "raised_by"], false); + cur_frm.toggle_display("description", false); } refresh_field('status'); }, diff --git a/support/doctype/support_ticket/support_ticket.py b/support/doctype/support_ticket/support_ticket.py index 5625f1179c..8a705f41c7 100644 --- a/support/doctype/support_ticket/support_ticket.py +++ b/support/doctype/support_ticket/support_ticket.py @@ -45,6 +45,10 @@ class DocType(TransactionBase): def validate(self): self.update_status() + if self.doc.status == "Closed": + from webnotes.widgets.form.assign_to import clear + clear(self.doc.doctype, self.doc.name) + def on_communication_sent(self, comm): webnotes.conn.set(self.doc, 'status', 'Waiting for Customer') if comm.lead and not self.doc.lead: From 98cfe688a85db05e22c9b5efe0d78029d8bc9cb1 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 30 Apr 2013 17:22:43 +0530 Subject: [PATCH 21/38] [script report] purchase register in new style --- accounts/page/accounts_home/accounts_home.js | 5 + accounts/report/purchase_register/__init__.py | 0 .../purchase_register/purchase_register.js | 43 +++++ .../purchase_register/purchase_register.py | 147 ++++++++++++++++++ .../purchase_register/purchase_register.txt | 21 +++ .../report/sales_register/sales_register.js | 1 + .../report/sales_register/sales_register.py | 4 +- .../bank_clearance_report.txt | 39 ++--- 8 files changed, 240 insertions(+), 20 deletions(-) create mode 100644 accounts/report/purchase_register/__init__.py create mode 100644 accounts/report/purchase_register/purchase_register.js create mode 100644 accounts/report/purchase_register/purchase_register.py create mode 100644 accounts/report/purchase_register/purchase_register.txt diff --git a/accounts/page/accounts_home/accounts_home.js b/accounts/page/accounts_home/accounts_home.js index 2703d27f69..6a9f91a719 100644 --- a/accounts/page/accounts_home/accounts_home.js +++ b/accounts/page/accounts_home/accounts_home.js @@ -154,6 +154,11 @@ wn.module_page["Accounts"] = [ route: "query-report/Sales Register", doctype: "Sales Invoice" }, + { + "label":wn._("Purchase Register"), + route: "query-report/Purchase Register", + doctype: "Purchase Invoice" + }, ] }, { diff --git a/accounts/report/purchase_register/__init__.py b/accounts/report/purchase_register/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/accounts/report/purchase_register/purchase_register.js b/accounts/report/purchase_register/purchase_register.js new file mode 100644 index 0000000000..f943e84db1 --- /dev/null +++ b/accounts/report/purchase_register/purchase_register.js @@ -0,0 +1,43 @@ +wn.query_reports["Purchase Register"] = { + "add_total_row": true, + "filters": [ + { + "fieldname":"from_date", + "label": "From Date", + "fieldtype": "Date", + "default": wn.defaults.get_user_default("year_start_date"), + "width": "80" + }, + { + "fieldname":"to_date", + "label": "To Date", + "fieldtype": "Date", + "default": get_today() + }, + { + "fieldname":"account", + "label": "Account", + "fieldtype": "Link", + "options": "Account", + "get_query": function() { + var company = wn.query_report.filters_by_name.company.get_value(); + return { + "query": "accounts.utils.get_account_list", + "filters": { + "is_pl_account": "No", + "debit_or_credit": "Credit", + "company": company, + "master_type": "Supplier" + } + } + } + }, + { + "fieldname":"company", + "label": "Company", + "fieldtype": "Link", + "options": "Company", + "default": sys_defaults.company + } + ] +} \ No newline at end of file diff --git a/accounts/report/purchase_register/purchase_register.py b/accounts/report/purchase_register/purchase_register.py new file mode 100644 index 0000000000..01dc93700b --- /dev/null +++ b/accounts/report/purchase_register/purchase_register.py @@ -0,0 +1,147 @@ +# ERPNext - web based ERP (http://erpnext.com) +# Copyright (C) 2012 Web Notes Technologies Pvt Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from __future__ import unicode_literals +import webnotes +from webnotes.utils import flt + +def execute(filters=None): + if not filters: filters = {} + columns, expense_accounts, tax_accounts = get_columns() + + invoice_list = get_invoices(filters) + invoice_expense_map = get_invoice_expense_map(invoice_list) + invoice_tax_map = get_invoice_tax_map(invoice_list) + invoice_po_pr_map = get_invoice_po_pr_map(invoice_list) + account_map = get_account_details(invoice_list) + + data = [] + for inv in invoice_list: + # invoice details + purchase_order = ", ".join(invoice_po_pr_map.get(inv.name, {}).get("purchase_order", [])) + purchase_receipt = ", ".join(invoice_po_pr_map.get(inv.name, {}).get("purchase_receipt", [])) + row = [inv.name, inv.posting_date, inv.supplier, inv.credit_to, + account_map.get(inv.credit_to), inv.project_name, inv.bill_no, inv.bill_date, + inv.remarks, purchase_order, purchase_receipt] + + # map expense values + for expense_acc in expense_accounts: + row.append(invoice_expense_map.get(inv.name, {}).get(expense_acc)) + + # net total + row.append(inv.net_total) + + # tax account + for tax_acc in tax_accounts: + row.append(invoice_tax_map.get(inv.name, {}).get(tax_acc)) + + # total tax, grand total + row += [inv.total_tax, inv.grand_total] + data.append(row) + + return columns, data + + +def get_columns(): + """return columns based on filters""" + columns = [ + "Invoice:Link/Purchase Invoice:120", "Posting Date:Date:80", "Supplier:Link/Supplier:120", + "Supplier Account:Link/Account:120", "Account Group:LInk/Account:120", + "Project:Link/Project:80", "Bill No::120", "Bill Date:Date:80", "Remarks::150", + "Purchase Order:Link/Purchase Order:100", "Purchase Receipt:Link/Purchase Receipt:100" + ] + + expense_accounts = webnotes.conn.sql_list("""select distinct expense_head + from `tabPurchase Invoice Item` where docstatus = 1 and ifnull(expense_head, '') != '' + order by expense_head""") + tax_accounts = webnotes.conn.sql_list("""select distinct account_head + from `tabPurchase Taxes and Charges` where parenttype = 'Purchase Invoice' + and docstatus = 1 and ifnull(account_head, '') != '' order by account_head""") + + columns = columns + [(account + ":Currency:120") for account in expense_accounts] + \ + ["Net Total:Currency:120"] + [(account + ":Currency:120") for account in tax_accounts] + \ + ["Total Tax:Currency:120"] + ["Grand Total:Currency:120"] + + return columns, expense_accounts, tax_accounts + +def get_conditions(filters): + conditions = "" + + if filters.get("company"): conditions += " and company=%(company)s" + if filters.get("account"): conditions += " and account = %(account)s" + + if filters.get("from_date"): conditions += " and posting_date>=%(from_date)s" + if filters.get("to_date"): conditions += " and posting_date<=%(to_date)s" + + return conditions + +def get_invoices(filters): + conditions = get_conditions(filters) + return webnotes.conn.sql("""select name, posting_date, credit_to, project_name, supplier, + bill_no, bill_date, remarks, net_total, total_tax, grand_total + from `tabPurchase Invoice` where docstatus = 1 %s + order by posting_date desc, name desc""" % conditions, filters, as_dict=1) + +def get_invoice_expense_map(invoice_list): + expense_details = webnotes.conn.sql("""select parent, expense_head, sum(amount) as amount + from `tabPurchase Invoice Item` where parent in (%s) group by parent, expense_head""" % + ', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1) + + invoice_expense_map = {} + for d in expense_details: + invoice_expense_map.setdefault(d.parent, webnotes._dict()).setdefault(d.expense_head, []) + invoice_expense_map[d.parent][d.expense_head] = flt(d.amount) + + return invoice_expense_map + +def get_invoice_tax_map(invoice_list): + tax_details = webnotes.conn.sql("""select parent, account_head, sum(tax_amount) as tax_amount + from `tabPurchase Taxes and Charges` where parent in (%s) group by parent, account_head""" % + ', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1) + + invoice_tax_map = {} + for d in tax_details: + invoice_tax_map.setdefault(d.parent, webnotes._dict()).setdefault(d.account_head, []) + invoice_tax_map[d.parent][d.account_head] = flt(d.tax_amount) + + return invoice_tax_map + +def get_invoice_po_pr_map(invoice_list): + pi_items = webnotes.conn.sql("""select parent, purchase_order, purchase_receipt + from `tabPurchase Invoice Item` where parent in (%s) + and (ifnull(purchase_order, '') != '' or ifnull(purchase_receipt, '') != '')""" % + ', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1) + + invoice_po_pr_map = {} + for d in pi_items: + if d.purchase_order: + invoice_po_pr_map.setdefault(d.parent, webnotes._dict()).setdefault( + "purchase_order", []).append(d.purchase_order) + if d.purchase_receipt: + invoice_po_pr_map.setdefault(d.parent, webnotes._dict()).setdefault( + "purchase_receipt", []).append(d.purchase_receipt) + + return invoice_po_pr_map + +def get_account_details(invoice_list): + account_map = {} + accounts = list(set([inv.credit_to for inv in invoice_list])) + for acc in webnotes.conn.sql("""select name, parent_account from tabAccount + where name in (%s)""" % ", ".join(["%s"]*len(accounts)), tuple(accounts), as_dict=1): + account_map.setdefault(acc.name, "") + account_map[acc.name] = acc.parent_account + + return account_map \ No newline at end of file diff --git a/accounts/report/purchase_register/purchase_register.txt b/accounts/report/purchase_register/purchase_register.txt new file mode 100644 index 0000000000..799971ef0a --- /dev/null +++ b/accounts/report/purchase_register/purchase_register.txt @@ -0,0 +1,21 @@ +[ + { + "creation": "2013-04-29 16:13:11", + "docstatus": 0, + "modified": "2013-04-29 16:13:11", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "doctype": "Report", + "is_standard": "Yes", + "name": "__common__", + "ref_doctype": "Purchase Invoice", + "report_name": "Purchase Register", + "report_type": "Script Report" + }, + { + "doctype": "Report", + "name": "Purchase Register" + } +] \ No newline at end of file diff --git a/accounts/report/sales_register/sales_register.js b/accounts/report/sales_register/sales_register.js index 82246198c9..cf4543a713 100644 --- a/accounts/report/sales_register/sales_register.js +++ b/accounts/report/sales_register/sales_register.js @@ -1,4 +1,5 @@ wn.query_reports["Sales Register"] = { + "add_total_row": true, "filters": [ { "fieldname":"from_date", diff --git a/accounts/report/sales_register/sales_register.py b/accounts/report/sales_register/sales_register.py index 07772cb4e2..a0020c45a0 100644 --- a/accounts/report/sales_register/sales_register.py +++ b/accounts/report/sales_register/sales_register.py @@ -94,8 +94,8 @@ def get_conditions(filters): def get_invoices(filters): conditions = get_conditions(filters) - return webnotes.conn.sql("""select name, posting_date, territory, debit_to, territory, - project_name, customer, remarks, net_total, other_charges_total, grand_total + return webnotes.conn.sql("""select name, posting_date, debit_to, project_name, customer, + remarks, net_total, other_charges_total, grand_total from `tabSales Invoice` where docstatus = 1 %s order by posting_date desc, name desc""" % conditions, filters, as_dict=1) diff --git a/accounts/search_criteria/bank_clearance_report/bank_clearance_report.txt b/accounts/search_criteria/bank_clearance_report/bank_clearance_report.txt index 00384386f5..8aa94bf50a 100644 --- a/accounts/search_criteria/bank_clearance_report/bank_clearance_report.txt +++ b/accounts/search_criteria/bank_clearance_report/bank_clearance_report.txt @@ -1,29 +1,32 @@ [ { - "owner": "Administrator", + "creation": "2012-05-14 18:05:41", "docstatus": 0, - "creation": "2012-04-03 12:49:50", + "modified": "2013-04-30 14:49:06", "modified_by": "Administrator", - "modified": "2012-04-03 12:49:50" + "owner": "Administrator" }, { - "description": "Bank Clearance report", - "parent_doc_type": "Journal Voucher", - "module": "Accounts", - "standard": "Yes", - "sort_order": "DESC", - "filters": "{'Journal Voucher\u0001Submitted':1,'Journal Voucher\u0001Voucher Type':'','Journal Voucher\u0001Is Opening':'','Journal Voucher\u0001Fiscal Year':'','Journal Voucher\u0001Company':'','Journal Voucher\u0001TDS Applicable':'','Journal Voucher\u0001TDS Category':''}", - "dis_filters": "fiscal_year", - "doc_type": "Journal Voucher Detail", - "name": "__common__", - "doctype": "Search Criteria", - "sort_by": "ID", - "page_len": 50, + "columns": "Journal Voucher\u0001ID,Journal Voucher Detail\u0001Account,Journal Voucher Detail\u0001Debit,Journal Voucher Detail\u0001Credit,Journal Voucher\u0001Clearance Date,Journal Voucher\u0001Cheque No,Journal Voucher\u0001Cheque Date,Journal Voucher\u0001Voucher Date,Journal Voucher\u0001Posting Date,Journal Voucher Detail\u0001Against Payable,Journal Voucher Detail\u0001Against Receivable", "criteria_name": "Bank Clearance report", - "columns": "Journal Voucher\u0001ID,Journal Voucher Detail\u0001Account,Journal Voucher Detail\u0001Debit,Journal Voucher Detail\u0001Credit,Journal Voucher\u0001Clearance Date,Journal Voucher\u0001Cheque No,Journal Voucher\u0001Cheque Date,Journal Voucher\u0001Voucher Date,Journal Voucher\u0001Posting Date,Journal Voucher Detail\u0001Against Payable,Journal Voucher Detail\u0001Against Receivable" + "custom_query": "", + "description": "Bank Clearance report", + "dis_filters": "fiscal_year", + "disabled": 0, + "doc_type": "Journal Voucher Detail", + "doctype": "Search Criteria", + "filters": "{'Journal Voucher\u0001Submitted':1,'Journal Voucher\u0001Voucher Type':'','Journal Voucher\u0001Is Opening':'','Journal Voucher\u0001Fiscal Year':'','Journal Voucher\u0001Company':'','Journal Voucher\u0001TDS Applicable':'','Journal Voucher\u0001TDS Category':''}", + "module": "Accounts", + "name": "__common__", + "page_len": 50, + "parent_doc_type": "Journal Voucher", + "report_script": null, + "sort_by": "ID", + "sort_order": "DESC", + "standard": "Yes" }, { - "name": "bank_clearance_report", - "doctype": "Search Criteria" + "doctype": "Search Criteria", + "name": "bank_clearance_report" } ] \ No newline at end of file From 84e2af2212bf3025a06ae9dbb5b565d36e62afd0 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 30 Apr 2013 18:08:43 +0530 Subject: [PATCH 22/38] [report] add total row --- .../report/accounts_payable/accounts_payable.py | 12 ++---------- .../report/accounts_payable/accounts_payable.txt | 3 ++- .../accounts_receivable/accounts_receivable.py | 13 ++----------- .../accounts_receivable/accounts_receivable.txt | 3 ++- .../report/purchase_register/purchase_register.js | 1 - .../report/purchase_register/purchase_register.txt | 3 ++- accounts/report/sales_register/sales_register.js | 1 - accounts/report/sales_register/sales_register.txt | 3 ++- 8 files changed, 12 insertions(+), 27 deletions(-) diff --git a/accounts/report/accounts_payable/accounts_payable.py b/accounts/report/accounts_payable/accounts_payable.py index 34c8ccd2be..a10dc7e7e7 100644 --- a/accounts/report/accounts_payable/accounts_payable.py +++ b/accounts/report/accounts_payable/accounts_payable.py @@ -19,7 +19,6 @@ def execute(filters=None): and nowdate() or filters.get("report_date") data = [] - total_invoiced_amount = total_paid = total_outstanding = 0 for gle in entries: if cstr(gle.against_voucher) == gle.voucher_no or not gle.against_voucher \ or [gle.against_voucher_type, gle.against_voucher] in entries_after_report_date: @@ -36,7 +35,7 @@ def execute(filters=None): paid_amount = get_paid_amount(gle, filters.get("report_date") or nowdate(), entries_after_report_date) outstanding_amount = invoiced_amount - paid_amount - + if abs(flt(outstanding_amount)) > 0.01: row = [gle.posting_date, gle.account, gle.voucher_type, gle.voucher_no, gle.remarks, account_supplier_type_map.get(gle.account), due_date, bill_no, @@ -47,16 +46,9 @@ def execute(filters=None): ageing_based_on_date = due_date else: ageing_based_on_date = gle.posting_date + row += get_ageing_data(ageing_based_on_date, age_on, outstanding_amount) - - # Add to total - total_invoiced_amount += flt(invoiced_amount) - total_paid += flt(paid_amount) - total_outstanding += flt(outstanding_amount) data.append(row) - if data: - data.append(["", "", "", "", "", "", "", "Total", "", total_invoiced_amount, total_paid, - total_outstanding, "", "", "", ""]) return columns, data diff --git a/accounts/report/accounts_payable/accounts_payable.txt b/accounts/report/accounts_payable/accounts_payable.txt index 8920a0bf2e..6de97f64e6 100644 --- a/accounts/report/accounts_payable/accounts_payable.txt +++ b/accounts/report/accounts_payable/accounts_payable.txt @@ -2,11 +2,12 @@ { "creation": "2013-04-22 16:16:03", "docstatus": 0, - "modified": "2013-04-23 14:54:27", + "modified": "2013-04-30 17:55:54", "modified_by": "Administrator", "owner": "Administrator" }, { + "add_total_row": 1, "doctype": "Report", "is_standard": "Yes", "name": "__common__", diff --git a/accounts/report/accounts_receivable/accounts_receivable.py b/accounts/report/accounts_receivable/accounts_receivable.py index d385b36b90..a8c6d2311e 100644 --- a/accounts/report/accounts_receivable/accounts_receivable.py +++ b/accounts/report/accounts_receivable/accounts_receivable.py @@ -18,7 +18,6 @@ def execute(filters=None): and nowdate() or filters.get("report_date") data = [] - total_invoiced_amount = total_payment = total_outstanding = 0 for gle in entries: if cstr(gle.against_voucher) == gle.voucher_no or not gle.against_voucher \ or [gle.against_voucher_type, gle.against_voucher] in entries_after_report_date: @@ -41,17 +40,9 @@ def execute(filters=None): else: ageing_based_on_date = gle.posting_date row += get_ageing_data(ageing_based_on_date, age_on, outstanding_amount) - - # Add to total - total_invoiced_amount += flt(invoiced_amount) - total_payment += flt(payment_amount) - total_outstanding += flt(outstanding_amount) - + data.append(row) - if data: - data.append(["", "", "", "", "", "", "Total", total_invoiced_amount, total_payment, - total_outstanding, "", "", "", ""]) - + return columns, data def get_columns(): diff --git a/accounts/report/accounts_receivable/accounts_receivable.txt b/accounts/report/accounts_receivable/accounts_receivable.txt index 28f7e4f44d..7eb344fc08 100644 --- a/accounts/report/accounts_receivable/accounts_receivable.txt +++ b/accounts/report/accounts_receivable/accounts_receivable.txt @@ -2,11 +2,12 @@ { "creation": "2013-04-16 11:31:13", "docstatus": 0, - "modified": "2013-04-16 11:31:13", + "modified": "2013-04-30 17:54:47", "modified_by": "Administrator", "owner": "Administrator" }, { + "add_total_row": 1, "doctype": "Report", "is_standard": "Yes", "name": "__common__", diff --git a/accounts/report/purchase_register/purchase_register.js b/accounts/report/purchase_register/purchase_register.js index f943e84db1..21e0547f4a 100644 --- a/accounts/report/purchase_register/purchase_register.js +++ b/accounts/report/purchase_register/purchase_register.js @@ -1,5 +1,4 @@ wn.query_reports["Purchase Register"] = { - "add_total_row": true, "filters": [ { "fieldname":"from_date", diff --git a/accounts/report/purchase_register/purchase_register.txt b/accounts/report/purchase_register/purchase_register.txt index 799971ef0a..847f5f3b6c 100644 --- a/accounts/report/purchase_register/purchase_register.txt +++ b/accounts/report/purchase_register/purchase_register.txt @@ -2,11 +2,12 @@ { "creation": "2013-04-29 16:13:11", "docstatus": 0, - "modified": "2013-04-29 16:13:11", + "modified": "2013-04-30 17:51:19", "modified_by": "Administrator", "owner": "Administrator" }, { + "add_total_row": 1, "doctype": "Report", "is_standard": "Yes", "name": "__common__", diff --git a/accounts/report/sales_register/sales_register.js b/accounts/report/sales_register/sales_register.js index cf4543a713..82246198c9 100644 --- a/accounts/report/sales_register/sales_register.js +++ b/accounts/report/sales_register/sales_register.js @@ -1,5 +1,4 @@ wn.query_reports["Sales Register"] = { - "add_total_row": true, "filters": [ { "fieldname":"from_date", diff --git a/accounts/report/sales_register/sales_register.txt b/accounts/report/sales_register/sales_register.txt index 5aef814596..dbf41af0d0 100644 --- a/accounts/report/sales_register/sales_register.txt +++ b/accounts/report/sales_register/sales_register.txt @@ -2,11 +2,12 @@ { "creation": "2013-04-23 18:15:29", "docstatus": 0, - "modified": "2013-04-23 18:15:29", + "modified": "2013-04-30 17:53:10", "modified_by": "Administrator", "owner": "Administrator" }, { + "add_total_row": 1, "doctype": "Report", "is_standard": "Yes", "name": "__common__", From 76646fb279849deafe52ffc3451ac6d1945a6b08 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 1 May 2013 11:23:44 +0530 Subject: [PATCH 23/38] [script report] bank reconciliation statement in new style --- accounts/page/accounts_home/accounts_home.js | 5 ++ .../bank_reconciliation_statement/__init__.py | 0 .../bank_reconciliation_statement.js | 25 ++++++++ .../bank_reconciliation_statement.py | 63 +++++++++++++++++++ .../bank_reconciliation_statement.txt | 22 +++++++ 5 files changed, 115 insertions(+) create mode 100644 accounts/report/bank_reconciliation_statement/__init__.py create mode 100644 accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js create mode 100644 accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py create mode 100644 accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.txt diff --git a/accounts/page/accounts_home/accounts_home.js b/accounts/page/accounts_home/accounts_home.js index 6a9f91a719..5779307f70 100644 --- a/accounts/page/accounts_home/accounts_home.js +++ b/accounts/page/accounts_home/accounts_home.js @@ -187,6 +187,11 @@ wn.module_page["Accounts"] = [ right: true, icon: "icon-list", items: [ + { + "label":wn._("Bank Reconciliation Statement"), + route: "query-report/Bank Reconciliation Statement", + doctype: "Journal Voucher" + }, { "label":wn._("Delivered Items To Be Billed"), route: "query-report/Delivered Items To Be Billed", diff --git a/accounts/report/bank_reconciliation_statement/__init__.py b/accounts/report/bank_reconciliation_statement/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js b/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js new file mode 100644 index 0000000000..28ac9205a6 --- /dev/null +++ b/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js @@ -0,0 +1,25 @@ +wn.query_reports["Bank Reconciliation Statement"] = { + "filters": [ + { + "fieldname":"account", + "label": "Bank Account", + "fieldtype": "Link", + "options": "Account", + "get_query": function() { + return { + "query": "accounts.utils.get_account_list", + "filters": { + "is_pl_account": "No", + "account_type": "Bank or Cash" + } + } + } + }, + { + "fieldname":"report_date", + "label": "Date", + "fieldtype": "Date", + "default": get_today() + }, + ] +} \ 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 new file mode 100644 index 0000000000..4275958e5d --- /dev/null +++ b/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py @@ -0,0 +1,63 @@ +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() + data = get_entries(filters) + + from accounts.utils import get_balance_on + balance_as_per_company = get_balance_on(filters["account"], filters["report_date"]) + + total_debit, total_credit = 0,0 + for d in data: + total_debit += flt(d[4]) + total_credit += flt(d[5]) + + if webnotes.conn.get_value("Account", filters["account"], "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, ""], + ["", "", "", "Amounts not reflected in bank", total_debit, total_credit], + ["", "", "", "Balance as per bank", bank_bal, ""] + ] + + 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) + + return entries \ No newline at end of file diff --git a/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.txt b/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.txt new file mode 100644 index 0000000000..9867c5ded7 --- /dev/null +++ b/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.txt @@ -0,0 +1,22 @@ +[ + { + "creation": "2013-04-30 18:30:21", + "docstatus": 0, + "modified": "2013-05-01 10:53:12", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "add_total_row": 0, + "doctype": "Report", + "is_standard": "Yes", + "name": "__common__", + "ref_doctype": "Journal Voucher", + "report_name": "Bank Reconciliation Statement", + "report_type": "Script Report" + }, + { + "doctype": "Report", + "name": "Bank Reconciliation Statement" + } +] \ No newline at end of file From 91e4c144705e1c2417e77100ac9678120c20dc97 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 1 May 2013 12:00:44 +0530 Subject: [PATCH 24/38] [fixes] [__islocal] use doc.fields.get('__islocal') instead of doc.__islocal --- accounts/doctype/cost_center/cost_center.py | 2 +- stock/doctype/item/item.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/accounts/doctype/cost_center/cost_center.py b/accounts/doctype/cost_center/cost_center.py index e57b6a3758..a7672452aa 100644 --- a/accounts/doctype/cost_center/cost_center.py +++ b/accounts/doctype/cost_center/cost_center.py @@ -81,7 +81,7 @@ class DocType(DocTypeNestedSet): """ Cost Center name must be unique """ - if (self.doc.__islocal or not self.doc.name) and webnotes.conn.sql("select name from `tabCost Center` where cost_center_name = %s and company_name=%s", (self.doc.cost_center_name, self.doc.company_name)): + if (self.doc.fields.get("__islocal") or not self.doc.name) and webnotes.conn.sql("select name from `tabCost Center` where cost_center_name = %s and company_name=%s", (self.doc.cost_center_name, self.doc.company_name)): msgprint("Cost Center Name already exists, please rename", raise_exception=1) self.validate_mandatory() diff --git a/stock/doctype/item/item.py b/stock/doctype/item/item.py index fce6f32543..6b6dfb3700 100644 --- a/stock/doctype/item/item.py +++ b/stock/doctype/item/item.py @@ -55,7 +55,7 @@ class DocType(DocListController): ch.conversion_factor = 1 def check_stock_uom_with_bin(self): - if not self.doc.__islocal: + if not self.doc.fields.get("__islocal"): bin = webnotes.conn.sql("select stock_uom from `tabBin` where item_code = %s", self.doc.name) if self.doc.stock_uom and bin and cstr(bin[0][0]) \ From 4120ffefa1657255eae64d89b5cc276afe4ed200 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 1 May 2013 12:14:57 +0530 Subject: [PATCH 25/38] [project] [query] removed debug --- projects/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/utils.py b/projects/utils.py index a7a016ab3e..7a45b08d9d 100644 --- a/projects/utils.py +++ b/projects/utils.py @@ -5,4 +5,4 @@ import webnotes @webnotes.whitelist() def get_time_log_list(doctype, txt, searchfield, start, page_len, filters): - return webnotes.conn.get_values("Time Log", filters, ["name", "activity_type", "owner"], debug=True) \ No newline at end of file + return webnotes.conn.get_values("Time Log", filters, ["name", "activity_type", "owner"]) \ No newline at end of file From e388465e17acf20a00bf54c2870c7944d3524aa0 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 1 May 2013 12:23:07 +0530 Subject: [PATCH 26/38] [script report] bank clearance summary --- accounts/page/accounts_home/accounts_home.js | 5 ++ .../report/bank_clearance_summary/__init__.py | 0 .../bank_clearance_summary.js | 32 +++++++++++ .../bank_clearance_summary.py | 54 +++++++++++++++++++ .../bank_clearance_summary.txt | 21 ++++++++ .../bank_reconciliation_statement.py | 16 ++++++ .../delivered_items_to_be_billed.txt | 4 +- 7 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 accounts/report/bank_clearance_summary/__init__.py create mode 100644 accounts/report/bank_clearance_summary/bank_clearance_summary.js create mode 100644 accounts/report/bank_clearance_summary/bank_clearance_summary.py create mode 100644 accounts/report/bank_clearance_summary/bank_clearance_summary.txt diff --git a/accounts/page/accounts_home/accounts_home.js b/accounts/page/accounts_home/accounts_home.js index 5779307f70..99d92b576c 100644 --- a/accounts/page/accounts_home/accounts_home.js +++ b/accounts/page/accounts_home/accounts_home.js @@ -202,6 +202,11 @@ wn.module_page["Accounts"] = [ route: "query-report/Ordered Items To Be Billed", doctype: "Sales Invoice" }, + { + "label":wn._("Bank Clearance Summary"), + route: "query-report/Bank Clearance Summary", + doctype: "Journal Voucher" + }, ] } ] diff --git a/accounts/report/bank_clearance_summary/__init__.py b/accounts/report/bank_clearance_summary/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/accounts/report/bank_clearance_summary/bank_clearance_summary.js b/accounts/report/bank_clearance_summary/bank_clearance_summary.js new file mode 100644 index 0000000000..76adfd3174 --- /dev/null +++ b/accounts/report/bank_clearance_summary/bank_clearance_summary.js @@ -0,0 +1,32 @@ +wn.query_reports["Bank Clearance Summary"] = { + "filters": [ + { + "fieldname":"from_date", + "label": "From Date", + "fieldtype": "Date", + "default": wn.defaults.get_user_default("year_start_date"), + "width": "80" + }, + { + "fieldname":"to_date", + "label": "To Date", + "fieldtype": "Date", + "default": get_today() + }, + { + "fieldname":"account", + "label": "Bank Account", + "fieldtype": "Link", + "options": "Account", + "get_query": function() { + return { + "query": "accounts.utils.get_account_list", + "filters": { + "is_pl_account": "No", + "account_type": "Bank or Cash" + } + } + } + }, + ] +} \ No newline at end of file diff --git a/accounts/report/bank_clearance_summary/bank_clearance_summary.py b/accounts/report/bank_clearance_summary/bank_clearance_summary.py new file mode 100644 index 0000000000..49ac1a46c8 --- /dev/null +++ b/accounts/report/bank_clearance_summary/bank_clearance_summary.py @@ -0,0 +1,54 @@ +# ERPNext - web based ERP (http://erpnext.com) +# Copyright (C) 2012 Web Notes Technologies Pvt Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from __future__ import unicode_literals +import webnotes +from webnotes import _, msgprint + +def execute(filters=None): + if not filters: filters = {} + + columns = get_columns() + data = get_entries(filters) + + return columns, data + +def get_columns(): + return ["Journal Voucher:Link/Journal Voucher:140", "Account:Link/Account: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 filters.get("from_date"): conditions += " and jv.posting_date>=%(from_date)s" + if filters.get("to_date"): conditions += " and jv.posting_date<=%(to_date)s" + + return conditions + +def get_entries(filters): + conditions = get_conditions(filters) + entries = webnotes.conn.sql("""select jv.name, jvd.account, 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 %s + order by jv.name DESC""" % conditions, filters, as_list=1) + return entries \ No newline at end of file diff --git a/accounts/report/bank_clearance_summary/bank_clearance_summary.txt b/accounts/report/bank_clearance_summary/bank_clearance_summary.txt new file mode 100644 index 0000000000..3dd2079f3a --- /dev/null +++ b/accounts/report/bank_clearance_summary/bank_clearance_summary.txt @@ -0,0 +1,21 @@ +[ + { + "creation": "2013-05-01 12:13:25", + "docstatus": 0, + "modified": "2013-05-01 12:13:25", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "doctype": "Report", + "is_standard": "Yes", + "name": "__common__", + "ref_doctype": "Journal Voucher", + "report_name": "Bank Clearance Summary", + "report_type": "Script Report" + }, + { + "doctype": "Report", + "name": "Bank Clearance Summary" + } +] \ 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 4275958e5d..1345cd8006 100644 --- a/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py +++ b/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py @@ -1,3 +1,19 @@ +# ERPNext - web based ERP (http://erpnext.com) +# Copyright (C) 2012 Web Notes Technologies Pvt Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + from __future__ import unicode_literals import webnotes from webnotes import _, msgprint diff --git a/accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.txt b/accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.txt index c84854f39d..e84c597b1d 100644 --- a/accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.txt +++ b/accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.txt @@ -1,8 +1,8 @@ [ { - "creation": "2013-02-22 17:55:23", + "creation": "2013-02-25 10:38:57", "docstatus": 0, - "modified": "2013-02-23 14:35:28", + "modified": "2013-05-01 11:56:43", "modified_by": "Administrator", "owner": "Administrator" }, From e97b07e43fe436049daf8b9e9620dd151d16d1fd Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 1 May 2013 14:12:19 +0530 Subject: [PATCH 27/38] [backup manager] [fix] manage mysql connection --- setup/doctype/backup_manager/backup_dropbox.py | 2 ++ setup/doctype/backup_manager/backup_googledrive.py | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/setup/doctype/backup_manager/backup_dropbox.py b/setup/doctype/backup_manager/backup_dropbox.py index ac07824a88..054d2b26b6 100644 --- a/setup/doctype/backup_manager/backup_dropbox.py +++ b/setup/doctype/backup_manager/backup_dropbox.py @@ -85,6 +85,7 @@ def backup_to_dropbox(): os.path.basename(backup.backup_path_db)) upload_file_to_dropbox(filename, "/database", dropbox_client) + webnotes.conn.close() response = dropbox_client.metadata("/files") # upload files to files folder @@ -108,6 +109,7 @@ def backup_to_dropbox(): did_not_upload.append(filename) error_log.append(cstr(e)) + webnotes.connect() return did_not_upload, list(set(error_log)) def get_dropbox_session(): diff --git a/setup/doctype/backup_manager/backup_googledrive.py b/setup/doctype/backup_manager/backup_googledrive.py index 7d980debe7..a705f0efa9 100644 --- a/setup/doctype/backup_manager/backup_googledrive.py +++ b/setup/doctype/backup_manager/backup_googledrive.py @@ -34,7 +34,6 @@ def get_gdrive_authorize_url(): "authorize_url": authorize_url, } -@webnotes.whitelist() def upload_files(name, mimetype, service, folder_id): if not webnotes.conn: webnotes.connect() @@ -78,6 +77,9 @@ def backup_to_gdrive(): did_not_upload = [] error_log = [] + files_folder_id = webnotes.conn.get_value("Backup Manager", None, "files_folder_id") + + webnotes.conn.close() path = os.path.join(get_base_path(), "public", "files") for filename in os.listdir(path): found = False @@ -91,9 +93,7 @@ def backup_to_gdrive(): #Compare Local File with Server File param = {} - children = drive_service.children().list( - folderId=webnotes.conn.get_value("Backup Manager", None, "files_folder_id"), - **param).execute() + children = drive_service.children().list(folderId=files_folder_id, **param).execute() for child in children.get('items', []): file = drive_service.files().get(fileId=child['id']).execute() if filename == file['title'] and size == int(file['fileSize']): @@ -101,12 +101,12 @@ def backup_to_gdrive(): break if not found: try: - upload_files(filepath, mimetype, drive_service, - webnotes.conn.get_value("Backup Manager", None, "files_folder_id")) + upload_files(filepath, mimetype, drive_service, files_folder_id) except Exception, e: did_not_upload.append(filename) error_log.append(cstr(e)) + webnotes.connect() return did_not_upload, list(set(error_log)) def get_gdrive_flow(): From 006d074b260574d5d1b556b0f8e9fb96d2c9d327 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 1 May 2013 15:05:29 +0530 Subject: [PATCH 28/38] [script report] collection report --- .../accounts_payable/accounts_payable.py | 5 +- .../accounts_receivable.py | 7 +- accounts/report/collection_report/__init__.py | 0 .../collection_report/collection_report.js | 42 +++++++++ .../collection_report/collection_report.py | 86 +++++++++++++++++++ .../collection_report/collection_report.txt | 22 +++++ .../purchase_register/purchase_register.py | 1 - .../report/sales_register/sales_register.py | 2 - 8 files changed, 155 insertions(+), 10 deletions(-) create mode 100644 accounts/report/collection_report/__init__.py create mode 100644 accounts/report/collection_report/collection_report.js create mode 100644 accounts/report/collection_report/collection_report.py create mode 100644 accounts/report/collection_report/collection_report.txt diff --git a/accounts/report/accounts_payable/accounts_payable.py b/accounts/report/accounts_payable/accounts_payable.py index a10dc7e7e7..5e944a1b84 100644 --- a/accounts/report/accounts_payable/accounts_payable.py +++ b/accounts/report/accounts_payable/accounts_payable.py @@ -67,8 +67,7 @@ def get_gl_entries(filters, before_report_date=True): gl_entries = [] gl_entries = webnotes.conn.sql("""select * from `tabGL Entry` where ifnull(is_cancelled, 'No') = 'No' %s order by posting_date, account""" % - (conditions) % (", ".join(['%s']*len(supplier_accounts))), - tuple(supplier_accounts), as_dict=1) + (conditions), tuple(supplier_accounts), as_dict=1) return gl_entries def get_conditions(filters, before_report_date=True): @@ -85,7 +84,7 @@ def get_conditions(filters, before_report_date=True): conditions, filters) if supplier_accounts: - conditions += " and account in (%s)" + conditions += " and account in (%s)" % (", ".join(['%s']*len(supplier_accounts))) if filters.get("report_date"): if before_report_date: diff --git a/accounts/report/accounts_receivable/accounts_receivable.py b/accounts/report/accounts_receivable/accounts_receivable.py index a8c6d2311e..47908c3f13 100644 --- a/accounts/report/accounts_receivable/accounts_receivable.py +++ b/accounts/report/accounts_receivable/accounts_receivable.py @@ -58,8 +58,7 @@ def get_gl_entries(filters, upto_report_date=True): conditions, customer_accounts = get_conditions(filters, upto_report_date) return webnotes.conn.sql("""select * from `tabGL Entry` where ifnull(is_cancelled, 'No') = 'No' %s order by posting_date, account""" % - (conditions) % (", ".join(['%s']*len(customer_accounts))), - tuple(customer_accounts), as_dict=1) + (conditions), tuple(customer_accounts), as_dict=1) def get_conditions(filters, upto_report_date=True): conditions = "" @@ -75,7 +74,7 @@ def get_conditions(filters, upto_report_date=True): conditions, filters) if customer_accounts: - conditions += " and account in (%s)" + conditions += " and account in (%s)" % (", ".join(['%s']*len(customer_accounts))) if filters.get("report_date"): if upto_report_date: @@ -96,7 +95,7 @@ def get_account_territory_map(): def get_si_due_date_map(): """ get due_date from sales invoice """ si_due_date_map = {} - for t in webnotes.conn.sql("""select name, due_date from `tabSales Invoice` group by name"""): + for t in webnotes.conn.sql("""select name, due_date from `tabSales Invoice`"""): si_due_date_map[t[0]] = t[1] return si_due_date_map diff --git a/accounts/report/collection_report/__init__.py b/accounts/report/collection_report/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/accounts/report/collection_report/collection_report.js b/accounts/report/collection_report/collection_report.js new file mode 100644 index 0000000000..697a779c16 --- /dev/null +++ b/accounts/report/collection_report/collection_report.js @@ -0,0 +1,42 @@ +wn.query_reports["Collection Report"] = { + "filters": [ + { + "fieldname":"from_date", + "label": "From Date", + "fieldtype": "Date", + "default": wn.defaults.get_user_default("year_start_date"), + "width": "80" + }, + { + "fieldname":"to_date", + "label": "To Date", + "fieldtype": "Date", + "default": get_today() + }, + { + "fieldname":"account", + "label": "Customer Account", + "fieldtype": "Link", + "options": "Account", + "get_query": function() { + var company = wn.query_report.filters_by_name.company.get_value(); + return { + "query": "accounts.utils.get_account_list", + "filters": { + "is_pl_account": "No", + "debit_or_credit": "Debit", + "company": company, + "master_type": "Customer" + } + } + } + }, + { + "fieldname":"company", + "label": "Company", + "fieldtype": "Link", + "options": "Company", + "default": sys_defaults.company + }, + ] +} \ No newline at end of file diff --git a/accounts/report/collection_report/collection_report.py b/accounts/report/collection_report/collection_report.py new file mode 100644 index 0000000000..50f74e0e82 --- /dev/null +++ b/accounts/report/collection_report/collection_report.py @@ -0,0 +1,86 @@ +# ERPNext - web based ERP (http://erpnext.com) +# Copyright (C) 2012 Web Notes Technologies Pvt Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from __future__ import unicode_literals +import webnotes +from accounts.report.accounts_receivable.accounts_receivable import get_ageing_data + +def execute(filters=None): + if not filters: filters = {} + + columns = get_columns() + entries = get_entries(filters) + si_posting_date_map = get_si_posting_date_map() + + data = [] + for d in entries: + against_invoice_date = d.against_invoice and si_posting_date_map[d.against_invoice] or "" + + row = [d.name, d.account, d.posting_date, d.against_invoice, against_invoice_date, + d.debit, d.credit, d.cheque_no, d.cheque_date, d.remark] + + if d.against_invoice: + row += get_ageing_data(against_invoice_date, d.posting_date, d.credit or -1*d.debit) + else: + row += ["", "", "", "", ""] + + data.append(row) + + return columns, data + +def get_columns(): + return ["Journal Voucher:Link/Journal Voucher:140", "Account:Link/Account:140", + "Posting Date:Date:100", "Against Invoice:Link/Sales Invoice:130", + "Against Invoice Posting Date:Date:130", "Debit:Currency:120", "Credit:Currency:120", + "Reference No::100", "Reference Date:Date:100", "Remarks::150", "Age:Int:40", + "0-30:Currency:100", "30-60:Currency:100", "60-90:Currency:100", "90-Above:Currency:100" + ] + +def get_conditions(filters): + conditions = "" + + customer_accounts = [] + if filters.get("account"): + customer_accounts = [filters["account"]] + elif filters.get("company"): + customer_accounts = webnotes.conn.sql_list("""select name from `tabAccount` + where ifnull(master_type, '') = 'Customer' and docstatus < 2 + and company = %s""", filters["company"]) + + if customer_accounts: + conditions += " and jvd.account in (%s)" % (", ".join(['%s']*len(customer_accounts))) + + if filters.get("from_date"): conditions += " and jv.posting_date >= '%s'" % filters["from_date"] + if filters.get("to_date"): conditions += " and jv.posting_date <= '%s'" % filters["to_date"] + + return conditions, customer_accounts + +def get_entries(filters): + conditions, customer_accounts = get_conditions(filters) + entries = webnotes.conn.sql("""select jv.name, jvd.account, jv.posting_date, + jvd.against_invoice, jvd.debit, jvd.credit, jv.cheque_no, jv.cheque_date, jv.remark + from `tabJournal Voucher Detail` jvd, `tabJournal Voucher` jv + where jvd.parent = jv.name and jv.docstatus=1 %s order by jv.name DESC""" % + (conditions), tuple(customer_accounts), as_dict=1) + + return entries + +def get_si_posting_date_map(): + si_posting_date_map = {} + for t in webnotes.conn.sql("""select name, posting_date from `tabSales Invoice`"""): + si_posting_date_map[t[0]] = t[1] + + return si_posting_date_map \ No newline at end of file diff --git a/accounts/report/collection_report/collection_report.txt b/accounts/report/collection_report/collection_report.txt new file mode 100644 index 0000000000..3933dee3a6 --- /dev/null +++ b/accounts/report/collection_report/collection_report.txt @@ -0,0 +1,22 @@ +[ + { + "creation": "2013-05-01 12:29:12", + "docstatus": 0, + "modified": "2013-05-01 12:29:12", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "add_total_row": 1, + "doctype": "Report", + "is_standard": "Yes", + "name": "__common__", + "ref_doctype": "Journal Voucher", + "report_name": "Collection Report", + "report_type": "Script Report" + }, + { + "doctype": "Report", + "name": "Collection Report" + } +] \ No newline at end of file diff --git a/accounts/report/purchase_register/purchase_register.py b/accounts/report/purchase_register/purchase_register.py index 01dc93700b..c131c17b4b 100644 --- a/accounts/report/purchase_register/purchase_register.py +++ b/accounts/report/purchase_register/purchase_register.py @@ -141,7 +141,6 @@ def get_account_details(invoice_list): accounts = list(set([inv.credit_to for inv in invoice_list])) for acc in webnotes.conn.sql("""select name, parent_account from tabAccount where name in (%s)""" % ", ".join(["%s"]*len(accounts)), tuple(accounts), as_dict=1): - account_map.setdefault(acc.name, "") account_map[acc.name] = acc.parent_account return account_map \ No newline at end of file diff --git a/accounts/report/sales_register/sales_register.py b/accounts/report/sales_register/sales_register.py index a0020c45a0..23d2227fc2 100644 --- a/accounts/report/sales_register/sales_register.py +++ b/accounts/report/sales_register/sales_register.py @@ -145,7 +145,6 @@ def get_customer_deatils(invoice_list): customers = list(set([inv.customer for inv in invoice_list])) for cust in webnotes.conn.sql("""select name, territory from `tabCustomer` where name in (%s)""" % ", ".join(["%s"]*len(customers)), tuple(customers), as_dict=1): - customer_map.setdefault(cust.name, "") customer_map[cust.name] = cust.territory return customer_map @@ -155,7 +154,6 @@ def get_account_details(invoice_list): accounts = list(set([inv.debit_to for inv in invoice_list])) for acc in webnotes.conn.sql("""select name, parent_account from tabAccount where name in (%s)""" % ", ".join(["%s"]*len(accounts)), tuple(accounts), as_dict=1): - account_map.setdefault(acc.name, "") account_map[acc.name] = acc.parent_account return account_map \ No newline at end of file From 81bbfba0cc212ce38c29ca1094e7168935c4f9d4 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 2 May 2013 11:27:25 +0530 Subject: [PATCH 29/38] [hr] allowed rename in earning and deduction type --- .../accounts_payable/accounts_payable.py | 19 ++-------- .../collection_report/collection_report.js | 2 +- hr/doctype/deduction_type/deduction_type.txt | 5 +-- hr/doctype/earning_type/earning_type.txt | 5 +-- stock/doctype/batch/batch.txt | 35 +++++-------------- 5 files changed, 18 insertions(+), 48 deletions(-) diff --git a/accounts/report/accounts_payable/accounts_payable.py b/accounts/report/accounts_payable/accounts_payable.py index 5e944a1b84..4e9b2c88ba 100644 --- a/accounts/report/accounts_payable/accounts_payable.py +++ b/accounts/report/accounts_payable/accounts_payable.py @@ -1,6 +1,7 @@ from __future__ import unicode_literals import webnotes from webnotes.utils import getdate, nowdate, flt, cstr +from accounts.report.accounts_receivable.accounts_receivable import get_ageing_data def execute(filters=None): if not filters: filters = {} @@ -124,20 +125,4 @@ def get_paid_amount(gle, report_date, entries_after_report_date): and against_voucher = %s and name != %s and ifnull(is_cancelled, 'No') = 'No'""", (gle.account, report_date, gle.voucher_type, gle.voucher_no, gle.name))[0][0] - return flt(paid_amount) - -def get_ageing_data(ageing_based_on_date, age_on, outstanding_amount): - val1 = val2 = val3 = val4 = diff = 0 - diff = age_on and ageing_based_on_date \ - and (getdate(age_on) - getdate(ageing_based_on_date)).days or 0 - - if diff <= 30: - val1 = outstanding_amount - elif 30 < diff <= 60: - val2 = outstanding_amount - elif 60 < diff <= 90: - val3 = outstanding_amount - elif diff > 90: - val4 = outstanding_amount - - return [diff, val1, val2, val3, val4] \ No newline at end of file + return flt(paid_amount) \ No newline at end of file diff --git a/accounts/report/collection_report/collection_report.js b/accounts/report/collection_report/collection_report.js index 697a779c16..b370453c5f 100644 --- a/accounts/report/collection_report/collection_report.js +++ b/accounts/report/collection_report/collection_report.js @@ -1,7 +1,7 @@ wn.query_reports["Collection Report"] = { "filters": [ { - "fieldname":"from_date", + "fieldname": "from_date", "label": "From Date", "fieldtype": "Date", "default": wn.defaults.get_user_default("year_start_date"), diff --git a/hr/doctype/deduction_type/deduction_type.txt b/hr/doctype/deduction_type/deduction_type.txt index 4c9ad7ac4c..f3467936f5 100644 --- a/hr/doctype/deduction_type/deduction_type.txt +++ b/hr/doctype/deduction_type/deduction_type.txt @@ -1,12 +1,13 @@ [ { - "creation": "2013-01-10 16:34:13", + "creation": "2013-01-22 16:50:30", "docstatus": 0, - "modified": "2013-01-22 14:25:38", + "modified": "2013-05-02 11:22:59", "modified_by": "Administrator", "owner": "Administrator" }, { + "allow_rename": 1, "autoname": "field:deduction_name", "doctype": "DocType", "document_type": "Master", diff --git a/hr/doctype/earning_type/earning_type.txt b/hr/doctype/earning_type/earning_type.txt index 18cac6821a..d69f48619c 100644 --- a/hr/doctype/earning_type/earning_type.txt +++ b/hr/doctype/earning_type/earning_type.txt @@ -1,12 +1,13 @@ [ { - "creation": "2013-01-10 16:34:13", + "creation": "2013-01-24 11:03:32", "docstatus": 0, - "modified": "2013-01-23 16:32:07", + "modified": "2013-05-02 11:22:48", "modified_by": "Administrator", "owner": "Administrator" }, { + "allow_rename": 1, "autoname": "field:earning_name", "doctype": "DocType", "document_type": "Master", diff --git a/stock/doctype/batch/batch.txt b/stock/doctype/batch/batch.txt index 4722996c0f..c6ed3c370a 100644 --- a/stock/doctype/batch/batch.txt +++ b/stock/doctype/batch/batch.txt @@ -1,8 +1,8 @@ [ { - "creation": "2013-03-01 19:09:43", + "creation": "2013-03-05 14:50:38", "docstatus": 0, - "modified": "2013-03-01 08:22:16", + "modified": "2013-05-01 15:49:47", "modified_by": "Administrator", "owner": "harshada@webnotestech.com" }, @@ -24,14 +24,19 @@ "permlevel": 0 }, { + "cancel": 1, + "create": 1, "doctype": "DocPerm", "name": "__common__", "parent": "Batch", "parentfield": "permissions", "parenttype": "DocType", + "permlevel": 0, "read": 1, + "report": 1, "role": "Material Master Manager", - "submit": 0 + "submit": 0, + "write": 1 }, { "doctype": "DocType", @@ -94,28 +99,6 @@ "oldfieldtype": "Date" }, { - "doctype": "DocField", - "fieldname": "trash_reason", - "fieldtype": "Small Text", - "label": "Trash Reason", - "oldfieldname": "trash_reason", - "oldfieldtype": "Small Text", - "read_only": 1 - }, - { - "cancel": 1, - "create": 1, - "doctype": "DocPerm", - "permlevel": 0, - "report": 1, - "write": 1 - }, - { - "amend": 0, - "cancel": 0, - "create": 0, - "doctype": "DocPerm", - "match": "", - "permlevel": 1 + "doctype": "DocPerm" } ] \ No newline at end of file From ecb36f2cb0486055ea076432878e99a3fddd5cfb Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 2 May 2013 11:34:37 +0530 Subject: [PATCH 30/38] [purchase] [validation] validate warehouse belongs to company if set --- .../doctype/purchase_order/test_purchase_order.py | 6 ++++++ controllers/buying_controller.py | 13 ++++++++++++- .../material_request/test_material_request.py | 6 ++++++ stock/doctype/warehouse/test_warehouse.py | 3 ++- 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/buying/doctype/purchase_order/test_purchase_order.py b/buying/doctype/purchase_order/test_purchase_order.py index bd27f07687..be2e2946a9 100644 --- a/buying/doctype/purchase_order/test_purchase_order.py +++ b/buying/doctype/purchase_order/test_purchase_order.py @@ -27,6 +27,12 @@ class TestPurchaseOrder(unittest.TestCase): po.insert() self.assertEquals(len(po.doclist.get({"parentfield": "po_raw_material_details"})), 2) + def test_warehouse_company_validation(self): + from controllers.buying_controller import WrongWarehouseCompany + po = webnotes.bean(copy=test_records[0]) + po.doc.company = "_Test Company 1" + self.assertRaises(WrongWarehouseCompany, po.insert) + test_dependencies = ["BOM"] diff --git a/controllers/buying_controller.py b/controllers/buying_controller.py index e167dc57b7..cd822e6ecc 100644 --- a/controllers/buying_controller.py +++ b/controllers/buying_controller.py @@ -26,10 +26,13 @@ from webnotes.model.utils import round_floats_in_doc from controllers.stock_controller import StockController +class WrongWarehouseCompany(Exception): pass + class BuyingController(StockController): def validate(self): super(BuyingController, self).validate() self.validate_stock_or_nonstock_items() + self.validate_warehouse_belongs_to_company() if self.meta.get_field("currency"): self.company_currency = get_company_currency(self.doc.company) self.validate_conversion_rate("currency", "conversion_rate") @@ -42,7 +45,15 @@ class BuyingController(StockController): # set total in words self.set_total_in_words() - + + def validate_warehouse_belongs_to_company(self): + for d in self.doclist.get({"warehouse": True}): + warehouse_company = webnotes.conn.get_value("Warehouse", d.warehouse, "company") + if warehouse_company and warehouse_company != self.doc.company: + webnotes.msgprint(_("Warehouse must belong to company") + \ + (": %s (%s, %s)" % (d.warehouse, warehouse_company, self.doc.company)), + raise_exception=WrongWarehouseCompany) + def validate_stock_or_nonstock_items(self): items = [d.item_code for d in self.doclist.get({"parentfield": self.fname})] if self.stock_items: diff --git a/stock/doctype/material_request/test_material_request.py b/stock/doctype/material_request/test_material_request.py index 080989f2d9..f5dbb52bbe 100644 --- a/stock/doctype/material_request/test_material_request.py +++ b/stock/doctype/material_request/test_material_request.py @@ -263,6 +263,12 @@ class TestMaterialRequest(unittest.TestCase): se = webnotes.bean(copy=se_doclist) self.assertRaises(webnotes.MappingMismatchError, se.insert) + def test_warehouse_company_validation(self): + from controllers.buying_controller import WrongWarehouseCompany + mr = webnotes.bean(copy=test_records[0]) + mr.doc.company = "_Test Company 1" + self.assertRaises(WrongWarehouseCompany, mr.insert) + test_records = [ [ { diff --git a/stock/doctype/warehouse/test_warehouse.py b/stock/doctype/warehouse/test_warehouse.py index 26501beab9..f3a04581a9 100644 --- a/stock/doctype/warehouse/test_warehouse.py +++ b/stock/doctype/warehouse/test_warehouse.py @@ -2,7 +2,8 @@ test_records = [ [{ "doctype": "Warehouse", "warehouse_name": "_Test Warehouse", - "warehouse_type": "_Test Warehouse Type" + "warehouse_type": "_Test Warehouse Type", + "company": "_Test Company" }], [{ "doctype": "Warehouse", From 3aeed95e0a5f51e3751ec9aa24912edccd5418c2 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 2 May 2013 11:39:46 +0530 Subject: [PATCH 31/38] [customer/supplier] [address] extended list to 5 --- buying/doctype/supplier/supplier.js | 4 ++-- selling/doctype/customer/customer.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/buying/doctype/supplier/supplier.js b/buying/doctype/supplier/supplier.js index 3834bda92c..202be71dfe 100644 --- a/buying/doctype/supplier/supplier.js +++ b/buying/doctype/supplier/supplier.js @@ -47,7 +47,7 @@ cur_frm.cscript.make_address = function() { if(!cur_frm.address_list) { cur_frm.address_list = new wn.ui.Listing({ parent: cur_frm.fields_dict['address_html'].wrapper, - page_length: 2, + page_length: 5, new_doctype: "Address", custom_new_doc: function(doctype) { var address = wn.model.make_new_doc_and_get_name('Address'); @@ -78,7 +78,7 @@ cur_frm.cscript.make_contact = function() { if(!cur_frm.contact_list) { cur_frm.contact_list = new wn.ui.Listing({ parent: cur_frm.fields_dict['contact_html'].wrapper, - page_length: 2, + page_length: 5, new_doctype: "Contact", custom_new_doc: function(doctype) { var contact = wn.model.make_new_doc_and_get_name('Contact'); diff --git a/selling/doctype/customer/customer.js b/selling/doctype/customer/customer.js index 403b83f582..40a7846430 100644 --- a/selling/doctype/customer/customer.js +++ b/selling/doctype/customer/customer.js @@ -57,7 +57,7 @@ cur_frm.cscript.make_address = function() { if(!cur_frm.address_list) { cur_frm.address_list = new wn.ui.Listing({ parent: cur_frm.fields_dict['address_html'].wrapper, - page_length: 2, + page_length: 5, new_doctype: "Address", custom_new_doc: function(doctype) { var address = wn.model.make_new_doc_and_get_name('Address'); @@ -88,7 +88,7 @@ cur_frm.cscript.make_contact = function() { if(!cur_frm.contact_list) { cur_frm.contact_list = new wn.ui.Listing({ parent: cur_frm.fields_dict['contact_html'].wrapper, - page_length: 2, + page_length: 5, custom_new_doc: function(doctype) { var contact = wn.model.make_new_doc_and_get_name('Contact'); contact = locals['Contact'][contact]; From f2edbbd5cb4b0f3c80eeee58634f38cb33e0cf7b Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 2 May 2013 11:49:02 +0530 Subject: [PATCH 32/38] [serial no][validation] status delivered -> in store, allowed for material receipt --- stock/doctype/stock_ledger/stock_ledger.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stock/doctype/stock_ledger/stock_ledger.py b/stock/doctype/stock_ledger/stock_ledger.py index 3c83de3260..8fdb50e7a4 100644 --- a/stock/doctype/stock_ledger/stock_ledger.py +++ b/stock/doctype/stock_ledger/stock_ledger.py @@ -114,7 +114,8 @@ class DocType: def update_serial_purchase_details(self, obj, d, serial_no, is_submit, purpose = '', rejected=None): exists = webnotes.conn.sql("select name, status, docstatus from `tabSerial No` where name = '%s'" % (serial_no)) if is_submit: - if exists and exists[0][2] != 2 and purpose not in ['Material Transfer', 'Sales Return']: + if exists and exists[0][2] != 2 and \ + purpose not in ['Material Transfer', "Material Receipt", 'Sales Return']: msgprint("Serial No: %s already %s" % (serial_no, exists and exists[0][1]), raise_exception = 1) elif exists: s = Document('Serial No', exists and exists[0][0]) From d7889cd5d505e4104aa60afb5192500f69cd805c Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 2 May 2013 12:14:59 +0530 Subject: [PATCH 33/38] [script report] payment collection with ageing --- accounts/page/accounts_home/accounts_home.js | 5 +++++ .../__init__.py | 0 .../payment_collection_with_ageing.js} | 2 +- .../payment_collection_with_ageing.py} | 0 .../payment_collection_with_ageing.txt} | 8 ++++---- 5 files changed, 10 insertions(+), 5 deletions(-) rename accounts/report/{collection_report => payment_collection_with_ageing}/__init__.py (100%) rename accounts/report/{collection_report/collection_report.js => payment_collection_with_ageing/payment_collection_with_ageing.js} (94%) rename accounts/report/{collection_report/collection_report.py => payment_collection_with_ageing/payment_collection_with_ageing.py} (100%) rename accounts/report/{collection_report/collection_report.txt => payment_collection_with_ageing/payment_collection_with_ageing.txt} (63%) diff --git a/accounts/page/accounts_home/accounts_home.js b/accounts/page/accounts_home/accounts_home.js index 99d92b576c..7038fe9720 100644 --- a/accounts/page/accounts_home/accounts_home.js +++ b/accounts/page/accounts_home/accounts_home.js @@ -207,6 +207,11 @@ wn.module_page["Accounts"] = [ route: "query-report/Bank Clearance Summary", doctype: "Journal Voucher" }, + { + "label":wn._("Payment Collection With Ageing"), + route: "query-report/Payment Collection With Ageing", + doctype: "Journal Voucher" + }, ] } ] diff --git a/accounts/report/collection_report/__init__.py b/accounts/report/payment_collection_with_ageing/__init__.py similarity index 100% rename from accounts/report/collection_report/__init__.py rename to accounts/report/payment_collection_with_ageing/__init__.py diff --git a/accounts/report/collection_report/collection_report.js b/accounts/report/payment_collection_with_ageing/payment_collection_with_ageing.js similarity index 94% rename from accounts/report/collection_report/collection_report.js rename to accounts/report/payment_collection_with_ageing/payment_collection_with_ageing.js index b370453c5f..d608fbd1d8 100644 --- a/accounts/report/collection_report/collection_report.js +++ b/accounts/report/payment_collection_with_ageing/payment_collection_with_ageing.js @@ -1,4 +1,4 @@ -wn.query_reports["Collection Report"] = { +wn.query_reports["Payment Collection With Ageing"] = { "filters": [ { "fieldname": "from_date", diff --git a/accounts/report/collection_report/collection_report.py b/accounts/report/payment_collection_with_ageing/payment_collection_with_ageing.py similarity index 100% rename from accounts/report/collection_report/collection_report.py rename to accounts/report/payment_collection_with_ageing/payment_collection_with_ageing.py diff --git a/accounts/report/collection_report/collection_report.txt b/accounts/report/payment_collection_with_ageing/payment_collection_with_ageing.txt similarity index 63% rename from accounts/report/collection_report/collection_report.txt rename to accounts/report/payment_collection_with_ageing/payment_collection_with_ageing.txt index 3933dee3a6..3405d197a7 100644 --- a/accounts/report/collection_report/collection_report.txt +++ b/accounts/report/payment_collection_with_ageing/payment_collection_with_ageing.txt @@ -1,8 +1,8 @@ [ { - "creation": "2013-05-01 12:29:12", + "creation": "2013-05-02 12:09:51", "docstatus": 0, - "modified": "2013-05-01 12:29:12", + "modified": "2013-05-02 12:09:51", "modified_by": "Administrator", "owner": "Administrator" }, @@ -12,11 +12,11 @@ "is_standard": "Yes", "name": "__common__", "ref_doctype": "Journal Voucher", - "report_name": "Collection Report", + "report_name": "Payment Collection With Ageing", "report_type": "Script Report" }, { "doctype": "Report", - "name": "Collection Report" + "name": "Payment Collection With Ageing" } ] \ No newline at end of file From 76b3fcdb45128cce92dc2a9936f988396f883f10 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Thu, 2 May 2013 14:14:38 +0530 Subject: [PATCH 34/38] [backup manager] [fix] hide google drive settings and show proper intro messages --- .../backup_manager/backup_googledrive.py | 3 +- .../doctype/backup_manager/backup_manager.js | 151 ++++++++++-------- .../doctype/backup_manager/backup_manager.py | 8 +- .../doctype/backup_manager/backup_manager.txt | 5 +- 4 files changed, 95 insertions(+), 72 deletions(-) diff --git a/setup/doctype/backup_manager/backup_googledrive.py b/setup/doctype/backup_manager/backup_googledrive.py index a705f0efa9..533b37ddb0 100644 --- a/setup/doctype/backup_manager/backup_googledrive.py +++ b/setup/doctype/backup_manager/backup_googledrive.py @@ -92,8 +92,7 @@ def backup_to_gdrive(): mimetype = mimetypes.types_map.get("." + ext) or "application/octet-stream" #Compare Local File with Server File - param = {} - children = drive_service.children().list(folderId=files_folder_id, **param).execute() + children = drive_service.children().list(folderId=files_folder_id).execute() for child in children.get('items', []): file = drive_service.files().get(fileId=child['id']).execute() if filename == file['title'] and size == int(file['fileSize']): diff --git a/setup/doctype/backup_manager/backup_manager.js b/setup/doctype/backup_manager/backup_manager.js index 8d2d8de853..c78be3a1eb 100644 --- a/setup/doctype/backup_manager/backup_manager.js +++ b/setup/doctype/backup_manager/backup_manager.js @@ -1,67 +1,90 @@ -cur_frm.cscript.refresh = function(doc) { - cur_frm.disable_save(); -} - -//dropbox -cur_frm.cscript.allow_dropbox_access = function(doc) { - if (doc.send_notifications_to == '') { - msgprint("Please enter email address.") - } - else { - wn.call({ - method: "setup.doctype.backup_manager.backup_dropbox.get_dropbox_authorize_url", - callback: function(r) { - if(!r.exc) { - cur_frm.set_value("dropbox_access_secret", r.message.secret); - cur_frm.set_value("dropbox_access_key", r.message.key); - cur_frm.save(null, function() { - window.open(r.message.url); - }); - } +$.extend(cur_frm.cscript, { + refresh: function() { + cur_frm.disable_save(); + + if(!(cint(cur_frm.doc.dropbox_access_allowed) || + cint(cur_frm.doc.gdrive_access_allowed))) { + cur_frm.set_intro(wn._("You can start by selecting backup frequency and \ + granting access for sync")); + } else { + var services = { + "dropbox": wn._("Dropbox"), + "gdrive": wn._("Google Drive") + } + var active_services = []; + + $.each(services, function(service, label) { + var access_allowed = cint(cur_frm.doc[service + "_access_allowed"]); + var frequency = cur_frm.doc["upload_backups_to_" + service]; + if(access_allowed && frequency && frequency !== "Never") { + active_services.push(label + " [" + frequency + "]"); + } + }); + + if(active_services.length > 0) { + cur_frm.set_intro(wn._("Backups will be uploaded to") + ": " + + wn.utils.comma_and(active_services)); + } else { + cur_frm.set_intro(""); } - }) - } -} - -cur_frm.cscript.backup_right_now = function(doc) { - msgprint("Backing up and uploading. This may take a few minutes.") - wn.call({ - method: "setup.doctype.backup_manager.backup_manager.take_backups_dropbox", - callback: function(r) { - msgprint("Backups taken. Please check your email for the response.") } - }) -} -//gdrive -cur_frm.cscript.allow_gdrive_access = function(doc) { - if (doc.send_notifications_to == '') { - msgprint("Please enter email address.") - } - else { - wn.call({ - method: "setup.doctype.backup_manager.backup_googledrive.get_gdrive_authorize_url", - callback: function(r) { - if(!r.exc) { - window.open(r.message.authorize_url); + + }, + + validate_send_notifications_to: function() { + if(!cur_frm.doc.send_notifications_to) { + msgprint(wn._("Please specify") + ": " + + wn._(wn.meta.get_label(cur_frm.doctype, "send_notifications_to"))); + return false; + } + + return true; + }, + + allow_dropbox_access: function() { + if(cur_frm.cscript.validate_send_notifications_to()) { + wn.call({ + method: "setup.doctype.backup_manager.backup_dropbox.get_dropbox_authorize_url", + callback: function(r) { + if(!r.exc) { + cur_frm.set_value("dropbox_access_secret", r.message.secret); + cur_frm.set_value("dropbox_access_key", r.message.key); + cur_frm.save(null, function() { + window.open(r.message.url); + }); + } } - } - }) - } -} - -cur_frm.cscript.validate_gdrive = function(doc) { - wn.call({ - method: "setup.doctype.backup_manager.backup_googledrive.gdrive_callback", - args: { - verification_code: doc.verification_code - }, - }); -} - -cur_frm.cscript.upload_backups_to_dropbox = function(doc) { - cur_frm.save() -} - -cur_frm.cscript.upload_backups_to_gdrive = function(doc) { - cur_frm.save() -} + }); + } + }, + + allow_gdrive_access: function() { + if(cur_frm.cscript.validate_send_notifications_to()) { + wn.call({ + method: "setup.doctype.backup_manager.backup_googledrive.get_gdrive_authorize_url", + callback: function(r) { + if(!r.exc) { + window.open(r.message.authorize_url); + } + } + }); + } + }, + + validate_gdrive: function() { + wn.call({ + method: "setup.doctype.backup_manager.backup_googledrive.gdrive_callback", + args: { + verification_code: cur_frm.doc.verification_code + }, + }); + }, + + upload_backups_to_dropbox: function() { + cur_frm.save(); + }, + + upload_backups_to_gdrive: function() { + cur_frm.save(); + }, +}); \ No newline at end of file diff --git a/setup/doctype/backup_manager/backup_manager.py b/setup/doctype/backup_manager/backup_manager.py index a8ecd636db..c91cf1110f 100644 --- a/setup/doctype/backup_manager/backup_manager.py +++ b/setup/doctype/backup_manager/backup_manager.py @@ -20,8 +20,8 @@ def take_backups_if(freq): if webnotes.conn.get_value("Backup Manager", None, "upload_backups_to_dropbox")==freq: take_backups_dropbox() - if webnotes.conn.get_value("Backup Manager", None, "upload_backups_to_gdrive")==freq: - take_backups_gdrive() + # if webnotes.conn.get_value("Backup Manager", None, "upload_backups_to_gdrive")==freq: + # take_backups_gdrive() @webnotes.whitelist() def take_backups_dropbox(): @@ -35,7 +35,7 @@ def take_backups_dropbox(): except Exception: file_and_error = [" - ".join(f) for f in zip(did_not_upload, error_log)] error_message = ("\n".join(file_and_error) + "\n" + webnotes.getTraceback()) - print error_message + webnotes.errprint(error_message) send_email(False, "Dropbox", error_message) #backup to gdrive @@ -51,7 +51,7 @@ def take_backups_gdrive(): except Exception: file_and_error = [" - ".join(f) for f in zip(did_not_upload, error_log)] error_message = ("\n".join(file_and_error) + "\n" + webnotes.getTraceback()) - print error_message + webnotes.errprint(error_message) send_email(False, "Google Drive", error_message) def send_email(success, service_name, error_status=None): diff --git a/setup/doctype/backup_manager/backup_manager.txt b/setup/doctype/backup_manager/backup_manager.txt index 9a43f34746..2d6f191e5e 100644 --- a/setup/doctype/backup_manager/backup_manager.txt +++ b/setup/doctype/backup_manager/backup_manager.txt @@ -1,8 +1,8 @@ [ { - "creation": "2013-03-15 11:06:59", + "creation": "2013-04-30 12:58:38", "docstatus": 0, - "modified": "2013-03-15 17:27:33", + "modified": "2013-05-02 11:42:08", "modified_by": "Administrator", "owner": "Administrator" }, @@ -109,6 +109,7 @@ "doctype": "DocField", "fieldname": "sync_with_gdrive", "fieldtype": "Section Break", + "hidden": 1, "label": "Sync with Google Drive" }, { From c711598940c04ed8cb7b7f873c343ab3665c21ad Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 2 May 2013 14:22:40 +0530 Subject: [PATCH 35/38] [doclist] new pattern / [item] pricelist must be unique / [formatter] show null floats as empty string --- controllers/buying_controller.py | 10 +++++----- stock/doctype/item/item.py | 12 ++++++------ stock/doctype/item/test_item.py | 17 ++++++++++++++++- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/controllers/buying_controller.py b/controllers/buying_controller.py index cd822e6ecc..0c25b9855e 100644 --- a/controllers/buying_controller.py +++ b/controllers/buying_controller.py @@ -47,13 +47,13 @@ class BuyingController(StockController): self.set_total_in_words() def validate_warehouse_belongs_to_company(self): - for d in self.doclist.get({"warehouse": True}): - warehouse_company = webnotes.conn.get_value("Warehouse", d.warehouse, "company") - if warehouse_company and warehouse_company != self.doc.company: + for warehouse, company in webnotes.conn.get_values("Warehouse", + self.doclist.get_distinct_values("warehouse"), "company").items(): + if company and company != self.doc.company: webnotes.msgprint(_("Warehouse must belong to company") + \ - (": %s (%s, %s)" % (d.warehouse, warehouse_company, self.doc.company)), + (": %s (%s, %s)" % (warehouse, company, self.doc.company)), raise_exception=WrongWarehouseCompany) - + def validate_stock_or_nonstock_items(self): items = [d.item_code for d in self.doclist.get({"parentfield": self.fname})] if self.stock_items: diff --git a/stock/doctype/item/item.py b/stock/doctype/item/item.py index 6b6dfb3700..c6bf017647 100644 --- a/stock/doctype/item/item.py +++ b/stock/doctype/item/item.py @@ -23,6 +23,7 @@ from webnotes.model.bean import getlist from webnotes import msgprint, _ from webnotes.model.controller import DocListController + class DocType(DocListController): def validate(self): if not self.doc.stock_uom: @@ -124,13 +125,12 @@ class DocType(DocListController): def check_ref_rate_detail(self): check_list=[] for d in getlist(self.doclist,'ref_rate_details'): - if [cstr(d.price_list_name), cstr(d.ref_currency), - cint(d.selling), cint(d.buying)] in check_list: - msgprint("Ref Rate is entered twice for Price List : '%s' and Currency : '%s'." % - (d.price_list_name,d.ref_currency), raise_exception=1) + if d.price_list_name in check_list: + msgprint(_("Cannot have two prices for same Price List") + ": " + d.price_list_name, + raise_exception= webnotes.DuplicateEntryError) else: - check_list.append([cstr(d.price_list_name),cstr(d.ref_currency)]) - + check_list.append(d.price_list_name) + def fill_customer_code(self): """ Append all the customer codes and insert into "customer_code" field of item table """ cust_code=[] diff --git a/stock/doctype/item/test_item.py b/stock/doctype/item/test_item.py index dbbeecc85b..a59747c3e3 100644 --- a/stock/doctype/item/test_item.py +++ b/stock/doctype/item/test_item.py @@ -20,6 +20,14 @@ import webnotes test_ignore = ["BOM"] +class TestItem(unittest.TestCase): + def test_duplicate_price_list(self): + item = webnotes.bean(copy=test_records[0]) + item.doc.item_code = "_Test Item 10" + item_price = item.doclist.get({"doctype": "Item Price"})[0] + item.doclist.append(webnotes.doc(item_price.fields.copy())) + self.assertRaises(webnotes.DuplicateEntryError, item.insert) + test_records = [ [{ "doctype": "Item", @@ -45,7 +53,14 @@ test_records = [ "warehouse": "_Test Warehouse", "warehouse_reorder_level": 20, "warehouse_reorder_qty": 20 - }], + }, { + "doctype": "Item Price", + "parentfield": "ref_rate_details", + "price_list_name": "_Test Price List", + "ref_rate": 100, + "ref_currency": "INR" + } + ], [{ "doctype": "Item", "item_code": "_Test Item Home Desktop 100", From 3487e0a0f3a3ff265add2eebb729a44b306b79e2 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 2 May 2013 14:46:12 +0530 Subject: [PATCH 36/38] [price list] added currency property, validates currency, duplication in Item Price --- home/page/latest_updates/latest_updates.js | 2 ++ setup/doctype/price_list/price_list.txt | 13 ++++++++++--- setup/doctype/price_list/test_price_list.py | 3 ++- stock/doctype/item/item.js | 2 ++ stock/doctype/item/item.py | 18 +++++++++++++----- stock/doctype/item/test_item.py | 8 ++++++++ 6 files changed, 37 insertions(+), 9 deletions(-) diff --git a/home/page/latest_updates/latest_updates.js b/home/page/latest_updates/latest_updates.js index b768f1aa1e..e11b9c9243 100644 --- a/home/page/latest_updates/latest_updates.js +++ b/home/page/latest_updates/latest_updates.js @@ -1,4 +1,6 @@ erpnext.updates = [ + ["2nd May", ["Buying: Warehouse must belong to same company as transaction", + "Price List": "Added Currency Field. One price list can have only one currency"]], ["18th April", ["Cost Center: Set a default Cost Center for a Company"]], ["12th April", ["Employee: List of Leave Approvers who can approve the Employee's Leave Applications"]], ["10th April", ["Redesigned File Uploads and added File Manager in Setup"]], diff --git a/setup/doctype/price_list/price_list.txt b/setup/doctype/price_list/price_list.txt index a230f5b98c..bce8aae6e7 100644 --- a/setup/doctype/price_list/price_list.txt +++ b/setup/doctype/price_list/price_list.txt @@ -2,7 +2,7 @@ { "creation": "2013-01-25 11:35:09", "docstatus": 0, - "modified": "2013-01-22 14:56:41", + "modified": "2013-05-02 14:44:24", "modified_by": "Administrator", "owner": "Administrator" }, @@ -52,13 +52,21 @@ "oldfieldtype": "Data", "reqd": 1 }, + { + "doctype": "DocField", + "fieldname": "currency", + "fieldtype": "Link", + "label": "Currency", + "options": "Currency", + "reqd": 1 + }, { "depends_on": "price_list_name", "doctype": "DocField", "fieldname": "how_to_upload", "fieldtype": "HTML", "label": "How to upload", - "options": "
Use the Data Import Tool to upload, update Item Prices in bulk:\n
    \n
  1. Go to Data Import Tool.\n
  2. Select \"Item\"\n
  3. Check on \"With Data\"\n
  4. Download \"Item Price\" from Child Tables.\n
  5. Update the prices required and add new rows if required.\n
  6. Check on \"Overwrite\"\n
  7. Upload the modified sheet.\n
\n" + "options": "
Use the Data Import Tool to upload, update Item Prices in bulk:\n
    \n
  1. Go to Data Import Tool.\n
  2. Select \"Item\"\n
  3. Check on \"With Data\"\n
  4. Download \"Item Price\" from Child Tables.\n
  5. Update the prices required and add new rows if required.\n
  6. Check on \"Overwrite\"\n
  7. Upload the modified sheet.\n
\n" }, { "cancel": 0, @@ -78,7 +86,6 @@ "cancel": 1, "create": 1, "doctype": "DocPerm", - "match": "", "role": "Sales Master Manager", "write": 1 } diff --git a/setup/doctype/price_list/test_price_list.py b/setup/doctype/price_list/test_price_list.py index 53b86a39fc..30262dc8aa 100644 --- a/setup/doctype/price_list/test_price_list.py +++ b/setup/doctype/price_list/test_price_list.py @@ -1,6 +1,7 @@ test_records = [ [{ "doctype": "Price List", - "price_list_name": "_Test Price List" + "price_list_name": "_Test Price List", + "currency": "INR" }] ] \ No newline at end of file diff --git a/stock/doctype/item/item.js b/stock/doctype/item/item.js index 8b3e04484a..2635f3e904 100644 --- a/stock/doctype/item/item.js +++ b/stock/doctype/item/item.js @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +cur_frm.add_fetch("price_list_name", "currency", "ref_currency") + cur_frm.cscript.refresh = function(doc) { // make sensitive fields(has_serial_no, is_stock_item, valuation_method) // read only if any stock ledger entry exists diff --git a/stock/doctype/item/item.py b/stock/doctype/item/item.py index c6bf017647..8a804d8c13 100644 --- a/stock/doctype/item/item.py +++ b/stock/doctype/item/item.py @@ -24,6 +24,8 @@ from webnotes import msgprint, _ from webnotes.model.controller import DocListController +class PriceListCurrencyMismatch(Exception): pass + class DocType(DocListController): def validate(self): if not self.doc.stock_uom: @@ -34,7 +36,7 @@ class DocType(DocListController): self.add_default_uom_in_conversion_factor_table() self.valiadte_item_type() self.check_for_active_boms() - self.check_ref_rate_detail() + self.validate_price_lists() self.fill_customer_code() self.check_item_tax() self.validate_barcode() @@ -122,14 +124,20 @@ class DocType(DocListController): if cstr(self.doc.fields.get(d)) != 'Yes': _check_for_active_boms(fl[d]) - def check_ref_rate_detail(self): - check_list=[] + def validate_price_lists(self): + price_lists=[] for d in getlist(self.doclist,'ref_rate_details'): - if d.price_list_name in check_list: + if d.price_list_name in price_lists: msgprint(_("Cannot have two prices for same Price List") + ": " + d.price_list_name, raise_exception= webnotes.DuplicateEntryError) else: - check_list.append(d.price_list_name) + price_list_currency = webnotes.conn.get_value("Price List", d.price_list_name, "currency") + if price_list_currency and d.ref_currency != price_list_currency: + msgprint(_("Currency does not match Price List Currency for Price List") \ + + ": " + d.price_list_name, raise_exception=PriceListCurrencyMismatch) + + price_lists.append(d.price_list_name) + def fill_customer_code(self): """ Append all the customer codes and insert into "customer_code" field of item table """ diff --git a/stock/doctype/item/test_item.py b/stock/doctype/item/test_item.py index a59747c3e3..f5a688ca70 100644 --- a/stock/doctype/item/test_item.py +++ b/stock/doctype/item/test_item.py @@ -28,6 +28,14 @@ class TestItem(unittest.TestCase): item.doclist.append(webnotes.doc(item_price.fields.copy())) self.assertRaises(webnotes.DuplicateEntryError, item.insert) + def test_price_list_mismatch(self): + from stock.doctype.item.item import PriceListCurrencyMismatch + item = webnotes.bean(copy=test_records[0]) + item.doc.item_code = "_Test Item 11" + item_price = item.doclist.get({"doctype": "Item Price"})[0].ref_currency="USD" + self.assertRaises(PriceListCurrencyMismatch, item.insert) + + test_records = [ [{ "doctype": "Item", From 4d7a1c1f358778eb072ac0c23f6d20766fec5bc4 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 2 May 2013 15:19:00 +0530 Subject: [PATCH 37/38] [script report] payments made with ageing --- accounts/page/accounts_home/accounts_home.js | 5 ++ .../accounts_payable/accounts_payable.py | 6 +- .../accounts_receivable.py | 6 +- .../payment_collection_with_ageing.py | 10 ++- .../payment_made_with_ageing/__init__.py | 0 .../payment_made_with_ageing.js | 40 +++++++++ .../payment_made_with_ageing.py | 89 +++++++++++++++++++ .../payment_made_with_ageing.txt | 22 +++++ 8 files changed, 173 insertions(+), 5 deletions(-) create mode 100644 accounts/report/payment_made_with_ageing/__init__.py create mode 100644 accounts/report/payment_made_with_ageing/payment_made_with_ageing.js create mode 100644 accounts/report/payment_made_with_ageing/payment_made_with_ageing.py create mode 100644 accounts/report/payment_made_with_ageing/payment_made_with_ageing.txt diff --git a/accounts/page/accounts_home/accounts_home.js b/accounts/page/accounts_home/accounts_home.js index 7038fe9720..d2b0a0ea0d 100644 --- a/accounts/page/accounts_home/accounts_home.js +++ b/accounts/page/accounts_home/accounts_home.js @@ -212,6 +212,11 @@ wn.module_page["Accounts"] = [ route: "query-report/Payment Collection With Ageing", doctype: "Journal Voucher" }, + { + "label":wn._("Payment Made With Ageing"), + route: "query-report/Payment Made With Ageing", + doctype: "Journal Voucher" + }, ] } ] diff --git a/accounts/report/accounts_payable/accounts_payable.py b/accounts/report/accounts_payable/accounts_payable.py index 4e9b2c88ba..71aeb35ce0 100644 --- a/accounts/report/accounts_payable/accounts_payable.py +++ b/accounts/report/accounts_payable/accounts_payable.py @@ -1,6 +1,7 @@ from __future__ import unicode_literals import webnotes from webnotes.utils import getdate, nowdate, flt, cstr +from webnotes import msgprint, _ from accounts.report.accounts_receivable.accounts_receivable import get_ageing_data def execute(filters=None): @@ -79,13 +80,16 @@ def get_conditions(filters, before_report_date=True): supplier_accounts = [] if filters.get("account"): supplier_accounts = [filters["account"]] - elif filters.get("company"): + else: supplier_accounts = webnotes.conn.sql_list("""select name from `tabAccount` where ifnull(master_type, '') = 'Supplier' and docstatus < 2 %s""" % conditions, filters) if supplier_accounts: conditions += " and account in (%s)" % (", ".join(['%s']*len(supplier_accounts))) + else: + msgprint(_("No Supplier Accounts found. Supplier Accounts are identified based on \ + 'Master Type' value in account record."), raise_exception=1) if filters.get("report_date"): if before_report_date: diff --git a/accounts/report/accounts_receivable/accounts_receivable.py b/accounts/report/accounts_receivable/accounts_receivable.py index 47908c3f13..d791fad23f 100644 --- a/accounts/report/accounts_receivable/accounts_receivable.py +++ b/accounts/report/accounts_receivable/accounts_receivable.py @@ -1,5 +1,6 @@ from __future__ import unicode_literals import webnotes +from webnotes import msgprint, _ from webnotes.utils import getdate, nowdate, flt, cstr def execute(filters=None): @@ -68,13 +69,16 @@ def get_conditions(filters, upto_report_date=True): customer_accounts = [] if filters.get("account"): customer_accounts = [filters["account"]] - elif filters.get("company"): + else: customer_accounts = webnotes.conn.sql_list("""select name from `tabAccount` where ifnull(master_type, '') = 'Customer' and docstatus < 2 %s""" % conditions, filters) if customer_accounts: conditions += " and account in (%s)" % (", ".join(['%s']*len(customer_accounts))) + else: + msgprint(_("No Customer Accounts found. Customer Accounts are identified based on \ + 'Master Type' value in account record."), raise_exception=1) if filters.get("report_date"): if upto_report_date: diff --git a/accounts/report/payment_collection_with_ageing/payment_collection_with_ageing.py b/accounts/report/payment_collection_with_ageing/payment_collection_with_ageing.py index 50f74e0e82..12688525c6 100644 --- a/accounts/report/payment_collection_with_ageing/payment_collection_with_ageing.py +++ b/accounts/report/payment_collection_with_ageing/payment_collection_with_ageing.py @@ -16,6 +16,7 @@ from __future__ import unicode_literals import webnotes +from webnotes import msgprint, _ from accounts.report.accounts_receivable.accounts_receivable import get_ageing_data def execute(filters=None): @@ -55,13 +56,16 @@ def get_conditions(filters): customer_accounts = [] if filters.get("account"): customer_accounts = [filters["account"]] - elif filters.get("company"): + else: + cond = filters.get("company") and (" and company = '%s'" % filters["company"]) or "" customer_accounts = webnotes.conn.sql_list("""select name from `tabAccount` - where ifnull(master_type, '') = 'Customer' and docstatus < 2 - and company = %s""", filters["company"]) + where ifnull(master_type, '') = 'Customer' and docstatus < 2 %s""" % cond) if customer_accounts: conditions += " and jvd.account in (%s)" % (", ".join(['%s']*len(customer_accounts))) + else: + msgprint(_("No Customer Accounts found. Customer Accounts are identified based on \ + 'Master Type' value in account record."), raise_exception=1) if filters.get("from_date"): conditions += " and jv.posting_date >= '%s'" % filters["from_date"] if filters.get("to_date"): conditions += " and jv.posting_date <= '%s'" % filters["to_date"] diff --git a/accounts/report/payment_made_with_ageing/__init__.py b/accounts/report/payment_made_with_ageing/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/accounts/report/payment_made_with_ageing/payment_made_with_ageing.js b/accounts/report/payment_made_with_ageing/payment_made_with_ageing.js new file mode 100644 index 0000000000..533fe614d7 --- /dev/null +++ b/accounts/report/payment_made_with_ageing/payment_made_with_ageing.js @@ -0,0 +1,40 @@ +wn.query_reports["Payment Made With Ageing"] = { + "filters": [ + { + fieldname: "from_date", + label: "From Date", + fieldtype: "Date", + default: wn.defaults.get_user_default("year_start_date"), + }, + { + fieldname:"to_date", + label: "To Date", + fieldtype: "Date", + default: get_today() + }, + { + fieldname:"account", + label: "Supplier Account", + fieldtype: "Link", + options: "Account", + get_query: function() { + return { + query: "accounts.utils.get_account_list", + filters: { + is_pl_account: "No", + debit_or_credit: "Credit", + company: wn.query_report.filters_by_name.company.get_value(), + master_type: "Supplier" + } + } + } + }, + { + fieldname:"company", + label: "Company", + fieldtype: "Link", + options: "Company", + default: sys_defaults.company + }, + ] +} \ No newline at end of file diff --git a/accounts/report/payment_made_with_ageing/payment_made_with_ageing.py b/accounts/report/payment_made_with_ageing/payment_made_with_ageing.py new file mode 100644 index 0000000000..e7f13ef121 --- /dev/null +++ b/accounts/report/payment_made_with_ageing/payment_made_with_ageing.py @@ -0,0 +1,89 @@ +# ERPNext - web based ERP (http://erpnext.com) +# Copyright (C) 2012 Web Notes Technologies Pvt Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from __future__ import unicode_literals +import webnotes +from webnotes import msgprint, _ +from accounts.report.accounts_receivable.accounts_receivable import get_ageing_data + +def execute(filters=None): + if not filters: filters = {} + + columns = get_columns() + entries = get_entries(filters) + pi_posting_date_map = get_pi_posting_date_map() + + data = [] + for d in entries: + against_voucher_date = d.against_voucher and pi_posting_date_map[d.against_voucher] or "" + + row = [d.name, d.account, d.posting_date, d.against_voucher, against_voucher_date, + d.debit, d.credit, d.cheque_no, d.cheque_date, d.remark] + + if d.against_voucher: + row += get_ageing_data(against_voucher_date, d.posting_date, d.debit or -1*d.credit) + else: + row += ["", "", "", "", ""] + + data.append(row) + + return columns, data + +def get_columns(): + return ["Journal Voucher:Link/Journal Voucher:140", "Account:Link/Account:140", + "Posting Date:Date:100", "Against Invoice:Link/Purchase Invoice:130", + "Against Invoice Posting Date:Date:130", "Debit:Currency:120", "Credit:Currency:120", + "Reference No::100", "Reference Date:Date:100", "Remarks::150", "Age:Int:40", + "0-30:Currency:100", "30-60:Currency:100", "60-90:Currency:100", "90-Above:Currency:100" + ] + +def get_conditions(filters): + conditions = "" + supplier_accounts = [] + if filters.get("account"): + supplier_accounts = [filters["account"]] + else: + cond = filters.get("company") and (" and company = '%s'" % filters["company"]) or "" + supplier_accounts = webnotes.conn.sql_list("""select name from `tabAccount` + where ifnull(master_type, '') = 'Supplier' and docstatus < 2 %s""" % cond) + + if supplier_accounts: + conditions += " and jvd.account in (%s)" % (", ".join(['%s']*len(supplier_accounts))) + else: + msgprint(_("No Supplier Accounts found. Supplier Accounts are identified based on \ + 'Master Type' value in account record."), raise_exception=1) + + if filters.get("from_date"): conditions += " and jv.posting_date >= '%s'" % filters["from_date"] + if filters.get("to_date"): conditions += " and jv.posting_date <= '%s'" % filters["to_date"] + + return conditions, supplier_accounts + +def get_entries(filters): + conditions, supplier_accounts = get_conditions(filters) + entries = webnotes.conn.sql("""select jv.name, jvd.account, jv.posting_date, + jvd.against_voucher, jvd.debit, jvd.credit, jv.cheque_no, jv.cheque_date, jv.remark + from `tabJournal Voucher Detail` jvd, `tabJournal Voucher` jv + where jvd.parent = jv.name and jv.docstatus=1 %s order by jv.name DESC""" % + (conditions), tuple(supplier_accounts), as_dict=1) + + return entries + +def get_pi_posting_date_map(): + pi_posting_date_map = {} + for t in webnotes.conn.sql("""select name, posting_date from `tabPurchase Invoice`"""): + pi_posting_date_map[t[0]] = t[1] + + return pi_posting_date_map \ No newline at end of file diff --git a/accounts/report/payment_made_with_ageing/payment_made_with_ageing.txt b/accounts/report/payment_made_with_ageing/payment_made_with_ageing.txt new file mode 100644 index 0000000000..c5c85da89a --- /dev/null +++ b/accounts/report/payment_made_with_ageing/payment_made_with_ageing.txt @@ -0,0 +1,22 @@ +[ + { + "creation": "2013-05-02 12:10:21", + "docstatus": 0, + "modified": "2013-05-02 12:10:21", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "add_total_row": 1, + "doctype": "Report", + "is_standard": "Yes", + "name": "__common__", + "ref_doctype": "Journal Voucher", + "report_name": "Payment Made With Ageing", + "report_type": "Script Report" + }, + { + "doctype": "Report", + "name": "Payment Made With Ageing" + } +] \ No newline at end of file From f5f478ee78deee8d77f5d65ad31cecbb33aaee08 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 2 May 2013 15:36:33 +0530 Subject: [PATCH 38/38] [item] [naming] by series or code / [naming series] optionally set number of digits --- home/page/latest_updates/latest_updates.js | 4 +- .../global_defaults/global_defaults.py | 1 + .../global_defaults/global_defaults.txt | 18 ++++- setup/doctype/naming_series/naming_series.py | 9 ++- setup/doctype/naming_series/naming_series.txt | 8 +- stock/doctype/item/item.js | 6 +- stock/doctype/item/item.py | 7 ++ stock/doctype/item/item.txt | 77 ++++++++++++++++--- 8 files changed, 108 insertions(+), 22 deletions(-) diff --git a/home/page/latest_updates/latest_updates.js b/home/page/latest_updates/latest_updates.js index e11b9c9243..f254bf2349 100644 --- a/home/page/latest_updates/latest_updates.js +++ b/home/page/latest_updates/latest_updates.js @@ -1,6 +1,8 @@ erpnext.updates = [ ["2nd May", ["Buying: Warehouse must belong to same company as transaction", - "Price List": "Added Currency Field. One price list can have only one currency"]], + "Price List: Added Currency Field. One price list can have only one currency", + "Item: Naming can now be by series or item code", + "Naming Series: Set number of digits in series (optionally)"]], ["18th April", ["Cost Center: Set a default Cost Center for a Company"]], ["12th April", ["Employee: List of Leave Approvers who can approve the Employee's Leave Applications"]], ["10th April", ["Redesigned File Uploads and added File Manager in Setup"]], diff --git a/setup/doctype/global_defaults/global_defaults.py b/setup/doctype/global_defaults/global_defaults.py index 8275513dc9..191a47edf2 100644 --- a/setup/doctype/global_defaults/global_defaults.py +++ b/setup/doctype/global_defaults/global_defaults.py @@ -31,6 +31,7 @@ keydict = { 'item_group': 'default_item_group', 'customer_group': 'default_customer_group', 'cust_master_name': 'cust_master_name', + "item_naming_by": "item_naming_by", 'supplier_type': 'default_supplier_type', 'supp_master_name': 'supp_master_name', 'territory': 'default_territory', diff --git a/setup/doctype/global_defaults/global_defaults.txt b/setup/doctype/global_defaults/global_defaults.txt index 7f81618469..853bb57705 100644 --- a/setup/doctype/global_defaults/global_defaults.txt +++ b/setup/doctype/global_defaults/global_defaults.txt @@ -1,8 +1,8 @@ [ { - "creation": "2013-03-25 11:08:14", + "creation": "2013-04-01 15:05:24", "docstatus": 0, - "modified": "2013-03-28 15:41:03", + "modified": "2013-05-02 15:05:21", "modified_by": "Administrator", "owner": "Administrator" }, @@ -27,8 +27,6 @@ "permlevel": 0 }, { - "amend": 0, - "cancel": 0, "create": 1, "doctype": "DocPerm", "name": "__common__", @@ -167,6 +165,13 @@ "read_only": 0, "width": "50%" }, + { + "doctype": "DocField", + "fieldname": "item_naming_by", + "fieldtype": "Select", + "label": "Item Naming By", + "options": "Item Code\nNaming Series" + }, { "doctype": "DocField", "fieldname": "default_item_group", @@ -502,6 +507,11 @@ "label": "SMS Sender Name", "read_only": 0 }, + { + "amend": 0, + "cancel": 0, + "doctype": "DocPerm" + }, { "doctype": "DocPerm" } diff --git a/setup/doctype/naming_series/naming_series.py b/setup/doctype/naming_series/naming_series.py index 7b804f8a96..3a6b36d1ff 100644 --- a/setup/doctype/naming_series/naming_series.py +++ b/setup/doctype/naming_series/naming_series.py @@ -123,7 +123,14 @@ class DocType: def validate_series_name(self, n): import re - if not re.match('[a-zA-Z0-9]+(([-/][a-zA-Z0-9])?[-/][a-zA-Z0-9]*)*',n): + if "." in n: + parts = n.split(".") + if len(parts) > 2: + msgprint("Only one dot (.) allowed in " + n, raise_exception=1) + if not re.match("#+$", parts[-1]): + msgprint("Numbering series must be in hashes (e.g. ####)", raise_exception=1) + n = n[0] + if not re.match("^[a-zA-Z0-9-/]*$", n): msgprint('Special Characters except "-" and "/" not allowed in naming series') raise Exception diff --git a/setup/doctype/naming_series/naming_series.txt b/setup/doctype/naming_series/naming_series.txt index 3de9e5cfab..0dab9e970d 100644 --- a/setup/doctype/naming_series/naming_series.txt +++ b/setup/doctype/naming_series/naming_series.txt @@ -1,8 +1,8 @@ [ { - "creation": "2013-01-10 16:34:23", + "creation": "2013-01-25 11:35:08", "docstatus": 0, - "modified": "2013-01-22 14:56:34", + "modified": "2013-05-02 15:34:41", "modified_by": "Administrator", "owner": "Administrator" }, @@ -25,8 +25,6 @@ "permlevel": 0 }, { - "amend": 0, - "cancel": 0, "create": 1, "doctype": "DocPerm", "name": "__common__", @@ -62,7 +60,7 @@ "fieldname": "help_html", "fieldtype": "HTML", "label": "Help HTML", - "options": "
\nEdit list of Series in the box below. Each Series Prefix on a new line.

\nAllowed special characters are \"/\" and \"-\"
\nExamples:
\nINV-
\nINV-10-
\nINVK-
\n
" + "options": "
\nEdit list of Series in the box below. Rules:\n
    \n
  • Each Series Prefix on a new line.
  • \n
  • Allowed special characters are \"/\" and \"-\"
  • \n
  • Optionally, set the number of digits in the series using dot (.) followed by hashes (#). For example, \".####\" means that the series will have four digits. Default is five digits.
  • \n
\nExamples:
\nINV-
\nINV-10-
\nINVK-
\nINV-.####
\n
" }, { "doctype": "DocField", diff --git a/stock/doctype/item/item.js b/stock/doctype/item/item.js index 2635f3e904..a344ad3ce9 100644 --- a/stock/doctype/item/item.js +++ b/stock/doctype/item/item.js @@ -20,7 +20,11 @@ cur_frm.cscript.refresh = function(doc) { // make sensitive fields(has_serial_no, is_stock_item, valuation_method) // read only if any stock ledger entry exists - cur_frm.toggle_enable("item_code", doc.__islocal); + cur_frm.toggle_display("naming_series", sys_defaults.item_naming_by=="Naming Series" + && doc.__islocal) + cur_frm.toggle_display("item_code", sys_defaults.item_naming_by!="Naming Series" + && doc.__islocal) + if ((!doc.__islocal) && (doc.is_stock_item == 'Yes')) { var callback = function(r, rt) { diff --git a/stock/doctype/item/item.py b/stock/doctype/item/item.py index 8a804d8c13..63275047ad 100644 --- a/stock/doctype/item/item.py +++ b/stock/doctype/item/item.py @@ -27,6 +27,13 @@ from webnotes.model.controller import DocListController class PriceListCurrencyMismatch(Exception): pass class DocType(DocListController): + def autoname(self): + if webnotes.conn.get_default("item_naming_by")=="Naming Series": + from webnotes.model.doc import make_autoname + self.doc.item_code = make_autoname(self.doc.naming_series+'.#####') + + self.doc.name = self.doc.item_code + def validate(self): if not self.doc.stock_uom: msgprint(_("Please enter Default Unit of Measure"), raise_exception=1) diff --git a/stock/doctype/item/item.txt b/stock/doctype/item/item.txt index 3497402076..274719eec5 100644 --- a/stock/doctype/item/item.txt +++ b/stock/doctype/item/item.txt @@ -1,8 +1,8 @@ [ { - "creation": "2013-03-28 15:56:38", + "creation": "2013-04-25 10:56:55", "docstatus": 0, - "modified": "2013-04-23 11:44:39", + "modified": "2013-05-02 15:10:53", "modified_by": "Administrator", "owner": "Administrator" }, @@ -34,7 +34,6 @@ "parent": "Item", "parentfield": "permissions", "parenttype": "DocType", - "permlevel": 0, "read": 1, "submit": 0 }, @@ -51,6 +50,13 @@ "oldfieldtype": "Section Break", "read_only": 0 }, + { + "doctype": "DocField", + "fieldname": "naming_series", + "fieldtype": "Select", + "label": "Naming Series", + "options": "\nITEM" + }, { "description": "Item will be saved by this name in the data base.", "doctype": "DocField", @@ -877,17 +883,12 @@ "label": "Website Description", "read_only": 0 }, - { - "cancel": 1, - "create": 1, - "doctype": "DocPerm", - "role": "Material Master Manager", - "write": 1 - }, { "cancel": 0, "create": 0, "doctype": "DocPerm", + "permlevel": 1, + "report": 0, "role": "Material Manager", "write": 0 }, @@ -895,7 +896,63 @@ "cancel": 0, "create": 0, "doctype": "DocPerm", + "permlevel": 0, + "report": 1, + "role": "Material Manager", + "write": 0 + }, + { + "cancel": 0, + "create": 0, + "doctype": "DocPerm", + "permlevel": 1, + "report": 0, "role": "Material User", "write": 0 + }, + { + "cancel": 0, + "create": 0, + "doctype": "DocPerm", + "permlevel": 0, + "report": 1, + "role": "Material User", + "write": 0 + }, + { + "cancel": 1, + "create": 1, + "doctype": "DocPerm", + "permlevel": 0, + "report": 1, + "role": "Material Master Manager", + "write": 1 + }, + { + "cancel": 0, + "create": 0, + "doctype": "DocPerm", + "permlevel": 1, + "report": 0, + "role": "Material Master Manager", + "write": 0 + }, + { + "cancel": 1, + "create": 1, + "doctype": "DocPerm", + "permlevel": 0, + "report": 1, + "role": "System Manager", + "write": 1 + }, + { + "cancel": 0, + "create": 0, + "doctype": "DocPerm", + "permlevel": 1, + "report": 0, + "role": "System Manager", + "write": 0 } ] \ No newline at end of file