Showing posts with label System Administrator. Show all posts
Showing posts with label System Administrator. Show all posts

Thursday, August 6, 2026

Export label custom content

 GRID => Properties

"Export Label" => "SalesReportMexico"


To get download file with custom naming. 

Thursday, July 9, 2026

validateExistCommonRecord in D365FO X++

validateExistCommonRecord(

    RefTableId _refTableId,

    RefRecId _refRecId)

{

    boolean ret = true;

    if (!_refTableId || !_refRecId)

    {

        ret = CheckFailed(strFmt("Incorrect parameter for the function called ", funcName()));

    }


    if (ret)

    {

        Common record = new DictTable(_refTableId).makeRecord();


        select firstonly RecId from record

            where record.RecId == _refRecId;


        if (!record.RecId)

        {

            ret = checkFailed("Record not found");

        }

    }


    return ret;

}

Friday, May 8, 2026

Get or set adjust tax calculated amount using TAXDOCUMENT framework (Tax calculation service) in D365FO

 //Get or adjust tax calculation using TAXDOCUMENT framework (Tax calculation service)

TaxRegulation taxRegulationDetail;

TmpTaxRegulation  tmpTaxRegulationDetail;

SalesTotals salesTotals;


salesTotals = SalesTotals::construct(SalesTable::find(salesLineParentPOl.SalesId), SalesUpdate::All);

salesTotals.calc();


taxRegulationDetail = TaxRegulation::newTaxRegulation(salesTotals.tax());

tmpTaxRegulationDetail.setTmpData(taxRegulationDetail.tmpTaxRegulation()); // Get all current tax by order wise


//Get this buffer "tmpTaxRegulationDetail" to get all tax related data

//To adjust

TaxTable    taxTable;

select firstonly tmpTaxRegulationDetail

    where tmpTaxRegulationDetail.TaxCode

    join taxTable

        where taxTable.TaxCode == 'SAN_IPI';

if(tmpTaxRegulationDetail)

{

    taxRegulationDetail.updateTaxRegulationAmount(tmpTaxRegulationDetail, (<Updated tax amount after adjustment>), true); // to adjust use this call to do

    taxRegulationDetail.saveTaxRegulation(); //

}

Wednesday, March 4, 2026

Error readable from string in D365FO

 Reference class: RetailSyncOrdersSchedulerTask

Error readable:

private str generateHumanReadableErrorDetail(System.Exception _exception, str _errorDetail = '')

{

    str errorDetail, exceptionType, stackTrace, exceptionMessage;


    errorDetail = _errorDetail;

    // When the CLR error encounters it gets the inner exception message, call stack and stores in Database.

    if (_exception && _exception.InnerException)

    {

        if (_exception.InnerException.InnerException && _exception.InnerException.StackTrace)

        {

            // Use inner exception if it is available as it is often more descriptive.

            errorDetail = errorDetail ? errorDetail +

                        _exception.InnerException.InnerException.Message : _exception.InnerException.InnerException.Message +

                         _exception.InnerException.StackTrace.ToString();

        }

        else if (_exception.InnerException.StackTrace)

        {

            errorDetail = _exception.InnerException.Message +  _exception.InnerException.StackTrace.ToString();

        }

        else

        {

            // When the exeption not returns a call stack, we get the call stack from the <c>Xsession<c> object.

            errorDetail = _exception.InnerException.Message + con2str(xSession::xppCallStack());

        }

    }


    return errorDetail;

}

Thursday, January 1, 2026

Dynamically setting entire Form security access through Extension in D365FO

/// <summary>

/// To check if user can get access to the Parameter form

/// </summary>

class SAN_ParamFormsAccessCtrl

{

    protected void new()

    {

        super();

    }


    static SAN_ParamFormsAccessCtrl construct()

    {

        return new SAN_ParamFormsAccessCtrl();

    }


    public boolean validateUserRoleAccess()

    { 

        #characters

        UserId                  userId = curUserId();

        container               tmpValues; 

        SecurityRole            securityRole;

        SecurityUserRole        securityUserRole;

        int                     idx;

        boolean                 isValidated = false;

        Str                     secRoleList;

        //Created new custom parameter to have which roles alone should have EDIT access, apart from this any roles would have only READ access even System admin

        secRoleList = SAN_IntegrationParameters::find().ParametersAccessSecurityRole;


        if(secRoleList)

        {

            tmpValues = str2con(secRoleList, #semicolon);


            for(idx=1; idx<=conLen(tmpValues); idx++)

            {

                securityRole.clear();

                select firstonly securityRole

                where securityRole.Name == conPeek(tmpValues, idx);


                if(securityRole.RecId && !isValidated)

                {

                    securityUserRole.clear();

                    select firstonly RecId from securityUserRole

                    where securityUserRole.User == userId

                        && securityUserRole.SecurityRole == securityRole.RecId;


                    if (securityUserRole.RecId)

                    {

                        isValidated = true;

                    }

                }

            }

        }


        return isValidated;

    }


    public void disableFormDataSources(FormRun _callingForm)

    {


        FormBuildDataSource frmBuildDS;

        int i;

        for(i = 1; i<= _callingForm.form().dataSourceCount(); i++)

        {

            frmBuildDS = _callingForm.form().dataSource(i);

            frmBuildDS.allowEdit(false);

        }


    }


    public boolean checkRoleCtrlAccess(FormRun _callingForm)

    {

        boolean userHasAccess = this.validateUserRoleAccess();


        if(!userHasAccess)

        {

            this.disableFormDataSources(_callingForm);

        }


        return userHasAccess;

    }


}



[ExtensionOf(formStr(LedgerParameters))]

final class LedgerParametersFrm_SAN_Extension

{

    public void init()

    {

        next init();


        SAN_ParamFormsAccessCtrl paramFormsAccessCtrl;

        paramFormsAccessCtrl = SAN_ParamFormsAccessCtrl::construct();


        if(!paramFormsAccessCtrl.checkRoleCtrlAccess(this))

        {

            this.san_lockControls();

        }

    }


    void san_lockControls()

    {

        FormBuildControl  formBuildControl;

        int i;


        for (i=1;i<=this.form().design().controlCount(); i++)

        {

            formBuildControl = this.form().design().controlNum(i);

            this.control(formBuildControl.id()).enabled(false);

        }

    }


}

Tuesday, December 2, 2025

Override custom dimension value on posting sales invoice in X++

 Requirement:

1. Override custom dimension value on posting sales invoice

2.  Ledger posting type as "Cost of goods, invoiced" & "Sales revenue"

3. Reason: Requirement is to default for certain orders type, these account has to be changed. 

4. Why can't we acheive in Customer or item level dimension. [Reason: Currently it was managed in item level, but requirement is to for same item if order type met certain criteria on posting, this need to defaulted with this dimension value for ledger reporting]


Class 1:

 

/// <summary>

///    The <c>LedgerVoucherTransObject</c> class represents a single transaction in an individual voucher. COC

/// </summary>

/// <remarks>

///    The transaction is stored in a temporary instance of a <see cref="T:LedgerTrans" /> record buffer.

///    The temporary transaction is inserted into the database during posting and made a permanent record.

/// </remarks>

[ExtensionOf(ClassStr(LedgerVoucherTransObject))]

final class LedgerVoucherTransObjectCls_SAN_Extension

{

    /// <summary>

    ///    Initializes a new instance of the <c>LedgerVoucherTransObject</c> class by using a transaction COC POL

    ///    currency amount and a ledger posting reference for defaulting.

    /// </summary>

    /// <param name="_defaultLedgerPostingReference">

    ///    The ledger posting reference to use for defaulting.

    /// </param>

    /// <param name="_postingType">

    ///    The posting type of the general journal entry.

    /// </param>

    /// <param name="_ledgerDimensionId">

    ///    The dimension attribute value combination of the general journal entry.

    /// </param>

    /// <param name="_transactionCurrencyCode">

    ///    The currency code of the general journal entry.

    /// </param>

    /// <param name="_transactionCurrencyAmount">

    ///    The amount in the transaction currency.

    /// </param>

    /// <param name="_exchangeRateHelper">

    ///    The accounting currency amount and secondary currency amount exchange rates.

    /// </param>

    /// <returns>

    ///    A new instance of the <c>LedgerVoucherTransObject</c> class.

    /// </returns>

    /// <remarks>

    ///    The default ledger posting reference is used to set the transaction type and exchange rate date.

    /// </remarks>

    public static LedgerVoucherTransObject newTransactionAmountDefault(

        LedgerVoucherObject _defaultLedgerPostingReference,

        LedgerPostingType _postingType,

        LedgerDimensionAccount _ledgerDimensionId,

        CurrencyCode _transactionCurrencyCode,

        Money _transactionCurrencyAmount,

        CurrencyExchangeHelper _exchangeRateHelper)

    {

        LedgerVoucherTransObject polpostingTrans;

        LedgerDimensionAccount  ledgerDimensionAccount, tempLedgerDimenionAcc;

        ledgerDimensionAccount = _ledgerDimensionId;

 

        if(ledgerDimensionAccount && (_postingType == LedgerPostingType::SalesConsump

            || _postingType == LedgerPostingType::SalesRevenue))

        {

            SAN_SalesInvoiceDimensionMockContext contextCur = SAN_SalesInvoiceDimensionMockContext::current();

            if(contextCur != null)

            {

                if(contextCur.isParameterActive && contextCur.isValidToOverride && contextCur.polproductLineToOverride)

                {

                    tempLedgerDimenionAcc = _ledgerDimensionId;

 

                    ledgerDimensionAccount = SalesInvoiceJournalPost::SAN_buildDefaultAndLedgerDimension(tempLedgerDimenionAcc,contextCur.polproductLineToOverride);

                }

            }

        }

 

        polpostingTrans = next newTransactionAmountDefault(_defaultLedgerPostingReference, _postingType, ledgerDimensionAccount, _transactionCurrencyCode, _transactionCurrencyAmount, _exchangeRateHelper);

 

        return polpostingTrans;

    }

 

}

 

 

Class 2:

/// <summary>

/// To hold the value of SAN_SalesInvoiceDimensionMockContext through out the runtime.

/// </summary>

class SAN_SalesInvoiceDimensionMockContext implements System.IDisposable

{

    public  boolean  isParameterActive;

    public  boolean  isValidToOverride;

    public  SalesTable      polsalesTable;

    public  str             polsmmSegmentId;

    public  str             polproductLineToOverride;

    static  SAN_SalesInvoiceDimensionMockContext   instance;

 

    protected void new ()

    {

        if (instance)

        {

            throw Error('Nesting of SAN_SalesInvoiceDimensionMockContext is not supported');

        }

 

        instance = this;

    }

 

    /// <summary>

    ///  To Create the instance wherever the method is called during the run time.

    /// </summary>

    /// <returns>current new instance</returns>

    Public static SAN_SalesInvoiceDimensionMockContext createInstance()

    {

        SAN_SalesInvoiceDimensionMockContext newInstance = new SAN_SalesInvoiceDimensionMockContext();

        instance = newInstance;

 

        return instance;

    }

 

    /// <summary>

    /// Dispose the instance once the Aging snapshot batch is run.

    /// </summary>

    public void dispose()

    {

        instance = null;

    }

 

    /// <summary>

    ///  To get the instance wherever the method is called during the run time.

    /// </summary>

    /// <returns>Current instance</returns>

    public static SAN_SalesInvoiceDimensionMockContext current()

    {

        return instance;

    }

 

}

 

 

Class 3:

/// <summary>

/// Extension of class SalesInvoiceJournalPost

/// </summary>

[Extensionof (classstr(SalesInvoiceJournalPost))]

Public Final class SalesInvoiceJournalPostCls_SAN_Extension

{

    /// <summary>

    ///     Posts to inventory.

    /// </summary>

    protected void postInventory()

    {

        using(SAN_SalesInvoiceDimensionMockContext contextSet = SAN_SalesInvoiceDimensionMockContext::createInstance())

        {

            if(SalesParameters::find().SAN_OverrideDimensionValue)

            {

                contextSet.isParameterActive = true; 

                SalesTable      salesTable;

                salesTable =  salesLine.SalesTable();

                if(salesTable && salesLine)

                {

                     contextSet.polsalesTable = salesTable;

                        contextSet.isValidToOverride = true;

                        contextSet.polproductLineToOverride = '09';

                }

            }

            next postInventory();

        }

    }

 

    /// <summary>

    ///     Posts one journal line.

    /// </summary>

    protected void postLine()

    {

        using(SAN_SalesInvoiceDimensionMockContext contextSet = SAN_SalesInvoiceDimensionMockContext::createInstance())

        {

           if(SalesParameters::find().SAN_OverrideDimensionValue)

            {

                contextSet.isParameterActive = true;

 

                SalesTable      salesTable;

                salesTable = salesParmLine.SalesLine().SalesTable();

                if(salesTable && salesParmLine  )

                {

                   contextSet.polsalesTable = salesTable;

                        contextSet.isValidToOverride = true;

                        contextSet.polproductLineToOverride = '09';

                }

            }            

            next postLine();

        }

    }

 

    /// <summary>

    /// buildDefaultAndLedgerDimension for govt and non-govt segment

    /// </summary>

    /// <param name = "_ledger">LedgerDimensionAccount</param>

    /// <param name = "_overridePL">overridePL</param>

    /// <returns>ledgerDimensionAccount</returns>

    Static ledgerDimensionAccount  SAN_buildDefaultAndLedgerDimension(LedgerDimensionAccount   _ledger, str _overridePL)

    {

        DimensionAttributeValueSetStorage   dimensionAttributeValueSetStorage;

        DimensionAttributeValue             dimensionAttributeValue;

        DimensionDefault                    dimensionDefault;

        LedgerDimensionAccount              ledgerDimensionAccount;

        DimensionAttributeLevelValueAllView dimAttrValueallview;

        dimensionAttributeValueSetStorage = new DimensionAttributeValueSetStorage();

        RefRecId            mainAccountRecId, LedgerDimensionAcc;

        mainAccountRecId = LedgerDimensionFacade::getMainAccountRecIdFromLedgerDimension(_ledger);

        LedgerDimensionAcc = LedgerDefaultAccountHelper::getDefaultAccountFromMainAccountRecId(mainAccountRecId);

 

        while select dimAttrValueallview 

            where dimAttrValueallview.ValueCombinationRecId == _ledger

        {

            if(DimensionAttribute::find(dimAttrValueallview.DimensionAttribute).Name != "MainAccount")

            {

                if(DimensionAttribute::find(dimAttrValueallview.DimensionAttribute).Name == "ProductLine")

                {

                    dimensionAttributeValue = DimensionAttributeValue::findByDimensionAttributeAndValue(

                                    DimensionAttribute::find(dimAttrValueallview.DimensionAttribute),

                                    _overridePL, false, true);

                }

                else

                {

                    dimensionAttributeValue = DimensionAttributeValue::findByDimensionAttributeAndValue(

                                    DimensionAttribute::find(dimAttrValueallview.DimensionAttribute),

                                    dimAttrValueallview.DisplayValue, false, true);

                }

                dimensionAttributeValueSetStorage.addItem(dimensionAttributeValue);

                dimensionDefault = dimensionAttributeValueSetStorage.save();

            }

        }

        ledgerDimensionAccount = LedgerDimensionFacade::serviceCreateLedgerDimension(LedgerDimensionAcc,dimensionDefault);

        return ledgerDimensionAccount;

    }

 

}

Thursday, November 27, 2025

Changing instance of class to extension class to trigger logic on extension layer

Details:

In case, extensible support for class instance to reinstance with different class to execute on Extension layer.


public static SANSyncInventTable construct(Common _record, Common _record_orig, boolean _isUpdate)

{

    SANSyncInventTable syncRecordInventTable;

    syncRecordInventTable = new SANSyncInventTable(_record, _record_orig, _isUpdate);

    return syncRecordInventTable;

}


[PostHandlerFor(classStr(SANSyncInventTable), staticMethodStr(SANSyncInventTable, construct))]

public static void SANSyncInventTable_Post_construct(XppPrePostArgs args)

{

    args.setReturnValue(SAN_SANSyncInventTable::construct(args.getArg(identifierStr(_record))

        ,args.getArg(identifierStr(_record_orig))

        ,args.getArg(identifierStr(_isUpdate))));

}


Wednesday, November 19, 2025

DMF export using X++

Base class for extract

 /// <summary>

/// Class for extract data

/// </summary>

class SAN_SalesReportDailyService

{

    Filename                filename;

    int                     recordCnt;


    /// <summary>

    /// Import warranty claims

    /// </summary>

    /// <param name = "_contract">Contract of type <b>SAN_SalesReportDailyContract</b></param>

    [SysEntryPointAttribute(false)]

    public void processImport(SAN_SalesReportDailyContract _contract)

    {

        contract            = _contract;


        try

        {

            this.exportSalesInvoiceData();

              

            if (recordCnt)

            {

                info(strFmt("@SANaris:FileExportInfo", filename));

            }

        }

        catch

        {

            error("@SYP4861341");

        }


    }


    public void exportSalesInvoiceData()

    {

        #DMF

        SharedServiceUnitFileID fileId;

        SAN_DataEntityExporter exporter = new SAN_DataEntityExporter();


        DMFDefinitionGroupName definitionGroupName = SalesParameters::find().SAN_SalesDailyReportDefinitionGroup; //TODO create new parameter field to get DMF execution

        DMFDefinitionGroupEntity dmfDefinitionGroupEntity = SAN_SalesReportDailyService::findDMFDefinitionGroupEntity(definitionGroupName);


        if (dmfDefinitionGroupEntity)

        {

            this.updateQueryData(dmfDefinitionGroupEntity);

            this.setFileName();

 

            exporter.parmFilename(filename);

            exporter.exportDataEntity(definitionGroupName, dmfDefinitionGroupEntity.Entity);

        }

        else

        {

            throw error(strFmt("@SANaris:DataEntityMapError", definitionGroupName));

        }

    }


    public str setFileName()

    {

        #File

        str priFix;


        priFix = 'SalesReportSAN_';


        filename = priFix +

            date2str(systemDateGet(),123,DateDay::Digits2,DateSeparator::None,DateMonth::Digits2,DateSeparator::None,DateYear::Digits4) + #xlsx;


        return filename;

    }


    private void updateQueryData(DmfDefinitionGroupEntity _dmfDefinitionGroupEntity)

    {

        container queryData = _dmfDefinitionGroupEntity.QueryData;


        if (queryData == connull())

        {

            queryData = DMFUtil::getDefaultQueryForEntityV3(_dmfDefinitionGroupEntity.Entity, _dmfDefinitionGroupEntity.DefinitionGroup);

        }


        QueryRun queryRun = new QueryRun(queryData);

        Query query = queryRun.query();


        QueryBuildDataSource qbds = query.dataSourceTable(tableNum(SAN_SalesReportDailyEntity));

        SysQuery::findOrCreateRange(qbds, fieldNum(SAN_SalesReportDailyEntity, InvoiceDate)).value(queryRange(fromDate, toDate));

        if (warehouseId)

        {

            SysQuery::findOrCreateRange(qbds, fieldNum(SAN_SalesReportDailyEntity, Warehouse)).value(queryValue(warehouseId));

        }


        queryRun = new QueryRun(query);

        queryData = queryRun.pack();

        

        recordCnt = SysQuery::countTotal(queryRun);

        if (recordCnt < 1)

        {

            throw error("@SYS4205");

        }


        ttsbegin;

        _dmfDefinitionGroupEntity.reread();

        _dmfDefinitionGroupEntity.selectForUpdate(true);

        _dmfDefinitionGroupEntity.QueryData = queryData;

        _dmfDefinitionGroupEntity.update();

        ttscommit;

    }


    /// <summary>

    /// Finds the <c>DMFDefinitionGroupEntity</c> record in the given definition group for the Line active view record entity.

    /// </summary>

    /// <param name = "_definitionGroupName">The name if the definition group</param>

    /// <returns>the <c>DMFDefinitionGroupEntity</c> record if found, otherwise null</returns>

    public static DMFDefinitionGroupEntity findDMFDefinitionGroupEntity(DMFDefinitionGroupName _definitionGroupName)

    {

        DMFDefinitionGroupEntity definitionGroupEntity;

        DMFEntity dmfEntity;

        str targetEntityName;


        targetEntityName = 'SAN_SalesReport';


        select firstonly RecId, Entity, DefinitionGroup from definitionGroupEntity

            exists join dmfEntity

                where definitionGroupEntity.DefinitionGroup == _definitionGroupName

                    && dmfEntity.EntityName == definitionGroupEntity.Entity

                    && dmfEntity.TargetEntity == targetEntityName;


        return definitionGroupEntity;

    }


}



Helper class:

/// <summary>

/// Data entity data export helper class.

/// </summary>

public class SAN_DataEntityExporter

{

    Filename filename;

    

    /// <summary>

    /// set file name

    /// </summary>

    /// <param name = "_filename">file name to export data</param>

    /// <returns>file name</returns>

    public Filename parmFilename(Filename _filename = filename)

    {

        filename = _filename;


        return filename;

    }


    /// <summary>

    /// Export an entity to file

    /// </summary>

    /// <param name = "_definitionGroupName">Definition group to reuse</param>

    /// <param name = "_entityName">Entity label</param>

    public void exportDataEntity(DMFDefinitionGroupName _definitionGroupName, DMFEntityName _entityName)

    {

        #DMF

        SharedServiceUnitFileID fileId;


        try

        {

            DMFEntityExporter exporter = new DMFEntityExporter();

            fileId = exporter.exportToFile(_entityName,

                                            _definitionGroupName,

                                            '',

                                            BudgetPlanningConstants::Excel,

                                            #FieldGroupName_AllFields,

                                            conNull(),

                                            curExt()

                                            );

 

            if (fileId != '')

            {

                this.sendFileToDestination(fileId);

            }

            else

            {

                // DMF execution failed and details were written to the execution log.

                throw error("@CashManagement:DMFExportCallFailedToExecutionLog");

            }

        }

        catch

        {

            error("@SYP4861341");

        }

    }


    /// <summary>

    /// Creates a stream, puts it into temp storage (like SendFileToTempStore), and redirects the user to that file to cause it to be downloaded by the user's browser.

    /// </summary>

    /// <param name = "_fileId">The file name of the stream.</param>

    public client void sendFileToDestination(SharedServiceUnitFileID _fileId)

    {

        str downloadUrl = DMFDataPopulation::getAzureBlobReadUrl(str2Guid(_fileId));

        

        System.IO.Stream stream = File::UseFileFromURL(downloadUrl);

        File::SendFileToUser(stream, filename);

    }


}

Wednesday, September 10, 2025

Update ISV license on CHD D365FO

 Open command prompt:

//Enable maintenance mode

cd K:\AosService\PackagesLocalDirectory\Bin\

Microsoft.Dynamics.AX.Deployment.Setup.exe --metadatadir K:\AosService\PackagesLocalDirectory --bindir K:\AosService\PackagesLocalDirectory\Bin --sqlserver . --sqldatabase axdb --sqluser axdbadmin --sqlpwd "password from LCS" --setupmode maintenancemode --isinmaintenancemode true


//Restart IIS

 

iisreset

 

 //Import new license file comman


Microsoft.Dynamics.AX.Deployment.Setup.exe --setupmode importlicensefile --metadatadir K:\AOSService\PackagesLocalDirectory --bindir K:\AOSService\PackagesLocalDirectory --sqlserver . --sqldatabase AxDB --sqluser axdbadmin --sqlpwd "password from LCS" --licensefilename C:\Temp\<"license file name">.txt

 

 //Disbale maintenance mode


Microsoft.Dynamics.AX.Deployment.Setup.exe --metadatadir K:\AosService\PackagesLocalDirectory --bindir K:\AosService\PackagesLocalDirectory\Bin --sqlserver . --sqldatabase axdb --sqluser axdbadmin --sqlpwd "password from LCS" --setupmode maintenancemode --isinmaintenancemode false


//Restart IIS

iisreset


Build ISV model and custom model (If any).

DB Sync

Tuesday, July 1, 2025

Set visibility of menu item based on Feature or parameter options in D365FO

 [SubscribesTo(classstr(SysMenuNavigationObjectFactory), staticdelegatestr(SysMenuNavigationObjectFactory, checkAddSubMenuDelegate))]

public static void menuItemVisibilityHandler(SysDictMenu _rootMenu, SysDictMenu _subMenu, SysBoxedBoolean _subMenuVisibility)

{

    if (_subMenu.isMenuItem())

    {

        var metadataElement = _subMenu.GetMenuItemMetaElement();

        if (metadataElement != null)

        {

            SAN_HelperCls::santst_setVisibilityMenuItems(metadataElement.Name, _subMenuVisibility);

        }

    }

}


public class  SAN_HelperCls
{

private static void santst_setVisibilityMenuItems(str _menuItemName, SysBoxedBoolean _subMenuVisibility)

{

    const str menuItemsPrefix = "SAN_TEST";


    if (strScan(_menuItemName, menuItemsPrefix , 0, strLen(_menuItemName)))

    {

        _subMenuVisibility.value = SAN_HelperCls::isEnabled();

    }

}


 public static boolean isEnabled()

 {

     return isConfigurationkeyEnabled(configurationkeynum(Trade)) && 

             FeatureStateProvider::isFeatureEnabled(SAN_DevFeature::instance());

 }

}


Parameter control (Yes/No)

or

Feature class:

using System.ComponentModel.Composition;

using Microsoft.Dynamics.ApplicationPlatform.FeatureExposure;


/// <summary>

/// The <c>SAN_DevFeature</c> class defines the enable advanced order hold feature.

/// </summary>

[ExportAttribute(identifierstr(Microsoft.Dynamics.ApplicationPlatform.FeatureExposure.IFeatureMetadata))]

[Microsoft.Dynamics.BusinessPlatform.SharedTypes.InternalUseOnlyAttribute]

public final class SAN_DevFeature implements IFeatureMetadata, IFeatureLifecycle

{

    private static SAN_DevFeature instance;


    private void new()

    {

    }


    [Hookable(false)]

    public WebSiteURL learnMoreUrl()

    {

        return 'https://learn.microsoft.com/en-us/';

    }


    private static void TypeNew()

    {

        instance = new SAN_DevFeature();

    }


    /// <summary>

    /// Obtains the singleton object instance.

    /// </summary>

    /// <returns>The <c>SAN_DevFeature</c> instance.</returns>

    [Hookable(false)]

    public static SAN_DevFeature instance()

    {

        return SAN_DevFeature::instance;

    }


    [Hookable(false)]

    public FeatureLabelId label()

    {

        return literalStr("SAN DEV tool features");

    }


    [Hookable(false)]

    public int module()

    {

        return FeatureModuleV0::SalesAndMarketing;

    }


    [Hookable(false)]

    public FeatureLabelId summary()

    {

        return literalStr("SAN DEV tool features");

    }


    [Hookable(false)]

    public boolean isEnabledByDefault()

    {

        return false;

    }


    [Hookable(false)]

    public boolean canDisable()

    {

        return true;

    }


    [Hookable(false)]

    public FeatureLifecycleStage FeatureStage()

    {

        return FeatureLifecycleStage::Released;

    }


}

Tuesday, June 24, 2025

Getting multiple row data into single SQL column

Table data:

Id | Text | Description

1 | Test1 | Test description

1 | Test2 | Test description

1 | Test3 | Test description

2 | Test2 | Test description

3 | Test3 | Test description

Expected result: System should return "Test1;Test2;Test3" for data related to Id = '1'

Query (T-SQL)


Sample 1:

SELECT  t.LegalEntity, t.ITEMNUMBER,

       replace(STUFF((SELECT '; ' + CAST(t1.Text AS VARCHAR(255)) [text()]

         FROM TESTTABLE t1

         WHERE t1.ID = t.ITEMNUMBER and t1.LEGALENTITY = t.LEGALENTITY

         FOR XML PATH(''), TYPE)

        .value('.','NVARCHAR(255)'),1,2,''),' ','') AS ComputeDescription

FROM InventTable  t

where  t.ITEMNUMBER in ('1') and t.LEGALENTITY = 'usmf'

group by t.LegalEntity, t.ITEMNUMBER


Sample 2:

SELECT it.ITEMLE, it.ITEMNUMBER,

CAST (ISNULL((SELECT STRING_AGG(t1.Text,';') AS ProductLine 

 FROM TESTTABLE t1

where t1.ID = it.ITEMNUMBER and t1.LEGALENTITY = it.DataAreaId),'') as NVARCHAR(255)) AS ComputeDescription

from InventTable it

where it.DataAreaId = 'chhq'

and it.ITEMNUMBER in ('0000505','0000511','0000497','0000499')

Tuesday, April 15, 2025

OData Batch request API - D365FO

 --batch_MultipleInvoices

Content-Type: multipart/mixed;boundary=changeset_123


--changeset_123

Content-Type: application/http

Content-Transfer-Encoding: binary


POST https://<d365fourl>/data/PortalSalesDocuments/Microsoft.Dynamics.DataEntities.getSalesInvoice HTTP/1.1

Content-Type: application/json

Content-ID: 1


{

    "invoiceId": "SIAA00026",

    "dataAreaId": "usmf"

}

--changeset_123

Content-Type: application/http

Content-Transfer-Encoding: binary


POST https://<d365fourl>/data/PortalSalesDocuments/Microsoft.Dynamics.DataEntities.getSalesInvoice HTTP/1.1

Content-Type: application/json

Content-ID: 2


{

    "invoiceId": "SIAA00047",

    "dataAreaId": "usmf"

}

--changeset_123--

--batch_MultipleInvoices--

Friday, March 21, 2025

Disabling the flight in D365FO (CHD - Tier 1)

 INSERT INTO dbo.SYSFLIGHTING(FLIGHTNAME, ENABLED) 

VALUES ('<FlightObjectName>_KillSwitch', 1)

 or 

INSERT INTO dbo.SYSFLIGHTING(FLIGHTNAME, ENABLED) 

VALUES ('<FlightObjectName>', 0)

Thursday, December 12, 2024

Convert Call stack to readable format in D365FO X++

//Input

--container _xppCallStack = xSession::xppCallStack(); 


Public static str POL_formatXppCallStack(container _xppCallStack, int _skipFrames)

{

    str result = '';

    int startFrame = 1 + _skipFrames;


    // Each stack frame is four elements [Method, Line Number, Model Publisher, Model]

    for (int i = startFrame; i <= conLen(_xppCallStack); i += 4)

    {

        str methodName = conPeek(_xppCallStack, i);

        str lineNum = conPeek(_xppCallStack, i + 1);

        str publisher = conPeek(_xppCallStack, i + 2);

        str model = conPeek(_xppCallStack, i + 3);


        // Add a newline between stack frames

        if (i > 1)

        {

            result += '\n at';

        }

        

        // Model identifer

        if (publisher || model)

        {

            result += strFmt('[%1%2%3]', publisher, (publisher && model ? ':' : ''), model);

        }

        

        // Code

        result += strFmt('%1%2', methodName, (lineNum && lineNum != '0' ? ':' + lineNum : ''));

    }


    return result;

}

Thursday, October 10, 2024

Using SysOperationSandbox::callStaticMethod Sample in D365FO X++

 SysOperationSandbox::callStaticMethod(classnum(Classnum(<Class name>)), staticMethodStr(<Class name>, <Class static method name>), [<Parm1>, <Parm2>,<Parm3>], "<operation completion Message>");


 public static void updateOpr(container _callerParams)

 {

     if (conlen(_callerParams) != 3)

     {

         throw error("");

     }

     

     Anytype parm1 = conPeek(_callerParams, 1);

     Anytype parm2 = conPeek(_callerParams, 2);

     Anytype parm3 = conPeek(_callerParams, 3);        

        //Business Logic

 }

Tuesday, August 6, 2024

vlookup in excel

 

  • =VLOOKUP(A2,MDM!$A$2:$A$308971,1,FALSE)

  • Argument 1 -> lookup value
  • Argument 2 -> Table array. Note: if it is different sheet then SheetName!Table array
  • Argument 3 -> Column index to compare
  • Argument 4 -> FALSE (Looking for exact match)

Friday, July 19, 2024

Adding custom field on customer payment generation in D365FO X++

Sample code only for reference.


[ExtensionOf(classStr(CustOverPaym))]

final class CustOverPaymCls_san_Extension

{

    private  container      sanCustCRCTypes;


    #define.CurrentVersion(3)

    #localmacro.CurrentList

        sanCustCRCTypes

    #endmacro


    /// <summary>

    /// Set and get Parm customer credit management types

    /// </summary>

    /// <param name = "_sanParams">current params</param>

    /// <returns>CustCRCTypes</returns>

    public container san_parmCustCRCTypes(container _sanParams = sanCustCRCTypes)

    {

        sanCustCRCTypes = _sanParams;

        return sanCustCRCTypes;

    }


    public container pack()

    {

        container packedClass = next pack();

        return SysPackExtensions::appendExtension(packedClass, classStr(CustOverPaymCls_san_Extension), this.myPack());

    }


    private container myPack()

    {

        return [#CurrentVersion, #CurrentList];

    }


    public boolean unpack(container _packedClass)

    {

        boolean result = next unpack(_packedClass);


        if (result)

        {

            container myState = SysPackExtensions::findExtension(_packedClass, classStr(CustOverPaymCls_san_Extension));

            if (!this.myUnpack(myState))

            {

                result = false;

            }

        }


        return result;

    }


    private boolean myUnpack(container packedClass)

    {

        Integer version = RunBase::getVersion(packedClass);

        switch (version)

        {

            case #CurrentVersion:

                [version, #currentList] = packedClass;

                break;

            default:

                return false;

        }

        return true;

    }


    /// <summary>

    /// Builds the cross company query used to calculate summarized totals. COC

    /// </summary>

    /// <param name = "_calcArgs">Contains arguments used to construct the query</param>

    /// <returns>The generated query.</returns>

    protected Query buildCrossCompanyQueryForCalcTotalSummarized(CustOverPaymCalcTotalArgs _calcArgs)

    {

        Query       sanQuery;

        sanQuery = next buildCrossCompanyQueryForCalcTotalSummarized(_calcArgs);

        if(sanCustCRCTypes != conNull())

        {

            this.san_setQueryRangeCustCRCTypes(sanQuery);

        }

        return sanQuery;

    }


    /// <summary>

    /// Builds the cross company query used to calculate not summarized totals. COC

    /// </summary>

    /// <param name = "_calcArgs">Contains arguments used to construct the query</param>

    /// <returns>The generated query.</returns>

    protected Query buildCrossCompanyQueryForCalcTotalNonSummarized(CustOverPaymCalcTotalArgs _calcArgs)

    {

        Query       sanQuery;

        sanQuery = next buildCrossCompanyQueryForCalcTotalNonSummarized(_calcArgs);

        if(sanCustCRCTypes != conNull())

        {

            this.san_setQueryRangeCustCRCTypes(sanQuery);

        }

        return sanQuery;

    }


    /// <summary>

    /// Builds the query used in methods <c>findTransactionsForReimbursementNonSummarized</c> and <c>findTransactionsForReimbursementSummarized</c>. COC

    /// </summary>

    /// <param name = "_findTransArgs">Contains arguments used to build the query.</param>

    /// <returns>The generated query.</returns>

    protected Query buildFindTransactionsForReimbursementQuery(CustOverPaymFindTransactionsForReimburseArgs _findTransArgs)

    {

        Query       sanQuery;

        sanQuery = next buildFindTransactionsForReimbursementQuery(_findTransArgs);

        if(sanCustCRCTypes != conNull())

        {

            this.san_setQueryRangeCustCRCTypes(sanQuery);

        }

        return sanQuery;

    }


    /// <summary>

    /// setting query range for customer credit management types to existing query

    /// </summary>

    /// <param name = "_query">Query</param>

    public void san_setQueryRangeCustCRCTypes(Query  _query)

    {

        QueryBuildDataSource    qbdsCustTable;

        str                     CustCRCTypesIds;

        san_CustCreditManagementTypes       custCreditManagementTypes;


        #define.sanSemicolon(';')

        #define.sanComma(',')


        qbdsCustTable = _query.dataSourceTable(tableNum(CustTable));

        if(qbdsCustTable == null)

        {

            qbdsCustTable = _query.addDataSource(tableNum(CustTable));

        }


        CustCRCTypesIds = con2StrUnlimited(sanCustCRCTypes,#sanComma);

        if (CustCRCTypesIds)

        {

            CustCRCTypesIds = Global::strReplace(CustCRCTypesIds, #sanSemicolon, #sanComma);

            qbdsCustTable.addRange(fieldNum(CustTrans, san_CustCreditMgmtType)).value(CustCRCTypesIds);

        }

    }


}

Wednesday, April 24, 2024

SQL Delete statement with Not exists join

Sample SQL: 

Requirement: Delete with Not exsits join in where condition

DELETE  ITM FROM  InventItemInventSetup ITM 

WHERE  NOT EXISTS (SELECT 1 FROM   INVENTTABLE IT WHERE IT.DataAreaId =  ITM.DataAreaId 

AND IT.ITEMID = ITM.ITEMID)

       AND ITM.DATAAREAID in ('USMF')

Tuesday, March 5, 2024

Get Feature is enabled or disabled in D365FO X++

 Issue: Feature is enabled or disabled to get in customize ISV/VAR/USR model. Since it was defined as internal class by MS, and which can't be accessible in reference model.

Workaround solution (X++) in ISV/VAR/USR model: Without using MS OOB class.

IdentifierName featureEnableFeature = 'Dynamics.AX.Application.<>';

        FeatureManagementState featureManagementState;

boolean isFeatureEnabled = false;

        select firstonly featureManagementState

            where featureManagementState.Name == featureEnableFeature ;

        if (featureManagementState.IsEnabled)

        {

            isFeatureEnabled  = true;

        }

Export label custom content

 GRID => Properties "Export Label" => "SalesReportMexico" To get download file with custom naming.