Wednesday, June 26, 2024

How to Use CrossCompany in a Query in Dynamics 365 F&O (X++)

While working in Dynamics 365 Finance & Operations, there are many situations where we need to read data from multiple legal entities instead of just the current company.

By default, any query or select statement in X++ only fetches records from the company you are logged into. But what if you want data from all companies?

That’s where CrossCompany comes into the picture. 

What Is CrossCompany in D365 F&O?

CrossCompany allows you to read records from multiple legal entities in a single query without changing the company context.

Normally, D365 F&O automatically applies a DataAreaId filter behind the scenes. When CrossCompany is enabled, this filter is ignored and data is returned from all companies that the user has access to.


Example: Using CrossCompany in a Query

Below is a simple example where we want to read InventLocation records from all companies.



Query query = new Query();

QueryBuildDataSource queryBuildDataSource;

QueryBuildRange queryBuildRange;

queryBuildDataSource = query.addDataSource(tableNum(InventLocation));

query.allowCrossCompany(true);

How to cancel sales line in D365 F&O using X++

If there's a requirement to cancel a sales line through code X++ in D365 F&O, the following code can be used to achieve it. In this example, I’ve created an extension of the SalesLine table and added a new method that can be called to cancel the selected sales line.

[ExtensionOf(tableStr(SalesLine))]

final class SalesLine_Extension

{

    public void gauCancelSalesOrderLine()

    {

        ttsbegin;

        this.selectForUpdate(true);

        SalesUpdateRemain::construct().updateDeliverRemainder(this, 0, 0);

        ttscommit;

    }

}

How to call Runbase batch job using X++ in D365 F&O

If there's a requirement to call a RunBaseBatch class using X++ code, the following example demonstrates how to do it. In this case, we’re using the GUPItemBasePriceCalcJob class, which is a RunBaseBatch class, and calling it by setting the appropriate parameters.        

        BatchHeader         header;

        SysRecurrenceData   sysRecurrenceData;

        Batch               batch;

        BatchJob            batchJob;

        BatchInfo           processBatchInfo;

        BatchRetries        noOfRetriesOnFailure = 4;

        GUPItemBasePriceCalcJob GUPItemBasePriceCalcJob; // RunBase batch class

        #define.timeInSecondsDelay(20)

      

        select forupdate batch

        join batchJob

        where batchJob.RecId == batch.BatchJobId

                && batch.ClassNumber == classnum(GUPItemBasePriceCalcJob)

                && batchJob.Status == BatchStatus::Waiting

                && batch.Company == curext();

        if (!batch)

        {

            // Setup the RunBaseBatch Job

            header = BatchHeader::construct();

            GUPItemBasePriceCalcJob= GUPItemBasePriceCalcJob::construct();

            GUPItemBasePriceCalcJob.parmItemId(ItemId); // pass Item Id 

            GUPItemBasePriceCalcJob.parmSiteId(SiteId); // pass Site 

            processBatchInfo = GUPItemBasePriceCalcJob.batchInfo();

            processBatchInfo.parmRetriesOnFailure(noOfRetriesOnFailure);

            header.addTask(GUPItemBasePriceCalcJob);            


            // Set the recurrence data

            sysRecurrenceData = SysRecurrence::defaultRecurrence();

            sysRecurrenceData = SysRecurrence::setRecurrenceStartDateTime(sysRecurrenceData,                             DateTimeUtil::addSeconds(DateTimeUtil::utcNow(), #timeInSecondsDelay));

            sysRecurrenceData = SysRecurrence::setRecurrenceNoEnd(sysRecurrenceData);

            sysRecurrenceData = SysRecurrence::setRecurrenceEndAfter(sysRecurrenceData, 1); 


            header.parmRecurrenceData(sysRecurrenceData);

            // Set the batch alert configurations

            header.parmAlerts(NoYes::No, NoYes::Yes, NoYes::No, NoYes::Yes, NoYes::No);

            header.save();