A menudo los clientes que tienen implementado Microsoft Dynamics AX 2012 en México solicitan poder crear vínculos con sistemas externos.

El escenario que expondré hoy, es validar una Factura Electrónica por medio de un servicio web externo de un Proveedor De Certificación De Factura.

El Servicio de Administración Tributaria en México ofrece una lista de proveedores de este tipo. El cliente en cuestión será encargado de contratar el servicio de acuerdo a sus necesidades.

Para este artículo se trabajó con uno en particular, el cual por medio de un servicio web recibía archivos XML en formato binario (base64Binary).

Dynamics AX ofrece una clase de sistema para poder manejar datos binarios como imágenes u objetos serializados:

https://docs.microsoft.com/en-us/previous-versions/dynamics/ax-2012/system-classes/gg820660(v%3dax.60)

Binary Class

Syntax X++

class Binary extends Object

 

Prerrequisitos

Microsoft Visual Studio 2010.

Visual Studio Tools para Microsoft Dynamics AX 2012.

Crear y agregar la referencia de servicio

Se crea la referencia de servicio y se agrega al AOT en Visual Studio utilizando las herramientas de Visual Studio para Microsoft Dynamics AX 2012.

 ​WebService01.jpg

Crear la referencia de servicio.

Abrimos Visual Studio 2010 y luego creamos un nuevo proyecto de biblioteca de clases de Visual C #.

El proveedor habrá proporcionado un link a su servicio web público el cual generalmente está protegido por medio de contraseñas, Visual Studio importa el Web Services Description Language y crea las referencias.

Seleccionamos el proyecto ServiceReferences. En las Propiedades, verificamos que los parámetros estén configurados como se muestra en la siguiente tabla.

Propiedad
Implementar al cliente
Implementar en EPNo
Implementar en el servidor

 

 WebService02.jpg

A continuación, hacemos clic derecho en el nombre del proyecto y luego haga clic en Agregar a AOT.

WebService03.jpg

Para verificar la referencia de servicio. 

  1. En el cliente de Microsoft Dynamics AX, abrimos el Área de trabajo del desarrollador.
  2. En el AOT, vaya a Proyectos de Visual Studio > Proyectos de C Sharp para ver ServiceReferences.

La referencia de servicio está disponible cuando el proyecto se ha agregado correctamente al AOT.

 WebService04.jpg

Creando una instancia de un cliente de servicio 

Para usar el servicio web, debemos programar el código en Microsoft Dynamics AX para permitir que la referencia del servicio se construya y se configure una instancia de un cliente de servicio.

 

public void validateCFDI()

{

    ClrObject                                           clientType;

    //La clase del servicio web externo estará disponible en X++

    PacServicesClient    serviceClient;

    ;

 

    // La seguridad de acceso al código (CAS) ayuda a proteger las API que tienen riesgos de    

    seguridad potenciales cuando las API se ejecutan en el servidor.

 

    Las API habilitadas para CAS llamadas en el servidor requieren el uso de una clase de

    permiso, una de las clases derivadas de CodeAccessPermission.

    new InteropPermission(InteropKind::ClrInterop).assert();

    try

    {

    // La seguridad del servicio web del cliente se puede parametrizar y se manda llamar más

    adelante

        this.parmUser(PurchParameters::find().EIGOUserWS);

        this.parmPassword(PurchParameters::find().EIGOPassword);

 

        if(!this.parmUser() || !this.parmPassword())

        {

            throw error('Favor de configurar los parámetros de Servicio Web en Cuentas por Pagar');

        }

 

        // Habilitamos TLS 1.2

        System.Net.ServicePointManager::set_Expect100Continue(true);

        System.Net.ServicePointManager::set_SecurityProtocol(System.Net.SecurityProtocolType::Tls12);

 

        if(this.parmFileContainer())

        {

        // utilizamos un objeto System.Byte[] oByte;

            oByte = EIGOHelper::convertContainerToBytes(this.parmFileContainer());

        }

        else if(this.parmFilePath())

        {

            oByte = EIGOHelper::convertFileToBytes(this.parmFilePath());

        }

        encoding = System.Text.Encoding::get_Default();

        clientType = CLRInterop::getType("PacServicesClient");

        serviceClient = AifUtil::CreateServiceClient(clientType);

 

        switch(this.parmCFDIVersion())

        {

            case EIGOCFDIVersion::v32:

                retVal = encoding.GetString(serviceClient.validaComprobanteV32(this.parmUser(), this.parmPassword(), oByte));

                break;

            case EIGOCFDIVersion::v33:

                retVal = encoding.GetString(serviceClient.validaComprobanteV33(this.parmUser(), this.parmPassword(), oByte));

                break;

        }

        // En la mayoría de los casos los códigos de error de los servicios web externos vienen

        en la documentación, estos no permitirán enviar un mensaje de error según sea el caso

        hacia el usuario final

        if(!retVal)

        {

            throw error('No se obtuvo respuesta del servicio');

        }

 

        if(strLen(retVal) > 16)

        {

            key = subStr(retVal, 63);

            switch(key)

            {

                case 'V00':

                    info('El documento XML pasó correctamente la validación por medio del servicio web');

                    break;

                default:

                    throw error(retVal);

            }

        }

    }

    catch(Exception::CLRError)

    {

        ex = CLRInterop::getLastException();

        info(ex.ToString());

    }

    CodeAccessPermission::revertAssert();

}

 

 

Para el caso de los métodos que convertirán a objeto System.Byte[] utlizamos Binary Class:

 

public static System.Byte[] convertFileToBytes(str filePath)

{

    System.IO.FileStream    fileStream;

    System.IO.MemoryStream  memoryStream = new System.IO.MemoryStream();

    int                     size;

 

    Binary                  assemblyBinary;

    System.IO.MemoryStream  memStream;

    System.Byte[]           bytes;

 

    if (filePath)

    {

        try

        {

            new InteropPermission(InteropKind::ClrInterop).assert();

            //Leer el contenido del archivo

            fileStream = System.IO.File::OpenRead(filePath);

            size = fileStream.get_Length();

            memoryStream.SetLength(size);

            fileStream.Read(memoryStream.GetBuffer(), 0, size);

            //Utilización de la clase de sistema Binary

            assemblyBinary = Binary::constructFromMemoryStream(memoryStream);

 

            memStream       = assemblyBinary.getMemoryStream();

            bytes           = memStream.ToArray();

            memStream.Close();

 

            CodeAccessPermission::revertAssert();

 

        }

        catch (Exception::CLRError)

        {

            SRSProxy::handleClrException(Exception::Error);

        }

        //Regresamos el objeto bytes

        return bytes;

    }

 

    return null;

}

 

 

De esta forma el binario puede servir como una interfaz simple entre AX (usando contenedores) y flujos de datos en un entorno .NET.

Al final es posible la validación del documento por medio del servicio web externo con reglas de negocio codificadas en Dynamics AX.

Espero que este artículo les sea de utilidad, si quieren aprender más sobre desarrollo de aplicaciones, desarrollo en Dynamics o de Dynamics en general por favor visita nuestro site de Eigo Academy para conocer nuestra oferta de cursos.​