Andrea Stirpe 2025-04-17 06:01:35 +02:00 committed by GitHub
commit a752bd86b4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 138 additions and 1 deletions

View File

@ -158,9 +158,20 @@ class MassReconcileBase(models.AbstractModel):
currency = same_curr and lines[0].currency_id or lines[0].company_id.currency_id
journal = self.journal_id
partners = lines.mapped("partner_id")
# Adjust amount_currency to match the sign of the company's residual (amount)
if same_curr:
if amount != 0:
sign = 1 if amount > 0 else -1
adjusted_amount_curr = abs(amount_curr) * sign
else:
adjusted_amount_curr = 0.0
else:
adjusted_amount_curr = amount
write_off_vals = {
"name": _("Automatic writeoff"),
"amount_currency": same_curr and amount_curr or amount,
"amount_currency": adjusted_amount_curr if same_curr else amount,
"debit": amount > 0.0 and amount or 0.0,
"credit": amount < 0.0 and -amount or 0.0,
"partner_id": len(partners) == 1 and partners.id or False,

View File

@ -451,3 +451,129 @@ class TestScenarioReconcile(AccountTestInvoicingCommon):
)
self.assertEqual(len(writeoff_line), 1)
self.assertEqual(writeoff_line.date, fields.Date.today())
def test_reconcile_with_writeoff_currency_opposite_signs(self):
"""Test write-off when company and foreign residuals have opposite signs."""
self.env.ref("base.group_multi_currency").users |= self.env.user
self.company.currency_id = self.env.ref("base.EUR")
usd = self.env.ref("base.USD")
usd.active = True
inv_date = fields.Date.today() - timedelta(days=10)
pay_date = fields.Date.today() - timedelta(days=1)
# Create currency rates
self.env["res.currency.rate"].create(
[
{
"name": inv_date,
"currency_id": usd.id,
"rate": 1.2,
"company_id": self.company.id,
},
{
"name": pay_date,
"rate": 1.25,
"currency_id": usd.id,
"company_id": self.company.id,
},
{
"name": fields.Date.today(),
"rate": 1.25,
"currency_id": usd.id,
"company_id": self.company.id,
},
]
)
# Create invoice and payment with opposing residual signs
common_ref = "INV-PAY-OPPOSITE-SIGNS"
invoice = self.init_invoice(
move_type="out_invoice",
partner=self.partner_a,
currency=usd,
amounts=[100],
invoice_date=inv_date,
post=True,
)
invoice.ref = common_ref
payment = self.env["account.payment"].create(
{
"partner_type": "customer",
"payment_type": "inbound",
"partner_id": self.partner_a.id,
"destination_account_id": self.company_data[
"default_account_receivable"
].id,
"amount": 100.10,
"currency_id": usd.id,
"journal_id": self.bank_journal.id,
"date": pay_date,
"ref": common_ref,
}
)
payment.action_post()
# Create and run mass reconciliation
mass_rec = self.mass_rec_obj.create(
{
"name": "mass_reconcile_currency_writeoff_opposite",
"account": self.company_data["default_account_receivable"].id,
"reconcile_method": [
(
0,
0,
{
"name": "mass.reconcile.advanced.ref",
"account_lost_id": self.company_data[
"default_account_expense"
].id,
"account_profit_id": self.company_data[
"default_account_revenue"
].id,
"journal_id": self.company_data["default_journal_misc"].id,
"write_off": 3.50,
"date_base_on": "newest",
},
)
],
}
)
existing_moves = self.env["account.move"].search(
[("journal_id", "=", self.company_data["default_journal_misc"].id)]
)
mass_rec.run_reconcile()
# Validate write-off move
writeoff_move = self.env["account.move"].search(
[
("journal_id", "=", self.company_data["default_journal_misc"].id),
("id", "not in", existing_moves.ids),
]
)
self.assertEqual(
len(writeoff_move), 1, "Exactly one write-off move should exist"
)
self.assertEqual(
writeoff_move.currency_id, usd, "USD should be the write-off currency"
)
pl_line = writeoff_move.line_ids.filtered(
lambda ml: ml.account_id == self.company_data["default_account_expense"]
)
receivable_line = writeoff_move.line_ids.filtered(
lambda ml: ml.account_id == self.company_data["default_account_receivable"]
)
# Check amounts (0.10 USD residual, 3.25 EUR residual)
self.assertAlmostEqual(pl_line.debit, 3.25, 2, "Expense line debit (EUR)")
self.assertAlmostEqual(
pl_line.amount_currency, 0.10, 2, "Expense line USD amount"
)
self.assertAlmostEqual(
receivable_line.credit, 3.25, 2, "Receivable line credit (EUR)"
)
self.assertAlmostEqual(
receivable_line.amount_currency, -0.10, 2, "Receivable line USD amount"
)