Todos sabemos que personalizar el diseño de un Report en Microsoft Dynamics AX puede realizarse de diferentes formas y que, un mismo cambio puede resultar completamente diferente dependiendo de la versión del ERP sobre la que estemos desarrollando. Más si cabe, tratándose de la nueva versión Microsoft Dynamics 365 for Finance and Operations. Una versión en la que cualquier personalización realizada en el pasado resulta en una nueva aventura y multiplica exponencialmente el tiempo de desarrollo empleado.

Hoy en día Microsoft, al igual que nuestros clientes, abogan cada vez más por respetar el estándar y, aunque personalizar los diseños de los informes proporcionados por el ERP se hace inevitable, existe la posibilidad de utilizar la llamada “Gestión de Impresión”, la cual nos permite extraer la información deseada ya sea a través de nuestros reports personalizados o los que ofrece el estándar, sin prescindir de ninguno de ellos.

Hasta el momento, todo lo comentado es ya conocido por muchos de nosotros. Sin embargo, la primera vez que quise aplicar esta teoría sobre la nueva versión del ERP, encontré un sinfín de obstáculos debido a los cambios en el desarrollo y la escasa información existente en ese momento sobre esta nueva versión. Y es precisamente este conocimiento adquirido el que quiero compartir con todos vosotros, y que a día de hoy resulta complicado de encontrar. Y aunque, como dije al principio de este artículo, existen diferentes formas de hacerlo, aquí os presento un ejemplo de una de ellas:

  • En primer lugar, sobre nuestro proyecto de Visual Studio, debemos crear un duplicado del report que deseamos personalizar. Para nuestro ejemplo, haremos un duplicado del report estándar SalesPackingSlip (Packing Slip o Albarán de Ventas), al cual llamaremos AXZSalesPackingSlip.
  • Realizaremos las modificaciones de diseño que consideremos oportunas sobre el nuevo report en base a nuestras necesidades.
  • Crearemos una nueva clase llamada AXZSalesPackingSlipController que extenderá de la clase Controller correspondiente al Albarán estándar (SalesPackingSlipController), y la cual tendrá sus propios métodos Construct y Main que utilizaremos para llamar al nuevo report AXZSalesPackingSlip. El código de esta nueva clase podría ser el siguiente:​ 
public class AXZSalesPackingSlipController extends SalesPackingSlipController
{
         public static AXZSalesPackingSlipController construct()
         {
                  return new AXZSalesPackingSlipController();
         }
         public static void main(Args _args)
         {
                  SrsReportRunController             formLetterController =
       AXZSalesPackingSlipController::construct();
                  AXZSalesPackingSlipController      controller;
                  controller = formLetterController;
                  controller.initArgs(_args, ssrsReportStr(AXZSalesPackingSlip, Report));
                  if (classIdGet(_args.caller()) == classNum(SalesPackingSlipJournalPrint))
                  {
                          formLetterController.renderingCompleted +=
eventhandler(SalesPackingSlipJournalPrint::renderingCompleted);
                  }
                  formLetterController.parmDialogCaption(«@SYS24163»);
                  formLetterController.startOperation();
         }
         }
}
  • Crearemos una extensión del menú ítem de tipo Output llamado SalesPackingSlip, y lo llamaremos SalesPackingSlip.Extension_AXZSalesPackingSlip. Abriremos el nuevo menú ítem para que nos permita acceder a sus propiedades, y sobre la propiedad Object incluiremos el nombre de nuestra nueva clase Controller (AXZSalesPackingSlipController).
  • Para poder utilizar la mencionada Gestión de Impresión sobre nuestros diseños personalizados, manteniendo la posibilidad de seguir utilizando el diseño estándar, deberemos hacer una extensión de tipo Chain Of Command sobre la clase PrintMgmtReportFormatSubscriber y agregar en ella código nuevo que nos permita generar el registro necesario sobre la tabla PrintMgmtReportFormat que nos permita encontrar cada nuevo Report que queramos utilizar con dicha gestión de impresión. A nuestra nueva clase la llamaremos AXZPrintMbmtReportFormatSubscriber_Extension:
[ExtensionOf(classStr(PrintMgmtReportFormatSubscriber))]
final class AXZPrintMbmtReportFormatSubscriber_Extension
{
    public server static void populate()
    {
        #PrintMgmtSetup
       
        // New method to Register your Custom New Report to PrintMgmtReportFormat table
        void axzADD(PrintMgmtDocumentType _type,
                PrintMgmtReportFormatName _name,
                PrintMgmtReportFormatDescription _description,
                PrintMgmtReportFormatCountryRegionId _countryRegionId,
                PrintMgmtReportFormatSystem _system,
                PrintMgmtSSRS _ssrs = PrintMgmtSSRS::SSRS)
        {
            PrintMgmtReportFormat printMgmtReportFormat;
            boolean isDuplicateFound;
            boolean isSystemFormatWithDifferentDescriptionFound;
            #PrintMgmtSetup
            ttsbegin;
            isSystemFormatWithDifferentDescriptionFound = _system && (select firstOnly RecId
from printMgmtReportFormat
where printMgmtReportFormat.DocumentType == _type    &&
      printMgmtReportFormat.Description != _description &&
      printMgmtReportFormat.System == true).RecId != 0;
            // If the format no longer matches up with the existing system formats, change them all to
            // non-system formats. This ensure existing links / setup will not be broken, but also provides
            // a way for the user to fix the formats.
            if (isSystemFormatWithDifferentDescriptionFound)
            {
                update_recordSet printMgmtReportFormat
                setting System = false
                where printMgmtReportFormat.DocumentType == _type
                    && printMgmtReportFormat.Description != _description
                    && printMgmtReportFormat.System    == true;
            }
            isDuplicateFound = (select RecId from printMgmtReportFormat
            where printMgmtReportFormat.DocumentType           == _type
                && printMgmtReportFormat.Description           == _description
                && printMgmtReportFormat.CountryRegionId == _countryRegionId).RecId != 0;
            if (isDuplicateFound)
            {
                if (isSystemFormatWithDifferentDescriptionFound)
                {
                    // We must ensure that the system report always matches the country context
                    // of the company. If the the country context has been chagned multiple times
                    // such that the report format already exists, we must change it back to system.
                    update_recordSet printMgmtReportFormat
                    setting System = true
                    where printMgmtReportFormat.DocumentType == _type
                        && printMgmtReportFormat.Description == _description
                        && printMgmtReportFormat.CountryRegionId == _countryRegionId;
                }
            }
            else
            {
                // Add the new format
                printMgmtReportFormat.clear();
                printMgmtReportFormat.DocumentType = _type;
                printMgmtReportFormat.Name = _name;
                printMgmtReportFormat.Description = _description;
                printMgmtReportFormat.CountryRegionId = _countryRegionId;
                printMgmtReportFormat.System = _system;
                printMgmtReportFormat.ssrs = _ssrs;
                printMgmtReportFormat.insert();
            }
            ttscommit;
        }
        next populate();
        // Add here your Custom New Report
        axzADD(PrintMgmtDocumentType::SalesOrderPackingSlip,
               ssrsReportStr(AXZSalesPackingSlip, Report),
               ssrsReportStr(AXZSalesPackingSlip, Report),
               #NoCountryRegionId,
               false,
               PrintMgmtSSRS::SSRS);
    }
}

  • Como podréis comprobar en el código anterior, una vez extendida la clase PrintMgmtReportFormatSubscriber, bastará con añadir bajo la sentencia “next populate();”, para cada nuevo report personalizado a registrar en la gestión de impresión, la llamada a nuestro método axzADD pasando como parámetros la información correspondiente a dicho report.
  • Para finalizar, bastará con ir al espacio de trabajo y configurar la gestión de impresión correspondiente al albarán (sales order packing slip) del módulo de clientes, pudiendo configurar la impresión de albaranes de tipo original y/o copias utilizando el diseño estándar o personalizado según deseemos:

Generación de formatos de impresión personalizados en D3FO Axazure

Una vez terminada la configuración anterior, podremos imprimir el albarán estándar o personalizado correspondiente según elijamos la opción Copy Preview, Original Preview o Use print management (imagen extraída del diario de albaranes en el módulo de clientes):

Generación de formatos de impresión personalizados en D3FO Axazure

About the Author: Javier Ríos

Generación de formatos de impresión personalizados en D3FO Axazure

¿Quieres compartir?