--Hash:684F010088E07E5D3328C77A546D1B1C

-- Bloqueo exclusivo por base de datos
--//
SET NOCOUNT ON;

DECLARE @__ZiurDbScriptLockResource NVARCHAR(200) = N'ZiurSoft:DbScriptLock:' + CAST(DB_ID() AS NVARCHAR(20));
DECLARE @__ZiurDbScriptLockResult INT;
EXEC @__ZiurDbScriptLockResult = sp_getapplock
    @Resource = @__ZiurDbScriptLockResource,
    @LockMode = N'Exclusive',
    @LockOwner = N'Session',
    @LockTimeout = 600000; -- 10 min

IF (@__ZiurDbScriptLockResult < 0)
BEGIN
    RAISERROR(N'No se pudo obtener el bloqueo exclusivo de actualizacion para esta base de datos.', 16, 1);
    SET NOEXEC ON;
END

/* Idempotencia a nivel de script: si la version ya existe, no ejecutar nada. */
IF EXISTS (SELECT 1 FROM dbo.ZiurVersiones WHERE NumVersion = 969)
BEGIN
    PRINT N'Scripts_969.sql: la version 969 ya esta aplicada. Se omite ejecucion.';
    EXEC sp_releaseapplock @Resource = @__ZiurDbScriptLockResource, @LockOwner = N'Session';
    SET NOEXEC ON;
END

SET XACT_ABORT ON;
GO

SET DATEFORMAT mdy;

--Validar que no existan scripts que no se hayan ejecutado
--//
IF EXISTS
(
	SELECT a.NumVersion + 1 AS HuecoInicio
	FROM ZiurVersiones a
	LEFT JOIN ZiurVersiones b ON a.NumVersion + 1 = b.NumVersion
	WHERE a.NumVersion>830 AND b.NumVersion IS NULL
	AND a.NumVersion + 1 < 969
)
RAISERROR('Error : hay un script que no se ejecuto , debe ejecutarlo manualmente.', 20, -1) with log
--//

--Colocar contenido de script diferencial aqui (Ziur.Database.publish.sql)

GO
/*
 Plantilla de script anterior a la implementación							
--------------------------------------------------------------------------------------
 Este archivo contiene instrucciones de SQL que se ejecutarán antes del script de compilación	
 Use la sintaxis de SQLCMD para incluir un archivo en el script anterior a la implementación			
 Ejemplo:      :r .\miArchivo.sql								
 Use la sintaxis de SQLCMD para hacer referencia a una variable en el script anterior a la implementación		
 Ejemplo:      :setvar TableName miTabla							
               SELECT * FROM [$(TableName)]					
--------------------------------------------------------------------------------------
*/
GO

IF OBJECT_ID(N'dbo.DocElectronicos', N'U') IS NOT NULL
AND EXISTS (SELECT TOP 1 1 FROM [dbo].[DocElectronicos])
    PRINT N'Se detectaron filas. Se realizara el paso de datos a la nueva estructura de [dbo].[DocElectronicos].';

GO
PRINT N'Quitando Restricción DEFAULT restricción sin nombre en [dbo].[DocElectronicos]...';


GO
--ALTER TABLE [dbo].[DocElectronicos] DROP CONSTRAINT [DF__DocElectr__RowGu__48E8D9CA];


GO
PRINT N'Quitando Restricción DEFAULT restricción sin nombre en [dbo].[DocElectronicos]...';


GO
--ALTER TABLE [dbo].[DocElectronicos] DROP CONSTRAINT [DF__DocElectr__Creat__49DCFE03];


GO
PRINT N'Quitando Restricción UNIQUE restricción sin nombre en [dbo].[DocElectronicos]...';


GO
--ALTER TABLE [dbo].[DocElectronicos] DROP CONSTRAINT [UQ__DocElect__B975DD8342857F23];


GO
PRINT N'Iniciando recompilación de la tabla [dbo].[DocElectronicos]...';


GO
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

SET XACT_ABORT ON;

IF OBJECT_ID(N'dbo.DocElectronicos', N'U') IS NOT NULL
AND COL_LENGTH(N'dbo.DocElectronicos', N'RowGuid') IS NOT NULL
BEGIN
    BEGIN TRANSACTION;

    IF OBJECT_ID(N'dbo.tmp_ms_xx_DocElectronicos', N'U') IS NOT NULL
        DROP TABLE [dbo].[tmp_ms_xx_DocElectronicos];

    CREATE TABLE [dbo].[tmp_ms_xx_DocElectronicos] (
        [IdDoc]       INT             IDENTITY (1, 1) NOT NULL,
        [FechaRecep]  DATE            NOT NULL,
        [Fecha]       DATE            NOT NULL,
        [Prefijo]     NVARCHAR (10)   NOT NULL,
        [NroDoc]      NVARCHAR (200)  NOT NULL,
        [TipoDoc]     NVARCHAR (40)   NOT NULL,
        [NitEmisor]   NVARCHAR (100)  NOT NULL,
        [Emisor]      NVARCHAR (50)   NOT NULL,
        [Resultado]   NVARCHAR (50)   NOT NULL,
        [EstRadian]   NVARCHAR (50)   NOT NULL,
        [Total]       DECIMAL (28, 6) NOT NULL,
        [CreatedDate] DATETIME        DEFAULT GETDATE() NOT NULL,
        [NitReceptor] NVARCHAR (100)  NULL,
        [Receptor]    NVARCHAR (200)  NULL,
        [CUFE]        NVARCHAR (100)  NULL,
        CONSTRAINT [tmp_ms_xx_constraint_PK_Documentos_Electronicos1] PRIMARY KEY CLUSTERED ([IdDoc] ASC)
    );

    IF EXISTS (SELECT TOP 1 1 FROM [dbo].[DocElectronicos])
    BEGIN
        SET IDENTITY_INSERT [dbo].[tmp_ms_xx_DocElectronicos] ON;
        INSERT INTO [dbo].[tmp_ms_xx_DocElectronicos] ([IdDoc], [FechaRecep], [Fecha], [Prefijo], [NroDoc], [TipoDoc], [NitEmisor], [Emisor], [Resultado], [EstRadian], [Total], [CreatedDate])
        SELECT   [IdDoc],
                 [FechaRecep],
                 [Fecha],
                 [Prefijo],
                 [NroDoc],
                 [TipoDoc],
                 [NitEmisor],
                 [Emisor],
                 [Resultado],
                 [EstRadian],
                 [Total],
                 [CreatedDate]
        FROM     [dbo].[DocElectronicos]
        ORDER BY [IdDoc] ASC;
        SET IDENTITY_INSERT [dbo].[tmp_ms_xx_DocElectronicos] OFF;
    END

    DROP TABLE [dbo].[DocElectronicos];

    EXECUTE sp_rename N'[dbo].[tmp_ms_xx_DocElectronicos]', N'DocElectronicos';
    EXECUTE sp_rename N'[dbo].[tmp_ms_xx_constraint_PK_Documentos_Electronicos1]', N'PK_Documentos_Electronicos', N'OBJECT';

    COMMIT TRANSACTION;
END

SET TRANSACTION ISOLATION LEVEL READ COMMITTED;


GO
PRINT N'Creando Tabla [dbo].[DocElectronicos_DocRecursos]...';


GO
IF OBJECT_ID(N'dbo.DocElectronicos_DocRecursos', N'U') IS NULL
BEGIN
    CREATE TABLE [dbo].[DocElectronicos_DocRecursos] (
        [IdRecurso]   INT            NOT NULL,
        [IdDoc]       INT            NOT NULL,
        [Descripcion] NVARCHAR (100) NULL,
        [IdTipo]      INT            NULL,
        CONSTRAINT [PK_DocElectronicos_DocRecursos] PRIMARY KEY CLUSTERED ([IdRecurso] ASC, [IdDoc] ASC)
    );
END


GO
PRINT N'Creando Clave externa [dbo].[FK_DocElectronicos_DocRecursos_DocElectronicos]...';


GO
IF OBJECT_ID(N'dbo.DocElectronicos_DocRecursos', N'U') IS NOT NULL
AND OBJECT_ID(N'dbo.DocElectronicos', N'U') IS NOT NULL
AND NOT EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = N'FK_DocElectronicos_DocRecursos_DocElectronicos' AND parent_object_id = OBJECT_ID(N'dbo.DocElectronicos_DocRecursos'))
BEGIN
    ALTER TABLE [dbo].[DocElectronicos_DocRecursos] WITH NOCHECK
        ADD CONSTRAINT [FK_DocElectronicos_DocRecursos_DocElectronicos] FOREIGN KEY ([IdDoc]) REFERENCES [dbo].[DocElectronicos] ([IdDoc]);
END


GO
PRINT N'Creando Clave externa [dbo].[FK_DocElectronicos_DocRecursos_Parametros_Recursos]...';


GO
IF OBJECT_ID(N'dbo.DocElectronicos_DocRecursos', N'U') IS NOT NULL
AND OBJECT_ID(N'dbo.Parametros_Recursos', N'U') IS NOT NULL
AND NOT EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = N'FK_DocElectronicos_DocRecursos_Parametros_Recursos' AND parent_object_id = OBJECT_ID(N'dbo.DocElectronicos_DocRecursos'))
BEGIN
    ALTER TABLE [dbo].[DocElectronicos_DocRecursos] WITH NOCHECK
        ADD CONSTRAINT [FK_DocElectronicos_DocRecursos_Parametros_Recursos] FOREIGN KEY ([IdRecurso]) REFERENCES [dbo].[Parametros_Recursos] ([IdRecurso]);
END


GO
PRINT N'Creando Función [dbo].[GetDigitoVerificacion]...';


GO
IF OBJECT_ID(N'dbo.GetDigitoVerificacion', N'FN') IS NOT NULL
    DROP FUNCTION [dbo].[GetDigitoVerificacion];

GO
CREATE FUNCTION [dbo].[GetDigitoVerificacion] (@identification VARCHAR(15))
RETURNS VARCHAR(2)
AS
BEGIN
    IF @identification IS NULL OR @identification LIKE '%[^0-9]%'
        RETURN NULL

    DECLARE @x INT = 0, @i INT = 1, @len INT = LEN(@identification), @d INT
    DECLARE @pesos TABLE (pos INT, peso INT)
    
    INSERT INTO @pesos VALUES
    (1,3),(2,7),(3,13),(4,17),(5,19),(6,23),(7,29),(8,37),
    (9,41),(10,43),(11,47),(12,53),(13,59),(14,67),(15,71)

    WHILE @i <= @len
    BEGIN
        SET @d = CAST(SUBSTRING(@identification, @i, 1) AS INT)
        SELECT @x += @d * peso FROM @pesos WHERE pos = @len - @i + 1
        SET @i += 1
    END

    DECLARE @r INT = @x % 11
    RETURN CAST(CASE WHEN @r > 1 THEN 11 - @r ELSE @r END AS VARCHAR(2))
END;
GO
PRINT N'Creando Procedimiento [dbo].[GenerarDocumentos]...';


GO
IF OBJECT_ID(N'dbo.GenerarDocumentos', N'P') IS NULL
    EXEC(N'CREATE PROCEDURE [dbo].[GenerarDocumentos] AS BEGIN SET NOCOUNT ON; RETURN 0; END');
GO
ALTER PROCEDURE GenerarDocumentos
    @IdDoc INT,
    @IdEncabNew INT OUTPUT,
    @Exito INT = 0 OUTPUT,
    @MensajeError NVARCHAR(200) OUTPUT
AS
BEGIN
    SET NOCOUNT ON;
    BEGIN TRY
        DECLARE @IdEncab INT;
        DECLARE @XML XML;
        DECLARE @NumeroFactura VARCHAR(50);
        DECLARE @FechaFactura DATE;
        DECLARE @ValorTotal DECIMAL(18,2);
        DECLARE @TipoDocumento VARCHAR(100);
        DECLARE @Mensaje VARCHAR(500);
        DECLARE @ResponseID VARCHAR(50);
        DECLARE @FacturaRef VARCHAR(50);
        
        -- Variables para datos del XML
        DECLARE @NitProveedor VARCHAR(50);
        DECLARE @NombreProveedor VARCHAR(200);
        DECLARE @CodigoMoneda VARCHAR(10);
        DECLARE @TipoFactura VARCHAR(10);
        DECLARE @UnidadMedida VARCHAR(10);
        DECLARE @DescripcionProducto VARCHAR(500);
        DECLARE @TipoIdentProveedor VARCHAR(10);
        
        -- Variables para dirección del cliente
        DECLARE @DireccionCliente VARCHAR(500);
        DECLARE @TelefonoCliente VARCHAR(50);
        DECLARE @EmailCliente VARCHAR(100);
        DECLARE @IdCiudadCliente VARCHAR(20);
        DECLARE @IdFormaPago VARCHAR(10);
        DECLARE @PlazoCliente INT;
        
        -- Variables para cálculos
        DECLARE @Cantidad DECIMAL(18,6);
        DECLARE @BaseImpuesto DECIMAL(18,2);
        DECLARE @ValorImpuesto DECIMAL(18,2);
        DECLARE @PorcentajeImpuesto DECIMAL(18,2);
        DECLARE @SubTotal DECIMAL(18,2);
        DECLARE @DescuentoTotal DECIMAL(18,2);
        DECLARE @FactorDescuento DECIMAL(18,6);

        -- Variables para datos del XML
        DECLARE @NitEmpresa VARCHAR(50);
        DECLARE @CiudadBodega VARCHAR(50);
        DECLARE @CodigoCiudad VARCHAR(10);

        DECLARE @IdTipoIdent INT;
        DECLARE @TaxLevelCode VARCHAR(200);
        DECLARE @IdTipoRegimen INT;

        -- Obtenemos el XML
        SELECT @XML = CAST(PR.Recurso AS XML)
        FROM dbo.DocElectronicos DE 
        INNER JOIN dbo.DocElectronicos_DocRecursos DR ON DE.IdDoc = DR.IdDoc 
        INNER JOIN dbo.Parametros_Recursos PR ON DR.IdRecurso = PR.IdRecurso
        WHERE DE.IdDoc = @IdDoc
        AND DR.IdTipo = 0;

        IF @XML IS NULL
        BEGIN
            RAISERROR('No se encontró el documento XML para el ID especificado.', 16, 1);
            RETURN;
        END;

        -- Verificamos el tipo de documento
        SET @TipoDocumento = @XML.value('local-name(/*[1])', 'varchar(100)');
        
        IF @TipoDocumento = 'ApplicationResponse'
        BEGIN
            WITH XMLNAMESPACES (
                'urn:oasis:names:specification:ubl:schema:xsd:ApplicationResponse-2' as ar,
                'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2' as cbc,
                'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2' as cac
            )
            SELECT 
                @ResponseID = @XML.value('(/ar:ApplicationResponse/cbc:ID)[1]', 'varchar(50)'),
                @FacturaRef = @XML.value('(/ar:ApplicationResponse/cac:DocumentResponse/cac:DocumentReference/cbc:ID)[1]', 'varchar(50)');

            SET @Mensaje = 'Este documento es un ApplicationResponse (ID: ' + ISNULL(@ResponseID, 'N/A') + 
                          ') que hace referencia a la factura: ' + ISNULL(@FacturaRef, 'N/A');
            RAISERROR(@Mensaje, 16, 1);
            RETURN;
        END;

        IF @TipoDocumento != 'Invoice'
        BEGIN
            SET @Mensaje = 'El documento no es una factura válida. Tipo de documento: ' + ISNULL(@TipoDocumento, 'Desconocido');
            RAISERROR(@Mensaje, 16, 1);
            RETURN;
        END;

        -- Extraemos todos los datos relevantes del XML
        WITH XMLNAMESPACES (
            'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2' as inv,
            'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2' as cbc,
            'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2' as cac
        )
        SELECT 
            -- Datos básicos del documento
            @NumeroFactura = @XML.value('(/inv:Invoice/cbc:ID)[1]', 'varchar(50)'),
            @FechaFactura = @XML.value('(/inv:Invoice/cbc:IssueDate)[1]', 'date'),
            @TipoFactura = @XML.value('(/inv:Invoice/cbc:InvoiceTypeCode)[1]', 'varchar(10)'),
            @CodigoMoneda = @XML.value('(/inv:Invoice/cbc:DocumentCurrencyCode)[1]', 'varchar(10)'),
            
            -- Datos de la empresa receptora (para determinar IdEmpresa)
            @NitEmpresa = @XML.value('(/inv:Invoice/cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cbc:CompanyID)[1]', 'varchar(50)'),
            
            -- Datos de ubicación (para determinar bodega)
            @CiudadBodega = @XML.value('(/inv:Invoice/cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:CityName)[1]', 'varchar(50)'),
            @CodigoCiudad = @XML.value('(/inv:Invoice/cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:ID)[1]', 'varchar(10)'),
            
            -- Datos del proveedor
            @NitProveedor = @XML.value('(/inv:Invoice/cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc:CompanyID)[1]', 'varchar(50)'),
            @NombreProveedor = @XML.value('(/inv:Invoice/cac:AccountingSupplierParty/cac:Party/cac:PartyName/cbc:Name)[1]', 'varchar(200)'),
            @TipoIdentProveedor = @XML.value('(/inv:Invoice/cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc:CompanyID/@schemeName)[1]', 'varchar(10)'),
            
            -- Datos del producto/servicio
            @UnidadMedida = @XML.value('(/inv:Invoice/cac:InvoiceLine/cbc:InvoicedQuantity/@unitCode)[1]', 'varchar(10)'),
            
            -- Datos del proveedor y su dirección
            @DireccionCliente = @XML.value('(/inv:Invoice/cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cac:AddressLine/cbc:Line)[1]', 'varchar(500)'),
            @TelefonoCliente = @XML.value('(/inv:Invoice/cac:AccountingSupplierParty/cac:Party/cac:Contact/cbc:Telephone)[1]', 'varchar(50)'),
            @EmailCliente = @XML.value('(/inv:Invoice/cac:AccountingSupplierParty/cac:Party/cac:Contact/cbc:ElectronicMail)[1]', 'varchar(100)'),
            @IdCiudadCliente = @XML.value('(/inv:Invoice/cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:ID)[1]', 'varchar(20)'),
            @IdFormaPago = @XML.value('(/inv:Invoice/cac:PaymentMeans/cbc:ID)[1]', 'varchar(10)'),
            
            -- Cantidades y valores
            @Cantidad = @XML.value('(/inv:Invoice/cac:InvoiceLine/cbc:InvoicedQuantity)[1]', 'decimal(18,6)'),
            --@ValorUnitarioItem = @XML.value('(/inv:Invoice/cac:InvoiceLine/cac:Price/cbc:PriceAmount)[1]', 'decimal(18,2)'),
            @BaseImpuesto = @XML.value('(/inv:Invoice/cac:TaxTotal/cac:TaxSubtotal/cbc:TaxableAmount)[1]', 'decimal(18,2)'),
            @ValorImpuesto = @XML.value('(/inv:Invoice/cac:TaxTotal/cac:TaxSubtotal/cbc:TaxAmount)[1]', 'decimal(18,2)'),
            @PorcentajeImpuesto = @XML.value('(/inv:Invoice/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:Percent)[1]', 'decimal(18,2)'),
            @SubTotal = @XML.value('(/inv:Invoice/cac:LegalMonetaryTotal/cbc:LineExtensionAmount)[1]', 'decimal(18,2)'),
            @DescuentoTotal = @XML.value('(/inv:Invoice/cac:LegalMonetaryTotal/cbc:AllowanceTotalAmount)[1]', 'decimal(18,2)'),
            @ValorTotal = @XML.value('(/inv:Invoice/cac:LegalMonetaryTotal/cbc:PayableAmount)[1]', 'decimal(18,2)'),

            @IdTipoIdent = @XML.value('(/inv:Invoice/cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc:CompanyID/@schemeName)[1]', 'int'),
            @TaxLevelCode = @XML.value('(/inv:Invoice/cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc:TaxLevelCode)[1]', 'varchar(50)'),
           

            @IdTipoRegimen =
            CASE
                WHEN @IdTipoIdent = 42 THEN 9 -- Tercero del Exterior
                WHEN @IdTipoIdent = 13 AND @TaxLevelCode LIKE '%O-15%' THEN 10 -- Gran Contribuyente Persona Natural
                WHEN @IdTipoIdent = 13 AND @TaxLevelCode = 'R-99-PN' THEN 6 -- Persona Natural No Responsable de IVA
                WHEN @IdTipoIdent = 13 THEN 2 -- Persona Natural Responsable de IVA
                WHEN @IdTipoIdent = 31 AND @TaxLevelCode LIKE '%O-15%' THEN 4 -- Gran Contribuyente
                WHEN @IdTipoIdent = 31 THEN 3 -- Persona Jurídica
                ELSE 6
            END

        -- Validamos que tengamos los datos mínimos necesarios
        IF @NumeroFactura IS NULL OR @FechaFactura IS NULL OR @ValorTotal IS NULL OR @NitProveedor IS NULL
        BEGIN
            RAISERROR('No se pudieron extraer todos los datos necesarios de la factura.', 16, 1);
            RETURN;
        END;

        -- Buscamos o creamos el proveedor si no existe
        DECLARE @IdCliente INT;
        SELECT TOP 1 @IdCliente = IdCliente 
        FROM Clientes 
        WHERE Identificacion = @NitProveedor;

        -- Validamos que el documento no exista
        IF EXISTS (
            SELECT 1 
            FROM Encabezados 
            WHERE NumDocumentoExt = @NumeroFactura
        )
        BEGIN
            RAISERROR('El documento %s ya existe en el sistema.', 16, 1, @NumeroFactura);
            RETURN;
        END;

        -- Si el cliente no existe, lo creamos junto con su dirección
        IF @IdCliente IS NULL
        BEGIN
            -- Calculamos el DV
            DECLARE @DVCliente VARCHAR(2);
            SET @DVCliente = dbo.GetDigitoVerificacion(@NitProveedor);

            -- Insertamos el cliente
            INSERT INTO Clientes (
                Identificacion,
                Nombre1,
                FechaCreacion,
                FechaUltModificacion,
                EsActivo,
                IdTipoIdent,
                DVCliente,
                IdTipoRegimen
            )
            VALUES (
                @NitProveedor,
                @NombreProveedor,
                GETDATE(),
                GETDATE(),
                1,
                @IdTipoIdent,
                @DVCliente,
                @IdTipoRegimen
            );
            
            SET @IdCliente = SCOPE_IDENTITY();

            -- Obtenemos el IdTipoDir mínimo
            DECLARE @IdTipoDir INT;
            SELECT @IdTipoDir = MIN(IdTipoDir) FROM Clientes_TiposDireccion;

            -- Insertamos la dirección del cliente
            INSERT INTO Clientes_Direcciones (
                IdCliente,
                IdTipoDir,
                Direccion,
                DireccionFormato1,
                DireccionFormato2,
                Telefonos,
                Celular,
                Email,
                IdCiudad,
                Nota,
                EsDirPrincipal,
                Subdivision,
                CodigoPostal
            )
            VALUES (
                @IdCliente,
                @IdTipoDir,
                @DireccionCliente,
                @DireccionCliente,
                @DireccionCliente,
                @TelefonoCliente,
                @TelefonoCliente,
                @EmailCliente,
                @IdCiudadCliente,
                NULL,
                1,
                NULL,
                NULL
            );

            -- Insertamos las asociaciones del cliente
            INSERT INTO Clientes_Asociacion (IdCliente, IdTipo) VALUES (@IdCliente, 5);
            INSERT INTO Clientes_Asociacion (IdCliente, IdTipo) VALUES (@IdCliente, 8);
        END;

        -- Obtenemos el IdClienteDir principal
        DECLARE @IdClienteDir INT;
        SELECT @IdClienteDir = MAX(idclientedir) 
        FROM Clientes_Direcciones 
        WHERE EsDirPrincipal = 1 AND IdCliente = @IdCliente;

        -- Obtenemos el plazo del cliente
        SELECT @PlazoCliente = ISNULL(CupoCreditoPlazo, 0) 
        FROM Clientes 
        WHERE IdCliente = @IdCliente;

        -- Buscamos el ID de la moneda
        DECLARE @IdMoneda INT;
        IF @CodigoMoneda = 'COP'
            SET @IdMoneda = 1; -- Asumimos que 1 es el ID para COP
        ELSE
        BEGIN
            SELECT TOP 1 @IdMoneda = IdMoneda
            FROM Monedas
            WHERE Abrev = @CodigoMoneda
            OR NomMoneda1 = @CodigoMoneda;

            IF @IdMoneda IS NULL
                SET @IdMoneda = 1; -- Default a COP si no se encuentra
        END;

        -- Buscamos el tipo de documento basado en el código DIAN
        DECLARE @IdDocumento INT;
        SELECT TOP 1 @IdDocumento = IdDocumento
        FROM Documentos
        WHERE FeIdDocumentoDian = @TipoFactura;

        IF @IdDocumento IS NULL
            SET @IdDocumento = 13; -- Default a Comprobante de Egreso si no se encuentra

        SET @FactorDescuento=0

        -- Calculamos el factor de descuento
        --SET @FactorDescuento = CASE 
        --    WHEN @SubTotal > 0 THEN (@DescuentoTotal / @SubTotal) * 100
        --    ELSE 0
        --END;

        -- Buscamos la empresa por su NIT
        DECLARE @IdEmpresa INT;
        SELECT TOP 1 @IdEmpresa = IdEmpresa
        FROM Empresas
        WHERE EmpresaNit = @NitEmpresa;

        IF @IdEmpresa IS NULL
        BEGIN
            RAISERROR('No se encontró la empresa con NIT: %s', 16, 1, @NitEmpresa);
            RETURN;
        END;

        -- Buscamos la bodega por su ubicación
        DECLARE @IdBodega INT = -1; -- Valor por defecto
        /*
        SELECT TOP 1 @IdBodega = IdBodega
        FROM Bodegas
        WHERE Ciudad = @CiudadBodega;

        IF @IdBodega IS NULL
        BEGIN
            -- Si no encontramos la bodega, creamos una nueva
            INSERT INTO Bodegas (
                Ciudad,
                Descripcion,
                FechaCreacion,
                FechaUltModificacion,
                EsActivo
            )
            VALUES (
                @CiudadBodega,
                'Bodega en ' + @CiudadBodega,
                GETDATE(),
                GETDATE(),
                1
            );
            
            SET @IdBodega = SCOPE_IDENTITY();
        END;
        */

        -- Insertar en Encabezados
        INSERT INTO Encabezados (
            IdEmpresa,
            IdDocumento,
            NumDocumentoExt,
            Fecha,
            IdCliente1,
            IdCliente1_IdDir,
            IdMoneda,
            ValorTRM,
            FechaCreacion,
            FechaUltModificacion,
            Nota,
            IdFormaPago,
            Vence
        )
        VALUES (
            @IdEmpresa,
            CASE 
                WHEN EXISTS (SELECT 1 FROM DocElectronicos WHERE IdDoc = @IdDoc AND TipoDoc = 'Factura electrónica')
                THEN 1
                ELSE @IdDocumento
            END,
            @NumeroFactura,
            @FechaFactura,
            @IdCliente,
            @IdClienteDir,
            @IdMoneda,
            0,                  -- ValorTRM siempre 0
            GETDATE(),
            GETDATE(),
            'Importado automáticamente',
            @IdFormaPago,
            DATEADD(day, @PlazoCliente, @FechaFactura)
        );

        SET @IdEncab = SCOPE_IDENTITY();


        --*************************************************************************
		--ITERAR ITEMS
        DECLARE @TotalItems INT
        DECLARE @Index INT = 1
        DECLARE @IdInventario INT;
        DECLARE @IdUnidad INT = 1; -- Valor por defecto
        DECLARE @CodInventario VARCHAR(50);
        DECLARE @CodInventario2 VARCHAR(50);
        DECLARE @NomInventario VARCHAR(500);
        DECLARE @ValorUnitario NUMERIC(18,2);

        -- Contar cuántos nodos hay
		WITH XMLNAMESPACES (
			'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2' AS inv,
			'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2' AS cac,
			'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2' AS cbc
		)
		SELECT @TotalItems = @XML.value('count(/inv:Invoice/cac:InvoiceLine)', 'int')
        PRINT '@TotalItems: ' + CONVERT(VARCHAR, @TotalItems)


        -- Bucle para procesar cada uno
        WHILE @Index <= @TotalItems
        BEGIN
            -- Extraer valores del XML
            WITH XMLNAMESPACES (
                'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2' AS inv,
                'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2' AS cac,
                'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2' AS cbc
            )
            SELECT
                @CodInventario = @XML.value('(//inv:Invoice/cac:InvoiceLine[position()=sql:variable("@Index")]/cbc:ID)[1]', 'varchar(20)'),
                @CodInventario2 = @XML.value('(//inv:Invoice/cac:InvoiceLine[position()=sql:variable("@Index")]/cac:Item/cac:StandardItemIdentification/cbc:ID)[1]', 'varchar(20)'),

                --@NomInventario = @XML.value('(//inv:Invoice/cac:InvoiceLine[position()=sql:variable("@Index")]/cbc:Note)[1]', 'varchar(100)'),
                @NomInventario = @XML.value('(//inv:Invoice/cac:InvoiceLine[position()=sql:variable("@Index")]/cac:Item/cbc:Description)[1]', 'varchar(500)'),

                @Cantidad = @XML.value('(//inv:Invoice/cac:InvoiceLine[position()=sql:variable("@Index")]/cbc:InvoicedQuantity)[1]', 'decimal(18,2)'),
                @ValorTotal = @XML.value('(//inv:Invoice/cac:InvoiceLine[position()=sql:variable("@Index")]/cbc:LineExtensionAmount)[1]', 'decimal(18,2)'),
                @ValorUnitario = @XML.value('(//inv:Invoice/cac:InvoiceLine[position()=sql:variable("@Index")]/cac:Price/cbc:PriceAmount )[1]', 'numeric(18,2)');

            
            SET @CodInventario = COALESCE(@CodInventario, @CodInventario2);

            --Obtener el id del inventario
            --//
            SELECT TOP 1 @IdInventario = IdInventario FROM Inventarios WHERE CodInventario = @CodInventario;
            IF @IdInventario IS NULL
            BEGIN
                -- Aquí deberíamos insertar el nuevo producto
                INSERT INTO Inventarios (
                    CodigoBarras,
                    NomInventario,
                    CodInventario,     -- Campo obligatorio
                    FechaCreacion,
                    FechaUltModificacion,
                    EsActivo,
                    IdUnidad,          -- Campo probablemente obligatorio
                    ValorIva,          -- Campo probablemente obligatorio
                    IdTipoInv         -- Campo probablemente obligatorio
                )
                VALUES (
                    @CodInventario,
                    @DescripcionProducto,
                    @CodInventario,    -- Usamos el mismo código como CodInventario
                    GETDATE(),
                    GETDATE(),
                    1,
                    1,                  -- IdUnidad por defecto
                    0,                  -- ValorIva por defecto
                    1                   -- IdTipoInv por defecto
                );
            
                SET @IdInventario = SCOPE_IDENTITY();
            END;
            --//


            -- Insertar movimiento inventario
            INSERT INTO Encabezados_Mov (
                IdEncab,
                IdInventario,
                IdBodega,
                IdLote,
                Cantidad,
                CantidadFisica,
                IdUnidad,
                FactorCantidad,
                FactorMovim,
                ValorUnitario,
                ValorUnitarioExt,
                ValorIva,
                ValorImptoConsumo,
                TotalMov,
                IdCliente,
                Nota,
                Vence,
                IdCentroCosto,
                Dcto
            )
            VALUES (
                @IdEncab,
                @IdInventario,     -- Ya era dinámico
                @IdBodega,         -- Ahora dinámico basado en la ubicación
                NULL,              -- IdLote
                @Cantidad,         -- Ya era dinámico
                NULL,              -- CantidadFisica
                @IdUnidad,         -- Ya era dinámico
                @Cantidad,         -- Ya era dinámico
                1,                 -- FactorMovim
                @ValorUnitario,    -- Ya era dinámico
                NULL,              -- ValorUnitarioExt
                @PorcentajeImpuesto, -- Ya era dinámico
                0.000000,          -- ValorImptoConsumo
                @ValorTotal,       -- Ya era dinámico
                @IdCliente,        -- Ya era dinámico
                'Factura XML: ' + @NumeroFactura + ' - ' + @DescripcionProducto,
                NULL,              -- Vence
                NULL,              -- IdCentroCosto
                @FactorDescuento   -- Ya era dinámico
            );

            SET @Index = @Index + 1
        END

        -- Retornamos el ID del encabezado creado
        SELECT @IdEncab as IdEncabezado;
        SET @IdEncabNew = @IdEncab;

        --Contabilizar Documento
        --//
        EXEC [dbo].[ContabilizarDoc] @IdEncab = @IdEncab, @Exito = @Exito OUTPUT, @InfoUsuario = N'0,--BASEDATOS--';
        --//

        SET @Exito = NULL
    END TRY
    BEGIN CATCH
        DECLARE @ErrorMsg NVARCHAR(4000) = ERROR_MESSAGE();
        RAISERROR(@ErrorMsg, 16, 1);
    END CATCH;
END;
GO
	/*
	Plantilla de script posterior a la implementación							
	--------------------------------------------------------------------------------------
	 Este archivo contiene instrucciones de SQL que se anexarán al script de compilación.		
	 Use la sintaxis de SQLCMD para incluir un archivo en el script posterior a la implementación.			
	 Ejemplo:      :r .\miArchivo.sql								
	 Use la sintaxis de SQLCMD para hacer referencia a una variable en el script posterior a la implementación.		
	 Ejemplo:      :setvar TableName miTabla							
				   SELECT * FROM [$(TableName)]					
	--------------------------------------------------------------------------------------
	*/

	--ACTUALIZACION NORMATIVA NOMINA 2025 
UPDATE Parametros SET ValParametro = 220  Where CodParametro = 47 

--ACTUALIZACION 'Tributos' = 'No Aplica' a clientes del sistema

INSERT INTO Clientes_Tributos (IdCliente, IdTipo)
SELECT c.IdCliente, 6
FROM Clientes c
WHERE 
c.EsEspecial = 1 AND 
NOT EXISTS 
(
	SELECT 1
	FROM Clientes_Tributos ct
	WHERE 
	ct.IdCliente = c.IdCliente AND 
	ct.IdTipo = 6
)

--ACTUALIZACION 'Responsabilidad Fiscal' =  'Agente de Retención IVA' a clientes del sistema

INSERT INTO Clientes_ResponFiscal (IdCliente, IdResFiscal)
SELECT c.IdCliente, 14
FROM Clientes c
WHERE 
c.EsEspecial = 1 AND 
NOT EXISTS 
(
	SELECT 1
	FROM Clientes_ResponFiscal ct
	WHERE 
	ct.IdCliente = c.IdCliente AND 
	ct.IdResFiscal = 14
)

--ACTUALIZACION NORMATIVA HORAS EXTRAS REFORMA LABORAL  80%

update Nomina_Items set DivParteSuperior = 1.80,  PorcRecargo = 1.80 WHERE IdItem=106
GO

GO
PRINT N'Comprobando los datos existentes con las restricciones recién creadas';


GO



GO
ALTER TABLE [dbo].[DocElectronicos_DocRecursos] WITH CHECK CHECK CONSTRAINT [FK_DocElectronicos_DocRecursos_DocElectronicos];

ALTER TABLE [dbo].[DocElectronicos_DocRecursos] WITH CHECK CHECK CONSTRAINT [FK_DocElectronicos_DocRecursos_Parametros_Recursos];


GO
PRINT N'Actualización completada.';


GO


--Actualizar datos de la version

IF NOT EXISTS (SELECT 1 FROM dbo.ZiurVersiones WHERE NumVersion = 969)
BEGIN
    INSERT INTO dbo.ZiurVersiones (IdVersion, NumVersion, Descripcion)
    VALUES (379, 969, 'Actualizacion Tributos, Responsabilidad Fiscal, HORAS EXTRAS 80%, NORMATIVA NOMINA 2025 ');
END
GO
/* Liberar bloqueo exclusivo por base de datos */
DECLARE @__ZiurDbScriptLockResourceEnd NVARCHAR(200) = N'ZiurSoft:DbScriptLock:' + CAST(DB_ID() AS NVARCHAR(20));
EXEC sp_releaseapplock
    @Resource = @__ZiurDbScriptLockResourceEnd,
    @LockOwner = N'Session';
GO
