mirror of
https://github.com/frappe/erpnext.git
synced 2026-08-12 14:11:46 +00:00
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:
@@ -730,6 +730,8 @@ def get_company_default_account_fields():
|
||||
"default_discount_account": "Default Payment Discount Account",
|
||||
"unrealized_profit_loss_account": "Unrealized Profit / Loss Account",
|
||||
"exchange_gain_loss_account": "Exchange Gain / Loss Account",
|
||||
"exchange_gain_account": "Exchange Gain Account",
|
||||
"exchange_loss_account": "Exchange Loss Account",
|
||||
"unrealized_exchange_gain_loss_account": "Unrealized Exchange Gain / Loss Account",
|
||||
"round_off_account": "Round Off Account",
|
||||
"default_deferred_revenue_account": "Default Deferred Revenue Account",
|
||||
|
||||
@@ -179,6 +179,9 @@
|
||||
},
|
||||
"Impairment": {
|
||||
"account_category": "Operating Expenses"
|
||||
},
|
||||
"Exchange Loss": {
|
||||
"account_category": "Operating Expenses"
|
||||
}
|
||||
},
|
||||
"root_type": "Expense"
|
||||
@@ -196,6 +199,10 @@
|
||||
"account_type": "Income Account"
|
||||
},
|
||||
"Indirect Income": {
|
||||
"Exchange Gain": {
|
||||
"account_type": "Income Account",
|
||||
"account_category": "Other Operating Income"
|
||||
},
|
||||
"account_type": "Income Account",
|
||||
"is_group": 1
|
||||
},
|
||||
|
||||
@@ -138,6 +138,7 @@ def get():
|
||||
_("Gain/Loss on Asset Disposal"): {"account_category": "Other Operating Income"},
|
||||
_("Impairment"): {"account_category": "Operating Expenses"},
|
||||
_("Tax Expense"): {"account_category": "Tax Expense"},
|
||||
_("Exchange Loss"): {"account_category": "Operating Expenses"},
|
||||
},
|
||||
"root_type": "Expense",
|
||||
},
|
||||
@@ -149,6 +150,7 @@ def get():
|
||||
_("Indirect Income"): {
|
||||
_("Interest Income"): {"account_category": "Investment Income"},
|
||||
_("Interest on Fixed Deposits"): {"account_category": "Investment Income"},
|
||||
_("Exchange Gain"): {"account_category": "Other Operating Income"},
|
||||
"is_group": 1,
|
||||
},
|
||||
"root_type": "Income",
|
||||
|
||||
@@ -233,6 +233,7 @@ def get():
|
||||
},
|
||||
_("Impairment"): {"account_number": "5224", "account_category": "Operating Expenses"},
|
||||
_("Tax Expense"): {"account_number": "5225", "account_category": "Tax Expense"},
|
||||
_("Exchange Loss"): {"account_number": "5226", "account_category": "Operating Expenses"},
|
||||
"account_number": "5200",
|
||||
},
|
||||
"root_type": "Expense",
|
||||
@@ -250,6 +251,10 @@ def get():
|
||||
"account_number": "4220",
|
||||
"account_category": "Investment Income",
|
||||
},
|
||||
_("Exchange Gain"): {
|
||||
"account_number": "4230",
|
||||
"account_category": "Other Operating Income",
|
||||
},
|
||||
"is_group": 1,
|
||||
"account_number": "4200",
|
||||
},
|
||||
|
||||
@@ -950,6 +950,61 @@ class TestPaymentEntry(ERPNextTestSuite):
|
||||
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"))
|
||||
self.assertEqual(outstanding_amount, 0)
|
||||
|
||||
def test_exchange_gain_loss_split_accounts(self):
|
||||
gain_account = create_account(
|
||||
account_name="_Test Exchange Gain",
|
||||
parent_account="Indirect Expenses - _TC",
|
||||
company="_Test Company",
|
||||
)
|
||||
loss_account = create_account(
|
||||
account_name="_Test Exchange Loss",
|
||||
parent_account="Indirect Expenses - _TC",
|
||||
company="_Test Company",
|
||||
)
|
||||
frappe.db.set_value("Company", "_Test Company", "exchange_gain_account", gain_account)
|
||||
frappe.db.set_value("Company", "_Test Company", "exchange_loss_account", loss_account)
|
||||
self.addCleanup(frappe.db.set_value, "Company", "_Test Company", "exchange_gain_account", "")
|
||||
self.addCleanup(frappe.db.set_value, "Company", "_Test Company", "exchange_loss_account", "")
|
||||
|
||||
si_gain = create_sales_invoice(
|
||||
customer="_Test Customer USD",
|
||||
debit_to="_Test Receivable USD - _TC",
|
||||
currency="USD",
|
||||
conversion_rate=50,
|
||||
)
|
||||
pe_gain = get_payment_entry("Sales Invoice", si_gain.name, bank_account="_Test Bank USD - _TC")
|
||||
pe_gain.reference_no = "1"
|
||||
pe_gain.reference_date = "2016-01-01"
|
||||
pe_gain.source_exchange_rate = 55
|
||||
pe_gain.save()
|
||||
self.assertEqual(pe_gain.references[0].exchange_gain_loss, 500)
|
||||
pe_gain.submit()
|
||||
|
||||
self.assertEqual(self.get_gain_loss_journal_account(pe_gain.name), gain_account)
|
||||
|
||||
si_loss = create_sales_invoice(
|
||||
customer="_Test Customer USD",
|
||||
debit_to="_Test Receivable USD - _TC",
|
||||
currency="USD",
|
||||
conversion_rate=55,
|
||||
)
|
||||
pe_loss = get_payment_entry("Sales Invoice", si_loss.name, bank_account="_Test Bank USD - _TC")
|
||||
pe_loss.reference_no = "2"
|
||||
pe_loss.reference_date = "2016-01-01"
|
||||
pe_loss.source_exchange_rate = 50
|
||||
pe_loss.save()
|
||||
self.assertEqual(pe_loss.references[0].exchange_gain_loss, -500)
|
||||
pe_loss.submit()
|
||||
|
||||
self.assertEqual(self.get_gain_loss_journal_account(pe_loss.name), loss_account)
|
||||
|
||||
def get_gain_loss_journal_account(self, payment_entry_name: str) -> str | None:
|
||||
return frappe.db.get_value(
|
||||
"Journal Entry Account",
|
||||
{"reference_type": "Payment Entry", "reference_name": payment_entry_name, "docstatus": 1},
|
||||
"account",
|
||||
)
|
||||
|
||||
def test_payment_entry_against_sales_invoice_with_cost_centre(self):
|
||||
from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ from erpnext.accounts.doctype.process_payment_reconciliation.process_payment_rec
|
||||
is_any_doc_running,
|
||||
)
|
||||
from erpnext.accounts.services.advances import get_advance_payment_entries_for_regional
|
||||
from erpnext.accounts.services.exchange_gain_loss import get_exchange_gain_loss_account
|
||||
from erpnext.accounts.utils import (
|
||||
QueryPaymentLedger,
|
||||
create_gain_loss_journal,
|
||||
@@ -485,9 +486,6 @@ class PaymentReconciliation(Document):
|
||||
"Accounts Settings", "exchange_gain_loss_posting_date", cache=True
|
||||
)
|
||||
invoice_exchange_map = self.get_invoice_exchange_map(args.get("invoices"), args.get("payments"))
|
||||
default_exchange_gain_loss_account = frappe.get_cached_value(
|
||||
"Company", self.company, "exchange_gain_loss_account"
|
||||
)
|
||||
|
||||
entries = []
|
||||
for pay in args.get("payments"):
|
||||
@@ -507,7 +505,10 @@ class PaymentReconciliation(Document):
|
||||
pay["exchange_rate"] = invoice_exchange_map.get(pay.get("reference_name"))
|
||||
|
||||
res.difference_amount = self.get_difference_amount(pay, inv, res["allocated_amount"])
|
||||
res.difference_account = default_exchange_gain_loss_account
|
||||
is_gain = (
|
||||
res.difference_amount > 0 if self.party_type == "Customer" else res.difference_amount < 0
|
||||
)
|
||||
res.difference_account = get_exchange_gain_loss_account(self.company, is_gain)
|
||||
res.exchange_rate = inv.get("exchange_rate")
|
||||
res.update({"gain_loss_posting_date": pay.get("posting_date")})
|
||||
if not pay.get("is_advance"):
|
||||
|
||||
@@ -6,6 +6,7 @@ import frappe
|
||||
from frappe.utils import add_days, add_years, cint, flt, getdate, nowdate, today
|
||||
from frappe.utils.data import getdate as convert_to_date
|
||||
|
||||
from erpnext.accounts.doctype.account.test_account import create_account
|
||||
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
|
||||
from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_entry
|
||||
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
|
||||
@@ -187,6 +188,53 @@ class TestPaymentReconciliation(ERPNextTestSuite):
|
||||
)
|
||||
return je
|
||||
|
||||
def setup_split_exchange_accounts(self):
|
||||
gain_account = create_account(
|
||||
account_name="_Test PR Split Exchange Gain",
|
||||
parent_account="Indirect Expenses - _TC",
|
||||
company=self.company,
|
||||
)
|
||||
loss_account = create_account(
|
||||
account_name="_Test PR Split Exchange Loss",
|
||||
parent_account="Indirect Expenses - _TC",
|
||||
company=self.company,
|
||||
)
|
||||
frappe.db.set_value("Company", self.company, "exchange_gain_account", gain_account)
|
||||
frappe.db.set_value("Company", self.company, "exchange_loss_account", loss_account)
|
||||
self.addCleanup(frappe.db.set_value, "Company", self.company, "exchange_gain_account", "")
|
||||
self.addCleanup(frappe.db.set_value, "Company", self.company, "exchange_loss_account", "")
|
||||
return gain_account, loss_account
|
||||
|
||||
def create_foreign_currency_sales_invoice(self, conversion_rate):
|
||||
si = self.create_sales_invoice(
|
||||
qty=1, rate=100, posting_date=nowdate(), do_not_save=True, do_not_submit=True
|
||||
)
|
||||
si.customer = self.customer_usd
|
||||
si.currency = "USD"
|
||||
si.conversion_rate = conversion_rate
|
||||
si.debit_to = self.debtors_usd
|
||||
si.save().submit()
|
||||
return si
|
||||
|
||||
def create_foreign_currency_journal_payment(self, debtors_account, exchange_rate):
|
||||
je = self.create_journal_entry(self.bank, debtors_account, 100, nowdate())
|
||||
je.multi_currency = 1
|
||||
je.accounts[0].exchange_rate = 1
|
||||
je.accounts[0].credit_in_account_currency = 0
|
||||
je.accounts[0].credit = 0
|
||||
je.accounts[0].debit_in_account_currency = 100 * exchange_rate
|
||||
je.accounts[0].debit = 100 * exchange_rate
|
||||
je.accounts[1].party_type = "Customer"
|
||||
je.accounts[1].party = self.customer_usd
|
||||
je.accounts[1].exchange_rate = exchange_rate
|
||||
je.accounts[1].credit_in_account_currency = 100
|
||||
je.accounts[1].credit = 100 * exchange_rate
|
||||
je.accounts[1].debit_in_account_currency = 0
|
||||
je.accounts[1].debit = 0
|
||||
je.save()
|
||||
je.submit()
|
||||
return je
|
||||
|
||||
def test_voucher_outstanding_metadata_comes_from_one_ledger_entry(self):
|
||||
"""cost_center and remarks must describe the same Payment Ledger Entry.
|
||||
|
||||
@@ -956,6 +1004,85 @@ class TestPaymentReconciliation(ERPNextTestSuite):
|
||||
frappe.db.get_value("Journal Entry", jea_parent.parent, "voucher_type"), "Exchange Gain Or Loss"
|
||||
)
|
||||
|
||||
def test_exchange_gain_loss_split_default_account(self):
|
||||
gain_account, loss_account = self.setup_split_exchange_accounts()
|
||||
|
||||
self.create_foreign_currency_sales_invoice(conversion_rate=80)
|
||||
self.create_foreign_currency_journal_payment(self.debtors_usd, exchange_rate=85)
|
||||
|
||||
pr = self.create_payment_reconciliation()
|
||||
pr.party = self.customer_usd
|
||||
pr.receivable_payable_account = self.debtors_usd
|
||||
pr.get_unreconciled_entries()
|
||||
|
||||
invoices = [x.as_dict() for x in pr.invoices]
|
||||
payments = [x.as_dict() for x in pr.payments]
|
||||
pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))
|
||||
|
||||
self.assertEqual(pr.allocation[0].difference_amount, 500)
|
||||
self.assertEqual(pr.allocation[0].difference_account, gain_account)
|
||||
pr.reconcile()
|
||||
|
||||
self.create_foreign_currency_sales_invoice(conversion_rate=85)
|
||||
self.create_foreign_currency_journal_payment(self.debtors_usd, exchange_rate=80)
|
||||
|
||||
pr = self.create_payment_reconciliation()
|
||||
pr.party = self.customer_usd
|
||||
pr.receivable_payable_account = self.debtors_usd
|
||||
pr.get_unreconciled_entries()
|
||||
|
||||
invoices = [x.as_dict() for x in pr.invoices]
|
||||
payments = [x.as_dict() for x in pr.payments]
|
||||
pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))
|
||||
|
||||
self.assertEqual(pr.allocation[0].difference_amount, -500)
|
||||
self.assertEqual(pr.allocation[0].difference_account, loss_account)
|
||||
|
||||
def test_payment_reconciliation_difference_account_override(self):
|
||||
_, loss_account = self.setup_split_exchange_accounts()
|
||||
override_account = create_account(
|
||||
account_name="_Test PR Override Exchange Account",
|
||||
parent_account="Indirect Expenses - _TC",
|
||||
company=self.company,
|
||||
)
|
||||
|
||||
si = self.create_foreign_currency_sales_invoice(conversion_rate=85)
|
||||
self.create_foreign_currency_journal_payment(self.debtors_usd, exchange_rate=80)
|
||||
|
||||
pr = self.create_payment_reconciliation()
|
||||
pr.party = self.customer_usd
|
||||
pr.receivable_payable_account = self.debtors_usd
|
||||
pr.get_unreconciled_entries()
|
||||
|
||||
invoices = [x.as_dict() for x in pr.invoices]
|
||||
payments = [x.as_dict() for x in pr.payments]
|
||||
pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))
|
||||
|
||||
# Default, computed from the split company fields, is pre-filled onto the row...
|
||||
self.assertEqual(pr.allocation[0].difference_amount, -500)
|
||||
self.assertEqual(pr.allocation[0].difference_account, loss_account)
|
||||
|
||||
# ...but the user can override it in the "Select Difference Account" dialog before reconciling,
|
||||
# and that explicit choice must be what actually gets booked, not the computed default.
|
||||
pr.allocation[0].difference_account = override_account
|
||||
pr.reconcile()
|
||||
|
||||
jea_parent = frappe.db.get_all(
|
||||
"Journal Entry Account",
|
||||
filters={"account": self.debtors_usd, "docstatus": 1, "reference_name": si.name, "credit": 500},
|
||||
fields=["parent"],
|
||||
)[0]
|
||||
self.assertEqual(
|
||||
frappe.db.get_value("Journal Entry", jea_parent.parent, "voucher_type"), "Exchange Gain Or Loss"
|
||||
)
|
||||
|
||||
gain_loss_line_account = frappe.db.get_value(
|
||||
"Journal Entry Account",
|
||||
{"parent": jea_parent.parent, "account": ["!=", self.debtors_usd]},
|
||||
"account",
|
||||
)
|
||||
self.assertEqual(gain_loss_line_account, override_account)
|
||||
|
||||
def test_difference_amount_via_negative_debit_or_credit_journal_entry(self):
|
||||
# Make Sale Invoice
|
||||
si = self.create_sales_invoice(
|
||||
|
||||
@@ -24,6 +24,11 @@ class TestAccountBalance(ERPNextTestSuite):
|
||||
"currency": "EUR",
|
||||
"balance": -100.0,
|
||||
},
|
||||
{
|
||||
"account": "Exchange Gain - _TC2",
|
||||
"currency": "EUR",
|
||||
"balance": 0.0,
|
||||
},
|
||||
{
|
||||
"account": "Income - _TC2",
|
||||
"currency": "EUR",
|
||||
|
||||
@@ -11,6 +11,13 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import g
|
||||
from erpnext.accounts.utils import create_gain_loss_journal, get_currency_precision
|
||||
|
||||
|
||||
def get_exchange_gain_loss_account(company: str, is_gain: bool) -> str | None:
|
||||
fieldname = "exchange_gain_account" if is_gain else "exchange_loss_account"
|
||||
return frappe.get_cached_value("Company", company, fieldname) or frappe.get_cached_value(
|
||||
"Company", company, "exchange_gain_loss_account"
|
||||
)
|
||||
|
||||
|
||||
def gain_loss_journal_already_booked(
|
||||
gain_loss_account: str,
|
||||
exc_gain_loss: float,
|
||||
@@ -163,9 +170,7 @@ def make_exchange_gain_loss_journal(
|
||||
|
||||
reverse_dr_or_cr = "debit" if dr_or_cr == "credit" else "credit"
|
||||
|
||||
gain_loss_account = frappe.get_cached_value(
|
||||
"Company", doc.company, "exchange_gain_loss_account"
|
||||
)
|
||||
gain_loss_account = get_exchange_gain_loss_account(doc.company, reverse_dr_or_cr == "credit")
|
||||
je = create_gain_loss_journal(
|
||||
doc.company,
|
||||
args.get("difference_posting_date") if args else doc.posting_date,
|
||||
|
||||
@@ -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"),
|
||||
}
|
||||
|
||||
@@ -309,6 +309,8 @@ erpnext.company.setup_queries = function (frm) {
|
||||
["discount_allowed_account", { root_type: "Expense" }],
|
||||
["discount_received_account", { root_type: "Income" }],
|
||||
["exchange_gain_loss_account", { root_type: ["in", ["Expense", "Income"]] }],
|
||||
["exchange_gain_account", { root_type: ["in", ["Expense", "Income"]] }],
|
||||
["exchange_loss_account", { root_type: ["in", ["Expense", "Income"]] }],
|
||||
[
|
||||
"unrealized_exchange_gain_loss_account",
|
||||
{ root_type: ["in", ["Expense", "Income", "Equity", "Liability"]] },
|
||||
|
||||
@@ -65,6 +65,8 @@
|
||||
"default_finance_book",
|
||||
"exchange_gain__loss_section",
|
||||
"exchange_gain_loss_account",
|
||||
"exchange_gain_account",
|
||||
"exchange_loss_account",
|
||||
"column_break_sttp",
|
||||
"unrealized_exchange_gain_loss_account",
|
||||
"round_off_section",
|
||||
@@ -397,6 +399,24 @@
|
||||
"no_copy": 1,
|
||||
"options": "Account"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"fieldname": "exchange_gain_account",
|
||||
"fieldtype": "Link",
|
||||
"ignore_user_permissions": 1,
|
||||
"label": "Exchange Gain Account",
|
||||
"no_copy": 1,
|
||||
"options": "Account"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"fieldname": "exchange_loss_account",
|
||||
"fieldtype": "Link",
|
||||
"ignore_user_permissions": 1,
|
||||
"label": "Exchange Loss Account",
|
||||
"no_copy": 1,
|
||||
"options": "Account"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"fieldname": "unrealized_exchange_gain_loss_account",
|
||||
|
||||
@@ -103,7 +103,9 @@ class Company(NestedSet):
|
||||
enable_provisional_accounting_for_non_stock_items: DF.Check
|
||||
enable_stock_delivered_but_not_billed: DF.Check
|
||||
exception_budget_approver_role: DF.Link | None
|
||||
exchange_gain_account: DF.Link | None
|
||||
exchange_gain_loss_account: DF.Link | None
|
||||
exchange_loss_account: DF.Link | None
|
||||
existing_company: DF.Link | None
|
||||
expenses_added_to_stock_account: DF.Link | None
|
||||
expenses_added_to_stock_contra_account: DF.Link | None
|
||||
@@ -369,6 +371,8 @@ class Company(NestedSet):
|
||||
["Default Payment Discount Account", "default_discount_account"],
|
||||
["Unrealized Profit / Loss Account", "unrealized_profit_loss_account"],
|
||||
["Exchange Gain / Loss Account", "exchange_gain_loss_account"],
|
||||
["Exchange Gain Account", "exchange_gain_account"],
|
||||
["Exchange Loss Account", "exchange_loss_account"],
|
||||
["Unrealized Exchange Gain / Loss Account", "unrealized_exchange_gain_loss_account"],
|
||||
["Round Off Account", "round_off_account"],
|
||||
["Default Deferred Revenue Account", "default_deferred_revenue_account"],
|
||||
@@ -792,6 +796,20 @@ class Company(NestedSet):
|
||||
|
||||
self.db_set("exchange_gain_loss_account", exchange_gain_loss_acct)
|
||||
|
||||
if not self.exchange_gain_account:
|
||||
exchange_gain_acct = frappe.db.get_value(
|
||||
"Account", {"account_name": _("Exchange Gain"), "company": self.name, "is_group": 0}
|
||||
)
|
||||
|
||||
self.db_set("exchange_gain_account", exchange_gain_acct)
|
||||
|
||||
if not self.exchange_loss_account:
|
||||
exchange_loss_acct = frappe.db.get_value(
|
||||
"Account", {"account_name": _("Exchange Loss"), "company": self.name, "is_group": 0}
|
||||
)
|
||||
|
||||
self.db_set("exchange_loss_account", exchange_loss_acct)
|
||||
|
||||
if not self.disposal_account:
|
||||
disposal_acct = frappe.db.get_value(
|
||||
"Account",
|
||||
|
||||
Reference in New Issue
Block a user