diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py index 37863036492..11614467472 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py +++ b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py @@ -178,7 +178,7 @@ def start_repost(account_repost_doc=str) -> None: if doc.doctype in ["Sales Invoice", "Purchase Invoice"]: if not repost_doc.delete_cancelled_entries: doc.docstatus = 2 - doc.make_gl_entries_on_cancel() + doc.make_gl_entries_on_cancel(from_repost=True) doc.docstatus = 1 if doc.doctype == "Sales Invoice": @@ -190,7 +190,7 @@ def start_repost(account_repost_doc=str) -> None: elif doc.doctype == "Purchase Receipt": if not repost_doc.delete_cancelled_entries: doc.docstatus = 2 - doc.make_gl_entries_on_cancel() + doc.make_gl_entries_on_cancel(from_repost=True) doc.docstatus = 1 doc.make_gl_entries(from_repost=True) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 97ded97dd2e..386d28fd804 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -1206,7 +1206,6 @@ class SalesInvoice(SellingController): self.make_exchange_gain_loss_journal() elif self.docstatus == 2: - cancel_exchange_gain_loss_journal(frappe._dict(doctype=self.doctype, name=self.name)) make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name) if update_outstanding == "No": diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 39faa24c16a..aeb266b6d87 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -4668,6 +4668,59 @@ class TestSalesInvoice(FrappeTestCase): doc.db_set("do_not_use_batchwise_valuation", original_value) + def test_system_generated_exchange_gain_or_loss_je_after_repost(self): + from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry + from erpnext.accounts.doctype.repost_accounting_ledger.test_repost_accounting_ledger import ( + update_repost_settings, + ) + + update_repost_settings() + + si = create_sales_invoice( + customer="_Test Customer USD", + debit_to="_Test Receivable USD - _TC", + currency="USD", + conversion_rate=80, + ) + + pe = get_payment_entry("Sales Invoice", si.name) + pe.reference_no = "10" + pe.reference_date = nowdate() + pe.paid_from_account_currency = si.currency + pe.paid_to_account_currency = "INR" + pe.source_exchange_rate = 85 + pe.target_exchange_rate = 1 + pe.paid_amount = si.outstanding_amount + pe.insert() + pe.submit() + + ral = frappe.new_doc("Repost Accounting Ledger") + ral.company = si.company + ral.append("vouchers", {"voucher_type": si.doctype, "voucher_no": si.name}) + ral.save() + ral.submit() + + je = frappe.qb.DocType("Journal Entry") + jea = frappe.qb.DocType("Journal Entry Account") + q = ( + ( + frappe.qb.from_(je) + .join(jea) + .on(je.name == jea.parent) + .select(je.docstatus) + .where( + (je.voucher_type == "Exchange Gain Or Loss") + & (jea.reference_name == si.name) + & (jea.reference_type == "Sales Invoice") + & (je.is_system_generated == 1) + ) + ) + .limit(1) + .run() + ) + + self.assertEqual(q[0][0], 1) + def make_item_for_si(item_code, properties=None): from erpnext.stock.doctype.item.test_item import make_item diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index e375c2c362c..2369c39f508 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -959,8 +959,9 @@ class StockController(AccountsController): make_sl_entries(sl_entries, allow_negative_stock, via_landed_cost_voucher) update_batch_qty(self.doctype, self.name, via_landed_cost_voucher=via_landed_cost_voucher) - def make_gl_entries_on_cancel(self): - cancel_exchange_gain_loss_journal(frappe._dict(doctype=self.doctype, name=self.name)) + def make_gl_entries_on_cancel(self, from_repost=False): + if not from_repost: + cancel_exchange_gain_loss_journal(frappe._dict(doctype=self.doctype, name=self.name)) if frappe.db.sql( """select name from `tabGL Entry` where voucher_type=%s and voucher_no=%s""",