Files
mexus-app/prisma/schema.prisma
Mexus 56e39af3ff feat: Implement complete APU (Análisis de Precios Unitarios) module
High priority features:
- APU CRUD with materials, labor, and equipment breakdown
- Labor catalog with FSR (Factor de Salario Real) calculation
- Equipment catalog with hourly cost calculation
- Link APU to budget line items (partidas)
- Explosion de insumos (consolidated materials list)

Additional features:
- Duplicate APU functionality
- Excel export for explosion de insumos
- Search and filters in APU list
- Price validation alerts for outdated prices
- PDF report export for APU

New components:
- APUForm, APUList, APUDetail
- ManoObraForm, EquipoForm
- ConfiguracionAPUForm
- VincularAPUDialog
- PartidasManager
- ExplosionInsumos
- APUPDF

New UI components:
- Alert component
- Tooltip component

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 07:14:14 +00:00

1077 lines
29 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
HORA
JORNADA
VIAJE
LOTE
GLOBAL
}
enum CategoriaManoObra {
PEON
AYUDANTE
OFICIAL_ALBANIL
OFICIAL_FIERRERO
OFICIAL_CARPINTERO
OFICIAL_PLOMERO
OFICIAL_ELECTRICISTA
CABO
MAESTRO_OBRA
OPERADOR_EQUIPO
}
enum TipoEquipo {
MAQUINARIA_PESADA
MAQUINARIA_LIGERA
HERRAMIENTA_ELECTRICA
TRANSPORTE
}
enum TipoInsumoAPU {
MATERIAL
MANO_OBRA
EQUIPO
HERRAMIENTA_MENOR
}
// ============== 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[]
fotosSubidas FotoAvance[]
bitacorasRegistradas BitacoraObra[]
asistenciasRegistradas Asistencia[]
ordenesCreadas OrdenCompra[] @relation("OrdenCreador")
ordenesAprobadas OrdenCompra[] @relation("OrdenAprobador")
pushSubscriptions PushSubscription[]
notificaciones Notificacion[]
actividades ActividadLog[]
@@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[]
// APU Relations
categoriasTrabajo CategoriaTrabajoAPU[]
equiposMaquinaria EquipoMaquinaria[]
apus AnalisisPrecioUnitario[]
configuracionAPU ConfiguracionAPU?
}
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[]
accesos ClienteAcceso[]
@@index([empresaId])
}
// ============== PORTAL DE CLIENTES ==============
model ClienteAcceso {
id String @id @default(cuid())
email String @unique
password String? // Hash de contraseña (opcional si usa token)
token String? @unique // Token de acceso único
tokenExpira DateTime? // Expiración del token
activo Boolean @default(true)
ultimoAcceso DateTime?
// Permisos
verFotos Boolean @default(true)
verAvances Boolean @default(true)
verGastos Boolean @default(false)
verDocumentos Boolean @default(true)
descargarPDF Boolean @default(true)
// Relaciones
clienteId String
cliente Cliente @relation(fields: [clienteId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([clienteId])
@@index([token])
}
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[]
fotos FotoAvance[]
bitacoras BitacoraObra[]
asistencias Asistencia[]
ordenesCompra OrdenCompra[]
actividadesLog ActividadLog[]
@@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[]
fotos FotoAvance[]
@@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])
@@index([asignadoId])
@@index([faseId, 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])
@@index([registradoPorId])
@@index([obraId, createdAt])
}
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)
apuId String?
apu AnalisisPrecioUnitario? @relation(fields: [apuId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
gastos Gasto[]
@@index([presupuestoId])
@@index([apuId])
}
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[]
itemsOrden ItemOrdenCompra[]
insumosAPU InsumoAPU[]
@@unique([codigo, empresaId])
@@index([empresaId])
@@index([nombre])
@@index([activo, empresaId])
}
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[]
asistencias Asistencia[]
@@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])
@@index([empleadoId, 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])
}
// ============== ÓRDENES DE COMPRA ==============
enum EstadoOrdenCompra {
BORRADOR
PENDIENTE
APROBADA
ENVIADA
RECIBIDA_PARCIAL
RECIBIDA
CANCELADA
}
enum PrioridadOrden {
BAJA
NORMAL
ALTA
URGENTE
}
model OrdenCompra {
id String @id @default(cuid())
numero String // Número de orden (OC-001, etc.)
// Estado y prioridad
estado EstadoOrdenCompra @default(BORRADOR)
prioridad PrioridadOrden @default(NORMAL)
// Fechas
fechaEmision DateTime @default(now())
fechaRequerida DateTime? // Fecha en que se necesitan los materiales
fechaAprobacion DateTime?
fechaEnvio DateTime?
fechaRecepcion DateTime?
// Proveedor
proveedorNombre String
proveedorRfc String?
proveedorContacto String?
proveedorTelefono String?
proveedorEmail String?
proveedorDireccion String?
// Totales
subtotal Float @default(0)
descuento Float @default(0)
iva Float @default(0)
total Float @default(0)
// Condiciones
condicionesPago String? // Ej: "Contado", "Crédito 30 días"
tiempoEntrega String? // Ej: "3-5 días hábiles"
lugarEntrega String? // Dirección de entrega
// Notas
notas String? @db.Text
notasInternas String? @db.Text
// Relaciones
obraId String
obra Obra @relation(fields: [obraId], references: [id], onDelete: Cascade)
creadoPorId String
creadoPor User @relation("OrdenCreador", fields: [creadoPorId], references: [id])
aprobadoPorId String?
aprobadoPor User? @relation("OrdenAprobador", fields: [aprobadoPorId], references: [id])
// Items
items ItemOrdenCompra[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([numero, obraId])
@@index([obraId])
@@index([estado])
@@index([fechaEmision])
}
model ItemOrdenCompra {
id String @id @default(cuid())
// Descripción del item
codigo String? // Código del material
descripcion String
unidad UnidadMedida
// Cantidades
cantidad Float
cantidadRecibida Float @default(0)
// Precios
precioUnitario Float
descuento Float @default(0)
subtotal Float
// Relaciones
ordenId String
orden OrdenCompra @relation(fields: [ordenId], references: [id], onDelete: Cascade)
materialId String? // Opcional: vincular con catálogo de materiales
material Material? @relation(fields: [materialId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([ordenId])
@@index([materialId])
}
// ============== CONTROL DE ASISTENCIA ==============
enum TipoAsistencia {
PRESENTE
AUSENTE
RETARDO
PERMISO
INCAPACIDAD
VACACIONES
}
model Asistencia {
id String @id @default(cuid())
fecha DateTime @db.Date
// Estado de asistencia
tipo TipoAsistencia @default(PRESENTE)
// Registro de entrada
horaEntrada DateTime?
latitudEntrada Float?
longitudEntrada Float?
// Registro de salida
horaSalida DateTime?
latitudSalida Float?
longitudSalida Float?
// Horas trabajadas (calculadas)
horasTrabajadas Float?
horasExtra Float @default(0)
// Notas y observaciones
notas String?
motivoAusencia String?
// Relaciones
empleadoId String
empleado Empleado @relation(fields: [empleadoId], references: [id], onDelete: Cascade)
obraId String
obra Obra @relation(fields: [obraId], references: [id], onDelete: Cascade)
registradoPorId String
registradoPor User @relation(fields: [registradoPorId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([empleadoId, obraId, fecha])
@@index([empleadoId])
@@index([obraId])
@@index([fecha])
@@index([tipo])
}
// ============== BITÁCORA DE OBRA ==============
enum CondicionClima {
SOLEADO
NUBLADO
PARCIALMENTE_NUBLADO
LLUVIA_LIGERA
LLUVIA_FUERTE
TORMENTA
VIENTO_FUERTE
FRIO_EXTREMO
CALOR_EXTREMO
}
model BitacoraObra {
id String @id @default(cuid())
fecha DateTime @db.Date
// Condiciones climáticas
clima CondicionClima
temperaturaMin Float?
temperaturaMax Float?
condicionesExtra String? // Notas adicionales del clima
// Personal en obra
personalPropio Int @default(0)
personalSubcontrato Int @default(0)
personalDetalle String? // Descripción del personal
// Actividades del día
actividadesRealizadas String @db.Text
actividadesPendientes String? @db.Text
// Materiales
materialesUtilizados String? @db.Text
materialesRecibidos String? @db.Text
// Equipo y maquinaria
equipoUtilizado String? @db.Text
// Incidentes y observaciones
incidentes String? @db.Text
observaciones String? @db.Text
// Seguridad
incidentesSeguridad String? @db.Text
platicaSeguridad Boolean @default(false)
temaSeguridad String?
// Visitas
visitasInspeccion String? @db.Text
// Relaciones
obraId String
obra Obra @relation(fields: [obraId], references: [id], onDelete: Cascade)
registradoPorId String
registradoPor User @relation(fields: [registradoPorId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([obraId, fecha])
@@index([obraId])
@@index([fecha])
}
// ============== FOTOS DE AVANCE ==============
model FotoAvance {
id String @id @default(cuid())
url String // Ruta del archivo
thumbnail String? // Ruta de la miniatura
titulo String?
descripcion String?
fechaCaptura DateTime @default(now())
// Geolocalización
latitud Float?
longitud Float?
direccionGeo String? // Dirección obtenida por geocoding
// Metadatos
tamanio Int? // Tamaño en bytes
tipo String? // MIME type (image/jpeg, etc.)
ancho Int? // Width en pixels
alto Int? // Height en pixels
// Relaciones
obraId String
obra Obra @relation(fields: [obraId], references: [id], onDelete: Cascade)
faseId String?
fase FaseObra? @relation(fields: [faseId], references: [id])
subidoPorId String
subidoPor User @relation(fields: [subidoPorId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([obraId])
@@index([faseId])
@@index([fechaCaptura])
@@index([subidoPorId])
@@index([obraId, fechaCaptura])
}
// ============== NOTIFICACIONES PUSH ==============
enum TipoNotificacion {
TAREA_ASIGNADA
TAREA_COMPLETADA
GASTO_PENDIENTE
GASTO_APROBADO
ORDEN_APROBADA
AVANCE_REGISTRADO
RECORDATORIO
ALERTA_INVENTARIO
GENERAL
}
model PushSubscription {
id String @id @default(cuid())
endpoint String @unique
p256dh String
auth String
activo Boolean @default(true)
// Preferencias de notificación
notifyTareas Boolean @default(true)
notifyGastos Boolean @default(true)
notifyOrdenes Boolean @default(true)
notifyAvances Boolean @default(true)
notifyAlertas Boolean @default(true)
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([userId])
}
model Notificacion {
id String @id @default(cuid())
tipo TipoNotificacion
titulo String
mensaje String
url String? // URL para navegar al hacer clic
leida Boolean @default(false)
enviada Boolean @default(false)
// Datos adicionales en JSON
metadata String? @db.Text
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
@@index([userId])
@@index([leida])
@@index([createdAt])
}
// ============== LOG DE ACTIVIDADES ==============
enum TipoActividad {
OBRA_CREADA
OBRA_ACTUALIZADA
OBRA_ESTADO_CAMBIADO
FASE_CREADA
TAREA_CREADA
TAREA_ASIGNADA
TAREA_COMPLETADA
TAREA_ESTADO_CAMBIADO
GASTO_CREADO
GASTO_APROBADO
GASTO_RECHAZADO
ORDEN_CREADA
ORDEN_APROBADA
ORDEN_ENVIADA
ORDEN_RECIBIDA
AVANCE_REGISTRADO
FOTO_SUBIDA
BITACORA_REGISTRADA
MATERIAL_MOVIMIENTO
USUARIO_ASIGNADO
COMENTARIO_AGREGADO
DOCUMENTO_SUBIDO
}
model ActividadLog {
id String @id @default(cuid())
tipo TipoActividad
descripcion String
detalles String? @db.Text // JSON con datos adicionales
// Entidad afectada
entidadTipo String? // "obra", "tarea", "gasto", etc.
entidadId String?
entidadNombre String?
// Contexto
obraId String?
obra Obra? @relation(fields: [obraId], references: [id], onDelete: SetNull)
// Usuario que realizó la acción
userId String?
user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
// Empresa para filtrar
empresaId String
// Metadatos de IP/dispositivo (opcional)
ipAddress String?
userAgent String?
createdAt DateTime @default(now())
@@index([obraId])
@@index([userId])
@@index([empresaId])
@@index([tipo])
@@index([createdAt])
@@index([obraId, createdAt])
@@index([empresaId, createdAt])
}
// ============== ANÁLISIS DE PRECIOS UNITARIOS (APU) ==============
model CategoriaTrabajoAPU {
id String @id @default(cuid())
codigo String
nombre String
categoria CategoriaManoObra
salarioDiario Float
factorIMSS Float @default(0.2675)
factorINFONAVIT Float @default(0.05)
factorRetiro Float @default(0.02)
factorVacaciones Float @default(0.0411)
factorPrimaVac Float @default(0.0103)
factorAguinaldo Float @default(0.0411)
factorSalarioReal Float // Calculado: 1 + suma de factores
salarioReal Float // salarioDiario * FSR
activo Boolean @default(true)
empresaId String
empresa Empresa @relation(fields: [empresaId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
insumosAPU InsumoAPU[]
@@unique([codigo, empresaId])
@@index([empresaId])
@@index([categoria])
}
model EquipoMaquinaria {
id String @id @default(cuid())
codigo String
nombre String
tipo TipoEquipo
valorAdquisicion Float
vidaUtilHoras Float
valorRescate Float @default(0)
consumoCombustible Float? // Litros por hora
precioCombustible Float? // Precio por litro
factorMantenimiento Float @default(0.60)
costoOperador Float? // Costo por hora del operador
costoHorario Float // Calculado
activo Boolean @default(true)
empresaId String
empresa Empresa @relation(fields: [empresaId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
insumosAPU InsumoAPU[]
@@unique([codigo, empresaId])
@@index([empresaId])
@@index([tipo])
}
model AnalisisPrecioUnitario {
id String @id @default(cuid())
codigo String
descripcion String
unidad UnidadMedida
rendimientoDiario Float? // Cantidad de unidades por jornada
costoMateriales Float @default(0)
costoManoObra Float @default(0)
costoEquipo Float @default(0)
costoHerramienta Float @default(0)
costoDirecto Float @default(0)
porcentajeIndirectos Float @default(0)
costoIndirectos Float @default(0)
porcentajeUtilidad Float @default(0)
costoUtilidad Float @default(0)
precioUnitario Float @default(0)
activo Boolean @default(true)
empresaId String
empresa Empresa @relation(fields: [empresaId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
insumos InsumoAPU[]
partidas PartidaPresupuesto[]
@@unique([codigo, empresaId])
@@index([empresaId])
@@index([unidad])
}
model InsumoAPU {
id String @id @default(cuid())
tipo TipoInsumoAPU
descripcion String
unidad UnidadMedida
cantidad Float
desperdicio Float @default(0) // Porcentaje
cantidadConDesperdicio Float
rendimiento Float? // Para mano de obra: unidades por jornada
precioUnitario Float
importe Float
apuId String
apu AnalisisPrecioUnitario @relation(fields: [apuId], references: [id], onDelete: Cascade)
materialId String?
material Material? @relation(fields: [materialId], references: [id])
categoriaManoObraId String?
categoriaManoObra CategoriaTrabajoAPU? @relation(fields: [categoriaManoObraId], references: [id])
equipoId String?
equipo EquipoMaquinaria? @relation(fields: [equipoId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([apuId])
@@index([tipo])
@@index([materialId])
@@index([categoriaManoObraId])
@@index([equipoId])
}
model ConfiguracionAPU {
id String @id @default(cuid())
porcentajeHerramientaMenor Float @default(3)
porcentajeIndirectos Float @default(8)
porcentajeUtilidad Float @default(10)
empresaId String @unique
empresa Empresa @relation(fields: [empresaId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}