From 3438d0e32ae69acb21abab8af9dfca8dbc31cef0 Mon Sep 17 00:00:00 2001 From: Camila Vives Date: Thu, 14 May 2026 13:17:30 +0000 Subject: [PATCH 1/5] [FIX] l10n_ar_payment_bundle: prevent onchange from overriding linked payment amounts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Modified _onchange_amount method to exclude linked payments (with main_payment_id) - Linked payments now keep the amount suggested by x2many context - Added test_link_payment_onchange_does_not_override_remaining_amount test - Test validates that linked payments maintain their suggested amount Change note: Se corrigió un problema donde al crear pagos vinculados dentro de un payment bundle, el monto se sobrescribía incorrectamente. Ahora los pagos vinculados mantienen automáticamente el monto que les corresponde según el saldo pendiente. closes ingadhoc/account-payment#1062 Signed-off-by: rov-adhoc --- .../models/account_payment.py | 3 +- .../tests/test_payment_difference.py | 54 +++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/l10n_ar_payment_bundle/models/account_payment.py b/l10n_ar_payment_bundle/models/account_payment.py index 0aed3f5ac..f9bbb0b42 100644 --- a/l10n_ar_payment_bundle/models/account_payment.py +++ b/l10n_ar_payment_bundle/models/account_payment.py @@ -355,4 +355,5 @@ def _compute_warnings(self): @api.onchange("to_pay_move_line_ids") def _onchange_amount(self): - super(AccountPayment, self.filtered(lambda r: r.payment_method_code != "payment_bundle"))._onchange_amount() + payments = self.filtered(lambda r: r.payment_method_code != "payment_bundle" and not r.main_payment_id) + super(AccountPayment, payments)._onchange_amount() diff --git a/l10n_ar_payment_bundle/tests/test_payment_difference.py b/l10n_ar_payment_bundle/tests/test_payment_difference.py index 9a632b133..deab4eb17 100644 --- a/l10n_ar_payment_bundle/tests/test_payment_difference.py +++ b/l10n_ar_payment_bundle/tests/test_payment_difference.py @@ -357,3 +357,57 @@ def test_payment_difference_zero_when_exact(self): places=2, msg="Payment difference should be 0 when amounts match exactly", ) + + def test_link_payment_onchange_does_not_override_remaining_amount(self): + """Linked payments should keep the remaining amount suggested by the x2many context.""" + invoice = self._create_invoice(10511.35) + invoice.action_post() + + payment = self._create_payment_bundle() + payment.to_pay_move_line_ids = invoice.line_ids.filtered( + lambda l: l.account_id.account_type in ("asset_receivable", "liability_payable") + ) + + self.env["account.payment"].create( + { + "payment_type": "inbound", + "partner_type": "customer", + "partner_id": self.partner.id, + "journal_id": self.bank_journal.id, + "amount": 500.0, + "main_payment_id": payment.id, + } + ) + + virtual_payment = self.env["account.payment"].new( + { + "payment_type": "inbound", + "partner_type": "customer", + "partner_id": self.partner.id, + "journal_id": self.bundle_journal.id, + "payment_method_line_id": self.payment_method_line.id, + "amount": 0.0, + "to_pay_move_line_ids": [ + Command.set( + invoice.line_ids.filtered( + lambda l: l.account_id.account_type in ("asset_receivable", "liability_payable") + ).ids + ) + ], + } + ) + linked_payment = self.env["account.payment"].new( + { + "payment_type": "inbound", + "partner_type": "customer", + "partner_id": self.partner.id, + "journal_id": self.bank_journal.id, + "amount": 10011.35, + "main_payment_id": virtual_payment, + } + ) + self.assertFalse(linked_payment.main_payment_id._origin) + + linked_payment._onchange_amount() + + self.assertAlmostEqual(linked_payment.amount, 10011.35, places=2) From 8656f614277ecf0801702a1a81882730b8fe2f19 Mon Sep 17 00:00:00 2001 From: Camila Vives Date: Tue, 12 May 2026 16:15:46 -0300 Subject: [PATCH 2/5] [FIX] account_payment_pro: keep posted payment accounting rate closes ingadhoc/account-payment#1059 Signed-off-by: rov-adhoc --- account_payment_pro/models/account_payment.py | 12 ++++++-- .../test_account_paymet_pro_unit_test.py | 30 +++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/account_payment_pro/models/account_payment.py b/account_payment_pro/models/account_payment.py index 7931d2521..fb6f77903 100644 --- a/account_payment_pro/models/account_payment.py +++ b/account_payment_pro/models/account_payment.py @@ -378,11 +378,14 @@ def _onchange_currency_recompute_amount(self): amount = rec.env.context.get("default_amount") rec.update({"amount_exact": amount, "amount": amount}) - @api.depends("amount", "amount_exact", "other_currency", "force_amount_company_currency") + @api.depends( + "amount", "amount_exact", "other_currency", "force_amount_company_currency", "amount_company_currency_signed" + ) def _compute_amount_company_currency(self): """ * Si las monedas son iguales devuelve 1 * si no, si hay force_amount_company_currency, devuelve ese valor + * si ya hay asiento, usa el importe contable nativo sin signo * sino, devuelve el amount convertido a la moneda de la cia """ for rec in self: @@ -391,9 +394,14 @@ def _compute_amount_company_currency(self): amount_company_currency = amount elif rec.force_amount_company_currency: amount_company_currency = rec.force_amount_company_currency + elif rec.move_id: + amount_company_currency = abs(rec.amount_company_currency_signed) else: amount_company_currency = rec.currency_id._convert( - amount, rec.company_id.currency_id, rec.company_id, rec.date + amount, + rec.company_id.currency_id, + rec.company_id, + rec.date, ) rec.amount_company_currency = amount_company_currency diff --git a/account_payment_pro/tests/test_account_paymet_pro_unit_test.py b/account_payment_pro/tests/test_account_paymet_pro_unit_test.py index 99a565bac..2f0c93ca7 100644 --- a/account_payment_pro/tests/test_account_paymet_pro_unit_test.py +++ b/account_payment_pro/tests/test_account_paymet_pro_unit_test.py @@ -169,6 +169,36 @@ def test_force_amount_company_currency_without_payment_pro(self): msg="Liquidity line balance should still use forced amount after synchronization", ) + def test_posted_payment_without_payment_pro_keeps_accounting_rate_after_rate_change(self): + self.company.use_payment_pro = False + + payment = self.env["account.payment"].create( + { + "payment_type": "inbound", + "partner_type": "customer", + "partner_id": self.partner_ri.id, + "journal_id": self.company_bank_journal.id, + "amount": 100.0, + "currency_id": self.eur_currency.id, + "date": self.today, + } + ) + payment.action_post() + + liquidity_lines = payment.move_id.line_ids.filtered( + lambda line: line.account_id == payment.outstanding_account_id + ) + accounting_amount = abs(sum(liquidity_lines.mapped("balance"))) + self.assertAlmostEqual(accounting_amount, 100000.0, places=2) + self.assertAlmostEqual(payment.amount_company_currency, accounting_amount, places=2) + self.assertAlmostEqual(payment.exchange_rate, 1000.0, places=2) + + self.rates[1].inverse_company_rate = 2000 + payment.invalidate_recordset(["amount_company_currency", "exchange_rate"]) + + self.assertAlmostEqual(payment.amount_company_currency, accounting_amount, places=2) + self.assertAlmostEqual(payment.exchange_rate, 1000.0, places=2) + def test_write_off_line_amounts_company_vs_payment_currency(self): """Minimal test: company currency vs payment currency, force company amount and check write-off line balance""" # Use existing company and ensure we have a different currency for the payment From f65d59dc84e47d0112dc6870f0c13f9214917d57 Mon Sep 17 00:00:00 2001 From: Camila Vives Date: Mon, 18 May 2026 17:56:45 +0000 Subject: [PATCH 3/5] [ADD] l10n_ar_payment_bundle: set default_amount to 0 when bundle journal is default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add AccountMoveLine inherit to override action_register_payment. When the first available journal has the payment_bundle payment method (inbound or outbound), set default_amount to 0 in the action context so the payment wizard opens with an empty amount instead of the line's residual amount. Use setdefault to ensure context key is created if not present. Change note: Al registrar un pago desde una línea de asiento, si el diario por defecto tiene configurado el método de pago Bundle, el monto sugerido en el formulario de pago se establece en 0. closes ingadhoc/account-payment#1072 Signed-off-by: rov-adhoc --- l10n_ar_payment_bundle/models/__init__.py | 1 + .../models/account_move_line.py | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 l10n_ar_payment_bundle/models/account_move_line.py diff --git a/l10n_ar_payment_bundle/models/__init__.py b/l10n_ar_payment_bundle/models/__init__.py index bb2a9536b..839ada5fc 100644 --- a/l10n_ar_payment_bundle/models/__init__.py +++ b/l10n_ar_payment_bundle/models/__init__.py @@ -4,3 +4,4 @@ from . import account_payment_method from . import account_journal from . import account_payment_register +from . import account_move_line diff --git a/l10n_ar_payment_bundle/models/account_move_line.py b/l10n_ar_payment_bundle/models/account_move_line.py new file mode 100644 index 000000000..59662f649 --- /dev/null +++ b/l10n_ar_payment_bundle/models/account_move_line.py @@ -0,0 +1,22 @@ +from odoo import models + + +class AccountMoveLine(models.Model): + _inherit = "account.move.line" + + def action_register_payment(self, ctx=None): + action = super().action_register_payment(ctx=ctx) + # Si el diario por defecto es bundle + journal = self.env["account.journal"].search( + [ + *self.env["account.journal"]._check_company_domain(self.company_id), + ("type", "in", ["bank", "cash", "credit"]), + ], + limit=1, + ) + + if "payment_bundle" in ( + journal.inbound_payment_method_line_ids + journal.outbound_payment_method_line_ids + ).mapped("code"): + action.setdefault("context", {})["default_amount"] = 0 + return action From 8e0ed9a4baaf63f392a238dea79cad8038bda820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roc=C3=ADo=20Vega?= Date: Fri, 15 May 2026 13:41:41 -0300 Subject: [PATCH 4/5] [FIX] l10n_latam_check_ux: BKFP of https://github.com/ingadhoc/account-payment/commit/32f3dfa5138f00e7ab4d5e5f66b47a508c4b516d#diff-eefa0dffdfb1eb4e8ea275e68e1756d3d60648e686e438ccf530740323dd0539 closes ingadhoc/account-payment#1068 Signed-off-by: Filoquin adhoc --- l10n_latam_check_ux/models/account_payment.py | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/l10n_latam_check_ux/models/account_payment.py b/l10n_latam_check_ux/models/account_payment.py index f72b39946..79c1a1ddc 100644 --- a/l10n_latam_check_ux/models/account_payment.py +++ b/l10n_latam_check_ux/models/account_payment.py @@ -112,3 +112,43 @@ def action_draft(self): ) super().action_draft() + + def _is_latam_check_transfer(self): + self.ensure_one() + return super()._is_latam_check_transfer() or ( + self.is_internal_transfer + and bool(self.l10n_latam_move_check_ids) + and self.destination_account_id == self.company_id.transfer_account_id + ) + + @api.constrains( + "is_internal_transfer", + "payment_type", + "payment_method_line_id", + "destination_journal_id", + "l10n_latam_move_check_ids", + ) + def _check_inbound_transfer_checks_current_journal(self): + """Keep server-side behavior aligned with the wizard domain in Odoo. + + For inbound internal transfers receiving third-party checks, all selected checks + must come from the same current journal: the source journal (`destination_journal_id`). + """ + for rec in self.filtered( + lambda x: ( + x.state == "draft" + and x.is_internal_transfer + and x.payment_type == "inbound" + and x.payment_method_line_id.code == "in_third_party_checks" + and x.destination_journal_id + and x.l10n_latam_move_check_ids + ) + ): + invalid_checks = rec.l10n_latam_move_check_ids.filtered( + lambda c: c.current_journal_id != rec.destination_journal_id + ) + if invalid_checks: + raise ValidationError( + "All selected checks must belong to the source journal (%s)." + % rec.destination_journal_id.display_name + ) From 0fb612fc5b890a07965bb95107f236e081068511 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roc=C3=ADo=20Vega?= Date: Tue, 19 May 2026 15:12:37 -0300 Subject: [PATCH 5/5] [FIX] account_payment_pro: prevent ir.default journal from overriding payment company When `default_company_id` is passed via context, a journal previously set as user default via `ir.default` and belonging to a different company could trigger the `_compute_company_id` precompute, silently overwriting the intended company with the environment's main company. Fix: in `default_get`, check whether the resolved `journal_id` belongs to the requested company. If not, replace it with the ir.default journal for that company (if one exists), or clear it so Odoo can compute a safe default. closes ingadhoc/account-payment#1078 Signed-off-by: Filoquin adhoc --- account_payment_pro/models/account_payment.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/account_payment_pro/models/account_payment.py b/account_payment_pro/models/account_payment.py index fb6f77903..4cabe723e 100644 --- a/account_payment_pro/models/account_payment.py +++ b/account_payment_pro/models/account_payment.py @@ -149,6 +149,18 @@ class AccountPayment(models.Model): @api.model def default_get(self, fields_list): res = super().default_get(fields_list) + # Si se pasa company_id explícitamente por contexto, evitamos que journal_id + # proveniente de ir.default (valores predeterminados del usuario) y perteneciente + # a otra compañía dispare el precompute _compute_company_id y sobreescriba la + # compañía correcta del pago por la compañía principal del entorno. + default_company_id = self._context.get("default_company_id") + if default_company_id and "journal_id" in res: + journal = self.env["account.journal"].browse(res["journal_id"]) + if journal.company_id.id != default_company_id: + res.pop("journal_id") + ir_defaults = self.env["ir.default"].with_company(default_company_id)._get_model_defaults(self._name) + if "journal_id" in ir_defaults: + res["journal_id"] = self.env["account.journal"].browse(ir_defaults["journal_id"]).id if "previous_currency_id" in fields_list and "previous_currency_id" not in res: currency_id = res.get("currency_id") if not currency_id: