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:


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


  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

    q = new Query();
    if (_sysModule == SysModule::Cust)
    q.addDataSource(tableNum(CustTable)).addRange(fieldNum(CustTable, AccountNum)).value(queryValue(_accountNum));
    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).


Submit a Comment

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

Upcoming Events


02jun2:00 pm2:30 pmBusiness Intelligence for Batch Manufacturers

16jun10:00 am10:30 amHow AP automation can speed up month-end close in D365 Finance

17jun11:00 am12:00 pmConfab Live with Stoneridge – Real Time Marketing Strategies for Success

23jun10:00 am10:30 amThe Modern Manufacturer: Cost Accounting in D365

30jun10:00 am10:30 amAP Automation Checklist for a 2022 Rebound

30jun2:00 pm2:30 pmAchieving Success: How Technology Is Helping Nonprofits Thrive


01jul11:00 am12:00 pmConfab Live with Stoneridge – Dataverse Virtual Entities

14jul12:00 pm12:30 pmBeyond Reporting - What Business Intelligence Can Do For Your Agribusiness

14jul2:00 pm3:00 pmMastering the Production Floor

15jul11:00 am12:00 pmConfab Live with Stoneridge – Integration Strategies for End User Success

21jul10:00 am10:30 amThe Modern Manufacturer: Manufacturing Software in the Real World

21jul12:00 pm1:00 pmIs it Worth it to Upgrade to Dynamics 365 Finance and Supply Chain Management? - Everything AX Users Need to Consider

28jul2:00 pm2:30 pmConsiderations for Successful Testing Plans for Major Releases of Dynamics 365 Finance and Supply Chain 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!