7.7 KiB
7.7 KiB
fusion_accounting — AI Accounting Co-Pilot
What This Module Does
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
fusion_accounting/
├── models/ 7 models (6 new + 1 inherit on account.move)
├── services/
│ ├── agent.py AI orchestrator (prompt assembly, tool dispatch loop)
│ ├── adapters/ Claude + OpenAI adapters with native tool-calling
│ ├── tools/ 85 tool functions across 11 domain files
│ ├── prompts/ System prompt builder + 12 domain-specific prompts
│ └── scoring.py Confidence scoring + tier promotion logic
├── controllers/ 8 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/ 82 tool definitions, 2 default rules, 2 crons
└── 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 toir.config_parameter— NO hard dependency on fusion_api - Claude adapter: native
tool_useblocks, extended thinking enabled (8K budget) for 4.5+ models - OpenAI adapter: Chat Completions API with o-series reasoning model support (
developerrole,max_completion_tokens,reasoning_effort) - API keys stored in
ir.config_parameterwithfusion_accounting.prefix
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)
Menu Location
- Parent:
accountant.menu_accounting(NOTaccount.menu_finance— that's Community Edition only) - Enterprise uses
accountant.menu_accounting(ID 1663) as the visible menu root
Session Persistence
- Chat sessions stored in
fusion.accounting.sessionwithmessage_ids_json(JSON text field) - On page load, chat panel calls
/session/latestto restore the most recent active session - "New Chat" button closes current session and creates a fresh one
Odoo 19 Gotchas (Learned the Hard Way)
Search Views
- NO
stringattribute on<search>element - NO
stringattribute 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) — NOTstatic props = [](accept none)
Cron Safe Eval
- NO
importstatements (forbidden opcodeIMPORT_NAME) datetimemodule available asdatetime(usedatetime.datetime.now(),datetime.timedelta())- NO
from datetime import Xpattern
read_group Deprecated
read_group()is deprecated in Odoo 19 — use_read_group()instead- Still works but throws DeprecationWarning
Config Parameter Values
- When changing a Selection field's options, the stored DB value in
ir_config_parametermust match one of the new options or Settings page will crash withValueError: Wrong value - Fix: UPDATE the value in DB after changing selection options
Field Label Conflicts
- Odoo warns if two fields on the same model have the same
stringlabel - Our
display_name_fieldconflicted with built-indisplay_name— renamed string to "Tool Label"
Group Assignment
implied_idson groups only applies to NEWLY added users, not existing ones- After installing, manually add existing users to groups via 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;
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
Deployment Commands
# Deploy module to server
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"
# Upgrade module (use alt port to avoid conflict with running instance)
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"
# Restart container
ssh odoo-westin "docker restart odoo-dev-app"
# Check logs
ssh odoo-westin "docker logs odoo-dev-app --tail 100"
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
Models
| Model | Type | Purpose |
|---|---|---|
fusion.accounting.session |
Model | Chat sessions with message JSON storage |
fusion.accounting.match.history |
Model | Every AI tool call + decision (approved/rejected/pending) |
fusion.accounting.rule |
Model | Fusion Rules engine with versioning and auto-promotion |
fusion.accounting.tool |
Model | Tool registry (82 tools seeded from XML) |
fusion.accounting.dashboard |
TransientModel | Computed health metrics (use .new() not .create()) |
fusion.accounting.agent |
AbstractModel | AI orchestrator |
fusion.accounting.adapter.claude |
AbstractModel | Claude tool-calling adapter |
fusion.accounting.adapter.openai |
AbstractModel | OpenAI tool-calling adapter |
fusion.accounting.scoring |
AbstractModel | Confidence scoring |
account.move (inherit) |
Model | Post-action audit hook |
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)notrgba(0,0,0,0.1)
Known Issues / Future Work
read_group()deprecation warnings — migrate to_read_group()when format is documentedverify_source_deductions,generate_t4,generate_roeare stubs pointing to fusion_payroll (by design — Phase 2)account.returnmodel used in HST tools may not exist in all Odoo 19 setups — needs try/except guard- Batch approval "Approve All" / "Reject All" buttons are in the chat panel but not yet in the match history list view