Cas réel · migration rejouée
Cas pratique : migration d’un ERP WINDEV® 25 et HFSQL® vers React, Node.js et PostgreSQL
Un ERP de gestion développé en interne par une PME, dont nous avons rejoué la migration WINDEV de bout en bout. Cette page montre ce que nous avons tiré du dossier PDF, les correspondances et les points durs, puis la méthode suivie pour le code, la reprise des données et la recette.
Ce cas est réel : l’ERP existe et tourne aujourd’hui en WINDEV 25. Nous avons rejoué sa migration complète avec notre méthode, à partir du dossier PDF que WINDEV génère automatiquement. Le nom de l’entreprise n’est pas publié.
La version migrée n’est pas en service dans l’entreprise : vous lisez le travail réalisé et la méthode suivie, pas un retour d’utilisateurs.
Le cas en chiffres
- 120 fenêtres
- 10 états
- 110 000 lignes de WLangage
- 232 tables en base
- 1 dossier PDF généré par WINDEV
- Pourquoi migrer : rester en WINDEV 25 fige l’ERP ; le recompiler avec la génération 2026 le fait entrer dans la redevance par session ; la facture électronique l’oblige à évoluer.
- Comment : inventaire tiré du dossier PDF, traduction par l’IA, relecture et tests par nos développeurs seniors ; dans un projet, la recette se fait sur un carnet validé avec l’entreprise.
- Pour les utilisateurs : par défaut, les mêmes écrans, les mêmes libellés et le même enchaînement, dans un navigateur.
- Le prix : un forfait unique calculé sur l’inventaire, payé une fois, sans redevance de notre part.
Avant, après : la même fenêtre, dans le navigateur
Par défaut, chaque fenêtre garde sa disposition, ses libellés et son enchaînement. Seul l’habillage change, et l’application s’ouvre dans un navigateur.
Avant : Une fenêtre WINDEV 25
Migration rejouée par WinExit
Après : Le même écran, en React
Pourquoi migrer maintenant
L’ERP est en WINDEV 25, version annoncée par PC SOFT en octobre 2019, avec une base HFSQL. Pour lui, la redevance par session n’est pas l’argument principal : selon la Wx Alliance (22 septembre 2026), les applications compilées avec une version antérieure à la génération 2026 restent hors Sessions. Aujourd’hui, cet ERP ne paie aucune session. Le sujet est l’impasse.
| Rester en WINDEV 25 avec dongle | Aucune redevance. Tant que le dongle de l’entreprise fonctionne, son équipe ouvre les sources en WINDEV 25. Mais depuis février 2025, PC SOFT ne vend plus de licence perpétuelle à dongle ; selon la Wx Alliance, il ne remplace plus un dongle perdu ou cassé. Chaque mise à jour de Windows se vérifie par des tests, sans nouvelle version possible du côté de WINDEV 25. |
|---|---|
| Faire évoluer l’ERP sur une version récente | Il faut l’abonnement : 1 068 € par an et par développeur. Passer à l’abonnement convertit le dongle, qui ne sert plus ensuite qu’aux versions 23 et antérieures (CGV PC SOFT, version 1.6 du 25 mars 2026). Et si l’ERP était recompilé avec la génération 2026, chaque session coûterait 290 € HT par an au tarif catalogue, en plus de l’abonnement. Une session = un exécutable, un utilisateur, une machine. |
| Migrer vers React, Node.js et PostgreSQL | Un forfait unique, payé une fois, sans abonnement ni redevance de notre part. Le code est cédé en exclusivité au paiement intégral. |
Recompiler en 2026 fait entrer l’ERP dans les Sessions ; ne pas recompiler le fige. Or un ERP doit évoluer : depuis le 1er septembre 2026, toute entreprise assujettie à la TVA établie en France doit pouvoir recevoir des factures électroniques, et une PME devra les émettre à partir du 1er septembre 2027 (voir la facture électronique).
Le plan de continuité annoncé par PC SOFT le 21 septembre 2026 ne concerne que les entreprises de moins de dix salariés. Montants et sources : prix WINDEV 2026.
Ce que nous avons reçu : le dossier PDF
WINDEV génère automatiquement la documentation d’un projet : l’analyse (le modèle de données), les fenêtres, le code, les états (les documents imprimés), les requêtes. Pour ce cas, tout le travail est parti de ce dossier PDF.
| Partie du dossier | Ce que nous en avons tiré |
|---|---|
| Analyse : fichiers, rubriques, types, clés, liaisons | Le schéma PostgreSQL des 232 tables : types, clés primaires et étrangères, index, contraintes. Et le plan de reprise des données. |
| Fenêtres : image, champs et libellés, menus et raccourcis, code de la fenêtre et des champs | Les écrans React des 120 fenêtres, aux mêmes libellés et au même enchaînement ; les règles de saisie, vérifiées dans le navigateur puis par l’API. |
| Procédures, classes, collections de procédures | Les services TypeScript de l’API, traduits des 110 000 lignes de WLangage. |
| Requêtes | Du SQL paramétré et typé. |
| États : sources de données, ruptures, sous-états | Les 10 états, en modèles de documents PDF générés côté serveur. |
Un dossier PDF décrit le projet, pas ce qui vit autour. Voici ce qu’il ne contient pas, et comment nous le traitons :
| Absent du dossier | À quoi il sert | Comment nous le traitons |
|---|---|---|
| Les données | Mesurer les volumes, trouver les anomalies, rapprocher après la reprise | Échantillon anonymisé de préférence ; sinon copie de la base sous NDA, avec un accord de sous-traitance RGPD (DPA) si elle contient des données personnelles |
| Les droits du groupware utilisateur | Reprendre les droits de chaque utilisateur, stockés dans des fichiers HFSQL hors du projet | Lus dans ces fichiers, puis repris en rôles |
| Les états personnels des utilisateurs, créés ou modifiés avec Etats & Requêtes (hors du projet) | Garder ces états, qui vivent hors du projet : sans inventaire, ils disparaissent | Recensés avec l’entreprise, poste par poste |
| Les matériels et imprimantes des postes | Prévoir l’impression directe, les étiquettes, les codes-barres, la pesée | Listés avec l’entreprise pendant l’audit |
Pour ce cas, le travail est parti du dossier PDF. Pour un devis ferme, l’audit part de l’export global du projet : architecture, code source, ressources.
La cible : architecture avant et après
Avant : WINDEV 25
- Postes Windows L’exécutable WINDEV 25 de l’ERP : fenêtres, états, impressions.
- Base HFSQL 232 tables, décrites dans l’analyse du projet.
Après : application web
- Navigateur React 19, TypeScript en mode strict. Rien à installer sur les postes, sauf un agent d’impression là où l’impression directe est nécessaire.
- API Node.js (version LTS) Services métier, droits, PDF, fichiers Excel et Word, tâches planifiées.
- PostgreSQL 18 Les 232 tables, leurs contraintes et les compteurs de factures.
| Interface | React 19, TypeScript en mode strict, Vite, TanStack Query et TanStack Table, React Hook Form, Zod. |
|---|---|
| API | Node.js (version LTS), Fastify, node-postgres. SQL explicite pour les traitements critiques (facturation, compteurs), Kysely pour les requêtes typées des écrans. |
| Base | PostgreSQL 18. |
| Tâches planifiées | pg-boss : file de tâches et planification dans PostgreSQL, sans serveur de plus. |
| Documents | PDF rendus par Chromium sans interface, piloté par Playwright ; xlsx par exceljs ; docx par docxtemplater. |
Ces briques sont open source, à une exception près : les modules images et tableaux de docxtemplater sont payants, si un modèle Word les demande. Aucune ne se paie à la session.
Objets WINDEV et types HFSQL : leurs équivalents
Objets WINDEV et équivalents React / Node.js
| Dans WINDEV 25 | Dans la version web |
|---|---|
| Fenêtre | Page React avec sa route, ou boîte de dialogue. Par défaut, même disposition, mêmes libellés, même ordre de saisie. |
FichierVersEcran, EcranVersFichier | Formulaire React Hook Form relié à une API typée : lecture par GET, enregistrement par PUT. |
| Contrôles de saisie, champs obligatoires, masques | Schémas Zod partagés : vérifiés dans le navigateur, puis à nouveau par l’API. |
| Champ Table relié à un fichier | TanStack Table. Tri, filtres et pagination exécutés par PostgreSQL, pagination par clé plutôt que par OFFSET. |
Info, OuiNon, Erreur | Boîtes de dialogue React, avec les mêmes messages. |
| Procédures globales, collections, classes, composants internes | Services et modules TypeScript côté API. |
| Variables globales du projet | Contexte de session côté serveur (utilisateur, société, droits), passé explicitement aux services. |
| Requêtes (.WDR) | SQL paramétré, typé avec Kysely. |
Procédures stockées, triggers serveur, HAjoutePlanification | Services Node.js, SQL ou PL/pgSQL ; tâches pg-boss planifiées. |
États (.WDE), iImprimeEtat | PDF générés côté serveur : HTML et CSS rendus par Chromium sans interface. |
TableVersExcel, automation OLE de Word et Excel | Fichiers xlsx et docx générés côté serveur, sans Office sur le poste. |
| Groupware utilisateur | Rôles et permissions vérifiés par l’API ; authentification unique et double authentification en option. |
Types HFSQL et types PostgreSQL
| Rubrique HFSQL | PostgreSQL 18 | À contrôler |
|---|---|---|
| Identifiant automatique, 4 ou 8 octets | bigint GENERATED BY DEFAULT AS IDENTITY | Identifiants d’origine conservés, puis séquence recalée par setval. |
| Entier sur 1, 2, 4 ou 8 octets | smallint, integer, bigint | Entier sans signe : type immédiatement supérieur (sur 8 octets : numeric(20,0)). |
| Monétaire | numeric(24,6), ou numeric(14,2) si la règle métier le permet | Décimal exact : 24 chiffres significatifs, dont 6 décimales au plus. Jamais de double precision. |
| Réel sur 4 ou 8 octets | real, double precision | Réservé aux grandeurs non monétaires : poids, dimensions. |
| Texte ANSI ou Unicode | varchar(n) ou text, en UTF-8 | Choisi rubrique par rubrique dans l’analyse. ANSI décodé en Windows-1252, pas en ISO-8859-1, qui n’a ni « € » ni « œ ». |
| Date (AAAAMMJJ) | date | Dates non renseignées (des valeurs vides plutôt que NULL) et dates incohérentes repérées, puis converties en NULL. |
| Heure (HHMMSSCC) | time(2) | Centièmes de seconde conservés. |
| Date et heure, à la milliseconde | timestamptz(3) | Valeurs sans fuseau, interprétées à l’heure de Paris. |
| Mémo texte, mémo binaire | text, bytea ou stockage objet | Contenu lu dans le fichier .MMO, à côté du .FIC. |
| Clé composée | Index multicolonne, UNIQUE si la clé est unique | Colonnes dans le même ordre que la clé d’origine. |
| Clé texte insensible à la casse, aux accents ou à la ponctuation | Collation ICU non déterministe, ou colonne normalisée indexée | Voir les points durs. |
| Liaison avec intégrité référentielle | FOREIGN KEY | Posée après le traitement des orphelins. |
Côté Node.js, node-postgres a trois comportements par défaut à connaître. Un bigint arrive en chaîne : l’identifiant reste une chaîne. Un numeric arrive aussi en chaîne : le montant se calcule en SQL ou en décimal exact, jamais en Number. Une date devient un objet Date fixé à minuit, heure locale du processus Node.js, sauf avec setTypeParser(1082), qui la garde en « AAAA-MM-JJ ».
Après : schéma PostgreSQL d’une table reprise
-- Clé insensible à la casse et aux accents, comme la clé d'origine
CREATE COLLATION ci_ai (provider = icu, deterministic = false, locale = 'und-u-ks-level1');
CREATE TABLE customer (
id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, -- identifiant automatique repris
name text COLLATE ci_ai NOT NULL,
siren text, -- NULL si inconnu, et non plus chaîne vide
credit_limit numeric(24,6) NOT NULL DEFAULT 0, -- monétaire, décimal exact
version integer NOT NULL DEFAULT 1 -- verrou optimiste
);
CREATE INDEX customer_name_idx ON customer (name);
-- Après l'import des identifiants d'origine : la séquence repart après le plus grand
SELECT setval(pg_get_serial_sequence('customer', 'id'), (SELECT max(id) FROM customer));
Les points durs d’un ERP WINDEV, et ce que nous en faisons
| Point dur | WINDEV 25 et HFSQL | Version web |
|---|---|---|
| Numérotation continue des factures | Compteur lu avec hBlocageEcriture et incrémenté dans la transaction : il reste bloqué jusqu’à HTransactionFin. | Une ligne par série dans une table de compteurs, incrémentée par UPDATE … RETURNING dans la même transaction que la facture. Pas de SEQUENCE : la documentation PostgreSQL prévient qu’elle peut laisser des trous, car nextval n’est pas annulé au ROLLBACK. Contrepartie : les facturations passent une par une. Aucune facture n’est supprimée ensuite : on émet un avoir. |
| Montants et arrondis | Monétaire : décimal exact. Arrondi(x, 2) arrondit 0,5 vers le haut. | numeric de bout en bout. round(numeric, 2) départage les égalités en s’éloignant de zéro : même résultat sur les montants positifs ; les négatifs (avoirs, remises) passent par des tests de non-régression. En SQL, 15 / 100 vaut 0 : on écrit / 100.0. |
| Blocages | Blocage pessimiste (hBlocageEcriture, hBlocageLectureEcriture), réessayé H.NbEssais fois, puis fenêtre « réessayer / annuler ». | Une application web ne garde pas de verrou pendant la saisie. Pour la saisie : verrou optimiste par colonne version, conflit signalé à l’utilisateur. Pour les traitements : verrous courts, SELECT … FOR UPDATE dans une transaction. |
| Isolation des transactions | En HFSQL Client/Serveur, isolation par défaut READ UNCOMMITTED : un autre poste peut lire les écritures d’une transaction pas encore validée. | READ COMMITTED par défaut : une lecture ne voit que des données validées. Les calculs qui lisent des données en cours de transaction sont revérifiés par des tests. |
| Erreurs pendant une transaction | La gestion assistée des erreurs HFSQL peut ouvrir une fenêtre en pleine transaction, verrous posés. | Toute erreur lève une exception : ROLLBACK, verrous libérés, message à l’utilisateur. |
| Absence de valeur | Le NULL n’existe que si le fichier a « NULL supporté » et la rubrique « NULL autorisé ». Ailleurs, l’absence de valeur est une chaîne vide, une date vide ou 0. | Conversion en NULL à la reprise, règle par règle. Un test SI Client.DateRelance = "" devient IS NULL. Les 0 qui ont un sens métier restent des 0. |
| Clés insensibles | Clés texte sensibles ou non à la casse, aux accents, à la ponctuation. Sur une clé sensible à la casse, « DUPONT » ne trouve pas « Dupont ». | PostgreSQL compare au caractère près. Choix clé par clé : collation ICU non déterministe, plus lente, qui accepte LIKE depuis PostgreSQL 18 mais ni ILIKE ni les expressions régulières ; ou colonne normalisée indexée. |
OU et ET | En WINDEV 25, OU et ET évaluent toujours les deux opérandes. Seuls _OU_ et _ET_ s’arrêtent au premier. | || et && s’arrêtent dès que le résultat est connu. Chaque condition dont le second opérande a un effet (appel de procédure, lecture HFSQL qui déplace l’enregistrement en cours, écriture) est réécrite : voir l’exemple plus bas. |
| Date du jour | DateDuJour() renvoie la date du poste client. | Date du serveur, avec un fuseau horaire explicite (Europe/Paris). Un poste mal réglé ne change plus la date d’une facture. |
| Traitements dans la base | En HFSQL Client/Serveur : procédures stockées et triggers serveur écrits en WLangage, tâches planifiées du serveur. | Ils ne fonctionnent pas sur PostgreSQL. Réécrits un par un : une règle de cohérence des données va dans la base (contrainte ou trigger PL/pgSQL) ; une règle métier va dans l’API, où elle se teste ; une tâche planifiée va dans pg-boss. |
| Intégrité référentielle | Décrite sur les liaisons de l’analyse, désactivable par programmation (HGèreIntégrité, hIgnoreIntégrité). | FOREIGN KEY posées après la reprise, une fois les orphelins traités. |
| Plusieurs sociétés dans la même base | Le filtre sur la société dépend du code de chaque requête. | Sécurité au niveau des lignes (Row-Level Security) : la société courante est posée à chaque transaction ; le rôle de l’application n’est pas superutilisateur et n’a ni la propriété des tables ni l’attribut BYPASSRLS. Un filtre oublié ne montre plus les données d’une autre société. |
Le code, avant et après
Prenons une procédure présente dans la plupart des ERP de gestion : la facturation d’une commande. Le code de l’ERP n’est pas publié : celui-ci, écrit pour cette page et ramené à l’essentiel, montre les mécanismes WLangage qu’une migration doit traduire.
Avant : WLangage
PROCÉDURE FacturerCommande(nIDCommande est un entier sur 8 octets)
moTotalHT est un monétaire = 0
HTransactionDébut()
// Commande bloquée en écriture : un autre poste ne peut pas la facturer en même temps
HLitRecherchePremier(Commande, IDCommande, nIDCommande, hBlocageEcriture)
SI (PAS HTrouve(Commande)) _OU_ (Commande.Etat <> "VALIDEE") ALORS
HTransactionAnnule()
RENVOYER Faux
FIN
// Numéro continu : le compteur reste bloqué jusqu'à la fin de la transaction
HLitRecherchePremier(Compteur, Code, "FACTURE", hBlocageEcriture)
Compteur.Valeur++
HModifie(Compteur)
HLitRecherchePremier(LigneCmd, IDCommande, nIDCommande)
TANTQUE HTrouve(LigneCmd)
moTotalHT += Arrondi(LigneCmd.PrixHT * LigneCmd.Qte * (1 - LigneCmd.Remise / 100), 2)
HLitSuivant(LigneCmd, IDCommande)
FIN
HRAZ(Facture)
Facture.NumFacture = Compteur.Valeur
Facture.IDCommande = nIDCommande
Facture.DateFacture = DateDuJour()
Facture.TotalHT = moTotalHT
HAjoute(Facture)
Commande.Etat = "FACTUREE"
HModifie(Commande)
HTransactionFin()
RENVOYER Vrai
Après : TypeScript / Node.js
// Codes d'état repris de la base d'origine, sans traduction
export async function invoiceOrder(orderId: string): Promise<boolean> {
return withTransaction(async (tx) => {
// Une facturation concurrente attend ce verrou, puis relit 'FACTUREE' et s'arrête
const { rows: [order] } = await tx.query<{ status: string }>(
'SELECT status FROM sales_order WHERE id = $1 FOR UPDATE', [orderId]);
if (!order || order.status !== 'VALIDEE') return false;
// Total HT en numeric (décimal exact), arrondi ligne par ligne comme dans WINDEV
const { rows: [sum] } = await tx.query<{ total: string }>(
`SELECT COALESCE(SUM(ROUND(unit_price * quantity * (1 - discount / 100.0), 2)), 0) AS total
FROM order_line WHERE order_id = $1`, [orderId]);
// Numéro continu : pas de SEQUENCE (elle laisse des trous) ; ligne verrouillée jusqu'au COMMIT
const { rows: [counter] } = await tx.query<{ value: string }>(
"UPDATE counter SET value = value + 1 WHERE code = 'FACTURE' RETURNING value");
if (!counter) throw new Error('Compteur FACTURE absent');
// Date du serveur à l'heure de Paris, prise après l'obtention du numéro
await tx.query(
`INSERT INTO invoice (number, order_id, invoice_date, total_excl_tax)
VALUES ($1, $2, (statement_timestamp() AT TIME ZONE 'Europe/Paris')::date, $3)`,
[counter.value, orderId, sum.total]);
await tx.query("UPDATE sales_order SET status = 'FACTUREE' WHERE id = $1", [orderId]);
return true;
});
}
Après : la transaction, un seul client du pool
import type { PoolClient } from 'pg';
import { pool } from './db'; // pool partagé de l'application (new Pool())
export async function withTransaction<T>(work: (tx: PoolClient) => Promise<T>): Promise<T> {
const client = await pool.connect();
let broken = false;
try {
await client.query('BEGIN');
const result = await work(client);
await client.query('COMMIT');
return result;
} catch (err) {
// ROLLBACK impossible : la connexion est détruite au lieu de revenir dans le pool
await client.query('ROLLBACK').catch(() => { broken = true; });
throw err;
} finally {
client.release(broken);
}
}
| WLangage | TypeScript / PostgreSQL |
|---|---|
HTransactionDébut, HTransactionFin, HTransactionAnnule | withTransaction : un seul client, BEGIN, puis COMMIT, ou ROLLBACK à la première exception. |
HLitRecherchePremier(…, hBlocageEcriture) | SELECT … FOR UPDATE : le second poste attend, relit l’état « FACTUREE » et s’arrête. |
Boucle TANTQUE / HLitSuivant | Une seule requête SUM, avec l’arrondi ligne par ligne d’origine. |
Compteur bloqué puis HModifie | UPDATE counter … RETURNING, annulé avec la transaction en cas d’échec. |
DateDuJour() | Date du serveur, fuseau Europe/Paris, lue après l’obtention du numéro : les dates suivent l’ordre des numéros. |
_OU_ | ||, qui s’arrête aussi au premier opérande vrai. |
Un relecteur WINDEV le remarquera : dans le code WLangage ci-dessus, les résultats de HModifie et HAjoute ne sont pas testés, et la gestion assistée des erreurs HFSQL peut ouvrir une fenêtre pendant la transaction. La version TypeScript annule la transaction à la première erreur.
Quand OU appelle une procédure
Avant : WLangage
// OU évalue les deux opérandes : EnvoieAlerte() s'exécute même si EstAJour() renvoie Vrai
SI EstAJour(nIDClient) OU EnvoieAlerte(nIDClient) ALORS
Trace("Client traité")
FIN
Après : TypeScript / Node.js
// || s'arrêterait au premier opérande vrai : l'appel sort de la condition pour garder le comportement
const upToDate = await isUpToDate(customerId);
const alertSent = await sendAlert(customerId);
if (upToDate || alertSent) log.info('Client traité');
Saisie concurrente d’une fiche : le verrou optimiste
Quand une application WINDEV bloque une fiche à l’ouverture (hBlocageEcriture), un second poste qui veut la modifier attend, puis voit la fenêtre « réessayer / annuler ». Dans la version web, personne n’est bloqué : le second enregistrement est refusé, et l’utilisateur recharge la fiche.
Après : TypeScript / Node.js
// La fiche porte un numéro de version, lu à l'ouverture et renvoyé à l'enregistrement
const { rowCount } = await db.query(
`UPDATE customer SET name = $2, siren = $3, version = version + 1
WHERE id = $1 AND version = $4`,
[id, name, siren, version]);
// Aucune ligne modifiée : un autre utilisateur a enregistré la fiche entre-temps (HTTP 409)
if (!rowCount) throw new ConflictError('Fiche modifiée par un autre utilisateur : rechargez-la');
Ce qui ne se migre pas tel quel, et ce que nous faisons à la place
| Dans un ERP WINDEV | Pourquoi | À la place |
|---|---|---|
| Impression directe, sans boîte de dialogue | Un navigateur n’imprime pas sans boîte de dialogue par défaut. | PDF générés côté serveur. Pour l’impression directe et les étiquettes : un agent local sur les postes concernés. |
| Raccourcis clavier | Le navigateur se réserve certaines combinaisons, comme Ctrl+W, Ctrl+T ou Ctrl+N. | Touches de fonction (F1 à F12), Alt + lettre, Entrée et Tab reprises ; les combinaisons réservées sont remplacées par d’autres touches, listées dans la documentation. |
| Fonctionnalités automatiques du champ Table : tri, filtres, export Excel ou Word, impression | WINDEV les fournit sans code. Une page web ne les a pas d’office. | Recréées sur chaque liste : tri et filtres par PostgreSQL, export xlsx, impression en PDF. |
| États modifiés par les utilisateurs avec Etats & Requêtes | Ils vivent hors du projet. | Recensés, puis repris comme états serveur. |
| Automation OLE de Word et Excel | Il faut Office installé sur le poste. | Fichiers docx et xlsx générés côté serveur, sans Office. |
| Douchettes | Elles fonctionnent en émulation clavier. | Rien à changer : tous les navigateurs les acceptent. |
| Balance ou matériel sur port série | Le navigateur n’accède au port série que par Web Serial. | Web Serial, sur les navigateurs Chromium de bureau seulement ; sinon, agent local. |
| Groupware : droits sur fenêtres, champs, menus | Stockés dans des fichiers HFSQL, appliqués par l’exécutable du poste. | Rôles et permissions vérifiés par l’API : l’écran masque, l’API refuse. |
La reprise des données de HFSQL vers PostgreSQL
Le dossier PDF décrit les 232 tables, pas leur contenu : la reprise se prépare avec les données, transmises sous NDA, et sous DPA si elles contiennent des données personnelles. Elle suit cinq étapes, rejouables autant de fois que nécessaire.
- Extraction. Lecture des fichiers par le pilote ODBC HFSQL que PC SOFT fournit pour Windows et Linux 64 bits. Aucune écriture dans la base d’origine.
- Transformation. Textes ANSI décodés en Windows-1252, absences de valeur converties en NULL, dates incohérentes isolées, codes métier conservés tels quels.
- Chargement. Identifiants d’origine conservés, séquences recalées, compteurs de factures repris à leur dernière valeur.
- Contraintes. Clés étrangères, contraintes d’unicité et index posés après le chargement. Avant chaque contrainte, une requête liste les lignes qui la violeraient (orphelins, doublons), car PostgreSQL refuse la contrainte entière dès la première violation.
- Rapprochement. Contrôles automatiques entre la base HFSQL et PostgreSQL. Si l’un d’eux échoue, la reprise est refusée.
Chaque anomalie que la reprise détecte (date vide ou incohérente, orphelin, doublon révélé par une clé insensible, texte mal encodé) est listée et remise à l’entreprise. Nous ne fusionnons ni ne supprimons rien d’office : modifier l’historique est sa décision.
| Contrôle | Méthode |
|---|---|
| Comptages | Enregistrements par fichier HFSQL, lignes par table PostgreSQL. |
| Sommes | Totaux HT, TVA et TTC des factures, par exercice et par mois. |
| Recalcul de l’historique | Factures historiques recalculées par le nouveau code, comparées au centime aux totaux enregistrés par WINDEV. |
| En-cours | Encours clients, commandes non facturées, stock valorisé. |
| Numérotation | Continuité de chaque série de factures : ni trou ni doublon. |
| FEC (fichier des écritures comptables) | Si l’ERP tient la comptabilité : FEC d’un exercice produit par la version web, comparé aux écritures de la base HFSQL ; structure contrôlée avec l’outil Test Compta Demat de la DGFiP, qui vérifie la forme, pas le fond. |
Le carnet de recette
Les projets WINDEV anciens ont rarement une documentation fonctionnelle : le dossier PDF décrit l’analyse, les fenêtres et le code, pas ce que chaque écran doit faire pour l’utilisateur. L’IA reconstitue cette documentation écran par écran, et nous en tirons un carnet de recette : des lignes vérifiables, à faire valider par les référents de l’entreprise. Le carnet pilote les tests automatisés, puis la recette des utilisateurs. Voici les scénarios que nous écrivons pour les points durs d’un ERP :
| Module | Scénario | Résultat attendu |
|---|---|---|
| Facturation | Deux postes facturent la même commande au même instant | Une seule facture ; le second poste lit « commande déjà facturée » |
| Facturation | Coupure de la base au milieu d’une facturation | Aucune facture, aucun numéro consommé, série continue |
| Facturation | Facture avec remises, puis avoir partiel | Totaux HT, TVA et TTC égaux à ceux de l’ERP WINDEV, au centime près |
| Facturation | Facture validée à 23 h 30, heure de Paris, depuis un poste mal réglé | Date de facture du jour, à Paris |
| Clients | Recherche « dupont », « DUPONT », « Dupont » | Les mêmes fiches qu’avec la clé HFSQL |
| Clients | Deux utilisateurs enregistrent la même fiche | Le second est prévenu ; aucune saisie perdue en silence |
| Listes | Tri, filtre, puis export Excel | Mêmes lignes, même ordre ; fichier xlsx produit sans Office |
| Droits | Utilisateur sans droit sur les tarifs, qui appelle l’API directement | Écran masqué, appel refusé (HTTP 403) |
| Comptabilité | FEC d’un exercice | 18 champs, structure acceptée par Test Compta Demat |
Quand la recette révèle une anomalie de l’ERP d’origine, la version migrée reproduit d’abord le comportement d’origine, hors changements décrits plus haut (date du serveur, verrous, traitement des erreurs). Toute autre correction est une décision de l’entreprise, notée dans le carnet.
La facture électronique, à intégrer à la migration
Une PME doit pouvoir recevoir des factures électroniques depuis le 1er septembre 2026. Elle devra les émettre, et transmettre ses données de transaction (e-reporting), à partir du 1er septembre 2027. Les grandes entreprises et les ETI le font depuis le 1er septembre 2026. Ces fonctions peuvent être intégrées à la migration et chiffrées dans le devis ferme, au lieu d’être développées en WLangage.
| Obligation | Référence | À intégrer à la migration |
|---|---|---|
| Recevoir et émettre | Plateforme agréée ; formats UBL, CII et Factur-X (PDF/A-3 et XML CII), norme EN 16931. | Émettre et recevoir des factures UBL, CII ou Factur-X, échangées avec la plateforme agréée choisie par l’entreprise. Seules les plateformes sont agréées : un ERP ne l’est pas. |
| Nouvelles mentions | CGI, annexe II, art. 242 nonies A | SIREN du client, adresse de livraison si elle diffère, nature des opérations, option pour la TVA d’après les débits : champs à ajouter au schéma et aux factures. |
| Numérotation | « Un numéro unique basé sur une séquence chronologique et continue » (art. 242 nonies A, I, 7°) ; séries distinctes possibles si elles sont justifiées. | Compteur par série, dans la transaction de facturation. |
| Références de TVA | La TVA passe du CGI au code des impositions sur les biens et services (CIBS) au 1er janvier 2027 : les articles cités sur les factures changent. | Mentions légales paramétrables, plutôt que figées dans les états. |
| FEC | LPF, art. L47 A (remise au contrôle) et A47 A-1 (format, 18 champs). | Export FEC, structure contrôlée avec Test Compta Demat. |
| Conservation et corrections | 6 ans (LPF, art. L102 B), 10 ans (code de commerce, art. L123-22). | Factures émises archivées ; écritures validées non modifiables, corrigées par contre-passation ; facture corrigée par un avoir. |
| Pénalités de retard | Code de commerce, art. L441-9 et L441-10 ; indemnité forfaitaire de 40 € (art. D441-5). | Mentions paramétrées dans les conditions de paiement. |
État du droit au 23 octobre 2026, d’après Légifrance. Votre expert-comptable valide le paramétrage retenu.
Lots et bascule
Au-delà de 30 fenêtres, la migration se découpe en lots indépendants au sens du contrat, chacun au forfait : avec 120 fenêtres, cet ERP serait découpé ainsi. Mais dans un ERP, les modules écrivent dans les mêmes tables : une commande touche le stock, la facture et la comptabilité. Un module ne peut donc pas basculer seul sans double saisie, ou sans une synchronisation dans les deux sens, plus coûteuse et plus fragile. D’où notre plan par défaut : les lots sont réalisés et recettés l’un après l’autre, sur une copie des données, puis l’ERP bascule en une fois.
- Jusqu’à la bascule, HFSQL fait foi. L’ERP WINDEV reste l’outil de travail, et la facturation continue. Aucune double saisie.
- Bascule. Hors période de clôture : saisies gelées, reprise finale, rapprochement complet. La facturation ne s’interrompt que pendant la reprise et les contrôles.
- Continuité des numéros. Les compteurs sont repris à leur dernière valeur : la première facture de la version web suit la dernière facture WINDEV.
- Ouverture. PostgreSQL fait foi. L’ERP WINDEV reste consultable en lecture seule.
- Retour arrière. Si un contrôle échoue, l’ERP WINDEV reprend la main sur une base HFSQL restée intacte. Ce retour reste possible jusqu’à la première facture émise par la version web ; ensuite, les corrections se font dans la version web.
Pour les utilisateurs : ce qui reste, ce qui change
| Écrans | Disposition, libellés et enchaînement repris par défaut. La refonte des écrans reste une option. |
|---|---|
| Clavier | Touches de fonction (F1 à F12), Alt + lettre, Entrée et Tab reprises, sauf les combinaisons réservées par le navigateur. |
| Listes | Chargées page par page, triées et filtrées par PostgreSQL. |
| Accès | Un navigateur, au bureau ou en déplacement. Double authentification en option. |
| Mises à jour | Un déploiement sur le serveur, sans rien installer sur les postes. |
Ce que l’entreprise récupérerait
- le code source React, Node.js et SQL, cédé en exclusivité au paiement intégral ;
- le schéma PostgreSQL et les scripts de reprise, rejouables ;
- les tests automatisés, exécutés à chaque modification ;
- le carnet de recette ;
- la table de correspondance : chaque fenêtre, procédure et état WINDEV relié à son équivalent dans le nouveau code ;
- la documentation fonctionnelle reconstituée et la documentation technique : architecture, déploiement, exploitation.
Les données seraient dans une base ouverte, lisibles par les outils standards, et le code en TypeScript : l’équipe de l’entreprise, la nôtre ou un autre prestataire pourrait le maintenir.
Le prix, comparé au fait de rester
Le prix est un forfait unique calculé sur l’inventaire complet : fenêtres, lignes, tables, mais aussi états, tâches planifiées et interfaces. Il est payé une fois, en trois échéances : 30 % à la commande, 40 % à la livraison pour recette, 30 % à la validation de la recette.
| Poste | Migrer | Faire évoluer en génération 2026 |
|---|---|---|
| Une fois | Le forfait de migration, par lots | Le passage du projet en génération 2026, puis la recette de l’ERP recompilé |
| Chaque année | L’hébergement et la maintenance, optionnels et résiliables chez nous | L’abonnement, 1 068 € par développeur, et 290 € HT par session au tarif catalogue |
| Temps de l’entreprise | La recette par les utilisateurs clés, la formation | Une recette à chaque nouvelle génération |
| Facture électronique | Intégrable au projet, chiffrée dans le devis ferme | À développer en WLangage |
Rester en WINDEV 25 ne coûte rien en licences aujourd’hui, mais fige l’ERP. Pour chiffrer votre propre application, le simulateur donne une fourchette en 2 minutes.
Avant le devis : NDA mutuel, audit gratuit, devis ferme 48 h ouvrées après réception de l’export. Preuve de concept en option, de 2 000 à 3 000 € HT, déduite si la migration est validée sous 30 jours. Forfaits dès 5 k€ HT. Tarifs PC SOFT en engagement de trois ans : prix WINDEV 2026.
Ce que ce cas ne dit pas
- L’entreprise n’a pas basculé : son ERP tourne toujours en WINDEV 25. Ce cas décrit une migration rejouée, pas une exploitation.
- Les temps de réponse sous la charge réelle des utilisateurs ne sont pas mesurés ici.
- L’adoption par les utilisateurs (vitesse de saisie, habitudes) ne se mesure qu’après une bascule réelle.
- Ici, le travail est parti du dossier PDF ; le devis ferme d’un projet s’établit sur l’export global, sources comprises.
- Le prix d’un ERP se calcule sur son propre inventaire.
Votre ERP est en WINDEV ? Commencez par l’audit gratuit
Estimez votre migration en 2 minutes, demandez l’audit gratuit ou prenez 30 minutes pour en parler avec nous.
Estimer ma migration en 2 minutes Demander mon devis gratuit Réserver 30 minutes en visio (nouvel onglet)
À lire aussi : notre méthode, étape par étape · garder ou quitter HFSQL · migrer vers React / Node.js · faut-il quitter WINDEV ? · l’équipe