New models
- fusion.repair.service.plan.subscription
Tracks pre-paid maintenance packages: partner, plan product, optional
category restriction, visits_included / visits_used / visits_remaining,
start_date / end_date, computed state (active/exhausted/expired/cancelled),
burn_history One2many. PLAN-NNNNN sequence.
- fusion.repair.service.plan.burn
One row per maintenance visit that consumed a plan visit - feeds the
Burn History tab on the subscription form.
product.template extensions
- x_fc_is_service_plan boolean toggle
- x_fc_plan_visits_included (default 4)
- x_fc_plan_duration_months (default 12)
- x_fc_plan_category_id - if set, only burns for repairs in that category
(e.g. an Annual Stairlift Maintenance plan does not burn for wheelchair
repairs)
sale.order.action_confirm() override
- For each order line whose product has x_fc_is_service_plan=True,
spawns one fusion.repair.service.plan.subscription per qty unit.
- Start date = today; end date = today + plan_duration_months
(relativedelta - correct month boundaries).
Visit report wizard
- New _burn_service_plan_visit(repair) call from action_confirm() finds
the matching active subscription and burns one visit + posts a chatter
note "Visit burned for repair X. N of M remaining." on the subscription.
- Skips quote-only repairs.
- The wizard does NOT zero out the invoice - the burn is informational;
the office reconciles plan credits in their accounting workflow.
Backend
- Service Plans menu under Fusion Repairs root.
- List view colour-coded by state.
- Form with statusbar + cancel button + Burn History notebook.
- Service Plan tab added to product.template form (manager only).
- ACL: User read; Dispatcher write/create; Manager full + unlink.
Verified end-to-end on local westin-v19:
Created plan product 'Annual Stairlift Maintenance - 4 Visits'
Sold it via sale.order -> PLAN-00001 auto-created
(visits_included=4, end_date=2027-05-21)
Submitted visit-report on a stairlift repair -> visits_used=1
remaining=3 (correctly category-matched).
Bumped to 19.0.1.5.0.
Co-authored-by: Cursor <cursoragent@cursor.com>