Comparing timestamp from 2 different graphs with PXGraph.SelectTimestamp() - acumatica

I am trying to get the value of PXGraph.Timestamp of SOShipment graph and my custom graph to compare on the RowUpdating event. So far using the Document.Search to get my graph and get the timestamp will return the same timestamp as "this.SelectTimestamp()". How would I go about getting the actual timestamp for the first SOShipment graph so it returns the right value?
Below, ts and ts2 are the same value, everytime. I'm guessing because I am creating the graph right before, however I am not sure how to load the graph another way, if it is even possible.
protected virtual void SOShipLine_RowUpdating(PXCache sender, PXRowUpdatingEventArgs e)
{
SOShipmentEntry shipmentGraph = PXGraph.CreateInstance<SOShipmentEntry>();
shipmentGraph.Document.Current = shipmentGraph.Document.Search<SOShipment.shipmentNbr>(row.ShipmentNbr);
shipmentGraph.SelectTimeStamp();
var ts = shipmentGraph.TimeStamp;
this.SelectTimeStamp();
var ts2 = TimeStamp;
}

Related

Where is my error with my join in acumatica?

I want to get all the attributes from my "Actual Item Inventry" (From Stock Items Form) so i have:
PXResultset<CSAnswers> res = PXSelectJoin<CSAnswers,
InnerJoin<InventoryItem,
On<CSAnswers.refNoteID, Equal<Current<InventoryItem.noteID>>>
>
>.Select(new PXGraph());
But, this returns me 0 rows.
Where is my error?
UPDATED:
My loop is like this:
foreach (PXResult<CSAnswers> record in res)
{
CSAnswers answers = (CSAnswers)record;
string refnoteid = answers.RefNoteID.ToString();
string value = answers.Value;
}
... but i can not go inside foreach.
Sorry for the English.
You should use an initialized graph rather than just "new PXGraph()" for the select. This can be as simple as "this" or "Base" depending on where this code is located. There are times that it is ok to initialize a new graph instance, but also times that it is not ok. Not knowing the context of your code sample, let's assume that "this" and "Base" were insufficient, and you need to initialize a new graph. If you need to work within another graph instance, this is how your code would look.
InventoryItemMaint graph = PXGraph<InventoryItemMaint>.CreateInstance<InventoryItemMaint>();
PXResultset<CSAnswers> res = PXSelectJoin<CSAnswers,
InnerJoin<InventoryItem, On<CSAnswers.refNoteID, Equal<Current<InventoryItem.noteID>>>>>
.Select(graph);
foreach (PXResult<CSAnswers> record in res)
{
CSAnswers answers = (CSAnswers)record;
string refnoteid = answers.RefNoteID.ToString();
string value = answers.Value;
}
However, since you should be initializing graph within a graph or graph extension, you should be able to use:
.Select(this) // To use the current graph containing this logic
or
.Select(Base) // To use the base graph that is being extended if in a graph extension
Since you are referring to:
Current<InventoryItem.noteID>
...but are using "new PXGraph()" then there is no "InventoryItem" to be in the current data cache of the generic base object PXGraph. Hence the need to reference a fully defined graph.
Another syntax for specifying exactly what value you want to pass in is to use a parameter like this:
var myNoteIdVariable = ...
InventoryItemMaint graph = PXGraph<InventoryItemMaint>.CreateInstance<InventoryItemMaint>();
PXResultset<CSAnswers> res = PXSelectJoin<CSAnswers,
InnerJoin<InventoryItem, On<CSAnswers.refNoteID, Equal<Required<InventoryItem.noteID>>>>>
.Select(graph, myNoteIdVariable);
foreach (PXResult<CSAnswers> record in res)
{
CSAnswers answers = (CSAnswers)record;
string refnoteid = answers.RefNoteID.ToString();
string value = answers.Value;
}
Notice the "Required" and the extra value in the Select() section. A quick and easy way to check if you have a value for your parameter is to use PXTrace to write to the Trace that you can check after refreshing the screen and performing whatever action would execute your code:
PXTrace.WriteInformation(myNoteIdVariable.ToString());
...to see if there is a value in myNoteIdVariable to retrieve a result set. Place that outside of the foreach block or you will only get a value in the trace when you actually get records... which is not happening in your case.
If you want to get deep into what SQL statements are being generated and executed, look for Request Profiler in the menus and enable SQL logging while you run a test. Then come back to check the results. (Remember to disable the SQL logging when done or you can generate a lot of unnecessary data.)

How do I prevent SOLineSplit and INItemPlan from deleting when Qty = 0?

I noticed that when the quantity of a SOLine is zero, there are no SOLineSplit or INItemPlan records available for that line. The second the quantity is greater than 0, the system makes those records, and if the qty is set back to 0, the records are deleted.
Is there a way to prevent the SOLineSplit and INItemPlan objects from deleting when a record is set to 0 quantity?
Is there a way to still have the system create an SOLineSplit and INItemPlan if the SOLine is initially created with a 0 quantity?
The reason for the question is that a customer wants the system to lock the SOLine after a certain point, but also allow for the Qty to be adjusted from another screen. Since this is not directly changing the value on the SOLine screen, this isn't triggering the events to create the split and plan.
I have tried creating an instance of SOOrderEntry in the custom screen as follows:
SOOrderEntry graph = PXGraph.CreateInstance<SOOrderEntry>();
//Also tried graph.Transactions.Current = line, but did not work
graph.Transactions.Update(line);
graph.Actions.PressSave();
Doing that keeps resulting in a null object reference error:
Error: An error occurred during processing of the field OrderQty : Object reference not set to an instance of an object..
System.NullReferenceException: Object reference not set to an instance of an object.
at PX.Objects.SO.SOOrderEntry.SOLine_OrderQty_FieldUpdated(PXCache sender, PXFieldUpdatedEventArgs e) ...
I think the problem with your statement in using SOOrderEntry is you are not truly loading the order in the graph to update it correctly. After you create the graph instance and before the transaction update, you should load the document header like this...
SOOrderEntry graph = PXGraph.CreateInstance<SOOrderEntry>();
graph.Document.Current = graph.Document.Search<SOOrder.orderNbr>(line.OrderNbr, line.OrderType);
if(graph.Document.Current == null)
{
return;
}
graph.Transactions.Update(line);
graph.Actions.PressSave();
As for controlling how the plan and split records are entered from SOOrderEntry... The entries are controlled through the attributes on PlanID. The cache attached is where this gets added on SOOrderEntry...
[PXMergeAttributes(Method = MergeMethod.Append)]
[SOLineSplitPlanID(typeof(SOOrder.noteID), typeof(SOOrder.hold), typeof(SOOrder.orderDate))]
protected virtual void SOLineSplit_PlanID_CacheAttached(PXCache sender)
{
}
You can make your own graph extension of Sales order and replace the attribute with your own version of SOLineSplitPlanID... it might be a battle for you as I am not sure why you would want the plan record to exist when zero qty to plan.

Map to hold multiple sets of key and values

I have a map1 which holds the information as
[40256942,6] [60246792,5]
Now that I want to prepare a map2 that holds information such as
itemNo, 40256942
qty, 6
itemNo, 60246792
qty, 5
to prepare final information as json
“partialArticlesInfo”: [{itemNo:”40256942”, availQty:”6”}, {itemNo:”60246792”, availQty:”5”}]
I am trying to iterate map1 to retrieve values and set that against the key. But I am getting only one entry which is last one. Is there any way , I get the new map with entries such as mentioned above
Map<String, String> partialArticlesInfo = new HashMap<String,String>();
Map<String, String> partialArticlesTempMap = null;
for (Map.Entry<String,String> entry : partialStockArticlesQtyMap.entrySet())
{
partialArticlesTempMap = new HashMap<String,String>();
partialArticlesTempMap.put("itemNo",entry.getKey());
partialArticlesTempMap.put("availQty",entry.getValue());
partialArticlesInfo.putAll(partialArticlesTempMap);
}
In Java (I'm assuming you're using Java, in the future it would be helpful to specify that) and every other language I know of, a map holds mappings between keys and values. Only one mapping is allowed per key. In your "map2", the keys are "itemNo" and "availQty". So what is happening is that your for loop sets the values for the first entry, and then is overwriting them with the data from the second entry, which is why that is the only one you see. Look at Java - Map and Map - Java 8 for more info.
I don't understand why you are trying to put the data into a map, you could just put it straight into JSON with something like this:
JSONArray partialArticlesInfo = new JSONArray();
for (Map.Entry<String,String> entry : partialStockArticlesQtyMap.entrySet()) {
JSONObject stockEntry = new JSONObject();
stockEntry.put("itemNo", entry.getKey());
stockEntry.put("availQty", entry.getValue());
partialArticlesInfo.put(stockEntry);
}
JSONObject root = new JSONObject();
root.put("partialArticlesInfo",partialArticlesInfo);
This will take "map1" (partialStockArticlesQtyMap in your code) and create a JSON object exactly like your example - no need to have map2 as an intermediate step. It loops over each entry in map1, creates a JSON object representing it and adds it to a JSON array, which is finally added to a root JSON object as "partialArticlesInfo".
The exact code may be slightly different depending on which JSON library you are using - check the docs for the specifics.
I agree with Brendan. Another solution would be otherwise to store in the Set or List objects like the following.
class Item {
Long itemNo;
int quantity;
public int hashCode() {
Long.hashCode(itemNo) + Integer.hashCode(quantity);
}
public int equals(Object other) {
other instanceOf Item && other.itemNo == this.itemNo && other.quantity = this.quantity;
}
}
}
then you can use the JsonArray method described by him to get the Json string in output
This means that adding new variables to the object won't require any more effort to generate the Json

Android Plot for String Parameters

My app requires the Y-axis to have strings like 'Charging', 'Discharging' and 'Charging Failed'. Is it possible to plot a graph with this and have the parameter in question depicted in accordance with these strings on Android Plot?
I'm still not 100% sure I'm understanding the desired visualization but here are the basic steps I would suggest:
To start, you're going to need to convert your CSV data in to XYSeries data. To accomplish this, you'll need to map your current X/Y string values to numbers. I'd suggest creating a method that looks something like this:
// parses a CSV string into an XYSeries
// for example, DISCHARGE = 1, MPPT = 2
public XYSeries convertCSVToXYSeries(String csvContent) {...}
Next, setup your Plot etc. pretty much the same way you would for any other XYPlot as shown in the Androidplot Quickstart Tutorial.
When you add the XYSeries you get back from convertCSVToXYSeries to your plot, use an XYStepFormatter:
StepFormatter stepFormatter = new StepFormatter(Color.BLUE, Color.BLUE);
stepFormatter.setVertexPaint(null); // don't draw individual points
plot.addSeries(series, stepFormatter);
Finally, add a custom range value formatter to print your status strings instead of the int values they've been mapped to:
// create a custom getFormatter to draw our state names as range tick labels:
plot.setRangeValueFormat(new Format() {
#Override
public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
Number num = (Number) obj;
switch(num.intValue()) {
case 1:
toAppendTo.append("DISCHARGE");
break;
case 2:
toAppendTo.append("MPPT");
break;
default:
toAppendTo.append("Unknown");
break;
}
return toAppendTo;
}
#Override
public Object parseObject(String source, ParsePosition pos) {
return null;
}
});

Conversion Of Map Location To String

Below is the code i am running with all other.. Its running perfectly adn its showing all the desired locations on map.
But what i want now is to store all the marked locations in such a way that i can show them as a list on a new page.
I am not able to retrieve the resulted location from map in the form of some string or may be something else which can be displayed as a list ...
private void Button_Click_3(object sender, RoutedEventArgs e)
{
MapsTask mapsTask = new MapsTask();
string search = "Coffee";
mapsTask.SearchTerm = search;
mapsTask.ZoomLevel = 2;
mapsTask.Show(); }
The MapsTask does not return any information.
If you're looking to get Points of Interest for a given location, you may have to use an external service such as the HERE Places API.

Resources