Wednesday, June 26, 2024

How to use crosscompany in Query in D365 F&O | X++

Sometimes, we receive requirements to fetch data across all legal entities. In such cases, cross-company functionality can be utilized. Below is an example demonstrating this approach     

Query query = new Query();

QueryBuildDataSource queryBuildDataSource;

QueryBuildRange queryBuildRange;

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

query.allowCrossCompany(true);


This query will return all warehouses across legal entities. 


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();

Tuesday, May 14, 2024

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

ChangeItemController     controller  = ChangeItemController ::construct();

ChangeItemContract       contract    = controller ? controller.getDataContractObject() : null;


if (!contract)

        throw error(Error::wrongUseOfFunction(funcName()));


// Set contract fields

contract.parmItemId(this.ItemId);

contract.parmInventSiteId(this.SiteId );


controller.parmExecutionMode(SysOperationExecutionMode::ScheduledBatch); // Set execution mode

controller.parmShowDialog(false); 

controller.parmLoadFromSysLastValue(false); 

controller.parmInBatch(true);

controller.parmDialogCaption('Change Item');

controller.startOperation();

Friday, April 26, 2024

Create ledger journals in D365FO using X++

 Below code will help to create record in JedgerJournalTable and LedgerJournalTrans in D365FO using x++.

// Header creation 

ledgerJournalTable.JournalNum = NumberSeq::newGetNum(LedgerParameters::numRefJournalNum()).num();

ledgerJournalTable.initFromLedgerJournalName(ledgerJournalTrans_Buffer.JournalName);

ledgerJournalTable.insert();

ledgerJournalEngine = LedgerJournalEngine::construct(ledgerJournalTable.JournalType);

ledgerJournalEngine.ledgerJournalTable(ledgerJournalTable);

ledgerJournalEngine.newJournalActive(ledgerJournalTable);


//Line creation

ledgerJournalEngine.preCreate(ledgerJournalTrans);



ledgerJournalTrans.clear();

ledgerJournalTrans.initValue();

ledgerJournalTrans.JournalNum   = ledgerJournalTable.JournalNum;

ledgerJournalTrans.TransDate    = stagingTable.TransactionDate;

ledgerJournalTrans.modifiedField(fieldNum(LedgerJournalTrans, TransDate));

ledgerJournalTrans.Voucher          =   stagingTable.Voucher;

ledgerJournalTrans.CurrencyCode = stagingTable.CurrencyCode;

ledgerJournalTrans.Due  = stagingTable.DueDate;

ledgerJournalTrans.DocumentDate = stagingTable.DocumentDate;

ledgerJournalTrans.ExchRate = stagingTable.ExchRate;

ledgerJournalTrans.ReportingCurrencyExchRate = stagingTable.ExchRate;

ledgerJournalTrans.Txt  = stagingTable.Description;

ledgerJournalTrans.AccountType = str2Enum(ledgerJournalACType,stagingTable.AccountTypeStr);//stagingTable.AccountType;

ledgerJournalTrans.modifiedField(fieldNum(LedgerJournalTrans, AccountType));


if(stagingTable.AccountTypeStr == "Ledger")

{

ledgerJournalTrans.LedgerDimension  = this.generateLedgerDimension(stagingTable.AccountDisplayValue,stagingTable.BU,'',stagingTable.BranchCode,stagingTable.EmployeeCode);

}

else if(stagingTable.AccountTypeStr == "Vendor")

{

ledgerJournalTrans.LedgerDimension  = LedgerDynamicAccountHelper::getDynamicAccountFromAccountNumber(stagingTable.AccountDisplayValue,LedgerJournalACType::Vend);// stagingTable.Account;

ledgerJournalTrans.PostingProfile   = vendParameters.PostingProfile;

}

else if(stagingTable.AccountTypeStr == "Customer")

{

ledgerJournalTrans.LedgerDimension  = LedgerDynamicAccountHelper::getDynamicAccountFromAccountNumber(stagingTable.AccountDisplayValue,LedgerJournalACType::Cust);// stagingTable.Account;

ledgerJournalTrans.PostingProfile   = custParameters.PostingProfile;

}

else if(stagingTable.AccountTypeStr == "Bank")

{

ledgerJournalTrans.LedgerDimension  = LedgerDynamicAccountHelper::getDynamicAccountFromAccountNumber(stagingTable.AccountDisplayValue,LedgerJournalACType::Bank);// stagingTable.Account;

}

ledgerJournalTrans.modifiedField(fieldNum(LedgerJournalTrans, LedgerDimension));

ledgerJournalTrans.DefaultDimension = this.createDefaultDimension( stagingTable.LobCode,stagingTable.Department,stagingTable.BranchCode);;

if(stagingTable.Credit)

{

ledgerJournalTrans.AmountCurCredit   = stagingTable.Credit;

ledgerJournalTrans.modifiedField(fieldNum(LedgerJournalTrans, AmountCurCredit));

}

else if(stagingTable.Debit)

{

ledgerJournalTrans.AmountCurDebit    = stagingTable.Debit;

ledgerJournalTrans.modifiedField(fieldNum(LedgerJournalTrans, AmountCurDebit));

}         

ledgerJournalTrans.OffsetAccountType      = LedgerJournalACType::Ledger;

ledgerJournalTrans.modifiedField(fieldNum(LedgerJournalTrans, OffsetAccountType));         

ledgerJournalTrans.insert();


How to create LedgerDimension in D365 F&O using x++

 The code below will help out to generate Ledger Dimension using x++ in D365 FO

   


 public RefRecId  generateLedgerDimension(MainAccountNum     _mainAccountId,

                                             DimensionValue     _businessUnit, 

                                             DimensionValue     _department,

                                             DimensionValue     _branchCode,

                                             DimensionValue     _employeeCode)

    {

        container                           conData;

        int                                 hierarchyCount;

        int                                 hierarchyIdx;

        LedgerRecId                         ledgerRecId;

        MainAccount                         mainAccount;

        RefRecId                            recordvalue;

        DimensionAttribute                  dimensionAttribute;

        DimensionAttributeValue             dimensionAttributeValue;

        DimensionSetSegmentName             DimensionSet;

        DimensionStorage                    dimStorage;

        DimensionAttributeValueContract     ValueContract;

        LedgerAccountContract               LedgerAccountContract;

        DimensionAttributeValueCombination  dimensionAttributeValueCombination;

        List                                valueContracts;


        #define.MainAccount('MainAccount')

        #define.Department('Department')

        #define.BusinessUnit('BusinessUnit')

        #define.BranchCode('BranchCode')

        #define.EmployeeCode('EmployeeCode')

        



        LedgerAccountContract   = new LedgerAccountContract();

        valueContracts          = new List(Types::Class);


        conData = [_mainAccountId];



        mainAccount     =   MainAccount::findByMainAccountId(_mainAccountId);

        recordvalue     =   DimensionHierarchy::getAccountStructure(mainAccount.RecId,Ledger::current());

        hierarchyCount  =   DimensionHierarchy::getLevelCount(recordvalue);

        DimensionSet    =   DimensionHierarchyLevel::getDimensionHierarchyLevelNames(recordvalue);


        if (recordvalue)

        {

            for(hierarchyIdx = 1;hierarchyIdx<=hierarchyCount;hierarchyIdx++)

            {

                if(hierarchyIdx == 1)

                {

                    continue;

                }

                dimensionAttribute = DimensionAttribute::findByLocalizedName(DimensionSet[hierarchyIdx],false);

                                

                if (dimensionAttribute.Name == #Department)

                {

                    conData += [_department];

                }

                else if (dimensionAttribute.Name == #BusinessUnit)

                {

                    conData += [_businessUnit];

                }

                else if (dimensionAttribute.Name == #BranchCode)

                {

                    conData += [_branchCode];

                }

                else if (dimensionAttribute.Name == #EmployeeCode)

                {

                    conData += [_employeeCode];

                }



                if(dimensionAttribute)

                {

                    dimensionAttributeValue = DimensionAttributeValue::findByDimensionAttributeAndValue(dimensionAttribute,conPeek(conData,hierarchyIdx));


                    if(dimensionAttributeValue)

                    {

                        ValueContract = new DimensionAttributeValueContract();

                        ValueContract.parmName(dimensionAttribute.Name) ;

                        ValueContract.parmValue(dimensionAttributeValue.CachedDisplayValue);

                        valueContracts.addEnd(ValueContract);

                    }

                }


            }

            LedgerAccountContract.parmMainAccount(_mainAccountId);

            LedgerAccountContract.parmValues(valueContracts);


            dimStorage = DimensionServiceProvider::buildDimensionStorageForLedgerAccount(LedgerAccountContract);

            dimensionAttributeValueCombination = DimensionAttributeValueCombination::find(dimStorage.save());

            ledgerRecId = dimensionAttributeValueCombination.RecId;

        }

        else

        {

            warning (strfmt('Ledger dimension Issue for main account %1', _mainAccountId));

        }


        return  ledgerRecId;

    }

Monday, April 3, 2023

CostCenter lookup in Dynamics 365 for finance and operations


The code below will help to get cost center lookup for a field in D365 FO using X++.

Lets say our requirement is to show all values of "CostCentre" financial dimension. 

LedgerMatrixReportHelper_CN::dimensionValueLookup(this, "CostCenter");

Friday, April 24, 2020

Parameter display order in report dialog in Dynamics 365 for finance and operations

If you want to put data contract parameters/dialog in an order, you just need to add SysOperationDisplayOrderAttribute attribute to the parm method.

Below is the code snippet.

[DataMemberAttribute, SysOperationDisplayOrderAttribute("2")]
public str parmDocNum(str _docNum = docNum)
{
       docNum = _docNum;
       return docNum;
}

[DataMemberAttribute,SysOperationDisplayOrderAttribute("3")]
public str parmDocVersion(str _docVersion = docVersion)
{
       docVersion = _docVersion;
       return docVersion;
}

Hide parameters in report dialog in D365 FO | Dynamics 365 for finance and operations | D365 F&O

Sometime we get requirement to hide contract parameters either in SSRS reports or SysOperation.

To achieve the same, you need to add SysOperationControlVisibilityAttribute attribute to the parm method of contract class.
Below is the code snippet.

[DataMemberAttribute,SysOperationControlVisibilityAttribute(false)]
 public TableId parmTableId(TableId _tableId = tableId)
 {
     tableId = _tableId;
     return tableId;
 }

Sunday, February 25, 2018

How to create Details Master pattern form in D365 F&O


Objective :The objective of this tutorial is to take you through the development of details master form in Dynamics 365 for operations.

Development :

  • Create a project, Right-click your project, select Add -> New Item..
  • Select User Interface -> Form,  give some name, in my case its Gau_DistributorTable

  • Drag and drop your table to Data Sources node

  •  Right-click Design node, select Apply pattern -> Details Master

  •         After selecting pattern, we can see all the missing controls in Pattern pane

  • Add all missing controls to design, even after adding controls still some warming is showing up

  • .       Now add all the controls for which we are getting warnings and need to add field group to Detail tab Page from data source

  • .       Add some fields to Grid of Grid tab page

  • .       Right-click form and select Set as Startup Object

  • Select your project and hit Start, here you go
     
THANK YOU





Thursday, January 25, 2018

Data Entities error while uploading File in Dynamics 365 F&O

Error: File upload for entity in data project did not succeed

While importing data to Dynamics 365 for Operations you may encounter an error if Azure Storage Emulator is not up.




Solution:-

You will have to start Azure storage emulator .

About storage emulator :
The storage emulator uses a local Microsoft SQL Server instance and the local file system to emulate Azure storage services. 
The storage emulator is installed by default to -

 C:\Program Files (x86)\Microsoft SDKs\Azure\Storage Emulator.

How to start Azure storage emulator :
  • Run command Prompt as Administrator
  • Copy paste this path to cmd – cd C:\Program Files (x86)\Microsoft SDKs\Azure\Storage Emulator
  •      Execute this command on cmd- AzureStorageEmulator.exe start



THANK YOU


Monday, May 22, 2017

X++ new features in D365 F&O

DECLARE ANYWHERE:-  Previously, all local variables had to be placed at the start of the method in which they’re used. Readability is enhanced. You can reduce the risk of reusing a variable inappropriately during long-term maintenance of the code.

Static Constructor and Static field:- Static constructors are guaranteed to run before any static or instance calls are made to the class.

Const/ReadOnly:-  the const is known by IntelliSense, The const is subject to access modifiers, either private, protected, or public. The accessibility of macros is not well understood or even rigorously defined. Consts have scope, while macros do not

Var:-  It’s only possible to use var on declarations where an initialization expressions are provided

Private and Protected member varaibles:- Previously, all member variables defined in a class were invariably protected. It’s now possible to make the visibility of member variables explicit by adding the private, protected, and public keywords.

Extension method:- The extension class must be static, The name of the extension class must end with the ten-character suffix _Extension. However, there’s no restriction on the part of the name that precedes the suffix, Every extension method in the extension class must be declared as public static, the first parameter in every extension method is the type that the extension method extends. However, when the extension method is called, the caller must not pass in anything for the first parameter. Instead, the system automatically passes in the required object for the first parameter. 

Finally in try/catch statements :- Try/catch statements can now include an optional finally clause. The statements in the finally clause are executed when control leaves the try block, either normally or through an exception.

Tuesday, February 21, 2017

How to add methods to table using extension in D365 FO

D365F&O won’t allow user to add new methods to table directly. So here I will be demonstrating how to add new methods to table using extension class.

Lets say our requirement is to add new method to VendTable to get address of Vendors.

First step is to create a class, have a name that has the _Extension suffix and should be static.

public static class VendTable_Extension
{
}

Next Step is to create method, method should always be public static and first parameter should be Table buffer.

public static class VendTable_Extension
{
    public static Notes getVendAddress(VendTable vendTable)
    {
        DirPartyTable       dirPartyTable;
        LogisticsLocation   logisticsLocation;

        select dirPartyTable where dirPartyTable.RecId == vendTable.Party
        join logisticsLocation
        where dirPartyTable.PrimaryAddressLocation == logisticsLocation.RecId;      
       
        return logisticsLocation.postalAddress();
    }

}

Once we will build our project, this method will be usable as if it is method of VendTable.

I have tested the same using job.

class VendTable_Demo
{        
    /// <summary>
    /// job to test vendtable extension method
    /// </summary>
    /// <param name = "_args">The specified arguments.</param>
    public static void main(Args _args)
    {    
        VendTable vendTable;

        vendTable = VendTable::find("1001"); 
        
        info(strFmt("Vendor Address - %1",vendTable.getVendAddress()));
      
    }



Output:-


THANK YOU