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

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

        }

    }


}

16 September 2023

D365 F&O Data Management entity export for all companies data

 On the dataEntity properties "Primary company Context" property set to "DataAreaId" that means it will export the data on the current company.



To export all companies data:

 DataEntity properties "Primary company Context" property set to Emply  that means it will export the data on the current company



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->...