mirror of
https://github.com/R0m1k3/CollectFlow.git
synced 2026-10-12 09:46:56 +02:00
feat: Add FF Nancy API client and status endpoint, implement grid product fetching and draft change saving, and introduce AI Copilot core logic.
This commit is contained in:
1 parent
22aa6f101a
commit
1035489db1
13 files changed
+706
-265
No files matched your search
@@ -1,18 +1,20 @@
|
||||
"use server";
|
||||
|
||||
import { db } from "@/db";
|
||||
import { ventesProduits } from "@/db/schema";
|
||||
import { eq, and, sql } from "drizzle-orm";
|
||||
import { sessionSnapshots } from "@/db/schema";
|
||||
import { eq, desc } from "drizzle-orm";
|
||||
import { z } from "zod";
|
||||
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { auth } from "@/lib/auth";
|
||||
|
||||
const SaveDraftsSchema = z.object({
|
||||
codeFournisseur: z.string(),
|
||||
nomFournisseur: z.string().optional(),
|
||||
magasin: z.string(),
|
||||
changes: z.array(
|
||||
z.object({
|
||||
codein: z.string(),
|
||||
magasin: z.string(),
|
||||
codeGamme: z.enum(["A", "B", "C", "Z"]),
|
||||
codeGammeBefore: z.string().nullable(),
|
||||
codeGamme: z.string(),
|
||||
})
|
||||
),
|
||||
});
|
||||
@@ -25,29 +27,48 @@ export async function saveDraftChanges(
|
||||
return { success: false, saved: 0, error: "Validation failed: " + parsed.error.message };
|
||||
}
|
||||
|
||||
const { changes } = parsed.data;
|
||||
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 {
|
||||
// Batch update all rows for given codein.
|
||||
// If magasin is "TOTAL", update ALL stores for that product.
|
||||
await Promise.all(
|
||||
changes.map(({ codein, magasin, codeGamme }) => {
|
||||
const whereClause = [eq(ventesProduits.codein, codein)];
|
||||
if (magasin !== "TOTAL") {
|
||||
whereClause.push(eq(ventesProduits.magasin, magasin));
|
||||
}
|
||||
// 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);
|
||||
|
||||
return db
|
||||
.update(ventesProduits)
|
||||
.set({
|
||||
codeGamme,
|
||||
codeGammeInit: sql`COALESCE(ventes_produits.code_gamme_init, ventes_produits.code_gamme)`
|
||||
})
|
||||
.where(and(...whereClause));
|
||||
})
|
||||
);
|
||||
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",
|
||||
});
|
||||
|
||||
revalidatePath("/grid");
|
||||
return { success: true, saved: changes.length };
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : "Unknown error";
|
||||
|
||||
Reference in new issue
Block a user