Files
Odoo-Modules/fusion_accounting/PHASE_3_PLAN.md
gsinghpal 99b6990dd6 feat(fusion_accounting_assets): Phase 3 skeleton + plan
50-task plan to replace Enterprise account_asset module:
- CORE scope: 3 depreciation methods (straight-line, declining-balance, units-of-production)
- HYBRID engine: shared primitives + persisted asset/category/disposal/anomaly models
- AI augmentation: utilization anomaly detection + LLM-suggested useful life
- Full lifecycle: draft -> running -> paused -> disposed
- Coexists with Enterprise (group_fusion_show_when_enterprise_absent)
- Same V19 conventions + test pyramid + perf-budget discipline as Phases 1-2

Skeleton: empty manifest + dirs + icon. Tasks 3-50 add the substance.
Made-with: Cursor
2026-04-19 16:43:06 -04:00

7.5 KiB

Phase 3 — Fusion Accounting Assets Implementation Plan

Module: fusion_accounting_assets Branch: fusion_accounting/phase-3-assets Pre-phase tag: fusion_accounting/pre-phase-3 Estimated tasks: ~50 Reference: /Users/gurpreet/Github/RePackaged-Odoo/accounting/account_asset/ (~2258 LOC Python)

Goal

Replace Odoo Enterprise's account_asset module — asset management with depreciation schedules, disposal, partial sale, and reporting. CORE scope: 3 depreciation methods (straight-line, declining balance, units of production), full asset lifecycle, depreciation board, disposal/sale wizards. AI augmentation: utilization anomaly detection + AI-suggested useful life from invoice context. Coexists with Enterprise.

Architecture (HYBRID engine, Phase 1+2 pattern)

fusion.asset.engine (AbstractModel)         ← shared primitives
├── compute_depreciation_schedule(asset, recompute=False)
├── post_depreciation_entry(asset, period)
├── dispose_asset(asset, *, sale_amount, sale_date, sale_partner=None)
├── partial_sale(asset, *, sold_amount, sold_qty, sale_date)
├── pause_asset(asset, pause_date)
├── resume_asset(asset, resume_date)
└── reverse_disposal(asset)

services/                                    ← pure-Python
├── depreciation_methods.py  → straight_line, declining_balance, units_of_production
├── prorate.py               → first/last period prorating (calendar/365/etc.)
├── salvage_value.py         → end-of-life value math
├── anomaly_detection.py     → utilization variance vs expected
├── useful_life_predictor.py → LLM-suggested useful life from invoice description
└── useful_life_prompt.py    → provider-agnostic LLM prompt

models/
├── fusion_asset.py                  → main fusion.asset model
├── fusion_asset_depreciation_line.py → depreciation board lines
├── fusion_asset_category.py          → categories with default settings
├── fusion_asset_disposal.py          → disposal records
├── fusion_asset_anomaly.py           → flagged utilization issues
├── fusion_asset_engine.py            → AbstractModel orchestrator
└── account_move.py                   → inherit (link to asset, generate from invoice)

controllers/assets_controller.py            ← 8 JSON-RPC endpoints
├── /fusion/assets/list                      → paginated asset list with filters
├── /fusion/assets/get_detail                → single asset with full schedule
├── /fusion/assets/compute_schedule          → recompute depreciation board
├── /fusion/assets/post_depreciation         → run periodic depreciation cron
├── /fusion/assets/dispose                   → dispose an asset
├── /fusion/assets/get_anomalies             → list flagged variances
├── /fusion/assets/suggest_useful_life       → AI suggest useful life
└── /fusion/assets/get_partner_history       → asset-related partner history

static/src/
├── scss/                          ← asset-specific design tokens
├── services/assets_service.js     ← reactive state + RPC wrappers
├── views/asset_dashboard/         ← top-level OWL controller
└── components/                    ← asset_card, depreciation_board, disposal_dialog,
                                     ai_useful_life_panel, anomaly_strip

Coexistence

group_fusion_show_when_enterprise_absent from fusion_accounting_core. Asset menu only visible when account_asset NOT installed. Engine + AI tools always available.

Tasks (50 total)

Group 1: Foundation (1-2)

  1. Safety net (DONE)
  2. Plan doc + module skeleton

Group 2: Pure-Python services TDD (3-7)

  1. services/depreciation_methods.py — straight_line + declining_balance + units_of_production (TDD)
  2. services/prorate.py — first/last period prorating
  3. services/salvage_value.py — end-of-life math
  4. services/anomaly_detection.py — utilization variance
  5. services/useful_life_predictor.py + useful_life_prompt.py — LLM integration

Group 3: Persisted models (8-13)

  1. models/fusion_asset.py — main asset model with state machine
  2. models/fusion_asset_depreciation_line.py — depreciation board lines
  3. models/fusion_asset_category.py — categories with defaults
  4. models/fusion_asset_disposal.py — disposal records
  5. models/fusion_asset_anomaly.py — flagged anomalies
  6. models/account_move.py (inherit) — link asset to invoice

Group 4: Engine (14-15)

  1. models/fusion_asset_engine.py — 7-method API
  2. Engine integration tests (compute_schedule + post_depreciation + dispose end-to-end)

Group 5: Backend wiring (16-19)

  1. JSON-RPC controller (8 endpoints)
  2. AssetsAdapter wiring _via_fusion paths
  3. 5 new AI tools
  4. Cron — daily depreciation post + monthly anomaly scan

Group 6: Tests + perf (20-23)

  1. Property-based tests (Hypothesis: schedule sums == cost - salvage)
  2. Integration tests — straight-line + declining-balance + units-of-production
  3. Materialized view for asset book values (perf)
  4. Performance benchmarks

Group 7: Frontend OWL (24-31)

  1. SCSS tokens + main asset stylesheet (light + dark)
  2. assets_service.js (reactive state + RPC wrappers)
  3. asset_dashboard (top-level kanban + summary)
  4. asset_card (one asset summary card)
  5. asset_detail_panel (right-side: schedule, history, AI suggestions)
  6. depreciation_board (table view of schedule with edit chevrons)
  7. disposal_dialog (sale/scrap wizard)
  8. Fusion-only: ai_useful_life_panel + anomaly_strip

Group 8: Wizards (32-35)

  1. Asset creation wizard (from invoice line)
  2. Disposal wizard (sale, scrap, donation)
  3. Partial sale wizard
  4. Period picker for depreciation runs

Group 9: Migration + coexistence (36-39)

  1. Migration wizard inheritance — backfill from account.asset rows
  2. Audit report PDF (per-company asset count, total NBV, etc.)
  3. Menu + window action with coexistence group filter
  4. Coexistence test

Group 10: Final tests + polish (40-50)

  1. 5 OWL tour tests
  2. Performance benchmarks (P95: schedule compute < 500ms, board render < 200ms)
  3. Optimize if benchmarks fail (conditional)
  4. Local LLM compat test for useful_life_predictor
  5. Update meta-module manifest
  6. CLAUDE.md, UPGRADE_NOTES.md, README.md
  7. End-to-end smoke + tag phase-3-complete + push 47-50. Reserved for inherited features: account_move integration, draft journal entries, post-on-confirm flow, fiscal-year-aware proration

Performance Targets (P95)

  • compute_schedule (10-year asset): <500ms
  • post_depreciation_entry: <200ms
  • dispose_asset: <300ms
  • Controller list: <300ms
  • Controller get_detail: <500ms

V19 Conventions (carried from Phase 1+2)

  • models.Constraint not _sql_constraints
  • No @api.depends('id') on stored compute fields
  • @route(type='jsonrpc') not type='json'
  • ir.cron has no numbercall field
  • res.groups.user_ids not users
  • ir.ui.menu.group_ids not groups_id
  • models.Constraint for unique-keys
  • env.flush_all() before MV REFRESH
  • REFRESH MATERIALIZED VIEW CONCURRENTLY needs autocommit cursor

Test Targets

Match Phase 1+2 test pyramid:

  • Unit (pure-Python services)
  • Integration (engine end-to-end)
  • Property-based (Hypothesis: schedule total invariants)
  • Controller (HttpCase JSON-RPC)
  • MV correctness
  • Performance benchmarks (tagged 'benchmark')
  • OWL tours (tagged 'tour')
  • Local LLM smoke (tagged 'local_llm')

Phase 1+2 final: 287 tests. Phase 3 target: ~140-180 additional → ~430-470 total.