163 lines
9.1 KiB
TypeScript
163 lines
9.1 KiB
TypeScript
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;
|