import { and, eq } from "drizzle-orm"; import { drizzle } from "drizzle-orm/mysql2"; import { capexLignes, etablissements, InsertCapexLigne, InsertEtablissement, InsertOpexMontantEtab, InsertOpexPoste, InsertUser, inventaireMeta, inventairePostes, opexMontantsEtab, opexPostes, opexValidated, parametresApp, userEtablissements, users, } from "../drizzle/schema"; let _db: ReturnType | null = null; // Lazily create the drizzle instance so local tooling can run without a DB. export async function getDb() { if (!_db && process.env.DATABASE_URL) { try { _db = drizzle(process.env.DATABASE_URL); } catch (error) { console.warn("[Database] Failed to connect:", error); _db = null; } } return _db; } // ───────────────────────────────────────────────────────────────────────────── // USERS // ───────────────────────────────────────────────────────────────────────────── export async function getUserByLogin(login: string) { const db = await getDb(); if (!db) return undefined; const result = await db .select() .from(users) .where(eq(users.login, login)) .limit(1); return result.length > 0 ? result[0] : undefined; } export async function getUserById(id: number) { const db = await getDb(); if (!db) return undefined; const result = await db.select().from(users).where(eq(users.id, id)).limit(1); return result.length > 0 ? result[0] : undefined; } export async function createUser(user: InsertUser) { const db = await getDb(); if (!db) throw new Error("Database not available"); const [result] = await db.insert(users).values(user); return result; } export async function updateUser(id: number, data: Partial) { const db = await getDb(); if (!db) throw new Error("Database not available"); await db.update(users).set(data).where(eq(users.id, id)); } export async function listUsers() { const db = await getDb(); if (!db) return []; return db.select().from(users); } export async function deleteUser(id: number) { const db = await getDb(); if (!db) throw new Error("Database not available"); await db.delete(users).where(eq(users.id, id)); } export async function updateLastSignedIn(id: number) { const db = await getDb(); if (!db) return; await db .update(users) .set({ lastSignedIn: new Date() }) .where(eq(users.id, id)); } // ───────────────────────────────────────────────────────────────────────────── // ÉTABLISSEMENTS // ───────────────────────────────────────────────────────────────────────────── export async function listEtablissements() { const db = await getDb(); if (!db) return []; return db.select().from(etablissements); } export async function upsertEtablissement(etab: InsertEtablissement) { const db = await getDb(); if (!db) throw new Error("Database not available"); await db .insert(etablissements) .values(etab) .onDuplicateKeyUpdate({ set: { nom: etab.nom, groupe: etab.groupe, ville: etab.ville, actif: etab.actif, }, }); } export async function deleteEtablissement(code: string) { const db = await getDb(); if (!db) throw new Error("Database not available"); await db.delete(etablissements).where(eq(etablissements.code, code)); } // ───────────────────────────────────────────────────────────────────────────── // PARAMÈTRES // ───────────────────────────────────────────────────────────────────────────── export async function getParametres() { const db = await getDb(); if (!db) return []; return db.select().from(parametresApp); } export async function setParametre(cle: string, valeur: string) { const db = await getDb(); if (!db) throw new Error("Database not available"); await db .insert(parametresApp) .values({ cle, valeur }) .onDuplicateKeyUpdate({ set: { valeur } }); } // ───────────────────────────────────────────────────────────────────────────── // OPEX // ───────────────────────────────────────────────────────────────────────────── export async function getOpexPostes(annee: number) { const db = await getDb(); if (!db) return []; return db .select() .from(opexPostes) .where(eq(opexPostes.annee, annee)); } export async function upsertOpexPoste(poste: InsertOpexPoste) { const db = await getDb(); if (!db) throw new Error("Database not available"); if (poste.id) { await db .update(opexPostes) .set(poste) .where(eq(opexPostes.id, poste.id)); } else { await db.insert(opexPostes).values(poste); } } export async function insertOpexPostes(postes: InsertOpexPoste[]) { const db = await getDb(); if (!db) throw new Error("Database not available"); if (postes.length === 0) return; await db.insert(opexPostes).values(postes); } export async function getOpexMontantsEtab(annee: number) { const db = await getDb(); if (!db) return []; return db .select() .from(opexMontantsEtab) .where(eq(opexMontantsEtab.annee, annee)); } export async function setOpexMontantEtab(data: InsertOpexMontantEtab) { const db = await getDb(); if (!db) throw new Error("Database not available"); await db .insert(opexMontantsEtab) .values(data) .onDuplicateKeyUpdate({ set: { montant: data.montant } }); } export async function insertOpexMontantsEtab(rows: InsertOpexMontantEtab[]) { const db = await getDb(); if (!db) throw new Error("Database not available"); if (rows.length === 0) return; // Insert par batch de 100 for (let i = 0; i < rows.length; i += 100) { await db.insert(opexMontantsEtab).values(rows.slice(i, i + 100)); } } export async function deleteOpexPostes(annee: number) { const db = await getDb(); if (!db) return; await db.delete(opexPostes).where(eq(opexPostes.annee, annee)); } export async function deleteOpexMontantsEtab(annee: number) { const db = await getDb(); if (!db) return; await db.delete(opexMontantsEtab).where(eq(opexMontantsEtab.annee, annee)); } export async function getOpexValidated(annee: number) { const db = await getDb(); if (!db) return null; const result = await db .select() .from(opexValidated) .where(eq(opexValidated.annee, annee)) .limit(1); return result.length > 0 ? result[0] : null; } export async function setOpexValidated(annee: number, userId: number) { const db = await getDb(); if (!db) throw new Error("Database not available"); await db .insert(opexValidated) .values({ annee, validatedBy: userId }) .onDuplicateKeyUpdate({ set: { validatedAt: new Date() } }); } // ───────────────────────────────────────────────────────────────────────────── // INVENTAIRE PC // ───────────────────────────────────────────────────────────────────────────── export async function getInventaire(annee: number) { const db = await getDb(); if (!db) return []; return db .select() .from(inventairePostes) .where(eq(inventairePostes.annee, annee)); } export async function getInventaireMeta(annee: number) { const db = await getDb(); if (!db) return null; const result = await db .select() .from(inventaireMeta) .where(eq(inventaireMeta.annee, annee)) .limit(1); return result.length > 0 ? result[0] : null; } export async function listInventaireMeta() { const db = await getDb(); if (!db) return []; return db.select().from(inventaireMeta).orderBy(inventaireMeta.annee); } export async function importInventaire( annee: number, postes: typeof inventairePostes.$inferInsert[], meta: { filename: string; nbEtablissements: number; nbFixes: number; nbPortables: number } ) { const db = await getDb(); if (!db) throw new Error("Database not available"); // Supprimer l'inventaire existant pour cette année await db.delete(inventairePostes).where(eq(inventairePostes.annee, annee)); // Insérer les nouveaux postes par batch if (postes.length > 0) { for (let i = 0; i < postes.length; i += 200) { await db.insert(inventairePostes).values(postes.slice(i, i + 200)); } } // Upsert meta await db .insert(inventaireMeta) .values({ annee, ...meta }) .onDuplicateKeyUpdate({ set: { ...meta, dateImport: new Date() } }); } // ───────────────────────────────────────────────────────────────────────────── // CAPEX // ───────────────────────────────────────────────────────────────────────────── export async function getCapexLignes(annee: number, etablissementCode: string) { const db = await getDb(); if (!db) return []; return db .select() .from(capexLignes) .where( and( eq(capexLignes.annee, annee), eq(capexLignes.etablissementCode, etablissementCode) ) ); } export async function saveCapexLignes( annee: number, etablissementCode: string, lignes: { cle: string; montant: string | null }[] ) { const db = await getDb(); if (!db) throw new Error("Database not available"); for (const ligne of lignes) { await db .insert(capexLignes) .values({ annee, etablissementCode, cle: ligne.cle, montant: ligne.montant }) .onDuplicateKeyUpdate({ set: { montant: ligne.montant } }); } } export async function insertCapexLignes(rows: InsertCapexLigne[]) { const db = await getDb(); if (!db) throw new Error("Database not available"); if (rows.length === 0) return; for (let i = 0; i < rows.length; i += 100) { await db.insert(capexLignes).values(rows.slice(i, i + 100)); } }