erp-transportistas-database-v2/ddl/02-fleet-schema-ddl.sql
Adrian Flores Cortes 7a91823784 feat: Add complete DDL for all transport schemas (01-08)
DDL files created:
- 01-transport-schema-ddl.sql: OT, embarques, viajes, paradas, POD, incidencias
- 02-fleet-schema-ddl.sql: unidades, remolques, operadores, documentos, asignaciones
- 03-tracking-schema-ddl.sql: posiciones GPS, eventos, geocercas, alertas, ETA
- 04-fuel-schema-ddl.sql: cargas combustible, peajes, gastos, anticipos, rendimiento
- 05-maintenance-schema-ddl.sql: planes, programacion, ordenes trabajo, checklist
- 06-carriers-schema-ddl.sql: carriers, documentos, unidades, operadores, scorecard
- 07-billing-transport-ddl.sql: lanes, tarifas, recargos, facturas, fuel surcharge
- 08-compliance-schema-ddl.sql: carta porte CFDI 3.1, HOS NOM-087, inspecciones

Features:
- All tables with tenant_id and RLS policies
- ENUMs for all status and type fields
- Proper indexes for common queries
- PostGIS for geospatial data
- Partitioned tables for high-volume GPS data
- CFDI Carta Porte 3.1 compliant structure

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 10:26:20 -06:00

410 lines
12 KiB
SQL

-- =============================================================================
-- ERP TRANSPORTISTAS - Schema Fleet DDL
-- =============================================================================
-- Archivo: 02-fleet-schema-ddl.sql
-- Version: 1.0.0
-- Fecha: 2026-01-25
-- Descripcion: Unidades, remolques, operadores, documentos, licencias
-- =============================================================================
-- =============================================================================
-- TIPOS ENUMERADOS ADICIONALES
-- =============================================================================
CREATE TYPE fleet.tipo_licencia AS ENUM (
'A', -- Motociclista
'B', -- Automovilista particular
'C', -- Chofer particular
'D', -- Chofer público pasajeros
'E', -- Chofer público carga
'F' -- Federal (SCT)
);
CREATE TYPE fleet.estado_operador AS ENUM (
'ACTIVO',
'EN_VIAJE',
'DESCANSO',
'VACACIONES',
'INCAPACIDAD',
'SUSPENDIDO',
'BAJA'
);
CREATE TYPE fleet.tipo_documento AS ENUM (
'LICENCIA',
'INE',
'CURP',
'RFC',
'NSS',
'TARJETA_CIRCULACION',
'POLIZA_SEGURO',
'VERIFICACION',
'PERMISO_SCT',
'CERTIFICADO_FISICO',
'ANTIDOPING',
'OTRO'
);
-- =============================================================================
-- TABLA: unidades (Tractoras y vehículos)
-- =============================================================================
CREATE TABLE fleet.unidades (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES public.tenants(id),
-- Identificación
numero_economico VARCHAR(20) NOT NULL,
tipo fleet.tipo_unidad NOT NULL,
-- Vehículo
marca VARCHAR(50),
modelo VARCHAR(50),
anio INT,
color VARCHAR(30),
numero_serie VARCHAR(50),
numero_motor VARCHAR(50),
-- Placas
placa VARCHAR(15),
placa_estado VARCHAR(50),
-- SCT
permiso_sct VARCHAR(50),
tipo_permiso_sct VARCHAR(10),
configuracion_vehicular VARCHAR(10), -- C2, C3, T3S2, etc.
-- Capacidades
capacidad_peso_kg DECIMAL(10, 2),
capacidad_volumen_m3 DECIMAL(10, 4),
capacidad_pallets INT,
-- Combustible
tipo_combustible VARCHAR(20), -- DIESEL, GASOLINA, GAS
rendimiento_km_litro DECIMAL(6, 2),
capacidad_tanque_litros DECIMAL(8, 2),
-- Odómetro
odometro_actual INT DEFAULT 0,
odometro_ultimo_servicio INT,
-- GPS
tiene_gps BOOLEAN DEFAULT FALSE,
gps_proveedor VARCHAR(50),
gps_imei VARCHAR(50),
-- Estado
estado fleet.estado_unidad DEFAULT 'DISPONIBLE',
ubicacion_actual_lat DECIMAL(10, 7),
ubicacion_actual_lng DECIMAL(10, 7),
ultima_actualizacion_ubicacion TIMESTAMPTZ,
-- Propiedad
es_propia BOOLEAN DEFAULT TRUE,
propietario_id UUID, -- Si no es propia, referencia al carrier
-- Costos
costo_adquisicion DECIMAL(15, 2),
fecha_adquisicion DATE,
valor_actual DECIMAL(15, 2),
-- Fechas importantes
fecha_verificacion_proxima DATE,
fecha_poliza_vencimiento DATE,
fecha_permiso_vencimiento DATE,
-- Activo
activo BOOLEAN DEFAULT TRUE,
fecha_baja DATE,
motivo_baja TEXT,
-- Auditoría
created_at TIMESTAMPTZ DEFAULT NOW(),
created_by_id UUID NOT NULL,
updated_at TIMESTAMPTZ DEFAULT NOW(),
updated_by_id UUID,
CONSTRAINT uq_unidad_numero UNIQUE (tenant_id, numero_economico),
CONSTRAINT uq_unidad_placa UNIQUE (tenant_id, placa)
);
CREATE INDEX idx_unidad_tenant ON fleet.unidades(tenant_id);
CREATE INDEX idx_unidad_tipo ON fleet.unidades(tenant_id, tipo);
CREATE INDEX idx_unidad_estado ON fleet.unidades(tenant_id, estado);
CREATE INDEX idx_unidad_activo ON fleet.unidades(tenant_id, activo) WHERE activo = TRUE;
-- =============================================================================
-- TABLA: remolques
-- =============================================================================
CREATE TABLE fleet.remolques (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES public.tenants(id),
-- Identificación
numero_economico VARCHAR(20) NOT NULL,
tipo fleet.tipo_unidad NOT NULL, -- CAJA_SECA, PLATAFORMA, etc.
-- Vehículo
marca VARCHAR(50),
modelo VARCHAR(50),
anio INT,
numero_serie VARCHAR(50),
-- Placas
placa VARCHAR(15),
placa_estado VARCHAR(50),
-- Dimensiones
largo_metros DECIMAL(6, 2),
ancho_metros DECIMAL(6, 2),
alto_metros DECIMAL(6, 2),
-- Capacidades
capacidad_peso_kg DECIMAL(10, 2),
capacidad_volumen_m3 DECIMAL(10, 4),
capacidad_pallets INT,
-- Refrigeración (si aplica)
es_refrigerado BOOLEAN DEFAULT FALSE,
marca_refrigeracion VARCHAR(50),
modelo_refrigeracion VARCHAR(50),
temperatura_min DECIMAL(5, 2),
temperatura_max DECIMAL(5, 2),
-- Estado
estado fleet.estado_unidad DEFAULT 'DISPONIBLE',
-- Propiedad
es_propia BOOLEAN DEFAULT TRUE,
propietario_id UUID,
-- Fechas importantes
fecha_verificacion_proxima DATE,
fecha_poliza_vencimiento DATE,
-- Activo
activo BOOLEAN DEFAULT TRUE,
-- Auditoría
created_at TIMESTAMPTZ DEFAULT NOW(),
created_by_id UUID NOT NULL,
updated_at TIMESTAMPTZ DEFAULT NOW(),
CONSTRAINT uq_remolque_numero UNIQUE (tenant_id, numero_economico)
);
CREATE INDEX idx_remolque_tenant ON fleet.remolques(tenant_id);
CREATE INDEX idx_remolque_tipo ON fleet.remolques(tenant_id, tipo);
CREATE INDEX idx_remolque_estado ON fleet.remolques(tenant_id, estado);
-- =============================================================================
-- TABLA: operadores (Conductores)
-- =============================================================================
CREATE TABLE fleet.operadores (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES public.tenants(id),
-- Identificación
numero_empleado VARCHAR(20) NOT NULL,
nombre VARCHAR(100) NOT NULL,
apellido_paterno VARCHAR(100) NOT NULL,
apellido_materno VARCHAR(100),
nombre_completo VARCHAR(300) GENERATED ALWAYS AS (
nombre || ' ' || apellido_paterno || COALESCE(' ' || apellido_materno, '')
) STORED,
-- Documentos de identidad
curp VARCHAR(18),
rfc VARCHAR(13),
nss VARCHAR(15), -- Número Seguro Social
-- Contacto
telefono VARCHAR(30),
telefono_emergencia VARCHAR(30),
email VARCHAR(255),
-- Dirección
direccion TEXT,
codigo_postal VARCHAR(10),
ciudad VARCHAR(100),
estado VARCHAR(100),
-- Datos de nacimiento
fecha_nacimiento DATE,
lugar_nacimiento VARCHAR(100),
nacionalidad VARCHAR(50) DEFAULT 'Mexicana',
-- Licencia de conducir
tipo_licencia fleet.tipo_licencia,
numero_licencia VARCHAR(30),
licencia_vigencia DATE,
licencia_estado_expedicion VARCHAR(50),
-- Certificaciones
certificado_fisico_vigencia DATE,
antidoping_vigencia DATE,
capacitacion_materiales_peligrosos BOOLEAN DEFAULT FALSE,
capacitacion_mp_vigencia DATE,
-- Estado
estado fleet.estado_operador DEFAULT 'ACTIVO',
-- Unidad asignada (default)
unidad_asignada_id UUID REFERENCES fleet.unidades(id),
-- Métricas de desempeño
calificacion DECIMAL(3, 2) DEFAULT 5.00,
total_viajes INT DEFAULT 0,
total_km INT DEFAULT 0,
incidentes INT DEFAULT 0,
-- Datos bancarios (para pagos)
banco VARCHAR(100),
cuenta_bancaria VARCHAR(30),
clabe VARCHAR(18),
-- Salario
salario_base DECIMAL(12, 2),
tipo_pago VARCHAR(20), -- 'FIJO', 'POR_VIAJE', 'MIXTO'
-- Fechas
fecha_ingreso DATE,
fecha_baja DATE,
motivo_baja TEXT,
-- Activo
activo BOOLEAN DEFAULT TRUE,
-- Auditoría
created_at TIMESTAMPTZ DEFAULT NOW(),
created_by_id UUID NOT NULL,
updated_at TIMESTAMPTZ DEFAULT NOW(),
updated_by_id UUID,
CONSTRAINT uq_operador_numero UNIQUE (tenant_id, numero_empleado),
CONSTRAINT uq_operador_curp UNIQUE (tenant_id, curp)
);
CREATE INDEX idx_operador_tenant ON fleet.operadores(tenant_id);
CREATE INDEX idx_operador_estado ON fleet.operadores(tenant_id, estado);
CREATE INDEX idx_operador_activo ON fleet.operadores(tenant_id, activo) WHERE activo = TRUE;
CREATE INDEX idx_operador_licencia ON fleet.operadores(licencia_vigencia);
-- =============================================================================
-- TABLA: documentos_flota
-- =============================================================================
CREATE TABLE fleet.documentos_flota (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES public.tenants(id),
-- Referencia polimórfica
entidad_tipo VARCHAR(20) NOT NULL, -- 'UNIDAD', 'REMOLQUE', 'OPERADOR'
entidad_id UUID NOT NULL,
-- Documento
tipo_documento fleet.tipo_documento NOT NULL,
nombre VARCHAR(200) NOT NULL,
numero_documento VARCHAR(100),
descripcion TEXT,
-- Vigencia
fecha_emision DATE,
fecha_vencimiento DATE,
dias_alerta_vencimiento INT DEFAULT 30,
-- Archivo
archivo_url TEXT,
archivo_nombre VARCHAR(255),
archivo_tipo VARCHAR(50),
archivo_tamano_bytes BIGINT,
-- Estado
verificado BOOLEAN DEFAULT FALSE,
verificado_por UUID,
verificado_fecha TIMESTAMPTZ,
-- Activo
activo BOOLEAN DEFAULT TRUE,
-- Auditoría
created_at TIMESTAMPTZ DEFAULT NOW(),
created_by_id UUID NOT NULL,
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_documento_entidad ON fleet.documentos_flota(entidad_tipo, entidad_id);
CREATE INDEX idx_documento_vencimiento ON fleet.documentos_flota(fecha_vencimiento) WHERE activo = TRUE;
CREATE INDEX idx_documento_tipo ON fleet.documentos_flota(tenant_id, tipo_documento);
-- =============================================================================
-- TABLA: asignaciones_unidad_operador
-- =============================================================================
CREATE TABLE fleet.asignaciones (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES public.tenants(id),
unidad_id UUID NOT NULL REFERENCES fleet.unidades(id),
operador_id UUID NOT NULL REFERENCES fleet.operadores(id),
remolque_id UUID REFERENCES fleet.remolques(id),
-- Vigencia de asignación
fecha_inicio TIMESTAMPTZ NOT NULL,
fecha_fin TIMESTAMPTZ,
-- Activa
activa BOOLEAN DEFAULT TRUE,
-- Motivo
motivo VARCHAR(200),
-- Auditoría
created_at TIMESTAMPTZ DEFAULT NOW(),
created_by_id UUID NOT NULL
);
CREATE INDEX idx_asignacion_unidad ON fleet.asignaciones(unidad_id, activa);
CREATE INDEX idx_asignacion_operador ON fleet.asignaciones(operador_id, activa);
-- =============================================================================
-- RLS POLICIES
-- =============================================================================
ALTER TABLE fleet.unidades ENABLE ROW LEVEL SECURITY;
ALTER TABLE fleet.remolques ENABLE ROW LEVEL SECURITY;
ALTER TABLE fleet.operadores ENABLE ROW LEVEL SECURITY;
ALTER TABLE fleet.documentos_flota ENABLE ROW LEVEL SECURITY;
ALTER TABLE fleet.asignaciones ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation_unidades ON fleet.unidades
USING (tenant_id = current_setting('app.tenant_id')::uuid);
CREATE POLICY tenant_isolation_remolques ON fleet.remolques
USING (tenant_id = current_setting('app.tenant_id')::uuid);
CREATE POLICY tenant_isolation_operadores ON fleet.operadores
USING (tenant_id = current_setting('app.tenant_id')::uuid);
CREATE POLICY tenant_isolation_documentos ON fleet.documentos_flota
USING (tenant_id = current_setting('app.tenant_id')::uuid);
CREATE POLICY tenant_isolation_asignaciones ON fleet.asignaciones
USING (tenant_id = current_setting('app.tenant_id')::uuid);
-- =============================================================================
-- COMENTARIOS
-- =============================================================================
COMMENT ON TABLE fleet.unidades IS 'Unidades motrices (tractoras, camiones, camionetas)';
COMMENT ON TABLE fleet.remolques IS 'Remolques, cajas, plataformas, tanques';
COMMENT ON TABLE fleet.operadores IS 'Operadores/conductores de la flota';
COMMENT ON TABLE fleet.documentos_flota IS 'Documentos de unidades, remolques y operadores';
COMMENT ON TABLE fleet.asignaciones IS 'Historial de asignaciones unidad-operador';
-- =============================================================================
-- FIN DDL FLEET
-- =============================================================================