Monday, December 29, 2014

Getting number of recrods present in a query

If you want to get the total number of records from a query run object, which can be used to set total count in a progress bar (progress indication framework).

Solution: Use SysQuery::countloop([QueryRun _queryRun]). this will return the total number of records in a query object

Wednesday, December 24, 2014

Generating SSRS report in PDF via code X++

Following is a sample code for generating SSRS report in PDF format using X++ code. This sample code generates Purchase order confirmation report in PDF format and saves it into specified location.


PSAPurchaseOrderController poConfirmationController;
PurchPurchaseOrderContract purchPOContract;
SRSReportExecutionInfo     reportExecutionInfo;
Args                       args = new Args();
SrsReportRunImpl           srsReportRun;
VendPurchOrderJour         vendPurchOrderJour;
ReportName                 reportName = ssrsReportStr(PSAPurchaseOrder, Report);

str                        fileName;
;

select firstOnly vendPurchOrderJour
order by RecId desc
where vendPurchOrderJour.PurchId == '';//Replace with PurchOrder Id

if (!vendPurchOrderJour)
return '';


args.record(vendPurchOrderJour);
poConfirmationController= PSAPurchaseOrderController::construct();
poConfirmationController.parmArgs(args);
poConfirmationController.parmReportName(reportName);
reportExecutionInfo = poConfirmationController.parmReportContract().parmReportExecutionInfo();
purchPOContract= poConfirmationController.parmReportContract().parmRdpContract();


purchPOContract.parmRecordId(vendPurchOrderJour.RecId); // Record id must be passed otherwise the report will be empty

poConfirmationController.parmArgs(args);srsReportRun = poConfirmationController.parmReportRun() as SrsReportRunImpl;


fileName = System.IO.Path::Combine(WinAPIServer::getTempPath(), strFmt('purchConfirmation_%1.pdf', _purchId));
poConfirmationController.parmReportRun(srsReportRun);
poConfirmationController.parmReportContract().parmPrintSettings().printMediumType(SRSPrintMediumType::File);
poConfirmationController.parmReportContract().parmPrintSettings().overwriteFile(true);


poConfirmationController.parmReportContract().parmPrintSettings().fileFormat(SRSReportFileFormat::PDF);
poConfirmationController.parmReportContract().parmPrintSettings().fileName(fileName);

poConfirmationController.runReport();

Tuesday, November 25, 2014

Creating a class object using X++

The following Job shows the code used for creating a "Class" using X++ code. This code may be used in scenarios like AIF service, Workflow generation etc processes where different objects like "Class" are created automatically using the similar code mentioned below.

static void BlogTestJob(Args _args)
{
    ClassBuild  classBuild;
    str         header;
    str         newClassName = "SampleClass";
    ;

    header = 'public class '+ newClassName;
    classBuild = new ClassBuild(newClassName);
    classBuild.addMethod('classdeclaration', header + '\n{\n}\n');
    classBuild.addMethod('main', 'public static void main(Args    _args)' + '\n{\n}\n');
    classBuild.classNode().AOTcompile(1);

    info('Job completed....');
}

Monday, November 24, 2014

Importing Sales order XML using X++

The following job will create Sales order using Document service through X++ code.

static void JobTestWebService_ImportXml(Args _args)
{
    //feed the xml that was modified after exporting through exportxml job
    XmlDocument xml = XmlDocument::newFile(@'C:\SORequest.xml');
    AxdSalesOrder salesOrder;

    try
    {
        salesOrder = new AxdSalesOrder();
        salesOrder.create(xml.xml(),  new AifEndPointActionPolicyInfo(), new AifConstraintList());
    }
    catch
    {
        throw error('Error in document service');
    }
    info(strFmt('Sales order created'));
}

Sample XML File

<?xml version="1.0" encoding="utf-8" ?>
<SalesOrder xmlns="http://schemas.microsoft.com/dynamics/2008/01/documents/SalesOrder">
<SalesTable class="entity">
  <CustAccount>1204</CustAccount>
  <DeliveryDate>2011-10-11</DeliveryDate>
  <ReceiptDateRequested>2011-11-11</ReceiptDateRequested>
  <PurchOrderFormNum>ABC-98654</PurchOrderFormNum>
<TableDlvAddr class="entity">
<Address>KEVIN DAVIS 13075 MANCHESTER RD STE 228.A  DES PERES, MO 631311878 </Address>
<City>DES PERES</City>
<CountryRegionId>USA</CountryRegionId>
<County>JEFFERSON</County>
<ISOcode>US</ISOcode>
<LocationName>KEVIN DAVIS</LocationName>
<State>MO</State>
<Street>13075 MANCHESTER RD STE 228.A </Street>
<ValidFrom>2014-11-11T00:00:00Z</ValidFrom>
<ValidTo>2014-11-11T00:00:00Z</ValidTo>
<ZipCode>631311878</ZipCode>
</TableDlvAddr>
  <SalesLine class="entity">
<ItemId>0001</ItemId>
<SalesQty>20</SalesQty>
<SalesPrice>82.25</SalesPrice>
<SalesUnit>Pcs</SalesUnit>
  </SalesLine>
</SalesTable>

</SalesOrder>

Exporting XML Sales order using AIF service

The following job will export the Sales order information into an XML format which can be used by document service in order to test Sales order creation using XML.

static void JobTestWebService_ExportXml(Args _args)
{
    AxdAddress address;
    AxdSalesOrder salesOrder;

    AifEntityKey    key;
    Map             map;

    //dummy variable
    AifPropertyBag bag;

    map = new Map(Types::Integer, Types::Container);
    map.insert(fieldnum(SalesTable, SalesId), ['SO-101327']);
    
    key = new AifEntityKey();
    key.parmTableId(tablenum(SalesTable));
    
    key.parmKeyDataMap(map);

    try
    {
        address = new AxdAddress();
        salesOrder = new AxdSalesOrder();
        info('XML output');
        info(salesOrder.read(key, null, new AifEndPointActionPolicyInfo(), new AifConstraintList(), bag));
    }
    catch
    {
        throw error('Error in document service outbound');
    }
}

Filter records on form using X++

This post will shows the steps required to filter records on form using parameters provided by the caller.

Step 1
Declare a class variable 
In the ClassDeclaration method of form declare a QueryBuildRange

class FormRun extends ObjectRun
{
    QueryBuildRange      abcQueryRange;
    ABC                  abcCode;
}

Step 2
Initialize this range in the init method of datasource after super() call.

public void init()
{
    super();
    abcQueryRange = this.query().dataSourceName('X').addRange(fieldnum(X, ABC));

}

Step 3
Now assign the filter value in the executeQuery method of same datasource before super() call.

public void executeQuery()
{
    if (abcCode)
    {
        abcQueryRange.value(queryValue(abcCode));
    }
    super();

}

The query filtration part is done, you now need to fetch the value of "abcCode" from the caller. For this you need to grab the values from argument passed by the caller in the "init" method form.


public void init()
{
    if (element.args().record())
    {
        if (element.args().record().TableId == tablenum(x))
        {
            abcCode
 = X::findRecId(element.args().record().RecId).abcCode;
        }
    }
    super();

}

Wednesday, October 29, 2014

Fetching Financial Dimension Value X++

This post shows the code for extracting Financial Dimension value by providing dimension name for each dimension combination which is created and persisted. 

The DimensionAttributeValueCombination table contains information about accounts and various dimensions combinations that are used. However, they are stored as a combination ex: (100010-AX-00001- – – -). These values are retrieved through DimensionAttributeValueSetStorage storage class. This class can be used to manipulate these combinations.

The job below helps you in finding out the required values. 


static void AI_GetProjectCostCenterValue(Args _args)
{
    ProjTable                           projTable;
    DimensionAttributeValueSetStorage   dimStorage;
    str                                 dimValue;
       
    projTable = projTable::find('000409');
    dimStorage = DimensionAttributeValueSetStorage::find
                 projTable.DefaultDimension);
    
    info(strFmt('Project 000409, Cost Center value : %1',                        dimStorage.getDisplayValueByDimensionAttribute(                      DimensionAttribute::findByName('CostCenter').RecId)));
    
}

Output

Project 
In order to fetch Value and Description use the following query

      DimensionAttributeValueSet      dimensionAttributeValueSet;
    DimensionAttributeValueSetItem  dimensionAttributeValueSetItem;
    DimensionAttributeValue         dimensionAttributeValue;
    DimensionAttribute              dimensionAttribute;
    DimensionFinancialTag           dimensionFinancialTag;
    ProjTable                       projTable;

    while select RecId from projTable
        join RecId from dimensionAttributeValueSet
            where dimensionAttributeValueSet.RecId == projTable.DefaultDimension
               && projTable.ProjId == this.ProjId
        join RecId from dimensionAttributeValueSetItem
            where dimensionAttributeValueSetItem.DimensionAttributeValueSet == dimensionAttributeValueSet.RecId
        join RecId from dimensionAttributeValue
            where dimensionAttributeValue.RecId == dimensionAttributeValueSetItem.DimensionAttributeValue
        join RecId from dimensionAttribute
            where dimensionAttributeValue.DimensionAttribute == dimensionAttribute.RecId
//&& dimensionAttribute.Name == 'A_Managing_Group' //Un Comment to get specific value of Financial Dimension
        join Description from dimensionFinancialTag
            where dimensionFinancialTag.RecId == dimensionAttributeValue.EntityInstance
{
    info(strfmt('%1', dimensionFinancialTag.Description));
}