I'd like to add some custom code to the process of the Release Payments screen. If I create a customization project and add a Graph extension to the CODE section, I can't find any method with a name similar to 'Release Payments' to override in the list to select from (even though it exists as public in the BLC):
and if I try to manually code the override, I get an error that it can't find that method.
So basically, my question is, how do I intercept the process on the Release Payments screen?
I have had success with overriding the ARReleaseProcess.ReleaseDocProc like below. All the AR documents (invoices, payments, etc.) call the ARReleaseProcess.ReleaseDocProc during the release and that function does the main process. The below code is basically calling what that function was supposed to do and adding the delegate for when the release is completed.
public class ARReleaseProcessExt: PXGraphExtension<ARReleaseProcess>
{
public static bool IsActive()
{
return true;
}
public void OnReleaseComplete(ARRegister doc)
{
try
{
if (doc!=null && doc.DocType== ARDocType.Payment)
{
///ADD your code here
}
}
catch(Exception exc)
{
/// handler errors.
}
}
#region ReleaseDocProc
public delegate List<ARRegister> ReleaseDocProcDelegate(JournalEntry je, ARRegister ardoc, List<Batch> pmBatchList, ARDocumentRelease.ARMassProcessReleaseTransactionScopeDelegate onreleasecomplete);
[PXOverride]
public List<ARRegister> ReleaseDocProc(JournalEntry je, ARRegister ardoc, List<Batch> pmBatchList, ARDocumentRelease.ARMassProcessReleaseTransactionScopeDelegate onreleasecomplete, ReleaseDocProcDelegate del)
{
onreleasecomplete += OnReleaseComplete;
return del(je, ardoc, pmBatchList, onreleasecomplete);
}
#endregion
}
The override is a little different in case of AP module as the signature of the function is different there.
public class APReleaseProcess_Extension : PXGraphExtension<PX.Objects.AP.APReleaseProcess>
{
#region Event Handlers
public delegate List<APRegister> ReleaseDocProcDelegate(JournalEntry je, APRegister doc, Boolean isPrebooking, ref List<INRegister> inDocs);
[PXOverride]
public List<APRegister> ReleaseDocProc(JournalEntry je, APRegister doc, Boolean isPrebooking, ref List<INRegister> inDocs, ReleaseDocProcDelegate baseMethod)
{
var retVal = baseMethod(je,doc,isPrebooking,ref inDocs);
//Your code goes here.
PXTrace.WriteInformation("My override worked!");
return retVal;
}
#endregion
}
Good day
What is the correct way to change the below Release function to: first do the base function and only do your code?
When you use the built-in Acumatice "Override method"(that can be found when editing code) you get the following:
namespace PX.Objects.AR
{
public class ARPaymentEntry_Extension : PXGraphExtension<ARPaymentEntry>
{
#region Event Handlers
public delegate IEnumerable ReleaseDelegate(PXAdapter adapter);
[PXOverride]
public IEnumerable Release(PXAdapter adapter, ReleaseDelegate baseMethod)
{
//Normally you will add your code here.
return baseMethod(adapter);
}
#endregion
}
}
If you wanted the base to run fist and then you wanted your code after if would somthing like this:
namespace PX.Objects.AR
{
// Acuminator disable once PX1016 ExtensionDoesNotDeclareIsActiveMethod extension should be constantly active
public class ARPaymentEntry_Extension : PXGraphExtension<ARPaymentEntry>
{
#region Event Handlers
public delegate IEnumerable ReleaseDelegate(PXAdapter adapter);
[PXOverride]
public IEnumerable Release(PXAdapter adapter, ReleaseDelegate baseMethod)
{
baseMethod(adapter);
// your code here.
return;
}
#endregion
}
}
Question: What should I put as the return?
If I use null it gives a return nextstep error
public IEnumerable Release(PXAdapter adapter, ReleaseDelegate baseMethod)
{
IEnumerable result = baseMethod(adapter);
// your code here
return result;
}
gone through a variety of the articles, and none seem to "Work". In particular, 2021r1, not getting ANY of the PXTrace statement in the output
Challenge:
Static method of the graph directly called from ARPaymentEntry, and 4-5 overloads (From .\App_Data\CodeRepository\PX.Objects\AR\ARDocumentRelease.cs)
Eventually ends up calling a single method within that graph, starting with "public static void ReleaseDoc("
No clear place to add a delegate, though that seems the "most correct" method (E.g. question 37262565, comment from cbetabeta) - Yet the initialize event doesn't appear to be firing (possibly JIT optimization? Direct call into static method doesn't really need the class to be instantiated, I'd guess)
Also need a complete solution - e.g. Must handle the call from Payment Entry as well as from AR Document Release process
Sample Code:
using PX.Data;
using PX.Objects.AR;
using PX.Objects.GL;
using System.Collections;
using System.Collections.Generic;
using static PX.Objects.AR.ARDocumentRelease;
namespace Test.GraphExtensions
{
public class ARDocumentReleaseTestABC : PXGraphExtension<ARDocumentRelease>
{
// Tries include:
// https://html.developreference.com/article/11055300/How+to+customize+the+Process+button+on+the+AP505200+screen.+Acumatica
// https://stackoverflow.com/questions/36784480/customize-release-ap-document-in-acumatica-system
// https://stackoverflow.com/questions/37262565/how-can-i-execute-code-from-the-release-release-all-buttons-in-the-release-ar
// https://living-sun.com/es/acumatica/2179-extend-arpaymententry-release-action-acumatica.html
#region IsActive - Turn off if no setup record
public static bool IsActive()
{
return true;
}
#endregion IsActive - Turn off if no setup record
public virtual void BalancedARDocument_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
PXTrace.WriteVerbose(string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}", "dc1703c7-f8b7-4ce1-b838-d51475f4d477"));
}
public override void Initialize()
{
PXTrace.WriteVerbose(string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}", "8ecc4f83-9ac8-4bb6-bad7-ac2aabc5b58e"));
}
public static void ReleaseDocRBRR(ARRegister ardoc, bool isAborted)
{
PXTrace.WriteVerbose(string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0} {1} {2}", "20ae0d5e-44eb-42f2-ad15-0b9e307d2a86", isAborted, (ardoc == null)));
}
[PXUIField(DisplayName = "Release", MapEnableRights = PXCacheRights.Update, MapViewRights = PXCacheRights.Update)]
[PXProcessButton]
// [PXOverride]
public virtual IEnumerable Release(PXAdapter adapter)
{
PXTrace.WriteVerbose(string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}", "0ccff0b7-7702-4083-b717-17b031e27be5"));
List<ARRegister> list = new List<ARRegister>();
return list;
}
}
}
The proper place to override is either ARReleaseProcess.OnBeforeRelease if you need your code to fire before the release code or ARReleaseProcess.ReleaseDocProc.
Also, if you just need to run your code after the release, it is recommended that you add your code to onreleasecomplete Delegate in ARReleaseProcess.ReleaseDocProc.
Also, if you just need to run your code after the document release and you do not necessarily need to have it run exactly in the same transaction, please consider adding a separate process that picks up released documents and processes them further. You can either schedule that process ti run in the backgroud every minute or put a trigger with Business Events.
I think its the namespace that is the issue:
namespace PX.Objects.AR
{
public class ARDocumentRelease_Extension : PXGraphExtension<ARDocumentRelease>
{
#region Event Handlers
public override void Initialize()
{
PXTrace.WriteVerbose(string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}", "8ecc4f83-9ac8-4bb6-bad7-ac2aabc5b58e"));
}
#endregion
}
}
Seems I had a variety of issues, in particular was an extension to the wrong graph. Hooking up with Dmitrii's answer, I indicate at least some of the events that are hit, so others can use in the future
Code modified per #dmitrii-naumov's answer:
using PX.Data;
using PX.Objects.AR;
using PX.Objects.GL;
using System.Collections.Generic;
namespace Test.ABCD
{
public class ARDocumentReleaseTestABCD : PXGraphExtension<ARReleaseProcess>
{
#region IsActive - Turn off if no setup record
public static bool IsActive()
{
return true;
}
#endregion IsActive - Turn off if no setup record
public override void Initialize()
{
// Hit
PXTrace.WriteVerbose(string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}", "8ecc4f83-9ac8-4bb6-bad7-ac2aabc5b58e"));
}
public delegate List<ARRegister> ReleaseDocProcDelegate(JournalEntry je, ARRegister ardoc, List<Batch> pmBatchList, ARDocumentRelease.ARMassProcessReleaseTransactionScopeDelegate onreleasecomplete);
[PXOverride]
public List<ARRegister> ReleaseDocProc(JournalEntry je, ARRegister ardoc, List<Batch> pmBatchList, ARDocumentRelease.ARMassProcessReleaseTransactionScopeDelegate onreleasecomplete, ReleaseDocProcDelegate del)
{
// Hit
PXTrace.WriteVerbose(string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}", "8f153b0b-dd57-4893-aa8c-d29ea69528e4"));
PXTrace.WriteVerbose(string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}", "9b1caa30-5abf-4f21-8c45-a55c4047441a"));
return null;
}
[PXOverride]
public virtual ARRegister OnBeforeRelease(ARRegister ardoc)
{
// Hit
PXTrace.WriteVerbose(string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}", "741a01ad-5a37-40a8-ad10-a1fcd6659f7e"));
PXTrace.WriteVerbose(string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}", "9b1caa30-5abf-4f21-8c45-a55c4047441a"));
return ardoc;
}
}
}
This version implements OnReleaseComplete, from code Dmitrii provided to me (I'll take the blame for mistakes, but he got the event hooked up correctly, so do get the OnComplete event displayed in the log):
public class ARDocumentReleaseTESTABC : PXGraphExtension<ARReleaseProcess>
{
#region IsActive
public static bool IsActive()
{
return true;
}
#endregion IsActive
public void OnReleaseComplete(ARRegister doc)
{
///code
PXTrace.WriteVerbose(string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}", "7d22cef8-c14d-4111-bcc5-405be006ea6b"));
}
#region ReleaseDocProc
public delegate List<ARRegister> ReleaseDocProcDelegate(JournalEntry je, ARRegister ardoc, List<Batch> pmBatchList, ARDocumentRelease.ARMassProcessReleaseTransactionScopeDelegate onreleasecomplete);
[PXOverride]
public List<ARRegister> ReleaseDocProc(JournalEntry je, ARRegister ardoc, List<Batch> pmBatchList, ARDocumentRelease.ARMassProcessReleaseTransactionScopeDelegate onreleasecomplete, ReleaseDocProcDelegate del)
{
PXTrace.WriteVerbose(string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}", "d508b521-976c-452b-9765-57f532a0a513"));
onreleasecomplete += OnReleaseComplete;
PXTrace.WriteVerbose(string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}", "309e2e6b-6fb8-4c75-ab8a-40e56c173562"));
return del(je, ardoc, pmBatchList, onreleasecomplete);
}
#endregion
}
I am trying to customize the Release Cash Transactions screen and I am using this way to be able to call the Persist method, however when I release a record it does not enter the method specified above.
Here I am showing my code that if it works correctly for AP and AR.
I am doing the same for CA.
Could you help me that I'm wrong. Thanks for your help beforehand.
public class CAReleaseProcess_Extension : PXGraphExtension<CAReleaseProcess>
{
#region Custom
private WeakReference<JournalEntry> je;
public override void Initialize()
{
base.Initialize();
PXGraph.InstanceCreated.AddHandler<JournalEntry>(delegate (JournalEntry graph)
{
je = new WeakReference<JournalEntry>(graph);
});
}
public delegate void PersistDelegate();
[PXOverride]
public void Persist(PersistDelegate baseMethod)
{
CASplit doc = Base.CASplits.Current;
ActualizarCATaxTran(doc);
baseMethod();
}
public virtual void ActualizarCATaxTran(CASplit doc)
{
foreach (CATaxTran iTaxTran in Base.CATaxTran_TranType_RefNbr.Select(doc.AdjTranType, doc.AdjRefNbr))
{
if (iTaxTran != null)
{
//do something
}
}
}
#endregion
}
CA502000
I want to execute some code (to change the shipment date) upon the 'Confirm Shipment' action on the Shipments screen (SO302000).
I was thinking that this would be the way to do it:
public class SOShipmentEntryExt : PXGraphExtension<SOShipmentEntry>
{
[PXOverride]
public virtual void ConfirmShipment(SOOrderEntry docgraph, SOShipment shiporder)
{
Base.ConfirmShipment(docgraph, shiporder);
//Add my code to do something here...
}
}
When I try this, I get a shipment counter error. Is there a better way to do this?
From a similar case:
How to add custom business logic to Acumatica framework's Actions?
public class SOShipmentEntryExt : PXGraphExtension<SOShipmentEntry>
{
public PXAction<SOShipment> action;
[PXButton]
[PXUIField(DisplayName = "Actions", MapEnableRights = PXCacheRights.Select)]
protected IEnumerable Action(PXAdapter adapter
,[PXIntList(new int[] { 1 }
,new string[] { "Confirm Shipment" })
,PXInt] int? actionID)
{
//actionID = 1 means the Confirm Shipment action was the one invoked
if (actionID == 1)
{
Base.Document.Current.ShipDate = Base.Accessinfo.BusinessDate;
Base.Document.Update(Base.Document.Current);
}
//calls the basic action that was invoked
return Base.action.Press(adapter);
}
}