I have had set my custom field 'UsrPrintQty' to be enabled on POReceiptLine_RowSelected event as below:
protected void POReceiptLine_RowSelected(PXCache cache, PXRowSelectedEventArgs e, PXRowSelected InvokeBaseHandler)
{
if (InvokeBaseHandler != null)
InvokeBaseHandler(cache, e);
var row = (POReceiptLine)e.Row;
PXUIFieldAttribute.SetEnabled<POReceiptLineExt.usrPrintQty>(cache, row, true);
//PXUIFieldAttribute.SetEnabled(cache, row, "UsrPrintQty", true);
}
And it is working perfectly on my development server with the Acumatica version 18.200.0075. But when I published the customization to the another instance with the version 18.112.0019, it just doesn't work.
I debug the code and the line is being hit too.
I set the highest customization level guessing there might be chance that other code is overriding this one.
I restart the application via Apply Updates.
I even changed the event from RowSelected to RowSelecting.
I tried the different overloaded method of SetEnabled (which is commented in the above code).
But nothing works.
If I put these two lines:
cache.AllowUpdate = true;
Base.transactions.Cache.AllowUpdate = true;
then it allows me to update but then I can update the whole row which I don't want to.
I also set the field property AllowUpdate to true.
But still no luck.
Thank you.
The cache AllowUpdate method takes precedence on SetEnabled method.
Calling the cache AllowUpdate with false parameter is commonly used on closed document to prevent any modification.
If you require the user to be able to modify one field of a closed document you'll have to jump through some hoops. Setting AllowUpdate to true after the base graph has set it to false is necessary.
Try this pattern:
// Required to enable any field
Base.transactions.Cache.AllowUpdate = true;
// Set all fields to false
PXUIFieldAttribute.SetEnabled(Base.transactions.Cache, null, false);
// Set the only field we want to enable to true
PXUIFieldAttribute.SetEnabled<POReceiptLineExt.usrPrintQty>(Base.transactions.Cache, null, true);
Related
I would like to modify the ShippedQty field by putting the same value as the OpenOrderQty field after adding the line, but that does nothing. I removed the PXDefault. The value stay at 0.00.
protected void SOShipLine_RowInserted(PXCache cache, PXRowInsertedEventArgs e, PXRowInserted InvokeBaseHandler)
{
if(InvokeBaseHandler != null)
InvokeBaseHandler(cache, e);
var row = (SOShipLine)e.Row;
if (row==null) {return;}
row.ShippedQty=row.OpenOrderQty;
}
Thanks.
Xavier
I would like to suggest you to not set the ShippedQty because it might have some implications as it is a calculated field. Instead, you can create a custom field and set the value of OpenOrderQty to that field.
When the RowInserted event is fired, the data has already been inserted into the cache so it's too late to try and edit the data. You should change this to use a RowInserting() event. See more details here
I'm trying to set the PMProject.TemplateID from code (specifically when creating a project from a different form, but that doesn't seem to be the issue) but when I set it with code in any of the obvious ways, it only sets the value but doesn't update the fields or tasks like it does when you enter in manually.
What's especially weird is that I've tried this on two installs and I can't make it work, but on the customer site it DOES work as expected (grabs the description, tasks, etc from the template).
I made this button on the Projects (PM301000) form just to see if I could make it work. None of these methods update the other fields. I also tried capturing any error (doesn't seem like there is one) or checking the trace (It's not writing anything).
public PXAction<PX.Objects.PM.PMProject> TekAssTemp;
[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "Assign Template")]
protected void tekAssTemp()
{
PMProject TheRow = Base.Project.Current;
// 157 = SalesDemo INTERNAL
// Update the Cache with EXT
Base.Project.Cache.SetValueExt<PMProject.templateID>(TheRow, 157);
Base.Project.Cache.Update(TheRow); // Bonus just to try and force it's hand. Same result with or without this.
// Update the row, then update the view to run app logic. Nada.
//TheRow.TemplateID = 157;
//Base.Project.Update(TheRow);
}
Just to check my sanity, I tested almost the same code on stock items and it works just like I would think in all the normal ways:
public PXAction<PX.Objects.IN.InventoryItem> TekAssSome;
[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "Assign Something")]
protected void tekAssSome()
{
InventoryItem TheRow = Base.Item.Current;
// On stock item, all these work. (57 = SalesDemo Widget)
// Update the view directly with EXT, sets the values of Tax, Posting, Lot/Serial, etc.
Base.Item.SetValueExt<InventoryItem.itemClassID>(TheRow, 57); // Works
// Update the Cache with EXT, sets the values of Tax, Posting, Lot/Serial, etc.
//Base.Item.Cache.SetValueExt<InventoryItem.itemClassID>(TheRow, 57); // Works
// Update the Cache value only, force update with update, sets the values of Tax, Posting, Lot/Serial, etc.
//Base.Item.Cache.SetValue<InventoryItem.itemClassID>(TheRow, 57);
//Base.Item.Cache.Update(TheRow); // Works
// Update the row (how I like it the most). Also works.
//TheRow.ItemClassID = 57; // Assigns the value
//Base.Item.Update(TheRow); // Run Logic. Works
}
I need to attach custom data into new fields added to INTranCost when the PO Receipt occurs.
Following the breadcrumbs, it seems that POReceiptEntry -> Release Action eventually calls INDocumentRelease.ReleaseDoc that eventually creates INTranCost. I tried extending both POReceiptEntry and INDocumentRelease to add an event for INTranCost_RowInserted to publish a PXTrace message, but the trace doesn't appear, telling me that I'm not hitting the event that I expected. (Which explains why the real business logic I need included didn't fire.)
protected virtual void _(Events.RowInserted<INTranCost> e)
{
PXTrace.WriteInformation("This is it!");
}
Of course, I want to put real code in this spot, but I am just trying to make sure I'm hitting the event properly. This works on pretty much everything else I've done, including attaching similar data to INTranExt fields. I cannot get it to work for INTranCost so that I can add to INTranCostExt. At this point, I can't determine if it is location (which graph extension) or a special methodology required for this special case.
I also tried overriding events and putting a breakpoint on the code, but it's like I'm not even on the same process. (Yes, I checked that I am connected to the right Acumatica instance and that I have no errors.)
What event in which graph is required to capture the creation in INTranCost for a PO Receipt to update custom fields in INTranCostExt?
Using Request Profiler, I was able to determine that I was close but not deep enough. While the INTranCost object to insert was built in INDocumentRelease FILE, the actual insert was processed in INReleaseProcess graph in that same file.
I only need to execute this "push" from the data captured on the POLine when the INTranCost record is created, and LineNbr is a key field and therefore never updated after it is set. I need to be sure that I have enough data to make the connection back, and the primary key links me back to the INTran easily. That subsequently gets back to the POReceiptLine to the POLine where the data is maintained that needs the "current value" to be captured when the transaction is posted. Since I need to update the DAC Extension, I need to use an event that will allow an existing DAC.Update to apply my values. Therefore, I added an event handler on INTranCost_LineNbr_FieldUpdated since that value should not be "updated" after it is set initially.
Code that accomplished the task:
public class INReleaseProcess_Extension : PXGraphExtension<INReleaseProcess>
{
public override void Initialize()
{
base.Initialize();
}
protected virtual void _(Events.FieldUpdated<INTranCost.lineNbr> e)
{
INTranCost row = (INTranCost) e.Row;
INTran tran = PXSelect<INTran,
Where<INTran.docType, Equal<Required<INTran.docType>>,
And<INTran.refNbr, Equal<Required<INTran.refNbr>>,
And<INTran.lineNbr, Equal<Required<INTran.lineNbr>>
>>>>
.SelectSingleBound(Base, null, row.DocType, row.RefNbr, (int?) e.NewValue);
if (tran?.POReceiptType != null && tran?.POReceiptNbr != null)
{
PXResultset<POReceiptLine> Results = PXSelectJoin<POReceiptLine,
InnerJoin<POLine, On<POLine.orderType, Equal<POReceiptLine.pOType>,
And<POLine.orderNbr, Equal<POReceiptLine.pONbr>,
And<POLine.lineNbr, Equal<POReceiptLine.pOLineNbr>>>>,
InnerJoin<POOrder, On<POOrder.orderType, Equal<POLine.orderType>,
And<POOrder.orderNbr, Equal<POLine.orderNbr>>>>>,
Where<POReceiptLine.receiptType, Equal<Required<POReceiptLine.receiptType>>,
And<POReceiptLine.receiptNbr, Equal<Required<POReceiptLine.receiptNbr>>,
And<POReceiptLine.lineNbr, Equal<Required<POReceiptLine.lineNbr>>>>>>.
SelectSingleBound(Base, null, tran.POReceiptType, tran.POReceiptNbr, tran.POReceiptLineNbr);
if (Results != null)
{
foreach (PXResult<POReceiptLine, POLine, POOrder> result in Results)
{
POReceiptLine receipt = result;
POLine line = result;
POOrder order = result;
POLineExt pOLineExt = PXCache<POLine>.GetExtension<POLineExt>(line);
INTranCostExt iNTranCostExt = PXCache<INTranCost>.GetExtension<INTranCostExt>(row);
if (pOLineExt != null && iNTranCostExt != null)
{
Base.Caches[typeof(INTranCost)].SetValueExt<INTranCostExt.usrField>(row, pOLineExt.UsrField);
}
}
}
}
}
}
In POOrderEntry as a POLine is created or deleted, I need to push a reference back to a custom DAC that originates the PO Line. For instance, if the PO Line is deleted, my custom DAC has the reference removed in Events.RowDeleted via:
using (PXTransactionScope ts = new PXTransactionScope())
{
Base.Caches[typeof(MyDAC)].SetValueExt<MyDAC.pOType>(row, null);
Base.Caches[typeof(MyDAC)].SetValueExt<MyDAC.pONbr>(row, null);
Base.Caches[typeof(MyDAC)].SetValueExt<MyDAC.pOLineNbr>(row, null);
Base.Caches[typeof(MyDAC)].Update(row);
Base.Caches[typeof(MyDAC)].Persist(PXDBOperation.Update);
ts.Complete(Base);
}
I have tried to allow the normal Persist to save the values, but it doesn't unless I call Persist (last line of my example above). The result is an error via Acuminator of "Changes cannot be saved to the database from the event handler". As I look at this, I wonder if it should be in an Long Operation instead of a Transaction Scope, but the error from Acuminator tells me I'm doing this wrong. What is the proper way to achieve my update back to "MyDAC" for each PO Line?
I have also tried initializing a graph instance for MyDAC's graph, but I get a warning about creating a PXGraph in an event handler so I can't "legally" call the graph where MyDAC is maintained.
My code compiles and functions as desired, but the error from Acuminator tells me there must be a more proper way to accomplish this.
You can add a view to the graph extension.
Then in the row deleted you will use your view.Update(row) to update your custom dac.
During the base graph persist your records will commit as long as there are no other errors found in other events.
The way you have it now commits your changes with a chance the row that was being deleted is never deleted.
Also with this change there is no need to use PXTransactionScope.
An example might look something like this...
public class POOrderEntryExtension : PXGraphExtension<POOrderEntry>
{
public PXSelect<MyDac> MyView;
protected virtual void _(Events.RowDeleted<POLine> e)
{
//get your row to update from e.Row
var myRow = PXSelect...
myRow.pOType = null;
myRow.pONbr = null;
myRow.pOLineNbr = null;
MyView.Update(myRow);
}
}
I have added a user defined checkbox UsrContractCustomer to CRCase. My first step is to try to set the checkbox when the user selects the Business Account (CustomerID).
Here is my latest attempt to set the checkbox.
protected void CRCase_CustomerID_FieldUpdated(PXCache cache, PXFieldUpdatedEventArgs e)
{
var row = (CRCase)e.Row;
if (row.CustomerID != null)
{
//CRCaseExt rowExt = PXCache<CRCase>.GetExtension<CRCaseExt>(row);
CRCaseExt rowExt = row.GetExtension<CRCaseExt>();
rowExt.UsrContractCustomer = true;
}
}
On your field in your dac extension you should be able to use a formula to set the value. This will check or uncheck you field when the customer is entered or removed. Having the logic on the field also removes the need to write graph level changes such as events.
[PXFormula(typeof(IIf<Where<CRCase.customerID, IsNull>, False, True>))]
If you want to use the event as you have it I would try cache set value such as:
cache.SetValueExt<CRCaseExt.usrContractCustomer>(e.Row, row.CustomerID != null);
Brendan's solution is correct. In another post I retrieved the value that I wanted to use to set the user-defined field. The 'false' was replaced with a condition that sets the checkbox field.
sender.SetValueExt<CRCaseExt.usrContractCustomer>(crcase, false);
Thanks for the help and support.