AX 2012: Create SSRS Line Chart Report

MakItemSalesHistory

 

Purpose:

The purpose of this document is to demonstrate how we can leverage the power of business intelligence through a simple SSRS line chart report.

Prerequisites:

  1. Visual Studio 2013
  2. Visual Studio 2013 tools.
  3. Reporting extension.
  4. Report Builder.
  5. Should be well-versed in Report Programming Model.

Business requirement:

Leverage business intelligence by analyzing sales trends for top item groups over the period of time.

Project overview:

MakItemSalesHistoryProject

Development:

We will be following the Report Programming Model to develop a precision design report.

1. Create an InMemory table, MakItemSalesHistoryTmp. This table will be used as a data set for the report in Visual Studio.

MakItemSalesHistory

2. Create an AOT query, MakItemSalesHistory. This query will be used in the Data Provider class to fetch records for the report.

MakItemSalesHistory

3. Create a data provider class, MakItemSalesHistoryDP. Bind the AOT query with it.

[
    SRSReportQueryAttribute(queryStr(MakItemSalesHistory))
]
class MakItemSalesHistoryDP extends SRSReportDataProviderBase
{
    MakItemSalesHistoryTmp  makItemSalesHistoryTmp;
}
[
    SRSReportDataSetAttribute(tableStr(MakItemSalesHistoryTmp))
]
public MakItemSalesHistoryTmp getItemSalesHistoryTmp()
{
    select makItemSalesHistoryTmp;
    return makItemSalesHistoryTmp;
}
private void insertTmpTable(SalesLine _salesLine)
{
    Qty                 qty;
    Date                shipDate;
    InventItemGroupItem groupItem;

    qty = _salesLine.QtyOrdered;
    shipDate = _salesLine.ShippingDateConfirmed;
    groupItem = InventItemGroupItem::findByItemIdLegalEntity(
        _salesLine.ItemId,
        _salesLine.DataAreaId);

    ttsBegin;
    makItemSalesHistoryTmp.clear();
    makItemSalesHistoryTmp.ItemId = _salesLine.ItemId;
    makItemSalesHistoryTmp.ItemGroupId = groupItem.ItemGroupId;
    makItemSalesHistoryTmp.Price = _salesLine.salesPrice;
    makItemSalesHistoryTmp.Amount = _salesLine.SalesPrice * Qty;
    makItemSalesHistoryTmp.Qty = qty;
    makItemSalesHistoryTmp.Year = year(shipDate);
    makItemSalesHistoryTmp.MonthOfYearId = mthOfYr(shipDate);
    makItemSalesHistoryTmp.Days = dayOfMth(shipDate);
    makItemSalesHistoryTmp.insert();
    ttsCommit;
}
[SysEntryPointAttribute(false)]
public void processReport()
{
    Query                   query;
    QueryRun                queryRun;
    QueryBuildDataSource    qbds;
    QueryBuildRange         qbr;
    SalesLine               salesLine;
    InventItemGroup         ItemitemGroup;

    query = this.parmQuery();
    qbds = query.dataSourceTable(tableNum(InventItemGroupItem));
    qbds.name("InventItemGroupItem");

    qbr = qbds.addRange(fieldNum(InventItemGroupItem, ItemGroupId));
    qbr.value(strFmt('((%1.%2 == "Speakers") || (%1.%2 == "Television"))',
        qbds.name(),
        fieldStr(InventItemGroupItem, ItemGroupId)));

    queryRun = new queryRun(query);

    while (queryRun.next())
    {
        salesLine = queryRun.get(tableNum(salesLine));
        this.insertTmpTable(salesLine);
    }
}

4. Create a controller class, MakItemSalesHistoryController. You can observe, how the report dialog has been suppressed in the controller.

class MakItemSalesHistoryController extends SrsReportRunController
{
}
static void main(Args _args)
{
    MakItemSalesHistoryController controller;

    controller = new MakItemSalesHistoryController();
    controller.parmReportName(ssrsReportStr(MakItemSalesHistory, LineChart));
    controller.parmArgs(_args);
    controller.parmShowDialog(false);
    controller.startOperation();
}

5. In Visual Studio 2013

  • Create a new Project
  • Add new Report to the solution.
  • Add new Dataset, MakItemSalesHistoryTmp, of type Report Data Provider.
  • Choose MakItemSalesHistoryDP class in the Query.
  • Add new precision design, LineChart, to the report Designs node.

MakItemSalesHistory

6. Edit LineChart using Designer.
7. Insert a new Chart report item from the Toolbox.

MakItemSalesHistory

8. Double click on the chart area to open the field editor, add the following fields as specified.

Field Drop area
Year, MonthOfYearId Category
ItemGroupId Series
Qty Data

9. Next, you can improve the aesthetics of the chart, as it pleases, by updating different chart properties available out of the box in Visual Studio.
10. Save, build and deploy the report.
11. Create an output menu item and bind it with the SSRS report.

MakItemSalesHistory

12. Add menu item to Sales and marketing > Reports > Sales orders > Item sales history.
13. You should be able to see the report in the Report viewer.

MakItemSalesHistory

Advertisements

AX 2012: Automated build deployment process

Purpose:

The purpose of this document is to describe how we can deploy automated builds to different Dynamics AX pre-production environments so that newly developed features could be rolled-out for UAT. The document also illustrates how version controlling by TFS and data migration activities fit into the big picture.

Business requirement:

Ability to release, deploy automated builds to different Dynamics AX pre-production environments to roll-out newly developed features, bug fixes for testing.

Assumptions:

  • Dynamics AX Management Utilities have been installed and configured.
  • Build scripts have been installed and configured.

AX pre-production servers topology:

ax-pre-production-environments

Process:

  1. ISV model server (Optional)
    1. Only applicable when an ISV model needs to be updated in the next build.
    2. TFS Force sync.
    3. Perform full compile, full CIL, DB synchronization.
    4. Export ISV model.
  2. Build server
    1. Must have 2 AOS instances, build and deploy. Both must not be connected to TFS.
    2. Copy ISV model to file system.
    3. Uninstall existing ISV model from build instance.
    4. Uninstall existing ISV model from deploy instance.
    5. Install new ISV model to build instance.
    6. Install new ISV model to deploy instance.
    7. Restart AOS service of build instance.
    8. Restart AOS service of deploy instance.
    9. Perform full compile, full CIL, DB synchronization on build instance.
    10. Perform full compile, full CIL, DB synchronization on deploy instance.
    11. Run build command, buildax.ps1, on build instance.
      1. Output is CUS model file created on the file system.
    12. Run deploy command, deployax.ps1 on deploy instance.
      1. Output is modelstore file created on the file system.
  3. ConsTest server
    1. Copy modelstore file to file system.
    2. Import modelstore file via powershell.
    3. Restart AOS service.
    4. Perform full compile, full CIL, DB synchronization.
  4. Document newly developed features and bug fixes in release notes.
  5. Email the notification and release notes to business stake holders.

AX 2012: Create AIF document service

Purpose:

The purpose of this document is to illustrate how we can develop AIF document service, what are the important methods available that can be overridden to do the customization and finally how we can consume/unit test the document service through an external .NET application.

Business requirement:

Ability to integrate Dynamics AX with external systems.

Assumptions:

Application Integration Framework (AIF) has been configured to process inbound and outbound messages.

Development:

  • Create an AOT query. Prefix it with Axd to follow the naming convention for document service.
  • Run AIF document service wizard to generate/regenerate:
    • Document class (Axd class).
      • Represents whole business document.
      • Used to perform cross-table validations.
      • Serializes/deserializes the document to/from XML.
    • Document object class
      • Object interface to whole business document.
    • Data object classes
      • Object interface to underlying tables involved in the document.
    • AxBC classes, if chosen
      • Wrapper classes for underlying tables involved in the document.
      • Used to perform table-level validations.
        • For example, AxSalesLine.validateWrite method.
        • It then calls validateWrite method of SalesLine table.
      • Used by Axd class to create, read, update, delete data in tables.
    • Service class
      • Contains the service operations in the form of methods.
    • Service node
      • Exposes service operations to inbound/outbound ports
  • Change namespace property of service node (optional).
  • Generate incremental CIL.
  • Register the service
  • Create security privilege for each service operation (optional).
  • Create an enhanced inbound port
  • Choose an adapter
    • File system adapter
    • HTTP
    • ISABEL SEPA credit transfer
    • MSMQ
    • NetTcp
    • Windows Azure Service Bus
  • Choose service operations
  • Activate

Important methods:

  • Axd class
    • prepareForSave/prepareForSaveExtended method
      • Validation code goes here.
      • For example checkSalesTable method in AxdSalesOrder class.
    • updateNow method
      • Business logic to be executed post insert/update of document.
      • For example, post receipt in II7.
    • expandSurrogateForeignKeys method
      • To automatically resolve surrogate foreign keys to natural keys.
    • getSurrogateForeignKeyValue method
      • To manually resolve surrogate foreign keys to natural keys.
  • AxBC class
    • initMandatoryFieldsExemptionList method
      • To make a field optional which is mandatory at the table level.
    • initMandatoryFieldsMap method
      • To make a field mandatory which is optional at the table level.
    • set<Field> method
      • To set default value of a field in service.
      • This method calls parm method to set the default value.
      • For example, setLineNum method of AxSalesLine class.
      • It calls parmLineNum method of AxSalesLine class.

Consuming service:

  • Create console application in Visual Studio
  • Add service reference
  • Sometimes, setting some fields doesn’t work in C#. We use “<Field>Specified” parameters for them.
  • For example:
    • Course.Name = “Name”;
    • Course.NameSpecified = true;
    • Course.Description = “Desc”;
    • Course.DescriptionSpecified = true;

AX 2012: Create AIF custom service

Purpose:

The purpose of this document is to illustrate how we can develop AIF custom service.

Business requirement:

Ability to integrate Dynamics AX with external systems.

Assumptions:

Application Integration Framework has been configured to process inbound and outbound messages.

Development:

  1. Create a data contract class.
    1. Use [DataContractAttribute(‘Name’)] attribute to indicate class represents data contract.
    2. Use [DataMemberAttribute(‘Name’)] attribute to indicate method represents data member.
    3. Use [AifCollectionTypeAttribute] attribute to define parameter and return types.
  2. Create a service class.
    1. Set RunOn property of class to Server.
    2. Create a method attributed with [SysEntryPointAttribute(true)] to designate it as a service operation.
    3. The boolean parameter of attribute defines whether AOSAuthorization property of tables will be checked or not in this method.
  3. Create a service contract by creating service node.
  4. Add service operation.
  5. Create a service group for the basic inbound port.
  6. Deploy the service group.
  7. The inbound port created must be activated now.

AX 2012: Add custom field to standard DIXF target entity

Purpose:

The purpose of this document is to describe how we can add custom fields to standard DIXF target entity. While performing data migration for standard entities like customer, we often come across a requirement to load data for customized fields as well. In this post, we will add custom fields of customer master to its standard DIXF entity.

Business requirement:

To load customer master through DIXF along with custom fields.

Assumptions:

1. Custom fields are already added to CustTable table.
2. DIXF component is up and running.
3. ODBC source data format has been configured.
4. Prestaging database and table is ready to fetch data from.

untitled

Development:

1. The following are the custom fields that need to be loaded through standard DIXF entity for customer master:

untitled

2. Add custom fields to DMFCustomerEntity table, which is the standard DIXF staging entity for customer master.

untitled

3. Add the same fields to the DMF field group of DMFCustomerEntity table.
4. Add the same fields to DMFCustomerTargetEntity query.

Queries > DMFCustomerTargetEntity > Data Sources > Customer(CustTable) > Fields

5. Make sure the same fields exist in the target entity, CustTable table.
6. Open Data import export framework > Setup > Target entities
7. Create new target entity as follows. You must create a new target entity to include the newly added fields.

untitled

8. Verify the newly added fields by looking at the mappings.

untitled

9. Create new processing group and select the newly created target entity

untitled

10. Generate source mapping and verify the mappings by clicking Modify source mapping.

untitled

11. You can also preview the source data by clicking Preview source file to validate data is pulling up correctly.

untitled

12. Get staging data

untitled

untitled

13. Copy data to target.

untitled

untitled

14. You can verify loaded customers in All customers list page.

untitled

15. You can also verify custom fields loaded successfully!

untitled

 

AX 2012: Open fiscal periods in X++

Purpose:

The purpose of this document is to describe how we can quickly open fiscal periods through X++.

Development:

// Developed on 28 Dec 2015 by Muhammad Anas Khan
// Blog: dynamicsaxinsight.wordpress.com
// LinkedIn: pk.linkedin.com/in/muhammadanaskhan
// Description: Ability to confirm purchase order
static void MAKOpenFiscalPeriods(Args _args)
{
    FiscalCalendarPeriod       fiscalCalendarPeriod;
    LedgerFiscalCalendarPeriod ledgerFiscalCalendarPeriod;

    ttsBegin;

    //Open fiscal periods
    update_recordSet ledgerFiscalCalendarPeriod
        setting Status = FiscalPeriodStatus::Open
        join fiscalCalendarPeriod
            where fiscalCalendarPeriod.RecId == ledgerFiscalCalendarPeriod.FiscalCalendarPeriod
                && fiscalCalendarPeriod.Type == FiscalPeriodType::Operating;

    ttsCommit;
}