diff --git a/erpnext/__init__.py b/erpnext/__init__.py index bb94383aed..eb60e754ed 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -74,7 +74,7 @@ def is_perpetual_inventory_enabled(company): frappe.local.enable_perpetual_inventory = {} if not company in frappe.local.enable_perpetual_inventory: - frappe.local.enable_perpetual_inventory[company] = frappe.get_cached_value('Company', + frappe.local.enable_perpetual_inventory[company] = frappe.get_cached_value('Company', company, "enable_perpetual_inventory") or 0 return frappe.local.enable_perpetual_inventory[company] @@ -87,7 +87,7 @@ def get_default_finance_book(company=None): frappe.local.default_finance_book = {} if not company in frappe.local.default_finance_book: - frappe.local.default_finance_book[company] = frappe.get_cached_value('Company', + frappe.local.default_finance_book[company] = frappe.get_cached_value('Company', company, "default_finance_book") return frappe.local.default_finance_book[company] @@ -108,7 +108,7 @@ def get_region(company=None): You can also set global company flag in `frappe.flags.company` ''' if company or frappe.flags.company: - return frappe.get_cached_value('Company', + return frappe.get_cached_value('Company', company or frappe.flags.company, 'country') elif frappe.flags.country: return frappe.flags.country @@ -144,4 +144,4 @@ def is_member(): last_membership = get_last_membership() if last_membership and getdate(last_membership.to_date) > getdate(): return True - return False \ No newline at end of file + return False 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 e6200659cf..9e4c08da7c 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 @@ -15,6 +15,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -44,10 +45,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -77,10 +80,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -99,7 +104,7 @@ "no_copy": 0, "oldfieldname": "charge_type", "oldfieldtype": "Select", - "options": "\nActual\nOn Net Total\nOn Previous Row Amount\nOn Previous Row Total", + "options": "\nActual\nOn Net Total\nOn Previous Row Amount\nOn Previous Row Total\nOn Item Quantity", "permlevel": 0, "print_hide": 0, "print_hide_if_no_value": 0, @@ -109,10 +114,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -141,10 +148,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -172,10 +181,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -200,10 +211,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -232,10 +245,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -265,10 +280,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -297,11 +314,13 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "300px" }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -327,10 +346,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -358,10 +379,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -387,10 +410,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -419,10 +444,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -450,10 +477,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -482,10 +511,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -511,10 +542,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -542,10 +575,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -573,10 +608,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -604,10 +641,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -635,10 +674,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -666,6 +707,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -679,7 +721,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-12-06 13:37:44.483509", + "modified": "2018-09-19 13:48:32.755198", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Taxes and Charges", @@ -690,5 +732,6 @@ "read_only_onload": 0, "show_name_in_global_search": 0, "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file 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 477ee3b008..9d842a7cde 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 @@ -33,7 +33,7 @@ "no_copy": 0, "oldfieldname": "charge_type", "oldfieldtype": "Select", - "options": "\nActual\nOn Net Total\nOn Previous Row Amount\nOn Previous Row Total", + "options": "\nActual\nOn Net Total\nOn Previous Row Amount\nOn Previous Row Total\nOn Item Quantity", "permlevel": 0, "print_hide": 0, "print_hide_if_no_value": 0, @@ -652,7 +652,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-08-21 16:15:51.518582", + "modified": "2018-09-19 13:48:59.341454", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Taxes and Charges", @@ -666,4 +666,4 @@ "track_changes": 0, "track_seen": 0, "track_views": 0 -} \ No newline at end of file +} diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py index 6985c80bc1..684e239b25 100644 --- a/erpnext/controllers/taxes_and_totals.py +++ b/erpnext/controllers/taxes_and_totals.py @@ -270,6 +270,8 @@ class calculate_taxes_and_totals(object): elif tax.charge_type == "On Previous Row Total": current_tax_amount = (tax_rate / 100.0) * \ self.doc.get("taxes")[cint(tax.row_id) - 1].grand_total_for_current_item + elif tax.charge_type == "On Item Quantity": + current_tax_amount = tax_rate * item.stock_qty self.set_item_wise_tax(item, tax, tax_rate, current_tax_amount) @@ -646,4 +648,4 @@ def get_rounded_tax_amount(itemised_tax, precision): # Rounding based on tax_amount precision for taxes in itemised_tax.values(): for tax_account in taxes: - taxes[tax_account]["tax_amount"] = flt(taxes[tax_account]["tax_amount"], precision) \ No newline at end of file + taxes[tax_account]["tax_amount"] = flt(taxes[tax_account]["tax_amount"], precision) diff --git a/erpnext/controllers/tests/test_qty_based_taxes.py b/erpnext/controllers/tests/test_qty_based_taxes.py new file mode 100644 index 0000000000..d6eb6fd269 --- /dev/null +++ b/erpnext/controllers/tests/test_qty_based_taxes.py @@ -0,0 +1,94 @@ +from __future__ import unicode_literals, print_function +import unittest +import frappe +from uuid import uuid4 as _uuid4 + +def uuid4(): + return str(_uuid4()) + +class TestTaxes(unittest.TestCase): + def setUp(self): + self.company = frappe.get_doc({ + 'doctype': 'Company', + 'company_name': uuid4(), + 'abbr': ''.join(s[0] for s in uuid4().split('-')), + 'default_currency': 'USD', + 'country': 'United States', + }).insert() + self.account = frappe.get_doc({ + 'doctype': 'Account', + 'account_name': uuid4(), + 'account_type': 'Tax', + 'company': self.company.name, + 'parent_account': 'Duties and Taxes - {self.company.abbr}'.format(self=self) + }).insert() + self.item_group = frappe.get_doc({ + 'doctype': 'Item Group', + 'item_group_name': uuid4(), + 'parent_item_group': 'All Item Groups', + }).insert() + self.item = frappe.get_doc({ + 'doctype': 'Item', + 'item_code': uuid4(), + 'item_group': self.item_group.name, + 'is_stock_item': 0, + 'taxes': [ + { + 'tax_type': self.account.name, + 'tax_rate': 2, + } + ], + }).insert() + self.customer = frappe.get_doc({ + 'doctype': 'Customer', + 'customer_name': uuid4(), + 'customer_group': 'All Customer Groups', + }).insert() + self.supplier = frappe.get_doc({ + 'doctype': 'Supplier', + 'supplier_name': uuid4(), + 'supplier_group': 'All Supplier Groups', + }).insert() + + def test_taxes(self): + self.created_docs = [] + for dt in ['Purchase Order', 'Purchase Receipt', 'Purchase Invoice', + 'Quotation', 'Sales Order', 'Delivery Note', 'Sales Invoice']: + doc = frappe.get_doc({ + 'doctype': dt, + 'company': self.company.name, + 'supplier': self.supplier.name, + 'schedule_date': frappe.utils.nowdate(), + 'delivery_date': frappe.utils.nowdate(), + 'customer': self.customer.name, + 'buying_price_list' if dt.startswith('Purchase') else 'selling_price_list' + : 'Standard Buying' if dt.startswith('Purchase') else 'Standard Selling', + 'items': [ + { + 'item_code': self.item.name, + 'qty': 300, + 'rate': 100, + } + ], + 'taxes': [ + { + 'charge_type': 'On Item Quantity', + 'account_head': self.account.name, + 'description': 'N/A', + 'rate': 0, + }, + ], + }) + doc.run_method('set_missing_values') + doc.run_method('calculate_taxes_and_totals') + doc.insert() + self.assertEqual(doc.taxes[0].tax_amount, 600) + self.created_docs.append(doc) + + def tearDown(self): + for doc in self.created_docs: + doc.delete() + self.item.delete() + self.item_group.delete() + self.account.delete() + self.company.delete() diff --git a/erpnext/regional/__init__.py b/erpnext/regional/__init__.py index 510ed58766..cdbecd0e8c 100644 --- a/erpnext/regional/__init__.py +++ b/erpnext/regional/__init__.py @@ -6,6 +6,6 @@ from frappe import _ from erpnext import get_region def check_deletion_permission(doc, method): - region = get_region() + region = get_region(doc.company) if region in ["Nepal", "France"]: - frappe.throw(_("Deletion is not permitted for country {0}".format(region))) \ No newline at end of file + frappe.throw(_("Deletion is not permitted for country {0}".format(region)))