gigafibre-fsm/docs/STATUS_2026-04-18b.md
louispaulb 41d9b5f316 feat: flow editor, Gemini QR scanner with offline queue, dispatch planning v2
Major additions accumulated over 9 days — single commit per request.

Flow editor (new):
- Generic visual editor for step trees, usable by project wizard + agent flows
- PROJECT_KINDS / AGENT_KINDS catalogs decouple UI from domain
- Drag-and-drop reorder via vuedraggable with scope isolation per peer group
- Chain-aware depends_on rewrite on reorder (sequential only — DAGs preserved)
- Variable picker with per-applies_to catalog (Customer / Quotation /
  Service Contract / Issue / Subscription), insert + copy-clipboard modes
- trigger_condition helper with domain-specific JSONLogic examples
- Global FlowEditorDialog mounted once in MainLayout, Odoo inline pattern
- Server: targo-hub flow-runtime.js, flow-api.js, flow-templates.js
- ERPNext: Flow Template/Run doctypes, scheduler, 5 seeded system templates
- depends_on chips resolve to step labels instead of opaque "s4" ids

QR/OCR scanner (field app):
- Camera capture → Gemini Vision via targo-hub with 8s timeout
- IndexedDB offline queue retries photos when signal returns
- Watcher merges late-arriving scan results into the live UI

Dispatch:
- Planning mode (draft → publish) with offer pool for unassigned jobs
- Shared presets, recurrence selector, suggested-slots dialog
- PublishScheduleModal, unassign confirmation

Ops app:
- ClientDetailPage composables extraction (useClientData, useDeviceStatus,
  useWifiDiagnostic, useModemDiagnostic)
- Project wizard: shared detail sections, wizard catalog/publish composables
- Address pricing composable + pricing-mock data
- Settings redesign hosting flow templates

Targo-hub:
- Contract acceptance (JWT residential + DocuSeal commercial tracks)
- Referral system
- Modem-bridge diagnostic normalizer
- Device extractors consolidated

Migration scripts:
- Invoice/quote print format setup, Jinja rendering
- Additional import + fix scripts (reversals, dates, customers, payments)

Docs:
- Consolidated: old scattered MDs → HANDOFF, ARCHITECTURE, DATA_AND_FLOWS,
  FLOW_EDITOR_ARCHITECTURE, BILLING_AND_PAYMENTS, CPE_MANAGEMENT,
  APP_DESIGN_GUIDELINES
- Archived legacy wizard PHP for reference
- STATUS snapshots for 2026-04-18/19

Cleanup:
- Removed ~40 generated PDFs/HTMLs (invoice_preview*, rendered_jinja*)
- .gitignore now covers invoice preview output + nested .DS_Store

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 10:44:17 -04:00

5.7 KiB

Status — 2026-04-18 (session 2)

Follow-up to STATUS_2026-04-18.md. This session was the sales-flow sprint.

What changed this session

1. Field scanner — offline resilience for weak-signal zones

Photos that can't reach Gemini Vision within 8s (weak LTE / no service) are now queued in IndexedDB and retried in the background; late results are merged back into the scanner UI when they arrive.

  • apps/field/src/stores/offline.js — new visionQueue, scanResults, enqueueVisionScan, syncVisionQueue, consumeScanResult. Driven off queue length (not navigator.onLine, which lies in basements).
  • apps/field/src/composables/useScanner.jsPromise.race with 8s timeout, retryable errors enqueue, late arrivals dispatched through onNewCode.
  • apps/field/src/pages/ScanPage.vue — pending chip "N scan(s) en attente".

2. Sales flow — residential contract wiring

The ProjectWizard now knows how to turn a quotation into the Service Contract (promotion-framing récap). The contract is the shopping-cart recap per your brief: "c'est un peu le récapitulatif d'un panier d'achat."

Entry from customer page: ClientDetailPage → Soumissions section now has a "+ Nouvelle soumission" button that opens the wizard pre-filled with customer phone/email/primary service location. Wizard skips to quotation mode

  • requireAcceptance=true by default when launched from a customer.

Residential presets (one-click):

  • Installation standard (Internet 500 + Routeur offert + Frais offerts, 24 mois)
  • Duo 300 + Tél (79.99$/mois, 24 mois, installation offerte)
  • Trio complet (119.99$/mois, 24 mois, routeur + installation offerts)
  • Internet seul (89.99$/mois, 12 mois)

Presets live in apps/ops/src/data/wizard-constants.jsRESIDENTIAL_PRESETS — edit there to tune prices / add bundles.

Promo framing on one-time items: each one-time line has a "Prix régulier (si promo)" field. When regular_price > rate, the line becomes a benefit on the Service Contract (e.g. Installation 75$ → 0$ = 75$ de promotion étalée sur 24 mois). Shown with celebration chip + line-through regular price in review.

What publish() now does on a residential quotation:

  1. Creates Quotation (as before).
  2. Creates Service Contract via hub /contract/create with duration_months = max(contract_months), monthly_rate = sum(recurring), benefits[] = onetime items where regular_price > rate, contract_type = 'Résidentiel' (or Commercial when DocuSeal is selected).
  3. Sends acceptance via /contract/send (promotion-framed récap, not the old Quotation /accept/generate) — résidentiel gets the "J'accepte ce récapitulatif" page; commercial gets DocuSeal.

If no recurring commitment items exist, the old /accept/generate path is still used (unchanged). Direct-order / prepaid modes are untouched.

Success screen shows the Service Contract name when one was created.

Files touched this session

apps/field/src/stores/offline.js                       +vision queue
apps/field/src/composables/useScanner.js               +timeout/retry
apps/field/src/pages/ScanPage.vue                      +pending chip
apps/ops/src/composables/useWizardPublish.js           +contract creation branch
apps/ops/src/composables/useWizardCatalog.js           +applyPreset
apps/ops/src/data/wizard-constants.js                  +RESIDENTIAL_PRESETS
apps/ops/src/components/shared/ProjectWizard.vue       +presets, promo UI, customer prop
apps/ops/src/pages/ClientDetailPage.vue                +Nouvelle soumission button + wizard dialog
docs/STATUS_2026-04-18.md                              scanner stack corrected (Gemini, not html5-qrcode)

Deployed

  • Ops app: dist/pwa/*/opt/ops-app/ at 2026-04-18 ~08:05 EDT. New bundle: index.caa91ade.js. Hard-reload in browser to pick up.
  • Field app: not yet deployed. Build + deploy when you want it live: cd apps/field && quasar build && scp -r dist/spa/* root@96.125.196.67:/opt/field-app/

End-to-end smoke test done

  • CTR-00001 for C-LPB4 (Louis-Paul Bourdon) created via manual hub call during the Service Contract prod-doctype setup. See memory/project_contract_acceptance.md for creation gotchas (Dispatch User role).
  • The wizard integration has not been exercised end-to-end yet — it compiles, UI renders, but please run one manual test on a real customer before announcing it.

Suggested test path when you're back

  1. Open ops → any customer → Soumissions → "+ Nouvelle soumission".
  2. Pick "Duo 300 + Tél" preset. Set Frais d'installation prix régulier = 75$ (rate stays 0 → benefit of 75$).
  3. Keep acceptation = JWT (Résidentiel).
  4. Publish. Confirm: Quotation created + Service Contract created + SMS sent.
  5. Open the SMS link on phone, click "J'accepte ce récapitulatif", verify contract goes Actif + signature_proof stored.

Known follow-ups (deliberately deferred)

  • Wizard doesn't yet let the agent pick Résidentiel vs Commercial independently of the acceptance method. Today: JWT = Résidentiel, DocuSeal = Commercial. If you want a large commercial client on JWT (or vice-versa), add a contract_type toggle in the expansion panel.
  • Presets use hard-coded prices. Eventually these should come from the live catalog (ERPNext Item price list) — same place loadCatalog() reads from.
  • /accept/send (old) and /contract/send (new) are two parallel paths. When the residential flow is proven, consider deprecating /accept/generate for quotations with recurring commitments.
  • Two-column visual split (recurring | one-time) was mentioned — current design keeps them in one list with swap button + promo chip, which seemed to stay readable. Flag if you want the split.