feat(accounts): split exchange gain and exchange loss accounts (#57839)

* feat(accounts): split exchange gain and exchange loss accounts

Add optional Exchange Gain Account and Exchange Loss Account fields on
Company. When set, realized FX gain/loss from settling an invoice in a
foreign currency (via Payment Entry, Payment Reconciliation, or a
Journal-Entry-based advance) books to the matching account instead of
the single Exchange Gain/Loss account. Either field left blank falls
back to the existing Exchange Gain/Loss account, so companies that
don't configure the new fields are unaffected.

New companies get "Exchange Gain" and "Exchange Loss" accounts
auto-created in their chart of accounts and auto-assigned to the new
fields, same as the existing Exchange Gain/Loss account provisioning.

The Payment Reconciliation tool's per-allocation "Difference Account"
override in its reconcile dialog continues to work as before; the
split accounts only change the computed default shown there.

* test(account_balance): account for new Exchange Gain account in income report

The new auto-provisioned Exchange Gain account under Indirect Income
now shows up in the Income root type report for _Test Company 2.

---------

Co-authored-by: test <test@test.com>
This commit is contained in:
Jatin3128
2026-08-06 17:36:43 +05:30
committed by GitHub
parent a49fcfe888
commit 96a6db7387
13 changed files with 264 additions and 10 deletions

View File

@@ -1039,9 +1039,16 @@ class AccountsController(TransactionBase):
party_account = self.credit_to
dr_or_cr = "debit_in_account_currency"
from erpnext.accounts.services.exchange_gain_loss import get_exchange_gain_loss_account
lst = []
for d in self.get("advances"):
if flt(d.allocated_amount) > 0:
is_gain = (
flt(d.get("exchange_gain_loss")) > 0
if party_type == "Customer"
else flt(d.get("exchange_gain_loss")) < 0
)
args = frappe._dict(
{
"voucher_type": d.reference_type,
@@ -1068,9 +1075,7 @@ class AccountsController(TransactionBase):
else self.grand_total
),
"outstanding_amount": self.outstanding_amount,
"difference_account": frappe.get_cached_value(
"Company", self.company, "exchange_gain_loss_account"
),
"difference_account": get_exchange_gain_loss_account(self.company, is_gain),
"exchange_gain_loss": flt(d.get("exchange_gain_loss")),
"difference_posting_date": d.get("difference_posting_date"),
}