diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json index 25ac8ffcc3..c1801eb20a 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 a00184bf01..9e43ca05f8 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 29534d832d..a0d8df47b1 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 656d29c461..69dbd8e9a6 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 0000000000..4b059dc564 --- /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 0000000000..60011dd9a3 --- /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 0000000000..0a9bb1114b --- /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 0000000000..0913fba4fb --- /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 0000000000..3e175fabf7 --- /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 4f49bc07fd..a589a694dd 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -43,6 +43,7 @@ def _get_party_details(party=None, account=None, party_type="Customer", company= 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 @@ def set_other_values(out, party, party_type): 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 @@ def validate_due_date(posting_date, due_date, party_type, party, company): 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 f32aeed022..71a2d700a6 100644 --- a/erpnext/config/accounts.py +++ b/erpnext/config/accounts.py @@ -106,6 +106,11 @@ def get_data(): "name": "Accounts Settings", "description": _("Default settings for accounting transactions.") }, + { + "type": "doctype", + "name": "Tax Rule", + "description": _("Tax Rule for transactions.") + }, { "type": "doctype", "name": "Sales Taxes and Charges Template", diff --git a/erpnext/patches/v5_8/tax_rule.py b/erpnext/patches/v5_8/tax_rule.py new file mode 100644 index 0000000000..b710ddcbe4 --- /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 919225f9a9..1a86b2b620 100644 --- a/erpnext/public/js/utils/party.js +++ b/erpnext/public/js/utils/party.js @@ -20,6 +20,7 @@ erpnext.utils.get_party_details = function(frm, method, args, callback) { price_list: frm.doc.buying_price_list }; } + args.posting_date = frm.doc.transaction_date; } if(!args) return; @@ -42,6 +43,7 @@ erpnext.utils.get_party_details = function(frm, method, args, callback) { 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 @@ erpnext.utils.get_address_display = function(frm, address_field, display_field) 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 14d815ce76..cc3f87e098 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 cfba98b4ab..30f4aba493 100644 --- a/erpnext/shopping_cart/cart.py +++ b/erpnext/shopping_cart/cart.py @@ -266,12 +266,18 @@ def _set_price_list(quotation, cart_settings, billing_territory): 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 818550e75f..881ff4e377 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 @@ -200,6 +200,27 @@ "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, + "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, @@ -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 8fbf4a430e..da7d27af10 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 @@ class ShoppingCartSettings(Document): 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 @@ class ShoppingCartSettings(Document): 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 @@ class ShoppingCartSettings(Document): 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 @@ class ShoppingCartSettings(Document): 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 @@ class ShoppingCartSettings(Document): "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 get_default_territory(): 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 46cbfdf9ed..b18cece44a 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 @@ class TestShoppingCartSettings(unittest.TestCase): 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 @@ class TestShoppingCartSettings(unittest.TestCase): 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 @@ class TestShoppingCartSettings(unittest.TestCase): 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 e15dcab5af..0000000000 --- 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 d2ec545c7e..0000000000 --- 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 1873b813be..bd0b138d45 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 @@ class TestShoppingCart(unittest.TestCase): 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 @@ class TestShoppingCart(unittest.TestCase): {"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 @@ class TestShoppingCart(unittest.TestCase): 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 41a6abcd09..a7bde9a814 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",