Merge pull request #12932 from achillesrasquinha/py3-basestring

Py3 basestring
diff --git a/erpnext/hub_node/__init__.py b/erpnext/hub_node/__init__.py
index ea1693d..b2a98b4 100644
--- a/erpnext/hub_node/__init__.py
+++ b/erpnext/hub_node/__init__.py
@@ -31,25 +31,29 @@
 	return meta
 
 @frappe.whitelist()
-def get_categories():
+def get_categories(parent='All Categories'):
 	# get categories info with parent category and stuff
 	connection = get_client_connection()
-	response = connection.get_list('Hub Category')
+	categories = connection.get_list('Hub Category', filters={'parent_hub_category': parent})
+
+	response = [{'value': c.get('name'), 'expandable': c.get('is_group')} for c in categories]
 	return response
 
 @frappe.whitelist()
-def get_item_details(hub_sync_id=None):
+def update_category(item_name, category):
+	connection = get_hub_connection()
+	response = connection.update('Hub Item', dict(
+		hub_category = category
+	), item_name)
+	return response.ok
+
+@frappe.whitelist()
+def get_details(hub_sync_id=None, doctype='Hub Item'):
 	if not hub_sync_id:
 		return
 	connection = get_client_connection()
-	item_details = connection.get_doc('Hub Item', hub_sync_id)
-	print(item_details)
-	return item_details
-
-@frappe.whitelist()
-def get_company_details(hub_sync_id):
-	connection = get_client_connection()
-	return connection.get_doc('Hub Company', hub_sync_id)
+	details = connection.get_doc(doctype, hub_sync_id)
+	return details
 
 def get_client_connection():
 	# frappeclient connection
diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js
index bd3a03d..68bb2b8 100644
--- a/erpnext/public/js/controllers/buying.js
+++ b/erpnext/public/js/controllers/buying.js
@@ -254,10 +254,10 @@
 							cur_frm.doc.items[i].qty = my_qty;
 							
 							frappe.msgprint(__("Assigning {0} to {1} (row {2})", 
-								[d.mr_name, d.item_code, cur_frm.doc.items[i].idx]);
+								[d.mr_name, d.item_code, cur_frm.doc.items[i].idx]));
 							
 							if (qty > 0) {
-								frappe.msgprint(__("Splitting {0} units of {1}", [qty, d.item_code]);
+								frappe.msgprint(__("Splitting {0} units of {1}", [qty, d.item_code]));
 								var newrow = frappe.model.add_child(cur_frm.doc, cur_frm.doc.items[i].doctype, "items");
 								item_length++;
 
diff --git a/erpnext/public/js/hub/hub_factory.js b/erpnext/public/js/hub/hub_factory.js
index 6789b80..1578e4d 100644
--- a/erpnext/public/js/hub/hub_factory.js
+++ b/erpnext/public/js/hub/hub_factory.js
@@ -15,37 +15,33 @@
 				'/assets/erpnext/css/hub.css',
 			]
 		};
+		frappe.model.with_doc('Hub Settings', 'Hub Settings', () => {
+			this.hub_settings = frappe.get_doc('Hub Settings');
 
-		if (!erpnext.hub.pages[page_name]) {
-			if (page === 'Item' && !route[2]) {
-				frappe.require(assets['List'], () => {
-					erpnext.hub.pages[page_name] = new erpnext.hub.ItemListing({
-						doctype: 'Hub Settings',
-						parent: this.make_page(true, page_name)
+			if (!erpnext.hub.pages[page_name]) {
+				if (!route[2]) {
+					frappe.require(assets['List'], () => {
+						erpnext.hub.pages[page_name] = new erpnext.hub[page+'Listing']({
+							parent: this.make_page(true, page_name),
+							hub_settings: this.hub_settings
+						});
+						window.hub_page = erpnext.hub.pages[page_name];
 					});
-					window.hub_page = erpnext.hub.pages[page_name];
-				});
-			} if (page === 'Company' && !route[2]) {
-				frappe.require(assets['List'], () => {
-					erpnext.hub.pages[page_name] = new erpnext.hub.CompanyListing({
-						doctype: 'Hub Settings',
-						parent: this.make_page(true, page_name)
+				} else {
+					frappe.require(assets['Form'], () => {
+						erpnext.hub.pages[page_name] = new erpnext.hub[page+'Page']({
+							unique_id: route[2],
+							doctype: route[2],
+							parent: this.make_page(true, page_name),
+							hub_settings: this.hub_settings
+						});
+						window.hub_page = erpnext.hub.pages[page_name];
 					});
-					window.hub_page = erpnext.hub.pages[page_name];
-				});
-			} else if(route[2]) {
-				frappe.require(assets['Form'], () => {
-					erpnext.hub.pages[page_name] = new erpnext.hub.HubForm({
-						hub_item_code: route[2],
-						doctype: 'Hub Settings',
-						parent: this.make_page(true, page_name)
-					});
-					window.hub_page = erpnext.hub.pages[page_name];
-				});
+				}
+			} else {
+				frappe.container.change_to(page_name);
+				window.hub_page = erpnext.hub.pages[page_name];
 			}
-		} else {
-			frappe.container.change_to(page_name);
-			window.hub_page = erpnext.hub.pages[page_name];
-		}
+		});
 	}
 });
diff --git a/erpnext/public/js/hub/hub_form.js b/erpnext/public/js/hub/hub_form.js
index 208af41..130a0db 100644
--- a/erpnext/public/js/hub/hub_form.js
+++ b/erpnext/public/js/hub/hub_form.js
@@ -3,18 +3,15 @@
 erpnext.hub.HubForm = class HubForm extends frappe.views.BaseList {
 	setup_defaults() {
 		super.setup_defaults();
-		this.page_title = this.data.item_name || this.hub_item_code || __('Hub Item');
-		this.method = 'erpnext.hub_node.get_item_details';
-	}
-
-	setup_fields() {
-		this.fields = ['hub_item_code', 'item_name', 'item_code', 'description', 'seller', 'company_name', 'country'];
+		this.method = 'erpnext.hub_node.get_details';
+		const route = frappe.get_route();
+		this.page_name = route[2];
 	}
 
 	set_breadcrumbs() {
 		frappe.breadcrumbs.add({
 			label: __('Hub'),
-			route: '#Hub/Item',
+			route: '#Hub/' + this.doctype,
 			type: 'Custom'
 		});
 	}
@@ -26,17 +23,14 @@
 		});
 	}
 
-	setup_filter_area() {
+	setup_filter_area() { }
 
-	}
-
-	setup_sort_selector() {
-
-	}
+	setup_sort_selector() { }
 
 	get_args() {
 		return {
-			hub_sync_id: this.hub_item_code
+			hub_sync_id: this.unique_id,
+			doctype: 'Hub ' + this.doctype
 		};
 	}
 
@@ -49,19 +43,16 @@
 	}
 
 	render() {
+		const image_html = this.data[this.image_field_name] ?
+			`<img src="${this.data[this.image_field_name]}">
+			<span class="helper"></span>` :
+			`<div class="standard-image">${frappe.get_abbr(this.page_title)}</div>`;
+
 		this.sidebar.add_item({
-			label: `<img src="${this.data.image}" />`
+			label: image_html
 		});
 
-		let fields = [];
-		this.fields.map(fieldname => {
-			fields.push({
-				label: toTitle(frappe.model.unscrub(fieldname)),
-				fieldname,
-				fieldtype: 'Data',
-				read_only: 1
-			});
-		});
+		let fields = this.get_field_configs();
 
 		this.form = new frappe.ui.FieldGroup({
 			parent: this.$result,
@@ -73,7 +64,7 @@
 	}
 
 	toggle_result_area() {
-		this.$result.toggle(this.data.hub_item_code);
+		this.$result.toggle(this.unique_id);
 		this.$paging_area.toggle(this.data.length > 0);
 		this.$no_result.toggle(this.data.length == 0);
 
@@ -82,3 +73,83 @@
 			.toggle(show_more);
 	}
 };
+
+erpnext.hub.ItemPage = class ItemPage extends erpnext.hub.HubForm{
+	setup_defaults() {
+		super.setup_defaults();
+		this.doctype = 'Item';
+		this.image_field_name = 'image';
+	}
+
+	get_field_configs() {
+		let fields = [];
+		this.fields.map(fieldname => {
+			fields.push({
+				label: toTitle(frappe.model.unscrub(fieldname)),
+				fieldname,
+				fieldtype: 'Data',
+				read_only: 1
+			});
+		});
+
+		let category_field = {
+			label: 'Hub Category',
+			fieldname: 'hub_category',
+			fieldtype: 'Data'
+		}
+
+		if(this.data.company_name === this.hub_settings.company) {
+			this.page.set_primary_action(__('Update'), () => {
+				this.update_on_hub();
+			}, 'octicon octicon-plus');
+		} else {
+			category_field.read_only = 1;
+		}
+
+		fields.unshift(category_field);
+
+		return fields;
+	}
+
+	update_on_hub() {
+		return new Promise((resolve, reject) => {
+			frappe.call({
+				method: 'erpnext.hub_node.update_category',
+				args: { item: this.unique_id, category: this.form.get_value('hub_category') },
+				callback: resolve,
+				freeze: true
+			}).fail(reject);
+		});
+	}
+
+	setup_fields() {
+		this.fields = ['hub_item_code', 'item_name', 'item_code', 'description',
+			'seller', 'company_name', 'country'];
+	}
+}
+
+erpnext.hub.CompanyPage = class CompanyPage extends erpnext.hub.HubForm{
+	setup_defaults() {
+		super.setup_defaults();
+		this.doctype = 'Company';
+		this.image_field_name = 'company_logo';
+	}
+
+	get_field_configs() {
+		let fields = [];
+		this.fields.map(fieldname => {
+			fields.push({
+				label: toTitle(frappe.model.unscrub(fieldname)),
+				fieldname,
+				fieldtype: 'Data',
+				read_only: 1
+			});
+		});
+
+		return fields;
+	}
+
+	setup_fields() {
+		this.fields = ['company_name', 'description', 'route', 'country', 'seller', 'site_name'];
+	}
+}
diff --git a/erpnext/public/js/hub/hub_page.js b/erpnext/public/js/hub/hub_page.js
index 6e5ab98..27986de 100644
--- a/erpnext/public/js/hub/hub_page.js
+++ b/erpnext/public/js/hub/hub_page.js
@@ -13,21 +13,24 @@
 	setup_fields() {
 		return this.get_meta()
 			.then(r => {
-				console.log('fields then', this.doctype);
 				this.meta = r.message || this.meta;
 				frappe.model.sync(this.meta);
 			});
 	}
 
 	get_meta() {
-		console.log('get_meta', this.doctype);
 		return new Promise(resolve =>
 			frappe.call('erpnext.hub_node.get_meta', {doctype: this.doctype}, resolve));
 	}
 
 	set_breadcrumbs() { }
 
-	setup_side_bar() { }
+	setup_side_bar() {
+		this.sidebar = new frappe.ui.Sidebar({
+			wrapper: this.page.wrapper.find('.layout-side-section'),
+			css_class: 'hub-sidebar'
+		});
+	}
 
 	setup_sort_selector() { }
 
@@ -46,7 +49,6 @@
 
 	update_data(r) {
 		const data = r.message;
-		console.log('update data', data);
 
 		if (this.start === 0) {
 			this.data = data;
@@ -74,7 +76,6 @@
 
 	render_image_view() {
 		let data = this.data;
-		// console.log('this.data render', this.data);
 		if (this.start === 0) {
 			this.$result.html('<div class="image-view-container small padding-top">');
 			data = this.data.slice(this.start);
@@ -108,6 +109,41 @@
 		];
 	}
 
+	setup_side_bar() {
+		super.setup_side_bar();
+		this.category_tree = new frappe.ui.Tree({
+			parent: this.sidebar.$sidebar,
+			label: 'All Categories',
+			expandable: true,
+
+			args: {parent: this.current_category},
+			method: 'erpnext.hub_node.get_categories',
+			on_click: (node) => {
+				this.update_category(node.label);
+			}
+		});
+
+		this.sidebar.add_item({
+			label: __('Companies'),
+			on_click: () => frappe.set_route('Hub', 'Company')
+		});
+
+		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: __("My Orders"),
+			on_click: () => frappe.set_route('List', 'Request for Quotation')
+		}, __("Account"));
+	}
+
+	update_category(label) {
+		this.current_category = (label=='All Categories') ? undefined : label;
+		this.refresh();
+	}
+
 	get_filters_for_args() {
 		let filters = {};
 		this.filter_area.get().forEach(f => {
@@ -124,7 +160,6 @@
 		item._name = encodeURI(item.name);
 		const encoded_name = item._name;
 		const title = strip_html(item['item_name' || 'item_code']);
-		// console.log(item);
 		const company_name = item['company_name'];
 
 		const route = `#Hub/Item/${item.hub_item_code}`;
@@ -139,16 +174,17 @@
 				<a href="${route}">
 					<div class="hub-item-image">
 						<div class="img-wrapper" style="height: 200px; width: 200px">
-							${image_html}
+							${ image_html }
 						</div>
 					</div>
 					<div class="hub-item-title">
 						<h5 class="bold">
 							${ title }
 						</h5>
-						<p>${ company_name }</p>
+
 					</div>
 				</a>
+				<a href="${'#Hub/Company/'+company_name}"><p>${ company_name }</p></a>
 			</div>
 		`;
 	}
@@ -158,16 +194,10 @@
 	setup_defaults() {
 		super.setup_defaults();
 		this.doctype = 'Hub Company';
-		this.fields = ['name', 'site_name', 'seller_city', 'seller_description', 'seller', 'country', 'company_name'];
+		this.fields = ['company_logo', 'name', 'site_name', 'seller_city', 'seller_description', 'seller', 'country', 'company_name'];
 		this.filters = [];
 		this.custom_filter_configs = [
 			{
-				fieldtype: 'Data',
-				label: 'Company',
-				condition: 'like',
-				fieldname: 'company_name',
-			},
-			{
 				fieldtype: 'Link',
 				label: 'Country',
 				options: 'Country',
@@ -186,33 +216,26 @@
 		return filters;
 	}
 
-	card_html(item) {
-		item._name = encodeURI(item.name);
-		const encoded_name = item._name;
-		const title = strip_html(item['item_name' || 'item_code']);
-		// console.log(item);
-		const company_name = item['company_name'];
+	card_html(company) {
+		company._name = encodeURI(company.name);
+		const route = `#Hub/Company/${company.company_name}`;
 
-		const route = `#Hub/Item/${item.hub_item_code}`;
-
-		const image_html = item.image ?
-			`<img src="${item.image}">
-			<span class="helper"></span>` :
-			`<div class="standard-image">${frappe.get_abbr(title)}</div>`;
+		let image_html = company.company_logo ?
+			`<img src="${company.company_logo}"><span class="helper"></span>` :
+			`<div class="standard-image">${frappe.get_abbr(company.company_name)}</div>`;
 
 		return `
 			<div class="hub-item-wrapper margin-bottom" style="width: 200px;">
 				<a href="${route}">
 					<div class="hub-item-image">
 						<div class="img-wrapper" style="height: 200px; width: 200px">
-							${image_html}
+							${ image_html }
 						</div>
 					</div>
 					<div class="hub-item-title">
 						<h5 class="bold">
-							${ title }
+							${ company.company_name }
 						</h5>
-						<p>${ company_name }</p>
 					</div>
 				</a>
 			</div>