Monday, October 27, 2014

Find Price and Not Lose It

A system bug in PriceDisc class that leads to losing the found price/discount. Still presented in AX 2012 R3 (Application version 6.3.164.0) The local subroutine findDisc in findDisc method is called inside the buffer loop and must be fixed as follows.
void findDisc()
    {

        if ((discDate >= localFromDate  || ! localFromDate)
            && (discDate <= localToDate || ! localToDate))
        {
            if (_relation == PriceType::EndDiscPurch ||
                _relation == PriceType::EndDiscSales )
            {
                // for end discounts, the QuantiyAmountField field contains order total amounts, not quantities
                if (this.calcCur2CurPriceAmount(localQuantityAmountFrom, priceDiscTable) <= qty &&
                    ((qty < this.calcCur2CurPriceAmount(localQuantityAmountTo, priceDiscTable)) || !localQuantityAmountTo))
                {
                    reselectBuffer();

                    discExist               = true;
                    discAmount             += this.calcCur2CurPriceAmount(priceDiscTable.Amount, priceDiscTable)/ this.priceUnit();
                    percent1               += priceDiscTable.Percent1;
                    percent2               += priceDiscTable.Percent2;
                      // Begin: Alexey Voytsekhovskiy Not to lose the buffer!
                    actualDiscTable        =  priceDiscTable.data();
                    //actualDiscTable        = priceDiscTable;
                    // End: Alexey Voytsekhovskiy
                      
                  }
            }
            else
            {
                if (localQuantityAmountFrom <= qty
                    && (qty < localQuantityAmountTo || !localQuantityAmountTo))
                {
                    reselectBuffer();

                    discExist               = true;
                    discAmount             += this.calcCur2CurPriceAmount(priceDiscTable.Amount, priceDiscTable)/ this.priceUnit();
                    percent1               += priceDiscTable.Percent1;
                    percent2               += priceDiscTable.Percent2;
                      // Begin: Alexey Voytsekhovskiy Not to lose the buffer!
                    actualDiscTable        =  priceDiscTable.data();
                    //actualDiscTable        = priceDiscTable;
                    // End: Alexey Voytsekhovskiy
                  }
            }
        }
    }

 
The subroutine findPrice in findPriceAgreement method is called inside the buffer loop and must be fixed as follows.
void findPrice()
    {
        if (((discDate >= localFromDate || ! localFromDate)
            &&(discDate <= localToDate  || ! localToDate))
        && (localQuantityAmountFrom <= absQty
            &&(localQuantityAmountTo > absQty || !localQuantityAmountTo)))
        {
            if (cacheMode)
            {
                priceDiscTable = PriceDiscTable::findRecId(localRecid);
            }

            if (this.calcCur2CurPriceAmount(priceDiscTable.calcPriceAmount(absQty),  priceDiscTable) < this.calcPriceAmount(absQty) ||
                ! priceExist)
            {
                priceUnit               = priceDiscTable.priceUnit();
                price                   = this.calcCur2CurPriceAmount(priceDiscTable.price(),  priceDiscTable);

                if (salesParameters.ApplySmartRoundingAfterConversion && (priceDiscTable.Currency != currency) &&
                    relation == PriceType::PriceSales)
                {
                    price = PriceDiscSmartRounding::smartRound(price,Currency::find(currency));
                }

                markup                  = this.calcCur2CurPriceAmount(priceDiscTable.markup(),  priceDiscTable);

                pdsCalculationId        = priceDiscTable.PDSCalculationId;

                if (priceDiscTable.DisregardLeadTime)
                {
                    this.updateLeadTime();
                }
                else
                {
                    deliveryDays        = priceDiscTable.DeliveryTime;
                    calendarDays        = priceDiscTable.CalendarDays;
                }

                // <GEERU>
                inventBaileeFreeDays    = priceDiscTable.InventBaileeFreeDays_RU;
                // </GEERU>
                  // Begin: Alexey Voytsekhovskiy, Not to lose the buffer!
                actualPriceTable        = priceDiscTable.data();
                 // actualPriceTable        = priceDiscTable;
                // End: Alexey Voytsekhovskiy
                  
                  priceExist              = true;
  
                  // <GIN>
                  // Begin: Alexey Voytsekhovskiy, ThinkMax, 04Dec13, UAP_FDD017_PriceSimulation
                uapPriceDiscTableRecId  = priceDiscTable.RecId;
                // End: Alexey Voytsekhovskiy, ThinkMax, 04Dec13, UAP_FDD017_PriceSimulation
                  if (countryRegion_IN)
                {
                    // Firstly, retrieve the MRP from the trade agreement. If there is no MRP defined in
                    // the trade agreement, the MRP should be retrieved from the item master.
                    maxRetailPrice = this.calcCur2CurPriceAmount(
                        priceDiscTable.MaximumRetailPrice_IN ?
                            priceDiscTable.MaximumRetailPrice_IN :
                            InventTableModule::find(itemId, moduleType).maxRetailPrice_IN(),
                        priceDiscTable);
                }
                // </GIN>
            }
        }
    }

 
Happy pricing!

Friday, October 24, 2014

How to iterate project group members: Tables, EDT, etc

Based on S. Kuskov's suggestion and Vania Kashperuk's article, I put down this simple job that iterates Tables and Extended Data Types groups members in a given shared project.
static void tmxIterateProjectGroupMembers(Args _args)
{
    #aot
    #properties
    Str                         projectName = "tmxEDI999";
    ProjectNode                 projectNode;
    ProjectGroupNode            ddProjectGroupNode;
    ProjectGroupNode            edtProjectGroupNode;
    ProjectGroupNode            tblProjectGroupNode;
    ProjectListNode             projectListNode;
    TreeNode                    memberTreeNode;              
    TreeNode                    projectTreeNode;
    TreeNodeIterator            projectIterator;
    
    if(projectName)
    {
        // find all shared projects
        projectListNode = SysTreeNode::getSharedProject();
        // find project with a given name
        projectNode = projectListNode.AOTfindChild(projectName);
        // open it in a separate window in AOT
        projectTreeNode = projectNode.getRunNode();
        // this is the key point after which we can iterate group members
        projectNode = projectNode.loadForInspection();
        // get nested nodes for appropriate names
        ddProjectGroupNode = projectNode.AOTfindChild('DataDictionary');
        edtProjectGroupNode = ddProjectGroupNode.AOTfindChild('Extended Data Types');
        tblProjectGroupNode = ddProjectGroupNode.AOTfindChild('Tables');
        
        // tables
        projectIterator = tblProjectGroupNode.AOTiterator();
        memberTreeNode = projectIterator.next();

        while(memberTreeNode)
        {
            info(strFmt("%1 %2", memberTreeNode.AOTname(), memberTreeNode.treeNodeName()));
            memberTreeNode = projectIterator.next();
        }

        // extended data types
        projectIterator = edtProjectGroupNode.AOTiterator();
        memberTreeNode = projectIterator.next();

        while(memberTreeNode)
        {
            info(strFmt("%1 %2", memberTreeNode.AOTname(), memberTreeNode.treeNodeName()));
            memberTreeNode = projectIterator.next();
        }
    }
}
The key method is loadForInspection. Happy iterating!

Wednesday, October 8, 2014

C# code to test EDI-XML transformation

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using Microsoft.Dynamics.IntegrationFramework.Transform;
using tmxEDITransformsX12.SharedXSD;
using tmxEDITransformsX12.Transform820XSD;

namespace TransformTest
{
    class Program
    {
        static void Main(string[] args)
        {
            FileStream input = new FileStream("C:\\Test.edi", FileMode.Open);
            FileStream output = new FileStream("C:\\Output.xml", FileMode.OpenOrCreate);

            tmxEDITransformsX12.Transform820 transform = new tmxEDITransformsX12.Transform820();

            transform.Transform(input, output, "");


        }
    }
}