From fa37426f34cbcfff7eeca915283d4b61e9635529 Mon Sep 17 00:00:00 2001 From: louispaulb Date: Fri, 3 Apr 2026 09:37:38 -0400 Subject: [PATCH] docs: data structure foundation for lead-to-service pipeline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ERPNext doctype relationships and field additions: - Customer → Service Location → Subscriptions + Equipment - Project with installation task templates - Dispatch Job linked to project and location - New custom fields: wifi_ssid/password, sip_username/password, gpon_serial, cwmp_serial, radius credentials on Service Equipment Order wizard flow (website + agent): - Address check → plan selection → customer info → dates → payment - Atomic creation: Customer + Location + Subs + Equipment + Project + Tasks + Dispatch Job + fibre port reservation Existing field tech app inventory: - TasksPage (jobs + tickets), ScanPage (photo/live/manual), DevicePage (detail + customer link), DiagnosticPage (speed test) - useScanner composable (3-strip photo scan for multi-barcode) - Offline queue with replay Migration gaps identified: WiFi/VoIP provisioning data, RADIUS credentials, product catalog, fibre→RQA address matching Co-Authored-By: Claude Opus 4.6 --- docs/DATA-STRUCTURE-FOUNDATION.md | 394 ++++++++++++++++++++++++++++++ 1 file changed, 394 insertions(+) create mode 100644 docs/DATA-STRUCTURE-FOUNDATION.md diff --git a/docs/DATA-STRUCTURE-FOUNDATION.md b/docs/DATA-STRUCTURE-FOUNDATION.md new file mode 100644 index 0000000..d88604d --- /dev/null +++ b/docs/DATA-STRUCTURE-FOUNDATION.md @@ -0,0 +1,394 @@ +# Data Structure Foundation — Lead to Live Service + +## ERPNext Doctype Relationships + +``` + ┌──────────────┐ + │ Lead │ ← Website visitor / phone call + │ (new type) │ Not yet a customer + └──────┬───────┘ + │ Convert to Customer + ▼ +┌───────────────────────────────────────────────────────────┐ +│ Customer │ +│ name, email, phone, customer_group (Résidentiel/Comm.) │ +│ stripe_id, legacy_customer_id │ +└──────────┬─────────────────────────┬──────────────────────┘ + │ │ + ▼ ▼ +┌─────────────────────┐ ┌─────────────────────────┐ +│ Service Location │ │ Sales Invoice │ +│ (delivery address) │ │ Payment Entry │ +│ │ │ (billing) │ +│ address, city, zip │ └─────────────────────────┘ +│ lat, lng │ +│ connection_type │ +│ olt_name, olt_ip │ +│ frame/slot/port │ +│ ont_id │ +│ status: Pending → │ +│ Active │ +│ fibre_id (legacy) │ +└──────┬──────────────┘ + │ + ├──────────────────────────────────┐ + ▼ ▼ +┌──────────────────┐ ┌──────────────────────┐ +│ Service │ │ Service Equipment │ +│ Subscription │ │ │ +│ │ │ serial_number │ +│ item (product) │ │ mac_address │ +│ status: Pending │ │ equipment_type │ +│ → Active │ │ brand, model │ +│ start_date │ │ status: En inventaire│ +│ billing_interval │ │ → Actif │ +│ rate (monthly $) │ │ olt_* fields │ +└──────────────────┘ │ wifi_ssid (new) │ + │ wifi_password (new) │ + │ sip_username (new) │ + │ sip_password (new) │ + └──────────────────────┘ + +┌──────────────────────────────────────────────────┐ +│ Project │ +│ "Installation - {customer_name}" │ +│ customer, service_location │ +│ status: Open → Completed │ +│ │ +│ ┌─── Task ────────────────────────────────┐ │ +│ │ "Préparer équipement" │ support │ │ +│ │ "Activer port OLT" │ support │ │ +│ │ "Configurer WiFi/VoIP" │ support │ │ +│ │ "Installation sur site" │ tech │ │ +│ │ "Vérifier signal" │ tech │ │ +│ │ "Confirmer service" │ tech │ │ +│ └─────────────────────────────────────────┘ │ +└──────────────────────────────────────────────────┘ + +┌──────────────────────────────────────────────────┐ +│ Dispatch Job │ +│ customer, service_location │ +│ project (link to Installation project) │ +│ scheduled_date, preferred_dates │ +│ assigned_technician │ +│ required_tags: [Fibre, Installation] │ +│ equipment_list (child table) │ +│ status: Scheduled → In Progress → Completed │ +└──────────────────────────────────────────────────┘ + +┌──────────────────────────────────────────────────┐ +│ Issue (Ticket) │ +│ customer, service_location │ +│ subject, description │ +│ issue_type: Installation, Support, Réparation │ +│ status: Open → Resolved → Closed │ +│ linked_project (new field) │ +└──────────────────────────────────────────────────┘ +``` + +--- + +## New Doctype: Installation Order (or use Lead + Project) + +Rather than creating a new doctype, we use ERPNext's existing **Lead** → **Customer** conversion + **Project** with tasks. The wizard creates everything in one shot. + +### Option A: Use ERPNext Lead Doctype + +``` +Lead (ERPNext built-in) + lead_name: "Jean Tremblay" + email_id, phone + source: "Website" | "Phone" | "Walk-in" + status: "Lead" → "Opportunity" → "Converted" → "Do Not Contact" + + Custom fields: + address_line, city, postal_code + fibre_id (link to fibre table entry) + olt_port (frame/slot/port) + requested_services: ["Internet", "TV", "Phone"] + internet_plan: "FTTH150I" + tv_package: "TVBSTANDARD" + phone: Check + preferred_date_1, preferred_date_2, preferred_date_3 + stripe_payment_intent + notes +``` + +### Option B: Direct Customer Creation (simpler) + +Skip Lead, create Customer directly on checkout. Use a Project as the "order" container. + +**Recommended: Option B** — for self-service checkout, the customer already paid. No need for a Lead stage. For phone orders, the agent creates the customer directly too. + +--- + +## The Wizard Flow (Website or Agent) + +### Step 1: Address Check +``` +Input: address string +Output: fibre entry (id, olt_port, max_speed, zone_tarifaire) + OR "not available" → lead capture +``` + +### Step 2: Plan Selection +``` +Input: fibre zone_tarifaire +Output: available plans with pricing + - Internet: filtered by max_speed and zone + - TV: always available if internet selected + - Phone: always available (even without fiber) + - Discounts: auto-calculated (2x, 3x, 4x combo) +``` + +### Step 3: Customer Info +``` +Input: name, email, phone + preferred installation dates (3 choices) + OR "contactez-moi" +Output: customer data ready for creation +``` + +### Step 4: Payment (Stripe) +``` +Input: card details (Stripe Elements) +Output: payment_intent confirmed + First month pro-rated + one-time charges +``` + +### Step 5: Order Creation (atomic — all or nothing) +``` +Creates in ERPNext (via targo-hub or n8n): + +1. Customer + { customer_name, email, phone, customer_group } + +2. Service Location + { customer, address, olt_port, fibre_id, status: "Pending Install" } + +3. Service Subscriptions (one per service) + { customer, location, item: FTTH150I, status: "Pending" } + { customer, location, item: TVBSTANDARD, status: "Pending" } + { customer, location, item: TELEPMENS, status: "Pending" } + +4. Service Equipment (placeholders — serials TBD by tech) + { customer, location, type: "ONT", status: "En inventaire" } + { customer, location, type: "Routeur", status: "En inventaire" } + { customer, location, type: "Décodeur TV", status: "En inventaire" } (if TV) + +5. Project "Installation - Jean Tremblay" + { customer, service_location, status: "Open" } + Tasks: + - Préparer équipement (assigné: support) + - Activer port OLT {frame/slot/port} (assigné: support) + - Configurer WiFi (assigné: support, auto-possible) + - Configurer VoIP (if phone, assigné: support) + - Installation sur site (assigné: tech via dispatch) + - Vérifier signal ONT (assigné: tech) + - Confirmer service fonctionnel (assigné: tech) + +6. Dispatch Job + { customer, location, project, scheduled_date: preferred_date_1, + tags: [Fibre, Installation], status: "Scheduled" } + +7. Reserve Fibre Port + UPDATE fibre SET sn = 'RESERVED-{customer_id}' WHERE id = {fibre_id} + +8. Notifications + - SMS to customer (Twilio): "Commande confirmée!" + - Email to customer (Mailjet): order summary + - SSE to Ops: new-installation event +``` + +--- + +## Provisioning Data on Service Equipment + +### New Custom Fields Needed + +```python +# On Service Equipment doctype, add: + +# WiFi provisioning (for Deco routers) +custom_wifi_ssid = Data, label="WiFi SSID" +custom_wifi_password = Password, label="WiFi Password" +custom_wifi_ssid_5g = Data, label="WiFi SSID 5GHz" (if different) +custom_wifi_enabled = Check, label="WiFi Enabled", default=1 + +# VoIP provisioning (for ONTs with phone) +custom_sip_username = Data, label="SIP Username" +custom_sip_password = Password, label="SIP Password" +custom_sip_line = Int, label="SIP Line Number", default=1 + +# GPON provisioning +custom_gpon_serial = Data, label="GPON Serial" (physical sticker: RCMG/TPLG) +custom_cwmp_serial = Data, label="CWMP Serial" (GenieACS internal) +custom_fibre_line_profile = Data, label="Line Profile ID" +custom_fibre_service_profile = Data, label="Service Profile ID" + +# RADIUS (for PPPoE if applicable) +custom_radius_user = Data, label="RADIUS Username" +custom_radius_password = Password, label="RADIUS Password" +``` + +### WiFi Generation on Order +``` +When order is created: + 1. Generate WiFi SSID: "Gigafibre-{lastname}" or customer-chosen + 2. Generate WiFi password: random 12-char alphanumeric + 3. Store on Service Equipment (Routeur type) + 4. When tech installs Deco → it bootstraps → ACS reads WiFi from ERPNext + via targo-hub: GET /devices/{mac}/provision → returns SSID/password +``` + +### VoIP Provisioning on Order +``` +When phone service ordered: + 1. Allocate SIP account from Fonoster/Routr + POST /telephony/credentials → creates SIP user + 2. Store SIP username/password on Service Equipment (ONT type) + 3. When tech installs ONT → it bootstraps → ACS reads VoIP from ERPNext + via targo-hub: GET /devices/{serial}/provision → returns SIP creds +``` + +--- + +## Fibre Availability: Linking to RQA Addresses + +### Current State +- `fiber_availability` table in Supabase: uuidadresse → zone_tarifaire + max_speed +- This table was imported from a different source than the legacy `fibre` table +- They need to be linked + +### Target +```sql +-- Add fibre_id column to fiber_availability +ALTER TABLE fiber_availability ADD COLUMN fibre_id INTEGER; +ALTER TABLE fiber_availability ADD COLUMN olt_ip VARCHAR(64); +ALTER TABLE fiber_availability ADD COLUMN olt_port VARCHAR(16); -- "0/3/2" +ALTER TABLE fiber_availability ADD COLUMN ont_slot INTEGER; -- available ontid +ALTER TABLE fiber_availability ADD COLUMN port_available BOOLEAN DEFAULT true; + +-- Match fibre entries to RQA addresses +-- Strategy: postal code + street name fuzzy match + civic number +UPDATE fiber_availability fa +SET fibre_id = f.id, + olt_ip = f.info_connect, + olt_port = CONCAT(f.frame, '/', f.slot, '/', f.port), + port_available = (f.sn IS NULL OR f.sn = '' OR f.sn LIKE 'RESERVED%') +FROM fibre f +JOIN addresses a ON a.identifiant_unique_adresse = fa.uuidadresse +WHERE similarity(lower(f.rue), lower(a.odonyme_recompose_normal)) > 0.5 + AND lower(f.ville) = lower(a.nom_municipalite) + AND f.zip = a.code_postal; +``` + +### Alternative: Serve Fibre Data Directly +Instead of linking to Supabase, have targo-hub serve a `/availability` endpoint that queries the legacy fibre table directly: + +``` +GET /availability?q=123+rue+principale+saint-anicet + +1. Fuzzy search RQA addresses (Supabase/pg_trgm) +2. For matched address, query fibre table: + SELECT * FROM fibre + WHERE rue LIKE '%principale%' AND ville LIKE '%anicet%' + AND (sn IS NULL OR sn = '') -- available port +3. Return: { available, max_speed, olt_port, zone_tarifaire, fibre_id } +``` + +--- + +## Agent Phone Order Flow + +Same data structure, different entry point: + +``` +Agent in Ops app: + 1. Search customer (existing) or click "Nouveau client" + 2. Enter address → same availability check + 3. Select services → same plan picker + 4. Choose dates → same date picker + 5. Click "Créer commande" + → Same API call as website checkout + → Same n8n/targo-hub workflow + → Same Project + Tasks + Dispatch Job creation + +Difference: no Stripe payment upfront + → Invoice generated, customer pays later or agent takes CC over phone +``` + +### Ops App: New "Nouvelle installation" Wizard +``` +Route: /ops/new-installation +Components: + Step1_AddressCheck.vue — address search + availability + Step2_PlanSelection.vue — internet/tv/phone picker + pricing + Step3_CustomerInfo.vue — name/email/phone (or existing customer) + Step4_DateSelection.vue — preferred dates calendar + Step5_Summary.vue — review + confirm + +On confirm → POST /api/checkout (same endpoint as website) +``` + +--- + +## Migration: Legacy Data → ERPNext + +### Already Migrated +- ✅ Customers (account → Customer) +- ✅ Service Locations (delivery → Service Location) +- ✅ Service Subscriptions (service → Service Subscription) +- ✅ Service Equipment (device → Service Equipment) +- ✅ Tickets (ticket → Issue) +- ✅ Invoices (invoice → Sales Invoice) +- ✅ OLT data on equipment (fibre → custom fields) + +### Still Needed +1. **WiFi provisioning data** → Service Equipment custom fields + - genieacs.wifi (1,713 entries, 858 unique Deco MACs) + - Match: wifi.serial (Deco MAC) → device.mac → Service Equipment.mac_address + +2. **VoIP provisioning data** → Service Equipment custom fields + - genieacs.voip (797 entries, 469 unique RCMG serials) + - Match: voip.serial (RCMG) → device.sn → Service Equipment.serial_number + +3. **RADIUS credentials** → Service Equipment or Service Subscription + - service.radius_user + service.radius_pwd + - Match: service.device_id → device.sn → Service Equipment + +4. **Product catalog** → ERPNext Item (if not already done) + - 100+ legacy products with SKU, pricing, speed tiers + - fibre_lineprofile + fibre_serviceprofile for OLT provisioning + +5. **Fibre → RQA address link** for availability search + - 16,056 fibre entries need matching to 5.2M RQA addresses + - Strategy: postal code + street similarity + civic number + +--- + +## Build Priority + +### Week 1: Data Foundation +1. Add provisioning custom fields to Service Equipment +2. Migrate WiFi/VoIP/RADIUS data to those fields +3. Match fibre entries to RQA addresses +4. Expose availability API (fibre port check) + +### Week 2: Order Wizard +1. Build /ops/new-installation wizard in Ops app +2. Build targo-hub /checkout endpoint +3. Build n8n "New Order" workflow +4. Auto-create: Customer → Location → Subscriptions → Equipment → Project → Tasks → Dispatch Job + +### Week 3: Website Checkout +1. Upgrade AvailabilityDialog → full checkout flow +2. Stripe integration +3. Same /checkout endpoint as Ops wizard +4. SMS/email confirmations + +### Week 4: Auto-Provisioning +1. targo-hub /devices/{serial}/provision endpoint +2. ACS webhook on device bootstrap → reads ERPNext +3. WiFi/VoIP auto-push from Service Equipment fields +4. "Device online" notifications