[enhancement] add bom tree view
diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js
index 720575a..65ecfd8 100644
--- a/erpnext/manufacturing/doctype/bom/bom.js
+++ b/erpnext/manufacturing/doctype/bom/bom.js
@@ -1,6 +1,8 @@
 // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
 // License: GNU General Public License v3. See license.txt
 
+frappe.provide("erpnext.bom");
+
 frappe.ui.form.on("BOM", {
 	onload_post_render: function(frm) {
 		frm.get_field("items").grid.set_multiple_add("item_code", "qty");
@@ -13,6 +15,9 @@
 			frm.add_custom_button(__("Update Cost"), function() {
 				frm.events.update_cost(frm);
 			});
+			frm.add_custom_button(__("Browse BOM"), function() {
+				frappe.set_route("bom-browser", frm.doc.name);
+			});
 		}
 	},
 	update_cost: function(frm) {
@@ -27,10 +32,6 @@
 	}
 });
 
-
-// On REFRESH
-frappe.provide("erpnext.bom");
-
 cur_frm.add_fetch("item", "description", "description");
 cur_frm.add_fetch("item", "image", "image");
 cur_frm.add_fetch("item", "item_name", "item_name");
diff --git a/erpnext/manufacturing/page/__init__.py b/erpnext/manufacturing/page/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/manufacturing/page/__init__.py
diff --git a/erpnext/manufacturing/page/bom_browser/__init__.py b/erpnext/manufacturing/page/bom_browser/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/manufacturing/page/bom_browser/__init__.py
diff --git a/erpnext/manufacturing/page/bom_browser/bom_browser.js b/erpnext/manufacturing/page/bom_browser/bom_browser.js
new file mode 100644
index 0000000..453d8c5
--- /dev/null
+++ b/erpnext/manufacturing/page/bom_browser/bom_browser.js
@@ -0,0 +1,90 @@
+// 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 = $('<div class="padding"><p class="text-muted">'+
+		__("Select BOM to start")
+		+'</p></div>').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.parent);
+					}
+				}
+			],
+			get_label: function(node) {
+				if(node.data.qty) {
+					return node.data.qty + " x " + node.data.value;
+				} else {
+					return node.data.value;
+				}
+			}
+		});
+	}
+});
diff --git a/erpnext/manufacturing/page/bom_browser/bom_browser.json b/erpnext/manufacturing/page/bom_browser/bom_browser.json
new file mode 100644
index 0000000..5b75463
--- /dev/null
+++ b/erpnext/manufacturing/page/bom_browser/bom_browser.json
@@ -0,0 +1,21 @@
+{
+ "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
new file mode 100644
index 0000000..8051e69
--- /dev/null
+++ b/erpnext/manufacturing/page/bom_browser/bom_browser.py
@@ -0,0 +1,15 @@
+# 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):
+	return frappe.db.sql("""select item_code as value,
+		bom_no as parent, qty,
+		if(ifnull(bom_no, "")!="", 1, 0) as expandable
+		from `tabBOM Item`
+		where parent=%s
+		order by idx
+		""", parent, as_dict=True)