Saturday, April 11, 2020

Message API - Message::AddAction() in D365FO Version 10.0.10 PU34 | New Feature

Introduction: 
From the version 10.0.10 Platform update 34, Microsoft has added a new feature Message::AddAction() which is shown in the message bar. 

Details: 
Message API associated with display or action menu items, which is visualized as a hyperlink/link button. 

It is linked with a single record at a time, called single action. 

In below taken example, we will show sales order is navigated to the form SalesTable from the message bar. 

For testing it, we'll create the runnable class also know as job in AX 2012. 
class CFSMessageAPI
{
    public static void main(Args _args)
    {
        SalesTable            salesTable = SalesTable::find('SH-000121');
        MenuItemMessageAction actionData = new MenuItemMessageAction();

        actionData.MenuItemName(menuItemDisplayStr(SalesTable));
        actionData.TableName(tableStr(SalesTable));
        actionData.RecId(salesTable.RecId);
        str jsonData = FormJsonSerializer::serializeClass(actionData);

        int64 messageId = Message::AddAction(MessageSeverity::Informational, "Sales order details", salesTable.customerName(), MessageActionType::DisplayMenuItem, jsonData);
    }

}
Let's see how it works, 









In my case it's showing Mitchell. Click on the link. 



















After clicking on the action link, it is navigated to the sales order record form as shown in the above link. 

Hurray, How pretty feature is released !!!

Conclusion:
In above example, we have seen how Message API is routed to the record. 

Thanks for reading !!!

Friday, April 10, 2020

How to delete workspace from TFS Visual Studio

Introduction:

In this blog, we will see how we can delete any of the TFS workspace which is assigned to different user

Even if tried to remove/delete the workspace from Visual Studio, We're unable to map existing workspace to new user.  

In such scenario, It is necessary to delete the workspace explicitly while getting the error as below 
"The working folder 'Workspace_Folder_Local_Path' is already in use by  the workspace : on computer 


Solution: 

1. Open Developer Command Prompt for VS2015 from Start menu

2. For getting the list of workspaces associated with user, run below command
tf workspaces /server:https://{TFS}.visualstudio.com/{CollectionName} /owner:"{Owner}"
Explanation, in my case {TFS} is xxxx.visualstudio.com/defaultcollection and {Owner} as Jagdish Solanki, Eventually it will look something like this,
tf workspaces /server:https://xxxx.visualstudio.com/{CollectionName} /owner:"Jagdish Solanki"
Reference:



3. To delete the workspace, run below command 
tf workspace /server:https://{TFS}.visualstudio.com/defaultcollection /delete "{Workspace};{Owner}"
It will looks something like this,
tf workspace /server:https://xxxx.visualstudio.com/defaultcollection /delete "SCM-DEV-1;Jagdish Solanki"
Once the above command is executed, system will prompt you if user has any pending change(s). Are you sure want to delete the workspace? (Yes/No). Enter yes
Reference: 











Enable/Disable & Visibility an Action pane button on a list page using interaction class in D365

Introduction:
In this blog, we will see how we can enable/disable or change the visibility of the form control in interaction class.

Standard behavior of the form, system does not allow us to write code on form which comes under form template -> List page

It Seems like below attached image (Here we will consider form VendTableListPage. Property of form as shown below)










Each ListPage form consisting with an interaction class as shown in property, Here it is VendTableListInteraction. Each interaction class has one override method which is selectionchanged()

Solution: 
Here we will override the method of selectionchanged() as below
[ExtensionOf(classStr(VendTableListPageInteraction))]
final class VendTableListPageInteractionCFSJSClass_Extension
public void selectionChanged()
{
    next selectionChanged();

    //for visibility
    this.listPage().actionPaneControlVisible(formControlStr(VendTableListPage, ), false);

    //for enable/disable
    this.listPage().actionPaneControlEnabled(formControlStr(VendTableListPage, true);
}

For all other ListPage, we can go through interaction class. For reference, go through below mentioned classes:

AgreementListPageInteraction
BankDocumentTableListPageInteraction
CatProcureOrderListPageInteraction
CatVendorCatalogListPageInteraction
CustBillOfExchEndorseListPageInteraction
CustomsExportOrderListPageInteraction
CustPDCListPageInteraction
CustPDCSettleListPageInteraction
CzCustAdvanceInvoiceListPageInteraction
CzVendAdvanceInvoiceListPageInteraction
EcoResCategoryHierarchyPageInteraction
EcoResProductListPageInteraction
EmplAdvTableListPageInteraction
EntAssetObjectCalendarListPageInteraction
EntAssetWorkOrderPurchaseListPageInteraction
EntAssetWorkOrderPurchReqListPageInteraction
EntAssetWorkOrderScheduleListPageInteraction
EPRetailPickingListPageInteraction
EPRetailStockCountListPageInteraction
EximAuthorizationListPageInteraction
EximDEPBListPageInteraction
EximEPCGListPageInteraction
GlobalAddBookListPageInteraction
HcmCourseAttendeeListPageInteraction
HcmWorkerAdvHoldTableListPageInteraction
InventBatchJournalListPageInteraction
InventDimListPageInteractionAdapter
JmgProdStatusListPageInteraction
JmgProjStatusListPageInteraction
PCProductModelListPageInteraction
PMFSeqReqRouteChangesListPageInteraction
ProdBOMVendorListPageInteraction
ProdRouteJobListPageInteraction
ProdTableListPageInteraction
ProjForecastListPageInteraction
ProjInvoiceListPageInteraction
ProjInvoiceProposalListPageInteraction
ProjProjectContractsListPageInteraction
ProjProjectsListPageInteraction
projProjectTransListPageInteraction
ProjUnpostedTransListPageInteraction
PurchCORListPageInteraction
PurchCORRejectsListPageInteraction
PurchLineBackOrderListPageInteraction
PurchReqTableListPageInteraction
PurchRFQCaseTableListPageInteraction
PurchRFQReplyTableListPageInteraction
PurchRFQVendorListPageInteraction_PSN
PurchRFQvendTableListPageInteraction
PurchTableVersionListPageInteraction
ReqTransActionListPageInteraction
ReqTransFuturesListPageInteraction
ReqTransListPageInteraction
RetailOnlineChannelListPageInteraction
RetailSPOnlineStoreListPageInteraction
ReturnTableListPageInteraction
SalesAgreementListPageInteraction
SalesQuotationListPageInteraction
SalesTableListPageInteraction
SysListPageInteractionBase
SysUserRequestListPageInteraction
UserRequestExternalListPageInteraction
UserRequestListPageInteraction
VendEditInvoiceHeaderStagingListPageInteraction
VendNotificationListPageInteraction
VendPackingSlipJourListPageInteraction
VendPDCListPageInteraction
VendPDCSettleListPageInteraction
VendProfileContactListPageInteraction
VendPurchOrderJournalListPageInteraction
VendRequestCategoryListPageInteraction
VendRequestListPageInteraction
VendRequestWorkerListPageInteraction
VendTableListPageInteraction
VendUnrealizedRevListPageInteraction

Thanks for reading !!!

Deploy SSRS reports through Windows Powershell in Dynamics 365 Finance and Operations

Introduction:
In this blog, we will see how to deploy SSRS reports in Microsoft Dynamics 365 Finance and Operations  

Solution: 

For on-prem environment, we will open Windows PowerShell in administrator mode and run the below scrip step by step.
cd C:\AOSService\PackagesLocalDirectory\Plugins\AxReportVmRoleStartupTask\

.\DeployAllReportsToSsrs.ps1

For online Cloudhosted/Dev environment, we will run below mentioned script
cd k:\AosService\PackagesLocalDirectory\Plugins\AxReportVmRoleStartupTask\

.\DeployAllReportsToSSRS.ps1 -PackageInstallLocation "k:\AosService\PackagesLocalDirectory"


It appears as





















When deploying reports are completed, It looks like






















Thanks for reading !!!

Thursday, April 9, 2020

Duplicate address record entry through Data entity in Dynamics 365 Finance and Operations

Introduction:
In this blog, we will see how to allow system for accepting duplicate addresses of customer, vendor or any other, through doing bit change in Data Entity 

Solution:
For allowing duplicate entries we will create one field in LogisticsPostalAddress. Here field name is as IsCreateFromEntity. Field-IsCreateFromEntity will be used as flag, type of boolean / NoYesId (EDT).

[ExtensionOf(tableStr(LogisticsPostalAddressBaseEntity))]
final class LogisticsPostalAddressBaseEntityCFSJSTable_Extension
{
    public static LogisticsLocationId resolveRemittanceAddressLocationId(LogisticsPostalAddressBaseEntity _postalAddressEntity, DirPartyNumber _partyNumber)
    {
        LogisticsLocationId locationId, locationIdCreateNew;

        locationId = next resolveRemittanceAddressLocationId(_postalAddressEntity, _partyNumber);

        if(_postalAddressEntity.IsCreateFromEntity)
        {
            locationId = locationIdCreateNew;
        }

        return locationId;
    }
}

Aforementioned code would replace the standard locationId variable with new locationIdCreateNew which will be null always. Once new variable locationIdCreateNew is replaced with standard code,  system will generate the new locationId in the LogisticsLocation(Table) and create the same duplicate address along with state, city, country, zipcode and all other respective fields.

Moreover, we will just need to pass YES value to the newly created field ISCreateFromEntity while creating the new address and run the execution. How easy it is!!!

Thanks for reading !!!

Rest API GET call in JSON format in Dynamics 365 Finance and Operations

Introduction:
In this blog, we will see how to get response from Rest Api through GET call


Solution: 
Consisting of basic authentication, we will pass username and password in byteStr and for the endpoint we will put it in url in below code.
class CFSJSTestRestAPI
{
    public static void main(Args _args)
    {
        int                                find;
        str                                url,aosUri,activeDirectoryTenant;
        str                                activeDirectoryClientAppId;
        str                                activeDirectoryClientAppSecret;
        str                                postData,activeDirectoryResource;
        str                                aadClientAppSecret,oAuthHeader;
        str                                returnValue,jsonString,jsondszstr;
        System.Net.HttpWebRequest          request;
        System.Net.HttpWebResponse         response;
        System.Byte[]                      byteArray;
        System.IO.Stream                   dataStream;
        System.IO.StreamReader             streamRead;
        System.IO.StreamWriter             streamWrite;
        System.Net.ServicePoint            servicePoint;
        System.Net.ServicePointManager     servicePointmgr;
        System.Net.HttpVersion             version;
        CLRObject                          clrObj;
        Newtonsoft.Json.JsonReader         reader;
        System.Text.Encoding               utf8;
        Counter                            countCounter;
        Object                             obj;
        Map                                data;
        System.Byte[]                      byteArraynew;
        System.Net.WebHeaderCollection     headers = new System.Net.WebHeaderCollection();
     
        new InteropPermission(InteropKind::ClrInterop).assert();
  
        str  byteStr = strfmt('%1:%2', "USERNAME", "PASSWORD");
        
        headers  = new System.Net.WebHeaderCollection();
        url      = "http://dummy.restapiexample.com/api/v1/employees";
        clrObj   = System.Net.WebRequest::Create(url);
        request  = clrObj;
        request.set_Method("GET");
        request.set_KeepAlive(true);
        request.set_ContentType("application/json");
        utf8            = System.Text.Encoding::get_UTF8();
        byteArraynew    = utf8.GetBytes(byteStr);
        byteStr         = System.Convert::ToBase64String(byteArraynew);

        headers.Add("Authorization", 'Basic ' + byteStr);
        request.set_Headers(headers);

        servicePoint = request.get_ServicePoint();

        System.Net.ServicePointManager::set_Expect100Continue(false);
        System.Net.ServicePointManager::set_SecurityProtocol(System.Net.SecurityProtocolType::Tls12);

        response    = request.GetResponse();
        dataStream  = response.GetResponseStream();
        streamRead  = new System.IO.StreamReader(dataStream);
        jsonString  = streamRead.ReadToEnd();

        info(strFmt("RESPONSE: %1",jsonString));

        dataStream.Close();
        response.Close();
    }
}

Thanks for reading !!!