Extending Prepayment validation to RM behaviour order types
I’m attempting to extend the out of the box functionality for Prepayment validation to RM behaviour order types. It currently only works for SO behaviour order types.
So far I have overridden the CreatePaymentExt.GetRequiredPrepaymentEnabled function and I’ve overridden the PXFormula attribute for the SOOrder.PrepaymentReqPct field.
That part is working fine, but I’m now hung up on the the following two functions that are implemented as extension methods on the SOOrder DAC class.
I don’t believe it’s possilbe in CSharp, to override extension methods, unless there is something specific to the Acumatica framework I’m not aware of.
I was trying to override the AffectedSOOrdersWithPrepaymentRequirementsBase which calls those two extension methods, but I have not yet found a working override. It compiles, but does not seem like it is ever being executed.
Here’s my attempt so far.
namespace PX.Objects.SO.GraphExtensions.SOOrderEntryExt { public abstract class AffectedSOOrdersWithPrepaymentRequirementsBaseExt<TSelf, TGraph> : AffectedSOOrdersWithPrepaymentRequirementsBase<TSelf, TGraph> where TSelf : ProcessAffectedEntitiesInPrimaryGraphBase<TSelf, TGraph, SOOrder, SOOrderEntry> where TGraph : PXGraph {
Any ideas on the proper override or a different approach?
Scott
Page 1 / 1
After researching this more, it looks like the AffectedSOOrdersWithPrepaymentRequirementsExt extension is the correct one to override. I have the following code to override that extension, which compiles, but It it never executed when I debug. Any ideas on overriding this specific extension?
// Acuminator disable once PX1016 ExtensionDoesNotDeclareIsActiveMethod extension should be constantly active PXProtectedAccess(typeof(AffectedSOOrdersWithPrepaymentRequirementsExt))]
public abstract class AffectedSOOrdersWithPrepaymentRequirementsExtExt : PXGraphExtension<AffectedSOOrdersWithPrepaymentRequirementsExt, ARPaymentEntry> {
The PXOverride in your code is declared on the protected method ProcessAffectedEntity. Acumatica platform does not recognize protected methods as overrides, the ProcessAffectedEntity method should be a public method.
Also make sure that the method you are overriding is not static and that it does not declare any generic parameters. Acumatica platform does not support overriding of static or generic methods. The base method also should be virtual and have either public or protected access modifier.
@scottstanaland12 , I’m not entirely sure, but it seems to me that the PXProtectedAccess mechanism is declared incorrectly in your code.
Nothing should be passed to the PXProtectedAccess attribute declared on the graph extension class itself. And, if the ProcessAffectedEntity method is declared in the graph extension AffectedSOOrdersWithPrepaymentRequirementsExt, then you need to pass the extension type to the PXProtectedAccess attribute placed on the abstract method ProcessAffectedEntity that represents the protected method ProcessAffectedEntity from the base graph extension. The code should look like this:
namespace PX.Objects.SO.GraphExtensions.ARPaymentEntryExt { // Acuminator disable once PX1016 ExtensionDoesNotDeclareIsActiveMethod extension should be constantly active /PXProtectedAccess] public abstract class AffectedSOOrdersWithPrepaymentRequirementsExtExt : PXGraphExtension<AffectedSOOrdersWithPrepaymentRequirementsExt, ARPaymentEntry> {
Update about the overrides of graph methods with PXOverride attribute. I had a small mistake. The overriding methods must be public but they don’t have to be virtual. You can declare overriding methods as normal, not virtual methods as well. I’ve updated the original comment.
@snikomarov36 Thanks for your suggestions. I believe I made all your suggested changes, my current code is included below.
My overidden, ProcessAffectedEntity function is still never being called when I debug.
The AffectedSOOrdersWithPrepaymentRequirementsExt extension does not override that method, it’s in the AffectedSOOrdersWithPrepaymentRequirementsBase class. Should my override still work in this case? I included the code for the AffectedSOOrdersWithPrepaymentRequirementsExt extension in the second code block.
// Acuminator disable once PX1016 ExtensionDoesNotDeclareIsActiveMethod extension should be constantly active cPXProtectedAccess] //typeof(AffectedSOOrdersWithPrepaymentRequirementsExt))]
public abstract class AffectedSOOrdersWithPrepaymentRequirementsExtExt : PXGraphExtension<AffectedSOOrdersWithPrepaymentRequirementsExt, ARPaymentEntry> {
public delegate void ProcessAffectedEntityDelegate(SOOrderEntry orderEntry, SOOrder order);
>PXOverride] public virtual void ProcessAffectedEntity(SOOrderEntry orderEntry, SOOrder order, ProcessAffectedEntityDelegate baseMethod) { if (order.CuryPaymentOverall >= order.CuryPrepaymentReqAmt) order.SatisfyPrepaymentRequirementsAHS(orderEntry); else order.ViolatePrepaymentRequirementsAHS(orderEntry); }
} }
public class AffectedSOOrdersWithPrepaymentRequirementsExt : AffectedSOOrdersWithPrepaymentRequirementsBase<AffectedSOOrdersWithPrepaymentRequirementsExt, ARPaymentEntry> { public static bool IsActive() { return PXAccess.FeatureInstalled<FeaturesSet.distributionModule>(); } }
Hi @scottstanaland12 .
I don’t understand what do you want to achieve. Are you trying to override the existing virtual method ProcessAffectedEntity on the base graph or base graph extension?
In that case you should go with the PXOverride approach, You don’t need PXProtectedAccess mechanism at all, you can delete it, and make the extension non abstract
public class AffectedSOOrdersWithPrepaymentRequirementsExtExt : PXGraphExtension<AffectedSOOrdersWithPrepaymentRequirementsExt, ARPaymentEntry> { public delegate void ProcessAffectedEntityDelegate(SOOrderEntry orderEntry, SOOrder order); PXOverride] public virtual void ProcessAffectedEntity(SOOrderEntry orderEntry, SOOrder order, ProcessAffectedEntityDelegate baseMethod) { ... } }
@snikomarov36 Really appreciate your continued help.
I tried the PXOverride approach as you suggested in your last post with the same results. It compiles, but that method is never executed when I debug.
The end goal is to be able to modify the base functionality of the Prepayment required credit terms option to work for order behaviour RM as well as SO. See the screenshots below. The two SO order extension methods highlighted in the screenshots have conditions that only apply to SO behaviour orders.
Hi @scottstanaland12,
Thanks, the context is much clearer for me now, especially with screenshots. The syntax highlighting of the code snippets unfortunately is not perfect. It would be helpful if you could provide a screenshot of your extension too.
It also may be useful to know where the ProcessAffectedEntity method is called. If there are only a couple of call sites, and it is impossible to override the method itself, you can try to override the call sites. But that should be your last option.
Now about the context you have provided.
PXProtectedAccess Mechanism
First of all, it really looks like you don’t need the PXProtectedAccess mechanism at all. This functionality is needed when you have a graph extension, and you need to call the protected member of the Base graph without any overriding.
Here are some details about why we even need this mechanism:
From the C# POV graph extension and its base graph are not related, a graph extension is not derived from its base graph. Hence, graph’s protected members are not accessible to it. Before the PXProtectedAccess mechanism developers had to resort to using reflection to access protected graph members (and you still can), and it was a rather inconvenient approach. So, the PXProtectedAccess mechanism was added to simplify this task.
You only need to override only the ProcessAffectedEntity protected method. You don’t need to call other protected methods from the base graph, so you should not bother with PXProtectedAccess.
@scottstanaland12 here is the continuation.
PXOverride Approach
What you are trying to do should be possible with the PXOverride mechanism. The ProcessAffectedEntity method is virtual and protected. So, it should be possible to override it with the PXOverride mechanism.
However, overriding this method can be tricky because of the complex graph extension class hierarchy and especially because of the TSelf type parameter. This parameter represents the final most derived type of a graph extension derived from the base ProcessAffectedEntitiesInPrimaryGraphBase extension.
It makes it difficult to override the ProcessAffectedEntity method in the abstract base extension class AffectedSOOrdersWithPrepaymentRequirementsBase. Usually, I would advice to declare a chained 2nd level graph extension that would extend the AffectedSOOrdersWithPrepaymentRequirementsBase. Such extension would be abstract, and declare same generic type parameters with same constraints as the AffectedSOOrdersWithPrepaymentRequirementsBase class. You would declare the PXOverride in that extension and then create trivial graph extensions derived from it for each screen than needs to be extended.
However, due to the TSelf type parameter you can’t do that. It’s unclear what should be passed to this parameter because your chained extension and its inheritors are not derived from the ProcessAffectedEntitiesInPrimaryGraphBase extension. They won’t satisfy the generic type constraint.
So, extending the AffectedSOOrdersWithPrepaymentRequirementsBase extension itself is not a good idea.
@scottstanaland12 fortunately, you can come with the PXOverride mechanism from a different angle.
From what I can see in the source code, the AffectedSOOrdersWithPrepaymentRequirementsBase extension has two trivial derived extensions that extend particular graphs and have all their type parameters specified. I usually call such extensions concrete extensions for brevity. Here they are:
There are only two concrete extensions. You can declare a graph extension with PXOverride for each of them. In this case I believe you don’t need any complex type parameters and a simple chained graph extension will do. Here is an example:
public class MyExt : PXGraphExtension<AffectedSOOrdersWithPrepaymentRequirementsExt, ARPaymentEntry> { >PXOverride] public virtual void ProcessAffectedEntity(SOOrderEntry orderEntry, SOOrder order, Action<SOOrderEntry, SOOrder> baseMethod) { // Note that it's a good practice to extend the logic with // some extra cases and call the baseMethod delegate // for the cases handled by the base method's logic. ... } }