Comparing AX 2012 hotfix model lists

When Microsoft started releasing hotfixes for the Dynamics AX 2012 R3 release they made our lives a little harder. If you had just one or two hotfixes load it wasn’t too bad but as eventually you find yourself loading a hotfix that has hundreds of dependant hotfixes and suddenly your model store has a list of models a mile long in it. So, when you’re promoting code from your Development system through to Test and Production you need to be sure that you have all the right hotfixes loaded and with a long list of models in each model store, you can easily make a mistake and miss something.

Continue reading

Old cache files may cause AX 2012 Real Time Service to fail

Recently one of my colleagues ran into a strange issue. When performing some actions on the POS that involved calling AX 2012 via Real Time Service, the call failed. In another environment with the same code base, the code succeeded. Also, the RTS failure happened only on certain calls, other calls against the same server worked correctly (the specific case: retrieving a previous sales order succeeded, but sending a completed return order to AX failed).

The event log on the RTS machine was quite confusing: the error message was “Cannot create a record in System parameters (SystemParameters). The record already exists.” But there was nothing wrong with the system parameters.

I captured the request from the POS to the RTS and wrote a small job in AX to call the respective class/method directly using the same request and this worked fine. Even more confusing.

The solution came after realising that the Real Time Service uses .NET Business Connector to connect to the AOS. From the architectural perspective, the Business Connector is like a regular AX client without a user interface. Recently the AX environment in question had been updated with new code – but the same code worked fine on another machine. Earlier I had seen weird issues on a regular AX client where the solution was to get rid of the user cache files. And this turned out to be the solution for the RTS too. Continue reading

Tax amount override in free text invoices

Introduction

One of the common issues we encounter when importing free text invoices into Dynamics AX is overriding the tax. Usually AX calculates the tax when sales invoice lines are inserted into the free text invoice. On some occasions, such as when integrating AX with external systems, users will want the tax calculated by AX to be overridden with the value form the external system so that the tax in  both system matches to the penny.

Override the tax manually

To override tax manually in free text invoices, go to Sales ledger/Common/Free text invoices/All free text invoices. Choose one of the free text invoices that has not been posted yet (e.g. no invoice Id was assigned). Then from the action pane, click on VAT under Details group. This will open a form that will look like this…

B1

Click on the Adjustment tab and you will see the following:

B2

In the form above, you can tick the “Override calculated VAT” field and then set the new tax value in the “Actual VAT amount” text box. Before you close the form, click apply.

Override the tax in x++

We will do the same exercise but from x++ code. There are many blogs and articles on how to do this but in order not to jump into different websites to get the code, I copied the code from a random website here below and then added my code afterwards.

So, the original code will look something like the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
static void FreeTextTaxAdjust(Args _args)  
{  
  CustInvoiceTable    custInvoiceTable;  
  CustInvoiceCalcTax  custInvoiceCalcTax;  
  TaxFreeInvoice      taxFreeInvoice;  
  TaxRegulation       taxRegulation;  
  ;  
 
  ttsbegin;  
 
  select firstonly custInvoiceTable  
  where custInvoiceTable.RecId == 54371652769;  
 
  custInvoiceCalcTax = new CustInvoiceCalcTax_Table(custInvoiceTable);  
  taxFreeInvoice     = new TaxFreeInvoice(custInvoiceCalcTax);  
  taxFreeInvoice.calc();  
  taxRegulation = TaxRegulation::newTaxRegulation(taxFreeInvoice);  
  taxRegulation.allocateAmount(2.01);  
  taxRegulation.saveTaxRegulation();  
 
  ttscommit;  
}

As shown in the code above, this will override the total tax amount of the free text invoice from the automatically calculated £2 to £2.01. The issue with this is that AX will merge the taxes by the VAT code. So, if in the form above we had two tax codes (STD and RED) instead of only one tax code (STD), then the code above will not handle it. The code above will only allow inserting the total tax amount for both tax codes. It will not allow splitting the values for each tax code.

I managed to fix the issue by splitting the above into two steps:

  1. A method to get the tax code. In my case, I cross reference the Tax Group with the Tax Item Group to get the tax code. This can be done by using the following code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static TaxCode CWFGetCrossRefTaxCode(TaxGroup _taxGroup, 
                                            TaxItemGroup _taxItemGroup)
{
    TaxOnItem           taxOnItem;
    TaxGroupData        taxGroupData;
    TaxTable            taxTable;
    ;
 
    select firstonly TaxCode from taxTable
    join firstonly TaxGroup, TaxCode from taxGroupData
    where taxGroupData.TaxCode == taxTable.TaxCode
       && taxGroupData.TaxGroup == _taxGroup
    join firstonly TaxItemGroup, TaxCode from taxOnItem
    where taxOnItem.TaxCode == taxTable.TaxCode
       && taxOnItem.TaxItemGroup == _taxItemGroup;
 
    return taxTable.TaxCode;
}
  1. Use the tax code from the method above and pass it to the method below along with the new tax amount:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public static void CWFCalculateTax(TaxCode _taxCode, 
                                   TaxAmount _taxAmount, 
                                   CustInvoiceTable _custInvoiceTable)
{
    CustInvoiceCalcTax          custInvoiceCalcTax;
    TaxFreeInvoice              taxFreeInvoice;
    TaxRegulation               taxRegulation;
    TmpTaxWorkTrans             tmpTaxWorkTrans;
    TmpTaxRegulation            tmpTaxRegulation;
    ;
 
    ttsbegin;
 
    custInvoiceCalcTax = new CustInvoiceCalcTax_Table(_custInvoiceTable);
    taxFreeInvoice     = new TaxFreeInvoice(custInvoiceCalcTax, true, true, true);
    taxFreeInvoice.calcTax();
 
    taxRegulation = TaxRegulation::newTaxRegulation(taxFreeInvoice);
    tmpTaxRegulation = taxRegulation.tmpTaxRegulation();
    tmpTaxWorkTrans = taxRegulation.tmpTaxWorkTrans();
 
    while select tmpTaxRegulation
    where tmpTaxRegulation.TaxCode == _taxCode
    {
        tmpTaxRegulation.SourceRegulateAmountCur = _taxAmount;
        tmpTaxRegulation.OverrideCalculatedTax = NoYes::Yes;
        tmpTaxRegulation.update();
    }
 
    while select tmpTaxWorkTrans
        where tmpTaxWorkTrans.TaxCode == _taxCode
    {
        tmpTaxWorkTrans.SourceRegulateAmountCur = _taxAmount;
        tmpTaxWorkTrans.update();
    }
 
    taxRegulation.setTmpTaxWorkTransTmpData(tmpTaxWorkTrans);
    taxRegulation.saveTaxRegulation();
    ttscommit;
}

With the code above, I managed to override the tax amount for multiple tax codes only when I’ve updated the table TmpTaxWorkTrans.

Happy DAXing!