From 43e1f3d6f52a68971440d89dfd39ba134b1e5fa3 Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Sun, 19 Apr 2026 20:25:16 -0400 Subject: [PATCH] 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 --- fusion_accounting_assets/CLAUDE.md | 130 ++++++++++++++++++++++ fusion_accounting_assets/README.md | 53 +++++++++ fusion_accounting_assets/UPGRADE_NOTES.md | 49 ++++++++ 3 files changed, 232 insertions(+) create mode 100644 fusion_accounting_assets/CLAUDE.md create mode 100644 fusion_accounting_assets/README.md create mode 100644 fusion_accounting_assets/UPGRADE_NOTES.md diff --git a/fusion_accounting_assets/CLAUDE.md b/fusion_accounting_assets/CLAUDE.md new file mode 100644 index 00000000..e7b109b8 --- /dev/null +++ b/fusion_accounting_assets/CLAUDE.md @@ -0,0 +1,130 @@ +# 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 diff --git a/fusion_accounting_assets/README.md b/fusion_accounting_assets/README.md new file mode 100644 index 00000000..2815180b --- /dev/null +++ b/fusion_accounting_assets/README.md @@ -0,0 +1,53 @@ +# fusion_accounting_assets + +AI-augmented fixed asset management for Odoo 19 Community — a +Fusion-native replacement for Enterprise's `account_asset` module. + +## What it does + +- Three depreciation methods: straight-line, declining balance, and + units-of-production +- Asset lifecycle state machine: draft → running → paused → disposed +- Editable depreciation board with full schedule recompute +- Disposal flow (sale, scrap, donation) plus partial-sale wizard +- Daily cron for posting periodic depreciation +- AI augmentation: + - **Anomaly detection** — variance vs expected schedule, low utilization + - **Useful-life suggestion** — LLM-driven from invoice context, with a + keyword-based templated fallback so the feature still works offline +- Coexists with Enterprise `account_asset` (Enterprise wins by default; + the Fusion menu only appears when Enterprise is uninstalled) +- Migration-aware: bootstrap step backfills `fusion.asset` from existing + `account.asset` rows so the AI has memory from day 1 + +## Quick start + +```bash +# Install +odoo --addons-path=... -i fusion_accounting_assets + +# Open the dashboard (when Enterprise's account_asset is NOT installed) +# Apps -> Asset Management -> Assets + +# When Enterprise IS installed: use Enterprise's UI; the engine + AI tools +# are still available via the AI chat. +``` + +## Configuration + +- Local LLM (LM Studio, Ollama): + - `fusion_accounting.openai_base_url` = + `http://host.docker.internal:1234/v1` + - `fusion_accounting.openai_model` = your local model name + - `fusion_accounting.openai_api_key` = `lm-studio` (anything non-empty) + - `fusion_accounting.provider.asset_useful_life` = `openai` + +## Public API (engine) + +`fusion.asset.engine` is the single write surface. See `CLAUDE.md` for +the full 7-method signature list. + +## See also + +- `CLAUDE.md` — agent context +- `UPGRADE_NOTES.md` — Odoo version anchoring diff --git a/fusion_accounting_assets/UPGRADE_NOTES.md b/fusion_accounting_assets/UPGRADE_NOTES.md new file mode 100644 index 00000000..916420b1 --- /dev/null +++ b/fusion_accounting_assets/UPGRADE_NOTES.md @@ -0,0 +1,49 @@ +# fusion_accounting_assets — Upgrade Notes + +## Odoo Version Anchor + +This module targets **Odoo 19.0** (community-base). + +Reference snapshot of Enterprise code mirrored from: +- `account_asset` (Odoo 19.0.x) +- Source: `/Users/gurpreet/Github/RePackaged-Odoo/accounting/account_asset/` + +## Cross-Version Diff Strategy + +When a new Odoo version ships: + +1. Run `check_odoo_diff.sh` (in repo root) against the new Enterprise version +2. Note any breaking changes in `account.asset` / `account.move.line` API +3. For mirrored OWL components, diff Enterprise's new versions against ours + and port material changes (signature renames, new behaviour we want to + inherit) +4. Re-run the full test suite + tour tests against the new Odoo version +5. Update this file with the new version anchor + any deviations + +## V19 Migration Notes (already applied) + +- `_sql_constraints` → `models.Constraint` (every persisted model) +- `@api.depends('id')` → removed (none introduced) +- `@route(type='json')` → `type='jsonrpc'` (all 8 endpoints in + `controllers/assets_controller.py`) +- `numbercall` removed from `ir.cron` (data/cron.xml) +- `res.groups.users` → `user_ids` and `ir.ui.menu.groups_id` → + `group_ids` (security + menu_views.xml) + +## Phase 3 → Phase 3.5 Migration + +If we ship Phase 3.5 (sub-annual depreciation frequency, disposal journal +entries, multi-currency, allocation rules), changes will go in +incremental commits. No DB migration needed (Phase 3 schema is +forward-compatible — new columns will be nullable / default-valued). + +## Coexistence with Enterprise `account_asset` + +The migration step in `fusion.migration.wizard` backfills `fusion.asset` +records from existing `account.asset` rows. It is idempotent (skips rows +already linked via the `legacy_account_asset_id` column). Verified live +on westin-v19: 2 records migrated cleanly. + +When `account_asset` is installed the Asset Management menu hides via +`fusion_accounting_core.group_fusion_show_when_enterprise_absent`. The +engine and AI tools remain available for chat-driven workflows.