Thursday, June 15, 2023

Enable and Disable Vendor invoice button on PO list and details page X++

Hi folks,

This blog will be useful where vendor invoice process is required to be controlled based on certain conditions.

Requirements:

Procurement department wants to have control on Vendor invoicing process due to which they need PO on hold for Vendor Invoice functionality. 

Once, the PO is on hold then users shouldn't be able to process the invoice which means that Vendor invoice button should be disabled for on hold POs.

Solution:

Standard Microsoft "PurchTableType" class is responsible for handling the logic related to enabling and disabling of controls on the action pane of PO list and details page therefore extending the logic on this class is suffice to fulfill the requirements.

I added the custom onhold flag field as a control field to enable or disable the Vendor invoice button. You can apply your logic based on your requirements. 

"CanInvoiceBeUpdated" is the method which is being called to enable and disable Vendor invoice button on PO list and details page and returns boolean value. If this method returns false then Vendor invoice button will be disabled otherwise enabled.

Below is the code snippet of the solution:

 [ExtensionOf(classStr(PurchTableType))]  
 final class DemoPurchTableType_Extension  
 {  
   public boolean canInvoiceBeUpdated(boolean _excludePending)  
   {  
      next canInvoiceBeUpdated(false);  
   
      //You can apply your logic here.  
      if(this.purchTable.OnHold == NoYes::Yes)  
      {   
        return false;  
      }  
    }  
 }  

Wednesday, May 31, 2023

SQL script to retrieve the list of active users with license details D365 FnO

Hi guys,

I am writing this blog to share the information regarding active users license details in D365 FnO. 

Below is the SQL script that will fetch list of active users, roles and their license details.

Select userId.ID as "User id",
       userId.NAME as "User name", 
       securityRole.NAME AS "Role name",
       securityRole.description AS "Role description",      
       ISNULL(internalOrganization.NAME,'All') as "Legal entity", 
       (CASE securityRole.USERLICENSETYPE
        WHEN 4 Then 'Operations'
        WHEN 6 Then 'Team Members'
        WHEN 7 Then 'Activity'
        Else 'Unknown' end) as "License type"
       from userInfo userid
       inner JOIN SECURITYUSERROLE UserRole
       on UserRole.USER_ = userid.ID
       inner JOIN AXDB.dbo.SECURITYROLE securityRole
       on securityRole.RecId = UserRole.SecurityRole
       LEFT JOIN OMUserRoleOrganization roleOrganization
       on roleOrganization.SecurityRole = UserRole.SecurityRole
       AND roleOrganization.USER_ = userid.Id
       LEFT JOIN DIRPARTYTABLE internalOrganization
       on internalOrganization.RECID = roleOrganization.OMINTERNALORGANIZATION
       left join SYSUSERLICENSELIST ssul
       on  ssul.username = userid.ID
       left join SYSUSERLICENSECOUNT sslc
       on  sslc.recid = ssul.SYSUSERLICENSECOUNT
where userid.ENABLE = '1'
order by userid.ID

Tuesday, May 23, 2023

How to extend Form datasource method X++

Hi guys,

This blog will be useful in those scenarios where in standard MS Form datasource methods (init, write, validateWrite, active, selectionChanged etc) will be required to further extend the standard functionality.

Requirement:
I came across a requirement on which I had to disable the standard MS field on the basis of a true value on custom boolean field. If custom flag field contains true value then target field "Allow reservation" on the return sales order line should be disabled as a result of focus set on that selected return sales order line.

Solution:
Right click on the Form datasource active method and then click create an extension to create an extension class.
 [ExtensionOf(formDataSourceStr(ReturnTable, SalesLine))]  
 final class DemoReturnTableSalesLineFrm_Extension  
 {  
   int active()  
   {  
     int ret = next active();  
     SalesLine salesLine = this.cursor();  
     SalesTable salesTable = SalesTable::find(salesLine.SalesId);  
     FormRun formRun = this.formRun();  
     if(salesTable.DemoPriceAdjustment)  
     {  
       formRun.control(formRun.controlId(formControlStr(ReturnTable, return_ReturnAllowReservation))).enabled(false);  
     }  
     return ret;  
   }  
 }  

Friday, May 19, 2023

How to extend lookup method and apply query range on the standard MS form X++

Hi folks

In this blog, I am going to explain how lookup control on the standard form can be overridden. 

Requirement:

I got the requirement from the customer where in user wants to select Operating unit of type "Department" from the drop down list on the custom fast tab which contains the custom fields on the grid.

Since, Operating units are shared across mutiple legal entities therefore lookup control will display Departments across all companies.

Solution: 

Create a class that will handle the logic of overriding the lookup control and applying the range of Operating unit of type "Department" on the lookup. This class is being called on the Form event handler on the lookup control

Form control lookup override extension class:

 public class DemoLogisticsPostalAddressFormExtensionOverrides  
 {  
   protected void new()  
   {  
   }  
   public static DemoLogisticsPostalAddressFormExtensionOverrides construct()  
   {  
     return new DemoLogisticsPostalAddressFormExtensionOverrides();  
   }  
   public Common lookupReference(FormReferenceControl _formReferenceControl)  
   {  
     return OMOperatingUnitHelper::operatingUnitLookup(_formReferenceControl,     OMOperatingUnitType::OMDepartment);  
   }  
   public Common resolveReference(FormReferenceControl _formReferenceControl)  
   {  
     // Do not call super since we're providing our own disambiguation logic.  
     return OMOperatingUnitHelper::operatingUnitResolve(_formReferenceControl, OMOperatingUnitType::OMDepartment);  
   }  
 }  
Form datasource event handler class:

Create a form datasource event handler class for the control on which Departments will be displayed.

Create datasource post event handler initialize method

 public class DemoLogisticsPostalAddressFrmEventHandler  
 {  
   [FormDataSourceEventHandler(formDataSourceStr(LogisticsPostalAddress, DemoDeliverySettings), FormDataSourceEventType::Initialized)]  
   public static void DemoLogisticsPostalAddress_OnInitialized(FormDataSource _sender, FormDataSourceEventArgs _e)  
   {  
     var overrides = DemoLogisticsPostalAddressFormExtensionOverrides::construct();   
     
     _sender.object(fieldNum(DemoShiftDeliverySettings, Department)).registerOverrideMethod(methodStr(FormDataObject, lookupReference),  
       methodStr(DemoLogisticsPostalAddressFormExtensionOverrides, lookupReference), overrides);
       
     _sender.object(fieldNum(DemoShiftDeliverySettings, Department)).registerOverrideMethod(methodStr(FormDataObject, resolveReference),  
       methodStr(DemoLogisticsPostalAddressFormExtensionOverrides, resolveReference), overrides);  
   }  
 }  

Friday, August 12, 2022

Download an external file from Azure blob storage in D365 FO X++

Hi folks, 

This post will be useful in scenario where an external file is stored in Azure blob storage and users wants to download that external file without having it stored in D365 FO database. 

Requirement:

Recently, I came across a requirement where I had to access the external file from Azure blob storage and then download that external file for the user from D365 FO application although the file doesn't even exist in D365 FO database. 

Solution:

Below is the code snippet of the solution that can be used to download external file for the users.

 class ExternalFileDownload  
 {  
   public static void main(Args _args)  
   {  
     str url;  
     System.Net.HttpWebRequest httpRequest;  
     System.Net.HttpWebResponse httpResponse;  
     CLRObject clro;  
     System.IO.MemoryStream memoryStream = new System.IO.MemoryStream();  
     Browser browser = new Browser();  
     url = "https://[azureblobstorageurloftenant].blob.core.windows.net/temporary-file/%7B81D4B98A-1989-4B13-B056-684FE6AA86C7%7D/CustGroupPackage_340228B4-1D45-4DC9-9931-5C4900457149_DMFPackage.zip?sv=2014-02-14&sr=b&sig=1uHDh1D%2FqDScyDXE8rPA7HfLgTCnleYd0cPp%2FCkmwwg%3D&st=2022-06-14T16%3A14%3A49Z&se=2022-06-14T17%3A19%3A49Z&sp=r";  
     clro = System.Net.WebRequest::Create(url);  
     httpRequest = clro;  
     httpRequest.set_Method("GET");  
     httpRequest.set_KeepAlive(true);  
     httpRequest.set_ContentType("application/json");  
     httpResponse = httpRequest.GetResponse();  
     httpResponse.GetResponseStream().CopyTo(memoryStream);  
     FileUploadTemporaryStorageResult result = File::SendFileToTempStore_GetResult(memoryStream, "Sample");  
     browser.navigate(result.getDownloadUrl(), true);  
     memoryStream.Close();  
     httpResponse.Close();  
   }  
 }  

Saturday, August 6, 2022

Auto submission of workflow X++

Hi folks,

In this blog, I am going to explain how to submit workflow automatically for approval without user interaction in D365 FO.

Requirement:

I got a requirement where in Vendor master data workflow was required to be submitted automatically for approval because Vendors were created through integration and not manually by D365 FO users.

As part of business process, vendor workflow approval process was configured and implemented for finance key users in D365 FO.

Solution:

As soon as Vendors are created through integration, submit workflow action is triggered by applying the below logic. 

 class AutoWorkflowSubmit  
 {  
   public static void main(Args args)  
   {  
     //Get the VendTable RecId for the vendor to submit the workflow  
     RecId recId;  
     try  
     {  
       ttsbegin;  
       //Pass the recId of VendTable in Workflow class that is responsible to trigger the workflow submit action  
       //Activate the workflow  
       Workflow::activateFromWorkflowType(workFlowTypeStr(VendTableChangeProposalWorkflow), recId, "@AccountsPayable:VendChangeProposalSubmit_SubmittedMessage", NoYes::No);  
       //Pass the recId of VendTable in VendTable class that is responsible to update the workflow status as Submitted  
       VendTable::updateWorkflowState(recId,VendTableChangeProposalWorkflowState::Submitted);  
       ttscommit;  
     }  
     catch(exception::Error)  
     {  
       throw Error("Not submitted");  
     }  
   }  
 }  

Saturday, July 9, 2022

Financial dimension sets values lookup X++

Hi guys,

In this blog, I will explain how to create Financial dimension sets values lookup.

Requirement:

I came across a requirement where in Financial dimension sets values lookup were required on the dialog form and General ledger balances for Main accounts with Financial dimensions calculated based on the Financial dimension set values selected on the dialog form just like calculation on General ledger trial balance form.

Solution:

Create an extended class that handles the logic of loading Financial dimension sets values on dialog control lookup.

Extend the class with SysLookup class to reuse SysTableLookup methods for generating lookup from the SysLookup class

 class FinDimSetValuesLookup extends SysLookup  
 {  
   /// <summary>  
   /// This method is used to load Financial dimension sets values on dialog control lookup  
   /// </summary>  
   /// <param name="_formControl">Gets the form control of financial dimension sets lookup</param>  
   public void dimensionHierarchyLookup(FormControl _formControl)  
   {  
     Query             query;  
     SysTableLookup     sysTableLookup;  
     QueryBuildRange     queryBuildRange;  
     QueryBuildDataSource  qbds;  
     query = new Query();  
     qbds = query.addDataSource(tableNum(DimensionHierarchy));  
     // Filter dimension hierarchy to only show focuses that are not deleted.  
     queryBuildRange = qbds.addRange(fieldnum(DimensionHierarchy, StructureType));  
     queryBuildRange.value(queryValue(DimensionHierarchyType::Focus));  
     queryBuildRange.status(RangeStatus::Hidden);  
     queryBuildRange = qbds.addRange(fieldnum(DimensionHierarchy, DeletedVersion));  
     queryBuildRange.value(queryValue(0));  
     queryBuildRange.status(RangeStatus::Hidden);  
     sysTableLookup = SysTableLookup::newParameters(tableNum(DimensionHierarchy), _formControl, true);  
     sysTableLookup.addLookupfield(fieldNum(DimensionHierarchy, Name));  
     sysTableLookup.parmQuery(query);  
     sysTableLookup.performFormLookup();  
   }  
 }  

Enable and Disable Vendor invoice button on PO list and details page X++

Hi folks, This blog will be useful where vendor invoice process is required to be controlled based on certain conditions. Requirements: Proc...