I need to conditionally set a field to be required - acumatica

I'm customizing the Sales Order screen as follows:
I've added a custom boolean field added to the Order Types screen called 'Require Customer Order Number'.
I've added code to the BLC of the Sales Order screen where I want to conditionally make the CustomerOrderNumber field required, based on whether the 'Require Customer Order Number' field is checked or not.
I'm using the SOOrder_RowSelected event as follows:
protected virtual void SOOrder_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
var soorder = (SOOrder)e.Row;
if (soorder == null) return;
string ordtype = soorder.OrderType;
var soot = (SOOrderType)PXSelect<SOOrderType,
Where<SOOrderType.orderType, Equal<Required<SOOrderType.orderType>>>>.Select(Base, ordtype);
if (soot != null)
{
var sootext = PXCache<SOOrderType>.GetExtension<SOOrderTypeExt>(soot);
if (sootext != null)
{
PXUIFieldAttribute.SetRequired<SOOrder.customerOrderNbr>(sender, sootext.UsrRequireCustOrdNbr == null ? false : (bool)sootext.UsrRequireCustOrdNbr);
}
}
}
This DOES put an asterisk on the CustomerOrderNumber field - but it doesn't spawn an error upon save if that field is empty.
Another issue is my PXSelect to get the record out of SOOrderType ALWAYS returns a null for the check box user field, even if it has a 'True' value in the database (which is why I put the ternary operator on the call). Even if I hard-code a 'true' value in the PXUIFieldAttribute.SetRequired call, it still doesn't spawn the error to prevent a save. The asterisk is there, but it doesn't work.
If I use a Cache_Attached event to add [PXDefault] it works perfectly - but this doesn't help me - I need it conditionally set.
Any ideas?

Required is used only for displaying the asterisk. PXDefault attribute is the one that makes the field mandatory based on PersistingCheck property value.
The issue is that PXUIFieldAttributes like PersistingCheck can only be set once at the time of graph creation. You can set it dynamically in the constructor/Initialize method but if you change the property after that it has no effects.
When I need a field to be mandatory based on a dynamic condition I remove the PXDefault attribute and validate the field manually in event handlers like RowPersisting:
public void PMTimeActivity_RowPersisting(PXCache sender, PXRowPersistingEventArgs e)
{
PMTimeActivity timeActivity = e.Row as PMTimeActivity;
if (timeActivity != null && PMTimeActivity.timeSpent == null)
{
PXUIFieldAttribute.SetError<PMTimeActivity.timeSpent>(sender, timeActivity, "'Time Spent' cannot be empty."));
}
}

Related

BQL expression in FieldDefaulting for Current User

I'm trying to set the default value of a custom field to the defContactID of the currently logged in user. I cannot get the BQL correct, any advise?
namespace PX.Objects.PJ.DailyFieldReports.PJ.Graphs
{
public class DailyFieldReportEntry_Extension : PXGraphExtension<DailyFieldReportEntry>
{
protected void DailyFieldReport_UsrOwner_FieldDefaulting(PXCache cache, PXFieldDefaultingEventArgs e, PXFieldDefaulting InvokeBaseHandler)
{
if (InvokeBaseHandler != null)
InvokeBaseHandler(cache, e);
var row = e.Row as DailyFieldReport;
//BQL Statement to pull the EPEmployee record for the currently logged in employee
e.NewValue = EPEmployee.defContactID;
}
}
}
To get the logged in user details you can use the AccessInfo object which is in every graph. Accessinfo.UserContactID will retrieve the logged in user contact ID.
you can also use this by specifying it in the PXDefault attribute, without having the need to use the field event. In this case:
[PXDefault(typeof(AccessInfo.userContactID))

How do I use the user set value of a DAC extension to enable/disable a UI field of the Base DAC?

I added a bool field to APVendorPrice that needs to be enabled only when a SiteID is entered in the APVendorPriceMaint graph. Likewise, if it is set true, it needs to disable the SiteID field. By creating a graph extension for APVendorPriceMaint, I can tap into the APVendorPrice_RowSelected event to enable/disable my custom field easily. However, when I set my new field to Commit Changes = true, the user entry value of my DAC extension field is lost to me.
How do I get the user entered value on my DAC extension field?
protected virtual void APVendorPrice_RowSelected(PXCache sender, PXRowSelectedEventArgs e, PXRowSelected baseEvent)
{
APVendorPrice row = (APVendorPrice)e.Row;
APVendorPriceExt vendorPriceExt = sender.GetExtension<APVendorPriceExt>(row);
baseEvent(sender, e);
PXUIFieldAttribute.SetEnabled<APVendorPrice.siteID>(sender, row, vendorPriceExt?.UsrMyField != true);
PXUIFieldAttribute.SetEnabled<APVendorPriceExt.UsrMyField>(sender, row, row?.SiteID != null);
}
The GetExtension always returns the saved value rather than seeing that the user toggled the value.
How do I see the user entered value for UsrMyField so that I can enable/disable access to SiteID?

Acumatica - Set checkbox to true based on a different field

I know that this is basic stuff and conditions, but I have an issue with a line that already exists in a service order. So we have Service Orders that will be imported into Acumatica and will already have a line. When in the Acumatica system someone will go to the Service Order screen (SD300100) and make the changes they wish after the import. In this case, they will change the Warranty Status, a custom field that we made, and it will change some values in the details and header. I have everything working, except for the first line that is brought in from the import on the detail line. So this order will come in with a line already inserted into the Labor tab. My issue is when we change the Warranty Status to warranty it should check another custom field's box called Warranty down in the detail line. I have this working for any newly inserted line but I can't get it with the already existing line. I have tried RowUpdated, RowUpdating, RowInserted, RowInserting on both the Header and Labor line data views. As well as the FieldUpdated, FieldUpdating and Selecting, on the header warranty selector and the Warranty checkbox in the details under the labor tab.
Here is my code:
public PXSelect<FSSODet, Where<FSSODet.sOID, Equal<Current<FSSODet.sOID>>>> FSSODets;
protected void FSServiceOrder_Usrwarrstat_FieldUpdated(PXCache cache, PXFieldUpdatedEventArgs e)
{
var row = (FSServiceOrder)e.Row;
if (row == null) return;
FSSODet line = FSSODets.Current;
if (line == null) return;
if (line != null){
FSServiceOrderExt rowExt = PXCache<FSServiceOrder>.GetExtension<FSServiceOrderExt>(row);
if(rowExt == null)
return;
if (rowExt.Usrwarrstat == null)
return;
if (rowExt.Usrwarrstat == "W"){
cache.SetValueExt<FSSODetExt.usrwarrantydetail>(line, true);
}
}
}
This was the last way I tried before going to here. If anyone has a different way, I can provide code for any of the methods metioned above, RowUpdated, RowUpdating, etc. Commit Changes is set to true on both fields.
In short, when the Usrwarrstat field is set to "W" in the Service Order header, I want the Usrwarrantydetail in the Labor Tab/Details to be set to true.
Update 1: So I used the 1st answer suggestion below and it did change the checkbox to checked, but it happens no matter what the status is. I only need it to be check if it is set to "W" or "P", the only the other option is "N" so I added a check to if it is set to "N" then it would be false. However, it is still saving it as true.
Here is the updated code:
public PXSelect<FSSODetService, Where<FSSODetService.sOID, Equal<Current<FSSODetService.sOID>>>> FSSODets;
protected void FSServiceOrder_Usrwarrstat_FieldUpdated(PXCache cache, PXFieldUpdatedEventArgs e)
{
var row = (FSServiceOrder)e.Row;
if (row == null) return;
FSSODetService line = FSSODets.Current;
if (line == null) return;
if (line != null){
FSServiceOrderExt rowExt = PXCache<FSServiceOrder>.GetExtension<FSServiceOrderExt>(row);
if(rowExt == null)
return;
if (rowExt.Usrwarrstat == null)
return;
if (rowExt.Usrwarrstat == "W" || rowExt.Usrwarrstat == "P"){
FSSODets.Cache.SetValueExt<FSSODetExt.usrwarrantydetail>(line, true);
}
if (rowExt.Usrwarrstat == "N"){
FSSODets.Cache.SetValueExt<FSSODetExt.usrwarrantydetail>(line, false);
}
}
}
}
Overall the logic looks good. There's a Cache object mismatch that could prevent SetValueExt from working:
// When this event handler is called by the framework
// PXCache cache object will be of type FSServiceOrder
// because the event is bound on FSServiceOrder DAC
protected void FSServiceOrder_Usrwarrstat_FieldUpdated(PXCache cache, PXFieldUpdatedEventArgs e)
When you call SetValueExt you should use a cache object of matching type:
// cache reference is of type FSServiceOrder but we want to modify FSSODetExt DAC field
cache.SetValueExt<FSSODetExt.usrwarrantydetail>(line, true);
// With extensions you have to use the base DAC cache
// you already declared a DataView on FSSODet so you can use it's cache reference
FSSODets.Cache.SetValueExt<FSSODetExt.usrwarrantydetail>(line, true);
Besides the DAC cache reference mismatch there's a possibility that you do successfully modify the field value but another event handler/mechanism modifies it again after you.
To check that you can declare a event handler on the target field, put a breakpoint in it and debug it using visual studio debug stack trace window. The stack trace will show which methods lead to the field modification.
protected void FSSODet_Usrwarrantydetail_FieldUpdated(PXCache cache, PXFieldUpdatedEventArgs e)
Also make sure Usrwarrstat field has the CommitChanges = True property set in the ASPX file or else modifying the field on screen won't execute the associated FieldUpdated event handler.

Unbound fields on DAC extension - where to populate?

I have extended the CRMarketingListMember DAC in order to include a number of unbound fields. I'm adding these new unbound fields to the List Members grid on CR204000 and need to execute some code in order to put values into these fields when the List Members grid is displayed. The problem is that my unbound fields are always blank in the grid. I've tried extending the CRMarketingListMaint graph and putting the code that populates the unbound fields into the CRMarketingList_RowSelected() event but that, of course, doesn't work.
Thanks for the help!
RowSelecting is the proper event in which to populate unbound fields, if doing additional BQL selects make sure to wrap the logic in a new PXConnectionScope.
Example Below :
public virtual void ARInvoice_RowSelecting(PXCache sender, PXRowSelectingEventArgs e)
{
ARInvoice row = e.Row as ARInvoice;
if (row != null)
{
using (new PXConnectionScope())
{
ARRegisterExtension rowExt = PXCache<ARRegister>.GetExtension<ARRegisterExtension>(row);
var result = PXSelect<.....>
rowExt.UsrISExternalTax = result.IsExternalTax;
}
}
}

BQL on custom DAC referencing SOOrder.orderNbr not reflecting current Order Nbr

We have a test DAC called UsrNonRelatedScanField with two fields : OrderNbr and ScanStatus.
Here's our simple query to grab the correct ordernbr and assign it to a SOOrderExt field:
NonRelatedScanField lastScan = PXSelect<NonRelatedScanField,
Where<NonRelatedScanField.orderNbr,
Equal<Required<SOOrder.orderNbr>>>>.Select(Base, row.OrderNbr);
if(lastScan != null)
{
rowExt.UsrNonRelatedScanField = lastScan.ScanStatus;
}
This logic is held in a SOOrder_RowSelecting() method.
Full Method implementation:
protected virtual void SOOrder_RowSelecting(PXCache sender, PXRowSelectingEventArgs e)
{
SOOrder row = (SOOrder)e.Row;
if (row == null) return;
SOOrderExt rowExt = PXCache<SOOrder>.GetExtension<SOOrderExt>(row);
NonRelatedScanField lastScan = PXSelect<NonRelatedScanField,
Where<NonRelatedScanField.orderNbr,
Equal<Required<SOOrder.orderNbr>>>>.Select(Base, row.OrderNbr);
if (lastScan != null)
{
rowExt.UsrNonRelatedScanField = lastScan.ScanStatus;
}
}
Expected Results : Get the current Orders scan status from lastScan DAC
Actual Results: Will populate correctly only on the initial order opened. When selecting other orders the old value is persisting unless I manually refresh the page. When manually refreshed the correct data comes in.
I haven't had any issues in the past with BQL queries, this specific query is not behaving as expected.
Thank you

Resources