How to enable a custom field on PO301000 when the PO is in Open status? - acumatica

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:

Related

How can I save value of user-defined in the database without clicking the save button

I have created a user-defined field (Last Activity Date) on the Opportunities (CR304000) screen which is populated from the last Start Date of the activity on the Activities tab of the Opportunities screen (CR304000) on RowSelected as shown on screenshot one. When an activity is added for an opportunity, the user is not required to click the save button on the form of the opportunity, therefore the user-defined field I have added does not save the value to the database. I would like the value of the user-defined field to be saved to the database whenever an activity is added to the opportunity and the value of the user-defined field changes without having to click the save button on the opportunity form as I need to use it on a generic Inquiry.
Screenshot 1
Code Snippet:
protected void CROpportunity_RowSelected(PXCache cache, PXRowSelectedEventArgs e)
{
var row = (PX.Objects.CR.CROpportunity)e.Row;
if (row == null)
{
return;
}
CRActivity cRActivity = PXSelect<CRActivity, Where<CRActivity.refNoteID, Equal<Required<PX.Objects.CR.CROpportunity.noteID>>>, OrderBy<Desc<CRActivity.startDate>>>.Select(Base, row.NoteID);
if (cRActivity == null)
{
return;
}
CROpportunityExt cROpportunityExt = row.GetExtension<CROpportunityExt>();
cROpportunityExt.UsrLastActivity = cRActivity.StartDate;
Base.Opportunity.SetValueExt<CROpportunityExt.usrLastActivity>(Base.Opportunity.Current, cROpportunityExt.UsrLastActivity);
Base.Save.SetPressed(true);
}
In my opinion, push the value to the opportunity instead from the CRActivityMaint graph in the CRActivity RowPersisted event instead of pulling it from the activity in CROpportunity RowSelected. It is not good practice to change values of DAC rows in the RowSelected event.
Your code would be as follows
In CRActivityMaintExt
In RowPersisted
if (!(e.Row?.EntityDescription?.ToLower().Contains("opportunity") ?? false)) return;
CROpportunity opportunity = SelectFrom<CROpportunity>.Where<CROpportunity.noteID.IsEqual<#P.asGuid>>.View.Readonly.Select(Base, e.Row.RefNoteID);
if (opportunity is null) return;
var oppExt = opportunity.GetExtension<YourExtension>();
oppExt.YourValue = e.Row.SomeValue;
Base.Caches<CROpportunity>().PersistUpdated(opportunity);

How can I filter records for the Generate Recurring Entries (GL504000) screen

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;
}
}
}
}

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?

Sales Order SOLines Conditionally Disabled tranDesc being overridden

I have custom code on the Sales Order form that prevents editing SOLine descriptions unless it's a specific SOLine Code. I see that my custom code is being reached, but it seems that something else is overriding my logic, enabling editing on the field after I disable it. I was wondering if there are pre-defined automations that might be doing this for the Sales Order screen, or if there is some other place I should be looking to prevent this behavior.
//I had debug code that validated that RowSelected and SetEnabled were begin called
public class SOOrderEntry_Extension:PXGraphExtension
{
#region Event Handlers
protected void SOLine_RowSelected(PXCache cache, PXRowSelectedEventArgs e, PXRowSelected InvokeBaseHandler)
{
if(InvokeBaseHandler != null)
InvokeBaseHandler(cache, e);
var row = (SOLine)e.Row;
if(row != null && row.InventoryID.HasValue) {
//Only allow editing of parts description if the partno is 'NOTE'
InventoryItem inventoryItem = PXSelect<InventoryItem, Where<InventoryItem.inventoryID, Equal<Required<InventoryItem.inventoryID>>>>.Select(this.Base, row.InventoryID);
if(inventoryItem.InventoryCD == "NOTE") {
PXUIFieldAttribute.SetEnabled<SOLine.tranDesc>(cache, row, true);
} else {
PXUIFieldAttribute.SetEnabled<SOLine.tranDesc>(cache, row, false);
}
}
}
}
Unfortunately, your RowSelected handler will make no effect on the Line Description column because of how automation steps are configured for the Sales Orders screen:
In order to keep Line Description open for editing, you should change a number of Automation Steps disabling the entire Document Details grid on Sales Orders and subscribe to RowSelected handler for the SOOrder DAC to allow editing on the cache level for the SOOrder and SOLine DACs. Below are the changes required to enable Line Description for completed sales orders (if necessary, similar changes should be made to other Automation steps defined for the Sales Orders screen):
Subscribe to SOOrder_RowSelected handler to allow editing on the cache level for the SOOrder and SOLine DACs:
public class SOOrderEntryExt : PXGraphExtension<SOOrderEntry>
{
public void SOOrder_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
SOOrder order = e.Row as SOOrder;
if (order != null && order.Status == SOOrderStatus.Completed)
{
sender.AllowUpdate = true;
Base.Transactions.Cache.AllowUpdate = true;
}
}
}
Modify Sales Orders' SO Completed automation step to open Line Description for editing. In addition to enabled Line Description, it's necessary to enable at least one of the SOOrder fields, otherwise the Save button will never become enabled for completed sales orders:

Intercept process on Run Project Billing screen

We're using the Run Project Billing screen to create records in AR / Invoice and Memo.
In the Invoice & Memo screen, we need the process to populate the header Customer Ord. number, along with a user field that has been added to the grid section on the 'Document Details' tab. At the moment, the process is not doing this.
I'd like to intercept the processing action on the screen using a technique I'm familiar with, namely using an 'AddHandler':
[PXOverride]
protected virtual IEnumerable Items (PXAdapter adapter)
{
PXGraph.InstanceCreated.AddHandler<BillingProcess>((graph) =>
{
graph.RowInserting.AddHandler<BillingProcess.ProjectsList>((sender, e) =>
{
//Custom logic goes here
});
});
return Base.action.Press(adapter);
}
I see no Base.Actions that remotely resembles 'Bill' or 'Bill All'.
This is obviously not exactly the code I need, but I would think this is the general place to start.
After reviewing the source business logic, I don't see any 'Bill' or 'Bill All' Actions - or any 'Actions' at all (baffling). I see an IEnumerable method called 'items', so that's what I started with above.
Is this the correct way to go about this?
Update: 2/14/2017
Using the answer provided re: the overridden method InsertTransaction(...) I've tried to set our ARTran user field (which is required) using the following logic:
PMProject pmproj = PXSelect<PMProject, Where<PMProject.contractID, Equal<Required<PMProject.contractID>>>>.Select(Base, tran.ProjectID);
if (pmproj == null) return;
PMProjectExt pmprojext = PXCache<PMProject>.GetExtension<PMProjectExt>(pmproj);
if (pmprojext == null) return;
ARTranExt tranext = PXCache<ARTran>.GetExtension<ARTranExt>(tran);
if (tranext == null) return;
tranext.UsrContractID = pmprojext.UsrContractID;
Even though this sets the user field to the correct value, it still gives me an error that the required field is empty when the process finishes. My limited knowledge prevents me from understanding why.
On the Run Project Billing screen, captions of Process and Process All buttons were changed to Bill and Bill All respectively in BLC constructor.
Process delegate is set for Items data view within the BillingFilter_RowSelected handler:
public class BillingProcess : PXGraph<BillingProcess>
{
...
public BillingProcess()
{
Items.SetProcessCaption(PM.Messages.ProcBill);
Items.SetProcessAllCaption(PM.Messages.ProcBillAll);
}
...
protected virtual void BillingFilter_RowSelected(PXCache cache, PXRowSelectedEventArgs e)
{
BillingFilter filter = Filter.Current;
Items.SetProcessDelegate<PMBillEngine>(
delegate (PMBillEngine engine, ProjectsList item)
{
if (!engine.Bill(item.ProjectID, filter.InvoiceDate, filter.InvFinPeriodID))
{
throw new PXSetPropertyException(Warnings.NothingToBill, PXErrorLevel.RowWarning);
}
});
}
...
}
As code snippet above confirms, all records in the AR Invoice and Memos screen are created by instance of the PMBillEngine class. Below is code snippet showing how to override InsertNewInvoiceDocument and InsertTransaction methods within the PMBillEngine BLC extension:
public class PMBillEngineExt : PXGraphExtension<PMBillEngine>
{
public delegate ARInvoice InsertNewInvoiceDocumentDel(string finPeriod, string docType, Customer customer,
PMProject project, DateTime billingDate, string docDesc);
[PXOverride]
public ARInvoice InsertNewInvoiceDocument(string finPeriod, string docType, Customer customer, PMProject project,
DateTime billingDate, string docDesc, InsertNewInvoiceDocumentDel del)
{
var result = del(finPeriod, docType, customer, project, billingDate, docDesc);
// custom logic goes here
return result;
}
[PXOverride]
public void InsertTransaction(ARTran tran, string subCD, string note, Guid[] files)
{
// the system will automatically invoke base method prior to the customized one
// custom logic goes here
}
}
Run Project Billing process invokes InsertNewInvoiceDocument method to create new record on the AR Invoice and Memos screen and InsertTransaction method to add new invoice transaction.
One important thing to mention: overridden InsertNewInvoiceDocument and InsertTransaction methods will be invoked when a user launches Run Project Billing operation either from the processing Run Project Billing screen or from the data entry Projects screen.
For more information on how to override virtual BLC methods, see Help -> Customization -> Customizing Business Logic -> Graph -> To Override a Virtual Method available in every Acumatica ERP 6.1 website

Resources