PartDtl does not change after BPM adjust PO release vendor qty

Hi everyone,

I have a pre-processing execute custom code on DMRProcessing.CustomUpdate BPM that able to adjust the PO release vendor qty when rejected. However the PartDtl list in Time Phase does not change, I’m on version 10.2.300.7 of Epicor. Thanks in advance for any assistance!

// Update PO Supplier Qty

using (var txScope = IceContext.CreateDefaultTransactionScope())
{
  foreach (var ttDMRActnRow in (from ttDMRActnRow in ttDMRActn where ttDMRActnRow.ActionType=="R" && (Boolean)ttDMRActnRow.UDField("RejectPO_c")==false select ttDMRActnRow)) // RejectPO_c flag control update once
  {
    foreach (var RcvDtlRow in (from RcvDtlRow in Db.RcvDtl.With(LockHint.UpdLock) where ttDMRActnRow.Company==RcvDtlRow.Company && ttDMRActnRow.PackSlip==RcvDtlRow.PackSlip && ttDMRActnRow.PackLine==RcvDtlRow.PackLine && ttDMRActnRow.PONum==RcvDtlRow.PONum select RcvDtlRow))
    {
      foreach (var PORelRow in (from PORelRow in Db.PORel.With(LockHint.UpdLock) where RcvDtlRow.Company==PORelRow.Company && RcvDtlRow.PONum==PORelRow.PONum && RcvDtlRow.POLine==PORelRow.POLine && RcvDtlRow.PORelNum==PORelRow.PORelNum select PORelRow))
      {
        Erp.Contracts.POSvcContract vh_PO = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.POSvcContract>(Db);
        var dsPO = vh_PO.GetByID(PORelRow.PONum);
        
        // If PORel is CLOSED, REOPEN it
        if (PORelRow.OpenRelease==false)
        {
          vh_PO.ReOpenRelease(PORelRow.PONum, PORelRow.POLine, PORelRow.PORelNum);               
        }
        // If PORel is CLOSED, REOPEN it
          
        var outStr = String.Empty;
        var dRelVendQty = PORelRow.RelQty + ttDMRActnRow.DispQuantity;
                
        // this.PublishInfoMessage(dRelVendQty.ToString(), Ice.Common.BusinessObjectMessageType.Information, Ice.Bpm.InfoMessageDisplayMode.Individual, "PORel", "ChangeRelVendQty");

        // Update PORel Supplier Qty with dRelVendQty
        if (PORelRow.RelQty != dRelVendQty)
        {
          dsPO.PORel[0].RowMod="U";
          vh_PO.ChangeRelVendQty(dRelVendQty, ref dsPO, out outStr);
        }
        // Update PORel Supplier Qty with dRelVendQty
      }
    }
  }
  Db.Validate();
  txScope.Complete();
}

The main problem you have is you are mixing your db rows with the business object data.
Use the linq query to find the po release you want, then use the business object to update the data.
Below is untested code. I would also probably do it as a post process async process and drop the transaction scope.

using(var txScope = IceContext.CreateDefaultTransactionScope()) 
{

	foreach(var ttDMRActnRow in (from ttDMRActnRow in ttDMRActn where ttDMRActnRow.ActionType == “R” && (Boolean) ttDMRActnRow.UDField(“RejectPO_c”) == false select ttDMRActnRow)) // RejectPO_c flag control update once
	{
		//copy the data we need to temp variables so the LINQ query knows the type for sure
		int packSlip = tDMRActnRow.PackSlip;
		int packLine = ttDMRActnRow.PackLine;

		//get just the info we need for performance.
		var poInfo = (from rd in Db.RcvDtl
		where rd.PackSlip == packSlip && rd.PackLine == packLine
		select new {
			rd.PONum,
			rd.POLine,
			rd.PORelNum,
		}).FirstOrDefualt();

		Erp.Contracts.POSvcContract vh_PO = Ice.Assemblies.ServiceRenderer.GetService < Erp.Contracts.POSvcContract > (Db);
		var dsPO = vh_PO.GetByID(poInfo.PONum);

		//find the po release  row we are looking for
		var PORelRow = (from r in dsPO.PORel
		where r.PONum == poInfo.PONum && r.POLine == poInfo.POLine && r.PORelNum == poInfo.PORelNum
		select r).FirstOrDefualt();

		// If PORel is CLOSED, REOPEN it
		if (PORelRow.OpenRelease == false) {
			vh_PO.ReOpenRelease(PORelRow.PONum, PORelRow.POLine, PORelRow.PORelNum);
		}
		// If PORel is CLOSED, REOPEN it

		var outStr = String.Empty;
		var dRelVendQty = PORelRow.RelQty + ttDMRActnRow.DispQuantity;

		// this.PublishInfoMessage(dRelVendQty.ToString(), Ice.Common.BusinessObjectMessageType.Information, Ice.Bpm.InfoMessageDisplayMode.Individual, "PORel", "ChangeRelVendQty");

		// Update PORel Supplier Qty with dRelVendQty
		if (PORelRow.RelQty != dRelVendQty) {
			dsPO.PORel[0].RowMod = "U";
			vh_PO.ChangeRelVendQty(dRelVendQty, ref dsPO, out outStr);
		}
		// Update PORel Supplier Qty with dRelVendQty
	}

	txScope.Complete();
}
2 Likes

Hi Carson,

Thanks your reply that I can learn more LINQ query. Following your comments I can still reopen the PO Release but nothing change on both vendor qty and PartDtl. Did I missing some step? Pls advise.

// Update PO Supplier Qty

using (var txScope = IceContext.CreateDefaultTransactionScope())
{
foreach (var ttDMRActnRow in (from ttDMRActnRow in ttDMRActn where ttDMRActnRow.ActionType==“R” && (Boolean)ttDMRActnRow.UDField(“RejectPO_c”)==false select ttDMRActnRow)) // RejectPO_c flag control update once
{
// copy the data we need to temp variables so the LINQ query knows the type for
string packSlip = ttDMRActnRow.PackSlip;
int packLine = ttDMRActnRow.PackLine;
int poNum = ttDMRActnRow.PONum;

// this.PublishInfoMessage(poNum.ToString(), Ice.Common.BusinessObjectMessageType.Information, Ice.Bpm.InfoMessageDisplayMode.Individual, "DRMActn", "ChangeRelVendQty");

// get just the info we need for performance
var poInfo = (from rd in Db.RcvDtl where rd.PackSlip==packSlip && rd.PackLine==packLine && rd.PONum==poNum select new {rd.PONum, rd.POLine, rd.PORelNum,}).FirstOrDefault();
Erp.Contracts.POSvcContract vh_PO = Ice.Assemblies.ServiceRenderer.GetService <Erp.Contracts.POSvcContract> (Db);

// this.PublishInfoMessage(poInfo.PONum.ToString(), Ice.Common.BusinessObjectMessageType.Information, Ice.Bpm.InfoMessageDisplayMode.Individual, "RcvDtl", "ChangeRelVendQty");

var dsPO = vh_PO.GetByID(poInfo.PONum);

// find the po release row we are looking for
var PORelRow = (from r in dsPO.PORel where r.PONum==poInfo.PONum && r.POLine==poInfo.POLine && r.PORelNum==poInfo.PORelNum select r).FirstOrDefault();

// this.PublishInfoMessage(PORelRow.PONum.ToString(), Ice.Common.BusinessObjectMessageType.Information, Ice.Bpm.InfoMessageDisplayMode.Individual, "PORel", "ChangeRelVendQty");
    
// If PORel is CLOSED, REOPEN it
if (PORelRow.OpenRelease == false)
{
  vh_PO.ReOpenRelease(PORelRow.PONum, PORelRow.POLine, PORelRow.PORelNum);
}
// If PORel is CLOSED, REOPEN it

var outStr = String.Empty;
var dRelVendQty = PORelRow.RelQty + ttDMRActnRow.DispQuantity;

// this.PublishInfoMessage(dRelVendQty.ToString(), Ice.Common.BusinessObjectMessageType.Information, Ice.Bpm.InfoMessageDisplayMode.Individual, "PORel", "ChangeRelVendQty");


// Update PORel Supplier Qty with dRelVendQty
if (PORelRow.RelQty != dRelVendQty)
{
  dsPO.PORel[0].RowMod = "U";
  vh_PO.ChangeRelVendQty(dRelVendQty, ref dsPO, out outStr);
}
// Update PORel Supplier Qty with dRelVendQty

}
txScope.Complete();
}

My guess is it needs the release qty set and an update. It needs the update for sure.

if (PORelRow.RelQty != dRelVendQty)
{
  PORelRow.RelQty = dRelVendQty;
  dsPO.PORel[0].RowMod = "U";
  vh_PO.ChangeRelVendQty(dRelVendQty, ref dsPO, out outStr);
  vh_PO.Update(ref dsPO);

}

Hi Carson,

PO release does not close but prompt me alert ‘Release is Closed’ as below messages. Try unapproved PO too.

Business Layer Exception

Release is closed

Exception caught in: Epicor.ServiceModel

Error Detail

Description: Release is closed
Program: Erp.Services.BO.PO.dll
Method: PORelBeforeUpdate
Line Number: 16652
Column Number: 17

Client Stack Trace

at Epicor.ServiceModel.Channels.ImplBase`1.ShouldRethrowNonRetryableException(Exception ex, DataSet dataSets)
at Erp.Proxy.BO.DMRProcessingImpl.CustomUpdate(DMRProcessingDataSet ds, String& opLegalNumberMessage)
at Erp.Adapters.DMRProcessingAdapter.Update(String& opLegalNumberMessage)
at Erp.UI.App.DMRProcessingEntry.Transaction.adapterUpdate()
at Erp.UI.App.DMRProcessingEntry.Transaction.Update()

You will need to open the release first if it is closed. Do a trace on changing the quantity and see what methods are hit.

I see you already had the open release method in there. I think it needs another get by ID after reopening the release.

		if (PORelRow.RelQty != dRelVendQty)
		{
			if (PORelRow.OpenRelease == false)	//the release is closed so reopen it.
			{
				vh_PO.ReOpenRelease(PORelRow.PONum, PORelRow.POLine, PORelRow.PORelNum);
				dsPO = vh_PO.GetByID(poInfo.PONum);
				//I'm not sure if PORelRow will still be valid here it may need to be queried again
			}
			PORelRow.RelQty = dRelVendQty;
			dsPO.PORel[0].RowMod = "U";
			vh_PO.ChangeRelVendQty(dRelVendQty, ref dsPO, out outStr);
			vh_PO.Update(ref dsPO);

But my first post used the foreach loop that can update the PO release supplier qty except PartDtl.

In your first post you were updating the records with a db write skipping all the business logic. That works great because you don’t get stopped by any rules, but doesn’t fix all the related fields that get updated by the business object. There were probably more problems than just the partdtl record lurking around.

If the PO is approved you may need to unapprove it also.

In general I only use dataContext.Validate(); to update custom fields or things like comments. Even updating comments or custom fields with a db write can cause problems if people expect the change log to show the updates.

1 Like

Noted and thanks.
Already try to unapprove but same as before.

I change back to my foreach loop method and add two variables to adjust both supplier and our qty. Successful update PO Release and PartDtl. Nothing problem after process MRP.
Thanks Carson.

P.S. testing with the LINQ query still not work.

// Update PO Supplier Qty and PartDtl Receipt Qty

using (var txScope = IceContext.CreateDefaultTransactionScope())
{
foreach (var ttDMRActnRow in (from ttDMRActnRow in ttDMRActn where ttDMRActnRow.ActionType==“R” && (Boolean)ttDMRActnRow.UDField(“RejectPO_c”)==false select ttDMRActnRow)) // RejectPO_c flag control update once
{
foreach (var RcvDtlRow in (from RcvDtlRow in Db.RcvDtl.With(LockHint.UpdLock) where ttDMRActnRow.Company==RcvDtlRow.Company && ttDMRActnRow.PackSlip==RcvDtlRow.PackSlip && ttDMRActnRow.PackLine==RcvDtlRow.PackLine && ttDMRActnRow.PONum==RcvDtlRow.PONum select RcvDtlRow))
{
foreach (var PORelRow in (from PORelRow in Db.PORel.With(LockHint.UpdLock) where RcvDtlRow.Company==PORelRow.Company && RcvDtlRow.PONum==PORelRow.PONum && RcvDtlRow.POLine==PORelRow.POLine && RcvDtlRow.PORelNum==PORelRow.PORelNum select PORelRow))
{
Erp.Contracts.POSvcContract vh_PO = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.POSvcContract>(Db);
var dsPO = vh_PO.GetByID(PORelRow.PONum);

    // If PORel is CLOSED, REOPEN it
    if (PORelRow.OpenRelease==false)
    {
      vh_PO.ReOpenRelease(PORelRow.PONum, PORelRow.POLine, PORelRow.PORelNum);               
    }
      
    // Update PORel Supplier and Our Qty
    var outStr = String.Empty;
    var dFactor = PORelRow.RelQty / PORelRow.XRelQty; // Calculate the factor base on Our Qty
    var dRelVenQty = PORelRow.RelQty + ttDMRActnRow.DispQuantity;
    var dRelOurQty = Decimal.Zero;      
    switch (PORelRow.PurchasingFactorDirection)
    {
      case "M":
        dRelOurQty = PORelRow.XRelQty + ttDMRActnRow.DispQuantity * dFactor;
        break;
      case "D":
        dRelOurQty = PORelRow.XRelQty + ttDMRActnRow.DispQuantity / dFactor;
        break;
    }

    // this.PublishInfoMessage(dRelOurQty.ToString(), Ice.Common.BusinessObjectMessageType.Information, Ice.Bpm.InfoMessageDisplayMode.Individual, "PORel", "ChangeRelVendQty");

    dsPO.PORel[0].RowMod="U";
    PORelRow.RelQty = dRelVenQty;
    PORelRow.XRelQty = dRelOurQty;
    vh_PO.ChangeRelVendQty(dRelVenQty, ref dsPO, out outStr);
  }
}

}
Db.Validate();
txScope.Complete();
}