erp-transportistas-database-v2/ddl/06-carriers-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

345 lines
10 KiB
SQL

-- =============================================================================
-- ERP TRANSPORTISTAS - Schema Carriers DDL
-- =============================================================================
-- Archivo: 06-carriers-schema-ddl.sql
-- Version: 1.0.0
-- Fecha: 2026-01-25
-- Descripcion: Transportistas subcontratados, documentos, scorecard
-- =============================================================================
-- =============================================================================
-- TIPOS ENUMERADOS
-- =============================================================================
CREATE TYPE carriers.estado_carrier AS ENUM (
'PROSPECTO',
'EN_VALIDACION',
'ACTIVO',
'SUSPENDIDO',
'BAJA'
);
CREATE TYPE carriers.tipo_contrato AS ENUM (
'SPOT',
'DEDICADO',
'PREFERENTE'
);
-- =============================================================================
-- TABLA: carriers (Transportistas terceros)
-- =============================================================================
CREATE TABLE carriers.carriers (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES public.tenants(id),
-- Identificación
codigo VARCHAR(20) NOT NULL,
razon_social VARCHAR(200) NOT NULL,
nombre_comercial VARCHAR(200),
-- Fiscal
rfc VARCHAR(13) NOT NULL,
regimen_fiscal VARCHAR(100),
-- SCT
permiso_sct VARCHAR(50),
tipo_permiso_sct VARCHAR(10),
permiso_vigencia DATE,
-- Contacto
contacto_nombre VARCHAR(200),
contacto_telefono VARCHAR(30),
contacto_email VARCHAR(255),
-- Dirección
direccion TEXT,
codigo_postal VARCHAR(10),
ciudad VARCHAR(100),
estado VARCHAR(100),
-- Operación
cobertura_estados TEXT[], -- Estados donde opera
tipos_equipo fleet.tipo_unidad[], -- Tipos de unidad disponibles
capacidad_unidades INT,
-- Tipo de relación
tipo_contrato carriers.tipo_contrato DEFAULT 'SPOT',
-- Términos comerciales
dias_pago INT DEFAULT 30,
porcentaje_retencion DECIMAL(5, 2) DEFAULT 4.00,
-- Seguros
poliza_seguro_carga VARCHAR(100),
poliza_vigencia DATE,
suma_asegurada DECIMAL(15, 2),
-- Evaluación
calificacion DECIMAL(3, 2) DEFAULT 0,
total_viajes INT DEFAULT 0,
viajes_a_tiempo INT DEFAULT 0,
incidentes INT DEFAULT 0,
-- Estado
estado carriers.estado_carrier DEFAULT 'PROSPECTO',
fecha_alta DATE,
fecha_baja DATE,
motivo_baja TEXT,
-- Datos bancarios
banco VARCHAR(100),
cuenta_bancaria VARCHAR(30),
clabe VARCHAR(18),
-- Auditoría
created_at TIMESTAMPTZ DEFAULT NOW(),
created_by_id UUID NOT NULL,
updated_at TIMESTAMPTZ DEFAULT NOW(),
updated_by_id UUID,
CONSTRAINT uq_carrier_codigo UNIQUE (tenant_id, codigo),
CONSTRAINT uq_carrier_rfc UNIQUE (tenant_id, rfc)
);
CREATE INDEX idx_carrier_tenant ON carriers.carriers(tenant_id);
CREATE INDEX idx_carrier_estado ON carriers.carriers(tenant_id, estado);
-- =============================================================================
-- TABLA: documentos_carrier
-- =============================================================================
CREATE TABLE carriers.documentos_carrier (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES public.tenants(id),
carrier_id UUID NOT NULL REFERENCES carriers.carriers(id),
-- Documento
tipo_documento VARCHAR(50) NOT NULL,
nombre VARCHAR(200) NOT NULL,
descripcion TEXT,
-- Vigencia
fecha_emision DATE,
fecha_vencimiento DATE,
-- Archivo
archivo_url TEXT,
archivo_nombre VARCHAR(255),
-- Verificación
verificado BOOLEAN DEFAULT FALSE,
verificado_por UUID,
verificado_fecha TIMESTAMPTZ,
-- Estado
activo BOOLEAN DEFAULT TRUE,
-- Auditoría
created_at TIMESTAMPTZ DEFAULT NOW(),
created_by_id UUID NOT NULL
);
CREATE INDEX idx_doc_carrier ON carriers.documentos_carrier(carrier_id);
CREATE INDEX idx_doc_vencimiento ON carriers.documentos_carrier(fecha_vencimiento);
-- =============================================================================
-- TABLA: unidades_carrier
-- =============================================================================
CREATE TABLE carriers.unidades_carrier (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES public.tenants(id),
carrier_id UUID NOT NULL REFERENCES carriers.carriers(id),
-- Unidad
numero_economico VARCHAR(20) NOT NULL,
tipo fleet.tipo_unidad NOT NULL,
marca VARCHAR(50),
modelo VARCHAR(50),
anio INT,
placa VARCHAR(15),
-- SCT
configuracion_vehicular VARCHAR(10),
-- Capacidad
capacidad_peso_kg DECIMAL(10, 2),
capacidad_volumen_m3 DECIMAL(10, 4),
-- GPS
tiene_gps BOOLEAN DEFAULT FALSE,
gps_proveedor VARCHAR(50),
-- Estado
activa BOOLEAN DEFAULT TRUE,
-- Auditoría
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_unidad_carrier ON carriers.unidades_carrier(carrier_id);
-- =============================================================================
-- TABLA: operadores_carrier
-- =============================================================================
CREATE TABLE carriers.operadores_carrier (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES public.tenants(id),
carrier_id UUID NOT NULL REFERENCES carriers.carriers(id),
-- Operador
nombre_completo VARCHAR(300) NOT NULL,
telefono VARCHAR(30),
-- Licencia
tipo_licencia fleet.tipo_licencia,
numero_licencia VARCHAR(30),
licencia_vigencia DATE,
-- Estado
activo BOOLEAN DEFAULT TRUE,
-- Auditoría
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_operador_carrier ON carriers.operadores_carrier(carrier_id);
-- =============================================================================
-- TABLA: asignaciones_carrier (Viajes asignados a carriers)
-- =============================================================================
CREATE TABLE carriers.asignaciones_carrier (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES public.tenants(id),
-- Carrier
carrier_id UUID NOT NULL REFERENCES carriers.carriers(id),
unidad_carrier_id UUID REFERENCES carriers.unidades_carrier(id),
operador_carrier_id UUID REFERENCES carriers.operadores_carrier(id),
-- Viaje/OT
viaje_id UUID,
ot_id UUID,
-- Tarifa acordada
tarifa_acordada DECIMAL(15, 2) NOT NULL,
moneda VARCHAR(3) DEFAULT 'MXN',
-- Fechas
fecha_asignacion TIMESTAMPTZ DEFAULT NOW(),
fecha_confirmacion TIMESTAMPTZ,
-- Estado
estado VARCHAR(20) DEFAULT 'PENDIENTE',
-- PENDIENTE, CONFIRMADA, EN_PROCESO, COMPLETADA, CANCELADA
-- Facturación
factura_carrier VARCHAR(50),
fecha_factura DATE,
monto_facturado DECIMAL(15, 2),
fecha_pago DATE,
-- Evaluación del viaje
calificacion INT, -- 1-5
comentarios TEXT,
-- Auditoría
created_at TIMESTAMPTZ DEFAULT NOW(),
created_by_id UUID NOT NULL
);
CREATE INDEX idx_asignacion_carrier ON carriers.asignaciones_carrier(carrier_id);
CREATE INDEX idx_asignacion_viaje ON carriers.asignaciones_carrier(viaje_id);
CREATE INDEX idx_asignacion_estado ON carriers.asignaciones_carrier(tenant_id, estado);
-- =============================================================================
-- TABLA: scorecard_carrier
-- =============================================================================
CREATE TABLE carriers.scorecard (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES public.tenants(id),
carrier_id UUID NOT NULL REFERENCES carriers.carriers(id),
-- Período
periodo_inicio DATE NOT NULL,
periodo_fin DATE NOT NULL,
-- Métricas de servicio
total_viajes INT DEFAULT 0,
viajes_a_tiempo INT DEFAULT 0,
viajes_retrasados INT DEFAULT 0,
viajes_cancelados INT DEFAULT 0,
-- Porcentajes
otif_porcentaje DECIMAL(5, 2), -- On Time In Full
puntualidad_porcentaje DECIMAL(5, 2),
-- Incidentes
total_incidentes INT DEFAULT 0,
incidentes_graves INT DEFAULT 0,
-- Calificación
calificacion_servicio DECIMAL(3, 2),
calificacion_documentacion DECIMAL(3, 2),
calificacion_comunicacion DECIMAL(3, 2),
calificacion_general DECIMAL(3, 2),
-- Financiero
monto_total_servicios DECIMAL(15, 2),
monto_penalizaciones DECIMAL(15, 2),
-- Auditoría
calculado_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_scorecard_carrier ON carriers.scorecard(carrier_id);
CREATE INDEX idx_scorecard_periodo ON carriers.scorecard(periodo_inicio, periodo_fin);
-- =============================================================================
-- RLS POLICIES
-- =============================================================================
ALTER TABLE carriers.carriers ENABLE ROW LEVEL SECURITY;
ALTER TABLE carriers.documentos_carrier ENABLE ROW LEVEL SECURITY;
ALTER TABLE carriers.unidades_carrier ENABLE ROW LEVEL SECURITY;
ALTER TABLE carriers.operadores_carrier ENABLE ROW LEVEL SECURITY;
ALTER TABLE carriers.asignaciones_carrier ENABLE ROW LEVEL SECURITY;
ALTER TABLE carriers.scorecard ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation_carriers ON carriers.carriers
USING (tenant_id = current_setting('app.tenant_id')::uuid);
CREATE POLICY tenant_isolation_docs ON carriers.documentos_carrier
USING (tenant_id = current_setting('app.tenant_id')::uuid);
CREATE POLICY tenant_isolation_unidades ON carriers.unidades_carrier
USING (tenant_id = current_setting('app.tenant_id')::uuid);
CREATE POLICY tenant_isolation_operadores ON carriers.operadores_carrier
USING (tenant_id = current_setting('app.tenant_id')::uuid);
CREATE POLICY tenant_isolation_asignaciones ON carriers.asignaciones_carrier
USING (tenant_id = current_setting('app.tenant_id')::uuid);
CREATE POLICY tenant_isolation_scorecard ON carriers.scorecard
USING (tenant_id = current_setting('app.tenant_id')::uuid);
-- =============================================================================
-- COMENTARIOS
-- =============================================================================
COMMENT ON TABLE carriers.carriers IS 'Transportistas subcontratados';
COMMENT ON TABLE carriers.documentos_carrier IS 'Documentos de carriers';
COMMENT ON TABLE carriers.unidades_carrier IS 'Unidades de carriers';
COMMENT ON TABLE carriers.operadores_carrier IS 'Operadores de carriers';
COMMENT ON TABLE carriers.asignaciones_carrier IS 'Asignaciones de viajes a carriers';
COMMENT ON TABLE carriers.scorecard IS 'Evaluación periódica de carriers';
-- =============================================================================
-- FIN DDL CARRIERS
-- =============================================================================