I have created a new CREATE QUOTE button on Requisition screen that replace the standard button which located at Action menu. After trying to hide it on RQRequisition_RowSelected event, the button still appear and able to click when the requisition is on Pending Quote Status. Kindly need advice how to hide it.
Customized Requisition Screen
To hide or show an action button, you should redefine the Visible parameter of the PXUIField attribute for the button.
You can change attributes of an action button by using one of the following approaches:
Dynamically at run time, in the Initialize() method of the graph
extension
Statically, by overriding the action attributes in the
graph extension
To Hide an Action Button at Run Time
In the graph extension, add the following code.
public override void Initialize()
{
base.Initialize();
Base.MyAction.SetVisible(false);
}
In the added code, replace MyAction with the action name.
To Hide or Show an Action Button Statically
To override action attributes in a graph extension statically, you should declare both the graph member of the PXAction type and the delegate. You should attach a new set of attributes to the action delegate, declared within the graph extension. Also, you need to invoke the Press() method on the base graph action. Having redeclared the member of PXAction, you prevent the action delegate execution from infinite loops.
Explore the original action declaration and copy the declaration to the graph extension.
In the action declaration, set to false the Visible parameter of the PXUIField attribute, as the following code snippet shows.
...
[PXUIField(…, Visible = false)]
...
Replace the action delegate with the following code template.
public virtual IEnumerable myAction(PXAdapter adapter)
{
return Base.MyAction.Press(adapter);
}
In the code template, replace myAction and MyAction with the appropriate names.
In the template, redefine the action delegate arguments and return type according to the signature of the base action delegate.
If you have a customization that replaces an original action
declaration statically, after upgrading Acumatica ERP to a new
version, a new functionality of the same action may became
unavailable.
Also, if a callback command for the button is declared in the PXDataSource control, you can hide the button by customizing the ASPX code. To do this, in the Layout Editor, expand the PXDataSource control, select the appropriate PXDSCallbackCommand element, and set to False the Visible property of the element.
CREATE QUOTE button on the Requisition screen is implemented like a normal action in the RQRequisitionEntry BLC:
public class RQRequisitionEntry : PXGraph<RQRequisitionEntry>
{
...
public PXAction<RQRequisition> createQTOrder;
[PXButton(ImageKey = PX.Web.UI.Sprite.Main.DataEntry)]
[PXUIField(DisplayName = Messages.CreateQuotation)]
public virtual IEnumerable CreateQTOrder(PXAdapter adapter)
{
...
}
...
}
However, CREATE QUOTE button is added into the Actions drop down via Automation Steps:
With that said, the best way to customize the CREATE QUOTE button is by re-declaring the action within the RQRequisitionEntry BLC extension following sample below. I would be happy to come up with a more specific sample, if you provide additional details regarding your request.
public class RQRequisitionEntryExt : PXGraphExtension<RQRequisitionEntry>
{
public PXAction<RQRequisition> createQTOrder;
[PXButton(ImageKey = PX.Web.UI.Sprite.Main.DataEntry)]
[PXUIField(DisplayName = RQ.Messages.CreateQuotation)]
public virtual IEnumerable CreateQTOrder(PXAdapter adapter)
{
return Base.createQTOrder.Press(adapter);
}
}
Related
Acumatica offers a great feature to Save as Template which makes creating new records from the template faster and easier. However, I have a use case where I need a more interactive sort of template in which the user can create a list of 100 items and then select which items to include when creating the new record.
In this case, the standard feature for Save as Template could be confusing, especially for new users learning the system. I have been asked to disable Save as Template on the Copy/Paste menu on my custom screen and transition to this new feature. I do not want to disable Copy/Paste entirely, just the Template functionality. If I disable Copy/Paste in Access Rights, the entire menu disappears. However, the template options do not appear in Access Rights.
Copy/Paste appears to be accessible via code as the PXAction CopyPaste which can be hidden or disabled, but again, I cannot find SaveTemplate as a child that I can control.
How can I disable/hide Save as Template (CopyPaste#SaveTemplate) on an Acumatica screen, either programmatically, in access rights, or in workflow? This menu is part of the standard Acumatica menu system when specifying a primary DAC when defining the graph. Alternatively, I think it enabled via the PXCopyPasteAction<> action if manually defining buttons on the page.
You can create your own PXCopyPasteAction by just extending the base class and then adding it to your graph
quick example below
public class CustomCopyPasteAction: PXCopyPasteAction<SOOrder>
{
public CustomCopyPasteAction(PXGraph graph, string name): base(graph, name) { }
protected override void RowSelected(PXCache cache, PXRowSelectedEventArgs e)
{
base.RowSelected(cache, e);
bmSaveTemplate.Enabled = false;
}
}
The CopyPaste action is coming predefined as part of the PXGraph<TGraph,TPrimary> class. So you should be able to just simply do CopyPaste.SetEnabled(false) in the RowSelected event handler of your graph.
Another option is to try to override the CanClipboardCopyPaste virtual function of the PXGraph class.
public class PXGraph<TGraph, TPrimary> : PXGraph where TGraph : PXGraph where TPrimary : class, IBqlTable, new()
{
public override bool CanClipboardCopyPaste()
{
return true;
}
/// <summary>The action that saves changes stored in the caches to the database. The code of an application graph typically saves changes through this action as well. To invoke it from code, use the PressSave() method of the Actions property.</summary>
public PXSave<TPrimary> Save;
/// <summary>The action that discard changes to the data from the caches.</summary>
public PXCancel<TPrimary> Cancel;
/// <summary>The action that inserts a new data record into the primary cache.</summary>
public PXInsert<TPrimary> Insert;
/// <summary>The action that deletes the Current data record of the primary cache.</summary>
public PXDelete<TPrimary> Delete;
/// <summary>The action that is represented on the user interface by an expandable menu that includes Copy and Paste items.</summary>
public PXCopyPasteAction<TPrimary> CopyPaste;
/// <summary>The action that navigates to the first data record in the primary data view. The data record is set to the Current property of the primary cache.</summary>
public PXFirst<TPrimary> First;
/// <summary>The action that navigates to the previous data record in the primary data view. The data record is set to the Current property of the primary cache.</summary>
public PXPrevious<TPrimary> Previous;
/// <summary>The action that navigates to the next data record in the primary data view. The data record is set to the Current property of the primary cache.</summary>
public PXNext<TPrimary> Next;
/// <summary>The action that navigates to the last data record in the primary data view. The data record is set to the Current property of the primary cache.</summary>
public PXLast<TPrimary> Last;
}
We are in to acumatica 20 r2 and when we publish the custom package, the default report menu print salesorder/quote option disappears.
We have custom reports which are added by overriding the initialize method of salesorderentry graph in my extension.
public override void Initialize()
{
base.Initialize();
base.Base.report.AddMenuAction(embroideryreport);
base.Base.report.AddMenuAction(embroiderysoreport);
base.Base.report.AddMenuAction(screenprintreport);
base.Base.report.AddMenuAction(screenprintsoreport);
}
I am not able to figure out the reason for missing report. I have upgraded the workflow to latest version and still having the issue.
UPDATE
I did not call base.Initialize() initially and since the default report is not coming, I thought it may be due to not invoking the base method.
I have tried bahaa-zantout suggestion and the base report is already tagged to the report menu and when I commented on the code in Initialize method for adding the report the default report appeared again under-report menu.
It looks like there is conflict in the workflow and I am not able to figure it out.
I have tried to add those report in the workflow action section and tagged them to Report and the entire report menu disappeared
Change you initialization method to....
public override void Initialize()
{
base.Base.report.AddMenuAction(embroideryreport);
base.Base.report.AddMenuAction(embroiderysoreport);
base.Base.report.AddMenuAction(screenprintreport);
base.Base.report.AddMenuAction(screenprintsoreport);
}
From Acumatica DEV documentation portal
You do not need to explicitly invoke the Initialize() method on the previous extension levels; these methods are called automatically. Invoking base.Initialize() makes no sense, because the base variable points to the base class, which is PXGraphExtension (not the base graph). The PXGraphExtension class defines Initialize() as an empty method.
You could attempt the following in attempt to restore the toolbar menu item.
Navigate to the Sales Order screen in the customization project
Go to the Actions
Locate the missing print options (ie. printSalesOrder) and place the Toolbar folder in the original folder in this case "Reports". If it doesn't work try moving to "Actions" and see if it appears.
See example screenshot.
I am not sure it is due to this statement or not but when I changed the following statement it fixed the issue
[PXButton(SpecialType = PXSpecialButtonType.ReportsFolder)]
to
[PXButton]
for Report action
public PXAction<SOOrder> embroideryreport;
[PXUIField(DisplayName = "Embroidery Production Report", MapEnableRights = PXCacheRights.Select)]
//[PXButton(SpecialType = PXSpecialButtonType.ReportsFolder)]
[PXButton]
I'm using Acumatica 2020R1 and I'm adding side panels. Is there anyway, for example on the PO form (PO301000), that I could link a side panel to update when clicking on the Document Details?
I actually discovered a way to do this on Acumatica 2020R1. Here's how I did it:
Edit: I did this for the SOOrderEntry screen, creating a side panel that looks at the SOOrder but uses parameters from the SOLine. This method will work for any two tables with a master-detail relationship by replacing SOOrder & SOLine accordingly.
Part A:
Create virtual fields on the SOOrder DAC that correlate to the SOLine Parameters you need
Update these as lines are selecting/updated using event handlers
pass these fields as the params to your side panel actions as you normally would
While It seems like this alone would work, the side panel actually doesn’t refresh when a new SOLine is selected. We’re going to have to get creative to resolve this issue.
Part B:
Create an additional virtual field on the SOOrder DAC to keep track of which side panel was last opened (I will explain how to track this later). I use a string field to do so. This is especially important if you have more than one side panel on your screen.
Next you want to define a standard graph action that will update this field. Make it Visible = false, since you don’t actually want this button to show. We will call if from behind the scenes later. This is the method I use:
public PXAction<SOOrder> SidePanelCallback;
[PXButton]
[PXUIField(DisplayName = "SidePanelCallback", Visible = false)]
public virtual IEnumerable sidePanelCallback(PXAdapter adapter)
{
SOOrder doc = Base.Document.Current;
if (doc == null) return adapter.Get();
var docExt = doc.GetExtension<SOOrderExt>();
docExt.UsrSidePanelDetailParamsRefresh = adapter.CommandArguments;
return adapter.Get();
}
*Note: docExt.UsrSidePanelDetailParamRefresh is the variable I for the previous step
Now you need a way to trigger your code when your side panel actions are called. To do this we’ll use the following JavaScript
function commandResult(ds, context) {
var ds = px_alls['ds'];
switch (context.command)
{
case ('JustAction'):
ds.executeCallback('GraphAction', 'parameter value');
break;
}
}
You want to replace JustAction with the internal name of your side panel action. it should look like this: NavigateToLayer$DB000028
where DB000028 is the target ScreenID for your sidepanel. If you want to make sure your actions follow the same naming convention, you can check it by adding breakpoints and checking with the debugger.
You should replace GraphAction with the name of the graph action you created in the previous step. In our case SidePanelCallback
Then finally for the parameter value pass whatever you’d like to use to identify the opened side panel. This will be stored in UsrSidePanelDetailParamRefresh, or your equivalent.
You can create a case statement for each side panel you want this functionality for, so you only have to do all this once per graph!
Then finally, attach your script to the client event ‘commandPerformed’ on your data source.
Next we will define another graph action to do the actual refresh of the side panel. Mine looks like this:
public PXAction<SOOrder> SidePanelRefresh;
[PXButton]
[PXUIField(DisplayName = "SidePanelRefresh", Visible = false)]
public virtual IEnumerable sidePanelRefresh(PXAdapter adapter)
{
SOOrder doc = Base.Document.Current;
if (doc == null) return adapter.Get();
var docExt = doc.GetExtension<SOOrderExt>();
Dictionary<string, string> parameters = new Dictionary<string, string>();
string[] args = adapter.CommandArguments.Split('*');
switch (docExt.UsrSidePanelDetailParamsRefresh)
{
case ("Component Inventory"):
parameters.Add("Kit", args[0]);
parameters.Add("SiteID", args[1]);
throw new PXRedirectToGIRequiredException("Component Inventory", parameters) { Mode = PXBaseRedirectException.WindowMode.Layer };
}
return adapter.Get();
}
Note that for my use case the parameters I am passing cannot contain the character ‘*’, so I use it as a delimiter
And again, you can define as many case statements as you need for each of your dynamic side panels.
And now finally we need javascript again to call this action. Using event handlers are too slow for this type of refresh, they will always pass the old SOLine parameters. If you know a way to avoid javascript here, I’d love to hear it, as doing callbacks like this does have a heavy overhead. Because of this, be careful where you attach this script to, I actually attach it to the grid’s RowSelectorClick client event rather than AfterRowChange for this reason, and train my users to select rows in this way (by clicking the arrow to the left of each row) so we don’t impact the rest of the company for the minority that use this feature. I’d recommend this if you're working on a high traffic screen such as SO301000.
Anyway, here’s the javascript:
function Side_Panel_Refresh() {
px_alls["ds"].executeCallback("SidePanelRefresh", this.func.caller.arguments[2].row.getCell("InventoryID").getValue() + "*" + this.func.caller.arguments[2].row.getCell("SiteID").getValue());
}
SidePanelRefresh: Name of our graph action from the previous step.
InventoryID & SiteID are my parameters.
And again, using ‘*’ as a delimiter.
Anyway, I hope this helps anyone looking to make dynamic side panels. If anyone has improvements on this method I’d love to hear constructive feedback.
Happy development!
It is a new feature. Side panel were restricted to generic inquiry. In version 2020 you still need a generic inquiry to configure the side panel but they can be viewed in data entry forms too.
The feature is implemented with wizards so it's pretty limited in what it can do. Currently you are limited to the choices available in navigation parameter. It seems like it's not possible to add details entity there. Maybe there's a way but I'm not aware of it.
Check documentation reference link for User Interface: Side Panels for Data Entry Forms (content copied below):
https://help-2020r1.acumatica.com/Help?ScreenId=ShowWiki&pageid=a11aa71b-5f18-4c8f-9c69-350f2c7a89f4
Adding a Side Panel to the Data Entry Form
A customizer can add multiple side panel navigation paths to a data entry form.
To add a side panel, the customizer navigates to the Customization Projects (SM204505) form and creates a new project.
In the Customization Project Editor, the customizer selects the screen for which the side panel is planned to be added.
On the Screens > Form ID > Actions, the customizer adds an action of the Navigation:
Side panel type (1), specifies general settings (2), adds destination screen (3), and specifies parameters (4), if needed (for instance, in the screenshot below, Business Account was selected as a parameter so that the side panel displayed the cases of the specific customer selected on the data entry form).
Example of a side panel on the Customers form
To apply the changes, the customizer must publish the created customization project.
Is it possible to display error in toolbar without using [PXProcessButton] and the delegate? I've overridden a Process Button in acumatica, but before it executes I have underlying codes to check a condition and fire an error if it find any.
There's not a lot of valid scenario where you have a PXProcessButton without a PXProcessing or PXFilteredProcessing data view. I would expect a PXButton to be used when there is no PXProcessing data view instead of a PXProcessButton.
With a PXProcessing view in the process screen you would do:
PXProcessing<DAC>.SetError(new PXException("Test));
There is no method that I know of that allows to directly set an error in the toolbar. You'll notice that these error are tied with a PXLongOperation. In the main toolbar you'll see the hourglass icon of the long operation and it can change to a success or error icon.
Process action does this but also Save action amongst others. Unless you require a long operation I would advise to avoid displaying error in the main toolbar because it's not a behavior found in the base Acumatica product.
That said you can replicate that functionality pretty much everywhere by throwing a PXExceptionfrom within a PXLongOperation inside an PXAction event handler like this:
public class SOOrderEntry_Extension : PXGraphExtension<SOOrderEntry>
{
public PXAction<SOOrder> test;
[PXUIField(DisplayName = "Test")]
[PXButton]
protected virtual IEnumerable Test(PXAdapter adapter)
{
PXLongOperation.StartOperation(Base, delegate {
throw new PXException("Test");
});
return adapter.Get();
}
}
As per title. A new action menu is automatically added to the bottom of the list. Is there a way to force them to appear on specific index or just before/after a specific action ?
Thanks in advance
In Automation Steps screen, in Actions tab you can find the button REORDER ACTIONS, this may help you.
PXGraph class has an action collections declared as:
public readonly PXActionCollection Actions;
It is a class deriving from .Net framework OrderedDictionary.
You can access it directly in your class deriving from PXGraph:
this.Actions
In the context of a graph extension deriving from PXGraphExtension it is available though Base member:
Base.Actions
Look at the public methods exposed by Actions, I think Move might be able to swap the Actions order in the menu. Here is some usage examples:
public PXAction<APInvoice> release;
public PXAction<APInvoice> prebook;
// Resolving name with static check
Base.Actions.Move(nameof(release), nameof(prebook));
// Using action display name with runtime check
Base.Actions.Move("Release", "Pre-book");