docs: data structure foundation for lead-to-service pipeline
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 <noreply@anthropic.com>
This commit is contained in:
parent
e9324b45bc
commit
fa37426f34
394
docs/DATA-STRUCTURE-FOUNDATION.md
Normal file
394
docs/DATA-STRUCTURE-FOUNDATION.md
Normal file
|
|
@ -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
|
||||
Loading…
Reference in New Issue
Block a user