1
votes

I have a custom field in AR Invoice and Memos (Screen ID AR301000) for the corresponding AP Ref. Nbr. And in the similar manager another custom field in AP Bills and Adjustment (Screen ID AP301000) for the corresponding AR Ref. Nbr.

I am trying to update AP Ref. Nbr. on AR screen when user updates the AR Ref. Nbr. in AP screen.

For example-

I am on AR Screen Invoice 0001, I am updating AP Ref. Nbr. to abc01. System will automatically update the AP Bill abc01 with the corresponding AR Ref. Nbr. with 0001.

I have below code written to achieve this but it runs into infinite loop as both it is trying to update the corresponding fields in other screen. Let me know if I missing anything or there is a better way.

On AR Graph Extension

public class ARInvoiceEntryExtension : PXGraphExtension<ARInvoiceEntry>
{
	protected virtual void ARInvoice_RowUpdated(PXCache sender, PXRowUpdatedEventArgs e)
	{
		var row = (ARInvoice)e.Row;
		if (row != null && sender.IsDirty)
		{
			ARRegisterExtension ext = PXCache<ARRegister>.GetExtension<ARRegisterExtension>(row);

			if (ext != null && !string.IsNullOrEmpty(ext.UsrAPRefNbr))
			{
				APInvoiceEntry graph = PXGraph.CreateInstance<APInvoiceEntry>();

				APInvoice apRow = PXSelect<APInvoice,
					Where<APInvoice.refNbr, Equal<Required<APInvoice.refNbr>>>>.Select(graph, ext.UsrAPRefNbr);

				if (apRow != null)
				{
					APRegisterExtension ext1 = PXCache<APRegister>.GetExtension<APRegisterExtension>(apRow);
					if (ext1 != null && string.IsNullOrEmpty(ext1.UsrARRefNbr))        //Update only if it is empty
					{
						ext1.UsrARRefNbr = row.RefNbr;

						graph.Document.Current = apRow;

						graph.Caches[typeof(APRegister)].SetValue<APRegisterExtension.usrARRefNbr>(apRow, row.RefNbr);
						graph.Caches[typeof(APRegister)].Update(apRow);
						graph.Actions.PressSave();
					}
				}
			}
		}
	}
}

On AP Graph Extension

public class APInvoiceEntryExtension : PXGraphExtension<APInvoiceEntry>
{
	protected virtual void APInvoice_RowUpdated(PXCache sender, PXRowUpdatedEventArgs e)
	{
		var row = (APInvoice)e.Row;
		if (row != null && sender.IsDirty)
		{
			APRegisterExtension ext = PXCache<APRegister>.GetExtension<APRegisterExtension>(row);

			if (ext != null && !string.IsNullOrEmpty(ext.UsrARRefNbr))
			{
				ARInvoiceEntry graph = PXGraph.CreateInstance<ARInvoiceEntry>();

				ARInvoice arRow = PXSelect<ARInvoice,
					Where<ARInvoice.refNbr, Equal<Required<ARInvoice.refNbr>>>>.Select(graph, ext.UsrARRefNbr);

				if (arRow != null)
				{
					ARRegisterExtension ext1 = PXCache<ARRegister>.GetExtension<ARRegisterExtension>(arRow);
					if (ext1 != null && string.IsNullOrEmpty(ext1.UsrAPRefNbr))        //Update only if it is empty
					{
						ext1.UsrAPRefNbr = row.RefNbr;

						graph.Document.Current = arRow;

						graph.Caches[typeof(ARRegister)].SetValue<ARRegisterExtension.usrAPRefNbr>(arRow, row.RefNbr);
						graph.Caches[typeof(ARRegister)].Update(arRow);
						graph.Actions.PressSave();
					}
				}
			}
		}
	}
}

AR Cache Extension

public class ARRegisterExtension : PXCacheExtension<ARRegister>
{
	public abstract class usrAPRefNbr : PX.Data.IBqlField
	{
	}

	protected string _usrAPRefNbr;

	[PXDBString(15)]
	[PXUIField(DisplayName = "AP Ref Nbr.", Visibility = PXUIVisibility.SelectorVisible)]

	[APInvoiceType.RefNbr(typeof(Search3<PX.Objects.AP.Standalone.APRegisterAlias.refNbr,
	InnerJoinSingleTable<APInvoice, On<APInvoice.docType, Equal<PX.Objects.AP.Standalone.APRegisterAlias.docType>,
		And<APInvoice.refNbr, Equal<PX.Objects.AP.Standalone.APRegisterAlias.refNbr>>>,
	InnerJoinSingleTable<Vendor, On<PX.Objects.AP.Standalone.APRegisterAlias.vendorID, Equal<Vendor.bAccountID>>>>,
	OrderBy<Desc<APRegister.refNbr>>>))]
	public virtual string UsrAPRefNbr
	{
		get; set;
	}
}

AP Cache Extension

public class APRegisterExtension : PXCacheExtension<APRegister>
{
	public abstract class usrARRefNbr : PX.Data.IBqlField
	{
	}

	protected string _usrARRefNbr;

	[PXDBString(15)]
	[PXUIField(DisplayName = "AR Ref Nbr.", Visibility = PXUIVisibility.SelectorVisible)]

	[ARInvoiceType.RefNbr(typeof(Search3<PX.Objects.AR.Standalone.ARRegisterAlias.refNbr,
	InnerJoinSingleTable<ARInvoice, On<ARInvoice.docType, Equal<PX.Objects.AR.Standalone.ARRegisterAlias.docType>,
		And<ARInvoice.refNbr, Equal<PX.Objects.AR.Standalone.ARRegisterAlias.refNbr>>>,
	InnerJoinSingleTable<Customer, On<PX.Objects.AR.Standalone.ARRegisterAlias.customerID, Equal<Customer.bAccountID>>>>,
	OrderBy<Desc<ARRegister.refNbr>>>))]
	public virtual string UsrARRefNbr
	{
		get; set;
	}
}
1
Did you try calling Persist() instead of calling PressSave() ?cbetabeta
I debugged and it is not even reaching to that line. Its just from Update (line above) is calling another method and ending into loop.Krunal
I think HB_ACUMATICA provided the solution for this issue on his reply below.cbetabeta

1 Answers

2
votes

When saving, APInvoice_RowUpdated modifies ARInvoice which in turn modifies APInvoice which triggers APInvoice_RowUpdated producing an infinite loop of event calls. The inverse in ARInvoice_RowUpdated which updates APInvoice will result in a similar infinite loop.

To get out of this, you can remove the graph event handler at runtime after instantiating the graph. First make your event handler access modifier public so you can reference them:

public virtual void APInvoice_RowUpdated(PXCache sender, PXRowUpdatedEventArgs e) 

After creating a graph, get the extension and remove the handler that cause the infinite loop:

APInvoiceEntry graph = PXGraph.CreateInstance<APInvoiceEntry>();
APInvoiceEntryExtension graphExt = graph.GetExtension<APInvoiceEntryExtension>();
graphExt.RowUpdated.RemoveHandler<APInvoice>(graphExt.APInvoice_RowUpdated);

The same modification has to be done for ARInvoice because the infinite loop goes both way, from AP to AR and from AR to AP.