D365 Mass de-reservation utility
In the Production control module in Dynamics 365 for SCM there is an automatic BOM reservation routine. For example, set the reservation on Estimation in the module parameters, run the materials Estimation for all open orders, done. If you did it by mistake, it is you who are done, because in the case of a just-in-time supply and a long production order backlog, the reservation is going to quickly deplete the stock, preventing any future urgent order from starting.
Since the reservation can only be cancelled production order by production order, BOM line by BOM line, then in a medium sized plant it can take a few days of work. In Dynamics 365 Business Central aka “Navision” the state of affairs is similar.
The below is a programmatic solution, a runnable class for mass de-reservation. You may place it on a D365 menu, or just run the following command in the browser: https://xxxprod.operations.dynamics.com/?mi=SysClassRunner&cls=InventDeReserve
The user may select the type of the order to cancel the reservation for, and add additional criteria such as the warehouse, expected date of the order et cetera. Set the safeguard parameter Cancel reservation to Yes, then run with OK. Upon execution, the system is going to show a number of success messages like “Reference: Production line, Number: B000021 Item number: 205026, Lot ID: 002516 Reservation has been removed“.
You may copy or download the X++ source code here: InventDeReserve.axpp
class InventDeReserve extends RunBaseBatch implements BatchRetryable
{
QueryRun queryRun;
boolean dereserveNow = false;
DialogField dlgDereserveNow;
#define.CurrentVersion(1)
#localmacro.CurrentList
dereserveNow
#endmacro
protected void deReserveByQuery()
{
while (queryRun.next())
{
InventTrans inventTrans = queryRun.get(tableNum(InventTrans));
if (inventTrans.StatusIssue != StatusIssue::ReservPhysical && inventTrans.StatusIssue != StatusIssue::ReservOrdered)
{
continue;
}
InventDim inventDim = queryRun.get(tableNum(InventDim));
InventDimParm inventDimParm;
inventDimParm.initFromInventDim(inventDim);
ttsbegin;
InventUpd_Reservation::newParameters(InventMovement::construct(inventTrans),
// At these specific inventory dimensions only
inventDim, inventDimParm, InventDimFixedClass::inventDimParm2InventDimFixed(inventDimParm),
-inventTrans.Qty,
false, // Do not allow auto reserve dim
true /*Show info*/).updateNow();
ttscommit;
}
}
public void run()
{
#OCCRetryCount
if (! dereserveNow)
{
info("@SYS52714"); // Nothing to do
return;
}
try
{
this.deReserveByQuery();
}
catch (Exception::Deadlock)
{
retry;
}
catch (Exception::UpdateConflict)
{
if (appl.ttsLevel() == 0)
{
if (xSession::currentRetryCount() >= #RetryNum)
{
throw Exception::UpdateConflictNotRecovered;
}
else
{
retry;
}
}
else
{
throw Exception::UpdateConflict;
}
}
}
public container pack()
{
return [#CurrentVersion, #CurrentList, queryRun.pack()];
}
public boolean unpack(container _packedClass)
{
Version version = RunBase::getVersion(_packedClass);
container packedQueryRun;
switch (version)
{
case #CurrentVersion:
[version, #CurrentList, packedQueryRun] = _packedClass;
queryRun = new QueryRun(packedQueryRun);
break;
default:
return false;
}
return true;
}
public Object dialog()
{
DialogRunbase dialog = super();
dlgDereserveNow = dialog.addFieldValue(extendedTypeStr(NoYesId), dereserveNow, "@SYS50399" /* Cancel reservation */);
return dialog;
}
public boolean getFromDialog()
{
dereserveNow = dlgDereserveNow.value();
return super();
}
static void main(Args _args)
{
InventDeReserve inventDeReserve = new InventDeReserve();
if (inventDeReserve.prompt())
{
inventDeReserve.runOperation();
}
}
public void initParmDefault()
{
super();
queryRun = new QueryRun(new Query(queryStr(InventDeReserve)));
}
QueryRun queryRun()
{
return queryRun;
}
public boolean showQueryValues()
{
return true;
}
static ClassDescription description()
{
return "@SYS50399"; // Cancel reservation
}
public final boolean isRetryable()
{
return true;
}
public boolean canGoBatchJournal()
{
return true;
}
public boolean canRunInNewSession()
{
return false;
}
}
Production and Manufacturing blog series
Further reading:
D365 Mass de-reservation utility
Picking list journal: Inventory dimension Location must be specified
Consumable “Kanban” parts in D365 Warehouse management
Subcontracting with Warehouse management Part 2
Subcontracting with Warehouse management Part 1
Semi-finished goods in an advanced warehouse
The case of a missing flushing principle