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;
}
}
}
Related
I'm trying to copy the value from a custom field called "customerExt.UsrRfc" to TaxRegistrationID field but it doesn't work in Customers screen, I'm using Customer_RowPersisting event handler.
This is the customerExt.UsrRfc field:
This is the TaxRegistrationID field:
This is the RowPersisting event:
protected void Customer_RowPersisting(PXCache cache, PXRowPersistingEventArgs e)
{
Customer row = (Customer)e.Row;
if (row == null)
{
return;
}
var customerExt = row.GetExtension<BAccountExt>();
row.TaxRegistrationID = customerExt.UsrRfc;
}
I tried to copy the value to another field like "Account Ref #" and it works fine.
Can you help me with this?
The TaxRegistrationID field in the screenshot is from Location DAC instead of Customer:
You need to change the solution to update the field in the correct view.
I'm trying to modify the Generate Recurring Transactions (GL504000) screen, and I want to add a user field to filter the grid. I've added a UsrRecurringClass user field to DAC extensions of both the 'Parameters' DAC for the header, and the 'Schedule' DAC for the grid. Now I want to filter that grid by the selection I've added to the header (The UsrRecurringClass field I've added to both)
The problem is, I can't add that field to the View select (Schedule_List) and have it make any difference (I did set the CommitChanges to true on the header filter field).
I've added this to graph extension of the 'ScheduleRun' BLC, as follows, but it doesn't seem to make any difference...
[PXFilterable]
public PXFilteredProcessing<Schedule, ScheduleRun.Parameters,
Where2<Where<ParametersExt.usrRecurringClass, IsNull, Or<ScheduleExt.usrRecurringClass, Equal<Current<ParametersExt.usrRecurringClass>>>>,
And2<Where<Schedule.active, Equal<True>>,
And<Schedule.nextRunDate, LessEqual<Current<ScheduleRun.Parameters.executionDate>>>>>> Schedule_List;
Maybe I'm not doing the BQL correctly, or there's a better way, using the View delegate - I'm not sure.
Any ideas?
I have done a similar customization, maybe the pattern will help you.
public class ARCreateWriteOff_Extension : PXGraphExtension<ARCreateWriteOff>
{
#region Event Handlers
// First expose the PXFilterable view in the extension
[PXFilterable]
[PX.SM.PXViewDetailsButton(typeof(ARRegisterEx.refNbr), WindowMode = PXRedirectHelper.WindowMode.NewWindow)]
public PXFilteredProcessingJoin<ARRegisterEx> ARDocumentList;
// the ARDocumentList view is a long BQL statement I just removed most of it for the example
// Over write the IEnumerabel
protected virtual IEnumerable aRDocumentList()
{
// Get the current row and its extention
ARWriteOffFilter aRWriteOffFilter = Base.Filter.Current;
ARWriteOffFilterExt aRWriteOffFilterExt = aRWriteOffFilter.GetExtension<ARWriteOffFilterExt>();
// loop the values
foreach (ARRegisterEx item in Base.ARDocumentList.Select())
{
//check if the field is Null to return all data
if (string.IsNullOrWhiteSpace(aRWriteOffFilterExt.UsrEmployeeID))
{
yield return item;
}
else
{
// Here you will check if your filter matches the row level
if (aRWriteOffFilterExt.UsrEmployeeID == bAccountExt.UsrEmployeeID)
{
yield return item;
}
}
}
}
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."));
}
}
I have added a customization to the PO Entry screen, PO.30.10.00. The customization adds four date fields, a combobox text field, and a string(10) field.
Right now, the fields are only editable when the PO is on hold. The user wants to be able to edit these fields at any time. They are using these fields to keep track of different POs and will build Generic Inquiries on them so they can communicate the statuses of the POs by maintaining these fields.
The Promise Date is editable when the PO is in Open status. We would like these custom fields to be editable like the Promise Date is.
The Purchase Orders screen is heavily driven by Automation Steps. This fact makes changes to automation steps a mandatory step needed to enable a custom field when the PO is in Open status:
To enable Custom Text Fields on the Purchase Order Summary area and the Document Details grid, one should modify the NL Open step by adding 2 lines as shown in the screenshot above.
After you added those lines, Custom Text Field becomes editable on the Purchase Order Summary area, however, the Custom Text Field column is still read-only in the Document Details grid because of how POLine_RowSelected handler is implemented in the POOrderEntry BLC:
[Serializable]
public class POOrderEntry : PXGraph<POOrderEntry, POOrder>, PXImportAttribute.IPXPrepareItems
{
...
protected virtual void POLine_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
POLine row = (POLine)e.Row;
POOrder doc = this.Document.Current;
if (row == null) return;
if (IsExport) return;//for performance
bool isLinkedToSO = row.Completed == true && IsLinkedToSO(row);
if (this.Document.Current.Hold != true || isLinkedToSO)
{
PXUIFieldAttribute.SetEnabled(sender, e.Row, false);
...
}
...
}
...
}
To enable the Custom Text Field column for editing, you should additionally subscribe to POLine_RowSelected handler within your POOrderEntry BLC extension as shown in the code snippet below:
public class POOrderEntryExt : PXGraphExtension<POOrderEntry>
{
public void POLine_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
POLine line = (POLine)e.Row;
POOrder order = Base.Document.Current;
if (order == null || line == null || Base.IsExport) return;
if (order.Status == POOrderStatus.Open)
{
PXUIFieldAttribute.SetEnabled<POLineExt.usrCustomTextField>(sender, line, true);
}
}
}
Once you made changes in Automation Steps and subscribed to POLine_RowSelected handler within a POOrderEntry BLC extension your custom fields on both the Purchase Order Summary area and the Document Details grid should be open for editing when the PO is in Open status:
I have a stored procedure that's called by a PXAction. I know it's against Acumatica's best practices to use a stored procedure, but I have yet find an alternative solution for my goal. The stored procedure evaluates each line item and the price class it's associated with depending on the breakQuantity that determines the unit price. If multiple items belong to the same price class == or exceed the break quantity the unit price is reduced.
What I started with was a row updating
protected virtual void SOLine_RowUpdating(PXCache sender, PXRowUpdatingEventArgs e)
{
SOLine row = (SOLine)e.Row;
formalizeOrderTotal(row);
}
then in my formalizeOrderTotal function it performed a foreach loop on SOLine in lines.Select() to add up order quantity. As a test i just tried adding up all order quantities and applying it to every line item. This only updated after refreshing which negates the purpose of moving the stored procedure to a c# function/Acumatica event handler.
If anyone has some recommendations a good approach to updating all line items in cache it would be greatly appreciated if you could provide some input.
Try using Base.Transactions.View.RequestRefresh(); which will ask the grid to refresh itself. In this example, I am setting each line quantity to the number of SOLines present in the grid.
using PX.Data;
namespace PX.Objects.SO
{
public class SOOrderEntry_Extension:PXGraphExtension<SOOrderEntry>
{
protected virtual void SOLine_RowUpdating(PXCache sender, PXRowUpdatingEventArgs e)
{
SOLine row = (SOLine)e.Row;
formalizeOrderTotal(row);
}
private void formalizeOrderTotal(SOLine row)
{
foreach (SOLine line in Base.Transactions.Select())
{
if(line.Qty == Base.Transactions.Select().Count)
{
continue;
}
line.Qty = Base.Transactions.Select().Count;
Base.Transactions.Update(line);
Base.Transactions.View.RequestRefresh();
}
}
}
}