Reserve Stock from Warehouses

Hi, I have some code attached to a Data Directive to reserve stock from the Primary warehouse of a Part Code as it was entered into the Order. This was fantastic until we started running out of space in the warehouse and we needed to stock in Separate Warehouses.

This Part of the code is now the issue, where CWhseType state primary only, i would like to specify 3 different warehouse codes instead. We have too many warehouses to allow all Reservations from all warehouses using String.Emtpy;

I have attached all the code below.

var hOrderAllocSvc = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.OrderAllocSvcContract>(Db);
using(hOrderAllocSvc)
{
foreach(var orderRelRow in (from row in ttOrderRel where row.RowMod == IceRow.ROWSTATE_ADDED || row.RowMod == IceRow.ROWSTATE_UPDATED select row))
{
int orderNum = orderRelRow.OrderNum;
int pageSize = 0;
int absolutePage = 0;
bool morePages ;
DateTime resultDate;
bool newReserveStkVal = orderRelRow.ReserveStock_c;
bool oldReserveStkVal = false;
if(orderRelRow.RowMod == IceRow.ROWSTATE_UPDATED)
{
oldReserveStkVal = (from row in ttOrderRel where row.RowMod == IceRow.ROWSTATE_UNCHANGED && row.Company == orderRelRow.Company && row.OrderNum == orderRelRow.OrderNum && row.OrderLine == orderRelRow.OrderLine && row.OrderRelNum == orderRelRow.OrderRelNum select row.ReserveStock_c).FirstOrDefault();
}
//string orderNumWhereClause = “OrderNum = '” + orderNum.ToString() +"’";
string orderNumWhereClause = “OrderNum = '” + orderNum.ToString() +"’ AND OrderLine = " + orderRelRow.OrderLine.ToString() + " AND OrderRelNum = " + orderRelRow.OrderRelNum.ToString() ;
bool reserveFlag = oldReserveStkVal == false && newReserveStkVal == true;
bool unReserveFlag = oldReserveStkVal == true && newReserveStkVal == false && orderRelRow.RowMod == IceRow.ROWSTATE_UPDATED;

if(reserveFlag || unReserveFlag)
{  

  var orderAllocDS = hOrderAllocSvc.GetListFWB(orderNumWhereClause,pageSize,absolutePage,out morePages);
  var orderAllocTableSet = hOrderAllocSvc.OrderAllocationGetRows(orderAllocDS, 0);
  bool opCalcFulfillOnSearch;
  hOrderAllocSvc.GetCalcPref(out opCalcFulfillOnSearch);
  hOrderAllocSvc.SetCalcPref(opCalcFulfillOnSearch);
  bool opFWBFulfillFromDemandWhseOnly;
  hOrderAllocSvc.GetFWBFulfillFromDemandWhseOnly(out opFWBFulfillFromDemandWhseOnly);
  string cMessageText = String.Empty;
//Reserve
if(reserveFlag)
{

  Erp.Tablesets.SlimOrderAllocTableset slimOrderTS = new Erp.Tablesets.SlimOrderAllocTableset();
  
  foreach(var orderAllocRow in orderAllocTableSet.OrderAlloc)
  {
  
  decimal unreservedInventory = orderAllocRow.UnreservedInventory; 
  decimal ourReqInv = orderAllocRow.OurReqQty ;
  
  //this.PublishInfoMessage("unreservedInventory: " + unreservedInventory.ToString()+ "ourReqInv: " + ourReqInv.ToString(),Ice.Common.BusinessObjectMessageType.Information, Ice.Bpm.InfoMessageDisplayMode.Individual,"","");
   bool makeDirect = (from row in Db.OrderRel where row.Company == orderAllocRow.Company && row.OrderNum == orderAllocRow.OrderNum && row.OrderLine == orderAllocRow.OrderLine && row.OrderRelNum == orderAllocRow.OrderRelNum select row.Make).FirstOrDefault();
   if(makeDirect == false)       
     {
      if(unreservedInventory >= ourReqInv)
      {
        orderAllocRow.SelectedForAction = true;
        orderAllocRow.RowMod = "U";
        Ice.IceRow  newRow = slimOrderTS.SlimOrderAlloc.NewRow();
       
        newRow["Company"] = orderAllocRow.Company;
        newRow["SelectedForAction"] = true;
        newRow["DemandType"] = "Order";
        newRow["JobNum"] = orderAllocRow.JobNum;
        newRow["AssemblySeq"] = orderAllocRow.AssemblySeq;
        newRow["MtlSeq"] = orderAllocRow.MtlSeq;
        newRow["OrderNum"] = orderAllocRow.OrderNum;
        newRow["OrderLine"] = orderAllocRow.OrderLine;
        newRow["OrderRelNum"] = orderAllocRow.OrderRelNum;
        newRow["FulfillmentSeq"] = orderAllocRow.FulfillmentSeq;
        newRow["TFOrdNum"] = orderAllocRow.TFOrdNum;
        newRow["TFOrdLine"] = orderAllocRow.TFOrdLine;
        newRow["RowMod"] = "A";

        if (DateTime.TryParse(orderAllocRow.DoNotShipBeforeDate.ToString(), out resultDate))
        newRow["DoNotShipBeforeDate"] = resultDate.ToShortDateString();

        if (DateTime.TryParse(orderAllocRow.DoNotShipAfterDate.ToString(), out resultDate))
        newRow["DoNotShipAfterDate"] = resultDate.ToShortDateString();
        slimOrderTS.SlimOrderAlloc.Add(newRow);           
      }
      else
      {
        errorRecList.Add(Tuple.Create(orderRelRow.OrderLine.ToString(), orderRelRow.OrderRelNum.ToString()));
      }
     }
  }
  
  if(slimOrderTS.SlimOrderAlloc.Count > 0)
  {
   hOrderAllocSvc.CheckDates(ref slimOrderTS, out cMessageText);
  
    if(!string.IsNullOrEmpty(cMessageText))
    {
    this.PublishInfoMessage(cMessageText ,Ice.Common.BusinessObjectMessageType.Information, Ice.Bpm.InfoMessageDisplayMode.Individual,"","");
    }
 
  
    foreach (var slimOrderAllocRows in slimOrderTS.SlimOrderAlloc)
    {             
      slimOrderAllocRows.RowMod = "U";     
      slimOrderAllocRows.SelectedForAction = true;
    }
    string cIPWhseList = String.Empty;
    string CWhseType = "primaryonly";
    hOrderAllocSvc.AutoReserve(ref slimOrderTS, cIPWhseList, CWhseType, out cMessageText);
    //Sync partWhse Recieved Qty        
      Erp.Internal.Lib.DeferredUpdate libDeferredUpdate = new Erp.Internal.Lib.DeferredUpdate(Db);
      libDeferredUpdate.UpdPQDemand();
    
    
    if(!string.IsNullOrEmpty(cMessageText))
    {
      string unReservedMsg = "0 Demand record(s) reserved";
      if(cMessageText.Contains(unReservedMsg,StringComparison.OrdinalIgnoreCase))      
      {
      this.PublishInfoMessage(cMessageText ,Ice.Common.BusinessObjectMessageType.Information, Ice.Bpm.InfoMessageDisplayMode.Individual,"","");
      }
    }
  }
  string exceptionMsg = "";
  string vSubject = "";
  
  if(errorRecList.Count > 0)
  {
    exceptionMsg = " Order Release has not been reserved ";
    vSubject = " Sufficient inventory is not available to allocate some order releases of order number: " + orderNum.ToString();
  }
  foreach(var errorRecord in errorRecList)
  {
    exceptionMsg = exceptionMsg + Environment.NewLine + "Order Line: " + errorRecord.Item1 + " Order Rel: " + errorRecord.Item2;
  }
  
  if(!string.IsNullOrEmpty(exceptionMsg))
  {
  //if(!string.IsNullOrEmpty(cMessageText) && (callContextClient.AssemblyName.StartsWith("Erp.UI")  || callContextClient.AssemblyName.StartsWith("Ice.UI")))
    this.PublishInfoMessage(exceptionMsg,Ice.Common.BusinessObjectMessageType.Information, Ice.Bpm.InfoMessageDisplayMode.Individual,"","");
    //Send mail with exception details and throw message
    var mailer = this.GetMailer(async: false);

    var message = new Ice.Mail.SmtpMail();
    exceptionMsg = exceptionMsg.Replace(Environment.NewLine,"<br>");
    message.SetTo(vToEmail);
    message.SetFrom(vFromEmail);        
    message.SetSubject(vSubject);
    message.SetBody(exceptionMsg);
    message.IsBodyHtml = true;
    mailer.Send(message);
  }
}
if(unReserveFlag)
{
  //UnReserve
  foreach(var orderAllocRow in orderAllocTableSet.OrderAlloc)
  {
   bool makeDirect = (from row in Db.OrderRel where row.Company == orderAllocRow.Company && row.OrderNum == orderAllocRow.OrderNum && row.OrderLine == orderAllocRow.OrderLine && row.OrderRelNum == orderAllocRow.OrderRelNum select row.Make).FirstOrDefault();
   if(makeDirect == false)       
   {
    orderAllocRow.SelectedForAction = true;
    orderAllocRow.RowMod = "U";
   }
  }
  if(orderAllocTableSet.OrderAlloc.Exists(x=> x.SelectedForAction == true))
  {
  hOrderAllocSvc.Unreserve(ref orderAllocTableSet,out cMessageText);
  //Sync partWhse Recieved Qty        
      Erp.Internal.Lib.DeferredUpdate libDeferredUpdate = new Erp.Internal.Lib.DeferredUpdate(Db);
      libDeferredUpdate.UpdPQDemand();
    //if(!string.IsNullOrEmpty(cMessageText) && (callContextClient.AssemblyName.StartsWith("Erp.UI")  || callContextClient.AssemblyName.StartsWith("Ice.UI")))
    if(!string.IsNullOrEmpty(cMessageText))
    {
      this.PublishInfoMessage(cMessageText ,Ice.Common.BusinessObjectMessageType.Information, Ice.Bpm.InfoMessageDisplayMode.Individual,"","");
      //Send mail with exception details and throw message
      var mailer = this.GetMailer(async: false);
      string vSubject = "Order UnReserve process failed with some errors for order number: " + orderNum.ToString();
      var message = new Ice.Mail.SmtpMail();
      cMessageText = cMessageText.Replace(Environment.NewLine,"<br>");
      message.SetTo(vToEmail);
      message.SetFrom(vFromEmail);        
      message.SetSubject(vSubject);
      message.SetBody(cMessageText);
      message.IsBodyHtml = true;
      mailer.Send(message);
    }
  }
}
}

}
}

What if you used standard functionality and allocated by Zone?
You set the zone at the bin level, but multiple bins and warehouses can be in the same zone.

Hi, we need to soft allocate (reserve) across multiple warehouses withoit anyone touching the fulfillment workbench until it is ready to send out to the warehouse where we just release to picking to the parts primary bin.

@Ricky90 Please format your code with ``` before and after.

This would still be a custom call, but you would trace how the zonal process was done and mimic that in the code.

@gpayne so i could have 1 zone which covered all my saleable warehouses and bins and then reserve against that zone but can i reserve against a Zone or does it have to be allocate as we cannot operate with a hard allocation.

We don’t use the workbench, so I don’t know the process @LarsonSolutions is referring to but you have to map out how it is possible using the UI to accomplish what you need and then make those same calls in the customization.

So, how is the job setup since a material can only have one demand warehouse as far as I know?
I think if we did this it would be a logical warehouse like materials and then bins of wh1-bin and wh2-bin to show where the material was located. Then reserve by Primary Warehouse would still work,

@gpayne It is not applicable to Jobs in our situation. It is purely Distribution from a Sales Order. Pick, Pack then Ship but we need to reserve stock at the time of order especially as our website places 60% of all order automatically via REST so our Office staff are not aware of new orders, they do a check on Fulfilment workbench for all Website Orders at intervals then any Orders they can 100% fulfil they just Release them for Picking.

The 1 Logical Warehouse is my last resort but we have so many customizations built upon separate logical warehouses for each physical site I really do not want to go down this route until all others have been explored.

@Ricky90 I am reading the method and IPWhseList is the list of warehouses. Have tou tried to set the three you want and then WhseType to All? My hope would be that All is now just the three in the list.

I have just come across the same thing.
I worry im losing the plot a little bit here with this but i cannot get a ‘Syntax OK’ for more than one Warehouse Code!!

I would go to the BL Tester. You might be able to trace it thru FWB with multiple warehouses to see how it is delimiting them.

@gpayne I managed to find that the WhseGroup uses “W1~W2~W3” but the WhseType of “all” overrides this and uses any warehouse :frowning:

@Ricky90 So I don’t know if this is possible, but I was looking at allocation by waves. usually these would be formal, but maybe you could make waves by order/line/release and then the warehouse zones could be available.