Friday, July 27, 2018

Metadata Lookup - list of forms in D365

Here I am explaining how to write a lookup to get a list of forms and same way we can write a lookup of any metadata lookups.

In AX 2012 we have a table called 'UtilElements' to get the list of objects and then you can filter with 'UtilElementType' in your query.

In 365, they have introduced an API instead to get the list of metaData based on your requirements.

var    forms = Microsoft.Dynamics.Ax.Xpp.MetadataSupport::FormNames();

So for lookup, I have developed a tmp table and that has two columns
1. FormName
2. FormLabel

And that table will get inserted when you open the form where we have a requirement to put the lookup. 
*******************************************************
   SysFormsListTmp    formsList;
    
    public void populateFormsListTmp() // custom method to populate the tmp table
    {
       
        var                     forms = Microsoft.Dynamics.Ax.Xpp.MetadataSupport::FormNames();

        ttsbegin;
        while (forms.MoveNext())
        {
            formsList.clear();
            formsList.FormName = forms.Current;
            formsList.FormLabel = formName2Pname(formsList.FormName);
            formsList.insert();
        }
        ttscommit;

    }

    
    public void init()  //init() method of the form.
    {
        super();
        element.populateFormsListTmp();
    }
******************************************************
And then you can write a lookup() method on your control.

******************************************************
public void lookup(FormControl _formControl, str _filterStr)
{
                
                SysTableLookup sysTableLookup = SysTableLookup::newParameters(Tablenum(SysListOfFormsTmp),_formControl);
                Query query = new Query();
                QueryBuildDataSource queryBuildDataSource;
                
                
                sysTableLookup.addLookupField(fieldNum(SysFormsListTmp, FormName));
                sysTableLookup.addLookupfield(fieldNum(SysFormsListTmp, FormLabel));

                queryBuildDataSource = query.addDataSource(tableNum(SysFormsListTmp));
                queryBuildDataSource.addSortField(fieldNum(SysFormsListTmp, FormName), SortOrder::Ascending);

                sysTableLookup.parmQuery(query);
                sysTableLookup.parmTmpBuffer(formsList);

                sysTableLookup.performFormLookup();

                super(_formControl, _filterStr);
                
    }

Tags: #FormLookup #MetaData #D365FO 

Saturday, July 21, 2018

Power BI - How to embed a PBIX in D365FO and add in a workspace.

We have an option in D365 to embed PowerBI visuals and run through workspaces. Here I am providing steps to do the same.

1. Create a PowerBI report using power BI desktop and save the file, .pbix file will be saved.  You can refer below youTube tutorial

2. Open Visual Studio in your dev box and Right click on your project - Add - New Item 



3. Create a new 'Resource' and give the name of that resource.


4. As soon as you hit the ok, VS will popup the file explorer to select the 'PBIX' file, select the pbix you have developed\created.


5. Hit 'ok', resource will get created in your project.




6. Create a Display Menu Item 'demoAddPowerBiDisplay' and also create a controller class 'demoAddPowerBIWorkSpaceController' and extends with 'PBIReportControllerBase'

Note - You can copy the standard controller class like - 'FinancialInsightsWorkspaceEmbeddedController' 

7. Now add or modify the 'Main' method of the class and call your pbix resource -


8. Add this controller class in your menu item as an object.

9. Now create a new 'Tile' Right click on your project -> Add -> new Items -> User Interface - Tile.

10 . Once created, select your display menu item in tile properties. And give the label.



11. Add this tile to your menu.


12 - Once you click on this workspace, your pbix will get called. 

Tags: #PowerBI #D365FO #Pbix #Dynamics 

Monday, June 11, 2018

Data Entities - Custom Query Change Tracking in D365FO

Requirement is to enable the change tracking on table which is not part of the entity at all. But that table is being used in postLoad() to populate the values in an entity.

Let’s take an example of WMSLocation entity, we have added a custom column in that table and poplulating that column in postLoad method of the entity from some other table (demoLocationType). Now the scenario is when we are updating or adding data in this custom table then system should push or update data in wmsLocation entity.

If we are enabling primary or All table change tracking on entity, system won't update the WMSLocation when we are updating or adding column in table 'demoLocationType'.

Solution - We should write a custom method and name that 'defaultCTQuery' and in that method we would have create a query based on the relation between above two tables WMSLocation and demoLocationType and return the query object.

public static Query defaultCTQuery()
   {
        Query q;

        q = new Query();
        QueryBuildDataSource qbd = q.addDataSource(tablename2id('WMSLocation'));
        qbd = qbd.addDataSource(tablename2id('demoLocationType'));
        qbd.relations(false);
                               qbd.addLink(fieldName2Id(tableName2Id('WMSLocation'),'wMSLocationId'),fieldName2Id(tableName2Id('demoLocationType'),'wMSLocationId'));

        return q;
    }




And then go to Data Entities -> Filter the entity (WMSLocation) ->  Change Tracking -> Enable Custom query.




Tags-  #DataEntities, #ChangeTracking, #MSDYN365FO

Tuesday, May 1, 2018

How to write a display method in extensions (D365)

Requirement is to display a column from InventTable on Movement Journal lines form based on the selected item.

1. Create a new class and give a name, best practice is to give a name of the object with extension keyword





2. Once class is created, make sure you are using proper syntax and namespaces as below and also write the display method based on your requirement -



3. Compile the class.
4. Now find the 'InventJournalMovement' form in AOT and create an Extension





5. Then open the form and create a column as per your requirement.








6 . After create a new column, right on the column and select properties and then select the data source and data method which we have created in a final class.




7 . Build the solution. Now we should be able to see that column in Movement journal lines form



Tags: #DisplayMethods , #Extensions, #X++, #D365FO

Wednesday, April 25, 2018

How to override a clicked method of a button in a form Extension D365

Requirement is to add a button on CustInvoiceJour form and override the clicked method, so I would be creating an extension of that form and will add button there.

1. Create extension of 'CustInvoiceJour' form


2. Open extension of that form from the solution explorer and add a button



3. We have added a button, now we have to perform some operations on click of that button. And for that we need to write the 'OnClicked' event. In order to do that, expand the 'Event's under that control and right click on 'onClicked' event and select 'Copy Event Handler Method'

4. 'OnClicked' event handler is copied and now you can paste as a method in any of your custom class or you can create a new class. I am using one of my custom classes.

5. Now the question is, how we will get the selected record on that form or how would we get the form data source, if you take a look of this above method, you will seen we have a formContol as a parameter and by using that we can get the form data source and selected records.


After getting the table buffer and form data source, we can perform other operations.

Tags : X++ , D365, Form extensions, Events, OnClicked

Wednesday, April 18, 2018

Add controls run time and override the method in D356 (X++)

Here I will be explaining, how to create buttons run time and override the clicked method.

We would be creating buttons run time based on the setup companies in some custom table, Like I have table called 'DemoCompanyList' and that table has 3 companies setup

1. USMF
2. USMG
3. IND

Lets create a form and give a name 'DemoRunTimeControl' and then we can apply the pattern based on our requirement and then add Action Pane - Button Group - Menu Button(control name - ButtonHeaderInquiry), change the AutoDeclaration property to 'Yes' for this control.

Form Methods - 


init() - To get the list of companies and call method addRunTimeButtons()

addRunTimeButton() - In this method we will add buttons to menu button and also register the clicked method so that when we click on those buttons, it should the written clicked method.

RunTimeButton_clicked() - In this method we will opening the custInvoiceJour menu item based on the clicked button.


[Form]
public class DemoRunTimeControl extends FormRun
{
    Map                 buttonCompany;
   
    public void init()
    {
        container   companies;
        counter     i;

        super();

        buttonCompany = new Map(Types::Integer, Types::String);

        companies = DemoCompanyList::findCompanyList(); // Find company list will return the list of the companies

        for (i = 1; i <= conLen(companies); i++)
        {
            element.addRunTimeButton(conPeek(companies, i)); //addRunTimeButtons will add buttons based on the company setup
        }
    }

    private void addRunTimeButtons(DataAreaId _dataAreaId = #emptyString)
    {
        FormButtonControl           runTimeControl;
        #define.runTimeCtrl         ('DemoRunTimeButton')

        runTimeControl = ButtonHeaderInquiry.addControl(FormControlType::Button, #runTimeCtrl + _dataAreaId);
        //Invoice (%1)
        runTimeControl.text(strfmt("Customer Invoice (%1)", _dataAreaId));
        runTimeControl.registerOverrideMethod(methodStr(FormButtonControl, clicked), formMethodStr(DemoRunTimeControl, 'RunTimeButton_clicked'), element);
        buttonCompany.insert(runTimeControl.id(), _dataAreaId);
    }

    public void RunTimeButton_clicked(FormButtonControl _formButtonControl)
    {
        //Set the local control to the actual control that is calling the method.
        _formButtonControl = this.controlCallingMethod();
        CompanyId company;

        company = buttonCompany.lookup(_formButtonControl.id());

        if (company)
        {
            changecompany (company)
            {
                //Open invoice journal in specific company
                new MenuFunction(MenuItemDisplayStr(CustInvoiceJour),MenuItemType::Display).run();
            }
        }

    }

}



When you will click on first button, system will open customer invoice journals form in USMF company and the same way if you click on IND one, system will open journals from IND company.