2020-05-26 12:32:21 +00:00
|
|
|
import frappe
|
2020-09-09 15:24:30 +00:00
|
|
|
from frappe import _
|
|
|
|
from frappe.utils import flt, money_in_words, round_based_on_smallest_currency_fraction
|
2021-09-02 11:14:59 +00:00
|
|
|
|
2020-09-09 15:24:30 +00:00
|
|
|
import erpnext
|
2017-12-28 08:50:13 +00:00
|
|
|
from erpnext.controllers.taxes_and_totals import get_itemised_tax
|
2021-09-02 11:14:59 +00:00
|
|
|
|
2017-12-28 08:50:13 +00:00
|
|
|
|
|
|
|
def update_itemised_tax_data(doc):
|
|
|
|
if not doc.taxes:
|
|
|
|
return
|
|
|
|
|
|
|
|
itemised_tax = get_itemised_tax(doc.taxes)
|
|
|
|
|
|
|
|
for row in doc.items:
|
2018-01-01 10:46:16 +00:00
|
|
|
tax_rate = 0.0
|
2020-07-03 15:53:23 +00:00
|
|
|
item_tax_rate = 0.0
|
|
|
|
|
|
|
|
if row.item_tax_rate:
|
|
|
|
item_tax_rate = frappe.parse_json(row.item_tax_rate)
|
2020-05-26 12:32:21 +00:00
|
|
|
|
|
|
|
# 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 item_tax_rate.items():
|
|
|
|
tax_rate += rate
|
2020-07-03 15:53:23 +00:00
|
|
|
elif row.item_code and itemised_tax.get(row.item_code):
|
2018-01-01 10:46:16 +00:00
|
|
|
tax_rate = sum([tax.get("tax_rate", 0) for d, tax in itemised_tax.get(row.item_code).items()])
|
2017-12-28 08:50:13 +00:00
|
|
|
|
2022-03-14 11:47:01 +00:00
|
|
|
meta = frappe.get_meta(row.doctype)
|
|
|
|
|
|
|
|
if meta.has_field("tax_rate"):
|
|
|
|
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"))
|
2020-09-09 15:24:30 +00:00
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
|
2020-09-09 15:24:30 +00:00
|
|
|
def get_account_currency(account):
|
2020-09-30 06:45:07 +00:00
|
|
|
"""Helper function to get account currency."""
|
2020-09-09 15:24:30 +00:00
|
|
|
if not account:
|
|
|
|
return
|
2022-03-28 13:22:46 +00:00
|
|
|
|
2020-09-09 15:24:30 +00:00
|
|
|
def generator():
|
2020-11-02 07:17:10 +00:00
|
|
|
account_currency, company = frappe.get_cached_value(
|
|
|
|
"Account", account, ["account_currency", "company"]
|
|
|
|
)
|
2020-09-09 15:24:30 +00:00
|
|
|
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)
|
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
|
2020-09-09 15:24:30 +00:00
|
|
|
def get_tax_accounts(company):
|
2020-09-30 06:45:07 +00:00
|
|
|
"""Get the list of tax accounts for a specific company."""
|
2020-09-09 15:24:30 +00:00
|
|
|
tax_accounts_dict = frappe._dict()
|
2020-09-28 09:08:14 +00:00
|
|
|
tax_accounts_list = frappe.get_all(
|
|
|
|
"UAE VAT Account", filters={"parent": company}, fields=["Account"]
|
|
|
|
)
|
2020-09-09 15:24:30 +00:00
|
|
|
|
|
|
|
if not tax_accounts_list and not frappe.flags.in_test:
|
2020-10-14 11:26:26 +00:00
|
|
|
frappe.throw(_('Please set Vat Accounts for Company: "{0}" in UAE VAT Settings').format(company))
|
2020-11-02 07:17:10 +00:00
|
|
|
for tax_account in tax_accounts_list:
|
2020-11-02 07:42:27 +00:00
|
|
|
for account, name in tax_account.items():
|
2020-09-09 15:24:30 +00:00
|
|
|
tax_accounts_dict[name] = name
|
|
|
|
|
|
|
|
return tax_accounts_dict
|
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
|
2020-09-09 15:24:30 +00:00
|
|
|
def update_grand_total_for_rcm(doc, method):
|
2020-09-30 06:45:07 +00:00
|
|
|
"""If the Reverse Charge is Applicable subtract the tax amount from the grand total and update in the form."""
|
2020-09-09 15:24:30 +00:00
|
|
|
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)
|
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
|
2020-09-09 15:24:30 +00:00
|
|
|
def update_totals(vat_tax, base_vat_tax, doc):
|
2020-09-30 06:45:07 +00:00
|
|
|
"""Update the grand total values in the form."""
|
2020-09-09 15:24:30 +00:00
|
|
|
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")
|
2022-03-28 13:22:46 +00:00
|
|
|
)
|
2020-09-09 15:24:30 +00:00
|
|
|
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)
|
2022-03-28 13:22:46 +00:00
|
|
|
)
|
2020-09-09 15:24:30 +00:00
|
|
|
doc.set_payment_schedule()
|
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
|
2020-09-09 15:24:30 +00:00
|
|
|
def make_regional_gl_entries(gl_entries, doc):
|
2020-09-30 06:45:07 +00:00
|
|
|
"""Hooked to make_regional_gl_entries in Purchase Invoice.It appends the region specific general ledger entries to the list of GL Entries."""
|
2020-09-09 15:24:30 +00:00
|
|
|
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
|
2020-10-29 04:22:17 +00:00
|
|
|
gl_entries = make_gl_entry(tax, gl_entries, doc, tax_accounts)
|
|
|
|
return gl_entries
|
2020-09-09 15:24:30 +00:00
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
|
2020-10-29 04:22:17 +00:00
|
|
|
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)
|
|
|
|
|
2020-11-02 07:17:10 +00:00
|
|
|
gl_entries.append(
|
|
|
|
doc.get_gl_dict(
|
|
|
|
{
|
2020-10-29 04:22:17 +00:00
|
|
|
"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,
|
2020-11-02 07:17:10 +00:00
|
|
|
},
|
|
|
|
account_currency,
|
|
|
|
item=tax,
|
2022-03-28 13:22:46 +00:00
|
|
|
)
|
2020-11-02 07:17:10 +00:00
|
|
|
)
|
2020-09-24 07:51:23 +00:00
|
|
|
return gl_entries
|
|
|
|
|
2020-10-29 04:22:17 +00:00
|
|
|
|
2020-09-24 07:51:23 +00:00
|
|
|
def validate_returns(doc, method):
|
2020-10-10 20:10:22 +00:00
|
|
|
"""Standard Rated expenses should not be set when Reverse Charge Applicable is set."""
|
2020-09-24 07:51:23 +00:00
|
|
|
country = frappe.get_cached_value("Company", doc.company, "country")
|
|
|
|
if country != "United Arab Emirates":
|
|
|
|
return
|
2020-10-19 12:28:50 +00:00
|
|
|
if doc.reverse_charge == "Y" and flt(doc.recoverable_standard_rated_expenses) != 0:
|
2020-11-02 07:17:10 +00:00
|
|
|
frappe.throw(
|
|
|
|
_("Recoverable Standard Rated expenses should not be set when Reverse Charge Applicable is Y")
|
|
|
|
)
|