Solved

Override 'Create Service Order' action in Projects

  • 12 September 2022
  • 18 replies
  • 459 views

Userlevel 4
Badge +1

Hello,

I would like to override the ‘Create Service Order’ action from Projects, as shown below.

I’ve found the source code for the action in a class called DialogBoxSOApptCreation but I don’t know how to extend the class or override the action. The class and action definition are below.
 

public abstract class DialogBoxSOApptCreation<TExtension, TGraph, TMain> : PXGraphExtension<TExtension, TGraph>
        where TExtension : PXGraphExtension<TGraph>, new()
        where TGraph : PXGraph, new()
        where TMain : class, IBqlTable, new()
    {
        public CRValidationFilter<DBoxDocSettings> DocumentSettings;

        #region Actions
        #region CreateSrvOrdDocument
        public PXAction<TMain> CreateSrvOrdDocument;
        [PXButton]
        [PXUIField(DisplayName = "Create Service Order", MapEnableRights = PXCacheRights.Select, MapViewRights = PXCacheRights.Select)]
        public virtual IEnumerable createSrvOrdDocument(PXAdapter adapter)
        {
            bool requiredFieldsFilled = DocumentSettings.AskExtFullyValid((graph, view) => { SetDBoxDefaults(ID.PostDoc_EntityType.SERVICE_ORDER); }, DialogAnswerType.Positive, false);
            ShowDialogBoxAndProcess(requiredFieldsFilled);

            return adapter.Get();
        }
        #endregion

 

The class is abstract and, I think, uses generics. I don’t know how to handle these. Can anyone assist please?

Thanks

icon

Best answer by Nayan Mansinha 18 September 2022, 00:47

View original

18 replies

Badge +11

I haven’t tested this, but have you tried extending it in the ProjectEntry graph?

 

namespace ProjectTest
{
public class ProjectTest_ProjectEntry_Extension : PXGraphExtension<PX.Objects.PM.ProjectEntry>
{
public delegate IEnumerable CreateSrvOrdDocumentDelegate(PXAdapter adapter);

[PXOverride]
public virtual IEnumerable createSrvOrdDocument(PXAdapter adapter, CreateSrvOrdDocumentDelegate baseMethod)
{
baseMethod(adapter);

PXTrace.WriteInformation("!");

return adapter.Get();
}
}
}

 

Badge +11

Got curious enough to try it. Doesn’t work. This is as far as I got. The [PXOverride] doesn’t work, and I’m out of my depth if it’s acceptable to override it this way.

This could be entirely wrong. Abstraction and generics are not my strong suite either. Very curious what the correct answer is.

namespace ProjectTest
{
public class ProjectTest_ProjectEntry_Extension : SM_ProjectEntry_DBox
{
/*
public delegate IEnumerable CreateSrvOrdDocumentDelegate(PXAdapter adapter);

[PXOverride]
public virtual IEnumerable createSrvOrdDocument(PXAdapter adapter, createSrvOrdDocumentDelegate baseMethod)
{
baseMethod(adapter);

PXTrace.WriteInformation("!");

return adapter.Get();
}
*/
public override IEnumerable createSrvOrdDocument(PXAdapter adapter)
{
return base.createSrvOrdDocument(adapter);
}
}
}

 

Where’s the white wizard @nmansinha?

Userlevel 4
Badge +2

Source code suggests abstract class DialogBoxSOApptCreation is implemented by graph extension SM_ProjectEntry_DBox which is declared as follows:

 

	public class SM_ProjectEntry_DBox
: DialogBoxSOApptCreation<SM_ProjectEntry, ProjectEntry, PMProject>
{
public static bool IsActive()
{
return PXAccess.FeatureInstalled<FeaturesSet.serviceManagementModule>();
}
...

which suggests it extends not just ProjectEntry graph but also first level of SM_ProjectEntry graph extension.  We have 3 levels involved here and so in order to override, one must override all 3 levels as follows:

 

	public class MySM_ProjectEntry_DBox : PXGraphExtension<SM_ProjectEntry_DBox, SM_ProjectEntry, ProjectEntry>
{
public static bool IsActive()
{
return PXAccess.FeatureInstalled<FeaturesSet.serviceManagementModule>();
}

// overrides here

}

Good luck!

Badge +11

@nmansinha - Thank you for satistfying my curiosity 😀

 

I had started down that road but couldn’t figure out how to extend correctly. I believe I was using DialogBoxSOApptCreation in all of them, which isn’t a graph.

Userlevel 4
Badge +1

Hi @darylbowman and @nmansinha and thanks for replying to this problem. After not receiving a quick responce I assumed my question is either too easy or too difficult. I’ve progressed to the same solution as you both, finding the DialogBoxSOApptCreation and extending it.

The problem is that the abstract class DialogBoxSOApptCreation contains 3 abstract methods and these must be overridden. The code generated by visual studio is shown below.

    public class DialogBoxSOApptCreation_Ext : DialogBoxSOApptCreation<SM_ProjectEntry, ProjectEntry, PMProject>
{
public static bool IsActive() => PXAccess.FeatureInstalled<FeaturesSet.serviceManagementModule>();

public override void CreateDocument(ServiceOrderEntry srvOrdGraph, AppointmentEntry apptGraph, DBoxHeader header, List<DBoxDetails> details)
{
throw new NotImplementedException();
}

public override void PrepareDBoxDefaults()
{
throw new NotImplementedException();
}

public override void PrepareHeaderAndDetails(DBoxHeader header, List<DBoxDetails> details)
{
throw new NotImplementedException();
}
}

This leads to a new set of problems. I can add breakpoints to these methods and Visual Studio shows that the methods are called but if I comment out the throw commands then a Service Order isn’t created. I wouldn’t know how to begin writing the code for the CreateDocument method and I cannot understand how to find the code in the Acumatica base code.

But also, I don’t think that these 3 methods are needed for me to achieve my goal, which is to edit the Service Order after it’s been created from the Project. There is another method, also called CreateDocument, which returns an FSServiceOrder object. The signature is below, I’m pretty sure this is the method I need to overwrite but I cannot do this without doing something with the 3 abstract methods mentioned above.

public virtual FSServiceOrder CreateDocument(ServiceOrderEntry srvOrdGraph, AppointmentEntry apptGraph, string sourceDocumentEntity, string sourceDocType, string sourceDocRefNbr, int? sourceDocID, PXCache headerCache, PXCache linesCache, DBoxHeader header, List<DBoxDetails> details, bool createAppointment);

Can you provide any information about how to can override the abstract methods please?

Thanks

Steve

@stephenward03 - If you look a little closer, I think you'll find that Mansina's answer and provided code is nothing the same as yours. I may have led you down the wrong path. His code is a graph extension, where as mine and yours are not.

Badge +11

Oops, wrong account 🤓

Userlevel 4
Badge +1

Oh yes, thanks for pointing this out. I’ll go and try his idea and report back if I make progress. 

Userlevel 4
Badge +1

Hi again,

Just tested this with a graph extension and it’s working great. See the code below, the CreateDocument method is overridden with [PXOverride]. After the baseMethod is called I can access the created service order from the cache. Now I have access to the service order object I can manipulate it to meet the customer requirements.

public class DialogBoxSOApptCreation_Ext : PXGraphExtension<SM_ProjectEntry_DBox, SM_ProjectEntry, ProjectEntry>
{
public static bool IsActive() => PXAccess.FeatureInstalled<FeaturesSet.serviceManagementModule>();

public delegate void createDocument(ServiceOrderEntry srvOrdGraph, AppointmentEntry apptGraph, DBoxHeader header, List<DBoxDetails> details);
[PXOverride]
public void CreateDocument(ServiceOrderEntry srvOrdGraph, AppointmentEntry apptGraph, DBoxHeader header, List<DBoxDetails> details, createDocument baseMethod)
{
baseMethod(srvOrdGraph, apptGraph, header, details);
FSServiceOrder myServiceOrder = (FSServiceOrder)srvOrdGraph.Caches<PX.Objects.FS.FSServiceOrder>().Current;
}
}

Next I’m going to review the Acumatica source code to try and understand how/why @nmansinha knew to extend the SM_ProjectEntry_DBox graph.
Thanks again to @nmansinha and @darylbowman 

Steve

Userlevel 4
Badge +1

Hello,

I’m revisiting this issue to try to further my understanding of the Acumatica framework and hopefully resolve similar issues in future. My aim is to understand how to quickly get from the button on screen to overridding the correct method in code.
Just as a reminder, the aim was to be able to be able to access the service order generated from the Create Service Order action within a Project.

The screen above shows the pop up sceen which appears when the Create Service Order action is clicked. From here I click Create and Review, a service order is created and displayed.

It seems likely that the Create Service Order action will need overriding so wecan inspect the element...

This suggests the graph is ProjectEntry and the action name createSrvOrdDocument. The action name doesn’t quite fit but you can highlight the name by double clicking it and pasting to notepad.

From here I clicked on Actions and Customize Business Logic. This opens the customisation, where I clicked on the Override Method button and searched for createSrvOrdDocument.

createSrvOrdDocument doesn’t appear in the list so it was clear that something more complex was happening.

I wasn’t really sure what to do next and ended up searching the Acumatica source code for createSrvOrdDocument and found a PXAction called createSrvOrdDocument in DialogBoxSOApptCreation.

The class structure and PXAction are shown below.

    public abstract class DialogBoxSOApptCreation<TExtension, TGraph, TMain>
: PXGraphExtension<TExtension, TGraph>
where TExtension : PXGraphExtension<TGraph>, new()
where TGraph : PXGraph, new()
where TMain : class, IBqlTable, new()
{
public CRValidationFilter<DBoxDocSettings> DocumentSettings;

#region Actions
#region CreateSrvOrdDocument
public PXAction<TMain> CreateSrvOrdDocument;
[PXButton]
[PXUIField(DisplayName = "Create Service Order", MapEnableRights = PXCacheRights.Select, MapViewRights = PXCacheRights.Select)]
public virtual IEnumerable createSrvOrdDocument(PXAdapter adapter)
{
bool requiredFieldsFilled = DocumentSettings.AskExtFullyValid((graph, view) => { SetDBoxDefaults(ID.PostDoc_EntityType.SERVICE_ORDER); }, DialogAnswerType.Positive, false);
ShowDialogBoxAndProcess(requiredFieldsFilled);

return adapter.Get();
}

We can see that DialogBoxSOApptCreation inherits using PXGraphExtension.
We can also see the use of generics in the class types.

I think from here I went to the definition of ShowDialogBoxAndProcess, this led me to the CreateDocument method and the abstract methods.
At this point I was stuck and didn’t understand how to override the CreateDocument method. I did a lot of google searching and found something similar

public class DialogBoxSOApptCreation_Ext : DialogBoxSOApptCreation<SM_ProjectEntry, ProjectEntry, PMProject>

Although this solution wasn’t correct, due to the lack of PXGraphExtension, it was useful because I was able to replace generics arguments with specific types.

At this point I was completely stuck and turned to the community for help, and we now know that the correct answer is

public class DialogBoxSOApptCreation_Ext : PXGraphExtension<SM_ProjectEntry_DBox, SM_ProjectEntry, ProjectEntry>

So, whilst I now have some working code, I’m really not at all clear how we get from the element inspector for the createSrvOrdDocument action to the end solution. I was the following questions:
1.Am I missing something within the Acumatica software which would have pointed me to the class the createSrvOrdDocument action is defined (the idea of searching through the whole Acumatica source code doesn’t seem like the correct solution - fortunely createSrvOrdDocument didn’t appear much in the source code but other action names might appear much more.

2.After finding DialogBoxSOApptCreation, and the PXAction for createSrvOrdDocument, I was sure I had found the correct class to override. How would I have known to look for the SM_ProjectEntry_DBox extension, or what would have been the best way to check for class inheriting from DialogBoxSOApptCreation.

Do you have any advise on how you were able to get to the correct class to override?

Thanks

Steve

Badge +11

In my experience (though limited), most Action extensions / overrides you encounter will not be this complicated. It may be partially dependent what module you work in.

I am curious as well though. It is a breadcrumb trail at best from what I can see 😀

Userlevel 4
Badge +1

Overridding this specific action does seem to be a fairly complex example, certainly far from the examples in the training course.

I’m still not sure of a quick way to find an Action definition, other than searching for the action name in the whole Acumatica source code solution but in this example I can now see how I could have found to correct class to override. You probably know this already but it’s new to me.

By highlighting the class name and pressing ctrl+F12 you can see which classes have inherited from it. In this case only 2 classes are returned and I am interested in the ProjectEntry version, so it’s easy to spot the correct result.

Double clicking on the result takes you to the definition….

...and here you see the specific types, not the generics. There is now enough info here to override the graph extension. Although I still wouldn’t have thought to use PXGraphExtension at this point - probably because the Acumatica source code doesn’t use this keyword for SM_ProjectEntry_DBox.

Thanks

Steve

 

Userlevel 4
Badge +1

Hi again, @nmansinha and @darylbowman 
I’m getting around to using this code in a real project and whilst it does allow for the Create Service Order action to be overridden, it also stops Acumatica from working in the expected way. I’ll explain. 

Below is the minimum amount of code required to make things go wrong. 

using PX.Data;
using PX.Objects.PM;
using PX.Objects.FS;
using PX.Objects.CS;

namespace ProjItemsToServiceOrder
{
public class MySM_ProjectEntry_DBox : PXGraphExtension<SM_ProjectEntry_DBox, SM_ProjectEntry, ProjectEntry>
{
public static bool IsActive() => PXAccess.FeatureInstalled<FeaturesSet.serviceManagementModule>();
}
}

With this graph extension in place, the layout of the Project screen changes, unexpected buttons appear on the main toolbar and the rest of the buttons appear in the panel but without a category. Also the Status field becomes editable. 

If I remove the graph from the Visual Studio project and recompile then everything works as normal again, as shown below. 

I cannot understand why this is happening, could it be a bug in the system? Would either of you have the time to try the code above and see if you get the same problem? Or can you see a problem with the graph extension code I’m using?
Any feedback would be welcome. 

Thanks
Steve

Badge +11

The code you have there does not break the Projects for me in 2022 R2. That’s the only instance I have up right now.

Userlevel 4
Badge +1

hmm, I need to use the following on this project

Acumatica 2022 R1
Build 22.110.0018

Not sure what to try next

Badge +11

I’m sorry, I led you astray. I don’t have Service Management turned on, which means that extension never activates. It may not be working.

 

Userlevel 4
Badge +2

Hi again, @nmansinha and @darylbowman 
I’m getting around to using this code in a real project and whilst it does allow for the Create Service Order action to be overridden, it also stops Acumatica from working in the expected way.

Yes, I do see some kind of issue which breaks workflow code.  Suggest you change namespace to PX.Objects.FS and compile.  

And please create developer support case with us if issue continues.

Userlevel 4
Badge +1

Yes!
I’m really pleased to report that after I set the namespace to PX.Objects.FS the buttons all appear properly again, with Workflow looking good too. 
Setting the namespace is something I will need to properly consider in future.

Thank you both so much for helping with this. 

Reply


About Acumatica ERP system
Acumatica Cloud ERP provides the best business management solution for transforming your company to thrive in the new digital economy. Built on a future-proof platform with open architecture for rapid integrations, scalability, and ease of use, Acumatica delivers unparalleled value to small and midmarket organizations. Connected Business. Delivered.
© 2008 — 2024  Acumatica, Inc. All rights reserved