Skip to content

Commit

Permalink
fix: Paid amount must be discounted considering accounting currency
Browse files Browse the repository at this point in the history
- Accounting is in the same currency if party currency and company currency is the same
- If accounting is in the same currency, paid and recvd amount is in the base currency
- Then, discount amount must also be in the base currency as it is deducted from paid amount
- Received amount must be in base currency if not multi currency
- cleanup: Deductions setting broken into smaller functions
  • Loading branch information
marination committed Mar 8, 2023
1 parent f02fc8a commit 761f68d
Showing 1 changed file with 37 additions and 21 deletions.
58 changes: 37 additions & 21 deletions erpnext/accounts/doctype/payment_entry/payment_entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -1683,7 +1683,7 @@ def get_payment_entry(
)

paid_amount, received_amount, discount_amount, valid_discounts = apply_early_payment_discount(
paid_amount, received_amount, doc
paid_amount, received_amount, doc, party_account_currency
)

pe = frappe.new_doc("Payment Entry")
Expand Down Expand Up @@ -1783,17 +1783,10 @@ def get_payment_entry(
pe.set_exchange_rate(ref_doc=reference_doc)
pe.set_amounts()

discount_amount = set_early_payment_discount_loss(pe, doc, valid_discounts, discount_amount)
if discount_amount > 0:
# Set pending base discount amount in deductions
positive_negative = -1 if payment_type == "Pay" else 1
pe.set_gain_or_loss(
account_details={
"account": frappe.get_cached_value("Company", pe.company, "default_discount_account"),
"cost_center": pe.cost_center
or frappe.get_cached_value("Company", pe.company, "cost_center"),
"amount": discount_amount * positive_negative * doc.get("conversion_rate", 1),
}
if discount_amount:
base_total_discount_loss = set_early_payment_discount_loss(pe, doc, valid_discounts)
set_pending_discount_loss(
pe, doc, discount_amount, base_total_discount_loss, party_account_currency
)

pe.set_difference_amount()
Expand Down Expand Up @@ -1907,7 +1900,7 @@ def set_paid_amount_and_received_amount(
return paid_amount, received_amount


def apply_early_payment_discount(paid_amount, received_amount, doc):
def apply_early_payment_discount(paid_amount, received_amount, doc, party_account_currency):
total_discount = 0
valid_discounts = []
eligible_for_payments = ["Sales Order", "Sales Invoice", "Purchase Order", "Purchase Invoice"]
Expand All @@ -1916,12 +1909,17 @@ def apply_early_payment_discount(paid_amount, received_amount, doc):
if doc.doctype in eligible_for_payments and has_payment_schedule:
for term in doc.payment_schedule:
if not term.discounted_amount and term.discount and getdate(nowdate()) <= term.discount_date:
is_multi_currency = party_account_currency != doc.company_currency

if term.discount_type == "Percentage":
discount_amount = flt(doc.get("grand_total")) * (term.discount / 100)
grand_total = doc.get("grand_total") if is_multi_currency else doc.get("base_grand_total")
discount_amount = flt(grand_total) * (term.discount / 100)
else:
discount_amount = term.discount

discount_amount_in_foreign_currency = discount_amount * doc.get("conversion_rate", 1)
# if accounting is done in the same currency, paid_amount = received_amount
conversion_rate = doc.get("conversion_rate", 1) if is_multi_currency else 1
discount_amount_in_foreign_currency = discount_amount * conversion_rate

if doc.doctype == "Sales Invoice":
paid_amount -= discount_amount
Expand All @@ -1940,20 +1938,38 @@ def apply_early_payment_discount(paid_amount, received_amount, doc):
return paid_amount, received_amount, total_discount, valid_discounts


def set_early_payment_discount_loss(pe, doc, valid_discounts, discount_amount):
"""Split early payment discount into Income Loss & Tax Loss."""
if not (discount_amount and valid_discounts):
return discount_amount
def set_pending_discount_loss(
pe, doc, discount_amount, base_total_discount_loss, party_account_currency
):
# If multi-currency, get base discount amount to adjust with base currency deductions/losses
if party_account_currency != doc.company_currency:
discount_amount = discount_amount * doc.get("conversion_rate", 1)

discount_amount -= base_total_discount_loss

# If pending base discount amount, set it in deductions
if discount_amount > 0.0:
positive_negative = -1 if pe.payment_type == "Pay" else 1
pe.set_gain_or_loss(
account_details={
"account": frappe.get_cached_value("Company", pe.company, "default_discount_account"),
"cost_center": pe.cost_center or frappe.get_cached_value("Company", pe.company, "cost_center"),
"amount": discount_amount * positive_negative,
}
)


def set_early_payment_discount_loss(pe, doc, valid_discounts) -> float:
"""Split early payment discount into Income Loss & Tax Loss."""
total_discount_percent = get_total_discount_percent(doc, valid_discounts)

if not total_discount_percent:
return discount_amount
return 0.0

loss_on_income = add_income_discount_loss(pe, doc, total_discount_percent)
loss_on_taxes = add_tax_discount_loss(pe, doc, total_discount_percent)

return flt(discount_amount - (loss_on_income + loss_on_taxes))
return flt(loss_on_income + loss_on_taxes)


def get_total_discount_percent(doc, valid_discounts) -> float:
Expand Down

0 comments on commit 761f68d

Please sign in to comment.