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

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