How come PXUIField attribute disables text edit boxes on a processing page in 2019 R1? - acumatica

I'm trying to setup a processing page that will update a SOShipment document lines with new data entered on the PXFilteredProcessing page. When declaring a PXString (virtual field), if I add the PXUIfield attribute, the field becomes read only.
Here is the DAC declaration showing the actual problem. The page I use is a simple PXFilteredProcessing page with a completely custom page that was made in Visual Studio.
#region StockRow
public abstract class stockRow : IBqlField { }
[PXString()]
[PXUIField(Enabled = true)]
public virtual String StockRow { get; set; }
#endregion
#region StockFlag
public abstract class stockFlag : IBqlField { }
[PXString]
public virtual String StockFlag { get; set; }
#endregion
The page has the fields defined as follow :
<px:PXTextEdit ID="edStockRow" runat="server"
DataField="StockRow" Enabled ="true" >
</px:PXTextEdit>
<px:PXTextEdit ID="edStockFlag" runat="server"
DataField="StockFlag" Enabled ="true">
</px:PXTextEdit>
<px:PXGridColumn DataField="StockRow" Width="200px" >
</px:PXGridColumn>
<px:PXGridColumn DataField="StockFlag" Width="200px">
</px:PXGridColumn>
Should the PXUIField really make the field become read only or is there something I am not getting?
PS: I know I can re-enable the field on the RowSelected even, I'm mostly looking for an explanation as to why this is happening.

if I add the PXUIfield attribute, the field becomes read only
Are you sure that this is the operation making the field read-only?
Typically all processing screen detail fields are disabled except the Selected column. I believe this is a behavior introduced by the use of PXProcessing type data view. Going against that behavior will likely not yield the desired result.
If the screen needs detail fields to be editable (except Selected column) I would advise not to create a processing screen. Using a PXSelect data view instead will provide correct behavior for the editable fields.

Related

How do I force user input to commit and save automatically when executing an action?

I have a custom graph, in this case called MyGraph. The page contains a Form Tab in a similar fashion to the Stocked Items page in which the header is a few fields of my DAC (MyDAC), and a form on the 1st tab is a form of my additional fields. The views, for the sake of discussion, are MyView and MyCurrentView.
On the Stocked Items page, I can set a value in the ItemSettings view (General Settings tab) and then execute an action which also happens to save my user input. In my custom page, the user input of the similar "MyCurrentView" tab is lost when I execute an action. I have reviewed the training material once again for T230 Actions, but I cannot seem to overcome this problem. The code sample below shows 2 simplified methods of how I execute the action "ConvertIt". In both cases during a Debug, both myDAC and myDAC2 contain the stale data, indicating that the view was not updated as expected per CommitChanges in the Button attribute and in the DataSource Callback Command. The user input that is not saved is entered via a field presented to the UI only in MyCurrentView.
The T230 training guide indicates that I should set the AutoCallBack Behavior in the action bar, which appears to be possible for a grid, but not for a form. The example from the training guide is:
<ActionBar>
<CustomItems>
<px:PXToolBarButton Text="Complete">
<AutoCallBack Command="Complete" Target="ds">
<Behavior CommitChanges="True" ></Behavior>
</AutoCallBack>
</px:PXToolBarButton>
</CustomItems>
</ActionBar>
Since I am hanging my action off the Action menu via action.AddMenuAction(convertIt);, I do not seem to have a way to specify the behavior as described in the training guide.
Views Defined
public PXSelect<MyDAC> MyView;
public PXSelect<MyDAC, Where<MyDAC.tagID, Equal<Current<MyDAC.tagID>>>> MyCurrentView;
Action Defined - Method 1
#region convertIt Action
public PXAction<MyDAC> convertIt;
[PXUIField(DisplayName = "My DAC Label", MapEnableRights = PXCacheRights.Update, MapViewRights = PXCacheRights.Select)]
[PXButton(CommitChanges = true)]
public virtual void ConvertIt()
{
this.Save.Press(); // Seems to make no difference in saving the unsaved user entry
MyDAC myDAC = MyView.Current;
MyDAC myDAC2 = MyCurrentView.Current;
** DO THE WORK OF THE ACTION HERE **
}
#endregion
Action Defined - Method 2
#region convertIt Action
public PXAction<MyDAC> convertIt;
[PXUIField(DisplayName = "My DAC Label", MapEnableRights = PXCacheRights.Update, MapViewRights = PXCacheRights.Select)]
[PXButton(CommitChanges = true)]
public virtual IEnumerable ConvertIt(PXAdapter adapter)
{
MyDAC myDAC = MyView.Current;
MyDAC myDAC2 = MyCurrentView.Current;
** DO THE WORK OF THE ACTION HERE **
return adapter.Get();
}
#endregion
ASPX Datasource Defined
<px:PXDataSource ID="ds" runat="server" Visible="True" Width="100%"
TypeName="MyGraph"
PrimaryView="MyView">
<CallbackCommands>
<px:PXDSCallbackCommand CommitChanges="True" Name="ConvertIt" ></px:PXDSCallbackCommand>
</CallbackCommands>
</px:PXDataSource>
In short, user input is lost when I complete my action. I have tried including this.Save.Press() at the beginning of my action, but I already save at the end of my action. Regardless, a Debug does not show my user entered values in the view, although I expected the commit changes on the button and in the data source to commit those changes from the client before proceeding with the action.
What have I left out of the C# code or ASPX page definition that is preventing my UI updates to be applied? Interestingly enough, UI changes in the MyView view ARE applied, but not changes in MyCurrentView unless I literally press the save button manually before selecting the action from the menu.
I ran into this problem recently as well. It’s easy to force the page to post back to server when opening a smart panel off of an action, but if there is no panel opening how do you force a post of data that was changed in fields that don’t commit on update?
The only way I’ve found to accomplish this is by editing the ASPX and adding StartNewGroup="true" and CommitChanges="true" to the PXDSCallbackCommand for the Action Folder that the action is added to.
<px:PXDataSource ID="ds" runat="server" Visible="True" Width="100%"
TypeName="MyGraph"
PrimaryView="MyView">
<CallbackCommands>
<px:PXDSCallbackCommand CommitChanges="True" Name="ActionFolder" StartNewGroup="True" />
</CallbackCommands>
</px:PXDataSource>
For the action, you should use the second method.
public PXAction<MyDAC> convertIt;
[PXUIField(DisplayName = "My DAC Label", MapEnableRights = PXCacheRights.Update, MapViewRights = PXCacheRights.Select)]
[PXButton(CommitChanges = true)]
public virtual IEnumerable ConvertIt(PXAdapter adapter)
{
MyDAC myDAC = MyView.Current;
MyDAC myDAC2 = MyCurrentView.Current;
**DO THE WORK OF THE ACTION HERE **
return adapter.Get();
}
public MyGraph()
{
actionFolder.AddMenuAction(convertIt);
}
It is not possible to save the focused field value. Value is saved when the control lose focus. However when the focus goes from an uncommitted field to an action button (clicked by user) the current field value is lost. Not sure this is the issue here but keep in mind that the user has to tab out of a control editor with uncommitted value before clicking on an action button or else the value is lost.

Acumatica - NonStockItem Screen on AlloAddNew in Page

Good Day!
I have a PXSelector field in DAC that only show non-stock items
public abstract class inventoryID : IBqlField { }
[PXDBInt]
[PXSelector(typeof(Search2<InventoryItem.inventoryID,
LeftJoin<RECOInventoryItem, On<RECOInventoryItem.inventoryID, Equal<InventoryItem.inventoryID>>>,
Where<RECOInventoryItem.inventoryID, IsNull,
And<InventoryItem.itemType, Equal<ItemType.NON_STOCK>,
And<InventoryItem.stkItem, Equal<False>>>>>),
typeof(InventoryItem.inventoryCD),
typeof(InventoryItem.descr),
DescriptionField = typeof(InventoryItem.descr))]
[PXUIField(DisplayName = "Inventory")]
[PXDefault(PersistingCheck = PXPersistingCheck.Nothing)]
public virtual int? InventoryID { get; set; }
I also have a selector in my page that allows edit and allows add new methods
<px:PXSelector ID="edInventoryID" runat="server" DataField="InventoryID" AllowEdit="true" AllowAddNew="true">
</px:PXSelector>
Now, my problem lies with the edit(pencil) button in the User Interface. When I'm clicking the edit button, with the item that i want to edit, I am being redirected to Non-Stock Items page,
But when I want to add another Non-stock Item by using the edit(pencil) button, I am redirected to the Stock Items page.
I already set my PrimaryGraph.
[PXPrimaryGraph(typeof(PropertyMaint))]
public class RECOInventoryItem : Audit, IBqlTable
How do you set the AllowAddNew redirect to Non-Stock Item Page instead of the Stock Item Page.
How do you override the PxPrimaryGraph of the InventoryItem so that the graph that i'm redirecting to is Non-stock Item, instead of Stock Item.
Thank you so much for the advice and suggestions.
PXPrimaryGraph can handle binding 1 DAC to multiple graphs using BQL conditions on the DAC fields as shown on InventoryItem DAC:
[PXPrimaryGraph(new Type[]
{
typeof(NonStockItemMaint),
typeof(InventoryItemMaint)
},
new Type[]
{
typeof(Where<InventoryItem.stkItem, Equal<False>>),
typeof(Where<InventoryItem.stkItem, Equal<True>>)
})]
This works well with AllowEdit functionality because the InventoryItem.stkItem field used for the graph redirection is already populated in the record you want to edit.
When you create a new record with AllowAddNew though I suspect the field InventoryItem.stkItem will be null or always defaulted to the same value by PXDefault attribute. This would have the side effect of always redirecting to the same graph.
As you can probably guess AllowAddNew doesn't have any options or programmatic interface to influence it's behavior so it is pretty limited in what it can do. For that reason I don't think you can override it's behavior.
This leave creating your own action button as the only option I know to achieve your use case. You can style the button to show a + icon and no text like AllowAddNew does. You would still be limited on where you can place that button because Selector popup windows also lack options and programmatic interface.

How to add a memo / formatted text field ala Cases

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

How to place a 'Related Entity' lookup on a field

In the Activity / Task screen (cr306020), there is a 'Related Entity' field with a PXSelector lookup as well as a pencil for opening the screen of the related entity:
I'd like to know if there is a way to do this for a custom field. I've looked at the source code for the field (it's EPActivity.Source in the DAC), but I see nothing that puts these attributes on that field. No PXSelector or anything similar.
The example below shows how to add the Related Entity field on the Opportunities (CR304000) screen. Please be aware, PXRefNoteSelector control used in this sample is not currently supported by the Layout Editor in Acumatica Customization Manager. I used Opportunities to simplify and shorten the example. Unfortunately, for now you can only add the Related Entity field on a custom screen.
Now let's move forward to the sample:
Implement extension for the CROpportunity DAC to declare the database bound UsrRefNoteID and unbound RelatedEntity fields. Related Entity's NoteID will be stored in UsrRefNoteID, and RelatedEntity will be used to display Related Entity's user-friendly description:
public class CROpportunityExt : PXCacheExtension<CROpportunity>
{
#region UsrRefNoteID
public abstract class usrRefNoteID : IBqlField { }
protected Guid? _UsrRefNoteID;
[PXDBGuid]
[PXParent(typeof(Select<CRActivityStatistics,
Where<CRActivityStatistics.noteID, Equal<Current<CROpportunityExt.usrRefNoteID>>>>), LeaveChildren = true)]
public Guid? UsrRefNoteID
{
get
{
return _UsrRefNoteID;
}
set
{
_UsrRefNoteID = value;
}
}
#endregion
#region Source
public abstract class relatedEntity : IBqlField { }
[PXString(IsUnicode = true)]
[PXUIField(DisplayName = "Related Entity Description", Enabled = false)]
[PXFormula(typeof(EntityDescription<CROpportunityExt.usrRefNoteID>))]
public string RelatedEntity { get; set; }
#endregion
}
Create extension for the OpportunityMaint BLC to decorate its primary Opportunity data view with PXRefNoteSelectorAttribute. The PXRefNoteSelectorAttribute is required for the Edit (pencil) and Lookup buttons to work on your custom Related Entity field:
public class OpportunityMaintExt : PXGraphExtension<OpportunityMaint>
{
[PXCopyPasteHiddenFields(typeof(CROpportunity.resolution))]
[PXViewName(Messages.Opportunity)]
[PXRefNoteSelector(typeof(CROpportunity), typeof(CROpportunityExt.usrRefNoteID))]
public PXSelect<CROpportunity> Opportunity;
}
On Aspx page, add PXRefNoteSelector control with the DataField property set to RelatedEntity and NoteIDDataField to UsrRefNoteID.
For the EditButton, LookupButton and LookupPanel tags, use the primary data view name decorated with the PXRefNoteSelector attribute (Opportunity in the code snippet below)
<pxa:PXRefNoteSelector ID="edRefEntity" runat="server" DataField="RelatedEntity" NoteIDDataField="UsrRefNoteID"
MaxValue="0" MinValue="0" ValueType="Guid" CommitChanges="true">
<EditButton CommandName="Opportunity$Navigate_ByRefNote" CommandSourceID="ds" />
<LookupButton CommandName="Opportunity$Select_RefNote" CommandSourceID="ds" />
<LookupPanel DataMember="Opportunity$RefNoteView" DataSourceID="ds" TypeDataField="Type" IDDataField="NoteID" />
</pxa:PXRefNoteSelector>
Hide 3 actions generated by the PXRefNoteSelector attribute from the form toolbar. Use the same primary data view name decorated with the PXRefNoteSelector attribute (Opportunity in the code snippet below) as in the step above:
<CallbackCommands>
...
<px:PXDSCallbackCommand Name="Opportunity$Navigate_ByRefNote" Visible="False" />
<px:PXDSCallbackCommand Name="Opportunity$Select_RefNote" Visible="False" />
<px:PXDSCallbackCommand Name="Opportunity$Attach_RefNote" Visible="False" />
</CallbackCommands>
You might also need to implement your own EntityDescription operator, since at the time this example was created, it had internal access modifier and was not available outside of the PX.Objects.dll:
public class EntityDescription<RefNoteID> : BqlFormulaEvaluator<RefNoteID>, IBqlOperand
where RefNoteID : IBqlField
{
public override object Evaluate(PXCache cache, object item, Dictionary<Type, object> pars)
{
Guid? refNoteID = (Guid?)pars[typeof(RefNoteID)];
return new EntityHelper(cache.Graph).GetEntityDescription(refNoteID, item.GetType());
}
}
And finally... screenshot of the customized Opportunities screen with a brand-new Related Entity field:

Showing smartpanel after field value changes - grid remains empty

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" />

Resources