@mostajs/wagon-engine 0.4.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,34 @@
3
3
  **Auteur** : Dr Hamid MADANI <drmdh@msn.com>
4
4
  Format : Keep a Changelog ; versions : SemVer.
5
5
 
6
+ ## [0.6.0] — 2026-10-28
7
+
8
+ ### Ajouté
9
+ - **Le vendeur de chaque devise** (`@mostajs/payment` ≥ 2.7) : `PAIEMENT_VENDEUR_<DEVISE>` dans le `.env`. Dès qu'une
10
+ telle variable est déclarée, une devise sans vendeur nommé n'est pas vendue : Stripe et les banques prépayées de
11
+ cette devise sont écartés, même avec leurs clés (un avertissement le dit au démarrage). `{{VENDEUR}}` des textes
12
+ légaux nomme le vendeur de chaque devise vendue, une ligne par devise ; `config.legal.VENDEUR` l'emporte s'il est
13
+ posé. `PAIEMENT_STRIPE_DEVISES` dit la devise de Stripe (défaut EUR), reprise par l'affichage des prix. Sans aucune
14
+ `PAIEMENT_VENDEUR_*`, rien ne change. Essai T-ENG-14.
15
+ - `creerWagon(…).moyens` : les moyens réellement proposés ; `demarrer` le rend tel quel.
16
+ - `llms.txt` et le README s'ouvrent sur la configuration du `.env` par `@mostajs/config` (chargement, cascade
17
+ `MOSTA_ENV`, valeur vide, priorité de l'environnement).
18
+
19
+ ### Dépendances
20
+ - `@mostajs/payment` ^2.7.0.
21
+
22
+ ## [0.5.0] — 2026-10-28
23
+
24
+ ### Ajouté
25
+ - **`config.cadreWagon`** : le cadre des pages du moteur (tarifs, inscription, connexion, aide, à propos, compte,
26
+ déconnexion), par exemple `{ disposition: 'application', application: { retour: '/', langues: true } }`. Une greffe
27
+ qui vit dans la disposition « application » n'y renvoie plus la vitrine et son menu commun à tous les publics. Une
28
+ page de la charge qui choisit son cadre le garde. Essai T-ENG-13.
29
+
30
+ ### Corrigé
31
+ - **Le pied de page ne liste que les textes légaux servis** (`legaux`, `@mostajs/wagon-ui` ≥ 0.11) : un texte incomplet
32
+ n'était pas servi (0.4) mais restait lié, d'où un 404 sur chaque page. Essai T-ENG-12.
33
+
6
34
  ## [0.4.1] — 2026-10-28
7
35
 
8
36
  ### Corrigé
package/README.md CHANGED
@@ -41,6 +41,12 @@ await demarrer({ config, charge });
41
41
  | `CHARGILY_SECRET_KEY` · `SATIM_MERCHANT_ID`, `SATIM_PASSWORD`, `SATIM_TERMINAL_ID` · `PAYPAL_…` | les banques prépayées proposées par `config.paiement.prepaye` |
42
42
  | `PAIEMENT_STRIPE=off`, `PAIEMENT_CHARGILY=off`, `PAIEMENT_SATIM=off`, `PAIEMENT_PAYPAL=off` | **coupe un moyen** sans toucher à ses clés |
43
43
  | `WAGON_ADMINS` | les courriels administrateurs (confirmés par un code reçu) |
44
+ | `PAIEMENT_VENDEUR_DZD`, `PAIEMENT_VENDEUR_EUR`… | 0.6 — **le vendeur de chaque devise** (dénomination, forme, adresse, immatriculations) ; dès qu'une est déclarée, une devise sans vendeur n'est pas vendue, et `{{VENDEUR}}` des CGV les nomme |
45
+ | `PAIEMENT_STRIPE_DEVISES` | 0.6 — la devise de Stripe (défaut `EUR`) |
46
+
47
+ **Le `.env` d'abord.** Toutes les clés passent par `getEnv` de `@mostajs/config` : cascade `MOSTA_ENV` (`PROD_CLÉ` l'emporte sur `CLÉ`), valeur vide = absente, et `loadEnv` n'écrase jamais une variable déjà posée par l'orchestrateur. Si `wagon.config.mjs` lit des variables, il appelle `loadEnv` lui-même, en tête.
48
+
49
+ **Un vendeur par devise (0.6).** Un SaaS qui vend en dinars par un auto-entrepreneur et en euros par une société pose `PAIEMENT_VENDEUR_DZD=…` et `PAIEMENT_VENDEUR_EUR=…`. Une devise déclarée vide (`PAIEMENT_VENDEUR_EUR=`, la société n'est pas encore immatriculée) n'est pas vendue : Stripe est écarté même avec sa clé. Sans aucune `PAIEMENT_VENDEUR_*`, rien ne change.
44
50
 
45
51
  **Le paiement est au choix de l'utilisateur**, parmi les moyens actifs. Un moyen est actif quand ses clés sont dans le `.env` et que son commutateur n'est pas sur `off`. Une banque prépayée doit en plus être proposée par la configuration.
46
52
 
package/llms.txt CHANGED
@@ -4,13 +4,28 @@
4
4
  > PayPal), espace client, administration, pages légales, robots/sitemap, sauvegarde, fr/en/ar. Une GREFFE n'apporte que
5
5
  > wagon.config.mjs, charge/, legal/ et son .env. N2 (pack). Extrait du gabarit mosta-wagon 0.11.0 le 26/10/2026.
6
6
 
7
- - Version: 0.2.0 · Licence: AGPL-3.0-or-later · Auteur: Dr Hamid MADANI <drmdh@msn.com>
7
+ - Version: 0.6.0 · Licence: AGPL-3.0-or-later · Auteur: Dr Hamid MADANI <drmdh@msn.com>
8
8
  - Chemin: mostajs/mosta-platform-stack/mosta-wagon-engine · gabarit d'une greffe : Entreprise/mosta-wagon
9
9
 
10
+ ## ⚙️ D'EMBLÉE : LE .env ET LA CASCADE @mostajs/config
11
+ Une greffe se configure par SON `.env` (dossier courant de `demarrer`, ou `racine`). Avant tout :
12
+ 1. **Qui le charge** : `demarrer` appelle `loadEnv({ path: <racine>/.env })` de `@mostajs/config`. Si `wagon.config.mjs`
13
+ lit lui-même des variables (getEnv au chargement du module), il doit appeler `loadEnv` EN TÊTE, avant de les lire :
14
+ `import { loadEnv, getEnv } from '@mostajs/config'; loadEnv({ path: join(process.cwd(), '.env') });`
15
+ Le second appel (celui de demarrer) n'écrase rien.
16
+ 2. **loadEnv ne SURCHARGE pas** une variable déjà dans l'environnement : la valeur de l'orchestrateur (pm2, systemd,
17
+ conteneur) prime sur le fichier.
18
+ 3. **Cascade** (première valeur NON VIDE) : `${MOSTA_ENV}_${CLÉ}` → `${CLÉ}` → défaut. Un seul .env, des profils
19
+ `TEST_`/`DEV_`/`PROD_`. Toutes les clés ci-dessous, et celles de `@mostajs/payment`, passent par `getEnv`.
20
+ 4. **Vide = absent** : `WAGON_STRIPE_SECRET_KEY=` ne configure rien. Exception voulue : `PAIEMENT_VENDEUR_<DEVISE>=`
21
+ vide DÉCLARE la devise sans la nommer (elle n'est pas vendue).
22
+ 5. Les secrets et les informations de l'entreprise sont posés par l'exploitant sur le serveur, jamais commités ;
23
+ `.env.example` de la greffe liste chaque clé, sans valeur.
24
+
10
25
  ## EXPORTS
11
- - demarrer({ config, charge, racine = cwd, journal }) → { wagon, serveur, moyens: string[], fermer() }
26
+ - demarrer({ config, charge, racine = cwd, journal }) → { wagon, serveur, moyens: string[], fermer() } (moyens = wagon.moyens, 0.6)
12
27
  - creerWagon({ config, charge, sgbd: string|{dialect,uri}, baseUrl, stripe?, webhookSecret?, transport?, journal?,
13
- paiement?: { banques: { chargily:'DZD', … }, port? }, racine? }) → { handler, catalogue(), catalogueStripe(), fermer(), … }
28
+ paiement?: { banques: { chargily:'DZD', … }, port?, deviseStripe? }, racine? }) → { moyens, handler, catalogue(), catalogueStripe(), fermer(), … }
14
29
  - schemasWagon() (sauvegarde) · sauvegarder({ cibles, driver, seau, recipients, garder }) · suivrePalette(…)
15
30
  - '@mostajs/wagon-engine/conformite' = src/conformite/conformite.test.mjs (suite mjs-unit, juge WAGON_GREFFE ou cwd)
16
31
 
@@ -19,7 +34,13 @@ PORT, HOST · WAGON_BASE_URL · WAGON_DB_DIALECT (sqlite|postgres…), WAGON_SGB
19
34
  WAGON_EMAIL_FROM (ou WAGON_COURRIEL_FICHIER pour les essais) · WAGON_STRIPE_SECRET_KEY|RESTRICTED_KEY, WAGON_STRIPE_WEBHOOK_SECRET ·
20
35
  CHARGILY_SECRET_KEY|API_KEY · SATIM_MERCHANT_ID, SATIM_PASSWORD, SATIM_TERMINAL_ID · PAYPAL_CLIENT_ID, PAYPAL_SECRET,
21
36
  PAYPAL_WEBHOOK_ID · PAIEMENT_<STRIPE|CHARGILY|SATIM|PAYPAL>=off (coupe le moyen) · WAGON_ADMINS · WAGON_INDEXER.
22
- Moyen ACTIF = clés présentes ET commutateur ≠ off (ET, pour une banque prépayée, proposée par config.paiement.prepaye).
37
+ 0.6 (@mostajs/payment ≥ 2.7) : PAIEMENT_VENDEUR_<DEVISE> (le vendeur de cette devise : dénomination, forme, adresse,
38
+ immatriculations) · PAIEMENT_STRIPE_DEVISES (la devise de Stripe, défaut EUR).
39
+ Moyen ACTIF = clés présentes ET commutateur ≠ off (ET, pour une banque prépayée, proposée par config.paiement.prepaye)
40
+ ET, 0.6, dès qu'une PAIEMENT_VENDEUR_* est déclarée, un vendeur NOMMÉ pour sa devise. `{{VENDEUR}}` des textes légaux
41
+ nomme alors le vendeur de chaque devise vendue (une ligne par devise, nom de la devise dans la langue de la page) ;
42
+ `config.legal.VENDEUR` l'emporte s'il est posé. Exemple : dinars par un auto-entrepreneur, euros par une société pas
43
+ encore immatriculée → `PAIEMENT_VENDEUR_DZD=…`, `PAIEMENT_VENDEUR_EUR=` (vide) : seule la vente en dinars s'ouvre.
23
44
 
24
45
  ## CONTRAT DE LA CHARGE (charge/index.mjs)
25
46
  liens · ressources (quota { cle, limite, periode } | plafond { cle, limite, plafond: true }) · accueil (fiche { fr: { titre, lede, actions, preuves } }, ou 0.3 : async (ctx) => ({ titre, contenu, disposition, application, console })) · dispositions (0.3 : { nom: (p) => corps }) · textes ·
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mostajs/wagon-engine",
3
- "version": "0.4.1",
3
+ "version": "0.6.0",
4
4
  "description": "Le wagon d'un SaaS, une fois pour toutes : comptes, connexion, paliers, quotas, paiement (Stripe, Chargily, SATIM), espace client, administration, pages légales, fr/en/ar. Une greffe n'apporte que wagon.config.mjs, charge/, legal/ et son .env ; la suite de conformité publiée juge la greffe.",
5
5
  "keywords": [
6
6
  "mostajs",
@@ -50,9 +50,9 @@
50
50
  "@mostajs/mailer": "^0.2.0",
51
51
  "@mostajs/markdown-html": "^0.3.0",
52
52
  "@mostajs/orm": "^2.12.1",
53
- "@mostajs/payment": "^2.6.0",
53
+ "@mostajs/payment": "^2.7.0",
54
54
  "@mostajs/subscriptions-plan": "^0.9.0",
55
- "@mostajs/wagon-ui": "^0.10.1",
55
+ "@mostajs/wagon-ui": "^0.11.0",
56
56
  "better-sqlite3": "^12.11.1",
57
57
  "stripe": "^17.7.0"
58
58
  },
package/src/demarrer.mjs CHANGED
@@ -11,6 +11,7 @@ import { createServer } from 'node:http';
11
11
  import { appendFileSync } from 'node:fs';
12
12
  import { join } from 'node:path';
13
13
  import { loadEnv, getEnv } from '@mostajs/config';
14
+ import { devisesDuMoyen } from '@mostajs/payment/server';
14
15
  import { creerWagon } from './wagon.mjs';
15
16
 
16
17
  const coupe = (moyen) => getEnv(`PAIEMENT_${moyen.toUpperCase()}`, '') === 'off';
@@ -53,10 +54,11 @@ export async function demarrer({ config, charge, racine = process.cwd(), journal
53
54
  stripe: cle ? new (await import('stripe')).default(cle) : null,
54
55
  webhookSecret: getEnv('WAGON_STRIPE_WEBHOOK_SECRET', ''),
55
56
  transport: await transport(),
56
- paiement: { banques },
57
+ // 0.6 — la devise de Stripe (PAIEMENT_STRIPE_DEVISES, défaut EUR) : creerWagon écarte une devise sans vendeur.
58
+ paiement: { banques, deviseStripe: devisesDuMoyen('stripe', ['EUR'])[0] },
57
59
  });
58
60
  await wagon.catalogue();
59
- const moyens = [...(cle ? ['stripe'] : []), ...Object.keys(banques)];
61
+ const moyens = wagon.moyens;
60
62
  const serveur = createServer(wagon.handler);
61
63
  const port = Number(getEnv('PORT', '4800'));
62
64
  await new Promise((ok) => serveur.listen(port, getEnv('HOST', '127.0.0.1'), ok));
package/src/wagon.mjs CHANGED
@@ -25,6 +25,7 @@ import { creerWagonUi, esc } from '@mostajs/wagon-ui';
25
25
  import { creerComptes, schemasComptes } from '@mostajs/comptes';
26
26
  import { createBilling, createStripeSale, createPrepaidSale, billingSchemas, checkLimits, assertMonotonicPlans } from '@mostajs/subscriptions-plan/server';
27
27
  import { PaymentSchema } from '@mostajs/payment';
28
+ import { venteAutorisee, vendeursFromEnv } from '@mostajs/payment/server';
28
29
  import { formatNumber, resolveFormatLocale } from '@mostajs/i18n';
29
30
  import { createPasswordAuth, createEmailCodeAuth, SessionSchema, ipClient, memoryLimiter } from '@mostajs/auth-lite';
30
31
  import { emailCodeEmailHtml, emailCodeEmailText, emailCodeForm, emailLinkConfirmPage, AUTH_CSS } from '@mostajs/auth-ui';
@@ -165,12 +166,18 @@ const cookieDe = (req, nom) => (req.headers.cookie || '').split(';').map((s) =>
165
166
  * @param {{ envoyer: Function } | null} [o.transport] les courriels (code de connexion)
166
167
  * @param {{ banques?: Record<string, string>, port?: object }} [o.paiement] 0.3 — vente prépayée : les banques ACTIVES
167
168
  * et leur devise (`{ chargily: 'DZD', paypal: 'EUR' }`, server.mjs ne garde que celles dont le .env porte les
168
- * clés) ; `port` remplace @mostajs/payment (essais)
169
+ * clés) ; `port` remplace @mostajs/payment (essais) ; 0.6 — `deviseStripe` (défaut 'EUR') : la devise de Stripe
170
+ * 0.6 — une devise sans VENDEUR (`PAIEMENT_VENDEUR_<DEVISE>`, @mostajs/payment ≥ 2.7, règle en vigueur dès qu'une telle
171
+ * variable est déclarée) n'est pas vendue : Stripe et les banques de cette devise sont écartés ici, et `{{VENDEUR}}`
172
+ * des textes légaux nomme le vendeur de chaque devise vendue.
169
173
  */
170
174
  /** 0.5 — le commit en service (posé par le déployeur dans le dossier de l'instance) et l'heure de démarrage. */
171
175
  const lireRevision = (racine) => { try { return readFileSync(join(racine, 'REVISION'), 'utf8').trim() || null; } catch { return null; } };
172
176
  export async function creerWagon({ config, charge, sgbd, baseUrl, stripe = null, webhookSecret = '', transport = null, journal = console, paiement = null, racine = process.cwd() }) {
173
177
  const origine = String(baseUrl || '').replace(/\/$/, '');
178
+ // 0.6 — pas de vente dans une devise sans vendeur (même si les clés de sa banque sont posées).
179
+ const deviseStripe = String(paiement?.deviseStripe ?? 'EUR').toUpperCase();
180
+ if (stripe && !venteAutorisee(deviseStripe)) { journal.warn(`wagon : Stripe écarté — aucun vendeur pour ${deviseStripe} (PAIEMENT_VENDEUR_${deviseStripe})`); stripe = null; }
174
181
  const REVISION = lireRevision(racine); const DEMARRE_LE = new Date().toISOString();
175
182
  const https = /^https:/.test(origine);
176
183
  const S = Object.fromEntries(schemasWagon().map((s) => [s.name, s]));
@@ -226,7 +233,11 @@ export async function creerWagon({ config, charge, sgbd, baseUrl, stripe = null,
226
233
  accountOf: async (c) => (await d.findOne(S.Account, { stripeCustomerId: c }))?.id ?? null,
227
234
  },
228
235
  }) : null;
229
- const banques = { ...(paiement?.banques ?? {}) };
236
+ const banques = Object.fromEntries(Object.entries(paiement?.banques ?? {}).filter(([b, dv]) => {
237
+ if (venteAutorisee(String(dv))) return true;
238
+ journal.warn(`wagon : ${b} écarté — aucun vendeur pour ${String(dv).toUpperCase()} (PAIEMENT_VENDEUR_${String(dv).toUpperCase()})`);
239
+ return false;
240
+ }));
230
241
  const prepaye = Object.keys(banques).length ? createPrepaidSale({
231
242
  billing: facturation, providers: banques, payment: paiement?.port, metadataKeys: { account: META.account, plan: META.plan, period: 'wagon_periode' },
232
243
  // 0.10 — `return` : SATIM ne notifie pas le serveur, il renvoie l'acheteur (@mostajs/payment ≥ 2.6). Les banques à
@@ -329,12 +340,26 @@ export async function creerWagon({ config, charge, sgbd, baseUrl, stripe = null,
329
340
  */
330
341
  const NOMS_MOYENS = { stripe: 'Stripe (carte bancaire)', chargily: 'Chargily (CIB, Edahabia)', paypal: 'PayPal', satim: 'SATIM (CIB)' };
331
342
  const signales = new Set();
343
+ /**
344
+ * 0.6 — `{{VENDEUR}}` : le vendeur de chaque devise VENDUE (Stripe et les banques actives), d'après
345
+ * `PAIEMENT_VENDEUR_<DEVISE>` ; une ligne par devise. Vide si aucune n'a de vendeur : le texte n'est alors pas servi.
346
+ */
347
+ function vendeurLegal(lang) {
348
+ const vendeurs = vendeursFromEnv();
349
+ const parDevise = new Map(stripe ? [[deviseStripe, ['stripe']]] : []);
350
+ for (const [b, dv] of Object.entries(banques)) { const k = String(dv).toUpperCase(); parDevise.set(k, [...(parDevise.get(k) ?? []), b]); }
351
+ let noms = null; try { noms = new Intl.DisplayNames([lang, 'fr'], { type: 'currency' }); } catch { /* langue inconnue */ }
352
+ return [...parDevise].filter(([dv]) => vendeurs[dv]).map(([dv, ms]) => {
353
+ const n = noms?.of(dv) ?? dv;
354
+ return `- **${n.charAt(0).toUpperCase()}${n.slice(1)} (${dv})** — ${ms.map((m) => NOMS_MOYENS[m] ?? m).join(', ')} : ${vendeurs[dv]}`;
355
+ }).join('\n');
356
+ }
332
357
  function documentLegal(doc, lang) {
333
358
  const dossier = config.dossierLegal ?? join(racine, 'legal'); // la greffe, plus le moteur
334
359
  const f = [lang, 'fr'].map((l) => join(dossier, `${doc}.${l}.md`)).find((x) => existsSync(x));
335
360
  if (!f) return { html: '', complet: false };
336
361
  const moyens = [...(stripe ? ['stripe'] : []), ...Object.keys(paiement?.banques ?? {})].map((m) => NOMS_MOYENS[m] ?? m).join(', ');
337
- const valeurs = { SERVICE: config.marque.nom, DOMAINE: origine.replace(/^https?:\/\//, ''), CONTACT_EMAIL: config.marque.courriel ?? '', PAIEMENT: moyens, ...(config.legal ?? {}) };
362
+ const valeurs = { SERVICE: config.marque.nom, DOMAINE: origine.replace(/^https?:\/\//, ''), CONTACT_EMAIL: config.marque.courriel ?? '', PAIEMENT: moyens, VENDEUR: vendeurLegal(lang), ...(config.legal ?? {}) };
338
363
  const manquants = new Set();
339
364
  const texte = readFileSync(f, 'utf8').replace(/\{\{(\w+)\}\}/g, (m, k) => { if (valeurs[k]) return String(valeurs[k]); manquants.add(k); return ''; });
340
365
  const aTrancher = /⚖️|À FAIRE TRANCHER/.test(texte);
@@ -347,6 +372,14 @@ export async function creerWagon({ config, charge, sgbd, baseUrl, stripe = null,
347
372
  return { html: complet ? mdToHtml(texte).html : '', complet };
348
373
  }
349
374
 
375
+ /** 0.5 — les textes légaux servis dans une langue (lus une fois : ils ne changent qu'au redéploiement). */
376
+ const LEGAUX = ['mentions-legales', 'cgu', 'cgv', 'confidentialite'];
377
+ const servis = new Map();
378
+ const legauxServis = (lang) => {
379
+ if (!servis.has(lang)) servis.set(lang, LEGAUX.filter((doc) => documentLegal(doc, lang).complet));
380
+ return servis.get(lang);
381
+ };
382
+
350
383
  async function vueEspace(compte) {
351
384
  const actif = await facturation.activePlan(String(compte.id));
352
385
  const quotas = {};
@@ -413,7 +446,9 @@ export async function creerWagon({ config, charge, sgbd, baseUrl, stripe = null,
413
446
  const qui = s ? await comptes.qui(String(s.user ?? s.userId ?? '')) : null;
414
447
  const estAdmin = !!(qui && await estAdministrateur(qui.utilisateur.courriel));
415
448
  // 0.5 — `chemin` : la page réelle (canonique, liens de langue) ; `actif` reste l'onglet (wagon-ui 0.5.1).
416
- const page = (o) => ui.page({ lang, connecte: !!qui, base: origine, chemin, ...o });
449
+ // 0.5 — le pied de page ne liste que les textes légaux SERVIS (un lien vers un texte incomplet menait à un 404) ;
450
+ // `config.cadreWagon` donne le cadre des pages du moteur (une page de la charge qui choisit le sien le garde).
451
+ const page = (o) => ui.page({ lang, connecte: !!qui, base: origine, chemin, legaux: legauxServis(lang), ...(config.cadreWagon ?? {}), ...o });
417
452
  const ouvrirSession = async (userId, vers = '/compte') => rediriger(vers, { 'set-cookie': cookieStrict('wagon_session', await sessions.ouvrir(userId), { maxAge: 30 * 86400, https }) });
418
453
 
419
454
  // 0.5 — la santé : le commit EN SERVICE (fichier REVISION posé par le déployeur) et l'heure de démarrage.
@@ -608,7 +643,7 @@ export async function creerWagon({ config, charge, sgbd, baseUrl, stripe = null,
608
643
  if (!p) return null;
609
644
  const pp = typeof p.prepaid === 'string' ? JSON.parse(p.prepaid || 'null') : p.prepaid;
610
645
  const l = [...new Set(Object.values(banques))].filter((dv) => Number(pp?.[dv]?.month) > 0).map((dv) => ({ centimes: Number(pp[dv].month), devise: dv }));
611
- if (stripe && Number(p.price) > 0) l.push({ centimes: Number(p.price), devise: 'EUR' });
646
+ if (stripe && Number(p.price) > 0) l.push({ centimes: Number(p.price), devise: deviseStripe });
612
647
  return l.length ? l : null;
613
648
  };
614
649
  const suite = suiteSure(url.searchParams.get('suite'));
@@ -884,6 +919,8 @@ export async function creerWagon({ config, charge, sgbd, baseUrl, stripe = null,
884
919
  }
885
920
 
886
921
  return {
922
+ // 0.6 — les moyens réellement proposés (après le contrôle du vendeur de chaque devise)
923
+ moyens: [...(stripe ? ['stripe'] : []), ...Object.keys(banques)],
887
924
  handler: (req, res) => handler(req, res).catch((e) => { journal.error(e); if (!res.headersSent) { res.writeHead(500, { 'content-type': 'text/plain; charset=utf-8' }); res.end('Erreur interne'); } }),
888
925
  catalogue, catalogueStripe, dialect: d, schemas: S, comptes, facturation, confirmerAdmin, reprendrePaiements,
889
926
  /** Fixe le mot de passe d'un compte depuis le serveur (mot de passe perdu) ; lève si la règle le refuse. */