# 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.**
