Planes de formación gratuíta para certificados funcionales en Dynamics Finance & Operations

Hace poco estube buscando formación para preparar los exámenes de la certificación oficial en Dynamics 365 Finance and Operations y, en mi opinión, los planes de formación gratuítos disponibles en Microsoft Learn son la mejor opción, ya que se mantienen actualizados al mismo ritmo que los exámenes.

Dejo por aquí una lista de los más recomendables para cada examen, de momento solo he usado la primera lista para aprobar el MB-300, lo demás es lo que pretendo utilizar para preparar el resto de ellos.

MB-300 – Exam MB-300: Microsoft Dynamics 365 Unified Operations Core

MB-310 – Microsoft Certified: Dynamics 365 for Finance and Operations, Financials Functional Consultant Associate

MB-320 – Microsoft Certified: Dynamics 365 for Finance and Operations, Manufacturing Functional Consultant Associate

MB-330 – Microsoft Certified: Dynamics 365 for Finance and Operations, Supply Chain Management Functional Consultant Associate

Leer Más >>

Acceptance Test Libraries (ATL) para Dynamics 365 for Finance and Operations

Uno de los anuncios más emocionantes de los últimos meses (y no es poco decir, con lo rápido que avanzamos tras el OneVersion) para programadores de Microsoft Dynamics 365 for Finance and Operations es la ATL. Esta es la librería que el equipo de producto utiliza para desarrollar sus propios test (unitarios o, mejor, de integración) funcionales. El framework de Unit Testing existe desde hace tiempo en Dynamics AX, pero era complicado utilizarlo debido a la complejidad de mantener los datos necesarios para la ejecución de las pruebas y permitir la creación de pruebas deterministas. Esa librería se ha publicado en el PU27 aunque solo una pequeña parte. En el PU28 que esta a día de hoy en el programa de preview se han liberado muchas más clases, y algunos ejemplos, a los que voy a echar un vistazo aquí para ver de qué hablamos. La documentación está en el siguiente enlace. De momento hay una buena introducción teórica aunque no muchos ejemplos, actualizaré este post cuando la cosa mejore: De momento, quiero comentar por encima los ejemplos publicados en la preview del PU28:
Como decía, el principal problema de desarrollar pruebas de integración (pruebas funcionales por código) en versiones anteriores era lo desproporcionadamente complejo que resultaba mantener el juego de pruebas. ¿Qué ocurre si podemos ejecutar test deterministas en, prácticamente, cualquier entorno? Pues eso mejoraría las cosas bastante. ¿Qué pasa si además tengo cientos de clases helper para crear estos datos y comprobar los resultados? Pues tendría prácticamente resuelto todo el problema, ¿verdad? Bueno, quizás no tanto. Pero, por ejemplo, la creación de un pedido de ventas (con sus artículos, inventario, cliente, almacenes, ...) en puro X++ plano nos llevaría probablemente decenas o cientos de líneas de código. Este es el código publicado en los primeros ejemplos que se han liberado esta semana:
// Create sales order line
var salesOrderLine = salesOrder.addLine() // Add a new line on the sales order
    .setItem(item)                        // Using standard cost item
    .setQuantity(SalesQuantity)           // Set the sales quantity
    .setInventDims([warehouse])           // Using default warehouse - site will be defaulted based on warehouse the same way as in the UI
    .setPrice(UnitPrice)                  // Set the price
    .setDeliverNow(PackingSlipQuantity)   // Set the quantity that should be delivered
    .save();                              // Save the sales order line
Esta sintáxis fluida para la creación de las entidades que necesitamos para las pruebas es posible gracias a la gran cantidad de clases que incluyen esta librería y que facilitan estas acciones. En la clase original se crean valores por defecto para los objetos secundarios como el artículo o el almacén, así como variables para las cantidades (que luego debemos comprobar en el siguiente paso). Bien, con esto creamos el pedido. Pero queremos comprobar que el pedido es correcto. ¡Esto es un test, aquí hemos venido a comprobar! No hay problema:
// Validate that we have one inventory transaction for the sales order line
salesOrder.lines().firstEntity().inventoryTransactions().assertExpectedLinesSet(AtlSpecifications::construct()
    .addSpec(inventoryTransactions.spec()      // Add one specification to the expected results
        .withItem(item)                        // Item should be the same as on the sales order line
        .withQty(-SalesQuantity)               // The quantity should be the same as the sales quantity
        .withStatusIssue(StatusIssue::OnOrder) // The status should be on order
        .withInventDims([warehouse]))          // The warehouse should be the same as on the sales order line
    , 'Inventory transactions after creating the sales order.');
Así de sencillo resulta validar que la acción anterior ha hecho lo que debería hacer (crear transacciones de cliente con los valores apropiados). Fácil, ¿no? Quería compartir esto en modo de introducción a la librería, pero seguro que vuelvo por aquí con más detalles y mejores ejemplos. Las pruebas son una parte fundamental de la estrategia OneVersion, y el desarrollo de Tests va a ser fundamental en los próximos meses para el éxito de los proyectos. Volveré también con el resto de las herramientas disponibles para Testing en F&O. De momento tienes una introducción rápida en el vídeo de mi charla del pasado Dynamics Saturday.
Leer Más >>

Dynamics 365 Saturday – Madrid 2019

El pasado sábado 25 de mayo tuvo lugar el Dynamics 365 Saturday - Madrid 2019 en las oficinas de Microsoft. Tras la buena experiencia del año pasado, no podía perdérmelo. El crecimiento del evento ha sido impresionante, con más de 400 asistentes es uno de los 365 Saturday más grandes del mundo, y tanto la calidad de las ponencias como la repuesta de los asistentes ha sido alucinante. Comparto como siempre mi sesión sobre OneVersion y actualización continua, un tema muy interesante tras el lanzamiento de la versión de Abril de Dynamics 365, que sigue evolucionando rápidamente. Aquí el vídeo:
https://www.youtube.com/watch?v=zF_9ms46CPI Y las slides compartidas por la organización: https://www.slideshare.net/DemianRaschkovan/dynamics-saturday-madrid-2019-jose-antonio-estevan-share Aprovecho para comentar que esta semana se han publicado novedades sobre OneVersion y el ritmo de actualización continua que modifican el plan que conté en la sesión, así que aquí teneis las últimas novedades, que se resumen en:
  • Se va a permitir pausar hasta 3 actualizaciones (eran 2)
  • Se van a publicar 8 actualizaciones al año (siendo 2 el mínimo que se deben implementar por año)
  • Se van a publicar hotfixes para la versión actual y la anterior (y no solo la última)a
En resumen, a quienes pudieron pasarse al evento, gracias por venir; y en cualquier caso, ¡nos vemos el año que viene! Foto de la sala con el gran Manel Querol, justo antes de empezar.
Leer Más >>

Release your Dynamics 365 for Finance and Operation packages to LCS with Azure DevOps Pipelines [EN]

The first automation task to close the continuous integration cycle in Dynamics 365 for Finance and Operations with Azure DevOps pipelines was released recently as described on the official announcement. These are some high-level instructions to set it up while the official documentation is released:  

Prerequisites

To keep things simple, these prerequisites should be prepared before starting this process: Also prepare:
  • A user with enough permissions in your LCS project (you must know the user and password). Consider using a service account whose password does not expire and not using 2FA.
  • Access to the Azure Active Directory administration of your organization, with permissions to create the API connection (this needs to be done only once), as explained on the next step.
 

Register an Application in AAD

In order to authorize DevOps Pipelines to connect to the new Lifecycle Services (LCS) API, an application must be created in the Azure Active Directory of the organization. Elevated permissions are required for this operation.
  • Go to portal.azure.com and search or navigate to Azure Active Directory.
  • Navigate to the menu Manage > App registrations > New application registration.
    • Provide a name for the new application.
    • Select Application Type: Native.
    • Use any value as Redirect URI (for example: http://localhost).
  • Open the newly created app and click Settings.
  • Save the Application ID value, we will need it on the next steps.
  • Navigate to Required permissions > +Add.
  • Click Select an API and search for Dynamics Lifecycle services API, then Select and Done.
  • Click Grant permissions (this is a critical step, be sure you get a “Successfully granted permissions for application XXX” message or integration will not work).
More information about registering applications in AAD here: And about permission consent here:  

Create the Azure Release Pipeline

A release pipelines will be used to connect the Build output with the Asset Library in LCS. New build packages will be uploaded to LCS automatically through this pipeline.
  • Login to your organization's Azure DevOps project and navigate to Pipelines > Releases.
  • Click New release pipeline (this is the only option if you don’t have any pipeline already created).
  • Select a template: Empty job.
  • Click on Artifacts > +Add an artifact (this will connect this release pipeline with our Build).
  • Select Build as Source type, and select your Project, Source and Default version (use Latest if this release will be executed automatically) and finally click Add.
  • If you want this release is executed immediately after the build finish (so the build output is uploaded to LCS each time) enable the Continuous Integration flag by using the small icon highlighted in blue in the next screenshot (C.I.).
  • Click on the Stage 1 or Tasks links o open the details.
  • Select the Agent job node and validate that Agent pool parameter is set to Hosted VS2017.
  • Click the [+] button on the Agent Job node.
  • Search for the Dynamics Lifecycle Services (LCS) Asset Upload task (it should be already installed or can be installed at this point, click Refresh if the task does not appear in the list) and finally click Add to add the task to the pipeline.
  • Fill these properties on the newly created Task:
    • LCS Connection: Select a connection or click [+New] if this is the first time
      • Connection name: use a descriptive name (in case you have multiple LCS projects).
      • Authentication Endpoint: let the default value
      • Lifecycle Services API Endpoint:
        • If your LCS URL is like: https://lcs.dynamics.com/V2, use the value https://lcsapi.lcs.dynamics.com (default).
        • If your LCS URL is like: https://eu.lcs.dynamics.com, use the value https://lcsapi.eu.lcs.dynamics.com.
      • Username and Password: use the credentials (fully qualified user name and password) from a user with enough permissions to upload files to your LCS project
      • Application (Client) ID: use the guid of the Application created in AAD on the first step.
  • LCS Project Id: this is the numeric value included in your LCS project URL
    • Example: for the URL https://lcs.dynamics.com/V2/ProjectOverview/1234567, your Project Id is 1234567.
  • Type of asset: Software Deployable Package
  • File to upload: click the […] button to select the AXDeployableRuntime_XXX_YYY file in the Packages folder of your Build artifacts.
    • This is the default configuration, you might want to select a different file if your build definition is customized, but it should be a deployable package and its name should include the build number.
    • Back in the Pipeline properties, replace the build number with the variable $(Build.BuildNumber)
      • Example, for the filename: $(System.DefaultWorkingDirectory)/_ Unified Operations platform - Build Main/Packages/AXDeployableRuntime_7.0.5126.35370_ 2019.1.29.1.zip
      • Use the property value: $(System.DefaultWorkingDirectory)/_ Unified Operations platform - Build Main/Packages/AXDeployableRuntime_7.0.5126.35370_$(Build.BuildNumber).zip
  • LCS Asset Name and LCS Asset Description: Use descriptive values to identify this package when uploaded to the LCS Asset Library. More information about Azure Pipeline variables on the docs here for the build and here for the release.
    • For example: $(Release.ReleaseName)_$(Build.BuildNumber)
 

Done! now what?

To test that the newly created release work, use the Create a release button to create a new release manually: And, hopefully, results will look like that (otherwise check the logs to understand what’s happening, most common error so far is authentication with the AAD app): And you should have a new file in the Software deployable package folder of the LCS Asset Library. To get more information about this release and the setup process check the official announcement here and this blog post. Hope these instructions are useful to understand how to setup this first automation task, that hopefully won’t be the last one. Check the documentation for upcoming changes regarding Developer tools and application lifecycle management.   This article was first published at "Dynamics AX in the Field", the blog from the Premier Field Engineering team at Microsoft.  
Leer Más >>

Dynamics 365 Saturday – Madrid 2018

El pasado sábado 19 de mayo tuvo lugar el Dynamics 365 Saturday - Madrid 2018 en las oficinas de Microsoft donde pudimos pasar el día rodeados de la comunidad y compartiendo conocimientos y conversaciones. Es la primera vez que acudía a uno de estos eventos y seguro que repetiré porque la experiencia ha sido realmente buena. Compartí una sesión sobre extensiones que comparto más abajo, basada en el contenido que ya publiqué en inglés en el blog de mi departamento en estos enlaces: Y aquí el vídeo con la charla: https://www.youtube.com/watch?v=vqmkH3ONy_8 Y las slides compartidas por la organización: https://www.slideshare.net/DemianRaschkovan/dynamics-saturday-madrid-2018-extensiones-y-que-la-fuerza-te-acompane-jose-antonio Quería agradecer a todos los asistentes que vinieron a comentar el contenido de la charla con preguntas o sugerencias. ¡Nos vemos el año que viene!
Leer Más >>

Embrace the extensions mindset with Dynamics 365 for Finance and Operations #2 – SysExtension framework [EN]

In my previous post Embrace the extensions mindset with Dynamics 365 for Finance and Operations we reflected on some of the patterns we can leverage to create our customizations by using only non-intrusive changes based on a real example: Adding a new Number Sequence to a standard module. In particular, we discussed:
  • Metadata Extensions — to add a new Enum Value in a standard Base Enum.
  • Class Extensions — to add a new method to a standard class.
  • Chain-of-Command — to add a block of code to an existing standard class method.
  • Event-Handler subscription — to subscribe our own method to an existing standard delegate provided as an extension point.
If you still didn't read that blog post, please take a moment now. If you already did it (thanks!), let's continue with another pattern we have to consider: SysExtension Framework (also SysPlugin, that is quite similar). This pattern allows us to create new sub-classes for factory methods without any over-layering or coupling with the original hierarchy. Therefore, we can add new sub-classes in our own packages without any intrusive modifications and replace a very common pattern, widely used all over the application, like this (taken from AX 2012 R3):
static SalesCopying construct(SalesPurchCopy salesPurchCopy)
{
    switch(salesPurchCopy)
    {
        case SalesPurchCopy::CreditNoteHeader       : return new SalesCopying_CreditNote();
        case SalesPurchCopy::CreditNoteLines        : return SalesCopyingCreditNoteLine::construct();

        case SalesPurchCopy::CopyAllHeader          :
        case SalesPurchCopy::CopyAllLines           :
        case SalesPurchCopy::CopyJournalHeader      :
        case SalesPurchCopy::CopyJournalLines       : return new SalesCopying();

        // 
        case SalesPurchCopy::VoidFiscalDocument_BR  : return new SalesCopying_VoidFiscalDocument_BR();
        // 

        default                                     : throw error(strFmt("@SYS19306",funcName()));
    }

    throw error(strFmt("@SYS19306",funcName()));
}
This pattern has many of problems to be extensible. The most obvious is likely the throw error on the default case, that makes impossible to an extension class to subscribe to the Post event on the method to add new cases. But even deleting this throw sentence (that has been indeed deleted in many standard methods as a quick way to make them extensible), the pattern itself is still a problem. If a new customer or partner customization or even a new standard module needs a new case, this class needs to be modified and the full package compiled and deployed.   Read the full article at "Dynamics AX in the Field", the blog from the Premier Field Engineering team at Microsoft.  
Leer Más >>