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

october

07oct12:00 pm1:00 pmThe Three Paths to Business Central from Dynamics GP

08oct11:00 am12:00 pmConfab with Stoneridge - Livestream - The Vision and Strategy of Microsoft Business Systems

14oct10:00 am10:30 amThe Modern Manufacturer - Managing Complex Cost Modeling

14oct12:00 pm12:30 pmGenerating Custom Inspection or Process Forms

19octAll Day22Stoneridge Connect Fall 2020

22oct11:00 am12:00 pmConfab with Stoneridge - Livestream - Stoneridge Connect Recap

28oct10:00 am10:30 amThe Modern Manufacturer - Engineering Change Management: Introduction of NEW Functionality for Manufacturers Using Dynamics 365

november

11nov10:00 am10:30 amThe Modern Manufacturer - Tears and Trauma of MRP

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