Merge pull request #4012 from saurabh6790/cart
Taxation for Shopping Cart based on Tax Rule template
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index 25ac8ff..c1801eb 100755
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -2375,4 +2375,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "title"
-}
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.json b/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.json
index a00184b..9e43ca0 100644
--- a/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.json
+++ b/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.json
@@ -504,7 +504,7 @@
"is_submittable": 0,
"issingle": 0,
"istable": 1,
- "modified": "2015-08-19 12:46:32.687299",
+ "modified": "2015-08-28 02:57:08.769473",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Taxes and Charges",
diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.json b/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.json
index 29534d8..a0d8df4 100644
--- a/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.json
+++ b/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.json
@@ -456,7 +456,7 @@
"is_submittable": 0,
"issingle": 0,
"istable": 1,
- "modified": "2015-08-19 12:46:33.165519",
+ "modified": "2015-08-28 02:57:00.766305",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Taxes and Charges",
diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges_template/test_records.json b/erpnext/accounts/doctype/sales_taxes_and_charges_template/test_records.json
index 656d29c..69dbd8e 100644
--- a/erpnext/accounts/doctype/sales_taxes_and_charges_template/test_records.json
+++ b/erpnext/accounts/doctype/sales_taxes_and_charges_template/test_records.json
@@ -153,5 +153,95 @@
"territory": "_Test Territory Rest Of The World"
}
]
+ },
+ {
+ "company": "_Test Company",
+ "doctype": "Sales Taxes and Charges Template",
+ "taxes": [
+ {
+ "account_head": "_Test Account VAT - _TC",
+ "charge_type": "On Net Total",
+ "description": "VAT",
+ "doctype": "Sales Taxes and Charges",
+ "parentfield": "taxes",
+ "rate": 12
+ },
+ {
+ "account_head": "_Test Account Service Tax - _TC",
+ "charge_type": "On Net Total",
+ "description": "Service Tax",
+ "doctype": "Sales Taxes and Charges",
+ "parentfield": "taxes",
+ "rate": 4
+ }
+ ],
+ "title": "_Test Sales Taxes and Charges Template 1",
+ "territories": [
+ {
+ "doctype": "Applicable Territory",
+ "parentfield": "territories",
+ "territory": "_Test Territory Rest Of The World"
+ }
+ ]
+ },
+ {
+ "company": "_Test Company",
+ "doctype": "Sales Taxes and Charges Template",
+ "taxes": [
+ {
+ "account_head": "_Test Account VAT - _TC",
+ "charge_type": "On Net Total",
+ "description": "VAT",
+ "doctype": "Sales Taxes and Charges",
+ "parentfield": "taxes",
+ "rate": 12
+ },
+ {
+ "account_head": "_Test Account Service Tax - _TC",
+ "charge_type": "On Net Total",
+ "description": "Service Tax",
+ "doctype": "Sales Taxes and Charges",
+ "parentfield": "taxes",
+ "rate": 4
+ }
+ ],
+ "title": "_Test Sales Taxes and Charges Template 2",
+ "territories": [
+ {
+ "doctype": "Applicable Territory",
+ "parentfield": "territories",
+ "territory": "_Test Territory Rest Of The World"
+ }
+ ]
+ },
+ {
+ "doctype" : "Sales Taxes and Charges Template",
+ "title": "_Test Tax 1",
+ "company": "_Test Company",
+ "taxes":[{
+ "charge_type": "Actual",
+ "account_head": "Sales Expenses - _TC",
+ "cost_center": "Main - _TC",
+ "description": "Test Shopping cart taxes with Tax Rule",
+ "tax_amount": 1000
+ }],
+ "territories":[{
+ "territory" : "All Territories"
+ }]
+ },
+ {
+ "doctype" : "Sales Taxes and Charges Template",
+ "title": "_Test Tax 2",
+ "company": "_Test Company",
+ "taxes":[{
+ "charge_type": "Actual",
+ "account_head": "Sales Expenses - _TC",
+ "cost_center": "Main - _TC",
+ "description": "Test Shopping cart taxes with Tax Rule",
+ "tax_amount": 200
+ }],
+ "territories":[{
+ "territory" : "All Territories"
+ }]
}
]
diff --git a/erpnext/shopping_cart/doctype/shopping_cart_taxes_and_charges_master/__init__.py b/erpnext/accounts/doctype/tax_rule/__init__.py
similarity index 100%
rename from erpnext/shopping_cart/doctype/shopping_cart_taxes_and_charges_master/__init__.py
rename to erpnext/accounts/doctype/tax_rule/__init__.py
diff --git a/erpnext/accounts/doctype/tax_rule/tax_rule.js b/erpnext/accounts/doctype/tax_rule/tax_rule.js
new file mode 100644
index 0000000..4b059dc
--- /dev/null
+++ b/erpnext/accounts/doctype/tax_rule/tax_rule.js
@@ -0,0 +1,60 @@
+// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+// License: GNU General Public License v3. See license.txt
+
+cur_frm.add_fetch("customer", "customer_group", "customer_group" );
+cur_frm.add_fetch("supplier", "supplier_type", "supplier_type" );
+
+cur_frm.toggle_reqd("sales_tax_template", cur_frm.doc.tax_type=="Sales");
+cur_frm.toggle_reqd("purchase_tax_template", cur_frm.doc.tax_type=="Purchase");
+
+
+frappe.ui.form.on("Tax Rule", "onload", function(frm) {
+ if(frm.doc.__islocal){
+ frm.set_value("use_for_shopping_cart", 1);
+ }
+})
+
+frappe.ui.form.on("Tax Rule", "use_for_shopping_cart", function(frm) {
+ if(!frm.doc.use_for_shopping_cart && (frappe.get_list("Tax Rule", {"use_for_shopping_cart":1}).length == 0)){
+ frappe.model.get_value("Shopping Cart Settings", "Shopping Cart Settings", "enabled", function(docfield) {
+ if(docfield.enabled){
+ frm.set_value("use_for_shopping_cart", 1);
+ frappe.throw(__("Shopping Cart is enabled"));
+ }
+ });
+ }
+})
+
+frappe.ui.form.on("Tax Rule", "customer", function(frm) {
+ frappe.call({
+ method:"erpnext.accounts.doctype.tax_rule.tax_rule.get_party_details",
+ args: {
+ "party": frm.doc.customer,
+ "party_type": "customer"
+ },
+ callback: function(r) {
+ if(!r.exc) {
+ $.each(r.message, function(k, v) {
+ frm.set_value(k, v);
+ });
+ }
+ }
+ });
+});
+
+frappe.ui.form.on("Tax Rule", "supplier", function(frm) {
+ frappe.call({
+ method:"erpnext.accounts.doctype.tax_rule.tax_rule.get_party_details",
+ args: {
+ "party": frm.doc.supplier,
+ "party_type": "supplier"
+ },
+ callback: function(r) {
+ if(!r.exc) {
+ $.each(r.message, function(k, v) {
+ frm.set_value(k, v);
+ });
+ }
+ }
+ });
+});
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/tax_rule/tax_rule.json b/erpnext/accounts/doctype/tax_rule/tax_rule.json
new file mode 100644
index 0000000..60011dd
--- /dev/null
+++ b/erpnext/accounts/doctype/tax_rule/tax_rule.json
@@ -0,0 +1,615 @@
+{
+ "allow_copy": 0,
+ "allow_import": 1,
+ "allow_rename": 0,
+ "autoname": "TR.####",
+ "creation": "2015-08-07 02:33:52.670866",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "fields": [
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "default": "Sales",
+ "fieldname": "tax_type",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 1,
+ "label": "Tax Type",
+ "no_copy": 0,
+ "options": "Sales\nPurchase",
+ "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": "use_for_shopping_cart",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Use for Shopping Cart",
+ "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_1",
+ "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,
+ "depends_on": "eval:doc.tax_type==\"Sales\"",
+ "fieldname": "sales_tax_template",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Sales Tax Template",
+ "no_copy": 0,
+ "options": "Sales Taxes and Charges Template",
+ "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": "eval:doc.tax_type==\"Purchase\"",
+ "fieldname": "purchase_tax_template",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Purchase Tax Template",
+ "no_copy": 0,
+ "options": "Purchase Taxes and Charges Template",
+ "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": "filters",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Filters",
+ "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": "eval:doc.tax_type==\"Sales\"",
+ "fieldname": "customer",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Customer",
+ "no_copy": 0,
+ "options": "Customer",
+ "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": "eval:doc.tax_type==\"Purchase\"",
+ "fieldname": "supplier",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Supplier",
+ "no_copy": 0,
+ "options": "Supplier",
+ "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": "billing_city",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Billing 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": "billing_state",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Billing State",
+ "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": "billing_country",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Billing Country",
+ "no_copy": 0,
+ "options": "Country",
+ "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_2",
+ "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,
+ "depends_on": "eval:doc.tax_type==\"Sales\"",
+ "fieldname": "customer_group",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Customer Group",
+ "no_copy": 0,
+ "options": "Customer Group",
+ "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": "eval:doc.tax_type==\"Purchase\"",
+ "fieldname": "supplier_type",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Supplier Type",
+ "no_copy": 0,
+ "options": "Supplier Type",
+ "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": "shipping_city",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Shipping 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": "shipping_state",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Shipping State",
+ "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": "shipping_country",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Shipping Country",
+ "no_copy": 0,
+ "options": "Country",
+ "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": "section_break_4",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Validity",
+ "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": "from_date",
+ "fieldtype": "Date",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "From Date",
+ "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_7",
+ "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": "to_date",
+ "fieldtype": "Date",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "To Date",
+ "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": "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,
+ "default": "1",
+ "fieldname": "priority",
+ "fieldtype": "Int",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Priority",
+ "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_20",
+ "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": "company",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Company",
+ "no_copy": 0,
+ "options": "Company",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ }
+ ],
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "in_create": 0,
+ "in_dialog": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "modified": "2015-09-15 12:29:34.435839",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Tax Rule",
+ "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": "Administrator",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ }
+ ],
+ "read_only": 0,
+ "read_only_onload": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC"
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/tax_rule/tax_rule.py b/erpnext/accounts/doctype/tax_rule/tax_rule.py
new file mode 100644
index 0000000..0a9bb11
--- /dev/null
+++ b/erpnext/accounts/doctype/tax_rule/tax_rule.py
@@ -0,0 +1,134 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+from frappe.model.document import Document
+from frappe.utils import cstr
+
+class IncorrectCustomerGroup(frappe.ValidationError): pass
+class IncorrectSupplierType(frappe.ValidationError): pass
+class ConflictingTaxRule(frappe.ValidationError): pass
+
+class TaxRule(Document):
+ def validate(self):
+ self.validate_tax_template()
+ self.validate_customer_group()
+ self.validate_supplier_type()
+ self.validate_date()
+ self.validate_filters()
+
+ def validate_tax_template(self):
+ if self.tax_type== "Sales":
+ self.purchase_tax_template = self.supplier = self.supplier_type= None
+ else:
+ self.sales_tax_template= self.customer = self.customer_group= None
+
+ if not (self.sales_tax_template or self.purchase_tax_template):
+ frappe.throw(_("Tax Template is mandatory."))
+
+ def validate_customer_group(self):
+ if self.customer and self.customer_group:
+ if not frappe.db.get_value("Customer", self.customer, "customer_group") == self.customer_group:
+ frappe.throw(_("Customer {0} does not belong to customer group {1}"). \
+ format(self.customer, self.customer_group), IncorrectCustomerGroup)
+
+ def validate_supplier_type(self):
+ if self.supplier and self.supplier_type:
+ if not frappe.db.get_value("Supplier", self.supplier, "supplier_type") == self.supplier_type:
+ frappe.throw(_("Supplier {0} does not belong to Supplier Type {1}"). \
+ format(self.supplier, self.supplier_type), IncorrectSupplierType)
+
+ def validate_date(self):
+ if self.from_date and self.to_date and self.from_date > self.to_date:
+ frappe.throw(_("From Date cannot be greater than To Date"))
+
+ def validate_filters(self):
+ filters = {
+ "tax_type": self.tax_type,
+ "customer": self.customer,
+ "customer_group": self.customer_group,
+ "supplier": self.supplier,
+ "supplier_type": self.supplier_type,
+ "billing_city": self.billing_city,
+ "billing_state": self.billing_state,
+ "billing_country": self.billing_country,
+ "shipping_city": self.shipping_city,
+ "shipping_state": self.shipping_state,
+ "shipping_country": self.shipping_country,
+ "company": self.company
+ }
+
+ conds=""
+ for d in filters:
+ if conds:
+ conds += " and "
+ conds += """ifnull({0}, '') = '{1}'""".format(d, frappe.db.escape(cstr(filters[d])))
+
+ if self.from_date and self.to_date:
+ conds += """ and ((from_date > '{from_date}' and from_date < '{to_date}') or
+ (to_date > '{from_date}' and to_date < '{to_date}') or
+ ('{from_date}' > from_date and '{from_date}' < to_date) or
+ ('{from_date}' = from_date and '{to_date}' = to_date))""".format(from_date=self.from_date, to_date=self.to_date)
+
+ elif self.from_date and not self.to_date:
+ conds += """ and to_date > '{from_date}'""".format(from_date = self.from_date)
+
+ elif self.to_date and not self.from_date:
+ conds += """ and from_date < '{to_date}'""".format(to_date = self.to_date)
+
+ tax_rule = frappe.db.sql("select name, priority \
+ from `tabTax Rule` where {0} and name != '{1}'".format(conds, self.name), as_dict=1)
+
+ if tax_rule:
+ if tax_rule[0].priority == self.priority:
+ frappe.throw(_("Tax Rule Conflicts with {0}".format(tax_rule[0].name)), ConflictingTaxRule)
+
+@frappe.whitelist()
+def get_party_details(party, party_type, args=None):
+ out = {}
+ if args:
+ billing_filters= {"name": args.get("billing_address")}
+ shipping_filters= {"name": args.get("shipping_address")}
+ else:
+ billing_filters= {party_type: party, "is_primary_address": 1}
+ shipping_filters= {party_type:party, "is_shipping_address": 1}
+
+ billing_address= frappe.get_all("Address", fields=["city", "state", "country"], filters= billing_filters)
+ shipping_address= frappe.get_all("Address", fields=["city", "state", "country"], filters= shipping_filters)
+
+ if billing_address:
+ out["billing_city"]= billing_address[0].city
+ out["billing_state"]= billing_address[0].state
+ out["billing_country"]= billing_address[0].country
+
+ if shipping_address:
+ out["shipping_city"]= shipping_address[0].city
+ out["shipping_state"]= shipping_address[0].state
+ out["shipping_country"]= shipping_address[0].country
+
+ return out
+
+def get_tax_template(posting_date, args):
+ """Get matching tax rule"""
+ args = frappe._dict(args)
+ conditions = []
+
+ for key, value in args.iteritems():
+ conditions.append("ifnull({0}, '') in ('', '{1}')".format(key, frappe.db.escape(cstr(value))))
+
+ matching = frappe.db.sql("""select * from `tabTax Rule`
+ where {0}""".format(" and ".join(conditions)), as_dict = True)
+
+ if not matching:
+ return None
+
+ for rule in matching:
+ 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]
+ return rule.sales_tax_template or rule.purchase_tax_template
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/tax_rule/test_records.json b/erpnext/accounts/doctype/tax_rule/test_records.json
new file mode 100644
index 0000000..0913fba
--- /dev/null
+++ b/erpnext/accounts/doctype/tax_rule/test_records.json
@@ -0,0 +1,28 @@
+[
+ {
+ "doctype": "Tax Rule",
+ "tax_type" : "Sales",
+ "sales_tax_template": "_Test Tax 1",
+ "use_for_shopping_cart": 1,
+ "billing_city": "_Test City",
+ "billing_state": "Test State",
+ "billing_country": "India",
+ "shipping_city": "_Test City",
+ "shipping_country": "India",
+ "priority": 1,
+ "company": "_Test Company"
+ },
+ {
+ "doctype": "Tax Rule",
+ "tax_type" : "Sales",
+ "sales_tax_template": "_Test Tax 2",
+ "use_for_shopping_cart": 0,
+ "billing_city": "_Test City",
+ "billing_country": "India",
+ "shipping_city": "_Test City",
+ "shipping_state": "Test State",
+ "shipping_country": "India",
+ "priority": 2,
+ "company": "_Test Company"
+ }
+]
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/tax_rule/test_tax_rule.py b/erpnext/accounts/doctype/tax_rule/test_tax_rule.py
new file mode 100644
index 0000000..3e175fa
--- /dev/null
+++ b/erpnext/accounts/doctype/tax_rule/test_tax_rule.py
@@ -0,0 +1,141 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+from erpnext.accounts.doctype.tax_rule.tax_rule import IncorrectCustomerGroup, IncorrectSupplierType, ConflictingTaxRule, get_tax_template
+
+test_records = frappe.get_test_records('Tax Rule')
+
+class TestTaxRule(unittest.TestCase):
+ def setUp(self):
+ frappe.db.sql("delete from `tabTax Rule` where use_for_shopping_cart <> 1")
+
+ def test_customer_group(self):
+ tax_rule = make_tax_rule(customer= "_Test Customer", customer_group= "_Test Customer Group 1",
+ sales_tax_template = "_Test Sales Taxes and Charges Template")
+ self.assertRaises(IncorrectCustomerGroup, tax_rule.save)
+
+ def test_supplier_type(self):
+ tax_rule = make_tax_rule(tax_type= "Purchase", supplier= "_Test Supplier", supplier_type= "_Test Supplier Type 1",
+ purchase_tax_template = "_Test Purchase Taxes and Charges Template")
+ self.assertRaises(IncorrectSupplierType, tax_rule.save)
+
+ def test_conflict(self):
+ tax_rule1 = make_tax_rule(customer= "_Test Customer",
+ sales_tax_template = "_Test Sales Taxes and Charges Template", priority = 1)
+ tax_rule1.save()
+
+ tax_rule2 = make_tax_rule(customer= "_Test Customer",
+ sales_tax_template = "_Test Sales Taxes and Charges Template", priority = 1)
+
+ self.assertRaises(ConflictingTaxRule, tax_rule2.save)
+
+ def test_conflict_with_non_overlapping_dates(self):
+ tax_rule1 = make_tax_rule(customer= "_Test Customer",
+ sales_tax_template = "_Test Sales Taxes and Charges Template", priority = 1, from_date = "2015-01-01")
+ tax_rule1.save()
+
+ tax_rule2 = make_tax_rule(customer= "_Test Customer",
+ sales_tax_template = "_Test Sales Taxes and Charges Template", priority = 1, to_date = "2013-01-01")
+
+ tax_rule2.save()
+ self.assertTrue(tax_rule2.name)
+
+ def test_conflict_with_overlapping_dates(self):
+ tax_rule1 = make_tax_rule(customer= "_Test Customer",
+ sales_tax_template = "_Test Sales Taxes and Charges Template", priority = 1, from_date = "2015-01-01", to_date = "2015-01-05")
+ tax_rule1.save()
+
+ tax_rule2 = make_tax_rule(customer= "_Test Customer",
+ sales_tax_template = "_Test Sales Taxes and Charges Template", priority = 1, from_date = "2015-01-03", to_date = "2015-01-09")
+
+ self.assertRaises(ConflictingTaxRule, tax_rule2.save)
+
+ def test_tax_template(self):
+ tax_rule = make_tax_rule()
+ self.assertEquals(tax_rule.purchase_tax_template, None)
+
+
+ def test_select_tax_rule_based_on_customer(self):
+ make_tax_rule(customer= "_Test Customer",
+ sales_tax_template = "_Test Sales Taxes and Charges Template", save=1)
+
+ make_tax_rule(customer= "_Test Customer 1",
+ sales_tax_template = "_Test Sales Taxes and Charges Template 1", save=1)
+
+ make_tax_rule(customer= "_Test Customer 2",
+ sales_tax_template = "_Test Sales Taxes and Charges Template 2", save=1)
+
+ self.assertEquals(get_tax_template("2015-01-01", {"customer":"_Test Customer 2"}),
+ "_Test Sales Taxes and Charges Template 2")
+
+ def test_select_tax_rule_based_on_better_match(self):
+ make_tax_rule(customer= "_Test Customer", billing_city = "Test City", billing_state = "Test State",
+ sales_tax_template = "_Test Sales Taxes and Charges Template", save=1)
+
+ make_tax_rule(customer= "_Test Customer", billing_city = "Test City1", billing_state = "Test State",
+ sales_tax_template = "_Test Sales Taxes and Charges Template 1", save=1)
+
+ self.assertEquals(get_tax_template("2015-01-01", {"customer":"_Test Customer", "billing_city": "Test City", "billing_state": "Test State"}),
+ "_Test Sales Taxes and Charges Template")
+
+ def test_select_tax_rule_based_on_state_match(self):
+ make_tax_rule(customer= "_Test Customer", shipping_state = "Test State",
+ sales_tax_template = "_Test Sales Taxes and Charges Template", save=1)
+
+ make_tax_rule(customer= "_Test Customer", shipping_state = "Test State12",
+ sales_tax_template = "_Test Sales Taxes and Charges Template 1", priority=2, save=1)
+
+ self.assertEquals(get_tax_template("2015-01-01", {"customer":"_Test Customer", "shipping_state": "Test State"}),
+ "_Test Sales Taxes and Charges Template")
+
+ def test_select_tax_rule_based_on_better_priority(self):
+ make_tax_rule(customer= "_Test Customer", billing_city = "Test City",
+ sales_tax_template = "_Test Sales Taxes and Charges Template", priority=1, save=1)
+
+ make_tax_rule(customer= "_Test Customer", billing_city = "Test City",
+ sales_tax_template = "_Test Sales Taxes and Charges Template 1", priority=2, save=1)
+
+ self.assertEquals(get_tax_template("2015-01-01", {"customer":"_Test Customer", "billing_city": "Test City"}),
+ "_Test Sales Taxes and Charges Template 1")
+
+ def test_select_tax_rule_based_cross_matching_keys(self):
+ make_tax_rule(customer= "_Test Customer", billing_city = "Test City",
+ sales_tax_template = "_Test Sales Taxes and Charges Template", save=1)
+
+ make_tax_rule(customer= "_Test Customer 1", billing_city = "Test City 1",
+ sales_tax_template = "_Test Sales Taxes and Charges Template 1", save=1)
+
+ self.assertEquals(get_tax_template("2015-01-01", {"customer":"_Test Customer", "billing_city": "Test City 1"}),
+ None)
+
+ def test_select_tax_rule_based_cross_partially_keys(self):
+ make_tax_rule(customer= "_Test Customer", billing_city = "Test City",
+ sales_tax_template = "_Test Sales Taxes and Charges Template", save=1)
+
+ make_tax_rule(billing_city = "Test City 1",
+ sales_tax_template = "_Test Sales Taxes and Charges Template 1", save=1)
+
+ self.assertEquals(get_tax_template("2015-01-01", {"customer":"_Test Customer", "billing_city": "Test City 1"}),
+ "_Test Sales Taxes and Charges Template 1")
+
+
+def make_tax_rule(**args):
+ args = frappe._dict(args)
+
+ tax_rule = frappe.new_doc("Tax Rule")
+
+ for key, val in args.iteritems():
+ if key != "save":
+ tax_rule.set(key, val)
+
+ tax_rule.company = args.company or "_Test Company"
+
+ if args.save:
+ tax_rule.insert()
+
+ return tax_rule
+
\ No newline at end of file
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index 4f49bc0..a589a69 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -43,6 +43,7 @@
set_contact_details(out, party, party_type)
set_other_values(out, party, party_type)
set_price_list(out, party, party_type, price_list)
+ out["taxes_and_charges"] = set_taxes(party.name, party_type, posting_date, company, out.customer_group, out.supplier_type)
if not out.get("currency"):
out["currency"] = currency
@@ -99,7 +100,7 @@
out[f] = party.get(f)
# fields prepended with default in Customer doctype
- for f in ['currency', 'taxes_and_charges'] \
+ for f in ['currency'] \
+ (['sales_partner', 'commission_rate'] if party_type=="Customer" else []):
if party.get("default_" + f):
out[f] = party.get("default_" + f)
@@ -274,4 +275,31 @@
msgprint(_("Note: Due / Reference Date exceeds allowed customer credit days by {0} day(s)")
.format(date_diff(due_date, default_due_date)))
else:
- frappe.throw(_("Due / Reference Date cannot be after {0}").format(formatdate(default_due_date)))
\ No newline at end of file
+ frappe.throw(_("Due / Reference Date cannot be after {0}").format(formatdate(default_due_date)))
+
+@frappe.whitelist()
+def set_taxes(party, party_type, posting_date, company, customer_group=None, supplier_type=None,
+ billing_address=None, shipping_address=None, use_for_shopping_cart=None):
+ from erpnext.accounts.doctype.tax_rule.tax_rule import get_tax_template, get_party_details
+ args = {
+ party_type: party,
+ "customer_group": customer_group,
+ "supplier_type": supplier_type,
+ "company": company
+ }
+
+ if billing_address or shipping_address:
+ args.update(get_party_details(party, party_type, {"billing_address": billing_address, \
+ "shipping_address": shipping_address }))
+ else:
+ args.update(get_party_details(party, party_type))
+
+ if party_type=="Customer":
+ args.update({"tax_type": "Sales"})
+ else:
+ args.update({"tax_type": "Purchase"})
+
+ if use_for_shopping_cart:
+ args.update({"use_for_shopping_cart": use_for_shopping_cart})
+
+ return get_tax_template(posting_date, args)
\ No newline at end of file
diff --git a/erpnext/config/accounts.py b/erpnext/config/accounts.py
index f32aeed..71a2d70 100644
--- a/erpnext/config/accounts.py
+++ b/erpnext/config/accounts.py
@@ -108,6 +108,11 @@
},
{
"type": "doctype",
+ "name": "Tax Rule",
+ "description": _("Tax Rule for transactions.")
+ },
+ {
+ "type": "doctype",
"name": "Sales Taxes and Charges Template",
"description": _("Tax template for selling transactions.")
},
diff --git a/erpnext/patches/v5_8/tax_rule.py b/erpnext/patches/v5_8/tax_rule.py
new file mode 100644
index 0000000..b710ddc
--- /dev/null
+++ b/erpnext/patches/v5_8/tax_rule.py
@@ -0,0 +1,27 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ customers = frappe.db.sql("""select name, default_taxes_and_charges from tabCustomer where
+ ifnull(default_taxes_and_charges, '') != '' """, as_dict=1)
+
+ for d in customers:
+ tr = frappe.new_doc("Tax Rule")
+ tr.tax_type = "Sales"
+ tr.customer = d.name
+ tr.sales_tax_template = d.default_taxes_and_charges
+ tr.save()
+
+
+ suppliers = frappe.db.sql("""select name, default_taxes_and_charges from tabSupplier where
+ ifnull(default_taxes_and_charges, '') != '' """, as_dict=1)
+
+ for d in suppliers:
+ tr = frappe.new_doc("Tax Rule")
+ tr.tax_type = "Purchase"
+ tr.supplier = d.name
+ tr.purchase_tax_template = d.default_taxes_and_charges
+ tr.save()
\ No newline at end of file
diff --git a/erpnext/public/js/utils/party.js b/erpnext/public/js/utils/party.js
index 919225f..1a86b2b 100644
--- a/erpnext/public/js/utils/party.js
+++ b/erpnext/public/js/utils/party.js
@@ -20,6 +20,7 @@
price_list: frm.doc.buying_price_list
};
}
+ args.posting_date = frm.doc.transaction_date;
}
if(!args) return;
@@ -42,6 +43,7 @@
erpnext.utils.get_address_display = function(frm, address_field, display_field) {
if(frm.updating_party_details) return;
+
if(!address_field) {
if(frm.doc.customer) {
address_field = "customer_address";
@@ -49,14 +51,32 @@
address_field = "supplier_address";
} else return;
}
+
if(!display_field) display_field = "address_display";
if(frm.doc[address_field]) {
frappe.call({
method: "erpnext.utilities.doctype.address.address.get_address_display",
args: {"address_dict": frm.doc[address_field] },
callback: function(r) {
- if(r.message)
+ if(r.message){
frm.set_value(display_field, r.message)
+ }
+ frappe.call({
+ method: "erpnext.accounts.party.set_taxes",
+ args: {
+ "party": frm.doc.customer || frm.doc.supplier,
+ "party_type": (frm.doc.customer ? "Customer" : "Supplier"),
+ "posting_date": frm.doc.posting_date || frm.doc.transaction_date,
+ "company": frm.doc.company,
+ "billing_address": ((frm.doc.customer) ? (frm.doc.customer_address) : (frm.doc.supplier_address)),
+ "shipping_address": frm.doc.shipping_address_name
+ },
+ callback: function(r) {
+ if(r.message){
+ frm.set_value("taxes_and_charges", r.message)
+ }
+ }
+ });
}
})
}
diff --git a/erpnext/setup/doctype/customer_group/test_records.json b/erpnext/setup/doctype/customer_group/test_records.json
index 14d815c..cc3f87e 100644
--- a/erpnext/setup/doctype/customer_group/test_records.json
+++ b/erpnext/setup/doctype/customer_group/test_records.json
@@ -4,5 +4,11 @@
"doctype": "Customer Group",
"is_group": "No",
"parent_customer_group": "All Customer Groups"
+ },
+ {
+ "customer_group_name": "_Test Customer Group 1",
+ "doctype": "Customer Group",
+ "is_group": "No",
+ "parent_customer_group": "All Customer Groups"
}
]
diff --git a/erpnext/shopping_cart/cart.py b/erpnext/shopping_cart/cart.py
index cfba98b..30f4aba 100644
--- a/erpnext/shopping_cart/cart.py
+++ b/erpnext/shopping_cart/cart.py
@@ -266,12 +266,18 @@
def set_taxes(quotation, cart_settings, billing_territory):
"""set taxes based on billing territory"""
- quotation.taxes_and_charges = cart_settings.get_tax_master(billing_territory)
-
- # clear table
+ from erpnext.accounts.party import set_taxes
+
+ customer_group = frappe.db.get_value("Customer", quotation.customer, "customer_group")
+
+ quotation.taxes_and_charges = set_taxes(quotation.customer, "Customer", \
+ quotation.transaction_date, quotation.company, customer_group, None, \
+ quotation.customer_address, quotation.shipping_address_name, 1)
+#
+# # clear table
quotation.set("taxes", [])
-
- # append taxes
+#
+# # append taxes
quotation.append_taxes_from_master()
def get_lead_or_customer():
diff --git a/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.json b/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.json
index 818550e..881ff4e 100644
--- a/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.json
+++ b/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.json
@@ -204,6 +204,27 @@
"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": "shipping_rules",
"fieldtype": "Table",
"hidden": 0,
@@ -221,48 +242,6 @@
"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,
- "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": "sales_taxes_and_charges_masters",
- "fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "label": "Taxes and Charges",
- "no_copy": 0,
- "options": "Shopping Cart Taxes and Charges Master",
- "permlevel": 0,
- "print_hide": 0,
- "read_only": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
}
],
"hide_heading": 0,
@@ -274,7 +253,7 @@
"is_submittable": 0,
"issingle": 1,
"istable": 0,
- "modified": "2015-02-05 05:11:46.714019",
+ "modified": "2015-09-11 19:03:54.750937",
"modified_by": "Administrator",
"module": "Shopping Cart",
"name": "Shopping Cart Settings",
diff --git a/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.py b/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.py
index 8fbf4a4..da7d27a 100644
--- a/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.py
+++ b/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.py
@@ -20,9 +20,9 @@
def validate(self):
if self.enabled:
self.validate_price_lists()
- self.validate_tax_masters()
self.validate_exchange_rates_exist()
-
+ self.validate_tax_rule()
+
def validate_overlapping_territories(self, parentfield, fieldname):
# for displaying message
doctype = self.meta.get_field(parentfield).options
@@ -48,20 +48,14 @@
msgprint(_("Please specify a Price List which is valid for Territory") +
": " + self.default_territory, raise_exception=ShoppingCartSetupError)
- def validate_tax_masters(self):
- self.validate_overlapping_territories("sales_taxes_and_charges_masters",
- "sales_taxes_and_charges_master")
-
def get_territory_name_map(self, parentfield, fieldname):
territory_name_map = {}
# entries in table
names = [doc.get(fieldname) for doc in self.get(parentfield)]
-
if names:
# for condition in territory check
parenttype = frappe.get_meta(self.meta.get_options(parentfield)).get_options(fieldname)
-
# to validate territory overlap
# make a map of territory: [list of names]
# if list against each territory has more than one element, raise exception
@@ -75,7 +69,6 @@
if len(territory_name_map[territory]) > 1:
territory_name_map[territory].sort(key=lambda val: names.index(val))
-
return territory_name_map
def validate_exchange_rates_exist(self):
@@ -112,7 +105,6 @@
def get_name_from_territory(self, territory, parentfield, fieldname):
name = None
territory_name_map = self.get_territory_name_map(parentfield, fieldname)
-
if territory_name_map.get(territory):
name = territory_name_map.get(territory)
else:
@@ -131,7 +123,11 @@
"price_lists", "selling_price_list")
return price_list and price_list[0] or None
-
+
+ def validate_tax_rule(self):
+ if not frappe.db.get_value("Tax Rule", {"use_for_shopping_cart" : 1}, "name"):
+ frappe.throw(frappe._("Set Tax Rule for shopping cart"), ShoppingCartSetupError)
+
def get_tax_master(self, billing_territory):
tax_master = self.get_name_from_territory(billing_territory, "sales_taxes_and_charges_masters",
"sales_taxes_and_charges_master")
@@ -167,52 +163,4 @@
def check_shopping_cart_enabled():
if not get_shopping_cart_settings().enabled:
frappe.throw(_("You need to enable Shopping Cart"), ShoppingCartSetupError)
-
-def apply_shopping_cart_settings(quotation, method):
- """Called via a validate hook on Quotation"""
- from erpnext.shopping_cart import get_party
- if quotation.order_type != "Shopping Cart":
- return
-
- quotation.billing_territory = (get_territory_from_address(quotation.customer_address)
- or get_party(quotation.contact_email).territory or get_default_territory())
- quotation.shipping_territory = (get_territory_from_address(quotation.shipping_address_name)
- or get_party(quotation.contact_email).territory or get_default_territory())
-
- set_price_list(quotation)
- set_taxes_and_charges(quotation)
- quotation.calculate_taxes_and_totals()
- set_shipping_rule(quotation)
-
-def set_price_list(quotation):
- previous_selling_price_list = quotation.selling_price_list
- quotation.selling_price_list = get_shopping_cart_settings().get_price_list(quotation.billing_territory)
-
- if not quotation.selling_price_list:
- quotation.selling_price_list = get_shopping_cart_settings().get_price_list(get_default_territory())
-
- if previous_selling_price_list != quotation.selling_price_list:
- quotation.price_list_currency = quotation.currency = quotation.plc_conversion_rate = quotation.conversion_rate = None
- for d in quotation.get("items"):
- d.price_list_rate = d.discount_percentage = d.rate = d.amount = None
-
- quotation.set_price_list_and_item_details()
-
-def set_taxes_and_charges(quotation):
- previous_taxes_and_charges = quotation.taxes_and_charges
- quotation.taxes_and_charges = get_shopping_cart_settings().get_tax_master(quotation.billing_territory)
-
- if previous_taxes_and_charges != quotation.taxes_and_charges:
- quotation.set_other_charges()
-
-def set_shipping_rule(quotation):
- shipping_rules = get_shopping_cart_settings().get_shipping_rules(quotation.shipping_territory)
- if not shipping_rules:
- quotation.remove_shipping_charge()
- return
-
- if quotation.shipping_rule not in shipping_rules:
- quotation.remove_shipping_charge()
- quotation.shipping_rule = shipping_rules[0]
-
- quotation.apply_shipping_rule()
+
diff --git a/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py b/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py
index 46cbfdf..b18cece 100644
--- a/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py
+++ b/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py
@@ -12,7 +12,6 @@
def setUp(self):
frappe.db.sql("""delete from `tabSingles` where doctype="Shipping Cart Settings" """)
frappe.db.sql("""delete from `tabShopping Cart Price List`""")
- frappe.db.sql("""delete from `tabShopping Cart Taxes and Charges Master`""")
frappe.db.sql("""delete from `tabShopping Cart Shipping Rule`""")
def get_cart_settings(self):
@@ -43,28 +42,6 @@
return cart_settings
- def test_taxes_territory_overlap(self):
- cart_settings = self.get_cart_settings()
-
- def _add_tax_master(tax_master):
- cart_settings.append("sales_taxes_and_charges_masters", {
- "doctype": "Shopping Cart Taxes and Charges Master",
- "sales_taxes_and_charges_master": tax_master
- })
-
- for tax_master in ("_Test Sales Taxes and Charges Template", "_Test India Tax Master"):
- _add_tax_master(tax_master)
-
- controller = cart_settings
- controller.validate_overlapping_territories("sales_taxes_and_charges_masters",
- "sales_taxes_and_charges_master")
-
- _add_tax_master("_Test Sales Taxes and Charges Template - Rest of the World")
-
- controller = cart_settings
- self.assertRaises(ShoppingCartSetupError, controller.validate_overlapping_territories,
- "sales_taxes_and_charges_masters", "sales_taxes_and_charges_master")
-
def test_exchange_rate_exists(self):
frappe.db.sql("""delete from `tabCurrency Exchange`""")
@@ -77,3 +54,12 @@
frappe.get_doc(currency_exchange_records[0]).insert()
controller.validate_exchange_rates_exist()
+ def test_tax_rule_validation(self):
+ frappe.db.sql("update `tabTax Rule` set use_for_shopping_cart = 0")
+ frappe.db.commit()
+
+ cart_settings = self.get_cart_settings()
+ cart_settings.enabled = 1
+ if not frappe.db.get_value("Tax Rule", {"use_for_shopping_cart": 1}, "name"):
+ self.assertRaises(ShoppingCartSetupError, cart_settings.validate_tax_rule)
+
diff --git a/erpnext/shopping_cart/doctype/shopping_cart_taxes_and_charges_master/shopping_cart_taxes_and_charges_master.json b/erpnext/shopping_cart/doctype/shopping_cart_taxes_and_charges_master/shopping_cart_taxes_and_charges_master.json
deleted file mode 100644
index e15dcab..0000000
--- a/erpnext/shopping_cart/doctype/shopping_cart_taxes_and_charges_master/shopping_cart_taxes_and_charges_master.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
- "allow_copy": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "creation": "2013-06-20 16:57:03",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "fields": [
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "fieldname": "sales_taxes_and_charges_master",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "in_filter": 0,
- "in_list_view": 1,
- "label": "Tax Master",
- "no_copy": 0,
- "options": "Sales Taxes and Charges Template",
- "permlevel": 0,
- "print_hide": 0,
- "read_only": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- }
- ],
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 1,
- "in_create": 0,
- "in_dialog": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "modified": "2013-12-20 19:30:47",
- "modified_by": "Administrator",
- "module": "Shopping Cart",
- "name": "Shopping Cart Taxes and Charges Master",
- "owner": "Administrator",
- "permissions": [],
- "read_only": 0,
- "read_only_onload": 0
-}
\ No newline at end of file
diff --git a/erpnext/shopping_cart/doctype/shopping_cart_taxes_and_charges_master/shopping_cart_taxes_and_charges_master.py b/erpnext/shopping_cart/doctype/shopping_cart_taxes_and_charges_master/shopping_cart_taxes_and_charges_master.py
deleted file mode 100644
index d2ec545..0000000
--- a/erpnext/shopping_cart/doctype/shopping_cart_taxes_and_charges_master/shopping_cart_taxes_and_charges_master.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
-# License: GNU General Public License v3. See license.txt
-
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-import frappe
-
-from frappe.model.document import Document
-
-class ShoppingCartTaxesandChargesMaster(Document):
- pass
diff --git a/erpnext/shopping_cart/test_shopping_cart.py b/erpnext/shopping_cart/test_shopping_cart.py
index 1873b81..bd0b138 100644
--- a/erpnext/shopping_cart/test_shopping_cart.py
+++ b/erpnext/shopping_cart/test_shopping_cart.py
@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import unittest
import frappe
-from erpnext.shopping_cart import get_quotation, set_item_in_cart
+from erpnext.shopping_cart import get_quotation, set_item_in_cart, get_party
class TestShoppingCart(unittest.TestCase):
"""
@@ -109,6 +109,53 @@
quotation = self.test_get_cart_lead()
self.assertEquals(quotation.net_total, 0)
self.assertEquals(len(quotation.get("items")), 0)
+
+
+ def test_taxe_rule(self):
+ self.login_as_customer()
+ quotation = self.create_quotation()
+
+ from erpnext.accounts.party import set_taxes
+
+ tax_rule_master = set_taxes(quotation.customer, "Customer", \
+ quotation.transaction_date, quotation.company, None, None, \
+ quotation.customer_address, quotation.shipping_address_name, 1)
+
+ self.assertEquals(quotation.taxes_and_charges, tax_rule_master)
+ self.assertEquals(quotation.total_taxes_and_charges, 1000.0)
+
+ self.remove_test_quotation(quotation)
+
+ def create_quotation(self):
+ quotation = frappe.new_doc("Quotation")
+
+ values = {
+ "doctype": "Quotation",
+ "quotation_to": "Customer",
+ "order_type": "Shopping Cart",
+ "customer": get_party(frappe.session.user).name,
+ "docstatus": 0,
+ "contact_email": frappe.session.user,
+ "selling_price_list": "_Test Price List Rest of the World",
+ "currency": "USD",
+ "taxes_and_charges" : "_Test Tax 1",
+ "items": [{
+ "item_code": "_Test Item",
+ "qty": 1
+ }],
+ "taxes": frappe.get_doc("Sales Taxes and Charges Template", "_Test Tax 1").taxes,
+ "company": "_Test Company"
+ }
+
+ quotation.update(values)
+
+ quotation.insert(ignore_permissions=True)
+
+ return quotation
+
+ def remove_test_quotation(self, quotation):
+ frappe.set_user("Administrator")
+ quotation.delete()
# helper functions
def enable_shopping_cart(self):
@@ -131,15 +178,9 @@
{"doctype": "Shopping Cart Price List", "parentfield": "price_lists",
"selling_price_list": "_Test Price List Rest of the World"}
])
- settings.set("sales_taxes_and_charges_masters", [
- # tax masters
- {"doctype": "Shopping Cart Taxes and Charges Master", "parentfield": "sales_taxes_and_charges_masters",
- "sales_taxes_and_charges_master": "_Test India Tax Master"},
- {"doctype": "Shopping Cart Taxes and Charges Master", "parentfield": "sales_taxes_and_charges_masters",
- "sales_taxes_and_charges_master": "_Test Sales Taxes and Charges Template - Rest of the World"},
- ])
settings.set("shipping_rules", {"doctype": "Shopping Cart Shipping Rule", "parentfield": "shipping_rules",
"shipping_rule": "_Test Shipping Rule - India"})
+
settings.save()
frappe.local.shopping_cart_settings = None
@@ -203,7 +244,6 @@
quotation = get_quotation()
quotation.set("items", [])
quotation.save(ignore_permissions=True)
-
-
+
test_dependencies = ["Sales Taxes and Charges Template", "Price List", "Item Price", "Shipping Rule", "Currency Exchange",
- "Customer Group", "Lead", "Customer", "Contact", "Address", "Item"]
+ "Customer Group", "Lead", "Customer", "Contact", "Address", "Item", "Tax Rule"]
diff --git a/erpnext/utilities/doctype/address/test_records.json b/erpnext/utilities/doctype/address/test_records.json
index 41a6abc..a7bde9a 100644
--- a/erpnext/utilities/doctype/address/test_records.json
+++ b/erpnext/utilities/doctype/address/test_records.json
@@ -3,7 +3,8 @@
"address_line1": "_Test Address Line 1",
"address_title": "_Test Address",
"address_type": "Office",
- "city": "_Test City",
+ "city": "_Test City",
+ "state": "Test State",
"country": "India",
"customer": "_Test Customer",
"customer_name": "_Test Customer",