From 8286ff63c15da500ae73f716afd4027fbe4b140f Mon Sep 17 00:00:00 2001 From: Camila Vives Date: Tue, 11 Aug 2026 15:17:15 +0000 Subject: [PATCH] [FIX] l10n_latam_check_ux: reject checks within the company that holds them The rejected journal had no company in its domain and the wizard had no company_id nor _check_company_auto, so the payments could be created in another company of the branch tree. check_company does not catch it because Odoo accepts records of a parent company on a branch, so the _compute_company_id of the check followed the payment and the check migrated of company as a side effect of the rejection, leaving the customer debt in the wrong company. Restrict the journal to the company of the checks and validate it on confirm. --- .../tests/test_check_transfers.py | 44 ++++++++++++++++++- .../wizards/account_check_reject_wizard.py | 30 ++++++++++++- .../account_check_reject_wizard_view.xml | 1 + 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/l10n_latam_check_ux/tests/test_check_transfers.py b/l10n_latam_check_ux/tests/test_check_transfers.py index 2ce60831b..2d2ad11e5 100644 --- a/l10n_latam_check_ux/tests/test_check_transfers.py +++ b/l10n_latam_check_ux/tests/test_check_transfers.py @@ -1,6 +1,6 @@ from odoo import Command, fields from odoo.addons.account.tests.common import AccountTestInvoicingCommon -from odoo.exceptions import ValidationError +from odoo.exceptions import UserError, ValidationError from odoo.tests.common import tagged @@ -152,6 +152,23 @@ def _create_third_party_check(self, journal, check_number): payment.action_post() return payment.l10n_latam_new_check_ids + def _create_branch(self, name="Branch", parent=None): + """Sucursal que comparte el plan de cuentas de su padre. + + Las propiedades company dependent del partner hay que setearlas para la sucursal + para poder postear pagos en ella. + """ + parent = parent or self.company + branch = self.env["res.company"].create({"name": name, "parent_id": parent.id}) + self.partner_a.with_company(branch).write( + { + "property_account_receivable_id": self.company_data["default_account_receivable"].id, + "property_account_payable_id": self.company_data["default_account_payable"].id, + } + ) + branch.transfer_account_id = self.company.transfer_account_id + return branch + def test_deposit_third_party_check_to_bank(self): check = self._create_third_party_check(self.third_party_check_journal, "UX-DEP-0001") bank_journal = self.company_bank_journal @@ -303,3 +320,28 @@ def test_inbound_internal_transfer_rejects_checks_from_other_current_journal(sel "amount": 200.0, } ) + + def test_reject_wizard_requires_a_journal_of_the_check_company(self): + """Rechazar contra un diario de otra compañía migraría el cheque de compañía. + + `check_company` no lo frena porque en branches Odoo acepta registros de la compañía + padre sobre una hija, así que la validación tiene que ser explícita. + """ + check = self._create_third_party_check(self.third_party_check_journal, "UX-REJ-COMP-0001") + self.env["l10n_latam.payment.mass.transfer"].with_context( + active_model="l10n_latam.check", + active_ids=check.ids, + ).create({"destination_journal_id": self.company_bank_journal.id})._create_payments() + + branch = self._create_branch() + branch_rejected_journal = self._create_check_journal("Branch Rejected Checks", "BRJC", company=branch) + + wizard = ( + self.env["account.check.reject.wizard"] + .with_context(active_model="l10n_latam.check", active_ids=check.ids) + .create({"rejected_journal_id": branch_rejected_journal.id}) + ) + + self.assertEqual(wizard.company_id, self.company) + with self.assertRaisesRegex(UserError, "belongs to"): + wizard.action_confirm() diff --git a/l10n_latam_check_ux/wizards/account_check_reject_wizard.py b/l10n_latam_check_ux/wizards/account_check_reject_wizard.py index c533f4d53..84a385762 100644 --- a/l10n_latam_check_ux/wizards/account_check_reject_wizard.py +++ b/l10n_latam_check_ux/wizards/account_check_reject_wizard.py @@ -16,11 +16,16 @@ class AccountCheckRejectWizard(models.TransientModel): default=fields.Date.context_today, required=True, ) + company_id = fields.Many2one( + "res.company", + compute="_compute_company_id", + help="Company of the checks being rejected. The rejection is always processed within it.", + ) rejected_journal_id = fields.Many2one( "account.journal", string="Rejected Checks Journal", required=True, - domain=[("type", "in", ("bank", "cash"))], + domain="[('type', 'in', ('bank', 'cash')), ('company_id', '=', company_id)]", help="Journal used for rejected third-party checks (e.g. 'Cheques de Terceros Rechazados').", ) case_description = fields.Char( @@ -40,6 +45,11 @@ def default_get(self, fields_list): ) return res + @api.depends_context("active_ids") + def _compute_company_id(self): + for rec in self: + rec.company_id = rec._get_checks().company_id[:1] + @api.depends("rejected_journal_id") def _compute_case_description(self): for rec in self: @@ -75,6 +85,24 @@ def action_confirm(self): if not checks: raise UserError(_("No checks selected.")) + # The rejection must stay within the company that holds the check: creating the + # payments in another company of the branch tree silently moves the check there + # (company_id is computed from its last operation) and books the customer debt in + # the wrong company. check_company does not catch it because Odoo accepts records + # of a parent company on a branch. + companies = checks.company_id + if len(companies) > 1: + raise UserError(_("All selected checks must belong to the same company.")) + if self.rejected_journal_id.company_id != companies: + raise UserError( + _("The journal '%(journal)s' belongs to '%(journal_company)s' but the check belongs to '%(company)s'.") + % { + "journal": self.rejected_journal_id.display_name, + "journal_company": self.rejected_journal_id.company_id.display_name, + "company": companies.display_name, + } + ) + for check in checks: last_operation = check._get_last_operation() if ( diff --git a/l10n_latam_check_ux/wizards/account_check_reject_wizard_view.xml b/l10n_latam_check_ux/wizards/account_check_reject_wizard_view.xml index 70fb867c1..8e1c7ac12 100644 --- a/l10n_latam_check_ux/wizards/account_check_reject_wizard_view.xml +++ b/l10n_latam_check_ux/wizards/account_check_reject_wizard_view.xml @@ -7,6 +7,7 @@
+