Phase 1: 833 Items + 34 Item Groups + custom fields (ISP speeds, RADIUS, legacy IDs) Phase 2: 6,667 Customers + Contacts + Addresses via direct PG (~30s) Phase 3: Tax template QC TPS+TVQ + 92 Subscription Plans Phase 4: 21,876 Subscriptions with RADIUS data CRITICAL: ERPNext scheduler is PAUSED — do not reactivate without explicit go. Includes: - ARCHITECTURE-COMPARE.md: full schema mapping legacy vs ERPNext - CHANGELOG.md: detailed migration log - MIGRATION-PLAN.md: strategy and next steps - scripts/migration/: idempotent Python scripts (direct PG method) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
386 lines
28 KiB
Markdown
386 lines
28 KiB
Markdown
# Architecture comparative — Legacy vs ERPNext
|
|
|
|
## 1. Schéma relationnel Legacy (gestionclient / MariaDB)
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ CLIENTS & ADRESSES │
|
|
├─────────────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ account (15,303) delivery (17,114) │
|
|
│ ├─ id (PK) ├─ id (PK) │
|
|
│ ├─ customer_id (ex: DR2) ├─ account_id → account.id │
|
|
│ ├─ first_name, last_name ├─ name (label) │
|
|
│ ├─ company ├─ address1, city, zip │
|
|
│ ├─ email, tel_home, cell ├─ longitude, latitude │
|
|
│ ├─ address1, city, zip └─ contact, email │
|
|
│ ├─ status (1=actif,4=terminé) │
|
|
│ ├─ group_id (5=rés, 8=com) │
|
|
│ ├─ ppa, ppa_code, ppa_account ← PPA AccesD Desjardins │
|
|
│ ├─ stripe_id ← Paiement carte │
|
|
│ ├─ tax_group │
|
|
│ └─ language_id │
|
|
│ │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ SERVICES & FORFAITS │
|
|
├─────────────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ service (66,879) product (833) │
|
|
│ ├─ id (PK) ├─ id (PK) │
|
|
│ ├─ delivery_id → delivery.id ├─ sku (ex: FTTH150I) │
|
|
│ ├─ device_id → device.id ├─ price │
|
|
│ ├─ product_id → product.id ├─ active │
|
|
│ ├─ status (1=actif, 0=inactif) ├─ category → product_cat.id │
|
|
│ ├─ date_orig, date_next_invoice ├─ download_speed (Kbps) │
|
|
│ ├─ payment_recurrence ├─ upload_speed (Kbps) │
|
|
│ ├─ hijack (prix spécial) ├─ quota_day, quota_night │
|
|
│ ├─ hijack_price, hijack_desc ├─ fibre_lineprofile │
|
|
│ ├─ radius_user, radius_pwd └─ fibre_serviceprofile │
|
|
│ ├─ date_end_contract │
|
|
│ └─ actif_until product_cat (34) │
|
|
│ ├─ id, name │
|
|
│ Note: service EST l'abonnement. ├─ num_compte (→ compta) │
|
|
│ Un client a N services actifs. └─ combo_dispo │
|
|
│ │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ FACTURATION & PAIEMENTS │
|
|
├─────────────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ invoice (629,944) payment (540,522) │
|
|
│ ├─ id (PK) ├─ id (PK) │
|
|
│ ├─ account_id → account.id ├─ account_id → account.id │
|
|
│ ├─ date_orig (unix timestamp) ├─ date_orig │
|
|
│ ├─ total_amt, billed_amt ├─ amount │
|
|
│ ├─ billing_status (0=draft,1=ok) ├─ type (chèque,PPA,CC...) │
|
|
│ ├─ process_status ├─ reference │
|
|
│ ├─ due_date └─ applied_amt │
|
|
│ ├─ notes, template_message │
|
|
│ └─ ppa_charge payment_item (684,778) │
|
|
│ ├─ payment_id → payment.id │
|
|
│ invoice_item (1,859,260) ├─ invoice_id → invoice.id │
|
|
│ ├─ invoice_id → invoice.id └─ amount │
|
|
│ ├─ service_id → service.id │
|
|
│ ├─ sku → product.sku invoice_tax (par facture) │
|
|
│ ├─ quantity, unitary_price ├─ invoice_id │
|
|
│ └─ product_name ├─ tax_id → tax.id │
|
|
│ └─ amount │
|
|
│ tax (4) │
|
|
│ ├─ TPS 5%, TVQ 8.925/9.975% │
|
|
│ │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ COMPTABILITÉ │
|
|
├─────────────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ compta_comptes (48) compta_journal_ecriture (1.2M)│
|
|
│ ├─ id, num_compte (ex: 4020) ├─ id │
|
|
│ ├─ category (Actif/Passif/Rev) ├─ date │
|
|
│ └─ desc ├─ compta_id → comptes.id │
|
|
│ ├─ debit, credit │
|
|
│ compta_setup └─ desc │
|
|
│ └─ month_closed (fermeture) │
|
|
│ │
|
|
│ LOGIQUE: product_cat.num_compte lie chaque catégorie │
|
|
│ de produit à un compte de revenus (ex: cat 32 → 4020) │
|
|
│ │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ RÉSEAU & ÉQUIPEMENTS │
|
|
├─────────────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ device (10,377) fibre (16,057) │
|
|
│ ├─ id (PK) ├─ id (PK) │
|
|
│ ├─ delivery_id → delivery.id ├─ service_id → service.id │
|
|
│ ├─ category, name ├─ terrain, rue, ville │
|
|
│ ├─ sn (serial number) ├─ frame, slot, port │
|
|
│ ├─ mac ├─ vlan_manage/internet/tel │
|
|
│ ├─ model, manufacturier ├─ ontid, sn │
|
|
│ ├─ manage (IP admin) ├─ info_connect (IP OLT) │
|
|
│ ├─ user, pass ├─ latitude, longitude │
|
|
│ └─ parent (device hiérarchie) └─ placemarks_id │
|
|
│ │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ TICKETS & SUPPORT │
|
|
├─────────────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ ticket (242,618) ticket_msg (784,290) │
|
|
│ ├─ id (PK) ├─ id │
|
|
│ ├─ account_id → account.id ├─ ticket_id → ticket.id │
|
|
│ ├─ delivery_id → delivery.id ├─ msg (mediumtext, base64) │
|
|
│ ├─ subject └─ unread_csv │
|
|
│ ├─ dept_id → ticket_dept.id │
|
|
│ ├─ assign_to → staff.id ticket_dept (21) │
|
|
│ ├─ status (open/pending/closed) ├─ Support, Facturation │
|
|
│ ├─ due_date, priority ├─ Installation, Réparation │
|
|
│ ├─ wizard (JSON install data) └─ Vente, SysAdmin, etc. │
|
|
│ └─ wizard_fibre │
|
|
│ │
|
|
│ bon_travail (14,472) staff (155) │
|
|
│ ├─ account_id, tech1, tech2 ├─ username, password │
|
|
│ ├─ heure_arrive/depart ├─ first_name, last_name │
|
|
│ └─ subtotal, tps, tvq, total ├─ email, cell, ext │
|
|
│ ├─ rights (serialized PHP) │
|
|
│ └─ dept_list │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 2. Schéma ERPNext cible
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ CLIENTS & ADRESSES │
|
|
├─────────────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ Customer Address │
|
|
│ ├─ name (PK, auto) ├─ name (PK, auto) │
|
|
│ ├─ customer_name ├─ address_title │
|
|
│ ├─ customer_type (Ind/Company) ├─ address_line1, city │
|
|
│ ├─ customer_group ├─ state, pincode, country │
|
|
│ ├─ territory (Canada) ├─ latitude, longitude │
|
|
│ ├─ *legacy_account_id ← NEW ├─ links[] → Customer │
|
|
│ ├─ *legacy_customer_id ← NEW └─ address_type │
|
|
│ ├─ *ppa_enabled ← NEW │
|
|
│ ├─ *stripe_id ← NEW Contact │
|
|
│ └─ disabled ├─ first_name, last_name │
|
|
│ ├─ email_ids[], phone_nos[] │
|
|
│ Note: Customer est SÉPARÉ de └─ links[] → Customer │
|
|
│ Address et Contact (pattern ERPNext) │
|
|
│ │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ SERVICES & FORFAITS │
|
|
├─────────────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ Item (type=Service) Subscription │
|
|
│ ├─ item_code (= legacy SKU) ├─ party_type = Customer │
|
|
│ ├─ item_name ├─ party → Customer │
|
|
│ ├─ item_group → Item Group ├─ plans[] → Subscription Plan│
|
|
│ ├─ standard_rate ├─ start_date, end_date │
|
|
│ ├─ *legacy_product_id ← NEW ├─ status (Active/Cancelled) │
|
|
│ ├─ *download_speed ← NEW ├─ generate_invoice_at │
|
|
│ ├─ *upload_speed ← NEW ├─ sales_tax_template │
|
|
│ ├─ *quota_day_gb ← NEW ├─ *radius_user ← NEW │
|
|
│ ├─ *quota_night_gb ← NEW ├─ *radius_pwd ← NEW │
|
|
│ ├─ *fibre_lineprofile ← NEW └─ *legacy_service_id ← NEW │
|
|
│ └─ *fibre_serviceprofile ← NEW │
|
|
│ Subscription Plan │
|
|
│ Item Group (34) ├─ plan_name │
|
|
│ ├─ Services/ ├─ item → Item │
|
|
│ │ ├─ Mensualités fibre ├─ cost (prix fixe) │
|
|
│ │ ├─ Mensualités sans fil ├─ billing_interval = Month │
|
|
│ │ ├─ Téléphonie └─ currency = CAD │
|
|
│ │ └─ ...16 sous-groupes │
|
|
│ ├─ Products/ │
|
|
│ │ ├─ Équipement fibre Note: hijack_price du legacy │
|
|
│ │ ├─ Quincaillerie → additional_discount sur │
|
|
│ │ └─ ...8 sous-groupes la Subscription │
|
|
│ └─ Frais et ajustements/ │
|
|
│ └─ ...10 sous-groupes │
|
|
│ │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ FACTURATION & PAIEMENTS │
|
|
├─────────────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ Sales Invoice Payment Entry │
|
|
│ ├─ customer → Customer ├─ party → Customer │
|
|
│ ├─ posting_date ├─ posting_date │
|
|
│ ├─ items[] (child table) ├─ paid_amount │
|
|
│ │ ├─ item_code → Item ├─ references[] (child) │
|
|
│ │ ├─ qty, rate │ ├─ reference_name → SINV │
|
|
│ │ └─ amount │ └─ allocated_amount │
|
|
│ ├─ taxes[] → Tax Template ├─ mode_of_payment │
|
|
│ ├─ grand_total └─ reference_no │
|
|
│ ├─ status (Draft/Submitted/Paid) │
|
|
│ └─ is_return (pour crédits) Payment Reconciliation │
|
|
│ └─ auto-match paiements │
|
|
│ Sales Taxes Template │
|
|
│ ├─ TPS 5% Journal Entry │
|
|
│ └─ TVQ 9.975% └─ Opening balance │
|
|
│ │
|
|
│ NATIF: Subscription génère auto les Sales Invoice chaque mois │
|
|
│ │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ RÉSEAU & ÉQUIPEMENTS (FSM) │
|
|
├─────────────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ Service Location (custom) Service Equipment (custom) │
|
|
│ ├─ name (LOC-#####) ├─ name (EQP-#####) │
|
|
│ ├─ customer → Customer ├─ location → Service Loc │
|
|
│ ├─ address → Address ├─ serial_number (SN) │
|
|
│ ├─ gps_lat, gps_lon ├─ mac_address │
|
|
│ ├─ connection_type (FTTH/Wireless) ├─ equipment_type │
|
|
│ ├─ olt_ip, olt_frame/slot/port ├─ status │
|
|
│ └─ vlan_internet/tele/manage └─ model, manufacturer │
|
|
│ │
|
|
│ Dispatch Job (custom) Dispatch Technician (custom) │
|
|
│ ├─ customer, service_location ├─ full_name, phone │
|
|
│ ├─ job_type (Install/Repair/...) ├─ traccar_device_id │
|
|
│ ├─ assigned_tech └─ status │
|
|
│ ├─ scheduled_date/time │
|
|
│ └─ equipment[], checklist[] │
|
|
│ │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ TICKETS & SUPPORT │
|
|
├─────────────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ Issue (natif ERPNext HD) Employee (natif ERPNext HR) │
|
|
│ ├─ subject ├─ employee_name │
|
|
│ ├─ customer → Customer ├─ department │
|
|
│ ├─ issue_type → ticket_dept ├─ user_id → User │
|
|
│ ├─ priority └─ cell_phone, email │
|
|
│ ├─ status (Open/Replied/Closed) │
|
|
│ ├─ description (HTML) Note: staff.rights (PHP) │
|
|
│ └─ resolution_details → Rôles ERPNext │
|
|
│ │
|
|
│ Issue peut contenir des Comments (Communication) │
|
|
│ → ticket_msg.msg migré ici (base64 images → fichiers) │
|
|
│ │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 3. Mapping table par table
|
|
|
|
| Legacy Table | Records | ERPNext DocType | Custom Fields | Notes |
|
|
|---|---|---|---|---|
|
|
| account | 15,303 | **Customer** | legacy_account_id, legacy_customer_id, ppa_enabled, stripe_id | status 1→enabled, 4→disabled |
|
|
| account (contact) | — | **Contact** | — | email, tel, cell séparés |
|
|
| delivery | 17,114 | **Address** + **Service Location** | latitude, longitude | GPS dans Address natif |
|
|
| product | 833 | **Item** | legacy_product_id, download/upload_speed, quota_gb, fibre_profiles | ✅ FAIT |
|
|
| product_cat | 34 | **Item Group** | — | ✅ FAIT |
|
|
| service | 66,879 | **Subscription** | radius_user, radius_pwd, legacy_service_id | hijack → discount |
|
|
| invoice | 629,944 | **Sales Invoice** | — | Opening balance pour historique |
|
|
| invoice_item | 1,859,260 | **Sales Invoice Item** | — | Idem |
|
|
| payment | 540,522 | **Payment Entry** | — | Opening balance pour historique |
|
|
| payment_item | 684,778 | **Payment Entry Reference** | — | Idem |
|
|
| tax | 4 | **Sales Taxes Template** | — | TPS 5% + TVQ 9.975% |
|
|
| compta_comptes | 48 | **Account** (Chart) | — | Map → plan comptable canadien existant |
|
|
| compta_journal | 1.2M | **Journal Entry** | — | Opening balance seulement |
|
|
| device | 10,377 | **Service Equipment** | — | FSM custom doctype |
|
|
| fibre | 16,057 | **Service Location** (champs OLT) | — | FSM custom doctype |
|
|
| ticket | 242,618 | **Issue** | — | AI knowledge base |
|
|
| ticket_msg | 784,290 | **Communication** | — | base64 → File uploads |
|
|
| bon_travail | 14,472 | **Dispatch Job** | — | FSM custom doctype |
|
|
| staff | 155 | **Employee** | — | rights → Roles |
|
|
| ticket_dept | 21 | **Issue Type** | — | Support, Facturation, etc. |
|
|
|
|
---
|
|
|
|
## 4. Différences d'architecture clés
|
|
|
|
### Ce qui change fondamentalement
|
|
|
|
| Aspect | Legacy | ERPNext |
|
|
|---|---|---|
|
|
| **Nommage** | ID numérique auto-inc | Naming series (CUST-.YYYY.-, etc.) |
|
|
| **Client/Adresse** | Tout dans `account` | Séparé : Customer + Address + Contact |
|
|
| **Abonnement** | `service` = ligne active | `Subscription` génère auto les factures |
|
|
| **Prix spécial** | `hijack_price` sur service | `additional_discount` sur Subscription ou Pricing Rule |
|
|
| **Taxes** | Calculées dans PHP | Template TPS+TVQ auto-appliqué |
|
|
| **Comptabilité** | Écritures manuelles PHP | GL Entry auto depuis Sales Invoice |
|
|
| **Permissions** | `staff.rights` (PHP serialize) | Rôles + DocType permissions |
|
|
| **Fichiers** | Base64 dans mediumtext | File doctype → /files/ directory |
|
|
| **RADIUS** | Champs sur `service` | Custom fields sur `Subscription` |
|
|
| **Dates** | Unix timestamp (bigint) | ISO date (YYYY-MM-DD) |
|
|
|
|
### Ce qui reste pareil
|
|
- SKU des produits
|
|
- Structure client → N adresses → N services
|
|
- Facturation mensuelle récurrente
|
|
- Système de tickets/support
|
|
|
|
---
|
|
|
|
## 5. Flux opérationnels comparés
|
|
|
|
### Facturation mensuelle
|
|
|
|
**Legacy :**
|
|
```
|
|
CRON → task_charge_recurrent.php
|
|
→ SELECT services WHERE date_next_invoice < NOW()
|
|
→ INSERT invoice + invoice_items
|
|
→ UPDATE service.date_next_invoice + 1 month
|
|
→ task_generate_statement.php (PDF)
|
|
→ task_mail.php (envoi email)
|
|
```
|
|
|
|
**ERPNext :**
|
|
```
|
|
Scheduler → Subscription.process()
|
|
→ Auto-génère Sales Invoice (draft ou submitted)
|
|
→ Taxes auto-appliquées via template
|
|
→ Email via Print Format + Email Account
|
|
→ Payment Entry (PPA/Stripe) auto-réconcilié
|
|
```
|
|
|
|
### Nouveau client
|
|
|
|
**Legacy :**
|
|
```
|
|
account_add.php → INSERT account
|
|
delivery_add.php → INSERT delivery
|
|
service_add.php → INSERT service + UPDATE radius
|
|
invoice_add.php → première facture manuelle
|
|
```
|
|
|
|
**ERPNext :**
|
|
```
|
|
Customer (create) → Address (link) → Contact (link)
|
|
Subscription (create, plans=[Item]) → auto-generates invoices
|
|
Webhook → n8n → FreeRADIUS (create user)
|
|
```
|
|
|
|
### Ticket support
|
|
|
|
**Legacy :**
|
|
```
|
|
ticket_new.php → INSERT ticket
|
|
ticket_view.php → INSERT ticket_msg (avec base64 images)
|
|
Assignation manuelle (assign_to → staff.id)
|
|
```
|
|
|
|
**ERPNext :**
|
|
```
|
|
Issue (create) → Communication (messages)
|
|
Assignment Rule (auto-assignation par type)
|
|
SLA tracking natif
|
|
File upload pour images (pas de base64)
|
|
```
|
|
|
|
---
|
|
|
|
## 6. État de la migration
|
|
|
|
| Phase | Statut | Détail |
|
|
|---|---|---|
|
|
| 1a. Item Groups | ✅ Fait | 34 groupes, 3 parents |
|
|
| 1b. Items | ✅ Fait | 833 items, vitesses, quotas, legacy IDs |
|
|
| 1c. Custom Fields | ✅ Fait | Item (8), Customer (4), Subscription (3) |
|
|
| 2. Customers + Contacts + Addresses | ✅ Fait | 6,667 Customers + ~6,600 Contacts + ~6,700 Addresses via direct PG (migrate_direct.py, ~30s) |
|
|
| 3. Tax Templates + Subscription Plans | ✅ Fait | QC TPS 5% + TVQ 9.975%, 92 Subscription Plans |
|
|
| 4. Subscriptions | ✅ Fait | 21,876 Subscriptions avec RADIUS data. **Scheduler PAUSED** |
|
|
| 5. Opening Balance | ⏳ Planifié | Soldes calculés legacy — prochaine étape |
|
|
| 6. Tickets → Issues | ⏳ Phase 2 | 242K tickets, extraction base64 |
|
|
| 7. Sync bidirectionnelle | ⏳ Phase 2 | n8n ETL nightly |
|
|
|
|
> **⚠ ATTENTION : Le scheduler ERPNext est PAUSED. Ne pas réactiver sans instruction explicite — cela déclencherait la facturation automatique des 21,876 abonnements.**
|