feat(grid): ajout algorithme score produit avec parametrage dynamique et page d'aide

This commit is contained in:
Michael committed 2026-02-21 04:00:51 +01:00
1 parent f540e4f2b3
commit 3544c0c898
67 files changed
+19476 -15

No files matched your search

+10
View File
@@ -0,0 +1,10 @@
import { drizzle } from "drizzle-orm/pg-proxy"; // Or node-postgres if using directly
import { drizzle as nodeDrizzle } from "drizzle-orm/node-postgres";
import { Pool } from "pg";
import * as schema from "./schema";
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
});
export const db = nodeDrizzle(pool, { schema });
+62
View File
@@ -0,0 +1,62 @@
import { pgTable, serial, varchar, numeric, smallint, timestamp, uniqueIndex, index, text, jsonb } from "drizzle-orm/pg-core";
export const ventesProduits = pgTable("ventes_produits", {
id: serial("id").primaryKey(),
// Identification produit
codein: varchar("codein", { length: 20 }).notNull(),
codeFournisseur: varchar("code_fournisseur", { length: 20 }),
nomFournisseur: varchar("nom_fournisseur", { length: 255 }),
libelle1: varchar("libelle1", { length: 500 }),
gtin: varchar("gtin", { length: 30 }),
reference: varchar("reference", { length: 100 }),
colisage: numeric("colisage", { precision: 10, scale: 5 }),
// Gamme & Nomenclature
codeGamme: varchar("code_gamme", { length: 20 }),
code3: varchar("code3", { length: 20 }),
libelle3: varchar("libelle3", { length: 500 }),
// Dimension magasin & période
magasin: varchar("magasin", { length: 20 }).notNull(),
codeMagasin: varchar("code_magasin", { length: 10 }),
annee: smallint("annee"),
mois: smallint("mois"),
periode: varchar("periode", { length: 10 }).notNull(),
// Métriques
quantite: numeric("quantite", { precision: 12, scale: 2 }),
montantMvt: numeric("montant_mvt", { precision: 14, scale: 4 }),
margeMvt: numeric("marge_mvt", { precision: 14, scale: 4 }),
// Métadonnées
importedAt: timestamp("imported_at").defaultNow(),
updatedAt: timestamp("updated_at").defaultNow(),
}, (table) => {
return [
uniqueIndex("uq_ventes_produit_magasin_periode").on(table.codein, table.magasin, table.periode),
index("idx_ventes_codein").on(table.codein),
index("idx_ventes_fournisseur").on(table.codeFournisseur),
index("idx_ventes_gamme").on(table.codeGamme),
index("idx_ventes_code3").on(table.code3),
index("idx_ventes_magasin").on(table.magasin),
index("idx_ventes_periode").on(table.periode),
index("idx_ventes_annee_mois").on(table.annee, table.mois),
index("idx_ventes_updated_at").on(table.updatedAt),
];
});
/** Snapshot of a complete arbitrage session (Epic 5) */
export const sessionSnapshots = pgTable("session_snapshots", {
id: serial("id").primaryKey(),
codeFournisseur: varchar("code_fournisseur", { length: 20 }).notNull(),
nomFournisseur: varchar("nom_fournisseur", { length: 255 }),
magasin: varchar("magasin", { length: 20 }).notNull(),
/** JSON map of codein → { before: GammeCode, after: GammeCode } */
changes: jsonb("changes").notNull(),
/** Summary stats at time of snapshot */
summaryJson: jsonb("summary_json"),
/** Label for the snapshot */
label: text("label"),
createdAt: timestamp("created_at").defaultNow(),
});