Sunday, March 27, 2016

AX 2012 : Generate customer account statement as PDF through X++

Customer account statement in AX 2012 R3 can be generated from Accounts Receivable > Reports > External > Customer account statement. However, if we need to generate this report through code - how can we achieve this?

I created a new query in AOT with only dataSource 'CustTable', as I want to loop on selected customers only. I created a class extending from RunBase (did not want to touch existing report and class for customer account statement) being considering it a custom process of generating customer account statement using X++ code opposed to what exists in system.

New query looks like this with three ranges, these ranges will show on dialog form

















Created a new class with following methods which are common for every dialog class;


  • main
  • construct
  • new
  • pack
  • unpack
  • dialog
  • getFromDialog
  • run
  • showQueryValues
  • queryRun

I will explain important methods from the class which I think need discussion.

QueryRun method - this method will be called from Pack() method from this line of code return [#CurrentVersion,#CurrentList,this.queryRun().pack()];


public QueryRun queryRun()
{
    QueryRun                ret;
    QueryBuildDataSource    qbds;
    CustTable               custTable = CustTable::findRecId(selectedRec);
    if (!queryRun)
    {
        query   =   new query(queryStr(FF_CustAccountStatement));
        qbds = query.dataSourceTable(tableNum(custTable));
        if(selectedRec)
        {
            SysQuery::findOrCreateRange(qbds, fieldNum(custTable, AccountNum)).value(custTable.AccountNum);
            SysQuery::findOrCreateRange(qbds, fieldNum(custTable, CustGroup)).value(custTable.CustGroup);
            SysQuery::findOrCreateRange(qbds, fieldNum(custTable, AccountStatement)).value(SysQuery::value(custTable.AccountStatement));
        }
        else
        {
            SysQuery::findOrCreateRange(qbds, fieldNum(custTable, AccountNum)).value(SysQuery::valueUnlimited());
            SysQuery::findOrCreateRange(qbds, fieldNum(custTable, CustGroup)).value(SysQuery::valueUnlimited());
            SysQuery::findOrCreateRange(qbds, fieldNum(custTable, AccountStatement)).value(SysQuery::valueUnlimited());
        }
        queryRun    =   new QueryRun(query);
    }
    ret = queryRun;
    return ret;
}

This method generates customer account statement for each provided customer in query. This method is called from run() method;

while (queryRun.next())
    {
        custTable    =   queryRun.get(tableNum(custTable));
        //this.setParameters(custTable);

        filename    =   WinAPI::getTempPath()+"Customer "+ custTable.AccountNum+ " Customer Account Statement.pdf";

        this.createCustAccountStatement(custTable, filename);

    }

public void createCustAccountStatement(CustTable _custTable,FileName _filename)
{
    CustAccountStatementExtController      controller = new CustAccountStatementExtController();
    SRSPrintDestinationSettings            printSettings;
    CustAccountStatementExtContract        Contract;

    controller.parmReportName(PrintMgmtDocType::construct(PrintMgmtDocumentType::CustAccountStatement).getDefaultReportFormat());
    controller.parmLoadFromSysLastValue(true);
    controller.parmShowDialog(false);

    printSettings = controller.parmReportContract().parmPrintSettings();

    printSettings.printMediumType(SRSPrintMediumType::File);
    printSettings.fileFormat(SRSReportFileFormat::PDF);
    printSettings.overwriteFile(true);
    printSettings.fileName(_filename);

    Contract = controller.parmReportContract().parmRdpContract() as CustAccountStatementExtContract;

    enumerator = controller.parmReportContract().parmQueryContracts().getEnumerator();
    enumerator.moveNext();
    query = enumerator.currentValue();
    query.dataSourceTable(tableNum(CustTable)).addRange(fieldNum(CustTable, AccountNum)).value(queryValue(_custTable.AccountNum));

    Contract.parmAgingBucket(agingBucket);
    Contract.parmAgingBucketPrintDescription(AgingBucketPrintDescription);
    Contract.parmAgingPeriod(agingPeriod);
    Contract.parmDayMonth(dayMonth);
    Contract.parmFromDate(fromDate);
    Contract.parmIncludeReversed(includeReversed);
    Contract.parmManualSetup(manualSetup);
    Contract.parmOnlyOpen(onlyOpen);
    Contract.parmPrintAging(printAging);
    Contract.parmPrintAmountGiro(printAmountGiro);
    Contract.parmPrintCreditLimit(printCreditLimit);
    Contract.parmPrintGiro(printGiro);
    Contract.parmPrintingDirection(printingDirection);
    Contract.parmPrintNonZero(printNonZero);
    Contract.parmPrintPaymentSchedule(printPaymentSchedule);
    Contract.parmPrintType(printType);
    Contract.parmSpecifyDueToDate(specifyDueToDate);
    Contract.parmToDate(toDate);
     
    controller.startOperation();
}

It generates report in user's temp folder for each selected customer on below screen [this is custom screen created by a class which I referred above]



4 comments:

  1. Thanks for this post.

    are there some missing declarations?
    getting errors on 'selectedRec' and 'enumerator'

    ReplyDelete
    Replies
    1. is it possible to add custom parameter in customer account statement ext. I am trying to add but it does not show up.

      Delete
    2. Yes that's absolutely possible - you need to add param methods for your required parameters in contract class and call them in controller or service class.

      Delete
    3. You can declare these variables in class declaration as follows;
      RecId selectedRec;
      Enumerator enumerator;

      Delete

I will appreciate your comments !