Sunday, 28 May 2017

Developing Report Data Provider (RDP) based SSRS reports.

Overview

There are multiple methods to develop SSRS reports in Microsoft Dynamics AX 2012. This tutorial will guide you in developing Report Data Provider (RDP) based SSRS reports.
RDP based SSRS Reports are used when complex business logic cannot be achieved using AOT query.

Pre-requisites

  1. Microsoft Dynamics AX 2012
  2. Visual studio 2012
  3. SQL Server Reporting Services (SSRS) must be configured
  4. Reporting services extensions must be installed in Dynamics AX

Important Concepts

  1. Report Data Provider (RDP) Class

  2. Report Data Provider Class is an X++ class that is used to access and process data for a SSRS report. The RDP class processes the business logic based on a specified parameter and/or query and returns a dataset to the reporting services. In order to create a RDP class in AX, you have to extend that class with SRSReportDataProviderBase. This tells AX that this class will be used by reporting services to process the data.
    Two important attributes are used in RDP classes:
    1. SRSReportQueryAttribute: specifies which AOT query will be used in this report. If the RDP class uses an AOT query to process data, define this attribute at the beginning of the class.
    2. SRSReportParameterAttribute: defines the data contract class that will be used by this report to prompt for parameter values. If the RDP class contains any parameters this define this attribute at the beginning of the class.
    Both the attributes are optional. If the report does not use any query or does not want any parameter to filter report data, these attributes do not need to be used.
  3. Data Contract Class

  4. A data contract class is an X++ class which contains parm methods with the DataMemberAttribute defined at the beginning of the method. This class is used to define one or more parameters that will be used in a SSRS report.
  5. Table

An AX table is used as the dataset to store data for the report. The RDP class processes the data and stores it in the table which is then used by a SSRS report to render data.
A table can be a temporary table (InMemory or TempDB) or a regular table, but it is Microsoft best practice to use a temporary table.
The type of temporary table is based upon the performance considerations. InMemory temporary table is used when the data set is small, while TempDB is normally used for larger datasets to improve performance.

Scenario

As part of this tutorial, the report will print a list of customers and their invoiced sales order counts.

Steps

  1. First of all, create a temporary table. Open AOT à Date Dictionary à Tables.
  2. Right Click on Tables and create a new Table called CustReportRDPDemoTmp.
  3. Set the TableType property to InMemory. This will define the table as a temporary table.


  4. Expand the CustReportRDPDemoTmp table node and add the following fields in the table:

  5. S. No.Field nameExtended Data TypeLabel
    1CustAccountCustAccount
    2NameName
    3SalesOrderInvoiceCountIntegerSales order invoiced

  6. The final table should look like the following:


  7. Now create a RDP class. Go to Classes and create a new class called CustReportRDPDemoDP by right clicking on Classes and selecting New Class. It is a best practice to suffix the RDP class name with DP .


  8. Open the Class declaration by right clicking on it and selecting View code.


  9. Now write the following code:
  10. class CustReportRDPDemoDP extends SRSReportDataProviderBase
    {
    //Temporary table buffer
    CustReportRDPDemoTmp custReportRDPDemoTmp;
    }
    
  11. Add a new method and name it getCustReportRDPDemoTmp. This method is mandatory because reporting services uses this method to get the table buffer containing the processed data. The SRSReportDataSetAttribute attribute is used to indicate the temporary table name and also tells the reporting services to use this method to retrieve the processed data.
  12. Write the following code in the method:
  13. [SRSReportDataSetAttribute(tablestr('CustReportRDPDemoTmp'))]
    public CustReportRDPDemoTmp getCustReportRDPDemoTmp()
    {
    //select data from table buffer
    select * from custReportRDPDemoTmp;
    //return the buffer
    return custReportRDPDemoTmp;
    }
    
  14. Add a new method and name it processReport. This method contains the business logic and is called by reporting services to generate data.
  15. This method will query customer details and fill the temporary table buffer. Write the following code in the method:
  16. ///
    /// Processes the SQL Server Reporting Services report business logic
    /// 
    /// 
    /// This method provides the ability to write the report business logic. This method will be called by
    /// SSRS at runtime. The method should compute data and populate the data tables that will be returned
    /// to SSRS.
    /// 
    public void processReport()
    {
    CustTable custTable;
    SalesTable salesTable;
    //select all customers
    while select * from custTable
    {
    //clear the temporary table
    custReportRDPDemoTmp.clear();
    //assign customer account and name
    custReportRDPDemoTmp.CustAccount = custTable.AccountNum;
    custReportRDPDemoTmp.Name = custTable.name();
    //select count of invoiced sales order of customer
    select count(RecId) from salesTable
    where salesTable.CustAccount == custTable.AccountNum
    && salesTable.SalesStatus == SalesStatus::Invoiced;
    custReportRDPDemoTmp.SalesOrderInvoiceCount = int642int(salesTable.RecId);
    //insert in temporary table buffer
    custReportRDPDemoTmp.insert();
    }
    }
    
  17. Now create a new report. Since the development of a SSRS report is done in Visual studio, we first need to create a new project in Visual studio.
  18. Open Visual studio. Go to File à New à Project
  19. In the Installed templates section select Microsoft Dynamics AX and then select Report Model in the right pane. Name the project RDPBasedDemo and press Ok.


  20. A new project will be created as shown below.


  21. Now add a new report in the project by right clicking on the project RDPBasedDemo à Add à Report.

  22. A report will be added to the project with the name Report1. Rename the report RDPBasedDemo.
  23. Now double click the report to open it.

  24. The description of the individual node is given below:
    1. Datasets: Datasets retrieve data from RDP class. It acts as a bridge between AX and the SSRS report. Only the fields added in the datasets can be used in a report.
    2. Designs: It defines the layout of the report.
    3. Images: It contains the images that you want to display in the SSRS report.
    4. Data Methods: It contains the business logic which can then be used in the report.
    5. Parameters: It is used to apply filtering to the data in a report. All the parameters defined in the data contract class are automatically added here when the RDP class is defined in the datasets.
  25. Now you will want to create a new Dataset by right clicking Datasets àAdd Dataset. Name it CustDetail.


  26. Select the CustDetail dataset and open the properties window. Set the Data Source Type to Report Data Provider. Then select the Query field. An ellipse button appears. Click it to open a dialog box.


  27. This dialog box lists all the RDP classes present in the AOT. Select CustReportRDPDemoDP and press Next.


  28. Select the fields to be displayed in the report and press OK. Only the fields selected in this dialog box can be shown in the report.


  29. There are two types of designs that can be created in a SSRS report:
    1. Auto design: Visual studio automatically creates a design based on the dataset provided. Auto design is the preferred method because it is easy and usually fulfills the majority scenarios.
    2. Precision Design: This is used when you need custom placement of fields or the layout of the report is too complex.
  30. In this demo we will use Auto Design. Now right click the Designs nodeàAdd àAuto Design. A new design is added. Rename it Design. It is recommended that you set the name of the Design to either ‘Design‘ or ‘Report‘.


  31. Now drag the CustDetail form to the Datasets node and drop it on the Design node. A table will be created which contain all the fields present in the data set. These fields will appear in the same order as in the report. So if you want to arrange the fields, right click the field and select either ‘move up’ or ‘move down’.
  32. The final design should look like the following:


  33. Now we have to define the layout of the report. Visual studio provides built in templates. Select the Design and open the properties window. Select ReportLayoutStyleTemplate in the LayoutTemplate field. Give a suitable title to the report.


  34. Select CustDetailTable under the Design node and open the properties window. Select TableStyleAlternatingRowsTemplate in the Style Template field.


  35. The report is now completed and can be viewed. To preview the report, select the Design node, right click it and select preview.


  36. Select the Report tab. The report will appear as shown below:

  37. To view this report from AX, Add the report to AOT and create an Output menu item and set the appropriate Properties. For further details on creating SSRS reporting, refer to our previous article ‘Developing SSRS report using Query‘.

Friday, 12 May 2017

Update Financial dimensions for all customers using X++

static void DefaultFinancialDim(Args _args)
{
    DimensionAttributeValue dimAttrBUValue,dimAtrrCCValue,dimAtrrDepValue,dimAttrIGValue,dimAtrrProjValue;
    DimensionAttribute dimAttrBU,dimAtrrCC,dimAtrrDep,dimAttrIG,dimAtrrProj;
    DimensionAttributeValueSetStorage davss;
    RecId defaultDimension;
    CustTable custTable;

    while select forUpdate custTable
    {
        if(custTable.AccountNum)
        {
            davss = DimensionAttributeValueSetStorage::find(CustTable::find(custTable.AccountNum).DefaultDimension);

            dimAttrBU = DimensionAttribute::findByName('BusinessUnit');
            dimAtrrCC = DimensionAttribute::findByName('CostCenter');
            dimAtrrDep = DimensionAttribute::findByName('Department');
            dimAttrIG = DimensionAttribute::findByName('ItemGroup');
            dimAtrrProj = DimensionAttribute::findByName('Project');

            dimAttrBUValue = DimensionAttributeValue::findByDimensionAttributeAndValue(dimAttrBU, "003", false, true);
            dimAtrrCCValue = DimensionAttributeValue::findByDimensionAttributeAndValue(dimAtrrCC, "009", false, true);
            dimAtrrDepValue = DimensionAttributeValue::findByDimensionAttributeAndValue(dimAtrrDep, "024", false, true);
            dimAttrIGValue = DimensionAttributeValue::findByDimensionAttributeAndValue(dimAttrIG, "AudioRM", false, true);
            dimAtrrProjValue = DimensionAttributeValue::findByDimensionAttributeAndValue(dimAtrrProj, "000006", false, true);

            if(dimAttrBUValue || dimAtrrCCValue ||dimAtrrDepValue || dimAttrIGValue || dimAtrrProjValue)
            {
                davss.addItem(dimAttrBUValue);
                davss.addItem(dimAtrrCCValue);
                davss.addItem(dimAtrrDepValue);
                davss.addItem(dimAttrIGValue);
                davss.addItem(dimAtrrProjValue);
                //custTable = custTable::find(custTable.AccountNum, true);

                ttsBegin;
                custTable.DefaultDimension = davss.save();

                custTable.update();
                ttsCommit;

                info(custTable.AccountNum);
            }
        }
    }

}

How to update financial dimensions for master data using x++ code in Ax 2012


Customers:

To update financial dimensions to all legal entities.

static void updateCustomerDimensions(Args _args)
{
    CustTable       custTable;
  
    Struct struct;// = new Struct();
    container           ledgerDimension,com;
    DimensionDefault    DimensionDefault;
    CompanyInfo         companyInfo;

    while select companyInfo where companyInfo.DataArea !="DAT"
    {
        struct = new struct();
        com = conNull();
        changeCompany(companyInfo.DataArea)
        {
            ledgerDimension =conNull();
            com = conIns(com,1,companyInfo.DataArea);
          
            struct.add('LegalEntity',companyInfo.DataArea);
            ledgerDimension += struct.fields();
            ledgerDimension += struct.fieldName(1);
            ledgerDimension += struct.valueIndex(1);


            DimensionDefault = AxdDimensionUtil::getDimensionAttributeValueSetId(ledgerDimension);
            //Customers
          
            while select forUpdate crossCompany:com * from custTable
            {
                if(custTable.RecId)
                {
                    ttsBegin;
                    custTable.DefaultDimension = DimensionDefault;
                    custTable.update();
                    info(strFmt("Customer %1 dimension updated -- %2",custTable.AccountNum,custTable.dataAreaId));
                    ttsCommit;
                }
            }
        }
    }


}

Fixed asset:

static void updateAssetDimensions(Args _args)
{
    AssetTable      assetTable;
    AssetBook       assetBook;
    Struct struct;// = new Struct();
    container           ledgerDimension,com;
    DimensionDefault    DimensionDefault;
    CompanyInfo         companyInfo;

    while select companyInfo where companyInfo.DataArea !="DAT"
    {
        struct = new struct();
        com = conNull();
        changeCompany(companyInfo.DataArea)
        {
            ledgerDimension =conNull();
            com = conIns(com,1,companyInfo.DataArea);

            struct.add('LegalEntity',companyInfo.DataArea);
            ledgerDimension += struct.fields();
            ledgerDimension += struct.fieldName(1);
            ledgerDimension += struct.valueIndex(1);


            DimensionDefault = AxdDimensionUtil::getDimensionAttributeValueSetId(ledgerDimension);
            //Vendors

            while select forUpdate crossCompany:com * from assetBook
            {
                if(assetBook.RecId)
                {
                    ttsBegin;
                    assetBook.DefaultDimension = DimensionDefault;
                    assetBook.update();
                    info(strFmt("Asset %1 dimension updated -- %2",assetBook.assetid,assetBook.dataAreaId));
                    ttsCommit;
                }
            }
        }
    }


}

Update financial dimensions for master data:

static void testUpdateCustomerDimensions(Args _args)
{
    CustTable           custTable;
    Struct              struct;
    container           ledgerDimension,com;
    DimensionDefault    DimensionDefault,custDimensionDefault;
    CompanyInfo         companyInfo;

    DimensionAttributeValueSetStorage    dimStorage;
    Counter                              i;
    str                                  BusUnit,CCUnit,Dep,IG;
    ProjId                               projId;
    container                            conDefaultdim;

    struct = new struct();
    com = conNull();

    ledgerDimension =conNull();

    select forUpdate custTable where custTable.AccountNum =="US-011";

    custDimensionDefault = custTable.DefaultDimension;

    dimStorage = DimensionAttributeValueSetStorage::find(custDimensionDefault); //default dimension value

    for (i=1 ; i<= dimStorage.elements() ; i++)
    {
        if(DimensionAttribute::find(dimStorage.getAttributeByIndex(i)).Name == "BusinessUnit")
        {
            BusUnit = dimStorage.getDisplayValueByIndex(i);
        }
        if(DimensionAttribute::find(dimStorage.getAttributeByIndex(i)).Name == "CostCenter")
        {
            CCUnit = dimStorage.getDisplayValueByIndex(i);
        }
        if(DimensionAttribute::find(dimStorage.getAttributeByIndex(i)).Name == "Department")
        {
            Dep = dimStorage.getDisplayValueByIndex(i);
        }
        if(DimensionAttribute::find(dimStorage.getAttributeByIndex(i)).Name == "ItemGroup")
        {
            IG = dimStorage.getDisplayValueByIndex(i);
        }


        if(DimensionAttribute::find(dimStorage.getAttributeByIndex(i)).Name == "Project")
        {
            projId = "000003";//dimStorage.getDisplayValueByIndex(i);
        }

    }
    //projId = "000002";

    conDefaultdim = [5,'BusinessUnit',BusUnit,'CostCenter',CCUnit,'Department',Dep,'ItemGroup',IG,'Project',projId];

    DimensionDefault = AxdDimensionUtil::getDimensionAttributeValueSetId(conDefaultdim);

    if(custTable.RecId)
    {
        ttsBegin;
        custTable.DefaultDimension = DimensionDefault;
        custTable.update();
        info(strFmt("Customer %1 dimension updated -- %2",custTable.AccountNum,custTable.dataAreaId));
        ttsCommit;
    }


}

http://axgenius.blogspot.in/2017/05/how-to-update-financial-dimensions-for.html


Monday, 1 May 2017

SysMultiTableLookup for Multiple lookup fields from multiple tables

   public void lookup()

   {

    SysMultiTableLookup  sysMultiTableLookup;
    Query                query;
    QueryBuildDataSource queryBuildDataSource,qbds1;
    QueryBuildRange      qbr;
    VendTable            vendtable;
    DirPartyTable        dirPartyTable;
    super();

 
    query = new Query();
    queryBuildDataSource = query.addDataSource(tableNum(VendTable));
    qbds1                =  queryBuildDataSource.addDataSource(tablenum(DirPartyTable));
    qbds1.relations(true);

    sysMultiTableLookup =   SysMultiTableLookup::newParameters(VendorAcc,query);
   //vendorAcc is control name

    sysMultiTableLookup.addLookupfield(fieldNum(VendTable,AccountNum),1);
    sysMultiTableLookup.addLookupfield(fieldNum(dirPartyTable,Name),2);

    sysMultiTableLookup.parmQuery(query);
    sysMultiTableLookup.performFormLookup();
}

Thursday, 27 April 2017

Import Vendor Postal address and Contact Info from Excel using X++

static void Na_ContactDetails(Args _args)
{
    Dialog                              dialog;
    Dialogfield                         dialogfield;
    VendTable                           vendTable;

    LogisticsElectronicAddress          logisticsElectronicAddress;
    LogisticsPostalAddress              logisticsPostalAddress;
    LogisticsLocation                   logisticsLocation,logisticsLocation1;
    LogisticsLocationRole               logisticsLocationRole;
    DirPartyTable                       dirPartyTable,dirPartyTable1;
    COMVariantType                      type;

    DirPartyLocation                    dirPartyLocation,dirPartyLocation1;
    DirPartyLocationRole                dirPartyLocationRole,dirPartyLocationRole1;
    LogisticsElectronicAddressRole      logisticsElectronicAddressRole;

    SysExcelApplication                 application;
    SysExcelWorkbooks                   workBooks;
    SysExcelWorkbook                    workBook;
    SysExcelWorksheets                  workSheets;
    SysExcelWorksheet                   workSheet;
    SysExcelCells                       cells;
    Filename                            fileName;
    int                                 row;

    AccountNum                          vendAccount;
    Name                                vendName;
    VendGroupId                         vendGroup;
    Description                         description;
    str 100                             Address,phonenum,namealiyas;
    CurrencyCode                        currency;


    str COMVariant2Str(COMVariant _cv, int _decimals = 0,int _characters = 0,int _separator1 = 0,int _separator2 = 0)
    {
        switch(_cv.variantType())
        {
            case (COMVariantType::VT_BSTR):
                return _cv.bStr();
            case (COMVariantType::VT_R4):
                return num2str(_cv.float(),_characters,_decimals, _separator1,_separator2);
            case (COMVariantType::VT_R8):
                return num2str(_cv.double(),_characters,_decimals,_separator1,_separator2);
            case (COMVariantType::VT_DECIMAL):
                return num2str(_cv.decimal(),_characters,_decimals, _separator1, _separator2);
            case (COMVariantType::VT_DATE):
                return date2str(_cv.date(),123,2,1,2, 1,4);
            case (COMVariantType::VT_EMPTY):
                return "";
            default:
                throw error(strfmt("@SYS26908",_cv.variantType()));
        }
        return "";
    }

    application =   SysExcelApplication::construct();
    workBooks   =   application.workbooks();
    dialog      = new Dialog("FileOpen");
    dialogfield = dialog.addField(extendedTypeStr(Filenameopen), "File Name");
    dialog.run();

    if (dialog.run())
    {
        filename = (dialogfield.value());
    }
    try
    {
        workBooks.open(fileName);
    }
    catch (Exception::Error)
    {
        throw error("File Cannot be opened");
    }

    workBook    =   workBooks.item(1);
    workSheets  =   workBook.worksheets();
    workSheet   =   workSheets.itemFromNum(1);
    cells      =   workSheet.cells();
    row =1;
    do
    {
        row++;


        vendAccount = cells.item(row,1).value().bStr();
        vendName    = cells.item(row,2).value().bStr();
        vendGroup   = COMVariant2Str(cells.item(row,3).value());
        phonenum    = COMVariant2Str(cells.item(row,4).value());
        description = COMVariant2Str(cells.item(row,5).value());
        Address     = cells.item(row,6).value().bStr();
        currency    = cells.item(row,7).value().bStr();
        namealiyas  = "working1";

        logisticsLocation.clear();
        logisticsLocation.initValue();
        logisticsLocation.Description               = description;
        logisticsLocation.insert();

        logisticsLocation1.clear();
        logisticsLocation1.initValue();
        logisticsLocation1.Description                      = namealiyas;
        logisticsLocation1.insert();

        logisticsPostalAddress.clear();
        logisticsPostalAddress.initValue();
        logisticsPostalAddress.Address                      = Address;
        logisticsPostalAddress.Location                     = LogisticsLocation.RecId;
        logisticsPostalAddress.CountryRegionId              = "IND";
        logisticsPostalAddress.State                        = "Telangana";
        logisticsPostalAddress.Street                       = "Kukatpally";
        logisticsPostalAddress.insert();

        dirPartyTable.clear();
        dirPartyTable.initValue();
        dirPartyTable.Name                                  = vendName;
        dirPartyTable.PrimaryContactPhone                   = logisticsElectronicAddress.recId;
        dirPartyTable.PrimaryAddressLocation                = logisticsLocation.RecId;
        dirPartyTable.insert();

        logisticsElectronicAddress.clear();
        logisticsElectronicAddress.initValue();
        logisticsElectronicAddress.Type                     = LogisticsElectronicAddressMethodType::Phone;
        logisticsElectronicAddress.Locator                  = phonenum;
        logisticsElectronicAddress.Description              = description;
        logisticsElectronicAddress.IsPrimary                = NoYes::No;
        logisticsElectronicAddress.Location                 = logisticsLocation1.RecId;
        logisticsElectronicAddress.PrivateForParty          = dirPartyTable.RecId;
        logisticsElectronicAddress.IsMobilePhone            = NoYes::No;
        logisticsElectronicAddress.LocatorExtension         = "+91";
        logisticsElectronicAddress.insert();

        logisticsElectronicAddressRole.clear();
        logisticsElectronicAddressRole.initValue();
        logisticsElectronicAddressRole.ElectronicAddress    = logisticsElectronicAddress.RecId;
        logisticsElectronicAddressRole.LocationRole         = LogisticsLocationRole::findBytype(LogisticsLocationRoleType::Home).RecId;
        logisticsElectronicAddressRole.insert();

        vendTable.clear();
        vendTable.initValue();
        vendTable.AccountNum                                =  vendAccount;
        vendTable.Currency                                  =  currency;
        vendTable.VendGroup                                 =  vendGroup;
        vendTable.Party                                     =  dirPartyTable.RecId;
        vendTable.insert();

        dirPartyLocation.clear();
        dirPartyLocation.initValue();
        dirPartyLocation.Party                              =  dirPartyTable.RecId;
        dirPartyLocation.Location                           =  logisticsLocation.RecId;
        dirPartyLocation.IsPostalAddress                    =  NoYes::Yes;
        dirPartyLocation.IsPrimary                          =  NoYes::Yes;
        dirPartyLocation.IsRoleDelivery                     =  NoYes::No;
        dirPartyLocation.insert();

        dirPartyLocation1.clear();
        dirPartyLocation1.initValue();
        dirPartyLocation1.Party                             =  dirPartyTable.RecId;
        dirPartyLocation1.Location                          =  logisticsLocation1.RecId;
        dirPartyLocation1.IsPostalAddress                   =  NoYes::No;
        dirPartyLocation1.IsPrimary                         =  NoYes::Yes;
        dirPartyLocation1.IsRoleDelivery                    =  NoYes::No;
        dirPartyLocation1.insert();

        dirPartyLocationRole.clear();
        dirPartyLocationRole.initValue();
        dirPartyLocationRole.LocationRole                   =  LogisticsLocationRole::findBytype(LogisticsLocationRoleType::Home).RecId;
        dirPartyLocationRole.PartyLocation                  =  dirPartyLocation.RecId;
        dirPartyLocationRole.insert();

        dirPartyLocationRole1.clear();
        dirPartyLocationRole1.initValue();
        dirPartyLocationRole1.LocationRole                  =  LogisticsLocationRole::findBytype(LogisticsLocationRoleType::Home).RecId;
        dirPartyLocationRole1.PartyLocation                 =  dirPartyLocation1.RecId;
        dirPartyLocationRole1.insert();

    }
    while (type != COMVariantType::VT_EMPTY);
    application.quit();
    workbooks.close();

    info("Done");

}

Create Product Master with Product Varients Using X++

Public void Create_ProductMaster(ItemId _itemid,ItemName _itemname,Name _searchname,Name _name,ProductType _ProductType)
{
 EcoResProductMaster                    ecoResProductMaster;
 EcoResProductIdentifier                ecoResProductIdentifier;
 EcoResProductDimensionGroupProduct     ecoResProductDimensionGroupProduct;
 EcoResProductMasterModelingPolicy      ecoResProductMasterModelingPolicy;

 EcoResStorageDimensionGroupProduct     ecoResStorageDimensionGroupProduct;
 EcoResTrackingDimensionGroupProduct    ecoResTrackingDimensionGroupProduct;

 EcoResConfiguration                    ecoResConfiguration;
 EcoResProductMasterConfiguration       ecoResProductMasterConfiguration;

 EcoResSize                             ecoResSize;
 EcoResProductMasterSize                ecoResProductMasterSize;

 EcoResColor                            ecoResColor;
 EcoResProductMasterColor               ecoResProductMasterColor;

 EcoResDistinctProductVariant           ecoResDistinctProductVariant;
 EcoResProductVariantConfiguration      ecoResProductVariantConfiguration;
 EcoResProductVariantColor              ecoResProductVariantColor;
 EcoResProductVariantSize               ecoResProductVariantSize;

 InventTable                            inventTable;
 InventTableModule                      inventTableModule;
 InventItemSetupSupplyType              inventItemSetupSupplyType;

 EcoResStorageDimensionGroupItem        ecoResStorageDimensionGroupItem;
 EcoResTrackingDimensionGroupItem       ecoResTrackingDimensionGroupItem;

 InventModelGroupItem                   inventModelGroupItem;
 InventItemGroupItem                    inventItemGroupItem;

 InventDim                              inventDim;
 InventDimCombination                   inventDimCombination;

try
 {
     //ProductMaster
         ecoResProductMaster.clear();
         ecoResProductMaster.initValue();
         ecoResProductMaster.ProductType                    = EcoResProductType::Item;
         ecoResProductMaster.DisplayProductNumber           = _itemid;
         ecoResProductMaster.SearchName                     = _searchname;
         ecoResProductMaster.VariantConfigurationTechnology = EcoResVariantConfigurationTechnologyType::PredefinedVariants;
         if (ecoResProductMaster.validateWrite())
         {
            ecoResProductMaster.insert();
         }

     //Product Identifer
        ecoResProductIdentifier.clear();
        ecoResProductIdentifier.initValue();
        ecoResProductIdentifier.ProductNumber = _itemid;
        ecoResProductIdentifier.Product       = ecoResProductMaster.RecId;
        ecoResProductIdentifier.insert();

    //Product dimension group
        ecoResProductDimensionGroupProduct.clear();
        ecoResProductDimensionGroupProduct.initValue();
        ecoResProductDimensionGroupProduct.initFromProduct(ecoResProductMaster);
        ecoResProductDimensionGroupProduct.ProductDimensionGroup = EcoResProductDimensionGroup::findByDimensionGroupName("SizeColCon").RecId;
        if(ecoResProductDimensionGroupProduct.validateWrite())
        {
            ecoResProductDimensionGroupProduct.insert();
        }

    //Storage dimension group
        ecoResStorageDimensionGroupProduct.clear();
        ecoResStorageDimensionGroupProduct.initValue();
        ecoResStorageDimensionGroupProduct.Product               = ecoResProductMaster.RecId;
        ecoResStorageDimensionGroupProduct.StorageDimensionGroup = EcoResStorageDimensionGroup::findByDimensionGroupName("Site").RecId;
        if (ecoResStorageDimensionGroupProduct.validateWrite())
        {
            ecoResStorageDimensionGroupProduct.insert();
        }

    //Tracking dimension group
        ecoResTrackingDimensionGroupProduct.clear();
        ecoResTrackingDimensionGroupProduct.initValue();
        ecoResTrackingDimensionGroupProduct.Product                = ecoResProductMaster.RecId;
        ecoResTrackingDimensionGroupProduct.TrackingDimensionGroup = EcoResTrackingDimensionGroup::findByDimensionGroupName("Serial").RecId;
        if (ecoResTrackingDimensionGroupProduct.validateWrite())
        {
            ecoResTrackingDimensionGroupProduct.insert();
        }

    //Product modeling policy
        ecoResProductMasterModelingPolicy.clear();
        ecoResProductMasterModelingPolicy.initValue();
        ecoResProductMasterModelingPolicy.ProductMaster = ecoResProductMaster.RecId;
        if (ecoResProductMasterModelingPolicy.validateWrite())
        {
            ecoResProductMasterModelingPolicy.insert();
        }

    //Product translation
       EcoResProductTranslation::createOrUpdateTranslation(ecoResProductMaster.RecId, _itemname, _searchname);

    //Configuration
         ecoResConfiguration = EcoResConfiguration::findByName("NoteBook");
         if (!ecoResConfiguration)
         {
             ecoResConfiguration.clear();
             ecoResConfiguration.initValue();
             ecoResConfiguration.Name = "NoteBook ";
             ecoResConfiguration.insert();
         }

    //Size
         ecoResSize = EcoResSize::findByName("1");
         if(!ecoResSize)
         {
             ecoResSize.clear();
             ecoResSize.initValue();
             ecoResSize.Name = "1 ";
             ecoResSize.insert();
         }
    //color
        ecoResColor = EcoResColor::findByName("Black");
        if(!ecoResColor)
        {
            ecoResColor.clear();
            ecoResColor.initValue();
            ecoResColor.Name = "Black";
            ecoResColor.insert();
        }

    //InventDimId Creating
        inventDim.clear();
        inventDim.ConfigId = "NoteBook";/*ConfigId*/
        inventDim.InventSizeId =  "1";  //size
        inventDim.InventColorId = "Black"; // name
        inventDim = InventDim::findOrCreate(inventDim);

    //Configuration assigned to product master
        ecoResProductMasterConfiguration.clear();
        ecoResProductMasterConfiguration.initValue();
        ecoResProductMasterConfiguration.Configuration = ecoResConfiguration.RecId;
        ecoResProductMasterConfiguration.ConfigProductDimensionAttribute = EcoResProductDimensionAttribute::inventDimFieldId2DimensionAttributeRecId(fieldNum(InventDim, ConfigId));
        ecoResProductMasterConfiguration.ConfigProductMaster = ecoResProductMaster.RecId;
        ecoResProductMasterConfiguration.insert();

    //Size assigned to product master
        ecoResProductMasterSize.clear();
        ecoResProductMasterSize.initValue();
        ecoResProductMasterSize.Size = ecoResSize.RecId;
        ecoResProductMasterSize.SizeProductDimensionAttribute = EcoResProductDimensionAttribute::inventDimFieldId2DimensionAttributeRecId(fieldNum(InventDim, InventSizeId));
        ecoResProductMasterSize.SizeProductMaster    = ecoResProductMaster.RecId;

    //color assigned to product master
        ecoResProductMasterColor.clear();
        ecoResProductMasterColor.initValue();
        ecoResProductMasterColor.Color = ecoResColor.RecId;
        ecoResProductMasterColor.ColorProductDimensionAttribute = EcoResProductDimensionAttribute::inventDimFieldId2DimensionAttributeRecId(fieldNum(InventDim, InventColorId));
        ecoResProductMasterColor.ColorProductMaster = ecoResProductMaster.RecId;

    //Product variant
        ecoResDistinctProductVariant.clear();
        ecoResDistinctProductVariant.initValue();
        ecoResDistinctProductVariant.DisplayProductNumber = EcoResProductNumberBuilderVariant::buildFromProductNumberAndDimensions(
        ecoResProductMaster.productNumber(),
        EcoResProductVariantDimValue::getDimensionValuesContainer(_itemname, "1", "Black",""));
        ecoResDistinctProductVariant.SearchName = ecoResProductMaster.SearchName /*ConfigId*/;
        ecoResDistinctProductVariant.ProductType = ecoResProductMaster.ProductType;
        ecoResDistinctProductVariant.ProductMaster = ecoResProductMaster.RecId;
        ecoResDistinctProductVariant.insert();

    //Product variant configuration
        ecoResProductVariantConfiguration.clear();
        ecoResProductVariantConfiguration.initValue();
        ecoResProductVariantConfiguration.initFromDistinctProductVariant(ecoResDistinctProductVariant);
        ecoResProductVariantConfiguration.ProductDimensionAttribute = EcoResProductDimensionAttribute::inventDimFieldId2DimensionAttributeRecId(fieldNum(InventDim, ConfigId));
        ecoResProductVariantConfiguration.Configuration = ecoResConfiguration.RecId;
        ecoResProductVariantConfiguration.insert();

    //product variant size
        ecoResProductVariantSize.clear();
        ecoResProductVariantSize.initValue();
        ecoResProductVariantSize.initFromDistinctProductVariant(ecoResDistinctProductVariant);
        ecoResProductVariantSize.ProductDimensionAttribute = EcoResProductDimensionAttribute::inventDimFieldId2DimensionAttributeRecId(fieldNum(InventDim, InventSizeId));
        ecoResProductVariantSize.Size                      = ecoResSize.RecId;
        ecoResProductVariantSize.insert();

    //product variant color
        ecoResProductVariantColor.clear();
        ecoResProductVariantColor.initValue();
        ecoResProductVariantColor.initFromDistinctProductVariant(ecoResDistinctProductVariant);
        ecoResProductVariantColor.ProductDimensionAttribute = EcoResProductDimensionAttribute::inventDimFieldId2DimensionAttributeRecId(fieldNum(InventDim, InventColorId));
        ecoResProductVariantColor.Color                     = ecoResColor.RecId;
        ecoResProductVariantColor.insert();


    //Product variant translation
         EcoResProductTranslation::createOrUpdateTranslation(ecoResDistinctProductVariant.RecId, _itemname, _searchname);

    //Released product
        inventTable.clear();
        inventTable.initValue();
        inventTable.initFromEcoResProduct(ecoResProductMaster);
        inventTable.ItemId    =_itemid;
        inventTable.NameAlias =_searchname;
        if(inventTable.validateWrite())
        {
            inventTable.insert();
        }

    //Inventory model group
        inventModelGroupItem.clear();
        inventModelGroupItem.initValue();
        inventModelGroupItem.ItemDataAreaId = inventTable.dataAreaId;
        inventModelGroupItem.ItemId         = inventTable.ItemId;
        inventModelGroupItem.ModelGroupId   = "FIFO";
        inventModelGroupItem.ModelGroupDataAreaId = curext();
        inventModelGroupItem.insert();

    //Item group
        inventItemGroupItem.clear();
        inventItemGroupItem.initValue();
        inventItemGroupItem.ItemDataAreaId = inventTable.dataAreaId;
        inventItemGroupItem.ItemId         = inventTable.ItemId;
        inventItemGroupItem.ItemGroupId    = "Parts";
        inventItemGroupItem.ItemGroupDataAreaId = curext();
        inventItemGroupItem.insert();

    //Extended product details – Inventory
        inventTableModule.clear();
        inventTableModule.initValue();
        inventTableModule.ItemId     = inventTable.ItemId;
        inventTableModule.ModuleType = ModuleInventPurchSales::Invent;
        inventTableModule.insert();

    //Extended product details – Purchase
        inventTableModule.clear();
        inventTableModule.initValue();
        inventTableModule.ItemId     = inventTable.ItemId;
        inventTableModule.ModuleType = ModuleInventPurchSales::Purch;
        inventTableModule.insert();

    //Extended product details – Sales
        inventTableModule.clear();
        inventTableModule.initValue();
        inventTableModule.ItemId     = inventTable.ItemId;
        inventTableModule.ModuleType = ModuleInventPurchSales::Sales;
        inventTableModule.insert();

    //Warehouse items
        InventItemLocation::createDefault(inventTable.ItemId);

    //Supply type setup
        inventItemSetupSupplyType.clear();
        inventItemSetupSupplyType.initValue();
        inventItemSetupSupplyType.ItemId         = inventTable.ItemId;
        inventItemSetupSupplyType.ItemDataAreaId = inventTable.DataAreaId;
        inventItemSetupSupplyType.insert();

    //Product storage dimension group
        ecoResStorageDimensionGroupProduct = EcoResStorageDimensionGroupProduct::findByProduct(ecoResProductMaster.RecId);
        if (ecoResStorageDimensionGroupProduct.RecId)
        {
            ecoResStorageDimensionGroupItem.clear();
            ecoResStorageDimensionGroupItem.initValue();
            ecoResStorageDimensionGroupItem.ItemDataAreaId        = inventTable.DataAreaId;
            ecoResStorageDimensionGroupItem.ItemId                = inventTable.ItemId;
            ecoResStorageDimensionGroupItem.StorageDimensionGroup = ecoResStorageDimensionGroupProduct.StorageDimensionGroup;
            ecoResStorageDimensionGroupItem.insert();
        }

    //Product tracking dimension group
        ecoResTrackingDimensionGroupProduct = EcoResTrackingDimensionGroupProduct::findByProduct(ecoResProductMaster.RecId);
        if (ecoResTrackingDimensionGroupProduct.RecId)
        {
            ecoResTrackingDimensionGroupItem.clear();
            ecoResTrackingDimensionGroupItem.initValue();
            ecoResTrackingDimensionGroupItem.ItemDataAreaId         = inventTable.DataAreaId;
            ecoResTrackingDimensionGroupItem.ItemId                 = inventTable.ItemId;
            ecoResTrackingDimensionGroupItem.TrackingDimensionGroup = ecoResTrackingDimensionGroupProduct.TrackingDimensionGroup;
            ecoResTrackingDimensionGroupItem.insert();
        }

    //Released product variant
        inventDimCombination.clear();
        inventDimCombination.initValue();
        inventDimCombination.DistinctProductVariant = ecoResDistinctProductVariant.RecId;
        inventDimCombination.ItemId                 = inventTable.ItemId;
        inventDimCombination.InventDimId            = inventDim.InventDimId;
        inventDimCombination.insert();
        info("Done!");
    }
   catch
   {
      error("Error!");
      return;
   }
}