/* Pagos y Convenios - estructura y migración de datos existentes. Preparado el 22/09/2026 para SIG_PlataformaDesarolladores. NO EJECUTADO. La edición de este archivo no autoriza su instalación. Migración de una sola aplicación. Ejecutar completa dentro de una transacción del instalador, que debe detenerse ante la primera excepción y confirmar únicamente después de instalar y verificar PAs y aplicación. NO INSTALAR DE FORMA AISLADA: El renombrado conserva identidades y FK, pero los PAs, la vista Vta_SaldosFavor, los servicios y la configuración de bitácora todavía deben adaptarse en una entrega posterior. Este archivo no los modifica. Alcance: - Renombrar las cuatro tablas aprobadas conservando sus claves actuales. - Migrar las obligaciones existentes desde sus ventas y detalles reales. - Separar importe abonado, saldo trasladado a convenio y saldo pendiente. - Preparar unidades, parcialidades, aplicaciones y CFDI externos. - No crear abonos a partir de facturas: un CFDI no prueba que hubo pago. - No crear usuarios, permisos, cuentas, productos ni tipos de cambio. Decisiones de estructura: - Una obligación, sus productos y sus parcialidades usan una sola unidad. - Importe y PrecioUnitario nuevos incluyen impuestos; las ventas anteriores mantienen intactos sus precios netos, impuestos y documentos fiscales. - EstadoAdministrativo es ACTIVO/CANCELADO/SUSTITUIDO. El estado financiero se deriva del saldo; no se persiste un CveEstatusPago que pueda desfasarse. - Saldo cobrable = importe - aplicaciones vigentes - saldo convenido vigente. El saldo trasladado se presenta por separado, nunca como dinero pagado. - Cada aplicación identifica parcialidad Y producto. ImporteAplicado está expresado en la unidad de la obligación; ImportePagoConsumido, en la del abono. Ambos factores a MXN se congelan en la aplicación/pago. - Convenios conservan detalle del saldo trasladado por producto y parcialidad. Esta primera estructura exige la misma unidad entre convenio y orígenes. - Las sumas entre filas, concurrencia, permisos, inmutabilidad del abono, distribución proporcional y redondeo pertenecen a servicios/PAs pendientes. La estructura por sí sola no implementa esas operaciones. - Al cancelar un convenio se libera el traslado sólo mediante la operación coordinada posterior; nunca se borran el origen ni los abonos históricos. - FechaProrroga, cuando exista, sustituye el vencimiento para calcular atraso. - Las equivalencias son históricos de sólo inserción en la futura API. No se cargan valores UMA, UDI ni divisas. - En CFDI externos los metadatos no conocidos permanecen NULL. No se fabrica XML sin timbrar ni un intento de PAC. Archivos protegidos bajo Documentos, resueltos por el servicio existente; las rutas nunca son URLs públicas. - Generación automática al crear trámite, importes finales y reparto proporcional son criterios propuestos; no se ejecutan en esta migración. Estado inspeccionado: tres obligaciones/ventas, tres CFDI y cero abonos. La venta 1019 y su CFDI tienen importes distintos; no se corrigen aquí. Los precontroles detienen la migración si aparecen abonos o datos ambiguos. */ SET NOCOUNT ON; SET ANSI_NULLS ON; SET QUOTED_IDENTIFIER ON; SET ANSI_PADDING ON; SET ANSI_WARNINGS ON; SET ARITHABORT ON; SET CONCAT_NULL_YIELDS_NULL ON; SET NUMERIC_ROUNDABORT OFF; IF DB_NAME() <> N'SIG_PlataformaDesarolladores' THROW 51200, N'La base seleccionada no corresponde a la revisada.', 1; IF @@TRANCOUNT = 0 OR XACT_STATE() <> 1 THROW 51201, N'Se requiere una transacción activa del instalador.', 1; IF OBJECT_ID(N'dbo.Tra_Pagos', N'U') IS NULL OR OBJECT_ID(N'dbo.Tra_PagosDetalle', N'U') IS NULL OR OBJECT_ID(N'dbo.Tra_SolicitudesPagos', N'U') IS NULL OR OBJECT_ID(N'dbo.Vta_Pagos', N'U') IS NULL OR COL_LENGTH(N'dbo.Tra_Pagos', N'CveTramitePago') IS NULL OR COL_LENGTH(N'dbo.Vta_Pagos', N'CvePago') IS NULL THROW 51202, N'No se encontró la estructura de origen revisada.', 1; IF EXISTS ( SELECT 1 FROM sys.objects WHERE schema_id = SCHEMA_ID(N'dbo') AND name IN ( N'Tra_TiposTramitePagos', N'Tra_TiposTramitePagosDetalle', N'Tra_SolicitudesPago', N'Gral_UnidadesCobro', N'Gral_UnidadesCobroValores', N'Tra_TiposSolicitudPago', N'Tra_SolicitudesPagoDetalle', N'Tra_SolicitudesPagoParcialidades', N'Tra_PagosAplicaciones', N'Tra_SolicitudesPagoConvenio', N'Tra_SolicitudesPagoConvenioOrigen', N'Tra_SolicitudesPagoConvenioOrigenDetalle', N'Tra_SolicitudesPagoRequeridoBitacora', N'Tra_PagosCfdi' ) ) THROW 51203, N'Ya existen objetos destino; revise si la migración fue aplicada.', 1; DECLARE @TablaPlantillas int = OBJECT_ID(N'dbo.Tra_Pagos'); DECLARE @TablaDetallePlantillas int = OBJECT_ID(N'dbo.Tra_PagosDetalle'); DECLARE @TablaSolicitudes int = OBJECT_ID(N'dbo.Tra_SolicitudesPagos'); DECLARE @TablaAbonos int = OBJECT_ID(N'dbo.Vta_Pagos'); DECLARE @Relaciones TABLE (Clave int PRIMARY KEY, Tabla int, Referencia int); INSERT INTO @Relaciones (Clave, Tabla, Referencia) SELECT object_id, parent_object_id, referenced_object_id FROM sys.foreign_keys WHERE parent_object_id IN (@TablaPlantillas, @TablaDetallePlantillas, @TablaSolicitudes, @TablaAbonos) OR referenced_object_id IN (@TablaPlantillas, @TablaDetallePlantillas, @TablaSolicitudes, @TablaAbonos); -- Bloquear el origen durante toda la instalación coordinada. DECLARE @CantidadPlantillas bigint, @CantidadDetalles bigint; DECLARE @CantidadSolicitudes bigint, @CantidadAbonos bigint; SELECT @CantidadPlantillas = COUNT_BIG(*) FROM dbo.Tra_Pagos WITH (TABLOCKX, HOLDLOCK); SELECT @CantidadDetalles = COUNT_BIG(*) FROM dbo.Tra_PagosDetalle WITH (TABLOCKX, HOLDLOCK); SELECT @CantidadSolicitudes = COUNT_BIG(*) FROM dbo.Tra_SolicitudesPagos WITH (TABLOCKX, HOLDLOCK); SELECT @CantidadAbonos = COUNT_BIG(*) FROM dbo.Vta_Pagos WITH (TABLOCKX, HOLDLOCK); IF @CantidadAbonos <> 0 THROW 51204, N'Existen abonos que requieren conciliación de conversión y aplicaciones.', 1; IF NOT EXISTS (SELECT 1 FROM dbo.Gral_Monedas WHERE Abreviatura = 'MXN') OR NOT EXISTS (SELECT 1 FROM dbo.Gral_Monedas WHERE Abreviatura = 'USD') OR EXISTS ( SELECT Abreviatura FROM dbo.Gral_Monedas GROUP BY Abreviatura HAVING COUNT(*) > 1 ) THROW 51205, N'Las monedas existentes no permiten una correspondencia inequívoca.', 1; SELECT SP.CveSolicitudPago, SP.CveSolicitud, SP.CveTramitePago, SP.CveVenta, S.CveCliente, S.CveFraccionamiento, S.CveFraccionamientoEtapa, S.CveTipoTramite, P.Nombre AS Descripcion, P.EsRequerido, V.CveMoneda, CONVERT(decimal(19, 6), V.Total) AS Importe, V.Fecha AS FechaGeneracion, V.FechaVencimiento2 AS FechaVencimiento, SP.FechaAlta, SP.CveUsuario INTO #PagosOrigenSolicitudes FROM dbo.Tra_SolicitudesPagos AS SP INNER JOIN dbo.Tra_Solicitudes AS S ON S.CveSolicitud = SP.CveSolicitud INNER JOIN dbo.Ventas AS V WITH (HOLDLOCK) ON V.CveVenta = SP.CveVenta INNER JOIN dbo.Tra_Pagos AS P ON P.CveTramitePago = SP.CveTramitePago WHERE V.CveCliente = S.CveCliente AND P.CveTipoTramite = S.CveTipoTramite; IF (SELECT COUNT_BIG(*) FROM #PagosOrigenSolicitudes) <> @CantidadSolicitudes OR EXISTS ( SELECT 1 FROM #PagosOrigenSolicitudes WHERE Importe <= 0 OR FechaVencimiento IS NULL ) THROW 51206, N'Existen obligaciones con contexto, importe o vencimiento por conciliar.', 1; SELECT O.CveSolicitudPago, D.CveVentaDetalle, D.CvePS, PS.PS AS Descripcion, D.Cantidad, CONVERT(decimal(19, 6), D.Importe + D.IVA + ISNULL(D.IEPS, 0) - ISNULL(D.ImporteRetIVA, 0) - ISNULL(D.ImporteRetISR, 0)) AS Importe INTO #PagosOrigenDetalle FROM #PagosOrigenSolicitudes AS O INNER JOIN dbo.VentasDetalle AS D WITH (HOLDLOCK) ON D.CveVenta = O.CveVenta INNER JOIN dbo.ProductosServicios AS PS ON PS.CvePS = D.CvePS; IF EXISTS ( SELECT 1 FROM #PagosOrigenDetalle WHERE Cantidad <= 0 OR Importe < 0 ) OR EXISTS ( SELECT 1 FROM #PagosOrigenSolicitudes AS O OUTER APPLY ( SELECT SUM(D.Importe) AS Importe FROM #PagosOrigenDetalle AS D WHERE D.CveSolicitudPago = O.CveSolicitudPago ) AS T WHERE T.Importe IS NULL OR T.Importe <> O.Importe ) THROW 51207, N'El detalle de venta no concilia con el total de la obligación.', 1; -- La plantilla actual obtiene costo vigente e IVA 16% del PA existente. -- No convertir esta regla de migración en una tasa fiscal para futuros cobros. IF OBJECT_DEFINITION(OBJECT_ID(N'dbo.PA_Vta_TramiteConceptoList')) NOT LIKE N'%@PorcentajeIVA decimal(9, 6) = 0.16%' OR OBJECT_DEFINITION(OBJECT_ID(N'dbo.PA_Vta_TramiteConceptoList')) IS NULL THROW 51208, N'Cambió la regla de cálculo de la plantilla; revise su migración.', 1; SELECT D.CveTramitePagoDetalle, D.CveTramitePago, D.Cantidad, CT.CveMoneda, CONVERT(decimal(19, 6), CT.Importe + ROUND(CT.Importe * 0.16, 2)) AS PrecioUnitario INTO #PagosOrigenPlantilla FROM dbo.Tra_PagosDetalle AS D INNER JOIN dbo.Tra_Pagos AS P ON P.CveTramitePago = D.CveTramitePago CROSS APPLY ( SELECT TOP (1) C.CveMoneda, C.Importe FROM dbo.Tra_CostosTramite AS C WHERE C.CveTipoTramite = P.CveTipoTramite AND C.CvePS = D.CvePS AND C.EsActivo = 1 AND (C.FechaInicioVigencia IS NULL OR C.FechaInicioVigencia <= CONVERT(date, GETDATE())) AND (C.FechaFinVigencia IS NULL OR C.FechaFinVigencia >= CONVERT(date, GETDATE())) ORDER BY ISNULL(C.FechaInicioVigencia, CONVERT(date, '19000101')) DESC, C.CveCostoTramite DESC ) AS CT; IF (SELECT COUNT_BIG(*) FROM #PagosOrigenPlantilla) <> @CantidadDetalles OR EXISTS (SELECT 1 FROM #PagosOrigenPlantilla WHERE Cantidad <> 1 OR PrecioUnitario < 0) OR EXISTS ( SELECT CveTramitePago FROM #PagosOrigenPlantilla GROUP BY CveTramitePago HAVING COUNT(DISTINCT CveMoneda) <> 1 ) OR EXISTS ( SELECT 1 FROM dbo.Tra_Pagos AS P WHERE NOT EXISTS ( SELECT 1 FROM #PagosOrigenPlantilla AS D WHERE D.CveTramitePago = P.CveTramitePago ) ) THROW 51209, N'La configuración de cobros requiere conciliación de costos, cantidades o monedas.', 1; SELECT CveCfdiDocumento, Total, Estado, CveOrigen, TipoOrigen, HASHBYTES('SHA2_256', XmlSinTimbrar) AS HuellaXml INTO #PagosOrigenCfdi FROM dbo.Fac_CfdiDocumentos WITH (HOLDLOCK); EXEC sys.sp_rename N'dbo.Tra_Pagos', N'Tra_TiposTramitePagos'; EXEC sys.sp_rename N'dbo.Tra_PagosDetalle', N'Tra_TiposTramitePagosDetalle'; EXEC sys.sp_rename N'dbo.Tra_SolicitudesPagos', N'Tra_SolicitudesPago'; EXEC sys.sp_rename N'dbo.Vta_Pagos', N'Tra_Pagos'; -- Fase 1: lote separado para resolver los nuevos nombres y columnas. EXEC sys.sp_executesql N'CREATE TABLE dbo.Gral_UnidadesCobro ( CveUnidadCobro int IDENTITY(1, 1) NOT NULL CONSTRAINT PK_Gral_UnidadesCobro PRIMARY KEY, Codigo varchar(10) COLLATE Modern_Spanish_CI_AS NOT NULL, Nombre varchar(100) COLLATE Modern_Spanish_CS_AS NOT NULL, EsMoneda bit NOT NULL, RequiereConversion bit NOT NULL, CveMoneda int NULL, Activo bit NOT NULL CONSTRAINT DF_Gral_UnidadesCobro_Activo DEFAULT (1), CONSTRAINT UQ_Gral_UnidadesCobro_Codigo UNIQUE (Codigo), CONSTRAINT FK_Gral_UnidadesCobro_Moneda FOREIGN KEY (CveMoneda) REFERENCES dbo.Gral_Monedas (CveMoneda), CONSTRAINT CK_Gral_UnidadesCobro_Moneda CHECK ((EsMoneda = 1 AND CveMoneda IS NOT NULL) OR (EsMoneda = 0 AND CveMoneda IS NULL)) ); CREATE UNIQUE INDEX UX_Gral_UnidadesCobro_Moneda ON dbo.Gral_UnidadesCobro (CveMoneda) WHERE CveMoneda IS NOT NULL; INSERT INTO dbo.Gral_UnidadesCobro (Codigo, Nombre, EsMoneda, RequiereConversion, CveMoneda, Activo) SELECT Abreviatura, Moneda, 1, CASE WHEN Abreviatura = ''MXN'' THEN 0 ELSE 1 END, CveMoneda, Estatus FROM dbo.Gral_Monedas; INSERT INTO dbo.Gral_UnidadesCobro (Codigo, Nombre, EsMoneda, RequiereConversion) VALUES (''UMA'', ''Unidad de Medida y Actualización'', 0, 1), (''UDI'', ''Unidad de Inversión'', 0, 1); CREATE TABLE dbo.Gral_UnidadesCobroValores ( CveUnidadCobroValor int IDENTITY(1, 1) NOT NULL CONSTRAINT PK_Gral_UnidadesCobroValores PRIMARY KEY, CveUnidadCobro int NOT NULL, FechaVigencia date NOT NULL, ValorMXN decimal(19, 8) NOT NULL, Fuente varchar(500) COLLATE Modern_Spanish_CS_AS NOT NULL, CveUsuarioRegistro int NOT NULL, FechaRegistro datetime2(0) NOT NULL CONSTRAINT DF_Gral_UnidadesCobroValores_Fecha DEFAULT (SYSDATETIME()), CONSTRAINT FK_Gral_UnidadesCobroValores_Unidad FOREIGN KEY (CveUnidadCobro) REFERENCES dbo.Gral_UnidadesCobro (CveUnidadCobro), CONSTRAINT FK_Gral_UnidadesCobroValores_Usuario FOREIGN KEY (CveUsuarioRegistro) REFERENCES dbo.Sis_Usuarios (CveUsuario), CONSTRAINT UQ_Gral_UnidadesCobroValores_Vigencia UNIQUE (CveUnidadCobro, FechaVigencia), CONSTRAINT UQ_Gral_UnidadesCobroValores_Unidad UNIQUE (CveUnidadCobroValor, CveUnidadCobro), CONSTRAINT CK_Gral_UnidadesCobroValores_Valor CHECK (ValorMXN > 0) ); CREATE TABLE dbo.Tra_TiposSolicitudPago ( CveTipoSolicitudPago int IDENTITY(1, 1) NOT NULL CONSTRAINT PK_Tra_TiposSolicitudPago PRIMARY KEY, Codigo varchar(30) COLLATE Modern_Spanish_CI_AS NOT NULL, TipoSolicitudPago varchar(100) COLLATE Modern_Spanish_CS_AS NOT NULL, Activo bit NOT NULL CONSTRAINT DF_Tra_TiposSolicitudPago_Activo DEFAULT (1), CONSTRAINT UQ_Tra_TiposSolicitudPago_Codigo UNIQUE (Codigo) ); -- Claves iniciales indicadas por la especificación; identidad nueva sin datos previos. INSERT INTO dbo.Tra_TiposSolicitudPago (Codigo, TipoSolicitudPago) VALUES (''NORMAL'', ''Normal''), (''CONVENIO'', ''Convenio''); ALTER TABLE dbo.Tra_TiposTramitePagos ADD CveUnidadCobro int NULL, Importe decimal(19, 6) NULL; ALTER TABLE dbo.Tra_TiposTramitePagosDetalle ADD Descripcion varchar(1000) COLLATE Modern_Spanish_CS_AS NULL, PrecioUnitario decimal(19, 6) NULL, CveUnidadCobro int NULL, Importe decimal(19, 6) NULL; ALTER TABLE dbo.Tra_SolicitudesPago ADD CveTipoSolicitudPago int NULL, CveCliente int NULL, CveFraccionamiento int NULL, CveFraccionamientoEtapa int NULL, CveTipoTramite int NULL, Descripcion varchar(1000) COLLATE Modern_Spanish_CS_AS NULL, Importe decimal(19, 6) NULL, CveUnidadCobro int NULL, EsRequerido bit NULL, FechaGeneracion datetime2(0) NULL, EstadoAdministrativo varchar(20) COLLATE Modern_Spanish_CS_AS NOT NULL CONSTRAINT DF_Tra_SolicitudesPago_Estado DEFAULT (''ACTIVO''), CveUsuarioModificacion int NULL, FechaModificacion datetime2(0) NULL; '; -- Fase 2: lote separado para resolver los nuevos nombres y columnas. EXEC sys.sp_executesql N'UPDATE D SET Descripcion = PS.PS, PrecioUnitario = O.PrecioUnitario, CveUnidadCobro = U.CveUnidadCobro, Importe = ROUND(O.Cantidad * O.PrecioUnitario, 6) FROM dbo.Tra_TiposTramitePagosDetalle AS D INNER JOIN #PagosOrigenPlantilla AS O ON O.CveTramitePagoDetalle = D.CveTramitePagoDetalle INNER JOIN dbo.Gral_UnidadesCobro AS U ON U.CveMoneda = O.CveMoneda INNER JOIN dbo.ProductosServicios AS PS ON PS.CvePS = D.CvePS; ;WITH Totales AS ( SELECT CveTramitePago, MAX(CveUnidadCobro) AS CveUnidadCobro, SUM(Importe) AS Importe FROM dbo.Tra_TiposTramitePagosDetalle GROUP BY CveTramitePago ) UPDATE P SET CveUnidadCobro = T.CveUnidadCobro, Importe = T.Importe FROM dbo.Tra_TiposTramitePagos AS P INNER JOIN Totales AS T ON T.CveTramitePago = P.CveTramitePago; UPDATE S SET CveTipoSolicitudPago = T.CveTipoSolicitudPago, CveCliente = O.CveCliente, CveFraccionamiento = O.CveFraccionamiento, CveFraccionamientoEtapa = O.CveFraccionamientoEtapa, CveTipoTramite = O.CveTipoTramite, Descripcion = O.Descripcion, Importe = O.Importe, CveUnidadCobro = U.CveUnidadCobro, EsRequerido = O.EsRequerido, FechaGeneracion = O.FechaGeneracion FROM dbo.Tra_SolicitudesPago AS S INNER JOIN #PagosOrigenSolicitudes AS O ON O.CveSolicitudPago = S.CveSolicitudPago INNER JOIN dbo.Gral_UnidadesCobro AS U ON U.CveMoneda = O.CveMoneda INNER JOIN dbo.Tra_TiposSolicitudPago AS T ON T.Codigo = ''NORMAL''; ALTER TABLE dbo.Tra_TiposTramitePagos ALTER COLUMN CveUnidadCobro int NOT NULL; ALTER TABLE dbo.Tra_TiposTramitePagos ALTER COLUMN Importe decimal(19, 6) NOT NULL; ALTER TABLE dbo.Tra_TiposTramitePagos ADD CONSTRAINT FK_Tra_TiposTramitePagos_Unidad FOREIGN KEY (CveUnidadCobro) REFERENCES dbo.Gral_UnidadesCobro (CveUnidadCobro), CONSTRAINT UQ_Tra_TiposTramitePagos_Unidad UNIQUE (CveTramitePago, CveUnidadCobro), CONSTRAINT CK_Tra_TiposTramitePagos_Importe CHECK (Importe >= 0); ALTER TABLE dbo.Tra_TiposTramitePagosDetalle ALTER COLUMN Descripcion varchar(1000) COLLATE Modern_Spanish_CS_AS NOT NULL; ALTER TABLE dbo.Tra_TiposTramitePagosDetalle ALTER COLUMN PrecioUnitario decimal(19, 6) NOT NULL; ALTER TABLE dbo.Tra_TiposTramitePagosDetalle ALTER COLUMN CveUnidadCobro int NOT NULL; ALTER TABLE dbo.Tra_TiposTramitePagosDetalle ALTER COLUMN Importe decimal(19, 6) NOT NULL; ALTER TABLE dbo.Tra_TiposTramitePagosDetalle ADD CONSTRAINT FK_Tra_TiposTramitePagosDetalle_Unidad FOREIGN KEY (CveTramitePago, CveUnidadCobro) REFERENCES dbo.Tra_TiposTramitePagos (CveTramitePago, CveUnidadCobro), CONSTRAINT CK_Tra_TiposTramitePagosDetalle_Importe CHECK (PrecioUnitario >= 0 AND Importe >= 0 AND Importe = ROUND(Cantidad * PrecioUnitario, 6)); ALTER TABLE dbo.Tra_SolicitudesPago ALTER COLUMN CveTipoSolicitudPago int NOT NULL; ALTER TABLE dbo.Tra_SolicitudesPago ALTER COLUMN CveCliente int NOT NULL; ALTER TABLE dbo.Tra_SolicitudesPago ALTER COLUMN CveFraccionamiento int NOT NULL; ALTER TABLE dbo.Tra_SolicitudesPago ALTER COLUMN Descripcion varchar(1000) COLLATE Modern_Spanish_CS_AS NOT NULL; ALTER TABLE dbo.Tra_SolicitudesPago ALTER COLUMN Importe decimal(19, 6) NOT NULL; ALTER TABLE dbo.Tra_SolicitudesPago ALTER COLUMN CveUnidadCobro int NOT NULL; ALTER TABLE dbo.Tra_SolicitudesPago ALTER COLUMN EsRequerido bit NOT NULL; ALTER TABLE dbo.Tra_SolicitudesPago ALTER COLUMN FechaGeneracion datetime2(0) NOT NULL; -- Se conservan FechaAlta y CveUsuario como fecha/usuario de registro reales. -- No se inventa un autor histórico a partir del usuario que ejecuta la migración. ALTER TABLE dbo.Tra_SolicitudesPago DROP CONSTRAINT UQ_Tra_SolicitudesPagos_Venta; ALTER TABLE dbo.Tra_SolicitudesPago DROP CONSTRAINT UQ_Tra_SolicitudesPagos_SolicitudPago; DROP INDEX IX_Tra_SolicitudesPagos_Solicitud ON dbo.Tra_SolicitudesPago; ALTER TABLE dbo.Tra_SolicitudesPago ALTER COLUMN CveSolicitud int NULL; ALTER TABLE dbo.Tra_SolicitudesPago ALTER COLUMN CveTramitePago int NULL; ALTER TABLE dbo.Tra_SolicitudesPago ALTER COLUMN CveVenta int NULL; CREATE INDEX IX_Tra_SolicitudesPagos_Solicitud ON dbo.Tra_SolicitudesPago (CveSolicitud) INCLUDE (CveTramitePago, CveVenta, FechaAlta); CREATE UNIQUE INDEX UX_Tra_SolicitudesPago_Venta ON dbo.Tra_SolicitudesPago (CveVenta) WHERE CveVenta IS NOT NULL; CREATE UNIQUE INDEX UX_Tra_SolicitudesPago_PlantillaSolicitud ON dbo.Tra_SolicitudesPago (CveSolicitud, CveTramitePago) WHERE CveSolicitud IS NOT NULL AND CveTramitePago IS NOT NULL; ALTER TABLE dbo.Tra_SolicitudesPago ADD CONSTRAINT FK_Tra_SolicitudesPago_Tipo FOREIGN KEY (CveTipoSolicitudPago) REFERENCES dbo.Tra_TiposSolicitudPago (CveTipoSolicitudPago), CONSTRAINT FK_Tra_SolicitudesPago_Cliente FOREIGN KEY (CveCliente) REFERENCES dbo.Clientes (CveCliente), CONSTRAINT FK_Tra_SolicitudesPago_Fraccionamiento FOREIGN KEY (CveFraccionamiento) REFERENCES dbo.Fraccionamientos (CveFraccionamiento), CONSTRAINT FK_Tra_SolicitudesPago_Etapa FOREIGN KEY (CveFraccionamientoEtapa) REFERENCES dbo.FraccionamientosEtapas (CveFraccionamientoEtapa), CONSTRAINT FK_Tra_SolicitudesPago_TipoTramite FOREIGN KEY (CveTipoTramite) REFERENCES dbo.Tra_TiposTramite (CveTipoTramite), CONSTRAINT FK_Tra_SolicitudesPago_Unidad FOREIGN KEY (CveUnidadCobro) REFERENCES dbo.Gral_UnidadesCobro (CveUnidadCobro), CONSTRAINT FK_Tra_SolicitudesPago_UsuarioModificacion FOREIGN KEY (CveUsuarioModificacion) REFERENCES dbo.Sis_Usuarios (CveUsuario), CONSTRAINT UQ_Tra_SolicitudesPago_Unidad UNIQUE (CveSolicitudPago, CveUnidadCobro), CONSTRAINT CK_Tra_SolicitudesPago_Importe CHECK (Importe >= 0), CONSTRAINT CK_Tra_SolicitudesPago_Estado CHECK (EstadoAdministrativo IN (''ACTIVO'', ''CANCELADO'', ''SUSTITUIDO'')); CREATE INDEX IX_Tra_SolicitudesPago_ClienteEstado ON dbo.Tra_SolicitudesPago (CveCliente, EstadoAdministrativo, FechaGeneracion) INCLUDE (CveFraccionamiento, CveFraccionamientoEtapa, CveSolicitud, Importe, CveUnidadCobro); '; -- Fase 3: lote separado para resolver los nuevos nombres y columnas. EXEC sys.sp_executesql N'CREATE TABLE dbo.Tra_SolicitudesPagoDetalle ( CveSolicitudPagoDetalle int IDENTITY(1, 1) NOT NULL CONSTRAINT PK_Tra_SolicitudesPagoDetalle PRIMARY KEY, CveSolicitudPago int NOT NULL, CvePS int NOT NULL, Descripcion varchar(1000) COLLATE Modern_Spanish_CS_AS NOT NULL, Cantidad decimal(18, 4) NOT NULL, PrecioUnitario decimal(19, 6) NOT NULL, CveUnidadCobro int NOT NULL, Importe decimal(19, 6) NOT NULL, CveVentaDetalleOrigen int NULL, CONSTRAINT FK_Tra_SolicitudesPagoDetalle_SolicitudUnidad FOREIGN KEY (CveSolicitudPago, CveUnidadCobro) REFERENCES dbo.Tra_SolicitudesPago (CveSolicitudPago, CveUnidadCobro), CONSTRAINT FK_Tra_SolicitudesPagoDetalle_Producto FOREIGN KEY (CvePS) REFERENCES dbo.ProductosServicios (CvePS), CONSTRAINT FK_Tra_SolicitudesPagoDetalle_VentaOrigen FOREIGN KEY (CveVentaDetalleOrigen) REFERENCES dbo.VentasDetalle (CveVentaDetalle), CONSTRAINT UQ_Tra_SolicitudesPagoDetalle_Solicitud UNIQUE (CveSolicitudPagoDetalle, CveSolicitudPago), CONSTRAINT CK_Tra_SolicitudesPagoDetalle_Importes CHECK (Cantidad > 0 AND PrecioUnitario >= 0 AND Importe >= 0) ); CREATE INDEX IX_Tra_SolicitudesPagoDetalle_Solicitud ON dbo.Tra_SolicitudesPagoDetalle (CveSolicitudPago, CvePS); CREATE UNIQUE INDEX UX_Tra_SolicitudesPagoDetalle_VentaOrigen ON dbo.Tra_SolicitudesPagoDetalle (CveVentaDetalleOrigen) WHERE CveVentaDetalleOrigen IS NOT NULL; CREATE TABLE dbo.Tra_SolicitudesPagoParcialidades ( CveSolicitudPagoParcialidad int IDENTITY(1, 1) NOT NULL CONSTRAINT PK_Tra_SolicitudesPagoParcialidades PRIMARY KEY, CveSolicitudPago int NOT NULL, NumeroParcialidad int NOT NULL, FechaVencimiento date NOT NULL, Importe decimal(19, 6) NOT NULL, CveUnidadCobro int NOT NULL, FechaProrroga date NULL, CONSTRAINT FK_Tra_SolicitudesPagoParcialidades_SolicitudUnidad FOREIGN KEY (CveSolicitudPago, CveUnidadCobro) REFERENCES dbo.Tra_SolicitudesPago (CveSolicitudPago, CveUnidadCobro), CONSTRAINT UQ_Tra_SolicitudesPagoParcialidades_Numero UNIQUE (CveSolicitudPago, NumeroParcialidad), CONSTRAINT UQ_Tra_SolicitudesPagoParcialidades_Solicitud UNIQUE (CveSolicitudPagoParcialidad, CveSolicitudPago), CONSTRAINT CK_Tra_SolicitudesPagoParcialidades_Importe CHECK (Importe >= 0 AND NumeroParcialidad > 0), CONSTRAINT CK_Tra_SolicitudesPagoParcialidades_Prorroga CHECK (FechaProrroga IS NULL OR FechaProrroga >= FechaVencimiento) ); CREATE INDEX IX_Tra_SolicitudesPagoParcialidades_Vencimiento ON dbo.Tra_SolicitudesPagoParcialidades (FechaVencimiento, CveSolicitudPago) INCLUDE (FechaProrroga, Importe, CveUnidadCobro); INSERT INTO dbo.Tra_SolicitudesPagoDetalle (CveSolicitudPago, CvePS, Descripcion, Cantidad, PrecioUnitario, CveUnidadCobro, Importe, CveVentaDetalleOrigen) SELECT D.CveSolicitudPago, D.CvePS, D.Descripcion, D.Cantidad, CONVERT(decimal(19, 6), D.Importe / D.Cantidad), S.CveUnidadCobro, D.Importe, D.CveVentaDetalle FROM #PagosOrigenDetalle AS D INNER JOIN dbo.Tra_SolicitudesPago AS S ON S.CveSolicitudPago = D.CveSolicitudPago; INSERT INTO dbo.Tra_SolicitudesPagoParcialidades (CveSolicitudPago, NumeroParcialidad, FechaVencimiento, Importe, CveUnidadCobro) SELECT O.CveSolicitudPago, 1, O.FechaVencimiento, O.Importe, S.CveUnidadCobro FROM #PagosOrigenSolicitudes AS O INNER JOIN dbo.Tra_SolicitudesPago AS S ON S.CveSolicitudPago = O.CveSolicitudPago; -- La restricción anterior impedía más de un abono por solicitud/plantilla. DROP INDEX UX_Vta_Pagos_SolicitudTramitePagoActivo ON dbo.Tra_Pagos; DROP INDEX IX_Vta_Pagos_Cliente_Venta ON dbo.Tra_Pagos; ALTER TABLE dbo.Tra_Pagos ALTER COLUMN CveVenta int NULL; ALTER TABLE dbo.Tra_Pagos ALTER COLUMN CveTramitePago int NULL; ALTER TABLE dbo.Tra_Pagos ALTER COLUMN CveMoneda int NULL; ALTER TABLE dbo.Tra_Pagos ALTER COLUMN Importe decimal(19, 6) NOT NULL; CREATE INDEX IX_Vta_Pagos_Cliente_Venta ON dbo.Tra_Pagos (CveCliente, CveVenta, EsActivo); -- Cero abonos fue comprobado con bloqueo; no se inventan factores históricos. ALTER TABLE dbo.Tra_Pagos ADD CveUnidadCobro int NOT NULL, CveUnidadCobroValor int NULL, ValorConversion decimal(19, 8) NOT NULL, ImporteMXN decimal(19, 6) NOT NULL; ALTER TABLE dbo.Tra_Pagos ADD CONSTRAINT FK_Tra_Pagos_Unidad FOREIGN KEY (CveUnidadCobro) REFERENCES dbo.Gral_UnidadesCobro (CveUnidadCobro), CONSTRAINT FK_Tra_Pagos_Equivalencia FOREIGN KEY (CveUnidadCobroValor, CveUnidadCobro) REFERENCES dbo.Gral_UnidadesCobroValores (CveUnidadCobroValor, CveUnidadCobro), CONSTRAINT CK_Tra_Pagos_Conversion CHECK (ValorConversion > 0 AND ImporteMXN > 0 AND ImporteMXN = CONVERT(decimal(19, 6), ROUND(Importe * ValorConversion, 6))); CREATE INDEX IX_Tra_Pagos_ClienteFecha ON dbo.Tra_Pagos (CveCliente, FechaPago) INCLUDE (Importe, ImporteMXN, CveUnidadCobro, EsActivo); CREATE TABLE dbo.Tra_PagosAplicaciones ( CvePagoAplicacion int IDENTITY(1, 1) NOT NULL CONSTRAINT PK_Tra_PagosAplicaciones PRIMARY KEY, CvePago int NOT NULL, CveSolicitudPago int NOT NULL, CveSolicitudPagoParcialidad int NOT NULL, CveSolicitudPagoDetalle int NOT NULL, CveUnidadCobro int NOT NULL, ImporteAplicado decimal(19, 6) NOT NULL, ValorConversionObligacion decimal(19, 8) NOT NULL, ImporteAplicadoMXN decimal(19, 6) NOT NULL, ImportePagoConsumido decimal(19, 6) NOT NULL, CveUsuarioRegistro int NOT NULL, FechaRegistro datetime2(0) NOT NULL CONSTRAINT DF_Tra_PagosAplicaciones_Fecha DEFAULT (SYSDATETIME()), CONSTRAINT FK_Tra_PagosAplicaciones_Pago FOREIGN KEY (CvePago) REFERENCES dbo.Tra_Pagos (CvePago), CONSTRAINT FK_Tra_PagosAplicaciones_Parcialidad FOREIGN KEY (CveSolicitudPagoParcialidad, CveSolicitudPago) REFERENCES dbo.Tra_SolicitudesPagoParcialidades (CveSolicitudPagoParcialidad, CveSolicitudPago), CONSTRAINT FK_Tra_PagosAplicaciones_Detalle FOREIGN KEY (CveSolicitudPagoDetalle, CveSolicitudPago) REFERENCES dbo.Tra_SolicitudesPagoDetalle (CveSolicitudPagoDetalle, CveSolicitudPago), CONSTRAINT FK_Tra_PagosAplicaciones_Unidad FOREIGN KEY (CveSolicitudPago, CveUnidadCobro) REFERENCES dbo.Tra_SolicitudesPago (CveSolicitudPago, CveUnidadCobro), CONSTRAINT FK_Tra_PagosAplicaciones_Usuario FOREIGN KEY (CveUsuarioRegistro) REFERENCES dbo.Sis_Usuarios (CveUsuario), CONSTRAINT UQ_Tra_PagosAplicaciones_Destino UNIQUE (CvePago, CveSolicitudPagoParcialidad, CveSolicitudPagoDetalle), CONSTRAINT CK_Tra_PagosAplicaciones_Importes CHECK (ImporteAplicado > 0 AND ValorConversionObligacion > 0 AND ImporteAplicadoMXN > 0 AND ImportePagoConsumido > 0 AND ImporteAplicadoMXN = CONVERT(decimal(19, 6), ROUND(ImporteAplicado * ValorConversionObligacion, 6))) ); CREATE INDEX IX_Tra_PagosAplicaciones_Parcialidad ON dbo.Tra_PagosAplicaciones (CveSolicitudPagoParcialidad) INCLUDE (CvePago, ImporteAplicado, CveSolicitudPagoDetalle); CREATE INDEX IX_Tra_PagosAplicaciones_Detalle ON dbo.Tra_PagosAplicaciones (CveSolicitudPagoDetalle) INCLUDE (CvePago, ImporteAplicado); CREATE TABLE dbo.Tra_SolicitudesPagoRequeridoBitacora ( CveSolicitudPagoRequeridoBitacora int IDENTITY(1, 1) NOT NULL CONSTRAINT PK_Tra_SolicitudesPagoRequeridoBitacora PRIMARY KEY, CveSolicitudPago int NOT NULL, ValorAnterior bit NOT NULL, ValorNuevo bit NOT NULL, Observacion varchar(2000) COLLATE Modern_Spanish_CS_AS NOT NULL, CveUsuarioRegistro int NOT NULL, FechaRegistro datetime2(0) NOT NULL CONSTRAINT DF_Tra_SolicitudesPagoRequeridoBitacora_Fecha DEFAULT (SYSDATETIME()), CONSTRAINT FK_Tra_SolicitudesPagoRequeridoBitacora_Solicitud FOREIGN KEY (CveSolicitudPago) REFERENCES dbo.Tra_SolicitudesPago (CveSolicitudPago), CONSTRAINT FK_Tra_SolicitudesPagoRequeridoBitacora_Usuario FOREIGN KEY (CveUsuarioRegistro) REFERENCES dbo.Sis_Usuarios (CveUsuario), CONSTRAINT CK_Tra_SolicitudesPagoRequeridoBitacora_Cambio CHECK (ValorAnterior <> ValorNuevo AND LEN(LTRIM(RTRIM(Observacion))) > 0) ); CREATE INDEX IX_Tra_SolicitudesPagoRequeridoBitacora_Solicitud ON dbo.Tra_SolicitudesPagoRequeridoBitacora (CveSolicitudPago, FechaRegistro); '; -- Fase 4: lote separado para resolver los nuevos nombres y columnas. EXEC sys.sp_executesql N'CREATE TABLE dbo.Tra_SolicitudesPagoConvenio ( CveSolicitudPago int NOT NULL CONSTRAINT PK_Tra_SolicitudesPagoConvenio PRIMARY KEY, ImporteSaldoConvenido decimal(19, 6) NOT NULL, Observaciones varchar(2000) COLLATE Modern_Spanish_CS_AS NULL, CveUsuarioRegistro int NOT NULL, FechaRegistro datetime2(0) NOT NULL CONSTRAINT DF_Tra_SolicitudesPagoConvenio_Fecha DEFAULT (SYSDATETIME()), CONSTRAINT FK_Tra_SolicitudesPagoConvenio_Solicitud FOREIGN KEY (CveSolicitudPago) REFERENCES dbo.Tra_SolicitudesPago (CveSolicitudPago), CONSTRAINT FK_Tra_SolicitudesPagoConvenio_Usuario FOREIGN KEY (CveUsuarioRegistro) REFERENCES dbo.Sis_Usuarios (CveUsuario), CONSTRAINT CK_Tra_SolicitudesPagoConvenio_Saldo CHECK (ImporteSaldoConvenido > 0) ); CREATE TABLE dbo.Tra_SolicitudesPagoConvenioOrigen ( CveConvenioOrigen int IDENTITY(1, 1) NOT NULL CONSTRAINT PK_Tra_SolicitudesPagoConvenioOrigen PRIMARY KEY, CveSolicitudPagoConvenio int NOT NULL, CveSolicitudPagoOrigen int NOT NULL, ImporteSaldoOriginal decimal(19, 6) NOT NULL, ImporteTomadoConvenio decimal(19, 6) NOT NULL, CveUnidadCobro int NOT NULL, CONSTRAINT FK_Tra_SolicitudesPagoConvenioOrigen_Convenio FOREIGN KEY (CveSolicitudPagoConvenio) REFERENCES dbo.Tra_SolicitudesPagoConvenio (CveSolicitudPago), CONSTRAINT FK_Tra_SolicitudesPagoConvenioOrigen_UnidadOrigen FOREIGN KEY (CveSolicitudPagoOrigen, CveUnidadCobro) REFERENCES dbo.Tra_SolicitudesPago (CveSolicitudPago, CveUnidadCobro), CONSTRAINT FK_Tra_SolicitudesPagoConvenioOrigen_UnidadConvenio FOREIGN KEY (CveSolicitudPagoConvenio, CveUnidadCobro) REFERENCES dbo.Tra_SolicitudesPago (CveSolicitudPago, CveUnidadCobro), CONSTRAINT UQ_Tra_SolicitudesPagoConvenioOrigen_Origen UNIQUE (CveSolicitudPagoConvenio, CveSolicitudPagoOrigen), CONSTRAINT UQ_Tra_SolicitudesPagoConvenioOrigen_Solicitud UNIQUE (CveConvenioOrigen, CveSolicitudPagoOrigen), CONSTRAINT CK_Tra_SolicitudesPagoConvenioOrigen_Saldo CHECK (CveSolicitudPagoConvenio <> CveSolicitudPagoOrigen AND ImporteTomadoConvenio > 0 AND ImporteSaldoOriginal >= ImporteTomadoConvenio) ); CREATE INDEX IX_Tra_SolicitudesPagoConvenioOrigen_Adeudo ON dbo.Tra_SolicitudesPagoConvenioOrigen (CveSolicitudPagoOrigen) INCLUDE (CveSolicitudPagoConvenio, ImporteTomadoConvenio); CREATE TABLE dbo.Tra_SolicitudesPagoConvenioOrigenDetalle ( CveConvenioOrigenDetalle int IDENTITY(1, 1) NOT NULL CONSTRAINT PK_Tra_SolicitudesPagoConvenioOrigenDetalle PRIMARY KEY, CveConvenioOrigen int NOT NULL, CveSolicitudPagoOrigen int NOT NULL, CveSolicitudPagoDetalleOrigen int NOT NULL, CveSolicitudPagoParcialidadOrigen int NOT NULL, ImporteSaldoOriginal decimal(19, 6) NOT NULL, ImporteTomadoConvenio decimal(19, 6) NOT NULL, CONSTRAINT FK_Tra_SolicitudesPagoConvenioOrigenDetalle_Origen FOREIGN KEY (CveConvenioOrigen, CveSolicitudPagoOrigen) REFERENCES dbo.Tra_SolicitudesPagoConvenioOrigen (CveConvenioOrigen, CveSolicitudPagoOrigen), CONSTRAINT FK_Tra_SolicitudesPagoConvenioOrigenDetalle_Producto FOREIGN KEY (CveSolicitudPagoDetalleOrigen, CveSolicitudPagoOrigen) REFERENCES dbo.Tra_SolicitudesPagoDetalle (CveSolicitudPagoDetalle, CveSolicitudPago), CONSTRAINT FK_Tra_SolicitudesPagoConvenioOrigenDetalle_Parcialidad FOREIGN KEY (CveSolicitudPagoParcialidadOrigen, CveSolicitudPagoOrigen) REFERENCES dbo.Tra_SolicitudesPagoParcialidades (CveSolicitudPagoParcialidad, CveSolicitudPago), CONSTRAINT UQ_Tra_SolicitudesPagoConvenioOrigenDetalle_Origen UNIQUE (CveConvenioOrigen, CveSolicitudPagoDetalleOrigen, CveSolicitudPagoParcialidadOrigen), CONSTRAINT CK_Tra_SolicitudesPagoConvenioOrigenDetalle_Saldo CHECK (ImporteTomadoConvenio > 0 AND ImporteSaldoOriginal >= ImporteTomadoConvenio) ); CREATE INDEX IX_Tra_SolicitudesPagoConvenioOrigenDetalle_Producto ON dbo.Tra_SolicitudesPagoConvenioOrigenDetalle (CveSolicitudPagoDetalleOrigen) INCLUDE (CveConvenioOrigen, ImporteTomadoConvenio); CREATE INDEX IX_Tra_SolicitudesPagoConvenioOrigenDetalle_Parcialidad ON dbo.Tra_SolicitudesPagoConvenioOrigenDetalle (CveSolicitudPagoParcialidadOrigen) INCLUDE (CveConvenioOrigen, ImporteTomadoConvenio); '; -- Fase 5: lote separado para resolver los nuevos nombres y columnas. EXEC sys.sp_executesql N'ALTER TABLE dbo.Fac_CfdiDocumentos ADD OrigenRegistro varchar(10) COLLATE Modern_Spanish_CS_AS NOT NULL CONSTRAINT DF_Fac_CfdiDocumentos_OrigenRegistro DEFAULT (''INTERNO''), UuidExterno uniqueidentifier NULL, FechaTimbradoExterno datetime2(0) NULL, RutaXmlExterno varchar(500) COLLATE Modern_Spanish_CS_AS NULL, HashXmlExterno binary(32) NULL, RutaPdf varchar(500) COLLATE Modern_Spanish_CS_AS NULL, HashPdf binary(32) NULL, ImporteValidado bit NOT NULL CONSTRAINT DF_Fac_CfdiDocumentos_ImporteValidado DEFAULT (0), CveUsuarioValida int NULL, FechaValidacion datetime2(0) NULL; -- Un documento externo puede capturarse manualmente sin un borrador de XML. -- Las exigencias del flujo interno se conservan mediante CHECK condicional. ALTER TABLE dbo.Fac_CfdiDocumentos ALTER COLUMN CveEmpresa int NULL; DROP INDEX IX_Fac_CfdiDocumentos_Cliente_Fecha ON dbo.Fac_CfdiDocumentos; ALTER TABLE dbo.Fac_CfdiDocumentos ALTER COLUMN FechaEmision datetime2(0) NULL; CREATE INDEX IX_Fac_CfdiDocumentos_Cliente_Fecha ON dbo.Fac_CfdiDocumentos (CveCliente, FechaEmision DESC, CveCfdiDocumento DESC); ALTER TABLE dbo.Fac_CfdiDocumentos ALTER COLUMN TipoComprobante char(1) COLLATE Modern_Spanish_CS_AS NULL; ALTER TABLE dbo.Fac_CfdiDocumentos ALTER COLUMN Exportacion varchar(2) COLLATE Modern_Spanish_CS_AS NULL; ALTER TABLE dbo.Fac_CfdiDocumentos ALTER COLUMN LugarExpedicion varchar(5) COLLATE Modern_Spanish_CI_AS NULL; ALTER TABLE dbo.Fac_CfdiDocumentos ALTER COLUMN Subtotal decimal(19, 6) NULL; ALTER TABLE dbo.Fac_CfdiDocumentos ALTER COLUMN Descuento decimal(19, 6) NULL; ALTER TABLE dbo.Fac_CfdiDocumentos ALTER COLUMN TotalImpuestosTrasladados decimal(19, 6) NULL; ALTER TABLE dbo.Fac_CfdiDocumentos ALTER COLUMN TotalImpuestosRetenidos decimal(19, 6) NULL; ALTER TABLE dbo.Fac_CfdiDocumentos ALTER COLUMN RfcEmisor varchar(13) COLLATE Modern_Spanish_CS_AS NULL; ALTER TABLE dbo.Fac_CfdiDocumentos ALTER COLUMN NombreEmisor varchar(300) COLLATE Modern_Spanish_CS_AS NULL; ALTER TABLE dbo.Fac_CfdiDocumentos ALTER COLUMN RegimenFiscalEmisor varchar(3) COLLATE Modern_Spanish_CS_AS NULL; ALTER TABLE dbo.Fac_CfdiDocumentos ALTER COLUMN RfcReceptor varchar(13) COLLATE Modern_Spanish_CS_AS NULL; ALTER TABLE dbo.Fac_CfdiDocumentos ALTER COLUMN NombreReceptor varchar(300) COLLATE Modern_Spanish_CS_AS NULL; ALTER TABLE dbo.Fac_CfdiDocumentos ALTER COLUMN DomicilioFiscalReceptor varchar(5) COLLATE Modern_Spanish_CI_AS NULL; ALTER TABLE dbo.Fac_CfdiDocumentos ALTER COLUMN RegimenFiscalReceptor varchar(3) COLLATE Modern_Spanish_CS_AS NULL; ALTER TABLE dbo.Fac_CfdiDocumentos ALTER COLUMN UsoCfdi varchar(5) COLLATE Modern_Spanish_CS_AS NULL; ALTER TABLE dbo.Fac_CfdiDocumentos ALTER COLUMN XmlSinTimbrar varbinary(max) NULL; ALTER TABLE dbo.Fac_CfdiDocumentos ALTER COLUMN HashXmlSinTimbrar binary(32) NULL; '; -- Fase 6: lote separado para resolver los nuevos nombres y columnas. EXEC sys.sp_executesql N'ALTER TABLE dbo.Fac_CfdiDocumentos ADD CONSTRAINT FK_Fac_CfdiDocumentos_UsuarioValida FOREIGN KEY (CveUsuarioValida) REFERENCES dbo.Sis_Usuarios (CveUsuario), CONSTRAINT CK_Fac_CfdiDocumentos_OrigenRegistro CHECK (OrigenRegistro IN (''INTERNO'', ''EXTERNO'')), CONSTRAINT CK_Fac_CfdiDocumentos_DatosInternos CHECK ( OrigenRegistro = ''EXTERNO'' OR ( CveEmpresa IS NOT NULL AND FechaEmision IS NOT NULL AND TipoComprobante IS NOT NULL AND Exportacion IS NOT NULL AND LugarExpedicion IS NOT NULL AND Subtotal IS NOT NULL AND Descuento IS NOT NULL AND TotalImpuestosTrasladados IS NOT NULL AND TotalImpuestosRetenidos IS NOT NULL AND RfcEmisor IS NOT NULL AND NombreEmisor IS NOT NULL AND RegimenFiscalEmisor IS NOT NULL AND RfcReceptor IS NOT NULL AND NombreReceptor IS NOT NULL AND DomicilioFiscalReceptor IS NOT NULL AND RegimenFiscalReceptor IS NOT NULL AND UsoCfdi IS NOT NULL AND XmlSinTimbrar IS NOT NULL AND HashXmlSinTimbrar IS NOT NULL ) ), CONSTRAINT CK_Fac_CfdiDocumentos_OrigenXml CHECK ( (OrigenRegistro = ''INTERNO'' AND UuidExterno IS NULL AND RutaXmlExterno IS NULL AND HashXmlExterno IS NULL AND FechaTimbradoExterno IS NULL) OR (OrigenRegistro = ''EXTERNO'' AND XmlSinTimbrar IS NULL AND HashXmlSinTimbrar IS NULL AND CveCfdiTimbradoVigente IS NULL) ), CONSTRAINT CK_Fac_CfdiDocumentos_Archivos CHECK ( ((RutaXmlExterno IS NULL AND HashXmlExterno IS NULL) OR (RutaXmlExterno IS NOT NULL AND HashXmlExterno IS NOT NULL)) AND ((RutaPdf IS NULL AND HashPdf IS NULL) OR (RutaPdf IS NOT NULL AND HashPdf IS NOT NULL)) ), CONSTRAINT CK_Fac_CfdiDocumentos_Validacion CHECK ( (ImporteValidado = 0 AND CveUsuarioValida IS NULL AND FechaValidacion IS NULL) OR (ImporteValidado = 1 AND CveUsuarioValida IS NOT NULL AND FechaValidacion IS NOT NULL) ), CONSTRAINT CK_Fac_CfdiDocumentos_ExternoCompleto CHECK ( OrigenRegistro = ''INTERNO'' OR Estado <> ''TIMBRADO'' OR (UuidExterno IS NOT NULL AND RutaXmlExterno IS NOT NULL AND RutaPdf IS NOT NULL AND ImporteValidado = 1) ); CREATE UNIQUE INDEX UX_Fac_CfdiDocumentos_UuidExterno ON dbo.Fac_CfdiDocumentos (UuidExterno) WHERE UuidExterno IS NOT NULL; CREATE TABLE dbo.Tra_PagosCfdi ( CvePagoCfdi int IDENTITY(1, 1) NOT NULL CONSTRAINT PK_Tra_PagosCfdi PRIMARY KEY, CvePago int NOT NULL, CveCfdiDocumento bigint NOT NULL, ImporteVinculadoMXN decimal(19, 6) NOT NULL, CveUsuarioRegistro int NOT NULL, FechaRegistro datetime2(0) NOT NULL CONSTRAINT DF_Tra_PagosCfdi_Fecha DEFAULT (SYSDATETIME()), CONSTRAINT FK_Tra_PagosCfdi_Pago FOREIGN KEY (CvePago) REFERENCES dbo.Tra_Pagos (CvePago), CONSTRAINT FK_Tra_PagosCfdi_Documento FOREIGN KEY (CveCfdiDocumento) REFERENCES dbo.Fac_CfdiDocumentos (CveCfdiDocumento), CONSTRAINT FK_Tra_PagosCfdi_Usuario FOREIGN KEY (CveUsuarioRegistro) REFERENCES dbo.Sis_Usuarios (CveUsuario), CONSTRAINT UQ_Tra_PagosCfdi_Vinculo UNIQUE (CvePago, CveCfdiDocumento), CONSTRAINT CK_Tra_PagosCfdi_Importe CHECK (ImporteVinculadoMXN > 0) ); CREATE INDEX IX_Tra_PagosCfdi_Documento ON dbo.Tra_PagosCfdi (CveCfdiDocumento); -- No vincular los CFDI actuales a abonos inexistentes. -- Su relación original con Ventas se conserva en TipoOrigen/CveOrigen. IF EXISTS ( SELECT CveCfdiDocumento, Total, Estado, CveOrigen, TipoOrigen, HuellaXml FROM #PagosOrigenCfdi EXCEPT SELECT CveCfdiDocumento, Total, Estado, CveOrigen, TipoOrigen, HASHBYTES(''SHA2_256'', XmlSinTimbrar) FROM dbo.Fac_CfdiDocumentos ) OR (SELECT COUNT_BIG(*) FROM #PagosOrigenCfdi) <> (SELECT COUNT_BIG(*) FROM dbo.Fac_CfdiDocumentos) THROW 51210, N''No se conservaron los documentos fiscales originales.'', 1; IF EXISTS ( SELECT CveSolicitudPago, CveSolicitud, CveTramitePago, CveVenta, Importe, FechaAlta, CveUsuario FROM #PagosOrigenSolicitudes EXCEPT SELECT CveSolicitudPago, CveSolicitud, CveTramitePago, CveVenta, Importe, FechaAlta, CveUsuario FROM dbo.Tra_SolicitudesPago ) THROW 51211, N''No se conservaron las claves, importes o autores de las obligaciones.'', 1; IF EXISTS ( SELECT 1 FROM dbo.Tra_SolicitudesPago AS S OUTER APPLY ( SELECT SUM(D.Importe) AS Importe FROM dbo.Tra_SolicitudesPagoDetalle AS D WHERE D.CveSolicitudPago = S.CveSolicitudPago ) AS D OUTER APPLY ( SELECT SUM(P.Importe) AS Importe FROM dbo.Tra_SolicitudesPagoParcialidades AS P WHERE P.CveSolicitudPago = S.CveSolicitudPago ) AS P WHERE D.Importe IS NULL OR D.Importe <> S.Importe OR P.Importe IS NULL OR P.Importe <> S.Importe ) THROW 51212, N''Los detalles o parcialidades no concilian con la obligación.'', 1; '; IF @TablaPlantillas <> OBJECT_ID(N'dbo.Tra_TiposTramitePagos') OR @TablaDetallePlantillas <> OBJECT_ID(N'dbo.Tra_TiposTramitePagosDetalle') OR @TablaSolicitudes <> OBJECT_ID(N'dbo.Tra_SolicitudesPago') OR @TablaAbonos <> OBJECT_ID(N'dbo.Tra_Pagos') THROW 51213, N'No se conservaron las identidades de las tablas originales.', 1; IF EXISTS ( SELECT R.Clave, R.Tabla, R.Referencia FROM @Relaciones AS R EXCEPT SELECT F.object_id, F.parent_object_id, F.referenced_object_id FROM sys.foreign_keys AS F WHERE F.is_disabled = 0 AND F.is_not_trusted = 0 ) THROW 51214, N'No se conservaron todas las relaciones originales verificadas.', 1; -- Consulta dinámica: estos nombres tienen una responsabilidad nueva tras renombrar. DECLARE @ConteosCorrectos bit; EXEC sys.sp_executesql N'SELECT @Correcto = CONVERT(bit, CASE WHEN (SELECT COUNT_BIG(*) FROM dbo.Tra_TiposTramitePagos) = @Plantillas AND (SELECT COUNT_BIG(*) FROM dbo.Tra_TiposTramitePagosDetalle) = @Detalles AND (SELECT COUNT_BIG(*) FROM dbo.Tra_SolicitudesPago) = @Solicitudes AND (SELECT COUNT_BIG(*) FROM dbo.Tra_Pagos) = @Abonos THEN 1 ELSE 0 END);', N'@Plantillas bigint, @Detalles bigint, @Solicitudes bigint, @Abonos bigint, @Correcto bit OUTPUT', @Plantillas = @CantidadPlantillas, @Detalles = @CantidadDetalles, @Solicitudes = @CantidadSolicitudes, @Abonos = @CantidadAbonos, @Correcto = @ConteosCorrectos OUTPUT; IF ISNULL(@ConteosCorrectos, 0) = 0 THROW 51215, N'Los conteos finales no coinciden con el origen.', 1; SELECT @CantidadPlantillas AS PlantillasConservadas, @CantidadSolicitudes AS ObligacionesMigradas, @CantidadAbonos AS AbonosConservados, N'Estructura preparada en la transacción. Faltan PAs, aplicación y configuración antes de confirmar.' AS Resultado; -- Mostrar diferencias fiscales existentes sin corregirlas. SELECT O.CveSolicitudPago, O.CveVenta, O.Importe AS ImporteObligacion, F.CveCfdiDocumento, F.Total AS ImporteCfdi FROM #PagosOrigenSolicitudes AS O INNER JOIN dbo.Fac_CfdiDocumentos AS F ON F.TipoOrigen = 'VENTA' AND F.CveOrigen = O.CveVenta WHERE F.Total <> O.Importe; DROP TABLE #PagosOrigenSolicitudes; DROP TABLE #PagosOrigenDetalle; DROP TABLE #PagosOrigenPlantilla; DROP TABLE #PagosOrigenCfdi;