brotherton-erpnext/erpnext/regional/united_arab_emirates/utils.py

179 lines
5.9 KiB
Python

from __future__ import unicode_literals
import frappe
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
def update_itemised_tax_data(doc):
if not doc.taxes: return
itemised_tax = get_itemised_tax(doc.taxes)
for row in doc.items:
tax_rate = 0.0
item_tax_rate = 0.0
if row.item_tax_rate:
item_tax_rate = frappe.parse_json(row.item_tax_rate)
# First check if tax rate is present
# If not then look up in item_wise_tax_detail
if item_tax_rate:
for account, rate in iteritems(item_tax_rate):
tax_rate += rate
elif row.item_code and itemised_tax.get(row.item_code):
tax_rate = sum([tax.get('tax_rate', 0) for d, tax in itemised_tax.get(row.item_code).items()])
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"))
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
Args:
company (String): Current Company set as default
Returns:
tax_accounts: List of Tax Accounts for the company
"""
tax_accounts_dict = frappe._dict()
tax_accounts_list = frappe.get_all("Account",
filters={"account_type": "Tax", "company": company},
fields=["name"])
if not tax_accounts_list and not frappe.flags.in_test:
frappe.throw(_("Please create at least one Account of type Tax"))
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
Args:
doc (Document): The document for the current Purchase Invoice
"""
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
Args:
vat_tax (float): Vat Tax to be subtracted
base_vat_tax (float): Base Vat Tax to be subtracted
doc (Document): The document for the current Purchase Invoice
"""
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):
"""This method is hooked to the make_regional_gl_entries in Purchase Invoice.
It appends the region specific general ledger entries to the list of GL Entries.
Args:
gl_entries (List): List of GL entries to be made
doc (Document): The document for the current Purchase Invoice
Returns:
List: Updates 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
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):
print("validate_returns")
country = frappe.get_cached_value('Company', doc.company, 'country')
if country != 'United Arab Emirates':
return
if flt(doc.tourist_tax_return) + flt(doc.standard_rated_expenses) > flt(doc.total_taxes_and_charges):
frappe.throw(_("The Total Returns(Tax Refund provided to Tourists (AED) + Standard Rated Expenses (AED)) should be less than the Total Taxes and Charges (Company Currency)"))