Merge branch 'develop'
diff --git a/erpnext/__version__.py b/erpnext/__version__.py
index 1752aca..9a900fe 100644
--- a/erpnext/__version__.py
+++ b/erpnext/__version__.py
@@ -1,2 +1,2 @@
 from __future__ import unicode_literals
-__version__ = '6.6.4'
+__version__ = '6.6.5'
diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py
index c3e4c39..8544b17 100644
--- a/erpnext/accounts/doctype/account/account.py
+++ b/erpnext/accounts/doctype/account/account.py
@@ -147,6 +147,8 @@
 					self.validate_warehouse(old_warehouse)
 				if self.warehouse:
 					self.validate_warehouse(self.warehouse)
+		elif self.warehouse:
+			self.warehouse = None
 
 	def validate_warehouse(self, warehouse):
 		if frappe.db.get_value("Stock Ledger Entry", {"warehouse": warehouse}):
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index 9525a3a..0826521 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -498,14 +498,17 @@
 	if voucher_type=="Bank Entry":
 		account = frappe.db.get_value("Company", company, "default_bank_account")
 		if not account:
-			account = frappe.db.get_value("Account", {"company": company, "account_type": "Bank", "is_group": 0})
+			account = frappe.db.get_value("Account", 
+				{"company": company, "account_type": "Bank", "is_group": 0})
 	elif voucher_type=="Cash Entry":
 		account = frappe.db.get_value("Company", company, "default_cash_account")
 		if not account:
-			account = frappe.db.get_value("Account", {"company": company, "account_type": "Cash", "is_group": 0})
+			account = frappe.db.get_value("Account", 
+				{"company": company, "account_type": "Cash", "is_group": 0})
 
 	if account:
-		account_details = frappe.db.get_value("Account", account, ["account_currency", "account_type"], as_dict=1)
+		account_details = frappe.db.get_value("Account", account, 
+			["account_currency", "account_type"], as_dict=1)
 		return {
 			"account": account,
 			"balance": get_balance_on(account),
@@ -814,11 +817,19 @@
 	return grid_values
 
 @frappe.whitelist()
-def get_exchange_rate(account, account_currency, company,
+def get_exchange_rate(account, account_currency=None, company=None,
 		reference_type=None, reference_name=None, debit=None, credit=None, exchange_rate=None):
 	from erpnext.setup.utils import get_exchange_rate
+	account_details = frappe.db.get_value("Account", account, 
+		["account_type", "root_type", "account_currency", "company"], as_dict=1)
+	
+	if not company:
+		company = account_details.company
+		
+	if not account_currency:
+		account_currency = account_details.account_currency
+		
 	company_currency = get_company_currency(company)
-	account_details = frappe.db.get_value("Account", account, ["account_type", "root_type"], as_dict=1)
 
 	if account_currency != company_currency:
 		if reference_type in ("Sales Invoice", "Purchase Invoice") and reference_name:
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 9d620c2..95e5a1c 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -160,6 +160,9 @@
 							me.set_dynamic_labels();
 							me.calculate_taxes_and_totals();
 							if(callback_fn) callback_fn();
+							frappe.after_ajax(function() {
+								cur_frm.doc.__missing_values_set = false;
+							})
 						}
 					}
 				});
diff --git a/erpnext/accounts/doctype/tax_rule/tax_rule.py b/erpnext/accounts/doctype/tax_rule/tax_rule.py
index bff1898..7b62082 100644
--- a/erpnext/accounts/doctype/tax_rule/tax_rule.py
+++ b/erpnext/accounts/doctype/tax_rule/tax_rule.py
@@ -109,7 +109,8 @@
 def get_tax_template(posting_date, args):
 	"""Get matching tax rule"""
 	args = frappe._dict(args)
-	conditions = []
+	conditions = ["""(from_date is null  or from_date = '' or from_date <= '{0}') 
+		and (to_date is null  or to_date = '' or to_date >= '{0}')""".format(posting_date)]
 
 	for key, value in args.iteritems():
 		if key in "use_for_shopping_cart":
@@ -117,16 +118,16 @@
 		else:
 			conditions.append("ifnull({0}, '') in ('', '{1}')".format(key, frappe.db.escape(cstr(value))))
 
-	matching = frappe.db.sql("""select * from `tabTax Rule`
+	tax_rule = frappe.db.sql("""select * from `tabTax Rule`
 		where {0}""".format(" and ".join(conditions)), as_dict = True)
 
-	if not matching:
+	if not tax_rule:
 		return None
 
-	for rule in matching:
+	for rule in tax_rule:
 		rule.no_of_keys_matched = 0
 		for key in args:
 			if rule.get(key): rule.no_of_keys_matched += 1
 
-	rule = sorted(matching, lambda b, a: cmp(a.no_of_keys_matched, b.no_of_keys_matched) or cmp(a.priority, b.priority))[0]
+	rule = sorted(tax_rule, lambda b, a: cmp(a.no_of_keys_matched, b.no_of_keys_matched) or cmp(a.priority, b.priority))[0]
 	return rule.sales_tax_template or rule.purchase_tax_template
diff --git a/erpnext/accounts/page/accounts_browser/accounts_browser.js b/erpnext/accounts/page/accounts_browser/accounts_browser.js
index abd7612..b172ae0 100644
--- a/erpnext/accounts/page/accounts_browser/accounts_browser.js
+++ b/erpnext/accounts/page/accounts_browser/accounts_browser.js
@@ -209,13 +209,12 @@
 				{fieldtype:'Check', fieldname:'is_group', label:__('Is Group'),
 					description: __('Further accounts can be made under Groups, but entries can be made against non-Groups')},
 				{fieldtype:'Select', fieldname:'account_type', label:__('Account Type'),
-					options: ['', 'Bank', 'Cash', 'Warehouse', 'Receivable', 'Payable',
-						'Equity', 'Cost of Goods Sold', 'Fixed Asset', 'Expense Account',
-						'Income Account', 'Tax', 'Chargeable', 'Temporary'].join('\n'),
+					options: ['', 'Bank', 'Cash', 'Warehouse', 'Tax', 'Chargeable'].join('\n'),
 					description: __("Optional. This setting will be used to filter in various transactions.") },
 				{fieldtype:'Float', fieldname:'tax_rate', label:__('Tax Rate')},
 				{fieldtype:'Link', fieldname:'warehouse', label:__('Warehouse'), options:"Warehouse"},
-				{fieldtype:'Link', fieldname:'account_currency', label:__('Currency'), options:"Currency"}
+				{fieldtype:'Link', fieldname:'account_currency', label:__('Currency'), options:"Currency", 
+					description: __("Optional. Sets company's default currency, if not specified.")}
 			]
 		})
 
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 5eacd95..0d29e96 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -29,7 +29,7 @@
 """
 app_icon = "icon-th"
 app_color = "#e74c3c"
-app_version = "6.6.4"
+app_version = "6.6.5"
 github_link = "https://github.com/frappe/erpnext"
 
 error_report_email = "support@erpnext.com"
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.js b/erpnext/hr/doctype/expense_claim/expense_claim.js
index 1d405da..780cd70 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.js
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.js
@@ -18,24 +18,25 @@
 				jv.voucher_type = 'Bank Entry';
 				jv.company = cur_frm.doc.company;
 				jv.remark = 'Payment against Expense Claim: ' + cur_frm.doc.name;
-				jv.fiscal_year = cur_frm.doc.fiscal_year;
 				var expense = cur_frm.doc.expenses || [];
 				for(var i = 0; i < expense.length; i++){
 					var d1 = frappe.model.add_child(jv, 'Journal Entry Account', 'accounts');
-					d1.debit = expense[i].sanctioned_amount;
 					d1.account = expense[i].default_account;
+					d1.debit_in_account_currency = expense[i].sanctioned_amount;
 					d1.reference_type = cur_frm.doc.doctype;
 					d1.reference_name = cur_frm.doc.name;
 				}
 
 				// credit to bank
 				var d1 = frappe.model.add_child(jv, 'Journal Entry Account', 'accounts');
-				d1.credit = cur_frm.doc.total_sanctioned_amount;
+				d1.credit_in_account_currency = cur_frm.doc.total_sanctioned_amount;
 				d1.reference_type = cur_frm.doc.doctype;
 				d1.reference_name = cur_frm.doc.name;
 				if(r.message) {
 					d1.account = r.message.account;
 					d1.balance = r.message.balance;
+					d1.account_currency = r.message.account_currency;
+					d1.account_type = r.message.account_type;
 				}
 
 				loaddoc('Journal Entry', jv.name);
diff --git a/erpnext/public/js/utils/party.js b/erpnext/public/js/utils/party.js
index 9173b71..427cd89 100644
--- a/erpnext/public/js/utils/party.js
+++ b/erpnext/public/js/utils/party.js
@@ -22,11 +22,16 @@
 		}
 		
 		if (args) {
-			args.posting_date = frm.doc.transaction_date;
+			args.posting_date = frm.doc.posting_date || frm.doc.transaction_date;
 		}
 	}
 	if(!args) return;
-
+	
+	if(frappe.meta.get_docfield(frm.doc.doctype, "taxes")) {
+		if(!erpnext.utils.validate_mandatory(frm, "Posting/Transaction Date", 
+			args.posting_date, args.party_type=="Customer" ? "customer": "supplier")) return;
+	}
+	
 	args.currency = frm.doc.currency;
 	args.company = frm.doc.company;
 	args.doctype = frm.doc.doctype;
@@ -64,6 +69,15 @@
 				if(r.message){
 					frm.set_value(display_field, r.message)
 				}
+				
+				if(frappe.meta.get_docfield(frm.doc.doctype, "taxes")) {
+					if(!erpnext.utils.validate_mandatory(frm, "Customer/Supplier", 
+						frm.doc.customer || frm.doc.supplier, address_field)) return;
+	
+					if(!erpnext.utils.validate_mandatory(frm, "Posting/Transaction Date", 
+						frm.doc.posting_date || frm.doc.transaction_date, address_field)) return;
+				} else return;
+				
 				frappe.call({
 					method: "erpnext.accounts.party.set_taxes",
 					args: {
@@ -99,3 +113,13 @@
 		})
 	}
 }
+
+erpnext.utils.validate_mandatory = function(frm, label, value, trigger_on) {
+	if(!value) {
+		frm.doc[trigger_on] = "";
+		refresh_field(trigger_on);
+		frappe.msgprint(__("Please enter {0} first", [label]));
+		return false;
+	}
+	return true;
+}
\ No newline at end of file
diff --git a/erpnext/setup/doctype/company/delete_company_transactions.py b/erpnext/setup/doctype/company/delete_company_transactions.py
index f7334b1..ba2a5b8 100644
--- a/erpnext/setup/doctype/company/delete_company_transactions.py
+++ b/erpnext/setup/doctype/company/delete_company_transactions.py
@@ -22,8 +22,10 @@
 
 	for doctype in frappe.db.sql_list("""select parent from
 		tabDocField where fieldtype='Link' and options='Company'"""):
-		if doctype not in ("Account", "Cost Center", "Warehouse", "Budget Detail", "Party Account", "Employee"):
-			delete_for_doctype(doctype, company_name)
+		if doctype not in ("Account", "Cost Center", "Warehouse", "Budget Detail", 
+			"Party Account", "Employee", "Sales Taxes and Charges Template", 
+			"Purchase Taxes and Charges Template", "POS Profile"):
+				delete_for_doctype(doctype, company_name)
 			
 	# Clear notification counts
 	clear_notifications()
diff --git a/erpnext/setup/doctype/email_digest/email_digest.py b/erpnext/setup/doctype/email_digest/email_digest.py
index f6c074d..e2b0de0 100644
--- a/erpnext/setup/doctype/email_digest/email_digest.py
+++ b/erpnext/setup/doctype/email_digest/email_digest.py
@@ -139,7 +139,7 @@
 
 		for i, e in enumerate(events):
 			e.starts_on_label = format_time(e.starts_on)
-			e.ends_on_label = format_time(e.ends_on)
+			e.ends_on_label = format_time(e.ends_on) if e.ends_on else None
 			e.date = formatdate(e.starts)
 			e.link = get_url_to_form("Event", e.name)
 
@@ -346,7 +346,7 @@
 		self.get_next_sending()
 
 	def fmt_money(self, value):
-		return fmt_money(value, currency = self.currency)
+		return fmt_money(abs(value), currency = self.currency)
 
 def send():
 	now_date = now_datetime().date()
diff --git a/erpnext/setup/doctype/email_digest/templates/default.html b/erpnext/setup/doctype/email_digest/templates/default.html
index 3aad202..d0bd13a 100644
--- a/erpnext/setup/doctype/email_digest/templates/default.html
+++ b/erpnext/setup/doctype/email_digest/templates/default.html
@@ -52,6 +52,8 @@
                     <span style="{{ label_css }}">
                     {% if e.all_day %}
                         {{ _("All Day") }}
+                    {% elif (not e.ends_on_label or e.starts_on_label == e.ends_on_label)%}
+                        {{ e.starts_on_label }}
                     {% else %}
                         {{ e.starts_on_label }} - {{ e.ends_on_label }}
                     {% endif %}
diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
index ceefaf5..96e2660 100644
--- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
+++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
@@ -735,7 +735,7 @@
    "ignore_user_permissions": 0, 
    "in_filter": 0, 
    "in_list_view": 1, 
-   "label": "Warehouse", 
+   "label": "From Warehouse", 
    "no_copy": 0, 
    "oldfieldname": "warehouse", 
    "oldfieldtype": "Link", 
@@ -755,13 +755,15 @@
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
+   "depends_on": "", 
+   "description": "", 
    "fieldname": "target_warehouse", 
    "fieldtype": "Link", 
    "hidden": 0, 
    "ignore_user_permissions": 0, 
    "in_filter": 0, 
    "in_list_view": 0, 
-   "label": "Target Warehouse", 
+   "label": "To Warehouse (Optional)", 
    "no_copy": 0, 
    "options": "Warehouse", 
    "permlevel": 0, 
@@ -831,7 +833,7 @@
    "ignore_user_permissions": 0, 
    "in_filter": 0, 
    "in_list_view": 0, 
-   "label": "Available Qty at Warehouse", 
+   "label": "Available Qty at From Warehouse", 
    "no_copy": 1, 
    "oldfieldname": "actual_qty", 
    "oldfieldtype": "Currency", 
@@ -857,7 +859,7 @@
    "ignore_user_permissions": 0, 
    "in_filter": 0, 
    "in_list_view": 0, 
-   "label": "Available Batch Qty at Warehouse", 
+   "label": "Available Batch Qty at From Warehouse", 
    "no_copy": 1, 
    "permlevel": 0, 
    "precision": "", 
@@ -1160,7 +1162,7 @@
  "is_submittable": 0, 
  "issingle": 0, 
  "istable": 1, 
- "modified": "2015-10-19 03:04:50.887288", 
+ "modified": "2015-10-26 02:19:18.053222", 
  "modified_by": "Administrator", 
  "module": "Stock", 
  "name": "Delivery Note Item", 
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index 94c0c62..0f1f0e0 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -5,6 +5,7 @@
 import frappe
 import json
 import urllib
+import itertools
 from frappe import msgprint, _
 from frappe.utils import cstr, flt, cint, getdate, now_datetime, formatdate
 from frappe.website.website_generator import WebsiteGenerator
@@ -130,6 +131,8 @@
 
 		self.set_attribute_context(context)
 
+		self.set_disabled_attributes(context)
+
 		context.parents = self.get_parents(context)
 
 		return context
@@ -189,15 +192,63 @@
 			for attr in self.attributes:
 				values = context.attribute_values.setdefault(attr.attribute, [])
 
-				# get list of values defined (for sequence)
-				for attr_value in frappe.db.get_all("Item Attribute Value",
-					fields=["attribute_value"], filters={"parent": attr.attribute}, order_by="idx asc"):
+				if cint(frappe.db.get_value("Item Attribute", attr.attribute, "numeric_values")):
+					for val in sorted(attribute_values_available.get(attr.attribute, []), key=flt):
+						values.append(val)
 
-					if attr_value.attribute_value in attribute_values_available.get(attr.attribute, []):
-						values.append(attr_value.attribute_value)
+				else:
+					# get list of values defined (for sequence)
+					for attr_value in frappe.db.get_all("Item Attribute Value",
+						fields=["attribute_value"], filters={"parent": attr.attribute}, order_by="idx asc"):
+
+						if attr_value.attribute_value in attribute_values_available.get(attr.attribute, []):
+							values.append(attr_value.attribute_value)
 
 			context.variant_info = json.dumps(context.variants)
 
+	def set_disabled_attributes(self, context):
+		"""Disable selection options of attribute combinations that do not result in a variant"""
+		if not self.attributes:
+			return
+
+		context.disabled_attributes = {}
+		attributes = [attr.attribute for attr in self.attributes]
+
+		def find_variant(combination):
+			for variant in context.variants:
+				if len(variant.attributes) < len(attributes):
+					continue
+
+				if "combination" not in variant:
+					ref_combination = []
+
+					for attr in variant.attributes:
+						idx = attributes.index(attr.attribute)
+						ref_combination.insert(idx, attr.attribute_value)
+
+					variant["combination"] = ref_combination
+
+				if not (set(combination) - set(variant["combination"])):
+					# check if the combination is a subset of a variant combination
+					# eg. [Blue, 0.5] is a possible combination if exists [Blue, Large, 0.5]
+					return True
+
+		for i, attr in enumerate(self.attributes):
+			if i==0:
+				continue
+
+			combination_source = []
+
+			# loop through previous attributes
+			for prev_attr in self.attributes[:i]:
+				combination_source.append([context.selected_attributes[prev_attr.attribute]])
+
+			combination_source.append(context.attribute_values[attr.attribute])
+
+			for combination in itertools.product(*combination_source):
+				if not find_variant(combination):
+					context.disabled_attributes.setdefault(attr.attribute, []).append(combination[-1])
+
 	def check_warehouse_is_set_for_stock_item(self):
 		if self.is_stock_item==1 and not self.default_warehouse and frappe.get_all("Warehouse"):
 			frappe.msgprint(_("Default Warehouse is mandatory for stock Item."),
diff --git a/erpnext/stock/doctype/packed_item/packed_item.json b/erpnext/stock/doctype/packed_item/packed_item.json
index bfd78bf..88e11d7 100644
--- a/erpnext/stock/doctype/packed_item/packed_item.json
+++ b/erpnext/stock/doctype/packed_item/packed_item.json
@@ -155,7 +155,7 @@
    "ignore_user_permissions": 0, 
    "in_filter": 0, 
    "in_list_view": 0, 
-   "label": "Warehouse", 
+   "label": "From Warehouse", 
    "no_copy": 0, 
    "oldfieldname": "warehouse", 
    "oldfieldtype": "Link", 
@@ -179,7 +179,7 @@
    "ignore_user_permissions": 0, 
    "in_filter": 0, 
    "in_list_view": 0, 
-   "label": "Target Warehouse", 
+   "label": "To Warehouse (Optional)", 
    "no_copy": 0, 
    "options": "Warehouse", 
    "permlevel": 0, 
@@ -511,7 +511,7 @@
  "is_submittable": 0, 
  "issingle": 0, 
  "istable": 1, 
- "modified": "2015-10-12 07:38:58.896987", 
+ "modified": "2015-10-26 02:25:47.718911", 
  "modified_by": "Administrator", 
  "module": "Stock", 
  "name": "Packed Item", 
diff --git a/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py b/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py
index 348cca2..51e3836 100644
--- a/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py
+++ b/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py
@@ -4,6 +4,7 @@
 from __future__ import unicode_literals
 import frappe
 from frappe import _
+from frappe.utils import flt, today
 
 def execute(filters=None):
 	filters = frappe._dict(filters or {})
@@ -18,12 +19,19 @@
 		_("Shortage Qty") + ":Float:100"]
 
 def get_data(filters):
-	item_map = {}
+	bin_list = get_bin_list(filters)
+	item_map = get_item_map(filters.get("item_code"))
 	warehouse_company = {}
 	data = []
 
-	for bin in get_bin_list(filters):
-		item = item_map.setdefault(bin.item_code, frappe.get_doc("Item", bin.item_code))
+	for bin in bin_list:
+		item = item_map.get(bin.item_code)
+
+		if not item:
+			# likely an item that has reached its end of life
+			continue
+
+		# item = item_map.setdefault(bin.item_code, get_item(bin.item_code))
 		company = warehouse_company.setdefault(bin.warehouse, frappe.db.get_value("Warehouse", bin.warehouse, "company"))
 
 		if filters.brand and filters.brand != item.brand:
@@ -45,7 +53,7 @@
 
 		data.append([item.name, item.item_name, item.description, item.item_group, item.brand, bin.warehouse,
 			item.stock_uom, bin.actual_qty, bin.planned_qty, bin.indented_qty, bin.ordered_qty, bin.reserved_qty,
-			bin.projected_qty, re_order_level, re_order_qty, re_order_level - bin.projected_qty])
+			bin.projected_qty, re_order_level, re_order_qty, re_order_level - flt(bin.projected_qty)])
 
 	return data
 
@@ -61,3 +69,35 @@
 		filters=bin_filters, order_by="item_code, warehouse")
 
 	return bin_list
+
+def get_item_map(item_code):
+	"""Optimization: get only the item doc and re_order_levels table"""
+
+	condition = ""
+	if item_code:
+		condition = 'and item_code = "{0}"'.format(frappe.db.escape(item_code))
+
+	items = frappe.db.sql("""select * from `tabItem` item
+		where is_stock_item = 1
+		{condition}
+		and (end_of_life > %(today)s or end_of_life is null or end_of_life='0000-00-00')
+		and exists (select name from `tabBin` bin where bin.item_code=item.name)"""\
+		.format(condition=condition), {"today": today()}, as_dict=True)
+
+	condition = ""
+	if item_code:
+		condition = 'where parent="{0}"'.format(frappe.db.escape(item_code))
+
+	reorder_levels = frappe._dict()
+	for ir in frappe.db.sql("""select * from `tabItem Reorder` {condition}""".format(condition=condition), as_dict=1):
+		if ir.parent not in reorder_levels:
+			reorder_levels[ir.parent] = []
+
+		reorder_levels[ir.parent].append(ir)
+
+	item_map = frappe._dict()
+	for item in items:
+		item["reorder_levels"] = reorder_levels.get(item.name) or []
+		item_map[item.name] = item
+
+	return item_map
diff --git a/erpnext/templates/generators/item.html b/erpnext/templates/generators/item.html
index 4bd521d..acbcedf 100644
--- a/erpnext/templates/generators/item.html
+++ b/erpnext/templates/generators/item.html
@@ -29,7 +29,8 @@
 				<div class="item-attribute-selectors">
                     {% if has_variants %}
                     {% for d in attributes %}
-                    <div class="item-view-attribute"
+					{% if attribute_values[d.attribute] -%}
+                    <div class="item-view-attribute {% if (attribute_values[d.attribute] | len)==1 -%} hidden {%- endif %}"
                             style="margin-bottom: 10px;">
                         <h6 class="text-muted">{{ _(d.attribute) }}</h6>
                         <select class="form-control"
@@ -37,12 +38,17 @@
                             data-attribute="{{ d.attribute }}">
 						{% for value in attribute_values[d.attribute] %}
                         <option value="{{ value }}"
-							{% if selected_attributes and selected_attributes[d.attribute]==value -%} selected {%- endif %}>
+						{% if selected_attributes and selected_attributes[d.attribute]==value -%}
+							selected
+						{%- elif disabled_attributes and value in disabled_attributes.get(d.attribute, []) -%}
+							disabled
+						{%- endif %}>
 							{{ _(value) }}
 						</option>
                         {% endfor %}
                         </select>
                     </div>
+					{%- endif %}
                     {% endfor %}
                     {% endif %}
 				</div>
diff --git a/erpnext/templates/includes/product_page.js b/erpnext/templates/includes/product_page.js
index 2345de4..f7a2360 100644
--- a/erpnext/templates/includes/product_page.js
+++ b/erpnext/templates/includes/product_page.js
@@ -64,8 +64,23 @@
 		});
 	});
 
-	$("[itemscope] .item-view-attribute select").on("change", function() {
-		var item_code = encodeURIComponent(get_item_code());
+	$("[itemscope] .item-view-attribute .form-control").on("change", function() {
+		try {
+			var item_code = encodeURIComponent(get_item_code());
+		} catch(e) {
+			// unable to find variant
+			// then chose the closest available one
+
+			var attribute = $(this).attr("data-attribute");
+			var attribute_value = $(this).val()
+			var item_code = update_attribute_selectors(attribute, attribute_value);
+
+			if (!item_code) {
+				msgprint(__("Please select some other value for {0}", [attribute]))
+				throw e;
+			}
+		}
+
 		if (window.location.search.indexOf(item_code)!==-1) {
 			return;
 		}
@@ -83,10 +98,8 @@
 
 function get_item_code() {
 	if(window.variant_info) {
-		attributes = {};
-		$('[itemscope]').find(".item-view-attribute select").each(function() {
-			attributes[$(this).attr('data-attribute')] = $(this).val();
-		});
+		var attributes = get_selected_attributes();
+
 		for(var i in variant_info) {
 			var variant = variant_info[i];
 			var match = true;
@@ -106,3 +119,51 @@
 		return item_code;
 	}
 }
+
+function update_attribute_selectors(selected_attribute, selected_attribute_value) {
+	// find the closest match keeping the selected attribute in focus and get the item code
+
+	var attributes = get_selected_attributes();
+
+	var previous_match_score = 0;
+	var matched;
+	for(var i in variant_info) {
+		var variant = variant_info[i];
+		var match_score = 0;
+		var has_selected_attribute = false;
+
+		for(var j in variant.attributes) {
+			if(attributes[variant.attributes[j].attribute]===variant.attributes[j].attribute_value) {
+				match_score = match_score + 1;
+
+				if (variant.attributes[j].attribute==selected_attribute && variant.attributes[j].attribute_value==selected_attribute_value) {
+					has_selected_attribute = true;
+				}
+			}
+		}
+
+		if (has_selected_attribute && (match_score > previous_match_score)) {
+			previous_match_score = match_score;
+			matched = variant;
+		}
+	}
+
+	if (matched) {
+		for (var j in matched.attributes) {
+			var attr = matched.attributes[j];
+			$('[itemscope]')
+				.find(repl('.item-view-attribute .form-control[data-attribute="%(attribute)s"]', attr))
+				.val(attr.attribute_value);
+		}
+
+		return matched.name;
+	}
+}
+
+function get_selected_attributes() {
+	var attributes = {};
+	$('[itemscope]').find(".item-view-attribute .form-control").each(function() {
+		attributes[$(this).attr('data-attribute')] = $(this).val();
+	});
+	return attributes;
+}
diff --git a/setup.py b/setup.py
index 1934282..c673dc3 100644
--- a/setup.py
+++ b/setup.py
@@ -1,6 +1,6 @@
 from setuptools import setup, find_packages
 
-version = "6.6.4"
+version = "6.6.5"
 
 with open("requirements.txt", "r") as f:
 	install_requires = f.readlines()