Tuesday 5 November 2019

Generate list of customer addresses with purposes

Recently I was asked by one of the customers to generate the list of all customer addresses with their purpose. The job below retrieves the information with ease.

static void GetCustomerExtract(Args _args)
{
    CustTable custTable;
    DirPartyTable dirPartyTable;
    LogisticsPostalAddressView postAddress;
    LogisticsLocationRole logisticsLocationRole;
    LogisticsLocationParty logisticsLocationparty;
    int iCount = 0;
    CommaIo file;
    ;
    file = new CommaIo(@"FILEPATH","W");
    file.write("dirPartyTable.Name","dirPartyTable.RecId","custTable.AccountNum","custTable.InvoiceAccount","custTable.TaxGroup","custTable.SalesGroup","custTable.DataAreaId","logisticsLocationRole.Name","postAddress.LocationName","postAddress.County","postAddress.District","postAddress.PostBox","postAddress.Address","postAddress.BuildingCompliment","postAddress.City","postAddress.CountryRegionId","postAddress.Latitude","postAddress.Longitude","postAddress.State","postAddress.Street","postAddress.StreetNumber","postAddress.TimeZone","postAddress.ZipCode","postAddress.PostalAddressRecId","postAddress.PostalAddress","postAddress.DistrictName","postAddress.ISOCode);
   
         
        while select custTable
        join dirPartyTable where (custTable.Party == dirPartyTable.RecId)
        join logisticsLocationparty where (custTable.party == logisticsLocationparty.Party)
        join postAddress where (logisticsLocationparty.location == postAddress.Location)
        join logisticsLocationRole where (logisticsLocationparty.LocationRole == logisticsLocationRole.RecId)
       
    {
        file.write(dirPartyTable.Name,dirPartyTable.RecId,custTable.AccountNum,custTable.InvoiceAccount,custTable.TaxGroup,custTable.SalesGroup,custTable.DataAreaId,logisticsLocationRole.Name,postAddress.LocationName,postAddress.County,postAddress.District,postAddress.PostBox,postAddress.Address,postAddress.BuildingCompliment,postAddress.City,postAddress.CountryRegionId,postAddress.Latitude,postAddress.Longitude,postAddress.State,postAddress.Street,postAddress.StreetNumber,postAddress.TimeZone,postAddress.ZipCode,postAddress.PostalAddressRecId,postAddress.PostalAddress,postAddress.DistrictName,postAddress.ISOCode);
        iCount++;
    }
    info(int2str(iCount)+" Records exctracted");

}


Sunday 13 January 2019

Division by zero error Sales Order Invoice Postings

Recently, came across an issue with the customer where they were getting an error as below everytime generating an invoice for the sales orders. { Division by zero. - (S)\Classes\SalesInvoiceDP\insertIntoSalesInvoiceTmp - line 123 }



I discovered there was an unhandled exception in the line of code for \classes\SalesInvoiceDP\insertIntoSalesInvoiceTmp method on a certain line of code as below

Line 122 of the method states

salesInvoiceTmp.SalesPrice =   _custInvoiceTrans.SalesPrice / (_custInvoiceTrans.LineAmount +_custInvoiceTrans.LineAmountTax) * _custInvoiceTrans.LineAmount;

Changing that line of code to below resolves the issue

// changes made to avoid division by zero error.
if((_custInvoiceTrans.LineAmount +_custInvoiceTrans.LineAmountTax) * _custInvoiceTrans.LineAmount == 0)
     salesInvoiceTmp.SalesPrice = 0 ;
else
     salesInvoiceTmp.SalesPrice =   _custInvoiceTrans.SalesPrice / (_custInvoiceTrans.LineAmount +_custInvoiceTrans.LineAmountTax) * _custInvoiceTrans.LineAmount;

Friday 14 December 2018

Update Variant Sizes based on Configuration

Recently in a project, there was a scenario where the sizes had an incorrect display order imported when the configuration was imported. On the size groups, the data seemed correct. To tackle that, the following job was created. It looks at the correct display order from the configuration and populates it to the variant configuration.

static void UpdateProductSizeDisplayOrder(Args _args)
{
    InventTable inventTable;
    EcoResProductMasterDimensionValue dimValue;
    EcoResProductMasterSize prodMasterSize;
    EcoResDistinctProduct disProduct;
    RetailSizeGroupTrans retailSizeGroupTrans;
    CommaIo file;
    int iCount=0;

    ;
    file = new CommaIo(@"\\XXX\ProdSizes_PROD_NEW"+".csv","W");

    file.write("ItemId","Size","sizeRecId","DisplayOrder","SizeGroup","CorrectDisplayOrder","ChangeMade");
    while select inventTable // where inventTable.ItemId == 'B4E2200'
    {
        while select forupdate prodMasterSize where prodMasterSize.SizeProductMaster == inventTable.Product
        {
            select retailSizeGroupTrans where retailSizeGroupTrans.size == EcoResSize::find(prodMasterSize.Size).Name
            && retailSizeGroupTrans.sizeGroup == EcoResProductMaster::find(prodMasterSize.SizeProductMaster).RetailSizeGroupId;



            if(prodMasterSize.RetailDisplayOrder != retailSizeGroupTrans.DisplayOrder)
            {
                file.write(
                            inventTable.ItemId,
                            EcoResSize::find(prodMasterSize.Size).Name,
                            prodMasterSize.RecId,
                            prodMasterSize.RetailDisplayOrder,
                            EcoResProductMaster::find(prodMasterSize.SizeProductMaster).RetailSizeGroupId,
                            retailSizeGroupTrans.DisplayOrder,"YES"
                            );

                ttsBegin;
                prodMasterSize.RetailDisplayOrder = retailSizeGroupTrans.DisplayOrder;
                prodMasterSize.update();
                ttsCommit;

                iCount++;
            }
            else
            {
                file.write( inventTable.ItemId,
            EcoResSize::find(prodMasterSize.Size).Name,
            prodMasterSize.RecId,
            prodMasterSize.RetailDisplayOrder,
            EcoResProductMaster::find(prodMasterSize.SizeProductMaster).RetailSizeGroupId,
            retailSizeGroupTrans.DisplayOrder,"NO");
            }

        }
    }
        info("Finished");
}

Tuesday 9 October 2018

Update Product numbers for Released and Product Master

In one of my projects, there was a requirement for bulk renaming the released products and the product master. Luckily, the numbers for both released and master were kept the same for me to filter on the PKs conveniently. Used the code below to achieve that.

static void RenameInvenTableProdsPK(Args _args)
{
    InventTable inventTable;
    str oldDisplayNumber,newDisplayNumber;
    int iCount;
    CommaIo file;
    ;
    file = new CommaIo(@"\\XXXXX\file.csv","W");
    While select ItemId from InventTable where inventTable.ItemId like 'B4*'
    {
        try
        {
            oldDisplayNumber = inventTable.ItemId;
            newdisplayNumber = "O_"+inventTable.ItemId;
            inventTable.ItemId = newdisplayNumber;
            inventTable.renamePrimaryKey(); //old method of product renaming
           
            //using the service to rename product master
            EcoResProductNumberRenameService::newFromProduct(
            EcoResProduct::findByProductNumber(oldDisplayNumber).RecId,
            oldDisplayNumber,
            newdisplayNumber,NoYes::Yes).rename(); //one of the attributes allows us to include product variants in the renaming process
            iCount++;
    }
    
    catch{
        file.write(oldDisplayNumber);
        continue;
    }
    }
   info(strFmt("Done - %1",iCount));  
}


Tuesday 2 October 2018

Dynamics AX R3 | List of all tables with details

In one of the recent projects, I had to pull the details of all the tables with their current record counts and if they are the part of any country specific localisation. I used the following code to pull those details. Nice simple code got the job done well.
static void GetTablesDetails(Args _args)

{
    #AOT
    #File
    #Properties

    CommaIo csvIO;
    str description;
    TreeNode tables;
    int total, counter;
  ;

    csvIO = new CommaIo(@"c:\AX_tables_details.csv", #IO_WRITE);
    csvIO.write("No","TableName""ID","LegacyId","SaveDataPerCompany","TableGroup","FormRef","CountryRegionCodes","RecordsCount");
    tables = TreeNode::findNode(@"\Data Dictionary\Tables");
    total = tables.AOTchildNodeCount();
    tables = tables.AOTfirstChild();

    for(counter = 1; counter <= total; counter++)
    {
       
        csvIO.write(counter,tables.AOTgetProperty("Name"),tables.AOTgetProperty("ID"),tables.AOTgetProperty("LegacyId"),tables.AOTgetProperty("SaveDataPerCompany"),tables.AOTgetProperty("TableGroup"),tables.AOTgetProperty("FormRef"),tables.AOTgetProperty("CountryRegionCodes"),SysDictTable::casRecordCount(tables.AOTname()));
        tables = tables.AOTnextSibling();
     }

    info("Done");
}

Wednesday 28 October 2015

Many times I have been asked by customers to copy the personalization settings of one user to another. It could just be relating to one form or to replicate the whole user settings from one to another. The code below would just do that job. If it is selective copy then either elementName or designName fields can be filtered. I have been using this code on regular basis and has been quite helpful and updating personalization.
static void copyUserPersonalisations(Args _args)
{
    str userFrom = "";//userId to copy from
    str userTo = ""; //userId to copy to
    SysLastValue sysLastValueTo, sysLastValueFrom;
    int iCount=0;
    ;

    //refreshes all the records for the destination user.
    delete_from sysLastValueTo where sysLastValueTo.userId == "XXX";

    while select sysLastValueFrom where sysLastValueFrom.userId == "XXX"
    {
        select forUpdate sysLastValueTo;
        ttsBegin;
        sysLastValueTo.company = sysLastValueFrom.company;
        sysLastValueTo.designName = sysLastValueFrom.designName;
        sysLastValueTo.elementName = sysLastValueFrom.elementName;
        sysLastValueTo.isKernel = sysLastValueFrom.isKernel;
        sysLastValueTo.recordType = sysLastValueFrom.recordType;
        sysLastValueTo.userId = userTo;
        sysLastValueTo.value = sysLastValueFrom.value;
        sysLastValueTo.insert();
        iCount++;
       
        ttsCommit;
    }
    info(strFmt("Records from %1 is copied to %2. \n\rTotal Records copied: %3",userFrom,userTo,iCount));

}