Trouble with while() loop in function

Hopefully this has not been discussed in another thread, as I wouldn’t even know how to search for it.

I have a project where I am working on writing custom function to move sales order releases around to different plants based on what they have available to ship. If there are partial quantities available, it will split the release and move the new release to the available plant. If the current plant has a partial quantity, it reduces the current release to the available, and then a new release is created for the remaining quantity. That new release then loops through the code again to go through the process. The function needs to loop as long as the remaining quantity >0.

I am testing the function with an order that is for 55. Current plant has 51, and 2 other plants have 1 each.

I expect the function to reduce release 1 to 51, then create release 2 for 4, then run the code again to create release 3 and move 1 to plant 2 and then create release 4 to move 1 to plant 3, leaving remaining 1 on release 2 in the current plant.

Running the function now correctly reduces release 1 to 51, and creates release 2 at quantity 4.

At this point it looks like the function gets “stuck” in the loop. there are no errors, and I have to recycle the app pool to make sure it is not still running. No other releases are created on the order.

outstrMsg = "";
var context = (Erp.ErpContext)Ice.Services.ContextFactory.CreateContext();
var erpContext = new Erp.Internal.Lib.CCredChk(context);
decimal curavail=0;
decimal regavail=0;
decimal avail=0;
string regplant="";
string regwhse="";
string alplant="";
string alwhse="";
int release=0;
decimal remaining=0;
int order=0;
int line=0;
bool newrel=false;

//using(var txScope = Ice.IceContext.CreateDefaultTransactionScope())
//{
 
 
 
 foreach (var vDbOrderrelExist in erpContext.Db.OrderRel.Where(x => x.Company == "MJP" && x.OpenRelease==true && x.OrderNum==901943))
 //foreach (var vDbOrderrelExist in erpContext.Db.OrderRel.Where(x => x.Company == "MJP" && x.OpenRelease==true && x.BuyToOrder==false  && (x.Plant=="MJP02" || x.Plant=="MJP20" || x.Plant=="MJP30" || x.Plant=="MJP55")))
  {  
	  if(vDbOrderrelExist!=null)
	  {
	  order=vDbOrderrelExist.OrderNum;
	  line=vDbOrderrelExist.OrderLine;
	  release=vDbOrderrelExist.OrderRelNum;
	  
	 //outstrMsg += "Order Number: " + vDbOrderrelExist.OrderNum.ToString() + " " + DateTime.Now + Environment.NewLine;
		 
		 remaining= (vDbOrderrelExist.OurReqQty - vDbOrderrelExist.OurStockShippedQty);
		 while(remaining>0)
		 {
			using (var svc = Ice.Assemblies.ServiceRenderer.GetService<Ice.Contracts.DynamicQuerySvcContract>(context)) 
			{ 
				Ice.Tablesets.DynamicQueryTableset dsQuery = svc.GetByID("CheckAftermarketInventory"); 
				 if (dsQuery != null) 
				 { 
					Ice.Tablesets.QueryExecutionTableset dsBAQ = svc.GetQueryExecutionParameters(dsQuery); 
					dsBAQ.ExecutionParameter[0].ParameterID = "pOrderNum"; 
					dsBAQ.ExecutionParameter[0].IsEmpty = false; 
					dsBAQ.ExecutionParameter[0].ParameterValue = order.ToString(); 
					dsBAQ.ExecutionParameter[1].ParameterID = "pOrderLine"; 
					dsBAQ.ExecutionParameter[1].IsEmpty = false; 
					dsBAQ.ExecutionParameter[1].ParameterValue = line.ToString(); 
					dsBAQ.ExecutionParameter[2].ParameterID = "pOrderRel"; 
					dsBAQ.ExecutionParameter[2].IsEmpty = false; 
					dsBAQ.ExecutionParameter[2].ParameterValue = release.ToString(); 
					DataSet results = svc.Execute(dsQuery,dsBAQ); 
					  if(results ==null)
					  {
					  remaining=0;
					  }
			
					  if(results !=null)
					  {
					  //outstrMsg += "Allocation found " + vDbOrderrelExist.OrderNum.ToString() +  "-" + vDbOrderrelExist.OrderLine.ToString() + "-" + vDbOrderrelExist.OrderRelNum.ToString() + " " + DateTime.Now + Environment.NewLine;
						foreach (DataTable table in results.Tables)
						{
						 if(table ==null)
						 {
						  remaining=0;
						 }
						
						 if(table!=null)
						 {
						  if(table.TableName.Contains("Results"))
						  {
						   if(table.Rows.Count==0)
						   {
							remaining=0;
						   }
						   if(table.Rows.Count>0)
						   {
							foreach (DataRow row in table.Rows)
							{
							   if(row !=null)
							   {
							   
							   if(row["Calculated_CurAvail"]!=System.DBNull.Value)
							   {
							   curavail=Convert.ToDecimal(row["Calculated_CurAvail"]);
							   }
							   if(row["Calculated_RegAvail"]!=System.DBNull.Value)
							   {
							   regavail=Convert.ToDecimal(row["Calculated_RegAvail"]);
							   }
							   if(row["Calculated_Avail"]!=System.DBNull.Value)
							   {
							   avail=Convert.ToDecimal(row["Calculated_Avail"]);
							   }
							   if(row["OrderHed_ShortChar02"]!=System.DBNull.Value)
							   {
							   regplant=row["OrderHed_ShortChar02"].ToString();
							   }
							   if(row["OrderHed_ShortChar02"]!=System.DBNull.Value)
							   {
							   regwhse=row["PartWhse2_WarehouseCode"].ToString();
							   }
							   if(row["PartPlant_Plant"]!=System.DBNull.Value)
							   {
							   alplant=row["PartPlant_Plant"].ToString();
							   }
							   if(row["PartPlant_PrimWhse"]!=System.DBNull.Value)
							   {
							   alwhse=row["PartPlant_PrimWhse"].ToString();
							   }
							   
							  
							  
								  if(curavail>=remaining)                         
								  {
									  remaining=0;
								  }
								  if(curavail<=0 && regavail>=remaining && (regplant=="MJP02" || regplant=="MJP20" || regplant=="MJP30" || regplant=="MJP55"))
								  {
									   this.CallService<Erp.Contracts.SalesOrderSvcContract>(osc => {
									   Erp.Tablesets.SalesOrderTableset sods = osc.GetByID(order);
									   var desiredRelease = sods.OrderRel.Where(r => r.OrderLine == line && r.OrderRelNum == release);
											foreach(var rel in desiredRelease)
											{
											   rel.Plant=regplant;
											   rel.WarehouseCode=regwhse;
											   rel.PurPoint="";
											   rel.RowMod="U";
											   remaining=0;
											}
									   osc.ChangePlant(regplant,ref sods);                          
									   osc.Update(ref sods);
								   outstrMsg += order.ToString() +  "-" + line.ToString() + "-" + release.ToString() + " Allocated to " + regplant + DateTime.Now + Environment.NewLine;                          
									   });
								  }
								  if(curavail<=0 && regavail<=0 && avail>=remaining)
								  {
									   this.CallService<Erp.Contracts.SalesOrderSvcContract>(osc => {
									   Erp.Tablesets.SalesOrderTableset sods = osc.GetByID(order);
									   var desiredRelease = sods.OrderRel.Where(r => r.OrderLine == line && r.OrderRelNum == release);
											foreach(var rel in desiredRelease)
											{
											   rel.Plant=alplant;
											   rel.WarehouseCode=alwhse;
											   rel.PurPoint="";
											   rel.RowMod="U";
											   remaining=0;
											}
									   osc.ChangePlant(alplant,ref sods);                          
									   osc.Update(ref sods);
									   outstrMsg += order.ToString() +  "-" + line.ToString() + "-" + release.ToString() + " Allocated to " + alplant + DateTime.Now + Environment.NewLine;                         
									   });
								  }
								  
								  if(curavail>0 && curavail<remaining)
								  {
									  decimal tomove=0;
									  string opWarningMsg="";
									  remaining=remaining-curavail;
									   this.CallService<Erp.Contracts.SalesOrderSvcContract>(osc => {
									   Erp.Tablesets.SalesOrderTableset sods = osc.GetByID(order);
									   var desiredRelease = sods.OrderRel.Where(r => r.OrderLine == line && r.OrderRelNum == release);
											foreach(var rel in desiredRelease)
											{
											   rel.SellingReqQty=curavail;
											   rel.OurReqQty=curavail;
											   rel.PurPoint="";
											   rel.RowMod="U";                                      
											}
									   osc.ChangeSellingReqQty(ref sods,curavail,out opWarningMsg);                          
									   osc.Update(ref sods);  
									  }); 
									  
									  if(remaining>0)
									  {
									 
										 this.CallService<Erp.Contracts.SalesOrderSvcContract>(osc => {
										 Erp.Tablesets.SalesOrderTableset sods = osc.GetByID(order);
										 osc.GetNewOrderRel(ref sods,order,line);
										 var desiredRelease = sods.OrderRel.Where(r => r.OrderLine == line && r.OrderRelNum == 0);
											  foreach(var rel in desiredRelease)
											  {
											   rel.SellingReqQty=remaining;
											   rel.OurReqQty=remaining;
											   rel.PurPoint="";
											   rel.RowMod="A";
											  }
										 osc.ChangeSellingReqQty(ref sods,remaining,out opWarningMsg);                          
										 osc.Update(ref sods);
										 
										 outstrMsg += order.ToString() +  "-" + line.ToString() + "-" + release.ToString() + " Quantity reduced to " + curavail.ToString("#.##")+ " " +  DateTime.Now + Environment.NewLine;
										 release+=1;
										 newrel=true;
										 outstrMsg += order.ToString() +  "-" + line.ToString() + "-" + release.ToString() + " Created at quantity " + remaining.ToString("#.##")+ " " + DateTime.Now + Environment.NewLine; 
										 });
									  }//remaining >0
								  }//partial current, create new release
								  
								  if(curavail<=0 && regavail<remaining && regavail>0 && newrel==false && (regplant=="MJP02" || regplant=="MJP20" || regplant=="MJP30" || regplant=="MJP55"))
								  {
									   decimal tomove=0;
									   tomove=regavail;
									   string opWarningMsg="";
									   remaining=remaining-regavail;
									   this.CallService<Erp.Contracts.SalesOrderSvcContract>(osc => {
									   Erp.Tablesets.SalesOrderTableset sods = osc.GetByID(order);
									   var desiredRelease = sods.OrderRel.Where(r => r.OrderLine == line && r.OrderRelNum == release);
											foreach(var rel in desiredRelease)
											{
											   rel.SellingReqQty=remaining;
											   rel.OurReqQty=remaining;
											   rel.PurPoint="";
											   rel.RowMod="U";
											  
											}
									   osc.ChangeSellingReqQty(ref sods,remaining,out opWarningMsg);                          
									   osc.Update(ref sods);  
									   outstrMsg += order.ToString() +  "-" + line.ToString() + "-" + release.ToString() + " Quantity reduced to " + remaining.ToString("#.##")+ " " +  DateTime.Now + Environment.NewLine;
									  }); 
									  if(tomove>0)
									  {
										 this.CallService<Erp.Contracts.SalesOrderSvcContract>(osc => {
										 Erp.Tablesets.SalesOrderTableset sods = osc.GetByID(order);
										 osc.GetNewOrderRel(ref sods,order,line);
										 var desiredRelease = sods.OrderRel.Where(r => r.OrderLine == line && r.OrderRelNum == 0);
											  foreach(var rel in desiredRelease)
											  {
											   rel.SellingReqQty=tomove;
											   rel.OurReqQty=tomove;
											   rel.PurPoint="";
											   rel.RowMod="A";
											  }
										 osc.ChangeSellingReqQty(ref sods,tomove,out opWarningMsg);                          
										 osc.Update(ref sods);
										 desiredRelease = sods.OrderRel.Where(r => r.OrderLine == line && r.OrderRelNum == release+1);
											  foreach(var rel in desiredRelease)
											  {
												 rel.Plant=regplant;
												 rel.WarehouseCode=regwhse;
												 rel.PurPoint="";
												 rel.RowMod="U";
											  }
										 osc.ChangePlant(regplant,ref sods);                          
										 osc.Update(ref sods);
									
										 newrel=false;
										 outstrMsg += order.ToString() +  "-" + line.ToString() + "-" + release+1.ToString() + " Created at quantity " + tomove.ToString("#.##") + " and Allocated to Plant " + regplant + " " + DateTime.Now + Environment.NewLine; 
										 tomove=0;
										 curavail=0;
										 regavail=0;
										 });
									  }//remaining >0 
								  }//partial region, create new release and move
								  
								  if(curavail<=0 && regavail<=0 && avail<remaining && avail>0 && newrel==false)
								  {
									   decimal tomove=0;
									   tomove=avail;
									   string opWarningMsg="";
									   remaining=remaining-avail;
									   this.CallService<Erp.Contracts.SalesOrderSvcContract>(osc => {
									   Erp.Tablesets.SalesOrderTableset sods = osc.GetByID(order);
									   var desiredRelease = sods.OrderRel.Where(r => r.OrderLine == line && r.OrderRelNum == release);
											foreach(var rel in desiredRelease)
											{
											   rel.SellingReqQty=remaining;
											   rel.OurReqQty=remaining;
											   rel.PurPoint="";
											   rel.RowMod="U";
											  
											}
									   osc.ChangeSellingReqQty(ref sods,remaining,out opWarningMsg);                          
									   osc.Update(ref sods);  
									   outstrMsg += order.ToString() +  "-" + line.ToString() + "-" + release.ToString() + " Quantity reduced to " + remaining.ToString("#.##")+ " " +  DateTime.Now + Environment.NewLine;
									  }); 
									  if(tomove>0)
									  {
										 this.CallService<Erp.Contracts.SalesOrderSvcContract>(osc => {
										 Erp.Tablesets.SalesOrderTableset sods = osc.GetByID(order);
										 osc.GetNewOrderRel(ref sods,order,line);
										 var desiredRelease = sods.OrderRel.Where(r => r.OrderLine == line && r.OrderRelNum == 0);
											  foreach(var rel in desiredRelease)
											  {
											   rel.SellingReqQty=tomove;
											   rel.OurReqQty=tomove;
											   rel.PurPoint="";
											   rel.RowMod="A";
											  }
										 osc.ChangeSellingReqQty(ref sods,tomove,out opWarningMsg);                          
										 osc.Update(ref sods);
										 desiredRelease = sods.OrderRel.Where(r => r.OrderLine == line && r.OrderRelNum == release+1);
											  foreach(var rel in desiredRelease)
											  {
												 rel.Plant=alplant;
												 rel.WarehouseCode=alwhse;
												 rel.PurPoint="";
												 rel.RowMod="U";
											  }
										 osc.ChangePlant(regplant,ref sods);                          
										 osc.Update(ref sods);
									
										 newrel=false;
										 outstrMsg += order.ToString() +  "-" + line.ToString() + "-" + release+1.ToString() + " Created at quantity " + tomove.ToString("#.##") + " and Allocated to Plant " + alplant + " " + DateTime.Now + Environment.NewLine; 
										 tomove=0;                                 
										 avail=0;
										 });
									  }//remaining >0 
								  }//partial region, create new release and move          
								  if(curavail<=0 && regavail<=0 && avail<=0 && remaining>0)
								  {
									if(vDbOrderrelExist.Plant!="MJP02")
									{
									   this.CallService<Erp.Contracts.SalesOrderSvcContract>(osc => {
									   Erp.Tablesets.SalesOrderTableset sods = osc.GetByID(order);
									   var desiredRelease = sods.OrderRel.Where(r => r.OrderLine == line && r.OrderRelNum == release);
											foreach(var rel in desiredRelease)
											{
											   rel.Plant="MJP02";
											   rel.WarehouseCode="02";
											   rel.PurPoint="";
											   rel.RowMod="U";
											}
									   osc.ChangePlant("MJP02",ref sods);                          
									   osc.Update(ref sods); 
									  });  
									}//remaining quantity <> MJP02
								  remaining=0;
								  }//nothing on hand remaining>0
							  
							   }//Row!=null
							}//each datarow in table.rows
						   }// loop through allocation
						  }//table contains results
						 }//table!=null
						}//each table in results
					  }//Loop through order lines                
				 
				 }//check if data in allocation table
			}//build allocation table            
		 }// loop for creating new releases
	  } //if orderrel exists
  }//loop order releases that are open in specific plants 
 // txScope.Complete();
//}
if(outstrMsg=="")
{
outstrMsg+="No Order Releases to Allocate " + Environment.NewLine;
}
System.IO.File.AppendAllText(@"\\servername\Supporting Files\Logs\AftermarketAllocation.txt", outstrMsg.Trim() + " " + DateTime.Now + " " + Session.AppServerURL + Environment.NewLine);

I don’t think I’ve ever used a while loop in a BPM or function, etc. I always get my list of items to work on in the front and iterate through that.

I think you could collapse a lot of this if you set up a LINQ query at the beginning and put your conditions in there. Then just iterate through your list.

1 Like

The only reason I am doing a loop is because as it needs to process the release through the BAQ again after each time it allocates to a new location. BAA right now returns 1 row with a record for current plant, 1 for regional plant, and 1 that is the highest on hand at one of the other plants. This information changes when a new release is added (demand changes) so I am need to run it again to get updated values.

1 issue I found from looking at it again after a break was that I did not reset newrel Boolean at the end of the loop, so it wasn’t firing parts for the next run.

Next is that I was decrementing the variables I set from the BAQ so that the last condition was met before I wanted it to be.

It no longer gets stuck in a loop, but it is not moving stuff correctly (plant is not getting assigned correctly based on available quantity).

this is day 4 of building this so I think I need to take the weekend and look at it with fresh eyes on Monday.

Alot of code here, it will be difficult for anyone to test this out to help. Not sure this the answer you are looking for as I am not seeing what is being returned by the BAQ. That call will be done over and over again. Is that expected?

I would start by making sure the code stops looping by testing each if… maybe an else statement like the following as well

if(results ==null)
{
remaining=0;
}

if(results !=null)
{
//outstrMsg += "Allocation found " + vDbOrderrelExist.OrderNum.ToString() +  "-" + vDbOrderrelExist.OrderLine.ToString() + "-" + vDbOrderrelExist.OrderRelNum.ToString() + " " + DateTime.Now + Environment.NewLine;

Might want to have it be something more like this. I am betting it is never getting to remaining = 0;

if(results ==null)
{
remaining=0;
}

else
{
//outstrMsg += "Allocation found " + vDbOrderrelExist.OrderNum.ToString() +  "-" + vDbOrderrelExist.OrderLine.ToString() + "-" + vDbOrderrelExist.OrderRelNum.ToString() + " " + DateTime.Now + Environment.NewLine;

I’m still not sure why you’d want to do a looping query for that. If you’re checking the sales order against site qty’s, I’d figure out the impact in the front end, then execute based on your estimate.

As a design goal, I try to query the DB once and only once per function or BPM. It’s not always practical to do so, but that’s the aim. I strongly avoid DB queries within loops, whether it’s a LINQ, BAQ, or BO call.

1 Like

Not sure if it helps at all, but this is the scenario I am testing with:
There are 4 distribution sites.
1 (main site) ,2,3,4
Order is place for quantity 15 of part A in site 1.

Current available qty (On hand-Demand) for part A is as follows:

1: 8
2: 1
3: 2
4: 0

This function will find the sales order, and split the line into release and assign them to the plant with the quantity:
Rel 1: 8 from site 1
Rel 2: 1 from site 2
Rel 3: 2 from site 3
Rel 4: 4 remain in site 1 (if order was placed in any other site it would change it to site 1 as it is the main site)

There is some other logic as well based on the region the customer is in, but won’t get into that (regavail in the code)

It seemed easier to loop the code as the demand is updated after every release is saved, so I do not need to keep track of the available in each site via code. Also helpful if they add another distribution center down the line.

Since posting this, I got it to stop looping and it now creates the 4 releases in the example above, it is just currently assigning as follows:
Rel 1: 8 from site 1
Rel 2: 1 from site 2
Rel 3: 2 from site 1
Rel 4: 4 from site 1

I ended up doing something similar to this. Did the query first and then set variables. The way I wrote this, is it reduces the current sites quantity to what it has available and then creates a new release for the remaining quantity. This new release is why I need a loop because it needs to go through all the logic again.

Now my issue is that If I am processing a release 1 and release 2 already exists, how to tell that the new release created is actually release 3 without having to do a lookup.

May open a new topic for that issue if I can’t figure it out

As a follow up, I got everything working (until users do UAT and find issues).

Ended up doing what you said and ditched the while loop completely.

Avoided the issue with not knowing the new release number by only moving stuff out from the current release being processes (new releases do not process again until the next batch run).

Was then able to take that logic and apply it to order line creation for the initial process. (batch process will run at night to check if inventory has come in for back orders)