Sistema de Gestión de Obras de Construcción completo con: - Dashboard con KPIs y gráficos - Módulo de obras con fases y tareas - Control financiero (gastos, presupuestos) - Gestión de recursos (personal, subcontratistas) - Inventario de materiales con alertas de stock - Reportes con exportación CSV - Autenticación con roles (NextAuth.js v5) - API REST completa - Documentación de API y base de datos - Configuración Docker para despliegue Stack: Next.js 14+, TypeScript, Tailwind CSS, Prisma, PostgreSQL Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
467 lines
12 KiB
Plaintext
467 lines
12 KiB
Plaintext
// Prisma schema for Construction Management System
|
|
|
|
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
// ============== ENUMS ==============
|
|
|
|
enum Role {
|
|
ADMIN
|
|
GERENTE
|
|
SUPERVISOR
|
|
CONTADOR
|
|
EMPLEADO
|
|
}
|
|
|
|
enum EstadoObra {
|
|
PLANIFICACION
|
|
EN_PROGRESO
|
|
PAUSADA
|
|
COMPLETADA
|
|
CANCELADA
|
|
}
|
|
|
|
enum EstadoTarea {
|
|
PENDIENTE
|
|
EN_PROGRESO
|
|
COMPLETADA
|
|
BLOQUEADA
|
|
}
|
|
|
|
enum EstadoGasto {
|
|
PENDIENTE
|
|
APROBADO
|
|
RECHAZADO
|
|
PAGADO
|
|
}
|
|
|
|
enum CategoriaGasto {
|
|
MATERIALES
|
|
MANO_DE_OBRA
|
|
EQUIPOS
|
|
SUBCONTRATISTAS
|
|
PERMISOS
|
|
TRANSPORTE
|
|
SERVICIOS
|
|
OTROS
|
|
}
|
|
|
|
enum TipoFactura {
|
|
EMITIDA
|
|
RECIBIDA
|
|
}
|
|
|
|
enum EstadoFactura {
|
|
PENDIENTE
|
|
PAGADA
|
|
VENCIDA
|
|
CANCELADA
|
|
}
|
|
|
|
enum TipoMovimiento {
|
|
ENTRADA
|
|
SALIDA
|
|
AJUSTE
|
|
}
|
|
|
|
enum UnidadMedida {
|
|
UNIDAD
|
|
METRO
|
|
METRO_CUADRADO
|
|
METRO_CUBICO
|
|
KILOGRAMO
|
|
TONELADA
|
|
LITRO
|
|
BOLSA
|
|
PIEZA
|
|
ROLLO
|
|
CAJA
|
|
}
|
|
|
|
// ============== MODELS ==============
|
|
|
|
model User {
|
|
id String @id @default(cuid())
|
|
email String @unique
|
|
password String
|
|
nombre String
|
|
apellido String
|
|
role Role @default(EMPLEADO)
|
|
telefono String?
|
|
activo Boolean @default(true)
|
|
empresaId String
|
|
empresa Empresa @relation(fields: [empresaId], references: [id])
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
// Relations
|
|
gastosCreados Gasto[] @relation("GastoCreador")
|
|
gastosAprobados Gasto[] @relation("GastoAprobador")
|
|
tareasAsignadas TareaObra[]
|
|
obrasSupervision Obra[] @relation("ObraSupervisor")
|
|
registrosAvance RegistroAvance[]
|
|
|
|
@@index([empresaId])
|
|
@@index([email])
|
|
}
|
|
|
|
model Empresa {
|
|
id String @id @default(cuid())
|
|
nombre String
|
|
rfc String? @unique
|
|
direccion String?
|
|
telefono String?
|
|
email String?
|
|
logo String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
// Relations
|
|
usuarios User[]
|
|
obras Obra[]
|
|
materiales Material[]
|
|
empleados Empleado[]
|
|
subcontratistas Subcontratista[]
|
|
clientes Cliente[]
|
|
}
|
|
|
|
model Cliente {
|
|
id String @id @default(cuid())
|
|
nombre String
|
|
rfc String?
|
|
direccion String?
|
|
telefono String?
|
|
email String?
|
|
empresaId String
|
|
empresa Empresa @relation(fields: [empresaId], references: [id])
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
// Relations
|
|
obras Obra[]
|
|
|
|
@@index([empresaId])
|
|
}
|
|
|
|
model Obra {
|
|
id String @id @default(cuid())
|
|
nombre String
|
|
descripcion String?
|
|
direccion String
|
|
estado EstadoObra @default(PLANIFICACION)
|
|
fechaInicio DateTime?
|
|
fechaFinPrevista DateTime?
|
|
fechaFinReal DateTime?
|
|
porcentajeAvance Float @default(0)
|
|
presupuestoTotal Float @default(0)
|
|
gastoTotal Float @default(0)
|
|
imagenPortada String?
|
|
empresaId String
|
|
empresa Empresa @relation(fields: [empresaId], references: [id])
|
|
clienteId String?
|
|
cliente Cliente? @relation(fields: [clienteId], references: [id])
|
|
supervisorId String?
|
|
supervisor User? @relation("ObraSupervisor", fields: [supervisorId], references: [id])
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
// Relations
|
|
fases FaseObra[]
|
|
presupuestos Presupuesto[]
|
|
gastos Gasto[]
|
|
facturas Factura[]
|
|
movimientosInv MovimientoInventario[]
|
|
asignaciones AsignacionEmpleado[]
|
|
contratos ContratoSubcontratista[]
|
|
registrosAvance RegistroAvance[]
|
|
|
|
@@index([empresaId])
|
|
@@index([estado])
|
|
@@index([clienteId])
|
|
}
|
|
|
|
model FaseObra {
|
|
id String @id @default(cuid())
|
|
nombre String
|
|
descripcion String?
|
|
orden Int
|
|
fechaInicio DateTime?
|
|
fechaFin DateTime?
|
|
porcentajeAvance Float @default(0)
|
|
obraId String
|
|
obra Obra @relation(fields: [obraId], references: [id], onDelete: Cascade)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
// Relations
|
|
tareas TareaObra[]
|
|
|
|
@@index([obraId])
|
|
}
|
|
|
|
model TareaObra {
|
|
id String @id @default(cuid())
|
|
nombre String
|
|
descripcion String?
|
|
estado EstadoTarea @default(PENDIENTE)
|
|
prioridad Int @default(1)
|
|
fechaInicio DateTime?
|
|
fechaFin DateTime?
|
|
porcentajeAvance Float @default(0)
|
|
faseId String
|
|
fase FaseObra @relation(fields: [faseId], references: [id], onDelete: Cascade)
|
|
asignadoId String?
|
|
asignado User? @relation(fields: [asignadoId], references: [id])
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([faseId])
|
|
@@index([estado])
|
|
}
|
|
|
|
model RegistroAvance {
|
|
id String @id @default(cuid())
|
|
descripcion String
|
|
porcentaje Float
|
|
fotos String[]
|
|
obraId String
|
|
obra Obra @relation(fields: [obraId], references: [id], onDelete: Cascade)
|
|
registradoPorId String
|
|
registradoPor User @relation(fields: [registradoPorId], references: [id])
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([obraId])
|
|
}
|
|
|
|
model Presupuesto {
|
|
id String @id @default(cuid())
|
|
nombre String
|
|
descripcion String?
|
|
version Int @default(1)
|
|
total Float @default(0)
|
|
aprobado Boolean @default(false)
|
|
obraId String
|
|
obra Obra @relation(fields: [obraId], references: [id], onDelete: Cascade)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
// Relations
|
|
partidas PartidaPresupuesto[]
|
|
|
|
@@index([obraId])
|
|
}
|
|
|
|
model PartidaPresupuesto {
|
|
id String @id @default(cuid())
|
|
codigo String
|
|
descripcion String
|
|
unidad UnidadMedida
|
|
cantidad Float
|
|
precioUnitario Float
|
|
total Float
|
|
categoria CategoriaGasto
|
|
presupuestoId String
|
|
presupuesto Presupuesto @relation(fields: [presupuestoId], references: [id], onDelete: Cascade)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
// Relations
|
|
gastos Gasto[]
|
|
|
|
@@index([presupuestoId])
|
|
}
|
|
|
|
model Gasto {
|
|
id String @id @default(cuid())
|
|
concepto String
|
|
descripcion String?
|
|
monto Float
|
|
fecha DateTime
|
|
categoria CategoriaGasto
|
|
estado EstadoGasto @default(PENDIENTE)
|
|
comprobante String?
|
|
notas String?
|
|
obraId String
|
|
obra Obra @relation(fields: [obraId], references: [id], onDelete: Cascade)
|
|
partidaId String?
|
|
partida PartidaPresupuesto? @relation(fields: [partidaId], references: [id])
|
|
creadoPorId String
|
|
creadoPor User @relation("GastoCreador", fields: [creadoPorId], references: [id])
|
|
aprobadoPorId String?
|
|
aprobadoPor User? @relation("GastoAprobador", fields: [aprobadoPorId], references: [id])
|
|
fechaAprobacion DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([obraId])
|
|
@@index([estado])
|
|
@@index([categoria])
|
|
@@index([fecha])
|
|
}
|
|
|
|
model Factura {
|
|
id String @id @default(cuid())
|
|
numero String
|
|
tipo TipoFactura
|
|
concepto String
|
|
monto Float
|
|
iva Float @default(0)
|
|
total Float
|
|
fechaEmision DateTime
|
|
fechaVencimiento DateTime?
|
|
fechaPago DateTime?
|
|
estado EstadoFactura @default(PENDIENTE)
|
|
archivo String?
|
|
obraId String
|
|
obra Obra @relation(fields: [obraId], references: [id], onDelete: Cascade)
|
|
proveedorNombre String?
|
|
proveedorRfc String?
|
|
clienteNombre String?
|
|
clienteRfc String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([obraId])
|
|
@@index([tipo])
|
|
@@index([estado])
|
|
}
|
|
|
|
model Material {
|
|
id String @id @default(cuid())
|
|
codigo String
|
|
nombre String
|
|
descripcion String?
|
|
unidad UnidadMedida
|
|
precioUnitario Float
|
|
stockMinimo Float @default(0)
|
|
stockActual Float @default(0)
|
|
ubicacion String?
|
|
activo Boolean @default(true)
|
|
empresaId String
|
|
empresa Empresa @relation(fields: [empresaId], references: [id])
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
// Relations
|
|
movimientos MovimientoInventario[]
|
|
|
|
@@unique([codigo, empresaId])
|
|
@@index([empresaId])
|
|
@@index([nombre])
|
|
}
|
|
|
|
model MovimientoInventario {
|
|
id String @id @default(cuid())
|
|
tipo TipoMovimiento
|
|
cantidad Float
|
|
motivo String?
|
|
materialId String
|
|
material Material @relation(fields: [materialId], references: [id])
|
|
obraId String?
|
|
obra Obra? @relation(fields: [obraId], references: [id])
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([materialId])
|
|
@@index([obraId])
|
|
@@index([tipo])
|
|
}
|
|
|
|
model Empleado {
|
|
id String @id @default(cuid())
|
|
nombre String
|
|
apellido String
|
|
documento String?
|
|
telefono String?
|
|
email String?
|
|
puesto String
|
|
salarioBase Float?
|
|
fechaIngreso DateTime
|
|
fechaBaja DateTime?
|
|
activo Boolean @default(true)
|
|
empresaId String
|
|
empresa Empresa @relation(fields: [empresaId], references: [id])
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
// Relations
|
|
asignaciones AsignacionEmpleado[]
|
|
jornadas JornadaTrabajo[]
|
|
|
|
@@index([empresaId])
|
|
}
|
|
|
|
model AsignacionEmpleado {
|
|
id String @id @default(cuid())
|
|
fechaInicio DateTime
|
|
fechaFin DateTime?
|
|
activo Boolean @default(true)
|
|
empleadoId String
|
|
empleado Empleado @relation(fields: [empleadoId], references: [id])
|
|
obraId String
|
|
obra Obra @relation(fields: [obraId], references: [id])
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([empleadoId])
|
|
@@index([obraId])
|
|
}
|
|
|
|
model JornadaTrabajo {
|
|
id String @id @default(cuid())
|
|
fecha DateTime
|
|
horasRegular Float @default(0)
|
|
horasExtra Float @default(0)
|
|
notas String?
|
|
empleadoId String
|
|
empleado Empleado @relation(fields: [empleadoId], references: [id])
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([empleadoId])
|
|
@@index([fecha])
|
|
}
|
|
|
|
model Subcontratista {
|
|
id String @id @default(cuid())
|
|
nombre String
|
|
rfc String?
|
|
especialidad String
|
|
telefono String?
|
|
email String?
|
|
direccion String?
|
|
activo Boolean @default(true)
|
|
empresaId String
|
|
empresa Empresa @relation(fields: [empresaId], references: [id])
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
// Relations
|
|
contratos ContratoSubcontratista[]
|
|
|
|
@@index([empresaId])
|
|
}
|
|
|
|
model ContratoSubcontratista {
|
|
id String @id @default(cuid())
|
|
descripcion String
|
|
montoContratado Float
|
|
montoPagado Float @default(0)
|
|
fechaInicio DateTime
|
|
fechaFin DateTime?
|
|
estado String @default("ACTIVO")
|
|
subcontratistaId String
|
|
subcontratista Subcontratista @relation(fields: [subcontratistaId], references: [id])
|
|
obraId String
|
|
obra Obra @relation(fields: [obraId], references: [id])
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([subcontratistaId])
|
|
@@index([obraId])
|
|
}
|