Files
itinova-budget-si/drizzle/schema.ts

163 lines
9.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import {
boolean,
decimal,
int,
mysqlEnum,
mysqlTable,
text,
timestamp,
varchar,
} from "drizzle-orm/mysql-core";
// ─────────────────────────────────────────────────────────────────────────────
// USERS — Auth locale (email/password), 3 profils : admin | standard | readonly
// ─────────────────────────────────────────────────────────────────────────────
export const users = mysqlTable("users", {
id: int("id").autoincrement().primaryKey(),
/** Identifiant de connexion (email ou login court comme adminItinova) */
login: varchar("login", { length: 255 }).notNull().unique(),
email: varchar("email", { length: 320 }),
passwordHash: varchar("passwordHash", { length: 255 }).notNull(),
firstName: varchar("firstName", { length: 100 }),
lastName: varchar("lastName", { length: 100 }),
role: mysqlEnum("role", ["admin", "standard", "readonly"]).default("standard").notNull(),
isActive: boolean("isActive").default(true).notNull(),
createdAt: timestamp("createdAt").defaultNow().notNull(),
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
lastSignedIn: timestamp("lastSignedIn"),
});
export type User = typeof users.$inferSelect;
export type InsertUser = typeof users.$inferInsert;
// ─────────────────────────────────────────────────────────────────────────────
// ÉTABLISSEMENTS
// ─────────────────────────────────────────────────────────────────────────────
export const etablissements = mysqlTable("etablissements", {
id: int("id").autoincrement().primaryKey(),
code: varchar("code", { length: 50 }).notNull().unique(),
nom: varchar("nom", { length: 255 }).notNull(),
groupe: varchar("groupe", { length: 100 }),
ville: varchar("ville", { length: 100 }),
actif: boolean("actif").default(true).notNull(),
createdAt: timestamp("createdAt").defaultNow().notNull(),
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
});
export type Etablissement = typeof etablissements.$inferSelect;
export type InsertEtablissement = typeof etablissements.$inferInsert;
// Rattachement utilisateur ↔ établissements (pour profil standard/readonly)
export const userEtablissements = mysqlTable("user_etablissements", {
id: int("id").autoincrement().primaryKey(),
userId: int("userId").notNull(),
etablissementCode: varchar("etablissementCode", { length: 50 }).notNull(),
});
// ─────────────────────────────────────────────────────────────────────────────
// PARAMÈTRES APPLICATION
// ─────────────────────────────────────────────────────────────────────────────
export const parametresApp = mysqlTable("parametres_app", {
id: int("id").autoincrement().primaryKey(),
cle: varchar("cle", { length: 100 }).notNull().unique(),
valeur: text("valeur"),
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
});
// ─────────────────────────────────────────────────────────────────────────────
// OPEX — Postes budgétaires
// ─────────────────────────────────────────────────────────────────────────────
export const opexPostes = mysqlTable("opex_postes", {
id: int("id").autoincrement().primaryKey(),
annee: int("annee").notNull(),
colIdx: int("colIdx").notNull(),
libelle: varchar("libelle", { length: 255 }).notNull(),
libelleCourt: varchar("libelleCourt", { length: 100 }),
libelleDetail: varchar("libelleDetail", { length: 255 }),
fournisseur: varchar("fournisseur", { length: 255 }),
categorie: varchar("categorie", { length: 100 }),
type: varchar("type", { length: 100 }),
facturation: varchar("facturation", { length: 100 }),
modeVentilation: varchar("modeVentilation", { length: 50 }).default("Prorata C 6"),
compte: varchar("compte", { length: 50 }),
detail: text("detail"),
budgetN1: decimal("budgetN1", { precision: 12, scale: 2 }),
montant: decimal("montant", { precision: 12, scale: 2 }),
isCustom: boolean("isCustom").default(false),
createdAt: timestamp("createdAt").defaultNow().notNull(),
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
});
export type OpexPoste = typeof opexPostes.$inferSelect;
export type InsertOpexPoste = typeof opexPostes.$inferInsert;
// Overrides manuels par établissement × poste × année
export const opexMontantsEtab = mysqlTable("opex_montants_etab", {
id: int("id").autoincrement().primaryKey(),
annee: int("annee").notNull(),
etablissementCode: varchar("etablissementCode", { length: 50 }).notNull(),
libellePoste: varchar("libellePoste", { length: 255 }).notNull(),
montant: decimal("montant", { precision: 12, scale: 2 }),
createdAt: timestamp("createdAt").defaultNow().notNull(),
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
});
export type OpexMontantEtab = typeof opexMontantsEtab.$inferSelect;
export type InsertOpexMontantEtab = typeof opexMontantsEtab.$inferInsert;
// Validation définitive par année
export const opexValidated = mysqlTable("opex_validated", {
id: int("id").autoincrement().primaryKey(),
annee: int("annee").notNull().unique(),
validatedAt: timestamp("validatedAt").defaultNow().notNull(),
validatedBy: int("validatedBy"),
});
// ─────────────────────────────────────────────────────────────────────────────
// INVENTAIRE PC
// ─────────────────────────────────────────────────────────────────────────────
export const inventairePostes = mysqlTable("inventaire_postes", {
id: int("id").autoincrement().primaryKey(),
annee: int("annee").notNull(),
etablissementCode: varchar("etablissementCode", { length: 50 }).notNull(),
libelle: varchar("libelle", { length: 255 }),
typePoste: mysqlEnum("typePoste", ["fixe", "portable"]).notNull(),
dateRef: varchar("dateRef", { length: 20 }),
ageAns: decimal("ageAns", { precision: 5, scale: 2 }),
modele: varchar("modele", { length: 255 }),
fabricant: varchar("fabricant", { length: 100 }),
createdAt: timestamp("createdAt").defaultNow().notNull(),
});
export type InventairePoste = typeof inventairePostes.$inferSelect;
export type InsertInventairePoste = typeof inventairePostes.$inferInsert;
// Métadonnées d'import inventaire
export const inventaireMeta = mysqlTable("inventaire_meta", {
id: int("id").autoincrement().primaryKey(),
annee: int("annee").notNull().unique(),
filename: varchar("filename", { length: 255 }),
dateImport: timestamp("dateImport").defaultNow().notNull(),
nbEtablissements: int("nbEtablissements").default(0),
nbFixes: int("nbFixes").default(0),
nbPortables: int("nbPortables").default(0),
});
// ─────────────────────────────────────────────────────────────────────────────
// CAPEX — Lignes budgétaires par établissement
// ─────────────────────────────────────────────────────────────────────────────
export const capexLignes = mysqlTable("capex_lignes", {
id: int("id").autoincrement().primaryKey(),
annee: int("annee").notNull(),
etablissementCode: varchar("etablissementCode", { length: 50 }).notNull(),
cle: varchar("cle", { length: 100 }).notNull(),
// cles possibles: renouvellement_2027 | machines_supplementaires | appel_malade
// | telephonie | wifi | video_surveillance | copieurs | visio | autres | commentaires
montant: decimal("montant", { precision: 12, scale: 2 }),
createdAt: timestamp("createdAt").defaultNow().notNull(),
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
});
export type CapexLigne = typeof capexLignes.$inferSelect;
export type InsertCapexLigne = typeof capexLignes.$inferInsert;