feat: Tax Category based on Address
diff --git a/erpnext/accounts/custom/address.json b/erpnext/accounts/custom/address.json
new file mode 100644
index 0000000..08f972d
--- /dev/null
+++ b/erpnext/accounts/custom/address.json
@@ -0,0 +1,58 @@
+{
+ "custom_fields": [
+  {
+   "_assign": null, 
+   "_comments": null, 
+   "_liked_by": null, 
+   "_user_tags": null, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "collapsible_depends_on": null, 
+   "columns": 0, 
+   "creation": "2018-12-28 22:29:21.828090", 
+   "default": null, 
+   "depends_on": null, 
+   "description": null, 
+   "docstatus": 0, 
+   "dt": "Address", 
+   "fetch_from": null, 
+   "fieldname": "tax_category", 
+   "fieldtype": "Link", 
+   "hidden": 0, 
+   "idx": 14, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "insert_after": "fax", 
+   "label": "Tax Category", 
+   "modified": "2018-12-28 22:29:21.828090", 
+   "modified_by": "Administrator", 
+   "name": "Address-tax_category", 
+   "no_copy": 0, 
+   "options": "Tax Category", 
+   "owner": "Administrator", 
+   "parent": null, 
+   "parentfield": null, 
+   "parenttype": null, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "print_width": null, 
+   "read_only": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "translatable": 0, 
+   "unique": 0, 
+   "width": null
+  }
+ ], 
+ "custom_perms": [], 
+ "doctype": "Address", 
+ "property_setters": [], 
+ "sync_on_migrate": 1
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
index 4597eae..305093b 100644
--- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
+++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
@@ -119,6 +119,41 @@
    "bold": 0, 
    "collapsible": 0, 
    "columns": 0, 
+   "default": "Billing Address", 
+   "description": "Address used to determine Tax Category in transactions.", 
+   "fieldname": "determine_address_tax_category_from", 
+   "fieldtype": "Select", 
+   "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": "Determine Address Tax Category From", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Billing Address\nShipping Address", 
+   "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, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
    "fieldname": "column_break_4", 
    "fieldtype": "Column Break", 
    "hidden": 0, 
@@ -674,7 +709,7 @@
  "issingle": 1, 
  "istable": 0, 
  "max_attachments": 0, 
- "modified": "2018-12-28 04:30:38.835015", 
+ "modified": "2018-12-28 23:18:29.863177", 
  "modified_by": "Administrator", 
  "module": "Accounts", 
  "name": "Accounts Settings", 
diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
index 8184178..3222aeb 100644
--- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
+++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
@@ -15,7 +15,9 @@
 		frappe.clear_cache()
 
 	def validate(self):
-		frappe.db.set_default("add_taxes_from_item_tax_template", self.get("add_taxes_from_item_tax_template", ""))
+		for f in ["add_taxes_from_item_tax_template"]:
+			frappe.db.set_default(f, self.get(f, ""))
+
 		self.validate_stale_days()
 		self.enable_payment_schedule_in_print()
 		self.enable_fields_for_cost_center_settings()
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index 90fc3d1..b22d3d4 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -8,7 +8,7 @@
 from frappe.defaults import get_user_permissions
 from frappe.model.utils import get_fetch_values
 from frappe.utils import (add_days, getdate, formatdate, date_diff,
-	add_years, get_timestamp, nowdate, flt, add_months, get_last_day)
+	add_years, get_timestamp, nowdate, flt, cstr, add_months, get_last_day)
 from frappe.contacts.doctype.address.address import (get_address_display,
 	get_default_address, get_company_address)
 from frappe.contacts.doctype.contact.contact import get_contact_details, get_default_contact
@@ -16,7 +16,7 @@
 from erpnext.accounts.utils import get_fiscal_year
 from erpnext import get_default_currency, get_company_currency
 
-from six import iteritems
+from six import iteritems, string_types
 
 class DuplicatePartyAccountError(frappe.ValidationError): pass
 
@@ -49,7 +49,8 @@
 	set_other_values(out, party, party_type)
 	set_price_list(out, party, party_type, price_list)
 
-	out["tax_category"] = get_tax_category(party, party_address, shipping_address)
+	out["tax_category"] = get_address_tax_category(party.get("tax_category"),
+		party_address, shipping_address if party_type != "Supplier" else party_address)
 	out["taxes_and_charges"] = set_taxes(party.name, party_type, posting_date, company, out.customer_group,
 		out.supplier_group, out.tax_category, party_address, shipping_address)
 
@@ -355,8 +356,17 @@
 				frappe.throw(_("Due / Reference Date cannot be after {0}")
 					.format(formatdate(default_due_date)))
 
-def get_tax_category(party, billing_address, shipping_address):
-	return party.get("tax_category")
+@frappe.whitelist()
+def get_address_tax_category(tax_category, billing_address=None, shipping_address=None):
+	addr_tax_category_from = frappe.db.get_single_value("Accounts Settings", "determine_address_tax_category_from")
+	if addr_tax_category_from == "Shipping Address":
+		if shipping_address:
+			tax_category = frappe.db.get_value("Address", shipping_address, "tax_category") or tax_category
+	else:
+		if billing_address:
+			tax_category = frappe.db.get_value("Address", billing_address, "tax_category") or tax_category
+
+	return cstr(tax_category)
 
 @frappe.whitelist()
 def set_taxes(party, party_type, posting_date, company, customer_group=None, supplier_group=None, tax_category=None,
diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js
index cefdbe7..1e2b574 100644
--- a/erpnext/public/js/controllers/buying.js
+++ b/erpnext/public/js/controllers/buying.js
@@ -105,6 +105,7 @@
 
 	supplier_address: function() {
 		erpnext.utils.get_address_display(this.frm);
+		erpnext.utils.set_taxes_from_address(this.frm, "supplier_address", "supplier_address", "supplier_address");
 	},
 
 	buying_price_list: function() {
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 744a861..d95ca04 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -452,9 +452,7 @@
 							frappe.run_serially([
 								() => {
 									var d = locals[cdt][cdn];
-									if(d.item_tax_template && d.item_tax_rate) {
-										me.add_taxes_from_item_tax_template(d.item_tax_rate);
-									}
+									me.add_taxes_from_item_tax_template(d.item_tax_rate);
 								},
 								() => me.frm.script_manager.trigger("price_list_rate", cdt, cdn),
 								() => me.toggle_conversion_factor(item),
@@ -482,7 +480,7 @@
 	add_taxes_from_item_tax_template: function(item_tax_map) {
 		let me = this;
 
-		if(cint(frappe.defaults.get_default("add_taxes_from_item_tax_template"))) {
+		if(item_tax_map && cint(frappe.defaults.get_default("add_taxes_from_item_tax_template"))) {
 			if(typeof (item_tax_map) == "string") {
 				item_tax_map = JSON.parse(item_tax_map);
 			}
@@ -1312,6 +1310,8 @@
 
 	tax_category: function() {
 		var me = this;
+		if(me.frm.updating_party_details) return;
+
 		var item_codes = [];
 		$.each(this.frm.doc.items || [], function(i, item) {
 			if(item.item_code) {
@@ -1334,6 +1334,7 @@
 									if(item.item_code && r.message.hasOwnProperty(item.item_code)) {
 										item.item_tax_template = r.message[item.item_code].item_tax_template;
 										item.item_tax_rate = r.message[item.item_code].item_tax_rate;
+										me.add_taxes_from_item_tax_template(item.item_tax_rate);
 									} else {
 										item.item_tax_template = "";
 										item.item_tax_rate = "{}";
@@ -1351,6 +1352,8 @@
 
 	item_tax_template: function(doc, cdt, cdn) {
 		var me = this;
+		if(me.frm.updating_party_details) return;
+
 		var item = frappe.get_doc(cdt, cdn);
 
 		if(item.item_tax_template) {
diff --git a/erpnext/public/js/utils/party.js b/erpnext/public/js/utils/party.js
index 747f141..0526931 100644
--- a/erpnext/public/js/utils/party.js
+++ b/erpnext/public/js/utils/party.js
@@ -92,9 +92,6 @@
 				if(r.message) {
 					frm.set_value(display_field, r.message)
 				}
-				if(frappe.meta.get_docfield(frm.doc.doctype, "taxes") && !is_your_company_address) {
-					erpnext.utils.set_taxes(frm, address_field);
-				}
 			}
 		})
 	} else {
@@ -102,6 +99,42 @@
 	}
 };
 
+erpnext.utils.set_taxes_from_address = function(frm, triggered_from_field, billing_address_field, shipping_address_field) {
+	if(frm.updating_party_details) return;
+
+	if(frappe.meta.get_docfield(frm.doc.doctype, "taxes")) {
+		if(!erpnext.utils.validate_mandatory(frm, "Lead/Customer/Supplier",
+			frm.doc.customer || frm.doc.supplier || frm.doc.lead, triggered_from_field)) {
+			return;
+		}
+
+		if(!erpnext.utils.validate_mandatory(frm, "Posting/Transaction Date",
+			frm.doc.posting_date || frm.doc.transaction_date, triggered_from_field)) {
+			return;
+		}
+	} else {
+		return;
+	}
+
+	frappe.call({
+		method: "erpnext.accounts.party.get_address_tax_category",
+		args: {
+			"tax_category": frm.doc.tax_category,
+			"billing_address": frm.doc[billing_address_field],
+			"shipping_address": frm.doc[shipping_address_field]
+		},
+		callback: function(r) {
+			if(!r.exc){
+				if(frm.doc.tax_category != r.message) {
+					frm.set_value("tax_category", r.message);
+				} else {
+					erpnext.utils.set_taxes(frm, triggered_from_field);
+				}
+			}
+		}
+	});
+};
+
 erpnext.utils.set_taxes = function(frm, triggered_from_field) {
 	if(frappe.meta.get_docfield(frm.doc.doctype, "taxes")) {
 		if(!erpnext.utils.validate_mandatory(frm, "Lead/Customer/Supplier",
diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js
index c431df4..3a3ba76 100644
--- a/erpnext/selling/sales_common.js
+++ b/erpnext/selling/sales_common.js
@@ -103,10 +103,12 @@
 
 	customer_address: function() {
 		erpnext.utils.get_address_display(this.frm, "customer_address");
+		erpnext.utils.set_taxes_from_address(this.frm, "customer_address", "customer_address", "shipping_address_name");
 	},
 
 	shipping_address_name: function() {
 		erpnext.utils.get_address_display(this.frm, "shipping_address_name", "shipping_address");
+		erpnext.utils.set_taxes_from_address(this.frm, "shipping_address_name", "customer_address", "shipping_address_name");
 	},
 
 	sales_partner: function() {