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();
}
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
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()
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);
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.
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);
}
}