Acumatica 2020R1 - FirstOrDefault selecting a different row - acumatica

I have used FirstOrDefault a ton in my code (its a habit, I used linq2sql a lot in the past) and use it in Acumatica. Per development support, it should only be used when you are expecting one result.
I have some code on SOOrderEntry that gets the item on the current line by clicking a button and checking a few things. This is in my Graph Extension.
This code worked prior to the upgrade:
SOLine Line = Base.Transactions.Current;
InventoryItem Item = SelectFrom<InventoryItem>.Where<InventoryItem.inventoryID.IsEqual<#P.AsInt>>.View.Select(Base, Line.InventoryID).FirstOrDefault();
InventoryItemExt ItemExt = Item.GetExtension<InventoryItemExt>();
The result is not as expected. Line.InventoryID returns 10045, which is the correct item. Item.InventoryID is 10046

After debugging, I found that the new argument that can be used easily is the new property TopFirst. This returns the First Result.
The following code works as expected (and how it worked in 2019 R2 and before!).
SOLine Line = Base.Transactions.Current;
InventoryItem Item = SelectFrom<InventoryItem>.Where<InventoryItem.inventoryID.IsEqual<#P.AsInt>>.View.Select(Base, Line.InventoryID).TopFirst;
InventoryItemExt ItemExt = Item.GetExtension<InventoryItemExt>();

Related

How to add a column to the grid that shows value from another screen in Acumatica?

I'm new to Acumatica, could you please help me? I have too screens IN202500 (stock items) and SO301000(sales orders). I added a field to stock items and now I need to show a value from that field in grid column of sale orders for each stock items. I suppose that I need to use PXDefault attribute for this?
There are a number of ways you can do this. I'll provide 3 possibilities.
If your View used by the grid contains InventoryItem, you may be able simply to select your custom field from InventoryItem and add it directly to the screen. I'll assume this is not an option or you likely would have found it already.
Create a custom field in a DAC extension on SOLine where you add your custom field as unbound (PXString, not PXDBString) and then use PXDBScalar or PXFormula to populate it. I haven't used PXDBScalar or PXFormula to retrieve a value from a DAC Extension, so I'll leave it to you to research. I do know this is super easy if you were pulling a value directly from InventoryItem, so worth doing the research.
Create as an unbound field as in #2, but populate it in the SOLine_RowSelecting event. This is similar to JvD's suggestion, but I'd go with RowSelecting because it is the point where the cache data is being built. RowSelected should be reserved, in general, for controlling the UI experience once the record is already in the cache. Keep in mind that this will require using a new PXConnectionScope, as Acuminator will advise and help you add. (Shown in example.) In a pinch, this is how I would do it if I don't have time to sort out the generally simpler solution provided as option 2.
Code for Option 3:
#region SOLine_RowSelecting
protected virtual void _(Events.RowSelecting<SOLine> e)
{
SOLine row = (SOLine)e.Row;
if (row == null)
{
return;
}
using (new PXConnectionScope())
{
SOLineExt rowExt = row.GetExtension<SOLineExt>();
InventoryItem item = SelectFrom<InventoryItem>
.Where<InventoryItem.inventoryID.IsEqual<#P.AsInt>>
.View.Select(Base, row.InventoryID);
InventoryItemExt itemExt = item.GetExtension<InventoryItemExt>();
rowExt.UsrSSMyDatAField = itemExt.UsrSSMyDataField;
}
}
#endregion

Updating the sales order line Unit Price

I am trying to override the unit price in sales order entry with my own price looked up elsewhere. I do have it working with the code below but what I cannot figure out is why the line that is commented out causes a "Stack Overflow". The price does update correctly and does save to the database from session to session.
The examples I followed were provided in this post and there it's clear that the commented out line is needed : Sales Price Updating Every Other Time
What it seems to be doing is the line Base.Transactions.Update(soLine); calls SOLine_RowUpdating and then you in an infinite loop.
Thanks
protected virtual void SOLine_RowUpdating(PXCache sender, PXRowUpdatingEventArgs e)
{
if (e.NewRow == null)
{
return;
}
SOLine soLine = (SOLine)e.NewRow;
decimal NewUnitPrice = 12349.56M;
sender.SetValueExt<SOLine.curyUnitPrice>(soLine, NewUnitPrice);
Base.Transactions.Cache.RaiseRowUpdated(soLine, soLine);
// Base.Transactions.Update(soLine);
Base.Transactions.View.RequestRefresh();
}
Let's say that your extension is named SOOrderEntryExt ( for simplification of explanation ).
Then we have 3 Actors:
1. SOOrderEntry, with it's method SOLine_RowUpdating ( created by Acumatica team )
2. SOOrderEntryExt with it's method SOLine_RowUpdating ( created by you )
3. Acumatica cache
4. Acumatica
Acumatica has following code:
Each time after SOLine is modified in cache, I need to execute two methods:
SOOrderEntry.SOLine_RowUpdating
SOOrderEntryExt.SOLine_RowUpdating
Following line of code:
Base.Transactions.Update(soLine);
basically says to Acumatica, hey, soLine was updated in the cache. What Acumatica should do? Execute those two lines again:
SOOrderEntry.SOLine_RowUpdating
SOOrderEntryExt.SOLine_RowUpdating
and again, and again, and again.
Then question arises, how to execute
SOOrderEntry.SOLine_RowUpdating
without causing eternal cycle? Next line of code is a solution:
Base.Transactions.Cache.RaiseRowUpdated(soLine, soLine);

RowPersisted on two different DAC's are in infinite loop

I currently have custom RowPersisted events on SOLine and POLine in Acumatica. Basically I need to make sure that custom Vendor cost field in SO and unit price field in PO update each other for all the linked PO's and SO's, when user saves them in Acumatica. So I have something like this in POLine_RowPersisted:
soRecExt.UsrVendorCost = line.CuryUnitCost;
SOOrderEntry graph = PXGraph.CreateInstance<SOOrderEntry>();
graph.CurrentDocument.Current = soOrd;
var result = graph.Transactions.Select();
graph.Transactions.Update(soRec);
graph.Actions.PressSave();
And something like this in SOLine_RowPersisted:
poRec.CuryUnitCost = lineExt.UsrVendorCost;
POOrderEntry graph = PXGraph.CreateInstance<POOrderEntry>();
graph.CurrentDocument.Current = poOrd;
var result = graph.Transactions.Select();
graph.Transactions.Update(poRec);
graph.Actions.PressSave();
So unfortunately when one is updated the whole thing enters infinite loop. I have tried something like this:
POOrderEntry_Extension graphExt = graph.GetExtension<POOrderEntry_Extension>();
graphExt.RowPersisted.RemoveHandler<SOOrderEntry_Extension>(graphExt.POLine_RowPersisted);
However, there is no RowPersisted on graph extension. My events are set to public. Can someone help please?
The events are registered and triggered by the Base graph so you have to remove them on base graph.
I believe what you're trying to accomplish is more along the lines of:
POOrderEntry_Extension graphExt = graph.GetExtension<POOrderEntry_Extension>();
graphExt.Base.RowPersisted.RemoveHandler<POOrderEntry>(graphExt.POLine_RowPersisted);
Where 'graph' is of type POOrderEntry then using 'graph' is equivalent to 'graphExt.Base'.

Can't set Orchard field values unless item already created

I seem to be having a problem with assigning values to fields of a content item with a custom content part and the values not persisting.
I have to create the content item (OrchardServices.ContentManager.Create) first before calling the following code which modifies a field value:
var fields = contentItem.As<MyPart>().Fields;
var imageField = fields.FirstOrDefault(o => o.Name.Equals("Image"));
if (imageField != null)
{
((MediaLibraryPickerField)imageField).Ids = new int[] { imageId };
}
The above code works perfectly when against an item that already exists, but the imageId value is lost if this is done before creating it.
Please note, this is not exclusive to MediaLibraryPickerFields.
I noticed that other people have reported this aswell:
https://orchard.codeplex.com/workitem/18412
Is it simply the case that an item must be created prior to amending it's value field?
This would be a shame, as I'm assigning this fields as part of a large import process and would inhibit performance to create it and then modify the item only to update it again.
As the comments on this issue explain, you do need to call Create. I'm not sure I understand why you think that is an issue however.

Approve file without modifying Modified date and editor values using Client Object Model

http://social.technet.microsoft.com/Forums/ar/sharepoint2010programming/thread/b60495ee-29be-4aa0-935e-484abce6b9d2 explains how to approve a file using Client Object Model. Doing so, the 'modified date' and 'modified by' values gets changed (which is obvious).
But, I have a requirement to approve the File without changing those field values.
Can it be done?
If I first publish the file and then update the above-mentioned fields, then the version gets incremented, which is undesirable.
Thanks and Regards,
Arjabh
Instead of using .update() use .systemupdate() - this bypasses modifying the date last I checked.
ListItem item = get the item here
item["Modified"] = modifiedDate; // new modified date
FieldUserValue newModifiedBy = new FieldUserValue();
newModifiedBy.LookupId = modifiedBy; // your LookupId value
item["Editor"] = newModifiedBy;
item.Update();
$ctx.ExecuteQuery();

Resources