mirror of
https://github.com/R0m1k3/CollectFlow.git
synced 2026-10-11 17:26:32 +02:00
Grille (navigateur) - « Rafraîchir » ne passe plus par l'URL : le paramètre _refresh restait mémorisé et chaque retour par le menu forçait un recalcul serveur complet (migration du store pour nettoyer les valeurs déjà enregistrées). - Lignes reçues regroupées toutes les 300 ms au lieu de reconstruire tout le tableau à chaque paquet de 150 (chargement quadratique). - Sélection indexée par code article (getRowId) : après un filtre, l'action groupée visait d'autres produits. Seules les lignes affichées comptent. - Recherche : un passage par ligne au lieu d'un par colonne ; formateurs de nombres partagés (lib/format.ts) ; colonnes mensuelles mémorisées ; plus de transition-all sur les lignes positionnées par transform. - exceljs, jspdf et xlsx chargés au clic seulement. Grille (serveur) - Requêtes Qlik et snapshot lancées en parallèle de la phase SQL. - Cache mémoire borné (LRU) ; calcul en cours réutilisé même en forcé ; flux interrompu quand le client part. - Après un enregistrement, les gammes sont reportées dans le cache et dans grid_rows au lieu d'invalider (recalcul de ~40 s évité). Données et API - lib/ff-cache.ts : cache mémoire 30 min des lectures FF (stock, hit-parade, CA mensuel, fournisseurs, dernière réception, publicités), vidé en fin de synchro nocturne ; erreurs jamais gardées. - Pool PostgreSQL unique (globalThis), réglage sans workers parallèles posé une fois par connexion au lieu d'une transaction autour de chaque requête. - Délai maximal sur tous les appels à l'API FF. - Index session_snapshots ; commandes : plus de double rechargement ; synchro : saisies regroupées ; paramètres : configuration lue une fois ; journal de capture en ajout seul, rien de formaté sans capture ouverte. Corrections - Historique : l'échec de chargement s'affiche (au lieu de « Aucun snapshot »). - Sessions et validations enregistrent le magasin affiché, plus « TOTAL ». - Publicités : libellé du statut « passées ». Plan complet : docs/plan-optimisation-webui.md Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AcA129WzGTH6zxPHFBGWmn
88 lines
3.2 KiB
TypeScript
88 lines
3.2 KiB
TypeScript
"use server";
|
|
|
|
import { db } from "@/db";
|
|
import { sessionSnapshots } from "@/db/schema";
|
|
import { eq, desc } from "drizzle-orm";
|
|
import { z } from "zod";
|
|
import { auth } from "@/lib/auth";
|
|
import { patchGridRowsCache } from "./get-product-rows";
|
|
import { updateGridRowsGamme } from "@/lib/grid-store";
|
|
|
|
const SaveDraftsSchema = z.object({
|
|
codeFournisseur: z.string(),
|
|
nomFournisseur: z.string().optional(),
|
|
magasin: z.string(),
|
|
changes: z.array(
|
|
z.object({
|
|
codein: z.string(),
|
|
codeGammeBefore: z.string().nullable(),
|
|
codeGamme: z.string(),
|
|
})
|
|
),
|
|
});
|
|
|
|
export async function saveDraftChanges(
|
|
raw: unknown
|
|
): Promise<{ success: boolean; saved: number; error?: string }> {
|
|
const parsed = SaveDraftsSchema.safeParse(raw);
|
|
if (!parsed.success) {
|
|
return { success: false, saved: 0, error: "Validation failed: " + parsed.error.message };
|
|
}
|
|
|
|
const { codeFournisseur, nomFournisseur, magasin, changes } = parsed.data;
|
|
|
|
const session = await auth();
|
|
const rawUserId = (session?.user as { id?: string | number })?.id;
|
|
const userId = rawUserId ? parseInt(String(rawUserId), 10) : null;
|
|
const finalUserId = userId && !isNaN(userId) ? userId : null;
|
|
|
|
try {
|
|
// Charger le dernier snapshot existant pour merger les changements
|
|
const existing = await db
|
|
.select()
|
|
.from(sessionSnapshots)
|
|
.where(eq(sessionSnapshots.codeFournisseur, codeFournisseur))
|
|
.orderBy(desc(sessionSnapshots.createdAt))
|
|
.limit(1);
|
|
|
|
const prevChanges: Record<string, { before: string | null; after: string }> =
|
|
existing.length > 0
|
|
? (existing[0].changes as Record<string, { before: string | null; after: string }>)
|
|
: {};
|
|
|
|
// Merger les nouveaux changements par-dessus l'existant
|
|
const mergedChanges = { ...prevChanges };
|
|
for (const c of changes) {
|
|
mergedChanges[c.codein] = {
|
|
before: c.codeGammeBefore,
|
|
after: c.codeGamme,
|
|
};
|
|
}
|
|
|
|
// Upsert : insérer un nouveau snapshot "draft" pour ce fournisseur
|
|
await db.insert(sessionSnapshots).values({
|
|
userId: finalUserId,
|
|
codeFournisseur,
|
|
nomFournisseur: nomFournisseur ?? null,
|
|
magasin,
|
|
label: `Draft — ${new Date().toLocaleDateString("fr-FR")}`,
|
|
changes: mergedChanges,
|
|
summaryJson: null,
|
|
type: "snapshot",
|
|
});
|
|
|
|
// Les lignes en cache reçoivent les nouvelles gammes au lieu d'être jetées :
|
|
// l'invalidation imposait un recalcul complet (jusqu'à ~40 s) à la
|
|
// réouverture suivante. L'instantané lu par /api/v1 suit, sans bloquer.
|
|
patchGridRowsCache(codeFournisseur, changes);
|
|
void updateGridRowsGamme(codeFournisseur, changes).catch((e) =>
|
|
console.error("[saveDraftChanges] mise à jour grid_rows KO:", (e as Error).message?.slice(0, 200)),
|
|
);
|
|
|
|
return { success: true, saved: changes.length };
|
|
} catch (err) {
|
|
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
return { success: false, saved: 0, error: msg };
|
|
}
|
|
}
|