Calculating Customer Aging Balances in X++

by | Updated January 29, 2020 | Development, Dynamics AX

I was recently asked to add an Account Summary to the footer of a report in AX 2012, to look something like this:

CustomerAgingBalances_LauraLake

In my research, I came across a helpful class that allowed me to meet this requirement of calculating customer aging balances in X++ with a minimum of coding effort; the CustVendAgingStatistics class. The calcStatistic method queries StatRepInterval and StatRepIntvervalLine to get the buckets and settings for the calculation, then it writes out the values to tmpAccountSum, which is an InMemory temporary table. Depending on what aging buckets you need, you can use a debugger to figure out which tmpAccountSum records you will want.

For my purpose, I created a new method to calculate the customer’s aging balances using a 30D format (#agingFormat macro). I needed open balances (Balance03) and I opted to store both balance and description in a Map. The integer key was helpful so that I could retrieve the values later and add them to the SalesInvoiceHeaderFooterTmp record in SalesInvoiceDP.insertSalesInvoiceHeaderFooterTmp method. You could easily use a container here, depending on how you are using the aging information.

Obviously, this could be used for Vendor Aging as well. I verified that the values match exactly with the Customer Aging report when it is run with the same parameters.

Related Posts

2 Comments

  1. RLP

    That works great if the you want the balances as of today, but not if you need to apply a statement end date: out of the box, the CustVendAgingStatistics class does not support a date range.

    The CustVendAgingStatistics class could be modified to support an end date, but the same end results can achieved (but with more code) without modifying any out-of-the-box classes. The following works, but might be able to be refactored to be more elegant.

    static void RLP_CustVendAgingAsOfDate(Args _args)
    {
    // These first variables would be passed in as parameters
    SysModule _sysModule = SysModule::Cust;
    AccountNum _accountNum = ‘C16652′;
    TransDate _statementEndDate = 28\03\2017;
    CustVendReportName _agingFormat = ’30/60/90/120’;
    DateTransactionDuedate _dateFieldToUseForAging = DateTransactionDuedate::DocumentDate;

    // These parallel arrays store the results
    str agingHeaders[];
    AmountCur agingAmounts[];

    CustAgingCalculation custAgingCalculation;
    CustVendAgingCalculatedTmp custVendAgingCalculatedTmp;
    CustVendAgingPeriodScaleTmp custVendAgingPeriodScaleTmp;
    Query q;
    QueryRun qr;

    custAgingCalculation = CustVendAgingCalculation::construct
    (
    _sysModule,
    _dateFieldToUseForAging,
    _statementEndDate,
    _agingFormat,
    _statementEndDate
    );

    q = new Query();
    if (_sysModule == SysModule::Cust)
    {
    q.addDataSource(tableNum(CustTable)).addRange(fieldNum(CustTable, AccountNum)).value(queryValue(_accountNum));
    }
    else
    {
    q.addDataSource(tableNum(VendTable)).addRange(fieldNum(VendTable, AccountNum)).value(queryValue(_accountNum));
    }
    qr = new QueryRun(q);

    custVendAgingCalculatedTmp = custAgingCalculation.process(qr);
    custVendAgingPeriodScaleTmp = custAgingCalculation.getCustVendAgingPeriodScaleTmp();

    while select BucketNumber, sum(AmountCur)
    from custVendAgingCalculatedTmp
    group by custVendAgingCalculatedTmp.BucketNumber
    {
    agingAmounts[custVendAgingCalculatedTmp.BucketNumber] = custVendAgingCalculatedTmp.AmountCur;
    }

    while select BucketNumber, BucketDescription
    from custVendAgingPeriodScaleTmp
    group by custVendAgingPeriodScaleTmp.BucketNumber, custVendAgingPeriodScaleTmp.BucketDescription
    {
    agingHeaders[custVendAgingPeriodScaleTmp.BucketNumber] = custVendAgingPeriodScaleTmp.BucketDescription;
    }
    }

  2. Brandon Carmichael

    Hello RLP,

    Thank you for your comment and code. After talking with Laura, she mentioned she didn’t need the date as she needed the ‘balance as of today’. I’m hoping someone will find your code helpful.

    User discretion is advised – Stoneridge Software did not create, use, or test the code above (RLP’s comment).

    Thanks,
    Brandon

Submit a Comment

Your email address will not be published. Required fields are marked *

Upcoming Events

august

12aug10:00 am10:30 amWhy Levridge Grain? How to Achieve Efficient and Accurate Scale Tickets

12aug12:00 pm1:00 pmThe Three Paths to Dynamics 365 Finance and Supply Chain from Dynamics AX

13aug11:00 am12:00 pmConfab with Stoneridge - Livestream - Inspire Keynote Breakdown

19aug10:00 am11:00 amWhat is Levridge? An Overview of the Ultimate Ag Solution

19aug12:00 pm12:30 pmThe Modern Manufacturer - Death by Safety Stock

27aug11:00 am12:00 pmConfab with Stoneridge - Livestream - Dynamics 365 2020 Wave 2 Preview

september

02sep10:00 am10:30 amThe Modern Manufacturer - Cycle Count Management

09sep10:00 am11:00 amWhat is Levridge? An Overview of the Ultimate Ag Solution

16sep10:00 am10:30 amThe Modern Manufacturer - Product Lifecycle Management

30sep10:00 am10:30 amThe Modern Manufacturer - Return Management

About Stoneridge
Stoneridge Software is a unique Microsoft Gold Partner, with emphasis on partner. With specialties in Microsoft Dynamics 365, Microsoft Dynamics AX, Microsoft Dynamics NAV, Microsoft Dynamics GP and Microsoft Dynamics CRM, we focus on attracting the most knowledgeable experts in the field to our team, and prioritize delivering stellar solutions with maximum impact for your business. At Stoneridge, we are deeply committed to your results. Each engagement is met with a dedicated team, ready to provide thorough, tailored, and expert service. Based in Minnesota, we intentionally “step into your shoes,” wherever you are. We focus on what you care about, and develop trusting, long-term relationships with our clients.

Subscribe To Our Blog

Sign up to get periodic updates on the latest posts.

Thank you for subscribing!

X