I am working on a process screen with an Action drop-down and a selector. I want the selector to display values based on Action selected.
For example, I have an Action drop-down of two values 1. Prepare and Release Invoice and 2. Print COnsolidated Invoice and selector which shows Sales orders with Completed status when the first Action is selected. Can anyone give me an idea on how to implement this? Below is my filter table with Action and a selector fields.
[Serializable()]
public partial class ImportInvoiceFilter : PX.Data.IBqlTable
{
public const string PrintConsolidatedInvoice = "PCI";
public const string PrepareAndReleaseInvoice = "PRI";
public class prepareAndReleaseInvoice : Constant<string> { public prepareAndReleaseInvoice() : base(PrepareAndReleaseInvoice) { } }
public class printConsolidatedInvoice : Constant<string> { public printConsolidatedInvoice() : base(PrintConsolidatedInvoice) { } }
#region ReferenceID
[PXString(30, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "Customer Reference Nbr")]
[PXSelector(typeof(Search<SOOrder.customerRefNbr,
Where<Where2<Where<SOOrder.status,
Equal<SOOrderStatus.open>,
And<Current<ImportInvoiceFilter.selectAction>,
Equal<ImportInvoiceFilter.prepareAndReleaseInvoice>>>,
Or<Where2<Where<SOOrder.status,
Equal<SOOrderStatus.completed>>,
And<Current<ImportInvoiceFilter.selectAction>,
Equal<ImportInvoiceFilter.printConsolidatedInvoice>>>>>>>),
typeof(SOOrder.orderNbr),typeof(SOOrder.orderDesc),
typeof(SOOrder.customerRefNbr))]
public virtual string ReferenceID { get; set; }
public abstract class referenceID : IBqlField { }
#region SelectAction
public abstract class selectAction : PX.Data.IBqlField
{
}
protected string _SelectAction;
[PXUIField(DisplayName = "Select ")]
[PXStringList(new string[] { PrepareAndReleaseInvoice, PrintConsolidatedInvoice },
new string[] { "Prepare and Release Invoice", "Print Consolidated Invoice" })]
[PXDefault(PrepareAndReleaseInvoice)]
public virtual string SelectTemplate
{
get
{
return this._SelectAction;
}
set
{
this._SelectAction = value;
}
}
#endregion
}
ASPX:
<%# Page Language="C#"
MasterPageFile="~/MasterPages/FormDetail.master"
AutoEventWireup="true" ValidateRequest="false"
CodeFile="KN506000.aspx.cs" Inherits="Page_KN506000" Title="Untitled
Page" %>
<%# MasterType VirtualPath="~/MasterPages/FormDetail.master" %>
<asp:Content ID="cont1" ContentPlaceHolderID="phDS" Runat="Server">
<px:PXDataSource ID="ds" runat="server" Visible="True" Width="100%"
PrimaryView="Filter" TypeName="KNLANOrderProcess.OrderInvoiceProcess">
</px:PXDataSource>
</asp:Content>
<asp:Content ID="cont2" ContentPlaceHolderID="phF" Runat="Server">
<px:PXFormView ID="form" runat="server" DataSourceID="ds" Style="z-
index: 100"
Width="100%" DataMember="Filter">
<Template>
<px:PXLayoutRule runat="server" ID="CstPXLayoutRule8" StartColumn="True" ></px:PXLayoutRule>
<px:PXDropDown runat="server" ID="CstPXDropDown10" DataField="SelectTemplate" CommitChanges="True" ></px:PXDropDown>
<px:PXSelector runat="server" ID="CstPXSelector9" DataField="ReferenceID" CommitChanges="True" AutoRefresh="True" ></px:PXSelector></Template>
</px:PXFormView>
</asp:Content>
<asp:Content ID="cont3" ContentPlaceHolderID="phG" Runat="Server">
<px:PXGrid ID="grid" runat="server" DataSourceID="ds" Style="z-index: 100"
Width="100%" Height="150px" SkinID="Details" TabIndex="300"
TemporaryFilterCaption="Filter Applied">
<EmptyMsg ComboAddMessage="No records found.
Try to change filter or modify parameters above to see records here."
NamedComboMessage="No records found as '{0}'.
Try to change filter or modify parameters above to see records here."
NamedComboAddMessage="No records found as '{0}'.
Try to change filter or modify parameters above to see records here."
FilteredMessage="No records found.
Try to change filter to see records here." FilteredAddMessage="No records
found.
Try to change filter to see records here." NamedFilteredMessage="No
records found as '{0}'.
Try to change filter to see records here." NamedFilteredAddMessage="No
records found as '{0}'.
Try to change filter to see records here." AnonFilteredMessage="No records
found.
Try to change filter to see records here." AnonFilteredAddMessage="No
records found.
Try to change filter to see records here."></EmptyMsg>
<Levels>
<px:PXGridLevel DataKeyNames="OrderType,OrderNbr,LineNbr"
DataMember="ImportInvoiceList">
<Columns>
<px:PXGridColumn DataField="OrderType">
</px:PXGridColumn>
<px:PXGridColumn DataField="OrderNbr">
</px:PXGridColumn>
<px:PXGridColumn DataField="OrderQty" TextAlign="Right" Width="100px">
</px:PXGridColumn></Columns>
</px:PXGridLevel>
</Levels>
<AutoSize Container="Window" Enabled="True" MinHeight="150" ></AutoSize>
</px:PXGrid>
</asp:Content>
Sample Screen:
Graph:
public class OrderInvoiceProcess : PXGraph<OrderInvoiceProcess>
{
#region Views
public PXCancel<ImportInvoiceFilter> Cancel;
public PXFilter<ImportInvoiceFilter> Filter;
[PXFilterable]
public PXFilteredProcessing<SOOrder, ImportInvoiceFilter> ImportInvoiceList;
public PXSelect<SOOrder, Where<SOOrder.customerRefNbr, Equal<Current<ImportInvoiceFilter.referenceID>>
>> SOOrders;
#endregion
public OrderInvoiceProcess()
{
ImportInvoiceList.SetProcessCaption("Process");
ImportInvoiceList.SetProcessVisible(false);
ImportInvoiceList.SetProcessAllCaption("Process ALL");
ImportInvoiceFilter currentFilter = this.Filter.Current;
ImportInvoiceList.SetProcessDelegate(
delegate (List<SOOrder> list)
{
ProcessOrders(list, currentFilter, true);
});
}
public IEnumerable importInvoiceList()
{
PXSelectBase<SOOrder> ImportOrderListBase = null;
ImportInvoiceFilter currentInquiryfilter = Filter.Current;
if (currentInquiryfilter != null && !string.IsNullOrEmpty(currentInquiryfilter.SelectTemplate))
{
switch (currentInquiryfilter.SelectTemplate)
{
case ImportInvoiceFilter.PrepareAndReleaseInvoice:
ImportOrderListBase = new PXSelectJoin<SOOrder, LeftJoin<SOOrderShipment, On<SOOrder.orderNbr,
Equal<SOOrderShipment.orderNbr>>>, Where2<Where<SOOrderShipment.confirmed, Equal<True>,
And<Where<SOOrderShipment.invoiceNbr, IsNull, And<SOOrder.customerRefNbr, Equal<Current<ImportInvoiceFilter.referenceID>>>>>>,
And<Where<SOOrder.orderType, Equal<salesOrderTypeRO>,
Or<SOOrder.orderType, Equal<salesOrderTypeCO>>>>>>(this);
return ImportOrderListBase.Select();
case ImportInvoiceFilter.PrintConsolidatedInvoice:
break;
}
}
return ImportOrderListBase.Select();
}
}
EDIT:
The other issue was that you were missing the base type attribute on the SelectAction field. You only had PXStringList:
[PXStringList(new string[] { PrepareAndReleaseInvoice, PrintConsolidatedInvoice },
new string[] { "Prepare and Release Invoice", "Print Consolidated Invoice" })]
PXStringList is not a base type so you should add the PXString attribute which is the base type:
[PXString(30, IsUnicode = true, InputMask = "")]
[PXStringList(new string[] { PrepareAndReleaseInvoice, PrintConsolidatedInvoice },
new string[] { "Prepare and Release Invoice", "Print Consolidated Invoice" })]
You can use your DAC filter field (selectAction) in the selector BQL query to filter the selector data based on your filter field:
[PXSelector(typeof(Search<SOOrder.orderNbr,
Where<Where2<Where<SOOrder.status, Equal<SOOrderStatus.open>, And<Current<SOImportFilter.selectAction>, Equal<SOImportFilter.createandConfirmShipment>>>,
Or<Where2<Where<SOOrder.status, Equal<SOOrderStatus.completed>>, And<Current<SOImportFilter.selectAction>, Equal<SOImportFilter.printInvoice>>>>>>>
In the above BQL request the logic of the where clause is equivalent to:
If (sales order status is open And select action is create and confirm shipment)
Or (sales order status is completed And select action is print invoice)
You can tweak it with your own rules.
For this filter to work you need to handle refresh behavior with CommitChanges and AutoRefresh properties on the ASPX controls.
You need CommitChanges set to true to send back the filter DAC modifications to the business layer as soon as the user change it:
// In a Grid
<px:PXGridColumn DataField="SelectAction" CommitChanges="True" />
// In a Form or in the RowTemplate of the Grid
<px:PXDropDown runat="server" ID="edSelectAction" DataField="SelectAction" CommitChanges="True" />
For the Sales Order selector you need AutoRefresh set to true so that the BQL query of the selector is executed every time the user opens the selector instead of using the stale values from cache:
// In a Grid RowTemplate element
<px:PXGridLevel DataMember="YourDataView"
<RowTemplate>
<px:PXSelector runat="server" ID="edSalesOrderSelector" DataField="SalesOrderSelector" AutoRefresh="True" />
</RowTemplate>
<Columns>
<px:PXGridColumn DataField="SalesOrderSelector" CommitChanges="True" />
</Columns>
</px:PXGridLevel>
// In a Form
<px:PXSelector runat="server" ID="edSalesOrderSelector" DataField="SalesOrderSelector" AutoRefresh="True" />
I want to pop up a smart panel that forces input before the OK button can be pressed. I've tried setting the button itself to disabled, linking it to the BLC through a PXButton declaration and setting it to disabled there, and setting the PXUIField Enabled = false on the PXAction/PXButton declaration in the BLC, but none of it works. Every time the option popup opens, the OK button starts enabled. Here are my code segments:
ASPX:
<px:PXButton Enabled="False" AlignLeft="False" runat="server" ID="CstButton13" Text="OK" CommandSourceID="ds" CommandName="DialogOptionPopupOk" DialogResult="OK"></px:PXButton>
PXAction Declaration:
public PXAction<PMProject> dialogOptionPopupOk;
[PXUIField(DisplayName = "OK", Enabled = false)]
[PXButton]
public virtual void DialogOptionPopupOk()
{ //No logic needed, only here to handle enable/disable of option popup ok button
}
Popup DAC Row Selected:
protected void OptionPopup_RowSelected(PXCache cache, PXRowSelectedEventArgs e)
{
dialogOptionPopupOk.SetEnabled(false);
}
Popup when opened:
You could add a new unbound Field of type PXBool. (EX. :IsButtonVisible )
Then you could use the Statecolumn property and the DependOnGrid property on the PXButton(ASPX):
.................
<px:PXPanel runat="server" SkinID="Buttons" ID="CstPanel11">
<px:PXButton runat="server" Text="Add" CommandName="AddRows" DialogResult="OK" CommandSourceID="ds" ID="CstButton12" DependOnGrid="CstPXGrid14" StateColumn="IsButtonVisible" ></px:PXButton>
<px:PXButton runat="server" DialogResult="Cancel" Text="Cancel" ID="CstButton13" ></px:PXButton>
</px:PXPanel>
...............
Then on your code you can modfiy this new unbound field value depending on your conditions and at the moment(event handler) you need to change.
Please find more information about these changes here on this stackoverflow article:
Is there any event triggered when highlighting a row?
I'd like to add a tab to a screen which contains a memo / formatted text area the way the Cases screen does, e.g.:
Adding a tab is straightforward, no help necessary there, but I don't remember seeing anything about how to add this type of text area in the training courses. If there's an example I'd appreciate a point in the right direction.
You can add the RichTextEditor manually to your aspx file.
<px:PXTabItem Text="Test">
<Template>
<px:PXRichTextEdit runat="server" AllowLoadTemplate="false"
AllowAttached="true" AllowSearch="true" AllowMacros="true"
AllowSourceMode="true" DataField="YOURFIELD" ID="edDescription"
Style='width:100%;'>
<AutoSize Enabled="True" />
</px:PXRichTextEdit>
</Template>
</px:PXTabItem>
Make sure you Tab has the correct Datamember where your field used on the RichTextEditor is located.
<px:PXTab DataMember="Document" ID="tab" runat="server" Height="540px" Style="z-index: 100;" Width="100%">
Also you could mark your Field used on the RichTextEditor as PXDBText.
#region YourField
public abstract class yourField : IBqlField { }
protected String _yourField;
[PXDBText(IsUnicode = true)]
[PXUIField(DisplayName = "YOURFIELD")]
public virtual String YourField
{
get
{
return this._yourField;
}
set
{
this._yourField = value;
}
}
#endregion
I have an attribute with the case number from another instance. I have to make it appear as a hyperlink so user can click on it and it can direct visit to that case.
Any suggestion.
It adds up the link to all row, but I need hyperlink only on Case Number attribute. (see below image).
Assuming you want the link inside a grid cell.
First make an action in your graph with it's primary DAC:
public PXAction<MyPrimaryDAC> viewCase;
Primary DAC can be found in the graph:
public class MyGraph : PXGraph<MyGraph, MyPrimaryDAC>
Make an event handler for the action in your graph to open the case:
[PXButton]
public virtual IEnumerable ViewCase(PXAdapter adapter)
{
// Assuming the case you want is already set as current
// Otherwise lookup case by ID if necessary
CRCase crCase = CRCases.Current as CRCase;
if (crCase != null && crCase.CaseID != null)
PXRedirectHelper.TryRedirect(this, crCase, PXRedirectHelper.WindowMode.NewWindow);
return adapter.Get();
}
Declare the action in the CallbackCommands of your ASPX page:
<asp:Content ID="cont1" ContentPlaceHolderID="phDS" runat="Server">
<px:PXDataSource ID="ds" runat="server" Visible="True" Width="100%"
PrimaryView="MyDataView" TypeName="MyNamespace.MyGraph">
<CallbackCommands>
<px:PXDSCallbackCommand CommitChanges="True" Name="ViewCase" DependOnGrid="gridCase" Visible="False" />
</CallbackCommands>
</px:PXDataSource>
</asp:Content>
Finally use LinkCommand attribute on your grid field to bind the action:
<px:PXGridColumn DataField="MyField" LinkCommand="ViewCase" />
I have the need in one of my customization to show a popup directly after the user modifies the value of one of the controls (in this case, a custom field in the SOLine of the Sales Order Entry screen). This popup shows some additional values in a grid that the user must select before completing the row.
Using the standard process a SmartPanel was added to the screen.
If I call this from an action / PXLookupButton, the popup shows and the grid is populated correctly.
If I move this to either the "FieldUpdated" or "RowSelected" event, the smartpanel is displayed however the grid is always empty. Once more, if I then click on the button the grid stays empty till I cancel the modifications and re-enter using only the button.
I tried calling the action's press method in these events as well but the same result occurs.
Watching SQL profiler and the debugger events I can see that the BQL statement is being executed and returning the correct rows it's just not displaying in the smartpanel's grid.
Is it possible to handle this type of request? I'm assuming I need to either move this to a different method and/or pass some additional values but haven't found the right combination.
This holds true on Acumatica 5.3 / 6.1
Any input would be appreciated.
RowUpdated handler allowed me to achieve requested behavior and show SmartPanel after field value change.
Example below relies on custom unbound Trigger Dialog field declared for the SOLine DAC. When a user checks or uncheckes Trigger Dialog flag, the system will show Item Quantity dialog to update Quantity for selected SOLine record:
public class SOLineExt : PXCacheExtension<SOLine>
{
#region TriggerDialog
public abstract class triggerDialog : PX.Data.IBqlField
{
}
[PXBool]
[PXUIField(DisplayName = "Trigger Dialog")]
public virtual bool? TriggerDialog { get; set; }
#endregion
}
Very basic SmartPanel declaration in Aspx:
<px:PXSmartPanel runat="server" ID="CstSmartPanel2" Key="SOLineParam" Caption="Item Quantity" AutoRepaint="True"
CaptionVisible="True" AcceptButtonID="CstButton6" AutoReload="true" >
<px:PXFormView runat="server" ID="CstFormView3" DataMember="SOLineParam" SkinID="Transparent" >
<Template>
<px:PXLayoutRule runat="server" StartColumn="True" />
<px:PXNumberEdit runat="server" ID="CstPXNumberEdit10" DataField="OrderQty" />
</Template>
</px:PXFormView>
<px:PXLayoutRule runat="server" StartRow="True" />
<px:PXPanel runat="server" ID="CstPanel5" SkinID="Buttons">
<px:PXButton runat="server" ID="CstButton6" DialogResult="OK" CommandName="ChangeOk" CommandSourceID="ds" />
<px:PXButton runat="server" ID="CstButton7" DialogResult="Cancel" Text="Cancel" />
</px:PXPanel>
</px:PXSmartPanel>
Accomplished with the SOOrderEntry BLC extension subscribing to RowUpdated handler for the SOLine DAC to show Item Quantity dialog to a user:
public class SOOrderEntryExt : PXGraphExtension<SOOrderEntry>
{
[Serializable]
public class SOLineParams : IBqlTable
{
#region OrderQty
public abstract class orderQty : PX.Data.IBqlField
{
}
[PXDBDecimal]
[PXDefault(TypeCode.Decimal, "0.0")]
[PXUIField(DisplayName = "Quantity")]
public virtual decimal? OrderQty { get; set; }
#endregion
}
public PXFilter<SOLineParams> SOLineParam;
public PXAction<SOOrder> ChangeOk;
[PXUIField(DisplayName = "OK")]
[PXButton(CommitChanges = true)]
protected void changeOk()
{
var lineParams = SOLineParam.Current;
Base.Transactions.Cache.SetValue<SOLine.orderQty>(Base.Transactions.Current, lineParams.OrderQty);
SOLineParam.Cache.Clear();
}
public void SOLine_RowUpdated(PXCache sender, PXRowUpdatedEventArgs e)
{
if (!sender.ObjectsEqual<SOLineExt.triggerDialog>(e.Row, e.OldRow) && e.ExternalCall == true)
{
SOLineParam.AskExt();
}
}
}
Another part of the extension class is ChangeOk action invoked by SmartPanel to update Quantity for selected record in the Document Details grid. To hide ChangeOk action from screen toolbar, it's also necessary to add the following command into PXDataSource.CallbackCommands collection:
<px:PXDSCallbackCommand Name="ChangeOk" Visible="False" />