# Fusion Accounting — Enterprise Takeover Roadmap **Status:** Design (approved 2026-04-18) **Owner:** Nexa Systems Inc. **Target:** Odoo 19 Community + fusion_accounting becomes a feature-complete drop-in replacement for Odoo 19 Enterprise accounting (`account_accountant`, `account_reports`, `accountant`, `account_followup`, plus selected satellite modules) for clients deployed by Nexa Systems. --- ## 1. Context and Goals ### 1.1 Current State `fusion_accounting` today is a thin AI co-pilot that depends on three Enterprise modules: ```python 'depends': ['account', 'account_accountant', 'account_reports', 'account_followup', 'mail'] ``` It adds Claude/GPT-driven tool calling, a chat panel, a dashboard, an approval workflow, and rule-based automation on top of Odoo's accounting features. It does not own any core accounting capability — it orchestrates Enterprise's APIs. ### 1.2 Business Driver Nexa Systems deploys Odoo to clients. The Enterprise subscription cost is a friction point. The goal is to deliver Enterprise-equivalent accounting capability on Odoo 19 Community via fusion_accounting, so clients can run on Community without losing core accounting features. fusion_accounting is **not** distributed publicly (no Odoo App Store listing); it ships only as part of a Nexa client engagement. ### 1.3 Scope of "Takeover" The Enterprise modules being targeted, with verified file counts: | Enterprise Module | Files | Role | Targeted Phase | |---|---|---|---| | `account_accountant` | 232 | bank-rec widget, journal dashboard, fiscal year, auto-reconcile, deferred revenue/expense, signing | Phases 1, 3 | | `account_reports` | 618 | financial reports engine + 18 standard reports | Phase 2 | | `accountant` | 26 | menu root + glue | Phase 0 | | `account_followup` | 58 | customer payment reminders | Phase 5 | | `account_asset` | n/a | asset register, depreciation | Phase 6 | | `account_budget` | n/a | budgets vs actuals | Phase 6 | | `account_loans`, `account_3way_match`, `account_check_printing`, `account_batch_payment`, `account_iso20022`, `account_intrastat`, `account_saft`, `account_sepa_direct_debit`, `account_online_synchronization`, `account_edi_*` | n/a | various | Phase 7+ (per client need) | ### 1.4 Existing Reference Material - `/Users/gurpreet/Github/Odoo-Modules/fusion_accounting/` — current AI module (will be reorganized in Phase 0) - `/Users/gurpreet/Github/Odoo-Modules/Work in Progress/fusion_accounting/` — abandoned earlier attempt; contains 461 files of code that a Feb 2026 audit (in that folder's `AUDIT_REPORT.md`) determined to be near-verbatim copies of Odoo Enterprise. **The WIP code is not continued.** Its `__manifest__.py` is harvested as a feature checklist; its file structure as a target-architecture sanity check - `/Users/gurpreet/Github/RePackaged-Odoo/accounting/` — pinned snapshot of Odoo 19 Enterprise accounting source; used as reference-only for clean-room rewrites and as the diff baseline for V19→V20 upgrades ### 1.5 Non-Goals - Not building a public commercial product (no App Store distribution, no commercial licensing pricing model) - Not replicating every Enterprise feature (Phase 7+ items are deferred until a real client needs them) - Not maintaining backward compatibility with Odoo versions before 19 - Not rewriting Community `account` — fusion_accounting builds on top of, never replaces, Community accounting --- ## 2. Sub-Module Topology fusion_accounting is split into independently installable sub-modules. Each has a single, well-bounded responsibility and a clear Enterprise counterpart it replaces. ### 2.1 The Sub-Modules ```mermaid graph TD community["account
Odoo Community base"] core["fusion_accounting_core
shared fields, lock dates, fiscal year base,
company config, security groups, analytic_mixin"] bankrec["fusion_accounting_bank_rec
reconcile widget + auto-reconcile engine"] reports["fusion_accounting_reports
financial reports engine + standard reports"] dashboard["fusion_accounting_dashboard
journal kanban, digest"] followup["fusion_accounting_followup
payment reminders"] assets["fusion_accounting_assets
asset register, depreciation"] budget["fusion_accounting_budget
budgets vs actuals"] ai["fusion_accounting_ai
Claude/GPT copilot + chat + dashboard tiles
(current fusion_accounting code lives here)"] migration["fusion_accounting_migration
transitional Enterprise to fusion data wizard"] meta["fusion_accounting
meta-module: depends on all sub-modules"] core --> community bankrec --> core reports --> core dashboard --> core followup --> reports assets --> core budget --> core ai --> core migration --> core ai -.optional adapter calls.-> bankrec ai -.optional adapter calls.-> reports ai -.optional adapter calls.-> followup ai -.optional adapter calls.-> assets meta --> core meta --> bankrec meta --> reports meta --> dashboard meta --> followup meta --> assets meta --> budget meta --> ai meta -.transitional only.-> migration ``` ### 2.2 Sub-Module Responsibilities | Sub-module | Replaces | Owns | Phase | |---|---|---|---| | `fusion_accounting_core` | `accountant` (menu glue), shared bits of `account_accountant` | Shared field declarations on `account.move`/`account.bank.statement.line` (deferred fields, signing user), `fusion.fiscal.year`, lock-date wizard, security groups, settings page, `analytic_mixin` shared ownership | Phase 0 | | `fusion_accounting_bank_rec` | `account_accountant` bank rec widget + `account_accountant/wizard/account_auto_reconcile_wizard.py` | OWL bank-rec widget, `fusion.reconcile.engine`, auto-reconcile wizard, reconcile model extensions | Phase 1 | | `fusion_accounting_reports` | `account_reports` (entire 618-file engine + reports) | `fusion.account.report`, `fusion.account.report.line`, PDF templates, OWL report viewer, P&L/BS/TB/GL/Aged/Partner/CashFlow/Executive Summary | Phase 2 | | `fusion_accounting_dashboard` | `account_accountant` journal dashboard, `accountant/data/account_accountant_data.xml`, digest | Journal kanban, digest tiles, "Needs Attention" data shape | Phase 3 | | `fusion_accounting_followup` | `account_followup` | `fusion.followup.line`, follow-up workflow, multi-level reminders | Phase 5 | | `fusion_accounting_assets` | `account_asset` | `fusion.asset`, `fusion.asset.group`, depreciation engine, asset-register report | Phase 6 | | `fusion_accounting_budget` | `account_budget` | `fusion.budget`, budget-vs-actual report | Phase 6 | | `fusion_accounting_ai` | (none — original) | Existing AI orchestrator, tools, chat panel, approval workflow, scoring, rules — moved verbatim from current `fusion_accounting` | Phase 0 | | `fusion_accounting_migration` | (none — transitional) | Wizard that copies Enterprise-only data into fusion tables before Enterprise uninstall; safety guard that blocks Enterprise uninstall until wizard runs | Phase 0 | | `fusion_accounting` (meta) | (none — packaging) | Empty shell; `depends` on every sub-module so a single install gets everything | Phase 0 | ### 2.3 Why Split (vs. monolith) - Sub-modules can be enabled per client need (a small client without payroll-style assets installs core + bank_rec + reports + ai only) - Each sub-module has independent test runs and CI (faster feedback loop) - Each sub-module's cross-version upgrade is independent — `fusion_accounting_reports` can absorb V20 changes without touching `fusion_accounting_bank_rec` - The AI sub-module stays cleanly separate, which makes it easy to keep using fusion's AI on top of Odoo Enterprise (when a client retains Enterprise) by installing `_ai` only ### 2.4 Open Sub-Module Naming Decisions The meta-module retains the name `fusion_accounting` so existing client installs don't see a name change. Sub-modules use the `fusion_accounting_*` prefix consistently. --- ## 3. Data Preservation and Client Switchover Strategy The single most important guarantee in this entire design: **client switchover from Odoo Enterprise to Odoo Community + fusion_accounting must lose zero accounting data**, especially bank reconciliations. This section is the contract that backs that guarantee. ### 3.1 What Survives an Enterprise Uninstall Automatically Verified by direct read of `RePackaged-Odoo/accounting/account/` source. These models and fields live in the Community `account` module and are unaffected by any Enterprise uninstall: | Data | Storage | Verified Location | |---|---|---| | Bank reconciliation links | `account.partial.reconcile` | `account/models/account_partial_reconcile.py` | | Full reconciliation markers | `account.full.reconcile` | `account/models/account_partial_reconcile.py` | | Bank statement lines + `is_reconciled` flag | `account.bank.statement.line` | `account/models/account_bank_statement_line.py` | | Invoices, bills, payments | `account.move`, `account.payment` | `account/models/account_move.py`, `account_payment.py` | | Journal entries + lines | `account.move`, `account.move.line` | `account/models/account_move_line.py` | | Chart of accounts | `account.account` | `account/models/account_account.py` | | Taxes | `account.tax` | `account/models/account_tax.py` | | Journals | `account.journal` | `account/models/account_journal.py` | | Partners | `res.partner` | `base` | | Reconciliation rule base | `account.reconcile.model` | `account/models/account_reconcile_model.py` | | `checked` (Reviewed) flag on moves | `account.move.checked` | `account/models/account_move.py` line 315 | **Critical observation about bank reconciliation in Odoo 19:** The Enterprise `account_accountant` module does **not** define a `bank.rec.widget` Python model in V19. The bank-rec widget is implemented entirely as frontend OWL components in `account_accountant/static/src/components/bank_reconciliation/`, with a thin `BankReconciliationService` (`bank_reconciliation_service.js`) that calls Community ORM methods directly. There is no Enterprise-side persistent storage for the widget. When the widget is removed (Enterprise uninstall), the underlying `account.partial.reconcile` rows are untouched; fusion's replacement widget reads the same rows and shows every historical reconciliation as already-matched. (The Work-in-Progress code at `Work in Progress/fusion_accounting/models/bank_rec_widget.py` uses the V17/V18 architecture where `bank.rec.widget` was a `_auto = False` Python model. That architecture was removed in V19. Our Phase 1 implementation must match V19 architecture.) **Verified Enterprise uninstall hook safety**: `account_accountant/__init__.py` line 32-42 only revokes security group assignments. There are zero destructive DB operations in the uninstall hook. **Verified absence of cascade hazards**: grep for `ondelete='cascade'` in `account_accountant/models/` returns zero matches. No Enterprise model deletion can cascade-delete a reconciliation. ### 3.2 What Is Lost on Enterprise Uninstall (Without Mitigation) | Enterprise-owned data | Importance | Mitigation Strategy | |---|---|---| | `account.fiscal.year` records (fiscal year closing definitions) | Medium | Migration wizard → `fusion.fiscal.year` | | `account.asset` records + asset-line links on moves | High if assets used | Migration wizard → `fusion.asset` | | `account.loan` records | Low (rare) | Migration wizard → `fusion.loan` (Phase 7+) | | Budget records | Medium if used | Migration wizard → `fusion.budget` | | Follow-up rule definitions + history | Medium | Migration wizard → `fusion.followup.*` | | `account.move.deferred_move_ids`, `deferred_original_move_ids`, `deferred_entry_type` | **High** if deferred revenue/expense used — breaks the link between original and deferred postings | **Shared-field ownership** in `fusion_accounting_core` | | `account.move.signing_user` (audit signer) | Medium | **Shared-field ownership** | | `account.move.payment_state_before_switch` | Throwaway (technical) | Ignore | | `account.reconcile.model.created_automatically` | Throwaway (single boolean) | Shared-field ownership in `_bank_rec` | | `account.bank.statement.line.cron_last_check` | Throwaway (technical) | Ignore | | Report XML records (P&L, BS structure) | None — reference data, not client data | fusion ships its own equivalents in `_reports` | | Enterprise-only menus, actions | None — UI only | fusion installs its own | ### 3.3 Mitigation Pattern A: Shared-Field Ownership For Enterprise-added fields on Community models (the `deferred_*`, `signing_user`, `created_automatically` fields), `fusion_accounting_core` declares **identical** field definitions with the **same** relation table names: ```python class AccountMove(models.Model): _inherit = "account.move" deferred_move_ids = fields.Many2many( comodel_name='account.move', relation='account_move_deferred_rel', # identical relation table to Enterprise column1='original_move_id', column2='deferred_move_id', copy=False, ) deferred_original_move_ids = fields.Many2many( comodel_name='account.move', relation='account_move_deferred_rel', column1='deferred_move_id', column2='original_move_id', copy=False, ) deferred_entry_type = fields.Selection( selection=[('expense', 'Deferred Expense'), ('revenue', 'Deferred Revenue')], copy=False, ) signing_user = fields.Many2one(comodel_name='res.users', copy=False) payment_state_before_switch = fields.Char(copy=False) ``` **Mechanism**: Odoo's module registry tracks every module that declares a given field on a given model. When `account_accountant` uninstalls, Odoo only drops the column (or relation table) if no other installed module also declares it. Because `fusion_accounting_core` declares these identically, Odoo retains the column/table. Existing data values are preserved row-by-row. **Caveat**: this pattern creates a schema dependency on Enterprise's choices. If Odoo ever renames `account_move_deferred_rel` in V20, both the Enterprise and fusion versions of that field break together — the migration is just `ALTER TABLE ... RENAME` in our migration script. We accept this risk because the alternative (renaming to fusion-namespaced fields) requires a much heavier migration of every existing row. ### 3.4 Mitigation Pattern B: Pre-Uninstall Migration Wizard For Enterprise-only models (`account.asset`, `account.fiscal.year`, `account.loan`, budgets, followups), `fusion_accounting_migration` provides a wizard accessible from Settings → Fusion Accounting → Migrate from Enterprise. The wizard: 1. Detects which Enterprise modules are installed 2. For each detected module, checks the corresponding fusion module is also installed (and prompts to install if missing) 3. Shows a preview: row counts per Enterprise table that will be migrated, listing target fusion table for each 4. On confirm, runs `INSERT INTO fusion_ SELECT ... FROM ` for each migration step, preserving primary keys and `ir.model.data` xml_ids 5. Generates a migration report (record counts, any rows that failed validation, warnings) 6. Marks each Enterprise table as "migrated" via an `ir.config_parameter` flag (`fusion_accounting.migration..completed`) 7. Re-running the wizard is idempotent: already-migrated tables are skipped unless explicitly re-migrated A separate **safety guard** in `fusion_accounting_migration` overrides `ir.module.module.button_immediate_uninstall` for Enterprise accounting modules; if the migration flag for that module is False and it has data, the uninstall is blocked with a UserError linking to the wizard. ### 3.5 Switchover Protocol (the operator workflow) ```mermaid graph TD start[Client on Odoo 19 Enterprise] --> step1["Install fusion_accounting meta-module
while Enterprise still running"] step1 --> step2["fusion_accounting_core declares shared fields
Odoo registers dual ownership for deferred_*, signing_user, etc."] step2 --> step3["Open Settings → Fusion Accounting → Migrate from Enterprise"] step3 --> step4["Wizard shows preview: row counts per table"] step4 --> step5["Operator confirms"] step5 --> step6["Wizard copies asset, fiscal year, loan, budget, followup rows
into fusion tables"] step6 --> step7["Wizard generates migration report"] step7 --> step8["Operator reviews report"] step8 --> step9["Operator triggers Enterprise uninstall in dep-safe order:
account_reports → account_followup → account_asset →
account_budget → account_loans → account_accountant → accountant"] step9 --> step10["Safety guard verifies migration flags before each uninstall"] step10 --> done["Done: Client on Community + fusion_accounting
Bank recs intact, deferred links preserved,
migrated data accessible via fusion menus"] ``` ### 3.6 Empirical Verification Test (Phase 0 deliverable) The shared-field-ownership analysis and the inventory of "what survives" is based on reading source. Strong, but not conclusive. **Phase 0 includes a one-time empirical test**: 1. Provision a throwaway Odoo 19 Enterprise instance 2. Install full Enterprise accounting stack 3. Create representative test data: - 50 invoices, 30 vendor bills, mix of paid/unpaid - 15 bank reconciliations (full and partial) - 5 deferred revenue entries with `deferred_move_ids` populated - 3 fiscal year closings - 10 asset records with depreciation history - 2 budgets with actuals - Multi-currency journal entries - 1 cash-basis tax move 3. Take `pg_dump` snapshot 4. Uninstall Enterprise modules in dep-safe order **without** running the migration wizard (this is the worst-case test) 5. Diff schema and row counts before and after 6. Document findings in `docs/superpowers/specs/2026-04-18-empirical-uninstall-test-results.md` 7. If gaps are found vs. Section 3.2, expand the wizard scope or shared-field declarations accordingly This test is a Phase 0 acceptance gate. The roadmap does not advance to Phase 1 until empirical verification confirms or expands the analysis. ### 3.7 Reverse-Migration Note The reverse direction (client on Community + fusion adds an Enterprise subscription later) is not a hard requirement. fusion's runtime feature-gating (Section 4.4) handles the coexistence case: when Enterprise is detected, fusion's conflicting menus hide and the AI module continues running on top of Enterprise. A reverse-migration wizard can be added in Phase 7+ if a real client needs it. ### 3.8 Backup and Rollback Every client deployment must include, before any switchover step: - `pg_dump` of the live database - Snapshot of all installed module versions (`SELECT name, latest_version FROM ir_module_module WHERE state='installed'`) - Snapshot of `/mnt/extra-addons/` contents Rollback procedure: restore DB from `pg_dump`, restore extra-addons from snapshot, restart Odoo. The migration wizard's "Generate Backup First" checkbox is checked by default and must be explicitly unchecked to skip. --- ## 4. Phased Roadmap Each phase produces shippable value. Phase order is locked. Time estimates are rough single-engineer figures and are not binding deadlines — the user has explicitly stated "no rush, product-first". ### 4.1 Phase Overview | Phase | Focus | Estimate | Depends On | |---|---|---|---| | 0 | Foundation, sub-module split, migration scaffold, empirical test | 1-2 wks | (none) | | 1 | Bank reconciliation (priority) | 3-5 wks | 0 | | 2 | Financial reports engine | 6-10 wks | 0 | | 3 | Dashboard + fiscal year + lock dates | 2-3 wks | 1, 2 | | 4 | Tax reports + returns | 3-5 wks | 2 | | 5 | Payment follow-ups | 2-3 wks | 3, 4 | | 6 | Assets + budgets | 3-5 wks | 5 | | 7+ | Optional satellites (loans, check printing, batch payment, 3-way match, EDI, SEPA, SAFT, intrastat, online sync) | per item | 6 | Phases 1 and 2 can run in parallel after Phase 0 (no shared scope). ### 4.2 Phase 0 — Foundation No user-facing features. Pure plumbing so every later phase is cheaper. **Scope:** - Create sub-module scaffolding for `fusion_accounting_core`, `fusion_accounting_migration`, `fusion_accounting_ai` - Move existing AI copilot code from current `fusion_accounting/` into `fusion_accounting_ai/`. Files moved: `models/`, `services/`, `controllers/`, `wizards/`, `data/`, `static/src/`, `views/`, `security/`, `report/`, `tests/`. Update internal imports - Convert current `fusion_accounting/` into the meta-module: empty `__init__.py`, manifest with `depends = ['fusion_accounting_core', 'fusion_accounting_ai', ...]` (sub-modules added as later phases ship), no Python/JS/XML code of its own - Strip hard Enterprise deps from `fusion_accounting_ai/__manifest__.py`. Replace `account_accountant`, `account_reports`, `account_followup` with `account` (Community). Add runtime detection (Section 4.4) - Refactor every AI tool in `fusion_accounting_ai/services/tools/` that calls Enterprise APIs to go through an adapter layer (`services/adapters/bank_rec_adapter.py`, `reports_adapter.py`, `followup_adapter.py`). Adapters pick between Enterprise APIs (when present) and fusion native (when present) and a "feature-unavailable" stub (when neither) - Create `fusion_accounting_core/models/account_move.py` with shared-field declarations (Section 3.3) - Create `fusion_accounting_migration/` shell: empty wizard, safety guard scaffold (no migrations yet) - Create `tools/check_odoo_diff.sh` script that diffs two pinned Odoo source snapshots and outputs a categorized change list - Move security groups: `group_fusion_accounting_user/manager/admin` move from current to `fusion_accounting_core/security/`. Multi-company record rule on `fusion.accounting.session` added (currently missing per existing CLAUDE.md "Known Issues") - Create per-sub-module `CLAUDE.md` (factor common rules from existing `fusion_accounting/CLAUDE.md`) and `UPGRADE_NOTES.md` template - Run the empirical verification test (Section 3.6) on a throwaway V19 Enterprise instance - CI: GitHub Actions or gitea workflow that runs `pytest` per sub-module on every push **Exit criteria:** - Current AI copilot installs and runs on pure Community (no Enterprise modules present) - Current AI copilot still installs and runs alongside Enterprise (coexistence mode) - Empirical test report committed - All adapter calls wired (no direct Enterprise API access from AI tools) - CI green **Risks and mitigations:** - **Risk**: moving code between modules breaks existing client deployments. **Mitigation**: meta-module install upgrade hook handles model-record reassignment via `ir_model_data` updates; pre-migration script runs on first install of Phase 0 - **Risk**: empirical test reveals gaps. **Mitigation**: scope-expand the migration wizard before declaring Phase 0 complete ### 4.3 Phase 1 — Bank Reconciliation The user's stated priority. Replaces `account_accountant`'s bank-rec widget end-to-end. **Scope:** - Create `fusion_accounting_bank_rec/` sub-module - **Frontend (mirror zone)**: build `static/src/components/bank_reconciliation/` mirroring the file layout of `account_accountant/static/src/components/bank_reconciliation/` (`kanban_controller`, `kanban_renderer`, `bank_reconciliation_service`, `apply_amount`, `bankrec_form_dialog`, `button`, `button_list`, `chatter`, `file_uploader`, `line_info_pop_over`, `line_to_reconcile`, `list_view`, `quick_create`, `reconciled_line_name`, `search_dialog`, `statement_line`, `statement_summary`). Mirror is structural — class names, file names, OWL component boundaries — not copy-paste. Implementation written fresh against documented Odoo behavior - **Backend (abstract zone)**: `models/fusion_reconcile_engine.py` containing the matching algorithm (FIFO, partial reconcile, write-off lines, exchange-rate diff posting, tax splits). Original implementation against documented requirements. Operates on Community `account.partial.reconcile` - `models/fusion_reconcile_model.py` extending Community `account.reconcile.model` with auto-rules, partner mapping, journal mapping. Shared-field ownership for `created_automatically` - `wizards/auto_reconcile_wizard.py` clean-room rewrite of `account_accountant/wizard/account_auto_reconcile_wizard.py` - `wizards/reconcile_wizard.py` clean-room rewrite of `account_accountant/wizard/account_reconcile_wizard.py` - `views/bank_rec_widget_views.xml` defines the action that opens the OWL widget; `views/account_reconcile_model_views.xml` for rule editing - Menu: "Bank Reconciliation" under fusion accounting menu, with feature-gate (hidden if `account_accountant` installed) - AI integration: existing AI tools `get_unreconciled_bank_lines`, `find_similar_bank_lines`, `get_bank_line_details`, `find_missing_itc_bills`, `find_duplicate_bills`, `get_overdue_invoices` get refactored to call fusion's bank rec engine via `fusion_accounting_ai/services/adapters/bank_rec_adapter.py`. The Tier 3 tools `create_vendor_bill`, `register_bill_payment`, `create_expense_entry` keep their existing logic (they write to Community `account.move`) - Migration: wizard validates `account.partial.reconcile` row count is preserved across switchover (read-only check, no migration needed) - Tests: - Unit (engine): matching correctness with fixtures (single partner, multi-partner, multi-currency, partial, exchange diff, write-off, tax split) - Integration: install + create statement + reconcile via UI + assert `account.partial.reconcile` rows - Tour (JS): smoke through the full bank rec workflow - Migration: install Enterprise, create 10 reconciliations, install fusion, uninstall Enterprise, assert reconciliations visible in fusion widget **Exit criteria:** - Community + fusion_accounting user can reconcile bank statements with feature parity to Enterprise - All Phase 1 tests passing - Migration round-trip (Enterprise → fusion) preserves every reconciliation - AI tools work against fusion bank rec engine ### 4.4 Phase 2 — Financial Reports Engine The largest phase. Replaces `account_reports` (618 files). **Scope:** - Create `fusion_accounting_reports/` sub-module - **Backend (abstract zone)**: `models/fusion_account_report.py` defining `fusion.account.report` and `fusion.account.report.line`. Generic engine that takes a report definition (sections, filters, computation rules) and produces report rows from `account.move.line` data. Original computation kernel — does not copy `account_reports`'s `account_report.py` - **Backend (mirror zone)**: report definition records mirror Odoo's data files. Files: `data/balance_sheet.xml`, `data/profit_and_loss.xml`, `data/cash_flow_report.xml`, `data/general_ledger.xml`, `data/trial_balance.xml`, `data/aged_partner_balance.xml`, `data/partner_ledger.xml`, `data/executive_summary.xml`, `data/sales_report.xml`, `data/multicurrency_revaluation_report.xml`, `data/bank_reconciliation_report.xml`, `data/deferred_reports.xml`, `data/journal_report.xml`, `data/customer_statement.xml`. XML structure follows Odoo's so V20 ports are diff-and-apply - **Frontend (mirror zone)**: `static/src/components/` mirrors `account_reports/static/src/components/` — filters bar, comparison toggle, drill-down, foldable sections, footnotes - **PDF export**: QWeb templates in `report/` mirror Odoo's `data/pdf_export_templates.xml` and `data/customer_reports_pdf_export_templates.xml`. Asset bundle `fusion_accounting_reports.assets_pdf_export` defined in manifest - Performance: denormalized read paths for trial balance and general ledger (materialized aggregations refreshed on `account.move` post). Drill-down lazy-loads line detail. Per-(company, period, filter_hash) cache invalidated on `account.move.line` write - Multi-company, multi-currency, cash-basis toggle — all handled by the engine - AI integration: tools `get_profit_loss`, `get_balance_sheet`, `get_trial_balance`, `get_aged_receivables`, `get_aged_payables`, `get_partner_ledger`, `answer_financial_question` refactored via `reports_adapter.py` - Migration: report XML records are reference data, not client data. fusion ships its own equivalent records; no migration of report definitions needed. Existing journal entry data (which the reports compute from) is in Community `account` and untouched - Tests: - Unit (engine): SQL-fixture comparisons (compute report → compare against hand-rolled SQL) for every standard report, every filter combination - Integration: install + post entries + open report + assert numbers - Multi-currency: single + multi + revaluation period - Performance: 1k / 10k / 100k journal lines, assert P95 latency under 5s - PDF: render every report to PDF, assert no QWeb errors - Tour: smoke through report viewer with filters **Exit criteria:** - All 14 standard reports rendering correctly (numerical match against SQL fixtures) - PDF export working for every report - Performance targets met - AI tools backed by fusion reports ### 4.5 Phase 3 — Dashboard + Fiscal Year + Lock Dates **Scope:** - Create `fusion_accounting_dashboard/` sub-module - **Journal kanban dashboard**: mirror layout of `account_accountant/views/account_journal_dashboard_views.xml`. Computed metrics in `models/account_journal.py` extending Community `account.journal` with kanban-state fields (counts, totals, action buttons). Original computation; mirror UI - `models/fusion_fiscal_year.py` defining `fusion.fiscal.year` (replaces `account.fiscal.year`) - Fiscal year wizard: closing workflow, period locks, initial-balance carry-forward - Lock date wizard: clean-room rewrite of `account_accountant/wizard/account_change_lock_date.py`. Operates on Community `account.lock_exception` model (verified at `account/models/account_lock_exception.py`) - Digest tile contributions: extend `mail.digest` with fusion accounting metrics (revenue, expense, AR, AP) - "Needs Attention" panel — connect data already returned by current AI dashboard endpoint to a frontend rendering. Dashboard endpoint (currently in `fusion_accounting_ai/controllers/`) moves to `fusion_accounting_dashboard/controllers/`; AI module's dashboard tiles call dashboard's endpoint via adapter - Tests: - Journal dashboard kanban metrics match expected values for fixtures - Fiscal year close locks subsequent edits - Lock date wizard prevents posting before lock date - Digest renders without errors **Exit criteria:** - Journal dashboard at parity with Enterprise - Fiscal year management functional - Lock dates enforced - Digest emails delivering ### 4.6 Phase 4 — Tax Reports + Returns **Scope:** - Build on Phase 2 reports engine; tax reports are specialized `fusion.account.report` records - Generic tax report (`data/generic_tax_report.xml`) with country-specific overrides - Canadian HST: unify the existing HST workflow in `fusion_accounting_ai` (currently in `services/prompts/domain_prompts.py` and tool functions) with the new tax report engine. The existing `find_missing_itc_bills`, `get_overdue_invoices`, etc. tools call into the tax report - `fusion.account.return` model (replaces `account.return` from `account_reports`) tracking tax return drafts, submitted state, payment status - Return creation wizard, return submission wizard, return generic payment wizard — clean-room rewrites of the corresponding `account_reports` wizards - Tax closing entries (move generation on tax period close) - Tests: - Tax report numbers match SQL fixtures - Return workflow: draft → review → submitted → paid - HST 4-phase workflow (per existing CLAUDE.md) end-to-end **Exit criteria:** - Generic tax report functional - Canadian HST workflow runs through fusion (no Enterprise dependency) - Return tracking working ### 4.7 Phase 5 — Payment Follow-ups **Scope:** - Create `fusion_accounting_followup/` sub-module - `models/fusion_followup_line.py` (replaces `account_followup.followup.line`) - `models/res_partner.py` extends `res.partner` with follow-up level, last reminder date, dunning history - `models/account_move.py` extends `account.move` with follow-up state (overdue days, last reminder) - Multi-level reminder workflow: each level has email template, days delay, optional SMS, optional `mail.activity` - `wizards/followup_send_wizard.py` for manual sends; cron for automatic - Follow-up report (PDF): clean-room template - AI integration: `fusion_accounting_ai` adds tools `draft_followup_message_for_partner`, `send_followup_to_overdue_partners` calling the followup engine via adapter - Migration: wizard copies `account_followup.followup.line` and partner-level follow-up state into `fusion.followup.line` and shared-field-owned partner fields - Tests: - Multi-level escalation - Email template rendering - SMS delivery (mock) - AI-drafted message quality (snapshot tests) **Exit criteria:** - Multi-level dunning working - Migration from `account_followup` preserves history ### 4.8 Phase 6 — Assets + Budgets **Scope:** - Create `fusion_accounting_assets/` sub-module - `models/fusion_asset.py` (replaces `account.asset`) - `models/fusion_asset_group.py` (replaces `account.asset.group`) - Depreciation engine: linear, declining, custom schedules. Original implementation - `wizards/asset_modify.py` for revaluation, sale, disposal — clean-room rewrite - Asset register report integrates with Phase 2 reports engine - Migration wizard copies `account.asset` rows + line links on moves - Create `fusion_accounting_budget/` sub-module - `models/fusion_budget.py` (replaces `budget.analytic`) - Budget vs actual report integrates with Phase 2 reports engine - Migration wizard copies budget records - Tests for both **Exit criteria:** - Asset depreciation schedules computed correctly - Disposal generates correct GL entries - Budget variance report functional ### 4.9 Phase 7+ — Optional Satellites Not scheduled. Each is its own brainstorming → spec → plan → implementation cycle when a real client needs it. Candidate satellite modules: - `fusion_accounting_loans` — loan amortization - `fusion_accounting_check_printing` — check printing - `fusion_accounting_batch_payment` — batch payments - `fusion_accounting_3way_match` — purchase 3-way match - `fusion_accounting_edi` — UBL/CII e-invoicing - `fusion_accounting_sepa` — SEPA direct debit + credit transfer - `fusion_accounting_saft` — SAFT export - `fusion_accounting_intrastat` — intrastat report - `fusion_accounting_iso20022` — ISO 20022 payment files - `fusion_accounting_online_sync` — online bank sync (Yodlee/Plaid integration) ### 4.10 Per-Phase Deliverables (uniform) Each phase produces: 1. A separate **design document** in `docs/superpowers/specs/YYYY-MM-DD-fusion-accounting-phase-N-*-design.md` (brainstormed in its own session) 2. A separate **implementation plan** via the `writing-plans` skill 3. Working code with passing tests 4. Entry in the sub-module's `UPGRADE_NOTES.md` listing Odoo source files referenced and intentional deltas 5. Coverage in `fusion_accounting_migration` if the phase replaces an Enterprise data-bearing model 6. Manual QA checklist (install, migrate, smoke, uninstall) committed to the sub-module 7. Update to the meta-module `__manifest__.py` adding the new sub-module to its `depends` --- ## 5. Architecture Rules These rules apply to every sub-module and every phase. They are the discipline that keeps V19→V20 upgrades mechanical and prevents the WIP-style descent into copied code with stale architecture. ### 5.1 The Hybrid Split Every sub-module has two zones with different rules: **Mirror zone** (follows Odoo structure 1:1): - XML view definitions and xpath targets - Frontend OWL component file layout, service registration, widget props - PDF/QWeb templates: structure, CSS class names - Wizard flows: step order, field names where they appear in views - Asset bundle declarations in manifests **Locations**: `views/`, `static/src/components/`, `report/` QWeb templates, `wizards/*_views.xml`, `__manifest__.py` asset bundles **Abstract zone** (our own design, insulated from Odoo internals): - Core algorithms: matching, aggregation, computation, depreciation - Data access helpers - Business validation, approval flows - AI integration adapters - Engine classes (e.g. `fusion_reconcile_engine.py`) **Locations**: `models/fusion_*_engine.py`, `services/`, `controllers/` (business logic only — request routing is mirror-zone) **Rule of thumb**: if Odoo refactors it every release, mirror it. If it's been stable for a decade (FIFO matching, accrual rules, depreciation math), abstract it. ### 5.2 Naming Conventions | Thing | Convention | Example | |---|---|---| | Model `_name` | `fusion.*` prefix always | `fusion.bank.rec.widget`, `fusion.account.report`, `fusion.fiscal.year` | | Model `_inherit` on Community | Keep `account.*` (no rename) | `class AccountMove(models.Model): _inherit = 'account.move'` | | Model `_inherit` on Enterprise | **Forbidden** — duplicate fields via shared-field-ownership instead | n/a | | Python class names | `Fusion` prefix for new models | `FusionBankRecWidget`, `FusionAccountReport` | | Table names (auto-derived) | Follows model prefix | `fusion_bank_rec_widget`, `fusion_account_report` | | XML record IDs | `fusion_*` prefix | `` | | Menu IDs | `fusion_menu_*` prefix | Avoids collision with `account_menu_*` | | Action IDs | `fusion_action_*` | Same | | Controller routes | `/fusion_accounting/*` | Already in use; carries forward | | Security groups | `group_fusion_*` | Already in use | | Field names on inherited Community models | Identical to Enterprise if shared-field-owned; otherwise `x_fusion_*` prefix | `deferred_move_ids` (shared), `x_fusion_ai_confidence` (our own) | | CSS/SCSS classes | `.fusion_*` or `.o_fusion_*` | Avoids Bootstrap/Odoo collision | | `ir.config_parameter` keys | `fusion_accounting.*` | Already in use | ### 5.3 Coexistence Detection Every sub-module that replaces an Enterprise feature must detect Enterprise at install time and at runtime, and feature-gate accordingly. **Helper function** (lives in `fusion_accounting_core/models/ir_module_module.py`): ```python class IrModuleModule(models.Model): _inherit = "ir.module.module" @api.model def _fusion_is_enterprise_accounting_installed(self): return bool(self.sudo().search_count([ ('name', 'in', ['account_accountant', 'account_reports', 'accountant']), ('state', '=', 'installed'), ])) ``` **Three coexistence modes per sub-module**, configurable in Settings → Fusion Accounting → Integration Mode: 1. **Replace** (default when Enterprise absent): fusion menus visible, fusion views primary, fusion workflows active 2. **Augment** (default when Enterprise present): fusion menus hidden, fusion widgets disabled, fusion AI module continues to call Enterprise APIs via adapters 3. **Force-replace** (manual): fusion menus visible alongside Enterprise (operator's choice — risk of confusion, used during migration) Menu visibility achieved via `groups` attribute referencing a dynamically-computed group (`group_fusion_show_menus_when_enterprise_absent`), implemented as a `@api.depends` computed field on `res.users` that recomputes membership when modules change state. ### 5.4 Zero Hard Enterprise Dependencies After Phase 0: - `fusion_accounting_core/__manifest__.py`: `depends = ['account', 'mail', 'web_tour']` - `fusion_accounting_ai/__manifest__.py`: `depends = ['fusion_accounting_core']` plus `external_dependencies` for `anthropic`, `openai` - Every other `fusion_accounting_*/__manifest__.py`: `depends = ['fusion_accounting_core']` plus fusion siblings as needed (e.g., `_followup` depends on `_reports`) **No `fusion_accounting_*` module may have `account_accountant`, `account_reports`, `accountant`, `account_followup`, `account_asset`, `account_budget`, `account_loans`, `account_3way_match`, `account_check_printing`, `account_batch_payment`, `account_iso20022`, `account_intrastat`, `account_saft`, `account_sepa_direct_debit`, `account_online_synchronization`, or any `account_edi_*` in its `depends`.** Runtime detection (Section 5.3) replaces compile-time dependency. ### 5.5 Canonical Sub-Module Directory Layout ``` fusion_accounting_/ ├── __manifest__.py ├── __init__.py ├── CLAUDE.md # module-specific context for Cursor agent ├── UPGRADE_NOTES.md # Odoo version deltas absorbed ├── README.md # operator-facing install/configure/troubleshoot ├── docs/ │ └── odoo_diff/ # snapshots of relevant Odoo source for diffing │ └── v19/ │ └── account_accountant__bank_reconciliation_service.js ├── controllers/ │ └── __init__.py ├── data/ ├── demo/ ├── i18n/ ├── models/ │ ├── __init__.py │ ├── fusion__engine.py # abstract zone: core algorithm │ ├── account_.py # mirror zone: inherits Community model │ └── fusion_.py # mirror zone: our own models ├── report/ ├── security/ │ ├── ir.model.access.csv │ └── _security.xml ├── services/ # AI / heavy business logic ├── static/ │ ├── description/ │ │ ├── icon.png │ │ └── index.html │ └── src/ │ ├── components/ # mirror zone: OWL components │ ├── scss/ │ ├── services/ # frontend services │ └── views/ ├── tests/ │ ├── __init__.py │ ├── test__engine.py # abstract zone unit tests │ ├── test__integration.py # full-stack integration tests │ ├── test_migration.py # Enterprise → fusion round-trip │ └── tours/ ├── views/ ├── wizards/ └── migrations/ # Odoo version migration scripts (XX.0.x.y.z) └── 19.0.1.0.0/ ├── pre-migration.py └── post-migration.py ``` ### 5.6 Odoo 19 Gotchas (carried forward, factored across CLAUDE.md files) The current `fusion_accounting/CLAUDE.md` documents Odoo 19-specific traps that have already cost time. All carry forward: - Search views: no `string` attribute on `` or ``; group-by filters need `domain="[]"`; `` before `` - OWL client actions: `static props = ["*"]` (accept any), not `static props = []` (accept none) - OWL rich HTML: `markup()` and `t-out` unreliable in Odoo 19; use `onMounted` + `onPatched` + direct `innerHTML` - Cron `safe_eval`: no `import` statements; use `datetime.datetime.now()` not `from datetime import datetime` - `read_group()` deprecated → use `_read_group()` - `ir_config_parameter` Selection field migrations: stored DB value must match new options or Settings page crashes - `implied_ids` on groups only applies to newly-added users — existing users need SQL backfill - `TransientModel` in controllers: use `.new({...})` not `.create({...})` - HTTP routes: `type="jsonrpc"`, not `type="json"` (deprecated) - `res.config.settings`: only boolean/integer/float/char/selection/many2one/datetime; no Date fields - `res.groups`: no `users` field, no `category_id` field - Search views: no `group expand="0"` syntax - SCSS imports: `@import "./partial"` is forbidden in Odoo 19 custom SCSS; register every SCSS file as a separate entry in `web.assets_backend` - Card styling: don't rely on `var(--bs-border-color)` or `var(--bs-body-bg)`; use Odoo's kanban explicit-hex pattern with custom-property tokens - Dark mode: branch on `$o-webclient-color-scheme` at SCSS compile time, not runtime DOM class - Asset bundle cache busting: bump manifest version + `DELETE FROM ir_attachment WHERE url LIKE '/web/assets/%'` if needed These rules belong in each sub-module's `CLAUDE.md` (the relevant subset) plus the workspace-root `CLAUDE.md` (common rules). ### 5.7 Manifest Versioning and Branch Strategy - Per-sub-module manifest: `'version': 'XX.0.x.y.z'` where XX is the Odoo version (e.g., `19.0.1.0.0` for V19, first release) - Bump `XX` on Odoo version change (V19 → V20 → V21) - Bump `x` on major feature additions within an Odoo version - Bump `y` on minor features and bug fixes - Bump `z` on hotfixes - Git branches: `main-v19`, `main-v20`, etc. Each client deployment is pinned to one branch - Release tags: `/v19.0.1.0.0` per sub-module per release --- ## 6. Cross-Version Upgrade Workflow This section is the user's stated top concern: how to keep porting Enterprise changes forward each year without it becoming a rewrite project. ### 6.1 Snapshot Discipline Maintain one pinned snapshot of the relevant Odoo source per Odoo version: ``` /Users/gurpreet/Github/RePackaged-Odoo/ ├── accounting-v19/ # current snapshot (already in place at accounting/) ├── accounting-v20/ # added when V20 ships ├── accounting-v21/ # added when V21 ships ``` Older snapshots are never deleted — they are the diff source for upgrade work. ### 6.2 Annual Upgrade Ritual When Odoo V ships: 1. Add the snapshot folder 2. For each fusion sub-module: - Run `tools/check_odoo_diff.sh v v > reports/v__diff.md` - Manually classify each change in the diff: - `[MIRROR]` — apply the same hunk to fusion's mirror-zone files (mechanical) - `[ABSTRACT]` — verify the Odoo public API surface our adapter uses still works; update the adapter if signatures changed - `[NEW FEATURE]` — decide port or defer - `[BUG FIX]` — port (usually cheap) - `[REMOVED]` — clean up our equivalent - Apply mirror-zone hunks (these are usually direct `patch -p1` operations) - Write Odoo version migration scripts in `migrations/.0.0.0.0/` for any data-shape changes - Update `UPGRADE_NOTES.md` - Run all tests 3. Tag releases on `main-v` branch 4. Pilot upgrade on one client first; ratchet outward ### 6.3 `UPGRADE_NOTES.md` Template ```markdown # UPGRADE_NOTES — fusion_accounting_bank_rec ## V19.0.1.0.0 (initial) - Ported from: account_accountant V19 (snapshot date 2026-04-18) - Mirror sources: - account_accountant/static/src/components/bank_reconciliation/* → fusion_accounting_bank_rec/static/src/components/bank_reconciliation/* - account_accountant/wizard/account_auto_reconcile_wizard.py → fusion_accounting_bank_rec/wizards/auto_reconcile_wizard.py (clean-room) - Abstract zone: - models/fusion_reconcile_engine.py — original implementation - Intentional deltas from Odoo: - AI hook in reconcile step (calls fusion_accounting_ai.suggest_match adapter) - Different default colour palette (SCSS var overrides) ## V20.0.x.y.z (planned, not yet shipped) - Odoo changes account_accountant V19 → V20 absorbed: - [MIRROR] kanban_renderer.js: column layout changed, applied identical hunk - [ABSTRACT] account.reconcile.model._apply_lines_for_bank_widget signature changed — updated adapter - [NEW FEATURE] batch-reconcile-across-journals — deferred to V20.1 - Migration scripts: - migrations/20.0.0.0.0/pre-migration.py: rename column foo → bar ``` ### 6.4 `tools/check_odoo_diff.sh` Specification The script lives at `fusion_accounting/tools/check_odoo_diff.sh` (workspace root, shared across sub-modules). Usage: ```bash tools/check_odoo_diff.sh [] ``` Behavior: - Runs `diff -ruN /Users/gurpreet/Github/RePackaged-Odoo/accounting-/ /Users/gurpreet/Github/RePackaged-Odoo/accounting-/` - Splits output into per-file sections - For each file, classifies based on file path: `views/` and `static/src/components/` and `report/` → `[MIRROR]` candidate; `models/*_engine.py`-like → `[ABSTRACT]` review; new files → `[NEW FEATURE]` review - Outputs a markdown report with per-file sections and classification suggestions - Exit code: 0 if no changes, non-zero if changes (CI can use to flag annual upgrades) ### 6.5 Pinning and Rollback - Git: `main-v19`, `main-v20`, etc. branches in fusion repo. Each client stays on their pinned Odoo version - Manifest version pinned per sub-module per Odoo version - Client deployment: never auto-upgrade. Upgrade is a deliberate, tested, per-client migration - Rollback: restore DB from `pg_dump` taken before upgrade, restore `fusion_accounting_*` checkout from git tag, restart Odoo ### 6.6 Cross-Version Migration Scripts Odoo's standard migration mechanism applies. Each sub-module has a `migrations/` folder with subfolders named after manifest versions. Scripts run automatically when the manifest version bumps in the database vs. on disk. ```python # fusion_accounting_assets/migrations/20.0.0.0.0/pre-migration.py def migrate(cr, version): # V20 renamed fusion_asset.original_value to fusion_asset.acquisition_cost cr.execute("ALTER TABLE fusion_asset RENAME COLUMN original_value TO acquisition_cost") ``` --- ## 7. AI Integration, Testing, Documentation ### 7.1 AI Integration The AI copilot (existing `fusion_accounting/services/`, `fusion_accounting/static/src/`, `fusion_accounting/controllers/` etc.) moves to `fusion_accounting_ai/` in Phase 0 and stays original code. What changes: **Adapter pattern**: every AI tool that today calls Enterprise APIs gets routed through an adapter: ``` fusion_accounting_ai/services/adapters/ ├── bank_rec_adapter.py ├── reports_adapter.py ├── followup_adapter.py ├── assets_adapter.py └── _registry.py ``` Adapter behavior (uniform pattern across all adapters): ```python class BankRecAdapter: def __init__(self, env): self.env = env def list_unreconciled_lines(self, journal_id, limit=100): # Prefer fusion native if installed if 'fusion.bank.rec.widget' in self.env.registry: return self.env['fusion.bank.rec.widget'].sudo().get_unreconciled(journal_id, limit) # Fall back to Enterprise if installed elif self.env['ir.module.module']._fusion_is_module_installed('account_accountant'): return self._enterprise_unreconciled_lines(journal_id, limit) # Last resort: pure Community search else: return self.env['account.bank.statement.line'].sudo().search([ ('journal_id', '=', journal_id), ('is_reconciled', '=', False), ], limit=limit) ``` This pattern means `fusion_accounting_ai` always works, regardless of which other modules are installed. The AI tool functions in `fusion_accounting_ai/services/tools/` get refactored once in Phase 0 to call adapters; subsequent phases just enrich the adapters. **New AI capabilities unlocked by native implementations**: each native phase exposes engine internals to AI tools that Enterprise didn't expose cleanly. Examples: - Phase 1: AI gets access to fusion's match-confidence scores - Phase 2: AI can request a report computation with custom comparison periods on the fly - Phase 4: AI has direct access to tax-grid-by-account decomposition - Phase 5: AI drafts follow-up messages with full payment history context **Existing AI patterns carry forward unchanged**: - Tool tiering (Tier 1 / 2 / 3 with auto-promotion) - Provider pinning per session (Claude vs OpenAI consistency within a session) - Tier 3 approval flow with `pending_approval` placeholder swap on approve/reject - Rich-text chat output via `mdToHtml()` and `innerHTML` injection - Interactive `fusion-table` blocks for actionable results - Session ownership / multi-company record rules (the `fusion.accounting.session` rule that's currently missing gets added in Phase 0) ### 7.2 Testing Strategy Every phase must pass these test categories before exit: | Category | Scope | Where it lives | |---|---|---| | **Unit (engine)** | Pure-Python; no Odoo DB. Algorithm correctness with fixtures | `tests/test__engine.py` | | **Integration (Odoo TestCase)** | Full Odoo DB; install + create data + exercise workflow + assert state | `tests/test__integration.py` | | **Migration round-trip** | Install Enterprise, create Enterprise-only data, install fusion, run wizard, uninstall Enterprise, assert data integrity | `tests/test_migration.py` | | **Tour (JS)** | End-to-end widget UI smoke | `tests/tours/_tour.js` | | **Performance** | Phase 2 reports especially; assert P95 latency at 1k/10k/100k rows | `tests/test__performance.py` | | **Multi-matrix** | Single-company, multi-company, multi-currency, cash-basis on/off | parameterized within other tests | CI runs all tests on every push. A nightly job runs migration tests against a fixture Enterprise DB. ### 7.3 Documentation Deliverables Per sub-module: - `CLAUDE.md` — module-specific context for Cursor/AI assistance - `UPGRADE_NOTES.md` — Odoo version porting log - `README.md` — operator-facing: install, configure, troubleshoot, common gotchas - One screencast or animated GIF per major user workflow, in `static/description/` - Per-feature feature flag documentation in `CLAUDE.md` if applicable Workspace-root documentation: - `/Users/gurpreet/Github/Odoo-Modules/CLAUDE.md` — common Odoo 19 conventions (already substantial; carries forward) - `/Users/gurpreet/Github/Odoo-Modules/fusion_accounting/CLAUDE.md` — meta-module overview pointing at sub-modules - `/Users/gurpreet/Github/Odoo-Modules/fusion_accounting/docs/superpowers/specs/` — design and plan docs (this doc and future ones) ### 7.4 Security - Three groups carry forward from existing module: `group_fusion_accounting_user/manager/admin`. Move from current location to `fusion_accounting_core/security/security.xml` in Phase 0 - Auto-assignments from Community accounting groups: `account.group_account_user` → fusion User; `account.group_account_manager` → fusion Admin (already in place) - Multi-company record rules on every fusion model with `company_id`. Add the missing rule on `fusion.accounting.session` in Phase 0 - ACLs in `security/ir.model.access.csv` per sub-module, scoped to that sub-module's models only - Approve/reject endpoints continue to use `auth='user'` with imperative `has_group()` check inside the handler (Odoo has no built-in `auth='manager'`) ### 7.5 Performance Considerations (Phase 2 in particular) Odoo Enterprise reports have known performance issues on large databases. The Phase 2 design doc must lock in: - Denormalized read paths for trial balance and general ledger (materialized aggregations refreshed on `account.move` post) - Lazy-load line detail (drill-down fetches separately, not all at once) - Cache report runs per `(company_id, period, filter_hash)` with invalidation on `account.move.line` write/post/cancel - Parallel computation across companies in multi-company reports - SQL query review (no Python aggregation of large result sets) ### 7.6 Multi-Company, Multi-Currency, Analytic Not a separate phase. Woven into every phase's exit criteria: - Every fusion model with company-scoped data has `company_id` field and a multi-company record rule - Every monetary field pairs with `currency_id` - `analytic_mixin` (currently in `account_accountant/models/analytic_mixin.py`): declared in `fusion_accounting_core` via shared-field-ownership pattern so analytic tags survive Enterprise uninstall ### 7.7 Localization Canadian HST is built into the existing AI module (`fusion_accounting_ai/services/prompts/domain_prompts.py`) and carries forward. Other localizations are deferred: - Each country-specific tax report becomes a `fusion.account.report` record in `fusion_accounting_reports/data/_.xml` - Country-specific chart of accounts: continue to use Odoo's `account.chart.template` mechanism (Community) - New countries are added on demand, per client engagement ### 7.8 Hosting and Deployment Out of scope for this design doc; covered in workspace-root operational docs. fusion_accounting deploys to the existing Nexa Odoo infrastructure (per existing `fusion_accounting/CLAUDE.md`: `odoo-westin` for Westin Healthcare, equivalents for other clients). Deploy commands in CLAUDE.md carry forward. --- ## 8. Acceptance Criteria for This Roadmap This roadmap is considered "done" (and ready for the first writing-plans session for Phase 0) when: - The user has reviewed this document and signed off - No unresolved ambiguity remains in any of the locked decisions (sub-module topology, data preservation, phase order, architecture rules, upgrade workflow) - The empirical verification test (Section 3.6) is scheduled as part of Phase 0 and not deferred The next session's deliverable will be the Phase 0 implementation plan (via the `writing-plans` skill), which will turn Section 4.2 into actionable, testable tasks. --- ## 9. Open Questions Deferred to Future Sessions Items consciously left open here, to be resolved in their respective phase brainstorming sessions: - Phase 1: exact UI deltas from Odoo's bank rec widget (colour palette, AI confidence badge placement, keyboard shortcuts) - Phase 2: report definition data format (XML mirroring Odoo vs. our own simpler format) - Phase 2: caching layer implementation (in-memory vs. Redis vs. PostgreSQL materialized views) - Phase 4: which non-Canadian tax jurisdictions to seed - Phase 5: SMS provider integration (Twilio? `mail.sms` Odoo built-in?) - Phase 6: depreciation methods to support beyond linear/declining (sum-of-years-digits, units-of-production) - Phase 7+: which satellites have actual client demand right now --- ## 10. References - Workspace root: `/Users/gurpreet/Github/Odoo-Modules/` - Current AI module: `/Users/gurpreet/Github/Odoo-Modules/fusion_accounting/` - Current AI module conventions: `/Users/gurpreet/Github/Odoo-Modules/fusion_accounting/CLAUDE.md` - Workspace conventions: `/Users/gurpreet/Github/Odoo-Modules/CLAUDE.md` - WIP code (not continued): `/Users/gurpreet/Github/Odoo-Modules/Work in Progress/fusion_accounting/` - WIP audit report: `/Users/gurpreet/Github/Odoo-Modules/Work in Progress/fusion_accounting/AUDIT_REPORT.md` - Pinned Odoo source: `/Users/gurpreet/Github/RePackaged-Odoo/accounting/` - Plan file (this session): `/Users/gurpreet/.cursor/plans/fusion_accounting_takeover_roadmap_c851fdb4.plan.md`