mirror of
https://github.com/R0m1k3/LogiFlow.git
synced 2026-10-17 04:06:44 +02:00
- Serveur Rust (server-rs/, axum + sqlx) : les 148 adresses de l'API, l'interface, les migrations de démarrage et les tâches de fond ; même comportement que Node (banc : 2027 cas, 0 écart hors écarts déclarés USERS-02, RAPPRO-21, R4, R5). - Node retiré : server/, dépendances serveur, image Docker sans Node (51 Mo), docker-compose à un seul service applicatif. - R4 : écritures d'un autre site refusées (Sec-Fetch-Site / Origin). - R5 : « aujourd'hui » et sauvegarde automatique à l'heure de Paris. - R6 : mainteneur dans .github/CODEOWNERS. - Menu latéral : Accueil puis Calendrier en tête. - Plan et état : docs/PLAN-MIGRATION-RUST.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ke2qyS8rgacP3ap5iezDbM
314 lines
19 KiB
TypeScript
314 lines
19 KiB
TypeScript
// Lot 4, services partagés : rapprochement BL / factures (commentaires, courriels
|
|
// fournisseurs, vérification des factures, cache), configuration NocoDB, BAP et
|
|
// clés de l'API externe. NocoDB, les webhooks et le SMTP sont simulés par stub.ts.
|
|
import { STUB_SMTP_PORT, STUB_URL } from "../config";
|
|
import type { ReadCase, WriteScenario } from "../types";
|
|
|
|
export const reads: ReadCase[] = [
|
|
// Commentaires de rapprochement (ReconciliationComments.tsx)
|
|
{ module: "reconciliation", path: "/api/deliveries/2/reconciliation-comments" },
|
|
{ module: "reconciliation", path: "/api/deliveries/4/reconciliation-comments" },
|
|
{ module: "reconciliation", path: "/api/deliveries/6/reconciliation-comments" },
|
|
{ module: "reconciliation", path: "/api/deliveries/999/reconciliation-comments" },
|
|
{ module: "reconciliation", path: "/api/deliveries/abc/reconciliation-comments" },
|
|
// Historique des relances (BLReconciliation.tsx : « ? » seul, ou storeId pour admin et directeur)
|
|
{ module: "reconciliation", path: "/api/supplier-mail-logs?" },
|
|
{ module: "reconciliation", path: "/api/supplier-mail-logs?storeId=1" },
|
|
{ module: "reconciliation", path: "/api/supplier-mail-logs?storeId=2" },
|
|
{ module: "reconciliation", path: "/api/supplier-mail-logs?deliveryId=2" },
|
|
{ module: "reconciliation", path: "/api/supplier-mail-logs?deliveryId=abc" },
|
|
{ module: "reconciliation", path: "/api/supplier-mail-logs?storeId=abc" },
|
|
// Diagnostic du cache (sans appelant dans l'interface ; supprime au passage une entrée expirée)
|
|
{ module: "reconciliation", path: "/api/cache/diagnosis" },
|
|
// Configuration NocoDB (NocoDBConfig.tsx, Groups.tsx)
|
|
{ module: "nocodb-config", path: "/api/nocodb-config" },
|
|
{ module: "nocodb-config", path: "/api/nocodb-config/active" },
|
|
// Webhook BAP (WebhookBAPConfig.tsx, BapUploadModal.tsx)
|
|
{ module: "bap", path: "/api/webhook-bap-config" },
|
|
// Clés de l'API externe (ExternalApiSettings.tsx)
|
|
{ module: "external-api", path: "/api/external-api/keys" },
|
|
];
|
|
|
|
// Durée de vie des entrées du cache : relative à l'heure du passage, différente
|
|
// entre les deux serveurs (vérifiée par les tests unitaires de Rust)
|
|
const CACHE_IGNORE = ["expires_at"];
|
|
|
|
export const writes: WriteScenario[] = [
|
|
// ---------- Commentaires ----------
|
|
{
|
|
module: "reconciliation",
|
|
name: "commentaires : ajouter, modifier, supprimer",
|
|
steps: [
|
|
{ method: "POST", path: "/api/deliveries/2/reconciliation-comments", body: { content: "Relance faite", type: "warning" } },
|
|
{ method: "PUT", path: "/api/reconciliation-comments/{{0.id}}", body: { content: "Relance faite (modifié)", type: "success" } },
|
|
{ method: "GET", path: "/api/deliveries/2/reconciliation-comments" },
|
|
{ method: "DELETE", path: "/api/reconciliation-comments/{{0.id}}" },
|
|
{ method: "POST", path: "/api/deliveries/6/reconciliation-comments", body: { content: "Commentaire à Metz" } },
|
|
{ method: "PUT", path: "/api/reconciliation-comments/1", body: { content: "Modifié par un autre compte" } },
|
|
{ method: "DELETE", path: "/api/reconciliation-comments/2" },
|
|
{ method: "GET", path: "/api/deliveries/4/reconciliation-comments" },
|
|
],
|
|
tables: ["reconciliation_comments"],
|
|
},
|
|
{
|
|
module: "reconciliation",
|
|
name: "commentaires : corps invalides et identifiants inconnus",
|
|
steps: [
|
|
{ method: "POST", path: "/api/deliveries/2/reconciliation-comments", body: {} },
|
|
{ method: "POST", path: "/api/deliveries/2/reconciliation-comments", body: { content: "x", type: "bizarre" } },
|
|
{ method: "POST", path: "/api/deliveries/2/reconciliation-comments", body: { content: 5 } },
|
|
{ method: "POST", path: "/api/deliveries/2/reconciliation-comments", body: { content: "Forcé", deliveryId: 6, groupId: 2, authorId: "admin_local" } },
|
|
{ method: "POST", path: "/api/deliveries/999/reconciliation-comments", body: { content: "x" } },
|
|
{ method: "POST", path: "/api/deliveries/abc/reconciliation-comments", body: { content: "x" } },
|
|
{ method: "PUT", path: "/api/reconciliation-comments/1", body: { type: "inconnu" } },
|
|
{ method: "PUT", path: "/api/reconciliation-comments/1", body: { deliveryId: 4, authorId: "admin_local" } },
|
|
{ method: "PUT", path: "/api/reconciliation-comments/2", body: { deliveryId: 99999 } },
|
|
{ method: "PUT", path: "/api/reconciliation-comments/999", body: {} },
|
|
{ method: "PUT", path: "/api/reconciliation-comments/abc", body: {} },
|
|
{ method: "DELETE", path: "/api/reconciliation-comments/999" },
|
|
{ method: "DELETE", path: "/api/reconciliation-comments/abc" },
|
|
],
|
|
tables: ["reconciliation_comments"],
|
|
},
|
|
|
|
// ---------- Courriel au fournisseur ----------
|
|
{
|
|
module: "reconciliation",
|
|
name: "courriel au fournisseur : envoi et refus",
|
|
steps: [
|
|
{ method: "POST", path: "/api/deliveries/2/send-supplier-mail" },
|
|
{ method: "POST", path: "/api/deliveries/4/send-supplier-mail" },
|
|
{ method: "POST", path: "/api/deliveries/6/send-supplier-mail" },
|
|
{ method: "POST", path: "/api/deliveries/7/send-supplier-mail" },
|
|
{ method: "POST", path: "/api/deliveries/999/send-supplier-mail" },
|
|
{ method: "POST", path: "/api/deliveries/abc/send-supplier-mail" },
|
|
{ method: "GET", path: "/api/supplier-mail-logs?deliveryId=2" },
|
|
],
|
|
tables: ["supplier_mail_logs"],
|
|
ignore: ["messageId", "message_id"],
|
|
},
|
|
{
|
|
module: "reconciliation",
|
|
name: "courriel au fournisseur : SMTP incomplet ou injoignable",
|
|
steps: [
|
|
// PUT /api/groups/:id reste servi par Node (lot 5) : admin et manager
|
|
{ method: "PUT", path: "/api/groups/2", body: { smtpEnabled: true } },
|
|
{ method: "POST", path: "/api/deliveries/6/send-supplier-mail" },
|
|
// Metz : sans logo, sans nom d'expéditeur ni authentification
|
|
{ method: "PUT", path: "/api/groups/2", body: { smtpHost: " 127.0.0.1 ", smtpPort: STUB_SMTP_PORT, smtpSenderEmail: "metz@banc.test", smtpUser: null } },
|
|
{ method: "POST", path: "/api/deliveries/6/send-supplier-mail" },
|
|
// Nancy : serveur injoignable
|
|
{ method: "PUT", path: "/api/groups/1", body: { smtpPort: 1 } },
|
|
{ method: "POST", path: "/api/deliveries/2/send-supplier-mail" },
|
|
{ method: "GET", path: "/api/supplier-mail-logs?" },
|
|
{ method: "GET", path: "/api/supplier-mail-logs?deliveryId=6&storeId=2" },
|
|
],
|
|
tables: ["supplier_mail_logs"],
|
|
ignore: ["messageId", "message_id"],
|
|
},
|
|
|
|
// ---------- Vérification des factures ----------
|
|
{
|
|
module: "reconciliation",
|
|
name: "vérifier la facture d'une livraison",
|
|
steps: [
|
|
{ method: "POST", path: "/api/deliveries/4/verify-invoice", body: { invoiceReference: "FAC-2004", forceRefresh: false } },
|
|
{ method: "POST", path: "/api/deliveries/4/verify-invoice", body: { invoiceReference: "FAC-2004", forceRefresh: true } },
|
|
{ method: "POST", path: "/api/deliveries/2/verify-invoice", body: { blNumber: "BL-1002", forceRefresh: false } },
|
|
{ method: "POST", path: "/api/deliveries/2/verify-invoice", body: { blNumber: "BL-1002" } },
|
|
{ method: "POST", path: "/api/deliveries/2/verify-invoice", body: { blNumber: "BL-1004" } },
|
|
{ method: "POST", path: "/api/deliveries/2/verify-invoice", body: { invoiceReference: "FAC-9999", blNumber: "BL-1002" } },
|
|
{ method: "POST", path: "/api/deliveries/3/verify-invoice", body: { invoiceReference: " BL-1001 " } },
|
|
{ method: "POST", path: "/api/deliveries/1/verify-invoice", body: { invoiceReference: "FAC-2001" } },
|
|
{ method: "POST", path: "/api/deliveries/6/verify-invoice", body: { invoiceReference: "FAC-2006", forceRefresh: true } },
|
|
{ method: "POST", path: "/api/deliveries/7/verify-invoice", body: { invoiceReference: "FAC-3000" } },
|
|
{ method: "POST", path: "/api/deliveries/8/verify-invoice", body: { invoiceReference: "AV-3001", forceRefresh: true } },
|
|
],
|
|
tables: ["deliveries", "invoice_verification_cache"],
|
|
ignore: CACHE_IGNORE,
|
|
},
|
|
{
|
|
module: "reconciliation",
|
|
name: "vérifier la facture d'une livraison : corps invalides",
|
|
steps: [
|
|
{ method: "POST", path: "/api/deliveries/4/verify-invoice", body: {} },
|
|
{ method: "POST", path: "/api/deliveries/4/verify-invoice", body: { invoiceReference: " ", blNumber: "" } },
|
|
{ method: "POST", path: "/api/deliveries/4/verify-invoice", body: { invoiceReference: 12 } },
|
|
{ method: "POST", path: "/api/deliveries/4/verify-invoice", body: { invoiceReference: " ", blNumber: true } },
|
|
{ method: "POST", path: "/api/deliveries/999/verify-invoice", body: { invoiceReference: "FAC-2004" } },
|
|
{ method: "POST", path: "/api/deliveries/abc/verify-invoice", body: { invoiceReference: "FAC-2004" } },
|
|
],
|
|
tables: ["deliveries", "invoice_verification_cache"],
|
|
ignore: CACHE_IGNORE,
|
|
},
|
|
{
|
|
module: "reconciliation",
|
|
name: "vérifier une facture : NocoDB injoignable, en erreur ou désactivé",
|
|
steps: [
|
|
{ method: "PUT", path: "/api/nocodb-config/1", body: { baseUrl: "http://127.0.0.1:1" } },
|
|
{ method: "POST", path: "/api/deliveries/4/verify-invoice", body: { invoiceReference: "FAC-2004", forceRefresh: true } },
|
|
{ method: "PUT", path: "/api/nocodb-config/1", body: { baseUrl: `${STUB_URL}/autre` } },
|
|
{ method: "POST", path: "/api/deliveries/2/verify-invoice", body: { invoiceReference: "FAC-2002", forceRefresh: true } },
|
|
{ method: "POST", path: "/api/deliveries/2/verify-invoice", body: { blNumber: "BL-1002", forceRefresh: true } },
|
|
{ method: "PUT", path: "/api/nocodb-config/1", body: { baseUrl: "pas une adresse" } },
|
|
{ method: "POST", path: "/api/deliveries/4/verify-invoice", body: { invoiceReference: "FAC-2004", forceRefresh: true } },
|
|
{ method: "PUT", path: "/api/nocodb-config/1", body: { isActive: false } },
|
|
{ method: "POST", path: "/api/deliveries/4/verify-invoice", body: { invoiceReference: "FAC-2004", forceRefresh: true } },
|
|
],
|
|
tables: ["invoice_verification_cache", "nocodb_config"],
|
|
ignore: CACHE_IGNORE,
|
|
},
|
|
{
|
|
module: "reconciliation",
|
|
name: "vérifier des factures (adresses sans magasin contrôlé)",
|
|
steps: [
|
|
{ method: "POST", path: "/api/verify-invoice", body: { groupId: 1, invoiceReference: "FAC-2002" } },
|
|
{ method: "POST", path: "/api/verify-invoice", body: { groupId: "1", invoiceReference: "fac-2002" } },
|
|
{ method: "POST", path: "/api/verify-invoice", body: { groupId: 2, invoiceReference: "FAC-2001" } },
|
|
{ method: "POST", path: "/api/verify-invoice", body: { groupId: 3, invoiceReference: "FAC-2001" } },
|
|
{ method: "POST", path: "/api/verify-invoice", body: { groupId: 99, invoiceReference: "FAC-2001" } },
|
|
{ method: "POST", path: "/api/verify-invoice", body: { groupId: "abc", invoiceReference: "FAC-2001" } },
|
|
{ method: "POST", path: "/api/verify-invoice", body: { groupId: 1, invoiceReference: 5 } },
|
|
{ method: "POST", path: "/api/verify-invoice", body: { groupId: 1, invoiceReference: " " } },
|
|
{ method: "POST", path: "/api/verify-invoice", body: { groupId: 1 } },
|
|
{ method: "POST", path: "/api/verify-invoices", body: { invoiceReferences: [{ groupId: 1, invoiceReference: "fac-2001", deliveryId: 10, supplierName: "lactalis" }, { groupId: 3, invoiceReference: "X", deliveryId: 2 }] } },
|
|
{ method: "POST", path: "/api/verify-invoices", body: { invoiceReferences: [{ groupId: 1, invoiceReference: "FAC-2001", deliveryId: 1, supplierName: "Bonduelle" }] } },
|
|
{ method: "POST", path: "/api/verify-invoices", body: { invoiceReferences: [{ groupId: 1, deliveryId: 3 }] } },
|
|
// Une seule clé non numérique par appel : Node les range dans l'ordre où ses
|
|
// vérifications parallèles se terminent
|
|
{ method: "POST", path: "/api/verify-invoices", body: { invoiceReferences: [{ deliveryId: "a" }, { groupId: 99, deliveryId: 5 }] } },
|
|
{ method: "POST", path: "/api/verify-invoices", body: { invoiceReferences: [7] } },
|
|
{ method: "POST", path: "/api/verify-invoices", body: { invoiceReferences: [{ groupId: "abc", deliveryId: 4 }] } },
|
|
{ method: "POST", path: "/api/verify-invoices", body: { invoiceReferences: [null] } },
|
|
{ method: "POST", path: "/api/verify-invoices", body: { invoiceReferences: "FAC-2001" } },
|
|
],
|
|
tables: ["invoice_verification_cache"],
|
|
ignore: CACHE_IGNORE,
|
|
},
|
|
|
|
// ---------- Cache des factures ----------
|
|
{
|
|
module: "reconciliation",
|
|
name: "cache : marquer rapproché, mise à jour en lot, diagnostic",
|
|
steps: [
|
|
{ method: "POST", path: "/api/cache/mark-reconciled", body: { invoiceReference: " FAC-2004 ", groupId: 1 } },
|
|
{ method: "POST", path: "/api/cache/mark-reconciled", body: { invoiceReference: "FAC-1900", groupId: "1" } },
|
|
{ method: "POST", path: "/api/cache/mark-reconciled", body: { invoiceReference: 5, groupId: 1 } },
|
|
{ method: "POST", path: "/api/cache/mark-reconciled", body: { invoiceReference: "FAC-2004" } },
|
|
{ method: "POST", path: "/api/cache/update-reconciled" },
|
|
{ method: "GET", path: "/api/cache/diagnosis" },
|
|
],
|
|
tables: ["invoice_verification_cache"],
|
|
},
|
|
|
|
// ---------- Configuration NocoDB ----------
|
|
{
|
|
module: "nocodb-config",
|
|
name: "configurations NocoDB : créer, modifier, supprimer",
|
|
steps: [
|
|
{ method: "POST", path: "/api/nocodb-config", body: { name: "NocoDB secours", baseUrl: `${STUB_URL}/nocodb`, projectId: "psecours", apiToken: "jeton-neuf", description: "Seconde base", isActive: false, createdBy: "pirate" } },
|
|
{ method: "PUT", path: "/api/nocodb-config/{{0.id}}", body: { name: "NocoDB renommée", apiToken: "jeton-modifié" } },
|
|
{ method: "PUT", path: "/api/nocodb-config/{{0.id}}", body: {} },
|
|
{ method: "GET", path: "/api/nocodb-config" },
|
|
{ method: "GET", path: "/api/nocodb-config/active" },
|
|
{ method: "DELETE", path: "/api/nocodb-config/{{0.id}}" },
|
|
{ method: "DELETE", path: "/api/nocodb-config/999" },
|
|
{ method: "PUT", path: "/api/nocodb-config/999", body: { name: "Absente" } },
|
|
{ method: "POST", path: "/api/nocodb-config", body: { name: "Sans jeton", baseUrl: "http://x.test", projectId: "p", apiToken: "" } },
|
|
],
|
|
tables: ["nocodb_config"],
|
|
ignore: ["api_token"],
|
|
},
|
|
{
|
|
module: "nocodb-config",
|
|
name: "configurations NocoDB : corps invalides",
|
|
steps: [
|
|
{ method: "POST", path: "/api/nocodb-config", body: {} },
|
|
{ method: "POST", path: "/api/nocodb-config", body: { name: "x", baseUrl: 1, projectId: "p", apiToken: "t" } },
|
|
{ method: "PUT", path: "/api/nocodb-config/1", body: { isActive: "oui" } },
|
|
{ method: "PUT", path: "/api/nocodb-config/abc", body: {} },
|
|
{ method: "DELETE", path: "/api/nocodb-config/abc" },
|
|
],
|
|
tables: ["nocodb_config"],
|
|
ignore: ["api_token"],
|
|
},
|
|
|
|
// ---------- BAP ----------
|
|
{
|
|
module: "bap",
|
|
name: "webhook BAP : configuration",
|
|
steps: [
|
|
{ method: "POST", path: "/api/webhook-bap-config", body: { name: "BAP banc", webhookUrl: `${STUB_URL}/webhook/bap-nouveau`, description: "Modifiée", isActive: true, id: 7 } },
|
|
{ method: "GET", path: "/api/webhook-bap-config" },
|
|
{ method: "POST", path: "/api/webhook-bap-config", body: { webhookUrl: 12 } },
|
|
{ method: "POST", path: "/api/webhook-bap-config", body: {} },
|
|
{ method: "POST", path: "/api/webhook-bap-config", body: { name: "x".repeat(101), webhookUrl: "u", isActive: "oui" } },
|
|
],
|
|
tables: ["webhook_bap_config"],
|
|
},
|
|
{
|
|
module: "bap",
|
|
name: "webhook BAP : test de connexion",
|
|
steps: [
|
|
{ method: "POST", path: "/api/webhook-bap-config/test", body: { webhookUrl: `${STUB_URL}/webhook/bap` } },
|
|
{ method: "POST", path: "/api/webhook-bap-config/test", body: { webhookUrl: `${STUB_URL}/autre` } },
|
|
{ method: "POST", path: "/api/webhook-bap-config/test", body: {} },
|
|
{ method: "POST", path: "/api/webhook-bap-config/test", body: { webhookUrl: "pas-une-url" } },
|
|
{ method: "POST", path: "/api/webhook-bap-config/test", body: { webhookUrl: "http://127.0.0.1:1" } },
|
|
{ method: "POST", path: "/api/webhook-bap-config/test", body: { webhookUrl: "ftp://x.test/a" } },
|
|
],
|
|
tables: [],
|
|
},
|
|
{
|
|
module: "bap",
|
|
name: "envoi d'un BAP au webhook",
|
|
steps: [
|
|
{ method: "POST", path: "/api/bap/send-webhook", body: { pdfBase64: "JVBERi0xLjQKJcOkw7zDtsOf", fileName: "Facture-123.PDF", recipient: "Laurie" } },
|
|
{ method: "POST", path: "/api/bap/send-webhook", body: { pdfBase64: "JVBERi0xLjQK", fileName: "a.pdf", recipient: "Paul" } },
|
|
{ method: "POST", path: "/api/bap/send-webhook", body: { pdfBase64: "JVBERi0xLjQK", fileName: "a.txt", recipient: "Jeremy" } },
|
|
{ method: "POST", path: "/api/bap/send-webhook", body: { pdfBase64: 5, fileName: "a.pdf", recipient: "Jeremy" } },
|
|
{ method: "POST", path: "/api/bap/send-webhook", body: { pdfBase64: [1, 2], fileName: "a.pdf", recipient: "Jeremy" } },
|
|
{ method: "POST", path: "/api/bap/send-webhook", body: { pdfBase64: "x", fileName: 5, recipient: "Laurie" } },
|
|
{ method: "POST", path: "/api/bap/send-webhook", body: { fileName: "a.pdf" } },
|
|
{ method: "POST", path: "/api/webhook-bap-config", body: { webhookUrl: `${STUB_URL}/autre` } },
|
|
{ method: "POST", path: "/api/bap/send-webhook", body: { pdfBase64: "JVBERi0xLjQK", fileName: "b.pdf", recipient: "Jeremy" } },
|
|
{ method: "POST", path: "/api/webhook-bap-config", body: { webhookUrl: `${STUB_URL}/webhook/bap`, isActive: false } },
|
|
{ method: "POST", path: "/api/bap/send-webhook", body: { pdfBase64: "JVBERi0xLjQK", fileName: "c.pdf", recipient: "Laurie" } },
|
|
],
|
|
tables: ["webhook_bap_config"],
|
|
},
|
|
|
|
// ---------- Clés de l'API externe ----------
|
|
{
|
|
module: "external-api",
|
|
name: "clés d'API : créer, révoquer",
|
|
steps: [
|
|
{ method: "POST", path: "/api/external-api/keys", body: { name: " Nouvel outil " } },
|
|
{ method: "DELETE", path: "/api/external-api/keys/{{0.apiKey.id}}" },
|
|
{ method: "DELETE", path: "/api/external-api/keys/{{0.apiKey.id}}" },
|
|
{ method: "DELETE", path: "/api/external-api/keys/2" },
|
|
{ method: "DELETE", path: "/api/external-api/keys/1" },
|
|
{ method: "DELETE", path: "/api/external-api/keys/1e2" },
|
|
{ method: "GET", path: "/api/external-api/keys" },
|
|
],
|
|
tables: ["external_api_keys"],
|
|
ignore: ["key", "keyPrefix", "key_prefix", "key_hash"],
|
|
},
|
|
{
|
|
module: "external-api",
|
|
name: "clés d'API : nom ou identifiant invalide",
|
|
steps: [
|
|
{ method: "POST", path: "/api/external-api/keys", body: {} },
|
|
{ method: "POST", path: "/api/external-api/keys", body: { name: " " } },
|
|
{ method: "POST", path: "/api/external-api/keys", body: { name: 5 } },
|
|
{ method: "POST", path: "/api/external-api/keys", body: { name: "x".repeat(101) } },
|
|
{ method: "POST", path: "/api/external-api/keys", body: [] },
|
|
{ method: "DELETE", path: "/api/external-api/keys/abc" },
|
|
{ method: "DELETE", path: "/api/external-api/keys/0" },
|
|
{ method: "DELETE", path: "/api/external-api/keys/1.5" },
|
|
{ method: "DELETE", path: "/api/external-api/keys/99999999999" },
|
|
],
|
|
tables: ["external_api_keys"],
|
|
},
|
|
];
|