miércoles, 31 de octubre de 2012

Bug: Version Control


Not using version control on your code is like playing Russian Roulette over the whole lifetime of your project.  You might not 'lose' anything at first, but later on you may regret the omission.

I had a strange bug upon opening the Ax Client related the to the inbuilt version control system, and didn't know where it came from
Translation: Error
A quick look in the logs, indicated the cause of the problem...

   Object Server 01:  
   [Microsoft][SQL Native Client][SQL Server]El nombre de columna 'MODIFIEDBY' no es válido. 
   INSERT INTO SYSVERSIONCONTROLMORPHXITE2541 (ITEMPATH,MODIFIEDBY,CREATEDBY,RECVERSION,RECID) OUTPUT INSERTED.CREATEDDATETIME VALUES (?,?,?,?,?) 

What fool did this then?...  Me!
For some reason we had added the ModifiedBy, ModifiedDatetime, etc, etc fields to the entity!  I may have done this accidentally when I added the fields to entities such as LedgerTable, TaxTable, TaxData...  Some of them had been added to the version control, and some of them were not.

miércoles, 24 de octubre de 2012

Adjusting Sales/Purchase Tax

When importing invoices from an external system you find penny differences between how tax is calculated between these two applications.  Integrating thousands of invoices can surmount to a whole free beer a day appearing on your ledger books, much to the disdain of our client's accountant.  A decision was therefore taken to send me to New Zealand for the week to fix the problem and force Ax to accept some different tax rounding rules.

A penny difference in how Ax and an external system calculates taxes.
When registering a sales invoice it is possible to manually adjust the tax amount, per tax code.
This is what we want to do, via X++.
Fortunately a blogger called KiwiAxGuy has already achieved half of the work for us, adjusting tax on journals and free text invoices.  No need for those plane tickets after all!

static void XXX_AdjustSalesTaxesJob(Args _args)
{    
    //Manually adjust sales taxes
    TaxRegulation       taxRegulation;
    SalesTable          salesTable;
    SalesTotals         salesTotals;
    ;
    salesTable         = SalesTable::find('12A0012');

    if (salesTable)
    {
        salesTotals = SalesTotals::construct(salesTable, SalesUpdate::All);
        salesTotals.calc();

        // Launch the form to manually adjust the taxes (TaxTmpWorkTrans)
        // --------------------------------------------------------------
        //Tax::showTaxes(salesTotals.tax(), salesTable);

        // Or do it by X++
        // ---------------
        ttsBegin;
        // EDIT: I've just realised that this method has been modified in the GLP-EE patch
        // taxRegulation = TaxRegulation::newTaxRegulation(salesTotals.tax(), null);
        taxRegulation = TaxRegulation::newTaxRegulation(salesTotals.tax(), null, salesTable, null, null);
        taxRegulation.allocateAmount(498.54);
        taxRegulation.saveTaxRegulation();
        ttsCommit;
    }
}


The same can be done for purchase invoices.  In my example once more we have a penny difference in the tax calculation, it should be 13.60.
Purchase order, with 14.60 PLN of taxes we need to apply

static void XXX_AdjustPurchTaxesJob(Args _args)
{
    TaxRegulation       taxRegulation;
    PurchTable          purchTable;
    PurchTotals         purchTotals;
    ;
    purchTable         = PurchTable::find('129/2012');

    if (purchTable)
    {
        purchTotals = PurchTotals::newPurchTable(purchTable, PurchUpdate::All);
        purchTotals.calc();

        // Launch the Form to manually adjust the taxes (TaxTmpWorkTrans)
        // --------------------------------------------------------------
        //Tax::showTaxes(purchTotals.tax(), purchTable);

        // Or do it by X++
        // ---------------
        ttsBegin;
        taxRegulation = TaxRegulation::newTaxRegulation(purchTotals.tax(), null, null, purchTable, null);
        if (taxRegulation.taxLinesExist())
        {
            taxRegulation.allocateAmount(13.60);
            taxRegulation.saveTaxRegulation();
        }
        ttsCommit;
    }
}

HOWEVER.  What happens when we have two tax codes in the same invoice?

Two tax codes, one value to change.
For me it didn't work.  The TaxRegulation class allocated the change in amount to the second tax line, but didn't save the changes in the underlying temporary table :(  Check out the knowledge base article KB2028633 as I'm confident that it's the same issue (more Ax 2009, GLP-EE pains).
You people with the AX 2009 Eastern European patch have been warned.

Our changes are all recorded in the TaxWorkRegulation entity, should you need to check your changes across invoices.
TaxWorkRegulation - The entity that stores the adjusted taxes we have applied... Where is my second line?
BUT, "After posting is successful, all records in this table related to the transaction are deleted." and so within TaxTrans we have the columns SourceTaxAmountCur (calculated sales tax amount shown in the current currency) and SourceRegulateAmountCur (amount that the sales tax is being adjusted to) to compare.

Edit:  Found another possible bug, or it's my lack of knowledge.  Registering changes to taxes for the Purch* entities, I could only do it by changing the HeadingTableId and HeadingRecId values to that of PurchParmTable (343), and not PurchTable (345).  This is probably something to do with rearranging the purchase lines.

Remember people:  Taxes are hard.  Let's go tax-free shopping!