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]