Tuesday, October 31, 2017

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();
    }


Wednesday, May 17, 2017

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. 



Saturday, April 1, 2017

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: