Hub (#10934)

* [WIP]Hub

* [listing] Show items, users and item_groups

* Show filters

* [start] cart, api for rfq and opp

* rfq working

* [wip] keys

* wip quotes

* [hub] register/unregister

* [hub] rename password to access_token, remove passed company field

* [hub] publishing cases, api call wrapper

* [hub] add and remove fields working

* [hub] fix flags, update on client save working

* [hub] new hub page, client item CUD at hub working

* listing, standard rate, local site hack

* item listing, item page, search, back to home

* [hub] implement hub company

* [hub] company filter

* [hub] basic rfq-ing, item page cleanup

* categories wip

* [hub] use get_doc_before_save()

* [hub] send opportunity message to hub, api to make locally

* [hub] enqueueing in hub api request wrapper

* cleanup

* [hub] refactor shopping cart's product.py to reuse

* sync dynamic item fields daily

* Scheduler heartbeat check

* [wip] hub categories

* [hub] wip enqueued callbacks

* [hub] outgoing messages, fixing callback loop

* [hub] bug: callback save after primary save

* [hub] pricing, stock, currency

* [hub] replace send_hub_request with make_and_enqueue

* add hub.less, refactor code

* Remove template html files, add styling for hub item cards

* fix paging

* add breadcrumb

* Add sidebar

* [hub] add company page, change country

* [hub] order_by filters

* [hub] make hub category a tree

* [hub] enqueue batched item enqueueing

* [hub] requested products page

* [minor]

* update hub url

* [fix] url

* [fix] more reform

* fix recursion

* [hub] data migration plans as jsons

* Hub register, create data connector, sync with run

* [add] user registration by session user

* Removed hub_message

* Remove sync code from hub_settings

* Remove hub methods from item.py

* Update Hub Sync plan

* Hub unregister

* Update Hub connector on reregister

* Dont delete Hub Connector on unregister

* Enable hub on success response

* Add new hub whitelisted methods

* [hub] list working

* Hub register from hub page

* [hub] Add hub logo in desk icon, link to page

* [hub] hide page head on empty state

* [hub] make rfq

* [hub] push opportunity doc, poll for opportunity docs

* add fields to item mapping

* update hub mappings

* Make RFQ

* [hub] item, home routing

* Make rfq and send opportunity refactor

* [hub][fix] remote lead data

* images passed as base64

* set default company on register

* Revert "images passed as base64"

This reverts commit 0b033a5fb7072b2d39a1b87a47dc41e7af707bb4.

* Add sync to hub page

* Prompt for publish items to hub

* add post process to hub document to lead

* Rename Hub document to Hub message, create opportunity in post process
diff --git a/erpnext/hub_node/__init__.py b/erpnext/hub_node/__init__.py
index 1c97299..1756b76 100644
--- a/erpnext/hub_node/__init__.py
+++ b/erpnext/hub_node/__init__.py
@@ -2,16 +2,275 @@
 # For license information, please see license.txt
 
 from __future__ import unicode_literals
-import frappe, requests
+import frappe, requests, json
+from frappe.utils import now, nowdate, cint
+from frappe.utils.nestedset import get_root_of
+from frappe.contacts.doctype.contact.contact import get_default_contact
 
 @frappe.whitelist()
-def get_items(text, start, limit):
-	hub = frappe.get_single("Hub Settings")
-	response = requests.get(hub.hub_url + "/api/method/hub.hub.api.get_items", params={
-		"access_token": hub.access_token,
-		"text": text,
-		"start": start,
-		"limit": limit
-	})
-	response.raise_for_status()
-	return response.json().get("message")
+def enable_hub():
+	hub_settings = frappe.get_doc('Hub Settings')
+	hub_settings.register()
+	frappe.db.commit()
+	return hub_settings
+
+@frappe.whitelist()
+def get_items(start=0, page_length=20):
+	connection = get_connection()
+	response = connection.connection.get_list('Hub Item', limit_start=start, limit_page_length=page_length)
+	return response
+
+@frappe.whitelist()
+def get_categories():
+	connection = get_connection()
+	response = connection.get_list('Hub Category')
+	return response.list
+
+@frappe.whitelist()
+def get_item_details(hub_sync_id):
+	connection = get_connection()
+	return connection.connection.get_doc('Hub Item', hub_sync_id)
+
+@frappe.whitelist()
+def get_company_details(hub_sync_id):
+	connection = get_connection()
+	return connection.connection.get_doc('Hub Company', hub_sync_id)
+
+def get_connection():
+	hub_connector = frappe.get_doc(
+		'Data Migration Connector', 'Hub Connector')
+	hub_connection = hub_connector.get_connection()
+	return hub_connection
+
+def make_opportunity(buyer_name, email_id):
+	buyer_name = "HUB-" + buyer_name
+
+	if not frappe.db.exists('Lead', {'email_id': email_id}):
+		lead = frappe.new_doc("Lead")
+		lead.lead_name = buyer_name
+		lead.email_id = email_id
+		lead.save(ignore_permissions=True)
+
+	o = frappe.new_doc("Opportunity")
+	o.enquiry_from = "Lead"
+	o.lead = frappe.get_all("Lead", filters={"email_id": email_id}, fields = ["name"])[0]["name"]
+	o.save(ignore_permissions=True)
+
+# @frappe.whitelist()
+# def get_items(text='', by_item_codes=0, start=0, limit=20, order_by='', category=None, company_name=None, country=None):
+# 	item_codes = []
+# 	if cint(by_item_codes):
+# 		item_codes = [d["item_code"] for d in frappe.get_all("Item", fields=["item_code"], filters={"is_hub_item": "1"},
+# 			limit_start = start, limit_page_length = limit)]
+# 		if not item_codes:
+# 			return []
+
+# 	args = {
+# 		"text": text,
+# 		"item_codes": item_codes,
+# 		"category": category,
+# 		"company_name": company_name,
+# 		"country": country,
+# 		"order_by": order_by,
+# 		"start": start,
+# 		"limit": limit
+# 	}
+# 	return hub_request('get_items', data=json.dumps(args))
+
+# @frappe.whitelist()
+# def get_all_companies():
+# 	return hub_request('get_all_companies')
+
+# @frappe.whitelist()
+# def get_item_details(item_code):
+# 	args = {
+# 		"item_code": item_code,
+# 	}
+# 	return hub_request('get_item_details', data=json.dumps(args))
+
+# @frappe.whitelist()
+# def get_company_details(company_id):
+# 	args = {
+# 		"company_id": company_id,
+# 	}
+# 	return hub_request('get_company_details', data=json.dumps(args))
+
+# @frappe.whitelist()
+# def get_categories():
+# 	# update_local_hub_categories()
+# 	return hub_request('get_categories')
+
+# def update_local_hub_categories():
+# 	categories = get_categories()
+# 	categories_to_remove = []
+# 	categories_to_add = []
+# 	old_categories = frappe.db.sql_list("select category_name from from `tabHub Category`")
+# 	new_categories = [d.category_name for d in categories]
+# 	for old_category in old_categories:
+# 		if old_category not in new_categories:
+# 			categories_to_remove.append(old_category)
+
+# 	for new_category in new_categories:
+# 		if new_category not in old_categories:
+# 			categories_to_add.append(new_category)
+
+# 	for d in categories_to_remove:
+# 		docname = frappe.get_list('Hub Category', filters = {"category_name": d})[0]["name"]
+# 		frappe.delete_doc("Hub Category", docname)
+
+# 	for d in categories_to_add:
+# 		doc = frappe.new_doc("Hub Category")
+# 		doc.category_name = d
+# 		doc.save()
+
+
+# @frappe.whitelist()
+# def get_items_seen_states(items):
+# 	items = json.loads(items)
+# 	for d in items:
+# 		local_item_code = "HUB-" + d["item_code"]
+# 		if frappe.db.exists("Item", {"item_code": local_item_code}):
+# 			d["seen"] = 1
+# 		else:
+# 			d["seen"] = 0
+# 	return items
+
+# @frappe.whitelist()
+# def get_local_hub_item_codes():
+# 	item_codes = []
+# 	for d in frappe.get_all("Item", fields=["item_code"], filters={"is_hub_item": 1}):
+# 		item_codes.append(d["item_code"][4:])
+# 	return item_codes
+
+# @frappe.whitelist()
+# def hub_item_request_action(item):
+# 	item = json.loads(item)
+# 	rfq = make_rfq(item)
+# 	# , send click count and say requested
+# 	send_opportunity_details(supplier_name, supplier_email)
+# 	make_opportunities()
+# 	return rfq
+
+# def send_opportunity_details(supplier_name, supplier_email):
+# 	connection = get_connection()
+# 	params = {
+# 		"buyer_name": supplier_name,
+# 		"email_id": supplier_email
+# 	}
+# 	args = frappe._dict(dict(
+# 		doctype="Hub Document",
+# 		type="Opportunity",
+# 		document_data=json.dumps(params),
+# 		user=supplier_email
+# 	))
+# 	response = connection.insert("Hub Document", args)
+
+@frappe.whitelist()
+def make_rfq_and_send_opportunity(item, supplier):
+	supplier = make_supplier(supplier)
+	contact = make_contact(supplier)
+	item = make_item(item)
+	rfq = make_rfq(item, supplier, contact)
+	status = send_opportunity(contact)
+
+	return {
+		'rfq': rfq,
+		'hub_document_created': status
+	}
+
+def make_supplier(supplier):
+	# make supplier if not already exists
+	supplier = frappe._dict(json.loads(supplier))
+
+	if not frappe.db.exists('Supplier', {'supplier_name': supplier.supplier_name}):
+		supplier_doc = frappe.get_doc({
+			'doctype': 'Supplier',
+			'supplier_name': supplier.supplier_name,
+			'supplier_type': supplier.supplier_type,
+			'supplier_email': supplier.supplier_email
+		}).insert()
+	else:
+		supplier_doc = frappe.get_doc('Supplier', supplier.supplier_name)
+
+	return supplier_doc
+
+def make_contact(supplier):
+	contact_name = get_default_contact('Supplier', supplier.supplier_name)
+	# make contact if not already exists
+	if not contact_name:
+		contact = frappe.get_doc({
+			'doctype': 'Contact',
+			'first_name': supplier.supplier_name,
+			'email_id': supplier.supplier_email,
+			'is_primary_contact': 1,
+			'links': [
+				{'link_doctype': 'Supplier', 'link_name': supplier.supplier_name}
+			]
+		}).insert()
+	else:
+		contact = frappe.get_doc('Contact', contact_name)
+
+	return contact
+
+def make_item(item):
+	# make item if not already exists
+	item = frappe._dict(json.loads(item))
+
+	if not frappe.db.exists('Item', {'item_code': item.item_code}):
+		item_doc = frappe.get_doc({
+			'doctype': 'Item',
+			'item_code': item.item_code,
+			'item_group': item.item_group,
+			'is_hub_item': 1
+		}).insert()
+	else:
+		item_doc = frappe.get_doc('Item', item.item_code)
+
+	return item_doc
+
+def make_rfq(item, supplier, contact):
+	# make rfq
+	rfq = frappe.get_doc({
+		'doctype': 'Request for Quotation',
+		'transaction_date': nowdate(),
+		'status': 'Draft',
+		'company': frappe.db.get_single_value('Hub Settings', 'company'),
+		'message_for_supplier': 'Please supply the specified items at the best possible rates',
+		'suppliers': [
+			{ 'supplier': supplier.name, 'contact': contact.name }
+		],
+		'items': [
+			{
+				'item_code': item.item_code,
+				'qty': 1,
+				'schedule_date': nowdate(),
+				'warehouse': item.default_warehouse or get_root_of("Warehouse"),
+				'description': item.description,
+				'uom': item.stock_uom
+			}
+		]
+	}).insert()
+
+	rfq.save()
+	rfq.submit()
+	return rfq
+
+def send_opportunity(contact):
+	# Make Hub Message on Hub with lead data
+	doc = {
+		'doctype': 'Lead',
+		'lead_name': frappe.db.get_single_value('Hub Settings', 'company'),
+		'email_id': frappe.db.get_single_value('Hub Settings', 'user')
+	}
+
+	args = frappe._dict(dict(
+		doctype='Hub Message',
+		reference_doctype='Lead',
+		data=json.dumps(doc),
+		user=contact.email_id
+	))
+
+	connection = get_connection()
+	response = connection.insert('Hub Message', args)
+
+	return response.ok
diff --git a/erpnext/hub_node/api.py b/erpnext/hub_node/api.py
new file mode 100644
index 0000000..b32efd9
--- /dev/null
+++ b/erpnext/hub_node/api.py
@@ -0,0 +1,29 @@
+# Copyright (c) 2015, Web Notes Technologies Pvt. Ltd. and Contributors and contributors
+# For license information, please see license.txt
+
+
+import frappe, json
+from frappe.utils import now, nowdate
+from erpnext.hub_node.doctype.hub_settings.hub_settings import get_hub_settings
+
+# API wrapper
+@frappe.whitelist(allow_guest=True)
+def call_method(access_token, method, message):
+	try:
+		args = json.loads(message)
+		if args:
+			return globals()[method](access_token, args)
+		else:
+			return globals()[method](access_token)
+	except:
+		print("Client Exception")
+		print(frappe.get_traceback())
+
+def disable_and_suspend_hub_user(access_token):
+	hub_settings = get_hub_settings()
+	hub_settings.publish = 0
+	hub_settings.publish_pricing = 0
+	hub_settings.publish_availability = 0
+	hub_settings.suspended = 1
+	hub_settings.enabled = 0
+	hub_settings.save(ignore_permissions=True)
diff --git a/erpnext/hub_node/data_migration_mapping/__init__.py b/erpnext/hub_node/data_migration_mapping/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/hub_node/data_migration_mapping/__init__.py
diff --git a/erpnext/hub_node/data_migration_mapping/company_to_hub_company/company_to_hub_company.json b/erpnext/hub_node/data_migration_mapping/company_to_hub_company/company_to_hub_company.json
new file mode 100644
index 0000000..dac8fe6
--- /dev/null
+++ b/erpnext/hub_node/data_migration_mapping/company_to_hub_company/company_to_hub_company.json
@@ -0,0 +1,45 @@
+{
+ "condition": "{'name': ('=', frappe.db.get_single_value('Hub Settings', 'company'))}", 
+ "creation": "2017-09-07 11:38:43.169065", 
+ "docstatus": 0, 
+ "doctype": "Data Migration Mapping", 
+ "fields": [
+  {
+   "is_child_table": 0, 
+   "local_fieldname": "name", 
+   "remote_fieldname": "company_name"
+  }, 
+  {
+   "is_child_table": 0, 
+   "local_fieldname": "country", 
+   "remote_fieldname": "country"
+  }, 
+  {
+   "is_child_table": 0, 
+   "local_fieldname": "\"city\"", 
+   "remote_fieldname": "seller_city"
+  }, 
+  {
+   "is_child_table": 0, 
+   "local_fieldname": "eval:frappe.local.site", 
+   "remote_fieldname": "site_name"
+  }, 
+  {
+   "is_child_table": 0, 
+   "local_fieldname": "eval:frappe.session.user", 
+   "remote_fieldname": "user"
+  }
+ ], 
+ "idx": 2, 
+ "local_doctype": "Company", 
+ "mapping_name": "Company to Hub Company", 
+ "mapping_type": "Push", 
+ "migration_id_field": "hub_sync_id", 
+ "modified": "2017-09-22 15:32:12.459172", 
+ "modified_by": "Administrator", 
+ "name": "Company to Hub Company", 
+ "owner": "Administrator", 
+ "page_length": 10, 
+ "remote_objectname": "Hub Company", 
+ "remote_primary_key": "name"
+}
\ No newline at end of file
diff --git a/erpnext/hub_node/data_migration_mapping/hub_message_to_lead/__init__.py b/erpnext/hub_node/data_migration_mapping/hub_message_to_lead/__init__.py
new file mode 100644
index 0000000..79769ee
--- /dev/null
+++ b/erpnext/hub_node/data_migration_mapping/hub_message_to_lead/__init__.py
@@ -0,0 +1,29 @@
+import frappe, json
+
+def pre_process(doc):
+	return json.loads(doc['data'])
+
+def post_process(remote_doc=None, local_doc=None, **kwargs):
+	if not local_doc:
+		return
+
+	hub_message = remote_doc
+	# update hub message on hub
+	hub_connector = frappe.get_doc('Data Migration Connector', 'Hub Connector')
+	connection = hub_connector.get_connection()
+	connection.update('Hub Message', dict(
+		status='Synced'
+	), hub_message['name'])
+
+	# make opportunity after lead is created
+	lead = local_doc
+	opportunity = frappe.get_doc({
+		'doctype': 'Opportunity',
+		'naming_series': 'OPTY-',
+		'enquiry_type': 'Sales',
+		'enquiry_from': 'Lead',
+		'status': 'Open',
+		'lead': lead.name,
+		'company': lead.company,
+		'transaction_date': frappe.utils.today()
+	}).insert()
diff --git a/erpnext/hub_node/data_migration_mapping/hub_message_to_lead/hub_message_to_lead.json b/erpnext/hub_node/data_migration_mapping/hub_message_to_lead/hub_message_to_lead.json
new file mode 100644
index 0000000..a0194ad
--- /dev/null
+++ b/erpnext/hub_node/data_migration_mapping/hub_message_to_lead/hub_message_to_lead.json
@@ -0,0 +1,31 @@
+{
+ "condition": "{'reference_doctype': 'Lead', 'user': frappe.db.get_single_value('Hub Settings', 'user'), 'status': 'Pending'}", 
+ "creation": "2017-09-20 15:06:40.279930", 
+ "docstatus": 0, 
+ "doctype": "Data Migration Mapping", 
+ "fields": [
+  {
+   "is_child_table": 0, 
+   "local_fieldname": "email_id", 
+   "remote_fieldname": "email_id"
+  }, 
+  {
+   "is_child_table": 0, 
+   "local_fieldname": "lead_name", 
+   "remote_fieldname": "lead_name"
+  }
+ ], 
+ "idx": 0, 
+ "local_doctype": "Lead", 
+ "local_primary_key": "email_id", 
+ "mapping_name": "Hub Message to Lead", 
+ "mapping_type": "Pull", 
+ "migration_id_field": "hub_sync_id", 
+ "modified": "2017-09-28 13:21:41.575155", 
+ "modified_by": "faris@erpnext.com", 
+ "name": "Hub Message to Lead", 
+ "owner": "frappetest@gmail.com", 
+ "page_length": 10, 
+ "remote_objectname": "Hub Message", 
+ "remote_primary_key": "name"
+}
\ No newline at end of file
diff --git a/erpnext/hub_node/data_migration_mapping/item_to_hub_item/item_to_hub_item.json b/erpnext/hub_node/data_migration_mapping/item_to_hub_item/item_to_hub_item.json
new file mode 100644
index 0000000..ef90918
--- /dev/null
+++ b/erpnext/hub_node/data_migration_mapping/item_to_hub_item/item_to_hub_item.json
@@ -0,0 +1,54 @@
+{
+ "creation": "2017-09-07 13:27:52.726350", 
+ "docstatus": 0, 
+ "doctype": "Data Migration Mapping", 
+ "fields": [
+  {
+   "is_child_table": 0, 
+   "local_fieldname": "item_code", 
+   "remote_fieldname": "item_code"
+  }, 
+  {
+   "is_child_table": 0, 
+   "local_fieldname": "item_name", 
+   "remote_fieldname": "item_name"
+  }, 
+  {
+   "is_child_table": 0, 
+   "local_fieldname": "eval:frappe.db.get_default(\"company\")", 
+   "remote_fieldname": "company_name"
+  }, 
+  {
+   "is_child_table": 0, 
+   "local_fieldname": "image", 
+   "remote_fieldname": "image"
+  }, 
+  {
+   "is_child_table": 0, 
+   "local_fieldname": "item_group", 
+   "remote_fieldname": "item_group"
+  }, 
+  {
+   "is_child_table": 0, 
+   "local_fieldname": "eval:frappe.session.user", 
+   "remote_fieldname": "seller"
+  }, 
+  {
+   "is_child_table": 0, 
+   "local_fieldname": "eval:frappe.db.get_default(\"country\")", 
+   "remote_fieldname": "country"
+  }
+ ], 
+ "idx": 1, 
+ "local_doctype": "Item", 
+ "mapping_name": "Item to Hub Item", 
+ "mapping_type": "Push", 
+ "migration_id_field": "hub_sync_id", 
+ "modified": "2017-09-22 15:32:12.674169", 
+ "modified_by": "Administrator", 
+ "name": "Item to Hub Item", 
+ "owner": "Administrator", 
+ "page_length": 10, 
+ "remote_objectname": "Hub Item", 
+ "remote_primary_key": "item_code"
+}
\ No newline at end of file
diff --git a/erpnext/hub_node/data_migration_plan/hub_sync/hub_sync.json b/erpnext/hub_node/data_migration_plan/hub_sync/hub_sync.json
new file mode 100644
index 0000000..9edbac9
--- /dev/null
+++ b/erpnext/hub_node/data_migration_plan/hub_sync/hub_sync.json
@@ -0,0 +1,26 @@
+{
+ "creation": "2017-09-07 11:39:38.445902",
+ "docstatus": 0,
+ "doctype": "Data Migration Plan",
+ "idx": 1,
+ "mappings": [
+  {
+   "enabled": 1,
+   "mapping": "Company to Hub Company"
+  },
+  {
+   "enabled": 1,
+   "mapping": "Item to Hub Item"
+  },
+  {
+   "enabled": 1,
+   "mapping": "Hub Message to Lead"
+  }
+ ],
+ "modified": "2017-09-28 15:37:17.616828",
+ "modified_by": "faris@erpnext.com",
+ "module": "Hub Node",
+ "name": "Hub Sync",
+ "owner": "Administrator",
+ "plan_name": "Hub Sync"
+}
\ No newline at end of file
diff --git a/erpnext/hub_node/doctype/hub_category/__init__.py b/erpnext/hub_node/doctype/hub_category/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/hub_node/doctype/hub_category/__init__.py
diff --git a/erpnext/hub_node/doctype/hub_category/hub_category.js b/erpnext/hub_node/doctype/hub_category/hub_category.js
new file mode 100644
index 0000000..9f54166
--- /dev/null
+++ b/erpnext/hub_node/doctype/hub_category/hub_category.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Hub Category', {
+	refresh: function(frm) {
+
+	}
+});
diff --git a/erpnext/hub_node/doctype/hub_category/hub_category.json b/erpnext/hub_node/doctype/hub_category/hub_category.json
new file mode 100644
index 0000000..4f8d66a
--- /dev/null
+++ b/erpnext/hub_node/doctype/hub_category/hub_category.json
@@ -0,0 +1,275 @@
+{
+ "allow_copy": 0, 
+ "allow_guest_to_view": 0, 
+ "allow_import": 0, 
+ "allow_rename": 0, 
+ "autoname": "field:hub_category_name", 
+ "beta": 0, 
+ "creation": "2017-08-22 11:31:10.410322", 
+ "custom": 0, 
+ "docstatus": 0, 
+ "doctype": "DocType", 
+ "document_type": "", 
+ "editable_grid": 1, 
+ "engine": "InnoDB", 
+ "fields": [
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "hub_category_name", 
+   "fieldtype": "Data", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 1, 
+   "in_standard_filter": 0, 
+   "label": "Category Name", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 1, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "parent_hub_category", 
+   "fieldtype": "Link", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Parent Category", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Hub Category", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "is_group", 
+   "fieldtype": "Check", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Is Group", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "description", 
+   "fieldtype": "Text Editor", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Description", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "lft", 
+   "fieldtype": "Int", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Left", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "rgt", 
+   "fieldtype": "Int", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Right", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "old_parent", 
+   "fieldtype": "Data", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Old Parent", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }
+ ], 
+ "has_web_view": 0, 
+ "hide_heading": 0, 
+ "hide_toolbar": 0, 
+ "idx": 0, 
+ "image_view": 0, 
+ "in_create": 0, 
+ "is_submittable": 0, 
+ "issingle": 0, 
+ "istable": 0, 
+ "max_attachments": 0, 
+ "modified": "2017-09-03 22:04:22.958831", 
+ "modified_by": "Administrator", 
+ "module": "Hub Node", 
+ "name": "Hub Category", 
+ "name_case": "", 
+ "owner": "Administrator", 
+ "permissions": [
+  {
+   "amend": 0, 
+   "apply_user_permissions": 0, 
+   "cancel": 0, 
+   "create": 1, 
+   "delete": 1, 
+   "email": 1, 
+   "export": 1, 
+   "if_owner": 0, 
+   "import": 0, 
+   "permlevel": 0, 
+   "print": 1, 
+   "read": 1, 
+   "report": 1, 
+   "role": "System Manager", 
+   "set_user_permissions": 0, 
+   "share": 1, 
+   "submit": 0, 
+   "write": 1
+  }
+ ], 
+ "quick_entry": 1, 
+ "read_only": 0, 
+ "read_only_onload": 0, 
+ "show_name_in_global_search": 0, 
+ "sort_field": "modified", 
+ "sort_order": "DESC", 
+ "title_field": "hub_category_name", 
+ "track_changes": 1, 
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/hub_node/doctype/hub_category/hub_category.py b/erpnext/hub_node/doctype/hub_category/hub_category.py
new file mode 100644
index 0000000..5d19082
--- /dev/null
+++ b/erpnext/hub_node/doctype/hub_category/hub_category.py
@@ -0,0 +1,11 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.utils.nestedset import NestedSet
+from frappe.model.document import Document
+
+class HubCategory(NestedSet):
+	pass
diff --git a/erpnext/hub_node/doctype/hub_category/hub_category_tree.js b/erpnext/hub_node/doctype/hub_category/hub_category_tree.js
new file mode 100644
index 0000000..d0309e3
--- /dev/null
+++ b/erpnext/hub_node/doctype/hub_category/hub_category_tree.js
@@ -0,0 +1,4 @@
+frappe.treeview_settings["Hub Category"] = {
+	title: __("Hub Category"),
+	breadcrumb: "Hub"
+}
\ No newline at end of file
diff --git a/erpnext/hub_node/doctype/hub_category/test_hub_category.js b/erpnext/hub_node/doctype/hub_category/test_hub_category.js
new file mode 100644
index 0000000..73c06d5
--- /dev/null
+++ b/erpnext/hub_node/doctype/hub_category/test_hub_category.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Hub Category", function (assert) {
+	let done = assert.async();
+
+	// number of asserts
+	assert.expect(1);
+
+	frappe.run_serially([
+		// insert a new Hub Category
+		() => frappe.tests.make('Hub Category', [
+			// values to be set
+			{key: 'value'}
+		]),
+		() => {
+			assert.equal(cur_frm.doc.key, 'value');
+		},
+		() => done()
+	]);
+
+});
diff --git a/erpnext/hub_node/doctype/hub_category/test_hub_category.py b/erpnext/hub_node/doctype/hub_category/test_hub_category.py
new file mode 100644
index 0000000..7df2088
--- /dev/null
+++ b/erpnext/hub_node/doctype/hub_category/test_hub_category.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+class TestHubCategory(unittest.TestCase):
+	pass
diff --git a/erpnext/hub_node/doctype/hub_settings/hub_settings.js b/erpnext/hub_node/doctype/hub_settings/hub_settings.js
index 95b6d62..ce0f8bc 100644
--- a/erpnext/hub_node/doctype/hub_settings/hub_settings.js
+++ b/erpnext/hub_node/doctype/hub_settings/hub_settings.js
@@ -1,17 +1,87 @@
-frappe.ui.form.on("Hub Settings", "onload", function(frm) {
-	if(!frm.doc.seller_country) {
-		frm.set_value("seller_country", frappe.defaults.get_default("Country"));
-	}
-	if(!frm.doc.seller_name) {
-		frm.set_value("seller_name", frappe.defaults.get_default("Company"));
-	}
-});
+frappe.ui.form.on("Hub Settings", {
+	refresh: function(frm) {
+		frm.add_custom_button(__('Logs'),
+			() => frappe.set_route('List', 'Data Migration Run', {
+				data_migration_plan: 'Hub Sync'
+			}));
 
-frappe.ui.form.on("Hub Settings", "refresh", function(frm) {
-	// make mandatory if published
-	frm.toggle_reqd(["seller_name", "seller_email", "seller_country"], frm.doc.publish);
-});
+		frm.trigger("enabled");
+		if (frm.doc.enabled) {
+			frm.add_custom_button(__('View Hub'),
+				() => frappe.set_route('hub'));
+			frm.add_custom_button(__('Sync'),
+				() => frm.call('sync'));
+		}
+	},
+	onload: function(frm) {
+		if(!frm.doc.country) {
+			frm.set_value("country", frappe.defaults.get_default("Country"));
+		}
+		if(!frm.doc.company) {
+			frm.set_value("company", frappe.defaults.get_default("Company"));
+		}
+	},
+	onload_post_render: function(frm) {
+		if(frm.get_field("unregister_from_hub").$input)
+			frm.get_field("unregister_from_hub").$input.addClass("btn-danger");
+	},
+	on_update: function(frm) {
+	},
+	enabled: function(frm) {
+		if(!frm.doc.enabled) {
+			frm.trigger("set_enable_hub_primary_button");
+		} else {
+			frm.page.set_primary_action(__("Save Settings"), () => {
+				frm.save();
+			});
+		}
+	},
 
-frappe.ui.form.on("Hub Settings", "publish", function(frm) {
-	frm.trigger("refresh");
+	hub_user_email: function(frm) {
+		if(frm.doc.hub_user_email){
+			frm.set_value("hub_user_name", frappe.user.full_name(frm.doc.hub_user_email));
+		}
+	},
+
+	set_enable_hub_primary_button: (frm) => {
+		frm.page.set_primary_action(__("Enable Hub"), () => {
+			if(frappe.session.user === "Administrator") {
+				frappe.msgprint("Please login as another user.")
+			} else {
+				frappe.verify_password(() => {
+					this.frm.call({
+						doc: this.frm.doc,
+						method: "register",
+						args: {},
+						freeze: true,
+						callback: function(r) {},
+						onerror: function() {
+							frappe.msgprint(__("Wrong Password"));
+							frm.set_value("enabled", 0);
+						}
+					});
+				} );
+			}
+		});
+	},
+
+	// update_hub: (frm) => {
+	// 	this.frm.call({
+	// 		doc: this.frm.doc,
+	// 		method: "update_hub",
+	// 		args: {},
+	// 		freeze: true,
+	// 		callback: function(r) { },
+	// 		onerror: function() { }
+	// 	});
+	// },
+
+	unregister_from_hub: (frm) => {
+		frappe.verify_password(() => {
+			var d = frappe.confirm(__('Are you sure you want to unregister?'), () => {
+				frm.call('unregister');
+			}, () => {}, __('Confirm Action'));
+			d.get_primary_btn().addClass("btn-danger");
+		});
+	},
 });
diff --git a/erpnext/hub_node/doctype/hub_settings/hub_settings.json b/erpnext/hub_node/doctype/hub_settings/hub_settings.json
index 30cb816..b96d6b3 100644
--- a/erpnext/hub_node/doctype/hub_settings/hub_settings.json
+++ b/erpnext/hub_node/doctype/hub_settings/hub_settings.json
@@ -1,29 +1,41 @@
 {
  "allow_copy": 0, 
+ "allow_guest_to_view": 0, 
  "allow_import": 0, 
  "allow_rename": 0, 
+ "beta": 1, 
  "creation": "2015-02-18 00:59:34.560476", 
  "custom": 0, 
+ "description": "", 
  "docstatus": 0, 
  "doctype": "DocType", 
- "document_type": "System", 
+ "document_type": "", 
+ "editable_grid": 0, 
  "fields": [
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
-   "fieldname": "publish", 
+   "columns": 0, 
+   "fieldname": "enabled", 
    "fieldtype": "Check", 
-   "hidden": 0, 
+   "hidden": 1, 
    "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
    "in_filter": 0, 
+   "in_global_search": 0, 
    "in_list_view": 0, 
-   "label": "Publish Items to Hub", 
+   "in_standard_filter": 0, 
+   "label": "Enabled", 
+   "length": 0, 
    "no_copy": 0, 
    "permlevel": 0, 
    "precision": "", 
    "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
    "read_only": 0, 
+   "remember_last_selected_value": 0, 
    "report_hide": 0, 
    "reqd": 0, 
    "search_index": 0, 
@@ -31,43 +43,29 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
-   "depends_on": "publish", 
-   "fieldname": "section_break_2", 
-   "fieldtype": "Section Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "in_filter": 0, 
-   "in_list_view": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 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": "publish_pricing", 
+   "columns": 0, 
+   "fieldname": "suspended", 
    "fieldtype": "Check", 
-   "hidden": 0, 
+   "hidden": 1, 
    "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
    "in_filter": 0, 
+   "in_global_search": 0, 
    "in_list_view": 0, 
-   "label": "Publish Pricing", 
+   "in_standard_filter": 0, 
+   "label": "Suspended", 
+   "length": 0, 
    "no_copy": 0, 
    "permlevel": 0, 
    "precision": "", 
    "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
    "read_only": 0, 
+   "remember_last_selected_value": 0, 
    "report_hide": 0, 
    "reqd": 0, 
    "search_index": 0, 
@@ -75,132 +73,124 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
-   "fieldname": "publish_availability", 
-   "fieldtype": "Check", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "in_filter": 0, 
-   "in_list_view": 0, 
-   "label": "Publish Availability", 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 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": "column_break_5", 
-   "fieldtype": "Column Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "in_filter": 0, 
-   "in_list_view": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 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": "sync_now", 
-   "fieldtype": "Button", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "in_filter": 0, 
-   "in_list_view": 0, 
-   "label": "Sync Now", 
-   "no_copy": 0, 
-   "options": "sync", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 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, 
-   "depends_on": "publish", 
-   "fieldname": "section_break_6", 
-   "fieldtype": "Section Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "in_filter": 0, 
-   "in_list_view": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 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": "seller_name", 
-   "fieldtype": "Data", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "in_filter": 0, 
-   "in_list_view": 0, 
-   "label": "Seller Name", 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 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": "seller_country", 
+   "columns": 0, 
+   "fieldname": "user", 
    "fieldtype": "Link", 
    "hidden": 0, 
    "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
    "in_filter": 0, 
+   "in_global_search": 0, 
    "in_list_view": 0, 
-   "label": "Seller Country", 
+   "in_standard_filter": 0, 
+   "label": "User", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "User", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 1, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 1, 
+   "collapsible_depends_on": "eval:(!doc.enabled)", 
+   "columns": 0, 
+   "depends_on": "", 
+   "fieldname": "seller_profile_section", 
+   "fieldtype": "Section Break", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Company and Seller Profile", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "company", 
+   "fieldtype": "Link", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 1, 
+   "in_standard_filter": 0, 
+   "label": "Company", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Company", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "country", 
+   "fieldtype": "Link", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 1, 
+   "in_standard_filter": 0, 
+   "label": "Country", 
+   "length": 0, 
    "no_copy": 0, 
    "options": "Country", 
    "permlevel": 0, 
    "precision": "", 
    "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
    "read_only": 0, 
+   "remember_last_selected_value": 0, 
    "report_hide": 0, 
    "reqd": 0, 
    "search_index": 0, 
@@ -208,131 +198,29 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
-   "fieldname": "seller_email", 
-   "fieldtype": "Data", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "in_filter": 0, 
-   "in_list_view": 0, 
-   "label": "Seller Email", 
-   "no_copy": 0, 
-   "options": "Email", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 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": "column_break_10", 
-   "fieldtype": "Column Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "in_filter": 0, 
-   "in_list_view": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 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": "seller_city", 
-   "fieldtype": "Data", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "in_filter": 0, 
-   "in_list_view": 0, 
-   "label": "Seller City", 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 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": "seller_website", 
-   "fieldtype": "Data", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "in_filter": 0, 
-   "in_list_view": 0, 
-   "label": "Seller Website", 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 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, 
-   "depends_on": "publish", 
-   "fieldname": "section_break_13", 
-   "fieldtype": "Section Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "in_filter": 0, 
-   "in_list_view": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 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, 
+   "columns": 0, 
    "fieldname": "seller_description", 
    "fieldtype": "Text Editor", 
    "hidden": 0, 
    "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
    "in_filter": 0, 
+   "in_global_search": 0, 
    "in_list_view": 0, 
-   "label": "Seller Description", 
+   "in_standard_filter": 0, 
+   "label": "Description", 
+   "length": 0, 
    "no_copy": 0, 
    "permlevel": 0, 
    "precision": "", 
    "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
    "read_only": 0, 
+   "remember_last_selected_value": 0, 
    "report_hide": 0, 
    "reqd": 0, 
    "search_index": 0, 
@@ -340,21 +228,30 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
-   "fieldname": "name_token", 
-   "fieldtype": "Data", 
-   "hidden": 1, 
+   "columns": 0, 
+   "depends_on": "enabled", 
+   "fieldname": "publish_section", 
+   "fieldtype": "Section Break", 
+   "hidden": 0, 
    "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
    "in_filter": 0, 
+   "in_global_search": 0, 
    "in_list_view": 0, 
-   "label": "Name Token", 
+   "in_standard_filter": 0, 
+   "label": "Publish", 
+   "length": 0, 
    "no_copy": 0, 
    "permlevel": 0, 
    "precision": "", 
    "print_hide": 0, 
-   "read_only": 1, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
    "report_hide": 0, 
    "reqd": 0, 
    "search_index": 0, 
@@ -362,21 +259,216 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
-   "fieldname": "access_token", 
-   "fieldtype": "Data", 
-   "hidden": 1, 
+   "columns": 0, 
+   "fieldname": "publish", 
+   "fieldtype": "Check", 
+   "hidden": 0, 
    "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
    "in_filter": 0, 
+   "in_global_search": 0, 
    "in_list_view": 0, 
-   "label": "Access Token", 
+   "in_standard_filter": 0, 
+   "label": "Publish Items to Hub", 
+   "length": 0, 
    "no_copy": 0, 
    "permlevel": 0, 
    "precision": "", 
    "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "depends_on": "publish", 
+   "fieldname": "publish_pricing", 
+   "fieldtype": "Check", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Publish Pricing", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "depends_on": "eval:(doc.publish && doc.publish_pricing)", 
+   "fieldname": "selling_price_list", 
+   "fieldtype": "Link", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Selling Price List", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Price List", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "depends_on": "publish", 
+   "fieldname": "publish_availability", 
+   "fieldtype": "Check", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Publish Availability", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "depends_on": "publish", 
+   "fieldname": "last_sync_datetime", 
+   "fieldtype": "Datetime", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Last Sync On", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
    "read_only": 1, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "collapsible_depends_on": "", 
+   "columns": 0, 
+   "depends_on": "enabled", 
+   "fieldname": "unregister_section", 
+   "fieldtype": "Section Break", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Unregister", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "unregister_from_hub", 
+   "fieldtype": "Button", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Unregister from Hub", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
    "report_hide": 0, 
    "reqd": 0, 
    "search_index": 0, 
@@ -384,15 +476,18 @@
    "unique": 0
   }
  ], 
+ "has_web_view": 0, 
  "hide_heading": 0, 
  "hide_toolbar": 0, 
+ "idx": 0, 
+ "image_view": 0, 
  "in_create": 0, 
- "in_dialog": 0, 
  "is_submittable": 0, 
  "issingle": 1, 
  "istable": 0, 
- "modified": "2015-02-18 08:14:46.140473", 
- "modified_by": "Administrator", 
+ "max_attachments": 0, 
+ "modified": "2017-09-21 12:13:50.841646", 
+ "modified_by": "manas@erpnext.com", 
  "module": "Hub Node", 
  "name": "Hub Settings", 
  "name_case": "", 
@@ -419,8 +514,12 @@
    "write": 1
   }
  ], 
+ "quick_entry": 0, 
  "read_only": 0, 
  "read_only_onload": 0, 
+ "show_name_in_global_search": 0, 
  "sort_field": "modified", 
- "sort_order": "DESC"
+ "sort_order": "DESC", 
+ "track_changes": 1, 
+ "track_seen": 0
 }
\ No newline at end of file
diff --git a/erpnext/hub_node/doctype/hub_settings/hub_settings.py b/erpnext/hub_node/doctype/hub_settings/hub_settings.py
index 35f1f67..7e54b65 100644
--- a/erpnext/hub_node/doctype/hub_settings/hub_settings.py
+++ b/erpnext/hub_node/doctype/hub_settings/hub_settings.py
@@ -3,94 +3,103 @@
 
 from __future__ import unicode_literals
 import frappe, requests, json
-from frappe.model.document import Document
-from frappe.utils import cint, expand_relative_urls
-from frappe import _
 
+from frappe.model.document import Document
+from frappe.utils import add_years, now, get_datetime, get_datetime_str
+from frappe import _
+from erpnext.utilities.product import get_price, get_qty_in_stock
+from six import string_types
+
+hub_url = "http://erpnext.hub:8000"
+# hub_url = "https://hub.erpnext.org"
+# hub_url = "http://192.168.29.145:3000"
+
+class HubSetupError(frappe.ValidationError): pass
 
 class HubSettings(Document):
-	hub_url = "http://localhost:8001"
-	def validate(self):
-		if cint(self.publish):
-			if not self.name_token:
-				self.register()
-			else:
-				self.update_seller_details()
-			self.publish_selling_items()
-		else:
-			if self.name_token:
-				self.unpublish()
 
-	def publish_selling_items(self):
-		"""Set `publish_in_hub`=1 for all Sales Items"""
-		for item in frappe.get_all("Item", fields=["name"],
-			filters={ "publish_in_hub": "0"}):
-			frappe.db.set_value("Item", item.name, "publish_in_hub", 1)
+	def validate(self):
+		if self.publish_pricing and not self.selling_price_list:
+			frappe.throw(_("Please select a Price List to publish pricing"))
+
+	def get_hub_url(self):
+		return hub_url
+
+	def sync(self):
+		"""Create and execute Data Migration Run for Hub Sync plan"""
+		frappe.has_permission('Hub Settings', throw=True)
+
+		doc = frappe.get_doc({
+			'doctype': 'Data Migration Run',
+			'data_migration_plan': 'Hub Sync',
+			'data_migration_connector': 'Hub Connector'
+		}).insert()
+
+		doc.run()
 
 	def register(self):
-		"""Register at hub.erpnext.com, save `name_token` and `access_token`"""
-		response = requests.post(self.hub_url + "/api/method/hub.hub.api.register", data=self.get_args())
-		response.raise_for_status()
-		response = response.json()
-		self.name_token = response.get("message").get("name")
-		self.access_token = response.get("message").get("access_token")
-
-	def unpublish(self):
-		"""Unpublish from hub.erpnext.com"""
-		response = requests.post(self.hub_url + "/api/method/hub.hub.api.unpublish", data={
-			"access_token": self.access_token
-		})
-		response.raise_for_status()
-
-	def update_seller_details(self):
-		"""Update details at hub.erpnext.com"""
-		args = self.get_args()
-		args["published"] = 1
-		response = requests.post(self.hub_url + "/api/method/hub.hub.api.update_seller", data={
-			"access_token": self.access_token,
-			"args": json.dumps(args)
-		})
-		response.raise_for_status()
-
-	def get_args(self):
-		return {
-			"seller_name": self.seller_name,
-			"seller_country": self.seller_country,
-			"seller_city": self.seller_city,
-			"seller_email": self.seller_email,
-			"seller_website": self.seller_website,
-			"seller_description": self.seller_description
+		""" Create a User on hub.erpnext.org and return username/password """
+		data = {
+			'email': frappe.session.user
 		}
+		post_url = hub_url + '/api/method/hub.hub.api.register'
 
-	def sync(self, verbose=True):
-		"""Sync items with hub.erpnext.com"""
-		if not self.publish:
-			if verbose:
-				frappe.msgprint(_("Publish to sync items"))
+		response = requests.post(post_url, data=data)
+		response.raise_for_status()
+		message = response.json().get('message')
+
+		if message and message.get('password'):
+			self.user = frappe.session.user
+			self.create_hub_connector(message)
+			self.company = frappe.defaults.get_user_default('company')
+			self.enabled = 1
+			self.save()
+
+	def unregister(self):
+		""" Disable the User on hub.erpnext.org"""
+
+		hub_connector = frappe.get_doc(
+			'Data Migration Connector', 'Hub Connector')
+
+		connection = hub_connector.get_connection()
+		response = connection.update('User', frappe._dict({'enabled': 0}), hub_connector.username)
+
+		if response.ok:
+			self.enabled = 0
+			self.save()
+
+	def create_hub_connector(self, message):
+		if frappe.db.exists('Data Migration Connector', 'Hub Connector'):
+			hub_connector = frappe.get_doc('Data Migration Connector', 'Hub Connector')
+			hub_connector.username = message['email']
+			hub_connector.password = message['password']
+			hub_connector.save()
 			return
 
-		items = frappe.db.get_all("Item",
-			fields=["name", "item_name", "description", "image", "item_group"],
-			filters={"publish_in_hub": 1, "synced_with_hub": 0})
+		frappe.get_doc({
+			'doctype': 'Data Migration Connector',
+			'connector_type': 'Frappe',
+			'connector_name': 'Hub Connector',
+			'hostname': hub_url,
+			'username': message['email'],
+			'password': message['password']
+		}).insert()
 
-		for item in items:
-			item.item_code = item.name
-			if item.image:
-				item.image = expand_relative_urls(item.image)
+def reset_hub_publishing_settings(last_sync_datetime = ""):
+	doc = frappe.get_doc("Hub Settings", "Hub Settings")
+	doc.reset_publishing_settings(last_sync_datetime)
+	doc.in_callback = 1
+	doc.save()
 
-		item_list = frappe.db.sql_list("select name from tabItem where publish_in_hub=1")
+def reset_hub_settings(last_sync_datetime = ""):
+	doc = frappe.get_doc("Hub Settings", "Hub Settings")
+	doc.reset_publishing_settings(last_sync_datetime)
+	doc.reset_enable()
+	doc.in_callback = 1
+	doc.save()
+	frappe.msgprint(_("Successfully unregistered."))
 
-		if items:
-			response = requests.post(self.hub_url + "/api/method/hub.hub.api.sync", data={
-				"access_token": self.access_token,
-				"items": json.dumps(items),
-				"item_list": json.dumps(item_list)
-			})
-			response.raise_for_status()
-			for item in items:
-				frappe.db.set_value("Item", item.name, "synced_with_hub", 1)
-			if verbose:
-				frappe.msgprint(_("{0} Items synced".format(len(items))))
-		else:
-			if verbose:
-				frappe.msgprint(_("Items already synced"))
+@frappe.whitelist()
+def sync():
+	hub_settings = frappe.get_doc('Hub Settings')
+	hub_settings.sync()
\ No newline at end of file
diff --git a/erpnext/hub_node/doctype/hub_settings/test_hub_settings.js b/erpnext/hub_node/doctype/hub_settings/test_hub_settings.js
new file mode 100644
index 0000000..546ce15
--- /dev/null
+++ b/erpnext/hub_node/doctype/hub_settings/test_hub_settings.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Hub Settings", function (assert) {
+	let done = assert.async();
+
+	// number of asserts
+	assert.expect(1);
+
+	frappe.run_serially('Hub Settings', [
+		// insert a new Hub Settings
+		() => frappe.tests.make([
+			// values to be set
+			{key: 'value'}
+		]),
+		() => {
+			assert.equal(cur_frm.doc.key, 'value');
+		},
+		() => done()
+	]);
+
+});
diff --git a/erpnext/hub_node/doctype/hub_settings/test_hub_settings.py b/erpnext/hub_node/doctype/hub_settings/test_hub_settings.py
new file mode 100644
index 0000000..1299adc
--- /dev/null
+++ b/erpnext/hub_node/doctype/hub_settings/test_hub_settings.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+class TestHubSettings(unittest.TestCase):
+	pass
diff --git a/erpnext/hub_node/page/hub/hub.js b/erpnext/hub_node/page/hub/hub.js
index ad09b9d..7f34a5a 100644
--- a/erpnext/hub_node/page/hub/hub.js
+++ b/erpnext/hub_node/page/hub/hub.js
@@ -1,90 +1,870 @@
+/* globals Hub, HubList */
+
+frappe.provide('erpnext.hub');
+
 frappe.pages['hub'].on_page_load = function(wrapper) {
-	var page = frappe.ui.make_app_page({
+	const page = frappe.ui.make_app_page({
 		parent: wrapper,
 		title: 'Hub',
-		single_column: true
+		single_col: false
 	});
 
-	frappe.hub = new frappe.Hub({page:page});
+	erpnext.hub.Hub = new Hub({ page });
 
-}
+};
 
-frappe.pages['hub'].on_page_show = function() {
-	frappe.hub.refresh();
-}
-
-frappe.Hub = Class.extend({
-	init: function(args) {
-		$.extend(this, args);
-		this.render();
-	},
-	refresh: function() {
-		if(this.hub && this.hub.publish && !this.hub_list) {
-			this.setup_list();
+frappe.pages['hub'].on_page_show = function(wrapper) {
+	const current_route = frappe.get_route();
+	if(current_route[1] === "Products") {
+		const item_code = current_route[2];
+		if(item_code) {
+			erpnext.hub.Hub.go_to_item_page(item_code);
 		}
-	},
-	render: function() {
-		this.page.main.empty();
-		var me = this;
-		frappe.model.with_doc("Hub Settings", "Hub Settings", function() {
-			me.hub = locals["Hub Settings"]["Hub Settings"];
-			if(!me.hub.publish) {
-				$(frappe.render_template("register_in_hub", {})).appendTo(me.page.main);
+	}
+
+	if(current_route[1] === "Company") {
+		const company_name = current_route[2];
+		if(company_name) {
+			erpnext.hub.Hub.go_to_company_page(company_name);
+		}
+	}
+}
+
+window.Hub = class Hub {
+	constructor({ page }) {
+		this.page = page;
+		frappe.require('/assets/erpnext/css/hub.css', () => {
+			this.setup();
+		});
+	}
+
+	setup() {
+		this.setup_header();
+		this.company_cache = {};
+		this.item_cache = {};
+		this.filters = {};
+		this.order_by = '';
+
+		this.$hub_main_section =
+			$(`<div class='hub-main-section'>`).appendTo(this.page.body);
+		this.bind_events();
+		this.refresh();
+	}
+
+	refresh() {
+		this.$hub_main_section.empty();
+		this.page.page_form.hide();
+
+		const $layout_main = this.page.wrapper.find('.layout-main');
+		const $page_head = this.page.wrapper.find('.page-head');
+
+		frappe.model.with_doc('Hub Settings', 'Hub Settings', () => {
+			this.hub_settings = frappe.get_doc('Hub Settings');
+
+			if(this.hub_settings.enabled == 0) {
+				let $empty_state = this.page.get_empty_state(
+					__("Register for Hub"),
+					__(`Let other ERPNext users discover your products
+						and automate workflow with Supplier from within ERPNext.`),
+					__("Register")
+				);
+
+				$page_head.hide();
+				$layout_main
+					.find('.layout-side-section, .layout-main-section-wrapper')
+					.hide();
+				$layout_main.append($empty_state);
+
+				$empty_state.find('.btn-primary').on('click', () => {
+					this.register_for_hub();
+				});
 			} else {
-				me.setup_list();
+				$page_head.show();
+				$layout_main.find('.page-card-container').remove();
+				$layout_main.find('.layout-side-section, .layout-main-section-wrapper').show();
+				this.setup_live_state();
 			}
 		});
-	},
-	setup_list: function() {
-		var me = this;
-		$(frappe.render_template("hub_body", {})).appendTo(this.page.main);
-		this.hub_list = this.page.main.find(".hub-list");
-		this.search = this.page.main.find("input").on("keypress", function(e) {
-			if(e.which===13) {
-				me.reset();
-			}
+	}
+
+	register_for_hub() {
+		frappe.verify_password(() => {
+			frappe.call({
+				method: 'erpnext.hub_node.enable_hub',
+				callback: (r) => {
+					if(r.message.enabled == 1) {
+						Object.assign(this.hub_settings, r.message);
+						this.refresh();
+						this.prompt_for_item_sync();
+					}
+				}
+			});
 		});
-		this.loading = this.page.main.find(".loading");
-		this.done = this.page.main.find(".done");
-		this.more = this.page.main.find(".more")
-		this.more.find(".btn").on("click", function() { me.next_page() });
-		this.reset();
-	},
-	reset: function() {
-		this.hub_list.empty();
-		this.start = 0;
-		this.page_length = 20;
-		this.next_page();
-	},
-	next_page: function() {
-		var me = this;
-		this.loading.toggleClass("hide", false);
+	}
+
+	prompt_for_item_sync() {
 		frappe.call({
-			method: "erpnext.hub_node.get_items",
+			method: 'frappe.client.get_list',
 			args: {
-				text: this.get_text(),
-				start: this.start,
-				limit: this.page_length
+				doctype: 'Data Migration Run',
+				filters: {
+					'data_migration_plan': 'Hub Sync'
+				},
+				limit_page_length: 1
 			},
 			callback: function(r) {
-				me.loading.toggleClass("hide", true);
-				if(!r.message)
-					r.message = [];
-				me.start += r.message.length;
-				$(frappe.render_template("hub_list", {items: r.message})).appendTo(me.hub_list);
-				if(r.message.length && r.message.length===me.page_length) {
-					// more
-					me.more.removeClass("hide");
-					me.done.addClass("hide");
-				} else {
-					// done
-					me.more.addClass("hide");
-					me.done.removeClass("hide");
+				if (!r) {
+					frappe.confirm(__('Do you want to publish your Items to Hub ?'), () => {
+						this.sync_items_to_hub();
+					});
 				}
 			}
+		})
+	}
+
+	setup_header() {
+		this.page.page_title = this.page.wrapper.find('.page-title');
+		this.tag_line = $(`
+			<div class='tag-line-container'>
+				<span class='tag-line text-muted small'>
+					${__('Product listing and discovery for ERPNext users')}
+				</span>
+			</div>`)
+			.appendTo(this.page.page_title);
+
+		this.bind_title();
+	}
+
+	setup_live_state() {
+		if(!this.$search) {
+			this.setup_filters();
+		}
+		this.page.page_form.show();
+		this.setup_menu();
+		this.setup_sidebar();
+		this.render_body();
+		this.setup_lists();
+	}
+
+	setup_filters() {
+
+		// frappe.call({
+		// 	method: 'erpnext.hub_node.get_categories'
+		// }).then((r) => {
+		// 	if (r.message) {
+		// 		const categories = r.message;
+		// 		console.log("categories", categories);
+		// 		categories
+		// 			.map(c => c.hub_category_name)
+		// 			.map(c => this.sidebar.add_item({
+		// 				label: c,
+		// 				on_click: () => {
+		// 					this.home_item_list &&
+		// 					this.home_item_list.refresh({
+		// 						text: '',
+		// 						start: 0,
+		// 						limit: 20,
+		// 						category: c && c !== 'All Categories' ? c : undefined
+		// 					});
+		// 				}
+		// 			}, __('Hub Category')));
+
+
+		// 	}
+		// });
+
+		// this.category_select = this.page.add_select(__('Category'),
+		// 	[
+		// 		{label: __('Sort by Price ...'), value: '' },
+		// 		{label: __('High to Low'), value: 'price desc' },
+		// 		{label: __('Low to High'), value: 'price' },
+		// 	]
+		// );
+
+		this.price_sort_select = this.page.add_select(__('Sort by Price'),
+			[
+				{label: __('Sort by Price ...'), value: '' },
+				{label: __('High to Low'), value: 'price desc' },
+				{label: __('Low to High'), value: 'price' },
+			]
+		);
+
+		this.criteria_select = this.page.add_select(__('Sort by Criteria'),
+			[
+				{label: __('Most Popular'), value: 'request_count' },
+				{label: __('Newest'), value: 'creation' },
+			]
+		);
+
+		this.price_sort_select.on('change', () => {
+			this.refresh_item_only_page();
 		});
-	},
-	get_text: function() {
-		return this.search.val();
-	},
-})
+
+		this.criteria_select.on('change', () => {
+			this.refresh_item_only_page();
+		});
+
+		this.$search = this.page.add_data(__('Search'));
+		this.setup_search();
+	}
+
+	bind_events() {
+		const me = this;
+		this.$hub_main_section
+			.on('click', '.company-link a', function(e) {
+				e.preventDefault();
+				const company_name = $(this).attr('data-company-name');
+				me.get_company_details(company_name);
+			})
+			.on('click', '.breadcrumb li', function(e) {
+				e.preventDefault();
+				const $li = $(this);
+				if ($li.attr('data-route') === 'Home') {
+					me.go_to_home_page();
+				}
+			});
+	}
+
+	update_filters() {
+		let price_sort = $(this.price_sort_select).val() || '';
+		let criteria = $(this.criteria_select).val() || '';
+
+		let order_by_params = [];
+		let query_string = '';
+		if(criteria) {
+			order_by_params.push(criteria);
+			// query_string += 'sort_by=' + criteria
+		}
+		if(price_sort) order_by_params.push(price_sort);
+		this.order_by = order_by_params.join(",");
+		// return query_string;
+	}
+
+	reset_filters() {
+		this.order_by = '';
+		$(this.category_select).val('');
+		$(this.price_sort_select).val('');
+		$(this.criteria_select).val('Most Popular');
+	}
+
+	refresh_item_only_page() {
+		this.reset_search();
+		this.update_filters();
+		this.go_to_items_only_page(
+			['hub', 'Products'],
+			'', 'product-list'
+		);
+	}
+
+	bind_title() {
+		this.page.page_title.find('.title-text').on('click', () => {
+			this.go_to_home_page();
+		});
+	}
+
+	render_body() {
+		this.$home_page = $(`
+			<div class = 'hub-home-page'>
+				<div class='banner'></div>
+				<div class='listing-body row'>
+					<div class='main-list-section'></div>
+				</div>
+			</div>
+		`).appendTo(this.$hub_main_section);
+
+		this.$banner = this.$hub_main_section.find('.banner');
+		this.$listing_body = this.$hub_main_section.find('.listing-body');
+		this.$main_list_section = this.$hub_main_section.find('.main-list-section');
+		this.$side_list_section = this.$hub_main_section.find('.side-list-section');
+	}
+
+	setup_lists() {
+		this.home_item_list = new HubList({
+			parent: this.$main_list_section,
+			title: 'New',
+			page_length: 20,
+			list_css_class: 'home-product-list',
+			method: 'erpnext.hub_node.get_items',
+			// order_by: 'request_count',
+			filters: {text: '', country: this.country}, // filters at the time of creation
+			on_item_click: (item_code) => {
+				frappe.set_route('hub', 'Products', item_code);
+			}
+		});
+
+		this.home_item_list.setup();
+	}
+
+	setup_search() {
+		this.$search.on('keypress', (e) => {
+			if(e.which === 13) {
+				var search_term = ($(this.$search).val() || '').toLowerCase();
+				this.go_to_items_only_page(
+					['hub', 'search', search_term],
+					'Search results for \''  + search_term + '\'',
+					'search-product-list',
+					{text: search_term}
+				);
+			}
+		});
+	}
+
+	go_to_items_only_page(route, title, class_name, filters = {text: ''}, by_item_codes=0) {
+		frappe.set_route(route);
+		this.$hub_main_section.empty();
+		this.filtered_item_list = new HubList({
+			parent: this.$hub_main_section,
+			title: title,
+			page_length: 20,
+			list_css_class: class_name,
+			method: 'erpnext.hub_node.get_items',
+			order_by: this.order_by,
+			filters: filters,
+			by_item_codes: by_item_codes
+		});
+		this.filtered_item_list.on_item_click = (item_code) => {
+			frappe.set_route('hub', 'Products', item_code);
+		}
+		this.filtered_item_list.setup();
+	}
+
+	go_to_item_page(item_code) {
+		if(this.item_cache) {
+			let item = this.item_cache[item_code];
+			if(item) {
+				this.render_item_page(item);
+				return;
+			}
+		} else {
+			this.item_cache = {};
+		}
+		frappe.call({
+			args:{
+				hub_sync_id: item_code
+			},
+			method: "erpnext.hub_node.get_item_details",
+			callback: (r) => {
+				let item = r.message;
+				this.item_cache[item_code] = item;
+				this.render_item_page(item);
+			}
+		});
+	}
+
+	render_item_page(item) {
+		this.$hub_main_section.empty();
+
+
+		let $item_page =
+			$(this.get_item_page(item))
+				.appendTo(this.$hub_main_section);
+
+		let $company_items = $item_page.find('.company-items');
+
+		let company_item_list = new HubList({
+			parent: $company_items,
+			title: 'More by ' + item.company_name,
+			page_length: 5,
+			list_css_class: 'company-item-list',
+			method: 'erpnext.hub_node.get_items',
+			// order_by: 'request_count',
+			filters: {text: '', company_name: item.company_name, country: this.country},
+			paginated: 0,
+			img_size: 150
+		});
+
+		company_item_list.on_item_click = (item_code) => {
+			frappe.set_route('hub', 'Products', item_code);
+		}
+		company_item_list.setup();
+
+		$item_page.find('.rfq-btn')
+			.click((e) => {
+				const $btn = $(e.target);
+
+				this.show_rfq_modal(item)
+					.then(values => {
+						item.item_code = values.item_code;
+						delete values.item_code;
+
+						const supplier = values;
+						return [item, supplier];
+					})
+					.then(([item, supplier]) => {
+						return this.make_rfq(item, supplier, $btn);
+					})
+					.then(r => {
+						console.log(r);
+						if (r.message && r.message.rfq) {
+							$btn.addClass('disabled').html(`<span><i class='fa fa-check'></i> ${__('Quote Requested')}</span>`);
+						} else {
+							throw r;
+						}
+					})
+					.catch((e) => {
+						console.log(e); //eslint-disable-line
+					});
+			});
+	}
+
+	show_rfq_modal(item) {
+		return new Promise(res => {
+			let fields = [
+				{ label: __('Item Code'), fieldtype: 'Data', fieldname: 'item_code', default: item.item_code },
+				{ fieldtype: 'Column Break' },
+				{ label: __('Item Group'), fieldtype: 'Link', fieldname: 'item_group', default: item.item_group },
+				{ label: __('Supplier Details'), fieldtype: 'Section Break' },
+				{ label: __('Supplier Name'), fieldtype: 'Data', fieldname: 'supplier_name', default: item.company_name },
+				{ label: __('Supplier Email'), fieldtype: 'Data', fieldname: 'supplier_email', default: item.seller },
+				{ fieldtype: 'Column Break' },
+				{ label: __('Supplier Type'), fieldname: 'supplier_type',
+					fieldtype: 'Link', options: 'Supplier Type' }
+			];
+			fields = fields.map(f => { f.reqd = 1; return f; });
+
+			const d = new frappe.ui.Dialog({
+				title: __('Request for Quotation'),
+				fields: fields,
+				primary_action_label: __('Send'),
+				primary_action: (values) => {
+					res(values);
+					d.hide();
+				}
+			});
+
+			d.show();
+		});
+	}
+
+	get_company_details(company_id) {
+		// get from cache if exists
+		let company_details = this.company_cache[company_id];
+		if(this.company_cache[company_id]) {
+			this.go_to_company_page(company_details);
+			return;
+		}
+		frappe.call({
+			method: 'erpnext.hub_node.get_company_details',
+			args: {company_id: company_id}
+		}).then((r) => {
+			if (r.message) {
+				const company_details = r.message.company_details;
+				this.company_cache[company_id] = company_details;
+				this.go_to_company_page(company_details)
+			}
+		});
+	}
+
+	go_to_company_page(company_details) {
+		frappe.set_route('hub', 'Company', company_details.company_name);
+		this.$hub_main_section.empty();
+
+		let $company_page =
+			$(this.get_company_page(company_details))
+				.appendTo(this.$hub_main_section);
+
+		let $company_items = $company_page.find('.company-items');
+
+		let company_item_list = new HubList({
+			parent: $company_items,
+			title: 'More by ' + company_details.company_name,
+			page_length: 5,
+			list_css_class: 'company-item-list',
+			method: 'erpnext.hub_node.get_items',
+			// order_by: 'request_count',
+			filters: {text: '', company: company_details.company_name, country: this.country},
+			paginated: 0,
+			img_size: 150
+		});
+
+		company_item_list.on_item_click = (item_code) => {
+			frappe.set_route('hub', 'Products', item_code);
+		}
+		company_item_list.setup();
+	}
+
+	get_item_page(item) {
+		return `
+			<div class="hub-item-page">
+				<div class="item-header">
+					<div class="item-page-image">
+						${ this.home_item_list.get_item_image(item) }
+					</div>
+					<div class="title-content">
+						<div class="breadcrumbs">
+							${this.get_breadcrumb(item.item_name, "Products") }
+						</div>
+						<div class="title">
+							<h2>${ item.item_name }</h2>
+						</div>
+						<div class="company">
+							<span class="">${ item.company_name }</span>
+						</div>
+						<div class="category">
+							<span class="text-muted">Products</span>
+						</div>
+						<div class="description">
+							<span class="small">${ item.description ? item.description : "" }</span>
+						</div>
+						<div class="price">
+							${ item.formatted_price ? item.formatted_price : '' }
+						</div>
+						<div class="actions">
+							<a class="btn btn-primary rfq-btn">Request A Quote</a>
+						</div>
+					</div>
+
+				</div>
+				<div class="item-more-info"></div>
+				<div class="company-items">
+
+				</div>
+			</div>
+		`;
+	}
+
+	get_company_page(company_details) {
+		return `
+			<div class="hub-item-page">
+				<div class="item-header">
+					<div class="title-content">
+						<div class="breadcrumbs">
+							${this.get_breadcrumb(company_details.company_name, "Company") }
+						</div>
+						<div class="title">
+							<h2>${ company_details.company_name }</h2>
+						</div>
+						<div class="company">
+							<span class="">${ company_details.seller_city }</span>
+						</div>
+						<div class="description">
+							<span class="small">${ company_details.seller_description }</span>
+						</div>
+					</div>
+
+				</div>
+				<div class="item-more-info"></div>
+				<div class="company-items">
+
+				</div>
+			</div>
+		`;
+	}
+
+	get_breadcrumb(name, type) {
+		return `
+			<ul class="breadcrumb">
+				<li data-route="Home">
+					<a href><span>Home</span></a>
+				</li>
+				<li data-route="List">
+					<a href><span>${type}</span></a>
+				</li>
+				<li class="active">
+					<span>${name}</span>
+				</li>
+			</ul>
+		`;
+	}
+
+	go_to_home_page() {
+		frappe.set_route('hub');
+		this.reset_filters();
+		this.refresh();
+	}
+
+	setup_menu() {
+		this.page.add_menu_item(__('Hub Settings'),
+			() => frappe.set_route('Form', 'Hub Settings'));
+
+		this.page.add_menu_item(__('Refresh'), () => this.refresh());
+
+		this.page.add_menu_item(__('Sync'), () => this.sync_items_to_hub());
+	}
+
+	sync_items_to_hub() {
+		frappe.call('erpnext.hub_node.doctype.hub_settings.hub_settings.sync')
+	}
+
+	setup_sidebar() {
+		var me = this;
+		this.sidebar = new HubSidebar({
+			wrapper: this.page.wrapper.find('.layout-side-section')
+		});
+
+		this.add_account_to_sidebar();
+
+	}
+
+	add_account_to_sidebar() {
+		this.sidebar.add_item({
+			label: this.hub_settings.company,
+			on_click: () => frappe.set_route('Form', 'Company', this.hub_settings.company)
+		}, __("Account"));
+
+		this.sidebar.add_item({
+			label: __("Requested Products"),
+			on_click: () => this.go_to_seen_items()
+		}, __("Account"));
+	}
+
+	get_search_term() {
+		return this.$search.val();
+	}
+
+	reset_search() {
+		this.$search.val('');
+	}
+
+	make_rfq(item, supplier, btn) {
+		console.log(supplier);
+		return new Promise((resolve, reject) => {
+			frappe.call({
+				method: 'erpnext.hub_node.make_rfq_and_send_opportunity',
+				args: { item, supplier },
+				callback: resolve,
+				btn,
+			}).fail(reject);
+		});
+	}
+
+	go_to_seen_items() {
+		this.go_to_items_only_page(
+			['hub', 'Requested Products'],
+			__('Requested Products'),
+			'requested-product-list',
+			{}, 1
+		);
+	}
+}
+
+class HubList {
+	constructor({
+		parent = null,
+		title = 'Products',
+		page_length = 20,
+		list_css_class = '',
+		method = 'erpnext.hub_node.get_items',
+		filters = {text: ''},
+		order_by = '',
+		by_item_codes = 0,
+		paginated = 1,
+		on_item_click = null,
+		img_size = 200
+	}) {
+		this.parent = parent;
+		this.title = title;
+		this.page_length = page_length;
+		this.list_css_class = list_css_class;
+		this.method = method;
+		this.filters = filters;
+		this.order_by = order_by;
+		this.by_item_codes = by_item_codes;
+		this.paginated = paginated;
+
+		this.on_item_click = on_item_click;
+		this.img_size = img_size;
+	}
+
+	// to be called on demand
+	setup() {
+		this.container = $(`
+			<div class='item-list-container ${this.list_css_class}' data-page-length='${this.page_length}'>
+				<div class='item-list-header'>
+					<h3>${this.title}</h3>
+				</div>
+				<div class='item-list'></div>
+				<div class='list-state'>
+					<div class='loading'>
+						<p class='text-muted text-center'>${__('Loading...')}</p>
+					</div>
+					<div class='done hide'>
+						<p class='text-muted text-center'>${__('No more results')}</p>
+					</div>
+					<div class='more text-right'>
+						<button class='btn btn-default btn-sm'>${__('More')}</div>
+					</div>
+				</div>
+			</div>`)
+			.appendTo(this.parent);
+
+		this.$item_list_title = this.container.find('.item-list-header h3');
+		this.$list = this.container.find('.item-list');
+		this.$loading = this.container.find('.loading').hide();
+		this.$more = this.container.find('.more').hide();
+		this.$done = this.container.find('.done');
+
+		this.$more.on('click', () => {
+			this.next_page();
+		});
+
+		this.next_page();
+	}
+
+	refresh(filters = this.filters) {
+		this.reset();
+		this.set_filters(filters);
+		this.next_page();
+	}
+
+	reset() {
+		this.$list.empty();
+	}
+
+	set_filters(filters) {
+		this.filters = filters;
+	}
+
+	next_page() {
+		this.$item_list_title.html(this.title);
+		const start = this.$list.find('.hub-item-wrapper').length;
+		this.$loading.show();
+
+		// build args
+		let args = {
+			start: start,
+			// query one extra
+			limit: this.page_length + 1
+		};
+		Object.assign(args, this.filters);
+		console.log("filters: ", args);
+		args.order_by = this.order_by;
+		args.by_item_codes = this.by_item_codes;
+
+		frappe.call({
+			method: this.method,
+			args: args,
+			callback: (r) => {
+				let items = r.message;
+				console.log("items: ", items);
+				this.render_items(items);
+			}
+		});
+	}
+
+	render_items(items) {
+		if(items) {
+			let done = 0;
+			console.log("items length", items.length);
+			if(items.length && items.length > this.page_length) {
+				// remove the extra queried
+				items.pop();
+			} else {
+				done = 1;
+			}
+			items.forEach((item) => {
+				this.make_item_card(item).appendTo(this.$list);
+			});
+			console.log(done);
+			this.update_list_state(done);
+		} else {
+			this.$item_list_title.html('No results found');
+		}
+	}
+
+	update_list_state(done=0) {
+		this.$loading.hide();
+		if(done) {
+			this.$done.removeClass('hide');
+			this.$more.hide();
+		} else {
+			this.$more.show();
+			this.$done.addClass('hide');
+		}
+	}
+
+	make_item_card(item) {
+		let $item_card = $(`
+			<div class="hub-item-wrapper" style="max-width: ${this.img_size}px;">
+				<a class="item-link" href>
+					<div class="hub-item-image">
+						${ this.get_item_image(item) }
+					</div>
+					<div class="hub-item-title">
+						<h5 class="bold">
+							${!item.seen ? item.item_name : `<span class="indicator blue">${item.item_name}</span>`}
+						<h5>
+					</div>
+				</a>
+				<div class="company-link">
+					<a data-company-name="${ item.company_id }" class="">${ item.company_name }</a>
+				</div>
+				<div>${ item.formatted_price ? item.formatted_price : ''}</div>
+			</div>
+		`);
+
+		$item_card.find(".item-link").click((e) => {
+			e.preventDefault();
+			this.on_item_click && this.on_item_click(item.name);
+		});
+
+		return $item_card;
+	}
+
+	get_item_image(item, size=this.img_size) {
+		const _size = size + 'px';
+		const item_image = item.image ?
+			`<img src="${item.image}"><span class="helper"></span>` :
+			`<div class="standard-image">${item.item_name[0]}</div>`;
+
+		return `
+			<div class="img-wrapper"
+				style="max-width: ${_size}; width: ${_size}; height: ${_size};">
+				${item_image}
+			</div>`;
+	}
+}
+
+class HubSidebar {
+	constructor({ wrapper }) {
+		this.wrapper = wrapper;
+		this.make_dom();
+	}
+
+	make_dom() {
+		this.wrapper.html(`
+			<div class="hub-sidebar overlay-sidebar hidden-xs hidden-sm">
+			</div>
+		`);
+
+		this.$sidebar = this.wrapper.find('.hub-sidebar');
+	}
+
+	add_item(item, section) {
+		let $section;
+		if(!section && this.wrapper.find('.sidebar-menu').length === 0) {
+			// if no section, add section with no heading
+			$section = this.get_section();
+		} else {
+			$section = this.get_section(section);
+		}
+
+		const $li_item = $(`
+			<li><a ${item.href ? `href="${item.href}"` : ''}>${item.label}</a></li>
+		`).click(
+			() => item.on_click && item.on_click()
+		);
+
+		$section.append($li_item);
+	}
+
+	get_section(section_heading="") {
+		let $section = $(this.wrapper.find(
+			`[data-section-heading="${section_heading}"]`));
+		if($section.length) {
+			return $section;
+		}
+
+		const $section_heading = section_heading ?
+			`<li class="h6">${section_heading}</li>` : '';
+
+		$section = $(`
+			<ul class="list-unstyled sidebar-menu" data-section-heading="${section_heading || 'default'}">
+				${$section_heading}
+			</ul>
+		`);
+
+		this.$sidebar.append($section);
+		return $section;
+	}
+}
\ No newline at end of file
diff --git a/erpnext/hub_node/page/hub/hub_body.html b/erpnext/hub_node/page/hub/hub_body.html
deleted file mode 100644
index e415f7e..0000000
--- a/erpnext/hub_node/page/hub/hub_body.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<div class="padding">
-    <div class="row">
-        <div class="col-md-4 col-md-offset-4">
-            <input class="form-control" name="search" placeholder="{%= __("Search") %}">
-        </div>
-    </div>
-    <hr style="margin: 15px -15px">
-    <div class="hub-list">
-
-    </div>
-    <div class="loading">
-        <p class="text-muted text-center">{%= __("Loading...") %}</p>
-    </div>
-    <div class="more text-center hide">
-        <button class="btn btn-default btn-sm">{%= __("More") %}</div>
-    </div>
-    <div class="done text-center text-extra-muted hide">
-        <p>{%= __("No more results.") %}</p>
-    </div>
-</div>
diff --git a/erpnext/hub_node/page/hub/hub_list.html b/erpnext/hub_node/page/hub/hub_list.html
deleted file mode 100644
index 036ef2b..0000000
--- a/erpnext/hub_node/page/hub/hub_list.html
+++ /dev/null
@@ -1,16 +0,0 @@
-{% for(var i=0, l=items.length; i < l; i++) { %}
-<div class="list-item">
-    <div class="row">
-        <div class="col-sm-6">
-            <h6>{%= items[i].item_name %}<h6>
-        </div>
-        <div class="col-sm-3">
-            <h6>{%= items[i].seller_name %}<h6>
-        </div>
-        <div class="col-sm-3 text-right">
-            <h6 class="text-muted">{%= items[i].seller_country %}<h6>
-        </div>
-    </div>
-    <p class="text-muted small">{%= items[i].description %}</p>
-</div>
-{% } %}
diff --git a/erpnext/hub_node/page/hub/register_in_hub.html b/erpnext/hub_node/page/hub/register_in_hub.html
deleted file mode 100644
index 96b1fb3..0000000
--- a/erpnext/hub_node/page/hub/register_in_hub.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<div style="padding: 70px 0px;">
-    <h2 class="text-center">{%= __("Register For ERPNext Hub") %}</h2>
-    <br>
-    <div class="row">
-        <div class="col-md-6 col-md-offset-3">
-            <ul>
-                <li>Free listing of your products</li>
-                <li>Let other ERPNext users discover your products</li>
-                <li>Discover products quickly</li>
-                <li>Automate workflow with Supplier from within ERPNext (later)</li>
-            </ul>
-        </div>
-    </div>
-    <br>
-    <div class="text-center">
-        <a class="btn btn-primary" href="#Form/Hub Settings">
-            Hub Settings</a>
-    </div>
-</div>