Merge branch 'develop' into UAE-VAT-Format
diff --git a/erpnext/accounts/desk_page/accounting/accounting.json b/erpnext/accounts/desk_page/accounting/accounting.json
index b0371e7..64e2b24 100644
--- a/erpnext/accounts/desk_page/accounting/accounting.json
+++ b/erpnext/accounts/desk_page/accounting/accounting.json
@@ -79,6 +79,11 @@
"hidden": 0,
"label": "Profitability",
"links": "[\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Gross Profit\",\n \"name\": \"Gross Profit\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Profitability Analysis\",\n \"name\": \"Profitability Analysis\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Invoice Trends\",\n \"name\": \"Sales Invoice Trends\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Purchase Invoice Trends\",\n \"name\": \"Purchase Invoice Trends\",\n \"type\": \"report\"\n }\n]"
+ },
+ {
+ "hidden": 0,
+ "label": "Value-Added Tax (VAT UAE)",
+ "links": "[\n {\n \"label\": \"UAE VAT Settings\",\n \"name\": \"UAE VAT Settings\",\n \"type\": \"doctype\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"UAE VAT 201\",\n \"name\": \"UAE VAT 201\",\n \"type\": \"report\"\n }\n]"
}
],
"category": "Modules",
@@ -153,4 +158,4 @@
"type": "Dashboard"
}
]
-}
\ No newline at end of file
+}
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index 2e5a714..f2499d2 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -998,7 +998,7 @@
'expense_account': args.expense_account or '_Test Account Cost for Goods Sold - _TC',
"conversion_factor": 1.0,
"serial_no": args.serial_no,
- "stock_uom": "_Test UOM",
+ "stock_uom": args.uom or "_Test UOM",
"cost_center": args.cost_center or "_Test Cost Center - _TC",
"project": args.project,
"rejected_warehouse": args.rejected_warehouse or "",
@@ -1040,7 +1040,8 @@
pi.is_return = args.is_return
pi.credit_to = args.return_against or "Creditors - _TC"
pi.is_subcontracted = args.is_subcontracted or "No"
- pi.supplier_warehouse = "_Test Warehouse 1 - _TC"
+ if args.supplier_warehouse:
+ pi.supplier_warehouse = "_Test Warehouse 1 - _TC"
pi.append("items", {
"item_code": args.item or args.item_code or "_Test Item",
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index dbb6c0d..e7e0c81 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -250,7 +250,11 @@
"on_trash": "erpnext.regional.check_deletion_permission"
},
"Purchase Invoice": {
- "validate": "erpnext.regional.india.utils.update_grand_total_for_rcm"
+ "validate": [
+ "erpnext.regional.india.utils.update_grand_total_for_rcm",
+ "erpnext.regional.united_arab_emirates.utils.update_grand_total_for_rcm",
+ "erpnext.regional.united_arab_emirates.utils.validate_returns"
+ ]
},
"Payment Entry": {
"on_submit": ["erpnext.regional.create_transaction_log", "erpnext.accounts.doctype.payment_request.payment_request.update_payment_req_status", "erpnext.accounts.doctype.dunning.dunning.resolve_dunning"],
@@ -390,7 +394,8 @@
'erpnext.accounts.doctype.purchase_invoice.purchase_invoice.make_regional_gl_entries': 'erpnext.regional.india.utils.make_regional_gl_entries'
},
'United Arab Emirates': {
- 'erpnext.controllers.taxes_and_totals.update_itemised_tax_data': 'erpnext.regional.united_arab_emirates.utils.update_itemised_tax_data'
+ 'erpnext.controllers.taxes_and_totals.update_itemised_tax_data': 'erpnext.regional.united_arab_emirates.utils.update_itemised_tax_data',
+ 'erpnext.accounts.doctype.purchase_invoice.purchase_invoice.make_regional_gl_entries': 'erpnext.regional.united_arab_emirates.utils.make_regional_gl_entries',
},
'Saudi Arabia': {
'erpnext.controllers.taxes_and_totals.update_itemised_tax_data': 'erpnext.regional.united_arab_emirates.utils.update_itemised_tax_data'
diff --git a/erpnext/regional/doctype/uae_vat_account/__init__.py b/erpnext/regional/doctype/uae_vat_account/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/regional/doctype/uae_vat_account/__init__.py
diff --git a/erpnext/regional/doctype/uae_vat_account/uae_vat_account.json b/erpnext/regional/doctype/uae_vat_account/uae_vat_account.json
new file mode 100644
index 0000000..73a8169
--- /dev/null
+++ b/erpnext/regional/doctype/uae_vat_account/uae_vat_account.json
@@ -0,0 +1,35 @@
+{
+ "actions": [],
+ "autoname": "account",
+ "creation": "2020-09-28 11:30:45.472053",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "account"
+ ],
+ "fields": [
+ {
+ "allow_in_quick_entry": 1,
+ "fieldname": "account",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_preview": 1,
+ "label": "Account",
+ "options": "Account"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2020-09-28 12:02:56.444007",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "UAE VAT Account",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/regional/doctype/uae_vat_account/uae_vat_account.py b/erpnext/regional/doctype/uae_vat_account/uae_vat_account.py
new file mode 100644
index 0000000..80d6b3a
--- /dev/null
+++ b/erpnext/regional/doctype/uae_vat_account/uae_vat_account.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class UAEVATAccount(Document):
+ pass
diff --git a/erpnext/regional/doctype/uae_vat_settings/__init__.py b/erpnext/regional/doctype/uae_vat_settings/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/regional/doctype/uae_vat_settings/__init__.py
diff --git a/erpnext/regional/doctype/uae_vat_settings/test_uae_vat_settings.py b/erpnext/regional/doctype/uae_vat_settings/test_uae_vat_settings.py
new file mode 100644
index 0000000..b88439f
--- /dev/null
+++ b/erpnext/regional/doctype/uae_vat_settings/test_uae_vat_settings.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+# import frappe
+import unittest
+
+class TestUAEVATSettings(unittest.TestCase):
+ pass
diff --git a/erpnext/regional/doctype/uae_vat_settings/uae_vat_settings.js b/erpnext/regional/doctype/uae_vat_settings/uae_vat_settings.js
new file mode 100644
index 0000000..07a9301
--- /dev/null
+++ b/erpnext/regional/doctype/uae_vat_settings/uae_vat_settings.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('UAE VAT Settings', {
+ // refresh: function(frm) {
+
+ // }
+});
diff --git a/erpnext/regional/doctype/uae_vat_settings/uae_vat_settings.json b/erpnext/regional/doctype/uae_vat_settings/uae_vat_settings.json
new file mode 100644
index 0000000..ce2c1d4
--- /dev/null
+++ b/erpnext/regional/doctype/uae_vat_settings/uae_vat_settings.json
@@ -0,0 +1,55 @@
+{
+ "actions": [],
+ "autoname": "field:company",
+ "creation": "2020-09-25 12:48:51.463265",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "company",
+ "uae_vat_accounts"
+ ],
+ "fields": [
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1,
+ "unique": 1
+ },
+ {
+ "fieldname": "uae_vat_accounts",
+ "fieldtype": "Table",
+ "label": "UAE VAT Accounts",
+ "options": "UAE VAT Account",
+ "reqd": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2020-09-30 20:08:18.764798",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "UAE VAT Settings",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/regional/doctype/uae_vat_settings/uae_vat_settings.py b/erpnext/regional/doctype/uae_vat_settings/uae_vat_settings.py
new file mode 100644
index 0000000..20dc604
--- /dev/null
+++ b/erpnext/regional/doctype/uae_vat_settings/uae_vat_settings.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class UAEVATSettings(Document):
+ pass
diff --git a/erpnext/regional/report/uae_vat_201/__init__.py b/erpnext/regional/report/uae_vat_201/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/regional/report/uae_vat_201/__init__.py
diff --git a/erpnext/regional/report/uae_vat_201/test_uae_vat_201.py b/erpnext/regional/report/uae_vat_201/test_uae_vat_201.py
new file mode 100644
index 0000000..5fdb264
--- /dev/null
+++ b/erpnext/regional/report/uae_vat_201/test_uae_vat_201.py
@@ -0,0 +1,299 @@
+# coding=utf-8
+from __future__ import unicode_literals
+
+import erpnext
+import frappe
+from unittest import TestCase
+from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
+from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
+from erpnext.stock.doctype.warehouse.test_warehouse import get_warehouse_account
+from erpnext.regional.report.uae_vat_201.uae_vat_201 import (
+ get_total_emiratewise,
+ get_tourist_tax_return_total,
+ get_tourist_tax_return_tax,
+ get_zero_rated_total,
+ get_exempt_total,
+ get_standard_rated_expenses_total,
+ get_standard_rated_expenses_tax,
+)
+
+test_dependencies = ["Territory", "Customer Group", "Supplier Group", "Item"]
+
+class TestUaeVat201(TestCase):
+ def setUp(self):
+ frappe.set_user("Administrator")
+
+ frappe.db.sql("delete from `tabSales Invoice` where company='_Test Company UAE VAT'")
+ frappe.db.sql("delete from `tabPurchase Invoice` where company='_Test Company UAE VAT'")
+
+
+ make_company("_Test Company UAE VAT", "_TCUV")
+ set_vat_accounts()
+
+ make_customer()
+
+ make_supplier()
+
+ create_warehouse("_Test UAE VAT Supplier Warehouse", company="_Test Company UAE VAT")
+
+ make_item("_Test UAE VAT Item", properties = {"is_zero_rated": 0, "is_exempt": 0})
+ make_item("_Test UAE VAT Zero Rated Item", properties = {"is_zero_rated": 1, "is_exempt": 0})
+ make_item("_Test UAE VAT Exempt Item", properties = {"is_zero_rated": 0, "is_exempt": 1})
+
+ make_sales_invoices()
+
+ create_purchase_invoices()
+
+ def test_uae_vat_201_report(self):
+ filters = {"company": "_Test Company UAE VAT"}
+ total_emiratewise = get_total_emiratewise(filters)
+ amounts_by_emirate = {}
+ for data in total_emiratewise:
+ emirate, amount, vat = data
+ amounts_by_emirate[emirate] = {
+ "raw_amount": amount,
+ "raw_vat_amount": vat,
+ }
+ self.assertEqual(amounts_by_emirate["Sharjah"]["raw_amount"],300)
+ self.assertEqual(amounts_by_emirate["Sharjah"]["raw_vat_amount"],5)
+ self.assertEqual(amounts_by_emirate["Dubai"]["raw_amount"],200)
+ self.assertEqual(amounts_by_emirate["Dubai"]["raw_vat_amount"],10)
+ self.assertEqual(get_tourist_tax_return_total(filters),100)
+ self.assertEqual(get_tourist_tax_return_tax(filters),2)
+ self.assertEqual(get_zero_rated_total(filters),100)
+ self.assertEqual(get_exempt_total(filters),100)
+ self.assertEqual(get_standard_rated_expenses_total(filters),250)
+ self.assertEqual(get_standard_rated_expenses_tax(filters),1)
+
+def make_company(company_name, abbr):
+ if not frappe.db.exists("Company", company_name):
+ company = frappe.get_doc({
+ "doctype": "Company",
+ "company_name": company_name,
+ "abbr": abbr,
+ "default_currency": "AED",
+ "country": "United Arab Emirates",
+ "create_chart_of_accounts_based_on": "Standard Template",
+ })
+ company.insert()
+ else:
+ company = frappe.get_doc("Company", company_name)
+
+ # indempotent
+ company.create_default_warehouses()
+
+ if not frappe.db.get_value("Cost Center", {"is_group": 0, "company": company.name}):
+ company.create_default_cost_center()
+
+ company.save()
+ return company
+
+def set_vat_accounts():
+ if not frappe.db.exists("UAE VAT Settings", "_Test Company UAE VAT"):
+ vat_accounts = frappe.get_all(
+ "Account",
+ fields=["name"],
+ filters = {
+ "company": "_Test Company UAE VAT",
+ "is_group": 0,
+ "account_type": "Tax"
+ }
+ )
+
+ uae_vat_accounts = []
+ for account in vat_accounts:
+ uae_vat_accounts.append({
+ "doctype": "UAE VAT Account",
+ "account": account.name
+ })
+
+ frappe.get_doc({
+ "company": "_Test Company UAE VAT",
+ "uae_vat_accounts": uae_vat_accounts,
+ "doctype": "UAE VAT Settings",
+ }).insert()
+
+def make_customer():
+ if not frappe.db.exists("Customer", "_Test UAE Customer"):
+ customer = frappe.get_doc({
+ "doctype": "Customer",
+ "customer_name": "_Test UAE Customer",
+ "customer_type": "Company",
+ })
+ customer.insert()
+ else:
+ customer = frappe.get_doc("Customer", "_Test UAE Customer")
+
+def make_supplier():
+
+ if not frappe.db.exists("Supplier", "_Test UAE Supplier"):
+ frappe.get_doc({
+ "supplier_group": "Local",
+ "supplier_name": "_Test UAE Supplier",
+ "supplier_type": "Individual",
+ "doctype": "Supplier",
+ }).insert()
+
+def create_warehouse(warehouse_name, properties=None, company=None):
+ if not company:
+ company = "_Test Company"
+
+ warehouse_id = erpnext.encode_company_abbr(warehouse_name, company)
+ if not frappe.db.exists("Warehouse", warehouse_id):
+ w = frappe.new_doc("Warehouse")
+ w.warehouse_name = warehouse_name
+ w.parent_warehouse = "All Warehouses - _TCUV"
+ w.company = company
+ w.account = get_warehouse_account(warehouse_name, company)
+ if properties:
+ w.update(properties)
+ w.save()
+ return w.name
+ else:
+ return warehouse_id
+
+def make_item(item_code, properties=None):
+ if frappe.db.exists("Item", item_code):
+ return frappe.get_doc("Item", item_code)
+
+ item = frappe.get_doc({
+ "doctype": "Item",
+ "item_code": item_code,
+ "item_name": item_code,
+ "description": item_code,
+ "item_group": "Products"
+ })
+
+ if properties:
+ item.update(properties)
+
+ item.insert()
+
+ return item
+
+def make_sales_invoices():
+ si = create_sales_invoice(company="_Test Company UAE VAT",
+ customer = '_Test UAE Customer',
+ currency = 'AED',
+ warehouse = 'Finished Goods - _TCUV',
+ debit_to = 'Debtors - _TCUV',
+ income_account = 'Sales - _TCUV',
+ expense_account = 'Cost of Goods Sold - _TCUV',
+ cost_center = 'Main - _TCUV',
+ sales_taxes_and_charges_template = "UAE VAT 5% - _TCUV",
+ item = "_Test UAE VAT Item",
+ do_not_save=1
+ )
+ si.append("taxes", {
+ "charge_type": "On Net Total",
+ "account_head": "VAT 5% - _TCUV",
+ "cost_center": "Main - _TCUV",
+ "description": "VAT 5% @ 5.0",
+ "rate": 5.0
+ })
+ si.vat_emirate = 'Dubai'
+ si.submit()
+
+ si = create_sales_invoice(company="_Test Company UAE VAT",
+ customer = '_Test UAE Customer',
+ currency = 'AED',
+ warehouse = 'Finished Goods - _TCUV',
+ debit_to = 'Debtors - _TCUV',
+ income_account = 'Sales - _TCUV',
+ expense_account = 'Cost of Goods Sold - _TCUV',
+ cost_center = 'Main - _TCUV',
+ sales_taxes_and_charges_template = "UAE VAT 5% - _TCUV",
+ item = "_Test UAE VAT Item",
+ do_not_save=1
+ )
+ si.vat_emirate = 'Sharjah'
+ si.append("taxes", {
+ "charge_type": "On Net Total",
+ "account_head": "VAT 5% - _TCUV",
+ "cost_center": "Main - _TCUV",
+ "description": "VAT 5% @ 5.0",
+ "rate": 5.0
+ })
+ si.submit()
+
+ si = create_sales_invoice(company="_Test Company UAE VAT",
+ customer = '_Test UAE Customer',
+ currency = 'AED',
+ warehouse = 'Finished Goods - _TCUV',
+ debit_to = 'Debtors - _TCUV',
+ income_account = 'Sales - _TCUV',
+ expense_account = 'Cost of Goods Sold - _TCUV',
+ cost_center = 'Main - _TCUV',
+ sales_taxes_and_charges_template = "UAE VAT 5% - _TCUV",
+ item = "_Test UAE VAT Item",
+ do_not_save=1
+ )
+
+ si.tourist_tax_return = 2
+
+ si.vat_emirate = 'Dubai'
+
+ si.append("taxes", {
+ "charge_type": "On Net Total",
+ "account_head": "VAT 5% - _TCUV",
+ "cost_center": "Main - _TCUV",
+ "description": "VAT 5% @ 5.0",
+ "rate": 5.0
+ })
+ si.submit()
+
+ si = create_sales_invoice(company="_Test Company UAE VAT",
+ customer = '_Test UAE Customer',
+ currency = 'AED',
+ warehouse = 'Finished Goods - _TCUV',
+ debit_to = 'Debtors - _TCUV',
+ income_account = 'Sales - _TCUV',
+ expense_account = 'Cost of Goods Sold - _TCUV',
+ cost_center = 'Main - _TCUV',
+ sales_taxes_and_charges_template = "UAE VAT 5% - _TCUV",
+ item = "_Test UAE VAT Zero Rated Item",
+ do_not_save=1
+ )
+ si.vat_emirate = 'Sharjah'
+ si.submit()
+
+ si = create_sales_invoice(company="_Test Company UAE VAT",
+ customer = '_Test UAE Customer',
+ currency = 'AED',
+ warehouse = 'Finished Goods - _TCUV',
+ debit_to = 'Debtors - _TCUV',
+ income_account = 'Sales - _TCUV',
+ expense_account = 'Cost of Goods Sold - _TCUV',
+ cost_center = 'Main - _TCUV',
+ sales_taxes_and_charges_template = "UAE VAT 5% - _TCUV",
+ item = "_Test UAE VAT Exempt Item",
+ do_not_save=1
+ )
+ si.vat_emirate = 'Sharjah'
+ si.submit()
+
+def create_purchase_invoices():
+
+ pi = make_purchase_invoice(
+ company="_Test Company UAE VAT",
+ supplier = '_Test UAE Supplier',
+ supplier_warehouse = '_Test UAE VAT Supplier Warehouse - _TCUV',
+ warehouse = '_Test UAE VAT Supplier Warehouse - _TCUV',
+ currency = 'AED',
+ cost_center = 'Main - _TCUV',
+ expense_account = 'Cost of Goods Sold - _TCUV',
+ item = "_Test UAE VAT Item",
+ do_not_save=1,
+ uom = "Nos"
+ )
+ pi.append("taxes", {
+ "charge_type": "On Net Total",
+ "account_head": "VAT 5% - _TCUV",
+ "cost_center": "Main - _TCUV",
+ "description": "VAT 5% @ 5.0",
+ "rate": 5.0
+ })
+
+ pi.recoverable_standard_rated_expenses = 1
+
+ pi.submit()
diff --git a/erpnext/regional/report/uae_vat_201/uae_vat_201.html b/erpnext/regional/report/uae_vat_201/uae_vat_201.html
new file mode 100644
index 0000000..d9b9968
--- /dev/null
+++ b/erpnext/regional/report/uae_vat_201/uae_vat_201.html
@@ -0,0 +1,77 @@
+{%
+ var report_columns = report.get_columns_for_print();
+ report_columns = report_columns.filter(col => !col.hidden);
+%}
+<style>
+ .print-format {
+ padding: 10mm;
+ font-size: 8.0pt !important;
+ font-family: Tahoma, sans-serif;
+ }
+</style>
+
+<h1 style="margin-top:0; text-align: center;">{%= __(report.report_name) %}</h1>
+
+<h3 style="margin-top:0; font-weight:500">{%= __("VAT on Sales and All Other Outputs") %}</h2>
+
+<table class="table table-bordered">
+
+ <thead>
+ <th style="width: 13">{%= report_columns[0].label %}</th>
+ <th style="width: {%= 100 - (report_columns.length - 1) * 13%}%">{%= report_columns[1].label %}</th>
+
+ {% for (let i=2; i<report_columns.length; i++) { %}
+ <th style="width: 13">{%= report_columns[i].label %}</th>
+ {% } %}
+ </thead>
+
+ <tbody>
+ {% for (let j=1; j<12; j++) { %}
+ {%
+ var row = data[j];
+ %}
+ <tr >
+ {% for (let i=0; i<report_columns.length; i++) { %}
+ <td >
+ {% const fieldname = report_columns[i].fieldname; %}
+ {% if (!is_null(row[fieldname])) { %}
+ {%= frappe.format(row[fieldname], report_columns[i], {}, row) %}
+ {% } %}
+ </td>
+ {% } %}
+ </tr>
+ {% } %}
+ </tbody>
+</table>
+
+<h3 style="margin-top:0; font-weight:500">{%= __("VAT on Expenses and All Other Inputs") %}</h2>
+
+<table class="table table-bordered">
+ <thead>
+ <th style="width: 13">{%= report_columns[0].label %}</th>
+ <th style="width: {%= 100 - (report_columns.length - 1) * 13%}%">{%= report_columns[1].label %}</th>
+
+ {% for (let i=2; i<report_columns.length; i++) { %}
+ <th style="width: 13">{%= report_columns[i].label %}</th>
+ {% } %}
+ </thead>
+
+ <tbody>
+ {% for (let j=14; j<data.length; j++) { %}
+ {%
+ var row = data[j];
+ %}
+ <tr >
+ {% for (let i=0; i<report_columns.length; i++) { %}
+ <td >
+ {% const fieldname = report_columns[i].fieldname; %}
+ {% if (!is_null(row[fieldname])) { %}
+ {%= frappe.format(row[fieldname], report_columns[i], {}, row) %}
+ {% } %}
+ </td>
+ {% } %}
+ </tr>
+ {% } %}
+ </tbody>
+
+</table>
\ No newline at end of file
diff --git a/erpnext/regional/report/uae_vat_201/uae_vat_201.js b/erpnext/regional/report/uae_vat_201/uae_vat_201.js
new file mode 100644
index 0000000..5957424
--- /dev/null
+++ b/erpnext/regional/report/uae_vat_201/uae_vat_201.js
@@ -0,0 +1,40 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+/* eslint-disable */
+
+frappe.query_reports["UAE VAT 201"] = {
+ "filters": [
+ {
+ "fieldname": "company",
+ "label": __("Company"),
+ "fieldtype": "Link",
+ "options": "Company",
+ "reqd": 1,
+ "default": frappe.defaults.get_user_default("Company")
+ },
+ {
+ "fieldname": "from_date",
+ "label": __("From Date"),
+ "fieldtype": "Date",
+ "reqd": 1,
+ "default": frappe.datetime.add_months(frappe.datetime.get_today(), -3),
+ },
+ {
+ "fieldname": "to_date",
+ "label": __("To Date"),
+ "fieldtype": "Date",
+ "reqd": 1,
+ "default": frappe.datetime.get_today()
+ },
+ ],
+ "formatter": function(value, row, column, data, default_formatter) {
+ if (data
+ && (data.legend=='VAT on Sales and All Other Outputs' || data.legend=='VAT on Expenses and All Other Inputs')
+ && data.legend==value) {
+ value = $(`<span>${value}</span>`);
+ var $value = $(value).css("font-weight", "bold");
+ value = $value.wrap("<p></p>").parent().html();
+ }
+ return value;
+ },
+};
diff --git a/erpnext/regional/report/uae_vat_201/uae_vat_201.json b/erpnext/regional/report/uae_vat_201/uae_vat_201.json
new file mode 100644
index 0000000..8a88bcd
--- /dev/null
+++ b/erpnext/regional/report/uae_vat_201/uae_vat_201.json
@@ -0,0 +1,22 @@
+{
+ "add_total_row": 0,
+ "columns": [],
+ "creation": "2020-09-10 08:51:02.298482",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "filters": [],
+ "idx": 0,
+ "is_standard": "Yes",
+ "modified": "2020-09-10 08:51:02.298482",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "UAE VAT 201",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "GL Entry",
+ "report_name": "UAE VAT 201",
+ "report_type": "Script Report",
+ "roles": []
+}
\ No newline at end of file
diff --git a/erpnext/regional/report/uae_vat_201/uae_vat_201.py b/erpnext/regional/report/uae_vat_201/uae_vat_201.py
new file mode 100644
index 0000000..201ddf6
--- /dev/null
+++ b/erpnext/regional/report/uae_vat_201/uae_vat_201.py
@@ -0,0 +1,336 @@
+# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+
+def execute(filters=None):
+ columns = get_columns()
+ data, emirates, amounts_by_emirate = get_data(filters)
+ chart = get_chart(emirates, amounts_by_emirate)
+ return columns, data, None, chart
+
+def get_columns():
+ """Creates a list of dictionaries that are used to generate column headers of the data table."""
+ return [
+ {
+ "fieldname": "no",
+ "label": _("No"),
+ "fieldtype": "Data",
+ "width": 50
+ },
+ {
+ "fieldname": "legend",
+ "label": _("Legend"),
+ "fieldtype": "Data",
+ "width": 300
+ },
+ {
+ "fieldname": "amount",
+ "label": _("Amount (AED)"),
+ "fieldtype": "Currency",
+ "width": 125,
+ "options": "currency"
+ },
+ {
+ "fieldname": "vat_amount",
+ "label": _("VAT Amount (AED)"),
+ "fieldtype": "Currency",
+ "width": 150,
+ "options": "currency"
+ }
+ ]
+
+def get_data(filters = None):
+ """Returns the list of dictionaries. Each dictionary is a row in the datatable and chart data."""
+ data = []
+ emirates, amounts_by_emirate = append_vat_on_sales(data, filters)
+ append_vat_on_expenses(data, filters)
+ return data, emirates, amounts_by_emirate
+
+def get_chart(emirates, amounts_by_emirate):
+ """Returns chart data."""
+ labels = []
+ amount = []
+ vat_amount = []
+ for d in emirates:
+ if d in amounts_by_emirate:
+ amount.append(amounts_by_emirate[d]["raw_amount"])
+ vat_amount.append(amounts_by_emirate[d]["raw_vat_amount"])
+ labels.append(d)
+
+ datasets = []
+ datasets.append({'name': _('Amount (AED)'), 'values': amount})
+ datasets.append({'name': _('Vat Amount (AED)'), 'values': vat_amount})
+
+ chart = {
+ "type": "bar",
+ "fieldtype": "Currency"
+ "data": {
+ 'labels': labels,
+ 'datasets': datasets
+ }
+ }
+
+ return chart
+
+def append_vat_on_sales(data, filters):
+ """Appends Sales and All Other Outputs."""
+ append_data(data, '', _('VAT on Sales and All Other Outputs'), '', '')
+
+ emirates, amounts_by_emirate = standard_rated_expenses_emiratewise(data, filters)
+
+ append_data(data, '2', _('Tax Refunds provided to Tourists under the Tax Refunds for Tourists Scheme'),
+ frappe.format((-1) * get_tourist_tax_return_total(filters), 'Currency'),
+ frappe.format((-1) * get_tourist_tax_return_tax(filters), 'Currency'))
+
+ append_data(data, '3', _('Supplies subject to the reverse charge provision'),
+ frappe.format(get_reverse_charge_total(filters), 'Currency'),
+ frappe.format(get_reverse_charge_tax(filters), 'Currency'))
+
+ append_data(data, '4', _('Zero Rated'),
+ frappe.format(get_zero_rated_total(filters), 'Currency'), "-")
+
+ append_data(data, '5', _('Exempt Supplies'),
+ frappe.format(get_exempt_total(filters), 'Currency'),"-")
+
+ append_data(data, '', '', '', '')
+
+ return emirates, amounts_by_emirate
+
+def standard_rated_expenses_emiratewise(data, filters):
+ """Append emiratewise standard rated expenses and vat."""
+ total_emiratewise = get_total_emiratewise(filters)
+ emirates = get_emirates()
+ amounts_by_emirate = {}
+ for d in total_emiratewise:
+ emirate, amount, vat= d
+ amounts_by_emirate[emirate] = {
+ "legend": emirate,
+ "raw_amount": amount,
+ "raw_vat_amount": vat,
+ "amount": frappe.format(amount, 'Currency'),
+ "vat_amount": frappe.format(vat, 'Currency'),
+ }
+ amounts_by_emirate = append_emiratewise_expenses(data, emirates, amounts_by_emirate)
+
+ for d, emirate in enumerate(emirates, 97):
+ if emirate in amounts_by_emirate:
+ amounts_by_emirate[emirate]["no"] = _('1{0}').format(chr(d))
+ amounts_by_emirate[emirate]["legend"] = _('Standard rated supplies in {0}').format(emirate)
+ data.append(amounts_by_emirate[emirate])
+ else:
+ append_data(data, _('1{0}').format(chr(d)),
+ _('Standard rated supplies in {0}').format(emirate),
+ frappe.format(0, 'Currency'), frappe.format(0, 'Currency'))
+ return emirates, amounts_by_emirate
+
+def append_emiratewise_expenses(data, emirates, amounts_by_emirate):
+ """Append emiratewise standard rated expenses and vat."""
+ for d, emirate in enumerate(emirates, 97):
+ if emirate in amounts_by_emirate:
+ amounts_by_emirate[emirate]["no"] = _('1{0}').format(chr(d))
+ amounts_by_emirate[emirate]["legend"] = _('Standard rated supplies in {0}').format(emirate)
+ data.append(amounts_by_emirate[emirate])
+ else:
+ append_data(data, _('1{0}').format(chr(d)),
+ _('Standard rated supplies in {0}').format(emirate),
+ frappe.format(0, 'Currency'), frappe.format(0, 'Currency'))
+ return amounts_by_emirate
+
+def append_vat_on_expenses(data, filters):
+ """Appends Expenses and All Other Inputs."""
+ append_data(data, '', _('VAT on Expenses and All Other Inputs'), '', '')
+ append_data(data, '9', _('Standard Rated Expenses'),
+ frappe.format(get_standard_rated_expenses_total(filters), 'Currency'),
+ frappe.format(get_standard_rated_expenses_tax(filters), 'Currency'))
+
+ append_data(data, '10', _('Supplies subject to the reverse charge provision'),
+ frappe.format(get_reverse_charge_recoverable_total(filters), 'Currency'),
+ frappe.format(get_reverse_charge_recoverable_tax(filters), 'Currency')
+)
+
+def append_data(data, no, legend, amount, vat_amount):
+ """Returns data with appended value."""
+ data.append({"no": no, "legend":legend, "amount": amount, "vat_amount": vat_amount})
+
+def get_total_emiratewise(filters):
+ """Returns Emiratewise Amount and Taxes."""
+ query_filters = get_filters(filters)
+ query_filters['docstatus'] = ['=', 1]
+ return frappe.db.get_list('Sales Invoice',
+ filters = query_filters,
+ fields = ['vat_emirate as emirate','sum(total)', 'sum(total_taxes_and_charges)'],
+ group_by='vat_emirate',
+ as_list=True
+ )
+
+def get_emirates():
+ """Returns a List of emirates in the order that they are to be displayed."""
+ return [
+ 'Abu Dhabi',
+ 'Dubai',
+ 'Sharjah',
+ 'Ajman',
+ 'Umm Al Quwain',
+ 'Ras Al Khaimah',
+ 'Fujairah'
+ ]
+
+def get_filters(filters):
+ """The conditions to be used to filter data to calculate the total sale."""
+ query_filters = {}
+ if filters.get("company"):
+ query_filters["company"] = ['=', filters['company']]
+ if filters.get("from_date"):
+ query_filters["posting_date"] = ['>=', filters['from_date']]
+ if filters.get("from_date"):
+ query_filters["posting_date"] = ['<=', filters['to_date']]
+ return query_filters
+
+def get_reverse_charge_total(filters):
+ """Returns the sum of the total of each Purchase invoice made."""
+ query_filters = get_filters(filters)
+ query_filters['reverse_charge'] = ['=', 'Y']
+ query_filters['docstatus'] = ['=', 1]
+ return frappe.db.get_list('Purchase Invoice',
+ filters = query_filters,
+ fields = ['sum(total)'],
+ as_list=True,
+ limit = 1
+ )[0][0] or 0
+
+def get_reverse_charge_tax(filters):
+ """Returns the sum of the tax of each Purchase invoice made."""
+ conditions = get_conditions_join(filters)
+ return frappe.db.sql("""
+ select sum(debit) from
+ `tabPurchase Invoice` p inner join `tabGL Entry` gl
+ on gl.voucher_no = p.name
+ where
+ p.reverse_charge = "Y"
+ and p.docstatus = 1
+ and gl.docstatus = 1
+ and account in (select account from `tabUAE VAT Account` where parent=%(company)s)
+ {where_conditions} ;
+ """.format(where_conditions=conditions), filters)[0][0] or 0
+
+def get_reverse_charge_recoverable_total(filters):
+ """Returns the sum of the total of each Purchase invoice made with recoverable reverse charge."""
+ query_filters = get_filters(filters)
+ query_filters['reverse_charge'] = ['=', 'Y']
+ query_filters['recoverable_reverse_charge'] = ['>', '0']
+ query_filters['docstatus'] = ['=', 1]
+ return frappe.db.get_list('Purchase Invoice',
+ filters = query_filters,
+ fields = ['sum(total)'],
+ as_list=True,
+ limit = 1
+ )[0][0] or 0
+
+def get_reverse_charge_recoverable_tax(filters):
+ """Returns the sum of the tax of each Purchase invoice made."""
+ conditions = get_conditions_join(filters)
+ return frappe.db.sql("""
+ select sum(debit * p.recoverable_reverse_charge / 100) from
+ `tabPurchase Invoice` p inner join `tabGL Entry` gl
+ on gl.voucher_no = p.name
+ where
+ p.reverse_charge = "Y"
+ and p.docstatus = 1
+ and p.recoverable_reverse_charge > 0
+ and gl.docstatus = 1
+ and account in (select account from `tabUAE VAT Account` where parent=%(company)s)
+ {where_conditions} ;
+ """.format(where_conditions=conditions), filters)[0][0] or 0
+
+def get_conditions_join(filters):
+ """The conditions to be used to filter data to calculate the total vat."""
+ conditions = ""
+ for opts in (("company", " and p.company=%(company)s"),
+ ("from_date", " and p.posting_date>=%(from_date)s"),
+ ("to_date", " and p.posting_date<=%(to_date)s")):
+ if filters.get(opts[0]):
+ conditions += opts[1]
+ return conditions
+
+def get_standard_rated_expenses_total(filters):
+ """Returns the sum of the total of each Purchase invoice made with recoverable reverse charge."""
+ query_filters = get_filters(filters)
+ query_filters['recoverable_standard_rated_expenses'] = ['>', 0]
+ query_filters['docstatus'] = ['=', 1]
+ return frappe.db.get_list('Purchase Invoice',
+ filters = query_filters,
+ fields = ['sum(total)'],
+ as_list=True,
+ limit = 1
+ )[0][0] or 0
+
+def get_standard_rated_expenses_tax(filters):
+ """Returns the sum of the tax of each Purchase invoice made."""
+ query_filters = get_filters(filters)
+ query_filters['recoverable_standard_rated_expenses'] = ['>', 0]
+ query_filters['docstatus'] = ['=', 1]
+ return frappe.db.get_list('Purchase Invoice',
+ filters = query_filters,
+ fields = ['sum(recoverable_standard_rated_expenses)'],
+ as_list=True,
+ limit = 1
+ )[0][0] or 0
+
+def get_tourist_tax_return_total(filters):
+ """Returns the sum of the total of each Sales invoice with non zero tourist_tax_return."""
+ query_filters = get_filters(filters)
+ query_filters['tourist_tax_return'] = ['>', 0]
+ query_filters['docstatus'] = ['=', 1]
+ return frappe.db.get_list('Sales Invoice',
+ filters = query_filters,
+ fields = ['sum(total)'],
+ as_list=True,
+ limit = 1
+ )[0][0] or 0
+
+def get_tourist_tax_return_tax(filters):
+ """Returns the sum of the tax of each Sales invoice with non zero tourist_tax_return."""
+ query_filters = get_filters(filters)
+ query_filters['tourist_tax_return'] = ['>', 0]
+ query_filters['docstatus'] = ['=', 1]
+ return frappe.db.get_list('Sales Invoice',
+ filters = query_filters,
+ fields = ['sum(tourist_tax_return)'],
+ as_list=True,
+ limit = 1
+ )[0][0] or 0
+
+def get_zero_rated_total(filters):
+ """Returns the sum of each Sales Invoice Item Amount which is zero rated."""
+ conditions = get_conditions(filters)
+ return frappe.db.sql("""
+ select sum(i.base_amount) as total from
+ `tabSales Invoice Item` i inner join `tabSales Invoice` s
+ on i.parent = s.name
+ where s.docstatus = 1 and i.is_zero_rated = 1
+ {where_conditions} ;
+ """.format(where_conditions=conditions), filters)[0][0] or 0
+
+def get_exempt_total(filters):
+ """Returns the sum of each Sales Invoice Item Amount which is Vat Exempt."""
+ conditions = get_conditions(filters)
+ return frappe.db.sql("""
+ select sum(i.base_amount) as total from
+ `tabSales Invoice Item` i inner join `tabSales Invoice` s
+ on i.parent = s.name
+ where s.docstatus = 1 and i.is_exempt = 1
+ {where_conditions} ;
+ """.format(where_conditions=conditions), filters)[0][0] or 0
+
+def get_conditions(filters):
+ """The conditions to be used to filter data to calculate the total sale."""
+ conditions = ""
+ for opts in (("company", " and company=%(company)s"),
+ ("from_date", " and posting_date>=%(from_date)s"),
+ ("to_date", " and posting_date<=%(to_date)s")):
+ if filters.get(opts[0]):
+ conditions += opts[1]
+ return conditions
diff --git a/erpnext/regional/united_arab_emirates/setup.py b/erpnext/regional/united_arab_emirates/setup.py
index 250659e..62156e4 100644
--- a/erpnext/regional/united_arab_emirates/setup.py
+++ b/erpnext/regional/united_arab_emirates/setup.py
@@ -5,24 +5,30 @@
import frappe, os, json
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
+from frappe.permissions import add_permission, update_permission_property
from erpnext.setup.setup_wizard.operations.taxes_setup import create_sales_tax
def setup(company=None, patch=True):
make_custom_fields()
add_print_formats()
-
+ add_custom_roles_for_reports()
+ add_permissions()
if company:
create_sales_tax(company)
def make_custom_fields():
+ is_zero_rated = dict(fieldname='is_zero_rated', label='Is Zero Rated',
+ fieldtype='Check', fetch_from='item_code.is_zero_rated', insert_after='description',
+ print_hide=1)
+ is_exempt = dict(fieldname='is_exempt', label='Is Exempt',
+ fieldtype='Check', fetch_from='item_code.is_exempt', insert_after='is_zero_rated',
+ print_hide=1)
+
invoice_fields = [
dict(fieldname='vat_section', label='VAT Details', fieldtype='Section Break',
insert_after='group_same_items', print_hide=1, collapsible=1),
dict(fieldname='permit_no', label='Permit Number',
fieldtype='Data', insert_after='vat_section', print_hide=1),
- dict(fieldname='reverse_charge_applicable', label='Reverse Charge Applicable',
- fieldtype='Select', insert_after='permit_no', print_hide=1,
- options='Y\nN', default='N')
]
purchase_invoice_fields = [
@@ -31,7 +37,15 @@
fetch_from='company.tax_id', print_hide=1),
dict(fieldname='supplier_name_in_arabic', label='Supplier Name in Arabic',
fieldtype='Read Only', insert_after='supplier_name',
- fetch_from='supplier.supplier_name_in_arabic', print_hide=1)
+ fetch_from='supplier.supplier_name_in_arabic', print_hide=1),
+ dict(fieldname='recoverable_standard_rated_expenses', label='Recoverable Standard Rated Expenses (AED)',
+ insert_after='permit_no', fieldtype='Currency', print_hide=1, default='0'),
+ dict(fieldname='reverse_charge', label='Reverse Charge Applicable',
+ fieldtype='Select', insert_after='recoverable_standard_rated_expenses', print_hide=1,
+ options='Y\nN', default='N'),
+ dict(fieldname='recoverable_reverse_charge', label='Recoverable Reverse Charge (Percentage)',
+ insert_after='reverse_charge', fieldtype='Percent', print_hide=1,
+ depends_on="eval:doc.reverse_charge=='Y'", default='100.000'),
]
sales_invoice_fields = [
@@ -41,6 +55,10 @@
dict(fieldname='customer_name_in_arabic', label='Customer Name in Arabic',
fieldtype='Read Only', insert_after='customer_name',
fetch_from='customer.customer_name_in_arabic', print_hide=1),
+ dict(fieldname='vat_emirate', label='VAT Emirate', insert_after='permit_no', fieldtype='Select',
+ options='\nAbu Dhabi\nAjman\nDubai\nFujairah\nRas Al Khaimah\nSharjah\nUmm Al Quwain'),
+ dict(fieldname='tourist_tax_return', label='Tax Refund provided to Tourists (AED)',
+ insert_after='vat_emirate', fieldtype='Currency', print_hide=1, default='0'),
]
invoice_item_fields = [
@@ -67,6 +85,12 @@
'Item': [
dict(fieldname='tax_code', label='Tax Code',
fieldtype='Data', insert_after='item_group'),
+ dict(fieldname='is_zero_rated', label='Is Zero Rated',
+ fieldtype='Check', insert_after='tax_code',
+ print_hide=1),
+ dict(fieldname='is_exempt', label='Is Exempt',
+ fieldtype='Check', insert_after='is_zero_rated',
+ print_hide=1)
],
'Customer': [
dict(fieldname='customer_name_in_arabic', label='Customer Name in Arabic',
@@ -82,7 +106,7 @@
'Sales Invoice': sales_invoice_fields + invoice_fields,
'Sales Order': sales_invoice_fields + invoice_fields,
'Delivery Note': sales_invoice_fields + invoice_fields,
- 'Sales Invoice Item': invoice_item_fields + delivery_date_field,
+ 'Sales Invoice Item': invoice_item_fields + delivery_date_field + [is_zero_rated, is_exempt],
'Purchase Invoice Item': invoice_item_fields,
'Sales Order Item': invoice_item_fields,
'Delivery Note Item': invoice_item_fields,
@@ -101,3 +125,25 @@
frappe.db.sql(""" update `tabPrint Format` set disabled = 0 where
name in('Simplified Tax Invoice', 'Detailed Tax Invoice', 'Tax Invoice') """)
+
+def add_custom_roles_for_reports():
+ """Add Access Control to UAE VAT 201."""
+ if not frappe.db.get_value('Custom Role', dict(report='UAE VAT 201')):
+ frappe.get_doc(dict(
+ doctype='Custom Role',
+ report='UAE VAT 201',
+ roles= [
+ dict(role='Accounts User'),
+ dict(role='Accounts Manager'),
+ dict(role='Auditor')
+ ]
+ )).insert()
+
+def add_permissions():
+ """Add Permissions for UAE VAT Settings and UAE VAT Account."""
+ for doctype in ('UAE VAT Settings', 'UAE VAT Account'):
+ add_permission(doctype, 'All', 0)
+ for role in ('Accounts Manager', 'Accounts User', 'System Manager'):
+ add_permission(doctype, role, 0)
+ update_permission_property(doctype, role, 0, 'write', 1)
+ update_permission_property(doctype, role, 0, 'create', 1)
diff --git a/erpnext/regional/united_arab_emirates/utils.py b/erpnext/regional/united_arab_emirates/utils.py
index a0425f6..7430db4 100644
--- a/erpnext/regional/united_arab_emirates/utils.py
+++ b/erpnext/regional/united_arab_emirates/utils.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
import frappe
-from frappe.utils import flt
+from frappe import _
+import erpnext
+from frappe.utils import flt, round_based_on_smallest_currency_fraction, money_in_words
from erpnext.controllers.taxes_and_totals import get_itemised_tax
from six import iteritems
@@ -26,4 +28,128 @@
row.tax_rate = flt(tax_rate, row.precision("tax_rate"))
row.tax_amount = flt((row.net_amount * tax_rate) / 100, row.precision("net_amount"))
- row.total_amount = flt((row.net_amount + row.tax_amount), row.precision("total_amount"))
\ No newline at end of file
+ row.total_amount = flt((row.net_amount + row.tax_amount), row.precision("total_amount"))
+
+def get_account_currency(account):
+ """Helper function to get account currency."""
+ if not account:
+ return
+ def generator():
+ account_currency, company = frappe.get_cached_value("Account", account, ["account_currency", "company"])
+ if not account_currency:
+ account_currency = frappe.get_cached_value('Company', company, "default_currency")
+
+ return account_currency
+
+ return frappe.local_cache("account_currency", account, generator)
+
+def get_tax_accounts(company):
+ """Get the list of tax accounts for a specific company."""
+ tax_accounts_dict = frappe._dict()
+ tax_accounts_list = frappe.get_all("UAE VAT Account",
+ filters={"parent": company},
+ fields=["Account"]
+ )
+
+ if not tax_accounts_list and not frappe.flags.in_test:
+ frappe.throw(_('Please set Vat Accounts for Company: "{0}" in UAE VAT Settings').format(company))
+ for d in tax_accounts_list:
+ for key, name in d.items():
+ tax_accounts_dict[name] = name
+
+ return tax_accounts_dict
+
+def update_grand_total_for_rcm(doc, method):
+ """If the Reverse Charge is Applicable subtract the tax amount from the grand total and update in the form."""
+ country = frappe.get_cached_value('Company', doc.company, 'country')
+
+ if country != 'United Arab Emirates':
+ return
+
+ if not doc.total_taxes_and_charges:
+ return
+
+ if doc.reverse_charge == 'Y':
+ tax_accounts = get_tax_accounts(doc.company)
+
+ base_vat_tax = 0
+ vat_tax = 0
+
+ for tax in doc.get('taxes'):
+ if tax.category not in ("Total", "Valuation and Total"):
+ continue
+
+ if flt(tax.base_tax_amount_after_discount_amount) and tax.account_head in tax_accounts:
+ base_vat_tax += tax.base_tax_amount_after_discount_amount
+ vat_tax += tax.tax_amount_after_discount_amount
+
+ doc.taxes_and_charges_added -= vat_tax
+ doc.total_taxes_and_charges -= vat_tax
+ doc.base_taxes_and_charges_added -= base_vat_tax
+ doc.base_total_taxes_and_charges -= base_vat_tax
+
+ update_totals(vat_tax, base_vat_tax, doc)
+
+def update_totals(vat_tax, base_vat_tax, doc):
+ """Update the grand total values in the form."""
+ doc.base_grand_total -= base_vat_tax
+ doc.grand_total -= vat_tax
+
+ if doc.meta.get_field("rounded_total"):
+
+ if doc.is_rounded_total_disabled():
+ doc.outstanding_amount = doc.grand_total
+
+ else:
+ doc.rounded_total = round_based_on_smallest_currency_fraction(doc.grand_total,
+ doc.currency, doc.precision("rounded_total"))
+ doc.rounding_adjustment = flt(doc.rounded_total - doc.grand_total,
+ doc.precision("rounding_adjustment"))
+ doc.outstanding_amount = doc.rounded_total or doc.grand_total
+
+ doc.in_words = money_in_words(doc.grand_total, doc.currency)
+ doc.base_in_words = money_in_words(doc.base_grand_total, erpnext.get_company_currency(doc.company))
+ doc.set_payment_schedule()
+
+def make_regional_gl_entries(gl_entries, doc):
+ """Hooked to make_regional_gl_entries in Purchase Invoice.It appends the region specific general ledger entries to the list of GL Entries."""
+ country = frappe.get_cached_value('Company', doc.company, 'country')
+
+ if country != 'United Arab Emirates':
+ return gl_entries
+
+ if doc.reverse_charge == 'Y':
+ tax_accounts = get_tax_accounts(doc.company)
+ for tax in doc.get('taxes'):
+ if tax.category not in ("Total", "Valuation and Total"):
+ continue
+ gl_entries = make_gl_entry(tax, gl_entries, doc, tax_accounts)
+ return gl_entries
+
+def make_gl_entry(tax, gl_entries, doc, tax_accounts):
+ dr_or_cr = "credit" if tax.add_deduct_tax == "Add" else "debit"
+ if flt(tax.base_tax_amount_after_discount_amount) and tax.account_head in tax_accounts:
+ account_currency = get_account_currency(tax.account_head)
+
+ gl_entries.append(doc.get_gl_dict(
+ {
+ "account": tax.account_head,
+ "cost_center": tax.cost_center,
+ "posting_date": doc.posting_date,
+ "against": doc.supplier,
+ dr_or_cr: tax.base_tax_amount_after_discount_amount,
+ dr_or_cr + "_in_account_currency": tax.base_tax_amount_after_discount_amount \
+ if account_currency==doc.company_currency \
+ else tax.tax_amount_after_discount_amount
+ }, account_currency, item=tax)
+ )
+ return gl_entries
+
+
+def validate_returns(doc, method):
+ """Standard Rated expenses should not be set when Reverse Charge Applicable is set."""
+ country = frappe.get_cached_value('Company', doc.company, 'country')
+ if country != 'United Arab Emirates':
+ return
+ if doc.reverse_charge == 'Y' and flt(doc.recoverable_standard_rated_expenses) != 0:
+ frappe.throw(_("Recoverable Standard Rated expenses should not be set when Reverse Charge Applicable is Y"))
\ No newline at end of file