mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-03 12:19:12 +00:00
fix: handle multicurrency in tds jv
This commit is contained in:
@@ -353,12 +353,15 @@ class JournalEntry(AccountsController):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def apply_tax_withholding(self):
|
def apply_tax_withholding(self):
|
||||||
|
from erpnext.setup.utils import get_exchange_rate
|
||||||
|
|
||||||
if not self.apply_tds or self.voucher_type not in ("Debit Note", "Credit Note"):
|
if not self.apply_tds or self.voucher_type not in ("Debit Note", "Credit Note"):
|
||||||
return
|
return
|
||||||
|
|
||||||
party = None
|
party = None
|
||||||
party_type = None
|
party_type = None
|
||||||
party_account = None
|
party_account = None
|
||||||
|
party_row = None
|
||||||
|
|
||||||
for d in self.get("accounts"):
|
for d in self.get("accounts"):
|
||||||
if d.party and party and d.party != party:
|
if d.party and party and d.party != party:
|
||||||
@@ -368,22 +371,25 @@ class JournalEntry(AccountsController):
|
|||||||
party = d.party
|
party = d.party
|
||||||
party_type = d.party_type
|
party_type = d.party_type
|
||||||
party_account = d.account
|
party_account = d.account
|
||||||
|
party_row = d
|
||||||
break
|
break
|
||||||
|
|
||||||
# debit or credit based on party type
|
if not (party and party_type):
|
||||||
dr_or_cr = "credit_in_account_currency" if party_type == "Supplier" else "debit_in_account_currency"
|
return
|
||||||
rev_dr_or_cr = (
|
|
||||||
"debit_in_account_currency" if party_type == "Supplier" else "credit_in_account_currency"
|
|
||||||
)
|
|
||||||
|
|
||||||
net_total = sum(
|
# debit or credit based on party type
|
||||||
|
dr_or_cr = "credit" if party_type == "Supplier" else "debit"
|
||||||
|
rev_dr_or_cr = "debit" if party_type == "Supplier" else "credit"
|
||||||
|
|
||||||
|
# net total in company currency.
|
||||||
|
net_total_in_company_currency = sum(
|
||||||
d.get(dr_or_cr) - d.get(rev_dr_or_cr)
|
d.get(dr_or_cr) - d.get(rev_dr_or_cr)
|
||||||
for d in self.get("accounts")
|
for d in self.get("accounts")
|
||||||
if d.party == party and d.party_type == party_type
|
if d.party == party and d.party_type == party_type
|
||||||
)
|
)
|
||||||
|
|
||||||
# only apply tds if net total is positive
|
# only apply tds if net total is positive
|
||||||
if net_total <= 0:
|
if net_total_in_company_currency <= 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
inv = frappe._dict(
|
inv = frappe._dict(
|
||||||
@@ -393,8 +399,8 @@ class JournalEntry(AccountsController):
|
|||||||
"doctype": self.doctype,
|
"doctype": self.doctype,
|
||||||
"company": self.company,
|
"company": self.company,
|
||||||
"posting_date": self.posting_date,
|
"posting_date": self.posting_date,
|
||||||
"tax_withholding_net_total": net_total,
|
"tax_withholding_net_total": net_total_in_company_currency,
|
||||||
"base_tax_withholding_net_total": net_total,
|
"base_tax_withholding_net_total": net_total_in_company_currency,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -403,47 +409,77 @@ class JournalEntry(AccountsController):
|
|||||||
if not tax_withholding_details:
|
if not tax_withholding_details:
|
||||||
return
|
return
|
||||||
|
|
||||||
accounts = []
|
tds_account = tax_withholding_details.get("account_head")
|
||||||
|
company_default_currency = frappe.get_cached_value("Company", self.company, "default_currency")
|
||||||
|
tds_account_currency = get_account_currency(tds_account)
|
||||||
|
|
||||||
|
tds_exch_rate = get_exchange_rate(tds_account_currency, company_default_currency, self.posting_date)
|
||||||
|
|
||||||
|
tds_amt_in_company_currency = tax_withholding_details.get("tax_amount")
|
||||||
|
tds_amt_in_account_currency = tds_amt_in_company_currency / tds_exch_rate
|
||||||
|
tds_amt_in_party_currency = tds_amt_in_company_currency / party_row.get("exchange_rate", 1)
|
||||||
|
|
||||||
|
# Update or create tax account row
|
||||||
|
tax_row = None
|
||||||
for d in self.get("accounts"):
|
for d in self.get("accounts"):
|
||||||
if d.get("account") == tax_withholding_details.get("account_head"):
|
if d.account == tds_account:
|
||||||
d.update(
|
tax_row = d
|
||||||
{
|
break
|
||||||
"account": tax_withholding_details.get("account_head"),
|
|
||||||
dr_or_cr: tax_withholding_details.get("tax_amount"),
|
|
||||||
rev_dr_or_cr: 0,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
accounts.append(d.get("account"))
|
if not tax_row:
|
||||||
|
tax_row = self.append(
|
||||||
if d.get("account") == party_account:
|
|
||||||
party_field = dr_or_cr
|
|
||||||
amount = net_total - tax_withholding_details.get("tax_amount")
|
|
||||||
if not d.get(party_field):
|
|
||||||
party_field = rev_dr_or_cr
|
|
||||||
amount = -1 * amount
|
|
||||||
|
|
||||||
d.update({party_field: amount})
|
|
||||||
|
|
||||||
if not accounts or tax_withholding_details.get("account_head") not in accounts:
|
|
||||||
self.append(
|
|
||||||
"accounts",
|
"accounts",
|
||||||
{
|
{
|
||||||
"account": tax_withholding_details.get("account_head"),
|
"account": tds_account,
|
||||||
dr_or_cr: tax_withholding_details.get("tax_amount"),
|
"account_currency": tds_account_currency,
|
||||||
"against_account": party,
|
"exchange_rate": tds_exch_rate,
|
||||||
|
"is_tax_withholding_account": 1,
|
||||||
|
"against_account": party_account,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
to_remove = [
|
# TDS will always be credit
|
||||||
d
|
tax_row.update(
|
||||||
for d in self.get("accounts")
|
{
|
||||||
if not d.get(dr_or_cr) and d.account == tax_withholding_details.get("account_head")
|
"credit": flt(tds_amt_in_company_currency, self.precision("credit")),
|
||||||
]
|
"credit_in_account_currency": flt(
|
||||||
|
tds_amt_in_account_currency, self.precision("credit_in_account_currency")
|
||||||
|
),
|
||||||
|
"debit": 0,
|
||||||
|
"debit_in_account_currency": 0,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
for d in to_remove:
|
party_field = dr_or_cr
|
||||||
self.remove(d)
|
if not party_row.get(party_field):
|
||||||
|
party_field = rev_dr_or_cr
|
||||||
|
tds_amt_in_company_currency = -1 * tds_amt_in_company_currency
|
||||||
|
tds_amt_in_party_currency = -1 * tds_amt_in_party_currency
|
||||||
|
|
||||||
|
if dr_or_cr == "debit":
|
||||||
|
# for customer,increase the receivable amount
|
||||||
|
party_row.update(
|
||||||
|
{
|
||||||
|
party_field: flt(party_row.get(party_field, 0)) + tds_amt_in_company_currency,
|
||||||
|
f"{party_field}_in_account_currency": flt(
|
||||||
|
party_row.get(f"{party_field}_in_account_currency", 0)
|
||||||
|
)
|
||||||
|
+ tds_amt_in_party_currency,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# for supplier,decrease the payable amount
|
||||||
|
party_row.update(
|
||||||
|
{
|
||||||
|
party_field: flt(party_row.get(party_field, 0)) - tds_amt_in_company_currency,
|
||||||
|
f"{party_field}_in_account_currency": flt(
|
||||||
|
party_row.get(f"{party_field}_in_account_currency", 0)
|
||||||
|
)
|
||||||
|
- tds_amt_in_party_currency,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Recalculate totals
|
||||||
self.set_amounts_in_company_currency()
|
self.set_amounts_in_company_currency()
|
||||||
self.set_total_debit_credit()
|
self.set_total_debit_credit()
|
||||||
self.set_against_account()
|
self.set_against_account()
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ def get_party_tax_withholding_details(inv, tax_withholding_category=None):
|
|||||||
party_type, parties, inv, tax_details, posting_date, pan_no
|
party_type, parties, inv, tax_details, posting_date, pan_no
|
||||||
)
|
)
|
||||||
|
|
||||||
if party_type == "Supplier":
|
if party_type == "Supplier" or inv.doctype == "Journal Entry":
|
||||||
tax_row = get_tax_row_for_tds(tax_details, tax_amount)
|
tax_row = get_tax_row_for_tds(tax_details, tax_amount)
|
||||||
else:
|
else:
|
||||||
tax_row = get_tax_row_for_tcs(inv, tax_details, tax_amount, tax_deducted)
|
tax_row = get_tax_row_for_tcs(inv, tax_details, tax_amount, tax_deducted)
|
||||||
@@ -349,7 +349,10 @@ def get_tax_amount(party_type, parties, inv, tax_details, posting_date, pan_no=N
|
|||||||
elif party_type == "Customer":
|
elif party_type == "Customer":
|
||||||
if tax_deducted:
|
if tax_deducted:
|
||||||
# if already TCS is charged, then amount will be calculated based on 'Previous Row Total'
|
# if already TCS is charged, then amount will be calculated based on 'Previous Row Total'
|
||||||
tax_amount = 0
|
if inv.doctype == "Sales Invoice":
|
||||||
|
tax_amount = 0
|
||||||
|
else:
|
||||||
|
tax_amount = inv.base_tax_withholding_net_total * tax_details.rate / 100
|
||||||
else:
|
else:
|
||||||
# if no TCS has been charged in FY,
|
# if no TCS has been charged in FY,
|
||||||
# then chargeable value is "prev invoices + advances - advance_adjusted" value which cross the threshold
|
# then chargeable value is "prev invoices + advances - advance_adjusted" value which cross the threshold
|
||||||
|
|||||||
Reference in New Issue
Block a user