Invoicing a Purchase Order related with a Project we can obtain the following error message:


After many tests creating purchase orders, evaluating the results obtained and the data created, my colleague Sergio Carrillo Vila and me reach the following conclusion:

This error occurs when we have a Purchase Order no-related with a project and after this Purchase became part of a project. For example, the next Purchase Order has no project related:


This generates a record in table InventTrans:


If now we associate a project to the purchase order:

image_thumb_4_68E9E6C6 image_thumb_12_68E9E6C6


And we look at the table InventTrans, we have the same as before:


And that’s the bug we found!
The error ‘No virtual transaction marked with inventory transaction [inventTrans]’ is shown because in the invoicing process, AX search on table InventTrans for a record with the field ‘TransType == InventTransType::InventTransaction’ and this record is not generated.

To check this, we can create a Purchase Order directly from the Project:

image_thumb_1_53F86453 image_thumb_11_53F86453 image_thumb_12_68E9E6C6

Apparently, there are no difference between both purchases, but if we look at table InventTrans we’ll see:


So, we have another record related to the purchase line with the field TransType == InventTransType::InventTransaction. If we try to invoice this second purchase, we’ll succeed on our purpose.

(It’s possible to create the Purchase Order and after adding the Project, but only if you add the project before creating the purchase lines).

To solve the problem with the first purchase we have 2 options:

  • Delete the lines and create them again: this will delete the lines from the table InventTrans and create again the records (this time correctly because AX already know the project of the purchase)
  • Execute a job with the following code to create the Invent Transaction lines:
    static void solveErrorVirtualInventTrans(Args _args)
        InventTrans     inventTrans;
        InventTrans     newInventTrans;
        NumberSeq       numberSeq;
        while select inventTrans where inventTrans.TransType == InventTransType::Purch && inventTrans.InventRefTransId == ''
            numberSeq = NumberSeq::newGetNum(InventParameters::numRefInventTransId(), true, true);
            newInventTrans.ItemId                   = inventTrans.ItemId;
            newInventTrans.StatusIssue              = StatusIssue::OnOrder;
            newInventTrans.DatePhysical             = inventTrans.DatePhysical;
            newInventTrans.Qty                      = -inventTrans.Qty;
            newInventTrans.CurrencyCode             = inventTrans.CurrencyCode;
            newInventTrans.TransType                = InventTransType::InventTransaction;
            newInventTrans.DateExpected             = inventTrans.DateExpected;
            newInventTrans.InventTransId            = numberSeq.num();
            newInventTrans.CostAmountAdjustment     = inventTrans.CostAmountAdjustment;
            newInventTrans.ShippingDateConfirmed    = inventTrans.ShippingDateConfirmed;
            newInventTrans.ShippingDateRequested    = inventTrans.ShippingDateRequested;
            newInventTrans.CostAmountPhysical       = -inventTrans.CostAmountPhysical;
            newInventTrans.ValueOpen                = inventTrans.ValueOpen;
            newInventTrans.Direction                = InventDirection::Issue;
            newInventTrans.DateStatus               = inventTrans.DateStatus;
            newInventTrans.ProjId                   = inventTrans.ProjId;
            newInventTrans.ProjCategoryId           = inventTrans.ProjCategoryId;
            newInventTrans.inventDimId              = inventTrans.inventDimId;
            newInventTrans.InventRefTransId         = inventTrans.InventTransId; //relation with the original line
            inventTrans.InventRefTransId = newInventTrans.InventTransId;


Also, you can solve the bug integrating this code in the method update() of the class PurchTableType:

if (purchTable.ProjId && !purchTable_Orig.ProjId)
      //here the previous code 
      info("It's necessary to fill the fields 'Category, Line Property and Currency' in all the Purchase Lines");


Hope this helps. Cheers!