Files
Odoo-Modules/fusion_accounting_assets/CLAUDE.md
gsinghpal 43e1f3d6f5
Some checks failed
fusion_accounting CI / test (fusion_accounting_ai) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_core) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_migration) (push) Has been cancelled
docs(fusion_accounting_assets): CLAUDE.md, UPGRADE_NOTES.md, README.md
Mirrors Phase 1 + 2 doc layout. CLAUDE.md captures architecture, the
7-method engine API, persisted models, controllers, OWL frontend,
performance baselines (Tasks 23 + 41 numbers), test counts (140), and
Phase 3.5 backlog. UPGRADE_NOTES.md anchors the Odoo 19 reference and
records V19 deprecations applied. README.md is the user-facing intro.

Made-with: Cursor
2026-04-19 20:25:16 -04:00

131 lines
6.1 KiB
Markdown

# fusion_accounting_assets — Cursor / Claude Context
## Purpose
AI-augmented fixed asset management with depreciation schedules — a
Fusion-native replacement for (and coexisting with) Odoo Enterprise's
`account_asset` module. Ships in Phase 3 of the fusion_accounting roadmap.
## Architecture
Hybrid: the engine (`fusion.asset.engine`, AbstractModel) is the SINGLE
write surface for the asset lifecycle. Everything else (controllers, OWL
widget, AI tools, wizards, cron) routes through the engine's 7-method
public API:
- `compute_depreciation_schedule(asset, recompute=False)`
- `post_depreciation_entry(asset, period_date=None)`
- `dispose_asset(asset, sale_amount=0, sale_date=None, sale_partner=None, disposal_type='sale')`
- `partial_sale(asset, sold_amount, sold_qty=None, sale_date=None, sale_partner=None)`
- `pause_asset(asset, pause_date=None)`
- `resume_asset(asset, resume_date=None)`
- `reverse_disposal(asset)`
Pure-Python services live in `services/`:
- `depreciation_methods` — straight_line, declining_balance, units_of_production
- `prorate` — first/last-period prorating: full_month, days_365, days_period
- `salvage_value` — % of cost, fixed amount, zero
- `anomaly_detection` — variance vs expected schedule, low utilization
- `useful_life_predictor` + `useful_life_prompt` — LLM-suggested useful life with templated fallback
Persisted models in `models/`:
- `fusion.asset` — main model, state machine: draft → running → paused → disposed
- `fusion.asset.depreciation.line` — board lines
- `fusion.asset.category` — templates
- `fusion.asset.disposal` — disposal records
- `fusion.asset.anomaly` — flagged variances
- `fusion.asset.book.values.mv` — pre-aggregated materialized view
- `fusion.asset.engine` — AbstractModel (the API)
- `fusion.assets.cron` — cron handlers (post depreciations, MV refresh, anomaly scan)
- `account.move.line` (inherits) — adds `fusion_asset_id` linkage
- `fusion.migration.wizard` (inherits in `models/`) — adds asset backfill step
Wizards (TransientModel) in `wizards/`:
- `fusion.create.asset.wizard` — assisted creation with AI useful-life suggestion
- `fusion.disposal.wizard` — full disposal flow
- `fusion.partial.sale.wizard` — partial-quantity disposal
- `fusion.depreciation.run.wizard` — period close runner
Controller: `controllers/assets_controller.py` exposes 8 JSON-RPC
endpoints under `/fusion/assets/*` (list, get_detail, compute_schedule,
post_depreciation, dispose, get_anomalies, suggest_useful_life,
get_partner_history). All calls route through the engine.
OWL frontend: `static/src/`
- `services/assets_service.js` — central reactive state + RPC wrappers
- `views/asset_dashboard/*` — top-level dashboard view
- `components/asset_card`, `asset_detail_panel`, `depreciation_board`,
`disposal_dialog`, `ai_useful_life_panel`, `anomaly_strip` — 6 components
- `scss/_variables.scss` + `assets.scss` + `dark_mode.scss`
- `tours/assets_tours.js` — 5 OWL tour smoke tests
## Coexistence
When `account_asset` is installed the Asset Management menu hides via
`fusion_accounting_core.group_fusion_show_when_enterprise_absent` (a
computed group). The engine + AI tools remain available for the chat.
The migration wizard backfills `fusion.asset` from existing
`account.asset` records (verified live: 2 records, Task 35).
## Conventions
- **V19 deprecations to avoid:** `_sql_constraints` (use
`models.Constraint`), `@api.depends('id')` (raises
`NotImplementedError`), `@route(type='json')` (use `type='jsonrpc'`),
`numbercall` field on `ir.cron` (removed), `groups_id` on `res.users`
(use `all_group_ids` for searching), `users` field on `res.groups`
(use `user_ids`), `groups_id` on `ir.ui.menu` (use `group_ids`).
- **Materialized view refresh:** `fusion.asset.book.values.mv` is
refreshed by cron (REFRESH CONCURRENTLY in an autocommit cursor since
it can't run inside a regular Odoo transaction).
- **Provider routing:** AI features look up
`fusion_accounting.provider.asset_useful_life`, falling back to
`fusion_accounting.provider.default`. When neither is set the
templated keyword fallback in `useful_life_predictor` keeps the
feature usable offline.
## Performance baseline (Tasks 23 + 41)
| Operation | P95 | Budget | Headroom |
|------------------------------------|-------|----------|----------|
| `engine.compute_schedule` (10yr SL)| 1ms | 500ms | 500x |
| `engine.post_depreciation_entry` | <1ms | 300ms | huge |
| `engine.dispose_asset` | 5ms | 300ms | 60x |
| `controller.list` (35 assets) | 42ms | 300ms | 7x |
| `controller.get_detail` | 40ms | 500ms | 12x |
All Phase 3 perf metrics are within 1x of budget; no optimization was
needed at ship (Task 42 skipped per the conditional rule).
## Test counts (Phase 3 ship)
- 140 logical tests total in fusion_accounting_assets
- 0 failures, 0 errors
- Coverage includes: 4 engine benchmarks + 1 controller benchmark
(tagged `benchmark`), 1 local LLM smoke (tagged `local_llm`, skips
when no LLM), 5 OWL tour tests (tagged `tour`, skip without
websocket-client), Hypothesis property tests on the engine,
integration tests on the public API, controller round-trip tests, MV
shape tests.
## Known concerns / Phase 3.5 backlog
- Sub-annual depreciation frequency (currently annual only)
- Units-of-production assumes even per-period units
- Disposal journal entry not yet created — `dispose_asset` writes the
`fusion.asset.disposal` record but not the cash / gain-loss move
- Multi-currency, allocation rules, and analytic tags for depreciation
moves are out of scope for Phase 3
- Partial-sale child asset is created with no own depreciation schedule
pre-disposal
- Migration wizard inheritance lives in `models/` rather than
`wizards/` (small inconsistency with the rest of the wizard layout —
intentional to keep ORM ordering simple)
- `useful_life_predictor` always returns a usable dict (templated
fallback when LLM absent), so callers can't distinguish "AI said so"
from "fallback fired"; the `confidence` key is the only signal