Skip to main content
Solved

Getting Error on 2022 R2 when closing Opportunity

  • 8 August 2023
  • 3 replies
  • 89 views

I have a problem when closing out an opportunity (OpportunityMaint) graph. 

It is giving the dreaded “Another process has added/updated/deleted the ‘{0}’ record. Your changes will be lost.”

In the past I have handled this by simply using:

PXTimeStampScope.SetRecordComesFirst(typeof(OpportunityMaint), true);

But I can’t figure out how to override the Closed as Won method. In source code, it seems Acumatica is now adding a “workflow” class but extending the OpportunityMaint class:

class OpportunityWorkflow : PX.Data.PXGraphExtension<OpportunityMaint>

And within that, it defines the options for closing an opportunity:

var formOpen = CreateForm("FormOpen", OpenReasons, OpportunityReason.Qualified);

var formWon = CreateForm("FormWon", WonReasons);

var formLost = CreateForm("FormLost", LostReasons);

 

But I can’t override it. 

I tried creating this:

 

  "PXOverride]
        public void CloseAsWon(PXAdapter adapter, Action<PXAdapter> baseMethod)
        {
            using (PXTimeStampScope ts = new PXTimeStampScope(null))
            {
                PXTimeStampScope.SetRecordComesFirst(typeof(OpportunityMaint), true);
                // Call the base CloseAsWon action logic.
                baseMethod?.Invoke(adapter);
            }
        }

 

Which compiles but errors out at runtime with an error:

Method Void CloseAsWon(PX.Data.PXAdapter, System.Action`1cPX.Data.PXAdapter]) in graph extension is marked as dPXOverride], but the original method with such name has not been found in PXGraph

 

What is the secret for overriding this? Anyone know?

The correct way to override an action involves a delegate:

public delegate void OriginalActionDelegate();

[PXOverride]
public void OriginalAction(OriginalActionDelegate baseMethod)
{
baseMethod();
}

But with further inspection, I found that the original action (from OpportunityMaint) looks like this:

public PXAction<CROpportunity> CloseAsWon;
[PXButton, PXUIField(DisplayName = "Close as Won", MapViewRights = PXCacheRights.Select, MapEnableRights = PXCacheRights.Update)]
protected virtual IEnumerable closeAsWon(PXAdapter adapter)
{
foreach (CROpportunity current in adapter.Get<CROpportunity>())
{
if (current != null)
{
CROpportunity.Events.Select(ev => ev.OpportunityWon).FireOn(this, current);
CROpportunity.Events.Select(ev => ev.OpportunityClosed).FireOn(this, current);
}
yield return current;
}
}

Since the override signature needs to match the original, the correct code to override the action should be this:

public delegate IEnumerable closeAsWonDelegate(PXAdapter adapter);

[PXOverride]
public IEnumerable closeAsWon(PXAdapter adapter, closeAsWonDelegate baseMethod)
{
// other code

var result = baseMethod(adapter);

// other code

return result;
}

One note is that in this particular situation, the original method is a protected method. This would ordinarily prevent it from being overridden (or rather require a more complicated override), but since it is also virtual, it is allowed to be overridden in derived classes.


Wow, Daryl… I owe you a beer for sure. Thank you so much for the help!


Sure thing. If you make it to the Summit this year, I’ll do my best to allow you to make good on that 😁


Reply