-- ============================================================================= -- 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 -- =============================================================================