Translate

Tuesday, November 12, 2019

New Microsoft certifications for Dynamics 365 - role based

HI,

Microsoft has released its updated certifications on all Microsoft stack.

you can also filter the technology based on Dynamics 365 for certifications Dynamics 365 Finance and operations. Most of the AX previous certifications will expire this year end and until june next year, but the transcript will be available if you have completed any before they expire.

https://www.microsoft.com/en-us/learning/browse-all-certifications.aspx



Good luck.
Thanks
Prasan

List of free AX7/D365 courses available for download

Hi,

Below are the list of AX7 and D365 finance and operations courses available for free downloaded.

https://community.dynamics.com/365/b/learningcurriculum/posts/list-of-courses-available-for-download

and additional R3 courses available in below link
https://community.dynamics.com/365/b/learningcurriculum/posts/we-ve-added-more-ax-2012-r3-courses-for-download


also about how to download and run this course information will be available in the below link.

https://community.dynamics.com/365/b/learningcurriculum/posts/how-to-run-a-downloaded-course

PS: All information are provided from Microsoft websites.

Happy AX/D365 learning and good luck,

Thanks,
Prasan

AX Pending workflows using X++

Below is the X++ code to get the active pending workflows which are waiting for approvals and yet to approve.

workflowTrackingStatusTable is the header table which holds information about the order and the order which triggered the workflow and the current status of the workflow approvals.

workflowworkitemTable is the table which holds the information about who are all users are required to action the workflow for the particular workflow instance, once the approvee actioned then record will be deleted from this table and new approver is added to this table with new record.

workflowtrackingcommenttable will holds the comments of the user who has submitted, approved,rejected.

while select /*firstOnly10*/ workflowTrackingStatusTable //order by workflowworkitemTable.createdDateTime asc
            where workflowTrackingStatusTable.TrackingStatus == WorkflowTrackingStatus::Pending
            //&& workflowTrackingStatusTable.InstanceNumber=='INS2367227'
            //TODO: for testing- commet it in LIVE
            && (workflowTrackingStatusTable.ContextTableId == 1425//Supplier Invoice
            || workflowTrackingStatusTable.ContextTableId == 1967//Sales quotations
            || workflowTrackingStatusTable.ContextTableId == 345//Purchase order
            || workflowTrackingStatusTable.ContextTableId == 1551//Purchase requisitions
            || workflowTrackingStatusTable.ContextTableId == 617//Invoice proposals
            || workflowTrackingStatusTable.ContextTableId == 484//Travel expense claims
            || workflowTrackingStatusTable.ContextTableId == 4627) //Timesheet
            && workflowTrackingStatusTable.ContextCompanyId != "01"
            && (((workflowTrackingStatusTable.ContextTableId != 1551 && workflowTrackingStatusTable.ContextTableId != 484) && workflowTrackingStatusTable.ContextCompanyId != strMin())
                || (workflowTrackingStatusTable.ContextTableId == 1551 || workflowTrackingStatusTable.ContextTableId == 484))
            && workflowTrackingStatusTable.ContextRecId != 0
            && workflowTrackingStatusTable.ContextTableId != 0
            join workflowworkitemTable
                where workflowTrackingStatusTable.CorrelationId==workflowworkitemTable.CorrelationId
                && workflowworkitemTable.Status==WorkflowWorkItemStatus::Pending
            //&& workflowworkitemTable.UserId == 'prasan.k'
            && workflowworkitemTable.modifiedDateTime >= dateStart
        //TODO:Uncomment the date criteia when release to LIVE
            outer Join  workflowtrackingtable
                where workflowtrackingtable.Workflowtrackingstatustable==workflowTrackingStatusTable.recId
                && workflowtrackingtable.TrackingType == WorkflowTrackingType::Submission
                && workflowtrackingtable.User == workflowworkitemTable.UserId
            outer join  workflowtrackingcommenttable
                where workflowtrackingcommenttable.trackingid ==workflowtrackingtable.trackingId
        {

}

Workflow Approvals message tracking X++

Helps to find the approvals tracking like who and all are approved so far for the particular workflow and what are the workflow approval comments as such in X++ code.




private str getworkflowTrackmessage(WorkflowInstanceNumber _instanceNumber)
{
    WORKFLOWTRACKINGSTATUSTABLE w;
    WORKFLOWTRACKINGTABLE wt ;
    WORKFLOWTRACKINGTABLE wt2;
    workflowsteptable wst;
    workflowElementtable wet;
    workflowTrackingWorkItem wtw;
    UserInfo user;
    UserInfo user2;
    str txt,ret;
    workflowtrackingcommenttable wtct;
    boolean first=true;

    while select * from w ORDER BY wt2.CREATEDdATEtIME ASC
       where w.instANCEnUMBER==_instanceNumber//'INS2380404'//INS2383500'//
    join  wt2 where w.recId == wt2.workflowTrackingStatusTable && wt2.USER!='axwfexec'
    join wtct where wt2.RecId==wtct.WorkflowTrackingTable
    outer join wtw where wt2.recId==wtw.workflowTrackingTable
    outer join wst where wst.stepId == wt2.stepId
    // join wet where wet.ElementId == wt2.ElementId
    outer join user where user.id == wt2.User
    outer join user2 where user2.id==wtw.ToUser
    {
        txt ='';
        if (wt2.TrackingType == WorkflowTrackingType::Approval)
        {
            txt = strFmt("%1 : %2 Approved on %3 ", wst.Name, User.name,wt2.createdDateTime);
            if (wtct.Comment != strMin())
            {
                txt = strFmt("%1 ,Comments: %2",txt, wtct.Comment);
            }
            //info(txt);
        }

        if (wt2.TrackingType == WorkflowTrackingType::Delegation)
        {
            txt =strFmt("%1 : %2 Delegated to %3 on %4",wst.Name,User.name,user2.name,wt2.createdDateTime);
            if (wtct.Comment != strMin())
            {
                txt = strFmt("%1 ,Comments: %2",txt, wtct.Comment);
            }
            //info(txt);
        }

         if (wt2.TrackingType == WorkflowTrackingType::Rejection)
        {
            txt = strFmt("%1 : %2 Rejected on %3",wst.Name, User.name,wt2.createdDateTime);
            if (wtct.Comment != strMin())
            {
                txt = strFmt("%1 ,Comments: %2",txt, wtct.Comment);
            }
            //info(txt);
        }

        if (wt2.TrackingType == WorkflowTrackingType::Creation)
        {
            txt =strFmt("%1 : Assigned to user: %2 on %3",wst.Name, User.name,wt2.createdDateTime);
            if (wtct.Comment != strMin())
            {
                txt = strFmt("%1 ,Comments: %2",txt, wtct.Comment);
            }
            //info(txt);
        }

        if (wt2.TrackingType == WorkflowTrackingType::Submission)
        {
            txt = strFmt("Submitted by : %1 on %2", User.name,wt2.createdDateTime);
            if (wtct.Comment != strMin())
            {
                txt = strFmt("%1 ,Comments: %2", txt, wtct.Comment);
            }
            //info(txt);
        }
        if(first)
        {
            ret = txt;
            first = false;
        }
        else
        {
            ret = ret + '\n' + txt;
        }
    }
    return ret;
}

Wednesday, October 30, 2019

MultiSelectHelper class - Select multilpe records in form grid to update the data altogether once.

1) Create a class that extends the runbase class.

2) write a main method to handle the class methods and its arugments

In main method declare the below helper class
 MultiSelectionHelper                helper;//multiselect

and also validate the class is invoked based on correct paramaters and caller

for example: if(_args && _args.dataset() == tableNum(VendInvoiceInfoTable))//if class is invoked from table VendInvoiceInfoTable.

also initialize the helper class as below
 helper  = MultiSelectionHelper::createFromCaller(_args.caller());

read the first record as vendInvoiceInfoTable = helper.getFirst();

and next records as vendInvoiceInfoTable = helper.getNext();

loop the multiple records recading
while (vendInvoiceInfoTable)
{
info(vendInvoiceInfoTable.num);

vendInvoiceInfoTable = helper.getNext();

}

refresh the caller form - formDataSourceRefresh(VendInvoiceInfoTable); this will help to show the data updated inmmidiately after the function runs.

Invoke this class using Action menu item and please make sure to setup the menu property :MultiSelect to YES whereever you add this menuitem on the form



complete example:

MultiSelectionHelper                helper;//multiselect
    if(_args && _args.dataset() == tableNum(VendInvoiceInfoTable))
    {
     
        helper  = MultiSelectionHelper::createFromCaller(_args.caller());
        vendInvoiceInfoTable = helper.getFirst();
   
        if (pendingInvoiceUpdate.prompt())
        {
            while (vendInvoiceInfoTable)
            {
                if(vendInvoiceInfoTable ))
                {
               info(vendInvoiceInfoTable.num);
                }
                vendInvoiceInfoTable = helper.getNext();
            }
            formDataSourceRefresh(VendInvoiceInfoTable);//refresh the caller form
        }
    }

Wednesday, March 20, 2019

Consuming AIF web services deployed from Dynamics Ax from External client- Mobile app

Hi folks,

Hope you are well!!


I have found some interesting things on how to communicate to AX from external client using AIF Websrvice

Once after the service classes is created in AX and deployed under Inbound ports- the svc file exposes the client.

we need to refer this web service reference using C#.

IN VS we need to use 'Add referencne' option and specify the svc file path where it path can be found on AX inbound port.


For example the path looks like this.
http://SERVERNane/MicrosoftDynamicsAXAif60/Messenger/xppservice.svc
where Messanger in the path is the name of the service.

once the service reference is created we need to use and refer that in C# code

using MessangerSolution.MessangerApp;
=>Name of the service refrence created in C# is MessangerApp

declare the service
MessangerApp.BasicHttpBinding_PSV_Messenger app = new BasicHttpBinding_PSV_Messenger();

Providing credentials:
app.UseDefaultCredentials = FALSE;
app.Credentials = new System.Net.NetworkCredential("USERVNAME","SECURE PASSWORD","DOMAIN");

then you can invoke the service class methods like
app.PassMessage();

This also fixes the below issue on network credentials:
System.Net.WebException: The request failed with HTTP status 401: Unauthorized