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() {