This commit is contained in:
gsinghpal
2026-05-16 13:18:52 -04:00
parent 191a9c82be
commit 9ebf89bde2
1080 changed files with 0 additions and 1197 deletions

BIN
fusion_accounting/.DS_Store vendored Normal file

Binary file not shown.

Binary file not shown.

View File

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

View 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)

View 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.

View 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.

View File

@@ -0,0 +1,4 @@
from . import models
from . import controllers
from . import services
from . import wizards

View File

@@ -0,0 +1,58 @@
{
'name': 'Fusion Accounting AI',
'version': '19.0.1.1.0',
'category': 'Accounting/Accounting',
'sequence': 26,
'summary': 'AI Co-Pilot for Odoo accounting (Claude/GPT) with conversational interface, dashboard, rules.',
'description': """
Fusion Accounting AI
====================
Conversational AI co-pilot for Odoo Accounting. Embeds Claude/GPT with
native tool-calling for bank reconciliation, HST management, AR/AP analysis,
journal review, month-end close, payroll, ADP reconciliation, financial
reporting, and auditing.
Works on three install profiles via the data-adapter pattern:
1. Pure Odoo Community + fusion_accounting_ai
2. Odoo Community + fusion_accounting_ai + fusion native sub-modules (bank_rec, reports, ...)
3. Odoo Enterprise + fusion_accounting_ai (legacy mode)
Built by Nexa Systems Inc.
""",
'icon': '/fusion_accounting_ai/static/description/icon.png',
'author': 'Nexa Systems Inc.',
'website': 'https://nexasystems.ca',
'support': 'support@nexasystems.ca',
'maintainer': 'Nexa Systems Inc.',
'depends': ['fusion_accounting_core'],
'external_dependencies': {
'python': ['anthropic', 'openai'],
},
'data': [
'security/ir.model.access.csv',
'security/fusion_accounting_ai_security.xml',
'data/cron.xml',
'data/tool_definitions.xml',
'data/default_rules.xml',
'views/config_views.xml',
'views/session_views.xml',
'views/match_history_views.xml',
'views/rule_views.xml',
'views/dashboard_views.xml',
'views/vendor_tax_profile_views.xml',
'views/recurring_pattern_views.xml',
'views/menus.xml',
'wizards/rule_wizard.xml',
'report/audit_report_template.xml',
],
'installable': True,
'application': True,
'license': 'OPL-1',
'assets': {
'web.assets_backend': [
'fusion_accounting_ai/static/src/**/*.js',
'fusion_accounting_ai/static/src/**/*.xml',
'fusion_accounting_ai/static/src/**/*.scss',
],
},
}

View File

@@ -0,0 +1 @@
from . import chat_controller

View File

@@ -0,0 +1,243 @@
import json
import logging
from odoo import http
from odoo.http import request
_logger = logging.getLogger(__name__)
class FusionAccountingChatController(http.Controller):
def _check_session_ownership(self, session):
"""S1-S3: Verify the current user owns the session."""
if session.user_id.id != request.env.user.id:
# Allow managers to access any session
if not request.env.user.has_group('fusion_accounting_core.group_fusion_accounting_manager'):
return {'error': 'Access denied: you do not own this session'}
return None
@http.route('/fusion_accounting/session/create', type='jsonrpc', auth='user')
def create_session(self, context_domain=None, **kwargs):
session = request.env['fusion.accounting.session'].create({
'user_id': request.env.user.id,
'company_id': request.env.company.id,
'context_domain': context_domain,
})
return {'session_id': session.id, 'name': session.name}
@http.route('/fusion_accounting/session/close', type='jsonrpc', auth='user')
def close_session(self, session_id, **kwargs):
session = request.env['fusion.accounting.session'].browse(int(session_id))
if not session.exists():
return {'status': 'closed'}
# S2: Ownership check
error = self._check_session_ownership(session)
if error:
return error
if session.state == 'active':
session.action_close_session()
return {'status': 'closed'}
@http.route('/fusion_accounting/chat', type='jsonrpc', auth='user')
def chat(self, session_id, message, context=None, image=None, **kwargs):
if not message and not image:
return {'error': 'Message or image is required'}
# S3: Ownership check
session = request.env['fusion.accounting.session'].browse(int(session_id))
if session.exists():
error = self._check_session_ownership(session)
if error:
return error
agent = request.env['fusion.accounting.agent']
result = agent.chat(int(session_id), message or '', context=context, image=image)
return result
@http.route('/fusion_accounting/approve', type='jsonrpc', auth='user')
def approve_action(self, match_history_id, **kwargs):
if not request.env.user.has_group('fusion_accounting_core.group_fusion_accounting_manager'):
return {'error': 'Insufficient permissions to approve actions'}
agent = request.env['fusion.accounting.agent']
result = agent.approve_action(int(match_history_id))
return result
@http.route('/fusion_accounting/reject', type='jsonrpc', auth='user')
def reject_action(self, match_history_id, reason='', **kwargs):
if not request.env.user.has_group('fusion_accounting_core.group_fusion_accounting_manager'):
return {'error': 'Insufficient permissions to reject actions'}
agent = request.env['fusion.accounting.agent']
result = agent.reject_action(int(match_history_id), reason)
return result
@http.route('/fusion_accounting/dashboard/data', type='jsonrpc', auth='user')
def dashboard_data(self, **kwargs):
# E2: Wrap in try/except so dashboard doesn't return 500
try:
dashboard = request.env['fusion.accounting.dashboard'].new({
'company_id': request.env.company.id,
})
return {
'bank_recon': {'count': dashboard.bank_recon_count, 'amount': dashboard.bank_recon_amount},
'ar': {'total': dashboard.ar_total, 'overdue_count': dashboard.ar_overdue_count},
'ap': {'total': dashboard.ap_total, 'due_this_week': dashboard.ap_due_this_week},
'hst': {'balance': dashboard.hst_balance},
'audit': {'score': dashboard.audit_score, 'flags': dashboard.audit_flag_count},
'month_end': {'status': dashboard.month_end_status, 'open_items': dashboard.month_end_open_items},
# E1: Include needs_attention and recent_activity
'needs_attention': json.loads(dashboard.needs_attention_json or '[]'),
'recent_activity': json.loads(dashboard.recent_activity_json or '[]'),
}
except Exception as e:
_logger.exception("Dashboard data computation failed")
return {
'error': 'Dashboard data could not be computed',
'bank_recon': {'count': 0, 'amount': 0},
'ar': {'total': 0, 'overdue_count': 0},
'ap': {'total': 0, 'due_this_week': 0},
'hst': {'balance': 0},
'audit': {'score': 0, 'flags': 0},
'month_end': {'status': 'Unknown', 'open_items': 0},
'needs_attention': [],
'recent_activity': [],
}
@http.route('/fusion_accounting/approve_all', type='jsonrpc', auth='user')
def approve_all(self, match_history_ids, **kwargs):
if not request.env.user.has_group('fusion_accounting_core.group_fusion_accounting_manager'):
return {'error': 'Insufficient permissions to approve actions'}
agent = request.env['fusion.accounting.agent']
results = []
for mid in match_history_ids:
try:
result = agent.approve_action(int(mid))
results.append({'id': mid, 'status': 'approved', 'result': result})
except Exception as e:
# S4: Sanitize exception — log full error, return generic message
_logger.exception("Error approving match history %s", mid)
results.append({'id': mid, 'status': 'error', 'error': 'Action could not be approved. Check server logs for details.'})
return {'results': results}
@http.route('/fusion_accounting/reject_all', type='jsonrpc', auth='user')
def reject_all(self, match_history_ids, reason='', **kwargs):
if not request.env.user.has_group('fusion_accounting_core.group_fusion_accounting_manager'):
return {'error': 'Insufficient permissions to reject actions'}
agent = request.env['fusion.accounting.agent']
results = []
for mid in match_history_ids:
try:
result = agent.reject_action(int(mid), reason)
# E3: Consistent return shape with approve_all
results.append({'id': mid, 'status': 'rejected', 'result': result})
except Exception as e:
# S4: Sanitize exception
_logger.exception("Error rejecting match history %s", mid)
results.append({'id': mid, 'status': 'error', 'error': 'Action could not be rejected. Check server logs for details.'})
return {'results': results}
@http.route('/fusion_accounting/chat/status', type='jsonrpc', auth='user')
def chat_status(self, session_id, **kwargs):
"""Poll the live execution state of a running chat — returns thinking text,
tool calls in progress, and current status. Called every 500ms by the frontend
while a chat request is in flight."""
from ..services.agent import get_execution_state
state = get_execution_state(int(session_id))
return state
@http.route('/fusion_accounting/search_matches', type='jsonrpc', auth='user')
def search_matches(self, statement_line_id, query='', **kwargs):
"""Live search for matching journal items — called directly by the
reconciliation table search bar (no AI round-trip)."""
from ..services.tools.bank_reconciliation import search_matching_entries
try:
result = search_matching_entries(request.env, {
'statement_line_id': int(statement_line_id),
'query': query,
})
return result
except Exception as e:
_logger.exception("Search matches failed")
return {'candidates': [], 'error': str(e)}
@http.route('/fusion_accounting/session/list', type='jsonrpc', auth='user')
def session_list(self, limit=20, **kwargs):
"""List recent sessions for the session picker dropdown."""
sessions = request.env['fusion.accounting.session'].search([
('user_id', '=', request.env.user.id),
], order='write_date desc', limit=int(limit))
return {
'sessions': [{
'id': s.id,
'name': s.name,
'state': s.state,
'date': s.write_date.isoformat() if s.write_date else '',
'message_count': len(json.loads(s.message_ids_json or '[]')),
'ai_model': s.ai_model or '',
} for s in sessions],
}
@http.route('/fusion_accounting/session/latest', type='jsonrpc', auth='user')
def session_latest(self, **kwargs):
# Find the most recent active session that has messages first,
# fall back to any active session (including empty ones)
sessions = request.env['fusion.accounting.session'].search([
('user_id', '=', request.env.user.id),
('state', '=', 'active'),
], order='write_date desc', limit=10)
if not sessions:
return {'session_id': None, 'messages': [], 'name': None}
# Prefer a session with actual messages
session = None
for s in sessions:
msg_json = s.message_ids_json or '[]'
if msg_json != '[]' and len(msg_json) > 5:
session = s
break
# If no session has messages, use the newest one
if not session:
session = sessions[0]
# Clean up empty stale sessions (created but never used)
for s in sessions:
if s.id != session.id and (s.message_ids_json or '[]') == '[]':
s.write({'state': 'closed'})
messages = json.loads(session.message_ids_json or '[]')
display_messages = []
for msg in messages:
if isinstance(msg.get('content'), str) and msg['content'].strip():
display_messages.append(msg)
elif isinstance(msg.get('content'), list):
for block in msg['content']:
if isinstance(block, dict) and block.get('type') == 'text' and block['text'].strip():
display_messages.append({'role': msg['role'], 'content': block['text']})
# Include any pending approvals so they show on page load
agent = request.env['fusion.accounting.agent']
pending = request.env['fusion.accounting.match.history'].search([
('session_id', '=', session.id),
('decision', '=', 'pending'),
])
pending_approvals = [agent._format_pending_approval(p) for p in pending]
return {
'session_id': session.id,
'messages': display_messages,
'name': session.name,
'pending_approvals': pending_approvals,
}
@http.route('/fusion_accounting/session/history', type='jsonrpc', auth='user')
def session_history(self, session_id, **kwargs):
session = request.env['fusion.accounting.session'].browse(int(session_id))
if not session.exists():
return {'error': 'Session not found'}
# S1: Ownership check
error = self._check_session_ownership(session)
if error:
return error
return {
'messages': json.loads(session.message_ids_json or '[]'),
'session_id': session.id,
'state': session.state,
}

View File

@@ -0,0 +1,83 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo noupdate="1">
<!-- Session name sequence -->
<record id="seq_fusion_accounting_session" model="ir.sequence">
<field name="name">Fusion AI Session</field>
<field name="code">fusion.accounting.session</field>
<field name="prefix">FAS/%(year)s/</field>
<field name="padding">5</field>
</record>
<!-- Daily audit scan: expire stale pending approvals -->
<record id="cron_fusion_audit_scan" model="ir.cron">
<field name="name">Fusion AI: Periodic Audit Scan</field>
<field name="model_id" ref="model_fusion_accounting_match_history"/>
<field name="state">code</field>
<field name="code">
cutoff = datetime.datetime.now() - datetime.timedelta(days=30)
stale = model.search([('decision', '=', 'pending'), ('proposed_at', '&lt;', cutoff.strftime('%Y-%m-%d %H:%M:%S'))])
stale.write({'decision': 'rejected', 'rejection_reason': 'Auto-expired after 30 days'})
</field>
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="active">True</field>
</record>
<!-- Weekly tier promotion check -->
<record id="cron_fusion_tier_promotion" model="ir.cron">
<field name="name">Fusion AI: Tier Promotion Check</field>
<field name="model_id" ref="model_fusion_accounting_rule"/>
<field name="state">code</field>
<field name="code">
for rule in model.search([('active', '=', True), ('approval_tier', '=', 'needs_approval')]):
rule._check_promotion()
</field>
<field name="interval_number">7</field>
<field name="interval_type">days</field>
<field name="active">True</field>
</record>
<!-- Weekly recurring pattern rebuild -->
<record id="cron_fusion_recurring_patterns" model="ir.cron">
<field name="name">Fusion AI: Rebuild Recurring Patterns</field>
<field name="model_id" ref="model_fusion_recurring_pattern"/>
<field name="state">code</field>
<field name="code">model._rebuild_all_patterns(min_occurrences=3)</field>
<field name="interval_number">7</field>
<field name="interval_type">days</field>
<field name="active">True</field>
</record>
<!-- Daily auto-reconcile inter-account transfers (CC payments) -->
<record id="cron_fusion_transfer_reconcile" model="ir.cron">
<field name="name">Fusion AI: Auto-Reconcile Inter-Account Transfers</field>
<field name="model_id" ref="model_fusion_accounting_agent"/>
<field name="state">code</field>
<field name="code">model._cron_reconcile_transfers()</field>
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="active">True</field>
</record>
<!-- Daily auto-reconcile payroll cheques against open liability entries -->
<record id="cron_fusion_payroll_cheque_reconcile" model="ir.cron">
<field name="name">Fusion AI: Reconcile Payroll Cheques</field>
<field name="model_id" ref="model_fusion_accounting_agent"/>
<field name="state">code</field>
<field name="code">model._reconcile_payroll_cheques()</field>
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="active">True</field>
</record>
<!-- Weekly vendor tax profile rebuild -->
<record id="cron_fusion_vendor_profiles" model="ir.cron">
<field name="name">Fusion AI: Rebuild Vendor Tax Profiles</field>
<field name="model_id" ref="model_fusion_vendor_tax_profile"/>
<field name="state">code</field>
<field name="code">model._rebuild_all_profiles(min_bills=3)</field>
<field name="interval_number">7</field>
<field name="interval_type">days</field>
<field name="active">True</field>
</record>
</odoo>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo noupdate="1">
<record id="rule_elavon_fee" model="fusion.accounting.rule">
<field name="name">Elavon Card Processing Fee</field>
<field name="rule_type">fee</field>
<field name="description">Elavon merchant service charges typically show as a fee deducted from card payment batches. The fee is approximately 1.5-1.8% of the gross batch amount and should be allocated to the Elavon Fee expense account.</field>
<field name="match_logic">When a bank statement line contains "elavon" or "mrch svc" and the amount is less than the sum of matching card payments, allocate the difference to the fee account as a processing fee.</field>
<field name="created_by">admin</field>
<field name="approval_tier">needs_approval</field>
<field name="sequence">10</field>
</record>
<record id="rule_weekend_batch" model="fusion.accounting.rule">
<field name="name">Weekend Card Batch Combination</field>
<field name="rule_type">match</field>
<field name="description">Card payment batches deposited on Monday often combine Friday, Saturday, and Sunday transactions. When matching Monday bank deposits to card payments, look across the preceding weekend.</field>
<field name="match_logic">For bank lines dated Monday with card-related labels, sum card payments from the preceding Friday through Sunday to find a match.</field>
<field name="created_by">admin</field>
<field name="approval_tier">needs_approval</field>
<field name="sequence">20</field>
</record>
</odoo>

View File

@@ -0,0 +1,837 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo noupdate="1">
<!-- Domain 1: Bank Reconciliation -->
<record id="tool_get_unreconciled_bank_lines" model="fusion.accounting.tool">
<field name="name">get_unreconciled_bank_lines</field>
<field name="display_name_field">Get Unreconciled Bank Lines</field>
<field name="description">List unreconciled bank statement lines with optional filters for journal, date range, and minimum amount.</field>
<field name="domain">bank_reconciliation</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"journal_id": {"type": "integer", "description": "Journal ID to filter by"}, "date_from": {"type": "string", "description": "Start date (YYYY-MM-DD)"}, "date_to": {"type": "string", "description": "End date (YYYY-MM-DD)"}, "min_amount": {"type": "number", "description": "Minimum absolute amount"}, "limit": {"type": "integer", "description": "Max records to return", "default": 50}}}</field>
<field name="odoo_method">account.bank.statement.line.search_read</field>
</record>
<record id="tool_get_unreconciled_receipts" model="fusion.accounting.tool">
<field name="name">get_unreconciled_receipts</field>
<field name="display_name_field">Get Unreconciled Receipts</field>
<field name="description">List unreconciled Outstanding Receipts entries on the specified account (default 1122).</field>
<field name="domain">bank_reconciliation</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"account_code": {"type": "string", "description": "Account code prefix", "default": "1122"}}}</field>
</record>
<record id="tool_match_bank_line_to_payments" model="fusion.accounting.tool">
<field name="name">match_bank_line_to_payments</field>
<field name="display_name_field">Match Bank Line to Payments</field>
<field name="description">Match a bank statement line to one or more payment journal items for reconciliation.</field>
<field name="domain">bank_reconciliation</field>
<field name="tier">3</field>
<field name="parameters_schema">{"type": "object", "properties": {"statement_line_id": {"type": "integer", "description": "Bank statement line ID"}, "move_line_ids": {"type": "array", "items": {"type": "integer"}, "description": "Journal item IDs to match"}}, "required": ["statement_line_id", "move_line_ids"]}</field>
<field name="required_groups">fusion_accounting_core.group_fusion_accounting_manager</field>
</record>
<record id="tool_auto_reconcile_bank_lines" model="fusion.accounting.tool">
<field name="name">auto_reconcile_bank_lines</field>
<field name="display_name_field">Auto-Reconcile Bank Lines</field>
<field name="description">Run Odoo's built-in auto-reconciliation engine on all unreconciled bank statement lines.</field>
<field name="domain">bank_reconciliation</field>
<field name="tier">3</field>
<field name="parameters_schema">{"type": "object", "properties": {"company_id": {"type": "integer"}}}</field>
<field name="required_groups">fusion_accounting_core.group_fusion_accounting_manager</field>
</record>
<record id="tool_apply_reconcile_model" model="fusion.accounting.tool">
<field name="name">apply_reconcile_model</field>
<field name="display_name_field">Apply Reconciliation Model</field>
<field name="description">Apply a specific reconciliation model to a bank statement line.</field>
<field name="domain">bank_reconciliation</field>
<field name="tier">3</field>
<field name="parameters_schema">{"type": "object", "properties": {"model_id": {"type": "integer"}, "statement_line_id": {"type": "integer"}}, "required": ["model_id", "statement_line_id"]}</field>
<field name="required_groups">fusion_accounting_core.group_fusion_accounting_manager</field>
</record>
<record id="tool_unmatch_bank_line" model="fusion.accounting.tool">
<field name="name">unmatch_bank_line</field>
<field name="display_name_field">Unmatch Bank Line</field>
<field name="description">Undo a bank statement line reconciliation.</field>
<field name="domain">bank_reconciliation</field>
<field name="tier">3</field>
<field name="parameters_schema">{"type": "object", "properties": {"statement_line_id": {"type": "integer"}}, "required": ["statement_line_id"]}</field>
<field name="required_groups">fusion_accounting_core.group_fusion_accounting_manager</field>
</record>
<record id="tool_get_reconcile_suggestions" model="fusion.accounting.tool">
<field name="name">get_reconcile_suggestions</field>
<field name="display_name_field">Get Reconciliation Suggestions</field>
<field name="description">Get available reconciliation models for a bank statement line.</field>
<field name="domain">bank_reconciliation</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"statement_line_id": {"type": "integer"}}, "required": ["statement_line_id"]}</field>
</record>
<record id="tool_sum_payments_by_date" model="fusion.accounting.tool">
<field name="name">sum_payments_by_date</field>
<field name="display_name_field">Sum Payments by Date</field>
<field name="description">Sum payment journal items for a date range. IMPORTANT: You MUST pass journal_ids to filter to specific journals (e.g., the card/POS journal). Without journal_ids, returns totals across ALL company journals which will be misleadingly large. Use this to verify card batch deposit amounts against the card payment journal for the prior business day.</field>
<field name="domain">bank_reconciliation</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"date_from": {"type": "string"}, "date_to": {"type": "string"}, "journal_ids": {"type": "array", "items": {"type": "integer"}}}, "required": ["date_from", "date_to"]}</field>
</record>
<!-- Domain 2: HST/GST Management -->
<record id="tool_calculate_hst_balance" model="fusion.accounting.tool">
<field name="name">calculate_hst_balance</field>
<field name="display_name_field">Calculate HST Balance</field>
<field name="description">Calculate net HST position (collected minus ITCs) for a period.</field>
<field name="domain">hst_management</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"date_from": {"type": "string"}, "date_to": {"type": "string"}}}</field>
</record>
<record id="tool_get_tax_report" model="fusion.accounting.tool">
<field name="name">get_tax_report</field>
<field name="display_name_field">Get Tax Report</field>
<field name="description">Generate a tax report for a period using Odoo's reporting engine.</field>
<field name="domain">hst_management</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"date_from": {"type": "string"}, "date_to": {"type": "string"}, "report_ref": {"type": "string", "default": "account.generic_tax_report"}}}</field>
</record>
<record id="tool_find_missing_tax_invoices" model="fusion.accounting.tool">
<field name="name">find_missing_tax_invoices</field>
<field name="display_name_field">Find Missing Tax Invoices</field>
<field name="description">Find customer invoices with taxable products but no tax applied.</field>
<field name="domain">hst_management</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"date_from": {"type": "string"}, "date_to": {"type": "string"}}}</field>
</record>
<record id="tool_find_missing_itc_bills" model="fusion.accounting.tool">
<field name="name">find_missing_itc_bills</field>
<field name="display_name_field">Find Missing ITC Bills</field>
<field name="description">Find vendor bills without input tax credits.</field>
<field name="domain">hst_management</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"date_from": {"type": "string"}, "date_to": {"type": "string"}}}</field>
</record>
<record id="tool_get_tax_return_status" model="fusion.accounting.tool">
<field name="name">get_tax_return_status</field>
<field name="display_name_field">Get Tax Return Status</field>
<field name="description">Check the status of periodic tax returns.</field>
<field name="domain">hst_management</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {}}</field>
</record>
<record id="tool_generate_tax_return" model="fusion.accounting.tool">
<field name="name">generate_tax_return</field>
<field name="display_name_field">Generate Tax Return</field>
<field name="description">Refresh all tax return data.</field>
<field name="domain">hst_management</field>
<field name="tier">2</field>
<field name="parameters_schema">{"type": "object", "properties": {}}</field>
<field name="required_groups">fusion_accounting_core.group_fusion_accounting_manager</field>
</record>
<record id="tool_validate_tax_return" model="fusion.accounting.tool">
<field name="name">validate_tax_return</field>
<field name="display_name_field">Validate Tax Return</field>
<field name="description">Mark a tax return as validated.</field>
<field name="domain">hst_management</field>
<field name="tier">3</field>
<field name="parameters_schema">{"type": "object", "properties": {"return_id": {"type": "integer"}}, "required": ["return_id"]}</field>
<field name="required_groups">fusion_accounting_core.group_fusion_accounting_manager</field>
</record>
<!-- Domain 3: Accounts Receivable -->
<record id="tool_get_ar_aging" model="fusion.accounting.tool">
<field name="name">get_ar_aging</field>
<field name="display_name_field">Get AR Aging</field>
<field name="description">Get accounts receivable aging buckets (current, 30, 60, 90+ days).</field>
<field name="domain">accounts_receivable</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {}}</field>
</record>
<record id="tool_get_overdue_invoices" model="fusion.accounting.tool">
<field name="name">get_overdue_invoices</field>
<field name="display_name_field">Get Overdue Invoices</field>
<field name="description">List invoices past due with partner contact information.</field>
<field name="domain">accounts_receivable</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"min_days_overdue": {"type": "integer", "default": 1}, "limit": {"type": "integer", "default": 50}}}</field>
</record>
<record id="tool_get_partner_balance" model="fusion.accounting.tool">
<field name="name">get_partner_balance</field>
<field name="display_name_field">Get Partner Balance</field>
<field name="description">[Tier 1: Read-only] Get a partner's AR and AP balance with open items. Shows: how much they owe us (receivable), how much we owe them (payable), and net balance. Use for "how much do we owe Pride Mobility?", "what's the balance for ADP?".</field>
<field name="domain">accounts_receivable</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"partner_id": {"type": "integer", "description": "Partner ID (optional if partner_name provided)"}, "partner_name": {"type": "string", "description": "Partner name to search for (e.g. 'Pride Mobility')"}}}</field>
</record>
<record id="tool_send_followup" model="fusion.accounting.tool">
<field name="name">send_followup</field>
<field name="display_name_field">Send Follow-Up</field>
<field name="description">Draft and send a follow-up email to a partner about overdue invoices.</field>
<field name="domain">accounts_receivable</field>
<field name="tier">2</field>
<field name="parameters_schema">{"type": "object", "properties": {"partner_id": {"type": "integer"}, "send_email": {"type": "boolean"}, "print_letter": {"type": "boolean"}, "email_subject": {"type": "string"}, "body": {"type": "string"}}, "required": ["partner_id"]}</field>
<field name="required_groups">fusion_accounting_core.group_fusion_accounting_manager</field>
</record>
<record id="tool_get_followup_report" model="fusion.accounting.tool">
<field name="name">get_followup_report</field>
<field name="display_name_field">Get Follow-Up Report</field>
<field name="description">Get the HTML follow-up report for a partner.</field>
<field name="domain">accounts_receivable</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"partner_id": {"type": "integer"}}, "required": ["partner_id"]}</field>
</record>
<record id="tool_reconcile_payment_to_invoice" model="fusion.accounting.tool">
<field name="name">reconcile_payment_to_invoice</field>
<field name="display_name_field">Reconcile Payment to Invoice</field>
<field name="description">Match a payment to an invoice by reconciling journal items.</field>
<field name="domain">accounts_receivable</field>
<field name="tier">3</field>
<field name="parameters_schema">{"type": "object", "properties": {"move_line_ids": {"type": "array", "items": {"type": "integer"}}}, "required": ["move_line_ids"]}</field>
<field name="required_groups">fusion_accounting_core.group_fusion_accounting_manager</field>
</record>
<record id="tool_get_unmatched_payments" model="fusion.accounting.tool">
<field name="name">get_unmatched_payments</field>
<field name="display_name_field">Get Unmatched Payments</field>
<field name="description">List payments not matched to invoices.</field>
<field name="domain">accounts_receivable</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {}}</field>
</record>
<!-- Domain 4: Accounts Payable -->
<record id="tool_get_ap_aging" model="fusion.accounting.tool">
<field name="name">get_ap_aging</field>
<field name="display_name_field">Get AP Aging</field>
<field name="description">Get accounts payable aging buckets.</field>
<field name="domain">accounts_payable</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {}}</field>
</record>
<record id="tool_find_duplicate_bills" model="fusion.accounting.tool">
<field name="name">find_duplicate_bills</field>
<field name="display_name_field">Find Duplicate Bills</field>
<field name="description">Detect potential duplicate vendor bills (same vendor + amount + date within window).</field>
<field name="domain">accounts_payable</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"window_days": {"type": "integer", "default": 7}}}</field>
</record>
<record id="tool_match_bill_to_po" model="fusion.accounting.tool">
<field name="name">match_bill_to_po</field>
<field name="display_name_field">Match Bill to PO</field>
<field name="description">Cross-reference bill lines to purchase order lines.</field>
<field name="domain">accounts_payable</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"bill_id": {"type": "integer"}}, "required": ["bill_id"]}</field>
</record>
<record id="tool_get_unpaid_bills" model="fusion.accounting.tool">
<field name="name">get_unpaid_bills</field>
<field name="display_name_field">Get Unpaid Bills</field>
<field name="description">List vendor bills with outstanding balance.</field>
<field name="domain">accounts_payable</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"partner_id": {"type": "integer"}, "limit": {"type": "integer", "default": 50}}}</field>
</record>
<record id="tool_verify_bill_taxes" model="fusion.accounting.tool">
<field name="name">verify_bill_taxes</field>
<field name="display_name_field">Verify Bill Taxes</field>
<field name="description">Check that bill tax matches fiscal position expectation.</field>
<field name="domain">accounts_payable</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"bill_id": {"type": "integer"}}, "required": ["bill_id"]}</field>
</record>
<record id="tool_get_payment_schedule" model="fusion.accounting.tool">
<field name="name">get_payment_schedule</field>
<field name="display_name_field">Get Payment Schedule</field>
<field name="description">Bills sorted by due date for cash planning.</field>
<field name="domain">accounts_payable</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"days_ahead": {"type": "integer", "default": 30}}}</field>
</record>
<!-- Domain 5: Journal Review -->
<record id="tool_find_wrong_direction_balances" model="fusion.accounting.tool">
<field name="name">find_wrong_direction_balances</field>
<field name="display_name_field">Find Wrong Direction Balances</field>
<field name="description">Find accounts where balance direction contradicts account type.</field>
<field name="domain">journal_review</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {}}</field>
</record>
<record id="tool_find_duplicate_entries" model="fusion.accounting.tool">
<field name="name">find_duplicate_entries</field>
<field name="display_name_field">Find Duplicate Entries</field>
<field name="description">Detect entries with matching partner + amount + date + journal.</field>
<field name="domain">journal_review</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"date_from": {"type": "string"}, "date_to": {"type": "string"}}}</field>
</record>
<record id="tool_find_wrong_account_entries" model="fusion.accounting.tool">
<field name="name">find_wrong_account_entries</field>
<field name="display_name_field">Find Wrong Account Entries</field>
<field name="description">Product lines on unlikely accounts (e.g., revenue on tax account).</field>
<field name="domain">journal_review</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"date_from": {"type": "string"}, "date_to": {"type": "string"}}}</field>
</record>
<record id="tool_find_sequence_gaps" model="fusion.accounting.tool">
<field name="name">find_sequence_gaps</field>
<field name="display_name_field">Find Sequence Gaps</field>
<field name="description">Find journal entries where made_sequence_gap is true.</field>
<field name="domain">journal_review</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {}}</field>
</record>
<record id="tool_find_draft_entries" model="fusion.accounting.tool">
<field name="name">find_draft_entries</field>
<field name="display_name_field">Find Draft Entries</field>
<field name="description">Draft entries older than specified days that should be posted or deleted.</field>
<field name="domain">journal_review</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"min_age_days": {"type": "integer", "default": 30}}}</field>
</record>
<record id="tool_find_unreconciled_suspense" model="fusion.accounting.tool">
<field name="name">find_unreconciled_suspense</field>
<field name="display_name_field">Find Unreconciled Suspense</field>
<field name="description">Suspense/clearing accounts with non-zero balance.</field>
<field name="domain">journal_review</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {}}</field>
</record>
<record id="tool_verify_reconciliation_integrity" model="fusion.accounting.tool">
<field name="name">verify_reconciliation_integrity</field>
<field name="display_name_field">Verify Reconciliation Integrity</field>
<field name="description">Check account.partial.reconcile consistency.</field>
<field name="domain">journal_review</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {}}</field>
</record>
<!-- Domain 6: Month-End -->
<record id="tool_get_close_checklist" model="fusion.accounting.tool">
<field name="name">get_close_checklist</field>
<field name="display_name_field">Get Close Checklist</field>
<field name="description">Aggregate all domain checks into a period close checklist.</field>
<field name="domain">month_end</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"period": {"type": "string", "description": "YYYY-MM format"}}}</field>
</record>
<record id="tool_get_unreconciled_counts" model="fusion.accounting.tool">
<field name="name">get_unreconciled_counts</field>
<field name="display_name_field">Get Unreconciled Counts</field>
<field name="description">Per-account count of unreconciled items.</field>
<field name="domain">month_end</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {}}</field>
</record>
<record id="tool_find_entries_in_locked_period" model="fusion.accounting.tool">
<field name="name">find_entries_in_locked_period</field>
<field name="display_name_field">Find Entries in Locked Period</field>
<field name="description">Find entries after lock dates.</field>
<field name="domain">month_end</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {}}</field>
</record>
<record id="tool_get_accrual_status" model="fusion.accounting.tool">
<field name="name">get_accrual_status</field>
<field name="display_name_field">Get Accrual Status</field>
<field name="description">Balance on accrual accounts (vacation, sick, etc.).</field>
<field name="domain">month_end</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"account_codes": {"type": "array", "items": {"type": "string"}}}}</field>
</record>
<record id="tool_run_hash_integrity_check" model="fusion.accounting.tool">
<field name="name">run_hash_integrity_check</field>
<field name="display_name_field">Run Hash Integrity Check</field>
<field name="description">Verify journal entry hash chain integrity.</field>
<field name="domain">month_end</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {}}</field>
</record>
<record id="tool_get_period_summary" model="fusion.accounting.tool">
<field name="name">get_period_summary</field>
<field name="display_name_field">Get Period Summary</field>
<field name="description">Trial balance for the closing period.</field>
<field name="domain">month_end</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"date_from": {"type": "string"}, "date_to": {"type": "string"}}, "required": ["date_from", "date_to"]}</field>
</record>
<!-- Domain 7: Payroll Verification -->
<record id="tool_get_payroll_entries" model="fusion.accounting.tool">
<field name="name">get_payroll_entries</field>
<field name="display_name_field">Get Payroll Entries</field>
<field name="description">Journal entries in payroll-related journals.</field>
<field name="domain">payroll_verification</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"date_from": {"type": "string"}, "date_to": {"type": "string"}, "journal_id": {"type": "integer"}}}</field>
</record>
<record id="tool_compare_payroll_to_bank" model="fusion.accounting.tool">
<field name="name">compare_payroll_to_bank</field>
<field name="display_name_field">Compare Payroll to Bank</field>
<field name="description">Cross-reference payroll cheques to bank statement lines.</field>
<field name="domain">payroll_verification</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"date_from": {"type": "string"}, "date_to": {"type": "string"}}, "required": ["date_from", "date_to"]}</field>
</record>
<record id="tool_verify_source_deductions" model="fusion.accounting.tool">
<field name="name">verify_source_deductions</field>
<field name="display_name_field">Verify Source Deductions</field>
<field name="description">CPP + EI + tax calculation verification against CRA tables.</field>
<field name="domain">payroll_verification</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {}}</field>
</record>
<record id="tool_get_cra_remittance_status" model="fusion.accounting.tool">
<field name="name">get_cra_remittance_status</field>
<field name="display_name_field">Get CRA Remittance Status</field>
<field name="description">CRA payable balance vs payments made.</field>
<field name="domain">payroll_verification</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {}}</field>
</record>
<record id="tool_find_unmatched_payroll_cheques" model="fusion.accounting.tool">
<field name="name">find_unmatched_payroll_cheques</field>
<field name="display_name_field">Find Unmatched Payroll Cheques</field>
<field name="description">Bank cheques without matching payroll entry.</field>
<field name="domain">payroll_verification</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {}}</field>
</record>
<!-- Domain 8: Inventory -->
<record id="tool_get_stock_valuation" model="fusion.accounting.tool">
<field name="name">get_stock_valuation</field>
<field name="display_name_field">Get Stock Valuation</field>
<field name="description">Stock In Hand balance and layers.</field>
<field name="domain">inventory</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {}}</field>
</record>
<record id="tool_get_price_differences" model="fusion.accounting.tool">
<field name="name">get_price_differences</field>
<field name="display_name_field">Get Price Differences</field>
<field name="description">Entries on price difference account (PO price vs bill price).</field>
<field name="domain">inventory</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"date_from": {"type": "string"}, "date_to": {"type": "string"}}}</field>
</record>
<record id="tool_get_cogs_ratio_by_category" model="fusion.accounting.tool">
<field name="name">get_cogs_ratio_by_category</field>
<field name="display_name_field">Get COGS Ratio</field>
<field name="description">COGS vs revenue per product category.</field>
<field name="domain">inventory</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"date_from": {"type": "string"}, "date_to": {"type": "string"}}}</field>
</record>
<record id="tool_find_unusual_adjustments" model="fusion.accounting.tool">
<field name="name">find_unusual_adjustments</field>
<field name="display_name_field">Find Unusual Adjustments</field>
<field name="description">Large inventory adjustment entries.</field>
<field name="domain">inventory</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"threshold": {"type": "number", "default": 1000}}}</field>
</record>
<record id="tool_get_inventory_turnover" model="fusion.accounting.tool">
<field name="name">get_inventory_turnover</field>
<field name="display_name_field">Get Inventory Turnover</field>
<field name="description">Sales vs average inventory calculation.</field>
<field name="domain">inventory</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"date_from": {"type": "string"}, "date_to": {"type": "string"}}}</field>
</record>
<!-- Domain 9: ADP -->
<record id="tool_get_adp_receivable_aging" model="fusion.accounting.tool">
<field name="name">get_adp_receivable_aging</field>
<field name="display_name_field">Get ADP Receivable Aging</field>
<field name="description">Aging on ADP Receivable account (1101).</field>
<field name="domain">adp</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {}}</field>
</record>
<record id="tool_match_adp_payment_to_invoice" model="fusion.accounting.tool">
<field name="name">match_adp_payment_to_invoice</field>
<field name="display_name_field">Match ADP Payment to Invoice</field>
<field name="description">Match ADP deposit to ADP invoices.</field>
<field name="domain">adp</field>
<field name="tier">3</field>
<field name="parameters_schema">{"type": "object", "properties": {"move_line_ids": {"type": "array", "items": {"type": "integer"}}}, "required": ["move_line_ids"]}</field>
<field name="required_groups">fusion_accounting_core.group_fusion_accounting_manager</field>
</record>
<record id="tool_verify_adp_split" model="fusion.accounting.tool">
<field name="name">verify_adp_split</field>
<field name="display_name_field">Verify ADP Split</field>
<field name="description">Check customer + ADP portion = invoice total.</field>
<field name="domain">adp</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"invoice_id": {"type": "integer"}}, "required": ["invoice_id"]}</field>
</record>
<record id="tool_find_adp_without_payment" model="fusion.accounting.tool">
<field name="name">find_adp_without_payment</field>
<field name="display_name_field">Find ADP Without Payment</field>
<field name="description">ADP invoices without matching government deposit.</field>
<field name="domain">adp</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {}}</field>
</record>
<record id="tool_get_adp_summary" model="fusion.accounting.tool">
<field name="name">get_adp_summary</field>
<field name="display_name_field">Get ADP Summary</field>
<field name="description">Period summary of ADP billing vs collection.</field>
<field name="domain">adp</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"date_from": {"type": "string"}, "date_to": {"type": "string"}}}</field>
</record>
<record id="tool_register_adp_batch_payment" model="fusion.accounting.tool">
<field name="name">register_adp_batch_payment</field>
<field name="display_name_field">Register ADP Batch Payment</field>
<field name="description">[Tier 3: Requires user approval] Register payments for a batch of ADP invoices from a remittance advice. Takes a list of invoice numbers with payment amounts and a payment date. Registers each payment via Odoo's payment wizard, creating outstanding receipt entries (PBNK2) on account 1050. After this, use suggest_bank_line_matches on the bank deposit to match the outstanding receipts. Use this when the user uploads an ADP remittance advice screenshot and says "mark these paid".</field>
<field name="domain">adp</field>
<field name="tier">3</field>
<field name="parameters_schema">{"type": "object", "properties": {"invoices": {"type": "array", "items": {"type": "object", "properties": {"invoice_number": {"type": "string"}, "amount": {"type": "number"}}, "required": ["invoice_number", "amount"]}, "description": "List of invoices with number and payment amount"}, "payment_date": {"type": "string", "description": "Payment date from remittance (YYYY-MM-DD)"}, "journal_id": {"type": "integer", "description": "Bank journal ID (default 50 = Scotia Current)"}}, "required": ["invoices", "payment_date"]}</field>
<field name="required_groups">fusion_accounting_core.group_fusion_accounting_manager</field>
</record>
<!-- Domain 10: Reporting -->
<record id="tool_get_profit_loss" model="fusion.accounting.tool">
<field name="name">get_profit_loss</field>
<field name="display_name_field">Get Profit &amp; Loss</field>
<field name="description">Generate P&amp;L report for a period.</field>
<field name="domain">reporting</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"date_from": {"type": "string"}, "date_to": {"type": "string"}}}</field>
</record>
<record id="tool_get_balance_sheet" model="fusion.accounting.tool">
<field name="name">get_balance_sheet</field>
<field name="display_name_field">Get Balance Sheet</field>
<field name="description">Generate balance sheet report.</field>
<field name="domain">reporting</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"date_from": {"type": "string"}, "date_to": {"type": "string"}}}</field>
</record>
<record id="tool_get_trial_balance" model="fusion.accounting.tool">
<field name="name">get_trial_balance</field>
<field name="display_name_field">Get Trial Balance</field>
<field name="description">Generate trial balance report.</field>
<field name="domain">reporting</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"date_from": {"type": "string"}, "date_to": {"type": "string"}}}</field>
</record>
<record id="tool_get_cash_flow" model="fusion.accounting.tool">
<field name="name">get_cash_flow</field>
<field name="display_name_field">Get Cash Flow</field>
<field name="description">Generate cash flow statement.</field>
<field name="domain">reporting</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"date_from": {"type": "string"}, "date_to": {"type": "string"}}}</field>
</record>
<record id="tool_compare_periods" model="fusion.accounting.tool">
<field name="name">compare_periods</field>
<field name="display_name_field">Compare Periods</field>
<field name="description">Two period reports side by side for comparison.</field>
<field name="domain">reporting</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"report_ref": {"type": "string"}, "period1_from": {"type": "string"}, "period1_to": {"type": "string"}, "period2_from": {"type": "string"}, "period2_to": {"type": "string"}}, "required": ["period1_from", "period1_to", "period2_from", "period2_to"]}</field>
</record>
<record id="tool_answer_financial_question" model="fusion.accounting.tool">
<field name="name">answer_financial_question</field>
<field name="display_name_field">Answer Financial Question</field>
<field name="description">Natural language to report query for financial questions.</field>
<field name="domain">reporting</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"question": {"type": "string"}}, "required": ["question"]}</field>
</record>
<record id="tool_export_report" model="fusion.accounting.tool">
<field name="name">export_report</field>
<field name="display_name_field">Export Report</field>
<field name="description">Export a report to PDF or XLSX.</field>
<field name="domain">reporting</field>
<field name="tier">2</field>
<field name="parameters_schema">{"type": "object", "properties": {"report_ref": {"type": "string"}, "format": {"type": "string", "enum": ["pdf", "xlsx"]}, "date_from": {"type": "string"}, "date_to": {"type": "string"}}, "required": ["report_ref"]}</field>
<field name="required_groups">fusion_accounting_core.group_fusion_accounting_manager</field>
</record>
<record id="tool_get_invoicing_summary" model="fusion.accounting.tool">
<field name="name">get_invoicing_summary</field>
<field name="display_name_field">Get Invoicing Summary</field>
<field name="description">[Tier 1: Read-only] Get customer invoicing summary — monthly breakdown for a year, date range totals, or filtered by partner. Use this for questions like "how much did we invoice this year?", "show me invoicing by month", "how much did we bill ADP this quarter?".</field>
<field name="domain">reporting</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"year": {"type": "integer", "description": "Year for monthly breakdown (default: current year)"}, "partner_name": {"type": "string", "description": "Filter by partner name (optional)"}, "date_from": {"type": "string", "description": "Start date for date range (YYYY-MM-DD)"}, "date_to": {"type": "string", "description": "End date for date range (YYYY-MM-DD)"}}}</field>
</record>
<record id="tool_get_billing_summary" model="fusion.accounting.tool">
<field name="name">get_billing_summary</field>
<field name="display_name_field">Get Billing Summary</field>
<field name="description">[Tier 1: Read-only] Get vendor billing (purchases) summary — monthly breakdown for a year or date range. Use for "how much are our bills this month?", "show me vendor bills by month".</field>
<field name="domain">reporting</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"year": {"type": "integer"}, "partner_name": {"type": "string"}, "date_from": {"type": "string"}, "date_to": {"type": "string"}}}</field>
</record>
<record id="tool_get_collections_summary" model="fusion.accounting.tool">
<field name="name">get_collections_summary</field>
<field name="display_name_field">Get Collections Summary</field>
<field name="description">[Tier 1: Read-only] Get payment collections summary — how much was collected (customer payments received) in a period, broken down by partner. Use for "how much are we collecting this month?", "show me collections for March".</field>
<field name="domain">reporting</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"date_from": {"type": "string"}, "date_to": {"type": "string"}}}</field>
</record>
<!-- Domain 11: Audit -->
<record id="tool_audit_posted_entry" model="fusion.accounting.tool">
<field name="name">audit_posted_entry</field>
<field name="display_name_field">Audit Posted Entry</field>
<field name="description">Run all entry-level checks on a single journal entry.</field>
<field name="domain">audit</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"move_id": {"type": "integer"}}, "required": ["move_id"]}</field>
</record>
<record id="tool_audit_account_balances" model="fusion.accounting.tool">
<field name="name">audit_account_balances</field>
<field name="display_name_field">Audit Account Balances</field>
<field name="description">Run all account-level checks (wrong direction, stale items).</field>
<field name="domain">audit</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {}}</field>
</record>
<record id="tool_audit_tax_compliance" model="fusion.accounting.tool">
<field name="name">audit_tax_compliance</field>
<field name="display_name_field">Audit Tax Compliance</field>
<field name="description">All tax checks (missing tax, wrong rate, exempt verification).</field>
<field name="domain">audit</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"date_from": {"type": "string"}, "date_to": {"type": "string"}}}</field>
</record>
<record id="tool_audit_reconciliation_integrity" model="fusion.accounting.tool">
<field name="name">audit_reconciliation_integrity</field>
<field name="display_name_field">Audit Reconciliation Integrity</field>
<field name="description">Verify partial/full reconcile consistency.</field>
<field name="domain">audit</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {}}</field>
</record>
<record id="tool_check_hash_chain" model="fusion.accounting.tool">
<field name="name">check_hash_chain</field>
<field name="display_name_field">Check Hash Chain</field>
<field name="description">Verify journal entry hash chain integrity.</field>
<field name="domain">audit</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {}}</field>
</record>
<record id="tool_check_sequence_gaps" model="fusion.accounting.tool">
<field name="name">check_sequence_gaps</field>
<field name="display_name_field">Check Sequence Gaps</field>
<field name="description">Check for sequence gaps in journals.</field>
<field name="domain">audit</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {}}</field>
</record>
<record id="tool_flag_entry" model="fusion.accounting.tool">
<field name="name">flag_entry</field>
<field name="display_name_field">Flag Entry</field>
<field name="description">Create a chatter note on a journal entry with flag and recommendation.</field>
<field name="domain">audit</field>
<field name="tier">2</field>
<field name="parameters_schema">{"type": "object", "properties": {"move_id": {"type": "integer"}, "flag": {"type": "string"}, "recommendation": {"type": "string"}}, "required": ["move_id"]}</field>
<field name="required_groups">fusion_accounting_core.group_fusion_accounting_manager</field>
</record>
<record id="tool_get_audit_status" model="fusion.accounting.tool">
<field name="name">get_audit_status</field>
<field name="display_name_field">Get Audit Status</field>
<field name="description">Account audit status per tax return.</field>
<field name="domain">audit</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {}}</field>
</record>
<record id="tool_set_audit_status" model="fusion.accounting.tool">
<field name="name">set_audit_status</field>
<field name="display_name_field">Set Audit Status</field>
<field name="description">Update review status (todo / reviewed / supervised / anomaly).</field>
<field name="domain">audit</field>
<field name="tier">2</field>
<field name="parameters_schema">{"type": "object", "properties": {"status_id": {"type": "integer"}, "status": {"type": "string", "enum": ["todo", "reviewed", "supervised", "anomaly"]}}, "required": ["status_id", "status"]}</field>
<field name="required_groups">fusion_accounting_core.group_fusion_accounting_manager</field>
</record>
<record id="tool_get_audit_trail" model="fusion.accounting.tool">
<field name="name">get_audit_trail</field>
<field name="display_name_field">Get Audit Trail</field>
<field name="description">Get mail.message history for a journal entry.</field>
<field name="domain">audit</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"move_id": {"type": "integer"}}, "required": ["move_id"]}</field>
</record>
<record id="tool_run_full_audit" model="fusion.accounting.tool">
<field name="name">run_full_audit</field>
<field name="display_name_field">Run Full Audit</field>
<field name="description">All checks across all domains for a period.</field>
<field name="domain">audit</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"date_from": {"type": "string"}, "date_to": {"type": "string"}}}</field>
</record>
<record id="tool_get_audit_report" model="fusion.accounting.tool">
<field name="name">get_audit_report</field>
<field name="display_name_field">Get Audit Report</field>
<field name="description">Summary of all audit findings with severity ratings.</field>
<field name="domain">audit</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"date_from": {"type": "string"}, "date_to": {"type": "string"}}}</field>
</record>
<!-- Domain 12: Payroll Management -->
<record id="tool_parse_payroll_summary" model="fusion.accounting.tool">
<field name="name">parse_payroll_summary</field>
<field name="display_name_field">Parse Payroll Summary</field>
<field name="description">Read pasted/uploaded payroll data from QBO or fusion_payroll.</field>
<field name="domain">payroll_management</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"data": {"type": "string"}}, "required": ["data"]}</field>
</record>
<record id="tool_create_payroll_journal_entry" model="fusion.accounting.tool">
<field name="name">create_payroll_journal_entry</field>
<field name="display_name_field">Create Payroll Journal Entry</field>
<field name="description">Create a payroll journal entry with debit/credit lines.</field>
<field name="domain">payroll_management</field>
<field name="tier">3</field>
<field name="parameters_schema">{"type": "object", "properties": {"journal_id": {"type": "integer"}, "date": {"type": "string"}, "ref": {"type": "string"}, "lines": {"type": "array", "items": {"type": "object", "properties": {"account_id": {"type": "integer"}, "name": {"type": "string"}, "debit": {"type": "number"}, "credit": {"type": "number"}, "partner_id": {"type": "integer"}}}}}, "required": ["journal_id", "date", "lines"]}</field>
<field name="required_groups">fusion_accounting_core.group_fusion_accounting_manager</field>
</record>
<record id="tool_match_payroll_cheques" model="fusion.accounting.tool">
<field name="name">match_payroll_cheques</field>
<field name="display_name_field">Match Payroll Cheques</field>
<field name="description">Match bank cheques to payroll liabilities.</field>
<field name="domain">payroll_management</field>
<field name="tier">3</field>
<field name="parameters_schema">{"type": "object", "properties": {"statement_line_id": {"type": "integer"}, "move_line_ids": {"type": "array", "items": {"type": "integer"}}}, "required": ["statement_line_id", "move_line_ids"]}</field>
<field name="required_groups">fusion_accounting_core.group_fusion_accounting_manager</field>
</record>
<record id="tool_prepare_cra_payment" model="fusion.accounting.tool">
<field name="name">prepare_cra_payment</field>
<field name="display_name_field">Prepare CRA Payment</field>
<field name="description">Create CRA remittance payment entry.</field>
<field name="domain">payroll_management</field>
<field name="tier">3</field>
<field name="parameters_schema">{"type": "object", "properties": {"journal_id": {"type": "integer"}, "date": {"type": "string"}, "lines": {"type": "array"}}, "required": ["journal_id", "date", "lines"]}</field>
<field name="required_groups">fusion_accounting_core.group_fusion_accounting_manager</field>
</record>
<record id="tool_generate_t4" model="fusion.accounting.tool">
<field name="name">generate_t4</field>
<field name="display_name_field">Generate T4</field>
<field name="description">Trigger T4 generation via fusion_payroll.</field>
<field name="domain">payroll_management</field>
<field name="tier">2</field>
<field name="parameters_schema">{"type": "object", "properties": {}}</field>
<field name="required_groups">fusion_accounting_core.group_fusion_accounting_manager</field>
</record>
<record id="tool_generate_roe" model="fusion.accounting.tool">
<field name="name">generate_roe</field>
<field name="display_name_field">Generate ROE</field>
<field name="description">Trigger ROE generation via fusion_payroll.</field>
<field name="domain">payroll_management</field>
<field name="tier">2</field>
<field name="parameters_schema">{"type": "object", "properties": {}}</field>
<field name="required_groups">fusion_accounting_core.group_fusion_accounting_manager</field>
</record>
<record id="tool_get_payroll_cost_report" model="fusion.accounting.tool">
<field name="name">get_payroll_cost_report</field>
<field name="display_name_field">Get Payroll Cost Report</field>
<field name="description">Period summary by employee/department.</field>
<field name="domain">payroll_management</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"date_from": {"type": "string"}, "date_to": {"type": "string"}}}</field>
</record>
<!-- HST Filing Workflow Tools (added 2026-04-03) -->
<record id="tool_search_partners" model="fusion.accounting.tool">
<field name="name">search_partners</field>
<field name="display_name_field">Search Partners</field>
<field name="description">Search for vendors/contacts by name keyword. Use this to resolve bank line descriptions (e.g., "AMAZON") to the correct Odoo partner record before creating bills. Pass supplier_only=true to filter to vendors only.</field>
<field name="domain">accounts_payable</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"keyword": {"type": "string", "description": "Name keyword to search (min 2 chars)"}, "supplier_only": {"type": "boolean", "description": "Only return suppliers/vendors"}, "limit": {"type": "integer"}}, "required": ["keyword"]}</field>
</record>
<record id="tool_find_similar_bank_lines" model="fusion.accounting.tool">
<field name="name">find_similar_bank_lines</field>
<field name="display_name_field">Find Similar Bank Lines</field>
<field name="description">Search past RECONCILED bank lines with similar payment_ref descriptions. Returns the expense account, tax treatment, and partner used for each historical match. Use this to check how similar expenses were coded in the past before proposing a new bill.</field>
<field name="domain">accounts_payable</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"keyword": {"type": "string", "description": "Keyword from payment_ref to search (min 3 chars)"}, "limit": {"type": "integer"}}, "required": ["keyword"]}</field>
</record>
<record id="tool_get_bank_line_details" model="fusion.accounting.tool">
<field name="name">get_bank_line_details</field>
<field name="display_name_field">Get Bank Line Details</field>
<field name="description">Get full details of a single unreconciled bank statement line. Also searches for existing vendor bills matching the amount and date, and suggests a partner based on the payment description. Use this to check if a bill already exists before creating a new one.</field>
<field name="domain">bank_reconciliation</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"line_id": {"type": "integer", "description": "Bank statement line ID"}}, "required": ["line_id"]}</field>
</record>
<record id="tool_create_vendor_bill" model="fusion.accounting.tool">
<field name="name">create_vendor_bill</field>
<field name="display_name_field">Create Vendor Bill</field>
<field name="description">[Tier 3: Requires user approval] Create a vendor bill (account.move in_invoice) with expense lines and tax. Use after confirming the expense details with the user. Pass post=true to auto-post the bill after creation.</field>
<field name="domain">accounts_payable</field>
<field name="tier">3</field>
<field name="parameters_schema">{"type": "object", "properties": {"partner_id": {"type": "integer", "description": "Vendor partner ID"}, "invoice_date": {"type": "string", "description": "Bill date (YYYY-MM-DD)"}, "lines": {"type": "array", "items": {"type": "object", "properties": {"description": {"type": "string"}, "account_id": {"type": "integer"}, "price_unit": {"type": "number"}, "quantity": {"type": "number"}, "tax_ids": {"type": "array", "items": {"type": "integer"}}}}, "description": "Invoice line items"}, "post": {"type": "boolean", "description": "Auto-post the bill after creation"}}, "required": ["partner_id", "invoice_date", "lines"]}</field>
</record>
<record id="tool_register_bill_payment" model="fusion.accounting.tool">
<field name="name">register_bill_payment</field>
<field name="display_name_field">Register Bill Payment</field>
<field name="description">[Tier 3: Requires user approval] Register a payment on a posted vendor bill from a specific bank journal. Optionally reconcile the payment to a bank statement line. Use after create_vendor_bill to complete the full bill+payment+reconciliation flow.</field>
<field name="domain">accounts_payable</field>
<field name="tier">3</field>
<field name="parameters_schema">{"type": "object", "properties": {"bill_id": {"type": "integer", "description": "Posted bill ID (account.move)"}, "journal_id": {"type": "integer", "description": "Bank journal ID for payment"}, "payment_date": {"type": "string", "description": "Payment date (YYYY-MM-DD)"}, "amount": {"type": "number", "description": "Payment amount (defaults to bill total)"}, "statement_line_id": {"type": "integer", "description": "Bank statement line ID to reconcile with"}}, "required": ["bill_id", "journal_id"]}</field>
</record>
<record id="tool_check_recurring_pattern" model="fusion.accounting.tool">
<field name="name">check_recurring_pattern</field>
<field name="display_name_field">Check Recurring Pattern</field>
<field name="description">Check if a bank line matches a known recurring payment pattern. Returns the historical account coding, HST treatment, partner, and reconciliation model if one exists. ALWAYS call this FIRST for every unreconciled bank line — if a recurring pattern exists, follow its instructions instead of asking the user. Pass line_id to auto-extract ref and amount.</field>
<field name="domain">bank_reconciliation</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"line_id": {"type": "integer", "description": "Bank statement line ID"}, "payment_ref": {"type": "string", "description": "Payment reference text (auto-extracted if line_id provided)"}, "amount": {"type": "number", "description": "Transaction amount (auto-extracted if line_id provided)"}}, "required": []}</field>
</record>
<record id="tool_match_internal_transfers" model="fusion.accounting.tool">
<field name="name">match_internal_transfers</field>
<field name="display_name_field">Match Internal Transfers</field>
<field name="description">[Tier 3: Requires user approval] Find and match inter-account transfers between two bank journals (e.g., Scotia Current ↔ Scotia Visa). Matches EXACT amounts within 2 days. ONLY matches when there is exactly one candidate — skips ambiguous cases. First call with execute=false to preview pairs, then execute=true to reconcile. Scotia Current=50, Scotia Visa=51, RBC Chequing=53, RBC Visa=28.</field>
<field name="domain">bank_reconciliation</field>
<field name="tier">3</field>
<field name="parameters_schema">{"type": "object", "properties": {"journal_a_id": {"type": "integer", "description": "First bank journal ID"}, "journal_b_id": {"type": "integer", "description": "Second bank journal ID"}, "date_from": {"type": "string"}, "date_to": {"type": "string"}, "max_days_apart": {"type": "integer", "description": "Max days between matching lines (default 2)"}, "execute": {"type": "boolean", "description": "false=preview pairs only, true=actually reconcile"}}, "required": ["journal_a_id", "journal_b_id"]}</field>
</record>
<record id="tool_suggest_bank_line_matches" model="fusion.accounting.tool">
<field name="name">suggest_bank_line_matches</field>
<field name="display_name_field">Suggest Bank Line Matches</field>
<field name="description">[Tier 1: Read-only] Find candidate invoices/bills that could match a bank statement line. Extracts partner from the bank line reference, searches open receivables (for incoming payments) or payables (for outgoing payments), scores candidates by amount/partner/date proximity, and finds the best combination of entries that sum to the bank amount. Returns data for a reconciliation-mode fusion-table with editable amounts and search. The user reviews matches, adjusts amounts for partial payments, searches and adds more entries, then clicks Apply Match.</field>
<field name="domain">bank_reconciliation</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"statement_line_id": {"type": "integer", "description": "Bank statement line ID to find matches for"}}, "required": ["statement_line_id"]}</field>
</record>
<record id="tool_find_unreconciled_cheques" model="fusion.accounting.tool">
<field name="name">find_unreconciled_cheques</field>
<field name="display_name_field">Find Unreconciled Cheques</field>
<field name="description">[Tier 1: Read-only] Find unreconciled cheque bank lines and classify them as payroll or non-payroll. Payroll cheques have a matching credit amount on 2201 Payroll Liabilities. Non-payroll cheques (vendor payments, rent, etc.) don't. Default journal: Scotia Current (50).</field>
<field name="domain">bank_reconciliation</field>
<field name="tier">1</field>
<field name="parameters_schema">{"type": "object", "properties": {"journal_id": {"type": "integer", "description": "Bank journal ID (default 50 = Scotia Current)"}, "limit": {"type": "integer", "description": "Max results (default 50)"}}}</field>
</record>
<record id="tool_reconcile_payroll_cheques" model="fusion.accounting.tool">
<field name="name">reconcile_payroll_cheques</field>
<field name="display_name_field">Reconcile Payroll Cheques</field>
<field name="description">[Tier 3: Requires user approval] Reconcile payroll cheque bank lines by applying the Payroll Cheque Clearing model. ONLY processes cheques whose amount matches an existing payroll liability entry on 2201. Non-payroll cheques (vendor/rent) are skipped automatically. Uses the pre-configured "Payroll Cheque Clearing" reconcile model (writeoff to Dr 2201).</field>
<field name="domain">bank_reconciliation</field>
<field name="tier">3</field>
<field name="parameters_schema">{"type": "object", "properties": {"journal_id": {"type": "integer", "description": "Bank journal ID (default 50)"}, "line_ids": {"type": "array", "items": {"type": "integer"}, "description": "Optional: specific bank line IDs to reconcile. If empty, reconciles all matching payroll cheques."}}}</field>
<field name="required_groups">fusion_accounting_core.group_fusion_accounting_manager</field>
</record>
<record id="tool_create_expense_entry" model="fusion.accounting.tool">
<field name="name">create_expense_entry</field>
<field name="display_name_field">Create Direct GL Expense</field>
<field name="description">[Tier 3: Requires user approval] Create a direct GL expense entry in the Miscellaneous Operations journal. Alternative to creating a vendor bill — posts immediately. If has_hst=true, automatically splits the amount into net expense + 13% HST ITC on the 2006 account. Use this for small expenses where a formal vendor bill is not needed.</field>
<field name="domain">hst_management</field>
<field name="tier">3</field>
<field name="parameters_schema">{"type": "object", "properties": {"date": {"type": "string", "description": "Entry date (YYYY-MM-DD)"}, "description": {"type": "string", "description": "Expense description"}, "expense_account_id": {"type": "integer", "description": "GL expense account ID"}, "amount": {"type": "number", "description": "Total amount including HST if applicable"}, "has_hst": {"type": "boolean", "description": "Whether HST (13%) is included in the amount"}, "bank_journal_id": {"type": "integer", "description": "Bank journal for the credit side"}}, "required": ["date", "description", "expense_account_id", "amount"]}</field>
</record>
</odoo>

View File

@@ -0,0 +1,294 @@
# Graph Report - /Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai (2026-04-22)
## Corpus Check
- 61 files · ~40,430 words
- Verdict: corpus is large enough that graph structure adds value.
## Summary
- 602 nodes · 894 edges · 40 communities detected
- Extraction: 79% EXTRACTED · 21% INFERRED · 0% AMBIGUOUS · INFERRED: 192 edges (avg confidence: 0.71)
- Token cost: 0 input · 0 output
## Community Hubs (Navigation)
- [[_COMMUNITY_Community 0|Community 0]]
- [[_COMMUNITY_Community 1|Community 1]]
- [[_COMMUNITY_Community 2|Community 2]]
- [[_COMMUNITY_Community 3|Community 3]]
- [[_COMMUNITY_Community 4|Community 4]]
- [[_COMMUNITY_Community 5|Community 5]]
- [[_COMMUNITY_Community 6|Community 6]]
- [[_COMMUNITY_Community 7|Community 7]]
- [[_COMMUNITY_Community 8|Community 8]]
- [[_COMMUNITY_Community 9|Community 9]]
- [[_COMMUNITY_Community 10|Community 10]]
- [[_COMMUNITY_Community 11|Community 11]]
- [[_COMMUNITY_Community 12|Community 12]]
- [[_COMMUNITY_Community 13|Community 13]]
- [[_COMMUNITY_Community 14|Community 14]]
- [[_COMMUNITY_Community 15|Community 15]]
- [[_COMMUNITY_Community 16|Community 16]]
- [[_COMMUNITY_Community 17|Community 17]]
- [[_COMMUNITY_Community 18|Community 18]]
- [[_COMMUNITY_Community 19|Community 19]]
- [[_COMMUNITY_Community 20|Community 20]]
- [[_COMMUNITY_Community 21|Community 21]]
- [[_COMMUNITY_Community 22|Community 22]]
- [[_COMMUNITY_Community 23|Community 23]]
- [[_COMMUNITY_Community 24|Community 24]]
- [[_COMMUNITY_Community 25|Community 25]]
- [[_COMMUNITY_Community 26|Community 26]]
- [[_COMMUNITY_Community 27|Community 27]]
- [[_COMMUNITY_Community 28|Community 28]]
- [[_COMMUNITY_Community 29|Community 29]]
- [[_COMMUNITY_Community 30|Community 30]]
- [[_COMMUNITY_Community 31|Community 31]]
- [[_COMMUNITY_Community 32|Community 32]]
- [[_COMMUNITY_Community 33|Community 33]]
- [[_COMMUNITY_Community 34|Community 34]]
- [[_COMMUNITY_Community 35|Community 35]]
- [[_COMMUNITY_Community 36|Community 36]]
- [[_COMMUNITY_Community 37|Community 37]]
- [[_COMMUNITY_Community 38|Community 38]]
- [[_COMMUNITY_Community 39|Community 39]]
## God Nodes (most connected - your core abstractions)
1. `FusionChatPanel` - 38 edges
2. `DataAdapter` - 38 edges
3. `get_adapter()` - 37 edges
4. `FollowupAdapter` - 28 edges
5. `ReportsAdapter` - 27 edges
6. `FusionAccountingAgent` - 22 edges
7. `FusionInteractiveTable` - 21 edges
8. `BankRecAdapter` - 20 edges
9. `AssetsAdapter` - 15 edges
10. `AdapterMode` - 14 edges
## Surprising Connections (you probably didn't know these)
- `Community shape + fusion AI fields (top suggestion, band, attachments).` --uses--> `DataAdapter` [INFERRED]
/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/bank_rec.py → /Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/base.py
- `Return AI suggestions per bank line. Shape: ``{line_id: [{'id', 'rank',` --uses--> `DataAdapter` [INFERRED]
/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/bank_rec.py → /Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/base.py
- `Accept a fusion AI suggestion and reconcile against its proposal. Retur` --uses--> `DataAdapter` [INFERRED]
/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/bank_rec.py → /Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/base.py
- `Reverse a reconciliation by partial IDs. Returns ``{'unreconciled_line_` --uses--> `DataAdapter` [INFERRED]
/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/bank_rec.py → /Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/base.py
- `Engine-free unreconcile for installs without fusion_accounting_bank_rec.` --uses--> `DataAdapter` [INFERRED]
/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/bank_rec.py → /Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/base.py
## Communities
### Community 0 - "Community 0"
Cohesion: 0.04
Nodes (6): FusionApprovalCard, FusionChatPanel, inlineFormat(), mdToHtml(), parseFusionTableBlock(), FusionInteractiveTable
### Community 1 - "Community 1"
Cohesion: 0.05
Nodes (21): _compute_display_label(), _compute_tool_display_name(), FusionAccountingMatchHistory, FusionAccountingRule, FusionAccountingAgent, Build a one-line summary of what a tool call did, for the collapsed tool log., Build a rich approval payload so the UI can show exactly what's being approved., Smart model routing: Haiku for routine tool calling, Sonnet for complex analysis (+13 more)
### Community 2 - "Community 2"
Cohesion: 0.04
Nodes (39): BankRecAdapter, Return AI suggestions per bank line. Shape: ``{line_id: [{'id', 'rank',, Accept a fusion AI suggestion and reconcile against its proposal. Retur, Reverse a reconciliation by partial IDs. Returns ``{'unreconciled_line_, Engine-free unreconcile for installs without fusion_accounting_bank_rec., Community shape + fusion AI fields (top suggestion, band, attachments)., check_recurring_pattern(), _extract_partner_from_ref() (+31 more)
### Community 3 - "Community 3"
Cohesion: 0.05
Nodes (37): get_ap_aging(), Return AP aging buckets. Routed through FollowupAdapter for tri-mode consistency, get_ar_aging(), get_followup_report(), get_overdue_invoices(), get_partner_balance(), Return the follow-up report HTML for a partner. Routed through FollowupAdapter., Return overdue customer invoices. Routed through FollowupAdapter. (+29 more)
### Community 4 - "Community 4"
Cohesion: 0.07
Nodes (30): Assets data adapter — routes asset queries through fusion engine if installed., Bank reconciliation data adapter. Routes bank-rec data lookups across: - FUSION, Return unreconciled bank statement lines. All filter params are optiona, AdapterMode, DataAdapter, Base class. Subclasses set FUSION_MODEL and ENTERPRISE_MODULE class attrs an, Pick FUSION if the model is loaded, else ENTERPRISE if the module is ins, Follow-up data adapter. Routes follow-up / aged-balance / collections data look (+22 more)
### Community 5 - "Community 5"
Cohesion: 0.05
Nodes (27): audit_account_balances(), audit_reconciliation_integrity(), audit_tax_compliance(), check_hash_chain(), check_sequence_gaps(), get_audit_report(), run_full_audit(), fusion_generate_followup_text() (+19 more)
### Community 6 - "Community 6"
Cohesion: 0.07
Nodes (14): Look up <method_name>_via_<mode> on self and call it. E.g. method_name=, _company_id(), fusion_compare_periods(), fusion_drill_down_report_line(), fusion_generate_commentary(), fusion_get_anomalies(), fusion_run_report(), Fusion-engine-routed AI tools for financial reports. These 5 tools route throug (+6 more)
### Community 7 - "Community 7"
Cohesion: 0.08
Nodes (14): LLMProvider, LLMProvider contract - every adapter must conform. Phase 1 generalisation: make, Contract every LLM backend must satisfy. Adapters declare capabilities as cl, Plain text completion. Required for ALL providers. Returns: {'content':, Tool-calling completion. Optional - caller checks supports_tool_calling first., Embeddings. Optional - caller checks supports_embeddings first. Returns, ClaudeAdapter, FusionAccountingAdapterClaude (+6 more)
### Community 8 - "Community 8"
Cohesion: 0.11
Nodes (13): FusionAccountingSession, get_execution_state(), Get the current execution state for a session (called by polling endpoint)., approve_action(), approve_all(), chat(), chat_status(), close_session() (+5 more)
### Community 9 - "Community 9"
Cohesion: 0.1
Nodes (13): AccountMoveAuditHook, create_vendor_bill(), find_similar_bank_lines(), Search for partners/vendors by name keyword., Find past reconciled bank lines with similar description to suggest coding patte, [Tier 3] Create a vendor bill (account.move with move_type='in_invoice'). Re, [Tier 3] Register payment on a posted vendor bill and optionally reconcile to ba, register_bill_payment() (+5 more)
### Community 10 - "Community 10"
Cohesion: 0.13
Nodes (3): _bucket_for_days(), FollowupAdapter, Shared aging-bucket implementation for receivable/payable accounts. Ret
### Community 11 - "Community 11"
Cohesion: 0.12
Nodes (5): fusion_dispose_asset(), fusion_suggest_asset_useful_life(), Fusion-engine-routed AI tools for asset management., AssetsAdapter, DataAdapter
### Community 12 - "Community 12"
Cohesion: 0.14
Nodes (10): create_payroll_journal_entry(), get_cra_remittance_due(), get_cra_remittance_status(), get_payroll_cost_report(), get_payroll_entries(), prepare_cra_payment(), Resolve an account code or ID to a valid account ID. Accepts: integer ID, st, _resolve_account_id() (+2 more)
### Community 13 - "Community 13"
Cohesion: 0.2
Nodes (1): FusionAccountingDashboard
### Community 14 - "Community 14"
Cohesion: 0.25
Nodes (2): Register payments for a batch of ADP invoices from a remittance advice. Tak, register_adp_batch_payment()
### Community 15 - "Community 15"
Cohesion: 0.33
Nodes (1): FusionDashboard
### Community 16 - "Community 16"
Cohesion: 0.4
Nodes (2): get_inventory_turnover(), get_stock_valuation()
### Community 17 - "Community 17"
Cohesion: 0.5
Nodes (2): FusionVendorTaxProfile, Rebuild all vendor tax profiles from posted bill history. Called by cron
### Community 18 - "Community 18"
Cohesion: 0.5
Nodes (2): FusionRecurringPattern, Scan reconciled bank lines for recurring patterns and cache how they were coded.
### Community 19 - "Community 19"
Cohesion: 0.5
Nodes (1): FusionHealthCard
### Community 20 - "Community 20"
Cohesion: 0.5
Nodes (3): build_prompt(), Bank reconciliation AI re-rank prompt. Used by fusion_accounting_bank_rec/servi, Build (system_prompt, user_prompt) for AI re-rank. Args: statement_
### Community 21 - "Community 21"
Cohesion: 0.67
Nodes (1): Reassign ir_model_data ownership from fusion_accounting to fusion_accounting_ai.
### Community 22 - "Community 22"
Cohesion: 0.67
Nodes (1): FusionRuleWizard
### Community 23 - "Community 23"
Cohesion: 1.0
Nodes (0):
### Community 24 - "Community 24"
Cohesion: 1.0
Nodes (1): FusionAccountingTool
### Community 25 - "Community 25"
Cohesion: 1.0
Nodes (1): ResConfigSettings
### Community 26 - "Community 26"
Cohesion: 1.0
Nodes (0):
### Community 27 - "Community 27"
Cohesion: 1.0
Nodes (0):
### Community 28 - "Community 28"
Cohesion: 1.0
Nodes (0):
### Community 29 - "Community 29"
Cohesion: 1.0
Nodes (0):
### Community 30 - "Community 30"
Cohesion: 1.0
Nodes (0):
### Community 31 - "Community 31"
Cohesion: 1.0
Nodes (0):
### Community 32 - "Community 32"
Cohesion: 1.0
Nodes (0):
### Community 33 - "Community 33"
Cohesion: 1.0
Nodes (0):
### Community 34 - "Community 34"
Cohesion: 1.0
Nodes (0):
### Community 35 - "Community 35"
Cohesion: 1.0
Nodes (1): Poll the live execution state of a running chat — returns thinking text,
### Community 36 - "Community 36"
Cohesion: 1.0
Nodes (1): Live search for matching journal items — called directly by the reconcil
### Community 37 - "Community 37"
Cohesion: 1.0
Nodes (1): List recent sessions for the session picker dropdown.
### Community 38 - "Community 38"
Cohesion: 1.0
Nodes (1): Automatically reconcile inter-account credit card payments. When a paym
### Community 39 - "Community 39"
Cohesion: 1.0
Nodes (1): Reconcile payroll cheque bank lines using writeoff to Payroll Liabilities (2201)
## Knowledge Gaps
- **86 isolated node(s):** `Reassign ir_model_data ownership from fusion_accounting to fusion_accounting_ai.`, `Verify ir_model_data ownership transferred from fusion_accounting to fusion_acco`, `No fusion-related model/view/data record should still claim module='fusion_accou`, `Spot-check that key xml-ids are reachable under the new module name.`, `FusionAccountingTool` (+81 more)
These have ≤1 connection - possible missing edges or undocumented components.
- **Thin community `Community 23`** (2 nodes): `get_db_param()`, `test_claude_api.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 24`** (2 nodes): `FusionAccountingTool`, `accounting_tool.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 25`** (2 nodes): `ResConfigSettings`, `accounting_config.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 26`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 27`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 28`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 29`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 30`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 31`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 32`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 33`** (1 nodes): `__manifest__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 34`** (1 nodes): `test_api_live.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 35`** (1 nodes): `Poll the live execution state of a running chat — returns thinking text,`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 36`** (1 nodes): `Live search for matching journal items — called directly by the reconcil`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 37`** (1 nodes): `List recent sessions for the session picker dropdown.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 38`** (1 nodes): `Automatically reconcile inter-account credit card payments. When a paym`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 39`** (1 nodes): `Reconcile payroll cheque bank lines using writeoff to Payroll Liabilities (2201)`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
## Suggested Questions
_Questions this graph is uniquely positioned to answer:_
- **Why does `get_audit_report()` connect `Community 5` to `Community 1`?**
_High betweenness centrality (0.205) - this node is a cross-community bridge._
- **Why does `FusionInteractiveTable` connect `Community 0` to `Community 1`?**
_High betweenness centrality (0.184) - this node is a cross-community bridge._
- **Why does `get_adapter()` connect `Community 3` to `Community 2`, `Community 4`, `Community 5`, `Community 6`, `Community 11`?**
_High betweenness centrality (0.168) - this node is a cross-community bridge._
- **Are the 33 inferred relationships involving `DataAdapter` (e.g. with `TestDataAdapterBase` and `TestBankRecAdapter`) actually correct?**
_`DataAdapter` has 33 INFERRED edges - model-reasoned connections that need verification._
- **Are the 35 inferred relationships involving `get_adapter()` (e.g. with `.test_list_unreconciled_returns_our_test_line()` and `.test_trial_balance_returns_rows_in_pure_community()`) actually correct?**
_`get_adapter()` has 35 INFERRED edges - model-reasoned connections that need verification._
- **What connects `Reassign ir_model_data ownership from fusion_accounting to fusion_accounting_ai.`, `Verify ir_model_data ownership transferred from fusion_accounting to fusion_acco`, `No fusion-related model/view/data record should still claim module='fusion_accou` to the rest of the system?**
_86 weakly-connected nodes found - possible documentation gaps or missing edges._
- **Should `Community 0` be split into smaller, more focused modules?**
_Cohesion score 0.04 - nodes in this community are weakly interconnected._

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_tests_test_claude_api_py", "label": "test_claude_api.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/tests/test_claude_api.py", "source_location": "L1"}, {"id": "test_claude_api_get_db_param", "label": "get_db_param()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/tests/test_claude_api.py", "source_location": "L6"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_tests_test_claude_api_py", "target": "anthropic", "relation": "imports", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/tests/test_claude_api.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_tests_test_claude_api_py", "target": "json", "relation": "imports", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/tests/test_claude_api.py", "source_location": "L2", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_tests_test_claude_api_py", "target": "subprocess", "relation": "imports", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/tests/test_claude_api.py", "source_location": "L3", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_tests_test_claude_api_py", "target": "sys", "relation": "imports", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/tests/test_claude_api.py", "source_location": "L4", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_tests_test_claude_api_py", "target": "test_claude_api_get_db_param", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/tests/test_claude_api.py", "source_location": "L6", "weight": 1.0}], "raw_calls": [{"caller_nid": "test_claude_api_get_db_param", "callee": "run", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/tests/test_claude_api.py", "source_location": "L7"}, {"caller_nid": "test_claude_api_get_db_param", "callee": "strip", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/tests/test_claude_api.py", "source_location": "L12"}]}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/__init__.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/__init__.py", "source_location": "L2", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/__init__.py", "source_location": "L3", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/__init__.py", "source_location": "L4", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/__init__.py", "source_location": "L5", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_tests_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/tests/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_tests_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_tests_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/tests/__init__.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_tests_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_tests_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/tests/__init__.py", "source_location": "L2", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_tests_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_tests_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/tests/__init__.py", "source_location": "L3", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_manifest_py", "label": "__manifest__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/__manifest__.py", "source_location": "L1"}], "edges": [], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_accounting_tool_py", "label": "accounting_tool.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/models/accounting_tool.py", "source_location": "L1"}, {"id": "accounting_tool_fusionaccountingtool", "label": "FusionAccountingTool", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/models/accounting_tool.py", "source_location": "L7"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_accounting_tool_py", "target": "logging", "relation": "imports", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/models/accounting_tool.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_accounting_tool_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/models/accounting_tool.py", "source_location": "L2", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_accounting_tool_py", "target": "accounting_tool_fusionaccountingtool", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/models/accounting_tool.py", "source_location": "L7", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_prompts_domain_prompts_py", "label": "domain_prompts.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/prompts/domain_prompts.py", "source_location": "L1"}, {"id": "domain_prompts_get_domain_prompt", "label": "get_domain_prompt()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/prompts/domain_prompts.py", "source_location": "L229"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_prompts_domain_prompts_py", "target": "domain_prompts_get_domain_prompt", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/prompts/domain_prompts.py", "source_location": "L229", "weight": 1.0}], "raw_calls": [{"caller_nid": "domain_prompts_get_domain_prompt", "callee": "get", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/prompts/domain_prompts.py", "source_location": "L233"}, {"caller_nid": "domain_prompts_get_domain_prompt", "callee": "get", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/prompts/domain_prompts.py", "source_location": "L235"}, {"caller_nid": "domain_prompts_get_domain_prompt", "callee": "get", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/prompts/domain_prompts.py", "source_location": "L236"}]}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_wizards_rule_wizard_py", "label": "rule_wizard.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/wizards/rule_wizard.py", "source_location": "L1"}, {"id": "rule_wizard_fusionrulewizard", "label": "FusionRuleWizard", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/wizards/rule_wizard.py", "source_location": "L4"}, {"id": "rule_wizard_fusionrulewizard_action_create_rule", "label": ".action_create_rule()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/wizards/rule_wizard.py", "source_location": "L23"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_wizards_rule_wizard_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/wizards/rule_wizard.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_wizards_rule_wizard_py", "target": "rule_wizard_fusionrulewizard", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/wizards/rule_wizard.py", "source_location": "L4", "weight": 1.0}, {"source": "rule_wizard_fusionrulewizard", "target": "rule_wizard_fusionrulewizard_action_create_rule", "relation": "method", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/wizards/rule_wizard.py", "source_location": "L23", "weight": 1.0}], "raw_calls": [{"caller_nid": "rule_wizard_fusionrulewizard_action_create_rule", "callee": "ensure_one", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/wizards/rule_wizard.py", "source_location": "L24"}, {"caller_nid": "rule_wizard_fusionrulewizard_action_create_rule", "callee": "create", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/wizards/rule_wizard.py", "source_location": "L25"}]}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_static_src_components_chat_approval_card_js", "label": "approval_card.js", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/static/src/components/chat/approval_card.js", "source_location": "L1"}, {"id": "approval_card_fusionapprovalcard", "label": "FusionApprovalCard", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/static/src/components/chat/approval_card.js", "source_location": "L5"}, {"id": "approval_card_fusionapprovalcard_toollabel", "label": ".toolLabel()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/static/src/components/chat/approval_card.js", "source_location": "L9"}, {"id": "approval_card_fusionapprovalcard_formatamount", "label": ".formatAmount()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/static/src/components/chat/approval_card.js", "source_location": "L25"}, {"id": "approval_card_fusionapprovalcard_approve", "label": ".approve()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/static/src/components/chat/approval_card.js", "source_location": "L30"}, {"id": "approval_card_fusionapprovalcard_reject", "label": ".reject()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/static/src/components/chat/approval_card.js", "source_location": "L34"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_static_src_components_chat_approval_card_js", "target": "owl", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/static/src/components/chat/approval_card.js", "source_location": "L3", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_static_src_components_chat_approval_card_js", "target": "approval_card_fusionapprovalcard", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/static/src/components/chat/approval_card.js", "source_location": "L5", "weight": 1.0}, {"source": "approval_card_fusionapprovalcard", "target": "approval_card_fusionapprovalcard_toollabel", "relation": "method", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/static/src/components/chat/approval_card.js", "source_location": "L9", "weight": 1.0}, {"source": "approval_card_fusionapprovalcard", "target": "approval_card_fusionapprovalcard_formatamount", "relation": "method", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/static/src/components/chat/approval_card.js", "source_location": "L25", "weight": 1.0}, {"source": "approval_card_fusionapprovalcard", "target": "approval_card_fusionapprovalcard_approve", "relation": "method", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/static/src/components/chat/approval_card.js", "source_location": "L30", "weight": 1.0}, {"source": "approval_card_fusionapprovalcard", "target": "approval_card_fusionapprovalcard_reject", "relation": "method", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/static/src/components/chat/approval_card.js", "source_location": "L34", "weight": 1.0}], "raw_calls": [{"caller_nid": "approval_card_fusionapprovalcard_toollabel", "callee": "replace", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/static/src/components/chat/approval_card.js", "source_location": "L22"}, {"caller_nid": "approval_card_fusionapprovalcard_toollabel", "callee": "replace", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/static/src/components/chat/approval_card.js", "source_location": "L22"}, {"caller_nid": "approval_card_fusionapprovalcard_formatamount", "callee": "toLocaleString", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/static/src/components/chat/approval_card.js", "source_location": "L27"}, {"caller_nid": "approval_card_fusionapprovalcard_formatamount", "callee": "Number", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/static/src/components/chat/approval_card.js", "source_location": "L27"}, {"caller_nid": "approval_card_fusionapprovalcard_approve", "callee": "onApprove", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/static/src/components/chat/approval_card.js", "source_location": "L31"}, {"caller_nid": "approval_card_fusionapprovalcard_reject", "callee": "onReject", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/static/src/components/chat/approval_card.js", "source_location": "L35"}]}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_wizards_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/wizards/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_wizards_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_wizards_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/wizards/__init__.py", "source_location": "L1", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/models/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/models/__init__.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/models/__init__.py", "source_location": "L2", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/models/__init__.py", "source_location": "L3", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/models/__init__.py", "source_location": "L4", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/models/__init__.py", "source_location": "L5", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/models/__init__.py", "source_location": "L6", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/models/__init__.py", "source_location": "L7", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/models/__init__.py", "source_location": "L8", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/models/__init__.py", "source_location": "L9", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_data_adapters_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_data_adapters_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_data_adapters_base_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/__init__.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_data_adapters_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_data_adapters_registry_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/__init__.py", "source_location": "L2", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_data_adapters_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_data_adapters_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/__init__.py", "source_location": "L4", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_data_adapters_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_data_adapters_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/__init__.py", "source_location": "L5", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_data_adapters_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_data_adapters_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/__init__.py", "source_location": "L6", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_data_adapters_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_data_adapters_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/__init__.py", "source_location": "L7", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_static_src_components_dashboard_health_card_js", "label": "health_card.js", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/static/src/components/dashboard/health_card.js", "source_location": "L1"}, {"id": "health_card_fusionhealthcard", "label": "FusionHealthCard", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/static/src/components/dashboard/health_card.js", "source_location": "L5"}, {"id": "health_card_fusionhealthcard_icon", "label": ".icon()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/static/src/components/dashboard/health_card.js", "source_location": "L9"}, {"id": "health_card_fusionhealthcard_onclick", "label": ".onClick()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/static/src/components/dashboard/health_card.js", "source_location": "L21"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_static_src_components_dashboard_health_card_js", "target": "owl", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/static/src/components/dashboard/health_card.js", "source_location": "L3", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_static_src_components_dashboard_health_card_js", "target": "health_card_fusionhealthcard", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/static/src/components/dashboard/health_card.js", "source_location": "L5", "weight": 1.0}, {"source": "health_card_fusionhealthcard", "target": "health_card_fusionhealthcard_icon", "relation": "method", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/static/src/components/dashboard/health_card.js", "source_location": "L9", "weight": 1.0}, {"source": "health_card_fusionhealthcard", "target": "health_card_fusionhealthcard_onclick", "relation": "method", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/static/src/components/dashboard/health_card.js", "source_location": "L21", "weight": 1.0}], "raw_calls": [{"caller_nid": "health_card_fusionhealthcard_onclick", "callee": "onCardClick", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/static/src/components/dashboard/health_card.js", "source_location": "L22"}]}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_accounting_session_py", "label": "accounting_session.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/models/accounting_session.py", "source_location": "L1"}, {"id": "accounting_session_fusionaccountingsession", "label": "FusionAccountingSession", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/models/accounting_session.py", "source_location": "L7"}, {"id": "accounting_session_fusionaccountingsession_action_close_session", "label": ".action_close_session()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/models/accounting_session.py", "source_location": "L59"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_accounting_session_py", "target": "logging", "relation": "imports", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/models/accounting_session.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_accounting_session_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/models/accounting_session.py", "source_location": "L2", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_accounting_session_py", "target": "accounting_session_fusionaccountingsession", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/models/accounting_session.py", "source_location": "L7", "weight": 1.0}, {"source": "accounting_session_fusionaccountingsession", "target": "accounting_session_fusionaccountingsession_action_close_session", "relation": "method", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/models/accounting_session.py", "source_location": "L59", "weight": 1.0}], "raw_calls": [{"caller_nid": "accounting_session_fusionaccountingsession_action_close_session", "callee": "write", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/models/accounting_session.py", "source_location": "L60"}]}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_controllers_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/controllers/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_controllers_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_controllers_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/controllers/__init__.py", "source_location": "L1", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/__init__.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/__init__.py", "source_location": "L2", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/__init__.py", "source_location": "L3", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/__init__.py", "source_location": "L4", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_accounting_config_py", "label": "accounting_config.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/models/accounting_config.py", "source_location": "L1"}, {"id": "accounting_config_resconfigsettings", "label": "ResConfigSettings", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/models/accounting_config.py", "source_location": "L7"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_accounting_config_py", "target": "logging", "relation": "imports", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/models/accounting_config.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_accounting_config_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/models/accounting_config.py", "source_location": "L2", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_models_accounting_config_py", "target": "accounting_config_resconfigsettings", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/models/accounting_config.py", "source_location": "L7", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_tests_test_api_live_py", "label": "test_api_live.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/tests/test_api_live.py", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_tests_test_api_live_py", "target": "anthropic", "relation": "imports", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/tests/test_api_live.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_tests_test_api_live_py", "target": "json", "relation": "imports", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/tests/test_api_live.py", "source_location": "L2", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_tests_test_api_live_py", "target": "sys", "relation": "imports", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/tests/test_api_live.py", "source_location": "L3", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_adapters_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/adapters/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_adapters_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_adapters_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/adapters/__init__.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_adapters_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_adapters_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/adapters/__init__.py", "source_location": "L2", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_adapters_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_adapters_base_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/adapters/__init__.py", "source_location": "L3", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_data_adapters_registry_py", "label": "_registry.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/_registry.py", "source_location": "L1"}, {"id": "registry_get_adapter", "label": "get_adapter()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/_registry.py", "source_location": "L6"}, {"id": "registry_register_adapter", "label": "register_adapter()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/_registry.py", "source_location": "L23"}, {"id": "registry_rationale_1", "label": "Registry: lazy-loads data adapter instances per env.", "file_type": "rationale", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/_registry.py", "source_location": "L1"}, {"id": "registry_rationale_7", "label": "Return a data adapter by short name. Cached per request via env.context.", "file_type": "rationale", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/_registry.py", "source_location": "L7"}, {"id": "registry_rationale_24", "label": "Register an adapter class. Call from each adapter module at import time.", "file_type": "rationale", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/_registry.py", "source_location": "L24"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_data_adapters_registry_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_data_adapters_base_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/_registry.py", "source_location": "L3", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_data_adapters_registry_py", "target": "registry_get_adapter", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/_registry.py", "source_location": "L6", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_data_adapters_registry_py", "target": "registry_register_adapter", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/_registry.py", "source_location": "L23", "weight": 1.0}, {"source": "registry_rationale_1", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_data_adapters_registry_py", "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/_registry.py", "source_location": "L1", "weight": 1.0}, {"source": "registry_rationale_7", "target": "registry_get_adapter", "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/_registry.py", "source_location": "L7", "weight": 1.0}, {"source": "registry_rationale_24", "target": "registry_register_adapter", "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/_registry.py", "source_location": "L24", "weight": 1.0}], "raw_calls": [{"caller_nid": "registry_get_adapter", "callee": "get", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/_registry.py", "source_location": "L8"}, {"caller_nid": "registry_get_adapter", "callee": "get", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/_registry.py", "source_location": "L12"}, {"caller_nid": "registry_get_adapter", "callee": "KeyError", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/_registry.py", "source_location": "L14"}, {"caller_nid": "registry_get_adapter", "callee": "list", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/_registry.py", "source_location": "L14"}, {"caller_nid": "registry_get_adapter", "callee": "cls", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/data_adapters/_registry.py", "source_location": "L15"}]}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_prompts_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/prompts/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_prompts_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_prompts_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/prompts/__init__.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_prompts_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_prompts_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/prompts/__init__.py", "source_location": "L2", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_prompts_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_services_prompts_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/services/prompts/__init__.py", "source_location": "L3", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_migrations_19_0_1_0_0_post_migration_py", "label": "post-migration.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/migrations/19.0.1.0.0/post-migration.py", "source_location": "L1"}, {"id": "post_migration_migrate", "label": "migrate()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/migrations/19.0.1.0.0/post-migration.py", "source_location": "L79"}, {"id": "post_migration_rationale_1", "label": "Reassign ir_model_data ownership from fusion_accounting to fusion_accounting_ai.", "file_type": "rationale", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/migrations/19.0.1.0.0/post-migration.py", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_migrations_19_0_1_0_0_post_migration_py", "target": "logging", "relation": "imports", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/migrations/19.0.1.0.0/post-migration.py", "source_location": "L21", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_migrations_19_0_1_0_0_post_migration_py", "target": "post_migration_migrate", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/migrations/19.0.1.0.0/post-migration.py", "source_location": "L79", "weight": 1.0}, {"source": "post_migration_rationale_1", "target": "users_gurpreet_github_odoo_modules_fusion_accounting_ai_migrations_19_0_1_0_0_post_migration_py", "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/migrations/19.0.1.0.0/post-migration.py", "source_location": "L1", "weight": 1.0}], "raw_calls": [{"caller_nid": "post_migration_migrate", "callee": "execute", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/migrations/19.0.1.0.0/post-migration.py", "source_location": "L81"}, {"caller_nid": "post_migration_migrate", "callee": "list", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/migrations/19.0.1.0.0/post-migration.py", "source_location": "L86"}, {"caller_nid": "post_migration_migrate", "callee": "execute", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/migrations/19.0.1.0.0/post-migration.py", "source_location": "L91"}, {"caller_nid": "post_migration_migrate", "callee": "list", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/migrations/19.0.1.0.0/post-migration.py", "source_location": "L100"}, {"caller_nid": "post_migration_migrate", "callee": "list", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/migrations/19.0.1.0.0/post-migration.py", "source_location": "L100"}, {"caller_nid": "post_migration_migrate", "callee": "execute", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/migrations/19.0.1.0.0/post-migration.py", "source_location": "L104"}, {"caller_nid": "post_migration_migrate", "callee": "list", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/migrations/19.0.1.0.0/post-migration.py", "source_location": "L112"}, {"caller_nid": "post_migration_migrate", "callee": "list", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/migrations/19.0.1.0.0/post-migration.py", "source_location": "L112"}, {"caller_nid": "post_migration_migrate", "callee": "info", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_accounting_ai/migrations/19.0.1.0.0/post-migration.py", "source_location": "L115"}]}

Some files were not shown because too many files have changed in this diff Show More