Wednesday, 15 November 2023

Insert/Update or remove the default dimension value in D365 FSCM via x++

Use below method to insert/update the dimension values, just pass the parameter values to the method and it will return the updated value:

public static DimensionDefault setDefaultDimension(Name             _dimensionName,

                                                          DimensionValue   _dimensionValue,

                                                          DimensionDefault _defaultDimension)

    {

        DimensionAttributeValueSetStorage   dimStorage = new DimensionAttributeValueSetStorage();

        DimensionAttribute                  dimAttribute;

        DimensionAttributeValue             dimAttributeValue;

        DimensionValue                      dimensionValue;

        DimensionDefault                    defaultDimension = _defaultDimension;

           

        if (_dimensionValue) //If dimension value is there then insert or update it. 

        {

            ttsBegin;

            dimStorage          = DimensionAttributeValueSetStorage::find(defaultDimension);

            dimAttribute        = DimensionAttribute::findByName(_dimensionName);

            dimAttributeValue   = DimensionAttributeValue::findByDimensionAttributeAndValue(dimAttribute, _dimensionValue, true, true);

            dimStorage.addItem(dimAttributeValue);

            defaultDimension = dimStorage.save();

            ttsCommit;

        }

        else if (!_dimensionValue) //If dimension value is not there then remove it.

        {

            ttsBegin;

            dimStorage          = DimensionAttributeValueSetStorage::find(defaultDimension);

            dimAttribute        = DimensionAttribute::findByName(_dimensionName);

            dimensionValue      = ProjProjectV2Entity::FindDefaultDimensionVal(_dimensionName, _defaultDimension);// This method is defined below

            dimAttributeValue   = DimensionAttributeValue::findByDimensionAttributeAndValue(dimAttribute, dimensionValue, true, true);

            dimStorage.removeDimensionAttributeValue(dimAttributeValue.RecId);

            defaultDimension = dimStorage.save();

            ttsCommit;

        }

        return defaultDimension;

    }

    /// <summary>

    /// Find the dimension value

    /// </summary>

    /// <param name = "_dimensionName">

    /// Dimension name

    /// </param>

    /// <param name = "_defaultDimension">

    /// Default dimension value

    /// </param>

    /// <returns>

    /// Dimension value

    /// </returns>


    public static DimensionValue findDefaultDimensionVal(Name             _dimensionName,

                                                            DimensionDefault _defaultDimension)

    {

        DimensionAttributeValueSetStorage   dimStorage;

        DimensionValue                      dimensionValue;

        Counter                             i;

        dimStorage = DimensionAttributeValueSetStorage::find(_defaultDimension);

        for (i= 1 ; i<= dimStorage.elements() ; i++)

        {

            if (DimensionAttribute::find(dimStorage.getAttributeByIndex(i)).Name == _dimensionName)

            {

                dimensionValue = dimStorage.getDisplayValueByIndex(i);

            }

        }

        return dimensionValue;

    }

Tuesday, 8 August 2023

Create Multi User Printer Setup to print multiple reports at a same time

 Hi all, in this post I'm going to talk about how we create a setup where different user can select different printers according to their requirements which then prints reports for multiple records.

I have created a setup where user can print all the work orders for a production wave and these reports will be routed to the printer selected by the user in the setup below:


Step 1: Create a table with 2 fields (Printer Name and UserId) and create relations as in below screenshot:




Step 2: Now create form menu item and privileges for this table, once form is created, then user can select their favorite printer against their user Id, so next time they print specific reports then it will go to the selected printer only:





Step 3: Now create a controller class to apply the logic to your specific reports, as in below screenshot:




Friday, 17 September 2021

Batch class with lookup on dialog using Sys Operation Framework in D365 FSCM

We need to create 4 classes 

  • Controller class - This class works as the entry point for the process.
  • Service class - This class does the actual job.
  • Contract class - Handles the data values.
  • UI Builder class (optional) - This class is used to do modifications on the dialog (Like - 01) To provide lookup on the field, 02) To make any field mandatory or disabled).

  • Controller class

 /// <summary>
/// Controller class to generate the ER business document for customer invoices.
/// </summary>
class SalesContractCustCommunicationController extends SysOperationServiceController
{
    /// <summary>
    /// New method for GenerateSalesOrderController class.
    /// </summary>
    protected void new()
    {
        super();
        this.parmClassName(classStr(SalesContractCustCommunicationService));
        this.parmMethodName(methodStr(SalesContractCustCommunicationService, processOperation));
     
        this.parmDialogCaption("Your dialog caption");
    }
    /// <summary>
    /// Caption for batch dialogue.
    /// </summary>
    /// <returns>
    /// caption
    /// </returns>
    public ClassDescription caption()
    {
        return "Your class description";
    }
    /// <summary>
    /// Main method for controller class.
    /// </summary>
    /// <param name = "args">
    /// Args
    /// </param>
    public static void main(Args args)
    {
        SalesContractCustCommunicationController controller = new SalesContractCustCommunicationController();
     
        controller.startOperation();
    }



  • Service class

 /// <summary>

/// Service class to generate the ER business document for customer invoices.

/// </summary>


class SalesContractCustCommunicationService extends SysOperationServiceBase

{

    /// <summary>

    /// Process the actual operation for the class.

    /// </summary>

    /// <param name = "_datacontract">

    /// SalesContractCustCommunicationDataContract object

    /// </param>

    public Void processOperation(SalesContractCustCommunicationDataContract _datacontract)

    {

        #OCCRetryCount

        try

        {

            CustInvoiceJour custInvoiceJour;

            Args args = new Args();


//Note here SalesSubContractID is a custom field.

            select custInvoiceJour

                where custInvoiceJour.SalesSubContractId == _datacontract.parmSalesSubContractId();


            

            if (custInvoiceJour.RecId)

            {

                args.parmEnumType(enumnum(PrintCopyOriginal));

                args.parmEnum(1);

                args.record(custInvoiceJour);


                new MenuFunction(menuitemOutputStr(SalesInvoiceOriginal), MenuItemType::Output).run(args);

            }

        }

       

        catch (Exception::Deadlock)

        {

            // retry on deadlock

            retry;

        }

        catch (Exception::UpdateConflict)

        {

            // try to resolve update conflict

            if (appl.ttsLevel() == 0)

            {

                if (xSession::currentRetryCount() >= #RetryNum)

                {

                    throw Exception::UpdateConflictNotRecovered;

                }

                else

                {

                    retry;

                }

            }

            else

            {

                throw Exception::UpdateConflict;

            }

        }

        catch(Exception::DuplicateKeyException)

        {

            // retry in case of an duplicate key conflict

            if (appl.ttsLevel() == 0)

            {

                if (xSession::currentRetryCount() >= #RetryNum)

                {

                    throw Exception::DuplicateKeyExceptionNotRecovered;

                }

                else

                {

                    retry;

                }

            }

            else

            {

                throw Exception::DuplicateKeyException;

            }

        }

    }





  • Data Contract class

 /// <summary>

/// Contract class to generate the ER business document for customer invoices.

/// </summary>

[DataContractAttribute,

SysOperationContractProcessingAttribute(classStr(SalesContractCustCommunicationUIBuilder))]

class SalesContractCustCommunicationDataContract

{

  // Note, here SalesSubContractId is a custom field

    SalesSubContractId  salesSubContractId;

    

    /// <summary>

    /// sub framwork parameter for Release batch job.

    /// </summary>

    /// <param name = "_salesSubContractId">

    /// Sales sub contract Id

    /// </param>

    /// <returns>

    /// Sales sub contract Id value

    /// </returns>

    [DataMemberAttribute,

    SysOperationLabelAttribute("Your Label Attribute Value"),

    SysOperationHelpTextAttribute("Your Help Text Attribute Value"),

    SysOperationDisplayOrderAttribute('1')]

    public SalesSubContractId parmSalesSubContractId(SalesSubContractId _salesSubContractId = salesSubContractId)

    {

        salesSubContractId = _salesSubContractId;

        return salesSubContractId;

    }


}



  • UI Builder class

 /// <summary>

/// UI Builder class to generate the ER business document for customer invoices.

/// </summary>


class SalesContractCustCommunicationUIBuilder extends SysOperationAutomaticUIBuilder

{

    /// <summary>

    ///    Implements a custom lookup for dimension attribute.

    /// </summary>

    /// <param name="_control">

    ///    The <c>FormStringControl</c> for which the lookup fields must be associated.

    /// </param>

    /// <remarks>

    ///    It uses the <c>SalesContractSubFCTable</c> table for lookup.

    /// </remarks>

    public void lookupSubContractId(FormStringControl _control)

    {

        Query                   query = new Query();

        QueryBuildDataSource    qbds;

        SysTableLookup          sysTableLookup;


        if (_control != null)

        {

            // NOTE: here "SalesContractSubFCTable" is a custom table

            sysTableLookup = SysTableLookup::newParameters(tablenum(SalesContractSubFCTable), _control);

            qbds = query.addDataSource(tableNum(SalesContractSubFCTable));

            SysTableLookup.addLookupfield(fieldNum(SalesContractSubFCTable, SalesSubContractId), true);

            SysTableLookup.addLookupfield(fieldNum(SalesContractSubFCTable, SalesContractId), false);

            sysTableLookup.parmQuery(query);

            sysTableLookup.performFormLookup();

        }

    }


    /// <summary>

    /// Post build method for UI Builder class

    /// </summary>

    public void postBuild()

    {

        super();


        // get datacontract

        SalesContractCustCommunicationDataContract salesContractCustCommunicationDataContract = this.dataContractObject();


        // get dialog fields

        DialogField dialogField = this.bindInfo().getDialogField(salesContractCustCommunicationDataContract, methodstr(SalesContractCustCommunicationDataContract, parmSalesSubContractId));


        dialogField.fieldControl().mandatory(true);


        // register override methods

        dialogField.registerOverrideMethod(

            methodStr(FormStringControl, lookup),

            methodStr(SalesContractCustCommunicationUIBuilder, lookupSubContractId),

            this);


    }


}


  • Now create a menu item of type Action and provide the controller class object in it.

=================================================================



Tuesday, 14 September 2021

Add Date Time Format with timestamp as HH:MM:SS:MS to FileName in D365 FSCM

 Some time we need to add the date timestamp with Mili seconds in the time format (Dynamics _ACTUALS_Sep-2020_20210909_13111510) to our output file, so below code will do it:


class Runnable1

{

    /// <summary>

    /// Runs the class with the specified arguments.

    /// </summary>

    /// <param name = "_args">The specified arguments.</param>

    public static void main(Args _args)

    {

        str     s;

        date    dateValue = DateTimeUtil::getToday(DateTimeUtil::getUserPreferredTimeZone());

        

        s = date2Str(dateValue,

                        123,

                        DateDay::None,

                        DateSeparator::Hyphen,

                        DateMonth::Short,

                        DateSeparator::Hyphen,

                        DateYear::Digits4

                      );

        

        int time = timenow();


        System.DateTime dateTime = System.DateTime::get_UtcNow();


        str utcTimeAsStr = dateTime.ToString('HHmmssff');

         // Use this format also and see the difference in timestamp value.

        //str utcTimeAsStr = dateTime.ToString('HHmmssfff');


        str customString = s + "_" + date2Str(DateTimeUtil::getSystemDate(DateTimeUtil::getUserPreferredTimeZone()),

            321, 

            2,

            DateSeparator::None,

            2,

            DateSeparator::None,

            4)+ "_"+ utcTimeAsStr;


        Info(strFmt("Format: %1", customString));

    }


}



The Output would be:

  1. Format: Sep-2021_20210914_13043935

Wednesday, 30 June 2021

Add Grid Control to dialog form in Sys Operation Framework in D365 F&SCM

 Hi All,


Recently I have a requirement for adding the grid control to the dialog form for one of the batch processing operation using sys operation framework.

So let's explore how to do it:


  • It will be really difficult to add the grid control at run time in dialog form using code, so better to create a new form with dialog pattern as Dialog - FastTabs


  • Now in your controller class, override "templateForm" method and give our custom dialog form name as shown below:
  • This will override the standard dialog form and use our custom form.

  • Now since we have implemented a new custom form instead of standard dialog form, we will not get the option "Records to include" for filtering data as we do in standard dialog form, so to resolve this issue, create a new button in your form (Label it as "Records to include") and use the below code on click of this button to get the "Records to include" button as below:

  • In the above image "isQueryRunData" and "queryRun" are global variables, which will help us to decide when to update the standard query in executeQuery() of form data source with our new filtered query after we select some filters in our query using Records To Include button so that our data in the grid gets modified based on the filter selection as shown below:



  • Now we want to pass our modified query back to our contract class SetQuery() so that it can update the original query object of controller class with our filtered query, to get that write code as below on the click of "close ok" button of our form:


  • Now finally in the "processOperation()" of service class fetch the query using queryRun() and loop the data:
    


  • Finally this is how our form will look like:



  • Click on Records To Include Button to view the filter form:




  • Thanks for reading this, let me know if you need any clarification.

Tuesday, 1 June 2021

How to check if a customer contains a specific Location Role and find the Logistics Location Id for that specific location role

 Below method will check if a customer contains a specific Location Role or not and find the Logistics Location Id for that specific location role:


This is where you can check the location role for a customer:






public LogisticsLocationId getLogisticsLocationId(CustAccount _custAccount)

{

        DirPartyAddressLocationRoleNames    locationRoleNames;

        DirPartyPostalAddressView                   addressView;

        LogisticsLocation                                   logisticsLocation;

        CustTable                                               custTable = CustTable::find(_custAccount);


        select firstonly PartyLocation from addressView

            where addressView.Party == custTable.Party;


        locationRoleNames = addressView.locationRoles();


        str billTo = 'Bill to'; // Here you should write the name of your location role which needs to be find out.

        if (strScan(locationRoleNames, billTo, 1, strLen(locationRoleNames)))

        {

            DirPartyLocation dirPartyLocation;

            select firstonly LocationId from logisticsLocation

                join Location from dirPartyLocation

                    where logisticsLocation.RecId ==  dirPartyLocation.Location

                        && dirPartyLocation.Party == custTable.Party;

        }


        return logisticsLocation.LocationId;

    }


Wednesday, 26 May 2021

Add Lookup on Form for Customer's Contact Information

 Recently I have a requirement for adding a lookup field for Customer's Contact Information:



  • Add a string field (using EDT "Description") to the table.
  • Once the field is added in the table, bring the field to your required form.
  • Now expand the form field which we have added in the previous step, expand the "Events", now copy the OnLookup Event.
  • Now create a new class and paste the event into a new method of this class, then modify the code as below:




  • This is how the lookup appeared:



Monday, 19 April 2021

Lookup for External Items on Sales Line in D365 F&SCM X++

 Recently I have a requirement where I have to create a custom lookup for those external items on sales line which are linked to the customer on the sales order.

  • External Item Id linked with Customer:


 


  • Create a view for adding the Product Dimensions as below:






  • For Lookup of External Item Id
    • Add a custom field on the saleslines and copy it's onlookup event handler from form.
    • Create a new class and paste the copied event handler in the class, it will create a new method.
    • Use the below code lookUp:

[FormControlEventHandler(formControlStr(SalesTable, SalesLine_ExtItemId), FormControlEventType::Lookup)]
    public static void SalesLine_ExtItemId_OnLookup(FormControl sender, FormControlEventArgs e)
    {
        Query                                 query = new Query();
        QueryBuildDataSource      queryBuildDataSource, qbds;
        SysTableLookup                sysTableLookup;
        SalesLine                           salesLine = sender.dataSourceObject().cursor();

        // CustVendExtItemView is a custom view showed above.
        sysTableLookup = SysTableLookup::newParameters(tableNum(CustVendExtItemView), sender);
        queryBuildDataSource = query.addDataSource(tableNum(CustVendExtItemView));

        queryBuildDataSource.addRange(fieldNum(CustVendExtItemView, CustVendRelation)).value(salesLine.CustAccount);
        
        sysTableLookup.addLookupField(fieldNum(CustVendExtItemView, ExternalItemId), true);
        sysTableLookup.addLookupField(fieldNum(CustVendExtItemView, Description));
        sysTableLookup.addLookupField(fieldNum(CustVendExtItemView, ItemId));
        sysTableLookup.addLookupField(fieldNum(CustVendExtItemView, ExternalItemTxt));
        sysTableLookup.addLookupField(fieldNum(CustVendExtItemView, CustVendRelation));
        sysTableLookup.addLookupField(fieldNum(CustVendExtItemView, InventColorId));
        sysTableLookup.addLookupField(fieldNum(CustVendExtItemView, InventSizeId));
        sysTableLookup.addLookupField(fieldNum(CustVendExtItemView, InventStyleId));
        sysTableLookup.addLookupField(fieldNum(CustVendExtItemView, InventVersionId));

        sysTableLookup.parmQuery(query);
        sysTableLookup.performFormLookup();
    }
    • Now create a table to hold the Product Dimension value as below:



    • Copy the Modified event handler of ExternalItemId from Form DS and use the below code:
    /// <summary>
        ///
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        [FormDataFieldEventHandler(formDataFieldStr(SalesTable, SalesLine, ExtItemId), FormDataFieldEventType::Modified)]
        public static void ExtItemId_OnModified(FormDataObject sender, FormDataFieldEventArgs e)
        {
            //Custom View
            CustVendExtItemView           externalItem;
            FormDataSource                    salesLine_ds  = sender.datasource();
            SalesLine                                salesLine     = salesLine_ds.cursor();
            ExtItemId                                isbnItemId;

            //Custom Table
            CustVendExtItemTempTable  custVendExtTempTable;
            
            ttsbegin;
            delete_from  custVendExtTempTable;
            ttscommit;

            select firstonly externalItem
                where externalItem.ExternalItemId == salesLine.ExtItemId;

            if (externalItem.RecId)
            {
                ttsbegin;
                custVendExtTempTable.clear();
                custVendExtTempTable.ItemId             = externalItem.ItemId;
                custVendExtTempTable.ExternalItemId     = externalItem.ExternalItemId;
                custVendExtTempTable.ExternalItemTxt    = externalItem.ExternalItemTxt;
                custVendExtTempTable.CustVendRelation   = externalItem.CustVendRelation;
                custVendExtTempTable.Description        = externalItem.Description;
                custVendExtTempTable.InventColorId      = externalItem.InventColorId;
                custVendExtTempTable.InventSizeId       = externalItem.InventSizeId;
                custVendExtTempTable.InventStyleId      = externalItem.InventStyleId;

                custVendExtTempTable.insert();
                ttscommit;
            } 

            salesLine.ItemId    = externalItem.ItemId;     
            isbnItemId          = salesLine.ExtItemId;

            salesLine_ds.object(fieldnum(SalesLine, ItemId)).modified();

            salesLine.ExtItemId =  isbnItemId;
        }

    • Now Create a COC for SalesLineType.initFromInventTable for populating the Product Dimensions on the External Item Id:
    void initFromInventTable(InventTable _inventTable, boolean _resetPrice, AgreementHeaderRecId _matchingAgreement, boolean _executeOnlyIfProductIsFullySpecified)
        {
            next initFromInventTable(_inventTable, _resetPrice, _matchingAgreement, _executeOnlyIfProductIsFullySpecified);
            
            InventDim inventDim = salesLine.inventdim();
            
            //Custom Table
            CustVendExtItemTempTable custVendExtTempTable;

            select firstonly custVendExtTempTable;
            
            // Populate Item Number and update InventDim with Product Attribute when user selects External Item Number.
            if (custVendExtTempTable.RecId)
            {
                if (custVendExtTempTable.InventColorId)
                {
                    inventDim.InventColorId   = custVendExtTempTable.InventColorId;
                }
                if (custVendExtTempTable.InventSizeId)
                {
                    inventDim.InventSizeId = custVendExtTempTable.InventSizeId;
                }
                if (custVendExtTempTable.InventStyleId)
                {
                    inventDim.InventStyleId = custVendExtTempTable.InventStyleId;
                }
                if (custVendExtTempTable.InventVersionId)
                {
                    inventDim.InventVersionId = custVendExtTempTable.InventVersionId;
                }
            
                salesLine.InventDimId = InventDim::findOrCreate(inventDim).inventDimId;
            
                ttsbegin;
                delete_from custVendExtTempTable;
                ttscommit;
            }
            // Populate External Item Number and update InventDim with Product Attribute when user selects ItemId.
            else if (salesLine.ItemId)
            {
                CustVendExternalItem custVendExternalItem;

                select firstonly custVendExternalItem
                    where custVendExternalItem.CustVendRelation == salesLine.CustAccount
                        && custVendExternalItem.ModuleType      == ModuleInventPurchSalesVendCustGroup::Cust
                        && custVendExternalItem.ItemId          == salesLine.ItemId;

                if (custVendExternalItem.RecId)
                {
                    salesLine.ExtItemId = custVendExternalItem.ExternalItemId;

                    // Custom View
                    CustVendExtItemView externalItem;
                    
                    select firstonly externalItem
                        where externalItem.ExternalItemId == salesLine.ExtItemId;

                    if (externalItem.InventColorId)
                    {
                        inventDim.InventColorId   = externalItem.InventColorId;
                    }
                    if (externalItem.InventSizeId)
                    {
                        inventDim.InventSizeId = externalItem.InventSizeId;
                    }
                    if (externalItem.InventStyleId)
                    {
                        inventDim.InventStyleId = externalItem.InventStyleId;
                    }
                    if (externalItem.InventVersionId)
                    {
                        inventDim.InventVersionId = externalItem.InventVersionId;
                    }
            
                    salesLine.InventDimId = InventDim::findOrCreate(inventDim).inventDimId;
                }

            }
        }
    • This is how it final development will look like:
            External Items on the customer:


    LookUp on Sales Line:


    Item and its Product Dimension on Sales Line:




    Friday, 26 March 2021

    Create Default Dimension using cost centre and it's Derived Dimensions in D365 FSCM X++

     Pass the CostCentre value in the parameter to create the default dimension and fill up other dimension values from cost centre's derived dimensions:


    Below is the code, pass the cost Centre value as a parameter.

    public static DimensionDefault QTQ_CreateDerivedDimension(String20 _costCentre)
        {
            DimensionAttributeValue dimAttrValue;
            DimensionAttribute      dimAttr;
            str                     dimAttrCCValue;
            DimensionDefault        result;
            boolean                 isDerivedDimension;
                                
            dimAttrCCValue          = _costCentre;
            
            dimAttr                 = DimensionAttribute::findByName("CostCentre");//CustParameters::find().QTQ_DimAttName);
            dimAttrValue            = DimensionAttributeValue::findByDimensionAttributeAndValue(dimAttr, dimAttrCCValue, false, true);
                            
            DimensionAttributeValueDerivedDimensions    derivedDim = DimensionAttributeValueDerivedDimensions::findByDimensionAttributeValue(dimAttrValue.DimensionAttribute, dimAttrValue.RecId);
            DimensionAttributeValueSetStorage           defaultDimStorage = new DimensionAttributeValueSetStorage();
            DimensionHierarchy                          dimHierarchy = DimensionAttributeDerivedDimensions::findDimensionHierarchyForDrivingDimension(DimensionAttribute::find(derivedDim.DimensionAttribute));
            DimensionHierarchyLevel                     dimHierarchyLevel;
            DimensionAttributeDerivedDimensions         derivedDimensions;

            while select RecId, DimensionAttribute from dimHierarchyLevel
                                    where dimHierarchyLevel.DimensionHierarchy == dimHierarchy.RecId
                                        join DerivedDimensionFieldNum from derivedDimensions
                                            where derivedDimensions.DimensionHierarchyLevel == dimHierarchyLevel.RecId
            {
                DimensionAttributeValueRecId    davRecId = derivedDim.(derivedDimensions.DerivedDimensionFieldNum);
                DimensionAttributeValue         dav = DimensionAttributeValue::find(davRecId);

                defaultDimStorage.addItemValues(dimHierarchyLevel.DimensionAttribute, dav.RecId, dav.HashKey);
                isDerivedDimension = true;
            }

            // If there is no derived dimension available then at-least create the default dimension with Cost Centre Value only.
            if (!isDerivedDimension)
            {
                defaultDimStorage.addItem(dimAttrValue);
            }
            result = defaultDimStorage.save();
            return result; 
        }


    Monday, 1 February 2021

    Add new Label File in D365 F&SCM

    •  Create a new project, right click on project and add new label file as shown below
    • Click on Add button in above image, next screen will appear as below
    • Select all languages (as shown in above image) in which you want to generate your label files, for eg I want my label files for en-US & en-GB.
    • Click on Next and then click on Finish as in below image and you will get your Label files 


    Sunday, 3 January 2021

    Validate the combination of Main Account (Ledger Dimension) with Financial Dimensions (Default Dimension)

     Hi All,

    Recently I came up with a requirement to validate the combination of Main Account and Default Dimensions in D365 F&&SCM, so sharing the piece of code, hope it help someone.


    public static boolean validateAccountStructureAndDefaultDim(

                                DimensionDefault        _defaultDimensions, 

                            LedgerDimensionBudget   _ledgerDimension,

                                TransDate               _transactionDate)

        {

            DimensionValidationStatus   dimensionValidationStatus = DimensionValidationStatus::Valid;

            boolean                     ret;

            

            LedgerDimensionAccount ledgerDimensionAccount = DimensionDerivationDistributionRule::buildLedgerDimension(_ledgerDimension, _defaultDimensions);

            dimensionValidationStatus = LedgerDimensionValidationHelper::validateByTree(ledgerDimensionAccount, _transactionDate, true, true);


            if (dimensionValidationStatus == DimensionValidationStatus::Valid)

            {

                ret = true;

            }

            return ret;

        }


    This piece of code can be used as below:


    //Select all the lines for validation

    while select LedgerDimension, DefaultDimension, LineNum from custInvoiceLine

                where custInvoiceLine.ParentRecId == _custInvoiceTable.RecId

            {

                if (!custInvoiceLine.DefaultDimension) // Validation to check if atleast 1 financial dimension value is specified. 

                {

                    canSubmitToWorkflow = checkFailed("Atleast 1 Financial Dimension value must be specified.");

                }


                if (canSubmitToWorkflow)

                {

    // Call to our method

                    canSubmitToWorkflow = QTQ_CustFreeInvoiceWorkflow::validateAccountStructureAndDefaultDim(custInvoiceLine.DefaultDimension, custInvoiceLine.LedgerDimension, today());

                }

            }

    Insert/Update or remove the default dimension value in D365 FSCM via x++

    Use below method to insert/update the dimension values, just pass the parameter values to the method and it will return the updated value: p...