09 April 2025

X++ code to create new user in D365 F&O

 public void createUser(UserId _userId,Name _userName)

{

    UserInfo userInfo;

    SecurityUserRole userRole,userRoleToSave;

    SecurityRole    securityRole;

   

    // Step 1: Create new User Info record

    ttsBegin;


    userInfo.id             = _userId;

    userInfo.Name           = _userName;

    userInfo.networkAlias   = Xine_UserAcessTable.Email;

    userInfo.networkDomain  = Xine_UserAcessTable.NetworkDomain;

    userInfo.ObjectId       = Xine_UserAcessTable.TelemetryId;        

    userInfo.enable         = Xine_UserAcessTable.Enabled;

    userInfo.insert(); // Save the user info record


    info(strFmt('User created: %1', userInfo.id));


    select securityRole

        where securityRole.Name == "System user";


    select forupdate userRoleToSave 

        where userRoleToSave.User == _userId &&

                userRoleToSave.SecurityRole == securityRole.recId;

    if ( userRoleToSave.recId)

    {

        userRoleToSave.AssignmentMode = RoleAssignmentMode::Manual;

        userRoleToSave.AssignmentStatus = RoleAssignmentStatus::Enabled;

        userRoleToSave.update();

    }

    else

    {

        userRole.User = _userId;

        userRole.SecurityRole = securityRole.recId; // Set the role of the user (System User role is used here as an example)

        userRole.AssignmentMode = RoleAssignmentMode::Manual;

        userRole.AssignmentStatus = RoleAssignmentStatus::Enabled;

        userRole.insert(); // Save user role


        info(strFmt('Role assigned to user: %1', userRole.SecurityRole));

    }


    // Commit the transaction

    ttsCommit;

}

19 April 2024

Ledger Voucher creation Framework and x++ code to create ledger voucher

 Please click her for MS reference file


Below is the out of the box example reference and code.

SalesInvoiceJournalPostSubBill_Extension->endPost()

this.postUnbilledRevenueAndRevenueOffset();


LedgerVoucher ledgerVoucher = this.ledgerVoucher;

                LedgerVoucherObject ledgerVoucherObject = ledgerVoucher.findLedgerVoucherObject();

                LedgerDimensionAccount unbilledRevenueAccount = LedgerDimensionFacade::serviceCreateLedgerDimension(unbilledRevenueTransactionLine.SubBillUnbilledRevenueAccount, salesLine.DefaultDimension);

                LedgerDimensionAccount unbilledRevenueOffsetAccount = LedgerDimensionFacade::serviceCreateLedgerDimension(unbilledRevenueTransactionLine.SubBillUnbilledRevenueOffsetAccount, salesLine.DefaultDimension);

                CurrencyExchangeHelper exchangeRateHelper = this.getExchangeRateHelper(ledgerVoucherObject, detailLine.SubBillSchedLineRecId);


                Amount revenueOffsetAmt = abs(custInvoiceTrans.lineAmount) + custInvoiceTrans.SumLineDisc;

                Amount revenueAmt = (revenueOffsetAmt * -1);


                // Unbilled Revenue

                LedgerVoucherTransObject ledgerVoucherTransObject = LedgerVoucherTransObject::newTransactionAmountDefault(

                            ledgerVoucherObject,

                            LedgerPostingType::SalesRevenue,

                            unbilledRevenueAccount,

                            custInvoiceTrans.CurrencyCode,

                            revenueAmt,

                            exchangeRateHelper);

                ledgerVoucherTransObject.parmText("@SubBill:UnbilledRevenueAccount");

                ledgerVoucher.addTrans(ledgerVoucherTransObject);


                // Unbilled Revenue Offset

                // Dr. Accounts Receivable + Dr. Unbilled discount offset = Cr. Unbilled Revenue offset

                ledgerVoucherTransObject = LedgerVoucherTransObject::newTransactionAmountDefault(

                            ledgerVoucherObject,

                            LedgerPostingType::SalesRevenueOffset,

                            unbilledRevenueOffsetAccount,

                            custInvoiceTrans.CurrencyCode,

                            revenueOffsetAmt,

                            exchangeRateHelper);

                ledgerVoucherTransObject.parmText("@SubBill:UnbilledRevenueOffsetAccount");

                ledgerVoucher.addTrans(ledgerVoucherTransObject);

                ledgerVoucherObject.lastTransTxt();


08 February 2024

Trial balance export to Azure Blob Storage


The file will be automatically generated from D365 using a batch job.

The trial balance file should include all dimensions. (Main-Dept-Cost center-Business unit-Value stream)



/// contract class to export file in azure blob storag

/// </summary>

[DataContractAttribute,

SysOperationContractProcessing(classStr(NPHFloQastExportUIBuilder))]

internal final class ExportContract extends SysOperationAttributedDataContractInfo

{

    private FromDate            fromDate;

    private ToDate              toDate;

    private DateCode            period;

    private Name                primaryDimensionFocus;

    private DimensionSetName    dimensionSetName;


    [DataMemberAttribute("@SYS2168")]

    public FromDate parmFromDate(FromDate _fromDate = fromDate)   

 {

        fromDate = _fromDate;

        return _fromDate;

    }


    [DataMemberAttribute("@SYS22882")]

    public ToDate parmToDate(ToDate _toDate = toDate)

    {

        toDate = _toDate;

        return _toDate;

    }


    [DataMemberAttribute("@SYS22717")]

    public DateCode parmPeriod(DateCode _period = period)

    {

        period = _period;

        return _period;

    }


    [DataMemberAttribute("@SYS83218")]

    public DimensionSetName parmDimensionSetName(DimensionSetName _dimensionSetName = dimensionSetName)

    {

        dimensionSetName = _dimensionSetName;

        return dimensionSetName;

}

}

Create Controller class

internal final class ExportController extends SysOperationServiceController

{

    public static void main(Args args)

    {

         ExportController sysOperationController = ExportController::construct();

        sysOperationController.parmClassName(classStr(ExportService));

        sysOperationController.parmMethodName(methodStr(ExportService, operation));

        sysOperationController.parmExecutionMode(SysOperationExecutionMode::Synchronous);

        sysOperationController.startOperation();

    }


    private static ExportController construct()

    {

        ExportController controller = new ExportController();

        controller.parmDialogCaption("Caption");


        return controller;

    }


    public ClassDescription caption()

    {

        return "Caption";

    }


    protected boolean canRunInNewSession()

    {

        return true;

    }


    /// <summary>

    ///

    /// </summary>

    /// <param name = "_dialogCaption"></param>

    /// <returns></returns>

    public LabelType parmDialogCaption(LabelType _dialogCaption = dialogCaption)

    {

        return "Caption";

    }


}    


Crate UI builder class 

internal final class ExportUIBuilder extends SysOperationAutomaticUIBuilder

{

    DialogField                         dialogPeriodName;

    DialogField                         dialogFromDate;

    DialogField                         dialogToDate;

    DialogField                         dialogDimset    ;


    private DateCode            period;

    private FromDate            fromDate;

    private ToDate              toDate;

    private DimensionSetName    dimensionSetName;


    ExportContract                  dataContract;


       

       public void build()

    {

        Dialog dialogLocal = dialog as Dialog;        


        dataContract = this.getContract();


        dialogPeriodName = this.addDialogField(methodstr(ExportContract,parmPeriod),dataContract);

        dialogPeriodName.label("@SYS22717");

        dialogPeriodName.lookupButton(2);

        dialogFromDate  = this.addDialogField(methodstr(ExportContract,parmFromDate),dataContract);

        dialogToDate    = this.addDialogField(methodstr(ExportContract,parmToDate),dataContract);

        dialogDimset    = this.addDialogField(methodstr(ExportContract,parmDimensionSetName),dataContract);

    }


    public boolean periodModified(FormStringControl _control)

    {

        DateCode            dateCode        ;

        LedgerPeriodCode    ledgerPeriodCode;

       

        dialogPeriodName.value(_control.valueStr());

       

        dateCode = dialogPeriodName.value();

        ledgerPeriodCode = ledgerPeriodCode::find(dateCode);


        dialogFromDate.value(ledgerPeriodCode.fromDate());

        dialogToDate.value(ledgerPeriodCode.toDate());


        return true;

    }


    [Hookable(false)]

    public void postRun()

    {

        super();


    

        dialogPeriodName.value(this.getContract().parmPeriod());

        dialogPeriodName.fieldControl().mandatory(true);


        dialogPeriodName.registerOverrideMethod(

            methodStr(FormStringControl, modified),

            methodStr(ExportUIBuilder, periodModified),

            this);

    

        dialogFromDate.value(this.getContract().parmFromDate());

        dialogFromDate.allowEdit(false);

        dialogToDate.value(this.getContract().parmToDate());

        dialogToDate.allowEdit(false);

        dialogDimset.value(this.getContract().parmDimensionSetName());

    }


    private ExportContract getContract()

    {

        if (dataContract == null)

        {

            dataContract = this.dataContractObject() as ExportContract;

        }


        return dataContract;

    }


}


/// <summary>

/// 15933 - Flocast integration

/// exports file in azure blob storage

/// </summary>

using Microsoft.WindowsAzure.Storage;

using System.Text;

create service  class 

internal final class ExportService

{

    int                 records             ;

    Filename            currentFileName     ;

    date                startDate           ;

    date                endDate             ;

    PeriodName          periodName          ;

    LedgerParameters    ledgerParameters    ;

    DimensionSetName    dimensionSetName    ;


    public void new()

    {

        LedgerPeriodCode            ledgerPeriodCode    ;


        super();

        

        ledgerPeriodCode    = ledgerPeriodCode::find("CP");

        startDate           = ledgerPeriodCode.fromDate()   ;

        endDate             = ledgerPeriodCode.toDate()     ;

        periodName          = ledgerPeriodCode.Code         ;

    }


    public void operation(ExportContract _dataContract)

    {

        System.Exception ex;


        periodName          = _dataContract.parmPeriod()            ;   

        startDate           = _dataContract.parmFromDate()          ;

        endDate             = _dataContract.parmToDate()            ;

        dimensionSetName    = _dataContract.parmDimensionSetName()  ;


        ledgerParameters = LedgerParameters::find();


        Filename    filename  = ledgerParameters.FileName ? ledgerParameters.FileName : "GLAccounts";


       

        str timestamp = strReplace(time2str(timeNow(),TimeSeparator::Colon, TimeSeparator::Colon),":","_");



        currentFileName     = strFmt("%1_%2_%3_%4.csv",filename,

                                                    date2str(startDate,321,2,DateSeparator::None,2,DateSeparator::None,4),

                                                    date2str(endDate,321,2,DateSeparator::None,2,DateSeparator::None,4),

                                                    timestamp);

                                                    //time2str(timeNow(),TimeSeparator::Colon, TimeSeparator::Colon));


        try

        {

            this.runExport();

            info(strFmt("@Newport:NPHFloQastRecords",records, currentFileName));

        }

        catch (Exception::CLRError)

        {

            ex = CLRInterop::getLastException();

            if (ex != null)

            {

                error(ex.ToString());

            }

        }

        catch (Exception::CodeAccessSecurity)

        {

            error("@Newport:NPHFloQastFileIssue");

        }

    }


    TextStreamIo openFile()

    {

        FileIOPermission perm;

        ;


        info("file: " + currentFileName);


        perm = new FileIOPermission(currentFilename, "w");


        if (perm == null)

        {

            return null;

        }


        perm.assert();


        TextStreamIo fileOut = TextStreamIo::constructForWrite();


        return fileOut;

    }


    void runExport()

    {

        DimensionHierarchy                      dimHier                 ;

        LedgerTrialBalanceTmp                   ledgerTrialBalanceTmp   ;

        LedgerTrialBalanceListPageBalanceParms  balanceParameters       ;


        List postingLayers = new List(Types::Enum);

        postingLayers.addEnd(currentOperationsTax::Current);


        dimHier = DimensionHierarchy::findByTypeAndName(DimensionHierarchyType::Focus, dimensionSetName);

        balanceParameters   = LedgerTrialBalanceListPageBalanceParms::construct();

        balanceParameters.loadDefault();

        balanceParameters.parmPostingLayers(postingLayers);

        balanceParameters.parmStartDate(startDate);

        balanceParameters.parmEndDate(endDate);

        balanceParameters.parmDimensionSetHierarchy(dimHier);


        //info(strFmt("@SYS2168" + "%1", startDate));

        //info(strFmt("@SYS22882" + "%1", endDate));


        select firstOnly RecId from LedgerTrialBalanceTmp;


        LedgerTrialBalanceTmp::calculateBalances_V2(

            ledgerTrialBalanceTmp,

            dimHier.Name,

            balanceParameters.getStartDate(),

            balanceParameters.getEndDate(),

            balanceParameters.getIncludeOpeningPeriods(),

            balanceParameters.getIncludeClosingAdjustments(),

            balanceParameters.getIncludeClosingTransactions(),

            balanceParameters.getPostingLayers(),

            true);


        this.writeFile(ledgerTrialBalanceTmp);

    }


    // 15933_Flocast integration 

    private void writeFile(LedgerTrialBalanceTmp _ledgerTrialBalanceTmp)

    {

        str                             recordStr       ;

        MainAccount                     mainAccount     ;

        AccountCategory                 accountCategory ;

        str                             hasActivity     ;

        container                       con;


        recordStr =  strFmt("CostCenter,MainAccount,BusinessUnit,ValueStrem,Department,Name,OpeningBalance,Debit,Credit,ClosingBalance");

        con += recordStr;


        while select _ledgerTrialBalanceTmp

            //join  mainAccount           where mainAccount.MainAccountId == _ledgerTrialBalanceTmp.DimensionValues[0]

        {

            accountCategory = mainAccount.accountCategory(false,"");

            if (this.isSuspended(mainAccount))

            {

                continue; 

            }


            if (_ledgerTrialBalanceTmp.AmountCredit == 0 && _ledgerTrialBalanceTmp.AmountDebit == 0)

            {

                hasActivity = "FALSE";

            }

            else

            {

                hasActivity = "TRUE";

            }


            recordStr =  strFmt("%1,%2,%3,%4,%5,%6,%7,%8,%9,%10",

                            _ledgerTrialBalanceTmp.DimensionValues[1],

                            _ledgerTrialBalanceTmp.DimensionValues[2],

                            _ledgerTrialBalanceTmp.DimensionValues[3],

                            _ledgerTrialBalanceTmp.DimensionValues[4],

                            _ledgerTrialBalanceTmp.DimensionValues[5],

                            _ledgerTrialBalanceTmp.PrimaryFocusDescription,

                            num2Str(_ledgerTrialBalanceTmp.OpeningBalance,16,2,DecimalSeparator::Dot, ThousandSeparator::None),

                            num2Str(_ledgerTrialBalanceTmp.AmountDebit,16,2,DecimalSeparator::Dot, ThousandSeparator::None),

                            num2Str(_ledgerTrialBalanceTmp.AmountCredit,16,2,DecimalSeparator::Dot, ThousandSeparator::None),

                            num2Str(_ledgerTrialBalanceTmp.EndingBalance,16,2,DecimalSeparator::Dot, ThousandSeparator::None)

                             );

                          

                             

            con += recordStr;

            records++;

            recordStr   = "";

        }

        //Info(strFmt("%1", con));

        this.uploadFileToAzureBlob(con);

    }


    Suspended isSuspended(MainAccount _mainAccount)

    {

        DimensionAttributeValue             dimAttrValue;

        DimensionAttribute                  mainAccountDimAttribute;

        Suspended                           isMainAccountSuspended;


        mainAccountDimAttribute.RecId =  DimensionAttribute::getWellKnownDimensionAttribute(DimensionAttributeType::MainAccount);


        dimAttrValue = DimensionAttributeValue::findByDimensionAttributeAndEntityInst(mainAccountDimAttribute.RecId, _mainAccount.RecId, true);


        isMainAccountSuspended = dimAttrValue.IsSuspended;


        return isMainAccountSuspended;

    }


    public void uploadFileToAzureBlob(container _lineData)

    {

        var storageCredentials = new Microsoft.WindowsAzure.Storage.Auth.StorageCredentials(ledgerParameters.StorageAccountName, ledgerParameters.FloQastAzureStorageAccountKey);


        CloudStorageAccount storageAccount = new Microsoft.WindowsAzure.Storage.CloudStorageAccount(storageCredentials, true);

        Microsoft.WindowsAzure.Storage.Blob.CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();

        Microsoft.WindowsAzure.Storage.Blob.CloudBlobContainer container1 = blobClient.GetContainerReference(ledgerParameters.FloQastBlobStorageEndpointContainerName);

        Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob blockBlob = container1.GetBlockBlobReference(currentFileName);


        StringBuilder csvData = new StringBuilder();


        for(int j = 1; j<= conLen(_lineData); j++)

        {

            csvData.AppendLine(con2Str(conPeek(_lineData,j)));

        }


        str dataToUpload = csvData.ToString();


        using (var ms = new System.IO.MemoryStream(System.Text.Encoding::get_UTF8().GetBytes(dataToUpload)))

        {

            blockBlob.UploadFromStream(ms,null,null,null);

        }


    }


}

Add parameters for Azure Account 

    











03 January 2024

Filter the form by date range in Dynamics 365 F&O or AX 2012 X++ code

Need to add range to the query.

Example: Need to add range in ExecuteQuery() method.

QueryBuildRange queryBuildDateRange = SysQuery::findOrCreate(this.queryBuildDataSource(),fieldNum(MyTable,Field));

queryBuildDateRange.value(SysQuery::range(fromDate.DateValue(),Todate.dateValue()));

22 September 2023

D365 F&O OData get call in Postman which is getting empty records even when we filtered with company in endpoint

The reason is: Default admin user company  is "DAT"
Soluion:
Need to setup for the admin user default company should be USMF or any company.


18 September 2023

Export data entity or composite data entity using X++ code in D365 F&O

using System;

using System.Globalization;


using System.Net.Http.Headers;

using System.Threading.Tasks;

using Microsoft.WindowsAzure.Storage;

using Microsoft.WindowsAzure.Storage.Blob;

using System.Net.Http;

//using Windows.Web.Http;


internal final class TRGExportEntitySO

{

    public static void main(Args _args)

    {

        TRGExportEntitySO entityExport = new TRGExportEntitySO();

        entityExport.exportEntityData();

    }


    public void exportEntityData()

    {

        DMFDefinitionGroupEntity        definitionGroupEntity,definitionGroupEnt;

        DMFEntity                       dmfEntity,dmfEntityLoc;

        CBBlobHelper                        helper         = new CBBlobHelper();

        #DMF

        Query query;

        DMFEntityName entityName = "Sales Orders Composite v3";

        DMFDefinitionGroupName definitionGroupName = 'SO Export';//'Customer payment journal Exp';

        SharedServiceUnitFileID fileId;

        List xsltFileList = new List(Types::String);

        boolean isGenerated = false;


        select firstonly DefinitionGroup,Entity,Source from definitionGroupEnt

            where definitionGroupEnt.DefinitionGroup == definitionGroupName

            join TargetEntity from dmfEntityLoc

            where dmfEntityLoc.EntityName == definitionGroupEnt.Entity

            && dmfEntityLoc.EntityType == DMFEntityTypes::CompositEntity;


        //DMFEntity   dmfEntityLoc = DMFEntity::find(definitionGroupEnt.Entity);


        //entityName = DMFEntity::findFirstByTableId(tableNum(SalesOrderV3Entity)).EntityName;

        // Update query

        query = new query(dmfutil::getDefaultQueryForEntityV3(definitionGroupEnt.Entity,definitionGroupName));

        //query = new query(this.getDefaultQueryForEntityV3(entityName));


        querybuilddatasource qbds = query.datasourcetable(tablenum(SalesOrderHeaderV2Entity));

        sysquery::findorcreaterange(qbds, fieldnum(SalesOrderHeaderV2Entity, SalesOrderNumber)).value("SOCN01-0000056"); // selected record value to be pass here

        

        select firstonly RecId,Entity,DefinitionGroup from definitionGroupEntity

        exists join dmfEntity

            where definitionGroupEntity.DefinitionGroup == definitionGroupName

        && dmfEntity.entityName == definitionGroupEntity.entity

        && dmfEntity.TargetEntity == dmfEntityLoc.TargetEntity;//"SalesOrderV3Entity";


        try

        {

            ttsbegin;

            definitionGroupEntity.reread();

            definitionGroupEntity.selectForUpdate(true);

            definitionGroupEntity.QueryData = query.pack();

            definitionGroupEntity.update();

            ttscommit;


            DMFEntityExporter exporter = new DMFEntityExporter();


            fileId = exporter.exportToFile( definitionGroupEnt.Entity,

                                        definitionGroupName,

                                        "",

                                        definitionGroupEnt.Source,//'CSV-Unicode',

                                        #FieldGroupName_AllFields,

            query.pack(),

                                        curExt(),

                                        null,

                                        true,

                                        false);


            if (fileId != '')

            {

                //Get Azure blob url from guid

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


                System.Uri uri = new System.Uri(downloadUrl);

                str fileExt;


                if (uri != null)

                {

                    fileExt = System.IO.Path::GetExtension(uri.LocalPath);

                }


                Filename filename = strFmt('%1,%2',definitionGroupEnt.Entity,fileExt);

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

                //Send the file to user

                //File::SendFileToUser(stream, filename);

                //filePath 

                //str connectStr =  CBKeyVaultCertificateHelper::getManualSecretValue('https://smartcoredev-a9b3cnb8fph3hae2.z01.azurefd.net/d365?sv=2022-11-02&ss=b&srt=sco&sp=rwdlacyx&se=2024-04-01T18:49:49Z&st=2023-10-12T10:49:49Z&spr=https&sig=xvLiFCCg6JmHjJ1x6i2Eu%2BhEw1DWSetEKD6jZtRWgu4%3D');

                str connenctionString = "https://smartcoredev-a9b3cnb8fph3hae2.z01.azurefd.net/d365/" + filename + "?sv=2022-11-02&ss=b&srt=sco&sp=rwdlacyx&se=2024-04-01T18:49:49Z&st=2023-10-12T10:49:49Z&spr=https&sig=xvLiFCCg6JmHjJ1x6i2Eu%2BhEw1DWSetEKD6jZtRWgu4%3D";


                //str connectStr = "https://smartcoredev-a9b3cnb8fph3hae2.z01.azurefd.net/d365?sv=2022-11-02&ss=b&srt=sco&sp=rwdlacyx&se=2024-04-01T18:49:49Z&st=2023-10-12T10:49:49Z&spr=https&sig=xvLiFCCg6JmHjJ1x6i2Eu%2BhEw1DWSetEKD6jZtRWgu4%3D";


                Uri blobUri = new Uri(connenctionString);


                //try

                //{



                //using(System.Net.Http.HttpClient cl = new System.Net.Http.HttpClient())

                //    {

                //        System.Net.Http.HttpClient clien = new System.Net.Http.HttpClient();

                //        System.Net.Http.StreamContent content = new System.Net.Http.StreamContent(stream);

                //        //content.Headers.Add("x-ms-blob-type", "BlockBlob");

                //        //string mimeType = "text/plain";

                //        //content.Headers.Add("Content-Type", mimeType);


                //        var response = cl.PutAsync(blobUri, content).Result;


                //        if (!response.IsSuccessStatusCode)

                //        {

                //            throw new InvalidPluginExecutionException("Put request wasn't a success.");

                //        }

                //    }

                //}

                //catch (Exception e)

                //{

                //    throw new InvalidPluginExecutionException("Your file upload wasn't successful.");

                //}


                helper.createBlobContainer(connenctionString,'');


                helper.uploadBlobFileByStream("filename", stream);

                DMFDefinitionGroup::find(definitionGroupName, true).delete();


                isGenerated = true;

            }

            else

            {

                //throw error("The file was not generated succefully. See execution log");

            }

        }

        catch

        {

            //throw error("DMF execution failed and details were written to the execution log");

        }

    }


}

Service class to get the selected record and deleted matching records and refresh the form data source in D365 F&O

 [DataContractAttribute] class ABCUserProfilesBulkDeleteContract {         UserId userId;     [DataMemberAttribute('UserId')]     pu...