docs(fusion_accounting): per-sub-module CLAUDE.md, UPGRADE_NOTES.md, README.md
Task 20 of Phase 0: document the sub-module split. - fusion_accounting_core: foundation doc covering security groups, shared-field schema preservation, and the Enterprise-detection helper. - fusion_accounting_ai: preserves the original module's AI-specific design decisions, Odoo 19 gotchas, deployment commands, controllers, models, theme rules, and known issues. Adds a new Data-adapter pattern section documenting tri-mode routing (fusion / enterprise / community). - fusion_accounting_migration: doc for the Enterprise uninstall safety guard and the wizard shell that future feature sub-modules will extend. - fusion_accounting (meta): rewritten CLAUDE.md as a pure overview pointing at sub-modules, plus a new README.md covering one-click install/uninstall. Each sub-module now has CLAUDE.md (Cursor/Claude context), UPGRADE_NOTES.md (version-by-version deltas / reference sources), and README.md (user-facing install/usage docs). 11 files total. Made-with: Cursor
This commit is contained in:
@@ -1,248 +1,46 @@
|
|||||||
# fusion_accounting — AI Accounting Co-Pilot
|
# fusion_accounting (meta-module) — Cursor / Claude Context
|
||||||
|
|
||||||
## What This Module Does
|
## Purpose
|
||||||
An AI agent (Claude/GPT with tool-calling) embedded in Odoo 19 Enterprise Accounting. Conversational interface backed by a dashboard for bank reconciliation, HST/GST management, AR/AP analysis, journal review, month-end close, payroll, inventory, ADP reconciliation, financial reporting, and auditing.
|
|
||||||
|
|
||||||
## Architecture
|
Meta-module that installs the entire Fusion Accounting sub-module suite with
|
||||||
```
|
one click. Owns no Python, JS, XML data, or views of its own. Just a manifest
|
||||||
fusion_accounting/
|
that depends on the sub-modules.
|
||||||
├── models/ 7 files (5 new models + 2 inherits: account.move, res.config.settings)
|
|
||||||
├── services/
|
|
||||||
│ ├── agent.py AI orchestrator (prompt assembly, tool dispatch loop)
|
|
||||||
│ ├── adapters/ Claude + OpenAI adapters with native tool-calling
|
|
||||||
│ ├── tools/ 93 tool functions across 11 domain files
|
|
||||||
│ ├── prompts/ System prompt builder + 12 domain-specific prompts
|
|
||||||
│ └── scoring.py Confidence scoring + tier promotion logic
|
|
||||||
├── controllers/ 10 JSON-RPC endpoints
|
|
||||||
├── wizards/ Rule creation wizard
|
|
||||||
├── static/src/ OWL dashboard + chat panel + approval cards
|
|
||||||
├── views/ List/form/search views, menus, settings
|
|
||||||
├── security/ 3 groups (User/Manager/Admin), record rules, ACLs
|
|
||||||
├── data/ 88 tool definitions, 2 default rules, 2 crons, 1 sequence
|
|
||||||
├── tests/ API integration tests
|
|
||||||
└── report/ Audit report QWeb template
|
|
||||||
```
|
|
||||||
|
|
||||||
## Key Design Decisions
|
## Sub-modules (current)
|
||||||
|
|
||||||
### AI Provider Integration
|
| Sub-module | Phase | Purpose |
|
||||||
- Uses `fusion.api.service` (from fusion_api module) for API key resolution with fallback to `ir.config_parameter` — NO hard dependency on fusion_api
|
|
||||||
- Claude adapter: native `tool_use` blocks, extended thinking enabled (8K budget) for all Claude 4.x models
|
|
||||||
- OpenAI adapter: Chat Completions API with o-series reasoning model support (`developer` role, `max_completion_tokens`, `reasoning_effort`)
|
|
||||||
- API keys stored in `ir.config_parameter` with `fusion_accounting.` prefix
|
|
||||||
- API key fields in Settings use `password="True"` widget — labels include "(Fusion AI)" suffix to avoid conflicts with other modules' key fields
|
|
||||||
- **Provider pinning**: Sessions remember which provider was used. If the global provider changes mid-session, the session continues with its original provider to prevent cross-adapter message format contamination.
|
|
||||||
|
|
||||||
### Tool Tiering
|
|
||||||
- **Tier 1** (Free): Read-only, execute immediately — 60+ tools
|
|
||||||
- **Tier 2** (Auto-approved): Low-risk writes, logged — ~10 tools
|
|
||||||
- **Tier 3** (Requires approval): Financial writes, user must approve — ~15 tools
|
|
||||||
- Auto-promotion: Tier 3 → Tier 2 at 95% accuracy over 30+ decisions (atomic SQL counters on `fusion.accounting.rule._record_decision`)
|
|
||||||
- Tool descriptions include tier labels (e.g., `[Tier 3: Requires user approval]`) so the AI knows which tools need approval
|
|
||||||
- When a Tier 3 tool is encountered during the chat loop, the loop short-circuits: a final text response is forced so the AI can present approval cards to the user
|
|
||||||
|
|
||||||
### Tier 3 Approval Flow
|
|
||||||
- When a Tier 3 action is approved/rejected, the session's `message_ids_json` is updated to replace the `pending_approval` placeholder with the actual tool result — this prevents dangling `tool_use` blocks that would cause API errors on the next chat turn
|
|
||||||
- After approval, `scoring.check_promotions()` is called to check if any rules should be promoted
|
|
||||||
|
|
||||||
### Menu Location
|
|
||||||
- **Parent**: `accountant.menu_accounting` (NOT `account.menu_finance` — that's Community Edition only)
|
|
||||||
- Enterprise uses `accountant.menu_accounting` (ID 1663) as the visible menu root
|
|
||||||
- `account.menu_finance` (ID 180) exists but has NO visible children in Enterprise — it's the Community root
|
|
||||||
|
|
||||||
### Session Persistence
|
|
||||||
- Chat sessions stored in `fusion.accounting.session` with `message_ids_json` (JSON text field)
|
|
||||||
- On page load, chat panel calls `/session/latest` to restore the most recent active session
|
|
||||||
- Empty assistant messages (tool-call-only responses with no text) are filtered out by the controller
|
|
||||||
- "New Chat" button closes current session and creates a fresh one
|
|
||||||
- Session name (e.g., FAS/2026/00001) shown in the chat header
|
|
||||||
- **Session ownership**: Controllers verify the current user owns the session (managers can access any session)
|
|
||||||
|
|
||||||
### Rich Text Chat Output
|
|
||||||
- AI responses are rendered as rich HTML, not plain text
|
|
||||||
- Markdown-to-HTML conversion happens client-side in `chat_panel.js` via `mdToHtml()` function
|
|
||||||
- HTML is injected via `innerHTML` on `onMounted` + `onPatched` (NOT via OWL's `markup()` / `t-out` — those proved unreliable in Odoo 19)
|
|
||||||
- The `_renderRichMessages()` method finds `.fusion_rich_slot[data-idx]` divs and sets their innerHTML
|
|
||||||
- Supported: headers (# through #####), **bold**, *italic*, `code`, tables, bullet/numbered lists, horizontal rules, [links](url)
|
|
||||||
- System prompt instructs AI to use markdown formatting and include Odoo record links like `[INV/2026/00123](/odoo/accounting/123)`
|
|
||||||
|
|
||||||
### Interactive Tables (fusion-table)
|
|
||||||
- AI can return `fusion-table` fenced code blocks instead of Markdown tables for actionable results
|
|
||||||
- `mdToHtml()` detects these blocks, extracts JSON, and renders `FusionInteractiveTable` OWL components via `mount()`
|
|
||||||
- **Interactive mode**: checkbox column + data columns + AI Recommendation column (colour-coded badge) + Your Input column (text field per row) + bottom bulk action bar
|
|
||||||
- **Read-only mode**: styled table, no inputs/actions
|
|
||||||
- Actions: Apply Recommendations, Flag Selected, Create Rules, Dismiss Selected, Submit All Notes to AI
|
|
||||||
- Action button clicks format a `[TABLE_ACTION]` structured message and send it back through the chat endpoint
|
|
||||||
- The AI decides per-response whether to use interactive or Markdown tables based on whether the data is actionable
|
|
||||||
- Used for: `find_missing_itc_bills`, `find_duplicate_bills`, `get_overdue_invoices`, `find_draft_entries`, `get_unreconciled_bank_lines`, etc.
|
|
||||||
- NOT used for: `get_profit_loss`, `get_balance_sheet`, `get_trial_balance` (informational, read-only)
|
|
||||||
- All styles use Odoo CSS variables — dark/light mode handled automatically
|
|
||||||
|
|
||||||
### Dashboard Layout
|
|
||||||
- Health cards row at top (6 cards: Bank Recon, AR, AP, HST, Audit Score, Month-End)
|
|
||||||
- Below: side-by-side layout — "Needs Attention" panel (flex-grow) + Chat panel (720px fixed width)
|
|
||||||
- Chat panel is 720px (80% larger than original 400px design)
|
|
||||||
- Dashboard endpoint returns `needs_attention` and `recent_activity` JSON arrays alongside health card metrics
|
|
||||||
|
|
||||||
## Odoo 19 Gotchas (Learned the Hard Way)
|
|
||||||
|
|
||||||
### Search Views
|
|
||||||
- NO `string` attribute on `<search>` element
|
|
||||||
- NO `string` attribute on `<group>` element inside search views
|
|
||||||
- Group-by filters MUST have `domain="[]"` attribute
|
|
||||||
- Add `<separator/>` before `<group>` in search views
|
|
||||||
|
|
||||||
### OWL Client Actions
|
|
||||||
- Components registered as client actions receive props: `action`, `actionId`, `updateActionState`, `className`
|
|
||||||
- Must use `static props = ["*"]` (accept any) — NOT `static props = []` (accept none)
|
|
||||||
|
|
||||||
### OWL Rich HTML Rendering
|
|
||||||
- `markup()` from `@odoo/owl` + `t-out` is UNRELIABLE in Odoo 19 for rendering HTML in OWL components
|
|
||||||
- Use `onMounted` + `onPatched` hooks to find DOM elements and set `innerHTML` directly
|
|
||||||
- Pattern: render a placeholder `<div class="slot" t-att-data-idx="index"/>`, then in the hook find it and set `.innerHTML`
|
|
||||||
- Always use BOTH `onMounted` AND `onPatched` — `onPatched` alone misses the first render
|
|
||||||
|
|
||||||
### Cron Safe Eval
|
|
||||||
- NO `import` statements (forbidden opcode `IMPORT_NAME`)
|
|
||||||
- `datetime` module available as `datetime` (use `datetime.datetime.now()`, `datetime.timedelta()`)
|
|
||||||
- NO `from datetime import X` pattern
|
|
||||||
|
|
||||||
### read_group Deprecated
|
|
||||||
- `read_group()` is deprecated in Odoo 19 — use `_read_group()` instead
|
|
||||||
- Still works but throws DeprecationWarning
|
|
||||||
- Dashboard `accounting_dashboard.py` still uses `read_group()` — migrate to `_read_group()` when the new API is stable
|
|
||||||
|
|
||||||
### Config Parameter Values
|
|
||||||
- When changing a Selection field's options, the stored DB value in `ir_config_parameter` must match one of the new options or Settings page will crash with `ValueError: Wrong value`
|
|
||||||
- Fix: UPDATE the value in DB after changing selection options:
|
|
||||||
```sql
|
|
||||||
UPDATE ir_config_parameter SET value = 'new_value' WHERE key = 'fusion_accounting.field_name';
|
|
||||||
```
|
|
||||||
|
|
||||||
### Field Label Conflicts
|
|
||||||
- Odoo warns if two fields on the same model have the same `string` label
|
|
||||||
- Our `display_name_field` conflicted with built-in `display_name` — renamed string to "Tool Label"
|
|
||||||
- API key fields use "(Fusion AI)" suffix to avoid label conflicts with other modules
|
|
||||||
- Tool model uses `domain` (not `domain_name`) and `parameters_schema` (not `parameters`) as field names
|
|
||||||
|
|
||||||
### Group Assignment
|
|
||||||
- `implied_ids` on groups only applies to NEWLY added users, not existing ones
|
|
||||||
- After installing, manually add existing users to groups via SQL:
|
|
||||||
```sql
|
|
||||||
INSERT INTO res_groups_users_rel (gid, uid)
|
|
||||||
SELECT <group_id>, gu.uid FROM res_groups_users_rel gu
|
|
||||||
JOIN ir_model_data imd ON imd.res_id = gu.gid AND imd.model = 'res.groups'
|
|
||||||
WHERE imd.module = 'account' AND imd.name = 'group_account_manager'
|
|
||||||
ON CONFLICT DO NOTHING;
|
|
||||||
```
|
|
||||||
|
|
||||||
### TransientModel in Controllers
|
|
||||||
- Use `.new({...})` NOT `.create({...})` for TransientModels in controller endpoints
|
|
||||||
- `.create()` writes a DB row on every request; `.new()` is in-memory only
|
|
||||||
- Dashboard controller uses `.new()` to compute health metrics without DB writes
|
|
||||||
|
|
||||||
## Server Details
|
|
||||||
- **Server**: odoo-westin (192.168.1.40, SSH via `ssh odoo-westin`)
|
|
||||||
- **Container**: odoo-dev-app (Odoo), odoo-dev-db (PostgreSQL)
|
|
||||||
- **Database**: westin-v19
|
|
||||||
- **Module path**: `/mnt/extra-addons/fusion_accounting/`
|
|
||||||
- **Python deps**: anthropic (v0.88.0), openai (v2.30.0) — installed with `--break-system-packages`
|
|
||||||
- **URL**: erp.westinhealthcare.ca
|
|
||||||
|
|
||||||
## Deployment Commands
|
|
||||||
```bash
|
|
||||||
# Full deploy cycle (clean + copy + upgrade + restart)
|
|
||||||
ssh odoo-westin "docker exec -u 0 odoo-dev-app rm -rf /mnt/extra-addons/fusion_accounting"
|
|
||||||
scp -r "K:\Github\Odoo-Modules\fusion_accounting" odoo-westin:/tmp/fusion_accounting
|
|
||||||
ssh odoo-westin "docker cp /tmp/fusion_accounting odoo-dev-app:/mnt/extra-addons/fusion_accounting && rm -rf /tmp/fusion_accounting"
|
|
||||||
ssh odoo-westin "docker exec odoo-dev-app odoo -d westin-v19 -u fusion_accounting --stop-after-init --http-port=8099 -c /etc/odoo/odoo.conf"
|
|
||||||
ssh odoo-westin "docker restart odoo-dev-app"
|
|
||||||
|
|
||||||
# Check logs
|
|
||||||
ssh odoo-westin "docker logs odoo-dev-app --tail 100"
|
|
||||||
|
|
||||||
# Quick DB queries
|
|
||||||
ssh odoo-westin "docker exec odoo-dev-db psql -U odoo -d westin-v19 -t -c \"<SQL>\""
|
|
||||||
|
|
||||||
# Check module state
|
|
||||||
ssh odoo-westin "docker exec odoo-dev-db psql -U odoo -d westin-v19 -t -c \"SELECT name, state, latest_version FROM ir_module_module WHERE name = 'fusion_accounting';\""
|
|
||||||
```
|
|
||||||
|
|
||||||
## Security Groups
|
|
||||||
| Group ID | XML ID | Name | Access |
|
|
||||||
|---|---|---|---|
|
|
||||||
| 564 | `group_fusion_accounting_user` | User | Dashboard, chat (read-only tools) |
|
|
||||||
| 565 | `group_fusion_accounting_manager` | Manager | + Approve/reject, Tier 2 tools, rules |
|
|
||||||
| 566 | `group_fusion_accounting_admin` | Administrator | + Config, all tools, rule admin |
|
|
||||||
|
|
||||||
Auto-assigned: `account.group_account_user` → User, `account.group_account_manager` → Admin
|
|
||||||
|
|
||||||
## Controller Endpoints
|
|
||||||
| Route | Auth | Purpose |
|
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `/fusion_accounting/session/create` | user | Create new chat session |
|
| `fusion_accounting_core` | 0 | Security groups, shared schema, Enterprise detection helper |
|
||||||
| `/fusion_accounting/session/close` | user (ownership check) | Close active session |
|
| `fusion_accounting_ai` | 0 | AI Co-Pilot (Claude/GPT) — was the original `fusion_accounting` code |
|
||||||
| `/fusion_accounting/session/latest` | user (own sessions only) | Load most recent active session + messages |
|
| `fusion_accounting_migration` | 0 | Transitional Enterprise->Fusion data migration |
|
||||||
| `/fusion_accounting/session/history` | user (ownership check, managers see all) | Load specific session messages |
|
|
||||||
| `/fusion_accounting/chat` | user (ownership check) | Send message, get AI response |
|
|
||||||
| `/fusion_accounting/approve` | user + manager group check | Approve single Tier 3 action |
|
|
||||||
| `/fusion_accounting/reject` | user + manager group check | Reject single Tier 3 action |
|
|
||||||
| `/fusion_accounting/approve_all` | user + manager group check | Batch approve multiple actions |
|
|
||||||
| `/fusion_accounting/reject_all` | user + manager group check | Batch reject multiple actions |
|
|
||||||
| `/fusion_accounting/dashboard/data` | user | Get dashboard health card metrics + needs_attention + recent_activity |
|
|
||||||
|
|
||||||
Note: Approve/reject endpoints use `auth='user'` at the decorator level with an imperative `has_group()` check inside the handler (Odoo has no built-in `auth='manager'`).
|
## Sub-modules (planned)
|
||||||
|
|
||||||
## Models
|
Per the roadmap design at `docs/superpowers/specs/2026-04-18-fusion-accounting-enterprise-takeover-roadmap-design.md`:
|
||||||
| Model | Type | Location | Purpose |
|
|
||||||
|---|---|---|---|
|
|
||||||
| `fusion.accounting.session` | Model | models/ | Chat sessions with message JSON storage |
|
|
||||||
| `fusion.accounting.match.history` | Model | models/ | Every AI tool call + decision (approved/rejected/pending) |
|
|
||||||
| `fusion.accounting.rule` | Model | models/ | Fusion Rules engine with versioning and auto-promotion |
|
|
||||||
| `fusion.accounting.tool` | Model | models/ | Tool registry (82 tools seeded from XML) |
|
|
||||||
| `fusion.accounting.dashboard` | TransientModel | models/ | Computed health metrics (use `.new()` not `.create()`) |
|
|
||||||
| `res.config.settings` (inherit) | TransientModel | models/ | Settings page (API keys, thresholds, toggles) |
|
|
||||||
| `account.move` (inherit) | Model | models/ | Post-action audit hook |
|
|
||||||
| `fusion.accounting.agent` | AbstractModel | services/ | AI orchestrator |
|
|
||||||
| `fusion.accounting.adapter.claude` | AbstractModel | services/ | Claude tool-calling adapter |
|
|
||||||
| `fusion.accounting.adapter.openai` | AbstractModel | services/ | OpenAI tool-calling adapter |
|
|
||||||
| `fusion.accounting.scoring` | AbstractModel | services/ | Confidence scoring |
|
|
||||||
| `fusion.accounting.rule.wizard` | TransientModel | wizards/ | Quick-create rule from chat suggestion |
|
|
||||||
|
|
||||||
## AI Models Available
|
| Sub-module | Phase | Purpose |
|
||||||
**Claude** (default: claude-sonnet-4-6):
|
|---|---|---|
|
||||||
- claude-opus-4-6, claude-sonnet-4-6, claude-haiku-4-5
|
| `fusion_accounting_bank_rec` | 1 | Native bank reconciliation (replaces account_accountant bank rec) |
|
||||||
- claude-sonnet-4-5, claude-opus-4-5, claude-sonnet-4-0, claude-opus-4-0
|
| `fusion_accounting_reports` | 2 | Native financial reports engine (replaces account_reports) |
|
||||||
|
| `fusion_accounting_dashboard` | 3 | Journal kanban + digest |
|
||||||
|
| `fusion_accounting_followup` | 5 | Customer payment follow-ups |
|
||||||
|
| `fusion_accounting_assets` | 6 | Asset register + depreciation |
|
||||||
|
| `fusion_accounting_budget` | 6 | Budget vs actual |
|
||||||
|
|
||||||
**OpenAI** (default: gpt-5.4-mini):
|
## Roadmap and plans
|
||||||
- gpt-5.4, gpt-5.4-mini, gpt-5.4-nano
|
|
||||||
- o3, o4-mini
|
|
||||||
- gpt-4o, gpt-4o-mini (legacy)
|
|
||||||
|
|
||||||
## Theme / Styling Rules
|
- Roadmap design: `docs/superpowers/specs/2026-04-18-fusion-accounting-enterprise-takeover-roadmap-design.md`
|
||||||
- NO hardcoded colours — use CSS variables (`var(--o-border-color)`, `var(--bs-body-color-rgb)`) and Bootstrap utility classes
|
- Phase 0 plan: `docs/superpowers/plans/2026-04-18-phase-0-foundation-plan.md`
|
||||||
- Must work in both light and dark mode
|
- Empirical uninstall test results: `docs/superpowers/specs/2026-04-18-empirical-uninstall-test-results.md` (produced in Task 18 of Phase 0)
|
||||||
- Box shadows: use `rgba(var(--bs-body-color-rgb), 0.1)` not `rgba(0,0,0,0.1)`
|
|
||||||
- AI messages use `var(--o-view-background-color)` background + `var(--o-border-color)` border
|
|
||||||
- Links use `var(--o-action-color)` for theme awareness
|
|
||||||
|
|
||||||
### HST Filing Workflow (4-Phase AI-Driven)
|
## Tooling
|
||||||
- Phase 1: AI runs all HST reports (tax report, missing ITCs, compliance audit, HST balance)
|
|
||||||
- Phase 2: AI sweeps ALL bank accounts for unreconciled expense payments
|
|
||||||
- Phase 3: Per-line processing — check for existing bills, check history for coding patterns, ask about HST, create bills, register payments
|
|
||||||
- Phase 4: Re-run reports to verify updated HST position
|
|
||||||
- New tools added: `search_partners` (Tier 1), `find_similar_bank_lines` (Tier 1), `get_bank_line_details` (Tier 1), `create_vendor_bill` (Tier 3), `register_bill_payment` (Tier 3), `create_expense_entry` (Tier 3)
|
|
||||||
- Two paths for recording expenses: (a) formal vendor bill + payment, or (b) direct GL entry in MISC journal with optional HST split
|
|
||||||
- The `create_expense_entry` tool posts directly to the Miscellaneous Operations journal — debit expense + debit HST ITC (2006) + credit bank
|
|
||||||
- Domain prompt (`hst_management` in domain_prompts.py) includes bank journal IDs and the full 4-phase workflow instructions
|
|
||||||
|
|
||||||
## Known Issues / Future Work
|
- `tools/check_odoo_diff.sh` — annual upgrade ritual: diff Enterprise source between Odoo versions
|
||||||
- `read_group()` deprecation warnings in `accounting_dashboard.py` — migrate to `_read_group()` when the new API format is stable
|
|
||||||
- `generate_t4`, `generate_roe` are stubs pointing to fusion_payroll (by design — Phase 2)
|
## Per-sub-module CLAUDE.md
|
||||||
- `get_payroll_schedule`, `verify_source_deductions`, `verify_payroll_deductions` are stubs (Phase 2 — fusion_payroll integration)
|
|
||||||
- `answer_financial_question` is a stub (returns message to use other tools instead)
|
Each sub-module has its own `CLAUDE.md` with feature-specific context. Read them when working on that sub-module.
|
||||||
- Batch approval "Approve All" / "Reject All" buttons are in the chat panel but not yet in the match history list view
|
|
||||||
- "Needs Attention" panel shows placeholder text in the dashboard — the data is computed and returned by the API but the frontend rendering needs to be connected
|
## Workspace-wide conventions
|
||||||
- Consider switching OpenAI adapter from Chat Completions API to Responses API for better tool handling with newer models
|
|
||||||
- `o1` model does not support tool calling — no guard in place (o3/o4-mini do support it)
|
`/Users/gurpreet/Github/Odoo-Modules/CLAUDE.md` — common Odoo 19 rules (search views, OWL components, SCSS, asset bundle cache busting, dark mode, etc.). Apply to every sub-module.
|
||||||
- Multi-company record rule missing on `fusion.accounting.session` — add if multi-company usage is needed
|
|
||||||
|
|||||||
38
fusion_accounting/README.md
Normal file
38
fusion_accounting/README.md
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# Fusion Accounting (meta-module)
|
||||||
|
|
||||||
|
One-click install of the entire Fusion Accounting suite for Odoo 19.
|
||||||
|
|
||||||
|
## What it installs
|
||||||
|
|
||||||
|
- AI Co-Pilot for accounting (Claude / GPT)
|
||||||
|
- Native foundation (security, schema preservation)
|
||||||
|
- Transitional Enterprise -> Fusion migration helper
|
||||||
|
|
||||||
|
As later sub-modules ship (bank rec, reports, follow-ups, assets, budgets),
|
||||||
|
they're added to the meta-module's `depends` and installed automatically when
|
||||||
|
the client upgrades fusion_accounting.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
docker exec odoo-dev-app odoo -d <db> -i fusion_accounting --stop-after-init
|
||||||
|
|
||||||
|
## Uninstall
|
||||||
|
|
||||||
|
Uninstalling the meta-module does NOT uninstall its sub-modules (Odoo
|
||||||
|
behavior). To fully remove Fusion Accounting:
|
||||||
|
|
||||||
|
docker exec odoo-dev-app odoo-shell -d <db> --no-http <<EOF
|
||||||
|
env['ir.module.module'].search([
|
||||||
|
('name', 'in', [
|
||||||
|
'fusion_accounting',
|
||||||
|
'fusion_accounting_ai',
|
||||||
|
'fusion_accounting_migration',
|
||||||
|
'fusion_accounting_core',
|
||||||
|
]),
|
||||||
|
('state', '=', 'installed'),
|
||||||
|
]).button_immediate_uninstall()
|
||||||
|
EOF
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
See `docs/superpowers/specs/` for the design and `docs/superpowers/plans/` for implementation plans.
|
||||||
272
fusion_accounting_ai/CLAUDE.md
Normal file
272
fusion_accounting_ai/CLAUDE.md
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
# fusion_accounting_ai — Cursor / Claude Context
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
Conversational AI co-pilot for Odoo Accounting using Claude or GPT with native
|
||||||
|
tool-calling. Embeds in any Odoo install via the data-adapter pattern (works on
|
||||||
|
Community-only, Community + fusion native sub-modules, or Community + Enterprise).
|
||||||
|
|
||||||
|
## Sub-module relationships
|
||||||
|
- `fusion_accounting_core`: hard dep, provides security groups + Enterprise detection
|
||||||
|
- `fusion_accounting_bank_rec` (Phase 1): adapter routes to it when present
|
||||||
|
- `fusion_accounting_reports` (Phase 2): same
|
||||||
|
- `fusion_accounting_followup` (Phase 5): same
|
||||||
|
- Odoo Enterprise modules: detected at runtime, AI tools route through them via adapters
|
||||||
|
|
||||||
|
## Data-adapter pattern (Phase 0 addition)
|
||||||
|
- `services/data_adapters/base.py` — `DataAdapter` + `AdapterMode`
|
||||||
|
- `services/data_adapters/_registry.py` — `get_adapter(env, name)` + `register_adapter`
|
||||||
|
- One adapter file per domain: `bank_rec.py`, `reports.py`, `followup.py`, `assets.py`
|
||||||
|
- Each adapter implements `<method>_via_fusion`, `<method>_via_enterprise`, `<method>_via_community`
|
||||||
|
- Adapter `_select_mode()` picks fusion if model loaded, else enterprise if module installed, else community
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
```
|
||||||
|
fusion_accounting_ai/
|
||||||
|
├── models/ 7 files (5 new models + 2 inherits: account.move, res.config.settings)
|
||||||
|
├── services/
|
||||||
|
│ ├── agent.py AI orchestrator (prompt assembly, tool dispatch loop)
|
||||||
|
│ ├── adapters/ Claude + OpenAI adapters with native tool-calling
|
||||||
|
│ ├── data_adapters/ Tri-mode domain routers (fusion / enterprise / community)
|
||||||
|
│ ├── tools/ 93 tool functions across 11 domain files
|
||||||
|
│ ├── prompts/ System prompt builder + 12 domain-specific prompts
|
||||||
|
│ └── scoring.py Confidence scoring + tier promotion logic
|
||||||
|
├── controllers/ 10 JSON-RPC endpoints
|
||||||
|
├── wizards/ Rule creation wizard
|
||||||
|
├── static/src/ OWL dashboard + chat panel + approval cards
|
||||||
|
├── views/ List/form/search views, menus, settings
|
||||||
|
├── security/ ACLs + record rules (groups themselves live in fusion_accounting_core)
|
||||||
|
├── data/ 88 tool definitions, 2 default rules, 2 crons, 1 sequence
|
||||||
|
├── tests/ API integration tests
|
||||||
|
└── report/ Audit report QWeb template
|
||||||
|
```
|
||||||
|
|
||||||
|
## Key Design Decisions
|
||||||
|
|
||||||
|
### AI Provider Integration
|
||||||
|
- Uses `fusion.api.service` (from fusion_api module) for API key resolution with fallback to `ir.config_parameter` — NO hard dependency on fusion_api
|
||||||
|
- Claude adapter: native `tool_use` blocks, extended thinking enabled (8K budget) for all Claude 4.x models
|
||||||
|
- OpenAI adapter: Chat Completions API with o-series reasoning model support (`developer` role, `max_completion_tokens`, `reasoning_effort`)
|
||||||
|
- API keys stored in `ir.config_parameter` with `fusion_accounting.` prefix
|
||||||
|
- API key fields in Settings use `password="True"` widget — labels include "(Fusion AI)" suffix to avoid conflicts with other modules' key fields
|
||||||
|
- **Provider pinning**: Sessions remember which provider was used. If the global provider changes mid-session, the session continues with its original provider to prevent cross-adapter message format contamination.
|
||||||
|
|
||||||
|
### Tool Tiering
|
||||||
|
- **Tier 1** (Free): Read-only, execute immediately — 60+ tools
|
||||||
|
- **Tier 2** (Auto-approved): Low-risk writes, logged — ~10 tools
|
||||||
|
- **Tier 3** (Requires approval): Financial writes, user must approve — ~15 tools
|
||||||
|
- Auto-promotion: Tier 3 → Tier 2 at 95% accuracy over 30+ decisions (atomic SQL counters on `fusion.accounting.rule._record_decision`)
|
||||||
|
- Tool descriptions include tier labels (e.g., `[Tier 3: Requires user approval]`) so the AI knows which tools need approval
|
||||||
|
- When a Tier 3 tool is encountered during the chat loop, the loop short-circuits: a final text response is forced so the AI can present approval cards to the user
|
||||||
|
|
||||||
|
### Tier 3 Approval Flow
|
||||||
|
- When a Tier 3 action is approved/rejected, the session's `message_ids_json` is updated to replace the `pending_approval` placeholder with the actual tool result — this prevents dangling `tool_use` blocks that would cause API errors on the next chat turn
|
||||||
|
- After approval, `scoring.check_promotions()` is called to check if any rules should be promoted
|
||||||
|
|
||||||
|
### Menu Location
|
||||||
|
- **Parent**: `accountant.menu_accounting` (NOT `account.menu_finance` — that's Community Edition only)
|
||||||
|
- Enterprise uses `accountant.menu_accounting` (ID 1663) as the visible menu root
|
||||||
|
- `account.menu_finance` (ID 180) exists but has NO visible children in Enterprise — it's the Community root
|
||||||
|
|
||||||
|
### Session Persistence
|
||||||
|
- Chat sessions stored in `fusion.accounting.session` with `message_ids_json` (JSON text field)
|
||||||
|
- On page load, chat panel calls `/session/latest` to restore the most recent active session
|
||||||
|
- Empty assistant messages (tool-call-only responses with no text) are filtered out by the controller
|
||||||
|
- "New Chat" button closes current session and creates a fresh one
|
||||||
|
- Session name (e.g., FAS/2026/00001) shown in the chat header
|
||||||
|
- **Session ownership**: Controllers verify the current user owns the session (managers can access any session)
|
||||||
|
|
||||||
|
### Rich Text Chat Output
|
||||||
|
- AI responses are rendered as rich HTML, not plain text
|
||||||
|
- Markdown-to-HTML conversion happens client-side in `chat_panel.js` via `mdToHtml()` function
|
||||||
|
- HTML is injected via `innerHTML` on `onMounted` + `onPatched` (NOT via OWL's `markup()` / `t-out` — those proved unreliable in Odoo 19)
|
||||||
|
- The `_renderRichMessages()` method finds `.fusion_rich_slot[data-idx]` divs and sets their innerHTML
|
||||||
|
- Supported: headers (# through #####), **bold**, *italic*, `code`, tables, bullet/numbered lists, horizontal rules, [links](url)
|
||||||
|
- System prompt instructs AI to use markdown formatting and include Odoo record links like `[INV/2026/00123](/odoo/accounting/123)`
|
||||||
|
|
||||||
|
### Interactive Tables (fusion-table)
|
||||||
|
- AI can return `fusion-table` fenced code blocks instead of Markdown tables for actionable results
|
||||||
|
- `mdToHtml()` detects these blocks, extracts JSON, and renders `FusionInteractiveTable` OWL components via `mount()`
|
||||||
|
- **Interactive mode**: checkbox column + data columns + AI Recommendation column (colour-coded badge) + Your Input column (text field per row) + bottom bulk action bar
|
||||||
|
- **Read-only mode**: styled table, no inputs/actions
|
||||||
|
- Actions: Apply Recommendations, Flag Selected, Create Rules, Dismiss Selected, Submit All Notes to AI
|
||||||
|
- Action button clicks format a `[TABLE_ACTION]` structured message and send it back through the chat endpoint
|
||||||
|
- The AI decides per-response whether to use interactive or Markdown tables based on whether the data is actionable
|
||||||
|
- Used for: `find_missing_itc_bills`, `find_duplicate_bills`, `get_overdue_invoices`, `find_draft_entries`, `get_unreconciled_bank_lines`, etc.
|
||||||
|
- NOT used for: `get_profit_loss`, `get_balance_sheet`, `get_trial_balance` (informational, read-only)
|
||||||
|
- All styles use Odoo CSS variables — dark/light mode handled automatically
|
||||||
|
|
||||||
|
### Dashboard Layout
|
||||||
|
- Health cards row at top (6 cards: Bank Recon, AR, AP, HST, Audit Score, Month-End)
|
||||||
|
- Below: side-by-side layout — "Needs Attention" panel (flex-grow) + Chat panel (720px fixed width)
|
||||||
|
- Chat panel is 720px (80% larger than original 400px design)
|
||||||
|
- Dashboard endpoint returns `needs_attention` and `recent_activity` JSON arrays alongside health card metrics
|
||||||
|
|
||||||
|
### HST Filing Workflow (4-Phase AI-Driven)
|
||||||
|
- Phase 1: AI runs all HST reports (tax report, missing ITCs, compliance audit, HST balance)
|
||||||
|
- Phase 2: AI sweeps ALL bank accounts for unreconciled expense payments
|
||||||
|
- Phase 3: Per-line processing — check for existing bills, check history for coding patterns, ask about HST, create bills, register payments
|
||||||
|
- Phase 4: Re-run reports to verify updated HST position
|
||||||
|
- New tools added: `search_partners` (Tier 1), `find_similar_bank_lines` (Tier 1), `get_bank_line_details` (Tier 1), `create_vendor_bill` (Tier 3), `register_bill_payment` (Tier 3), `create_expense_entry` (Tier 3)
|
||||||
|
- Two paths for recording expenses: (a) formal vendor bill + payment, or (b) direct GL entry in MISC journal with optional HST split
|
||||||
|
- The `create_expense_entry` tool posts directly to the Miscellaneous Operations journal — debit expense + debit HST ITC (2006) + credit bank
|
||||||
|
- Domain prompt (`hst_management` in domain_prompts.py) includes bank journal IDs and the full 4-phase workflow instructions
|
||||||
|
|
||||||
|
## Odoo 19 Gotchas (Learned the Hard Way)
|
||||||
|
|
||||||
|
### Search Views
|
||||||
|
- NO `string` attribute on `<search>` element
|
||||||
|
- NO `string` attribute on `<group>` element inside search views
|
||||||
|
- Group-by filters MUST have `domain="[]"` attribute
|
||||||
|
- Add `<separator/>` before `<group>` in search views
|
||||||
|
|
||||||
|
### OWL Client Actions
|
||||||
|
- Components registered as client actions receive props: `action`, `actionId`, `updateActionState`, `className`
|
||||||
|
- Must use `static props = ["*"]` (accept any) — NOT `static props = []` (accept none)
|
||||||
|
|
||||||
|
### OWL Rich HTML Rendering
|
||||||
|
- `markup()` from `@odoo/owl` + `t-out` is UNRELIABLE in Odoo 19 for rendering HTML in OWL components
|
||||||
|
- Use `onMounted` + `onPatched` hooks to find DOM elements and set `innerHTML` directly
|
||||||
|
- Pattern: render a placeholder `<div class="slot" t-att-data-idx="index"/>`, then in the hook find it and set `.innerHTML`
|
||||||
|
- Always use BOTH `onMounted` AND `onPatched` — `onPatched` alone misses the first render
|
||||||
|
|
||||||
|
### Cron Safe Eval
|
||||||
|
- NO `import` statements (forbidden opcode `IMPORT_NAME`)
|
||||||
|
- `datetime` module available as `datetime` (use `datetime.datetime.now()`, `datetime.timedelta()`)
|
||||||
|
- NO `from datetime import X` pattern
|
||||||
|
|
||||||
|
### read_group Deprecated
|
||||||
|
- `read_group()` is deprecated in Odoo 19 — use `_read_group()` instead
|
||||||
|
- Still works but throws DeprecationWarning
|
||||||
|
- Dashboard `accounting_dashboard.py` still uses `read_group()` — migrate to `_read_group()` when the new API is stable
|
||||||
|
|
||||||
|
### Config Parameter Values
|
||||||
|
- When changing a Selection field's options, the stored DB value in `ir_config_parameter` must match one of the new options or Settings page will crash with `ValueError: Wrong value`
|
||||||
|
- Fix: UPDATE the value in DB after changing selection options:
|
||||||
|
```sql
|
||||||
|
UPDATE ir_config_parameter SET value = 'new_value' WHERE key = 'fusion_accounting.field_name';
|
||||||
|
```
|
||||||
|
|
||||||
|
### Field Label Conflicts
|
||||||
|
- Odoo warns if two fields on the same model have the same `string` label
|
||||||
|
- Our `display_name_field` conflicted with built-in `display_name` — renamed string to "Tool Label"
|
||||||
|
- API key fields use "(Fusion AI)" suffix to avoid label conflicts with other modules
|
||||||
|
- Tool model uses `domain` (not `domain_name`) and `parameters_schema` (not `parameters`) as field names
|
||||||
|
|
||||||
|
### Group Assignment
|
||||||
|
- `implied_ids` on groups only applies to NEWLY added users, not existing ones
|
||||||
|
- After installing, manually add existing users to groups via SQL:
|
||||||
|
```sql
|
||||||
|
INSERT INTO res_groups_users_rel (gid, uid)
|
||||||
|
SELECT <group_id>, gu.uid FROM res_groups_users_rel gu
|
||||||
|
JOIN ir_model_data imd ON imd.res_id = gu.gid AND imd.model = 'res.groups'
|
||||||
|
WHERE imd.module = 'account' AND imd.name = 'group_account_manager'
|
||||||
|
ON CONFLICT DO NOTHING;
|
||||||
|
```
|
||||||
|
|
||||||
|
### TransientModel in Controllers
|
||||||
|
- Use `.new({...})` NOT `.create({...})` for TransientModels in controller endpoints
|
||||||
|
- `.create()` writes a DB row on every request; `.new()` is in-memory only
|
||||||
|
- Dashboard controller uses `.new()` to compute health metrics without DB writes
|
||||||
|
|
||||||
|
## Server Details
|
||||||
|
- **Server**: odoo-westin (192.168.1.40, SSH via `ssh odoo-westin`)
|
||||||
|
- **Container**: odoo-dev-app (Odoo), odoo-dev-db (PostgreSQL)
|
||||||
|
- **Database**: westin-v19
|
||||||
|
- **Module path**: `/mnt/extra-addons/fusion_accounting_ai/`
|
||||||
|
- **Python deps**: anthropic (v0.88.0), openai (v2.30.0) — installed with `--break-system-packages`
|
||||||
|
- **URL**: erp.westinhealthcare.ca
|
||||||
|
|
||||||
|
## Deployment Commands
|
||||||
|
```bash
|
||||||
|
# Full deploy cycle (clean + copy + upgrade + restart)
|
||||||
|
ssh odoo-westin "docker exec -u 0 odoo-dev-app rm -rf /mnt/extra-addons/fusion_accounting_ai"
|
||||||
|
scp -r "K:\Github\Odoo-Modules\fusion_accounting_ai" odoo-westin:/tmp/fusion_accounting_ai
|
||||||
|
ssh odoo-westin "docker cp /tmp/fusion_accounting_ai odoo-dev-app:/mnt/extra-addons/fusion_accounting_ai && rm -rf /tmp/fusion_accounting_ai"
|
||||||
|
ssh odoo-westin "docker exec odoo-dev-app odoo -d westin-v19 -u fusion_accounting_ai --stop-after-init --http-port=8099 -c /etc/odoo/odoo.conf"
|
||||||
|
ssh odoo-westin "docker restart odoo-dev-app"
|
||||||
|
|
||||||
|
# Check logs
|
||||||
|
ssh odoo-westin "docker logs odoo-dev-app --tail 100"
|
||||||
|
|
||||||
|
# Quick DB queries
|
||||||
|
ssh odoo-westin "docker exec odoo-dev-db psql -U odoo -d westin-v19 -t -c \"<SQL>\""
|
||||||
|
|
||||||
|
# Check module state
|
||||||
|
ssh odoo-westin "docker exec odoo-dev-db psql -U odoo -d westin-v19 -t -c \"SELECT name, state, latest_version FROM ir_module_module WHERE name = 'fusion_accounting_ai';\""
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Groups
|
||||||
|
(The three groups themselves are now defined in `fusion_accounting_core`. This
|
||||||
|
module's `security/ir.model.access.csv` grants access on AI-specific models
|
||||||
|
using those group XML-ids.)
|
||||||
|
|
||||||
|
| XML ID (in fusion_accounting_core) | Name | Access in AI module |
|
||||||
|
|---|---|---|
|
||||||
|
| `group_fusion_accounting_user` | User | Dashboard, chat (read-only tools) |
|
||||||
|
| `group_fusion_accounting_manager` | Manager | + Approve/reject, Tier 2 tools, rules |
|
||||||
|
| `group_fusion_accounting_admin` | Administrator | + Config, all tools, rule admin |
|
||||||
|
|
||||||
|
Auto-assigned (configured in _core): `account.group_account_user` → User,
|
||||||
|
`account.group_account_manager` → Admin
|
||||||
|
|
||||||
|
## Controller Endpoints
|
||||||
|
| Route | Auth | Purpose |
|
||||||
|
|---|---|---|
|
||||||
|
| `/fusion_accounting/session/create` | user | Create new chat session |
|
||||||
|
| `/fusion_accounting/session/close` | user (ownership check) | Close active session |
|
||||||
|
| `/fusion_accounting/session/latest` | user (own sessions only) | Load most recent active session + messages |
|
||||||
|
| `/fusion_accounting/session/history` | user (ownership check, managers see all) | Load specific session messages |
|
||||||
|
| `/fusion_accounting/chat` | user (ownership check) | Send message, get AI response |
|
||||||
|
| `/fusion_accounting/approve` | user + manager group check | Approve single Tier 3 action |
|
||||||
|
| `/fusion_accounting/reject` | user + manager group check | Reject single Tier 3 action |
|
||||||
|
| `/fusion_accounting/approve_all` | user + manager group check | Batch approve multiple actions |
|
||||||
|
| `/fusion_accounting/reject_all` | user + manager group check | Batch reject multiple actions |
|
||||||
|
| `/fusion_accounting/dashboard/data` | user | Get dashboard health card metrics + needs_attention + recent_activity |
|
||||||
|
|
||||||
|
Note: Approve/reject endpoints use `auth='user'` at the decorator level with an imperative `has_group()` check inside the handler (Odoo has no built-in `auth='manager'`).
|
||||||
|
|
||||||
|
## Models
|
||||||
|
| Model | Type | Location | Purpose |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `fusion.accounting.session` | Model | models/ | Chat sessions with message JSON storage |
|
||||||
|
| `fusion.accounting.match.history` | Model | models/ | Every AI tool call + decision (approved/rejected/pending) |
|
||||||
|
| `fusion.accounting.rule` | Model | models/ | Fusion Rules engine with versioning and auto-promotion |
|
||||||
|
| `fusion.accounting.tool` | Model | models/ | Tool registry (82 tools seeded from XML) |
|
||||||
|
| `fusion.accounting.dashboard` | TransientModel | models/ | Computed health metrics (use `.new()` not `.create()`) |
|
||||||
|
| `res.config.settings` (inherit) | TransientModel | models/ | Settings page (API keys, thresholds, toggles) |
|
||||||
|
| `account.move` (inherit) | Model | models/ | Post-action audit hook |
|
||||||
|
| `fusion.accounting.agent` | AbstractModel | services/ | AI orchestrator |
|
||||||
|
| `fusion.accounting.adapter.claude` | AbstractModel | services/ | Claude tool-calling adapter |
|
||||||
|
| `fusion.accounting.adapter.openai` | AbstractModel | services/ | OpenAI tool-calling adapter |
|
||||||
|
| `fusion.accounting.scoring` | AbstractModel | services/ | Confidence scoring |
|
||||||
|
| `fusion.accounting.rule.wizard` | TransientModel | wizards/ | Quick-create rule from chat suggestion |
|
||||||
|
|
||||||
|
## AI Models Available
|
||||||
|
**Claude** (default: claude-sonnet-4-6):
|
||||||
|
- claude-opus-4-6, claude-sonnet-4-6, claude-haiku-4-5
|
||||||
|
- claude-sonnet-4-5, claude-opus-4-5, claude-sonnet-4-0, claude-opus-4-0
|
||||||
|
|
||||||
|
**OpenAI** (default: gpt-5.4-mini):
|
||||||
|
- gpt-5.4, gpt-5.4-mini, gpt-5.4-nano
|
||||||
|
- o3, o4-mini
|
||||||
|
- gpt-4o, gpt-4o-mini (legacy)
|
||||||
|
|
||||||
|
## Theme / Styling Rules
|
||||||
|
- NO hardcoded colours — use CSS variables (`var(--o-border-color)`, `var(--bs-body-color-rgb)`) and Bootstrap utility classes
|
||||||
|
- Must work in both light and dark mode
|
||||||
|
- Box shadows: use `rgba(var(--bs-body-color-rgb), 0.1)` not `rgba(0,0,0,0.1)`
|
||||||
|
- AI messages use `var(--o-view-background-color)` background + `var(--o-border-color)` border
|
||||||
|
- Links use `var(--o-action-color)` for theme awareness
|
||||||
|
|
||||||
|
## Known Issues / Future Work
|
||||||
|
- `read_group()` deprecation warnings in `accounting_dashboard.py` — migrate to `_read_group()` when the new API format is stable
|
||||||
|
- `generate_t4`, `generate_roe` are stubs pointing to fusion_payroll (by design — Phase 2)
|
||||||
|
- `get_payroll_schedule`, `verify_source_deductions`, `verify_payroll_deductions` are stubs (Phase 2 — fusion_payroll integration)
|
||||||
|
- `answer_financial_question` is a stub (returns message to use other tools instead)
|
||||||
|
- Batch approval "Approve All" / "Reject All" buttons are in the chat panel but not yet in the match history list view
|
||||||
|
- "Needs Attention" panel shows placeholder text in the dashboard — the data is computed and returned by the API but the frontend rendering needs to be connected
|
||||||
|
- Consider switching OpenAI adapter from Chat Completions API to Responses API for better tool handling with newer models
|
||||||
|
- `o1` model does not support tool calling — no guard in place (o3/o4-mini do support it)
|
||||||
|
- Multi-company record rule on `fusion.accounting.session` — added in Phase 0 split-out (see UPGRADE_NOTES.md)
|
||||||
31
fusion_accounting_ai/README.md
Normal file
31
fusion_accounting_ai/README.md
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# Fusion Accounting AI
|
||||||
|
|
||||||
|
Conversational AI co-pilot for Odoo Accounting using Claude or GPT.
|
||||||
|
|
||||||
|
## What it does
|
||||||
|
|
||||||
|
Embeds an AI agent in the Odoo Accounting menu. Users chat with the AI, which
|
||||||
|
calls into Odoo via tool-functions (read journal entries, find unreconciled
|
||||||
|
bank lines, draft follow-ups, generate audit reports, etc.). Tier 3 actions
|
||||||
|
(financial writes) require user approval via in-chat approval cards.
|
||||||
|
|
||||||
|
## Install profiles
|
||||||
|
|
||||||
|
This module works on three install profiles:
|
||||||
|
|
||||||
|
1. **Pure Community + this module** — AI uses pure Community searches via the
|
||||||
|
data-adapter `_via_community` paths. Reduced functionality (no rich reports,
|
||||||
|
no Enterprise bank-rec features) but all read tools work.
|
||||||
|
2. **Community + this module + fusion native sub-modules** (recommended target) —
|
||||||
|
adapters route to fusion bank rec / fusion reports / etc. Full functionality.
|
||||||
|
3. **Community + Enterprise + this module** (legacy) — adapters route to Enterprise
|
||||||
|
APIs. Most functionality available; some Enterprise-specific UI integration
|
||||||
|
(e.g. live cursor in bank-rec widget) not supported.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Settings -> Fusion Accounting AI -> set API keys for Claude (default) and/or OpenAI.
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
See `CLAUDE.md` in this module for known Odoo 19 gotchas.
|
||||||
22
fusion_accounting_ai/UPGRADE_NOTES.md
Normal file
22
fusion_accounting_ai/UPGRADE_NOTES.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# UPGRADE_NOTES — fusion_accounting_ai
|
||||||
|
|
||||||
|
## V19.0.1.0.0 (initial — Phase 0 split-out)
|
||||||
|
|
||||||
|
### Origin
|
||||||
|
Code originally lived in `fusion_accounting/` (the original AI module). Split out
|
||||||
|
into this sub-module during Phase 0 of the Enterprise Takeover Roadmap.
|
||||||
|
|
||||||
|
### Additions in this version
|
||||||
|
- `services/data_adapters/` — DataAdapter base + 4 adapters (bank_rec, reports, followup, assets)
|
||||||
|
- `services/tools/*.py` — every tool that called Enterprise-specific APIs refactored through adapters
|
||||||
|
- `migrations/19.0.1.0.0/post-migration.py` — reassigns ir_model_data ownership from old module name
|
||||||
|
- Multi-company record rule on `fusion.accounting.session` (was missing pre-Phase-0 per CLAUDE.md Known Issues)
|
||||||
|
|
||||||
|
### Removed from manifest deps
|
||||||
|
- `account_accountant` (was hard dep)
|
||||||
|
- `account_reports` (was hard dep)
|
||||||
|
- `account_followup` (was hard dep)
|
||||||
|
- `mail` (now inherited via `fusion_accounting_core`)
|
||||||
|
|
||||||
|
Replaced with: `fusion_accounting_core` (Community-only). Runtime detection of
|
||||||
|
Enterprise modules via the data adapter pattern.
|
||||||
25
fusion_accounting_core/CLAUDE.md
Normal file
25
fusion_accounting_core/CLAUDE.md
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# fusion_accounting_core — Cursor / Claude Context
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
Foundation for the Fusion Accounting sub-module suite. Owns:
|
||||||
|
- Three security groups (User / Manager / Admin) shared across all sub-modules
|
||||||
|
- Shared-field-ownership declarations on `account.move` and `account.reconcile.model`
|
||||||
|
- Runtime Enterprise-detection helper: `env['ir.module.module']._fusion_is_enterprise_accounting_installed()`
|
||||||
|
|
||||||
|
## What lives here
|
||||||
|
- `models/account_move.py` — declares Enterprise-extension fields with identical
|
||||||
|
schemas / relation tables. Pure schema-preservation; no business logic.
|
||||||
|
- `models/account_reconcile_model.py` — same pattern for `created_automatically`
|
||||||
|
- `models/ir_module_module.py` — Enterprise-detection helpers
|
||||||
|
- `security/fusion_accounting_security.xml` — privilege + 3 groups + auto-assignment
|
||||||
|
|
||||||
|
## Critical rules
|
||||||
|
- NEVER add business logic to the shared-field models (account_move.py here).
|
||||||
|
Logic belongs in the feature sub-module that owns it (e.g. fusion_accounting_bank_rec).
|
||||||
|
- NEVER rename the relation tables for shared M2Ms. They must match Enterprise verbatim
|
||||||
|
for the dual-ownership pattern to work.
|
||||||
|
- Shared fields here have NO defaults beyond what Enterprise sets. The point is preservation.
|
||||||
|
|
||||||
|
## Cross-references
|
||||||
|
- Parent design: `fusion_accounting/docs/superpowers/specs/2026-04-18-fusion-accounting-enterprise-takeover-roadmap-design.md` (Section 3)
|
||||||
|
- Workspace conventions: `/Users/gurpreet/Github/Odoo-Modules/CLAUDE.md`
|
||||||
39
fusion_accounting_core/README.md
Normal file
39
fusion_accounting_core/README.md
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# Fusion Accounting Core
|
||||||
|
|
||||||
|
Foundation module for the Fusion Accounting suite.
|
||||||
|
|
||||||
|
## What it does
|
||||||
|
|
||||||
|
- Defines three security groups: Fusion Accounting User / Manager / Administrator
|
||||||
|
- Auto-promotes Odoo `account.group_account_user` -> Fusion User and
|
||||||
|
`account.group_account_manager` -> Fusion Admin
|
||||||
|
- Declares schema-preservation fields on `account.move` and `account.reconcile.model`
|
||||||
|
so that Enterprise extension fields (deferred revenue links, signing user, etc.)
|
||||||
|
survive an Enterprise uninstall
|
||||||
|
- Exposes the helper `env['ir.module.module']._fusion_is_enterprise_accounting_installed()`
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
This module never installs alone. Install `fusion_accounting` (the meta-module)
|
||||||
|
or any of the feature sub-modules — they all depend on `fusion_accounting_core`.
|
||||||
|
|
||||||
|
## Uninstall
|
||||||
|
|
||||||
|
Uninstalling `fusion_accounting_core` will remove the security groups and the
|
||||||
|
schema-preservation fields. If Enterprise is also installed, uninstalling
|
||||||
|
`fusion_accounting_core` will cause Odoo to consider the deferred / signing
|
||||||
|
fields owned only by Enterprise — which is the original Enterprise-only state
|
||||||
|
(no data loss, just back to Enterprise-controlled schema).
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
If users are missing the "Fusion Accounting" privilege section in user settings
|
||||||
|
after install, the `implied_ids` mechanism only fires for newly-added users.
|
||||||
|
Backfill existing users via SQL:
|
||||||
|
|
||||||
|
INSERT INTO res_groups_users_rel (gid, uid)
|
||||||
|
SELECT g.res_id, gu.uid
|
||||||
|
FROM res_groups_users_rel gu
|
||||||
|
JOIN ir_model_data g ON g.module = 'fusion_accounting_core' AND g.name = 'group_fusion_accounting_user'
|
||||||
|
JOIN ir_model_data ag ON ag.module = 'account' AND ag.name = 'group_account_user' AND gu.gid = ag.res_id
|
||||||
|
ON CONFLICT DO NOTHING;
|
||||||
28
fusion_accounting_core/UPGRADE_NOTES.md
Normal file
28
fusion_accounting_core/UPGRADE_NOTES.md
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# UPGRADE_NOTES — fusion_accounting_core
|
||||||
|
|
||||||
|
## V19.0.1.0.0 (initial — Phase 0)
|
||||||
|
|
||||||
|
### Reference sources
|
||||||
|
- `RePackaged-Odoo/accounting/account_accountant/models/account_move.py` (Enterprise extension fields read for schema match)
|
||||||
|
- `RePackaged-Odoo/accounting/account_accountant/models/account_reconcile_model.py` (same)
|
||||||
|
|
||||||
|
### Mirror-zone files (none in _core — _core has no Mirror zone)
|
||||||
|
|
||||||
|
### Abstract-zone files (all of _core is abstract)
|
||||||
|
- `models/account_move.py`
|
||||||
|
- `models/account_reconcile_model.py`
|
||||||
|
- `models/ir_module_module.py`
|
||||||
|
|
||||||
|
### Intentional deltas from Odoo
|
||||||
|
- Shared-field declarations have NO compute methods, NO @api decorators beyond
|
||||||
|
basic field types. Enterprise's account_move.py adds compute methods and
|
||||||
|
business logic; we deliberately do not duplicate them. When Enterprise is
|
||||||
|
installed, its compute methods run; when it's not, the fields are simply
|
||||||
|
unused (until a fusion sub-module decides to own that behavior).
|
||||||
|
|
||||||
|
### Migrations
|
||||||
|
- `migrations/19.0.1.0.0/pre-migration.py` — rehome fusion security xml-ids
|
||||||
|
from module='fusion_accounting' to module='fusion_accounting_core' BEFORE
|
||||||
|
data-load (avoids unique-constraint crash on upgrade from pre-Phase-0)
|
||||||
|
- `migrations/19.0.1.0.0/post-migration.py` — idempotent safety-net for the
|
||||||
|
same rehome (zero-op if pre-migration already ran)
|
||||||
20
fusion_accounting_migration/CLAUDE.md
Normal file
20
fusion_accounting_migration/CLAUDE.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# fusion_accounting_migration — Cursor / Claude Context
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
Transitional sub-module that helps clients move from Odoo Enterprise accounting
|
||||||
|
to Odoo Community + Fusion Accounting without losing data.
|
||||||
|
|
||||||
|
## What it does
|
||||||
|
- Safety guard: blocks uninstall of Enterprise accounting modules until the
|
||||||
|
migration wizard has run (per-module flag in ir.config_parameter)
|
||||||
|
- Migration wizard: shell that other fusion sub-modules extend with per-feature
|
||||||
|
migration logic (Phase 0 ships only the shell)
|
||||||
|
|
||||||
|
## Critical
|
||||||
|
- The safety guard overrides `button_immediate_uninstall` AND `module_uninstall`
|
||||||
|
on `ir.module.module`. Both paths must be guarded — UI uninstall, CLI uninstall,
|
||||||
|
and API uninstall all go through one or the other.
|
||||||
|
- Each fusion feature sub-module that replaces an Enterprise feature MUST extend
|
||||||
|
the migration wizard's `action_run_migration` to add its own migration step
|
||||||
|
AND set the corresponding `fusion_accounting.migration.<module>.completed`
|
||||||
|
flag to True after running.
|
||||||
22
fusion_accounting_migration/README.md
Normal file
22
fusion_accounting_migration/README.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# Fusion Accounting Migration
|
||||||
|
|
||||||
|
Transitional helper for moving clients from Odoo Enterprise to Community + Fusion.
|
||||||
|
|
||||||
|
## When to use
|
||||||
|
|
||||||
|
Install this module ONCE per client during the Enterprise->Fusion switchover.
|
||||||
|
After the switchover is complete and the client is comfortable on Community,
|
||||||
|
this module can be uninstalled.
|
||||||
|
|
||||||
|
## How it works
|
||||||
|
|
||||||
|
1. Install fusion_accounting (the meta-module) — pulls in this module
|
||||||
|
2. Open Fusion Accounting -> Migrate from Enterprise (top-level menu)
|
||||||
|
3. Wizard shows which Enterprise modules are detected and what migrations are available
|
||||||
|
4. Run migration; wizard reports counts and warnings
|
||||||
|
5. Uninstall Enterprise modules in dep-safe order (the safety guard prevents premature uninstall)
|
||||||
|
|
||||||
|
## Override the safety guard
|
||||||
|
|
||||||
|
If you need to uninstall an Enterprise module WITHOUT migrating (data will be lost),
|
||||||
|
set `fusion_accounting.migration.<module>.completed` to True in System Parameters.
|
||||||
10
fusion_accounting_migration/UPGRADE_NOTES.md
Normal file
10
fusion_accounting_migration/UPGRADE_NOTES.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# UPGRADE_NOTES — fusion_accounting_migration
|
||||||
|
|
||||||
|
## V19.0.1.0.0 (initial — Phase 0)
|
||||||
|
|
||||||
|
Skeleton: safety guard + wizard shell. No per-feature migration logic registered yet.
|
||||||
|
|
||||||
|
Added by future phases:
|
||||||
|
- Phase 1: bank-rec migration (verifies account.partial.reconcile rows are intact; sets `account_accountant.completed` flag)
|
||||||
|
- Phase 5: account_followup migration
|
||||||
|
- Phase 6: account_asset, account_budget migration
|
||||||
Reference in New Issue
Block a user