Generate a New Voucher Number for Each Inventory Journal Line

If you have a business requirement that requires a new voucher number to be generated for each posted inventory movement journal line – that means that you would need to make customization to the out-of-the-box functionality for generating vouchers for inventory journals.

 

Out of the box functionality that we have so far is that a new voucher is being generated on:

 

  • Change date: For each different date in the inventory journal lines.

 

    • Example: If we have an inventory movement journal with 10 lines, 4 lines with date 1/10/2020, and 6 lines with date 4/10/2020, this setup would post the journal and generate 2 voucher numbers: 1 voucher number for the lines with the date 1/10/2020 and 1 voucher number for the lines with the date 4/10/2020.

 

  • Change date or item: For each different date or item in the inventory journal lines.

 

    • Example: If we have an inventory movement journal with 10 lines, 4 lines with item itemnumber1 and 6 lines with item itemnumber2 and all lines having the same date, then this setup would post the journal and generate 2 voucher numbers: 1 voucher number for the lines with the item itemnumber1 and 1 voucher number for the lines with the item itemnumber2.

 

This is defined in the setup of the inventory journal name:

 

AX2012: (Inventory management/Setup/Journals/Journal names, inventory/General/Voucher)
D365: (Inventory management/Setup/Journal names/Inventory/General/Voucher)

 

 

 

So, this blog post is about how to extend this functionality by enabling the generation of a new voucher per journal line.

 

Example: We have 10 lines in the inventory movement journal, and we want to generate 10 different vouchers -one voucher per journal line.

 

Step-by-step Instructions for AX2012

 

  • The first step is to extend the enum InventJournalVoucherChange and add a new option ‘Line change’:

 

 

    • After this step, we should be able to select ‘Line change’ as an option in the inventory journal name setup:

 

 

  • Then we should modify the class InventJournalTransData and override the initVoucher method. This method is the place where we can control the voucher number generation for each journal line.

 

 

  • Now, we want to keep the same logic for voucher numbers when the setup is ‘Change date’ or ‘Change date or item’.

 

    • For that purpose, we need to copy the code from the \Classes\JournalTransData\initVoucher and add it in case the setup is ‘Change date’ or ‘Change date or item’. In case the setup is our new option ‘Line change’, then we need to add a code that will generate the new voucher number.

 

    • After these changes the initVoucher method on the InventJournalTransData should look something like below:

 

 

  • Now, when we create an inventory movement journal with 10 lines and post the journal, we will see 10 different vouchers created for each journal line.

 

Step-by-step Instructions for D365

 

  • The first step is to create an extension of the enum InventJournalVoucherChange and add a new option ‘Line change’:

 

    • After this step, we should be able to select ‘Line change’ as an option in the inventory journal name setup:

 

 

  • Then we should create an extension of the class InventJournalTransData and using Chain of command we will add the new initVoucher method.

 

    • Please note that this solution needs to call the super() (next call) and for that reason is going to create a new voucher number in the super call, and then we are going to override that voucher number with a new one.

 

  • Now, when we create an inventory movement journal with 10 lines and post the journal, we will see 10 different vouchers created for each journal line.

Zero Cost Price on Purchase Line Inventory Transactions

One of our clients experienced the following issue: Posting a purchase order invoice resulted in an inventory transaction with zero cost.

 

However, the postings in the General ledger were correct. The stock valuation model was Weighted average date. The AX version is AX2012, R2, CU7.

 

We went trough the execution of the invoice posting and noticed that the cost price calculation is based on the accounting distributions. The logic takes into account all distributions on the line with the same financial dimensions as the PO line. In our case these are different.

 

We assume this is because the PO is created from a PRQ. The accounting distribution has the same dimension as the PRQ line while the PO line dimensions are blank.

 

The cost price calculation starts in InventCostInputAmount class, getInputAmountFromDistribution method where the ledger dimension selection criteria is defined based on the purchase line. Then actual calculation is implemented in SourceDocumentLineProvider class. getDistributedAmountInAccountingCurrency method where AccountingDistribution entries are selected based on the previously defined ledger dimension combination.

 

This seems to be a common issue since it was experienced by others as well. The proposed solution from Microsoft is the following hotfix: KB 2967526 “Deleting a financial dimension affects the distributions on a purchase order receipt, invoice vouchers and inventory costs”.

Cannot Create a Record in Balance (CustVendTmpOpenTransBalances). Amount: 0,00. The Record Already Rxists. – SpecTrans Issue

In my previous post I wrote about vendor settlement issue related to inconsistent data. In this post the issue is more or less similar but in this case it is impossible to open the Vendor settlement form (Accounts payable > Common > All vendors > Tab: Invoice > Settle open transactions). When user try to open the form it ends up with error message:

 

“Cannot create a record in Balance (CustVendTmpOpenTransBalances). Amount: 0,00. The record already exists.”

 

Again the problem is the inconsistent data in the SpecTrans table. This table contains records that connect vendor records (VendTable) with vendor open transactions (VendTransOpen). These records are used to fill a temporary table called(CustVendTmpOpenTransBalances) which has unique index on TransOpenRecId field.

 

This filed is filled with VendTransOpen RecId value. SpecTrans table contains reference to non-existing VendTransOpen records so consequently TransOpenRecId field in CustVendTmpOpenTransBalances table is populated 0. The unique index restriction thrown an error when AX tries to insert the second record with the same 0 value.

 

The solution again is to cleanup inconsistent SpecTrans data. I created a job to cleanup the inconsistent SpecTrans. In my job the records are filtered by vendor but you can remove the range in order to execute for all vendors.

 

static void VendTransOpenSpecTransCleanup(Args _args)
{
VendTransOpen vendTransOpen; // tableId: 866
SpecTrans specTrans;
ttsBegin;
while select forUpdate SpecTrans
where  specTrans.SpecCompany == ‘DataAreaId’
&& specTrans.SpecTableId == 505         // VendTable ID
&& specTrans.SpecRecId   == 11111111 // Vendor RecId
&& SpecTrans.RefTableId  == 866
notExists join vendTransOpen
where  vendTransOpen.TableId    == specTrans.RefRecId
&& vendTransOpen.RecId      == specTrans.RefRecId
&& VendTransOpen.dataAreaId == SpecTrans.RefCompany
{
info(strFmt(‘%1’,specTrans.RecId));
SpecTrans.delete();
}
ttsCommit;
}

Reverse Wrong Invoice with Charges

The invoice reversal in AX is a process of creating credit notes (negative Purchase order or Sales order lines) and posting issue/receipt against these lines. At the end an invoice should be posted against the same lines.

 

With these steps the user can reverse the invoice and issue/receipt of products in case of items.

 

In order to post the correct invoice the user need to replicate the initial lines and then to issue/receive goods and post correct invoice as a last step.

 

When invoice with charges defined on lines need to be reversed the user need to be very careful because charges on the negative lines should also be negative. If charges are defined as positive AX posts the charges as normal charges resulting in double charges in the ledger. This happens often especially when user copies the lines and just change the sign in the quantity field. So, be careful when reversing invoices and always check the vouchers created.

Sales Order XX Has Been Updated by Another User – Packing Slip Posting

The error message “Sales order XX has been updated by another user.” is a standard error message when user tries to update (post document) against a sales order but in the mean time another user already did updated the same order.

 

In general, AX captures the quantities remaining when posting parameter form opens and check if these values are the same when posting executed. In case of a change, the error message appears.

 

This is a safety mechanism that prevents updating the same lines and quantities more times. However this error message can also be a result of customization.

 

One of my clients asked for a customization in packing slip grouping/splitting. Standard AX offers a setup for this but is some cases this setup does not fit the customer needs. In such a case SalesFormLetterParmData classes need to be customized. I did changed the ParmData class to meet the customer requirements. Everything was working just fine until we got the error message “Sales order XX has been updated by another user.”

 

At first I thought that multiple users tried to update the same order at the same time since we experienced this in test environment. But very soon I figured out that it was not updated by another user because the order was not updated at all.

 

Investigating the problem, I found out that one sales order line was part of multiple packing slips. This was the origin of the problem. When Packing slip update function called AX creates SalesParmLine records for each SalesLine that need to be updated. Besides other information like ItemId, InventTransId, quantities etc. AX also copies remaining quantities from SalesLine into SalesParmLine table. This information is stored into the following fields:

 

  • RemainBefore
  • RemainBeforeInvent
  • RemainBeforeInventPhysical
  • RemainAfter
  • RemainAfterInvent

 

In case when one sales line is split between multiple packing slips that should be posted in one go (same ParmIdI there is an issue. The first packing slip goes well without any issues and this action reduces the Remain fields on SalesLine. When second packing slip goes trough the validation process AX finds out that the Remain values on SalesLine and SalesParmLine differ and “Sales order XX has been updated by another user.” error message appears.

 

In order to avoid this Remain field on the SalesParmLines need to be maintained. For example, sales line has quantity 10 where 7 goes to first packing slip and 3 goes to second one. The second SalesParmLine record need to have Remain quantities reduced by 7. This way AX will validate that the remain quantity is 3 (which is correct) and will proceed with the posting.

 

The validation for remain quantities is executed twice, once when Parm form displayed and once when user clicks on OK button (when posting trough code or in batch is only once). Before form opening both SalesParmRecords must have the same values because they are compared with the original SalesLine. For the second check, after OK click, we need to udate Remain quantities. This is important because we need to change the values after prompt method on SalesFormLetter class, but before run method.

 

Another attention point are the units of measurement. The Remain fields that contain “Invent” in the name store quantities in inventory unit while the rest in sales unit. If these are different then inventory unit conversion is needed in order to calculate the inventory remain fields.

Caching Display Methods

In AX 2012 there are two ways of caching display methods on form.

 

The first way is to add attribute to display method itself:

 

[SysClientCacheDataMethodAttribute([_updateOnWrite])]
Display Type methodname(Params)
{

}

 

The second way is to call cacheAddMethod after super() call:

 

public void init()
{
super();
this.cacheAddMethod(tablemethodstr(methodName));
}

Problem with Vendor Settlement – SpecTrans Issue

One of my clients reported an issue that the settlement is not possible for vendor transactions (Accounts payable > Common > All vendors > Tab: Invoice > Settle open transactions). The records were marked with red exclamation and when the user try to mark the record gets the an error message:

 

“This transaction has been marked for settlement by another user.”

 

This error message is very clear and when I saw it I said that someone else already marked the transaction for settlement. The interesting part came when they said that they are sure that this is not correct.

 

Using the Specifications form (Inquires > Specifications) I tried to find the transaction that was marked against. The result was no transaction in the specification form.

 

On the other side the “Is marked” column shows that there is a related transaction.

 

This column is actually a display method that use SpecTrans table to decide if the transaction is already marked.

 

Select firstonly crossCompany RecId from specTrans where

(specTrans.SpecCompany != specCompany ||
specTrans.SpecTableId != specTableId ||
specTrans.SpecRecId != specRecId) &&
specTrans.RefCompany == _refCompany &&
specTrans.RefTableId == _refTableId &&
specTrans.RefRecId == _refRecId;

 

(Ref fields consist the relationship with Vendor open transaction in our case – VendOpenTrans)

 

This findings suggested that there is data inconsistency.

 

I created a simple job to find the marked lines that are inconsistent:

 

static void findMarkedTrans(Args _args)
{
VendTransOpen VendTransOpen;
SpecTrans     specTrans;
while select VendTransOpen
where VendTransOpen.AccountNum == ‘VendAccount’
join specTrans
where specTrans.RefRecId == VendTransOpen.RecId
&&    specTrans.RefTableId == tableNum(VendTransOpen)
&&    specTrans.RefCompany == ‘DataAreaId’
{
info(strFmt(‘%1 %2 %3’, specTrans.SpecCompany, tableId2name(specTrans.SpecTableId), specTrans.SpecRecId));
}
}

 

Using the Spec field I found out the records that marked those transactions. Then I just open the table I got from the job (in my case LedgerJournalTrans) and filtered by Record ID. As you assume, there we no data!

 

If you check the documentation for the SpecTrans table you can see that the description is “The SpecTrans table contains records that relate to transactions for the settlement and settlement reversal processes. Records are deleted after they are processed.” So, in this case SpecTrans table was not “cleaned up” properly.

 

Cleaning up the SpecTrans table from inconsistent records resolved the issue.

 

It is hard to say what is the reason for this issue. Probably it was an AOS crush during the time of posting. Unfortunately this happens sometimes and the consequences can be much bigger.

 

I experienced a case where the AOS crush caused to be impossible to post vendor invoices. The solution in this case was pretty similar, clean up a “temporary table”.

 

Another one resulted in even worse situation. The inventory transactions (Invoiced lines) and the postings in the ledger were not inconsistent.