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>
441 lines
14 KiB
SQL
441 lines
14 KiB
SQL
-- =============================================================================
|
|
-- ERP TRANSPORTISTAS - Schema Compliance DDL
|
|
-- =============================================================================
|
|
-- Archivo: 08-compliance-schema-ddl.sql
|
|
-- Version: 1.0.0
|
|
-- Fecha: 2026-01-25
|
|
-- Descripcion: Carta Porte CFDI 3.1, HOS, inspecciones, NOM-087/068
|
|
-- =============================================================================
|
|
|
|
-- =============================================================================
|
|
-- TIPOS ENUMERADOS
|
|
-- =============================================================================
|
|
|
|
CREATE TYPE compliance.estado_carta_porte AS ENUM (
|
|
'BORRADOR',
|
|
'VALIDADA',
|
|
'TIMBRADA',
|
|
'CANCELADA'
|
|
);
|
|
|
|
CREATE TYPE compliance.tipo_cfdi_carta_porte AS ENUM (
|
|
'INGRESO', -- Servicio de transporte
|
|
'TRASLADO' -- Traslado propio
|
|
);
|
|
|
|
CREATE TYPE compliance.estado_hos AS ENUM (
|
|
'DRIVING', -- Conduciendo
|
|
'ON_DUTY', -- En servicio (no conduciendo)
|
|
'SLEEPER', -- En litera
|
|
'OFF_DUTY' -- Fuera de servicio
|
|
);
|
|
|
|
-- =============================================================================
|
|
-- TABLA: cartas_porte
|
|
-- =============================================================================
|
|
|
|
CREATE TABLE compliance.cartas_porte (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES public.tenants(id),
|
|
|
|
-- Viaje relacionado
|
|
viaje_id UUID NOT NULL,
|
|
|
|
-- CFDI
|
|
tipo_cfdi compliance.tipo_cfdi_carta_porte NOT NULL,
|
|
version_carta_porte VARCHAR(10) DEFAULT '3.1',
|
|
|
|
-- Identificación CFDI
|
|
serie VARCHAR(10),
|
|
folio VARCHAR(20),
|
|
uuid_cfdi UUID,
|
|
fecha_timbrado TIMESTAMPTZ,
|
|
|
|
-- Emisor
|
|
emisor_rfc VARCHAR(13) NOT NULL,
|
|
emisor_nombre VARCHAR(200) NOT NULL,
|
|
emisor_regimen_fiscal VARCHAR(10),
|
|
|
|
-- Receptor (para Ingreso) / Propietario (para Traslado)
|
|
receptor_rfc VARCHAR(13) NOT NULL,
|
|
receptor_nombre VARCHAR(200) NOT NULL,
|
|
receptor_uso_cfdi VARCHAR(10),
|
|
receptor_domicilio_fiscal_cp VARCHAR(10),
|
|
|
|
-- Totales CFDI
|
|
subtotal DECIMAL(15, 2),
|
|
total DECIMAL(15, 2),
|
|
moneda VARCHAR(3) DEFAULT 'MXN',
|
|
|
|
-- Datos transporte federal
|
|
transporte_internacional BOOLEAN DEFAULT FALSE,
|
|
entrada_salida_merc VARCHAR(10), -- 'Entrada' o 'Salida'
|
|
pais_origen_destino VARCHAR(3),
|
|
|
|
-- Datos específicos autotransporte
|
|
permiso_sct VARCHAR(50),
|
|
num_permiso_sct VARCHAR(50),
|
|
config_vehicular VARCHAR(10), -- C2, C3, T3S2, etc.
|
|
peso_bruto_total DECIMAL(12, 3),
|
|
unidad_peso VARCHAR(10) DEFAULT 'KGM',
|
|
num_total_mercancias INT,
|
|
|
|
-- Seguro
|
|
asegura_resp_civil VARCHAR(100),
|
|
poliza_resp_civil VARCHAR(50),
|
|
asegura_med_ambiente VARCHAR(100),
|
|
poliza_med_ambiente VARCHAR(50),
|
|
asegura_carga VARCHAR(100),
|
|
poliza_carga VARCHAR(50),
|
|
prima_seguro DECIMAL(15, 2),
|
|
|
|
-- Estado
|
|
estado compliance.estado_carta_porte DEFAULT 'BORRADOR',
|
|
|
|
-- XML y PDF
|
|
xml_cfdi TEXT,
|
|
xml_carta_porte TEXT,
|
|
pdf_url TEXT,
|
|
qr_url TEXT,
|
|
|
|
-- Cancelación
|
|
fecha_cancelacion TIMESTAMPTZ,
|
|
motivo_cancelacion TEXT,
|
|
uuid_sustitucion UUID,
|
|
|
|
-- Auditoría
|
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
created_by_id UUID NOT NULL,
|
|
updated_at TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX idx_carta_porte_tenant ON compliance.cartas_porte(tenant_id);
|
|
CREATE INDEX idx_carta_porte_viaje ON compliance.cartas_porte(viaje_id);
|
|
CREATE INDEX idx_carta_porte_uuid ON compliance.cartas_porte(uuid_cfdi);
|
|
CREATE INDEX idx_carta_porte_estado ON compliance.cartas_porte(tenant_id, estado);
|
|
|
|
-- =============================================================================
|
|
-- TABLA: ubicaciones_carta_porte
|
|
-- =============================================================================
|
|
|
|
CREATE TABLE compliance.ubicaciones_carta_porte (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES public.tenants(id),
|
|
carta_porte_id UUID NOT NULL REFERENCES compliance.cartas_porte(id),
|
|
|
|
-- Tipo
|
|
tipo_ubicacion VARCHAR(10) NOT NULL, -- 'Origen' o 'Destino'
|
|
|
|
-- ID Ubicación (catálogo SAT)
|
|
id_ubicacion VARCHAR(10),
|
|
|
|
-- RFC
|
|
rfc_remitente_destinatario VARCHAR(13),
|
|
nombre_remitente_destinatario VARCHAR(200),
|
|
|
|
-- Domicilio
|
|
pais VARCHAR(3) DEFAULT 'MEX',
|
|
estado VARCHAR(10), -- Clave SAT
|
|
municipio VARCHAR(10), -- Clave SAT
|
|
localidad VARCHAR(10),
|
|
codigo_postal VARCHAR(10) NOT NULL,
|
|
colonia VARCHAR(10),
|
|
calle VARCHAR(200),
|
|
numero_exterior VARCHAR(50),
|
|
numero_interior VARCHAR(50),
|
|
referencia VARCHAR(500),
|
|
|
|
-- Fechas
|
|
fecha_hora_salida_llegada TIMESTAMPTZ,
|
|
|
|
-- Distancia
|
|
distancia_recorrida DECIMAL(10, 2), -- Solo para destinos
|
|
|
|
-- Secuencia (orden en la ruta)
|
|
secuencia INT NOT NULL
|
|
);
|
|
|
|
CREATE INDEX idx_ubicacion_carta ON compliance.ubicaciones_carta_porte(carta_porte_id);
|
|
|
|
-- =============================================================================
|
|
-- TABLA: mercancias_carta_porte
|
|
-- =============================================================================
|
|
|
|
CREATE TABLE compliance.mercancias_carta_porte (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES public.tenants(id),
|
|
carta_porte_id UUID NOT NULL REFERENCES compliance.cartas_porte(id),
|
|
|
|
-- Bienes transportados
|
|
bienes_transp VARCHAR(10) NOT NULL, -- Clave SAT
|
|
descripcion VARCHAR(1000) NOT NULL,
|
|
cantidad DECIMAL(14, 3) NOT NULL,
|
|
clave_unidad VARCHAR(10) NOT NULL, -- Clave SAT
|
|
unidad VARCHAR(50),
|
|
|
|
-- Dimensiones
|
|
peso_en_kg DECIMAL(14, 3) NOT NULL,
|
|
largo_cm DECIMAL(10, 2),
|
|
ancho_cm DECIMAL(10, 2),
|
|
alto_cm DECIMAL(10, 2),
|
|
|
|
-- Valor
|
|
valor_mercancia DECIMAL(15, 2),
|
|
moneda VARCHAR(3) DEFAULT 'MXN',
|
|
|
|
-- Material peligroso
|
|
material_peligroso BOOLEAN DEFAULT FALSE,
|
|
cve_material_peligroso VARCHAR(10),
|
|
tipo_embalaje VARCHAR(10),
|
|
descripcion_embalaje VARCHAR(200),
|
|
|
|
-- Fracción arancelaria (comercio exterior)
|
|
fraccion_arancelaria VARCHAR(10),
|
|
uuid_comercio_ext UUID,
|
|
|
|
-- Pedimentos (comercio exterior)
|
|
pedimentos TEXT[], -- Array de números de pedimento
|
|
|
|
-- Guías (paquetería)
|
|
guias TEXT[], -- Array de números de guía
|
|
|
|
-- Secuencia
|
|
secuencia INT NOT NULL
|
|
);
|
|
|
|
CREATE INDEX idx_mercancia_carta ON compliance.mercancias_carta_porte(carta_porte_id);
|
|
|
|
-- =============================================================================
|
|
-- TABLA: figuras_transporte (Operador, propietario, arrendatario)
|
|
-- =============================================================================
|
|
|
|
CREATE TABLE compliance.figuras_transporte (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES public.tenants(id),
|
|
carta_porte_id UUID NOT NULL REFERENCES compliance.cartas_porte(id),
|
|
|
|
-- Tipo de figura
|
|
tipo_figura VARCHAR(10) NOT NULL, -- '01'=Operador, '02'=Propietario, '03'=Arrendador
|
|
|
|
-- Datos
|
|
rfc_figura VARCHAR(13),
|
|
nombre_figura VARCHAR(200),
|
|
num_licencia VARCHAR(50), -- Solo para operadores
|
|
|
|
-- Domicilio (opcional)
|
|
pais VARCHAR(3),
|
|
estado VARCHAR(10),
|
|
codigo_postal VARCHAR(10),
|
|
calle VARCHAR(200),
|
|
|
|
-- Partes transporte (solo para Propietario/Arrendador)
|
|
partes_transporte JSONB -- Array de {parte_transporte: string}
|
|
);
|
|
|
|
CREATE INDEX idx_figura_carta ON compliance.figuras_transporte(carta_porte_id);
|
|
|
|
-- =============================================================================
|
|
-- TABLA: autotransporte_carta_porte
|
|
-- =============================================================================
|
|
|
|
CREATE TABLE compliance.autotransporte_carta_porte (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES public.tenants(id),
|
|
carta_porte_id UUID NOT NULL REFERENCES compliance.cartas_porte(id),
|
|
|
|
-- Permiso
|
|
perm_sct VARCHAR(10) NOT NULL, -- Tipo permiso SAT
|
|
num_permiso_sct VARCHAR(50) NOT NULL,
|
|
|
|
-- Identificación vehicular tractora
|
|
config_vehicular VARCHAR(10) NOT NULL, -- C2, C3, T3S2, etc.
|
|
placa_vm VARCHAR(15) NOT NULL,
|
|
anio_modelo_vm INT,
|
|
|
|
-- Remolques (puede haber hasta 2)
|
|
remolques JSONB -- Array de {sub_tipo_rem, placa}
|
|
);
|
|
|
|
CREATE INDEX idx_autotransporte_carta ON compliance.autotransporte_carta_porte(carta_porte_id);
|
|
|
|
-- =============================================================================
|
|
-- TABLA: hos_logs (Hours of Service - NOM-087)
|
|
-- =============================================================================
|
|
|
|
CREATE TABLE compliance.hos_logs (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES public.tenants(id),
|
|
|
|
-- Operador y viaje
|
|
operador_id UUID NOT NULL,
|
|
viaje_id UUID,
|
|
|
|
-- Log
|
|
fecha DATE NOT NULL,
|
|
hora_inicio TIME NOT NULL,
|
|
hora_fin TIME,
|
|
duracion_minutos INT,
|
|
|
|
-- Estado
|
|
estado compliance.estado_hos NOT NULL,
|
|
|
|
-- Ubicación
|
|
latitud DECIMAL(10, 7),
|
|
longitud DECIMAL(10, 7),
|
|
ubicacion_descripcion VARCHAR(200),
|
|
|
|
-- Odómetro
|
|
odometro_inicio INT,
|
|
odometro_fin INT,
|
|
|
|
-- Observaciones
|
|
observaciones TEXT,
|
|
|
|
-- Certificado
|
|
certificado_por_operador BOOLEAN DEFAULT FALSE,
|
|
certificado_fecha TIMESTAMPTZ,
|
|
|
|
-- Auditoría
|
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX idx_hos_operador ON compliance.hos_logs(operador_id);
|
|
CREATE INDEX idx_hos_fecha ON compliance.hos_logs(tenant_id, fecha);
|
|
CREATE INDEX idx_hos_viaje ON compliance.hos_logs(viaje_id);
|
|
|
|
-- =============================================================================
|
|
-- TABLA: hos_resumen_diario
|
|
-- =============================================================================
|
|
|
|
CREATE TABLE compliance.hos_resumen_diario (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES public.tenants(id),
|
|
|
|
operador_id UUID NOT NULL,
|
|
fecha DATE NOT NULL,
|
|
|
|
-- Horas por estado
|
|
horas_driving DECIMAL(4, 2) DEFAULT 0,
|
|
horas_on_duty DECIMAL(4, 2) DEFAULT 0,
|
|
horas_sleeper DECIMAL(4, 2) DEFAULT 0,
|
|
horas_off_duty DECIMAL(4, 2) DEFAULT 0,
|
|
horas_totales DECIMAL(4, 2) DEFAULT 0,
|
|
|
|
-- Cumplimiento NOM-087
|
|
horas_conduccion_disponibles DECIMAL(4, 2),
|
|
horas_servicio_disponibles DECIMAL(4, 2),
|
|
en_cumplimiento BOOLEAN DEFAULT TRUE,
|
|
violaciones TEXT[],
|
|
|
|
-- Acumulados (ciclo de 7 días)
|
|
horas_conduccion_ciclo DECIMAL(5, 2),
|
|
horas_servicio_ciclo DECIMAL(5, 2),
|
|
|
|
-- Certificación
|
|
certificado BOOLEAN DEFAULT FALSE,
|
|
certificado_fecha TIMESTAMPTZ,
|
|
|
|
CONSTRAINT uq_hos_resumen UNIQUE (operador_id, fecha)
|
|
);
|
|
|
|
CREATE INDEX idx_hos_resumen_operador ON compliance.hos_resumen_diario(operador_id);
|
|
CREATE INDEX idx_hos_resumen_fecha ON compliance.hos_resumen_diario(tenant_id, fecha);
|
|
|
|
-- =============================================================================
|
|
-- TABLA: inspecciones_pre_viaje
|
|
-- =============================================================================
|
|
|
|
CREATE TABLE compliance.inspecciones_pre_viaje (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES public.tenants(id),
|
|
|
|
-- Viaje y unidad
|
|
viaje_id UUID NOT NULL,
|
|
unidad_id UUID NOT NULL,
|
|
remolque_id UUID,
|
|
operador_id UUID NOT NULL,
|
|
|
|
-- Fecha
|
|
fecha_inspeccion TIMESTAMPTZ NOT NULL,
|
|
|
|
-- Resultado general
|
|
aprobada BOOLEAN DEFAULT FALSE,
|
|
|
|
-- Items checklist (JSON con resultados)
|
|
checklist_items JSONB NOT NULL,
|
|
-- Ejemplo: [{ "item": "Frenos", "estado": "OK", "observacion": null }, ...]
|
|
|
|
-- Defectos encontrados
|
|
defectos_encontrados TEXT[],
|
|
defectos_criticos INT DEFAULT 0,
|
|
defectos_menores INT DEFAULT 0,
|
|
|
|
-- Firma
|
|
firma_operador TEXT, -- Base64
|
|
firma_fecha TIMESTAMPTZ,
|
|
|
|
-- Evidencias
|
|
fotos JSONB, -- URLs de fotos
|
|
|
|
-- Auditoría
|
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX idx_inspeccion_viaje ON compliance.inspecciones_pre_viaje(viaje_id);
|
|
CREATE INDEX idx_inspeccion_unidad ON compliance.inspecciones_pre_viaje(unidad_id);
|
|
CREATE INDEX idx_inspeccion_fecha ON compliance.inspecciones_pre_viaje(tenant_id, fecha_inspeccion);
|
|
|
|
-- =============================================================================
|
|
-- RLS POLICIES
|
|
-- =============================================================================
|
|
|
|
ALTER TABLE compliance.cartas_porte ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE compliance.ubicaciones_carta_porte ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE compliance.mercancias_carta_porte ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE compliance.figuras_transporte ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE compliance.autotransporte_carta_porte ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE compliance.hos_logs ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE compliance.hos_resumen_diario ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE compliance.inspecciones_pre_viaje ENABLE ROW LEVEL SECURITY;
|
|
|
|
CREATE POLICY tenant_isolation_cartas ON compliance.cartas_porte
|
|
USING (tenant_id = current_setting('app.tenant_id')::uuid);
|
|
|
|
CREATE POLICY tenant_isolation_ubicaciones ON compliance.ubicaciones_carta_porte
|
|
USING (tenant_id = current_setting('app.tenant_id')::uuid);
|
|
|
|
CREATE POLICY tenant_isolation_mercancias ON compliance.mercancias_carta_porte
|
|
USING (tenant_id = current_setting('app.tenant_id')::uuid);
|
|
|
|
CREATE POLICY tenant_isolation_figuras ON compliance.figuras_transporte
|
|
USING (tenant_id = current_setting('app.tenant_id')::uuid);
|
|
|
|
CREATE POLICY tenant_isolation_autotransporte ON compliance.autotransporte_carta_porte
|
|
USING (tenant_id = current_setting('app.tenant_id')::uuid);
|
|
|
|
CREATE POLICY tenant_isolation_hos ON compliance.hos_logs
|
|
USING (tenant_id = current_setting('app.tenant_id')::uuid);
|
|
|
|
CREATE POLICY tenant_isolation_hos_resumen ON compliance.hos_resumen_diario
|
|
USING (tenant_id = current_setting('app.tenant_id')::uuid);
|
|
|
|
CREATE POLICY tenant_isolation_inspecciones ON compliance.inspecciones_pre_viaje
|
|
USING (tenant_id = current_setting('app.tenant_id')::uuid);
|
|
|
|
-- =============================================================================
|
|
-- COMENTARIOS
|
|
-- =============================================================================
|
|
|
|
COMMENT ON TABLE compliance.cartas_porte IS 'CFDI con complemento Carta Porte 3.1';
|
|
COMMENT ON TABLE compliance.ubicaciones_carta_porte IS 'Ubicaciones origen/destino de la carta porte';
|
|
COMMENT ON TABLE compliance.mercancias_carta_porte IS 'Mercancías transportadas en la carta porte';
|
|
COMMENT ON TABLE compliance.figuras_transporte IS 'Figuras de transporte (operador, propietario, arrendador)';
|
|
COMMENT ON TABLE compliance.autotransporte_carta_porte IS 'Datos del autotransporte federal';
|
|
COMMENT ON TABLE compliance.hos_logs IS 'Registros de horas de servicio (NOM-087)';
|
|
COMMENT ON TABLE compliance.hos_resumen_diario IS 'Resumen diario de HOS por operador';
|
|
COMMENT ON TABLE compliance.inspecciones_pre_viaje IS 'Inspecciones pre-viaje de unidades';
|
|
|
|
-- =============================================================================
|
|
-- FIN DDL COMPLIANCE
|
|
-- =============================================================================
|