How to make physical reserved items correctly appear in ATP table

In standard ATP calculates it’s table like Receipts – Issues + On hand
On hand it is Physical stock from On hand form. And it includes all Physical reservations.
So in standard ATP does not consider physical reservation on transaction level in Receipts. Instead it considers it in On hand.
Here is an example from system:
On hand:

Quality order blocking:

Expected date is 27
Relevant blocking transaction:

And ATP table for this item, how it works in standard:

Eventhough it should be availbe at 27 in ATP it appears from on hand from the first day.

We can make a change to consider physical resevration in ATP in receipts instead of taking a sum from on hand physical available. But we should consider following:
1. All physical reservation transactions will be handled in same way. And it will become standard behaviour and will appear in all places where ATP is used.

2. ATP selects only those inventory transations which are in ATP lookup range. Obviously it is done from performance consideration and it is possibly an issue. Those inventory transaction (receipt and issue) which have expected date before first day and after last day of ATP will not be considered at all.
In that case all physically reserved items which have expected date less than first day of ATP will not be considered anywhere. They simply will not appear in the table. Which does not seem to be correct.
We can extend development to calculate count of all reserved physical items that was found in Receipt and then deduct them from On hand physical available. In this case all reserved physical items which are in ATP range date will appear in the ATP table under correct date as Receipt and On hand will contain all others.
But there still will be one problem. If there are physical reservation transaction which expected date is more than last day of ATP table then it will appear right away as available in ATP from first day. Which also does not seems to be correct. Assuming that ATP date range is big enough to cover all possible expected dates in reservation then problem will not appear.

InventQty                       reservedPhysicalReceiptQty;
    // Insert after process receipts
    // Process receipts - physical reserved
Basically it is almost copy of processReceipts method with small changes highlighted with comments
protected void vkProcessReceiptsReservedPhysical(
    SalesTmpATP     _salesTmpATP,
    ItemId          _itemId,
    date            _atpEndDate,
    date            _supplyStartDate,
    date            _atpDateForPastSupply,
    InventTransId   _inventTransId,
    InventDim       _inventDimCriteria,
    InventDimParm   _inventDimParm)
    InventTrans                 inventTrans;
    InventTransOrigin           inventTransOrigin;
    InventTransOriginTransfer   inventTransOriginTransfer;
    InventTrans                 inventTransTransfer;
    InventDim                   inventDimTransfer;
    InventDim                   inventDim;

    // Calculate receipts - don't include transfers if a corresponding counterpart issue transaction exist with same grouping inventory dimensions.
    // Notice quarantine orders and wms orders are not linked together by the table inventTransOriginTransfer - instead the receipt and issue inventTrans have same inventTransOrigin.

    while select forceplaceholders DateExpected, sum (Qty) from inventTrans
        group by DateExpected
        where inventTrans.ItemId            == _itemId
            && inventTrans.Qty              >0 // receipt
            && inventTrans.DateExpected     <= _atpEndDate
            && (inventTrans.DateExpected        >= _supplyStartDate &&
                (inventTrans.StatusReceipt      == StatusReceipt::Arrived
                || inventTrans.StatusReceipt    == StatusReceipt::Ordered))
            && inventTrans.StatusIssue          == StatusIssue::None // to enable StatusItem index
        join TableId from inventTransOrigin
            where inventTransOrigin.RecId         == inventTrans.InventTransOrigin
               && inventTransOrigin.InventTransId != _inventTransId
        outer join TableId from inventTransOriginTransfer
            where inventTransOriginTransfer.ReceiptInventTransOrigin == inventTransOrigin.RecId
        #inventDimExistsJoin(inventTrans.inventDimId, inventDim, _inventDimCriteria, _inventDimParm)
        // notexists -> exists
        exists join inventTransTransfer
            where inventTransTransfer.ItemId                == _itemId
                && inventTransTransfer.StatusReceipt        == StatusReceipt::None
                && inventTransTransfer.StatusIssue          == StatusIssue::ReservPhysical // == StatusIssue::ReservPhysical instead of range
                && (    inventTransTransfer.InventTransOrigin   == inventTrans.InventTransOrigin
                    ||  inventTransTransfer.InventTransOrigin   == inventTransOriginTransfer.IssueInventTransOrigin)
        reservedPhysicalReceiptQty += inventTrans.Qty;

// change following line
return InventSum::findSumQty(_itemId, _inventDimCriteria, _inventDimParm).PhysicalInvent;

return InventSum::findSumQty(_itemId, _inventDimCriteria, _inventDimParm).PhysicalInvent - reservedPhysicalReceiptQty;


About is free platform that allows you to quickly store and reuse snippets, notes, articles related to Dynamics AX.

Authors are allowed to set their own AdSense units.
Join us.

Blog Tags