Dynamics 365 Finance and supply chain – X++ code to fetch open calendar days

One thing I like about coding in X++ is that we can reuse API’s and standard classes to perform a complex task. We do not need to reinvent the wheel and best way to do is to find any standard process and reuse the existing methods.

One such example is to find number of open days in a calendar setup between a date range. So you have a start date and end date and a calendar ID and you want to find which days are open in the calendar setup lines.

Instead of writing your own X++ SQL statement to understand table relations and loop through work calendar setup lines, there is a standard class which has this method built in and we can call it to find if a particular day is open in calendar or not.

This method also uses a global cache to lookup the setup and can be fast then writing SQL statements and pulling data directly from the database.

One example of using this method is shown below : Here we have a fromDate, toDate and Calendar ID. All we need to do is loop through the dates and call this method and we can then insert it into a map which can then be used in further logic.

   protected Days findOpenDates(
        TransDate   _fromDate,
        TransDate   _toDate)
    {
        CalendarId          calendarId;
        TransDate           calendarValidTo;

        TransDate           loopDate;

        Days                numOfOpenDays;

        WorkCalendarSched workCalendarSched = new WorkCalendarSched(true);

        for (loopDate = _fromDate; loopDate <= _toDate; loopDate++)
        {
            if ( ! calendarId
                || calendarValidTo < loopDate)
            {
                [calendarId, calendarValidTo] = this.calendar(loopDate);
            }

            if (workCalendarSched.isDateOpen(calendarId,loopDate))
            {
                if (mapAllDemand)
                {
                    mapAllDemand.insert(loopDate,0);
                }
                numOfOpenDays++;
            }
        }

        return numOfOpenDays;
    }

As X++ developers we should leverage standard API’s instead of reinventing the whole wheel. Thanks for reading the blog.

D365 Finance and supply chain ( F&O) : Adding custom fields on create product form via extension framework Approach

If you have added new fields in products table via extension, then their are high chances that you will also be asked to add them on the standard create product dialog.

Initially it may look like a simple task to add 2 fields on a form but when you will start developing and will have a look inside the form design you will notice that there is no data source on this form design and hence you cannot just add the fields by drag and drop feature.

No Datasource in the form design

Upon technical analysis , you will find that there is a method named createData2Controls() which basically populates a container with details of which controls on the form are mapped to which fields of the tables and then under the method writeMoreFields(), the container is read and the fields are assigned value based on the mappings present in the container.

Below is how we can use extension framework approach to add new fields to the form and add the mapping in the container.

  • Add new fields to Invent table. In my case I added 2 new fields.
  • Create extension of the EcoresProductCreate form and add unbounded controls on the form design. Set Auto declaration as True.
  • Create a new extension class and decorate it with attribute [ExtensionOf(formStr(EcoResProductCreate))].
  • In the new class , extend the method createdata2Controls() to add the mapping of your new fields on the table extension with the form unbounded controls . Below is the sample
[ExtensionOf(formStr(EcoResProductCreate))]
final class XYZ_EcoResProductCreate_Extension
{
    protected void createData2Controls()
    {
        next createData2Controls();

        data2Controls = conIns(data2Controls,
                                conLen(data2Controls) + 1,
                                [tableStr(InventTable), [[fieldNum(InventTable, YourFieldName1), formControlStr(EcoResProductCreate, YourControlName1)]]]);

        data2Controls = conIns(data2Controls,
                                conLen(data2Controls) + 1,
                                [tableStr(InventTable), [[fieldNum(InventTable, YourFieldName2), formControlStr(EcoResProductCreate, YourControlName2)]]]);

    }

}

After this build the project area and run the product create process and the values will flow to the inventTable.

Hope this helps if you are trying to figure out how to use extension framework to feed the value of new controls to the table.

Summary of what\’s new or changed in Dynamics 365 Finance and Supply Chain update 10.0.14 (November 2020)

 
Microsoft Dynamics 365 Finance & Operations update 10.0.14 became generally available in November 2020 and is loaded with another bag of goodies. 

I wanted to share a summary from the analysis I did post installing it. Talking about numbers, there are 35 new features and 630 KB fixes across various modules. Quality update which got released has around 118 fixes across application.  

Below is a quick summary snapshot of 10.0.14 update. 



I want to briefly talk about few key features :


Dynamics 365 Guides for Manufacturing  –>  This feature enables you to deliver mixed-reality, step-by-step instructions for production processes using Dynamics 365 Guides. 
Basically once you setup the guides parameters and then define the guides, then the worker can use their HoloLens to scan the QR code and the guide will get launched. 
Refer to this docs link for more details.  Below are some screenshots and steps from the same link, for quick reference: 
To configure how Guides appear on the shop floor, go to Mixed Reality > Dynamics 365 Guides > Configure Guides integration.


You can attach guides to various aspects of production control like Resources ,Resource groups, Released products, Formulas, Routes, Route versions. etc. 

When a worker opens a job list on the shop floor execution interface, Supply Chain Management finds the relevant guides for the jobs shown. Use the Guides button to view the relevant guides.


Then put on a HoloLens and access the respective guide by glancing at the QR code and activating the respective Guide.

Asset Leasing :
Asset leasing helps you adapt and be compliant to the ASC 842 and IFRS 16 accounting regulations related to lease management and its financial impact Asset leasing is integrated with fixed assets and the chart of accounts. Refer to Microsoft Tech talk on this topic having feature demonstration here.


Below is a summary of asset leasing capabilities from the tech talk presentation: 



All the asset leasing objects are under a separate model in the application explorer

Enable Project Operations on Dynamics 365 Customer Engagement : 

This feature allows to define default configurations can be defined to support Project Operations integration. It is dependent on the feature \”Enable multiple contract lines for a project\” . 

The feature to Enable multiple contract lines for a project provides support for a project to have fixed price components and time and material components. Project type will be moved to the contract line. Project group will become optional and the setup related to tracking of work in process and revenue calculation will be moved to a new entity – Project revenue profiles. The project revenue profile rules will determine which project revenue profile to use. Internal projects will be projects without a contract and only costs will be tracked. 

Test this in SBOX environment as these should be enabled only if using synchronous integration with the Common Data Service.


(Preview) Vendor invoice automation :

The automation processes can be used to perform these tasks:

·        Automatically submit imported invoices to the workflow system.

·        Match product receipts to pending vendor invoice lines.

·        Simulate posting before a vendor invoice is posted.

·        Quickly and efficiently view workflow history.

·        View and analyze the results of automating vendor invoice processing.

Refer docs here for more details. 

Below is a complete list of 35 new features shown in feature management post 1.0.0.14 installation 




KB Fixes

Below is the breakup of KB Fixes across various modules. The complete list of  KB details can be found in LCS here


We can see most of the fixes are in Localization, PMA, Retail, Financial management and Warehouse and Transportation management modules.


Quality update got released with around 118 fixes as well across various modules. The details can be seen from environment details page. 


Platform features

In terms of platform features now we can have drop-down list on multi-line controls. Previously, only single-line input controls permitted drop-down lists.


An update to the (Preview) Grouping in grids feature is available now to expand/collapse groups and select or unselect all rows in a group.

 

I hope this article gives a summarized view of what\’s new in 10.0.14 and will enable readers to dive deep into the areas of their interest and related ongoing projects. Thanks for reading the blog. Have a great day and keep DAXing :). 



New features at a glance for Microsoft Dynamics 365 Finance & Operations update 10.0.13

Microsoft Dynamics 365 Finance & Operations update 10.0.13 is generally available and the details of release can be found on docs site . This update marks end of 2020 wave 1 and as expected, this update is packed with lots of goodness and new features. 

I wanted to share a summary from the analysis I did post installing it. Talking about numbers, there are 60 new features and 950 KB fixes across various modules. 

Below is breakup of the new features per module. Most of the new features are released in Retail & Commerce, Project management & accounting and Accounts receivable module.

I did some more digging around the newly introduced featured and queried some tables under the hood and found: 
Some features that cannot be disabled once you enable them:
Features which are force enabled:
Preview features:
Some of my favorite features from the release, which I feel shall catch a lot of attention going forward: 

The complete list of the new features can be seen from feature management workspace after updating the environment

With regards to the platform capabilities, some cool and awaited features like saved views and new grid control have been made generally available. These will give great personalization capabilities to users and also allows them to use mathematical formulas in tabular grids and empowers them for fast data entry.

The tentative release plan for  wave 2 features can be accessed from  https://docs.microsoft.com/en-us/dynamics365-release-plan/2020wave2/ . 
Microsoft business applications launch event is also planned where James Phillips, President of the Business Applications Group, will guide the community through what’s new in Dynamics 365 and Microsoft Power Platform 2020 release wave 2. Register here https://msft.it/6049TsJ1J
Keep sharing and stay safe. 

Dynamics 365 Finance and Operations apps : SysExtensionSerializerMap – Your friend for adapting to normalization instead of extending tables when adding lot of fields

In every implementation of Dynamics 365 for Finance & Operation, there is need to add new fields in the core tables. With introduction of extension framework, Microsoft provided a clean way to add new fields without over layering the standard object hence making consumption of updates smooth.
However, Microsoft has introduced a best practice warning in the compiler when there are more than 10 fields added on a table via extension. The alternate recommended way is to create a new table and add a foreign key relation to standard table. One of the benefit of moving fields to separate tables is performance improvements. It makes sense because the performance cost associated with the retrieval of the custom fields should only be incurred when processes which needs these fields are executed.
This sounds good from database normalization perspective. But when you are working in a business application, then the expectation is that data in the custom table should be inserted, updated and deleted along with the core table.  In order to make developers life easy there are maps – SysExtensionSerializerMap and SysExtensionSerializerExtensionMap available out of the box.
These were available in previous versions of the product AX 2012.
If used smartly developers can save efforts and reduce complexity to write custom logic of CRUD operations on the new table and in fact provide more flexibility when we need to access the table buffer. Below are key steps we should use when creating a new table to store custom fields:

 Other best practices related to creation of tables like adding indexes, field groups, properties etc. still remain intact.


Below is how a table, for illustration, should look. In this example, I have created a table instead of adding fields via extension and have only added one field.

Mapping properties should look like : 
Below is how the relation properties should look like:
Define the index as alternate index and use it as replacement key on the table properties
Index properties: 
Table properties: 
Once this mapping is added then developers don’t have to worry about things like calling insert and update methods on the new table whenever a record is created or updated in core table. This is how it works:
SysExtensionSerializerMap has methods like postInsert(), postUpdate() and more as shown below.






postInsert() Inserts the packed extension table record after the base table record is inserted, it uses SysExtensionSerializerFormRunHelper class to perform the logic.
Most of the tables where insert method is overridden, call methods of these maps as shown below
A nicely modeled data structure will enable developers to focus on writing the business logic and leverage the platform capabilities. 
Thanks for reading the blog. I still love the old school tag line to end the blog – happy DAXing J

Dynamics 365 for Finance and Operations : Active periods in batch jobs

Friends,
In this blog post, I want to highlight the option of defining active period on a batch jobs. Microsoft released this feature it in platform update 21 (Link can be found Here)

When used properly this option helps to fine tune batch jobs so that the system resources can be used optimally.

Architects should identify business tasks running in batch jobs or system maintenance tasks which can be performed after hours and should configure batch jobs smartly. Some scenarios where this configuration is useful can be batch processes which are running consolidations at end of day or emailing out list of activities to be performed next day by field technicians or system maintenance tasks to clean up staging tables.

Active periods can be defined from System maintenance >> Setup >> Active period for batch jobs menu item 

Multiple active periods can be defined as per the use case, it is very important for architects to discuss this with there clients and understand the need of batch jobs execution time frame:
Once active periods are defined they can be linked to a batch job as shown below : 

Few important points:

1. Recurrence settings which are defined on the batch job are applied only within the active period define for the batch job.

2. This setting should not be used as an alternative for recurrence setting.

3. Active period does not go over midnight. 

4. The batch jobs are put to waiting status once active time is crossed and then again put back to executing status when the active time is reached. The reference code can be found in below highlighted class.

5. There is a default period define from 12:00:00 AM to 11:59:59 PM. Do not modify time or delete it , as system will check for a default active period and if this is deleted then system recreates it. The reference code can be found in below highlighted class.

It is always a good practice to:

  • Understand and discuss the need for defining active periods on batch jobs with your customers.
  • Define active periods and test batch jobs in tier 2 environments before applying to Production. 
  • Have correct understanding of this setup and identify options to  reduce the load on system during business hours when most of the business users are logged on. 

Thanks for reading the blog..please feel free to share your thoughts on the same topic. 

Microsoft Dynamics 365 for Finance and Operations, Enterprise edition : X++ code to post Purchase order invoice by matching a product receipt

Product receipt is the process of recording the products that were ordered, have been received. Once received, the purchase order lines can then be processed for invoicing. There can be multiple product receipts posted against a purchase order and there might be situations where we may need to post an invoice for a particular product receipt.
In Microsoft Dynamics 365 for Finance and Operations, Enterprise edition we can use the match product receipt function during creation of purchase order invoice to select a particular product receipt.

Let\’s do a quick walk through: Below are three product receipts posted against a purchase order
When we go to invoice the purchase order and use the highlighted option to default invoice lines from the product receipt quantity, system will by-default include all the posted product receipts \”multiple\” and will show in the product receipt as shown below
To choose a particular product receipt by using the Match product receipt functionality , click on \”Match product receipts\”
A new form will open where we can select any particular product receipt and the invoice will get updated to refer to the selected product receipt 
Enter the invoice number and post the invoice
We may need to build a process where we need to automate this and want to post invoice for a particular product receipt. You might just have the product receipt number and a purchase order number provided to you.
To do this from X++  code you can use the below code and make it as an API to post Invoice for a particular product receipt. It uses the product receipt number as the invoice number during posting. 
To use it quickly below is the code: 
public static void main (Args _args)
    {
        TmpFrmVirtual               tmpFrmVirtualVend;
        PurchFormLetter_Invoice     purchFormLetter;
        VendPackingSlipJour         vendPackingSlipJour;
        SysQueryRun                 chooseLinesQuery;
        SysQueryRun                 chooseLinesPendingInvoiceQuery;
        container                   conTmpFrmVirtual;
        List                        selectedList    = new List(Types::Record);
        PurchId                     purchId         = \”PO00001\” ; //Purchase order number
        PackingSlipId               packingSlipId   = \”PCK0001\”; //Product receipt number
        select firstonly vendPackingSlipJour
                    where vendPackingSlipJour.PurchId == purchId
            && vendPackingSlipJour.PackingSlipId == packingSlipId;
        if (vendPackingSlipJour)
        {
            tmpFrmVirtualVend.clear();
            tmpFrmVirtualVend.TableNum  = vendPackingSlipJour.TableId;
            tmpFrmVirtualVend.RecordNo  = vendPackingSlipJour.RecId;
            tmpFrmVirtualVend.NoYes     = NoYes::Yes;
            tmpFrmVirtualVend.Id        = vendPackingSlipJour.PurchId;
            tmpFrmVirtualVend.insert();
        }
        chooseLinesQuery = new SysQueryRun(queryStr(PurchUpdate));
        chooseLinesQuery.query().addDataSource(tableNum(VendInvoiceInfoTable)).enabled(false);
        // chooseLinesPendingInvoiceQuery needs to be initialized, although it will not be used
        chooseLinesPendingInvoiceQuery = new SysQueryRun(queryStr(PurchUpdatePendingInvoice));
        chooseLinesPendingInvoiceQuery.query().dataSourceTable(tableNum(PurchTable)).addRange(fieldNum(PurchTable,PurchId)).value(queryValue(\’\’));
           
        purchFormLetter = PurchFormLetter::construct(DocumentStatus::Invoice);
        purchFormLetter.chooseLinesQuery (chooseLinesQuery);
        purchFormLetter.parmQueryChooseLinesPendingInvoice(chooseLinesPendingInvoiceQuery);
        purchFormLetter.purchTable (PurchTable::find(PurchId));
        purchFormLetter.transDate (systemDateGet());
        purchFormLetter.parmParmTableNum (strFmt(\”%1\”,packingSlipId)); //This is invoice number
        purchFormLetter.printFormLetter (NoYes::No);
        purchFormLetter.sumBy (AccountOrder::Auto);
        purchFormLetter.specQty (PurchUpdate::PackingSlip);
      
        while select tmpFrmVirtualVend
        {
            selectedList.addEnd(tmpFrmVirtualVend);
            conTmpFrmVirtual = selectedList.pack();
        }
        purchFormLetter.selectFromJournal(conTmpFrmVirtual);
        purchFormLetter.reArrangeNow(true);
        purchFormLetter.run();
    }

D3FO: Customizing interaction classes using extensions

Dynamics AX technical community is finding cool and tricky ways to create extensions for customization\’s. In this post, let’s do a quick walk through on how we can customize a list page interaction class via extensions.  

To do this let\’s add a new button on sales order list page and enable/disable it on the basis of sales order status.
Below are the high level steps :
  • Create a new class to write the business logic to be executed by your new button.
  • Create a new menu item linked to your class
  • Create extension of the list page and add your new button
  • Create event handler for the list page interaction class and enable/disable the new button 

Let\’s create a new class: I have shown the total sales order amount in the Info-log, to show an example of business process in the method.


Now we create a new action type menu item for this class as shown below:




Create an extension of SalesTableListPage from : To do this, right click on the SalesTableListPage object in the AOT  and select \”Create extension\” . Make sure your model, where you are creating the project, has a reference to Application suite else this option will not be enabled.




In the designer window, expand the design node and navigate to the action pane where you want to add the button. Let’s add a new button group and add the menu item we created



Verify that the menu item button is having correct properties and define the data source property as SalesTable


Build the project and test the button. When you open the sales table list page the new button is visible


Click on the button just to make sure that it’s working. On clicking it we can see that Infolog is shown to display the Sales order total amount


Now let\’s add more logic to our button to only be enabled for sales orders which are not invoiced. Typically we would go to the interaction class and modify the function which is enabling/disabling button, but we want to do this without customizing the standard class and with the use of extensions.

That means we need to subscribe to the method of the interaction class. We can see that interaction class as methods available which are pretty much self-explanatory by their names. We can see there are few methods which set the button properties 


As we added the button in the sales order action pane group we can see that there is a method in this class which used to set buttons on the sales order action pane tab menu items . Notice that this is a protected method.  

Ideally you may want to create an event handler for this method. Try to right click on this method and then select the option to create a post event handler 


You will be greeted with the below error message. We can only create event handlers for Hookable methods. The definition of  Hookable method is also shown in the error message, these are non-abstract methods that are either public or tagged with the \”Hookable\” attribute as true. 


Let\’s find a hookable method in the interaction class:  On a quick scan in the class you can see that the setButtonEnabled() method is a protected method and decorated with the \”HookableAttribute\” as true. 



This is an important point for ISV\’s to consider when design their solutions, as this attribute will be helpful to tag extension plugs.Let\’s create an event handler listener for this method 


Add the event handler in the new class which we already created 


Now we need to  :
·         Get the object of the interaction class
·         Get the current sales table record
·         Set the button access
The below lines of code represent each step 


Below is the code text in case you want to reuse it
///

    /// This method enables/disables the new process button based on the sales order status
    ///

    ///
    [PostHandlerFor(classStr(SalesTableListPageInteraction), methodStr(SalesTableListPageInteraction, setButtonEnabled))]
    public static void SalesTableListPageInteraction_Post_setButtonEnabled(XppPrePostArgs args)
    {
        SalesTableListPageInteraction salesTableListPageInteraction = args.getThis();
        SalesTable salesTable = salesTableListPageInteraction.listPage().activeRecord(queryDataSourceStr(SalesTableListPage, SalesTable)) as SalesTable;
        salesTableListPageInteraction.listPage().actionPaneControlEnabled(formControlStr(SalesTableListPage, RGSalesProcess),SalesTable.SalesStatus != SalesStatus::Invoiced);
    }
Now we build the project and run the list page form to see if the button is disabled for invoiced sales orders:
The button is disabled for an invoiced sales order


The button is enabled for a sales order having a status other than Invoiced.


Thanks for reading the blog. Your feedback is welcome and keep sharing any cool ideas around extensions and the new frameworks of D3FO. 

Technical overview – Gantt control in Dynamics 365 for operations

In Microsoft Dynamics 365 for operations, form controls are split into logical and physical parts. The physical presentation is HTML, JavaScript and CSS within the browser and the logical state always runs on server which is controlled by X++.
 
ActiveX, ManagedHost and WPF controls were used in AX2012  to add new custom controls, these  are incompatible with HTML based platform and cannot be used in D3FO.

A new extensible control framework is introduced in D3FO which lets you add custom controls by using HTML5, Javascript and CSS3. The new Gantt control in D3FO is implemented by using extensible control framework.It comes with an advantage that you don’t  have to pay an additional license fee to use the control in your own forms or to extend the control.

In this post let\’s do a quick technical walkthrough on the various elements of the Gantt control and how to use it on your forms.
 The below diagram shows the basic elements of a Gantt control.
 
 
 
 
In a Gantt chart we can identify as per below sample diagram:
 
 
 
Lets go through brief summary of each Gantt element:
 
Activity : This is most important element is a Gantt control. Each activity is allocated its own row in the chart. Activities can form a hierarchy, like a tree, by referencing a parent activity. Two activities can be connected to each other through links. A Gantt activity can be further classified into a Milestone activity, task activity or a summary activity. Technical base is provided  a base enum which holds the type of Gantt control activity 
 
 

Below classes which are used to initialise and hold data for the activities for a Gantt control.

 
 
Links : Links are used to connect two activities on a Gantt control. The Link information is stored as a data contract in the class GanttControlLink.
 
 
The link types are stored in GanttLinkType enumeration:
FF : End to end link
FS : End to start link
SF : Start to End Link
SS : Start to start link
 
Vertical Markers: This represents a vertical marker on a Gantt control . This information is stored as a data contract in the ganttControlVerticalMarker class. The date time method stores the information of the date/time where the marker should be shown on the control. The text is text which is shown next to the marker.  We can add more than 1 markers on the control.
 
 
Calendar and working time intervals : Calendar holds the calendar ID and the working time intervals holds a set of working time information. These are controlled by GanttControlCalendar and GanttControlWorkingTimeInterval classes. This information is stored in below contract classes:
 
 
 
 
The list of working times in the GanttControlClendar is generated based on the GanttControlWorkingTimeInterval contract as shown in the below contract method
 
 
 
 
Columns: These are the column on a Gantt chart grid and are stored in the class GanttControlColumn as a contract. The below parm methods store the Columns information. The alignment is controlle d by SysAlignment base enum 
 
 
 
Configurations :Gantt configurations refer to configuration of view and edit behaviour of the Gantt control. There are configuration settings which are stored as a data contract. Use calendars method determines if calendars should be used in the Gantt chart. Switching calendars off have a huge performance benefit. Some configurations for Gantt control are :
  •  Show all links determines if all links should be shown; otherwise only links for the currently selected chain will be shown.
  • Use theme colours Determines if standard AX theme colours should be used for the elements of the chart.
  • Allow move activities Determines if activities are allowed to be moved using drag/drop.
  • Allow resize activities Determines if activities are allowed to be resized using drag/drop.
  • Allow completion change Determines if activities can have the completion percentage set using drag/drop.
  • Vertical move mode Determines if/how activities are allowed to be moved vertically.
 
Below list of methods show the configurations which can be defined when initialising the Gantt configuration.  
 
 
  
Gantt control timescales : Represents settings for a time scale on a Gantt chart. These are stored in the GanttControlConfiguration contract. The below methods are used in the contract
 
 
 
Gantt Control : This is the Gantt control class which stores the information of all the Gantt elements. The class name is GanttControl and it has methods to store the Gantt elements information. If you look at this class then you will see that this stores most of the Gantt elements information as a List. 
Activities:
 
 
Links
 
 
Calendars
 
 
Columns
 
 
Vertical markers
 
 
How it all works together: We can add a new Gantt control on the form by selecting it from the list of control available when we add a new control
 
 
We need to define auto declaration as true
 
 
 We can now set/populate to the GanttControl class methods using this control and load the gantt elements. A very good example is shown on the tutorial_Gantt form shipped in application foundation
 
 
All the activities are added to a list and
 
 
And then the list is assigned in the GanttControl class
 

 

 
 
To load the GanttControl we have to write the X++ code to create and populate the contracts, lists and initliaze the Gantt classes. The complete code sample can be referenced in tutorial_gantt form which shows the Gantt control as below:
 
There is much more to what we can do with the Gantt control classes and with the power of extensible control framework. It provides a great platform for vendors and ISV\’s to build amazing Gantt extensions and advanced controls.
 
References: