Skip to main content

Phase 4 — Per-Branch Journals

The structural fix that ends the date/sequence collision class for good. Implemented as the baywaters_branch_journals Odoo module at common/baywaters_branch_journals/.

Design decisions

What gets replicated, what doesn't

JournalReplicated per branch?Why
Customer Invoices (INV)✅ yesEach branch has its own invoice numbering; users want per-branch sales reports
Vendor Bills (BILL)✅ yesSame — per-branch purchasing
Miscellaneous (MISC)✅ yesThis is the journal that originally caused the validation errors
Cash (CSH)✅ yesEach branch counts its own till; needs independent sequence
Bank (BNK1, BNK2)no — stays at parentOne physical AUB account per fuel-station chain; all branches deposit/draw from the same account
Inventory Valuation (STJ)already replicated per company (legacy)Unchanged

11 branches × 4 templates = 44 new journals created on install.

Branch code prefixes

Source of truth: BRANCH_CODE_MAP in hooks.py.

CompanyPrefix
Shawarma Shacks (Petron)SS
Jamaican Patties (Petron)JP
Miguelitos Ice Cream (Petron)MI
Auntie Annes (Petron)AA
Bibingkinitan (Caltex)BB
Jamaican Patties (Caltex)JC
Henlin (Caltex)HN
Potato Corner (Caltex)PC
Sam's Everything on Stick (Caltex)SC
Buko Juan (Petron)BJ
Sams Everything on Sticks (Petron)SE

:::caution Why 2-char prefixes Odoo 17 caps account.journal.code at varchar(5) and silently truncates longer values at write time. With a 3-char suffix (INV/BIL/MSC/CSH), the prefix has to fit in 2 chars. The hook now raises ValueError if computed code exceeds 5 chars to prevent silent corruption. :::

Default debit/credit accounts

The Baywaters CoA is shared across all 12 companies (only one set of 142 accounts, owned by company_id=1). New branch journals reference the same accounts as the parent's journals:

JournalDefault account
<XX>INV430400 Sales/Revenues
<XX>BIL620000 Admin Expense
<XX>MSC(none — Odoo allows blank)
<XX>CSH100101 Cash

Per-branch differentiation in reporting goes through analytic accounts, not separate GL accounts. See Multi-Branch Setup.

Naming pattern after install

Once a branch posts its first entry, Odoo auto-seeds the move-name pattern from the journal code field:

PCINV/2026/05/0001
PCINV/2026/05/0002
SSMSC/2026/05/0001
...

Sequences are independent per branch + per journal — no more cross-branch collisions.

Why a post_init_hook instead of XML data

The new journals depend on:

  • Existing child companies — created by Odoo admins, not this module
  • Existing CoA accounts — looked up by code at runtime

XML data records would require either:

  • Hardcoded company/account database IDs (fragile across environments), or
  • Complex eval expressions doing the same lookups

The Python hook is shorter, more readable, and idempotent (safe to re-run).

Install

cd /Users/jsalinga/odoo/odoo17
python odoo-bin -c odoo.conf -d rts_baywaters \
-i baywaters_branch_journals --stop-after-init

Watch the log for Created lines (44 expected) or skip lines if re-running.

Verification queries

-- Count: should be 44 (11 branches × 4 templates)
SELECT COUNT(*)
FROM account_journal
WHERE code ~ '^[A-Z]{2}(INV|BIL|MSC|CSH)$';

-- Per-branch breakdown
SELECT c.name AS branch, j.code, j.type, a.code AS default_account
FROM account_journal j
JOIN res_company c ON c.id = j.company_id
LEFT JOIN account_account a ON a.id = j.default_account_id
WHERE c.parent_id IS NOT NULL
AND j.code ~ '^[A-Z]{2}(INV|BIL|MSC|CSH)$'
ORDER BY c.name, j.code;

Smoke test after install

For each branch, the accounting team should:

  1. Switch active company to the branch
  2. Accounting → Customer Invoices → New — verify <XX>INV is the default journal
  3. Save as draft and check the entry will be numbered <XX>INV/YYYY/MM/0001 on post
  4. Repeat for one bill, one MISC entry, one cash receipt

Cutover

Installing the module is additive — old journals stay untouched, new ones appear alongside. The user-facing switch (production install + branch user defaults + accounting handoff) is documented separately as Phase 5 — Cutover.

Adding a new branch later

  1. Create the new child company in Odoo
  2. Edit hooks.py, add the new branch to BRANCH_CODE_MAP
  3. Update the module:
    python odoo-bin -c odoo.conf -d rts_baywaters \
    -u baywaters_branch_journals --stop-after-init
    Existing branches' journals are detected and skipped — only the new branch's 4 journals get created.

Rollback

Uninstall preserves data by default. To remove the journals, archive them manually (active = false) — don't delete if any posted entries reference them.

-- Find branch journals to archive (if reverting)
SELECT id, code, company_id, active
FROM account_journal
WHERE code ~ '^[A-Z]{2}(INV|BIL|MSC|CSH)$';