Skip to main content

This custom Processing graph was modelled after PX.Objects.AM.AM.Fullgen.cs. There is no list of rows to Select, and only the ‘Process All’ is enabled. It uses PXProjection to set up a single row (AMRPSetup) to pass to the delegate method. During debugging the constructor runs fine, but the delegate method (public static void ProcessFcst(List)) is never executed.

Here is the complete source code:

using System;
using PX.Data;
using PX.Objects.AM;
using PX.Objects.IN;
using System.Collections.Generic;

namespace KSIMRPExtensions
{
public class ForecastWhseCubes : PXGraph<ForecastWhseCubes>
{

public PXProcessing<FcstProcessingSetup> FcstProcessing;
public PXCancel<FcstProcessingSetup> Cancel;
public PXSetup<AMRPSetup> setup;

// Turn off the new UI processing window (19R1+)
public override bool IsProcessing
{
get { return false; }
set { }
}
public ForecastWhseCubes()
{
//check for setup record entered
var setupCache = setup.Cache;
if (setupCache == null || setupCache.Current == null)
{
throw new PXSetupNotEnteredException(PX.Objects.AM.Messages.GetLocal(PX.Objects.AM.Messages.SetupNotEntered), typeof(AMRPSetup), PX.Objects.AM.Messages.GetLocal(PX.Objects.AM.Messages.MrpSetup));
}
PXTrace.WriteInformation("ForecastWhseCubes constructor method starting");
//FcstProcessing.SetProcessDelegate(ProcessFcst);
FcstProcessing.SetProcessDelegate(
delegate (List<FcstProcessingSetup> list)
{
ProcessFcst(list);
});
FcstProcessing.SetProcessEnabled(false);
FcstProcessing.SetProcessVisible(false);
FcstProcessing.SetProcessAllVisible(true);
FcstProcessing.SetProcessAllCaption(PX.Objects.IN.Messages.Process);
}

public static void ProcessFcst(List<FcstProcessingSetup> list)
{
PXTrace.WriteInformation("ProcessFcst method starting");
var forecastWhseCubes = CreateInstance<ForecastWhseCubes>();
var uid = GetProcessID(list);
if (uid != null)
{
// Required to correctly check to see if MRP is running now that we are not
// passing the original graph which started the process.
forecastWhseCubes.UID = uid;
}
CreateInstance<ForecastWhseBalances>().Run(forecastWhseCubes);
}
protected static Guid? GetProcessID(List<FcstProcessingSetup> list)
{
return list == null || list.Count == 0 ? null : listl0]?.ProcessID;
}
}
public class DefaultProcessIDAttribute : PXUnboundDefaultAttribute
{
public override void FieldDefaulting(PXCache sender, PXFieldDefaultingEventArgs e)
{
try
{
e.NewValue = sender.Graph.UID;
}
catch
{
// ignored
}
}
}
public class ForecastWhseBalances : PXGraph<ForecastWhseBalances>
{

public PXSelect<AMMRPBucketDetailInq> MRPBucketDetailInqRec;
public PXSetup<AMRPSetup> setup;
public ForecastWhseBalances()
{
PXCache setupCache = setup.Cache;

if (setupCache?.Current == null)
{
throw new PXSetupNotEnteredException(PX.Objects.AM.Messages.GetLocal(PX.Objects.AM.Messages.SetupNotEntered),
typeof(AMRPSetup), PX.Objects.AM.Messages.GetLocal(PX.Objects.AM.Messages.MrpSetup));
}

if (!Features.MRPEnabled())
{
throw new PXException(PX.Objects.AM.Messages.UnableToProcess, this.GetType().Name);
}
}

public virtual void Run()
{
Run(this);
}
/// <summary>
/// Call Forecast Generation using the calling graph allowing the calling graph to update when the long operation is complete
/// </summary>
/// <param name="graph"></param>
public virtual void Run(PXGraph graph)
{
/// Initialize data in AMMRPBucketDetailInq
DateTime lastActionDate = Common.Dates.Now;

/// Process rows in INItemStats
foreach (PXResult<INItemStats> record in PXSelect<
INItemStats>
.Select(this))
{
INItemStats itemStats = (INItemStats)record;
/// Process rows in AMRPPlan for the current SiteID, InventoryId, sorted by ActionDate
var mrpBucketDetailInq = new AMMRPBucketDetailInq
{
SiteID = itemStats.SiteID,
InventoryID = itemStats.InventoryID,
FromDate = lastActionDate,
ToDate = lastActionDate,
BeginQty = itemStats.QtyOnHand,
PlannedSupply = 0,
PlannedDemand = 0,
EndQty = 0
};

foreach (AMRPPlan mrpPlan in PXSelectGroupBy<
AMRPPlan,
Where<AMRPPlan.siteID, Equal<Required<INItemSite.siteID>>,
And<AMRPPlan.inventoryID, Equal<Required<INItemSite.inventoryID>>,
And<AMRPPlan.isPlan, Equal<True>>>>,
Aggregate<
GroupBy<AMRPPlan.actionDate,
GroupBy<AMRPPlan.refType,
Sum<AMRPPlan.baseQty>>>>>
.Select(this, itemStats.SiteID, itemStats.InventoryID))
{
// OrderBy<SiteId, InventoryId, ActionDate>
/// On change in actionDate:
if (mrpPlan.ActionDate != lastActionDate)
{
/// Complete creation of AMMRPBucketDetailInq row from previous actionDate
mrpBucketDetailInq.EndQty = mrpBucketDetailInq.BeginQty +
mrpBucketDetailInq.PlannedSupply -
mrpBucketDetailInq.PlannedDemand;
MRPBucketDetailInqRec.Insert(mrpBucketDetailInq);
/// Initialize new mrpBucketDetailInq row
mrpBucketDetailInq.BeginQty = mrpBucketDetailInq.EndQty;
mrpBucketDetailInq.FromDate = mrpPlan.ActionDate;
mrpBucketDetailInq.ToDate = mrpPlan.ActionDate;
mrpBucketDetailInq.PlannedSupply = 0;
mrpBucketDetailInq.PlannedDemand = 0;
mrpBucketDetailInq.EndQty = 0;
}
/// Determine RefType - supply vs demand
switch (mrpPlan.SDflag)
{
case "S":
mrpBucketDetailInq.PlannedSupply += mrpPlan.BaseQty;
break;
case "D":
mrpBucketDetailInq.PlannedDemand += mrpPlan.BaseQty;
break;
default:
break;
}
/// Capture current data
lastActionDate = (DateTime)mrpPlan.ActionDate;
}
/// Create AMMRPBucketDetailInq for the last ActionDate
mrpBucketDetailInq.EndQty = mrpBucketDetailInq.BeginQty +
mrpBucketDetailInq.PlannedSupply -
mrpBucketDetailInq.PlannedDemand;
MRPBucketDetailInqRec.Insert(mrpBucketDetailInq);
}
}
}

/// <summary>
/// Regenerate MRP processing setup record.
/// (AMRPSetup Projection)
/// </summary>
>Serializable]
>PXProjection(typeof(Select<AMRPSetup>))]
>PXCacheName(PX.Objects.AM.Messages.MrpSetup)]
public class FcstProcessingSetup : IBqlTable, IPXSelectable
{
#region Selected
public abstract class selected : PX.Data.BQL.BqlBool.Field<selected> { }
PXBool]
PXDefault(false, PersistingCheck = PXPersistingCheck.Nothing)]
PXUIField(DisplayName = "Selected")]
public bool? Selected { get; set; }
#endregion
#region ProcessID
public abstract class processID : PX.Data.BQL.BqlGuid.Field<processID> { }
protected Guid? _ProcessID;
PXGuid]
PXUIField(Visible = false)]
DefaultProcessID]
public virtual Guid? ProcessID
{
get
{
return this._ProcessID;
}
set
{
this._ProcessID = value;
}
}
#endregion
#region LastMrpRegenCompletedByID

public abstract class lastMrpRegenCompletedByID : PX.Data.BQL.BqlGuid.Field<lastMrpRegenCompletedByID> { }
protected Guid? _LastMrpRegenCompletedByID;
PXDBCreatedByID(DisplayName = "Last Completed By", DontOverrideValue = true, BqlField = typeof(AMRPSetup.lastMrpRegenCompletedByID))]
public virtual Guid? LastMrpRegenCompletedByID
{
get
{
return this._LastMrpRegenCompletedByID;
}
set
{
this._LastMrpRegenCompletedByID = value;
}
}
#endregion
#region LastMrpRegenCompletedDateTime

public abstract class lastMrpRegenCompletedDateTime : PX.Data.BQL.BqlDateTime.Field<lastMrpRegenCompletedDateTime> { }
protected DateTime? _LastMrpRegenCompletedDateTime;
PXDBDateAndTime(BqlField = typeof(AMRPSetup.lastMrpRegenCompletedDateTime))]
PXUIField(DisplayName = "Last Completed At", Enabled = false, IsReadOnly = true, Visible = true)]
public virtual DateTime? LastMrpRegenCompletedDateTime
{
get
{
return this._LastMrpRegenCompletedDateTime;
}
set
{
this._LastMrpRegenCompletedDateTime = value;
}
}
#endregion
}
}

Any insight would be most helpful!

Thank you!

Thank you BOTH! I had failed to add a Content element to the .aspx page for the FcstProcessing view. I added the element there, and now the graph List shows one row, and the delegate method is executing. You are lifesavers!


Hi @rdennisj57 

The DAC row should have a column “Selected” that must be true. When true, is included in the list 

List<FcstProcessingSetup> list

and the delegate is invoked


Hi @rdennisj57  Do you have any records in this table FcstProcessingSetup to process?

 


Yes, @rdennisj57  At least we should have one row and with a Selected boolean field for this DAC then only the process delegate will be invoked.


Reply