From dfbcdeb8a0160557bd78b50a120f0c7db991b886 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Tue, 24 May 2016 07:49:00 +0530 Subject: [PATCH 01/17] [enhancement] warehouse tree structure --- erpnext/patches.txt | 1 + .../v7_0/create_warehouse_nestedset.py | 18 ++ .../stock/doctype/warehouse/warehouse.json | 156 +++++++++++++++++- erpnext/stock/doctype/warehouse/warehouse.py | 12 +- 4 files changed, 182 insertions(+), 5 deletions(-) create mode 100644 erpnext/patches/v7_0/create_warehouse_nestedset.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 2493643e66..eda2c70ebb 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -273,3 +273,4 @@ execute:frappe.rename_doc("DocType", "Payments", "Sales Invoice Payment", force= erpnext.patches.v7_0.update_mins_to_first_response erpnext.patches.v6_20x.repost_valuation_rate_for_negative_inventory erpnext.patches.v7_0.re_route +erpnext.patches.v7_0.create_warehouse_nestedset diff --git a/erpnext/patches/v7_0/create_warehouse_nestedset.py b/erpnext/patches/v7_0/create_warehouse_nestedset.py new file mode 100644 index 0000000000..0d8d42e244 --- /dev/null +++ b/erpnext/patches/v7_0/create_warehouse_nestedset.py @@ -0,0 +1,18 @@ +import frappe +from frappe import _ + +def execute(): + if not frappe.db.exists("Warehouse", {"warehouse_name": _("All Warehouses")}): + parent_warehouse = frappe.get_doc({ + "doctype": "Warehouse", + "warehouse_name": _("All Warehouses"), + "is_group": "Yes" + }).insert(ignore_permissions=True) + + for warehouse in frappe.db.sql_list("""select name from tabWarehouse + where name != %s order by name asc""", "All Warehouses - SI"): + print warehouse + warehouse = frappe.get_doc("Warehouse", warehouse) + warehouse.is_group = "No" + warehouse.parent_warehouse = parent_warehouse.name + warehouse.save(ignore_permissions=True) \ No newline at end of file diff --git a/erpnext/stock/doctype/warehouse/warehouse.json b/erpnext/stock/doctype/warehouse/warehouse.json index 4e9dd07df4..6b60c635d4 100644 --- a/erpnext/stock/doctype/warehouse/warehouse.json +++ b/erpnext/stock/doctype/warehouse/warehouse.json @@ -2,6 +2,7 @@ "allow_copy": 0, "allow_import": 1, "allow_rename": 1, + "beta": 0, "creation": "2013-03-07 18:50:32", "custom": 0, "description": "A logical Warehouse against which stock entries are made.", @@ -420,6 +421,159 @@ "search_index": 0, "set_only_once": 0, "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "tree_details", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Tree Details", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "parent_warehouse", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 1, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Parent Warehouse", + "length": 0, + "no_copy": 0, + "options": "Warehouse", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 1, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "is_group", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "label": "Has Child Node", + "length": 0, + "no_copy": 0, + "options": "\nYes\nNo", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "lft", + "fieldtype": "Int", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "lft", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "rgt", + "fieldtype": "Int", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "rgt", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "old_parent", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Old Parent", + "length": 0, + "no_copy": 0, + "options": "Warehouse", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 } ], "hide_heading": 0, @@ -432,7 +586,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-04-18 05:44:24.837579", + "modified": "2016-05-23 21:25:21.396188", "modified_by": "Administrator", "module": "Stock", "name": "Warehouse", diff --git a/erpnext/stock/doctype/warehouse/warehouse.py b/erpnext/stock/doctype/warehouse/warehouse.py index 901b229cb8..d28a3c4a29 100644 --- a/erpnext/stock/doctype/warehouse/warehouse.py +++ b/erpnext/stock/doctype/warehouse/warehouse.py @@ -5,10 +5,11 @@ from __future__ import unicode_literals import frappe from frappe.utils import cint, validate_email_add from frappe import throw, msgprint, _ +from frappe.utils.nestedset import NestedSet -from frappe.model.document import Document - -class Warehouse(Document): +class Warehouse(NestedSet): + nsm_parent_field = 'parent_warehouse' + def autoname(self): suffix = " - " + frappe.db.get_value("Company", self.company, "abbr") if not self.warehouse_name.endswith(suffix): @@ -45,6 +46,7 @@ class Warehouse(Document): def on_update(self): self.create_account_head() + self.update_nsm_model() def create_account_head(self): if cint(frappe.defaults.get_global_default("auto_accounting_for_stock")): @@ -81,7 +83,9 @@ class Warehouse(Document): elif frappe.db.get_value("Account", self.create_account_under, "company") != self.company: frappe.throw(_("Warehouse {0}: Parent account {1} does not bolong to the company {2}") .format(self.name, self.create_account_under, self.company)) - + + def update_nsm_model(self): + frappe.utils.nestedset.update_nsm(self) def on_trash(self): # delete bin From 091ca75fa345a814e6d02e2e6f5eb8ef26b1c219 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Tue, 24 May 2016 12:04:45 +0530 Subject: [PATCH 02/17] [enhance] warehouse browser page for warehouse tree --- erpnext/setup/doctype/company/company.py | 13 +- .../stock/page/warehouse_browser/__init__.py | 0 .../warehouse_browser/warehouse_browser.js | 158 ++++++++++++++++++ .../warehouse_browser/warehouse_browser.json | 27 +++ .../warehouse_browser/warehouse_browser.py | 35 ++++ 5 files changed, 230 insertions(+), 3 deletions(-) create mode 100644 erpnext/stock/page/warehouse_browser/__init__.py create mode 100644 erpnext/stock/page/warehouse_browser/warehouse_browser.js create mode 100644 erpnext/stock/page/warehouse_browser/warehouse_browser.json create mode 100644 erpnext/stock/page/warehouse_browser/warehouse_browser.py diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index 7da7c25d13..0ed7a826ca 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -87,15 +87,22 @@ class Company(Document): .format(self.country.lower()))(self) def create_default_warehouses(self): - for whname in (_("Stores"), _("Work In Progress"), _("Finished Goods")): - if not frappe.db.exists("Warehouse", whname + " - " + self.abbr): + for wh_detail in [{"warehouse_name": _("All Warehouses"), "is_group": "Yes"}, + {"warehouse_name": _("Stores"), "is_group": "No"}, + {"warehouse_name": _("Work In Progress"), "is_group": "No"}, + {"warehouse_name": _("Finished Goods"), "is_group": "No"}]: + + if not frappe.db.exists("Warehouse", "{0} - {1}".format(wh_detail["warehouse_name"], self.abbr)): stock_group = frappe.db.get_value("Account", {"account_type": "Stock", "is_group": 1, "company": self.name}) if stock_group: warehouse = frappe.get_doc({ "doctype":"Warehouse", - "warehouse_name": whname, + "warehouse_name": wh_detail["warehouse_name"], + "is_group": wh_detail["is_group"], "company": self.name, + "parent_warehouse": "" if wh_detail["is_group"] == "Yes" \ + else "{0} - {1}".format(_("All Warehouses"), self.abbr), "create_account_under": stock_group }) warehouse.flags.ignore_permissions = True diff --git a/erpnext/stock/page/warehouse_browser/__init__.py b/erpnext/stock/page/warehouse_browser/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/stock/page/warehouse_browser/warehouse_browser.js b/erpnext/stock/page/warehouse_browser/warehouse_browser.js new file mode 100644 index 0000000000..d123ff4548 --- /dev/null +++ b/erpnext/stock/page/warehouse_browser/warehouse_browser.js @@ -0,0 +1,158 @@ +frappe.pages['warehouse-browser'].on_page_load = function(wrapper) { + var page = frappe.ui.make_app_page({ + parent: wrapper, + single_column: true + }); + + wrapper.page.add_menu_item(__('Refresh'), function() { + wrapper.make_tree(); + }); + + wrapper.make_tree = function() { + var ctype = frappe.get_route()[1] || 'Warehouse'; + return frappe.call({ + method: 'erpnext.stock.page.warehouse_browser.warehouse_browser.get_children', + args: {ctype: ctype}, + callback: function(r) { + var root = r.message[0]["value"]; + erpnext.warehouse_chart = new erpnext.WarehouseChart(ctype, root, page, + page.main.css({ + "min-height": "300px", + "padding-bottom": "25px" + })); + } + }); + } + + wrapper.make_tree(); +} + +frappe.pages['warehouse-browser'].on_page_show = function(wrapper){ + // set route + var ctype = frappe.get_route()[1] || 'Warehouse'; + + wrapper.page.set_title(__('{0} Tree',[__(ctype)])); + + if(erpnext.warehouse_chart && erpnext.warehouse_chart.ctype != ctype) { + wrapper.make_tree(); + } + + frappe.breadcrumbs.add(frappe.breadcrumbs.last_module || "Stock"); +}; + +erpnext.WarehouseChart = Class.extend({ + init: function(ctype, root, page, parent){ + $(parent).empty(); + var me = this; + me.ctype = ctype; + me.page = page; + me.can_read = frappe.model.can_read(this.ctype); + me.can_create = frappe.boot.user.can_create.indexOf(this.ctype) !== -1 || + frappe.boot.user.in_create.indexOf(this.ctype) !== -1; + me.can_write = frappe.model.can_write(this.ctype); + me.can_delete = frappe.model.can_delete(this.ctype); + + me.page.set_primary_action(__("New"), function() { + me.new_node(); + }, "octicon octicon-plus"); + + this.tree = new frappe.ui.Tree({ + parent: $(parent), + label: __(root), + args: {ctype: ctype}, + method: 'erpnext.stock.page.warehouse_browser.warehouse_browser.get_children', + toolbar: [ + {toggle_btn: true}, + { + label:__("Edit"), + condition: function(node) { + return !node.root && me.can_read; + }, + click: function(node) { + frappe.set_route("Form", me.ctype, node.label); + } + }, + { + label:__("Add Child"), + condition: function(node) { return me.can_create && node.expandable; }, + click: function(node) { + me.new_node(); + }, + btnClass: "hidden-xs" + }, + { + label:__("Rename"), + condition: function(node) { return !node.root && me.can_write; }, + click: function(node) { + frappe.model.rename_doc(me.ctype, node.label, function(new_name) { + node.$a.html(new_name); + }); + }, + btnClass: "hidden-xs" + }, + { + label:__("Delete"), + condition: function(node) { return !node.root && me.can_delete; }, + click: function(node) { + frappe.model.delete_doc(me.ctype, node.label, function() { + node.parent.remove(); + }); + }, + btnClass: "hidden-xs" + } + + ] + }); + }, + new_node: function() { + var me = this; + var node = me.tree.get_selected_node(); + + if(!(node && node.expandable)) { + frappe.msgprint(__("Select a group node first.")); + return; + } + + var fields = [ + {fieldtype:'Data', fieldname: 'name_field', + label:__('New {0} Name',[__(me.ctype)]), reqd:true}, + {fieldtype:'Select', fieldname:'is_group', label:__('Group Node'), options:'No\nYes', + description: __("Further nodes can be only created under 'Group' type nodes")} + ] + + // the dialog + var d = new frappe.ui.Dialog({ + title: __('New {0}',[__(me.ctype)]), + fields: fields + }) + + d.set_value("is_group", "No"); + // create + d.set_primary_action(__("Create New"), function() { + var btn = this; + var v = d.get_values(); + if(!v) return; + + var node = me.tree.get_selected_node(); + + v.parent = node.label; + v.ctype = me.ctype; + + return frappe.call({ + method: 'erpnext.stock.page.warehouse_browser.warehouse_browser.add_node', + args: v, + callback: function(r) { + if(!r.exc) { + d.hide(); + if(node.expanded) { + node.toggle_node(); + } + node.reload(); + } + } + }); + }); + + d.show(); + }, +}) \ No newline at end of file diff --git a/erpnext/stock/page/warehouse_browser/warehouse_browser.json b/erpnext/stock/page/warehouse_browser/warehouse_browser.json new file mode 100644 index 0000000000..3d0dcbcaf4 --- /dev/null +++ b/erpnext/stock/page/warehouse_browser/warehouse_browser.json @@ -0,0 +1,27 @@ +{ + "content": null, + "creation": "2016-05-24 11:01:06.887660", + "docstatus": 0, + "doctype": "Page", + "idx": 0, + "modified": "2016-05-24 11:11:32.317342", + "modified_by": "Administrator", + "module": "Stock", + "name": "warehouse-browser", + "owner": "Administrator", + "page_name": "Warehouse Browser", + "roles": [ + { + "role": "Stock Manager" + }, + { + "role": "Stock User" + }, + { + "role": "System Manager" + } + ], + "script": null, + "standard": "Yes", + "style": null +} \ No newline at end of file diff --git a/erpnext/stock/page/warehouse_browser/warehouse_browser.py b/erpnext/stock/page/warehouse_browser/warehouse_browser.py new file mode 100644 index 0000000000..48bb8a3389 --- /dev/null +++ b/erpnext/stock/page/warehouse_browser/warehouse_browser.py @@ -0,0 +1,35 @@ +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +@frappe.whitelist() +def get_children(): + ctype = frappe.local.form_dict.get('ctype') + parent_field = 'parent_' + ctype.lower().replace(' ', '_') + parent = frappe.form_dict.get("parent") or "" + + return frappe.db.sql("""select name as value, + if(is_group='Yes', 1, 0) as expandable + from `tab{ctype}` + where docstatus < 2 + and ifnull(`{parent_field}`,'') = %s + order by name""".format(ctype=frappe.db.escape(ctype), parent_field=frappe.db.escape(parent_field)), + parent, as_dict=1) + +@frappe.whitelist() +def add_node(): + ctype = frappe.form_dict.get('ctype') + parent_field = 'parent_' + ctype.lower().replace(' ', '_') + name_field = ctype.lower().replace(' ', '_') + '_name' + + doc = frappe.new_doc(ctype) + + doc.update({ + name_field: frappe.form_dict['name_field'], + parent_field: frappe.form_dict['parent'], + "is_group": frappe.form_dict['is_group'] + }) + + doc.save() \ No newline at end of file From eda1afb4ebc5686e9c64036c7286beb3d1f9cc4a Mon Sep 17 00:00:00 2001 From: Saurabh Date: Wed, 25 May 2016 11:54:54 +0530 Subject: [PATCH 03/17] [fixes] comnify tree view --- .../v7_0/create_warehouse_nestedset.py | 6 +- .../{sales_browser.js => tree.js} | 0 erpnext/setup/doctype/company/company.py | 4 +- .../stock/doctype/warehouse/test_records.json | 11 +- .../stock/page/warehouse_browser/__init__.py | 0 .../warehouse_browser/warehouse_browser.js | 158 ------------------ .../warehouse_browser/warehouse_browser.json | 27 --- .../warehouse_browser/warehouse_browser.py | 35 ---- 8 files changed, 15 insertions(+), 226 deletions(-) rename erpnext/selling/page/sales_browser/{sales_browser.js => tree.js} (100%) delete mode 100644 erpnext/stock/page/warehouse_browser/__init__.py delete mode 100644 erpnext/stock/page/warehouse_browser/warehouse_browser.js delete mode 100644 erpnext/stock/page/warehouse_browser/warehouse_browser.json delete mode 100644 erpnext/stock/page/warehouse_browser/warehouse_browser.py diff --git a/erpnext/patches/v7_0/create_warehouse_nestedset.py b/erpnext/patches/v7_0/create_warehouse_nestedset.py index 0d8d42e244..01ae89165c 100644 --- a/erpnext/patches/v7_0/create_warehouse_nestedset.py +++ b/erpnext/patches/v7_0/create_warehouse_nestedset.py @@ -2,15 +2,15 @@ import frappe from frappe import _ def execute(): - if not frappe.db.exists("Warehouse", {"warehouse_name": _("All Warehouses")}): + if not frappe.db.exists("Warehouse", {"warehouse_name": _("Warehouses")}): parent_warehouse = frappe.get_doc({ "doctype": "Warehouse", - "warehouse_name": _("All Warehouses"), + "warehouse_name": _("Warehouses"), "is_group": "Yes" }).insert(ignore_permissions=True) for warehouse in frappe.db.sql_list("""select name from tabWarehouse - where name != %s order by name asc""", "All Warehouses - SI"): + where name != %s order by name asc""", "Warehouses - SI"): print warehouse warehouse = frappe.get_doc("Warehouse", warehouse) warehouse.is_group = "No" diff --git a/erpnext/selling/page/sales_browser/sales_browser.js b/erpnext/selling/page/sales_browser/tree.js similarity index 100% rename from erpnext/selling/page/sales_browser/sales_browser.js rename to erpnext/selling/page/sales_browser/tree.js diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index 0ed7a826ca..7294834790 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -87,7 +87,7 @@ class Company(Document): .format(self.country.lower()))(self) def create_default_warehouses(self): - for wh_detail in [{"warehouse_name": _("All Warehouses"), "is_group": "Yes"}, + for wh_detail in [{"warehouse_name": _("Warehouses"), "is_group": "Yes"}, {"warehouse_name": _("Stores"), "is_group": "No"}, {"warehouse_name": _("Work In Progress"), "is_group": "No"}, {"warehouse_name": _("Finished Goods"), "is_group": "No"}]: @@ -102,7 +102,7 @@ class Company(Document): "is_group": wh_detail["is_group"], "company": self.name, "parent_warehouse": "" if wh_detail["is_group"] == "Yes" \ - else "{0} - {1}".format(_("All Warehouses"), self.abbr), + else "{0} - {1}".format(_("Warehouses"), self.abbr), "create_account_under": stock_group }) warehouse.flags.ignore_permissions = True diff --git a/erpnext/stock/doctype/warehouse/test_records.json b/erpnext/stock/doctype/warehouse/test_records.json index e2162d22eb..f57fda36a7 100644 --- a/erpnext/stock/doctype/warehouse/test_records.json +++ b/erpnext/stock/doctype/warehouse/test_records.json @@ -3,7 +3,16 @@ "company": "_Test Company", "create_account_under": "Stock Assets - _TC", "doctype": "Warehouse", - "warehouse_name": "_Test Warehouse" + "warehouse_name": "_Test Warehouse", + + + } + { + "company": "_Test Company", + "create_account_under": "Stock Assets - _TC", + "doctype": "Warehouse", + "warehouse_name": "_Test Warehouse", + "" }, { "company": "_Test Company", diff --git a/erpnext/stock/page/warehouse_browser/__init__.py b/erpnext/stock/page/warehouse_browser/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/stock/page/warehouse_browser/warehouse_browser.js b/erpnext/stock/page/warehouse_browser/warehouse_browser.js deleted file mode 100644 index d123ff4548..0000000000 --- a/erpnext/stock/page/warehouse_browser/warehouse_browser.js +++ /dev/null @@ -1,158 +0,0 @@ -frappe.pages['warehouse-browser'].on_page_load = function(wrapper) { - var page = frappe.ui.make_app_page({ - parent: wrapper, - single_column: true - }); - - wrapper.page.add_menu_item(__('Refresh'), function() { - wrapper.make_tree(); - }); - - wrapper.make_tree = function() { - var ctype = frappe.get_route()[1] || 'Warehouse'; - return frappe.call({ - method: 'erpnext.stock.page.warehouse_browser.warehouse_browser.get_children', - args: {ctype: ctype}, - callback: function(r) { - var root = r.message[0]["value"]; - erpnext.warehouse_chart = new erpnext.WarehouseChart(ctype, root, page, - page.main.css({ - "min-height": "300px", - "padding-bottom": "25px" - })); - } - }); - } - - wrapper.make_tree(); -} - -frappe.pages['warehouse-browser'].on_page_show = function(wrapper){ - // set route - var ctype = frappe.get_route()[1] || 'Warehouse'; - - wrapper.page.set_title(__('{0} Tree',[__(ctype)])); - - if(erpnext.warehouse_chart && erpnext.warehouse_chart.ctype != ctype) { - wrapper.make_tree(); - } - - frappe.breadcrumbs.add(frappe.breadcrumbs.last_module || "Stock"); -}; - -erpnext.WarehouseChart = Class.extend({ - init: function(ctype, root, page, parent){ - $(parent).empty(); - var me = this; - me.ctype = ctype; - me.page = page; - me.can_read = frappe.model.can_read(this.ctype); - me.can_create = frappe.boot.user.can_create.indexOf(this.ctype) !== -1 || - frappe.boot.user.in_create.indexOf(this.ctype) !== -1; - me.can_write = frappe.model.can_write(this.ctype); - me.can_delete = frappe.model.can_delete(this.ctype); - - me.page.set_primary_action(__("New"), function() { - me.new_node(); - }, "octicon octicon-plus"); - - this.tree = new frappe.ui.Tree({ - parent: $(parent), - label: __(root), - args: {ctype: ctype}, - method: 'erpnext.stock.page.warehouse_browser.warehouse_browser.get_children', - toolbar: [ - {toggle_btn: true}, - { - label:__("Edit"), - condition: function(node) { - return !node.root && me.can_read; - }, - click: function(node) { - frappe.set_route("Form", me.ctype, node.label); - } - }, - { - label:__("Add Child"), - condition: function(node) { return me.can_create && node.expandable; }, - click: function(node) { - me.new_node(); - }, - btnClass: "hidden-xs" - }, - { - label:__("Rename"), - condition: function(node) { return !node.root && me.can_write; }, - click: function(node) { - frappe.model.rename_doc(me.ctype, node.label, function(new_name) { - node.$a.html(new_name); - }); - }, - btnClass: "hidden-xs" - }, - { - label:__("Delete"), - condition: function(node) { return !node.root && me.can_delete; }, - click: function(node) { - frappe.model.delete_doc(me.ctype, node.label, function() { - node.parent.remove(); - }); - }, - btnClass: "hidden-xs" - } - - ] - }); - }, - new_node: function() { - var me = this; - var node = me.tree.get_selected_node(); - - if(!(node && node.expandable)) { - frappe.msgprint(__("Select a group node first.")); - return; - } - - var fields = [ - {fieldtype:'Data', fieldname: 'name_field', - label:__('New {0} Name',[__(me.ctype)]), reqd:true}, - {fieldtype:'Select', fieldname:'is_group', label:__('Group Node'), options:'No\nYes', - description: __("Further nodes can be only created under 'Group' type nodes")} - ] - - // the dialog - var d = new frappe.ui.Dialog({ - title: __('New {0}',[__(me.ctype)]), - fields: fields - }) - - d.set_value("is_group", "No"); - // create - d.set_primary_action(__("Create New"), function() { - var btn = this; - var v = d.get_values(); - if(!v) return; - - var node = me.tree.get_selected_node(); - - v.parent = node.label; - v.ctype = me.ctype; - - return frappe.call({ - method: 'erpnext.stock.page.warehouse_browser.warehouse_browser.add_node', - args: v, - callback: function(r) { - if(!r.exc) { - d.hide(); - if(node.expanded) { - node.toggle_node(); - } - node.reload(); - } - } - }); - }); - - d.show(); - }, -}) \ No newline at end of file diff --git a/erpnext/stock/page/warehouse_browser/warehouse_browser.json b/erpnext/stock/page/warehouse_browser/warehouse_browser.json deleted file mode 100644 index 3d0dcbcaf4..0000000000 --- a/erpnext/stock/page/warehouse_browser/warehouse_browser.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "content": null, - "creation": "2016-05-24 11:01:06.887660", - "docstatus": 0, - "doctype": "Page", - "idx": 0, - "modified": "2016-05-24 11:11:32.317342", - "modified_by": "Administrator", - "module": "Stock", - "name": "warehouse-browser", - "owner": "Administrator", - "page_name": "Warehouse Browser", - "roles": [ - { - "role": "Stock Manager" - }, - { - "role": "Stock User" - }, - { - "role": "System Manager" - } - ], - "script": null, - "standard": "Yes", - "style": null -} \ No newline at end of file diff --git a/erpnext/stock/page/warehouse_browser/warehouse_browser.py b/erpnext/stock/page/warehouse_browser/warehouse_browser.py deleted file mode 100644 index 48bb8a3389..0000000000 --- a/erpnext/stock/page/warehouse_browser/warehouse_browser.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -@frappe.whitelist() -def get_children(): - ctype = frappe.local.form_dict.get('ctype') - parent_field = 'parent_' + ctype.lower().replace(' ', '_') - parent = frappe.form_dict.get("parent") or "" - - return frappe.db.sql("""select name as value, - if(is_group='Yes', 1, 0) as expandable - from `tab{ctype}` - where docstatus < 2 - and ifnull(`{parent_field}`,'') = %s - order by name""".format(ctype=frappe.db.escape(ctype), parent_field=frappe.db.escape(parent_field)), - parent, as_dict=1) - -@frappe.whitelist() -def add_node(): - ctype = frappe.form_dict.get('ctype') - parent_field = 'parent_' + ctype.lower().replace(' ', '_') - name_field = ctype.lower().replace(' ', '_') + '_name' - - doc = frappe.new_doc(ctype) - - doc.update({ - name_field: frappe.form_dict['name_field'], - parent_field: frappe.form_dict['parent'], - "is_group": frappe.form_dict['is_group'] - }) - - doc.save() \ No newline at end of file From d64794510215ee2382e72c4bdbf2f405ef36522e Mon Sep 17 00:00:00 2001 From: Saurabh Date: Thu, 26 May 2016 16:56:14 +0530 Subject: [PATCH 04/17] [fixes] --- erpnext/stock/doctype/warehouse/warehouse_treeview.js | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 erpnext/stock/doctype/warehouse/warehouse_treeview.js diff --git a/erpnext/stock/doctype/warehouse/warehouse_treeview.js b/erpnext/stock/doctype/warehouse/warehouse_treeview.js new file mode 100644 index 0000000000..b0be3ec72e --- /dev/null +++ b/erpnext/stock/doctype/warehouse/warehouse_treeview.js @@ -0,0 +1,4 @@ +frappe.treeview_settings['Warehouse'] = { + get_tree_nodes: "erpnext.selling.page.sales_browser.sales_browser.get_children", + add_tree_node: "erpnext.selling.page.sales_browser.sales_browser.add_node" +} \ No newline at end of file From 5f48cb612843fff9674f0883f058b07923e50e95 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Fri, 27 May 2016 17:06:27 +0530 Subject: [PATCH 05/17] [enhancement] BOM treeview --- .../manufacturing/doctype/bom/bom_treeview.js | 34 +++++++++++++++++++ .../page/bom_browser/bom_browser.py | 3 +- 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 erpnext/manufacturing/doctype/bom/bom_treeview.js diff --git a/erpnext/manufacturing/doctype/bom/bom_treeview.js b/erpnext/manufacturing/doctype/bom/bom_treeview.js new file mode 100644 index 0000000000..359acdff6c --- /dev/null +++ b/erpnext/manufacturing/doctype/bom/bom_treeview.js @@ -0,0 +1,34 @@ +frappe.treeview_settings["BOM"] = { + get_tree_nodes: 'erpnext.manufacturing.page.bom_browser.bom_browser.get_children', + filters: [ + { + fieldname: "bom", + fieldtype:"Link", + options: "BOM", + label: __("BOM") + } + ], + breadcrumb: "Manufacturing", + disable_add_node: true, + label: "bom", // should be fieldname from filters + get_label: function(node) { + if(node.data.qty) { + return node.data.qty + " x " + node.data.item_code; + } else { + return node.data.item_code || node.data.value; + } + }, + toolbar: [ + {toggle_btn: true}, + { + label:__("Edit"), + condition: function(node) { + return node.expandable; + }, + click: function(node) { + + frappe.set_route("Form", "BOM", node.data.value); + } + } + ], +} \ No newline at end of file diff --git a/erpnext/manufacturing/page/bom_browser/bom_browser.py b/erpnext/manufacturing/page/bom_browser/bom_browser.py index 80993897a9..3437ab4ae9 100644 --- a/erpnext/manufacturing/page/bom_browser/bom_browser.py +++ b/erpnext/manufacturing/page/bom_browser/bom_browser.py @@ -5,7 +5,8 @@ from __future__ import unicode_literals import frappe @frappe.whitelist() -def get_children(parent): +def get_children(): + parent = frappe.local.form_dict.get('bom') return frappe.db.sql("""select item_code, bom_no as value, qty, if(ifnull(bom_no, "")!="", 1, 0) as expandable From 0e47bfeb16c2f8919a37ad7d7dc611bc63504c01 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Mon, 30 May 2016 17:54:16 +0530 Subject: [PATCH 06/17] [enhance] treeview to BOM, sales person, Cost Center and Chart of acounts --- .../doctype/account/account_treeview.js | 37 +++++++++++++++++++ .../cost_center/cost_center_treeview.js | 25 +++++++++++++ erpnext/accounts/utils.py | 8 ++++ .../manufacturing/doctype/bom/bom_treeview.js | 3 +- .../sales_person/sales_person_treeview.js | 11 ++++++ 5 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 erpnext/accounts/doctype/account/account_treeview.js create mode 100644 erpnext/accounts/doctype/cost_center/cost_center_treeview.js create mode 100644 erpnext/setup/doctype/sales_person/sales_person_treeview.js diff --git a/erpnext/accounts/doctype/account/account_treeview.js b/erpnext/accounts/doctype/account/account_treeview.js new file mode 100644 index 0000000000..673ef9f58f --- /dev/null +++ b/erpnext/accounts/doctype/account/account_treeview.js @@ -0,0 +1,37 @@ +frappe.treeview_settings["Account"] = { + breadcrumbs: "Accounts", + title: __("Chart Of Accounts"), + get_tree_root: false, + filters: [{ + fieldname: "comp", + fieldtype:"Select", + options: $.map(locals[':Company'], function(c) { return c.name; }).sort(), + label: __("Company") + }], + root_label: "Accounts", + get_tree_nodes: 'erpnext.accounts.page.accounts_browser.accounts_browser.get_children', + add_tree_node: 'erpnext.accounts.utils.add_ac', + menu_items:[ + { + label: __('New Company'), + action: function() { newdoc('Company'); }, + condition: 'frappe.boot.user.can_create.indexOf("Company") === -1' + } + ], + fields: [ + {fieldtype:'Data', fieldname:'account_name', label:__('New Account Name'), reqd:true, + description: __("Name of new Account. Note: Please don't create accounts for Customers and Suppliers")}, + {fieldtype:'Check', fieldname:'is_group', label:__('Is Group'), + description: __('Further accounts can be made under Groups, but entries can be made against non-Groups')}, + {fieldtype:'Select', fieldname:'root_type', label:__('Root Type'), + options: ['Asset', 'Liability', 'Equity', 'Income', 'Expense'].join('\n'), + }, + {fieldtype:'Select', fieldname:'account_type', label:__('Account Type'), + options: ['', 'Bank', 'Cash', 'Warehouse', 'Tax', 'Chargeable'].join('\n'), + description: __("Optional. This setting will be used to filter in various transactions.") }, + {fieldtype:'Float', fieldname:'tax_rate', label:__('Tax Rate')}, + {fieldtype:'Link', fieldname:'warehouse', label:__('Warehouse'), options:"Warehouse"}, + {fieldtype:'Link', fieldname:'account_currency', label:__('Currency'), options:"Currency", + description: __("Optional. Sets company's default currency, if not specified.")} + ] +} \ No newline at end of file diff --git a/erpnext/accounts/doctype/cost_center/cost_center_treeview.js b/erpnext/accounts/doctype/cost_center/cost_center_treeview.js new file mode 100644 index 0000000000..c3a222d2ca --- /dev/null +++ b/erpnext/accounts/doctype/cost_center/cost_center_treeview.js @@ -0,0 +1,25 @@ +frappe.treeview_settings["Cost Center"] = { + breadcrumbs: "Accounts", + get_tree_root: false, + filters: [{ + fieldname: "comp", + fieldtype:"Select", + options: $.map(locals[':Company'], function(c) { return c.name; }).sort(), + label: __("Company"), + }], + root_label: "Cost Centers", + get_tree_nodes: 'erpnext.accounts.page.accounts_browser.accounts_browser.get_children', + add_tree_node: 'erpnext.accounts.utils.add_cc', + menu_items:[ + { + label: __('New Company'), + action: function() { newdoc('Company'); }, + condition: 'frappe.boot.user.can_create.indexOf("Company") === -1' + } + ], + fields:[ + {fieldtype:'Data', fieldname:'cost_center_name', label:__('New Cost Center Name'), reqd:true}, + {fieldtype:'Check', fieldname:'is_group', label:__('Is Group'), + description:__('Further cost centers can be made under Groups but entries can be made against non-Groups')} + ] +} \ No newline at end of file diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 27f1394afe..06c15d7d96 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -135,6 +135,10 @@ def add_ac(args=None): args.pop("ignore_permissions") ac.update(args) + + if not ac.parent_account: + ac.parent_account = args.get("parent") + ac.old_parent = "" ac.freeze_account = "No" if cint(ac.get("is_root")): @@ -153,6 +157,10 @@ def add_cc(args=None): cc = frappe.new_doc("Cost Center") cc.update(args) + + if not cc.parent_cost_center: + cc.parent_cost_center = args.get("parent") + cc.old_parent = "" cc.insert() return cc.name diff --git a/erpnext/manufacturing/doctype/bom/bom_treeview.js b/erpnext/manufacturing/doctype/bom/bom_treeview.js index 359acdff6c..68ed4e2629 100644 --- a/erpnext/manufacturing/doctype/bom/bom_treeview.js +++ b/erpnext/manufacturing/doctype/bom/bom_treeview.js @@ -8,9 +8,10 @@ frappe.treeview_settings["BOM"] = { label: __("BOM") } ], + title: "BOM", breadcrumb: "Manufacturing", disable_add_node: true, - label: "bom", // should be fieldname from filters + root_label: "bom", //fieldname from filters get_label: function(node) { if(node.data.qty) { return node.data.qty + " x " + node.data.item_code; diff --git a/erpnext/setup/doctype/sales_person/sales_person_treeview.js b/erpnext/setup/doctype/sales_person/sales_person_treeview.js new file mode 100644 index 0000000000..fd2127d013 --- /dev/null +++ b/erpnext/setup/doctype/sales_person/sales_person_treeview.js @@ -0,0 +1,11 @@ +frappe.treeview_settings["Sales Person"] = { + fields: [ + {fieldtype:'Data', fieldname: 'name_field', + label:__('New Sales Person Name'), reqd:true}, + {fieldtype:'Link', fieldname:'employee', + label:__('Employee'), options:'Employee', + description: __("Please enter Employee Id of this sales person")}, + {fieldtype:'Select', fieldname:'is_group', label:__('Group Node'), options:'No\nYes', + description: __("Further nodes can be only created under 'Group' type nodes")} + ], +} \ No newline at end of file From 554f6f70aab8fe15f4a055f1b40d055cbbf446aa Mon Sep 17 00:00:00 2001 From: Saurabh Date: Mon, 6 Jun 2016 14:22:37 +0530 Subject: [PATCH 07/17] [fixes] nested set fix for warehouse, tree for accounts and cost center --- .../doctype/account/account_treeview.js | 29 ++++++++++---- .../cost_center/cost_center_treeview.js | 1 + .../v7_0/create_warehouse_nestedset.py | 20 +++------- erpnext/setup/doctype/company/company.py | 5 +-- erpnext/stock/doctype/warehouse/warehouse.py | 40 +++++++++++++++++++ .../doctype/warehouse/warehouse_treeview.js | 20 +++++++++- erpnext/stock/utils.py | 22 +++++++--- 7 files changed, 105 insertions(+), 32 deletions(-) diff --git a/erpnext/accounts/doctype/account/account_treeview.js b/erpnext/accounts/doctype/account/account_treeview.js index 673ef9f58f..ce5eb8fa7c 100644 --- a/erpnext/accounts/doctype/account/account_treeview.js +++ b/erpnext/accounts/doctype/account/account_treeview.js @@ -6,7 +6,8 @@ frappe.treeview_settings["Account"] = { fieldname: "comp", fieldtype:"Select", options: $.map(locals[':Company'], function(c) { return c.name; }).sort(), - label: __("Company") + label: __("Company"), + default: frappe.defaults.get_default('company') ? frappe.defaults.get_default('company'): "" }], root_label: "Accounts", get_tree_nodes: 'erpnext.accounts.page.accounts_browser.accounts_browser.get_children', @@ -24,14 +25,28 @@ frappe.treeview_settings["Account"] = { {fieldtype:'Check', fieldname:'is_group', label:__('Is Group'), description: __('Further accounts can be made under Groups, but entries can be made against non-Groups')}, {fieldtype:'Select', fieldname:'root_type', label:__('Root Type'), - options: ['Asset', 'Liability', 'Equity', 'Income', 'Expense'].join('\n'), - }, + options: ['Asset', 'Liability', 'Equity', 'Income', 'Expense'].join('\n')}, {fieldtype:'Select', fieldname:'account_type', label:__('Account Type'), options: ['', 'Bank', 'Cash', 'Warehouse', 'Tax', 'Chargeable'].join('\n'), - description: __("Optional. This setting will be used to filter in various transactions.") }, - {fieldtype:'Float', fieldname:'tax_rate', label:__('Tax Rate')}, - {fieldtype:'Link', fieldname:'warehouse', label:__('Warehouse'), options:"Warehouse"}, + description: __("Optional. This setting will be used to filter in various transactions."), + depends_on: 'eval:doc.is_group==1'}, + {fieldtype:'Float', fieldname:'tax_rate', label:__('Tax Rate'), + depends_on: 'eval:doc.is_group==1&&doc.account_type=="Tax"'}, + {fieldtype:'Link', fieldname:'warehouse', label:__('Warehouse'), options:"Warehouse", + depends_on: 'eval:(doc.is_group==1&&doc.account_type=="Warehouse")'}, {fieldtype:'Link', fieldname:'account_currency', label:__('Currency'), options:"Currency", description: __("Optional. Sets company's default currency, if not specified.")} - ] + ], + onrender: function(node) { + var dr_or_cr = node.data.balance < 0 ? "Cr" : "Dr"; + if (node.data && node.data.balance!==undefined) { + $('' + + (node.data.balance_in_account_currency ? + (format_currency(Math.abs(node.data.balance_in_account_currency), + node.data.account_currency) + " / ") : "") + + format_currency(Math.abs(node.data.balance), node.data.company_currency) + + " " + dr_or_cr + + '').insertBefore(node.$ul); + } + } } \ No newline at end of file diff --git a/erpnext/accounts/doctype/cost_center/cost_center_treeview.js b/erpnext/accounts/doctype/cost_center/cost_center_treeview.js index c3a222d2ca..eddf048446 100644 --- a/erpnext/accounts/doctype/cost_center/cost_center_treeview.js +++ b/erpnext/accounts/doctype/cost_center/cost_center_treeview.js @@ -6,6 +6,7 @@ frappe.treeview_settings["Cost Center"] = { fieldtype:"Select", options: $.map(locals[':Company'], function(c) { return c.name; }).sort(), label: __("Company"), + default: frappe.defaults.get_default('company') ? frappe.defaults.get_default('company'): "" }], root_label: "Cost Centers", get_tree_nodes: 'erpnext.accounts.page.accounts_browser.accounts_browser.get_children', diff --git a/erpnext/patches/v7_0/create_warehouse_nestedset.py b/erpnext/patches/v7_0/create_warehouse_nestedset.py index 01ae89165c..78cc3999a2 100644 --- a/erpnext/patches/v7_0/create_warehouse_nestedset.py +++ b/erpnext/patches/v7_0/create_warehouse_nestedset.py @@ -2,17 +2,9 @@ import frappe from frappe import _ def execute(): - if not frappe.db.exists("Warehouse", {"warehouse_name": _("Warehouses")}): - parent_warehouse = frappe.get_doc({ - "doctype": "Warehouse", - "warehouse_name": _("Warehouses"), - "is_group": "Yes" - }).insert(ignore_permissions=True) - - for warehouse in frappe.db.sql_list("""select name from tabWarehouse - where name != %s order by name asc""", "Warehouses - SI"): - print warehouse - warehouse = frappe.get_doc("Warehouse", warehouse) - warehouse.is_group = "No" - warehouse.parent_warehouse = parent_warehouse.name - warehouse.save(ignore_permissions=True) \ No newline at end of file + for warehouse in frappe.db.sql_list("""select name from tabWarehouse + order by company asc, name asc"""): + warehouse = frappe.get_doc("Warehouse", warehouse) + warehouse.is_group = "No" + warehouse.parent_warehouse = "" + warehouse.save(ignore_permissions=True) \ No newline at end of file diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index 7294834790..c45c2411df 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -87,7 +87,7 @@ class Company(Document): .format(self.country.lower()))(self) def create_default_warehouses(self): - for wh_detail in [{"warehouse_name": _("Warehouses"), "is_group": "Yes"}, + for wh_detail in [ {"warehouse_name": _("Stores"), "is_group": "No"}, {"warehouse_name": _("Work In Progress"), "is_group": "No"}, {"warehouse_name": _("Finished Goods"), "is_group": "No"}]: @@ -101,8 +101,7 @@ class Company(Document): "warehouse_name": wh_detail["warehouse_name"], "is_group": wh_detail["is_group"], "company": self.name, - "parent_warehouse": "" if wh_detail["is_group"] == "Yes" \ - else "{0} - {1}".format(_("Warehouses"), self.abbr), + "parent_warehouse": "", "create_account_under": stock_group }) warehouse.flags.ignore_permissions = True diff --git a/erpnext/stock/doctype/warehouse/warehouse.py b/erpnext/stock/doctype/warehouse/warehouse.py index d28a3c4a29..1032fb0ed3 100644 --- a/erpnext/stock/doctype/warehouse/warehouse.py +++ b/erpnext/stock/doctype/warehouse/warehouse.py @@ -165,3 +165,43 @@ class Warehouse(NestedSet): frappe.db.set_value("Stock Settings", None, "allow_negative_stock", existing_allow_negative_stock) frappe.db.auto_commit_on_many_writes = 0 + +@frappe.whitelist() +def get_children(): + from erpnext.stock.utils import get_stock_value_on + ctype = frappe.local.form_dict.get('ctype') + company = frappe.local.form_dict.get('comp') + + parent_field = 'parent_' + ctype.lower().replace(' ', '_') + parent = frappe.form_dict.get("parent") or "" + + if parent == "Warehouses": + parent = "" + + warehouses = frappe.db.sql("""select name as value, + if(is_group='Yes', 1, 0) as expandable + from `tab{ctype}` + where docstatus < 2 + and ifnull(`{parent_field}`,'') = %s and `company` = %s + order by name""".format(ctype=frappe.db.escape(ctype), parent_field=frappe.db.escape(parent_field)), + (parent, company), as_dict=1) + + # return warehouses + for wh in warehouses: + wh["balance"] = get_stock_value_on(warehouse=wh.value) + return warehouses + +@frappe.whitelist() +def add_node(): + ctype = frappe.form_dict.get('ctype') + parent_field = 'parent_' + ctype.lower().replace(' ', '_') + name_field = ctype.lower().replace(' ', '_') + '_name' + + doc = frappe.new_doc(ctype) + doc.update({ + name_field: frappe.form_dict['name_field'], + parent_field: frappe.form_dict['parent'], + "is_group": frappe.form_dict['is_group'] + }) + + doc.save() diff --git a/erpnext/stock/doctype/warehouse/warehouse_treeview.js b/erpnext/stock/doctype/warehouse/warehouse_treeview.js index b0be3ec72e..d23a5362db 100644 --- a/erpnext/stock/doctype/warehouse/warehouse_treeview.js +++ b/erpnext/stock/doctype/warehouse/warehouse_treeview.js @@ -1,4 +1,20 @@ frappe.treeview_settings['Warehouse'] = { - get_tree_nodes: "erpnext.selling.page.sales_browser.sales_browser.get_children", - add_tree_node: "erpnext.selling.page.sales_browser.sales_browser.add_node" + get_tree_nodes: "erpnext.stock.doctype.warehouse.warehouse.get_children", + add_tree_node: "erpnext.stock.doctype.warehouse.warehouse.add_node", + get_tree_root: false, + root_label: "Warehouses", + filters: [{ + fieldname: "comp", + fieldtype:"Select", + options: $.map(locals[':Company'], function(c) { return c.name; }).sort(), + label: __("Company"), + default: frappe.defaults.get_default('company') ? frappe.defaults.get_default('company'): "" + }], + onrender: function(node) { + if (node.data && node.data.balance!==undefined) { + $('' + + format_currency(Math.abs(node.data.balance), node.data.company_currency) + + '').insertBefore(node.$ul); + } + } } \ No newline at end of file diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py index 3f9de86493..af7dc588c1 100644 --- a/erpnext/stock/utils.py +++ b/erpnext/stock/utils.py @@ -15,24 +15,34 @@ def get_stock_value_on(warehouse=None, posting_date=None, item_code=None): values, condition = [posting_date], "" if warehouse: - values.append(warehouse) - condition += " AND warehouse = %s" + + wh = frappe.get_doc("Warehouse", warehouse) + + if wh.is_group == "Yes": + values.extend([wh.lft, wh.rgt]) + condition += "and exists (\ + select name from `tabWarehouse` wh where wh.name = sle.warehouse\ + and wh.lft >= %s and wh.rgt <= %s)" + + else: + values.append(warehouse) + condition += " AND warehouse = %s" if item_code: values.append(item_code) condition.append(" AND item_code = %s") stock_ledger_entries = frappe.db.sql(""" - SELECT item_code, stock_value - FROM `tabStock Ledger Entry` + SELECT item_code, stock_value, name, warehouse + FROM `tabStock Ledger Entry` sle WHERE posting_date <= %s {0} ORDER BY timestamp(posting_date, posting_time) DESC, name DESC """.format(condition), values, as_dict=1) sle_map = {} for sle in stock_ledger_entries: - sle_map.setdefault(sle.item_code, flt(sle.stock_value)) - + sle_map[sle.item_code] = sle_map.get(sle.item_code, 0.0) + flt(sle.stock_value) + return sum(sle_map.values()) def get_stock_balance(item_code, warehouse, posting_date=None, posting_time=None, with_valuation_rate=False): From 3d6aecd6182b2341fa9df03a4f2887d8df6577a9 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Mon, 20 Jun 2016 17:25:45 +0530 Subject: [PATCH 08/17] [fixes] set warehouse group wise reorder level, validate ledger (leaf warehouse) on sle and bin --- erpnext/public/js/queries.js | 6 ++- erpnext/stock/doctype/bin/bin.py | 11 ++++- erpnext/stock/doctype/item/item.js | 22 ++++++++++ .../doctype/item_reorder/item_reorder.json | 43 ++++++++++++++++++- .../stock_ledger_entry/stock_ledger_entry.py | 6 +++ erpnext/stock/doctype/warehouse/warehouse.py | 12 ++++-- erpnext/stock/reorder_item.py | 21 ++++++--- erpnext/stock/utils.py | 6 +++ 8 files changed, 115 insertions(+), 12 deletions(-) diff --git a/erpnext/public/js/queries.js b/erpnext/public/js/queries.js index 12307fb9b3..acc0409038 100644 --- a/erpnext/public/js/queries.js +++ b/erpnext/public/js/queries.js @@ -71,7 +71,11 @@ $.extend(erpnext.queries, { warehouse: function(doc) { return { - filters: [["Warehouse", "company", "in", ["", cstr(doc.company)]]] + filters: [ + ["Warehouse", "company", "in", ["", cstr(doc.company)]], + ["Warehouse", "is_group", "=", "No"] + + ] } } }); diff --git a/erpnext/stock/doctype/bin/bin.py b/erpnext/stock/doctype/bin/bin.py index a1580d52f0..c03ceee69c 100644 --- a/erpnext/stock/doctype/bin/bin.py +++ b/erpnext/stock/doctype/bin/bin.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals import frappe +from frappe import _ from frappe.utils import flt, nowdate import frappe.defaults from frappe.model.document import Document @@ -15,13 +16,21 @@ class Bin(Document): self.validate_mandatory() self.projected_qty = flt(self.actual_qty) + flt(self.ordered_qty) + \ - flt(self.indented_qty) + flt(self.planned_qty) - flt(self.reserved_qty) + flt(self.indented_qty) + flt(self.planned_qty) - flt(self.reserved_qty) + + self.validate_leaf_warehouse() def validate_mandatory(self): qf = ['actual_qty', 'reserved_qty', 'ordered_qty', 'indented_qty'] for f in qf: if (not getattr(self, f, None)) or (not self.get(f)): self.set(f, 0.0) + + def validate_leaf_warehouse(self): + from erpnext.stock.utils import is_leaf_warehouse + + if not is_leaf_warehouse(self.warehouse): + frappe.throw(_("Group node warehouse is not allowed to select for transactions")) def update_stock(self, args, allow_negative_stock=False, via_landed_cost_voucher=False): self.update_qty(args) diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js index fe7e54e8e5..f35fa58508 100644 --- a/erpnext/stock/doctype/item/item.js +++ b/erpnext/stock/doctype/item/item.js @@ -160,6 +160,28 @@ $.extend(erpnext.item, { frm.fields_dict.supplier_items.grid.get_field("supplier").get_query = function(doc, cdt, cdn) { return { query: "erpnext.controllers.queries.supplier_query" } } + + frm.fields_dict['default_warehouse'].get_query = function(doc) { + return { + filters: { "is_group": "No" } + } + } + + frm.fields_dict.reorder_levels.grid.get_field("warehouse_group").get_query = function(doc, cdt, cdn) { + return { + filters: { "is_group": "Yes" } + } + } + + frm.fields_dict.reorder_levels.grid.get_field("warehouse").get_query = function(doc, cdt, cdn) { + var d = locals[cdt][cdn]; + return { + filters: { + "is_group": "No", + "parent_warehouse": d.warehouse_group + } + } + } }, diff --git a/erpnext/stock/doctype/item_reorder/item_reorder.json b/erpnext/stock/doctype/item_reorder/item_reorder.json index fea8bf039a..27a311d927 100644 --- a/erpnext/stock/doctype/item_reorder/item_reorder.json +++ b/erpnext/stock/doctype/item_reorder/item_reorder.json @@ -3,11 +3,39 @@ "allow_import": 0, "allow_rename": 0, "autoname": "hash", + "beta": 0, "creation": "2013-03-07 11:42:59", "custom": 0, "docstatus": 0, "doctype": "DocType", + "document_type": "Setup", "fields": [ + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "warehouse_group", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Warehouse Group", + "length": 0, + "no_copy": 0, + "options": "Warehouse", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, @@ -16,6 +44,7 @@ "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, "label": "Warehouse", @@ -24,6 +53,7 @@ "options": "Warehouse", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 1, @@ -39,6 +69,7 @@ "fieldtype": "Float", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, "label": "Re-order Level", @@ -46,6 +77,7 @@ "no_copy": 0, "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 1, @@ -61,6 +93,7 @@ "fieldtype": "Float", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, "label": "Re-order Qty", @@ -68,6 +101,7 @@ "no_copy": 0, "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -83,6 +117,7 @@ "fieldtype": "Select", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, "label": "Material Request Type", @@ -91,6 +126,7 @@ "options": "Purchase\nTransfer", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 1, @@ -102,18 +138,21 @@ "hide_heading": 0, "hide_toolbar": 0, "idx": 1, + "image_view": 0, "in_create": 1, "in_dialog": 0, "is_submittable": 0, "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2015-11-16 06:29:48.492627", + "modified": "2016-06-20 15:52:01.978593", "modified_by": "Administrator", "module": "Stock", "name": "Item Reorder", "owner": "Administrator", "permissions": [], + "quick_entry": 0, "read_only": 0, - "read_only_onload": 0 + "read_only_onload": 0, + "track_seen": 0 } \ No newline at end of file diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py index 9931ffa7a4..1f446d2be0 100644 --- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py @@ -25,6 +25,7 @@ class StockLedgerEntry(Document): validate_warehouse_company(self.warehouse, self.company) self.scrub_posting_time() self.validate_and_set_fiscal_year() + self.validate_leaf_warehouse() from erpnext.accounts.utils import validate_fiscal_year validate_fiscal_year(self.posting_date, self.fiscal_year, self.meta.get_label("posting_date"), self) @@ -117,6 +118,11 @@ class StockLedgerEntry(Document): if not self.fiscal_year: self.fiscal_year = get_fiscal_year(self.posting_date, company=self.company)[0] + def validate_leaf_warehouse(self): + from erpnext.stock.utils import is_leaf_warehouse + + if not is_leaf_warehouse(self.warehouse): + frappe.throw(_("Group node warehouse is not allowed to select for transactions")) def on_doctype_update(): if not frappe.db.sql("""show index from `tabStock Ledger Entry` diff --git a/erpnext/stock/doctype/warehouse/warehouse.py b/erpnext/stock/doctype/warehouse/warehouse.py index 1032fb0ed3..a0b7296056 100644 --- a/erpnext/stock/doctype/warehouse/warehouse.py +++ b/erpnext/stock/doctype/warehouse/warehouse.py @@ -196,12 +196,18 @@ def add_node(): ctype = frappe.form_dict.get('ctype') parent_field = 'parent_' + ctype.lower().replace(' ', '_') name_field = ctype.lower().replace(' ', '_') + '_name' - + doc = frappe.new_doc(ctype) + + parent = frappe.form_dict['parent'] + + if cint(frappe.form_dict['is_root']): + parent = None + doc.update({ name_field: frappe.form_dict['name_field'], - parent_field: frappe.form_dict['parent'], + parent_field: parent, "is_group": frappe.form_dict['is_group'] }) - + doc.save() diff --git a/erpnext/stock/reorder_item.py b/erpnext/stock/reorder_item.py index 45319131fa..ad810a997a 100644 --- a/erpnext/stock/reorder_item.py +++ b/erpnext/stock/reorder_item.py @@ -37,7 +37,7 @@ def _reorder_item(): item_warehouse_projected_qty = get_item_warehouse_projected_qty(items_to_consider) - def add_to_material_request(item_code, warehouse, reorder_level, reorder_qty, material_request_type): + def add_to_material_request(item_code, warehouse, reorder_level, reorder_qty, material_request_type, warehouse_group=None): if warehouse not in warehouse_company: # a disabled warehouse return @@ -46,7 +46,10 @@ def _reorder_item(): reorder_qty = flt(reorder_qty) # projected_qty will be 0 if Bin does not exist - projected_qty = flt(item_warehouse_projected_qty.get(item_code, {}).get(warehouse)) + if warehouse_group: + projected_qty = flt(item_warehouse_projected_qty.get(item_code, {}).get(warehouse_group)) + else: + projected_qty = flt(item_warehouse_projected_qty.get(item_code, {}).get(warehouse)) if (reorder_level or reorder_qty) and projected_qty < reorder_level: deficiency = reorder_level - projected_qty @@ -70,7 +73,7 @@ def _reorder_item(): if item.get("reorder_levels"): for d in item.get("reorder_levels"): add_to_material_request(item_code, d.warehouse, d.warehouse_reorder_level, - d.warehouse_reorder_qty, d.material_request_type) + d.warehouse_reorder_qty, d.material_request_type, warehouse_group=d.warehouse_group) if material_requests: return create_material_request(material_requests) @@ -82,9 +85,17 @@ def get_item_warehouse_projected_qty(items_to_consider): from tabBin where item_code in ({0}) and (warehouse != "" and warehouse is not null)"""\ .format(", ".join(["%s"] * len(items_to_consider))), items_to_consider): - + item_warehouse_projected_qty.setdefault(item_code, {})[warehouse] = flt(projected_qty) - + + warehouse_doc = frappe.get_doc("Warehouse", warehouse) + + if warehouse_doc.parent_warehouse: + if not item_warehouse_projected_qty.get(item_code, {}).get(warehouse_doc.parent_warehouse): + item_warehouse_projected_qty.setdefault(item_code, {})[warehouse_doc.parent_warehouse] = flt(projected_qty) + else: + item_warehouse_projected_qty[item_code][warehouse_doc.parent_warehouse] += flt(projected_qty) + return item_warehouse_projected_qty def create_material_request(material_requests): diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py index af7dc588c1..6e56c5c7e7 100644 --- a/erpnext/stock/utils.py +++ b/erpnext/stock/utils.py @@ -187,3 +187,9 @@ def validate_warehouse_company(warehouse, company): if warehouse_company and warehouse_company != company: frappe.throw(_("Warehouse {0} does not belong to company {1}").format(warehouse, company), InvalidWarehouseCompany) + +def is_leaf_warehouse(warehouse): + if frappe.db.get_value("Warehouse", warehouse, "is_group") == "No": + return True + return False + \ No newline at end of file From 9c7b0079c5728515ada4b0dbc9ca107bd59af3c0 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Tue, 21 Jun 2016 11:56:08 +0530 Subject: [PATCH 09/17] [fixes] warehose group wise stock report and test cases for warehouse hierarchy and warehouse group wise reorder level --- erpnext/stock/doctype/item/test_records.json | 29 +++++++++++++ .../doctype/stock_entry/test_stock_entry.py | 13 +++--- .../stock/doctype/warehouse/test_records.json | 42 +++++++++++++++---- .../stock/doctype/warehouse/test_warehouse.py | 20 ++++++++- erpnext/stock/doctype/warehouse/warehouse.js | 10 +++++ .../report/stock_balance/stock_balance.py | 4 +- .../stock/report/stock_ledger/stock_ledger.py | 11 +++-- .../stock_projected_qty.py | 19 +++++---- 8 files changed, 122 insertions(+), 26 deletions(-) diff --git a/erpnext/stock/doctype/item/test_records.json b/erpnext/stock/doctype/item/test_records.json index fcf2d0bc14..c05c5f39bf 100644 --- a/erpnext/stock/doctype/item/test_records.json +++ b/erpnext/stock/doctype/item/test_records.json @@ -227,6 +227,35 @@ "warehouse_reorder_qty": 20 } ] + }, + { + "default_warehouse": "_Test Warehouse Group-C1 - _TC", + "description": "_Test Item 1", + "doctype": "Item", + "expense_account": "_Test Account Cost for Goods Sold - _TC", + "cost_center": "_Test Cost Center - _TC", + "has_batch_no": 0, + "has_serial_no": 0, + "income_account": "Sales - _TC", + "inspection_required": 0, + "is_stock_item": 1, + "is_sub_contracted_item": 0, + "item_code": "_Test Item Warehouse Group Wise Reorder", + "item_group": "_Test Item Group", + "item_name": "_Test Item Warehouse Group Wise Reorder", + "apply_warehouse_wise_reorder_level": 1, + "reorder_levels": [ + { + "warehouse_group": "_Test Warehouse Group - _TC", + "material_request_type": "Purchase", + "warehouse": "_Test Warehouse Group-C1 - _TC", + "warehouse_reorder_level": 20, + "warehouse_reorder_qty": 20 + } + ], + "stock_uom": "_Test UOM", + "show_in_website": 1, + "website_warehouse": "_Test Warehouse Group-C1 - _TC" } ] diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py index 0c33ff7f4f..24d0546224 100644 --- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py @@ -79,8 +79,11 @@ class TestStockEntry(unittest.TestCase): def test_auto_material_request_for_variant(self): self._test_auto_material_request("_Test Variant Item-S") - - def _test_auto_material_request(self, item_code, material_request_type="Purchase"): + + def test_auto_material_request_for_warehouse_group(self): + self._test_auto_material_request("_Test Item Warehouse Group Wise Reorder", warehouse="_Test Warehouse Group-C1 - _TC") + + def _test_auto_material_request(self, item_code, material_request_type="Purchase", warehouse="_Test Warehouse - _TC"): item = frappe.get_doc("Item", item_code) if item.variant_of: @@ -89,14 +92,14 @@ class TestStockEntry(unittest.TestCase): template = item projected_qty, actual_qty = frappe.db.get_value("Bin", {"item_code": item_code, - "warehouse": "_Test Warehouse - _TC"}, ["projected_qty", "actual_qty"]) or [0, 0] + "warehouse": warehouse}, ["projected_qty", "actual_qty"]) or [0, 0] # stock entry reqd for auto-reorder - create_stock_reconciliation(item_code=item_code, warehouse="_Test Warehouse - _TC", + create_stock_reconciliation(item_code=item_code, warehouse=warehouse, qty = actual_qty + abs(projected_qty) + 10, rate=100) projected_qty = frappe.db.get_value("Bin", {"item_code": item_code, - "warehouse": "_Test Warehouse - _TC"}, "projected_qty") or 0 + "warehouse": warehouse}, "projected_qty") or 0 frappe.db.set_value("Stock Settings", None, "auto_indent", 1) diff --git a/erpnext/stock/doctype/warehouse/test_records.json b/erpnext/stock/doctype/warehouse/test_records.json index f57fda36a7..c1dad5cfd0 100644 --- a/erpnext/stock/doctype/warehouse/test_records.json +++ b/erpnext/stock/doctype/warehouse/test_records.json @@ -4,43 +4,67 @@ "create_account_under": "Stock Assets - _TC", "doctype": "Warehouse", "warehouse_name": "_Test Warehouse", - - - } + "is_group": "No" + }, { "company": "_Test Company", "create_account_under": "Stock Assets - _TC", "doctype": "Warehouse", "warehouse_name": "_Test Warehouse", - "" + "is_group": "No" }, { "company": "_Test Company", "create_account_under": "Fixed Assets - _TC", "doctype": "Warehouse", - "warehouse_name": "_Test Warehouse 1" + "warehouse_name": "_Test Warehouse 1", + "is_group": "No" }, { "company": "_Test Company", "create_account_under": "Fixed Assets - _TC", "doctype": "Warehouse", - "warehouse_name": "_Test Warehouse 2" + "warehouse_name": "_Test Warehouse 2", + "is_group": "No" }, { "company": "_Test Company", "create_account_under": "Stock Assets - _TC", "doctype": "Warehouse", - "warehouse_name": "_Test Rejected Warehouse" + "warehouse_name": "_Test Rejected Warehouse", + "is_group": "No" }, { "company": "_Test Company 1", "create_account_under": "Stock Assets - _TC1", "doctype": "Warehouse", - "warehouse_name": "_Test Warehouse 2" + "warehouse_name": "_Test Warehouse 2", + "is_group": "No" }, { "company": "_Test Company", "doctype": "Warehouse", - "warehouse_name": "_Test Warehouse No Account" + "warehouse_name": "_Test Warehouse No Account", + "is_group": "No" + }, + { + "company": "_Test Company", + "doctype": "Warehouse", + "warehouse_name": "_Test Warehouse Group", + "is_group": "Yes" + }, + { + "company": "_Test Company", + "doctype": "Warehouse", + "warehouse_name": "_Test Warehouse Group-C1", + "is_group": "No", + "parent_warehouse": "_Test Warehouse Group - _TC" + }, + { + "company": "_Test Company", + "doctype": "Warehouse", + "warehouse_name": "_Test Warehouse Group-C2", + "is_group": "No", + "parent_warehouse": "_Test Warehouse Group - _TC" } ] diff --git a/erpnext/stock/doctype/warehouse/test_warehouse.py b/erpnext/stock/doctype/warehouse/test_warehouse.py index ca80ca793c..b6eaa13602 100644 --- a/erpnext/stock/doctype/warehouse/test_warehouse.py +++ b/erpnext/stock/doctype/warehouse/test_warehouse.py @@ -4,4 +4,22 @@ from __future__ import unicode_literals import frappe -test_records = frappe.get_test_records('Warehouse') \ No newline at end of file +import unittest +test_records = frappe.get_test_records('Warehouse') + +class TestWarehouse(unittest.TestCase): + def test_parent_warehouse(self): + parent_warehouse = frappe.get_doc("Warehouse", "_Test Warehouse Group - _TC") + self.assertEquals(parent_warehouse.is_group, "Yes") + + def test_warehouse_hierarchy(self): + p_warehouse = frappe.get_doc("Warehouse", "_Test Warehouse Group - _TC") + + child_warehouses = frappe.db.sql("""select name, is_group, parent_warehouse from `tabWarehouse` wh + where wh.lft > %s and wh.rgt < %s""", (p_warehouse.lft, p_warehouse.rgt), as_dict=1) + + for child_warehouse in child_warehouses: + self.assertEquals(p_warehouse.name, child_warehouse.parent_warehouse) + self.assertEquals(child_warehouse.is_group, "No") + + diff --git a/erpnext/stock/doctype/warehouse/warehouse.js b/erpnext/stock/doctype/warehouse/warehouse.js index f1f0b66fcb..debcbfdbb5 100644 --- a/erpnext/stock/doctype/warehouse/warehouse.js +++ b/erpnext/stock/doctype/warehouse/warehouse.js @@ -17,10 +17,20 @@ frappe.ui.form.on("Warehouse", { frappe.set_route("query-report", "General Ledger"); }); } + + frm.fields_dict['parent_warehouse'].get_query = function(doc) { + return { + filters: { + "is_group": "Yes", + } + } + } } }); + + cur_frm.set_query("create_account_under", function() { return { filters: { diff --git a/erpnext/stock/report/stock_balance/stock_balance.py b/erpnext/stock/report/stock_balance/stock_balance.py index 43b6b9a4f3..75200b340d 100644 --- a/erpnext/stock/report/stock_balance/stock_balance.py +++ b/erpnext/stock/report/stock_balance/stock_balance.py @@ -71,7 +71,9 @@ def get_conditions(filters): conditions += " and item_code = '%s'" % frappe.db.escape(filters.get("item_code"), percent=False) if filters.get("warehouse"): - conditions += " and warehouse = '%s'" % frappe.db.escape(filters.get("warehouse"), percent=False) + wh = frappe.get_doc("Warehouse", filters.get("warehouse")) + conditions += "and warehouse in (\ + select name from `tabWarehouse` wh where wh.lft >= %s and wh.rgt <= %s)"%(wh.lft, wh.rgt) return conditions diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py index ac4cbbd2e0..a65be6d8e7 100644 --- a/erpnext/stock/report/stock_ledger/stock_ledger.py +++ b/erpnext/stock/report/stock_ledger/stock_ledger.py @@ -73,7 +73,7 @@ def get_sle_conditions(filters): conditions.append("""item_code in (select name from tabItem {item_conditions})""".format(item_conditions=item_conditions)) if filters.get("warehouse"): - conditions.append("warehouse=%(warehouse)s") + conditions.append(get_warehouse_condition(filters.get("warehouse"))) if filters.get("voucher_no"): conditions.append("voucher_no=%(voucher_no)s") @@ -86,7 +86,7 @@ def get_opening_balance(filters, columns): from erpnext.stock.stock_ledger import get_previous_sle last_entry = get_previous_sle({ "item_code": filters.item_code, - "warehouse": filters.warehouse, + "warehouse": get_warehouse_condition(filters.warehouse), "posting_date": filters.from_date, "posting_time": "00:00:00" }) @@ -96,4 +96,9 @@ def get_opening_balance(filters, columns): for i, v in ((9, 'qty_after_transaction'), (11, 'valuation_rate'), (12, 'stock_value')): row[i] = last_entry.get(v, 0) - return row \ No newline at end of file + return row + +def get_warehouse_condition(warehouse): + wh = frappe.get_doc("Warehouse", warehouse) + return " warehouse in (select name from `tabWarehouse` wh\ + where wh.lft >= %s and wh.rgt <= %s)"%(wh.lft, wh.rgt) \ No newline at end of file diff --git a/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py b/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py index 89963abde3..2fb120a180 100644 --- a/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py +++ b/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py @@ -57,16 +57,19 @@ def get_data(filters): return data def get_bin_list(filters): - bin_filters = frappe._dict() + conditions = [] + if filters.item_code: - bin_filters.item_code = filters.item_code + conditions.append("item_code = '%s' "%filters.item_code) + if filters.warehouse: - bin_filters.warehouse = filters.warehouse + wh = frappe.get_doc("Warehouse", filters.warehouse) + conditions.append(" warehouse in (select name from `tabWarehouse` wh\ + where wh.lft >= %s and wh.rgt <= %s)"%(wh.lft, wh.rgt)) - bin_list = frappe.get_all("Bin", fields=["item_code", "warehouse", - "actual_qty", "planned_qty", "indented_qty", "ordered_qty", "reserved_qty", - "reserved_qty_for_production", "projected_qty"], - filters=bin_filters, order_by="item_code, warehouse") + bin_list = frappe.db.sql("""select item_code, warehouse, actual_qty, planned_qty, indented_qty, + ordered_qty, reserved_qty, reserved_qty_for_production, projected_qty + from tabBin where %s order by item_code, warehouse """% " and ".join(conditions), as_dict=1,debug=1) return bin_list @@ -101,4 +104,6 @@ def get_item_map(item_code): item["reorder_levels"] = reorder_levels.get(item.name) or [] item_map[item.name] = item + + frappe.errprint(item_map) return item_map From a9ba7343c4a4a19ac68cb583796582a9eaaeb128 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Tue, 21 Jun 2016 12:33:12 +0530 Subject: [PATCH 10/17] [fix] deprecate browser pages for accounts, cost_center, sales , bom, item group --- .../doctype/account/account_treeview.js | 2 +- .../cost_center/cost_center_treeview.js | 2 +- .../accounts/page/accounts_browser/README.md | 1 - .../page/accounts_browser/__init__.py | 1 - .../page/accounts_browser/accounts_browser.js | 334 ------------------ .../accounts_browser/accounts_browser.json | 22 -- .../page/accounts_browser/accounts_browser.py | 57 --- erpnext/accounts/utils.py | 51 ++- erpnext/manufacturing/doctype/bom/bom.py | 11 + .../manufacturing/doctype/bom/bom_treeview.js | 2 +- .../page/bom_browser/__init__.py | 0 .../page/bom_browser/bom_browser.js | 89 ----- .../page/bom_browser/bom_browser.json | 21 -- .../page/bom_browser/bom_browser.py | 16 - erpnext/selling/page/sales_browser/README.md | 1 - .../selling/page/sales_browser/__init__.py | 1 - .../page/sales_browser/sales_browser.json | 37 -- .../page/sales_browser/sales_browser.py | 37 -- erpnext/selling/page/sales_browser/tree.js | 166 --------- 19 files changed, 64 insertions(+), 787 deletions(-) delete mode 100644 erpnext/accounts/page/accounts_browser/README.md delete mode 100644 erpnext/accounts/page/accounts_browser/__init__.py delete mode 100644 erpnext/accounts/page/accounts_browser/accounts_browser.js delete mode 100644 erpnext/accounts/page/accounts_browser/accounts_browser.json delete mode 100644 erpnext/accounts/page/accounts_browser/accounts_browser.py delete mode 100644 erpnext/manufacturing/page/bom_browser/__init__.py delete mode 100644 erpnext/manufacturing/page/bom_browser/bom_browser.js delete mode 100644 erpnext/manufacturing/page/bom_browser/bom_browser.json delete mode 100644 erpnext/manufacturing/page/bom_browser/bom_browser.py delete mode 100644 erpnext/selling/page/sales_browser/README.md delete mode 100644 erpnext/selling/page/sales_browser/__init__.py delete mode 100644 erpnext/selling/page/sales_browser/sales_browser.json delete mode 100644 erpnext/selling/page/sales_browser/sales_browser.py delete mode 100644 erpnext/selling/page/sales_browser/tree.js diff --git a/erpnext/accounts/doctype/account/account_treeview.js b/erpnext/accounts/doctype/account/account_treeview.js index ce5eb8fa7c..3ee1c42fcb 100644 --- a/erpnext/accounts/doctype/account/account_treeview.js +++ b/erpnext/accounts/doctype/account/account_treeview.js @@ -10,7 +10,7 @@ frappe.treeview_settings["Account"] = { default: frappe.defaults.get_default('company') ? frappe.defaults.get_default('company'): "" }], root_label: "Accounts", - get_tree_nodes: 'erpnext.accounts.page.accounts_browser.accounts_browser.get_children', + get_tree_nodes: 'erpnext.accounts.utils.get_children', add_tree_node: 'erpnext.accounts.utils.add_ac', menu_items:[ { diff --git a/erpnext/accounts/doctype/cost_center/cost_center_treeview.js b/erpnext/accounts/doctype/cost_center/cost_center_treeview.js index eddf048446..3ca5232e3f 100644 --- a/erpnext/accounts/doctype/cost_center/cost_center_treeview.js +++ b/erpnext/accounts/doctype/cost_center/cost_center_treeview.js @@ -9,7 +9,7 @@ frappe.treeview_settings["Cost Center"] = { default: frappe.defaults.get_default('company') ? frappe.defaults.get_default('company'): "" }], root_label: "Cost Centers", - get_tree_nodes: 'erpnext.accounts.page.accounts_browser.accounts_browser.get_children', + get_tree_nodes: 'erpnext.accounts.utils.get_children', add_tree_node: 'erpnext.accounts.utils.add_cc', menu_items:[ { diff --git a/erpnext/accounts/page/accounts_browser/README.md b/erpnext/accounts/page/accounts_browser/README.md deleted file mode 100644 index b8795613fc..0000000000 --- a/erpnext/accounts/page/accounts_browser/README.md +++ /dev/null @@ -1 +0,0 @@ -Tree view browser for Chart of Accounts and Chart of Cost Centers \ No newline at end of file diff --git a/erpnext/accounts/page/accounts_browser/__init__.py b/erpnext/accounts/page/accounts_browser/__init__.py deleted file mode 100644 index baffc48825..0000000000 --- a/erpnext/accounts/page/accounts_browser/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/accounts/page/accounts_browser/accounts_browser.js b/erpnext/accounts/page/accounts_browser/accounts_browser.js deleted file mode 100644 index ec906f8798..0000000000 --- a/erpnext/accounts/page/accounts_browser/accounts_browser.js +++ /dev/null @@ -1,334 +0,0 @@ -// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -// License: GNU General Public License v3. See license.txt - -// tree of chart of accounts / cost centers -// multiple companies -// add node -// edit node -// see ledger - -frappe.pages["Accounts Browser"].on_page_load = function(wrapper){ - frappe.ui.make_app_page({ - parent: wrapper, - single_column: true - }) - - frappe.breadcrumbs.add("Accounts"); - - var main = wrapper.page.main, - chart_area = $("
") - .css({"margin-bottom": "15px", "min-height": "200px"}) - .appendTo(main), - help_area = $('
'+ - '

'+__('Quick Help')+'

'+ - '
    '+ - '
  1. '+__('To add child nodes, explore tree and click on the node under which you want to add more nodes.')+'
  2. '+ - '
  3. '+ - __('Accounting Entries can be made against leaf nodes. Entries against Groups are not allowed.')+ - '
  4. '+ - '
  5. '+__('Please do NOT create Accounts for Customers and Suppliers. They are created directly from the Customer / Supplier masters.')+'
  6. '+ - '
  7. '+ - ''+__('To create a Bank Account')+': '+ - __('Go to the appropriate group (usually Application of Funds > Current Assets > Bank Accounts and create a new Account (by clicking on Add Child) of type "Bank"')+ - '
  8. '+ - '
  9. '+ - ''+__('To create a Tax Account') +': '+ - __('Go to the appropriate group (usually Source of Funds > Current Liabilities > Taxes and Duties and create a new Account (by clicking on Add Child) of type "Tax" and do mention the Tax rate.')+ - '
  10. '+ - '
'+ - '

'+__('Please setup your chart of accounts before you start Accounting Entries')+'

').appendTo(main); - - if (frappe.boot.user.can_create.indexOf("Company") !== -1) { - wrapper.page.add_menu_item(__('New Company'), function() { newdoc('Company'); }, true); - } - - wrapper.page.add_menu_item(__('Refresh'), function() { - wrapper.$company_select.change(); - }); - - wrapper.page.set_primary_action(__('New'), function() { - erpnext.account_chart && erpnext.account_chart.make_new(); - }, "octicon octicon-plus"); - - var company_list = $.map(locals[':Company'], function(c) { return c.name; }).sort(); - - // company-select - wrapper.$company_select = wrapper.page.add_select("Company", company_list) - .change(function() { - var ctype = frappe.get_route()[1] || 'Account'; - erpnext.account_chart = new erpnext.AccountsChart(ctype, $(this).val(), - chart_area.get(0), wrapper.page); - }) - - if(frappe.defaults.get_default('company')) { - wrapper.$company_select.val(frappe.defaults.get_default('company')); - } - wrapper.$company_select.change(); -} - -frappe.pages["Accounts Browser"].on_page_show = function(wrapper){ - // set route - var ctype = frappe.get_route()[1] || 'Account'; - - if(frappe.route_options) { - if(frappe.route_options.company) { - wrapper.$company_select.val(frappe.route_options.company).change(); - } - frappe.route_options = null; - } else if(erpnext.account_chart && erpnext.account_chart.ctype != ctype) { - wrapper.$company_select.change(); - } - -} - -erpnext.AccountsChart = Class.extend({ - init: function(ctype, company, wrapper, page) { - $(wrapper).empty(); - var me = this; - me.ctype = ctype; - me.can_create = frappe.model.can_create(this.ctype); - me.can_delete = frappe.model.can_delete(this.ctype); - me.can_write = frappe.model.can_write(this.ctype); - me.page = page; - me.set_title(); - - // __("Accounts"), __("Cost Centers") - - me.company = company; - this.tree = new frappe.ui.Tree({ - parent: $(wrapper), - label: ctype==="Account" ? "Accounts" : "Cost Centers", - args: {ctype: ctype, comp: company}, - method: 'erpnext.accounts.page.accounts_browser.accounts_browser.get_children', - click: function(link) { - // bold - $('.bold').removeClass('bold'); // deselect - $(link).parent().find('.balance-area:first').addClass('bold'); // select - - }, - toolbar: [ - { toggle_btn: true }, - { - label: __("Open"), - condition: function(node) { return !node.root }, - click: function(node, btn) { - frappe.set_route("Form", me.ctype, node.label); - } - }, - { - condition: function(node) { return node.expandable; }, - label: __("Add Child"), - click: function() { - me.make_new() - }, - btnClass: "hidden-xs" - }, - { - condition: function(node) { - return !node.root && me.ctype === 'Account' - && frappe.boot.user.can_read.indexOf("GL Entry") !== -1 - }, - label: __("View Ledger"), - click: function(node, btn) { - frappe.route_options = { - "account": node.label, - "from_date": sys_defaults.year_start_date, - "to_date": sys_defaults.year_end_date, - "company": me.company - }; - frappe.set_route("query-report", "General Ledger"); - }, - btnClass: "hidden-xs" - }, - { - condition: function(node) { return !node.root && me.can_write }, - label: __("Rename"), - click: function(node) { - frappe.model.rename_doc(me.ctype, node.label, function(new_name) { - node.reload_parent(); - }); - }, - btnClass: "hidden-xs" - }, - { - condition: function(node) { return !node.root && me.can_delete }, - label: __("Delete"), - click: function(node) { - frappe.model.delete_doc(me.ctype, node.label, function() { - node.parent.remove(); - }); - }, - btnClass: "hidden-xs" - } - ], - onrender: function(node) { - var dr_or_cr = node.data.balance < 0 ? "Cr" : "Dr"; - if (me.ctype == 'Account' && node.data && node.data.balance!==undefined) { - $('' - + (node.data.balance_in_account_currency ? - (format_currency(Math.abs(node.data.balance_in_account_currency), - node.data.account_currency) + " / ") : "") - + format_currency(Math.abs(node.data.balance), node.data.company_currency) - + " " + dr_or_cr - + '').insertBefore(node.$ul); - } - } - }); - }, - set_title: function(val) { - var chart_str = this.ctype=="Account" ? __("Chart of Accounts") : __("Chart of Cost Centers"); - if(val) { - this.page.set_title(chart_str + " - " + cstr(val)); - } else { - this.page.set_title(chart_str); - } - }, - - make_new: function() { - if(this.ctype=='Account') { - this.new_account(); - } else { - this.new_cost_center(); - } - }, - - new_account: function() { - var me = this; - - var node = me.tree.get_selected_node(); - - if(!(node && node.expandable)) { - frappe.msgprint(__("Select a group node first.")); - return; - } - - // the dialog - var d = new frappe.ui.Dialog({ - title:__('New Account'), - fields: [ - {fieldtype:'Data', fieldname:'account_name', label:__('New Account Name'), reqd:true, - description: __("Name of new Account. Note: Please don't create accounts for Customers and Suppliers")}, - {fieldtype:'Check', fieldname:'is_group', label:__('Is Group'), - description: __('Further accounts can be made under Groups, but entries can be made against non-Groups')}, - {fieldtype:'Select', fieldname:'root_type', label:__('Root Type'), - options: ['Asset', 'Liability', 'Equity', 'Income', 'Expense'].join('\n'), - }, - {fieldtype:'Select', fieldname:'account_type', label:__('Account Type'), - options: ['', 'Bank', 'Cash', 'Warehouse', 'Tax', 'Chargeable'].join('\n'), - description: __("Optional. This setting will be used to filter in various transactions.") }, - {fieldtype:'Float', fieldname:'tax_rate', label:__('Tax Rate')}, - {fieldtype:'Link', fieldname:'warehouse', label:__('Warehouse'), options:"Warehouse"}, - {fieldtype:'Link', fieldname:'account_currency', label:__('Currency'), options:"Currency", - description: __("Optional. Sets company's default currency, if not specified.")} - ] - }) - - var fd = d.fields_dict; - - // account type if ledger - $(fd.is_group.input).change(function() { - if($(this).prop("checked")) { - $(fd.account_type.wrapper).toggle(false); - $(fd.tax_rate.wrapper).toggle(false); - $(fd.warehouse.wrapper).toggle(false); - } else { - $(fd.account_type.wrapper).toggle(node.root ? false : true); - fd.account_type.$input.trigger("change"); - } - }); - - // tax rate if tax - $(fd.account_type.input).change(function() { - $(fd.tax_rate.wrapper).toggle(fd.account_type.get_value()==='Tax'); - $(fd.warehouse.wrapper).toggle(fd.account_type.get_value()==='Warehouse'); - }) - - // create - d.set_primary_action(__("Create New"), function() { - var btn = this; - var v = d.get_values(); - if(!v) return; - - if(v.account_type==="Warehouse" && !v.warehouse) { - msgprint(__("Warehouse is required")); - return; - } - - var node = me.tree.get_selected_node(); - v.parent_account = node.label; - v.company = me.company; - - if(node.root) { - v.is_root = 1; - v.parent_account = null; - } else { - v.is_root = 0; - v.root_type = null; - } - - return frappe.call({ - args: v, - method: 'erpnext.accounts.utils.add_ac', - callback: function(r) { - d.hide(); - if(node.expanded) { - node.toggle_node(); - } - node.load(); - } - }); - }); - - // show - d.on_page_show = function() { - $(fd.is_group.input).change(); - $(fd.account_type.input).change(); - } - - $(fd.is_group.input).prop("checked", false).change(); - - // In case of root, show root type and hide account_type, is_group - $(fd.root_type.wrapper).toggle(node.root); - $(fd.is_group.wrapper).toggle(!node.root); - - d.show(); - }, - - new_cost_center: function(){ - var me = this; - // the dialog - var d = new frappe.ui.Dialog({ - title:__('New Cost Center'), - fields: [ - {fieldtype:'Data', fieldname:'cost_center_name', label:__('New Cost Center Name'), reqd:true}, - {fieldtype:'Check', fieldname:'is_group', label:__('Is Group'), - description:__('Further cost centers can be made under Groups but entries can be made against non-Groups')}, - {fieldtype:'Button', fieldname:'create_new', label:__('Create New') } - ] - }); - - // create - $(d.fields_dict.create_new.input).click(function() { - var v = d.get_values(); - if(!v) return; - - var node = me.tree.get_selected_node(); - - v.parent_cost_center = node.label; - v.company = me.company; - - return frappe.call({ - args: v, - method: 'erpnext.accounts.utils.add_cc', - callback: function(r) { - d.hide(); - if(node.expanded) { - node.toggle_node(); - } - node.load(); - } - }); - }); - d.show(); - } -}); diff --git a/erpnext/accounts/page/accounts_browser/accounts_browser.json b/erpnext/accounts/page/accounts_browser/accounts_browser.json deleted file mode 100644 index f0fe2e8288..0000000000 --- a/erpnext/accounts/page/accounts_browser/accounts_browser.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "creation": "2012-06-14 15:07:28.000000", - "docstatus": 0, - "doctype": "Page", - "icon": "icon-sitemap", - "idx": 1, - "modified": "2013-07-11 14:39:42.000000", - "modified_by": "Administrator", - "module": "Accounts", - "name": "accounts-browser", - "owner": "Administrator", - "page_name": "Accounts Browser", - "roles": [ - { - "role": "Accounts User" - }, - { - "role": "Accounts Manager" - } - ], - "standard": "Yes" -} diff --git a/erpnext/accounts/page/accounts_browser/accounts_browser.py b/erpnext/accounts/page/accounts_browser/accounts_browser.py deleted file mode 100644 index d96b21355f..0000000000 --- a/erpnext/accounts/page/accounts_browser/accounts_browser.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -import frappe.defaults -from frappe.utils import flt -from erpnext.accounts.utils import get_balance_on -from erpnext.accounts.report.financial_statements import sort_root_accounts - -@frappe.whitelist() -def get_companies(): - """get a list of companies based on permission""" - return [d.name for d in frappe.get_list("Company", fields=["name"], - order_by="name")] - -@frappe.whitelist() -def get_children(): - args = frappe.local.form_dict - ctype, company = args['ctype'], args['comp'] - fieldname = frappe.db.escape(ctype.lower().replace(' ','_')) - doctype = frappe.db.escape(ctype) - - # root - if args['parent'] in ("Accounts", "Cost Centers"): - fields = ", root_type, report_type, account_currency" if ctype=="Account" else "" - acc = frappe.db.sql(""" select - name as value, is_group as expandable {fields} - from `tab{doctype}` - where ifnull(`parent_{fieldname}`,'') = '' - and `company` = %s and docstatus<2 - order by name""".format(fields=fields, fieldname = fieldname, doctype=doctype), - company, as_dict=1) - - if args["parent"]=="Accounts": - sort_root_accounts(acc) - else: - # other - fields = ", account_currency" if ctype=="Account" else "" - acc = frappe.db.sql("""select - name as value, is_group as expandable, parent_{fieldname} as parent {fields} - from `tab{doctype}` - where ifnull(`parent_{fieldname}`,'') = %s - and docstatus<2 - order by name""".format(fields=fields, fieldname=fieldname, doctype=doctype), - args['parent'], as_dict=1) - - if ctype == 'Account': - company_currency = frappe.db.get_value("Company", company, "default_currency") - for each in acc: - each["company_currency"] = company_currency - each["balance"] = flt(get_balance_on(each.get("value"), in_account_currency=False)) - - if each.account_currency != company_currency: - each["balance_in_account_currency"] = flt(get_balance_on(each.get("value"))) - - return acc diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 06c15d7d96..78e07619b6 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -9,7 +9,8 @@ from frappe import throw, _ from frappe.utils import formatdate # imported to enable erpnext.accounts.utils.get_account_currency -from erpnext.accounts.doctype.account.account import get_account_currency +import frappe.defaults +from erpnext.accounts.report.financial_statements import sort_root_accounts class FiscalYearError(frappe.ValidationError): pass @@ -436,3 +437,51 @@ def get_account_name(account_type=None, root_type=None, is_group=None, account_c "account_currency": account_currency or frappe.defaults.get_defaults().currency, "company": company or frappe.defaults.get_defaults().company }, "name") + +@frappe.whitelist() +def get_companies(): + """get a list of companies based on permission""" + return [d.name for d in frappe.get_list("Company", fields=["name"], + order_by="name")] + +@frappe.whitelist() +def get_children(): + args = frappe.local.form_dict + ctype, company = args['ctype'], args['comp'] + fieldname = frappe.db.escape(ctype.lower().replace(' ','_')) + doctype = frappe.db.escape(ctype) + + # root + if args['parent'] in ("Accounts", "Cost Centers"): + fields = ", root_type, report_type, account_currency" if ctype=="Account" else "" + acc = frappe.db.sql(""" select + name as value, is_group as expandable {fields} + from `tab{doctype}` + where ifnull(`parent_{fieldname}`,'') = '' + and `company` = %s and docstatus<2 + order by name""".format(fields=fields, fieldname = fieldname, doctype=doctype), + company, as_dict=1) + + if args["parent"]=="Accounts": + sort_root_accounts(acc) + else: + # other + fields = ", account_currency" if ctype=="Account" else "" + acc = frappe.db.sql("""select + name as value, is_group as expandable, parent_{fieldname} as parent {fields} + from `tab{doctype}` + where ifnull(`parent_{fieldname}`,'') = %s + and docstatus<2 + order by name""".format(fields=fields, fieldname=fieldname, doctype=doctype), + args['parent'], as_dict=1) + + if ctype == 'Account': + company_currency = frappe.db.get_value("Company", company, "default_currency") + for each in acc: + each["company_currency"] = company_currency + each["balance"] = flt(get_balance_on(each.get("value"), in_account_currency=False)) + + if each.account_currency != company_currency: + each["balance_in_account_currency"] = flt(get_balance_on(each.get("value"))) + + return acc diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index 67301411db..287ee9b2f7 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -438,3 +438,14 @@ def validate_bom_no(item, bom_no): if item and not (bom.item.lower() == item.lower() or \ bom.item.lower() == cstr(frappe.db.get_value("Item", item, "variant_of")).lower()): frappe.throw(_("BOM {0} does not belong to Item {1}").format(bom_no, item)) + +@frappe.whitelist() +def get_children(parent=None): + if parent: + return frappe.db.sql("""select item_code, + bom_no as value, qty, + if(ifnull(bom_no, "")!="", 1, 0) as expandable + from `tabBOM Item` + where parent=%s + order by idx + """, parent, as_dict=True) \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/bom/bom_treeview.js b/erpnext/manufacturing/doctype/bom/bom_treeview.js index 68ed4e2629..0404360ee4 100644 --- a/erpnext/manufacturing/doctype/bom/bom_treeview.js +++ b/erpnext/manufacturing/doctype/bom/bom_treeview.js @@ -1,5 +1,5 @@ frappe.treeview_settings["BOM"] = { - get_tree_nodes: 'erpnext.manufacturing.page.bom_browser.bom_browser.get_children', + get_tree_nodes: 'erpnext.manufacturing.doctype.bom.bom.get_children', filters: [ { fieldname: "bom", diff --git a/erpnext/manufacturing/page/bom_browser/__init__.py b/erpnext/manufacturing/page/bom_browser/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/manufacturing/page/bom_browser/bom_browser.js b/erpnext/manufacturing/page/bom_browser/bom_browser.js deleted file mode 100644 index 3c13905caf..0000000000 --- a/erpnext/manufacturing/page/bom_browser/bom_browser.js +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -// License: GNU General Public License v3. See license.txt - -frappe.pages['bom-browser'].on_page_load = function(wrapper) { - var page = frappe.ui.make_app_page({ - parent: wrapper, - title: 'BOM Browser', - single_column: true - }); - - page.main.css({ - "min-height": "300px", - "padding-bottom": "25px" - }); - - page.tree_area = $('

'+ - __("Select BOM to start") - +'

').appendTo(page.main); - - frappe.breadcrumbs.add(frappe.breadcrumbs.last_module || "Manufacturing"); - - var make_tree = function() { - erpnext.bom_tree = new erpnext.BOMTree(page.$bom_select.val(), page, page.tree_area); - } - - page.$bom_select = wrapper.page.add_field({fieldname: "bom", - fieldtype:"Link", options: "BOM", label: __("BOM")}).$input - .change(function() { - make_tree(); - }); - - page.set_secondary_action(__('Refresh'), function() { - make_tree(); - }); -} - - -frappe.pages['bom-browser'].on_page_show = function(wrapper){ - // set from route - var bom = null; - if(frappe.get_route()[1]) { - var bom = frappe.get_route().splice(1).join("/"); - } - if(frappe.route_options && frappe.route_options.bom) { - var bom = frappe.route_options.bom; - } - if(bom) { - wrapper.page.$bom_select.val(bom).trigger("change"); - } -}; - -erpnext.BOMTree = Class.extend({ - init: function(root, page, parent) { - $(parent).empty(); - var me = this; - me.page = page; - me.bom = page.$bom_select.val(); - me.can_read = frappe.model.can_read("BOM"); - me.can_create = frappe.boot.user.can_create.indexOf("BOM") !== -1 || - frappe.boot.user.in_create.indexOf("BOM") !== -1; - me.can_write = frappe.model.can_write("BOM"); - me.can_delete = frappe.model.can_delete("BOM"); - this.tree = new frappe.ui.Tree({ - parent: $(parent), - label: me.bom, - args: {parent: me.bom}, - method: 'erpnext.manufacturing.page.bom_browser.bom_browser.get_children', - toolbar: [ - {toggle_btn: true}, - { - label:__("Edit"), - condition: function(node) { - return node.expandable; - }, - click: function(node) { - frappe.set_route("Form", "BOM", node.data.value); - } - } - ], - get_label: function(node) { - if(node.data.qty) { - return node.data.qty + " x " + node.data.item_code; - } else { - return node.data.item_code || node.data.value; - } - } - }); - } -}); diff --git a/erpnext/manufacturing/page/bom_browser/bom_browser.json b/erpnext/manufacturing/page/bom_browser/bom_browser.json deleted file mode 100644 index 5b75463457..0000000000 --- a/erpnext/manufacturing/page/bom_browser/bom_browser.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "content": null, - "creation": "2015-05-25 02:57:33.472044", - "docstatus": 0, - "doctype": "Page", - "modified": "2015-05-25 02:57:33.472044", - "modified_by": "Administrator", - "module": "Manufacturing", - "name": "bom-browser", - "owner": "Administrator", - "page_name": "bom-browser", - "roles": [ - { - "role": "Manufacturing User" - } - ], - "script": null, - "standard": "Yes", - "style": null, - "title": "BOM Browser" -} \ No newline at end of file diff --git a/erpnext/manufacturing/page/bom_browser/bom_browser.py b/erpnext/manufacturing/page/bom_browser/bom_browser.py deleted file mode 100644 index 3437ab4ae9..0000000000 --- a/erpnext/manufacturing/page/bom_browser/bom_browser.py +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -@frappe.whitelist() -def get_children(): - parent = frappe.local.form_dict.get('bom') - return frappe.db.sql("""select item_code, - bom_no as value, qty, - if(ifnull(bom_no, "")!="", 1, 0) as expandable - from `tabBOM Item` - where parent=%s - order by idx - """, parent, as_dict=True) diff --git a/erpnext/selling/page/sales_browser/README.md b/erpnext/selling/page/sales_browser/README.md deleted file mode 100644 index d6a20e10e7..0000000000 --- a/erpnext/selling/page/sales_browser/README.md +++ /dev/null @@ -1 +0,0 @@ -Tree editor for Territory, Customer Group, Item Group, Sales Partner \ No newline at end of file diff --git a/erpnext/selling/page/sales_browser/__init__.py b/erpnext/selling/page/sales_browser/__init__.py deleted file mode 100644 index baffc48825..0000000000 --- a/erpnext/selling/page/sales_browser/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/selling/page/sales_browser/sales_browser.json b/erpnext/selling/page/sales_browser/sales_browser.json deleted file mode 100644 index 54cac650c5..0000000000 --- a/erpnext/selling/page/sales_browser/sales_browser.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "creation": "2012-06-14 15:07:26.000000", - "docstatus": 0, - "doctype": "Page", - "icon": "icon-sitemap", - "idx": 1, - "modified": "2013-07-11 14:43:56.000000", - "modified_by": "Administrator", - "module": "Selling", - "name": "sales-browser", - "owner": "Administrator", - "page_name": "Sales Browser", - "roles": [ - { - "role": "Sales Master Manager" - }, - { - "role": "Material Master Manager" - }, - { - "role": "Accounts Manager" - }, - { - "role": "Sales Master Manager" - }, - { - "role": "Purchase Manager" - }, - { - "role": "Purchase Master Manager" - }, - { - "role": "Material Manager" - } - ], - "standard": "Yes" -} diff --git a/erpnext/selling/page/sales_browser/sales_browser.py b/erpnext/selling/page/sales_browser/sales_browser.py deleted file mode 100644 index 018ba3b081..0000000000 --- a/erpnext/selling/page/sales_browser/sales_browser.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - - -@frappe.whitelist() -def get_children(): - ctype = frappe.local.form_dict.get('ctype') - parent_field = 'parent_' + ctype.lower().replace(' ', '_') - parent = frappe.form_dict.get("parent") or "" - - return frappe.db.sql("""select name as value, - if(is_group='Yes', 1, 0) as expandable - from `tab{ctype}` - where docstatus < 2 - and ifnull(`{parent_field}`,'') = %s - order by name""".format(ctype=frappe.db.escape(ctype), parent_field=frappe.db.escape(parent_field)), - parent, as_dict=1) - -@frappe.whitelist() -def add_node(): - ctype = frappe.form_dict.get('ctype') - parent_field = 'parent_' + ctype.lower().replace(' ', '_') - name_field = ctype.lower().replace(' ', '_') + '_name' - - doc = frappe.new_doc(ctype) - doc.update({ - name_field: frappe.form_dict['name_field'], - parent_field: frappe.form_dict['parent'], - "is_group": frappe.form_dict['is_group'] - }) - if ctype == "Sales Person": - doc.employee = frappe.form_dict.get('employee') - - doc.save() diff --git a/erpnext/selling/page/sales_browser/tree.js b/erpnext/selling/page/sales_browser/tree.js deleted file mode 100644 index a99fe72872..0000000000 --- a/erpnext/selling/page/sales_browser/tree.js +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -// License: GNU General Public License v3. See license.txt - -frappe.pages["Sales Browser"].on_page_load = function(wrapper){ - var page = frappe.ui.make_app_page({ - parent: wrapper, - single_column: true, - }); - - wrapper.page.add_menu_item(__('Refresh'), function() { - wrapper.make_tree(); - }); - - wrapper.make_tree = function() { - var ctype = frappe.get_route()[1] || 'Territory'; - return frappe.call({ - method: 'erpnext.selling.page.sales_browser.sales_browser.get_children', - args: {ctype: ctype}, - callback: function(r) { - var root = r.message[0]["value"]; - erpnext.sales_chart = new erpnext.SalesChart(ctype, root, page, - page.main.css({ - "min-height": "300px", - "padding-bottom": "25px" - })); - } - }); - } - - wrapper.make_tree(); -} - -frappe.pages['Sales Browser'].on_page_show = function(wrapper){ - // set route - var ctype = frappe.get_route()[1] || 'Territory'; - - wrapper.page.set_title(__('{0} Tree',[__(ctype)])); - - if(erpnext.sales_chart && erpnext.sales_chart.ctype != ctype) { - wrapper.make_tree(); - } - - frappe.breadcrumbs.add(frappe.breadcrumbs.last_module || "Selling"); -}; - -erpnext.SalesChart = Class.extend({ - init: function(ctype, root, page, parent) { - $(parent).empty(); - var me = this; - me.ctype = ctype; - me.page = page; - me.can_read = frappe.model.can_read(this.ctype); - me.can_create = frappe.boot.user.can_create.indexOf(this.ctype) !== -1 || - frappe.boot.user.in_create.indexOf(this.ctype) !== -1; - me.can_write = frappe.model.can_write(this.ctype); - me.can_delete = frappe.model.can_delete(this.ctype); - - me.page.set_primary_action(__("New"), function() { - me.new_node(); - }, "octicon octicon-plus"); - - this.tree = new frappe.ui.Tree({ - parent: $(parent), - label: __(root), - args: {ctype: ctype}, - method: 'erpnext.selling.page.sales_browser.sales_browser.get_children', - toolbar: [ - {toggle_btn: true}, - { - label:__("Edit"), - condition: function(node) { - return !node.root && me.can_read; - }, - click: function(node) { - frappe.set_route("Form", me.ctype, node.label); - } - }, - { - label:__("Add Child"), - condition: function(node) { return me.can_create && node.expandable; }, - click: function(node) { - me.new_node(); - }, - btnClass: "hidden-xs" - }, - { - label:__("Rename"), - condition: function(node) { return !node.root && me.can_write; }, - click: function(node) { - frappe.model.rename_doc(me.ctype, node.label, function(new_name) { - node.$a.html(new_name); - }); - }, - btnClass: "hidden-xs" - }, - { - label:__("Delete"), - condition: function(node) { return !node.root && me.can_delete; }, - click: function(node) { - frappe.model.delete_doc(me.ctype, node.label, function() { - node.parent.remove(); - }); - }, - btnClass: "hidden-xs" - } - - ] - }); - }, - new_node: function() { - var me = this; - var node = me.tree.get_selected_node(); - - if(!(node && node.expandable)) { - frappe.msgprint(__("Select a group node first.")); - return; - } - - var fields = [ - {fieldtype:'Data', fieldname: 'name_field', - label:__('New {0} Name',[__(me.ctype)]), reqd:true}, - {fieldtype:'Select', fieldname:'is_group', label:__('Group Node'), options:'No\nYes', - description: __("Further nodes can be only created under 'Group' type nodes")} - ] - - if(me.ctype == "Sales Person") { - fields.splice(-1, 0, {fieldtype:'Link', fieldname:'employee', label:__('Employee'), - options:'Employee', description: __("Please enter Employee Id of this sales person")}); - } - - // the dialog - var d = new frappe.ui.Dialog({ - title: __('New {0}',[__(me.ctype)]), - fields: fields - }) - - d.set_value("is_group", "No"); - // create - d.set_primary_action(__("Create New"), function() { - var btn = this; - var v = d.get_values(); - if(!v) return; - - var node = me.tree.get_selected_node(); - - v.parent = node.label; - v.ctype = me.ctype; - - return frappe.call({ - method: 'erpnext.selling.page.sales_browser.sales_browser.add_node', - args: v, - callback: function(r) { - if(!r.exc) { - d.hide(); - if(node.expanded) { - node.toggle_node(); - } - node.reload(); - } - } - }); - }); - - d.show(); - }, -}); From ac53357f53f3dcf4f3957f9ae44a6b5e7037c2fd Mon Sep 17 00:00:00 2001 From: Saurabh Date: Tue, 21 Jun 2016 12:51:18 +0530 Subject: [PATCH 11/17] [fixes] renamed _treeview to _tree --- .../doctype/account/{account_treeview.js => account_tree.js} | 0 .../cost_center/{cost_center_treeview.js => cost_center_tree.js} | 0 .../manufacturing/doctype/bom/{bom_treeview.js => bom_tree.js} | 0 .../{sales_person_treeview.js => sales_person_tree.js} | 0 .../warehouse/{warehouse_treeview.js => warehouse_tree.js} | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename erpnext/accounts/doctype/account/{account_treeview.js => account_tree.js} (100%) rename erpnext/accounts/doctype/cost_center/{cost_center_treeview.js => cost_center_tree.js} (100%) rename erpnext/manufacturing/doctype/bom/{bom_treeview.js => bom_tree.js} (100%) rename erpnext/setup/doctype/sales_person/{sales_person_treeview.js => sales_person_tree.js} (100%) rename erpnext/stock/doctype/warehouse/{warehouse_treeview.js => warehouse_tree.js} (100%) diff --git a/erpnext/accounts/doctype/account/account_treeview.js b/erpnext/accounts/doctype/account/account_tree.js similarity index 100% rename from erpnext/accounts/doctype/account/account_treeview.js rename to erpnext/accounts/doctype/account/account_tree.js diff --git a/erpnext/accounts/doctype/cost_center/cost_center_treeview.js b/erpnext/accounts/doctype/cost_center/cost_center_tree.js similarity index 100% rename from erpnext/accounts/doctype/cost_center/cost_center_treeview.js rename to erpnext/accounts/doctype/cost_center/cost_center_tree.js diff --git a/erpnext/manufacturing/doctype/bom/bom_treeview.js b/erpnext/manufacturing/doctype/bom/bom_tree.js similarity index 100% rename from erpnext/manufacturing/doctype/bom/bom_treeview.js rename to erpnext/manufacturing/doctype/bom/bom_tree.js diff --git a/erpnext/setup/doctype/sales_person/sales_person_treeview.js b/erpnext/setup/doctype/sales_person/sales_person_tree.js similarity index 100% rename from erpnext/setup/doctype/sales_person/sales_person_treeview.js rename to erpnext/setup/doctype/sales_person/sales_person_tree.js diff --git a/erpnext/stock/doctype/warehouse/warehouse_treeview.js b/erpnext/stock/doctype/warehouse/warehouse_tree.js similarity index 100% rename from erpnext/stock/doctype/warehouse/warehouse_treeview.js rename to erpnext/stock/doctype/warehouse/warehouse_tree.js From 17022739687d07b8df5bac662bdd815f4f91aff5 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Tue, 21 Jun 2016 13:19:17 +0530 Subject: [PATCH 12/17] [fix] rename account browser and sales browser to tree/doctype for view --- erpnext/accounts/doctype/account/account.js | 2 +- .../accounts/doctype/cost_center/cost_center.js | 2 +- erpnext/config/accounts.py | 4 ++-- erpnext/config/buying.py | 4 ++-- erpnext/config/crm.py | 12 ++++++------ erpnext/config/selling.py | 16 ++++++++-------- erpnext/config/stock.py | 4 ++-- erpnext/public/js/conf.js | 12 ++++++------ erpnext/setup/doctype/company/company.js | 4 ++-- .../doctype/customer_group/customer_group.js | 2 +- erpnext/setup/doctype/item_group/item_group.js | 4 ++-- erpnext/startup/boot.py | 12 ++++++------ 12 files changed, 39 insertions(+), 39 deletions(-) diff --git a/erpnext/accounts/doctype/account/account.js b/erpnext/accounts/doctype/account/account.js index 703397e52a..078eff5504 100644 --- a/erpnext/accounts/doctype/account/account.js +++ b/erpnext/accounts/doctype/account/account.js @@ -48,7 +48,7 @@ cur_frm.cscript.account_type = function(doc, cdt, cdn) { cur_frm.cscript.add_toolbar_buttons = function(doc) { cur_frm.add_custom_button(__('Chart of Accounts'), - function() { frappe.set_route("Accounts Browser", "Account"); }, __("View")) + function() { frappe.set_route("Tree", "Account"); }, __("View")) if (doc.is_group == 1) { cur_frm.add_custom_button(__('Group to Non-Group'), diff --git a/erpnext/accounts/doctype/cost_center/cost_center.js b/erpnext/accounts/doctype/cost_center/cost_center.js index 85a605229a..6c456f8f2f 100644 --- a/erpnext/accounts/doctype/cost_center/cost_center.js +++ b/erpnext/accounts/doctype/cost_center/cost_center.js @@ -34,7 +34,7 @@ cur_frm.cscript.refresh = function(doc, cdt, cdn) { cur_frm.set_intro(intro_txt); cur_frm.add_custom_button(__('Chart of Cost Centers'), - function() { frappe.set_route("Accounts Browser", "Cost Center"); }, __("View")) + function() { frappe.set_route("Tree", "Cost Center"); }, __("View")) } cur_frm.cscript.parent_cost_center = function(doc, cdt, cdn) { diff --git a/erpnext/config/accounts.py b/erpnext/config/accounts.py index e11544abd1..b9f4def7d2 100644 --- a/erpnext/config/accounts.py +++ b/erpnext/config/accounts.py @@ -51,10 +51,10 @@ def get_data(): }, { "type": "page", - "name": "Accounts Browser", + "name": "Tree", "icon": "icon-sitemap", "label": _("Chart of Accounts"), - "route": "Accounts Browser/Account", + "route": "Tree/Account", "description": _("Tree of financial accounts."), "doctype": "Account", }, diff --git a/erpnext/config/buying.py b/erpnext/config/buying.py index 0dc51f6df0..b423ee925d 100644 --- a/erpnext/config/buying.py +++ b/erpnext/config/buying.py @@ -97,10 +97,10 @@ def get_data(): }, { "type": "page", - "name": "Sales Browser", + "name": "Tree", "icon": "icon-sitemap", "label": _("Item Group"), - "link": "Sales Browser/Item Group", + "link": "Tree/Item Group", "description": _("Tree of Item Groups."), "doctype": "Item Group", }, diff --git a/erpnext/config/crm.py b/erpnext/config/crm.py index dfefb75ed9..52958e39b7 100644 --- a/erpnext/config/crm.py +++ b/erpnext/config/crm.py @@ -92,27 +92,27 @@ def get_data(): { "type": "page", "label": _("Customer Group"), - "name": "Sales Browser", + "name": "Tree", "icon": "icon-sitemap", - "link": "Sales Browser/Customer Group", + "link": "Tree/Customer Group", "description": _("Manage Customer Group Tree."), "doctype": "Customer Group", }, { "type": "page", "label": _("Territory"), - "name": "Sales Browser", + "name": "Tree", "icon": "icon-sitemap", - "link": "Sales Browser/Territory", + "link": "Tree/Territory", "description": _("Manage Territory Tree."), "doctype": "Territory", }, { "type": "page", "label": _("Sales Person"), - "name": "Sales Browser", + "name": "Tree", "icon": "icon-sitemap", - "link": "Sales Browser/Sales Person", + "link": "Tree/Sales Person", "description": _("Manage Sales Person Tree."), "doctype": "Sales Person", }, diff --git a/erpnext/config/selling.py b/erpnext/config/selling.py index 771a0d7904..1a725e2ae9 100644 --- a/erpnext/config/selling.py +++ b/erpnext/config/selling.py @@ -30,9 +30,9 @@ def get_data(): { "type": "page", "label": _("Customer Group"), - "name": "Sales Browser", + "name": "Tree", "icon": "icon-sitemap", - "link": "Sales Browser/Customer Group", + "link": "Tree/Customer Group", "description": _("Manage Customer Group Tree."), "doctype": "Customer Group", }, @@ -69,10 +69,10 @@ def get_data(): }, { "type": "page", - "name": "Sales Browser", + "name": "Tree", "icon": "icon-sitemap", "label": _("Item Group"), - "link": "Sales Browser/Item Group", + "link": "Tree/Item Group", "description": _("Tree of Item Groups."), "doctype": "Item Group", }, @@ -101,9 +101,9 @@ def get_data(): { "type": "page", "label": _("Territory"), - "name": "Sales Browser", + "name": "Tree", "icon": "icon-sitemap", - "link": "Sales Browser/Territory", + "link": "Tree/Territory", "description": _("Manage Territory Tree."), "doctype": "Territory", }, @@ -115,9 +115,9 @@ def get_data(): { "type": "page", "label": _("Sales Person"), - "name": "Sales Browser", + "name": "Tree", "icon": "icon-sitemap", - "link": "Sales Browser/Sales Person", + "link": "Tree/Sales Person", "description": _("Manage Sales Person Tree."), "doctype": "Sales Person", }, diff --git a/erpnext/config/stock.py b/erpnext/config/stock.py index cf3a7baeb6..320d906a5b 100644 --- a/erpnext/config/stock.py +++ b/erpnext/config/stock.py @@ -78,10 +78,10 @@ def get_data(): }, { "type": "page", - "name": "Sales Browser", + "name": "Tree", "icon": "icon-sitemap", "label": _("Item Group"), - "link": "Sales Browser/Item Group", + "link": "Tree/Item Group", "description": _("Tree of Item Groups."), "doctype": "Item Group", }, diff --git a/erpnext/public/js/conf.js b/erpnext/public/js/conf.js index d8133ce4cb..233bd2e496 100644 --- a/erpnext/public/js/conf.js +++ b/erpnext/public/js/conf.js @@ -20,12 +20,12 @@ $(document).bind('toolbar_setup', function() { // doctypes created via tree $.extend(frappe.create_routes, { - "Customer Group": "Sales Browser/Customer Group", - "Territory": "Sales Browser/Territory", - "Item Group": "Sales Browser/Item Group", - "Sales Person": "Sales Browser/Sales Person", - "Account": "Accounts Browser/Account", - "Cost Center": "Accounts Browser/Cost Center" + "Customer Group": "Tree/Customer Group", + "Territory": "Tree/Territory", + "Item Group": "Tree/Item Group", + "Sales Person": "Tree/Sales Person", + "Account": "Tree/Account", + "Cost Center": "Tree/Cost Center" }); // preferred modules for breadcrumbs diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js index dfa6c0ac19..2a18286343 100644 --- a/erpnext/setup/doctype/company/company.js +++ b/erpnext/setup/doctype/company/company.js @@ -18,11 +18,11 @@ frappe.ui.form.on("Company", { !frm.doc.__onload.transactions_exist)); frm.add_custom_button(__('Cost Centers'), function() { - frappe.set_route('Accounts Browser', 'Cost Center', {'company': frm.doc.name}) + frappe.set_route('Tree', 'Cost Center', {'company': frm.doc.name}) }) frm.add_custom_button(__('Chart of Accounts'), function() { - frappe.set_route('Accounts Browser', 'Account', {'company': frm.doc.name}) + frappe.set_route('Tree', 'Account', {'company': frm.doc.name}) }) } diff --git a/erpnext/setup/doctype/customer_group/customer_group.js b/erpnext/setup/doctype/customer_group/customer_group.js index 7a5d2fa9dd..3dc5c6c607 100644 --- a/erpnext/setup/doctype/customer_group/customer_group.js +++ b/erpnext/setup/doctype/customer_group/customer_group.js @@ -1,7 +1,7 @@ // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors // License: GNU General Public License v3. See license.txt -cur_frm.list_route = "Sales Browser/Customer Group"; +cur_frm.list_route = "Tree/Customer Group"; cur_frm.cscript.refresh = function(doc, cdt, cdn) { cur_frm.cscript.set_root_readonly(doc); diff --git a/erpnext/setup/doctype/item_group/item_group.js b/erpnext/setup/doctype/item_group/item_group.js index d440c26a41..d6adebce97 100644 --- a/erpnext/setup/doctype/item_group/item_group.js +++ b/erpnext/setup/doctype/item_group/item_group.js @@ -3,7 +3,7 @@ frappe.ui.form.on("Item Group", { onload: function(frm) { - frm.list_route = "Sales Browser/Item Group"; + frm.list_route = "Tree/Item Group"; //get query select item group frm.fields_dict['parent_item_group'].get_query = function(doc,cdt,cdn) { @@ -19,7 +19,7 @@ frappe.ui.form.on("Item Group", { refresh: function(frm) { frm.trigger("set_root_readonly"); frm.add_custom_button(__("Item Group Tree"), function() { - frappe.set_route("Sales Browser", "Item Group"); + frappe.set_route("Tree", "Item Group"); }, "icon-sitemap"); }, diff --git a/erpnext/startup/boot.py b/erpnext/startup/boot.py index 7bdcb0aa9c..97ef3299a3 100644 --- a/erpnext/startup/boot.py +++ b/erpnext/startup/boot.py @@ -52,26 +52,26 @@ def update_page_info(bootinfo): bootinfo.page_info.update({ "Chart of Accounts": { "title": "Chart of Accounts", - "route": "Accounts Browser/Account" + "route": "Tree/Account" }, "Chart of Cost Centers": { "title": "Chart of Cost Centers", - "route": "Accounts Browser/Cost Center" + "route": "Tree/Cost Center" }, "Item Group Tree": { "title": "Item Group Tree", - "route": "Sales Browser/Item Group" + "route": "Tree/Item Group" }, "Customer Group Tree": { "title": "Customer Group Tree", - "route": "Sales Browser/Customer Group" + "route": "Tree/Customer Group" }, "Territory Tree": { "title": "Territory Tree", - "route": "Sales Browser/Territory" + "route": "Tree/Territory" }, "Sales Person Tree": { "title": "Sales Person Tree", - "route": "Sales Browser/Sales Person" + "route": "Tree/Sales Person" } }) From ec8babe7ac7e4383135af2698300f8771f3beac3 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Tue, 21 Jun 2016 15:55:54 +0530 Subject: [PATCH 13/17] [minor][fix] --- erpnext/accounts/doctype/account/account.js | 2 +- erpnext/accounts/doctype/cost_center/cost_center.js | 2 +- erpnext/accounts/doctype/payment_tool/payment_tool.py | 2 +- erpnext/config/accounts.py | 4 ++-- erpnext/controllers/accounts_controller.py | 3 ++- erpnext/manufacturing/doctype/bom/bom.js | 2 +- erpnext/setup/doctype/sales_person/sales_person.js | 2 +- erpnext/setup/doctype/territory/territory.js | 2 +- 8 files changed, 10 insertions(+), 9 deletions(-) diff --git a/erpnext/accounts/doctype/account/account.js b/erpnext/accounts/doctype/account/account.js index 078eff5504..44c2ca45fb 100644 --- a/erpnext/accounts/doctype/account/account.js +++ b/erpnext/accounts/doctype/account/account.js @@ -1,7 +1,7 @@ // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors // License: GNU General Public License v3. See license.txt -cur_frm.list_route = "Accounts Browser/Account"; +cur_frm.list_route = "Tree/Account"; cur_frm.cscript.refresh = function(doc, cdt, cdn) { if(doc.__islocal) { diff --git a/erpnext/accounts/doctype/cost_center/cost_center.js b/erpnext/accounts/doctype/cost_center/cost_center.js index 6c456f8f2f..a5419016e6 100644 --- a/erpnext/accounts/doctype/cost_center/cost_center.js +++ b/erpnext/accounts/doctype/cost_center/cost_center.js @@ -3,7 +3,7 @@ frappe.provide("erpnext.accounts"); -cur_frm.list_route = "Accounts Browser/Cost Center"; +cur_frm.list_route = "Tree/Cost Center"; frappe.ui.form.on('Cost Center', { diff --git a/erpnext/accounts/doctype/payment_tool/payment_tool.py b/erpnext/accounts/doctype/payment_tool/payment_tool.py index 5c5b393963..7f95ade877 100644 --- a/erpnext/accounts/doctype/payment_tool/payment_tool.py +++ b/erpnext/accounts/doctype/payment_tool/payment_tool.py @@ -7,7 +7,7 @@ from frappe import _, scrub from frappe.utils import flt from frappe.model.document import Document import json -from erpnext.accounts.utils import get_account_currency +from erpnext.accounts.doctype.account.account import get_account_currency from erpnext.accounts.doctype.journal_entry.journal_entry import get_exchange_rate class PaymentTool(Document): diff --git a/erpnext/config/accounts.py b/erpnext/config/accounts.py index b9f4def7d2..b6b14803ef 100644 --- a/erpnext/config/accounts.py +++ b/erpnext/config/accounts.py @@ -193,10 +193,10 @@ def get_data(): "items": [ { "type": "page", - "name": "Accounts Browser", + "name": "Tree", "icon": "icon-sitemap", "label": _("Chart of Cost Centers"), - "route": "Accounts Browser/Cost Center", + "route": "Tree/Cost Center", "description": _("Tree of financial Cost Centers."), "doctype": "Cost Center", }, diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index e3a66a4b11..ac58e9c4b1 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -6,7 +6,8 @@ import frappe from frappe import _, throw from frappe.utils import today, flt, cint, fmt_money, formatdate, getdate from erpnext.setup.utils import get_company_currency, get_exchange_rate -from erpnext.accounts.utils import get_fiscal_years, validate_fiscal_year, get_account_currency +from erpnext.accounts.utils import get_fiscal_years, validate_fiscal_year +from erpnext.accounts.doctype.account.account import get_account_currency from erpnext.utilities.transaction_base import TransactionBase from erpnext.controllers.recurring_document import convert_to_recurring, validate_recurring_document from erpnext.controllers.sales_and_purchase_return import validate_return diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js index 6f45ff2ed7..de8ac946c9 100644 --- a/erpnext/manufacturing/doctype/bom/bom.js +++ b/erpnext/manufacturing/doctype/bom/bom.js @@ -24,7 +24,7 @@ frappe.ui.form.on("BOM", { frm.events.update_cost(frm); }); frm.add_custom_button(__("Browse BOM"), function() { - frappe.set_route("bom-browser", frm.doc.name); + frappe.set_route("Tree", "BOM"); }); } diff --git a/erpnext/setup/doctype/sales_person/sales_person.js b/erpnext/setup/doctype/sales_person/sales_person.js index 8bae546a1c..1368392489 100644 --- a/erpnext/setup/doctype/sales_person/sales_person.js +++ b/erpnext/setup/doctype/sales_person/sales_person.js @@ -1,7 +1,7 @@ // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors // License: GNU General Public License v3. See license.txt -cur_frm.list_route = "Sales Browser/Sales Person"; +cur_frm.list_route = "Tree/Sales Person"; cur_frm.cscript.refresh = function(doc, cdt, cdn) { cur_frm.cscript.set_root_readonly(doc); diff --git a/erpnext/setup/doctype/territory/territory.js b/erpnext/setup/doctype/territory/territory.js index cde04b33aa..bf4e29b105 100644 --- a/erpnext/setup/doctype/territory/territory.js +++ b/erpnext/setup/doctype/territory/territory.js @@ -1,7 +1,7 @@ // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors // License: GNU General Public License v3. See license.txt -cur_frm.list_route = "Sales Browser/Territory"; +cur_frm.list_route = "Tree/Territory"; cur_frm.cscript.refresh = function(doc, cdt, cdn) { cur_frm.cscript.set_root_readonly(doc); From 4d029498148b5207496569ab9b6879e817e5bf56 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Thu, 23 Jun 2016 12:44:06 +0530 Subject: [PATCH 14/17] [fixes] validate trash condition for warehouse and related account, move existing warehouses under all warehouse group, set account parent and is group for warehouse account --- erpnext/accounts/doctype/account/account.py | 7 ++- .../accounts/doctype/account/account_tree.js | 2 +- .../doctype/cost_center/cost_center_tree.js | 2 +- .../doctype/payment_tool/payment_tool.py | 2 +- erpnext/accounts/utils.py | 7 +-- erpnext/controllers/accounts_controller.py | 3 +- erpnext/controllers/stock_controller.py | 3 +- erpnext/patches/v7_0/group_warehouses.py | 45 +++++++++++++++++++ erpnext/setup/doctype/company/company.py | 4 +- erpnext/stock/doctype/bin/bin.py | 10 ++--- .../stock_ledger_entry/stock_ledger_entry.py | 10 ++--- erpnext/stock/doctype/warehouse/warehouse.py | 17 +++++-- .../stock/doctype/warehouse/warehouse_tree.js | 2 +- .../report/stock_balance/stock_balance.py | 10 ++--- .../stock/report/stock_ledger/stock_ledger.py | 10 +++-- .../stock_projected_qty.py | 9 ++-- erpnext/stock/utils.py | 13 +++--- 17 files changed, 106 insertions(+), 50 deletions(-) create mode 100644 erpnext/patches/v7_0/group_warehouses.py diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py index 718ba31169..f5000f44ae 100644 --- a/erpnext/accounts/doctype/account/account.py +++ b/erpnext/accounts/doctype/account/account.py @@ -179,9 +179,12 @@ class Account(Document): self.warehouse = None def validate_warehouse(self, warehouse): - if frappe.db.get_value("Stock Ledger Entry", {"warehouse": warehouse}): + lft, rgt = frappe.db.get_value("Warehouse", warehouse, ["lft", "rgt"]) + + if frappe.db.sql_list("""select sle.name from `tabStock Ledger Entry` sle where exists (select wh.name from + tabWarehouse wh where lft >= %s and rgt <= %s and sle.warehouse = wh.warehouse)""", (lft, rgt)): throw(_("Stock entries exist against warehouse {0}, hence you cannot re-assign or modify Warehouse").format(warehouse)) - + def update_nsm_model(self): """update lft, rgt indices for nested set model""" import frappe diff --git a/erpnext/accounts/doctype/account/account_tree.js b/erpnext/accounts/doctype/account/account_tree.js index 3ee1c42fcb..3252788fa1 100644 --- a/erpnext/accounts/doctype/account/account_tree.js +++ b/erpnext/accounts/doctype/account/account_tree.js @@ -3,7 +3,7 @@ frappe.treeview_settings["Account"] = { title: __("Chart Of Accounts"), get_tree_root: false, filters: [{ - fieldname: "comp", + fieldname: "company", fieldtype:"Select", options: $.map(locals[':Company'], function(c) { return c.name; }).sort(), label: __("Company"), diff --git a/erpnext/accounts/doctype/cost_center/cost_center_tree.js b/erpnext/accounts/doctype/cost_center/cost_center_tree.js index 3ca5232e3f..ac82f23cb4 100644 --- a/erpnext/accounts/doctype/cost_center/cost_center_tree.js +++ b/erpnext/accounts/doctype/cost_center/cost_center_tree.js @@ -2,7 +2,7 @@ frappe.treeview_settings["Cost Center"] = { breadcrumbs: "Accounts", get_tree_root: false, filters: [{ - fieldname: "comp", + fieldname: "company", fieldtype:"Select", options: $.map(locals[':Company'], function(c) { return c.name; }).sort(), label: __("Company"), diff --git a/erpnext/accounts/doctype/payment_tool/payment_tool.py b/erpnext/accounts/doctype/payment_tool/payment_tool.py index 7f95ade877..5c5b393963 100644 --- a/erpnext/accounts/doctype/payment_tool/payment_tool.py +++ b/erpnext/accounts/doctype/payment_tool/payment_tool.py @@ -7,7 +7,7 @@ from frappe import _, scrub from frappe.utils import flt from frappe.model.document import Document import json -from erpnext.accounts.doctype.account.account import get_account_currency +from erpnext.accounts.utils import get_account_currency from erpnext.accounts.doctype.journal_entry.journal_entry import get_exchange_rate class PaymentTool(Document): diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 78e07619b6..5cccf1bf48 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -9,6 +9,7 @@ from frappe import throw, _ from frappe.utils import formatdate # imported to enable erpnext.accounts.utils.get_account_currency +from erpnext.accounts.doctype.account.account import get_account_currency import frappe.defaults from erpnext.accounts.report.financial_statements import sort_root_accounts @@ -128,7 +129,7 @@ def add_ac(args=None): if not args: args = frappe.local.form_dict args.pop("cmd") - + ac = frappe.new_doc("Account") if args.get("ignore_permissions"): @@ -139,7 +140,7 @@ def add_ac(args=None): if not ac.parent_account: ac.parent_account = args.get("parent") - + ac.old_parent = "" ac.freeze_account = "No" if cint(ac.get("is_root")): @@ -447,7 +448,7 @@ def get_companies(): @frappe.whitelist() def get_children(): args = frappe.local.form_dict - ctype, company = args['ctype'], args['comp'] + ctype, company = args['ctype'], args['company'] fieldname = frappe.db.escape(ctype.lower().replace(' ','_')) doctype = frappe.db.escape(ctype) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index ac58e9c4b1..e3a66a4b11 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -6,8 +6,7 @@ import frappe from frappe import _, throw from frappe.utils import today, flt, cint, fmt_money, formatdate, getdate from erpnext.setup.utils import get_company_currency, get_exchange_rate -from erpnext.accounts.utils import get_fiscal_years, validate_fiscal_year -from erpnext.accounts.doctype.account.account import get_account_currency +from erpnext.accounts.utils import get_fiscal_years, validate_fiscal_year, get_account_currency from erpnext.utilities.transaction_base import TransactionBase from erpnext.controllers.recurring_document import convert_to_recurring, validate_recurring_document from erpnext.controllers.sales_and_purchase_return import validate_return diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index 1976cc6c56..1e685e5ca1 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -321,6 +321,7 @@ def get_warehouse_account(): warehouse_account = frappe._dict() for d in frappe.db.sql("""select warehouse, name, account_currency from tabAccount - where account_type = 'Warehouse' and (warehouse is not null and warehouse != '')""", as_dict=1): + where account_type = 'Warehouse' and (warehouse is not null and warehouse != '' + and is_group != 1)""", as_dict=1): warehouse_account.setdefault(d.warehouse, d) return warehouse_account diff --git a/erpnext/patches/v7_0/group_warehouses.py b/erpnext/patches/v7_0/group_warehouses.py new file mode 100644 index 0000000000..8987d58561 --- /dev/null +++ b/erpnext/patches/v7_0/group_warehouses.py @@ -0,0 +1,45 @@ +import frappe +from frappe import _ + +def execute(): + frappe.reload_doc("stock", "doctype", "warehouse") + for company in frappe.get_all("Company", fields=["name", "abbr"]): + if not frappe.db.get_value("Warehouse", "{0} - {1}".format(_("All Warehouses"), company.abbr)): + create_default_warehouse_group(company) + + for warehouse in frappe.get_all("Warehouse", {"company": company}, ["name", "create_account_under", "parent_warehouse"]): + set_parent_to_warehouses(warehouse, company) + set_parent_to_warehouse_acounts(warehouse, company) + +def set_parent_to_warehouses(warehouse, company): + warehouse = frappe.get_doc("Warehouse", warehouse.name) + warehouse.is_group = "No" + + if not warehouse.parent_warehouse: + warehouse.parent_warehouse = "{0} - {1}".format(_("All Warehouses"), company.abbr) + + warehouse.save() + +def set_parent_to_warehouse_acounts(warehouse, company): + account = frappe.db.get_value("Account", {"warehouse": warehouse.name}) + stock_group = frappe.db.get_value("Account", {"account_type": "Stock", + "is_group": 1, "company": company.name}) + + if account: + account = frappe.get_doc("Account", account) + + if warehouse.create_account_under == stock_group or not warehouse.create_account_under: + if not warehouse.parent_warehouse: + account.parent_account = "{0} - {1}".format(_("All Warehouses"), company.abbr) + else: + account.parent_account = frappe.db.get_value("Account", {"warehouse": warehouse.parent_warehouse}) + account.save(ignore_permissions=True) + +def create_default_warehouse_group(company): + frappe.get_doc({ + "doctype": "Warehouse", + "warehouse_name": _("All Warehouses"), + "is_group": "Yes", + "company": company.name, + "parent_warehouse": "" + }).insert(ignore_permissions=True) \ No newline at end of file diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index c45c2411df..7d8829731d 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -88,6 +88,7 @@ class Company(Document): def create_default_warehouses(self): for wh_detail in [ + {"warehouse_name": _("All Warehouses"), "is_group": "Yes"}, {"warehouse_name": _("Stores"), "is_group": "No"}, {"warehouse_name": _("Work In Progress"), "is_group": "No"}, {"warehouse_name": _("Finished Goods"), "is_group": "No"}]: @@ -101,7 +102,8 @@ class Company(Document): "warehouse_name": wh_detail["warehouse_name"], "is_group": wh_detail["is_group"], "company": self.name, - "parent_warehouse": "", + "parent_warehouse": "{0} - {1}".format(_("All Warehouses"), self.abbr) \ + if wh_detail["is_group"] == "No" else "", "create_account_under": stock_group }) warehouse.flags.ignore_permissions = True diff --git a/erpnext/stock/doctype/bin/bin.py b/erpnext/stock/doctype/bin/bin.py index c03ceee69c..2378e3f3e6 100644 --- a/erpnext/stock/doctype/bin/bin.py +++ b/erpnext/stock/doctype/bin/bin.py @@ -18,7 +18,7 @@ class Bin(Document): self.projected_qty = flt(self.actual_qty) + flt(self.ordered_qty) + \ flt(self.indented_qty) + flt(self.planned_qty) - flt(self.reserved_qty) - self.validate_leaf_warehouse() + self.block_transactions_against_group_warehouse() def validate_mandatory(self): qf = ['actual_qty', 'reserved_qty', 'ordered_qty', 'indented_qty'] @@ -26,11 +26,9 @@ class Bin(Document): if (not getattr(self, f, None)) or (not self.get(f)): self.set(f, 0.0) - def validate_leaf_warehouse(self): - from erpnext.stock.utils import is_leaf_warehouse - - if not is_leaf_warehouse(self.warehouse): - frappe.throw(_("Group node warehouse is not allowed to select for transactions")) + def block_transactions_against_group_warehouse(self): + from erpnext.stock.utils import is_group_warehouse + is_group_warehouse(self.warehouse) def update_stock(self, args, allow_negative_stock=False, via_landed_cost_voucher=False): self.update_qty(args) diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py index 1f446d2be0..2caabee7b4 100644 --- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py @@ -25,7 +25,7 @@ class StockLedgerEntry(Document): validate_warehouse_company(self.warehouse, self.company) self.scrub_posting_time() self.validate_and_set_fiscal_year() - self.validate_leaf_warehouse() + self.block_transactions_against_group_warehouse() from erpnext.accounts.utils import validate_fiscal_year validate_fiscal_year(self.posting_date, self.fiscal_year, self.meta.get_label("posting_date"), self) @@ -118,11 +118,9 @@ class StockLedgerEntry(Document): if not self.fiscal_year: self.fiscal_year = get_fiscal_year(self.posting_date, company=self.company)[0] - def validate_leaf_warehouse(self): - from erpnext.stock.utils import is_leaf_warehouse - - if not is_leaf_warehouse(self.warehouse): - frappe.throw(_("Group node warehouse is not allowed to select for transactions")) + def block_transactions_against_group_warehouse(self): + from erpnext.stock.utils import is_group_warehouse + is_group_warehouse(self.warehouse) def on_doctype_update(): if not frappe.db.sql("""show index from `tabStock Ledger Entry` diff --git a/erpnext/stock/doctype/warehouse/warehouse.py b/erpnext/stock/doctype/warehouse/warehouse.py index a0b7296056..58f7f603ef 100644 --- a/erpnext/stock/doctype/warehouse/warehouse.py +++ b/erpnext/stock/doctype/warehouse/warehouse.py @@ -57,8 +57,9 @@ class Warehouse(NestedSet): ac_doc = frappe.get_doc({ "doctype": "Account", 'account_name': self.warehouse_name, - 'parent_account': self.create_account_under, - 'is_group':0, + 'parent_account': self.parent_warehouse if self.parent_warehouse \ + else self.create_account_under, + 'is_group': 1 if self.is_group=="Yes" else 0 , 'company':self.company, "account_type": "Warehouse", "warehouse": self.name, @@ -77,6 +78,7 @@ class Warehouse(NestedSet): {"account_name": "Stock Assets", "company": self.company}) if parent_account: + frappe.db.set_value("Warehouse", self.name, "create_account_under", parent_account) self.create_account_under = parent_account else: frappe.throw(_("Please enter parent account group for warehouse {0}").format(self.name)) @@ -105,6 +107,11 @@ class Warehouse(NestedSet): if frappe.db.sql("""select name from `tabStock Ledger Entry` where warehouse = %s""", self.name): throw(_("Warehouse can not be deleted as stock ledger entry exists for this warehouse.")) + + if frappe.db.sql("""select name from `tabWarehouse` where parent_warehouse = %s""", self.name): + throw(_("Child warehouse exists for this warehouse. You can not delete this warehouse.")) + + self.update_nsm_model() def before_rename(self, olddn, newdn, merge=False): # Add company abbr if not provided @@ -170,7 +177,7 @@ class Warehouse(NestedSet): def get_children(): from erpnext.stock.utils import get_stock_value_on ctype = frappe.local.form_dict.get('ctype') - company = frappe.local.form_dict.get('comp') + company = frappe.local.form_dict.get('company') parent_field = 'parent_' + ctype.lower().replace(' ', '_') parent = frappe.form_dict.get("parent") or "" @@ -194,6 +201,7 @@ def get_children(): @frappe.whitelist() def add_node(): ctype = frappe.form_dict.get('ctype') + company = frappe.form_dict.get('company') parent_field = 'parent_' + ctype.lower().replace(' ', '_') name_field = ctype.lower().replace(' ', '_') + '_name' @@ -207,7 +215,8 @@ def add_node(): doc.update({ name_field: frappe.form_dict['name_field'], parent_field: parent, - "is_group": frappe.form_dict['is_group'] + "is_group": frappe.form_dict['is_group'], + "company": company }) doc.save() diff --git a/erpnext/stock/doctype/warehouse/warehouse_tree.js b/erpnext/stock/doctype/warehouse/warehouse_tree.js index d23a5362db..03614931a5 100644 --- a/erpnext/stock/doctype/warehouse/warehouse_tree.js +++ b/erpnext/stock/doctype/warehouse/warehouse_tree.js @@ -4,7 +4,7 @@ frappe.treeview_settings['Warehouse'] = { get_tree_root: false, root_label: "Warehouses", filters: [{ - fieldname: "comp", + fieldname: "company", fieldtype:"Select", options: $.map(locals[':Company'], function(c) { return c.name; }).sort(), label: __("Company"), diff --git a/erpnext/stock/report/stock_balance/stock_balance.py b/erpnext/stock/report/stock_balance/stock_balance.py index 75200b340d..696f2b0059 100644 --- a/erpnext/stock/report/stock_balance/stock_balance.py +++ b/erpnext/stock/report/stock_balance/stock_balance.py @@ -71,9 +71,9 @@ def get_conditions(filters): conditions += " and item_code = '%s'" % frappe.db.escape(filters.get("item_code"), percent=False) if filters.get("warehouse"): - wh = frappe.get_doc("Warehouse", filters.get("warehouse")) - conditions += "and warehouse in (\ - select name from `tabWarehouse` wh where wh.lft >= %s and wh.rgt <= %s)"%(wh.lft, wh.rgt) + lft, rgt = frappe.db.get_value("Warehouse", filters.get("warehouse"), ["lft", "rgt"]) + conditions += " and exists (select name from `tabWarehouse` wh \ + where wh.lft >= %s and wh.rgt <= %s and sle.warehouse = wh.name)"%(lft, rgt) return conditions @@ -81,9 +81,9 @@ def get_stock_ledger_entries(filters): conditions = get_conditions(filters) return frappe.db.sql("""select item_code, warehouse, posting_date, actual_qty, valuation_rate, company, voucher_type, qty_after_transaction, stock_value_difference - from `tabStock Ledger Entry` force index (posting_sort_index) + from `tabStock Ledger Entry` sle force index (posting_sort_index) where docstatus < 2 %s order by posting_date, posting_time, name""" % - conditions, as_dict=1) + conditions, as_dict=1, debug=1) def get_item_warehouse_map(filters): iwb_map = {} diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py index a65be6d8e7..b2e46701da 100644 --- a/erpnext/stock/report/stock_ledger/stock_ledger.py +++ b/erpnext/stock/report/stock_ledger/stock_ledger.py @@ -41,7 +41,7 @@ def get_stock_ledger_entries(filters): return frappe.db.sql("""select concat_ws(" ", posting_date, posting_time) as date, item_code, warehouse, actual_qty, qty_after_transaction, incoming_rate, valuation_rate, stock_value, voucher_type, voucher_no, batch_no, serial_no, company - from `tabStock Ledger Entry` + from `tabStock Ledger Entry` sle where company = %(company)s and posting_date between %(from_date)s and %(to_date)s {sle_conditions} @@ -99,6 +99,8 @@ def get_opening_balance(filters, columns): return row def get_warehouse_condition(warehouse): - wh = frappe.get_doc("Warehouse", warehouse) - return " warehouse in (select name from `tabWarehouse` wh\ - where wh.lft >= %s and wh.rgt <= %s)"%(wh.lft, wh.rgt) \ No newline at end of file + lft, rgt = frappe.db.get_value("Warehouse", warehouse, ["lft", "rgt"]) + + return " exists (select name from `tabWarehouse` wh \ + where wh.lft >= %s and wh.rgt <= %s and sle.warehouse = wh.name)"%(lft, rgt) + \ No newline at end of file diff --git a/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py b/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py index 2fb120a180..409833a939 100644 --- a/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py +++ b/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py @@ -63,9 +63,10 @@ def get_bin_list(filters): conditions.append("item_code = '%s' "%filters.item_code) if filters.warehouse: - wh = frappe.get_doc("Warehouse", filters.warehouse) - conditions.append(" warehouse in (select name from `tabWarehouse` wh\ - where wh.lft >= %s and wh.rgt <= %s)"%(wh.lft, wh.rgt)) + lft, rgt = frappe.db.get_value("Warehouse", filters.warehouse, ["lft", "rgt"]) + + conditions.append(" exists (select name from `tabWarehouse` wh \ + where wh.lft >= %s and wh.rgt <= %s and sle.warehouse = wh.name)"%(lft, rgt)) bin_list = frappe.db.sql("""select item_code, warehouse, actual_qty, planned_qty, indented_qty, ordered_qty, reserved_qty, reserved_qty_for_production, projected_qty @@ -104,6 +105,4 @@ def get_item_map(item_code): item["reorder_levels"] = reorder_levels.get(item.name) or [] item_map[item.name] = item - - frappe.errprint(item_map) return item_map diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py index 6e56c5c7e7..51d82a6dcc 100644 --- a/erpnext/stock/utils.py +++ b/erpnext/stock/utils.py @@ -16,10 +16,10 @@ def get_stock_value_on(warehouse=None, posting_date=None, item_code=None): if warehouse: - wh = frappe.get_doc("Warehouse", warehouse) + lft, rgt, is_group = frappe.db.get_value("Warehouse", warehouse, ["lft", "rgt", "is_group"]) - if wh.is_group == "Yes": - values.extend([wh.lft, wh.rgt]) + if is_group == "Yes": + values.extend([lft, rgt]) condition += "and exists (\ select name from `tabWarehouse` wh where wh.name = sle.warehouse\ and wh.lft >= %s and wh.rgt <= %s)" @@ -188,8 +188,7 @@ def validate_warehouse_company(warehouse, company): frappe.throw(_("Warehouse {0} does not belong to company {1}").format(warehouse, company), InvalidWarehouseCompany) -def is_leaf_warehouse(warehouse): - if frappe.db.get_value("Warehouse", warehouse, "is_group") == "No": - return True - return False +def is_group_warehouse(warehouse): + if frappe.db.get_value("Warehouse", warehouse, "is_group") == "Yes": + frappe.throw(_("Group node warehouse is not allowed to select for transactions")) \ No newline at end of file From 3a0f96bd009dfdf66809e00ec4fc1aba73f2e71a Mon Sep 17 00:00:00 2001 From: Saurabh Date: Thu, 23 Jun 2016 12:50:09 +0530 Subject: [PATCH 15/17] [patch] patch to move all warehouses under all warehouse group --- erpnext/accounts/doctype/account/account.py | 2 +- .../v7_0/create_warehouse_nestedset.py | 55 +++++++++++++++++-- erpnext/patches/v7_0/group_warehouses.py | 45 --------------- 3 files changed, 50 insertions(+), 52 deletions(-) delete mode 100644 erpnext/patches/v7_0/group_warehouses.py diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py index f5000f44ae..918917c56a 100644 --- a/erpnext/accounts/doctype/account/account.py +++ b/erpnext/accounts/doctype/account/account.py @@ -182,7 +182,7 @@ class Account(Document): lft, rgt = frappe.db.get_value("Warehouse", warehouse, ["lft", "rgt"]) if frappe.db.sql_list("""select sle.name from `tabStock Ledger Entry` sle where exists (select wh.name from - tabWarehouse wh where lft >= %s and rgt <= %s and sle.warehouse = wh.warehouse)""", (lft, rgt)): + tabWarehouse wh where lft >= %s and rgt <= %s and sle.warehouse = wh.name)""", (lft, rgt)): throw(_("Stock entries exist against warehouse {0}, hence you cannot re-assign or modify Warehouse").format(warehouse)) def update_nsm_model(self): diff --git a/erpnext/patches/v7_0/create_warehouse_nestedset.py b/erpnext/patches/v7_0/create_warehouse_nestedset.py index 78cc3999a2..c313f31456 100644 --- a/erpnext/patches/v7_0/create_warehouse_nestedset.py +++ b/erpnext/patches/v7_0/create_warehouse_nestedset.py @@ -2,9 +2,52 @@ import frappe from frappe import _ def execute(): - for warehouse in frappe.db.sql_list("""select name from tabWarehouse - order by company asc, name asc"""): - warehouse = frappe.get_doc("Warehouse", warehouse) - warehouse.is_group = "No" - warehouse.parent_warehouse = "" - warehouse.save(ignore_permissions=True) \ No newline at end of file + frappe.reload_doc("stock", "doctype", "warehouse") + + for company in frappe.get_all("Company", fields=["name", "abbr"]): + if not frappe.db.get_value("Warehouse", "{0} - {1}".format(_("All Warehouses"), company.abbr)): + create_default_warehouse_group(company) + + for warehouse in frappe.get_all("Warehouse", filters={"company": company.name}, fields=["name", "create_account_under", + "parent_warehouse", "is_group"]): + set_parent_to_warehouses(warehouse, company) + set_parent_to_warehouse_acounts(warehouse, company) + frappe.db.commit() + +def set_parent_to_warehouses(warehouse, company): + warehouse = frappe.get_doc("Warehouse", warehouse.name) + warehouse.is_group = "Yes" if warehouse.is_group == "Yes" else "No" + + if not warehouse.parent_warehouse and warehouse.name != "{0} - {1}".format(_("All Warehouses"), company.abbr): + warehouse.parent_warehouse = "{0} - {1}".format(_("All Warehouses"), company.abbr) + + warehouse.save(ignore_permissions=True) + +def set_parent_to_warehouse_acounts(warehouse, company): + account = frappe.db.get_value("Account", {"warehouse": warehouse.name}) + stock_group = frappe.db.get_value("Account", {"account_type": "Stock", + "is_group": 1, "company": company.name}) + + if account and account != "{0} - {1}".format(_("All Warehouses"), company.abbr): + account = frappe.get_doc("Account", account) + + if warehouse.is_group == "Yes": + account.is_group = 1 + account.account_type = "" + + if warehouse.create_account_under == stock_group or not warehouse.create_account_under: + if not warehouse.parent_warehouse: + account.parent_account = "{0} - {1}".format(_("All Warehouses"), company.abbr) + else: + account.parent_account = frappe.db.get_value("Account", warehouse.parent_warehouse) + + account.save(ignore_permissions=True) + +def create_default_warehouse_group(company): + frappe.get_doc({ + "doctype": "Warehouse", + "warehouse_name": _("All Warehouses"), + "is_group": "Yes", + "company": company.name, + "parent_warehouse": "" + }).insert(ignore_permissions=True) \ No newline at end of file diff --git a/erpnext/patches/v7_0/group_warehouses.py b/erpnext/patches/v7_0/group_warehouses.py deleted file mode 100644 index 8987d58561..0000000000 --- a/erpnext/patches/v7_0/group_warehouses.py +++ /dev/null @@ -1,45 +0,0 @@ -import frappe -from frappe import _ - -def execute(): - frappe.reload_doc("stock", "doctype", "warehouse") - for company in frappe.get_all("Company", fields=["name", "abbr"]): - if not frappe.db.get_value("Warehouse", "{0} - {1}".format(_("All Warehouses"), company.abbr)): - create_default_warehouse_group(company) - - for warehouse in frappe.get_all("Warehouse", {"company": company}, ["name", "create_account_under", "parent_warehouse"]): - set_parent_to_warehouses(warehouse, company) - set_parent_to_warehouse_acounts(warehouse, company) - -def set_parent_to_warehouses(warehouse, company): - warehouse = frappe.get_doc("Warehouse", warehouse.name) - warehouse.is_group = "No" - - if not warehouse.parent_warehouse: - warehouse.parent_warehouse = "{0} - {1}".format(_("All Warehouses"), company.abbr) - - warehouse.save() - -def set_parent_to_warehouse_acounts(warehouse, company): - account = frappe.db.get_value("Account", {"warehouse": warehouse.name}) - stock_group = frappe.db.get_value("Account", {"account_type": "Stock", - "is_group": 1, "company": company.name}) - - if account: - account = frappe.get_doc("Account", account) - - if warehouse.create_account_under == stock_group or not warehouse.create_account_under: - if not warehouse.parent_warehouse: - account.parent_account = "{0} - {1}".format(_("All Warehouses"), company.abbr) - else: - account.parent_account = frappe.db.get_value("Account", {"warehouse": warehouse.parent_warehouse}) - account.save(ignore_permissions=True) - -def create_default_warehouse_group(company): - frappe.get_doc({ - "doctype": "Warehouse", - "warehouse_name": _("All Warehouses"), - "is_group": "Yes", - "company": company.name, - "parent_warehouse": "" - }).insert(ignore_permissions=True) \ No newline at end of file From 001d4d74faf28097783ac4d7c75a29b77d2bb996 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Thu, 23 Jun 2016 17:46:15 +0530 Subject: [PATCH 16/17] [fix] in set_valuation_method check for is group condition --- .../stock_reconciliation/test_stock_reconciliation.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py index f0eea5a3f6..9cc27b7e20 100644 --- a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py @@ -116,10 +116,11 @@ def create_stock_reconciliation(**args): def set_valuation_method(item_code, valuation_method): frappe.db.set_value("Item", item_code, "valuation_method", valuation_method) - for warehouse in frappe.get_all("Warehouse", filters={"company": "_Test Company"}): - update_entries_after({ - "item_code": item_code, - "warehouse": warehouse.name - }, allow_negative_stock=1) + for warehouse in frappe.get_all("Warehouse", filters={"company": "_Test Company"}, fields=["name", "is_group"]): + if warehouse.is_group == "No": + update_entries_after({ + "item_code": item_code, + "warehouse": warehouse.name + }, allow_negative_stock=1) test_dependencies = ["Item", "Warehouse"] From dc2fa86222f7fb1b6c9d64f535a0215d818e3ec7 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Fri, 24 Jun 2016 11:36:31 +0530 Subject: [PATCH 17/17] [fixes] rename ctype to doctype --- erpnext/accounts/utils.py | 12 ++++++------ .../patches/v7_0/create_warehouse_nestedset.py | 5 ----- erpnext/stock/doctype/warehouse/warehouse.js | 2 ++ erpnext/stock/doctype/warehouse/warehouse.py | 16 ++++++++-------- 4 files changed, 16 insertions(+), 19 deletions(-) diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 5cccf1bf48..fbead264cf 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -448,13 +448,13 @@ def get_companies(): @frappe.whitelist() def get_children(): args = frappe.local.form_dict - ctype, company = args['ctype'], args['company'] - fieldname = frappe.db.escape(ctype.lower().replace(' ','_')) - doctype = frappe.db.escape(ctype) + doctype, company = args['doctype'], args['company'] + fieldname = frappe.db.escape(doctype.lower().replace(' ','_')) + doctype = frappe.db.escape(doctype) # root if args['parent'] in ("Accounts", "Cost Centers"): - fields = ", root_type, report_type, account_currency" if ctype=="Account" else "" + fields = ", root_type, report_type, account_currency" if doctype=="Account" else "" acc = frappe.db.sql(""" select name as value, is_group as expandable {fields} from `tab{doctype}` @@ -467,7 +467,7 @@ def get_children(): sort_root_accounts(acc) else: # other - fields = ", account_currency" if ctype=="Account" else "" + fields = ", account_currency" if doctype=="Account" else "" acc = frappe.db.sql("""select name as value, is_group as expandable, parent_{fieldname} as parent {fields} from `tab{doctype}` @@ -476,7 +476,7 @@ def get_children(): order by name""".format(fields=fields, fieldname=fieldname, doctype=doctype), args['parent'], as_dict=1) - if ctype == 'Account': + if doctype == 'Account': company_currency = frappe.db.get_value("Company", company, "default_currency") for each in acc: each["company_currency"] = company_currency diff --git a/erpnext/patches/v7_0/create_warehouse_nestedset.py b/erpnext/patches/v7_0/create_warehouse_nestedset.py index c313f31456..80dbf2ec1c 100644 --- a/erpnext/patches/v7_0/create_warehouse_nestedset.py +++ b/erpnext/patches/v7_0/create_warehouse_nestedset.py @@ -12,7 +12,6 @@ def execute(): "parent_warehouse", "is_group"]): set_parent_to_warehouses(warehouse, company) set_parent_to_warehouse_acounts(warehouse, company) - frappe.db.commit() def set_parent_to_warehouses(warehouse, company): warehouse = frappe.get_doc("Warehouse", warehouse.name) @@ -31,10 +30,6 @@ def set_parent_to_warehouse_acounts(warehouse, company): if account and account != "{0} - {1}".format(_("All Warehouses"), company.abbr): account = frappe.get_doc("Account", account) - if warehouse.is_group == "Yes": - account.is_group = 1 - account.account_type = "" - if warehouse.create_account_under == stock_group or not warehouse.create_account_under: if not warehouse.parent_warehouse: account.parent_account = "{0} - {1}".format(_("All Warehouses"), company.abbr) diff --git a/erpnext/stock/doctype/warehouse/warehouse.js b/erpnext/stock/doctype/warehouse/warehouse.js index debcbfdbb5..4a84eadb99 100644 --- a/erpnext/stock/doctype/warehouse/warehouse.js +++ b/erpnext/stock/doctype/warehouse/warehouse.js @@ -1,6 +1,8 @@ // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors // License: GNU General Public License v3. See license.txt +cur_frm.list_route = "Tree/Warehouse"; + frappe.ui.form.on("Warehouse", { refresh: function(frm) { frm.toggle_display('warehouse_name', frm.doc.__islocal); diff --git a/erpnext/stock/doctype/warehouse/warehouse.py b/erpnext/stock/doctype/warehouse/warehouse.py index 58f7f603ef..f1f1e705a0 100644 --- a/erpnext/stock/doctype/warehouse/warehouse.py +++ b/erpnext/stock/doctype/warehouse/warehouse.py @@ -176,10 +176,10 @@ class Warehouse(NestedSet): @frappe.whitelist() def get_children(): from erpnext.stock.utils import get_stock_value_on - ctype = frappe.local.form_dict.get('ctype') + doctype = frappe.local.form_dict.get('doctype') company = frappe.local.form_dict.get('company') - parent_field = 'parent_' + ctype.lower().replace(' ', '_') + parent_field = 'parent_' + doctype.lower().replace(' ', '_') parent = frappe.form_dict.get("parent") or "" if parent == "Warehouses": @@ -187,10 +187,10 @@ def get_children(): warehouses = frappe.db.sql("""select name as value, if(is_group='Yes', 1, 0) as expandable - from `tab{ctype}` + from `tab{doctype}` where docstatus < 2 and ifnull(`{parent_field}`,'') = %s and `company` = %s - order by name""".format(ctype=frappe.db.escape(ctype), parent_field=frappe.db.escape(parent_field)), + order by name""".format(doctype=frappe.db.escape(doctype), parent_field=frappe.db.escape(parent_field)), (parent, company), as_dict=1) # return warehouses @@ -200,12 +200,12 @@ def get_children(): @frappe.whitelist() def add_node(): - ctype = frappe.form_dict.get('ctype') + doctype = frappe.form_dict.get('doctype') company = frappe.form_dict.get('company') - parent_field = 'parent_' + ctype.lower().replace(' ', '_') - name_field = ctype.lower().replace(' ', '_') + '_name' + parent_field = 'parent_' + doctype.lower().replace(' ', '_') + name_field = doctype.lower().replace(' ', '_') + '_name' - doc = frappe.new_doc(ctype) + doc = frappe.new_doc(doctype) parent = frappe.form_dict['parent']