Skip to content

[18.0][FIX] sale_operating_unit: strict journal selection for OU sale orders#845

Open
IJOL wants to merge 1 commit intoOCA:18.0from
BITVAX:18.0-fix-sale-operating-unit-journal-ou
Open

[18.0][FIX] sale_operating_unit: strict journal selection for OU sale orders#845
IJOL wants to merge 1 commit intoOCA:18.0from
BITVAX:18.0-fix-sale-operating-unit-journal-ou

Conversation

@IJOL
Copy link
Copy Markdown

@IJOL IJOL commented Apr 13, 2026

Problem

`sale_operating_unit._compute_journal_id` searches for the invoicing
journal with a domain that mixes `operating_unit_id = <so.ou>` and
`operating_unit_id = False` in a single OR clause, then takes
`limit=1` without an explicit order. When the database happens to
return a no-OU journal first, the sale order's `journal_id` is
silently set to it, and the invoice created from that SO inherits
the wrong journal. Downstream,
`account_operating_unit._check_journal_operating_unit` may trip with:

The OU in the Move and in Journal must be the same.

This can happen in perfectly configured multi-OU companies whenever
legacy no-OU journals coexist with OU-scoped journals.

Fix

Perform two separate searches:

  1. First prefer journals whose `operating_unit_id` exactly matches
    the SO's OU.
  2. Only fall back to a no-OU journal if no matching one exists.

The no-OU fallback is preserved for deployments that legitimately use
a shared journal across OUs.

Test

Includes a TDD regression test (`test_create_invoice_journal_ou.py`)
that:

  • creates two sale journals in the same company, one in OU1 and one
    in B2B (OU1 first, so its id is lower → it would be picked first
    by the previous OR-based domain);
  • creates a sale order as a B2B-restricted user;
  • invoices it and asserts that `invoice.journal_id.operating_unit_id`
    equals B2B.

Fails on upstream/18.0, passes with this fix.

@OCA-git-bot OCA-git-bot added series:18.0 mod:sale_operating_unit Module sale_operating_unit labels Apr 13, 2026
_compute_journal_id used to search with a domain that mixes
operating_unit_id=<so.ou> and operating_unit_id=False in a single OR
clause and then took limit=1 without an explicit order. When the
database returned a no-OU journal first, the SO's journal_id was
silently set to it, and the invoice created from that SO inherited
the wrong journal, breaking account_operating_unit's
_check_journal_operating_unit downstream.

This change performs two separate searches: first prefer journals
whose operating_unit_id exactly matches the SO's OU; only fall back
to a no-OU journal if no matching one exists. The no-OU fallback is
preserved for deployments that legitimately use a shared journal
across OUs.

Includes a TDD regression test that creates a B2B sale order in a
multi-OU company where an OU1 sale journal would otherwise be picked
first, and asserts that the resulting invoice journal belongs to
B2B.
@IJOL IJOL force-pushed the 18.0-fix-sale-operating-unit-journal-ou branch from 4a00957 to 1c034e9 Compare April 13, 2026 16:28
IJOL added a commit to BITVAX/operating-unit that referenced this pull request Apr 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

mod:sale_operating_unit Module sale_operating_unit series:18.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants