Commit Graph

3 Commits

Author SHA1 Message Date
gsinghpal
b4b59cc3c9 feat(fusion_repairs): Bundle 7 - tech mobile (T3 + T4 + T6 + T7)
T3 Labour timer on technician task
- Two new fields on fusion.technician.task: x_fc_timer_running_since
  (Datetime) + x_fc_timer_accumulated_minutes (Float).
- action_timer_start / action_timer_stop methods, idempotent (start when
  already running is a no-op, stop when not running is a no-op).
- Multiple start/stop cycles accumulate into the same total.
- Two header buttons (Start Timer green / Stop Timer amber), invisible
  based on the running_since field so the right one shows at any time.
- Stop posts a chatter line 'Labour timer stopped. Added X.X min, total
  Y.Y min.' so audit history shows every shift.

T4 Client signature on visit report
- New client_signature Binary field on the visit-report wizard with
  Odoo native widget='signature' that draws on canvas + base64-encodes
  the PNG.
- client_signature_name Char for typed name (audit).
- Persisted as an ir.attachment on the repair.order via the new
  _persist_mobile_artefacts helper.
- Chatter post 'Client signature captured (Jane Smith).'.

T6 Replaced parts - serial capture
- parts_serial_capture Text on the wizard (one per line per the spec).
- On confirm, posted to chatter wrapped in <pre> so line breaks survive.
- Used by OEM warranty filing in future M8.

T7 Client no-show photo proof
- no_show Boolean + no_show_photo Binary with widget='image' (visible
  only when no_show=True via Odoo 19 invisible= conditional).
- Photo saved as ir.attachment on the repair when present.
- Chatter post 'Visit recorded as client no-show (photo attached)'.

Verified end-to-end on local westin-v19:
  T3 timer started -> 2s sleep -> stopped -> 0.0357 min recorded
  T4 attachment 'signature-RO-202605-17.png' created on repair
  T6 chatter shows 'SN-AAA-111 / SN-BBB-222'
  T4 chatter shows 'Client signature captured (Jane Smith)'

Bumped to 19.0.1.7.0.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-21 00:24:35 -04:00
gsinghpal
65c4d8801c feat(fusion_repairs): Bundle 4 - M1 compliance inspection certificates
New fusion.repair.inspection.certificate model for the annual safety
inspections required on stairlifts, porch lifts, and power wheelchairs
in many jurisdictions.

Model
- mail.thread chatter-tracked; fields: name (CERT-YYYY-NNNN auto-seq),
  partner_id, product_id (filtered to safety-critical categories), lot_id,
  repair_order_id back-link, inspector_user_id (must be field staff),
  jurisdiction (selection: Ontario / BC / Alberta / Quebec / Other),
  issued_date, valid_for_months (default 12), expiry_date (computed,
  stored, uses relativedelta - correct month boundaries), status
  (non-stored compute: valid / expiring / expired / revoked), revoked,
  notes, last_reminder_band.
- Unique constraint on certificate number (models.Constraint, not
  _sql_constraints, per project rule).
- Sequence 'fusion.repair.inspection.certificate' with use_date_range=True
  so the counter resets each year (CERT-2026-0001 ... CERT-2027-0001).

Visit report integration
- New issue_inspection_cert checkbox on fusion.repair.visit.report.wizard.
- When ticked AND the repair's category is safety_critical, action_confirm()
  creates the certificate via _create_inspection_certificate() and
  redirects to the cert form so the tech can print immediately.
- Non-safety-critical equipment quietly skips with a chatter note
  explaining why.

PDF report
- web.html_container + web.external_layout, model bound so it appears
  as a Print action on the certificate form.
- 'Certificate of Inspection' / 'Safety Inspected' gold-banner layout
  with client name, equipment, serial, jurisdiction, issued + expiry
  dates, inspector signature line, and the certificate number.
- Print Certificate button in form header.

Daily cron
- cron_send_expiry_reminders runs at 09:00, sends two band-tracked
  reminders (30 days + 7 days before expiry) to the client.
- New mail.template email_template_inspection_expiry_reminder with
  4px amber accent, certificate ref, equipment, expiry date, and a
  CTA to call to book the re-inspection visit.
- last_reminder_band on the cert prevents re-sending the same band.

Backend wiring
- New menu entry 'Fusion Repairs > Inspection Certificates'.
- ACL: User read, Dispatcher write, Manager unlink. Field technicians
  can create (they need to issue from the field).
- List view with red/amber/green status decoration.
- Form with statusbar, header buttons (Print, Revoke with confirm),
  chatter.

Verified end-to-end on local westin-v19:
  Stairlift repair RO-202605-15 -> visit-report with issue_inspection_cert=True
  -> CERT-2026-0001 issued (status=valid, expires 2027-05-21)
  Cert CERT-2026-0002 expiring in 30 days -> cron flagged
  last_reminder_band='30' (would email client).

Bumped to 19.0.1.4.0 (minor bump for the new public-facing capability).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-21 00:11:59 -04:00
gsinghpal
7727745b73 feat(fusion_repairs): Phase 2 - service catalogue, visit report, warranty, Poynt
Service catalogue
- New fusion.repair.service.catalog model: named service entries per
  equipment category with symptom keywords, estimated hours / cost,
  default parts, auto_schedule flag, optional pricelist override
- find_best_match() scores candidates by symptom-keyword overlap against
  intake text hints (issue summary + category + notes)
- Intake service wires it in: on submit, the matcher sets
  x_fc_service_catalog_id + x_fc_estimated_duration + x_fc_estimated_cost
  and (when auto_schedule=True) creates a draft dispatch task
- Double-task guard: if catalogue match already created a task, the
  urgency-based dispatch skips so we never duplicate

Visit report wizard
- fusion.repair.visit.report.wizard with labour hours + parts lines +
  technician notes + 'found another issue' branch
- Computes actual cost = (labour x service_product.list_price) + parts
- Compares against estimate -> sets requires_requote when variance
  exceeds configured threshold (% or $); shows warning banner inline
- On confirm: writes actuals back to repair, posts notes to chatter,
  optionally spawns a follow-up repair (T5 'found another issue')

Repair warranty
- New fusion.repair.warranty.coverage model (start/expiry, partner,
  product, lot, active flag)
- find_active_for(partner, product, lot) returns the most-recent active
  coverage
- Intake service auto-checks: when a new repair lands on an equipment
  that has active warranty coverage, posts a chatter banner so the
  office knows the work may be free under our 30/90-day re-do policy
  (manager review still required; never auto-zeros pricing)

Repair form
- Header: Visit Report + Collect Payment buttons (gated by group)
- action_collect_payment looks up the linked posted unpaid invoice on
  the repair SO and opens the Poynt wizard (action_open_poynt_payment_wizard)

AI intake summary
- _generate_ai_summary calls self.env['fusion.api.service'].call_openai
  with consumer='fusion_repairs', feature='intake_triage'
- Strict system prompt: no medical advice, no diagnoses, no recommending
  stop equipment use; ~80 words; plain English
- Try/fallback per fusion-api-integration.mdc: if fusion_api not
  installed or call fails -> silently skip; intake never blocked

Verified end-to-end on local westin-v19:
- Stairlift motor intake -> catalogue match -> estimated $500/2h -> auto
  dispatch task (count=1, not duplicated)
- Visit report: 2.5h x $250 + $100 parts = $725 actual vs $500 estimated
  = 45% variance -> requires_requote=True
- Warranty: 30-day coverage on the completed repair; second repair on
  same partner triggers warranty banner in chatter

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-20 21:57:33 -04:00