How to sort a Data delegate array - acumatica

I am populating data using 2 views inside a data delegate. I have to calculate running balance by sorting the based on transaction date. How do i sort the data and populate the running balance.
The delegate code is given below.
[PXVirtualDAC]
public PXSelectOrderBy<FundBalanceData, OrderBy<Asc<FundBalanceData.tranDate>>> fbdata;
protected virtual IEnumerable FBData()
{
List<FundBalanceData> importlist = new List<FundBalanceData>();
PXSelectBase<ARPayment> cmd = new PXSelectJoin<ARPayment, InnerJoin<GLTran, On<ARPayment.batchNbr, Equal<GLTran.batchNbr>>,
InnerJoin<PMProject, On<GLTran.projectID, Equal<PMProject.contractID>>>>,
Where<GLTran.projectID, Equal<Current<PMProject.contractID>>,
And<ARPayment.docType, Equal<ARPaymentType.prepayment>>>>(Base);
foreach(PXResult<ARPayment,GLTran,PMProject> line in cmd.Select())
{
FundBalanceData data = new FundBalanceData();
ARPayment arp = line;
PMProject pmp = line;
GLTran glt = line;
data.BAccountID = arp.CustomerID;
data.CreditAmount = glt.CreditAmt;
data.DebitAmount = glt.DebitAmt;
data.RefNbr = arp.RefNbr;
data.DocType = arp.DocType;
data.Desc = arp.DocDesc;
data.TranDate = arp.DocDate;
importlist.Add(data);
}
PXSelectBase<APAdjust> cmd2 = new PXSelectJoin<APAdjust, LeftJoin<GLTran, On<APAdjust.adjBatchNbr, Equal<GLTran.batchNbr>, And<APAdjust.adjdAPAcct, Equal<GLTran.accountID>>>,
InnerJoin<APPayment, On<APAdjust.adjgRefNbr, Equal<APPayment.refNbr>, And<APAdjust.adjgDocType, Equal<APPayment.docType>>>,
InnerJoin<APTran,On<APTran.refNbr,Equal<APAdjust.adjdRefNbr>,And<APTran.tranType,Equal<APAdjust.adjdDocType>>>>>>,
//InnerJoin<GLTran, On<APTran.projectID, Equal<GLTran.projectID>>>>>,
Where<APAdjust.adjgDocType, Equal<APPaymentType.prepayment>, And<APTran.projectID, Equal<Current<PMProject.contractID>>, And<GLTran.accountID, NotEqual<APPayment.aPAccountID>>>>>(Base);
foreach (PXResult<APAdjust,GLTran,APPayment,APTran> line in cmd2.Select())
{
FundBalanceData data = new FundBalanceData();
APPayment arp = line;
GLTran glt = line;
APAdjust apd = line;
data.BAccountID = arp.VendorID;
data.CreditAmount = glt.CreditAmt;
data.DebitAmount = glt.DebitAmt;
data.RefNbr = arp.RefNbr;
data.DocType = arp.DocType;
data.Desc = arp.DocDesc;
data.TranDate = arp.DocDate;
importlist.Add(data);
}
decimal? balance = decimal.Zero;
foreach(FundBalanceData data in importlist)
{
balance = balance + (data.CreditAmount - data.DebitAmount);
data.Balance = balance;
}
return importlist;
}
The array is not sorted by TranDate and the balance calculated is wrong
The result after implementing Samvel Petrosov suggestion
I was trying to sort the array on DateTime? and missed used the Value property. I have tried Samvel Petrosov suggestion and it worked.

Here is the part about sorting of the Result set of data views from T200 Acumatica Framework Fundamentals Course:
A data view executes the delegate by the following rules:
If a delegate is defined, invoke the delegate
If the delegate returns null, execute the BQL command
If the delegate returns an object, reorder the result according to the OrderBy clause of the BQL command
If a delegate is not defined, execute the BQL command
The result set returned by the data view is always sorted by the ORDER
BY clause specified in the type of the data view object. If you sort
data records in a different way within the delegate, the result set
will be reordered before it is returned by the data view.
The calculation of the Balance in your code is done before the return of the result set. That is way it is not calculated as you are waiting. The sorting is taking place after you return the result set.
UPDATE 1
Change your cmd and cmd2 to the following queries:
PXSelectBase<ARPayment> cmd = new PXSelectJoin<ARPayment, InnerJoin<GLTran, On<ARPayment.batchNbr, Equal<GLTran.batchNbr>>,
InnerJoin<PMProject, On<GLTran.projectID, Equal<PMProject.contractID>>>>,
Where<GLTran.projectID, Equal<Current<PMProject.contractID>>,
And<ARPayment.docType, Equal<ARPaymentType.prepayment>>>,OrderBy<Asc<ARPayment.DocDate>>>(Base);
PXSelectBase<APAdjust> cmd2 = new PXSelectJoin<APAdjust, LeftJoin<GLTran, On<APAdjust.adjBatchNbr, Equal<GLTran.batchNbr>, And<APAdjust.adjdAPAcct, Equal<GLTran.accountID>>>,
InnerJoin<APPayment, On<APAdjust.adjgRefNbr, Equal<APPayment.refNbr>, And<APAdjust.adjgDocType, Equal<APPayment.docType>>>,
InnerJoin<APTran,On<APTran.refNbr,Equal<APAdjust.adjdRefNbr>,And<APTran.tranType,Equal<APAdjust.adjdDocType>>>>>>,
//InnerJoin<GLTran, On<APTran.projectID, Equal<GLTran.projectID>>>>>,
Where<APAdjust.adjgDocType, Equal<APPaymentType.prepayment>, And<APTran.projectID, Equal<Current<PMProject.contractID>>, And<GLTran.accountID, NotEqual<APPayment.aPAccountID>>>>,OrderBy<Asc<APPayment.DocDate>>>(Base);
UPDATE 2
Try to add additional sorting by transaction date before the last loop:
importlist= importlist.OrderBy(x => x.TranDate.Value).ToList();
or if TranDate is not DateTime?
importlist= importlist.OrderBy(x => x.TranDate).ToList();

Related

Acumatica - get the last displayed record

Is there an eloquent way, more or less, to get the last displayed record in a grid in Acumatica? Let's say even if they do all the sorting and rearranging, is there a way for example when pressing a button on a grid to get the last record? Basically, I would like to copy that record as a new one.
Create a PXAction for your button.
Inside the PXAction iterate in your data view until the last record.
For example, if the name of your Data view Bound to your grid is YzLines, and object type in the grid line (DAC) is Yz, then it can be:
Yz lastLine;
foreach (Yz line in YzLines.Select())
lastLine = line;
To get to the last record you can also use .Last() or .LastOrDefault().
If you need the last record according to client sorting, you should implement a data view delegate, it looks like this:
protected virtual IEnumerable yzLines()
{
PXSelectBase<Yz> cmd =
new PXSelectJoinGroupBy<Yz, ...>(this);
int startRow = PXView.StartRow; //Get starting row of the current page
int totalRows = 0;
foreach (PXResult<Yz> res in
cmd.View.Select(null, null,
PXView.Searches,
ARDocumentList.View.GetExternalSorts(),//Get sorting fields
ARDocumentList.View.GetExternalDescendings(),//Get sorting direction
ARDocumentList.View.GetExternalFilters(),//Get filters
ref startRow,
PXView.MaximumRows, //Get count of records in the page
ref totalRows))
{
//processing of records
}
PXView.StartRow = 0;//Reset starting row
}

Value does not fall within the expected range - Exception for SharePoint Lookup Field

I am trying to copy data from one list to other list (both lists are on different sites) along with lookup columns. But, I am getting an error for lookup field as:
Value does not fall within the expected range
Code works and data gets copied for other non-lookup fields. I tried every possible way including increasing List View Lookup Threshold and all possible ways of code but still error persists at ExecuteQuery().
Below is my code for lookup field:
if (field is FieldLookup && field.InternalName == "Country")
{
var CountryLookup = (item.FieldValues["Country"] as FieldLookupValue).LookupValue.ToString();
var CountryLookupId = (item.FieldValues["Country"] as FieldLookupValue).LookupId.ToString();
FieldLookupValue flvRDS = new FieldLookupValue();
flvRDS.LookupId = int.Parse(CountryLookupId);
itemToCreate["Country"] = flvRDS;
itemToCreate.Update();
destContext.ExecuteQuery();
}
Help is really appreciated.
I assume item is the new ListItem you're trying to create on your target list.
But you're never in fact reading any value from field here! So basically, you're trying to set your new FieldLookup.LookupId with the item["Country"].LookupId, which should logically be empty at this moment.
Here's a method I use to retrieve a lookup field ListItem from a value, feel free to modify it to fit your need, since I don't know how you want to retrieve it (SPList is an alias for Microsoft.SharePoint.Client.List).
private ListItem GetLookupItem(FieldLookup lookupField, string lookupValue)
{
string mappingField = lookupField.LookupField;
Microsoft.SharePoint.Client.List lookupList = Context.Web.Lists.GetById(new Guid(lookupField.LookupList));
Context.Load(lookupList);
Context.ExecuteQuery();
ListItemCollection libListItems = lookupList.GetItems(CamlQuery.CreateAllItemsQuery());
Context.Load(libListItems, items => items.Include(
itemlookup => itemlookup.Id,
itemlookup => itemlookup[mappingField]));
Context.ExecuteQuery();
foreach (ListItem mappedItem in libListItems)
{
object mappedField = mappedItem[mappingField];
if (mappedField != null && mappedField.ToString().Equals(lookupValue))
return mappedItem;
}
return null;
}
Now that you have the corresponding ListItem, you can set your item.LookupId with its Id:
if (field is FieldLookup && field.InternalName == "Country")
{
FieldLookupValue flvRDS = new FieldLookupValue();
flvRDS.LookupId = GetLookupItem(field as FieldLookup, "France").Id; // here, dunno how you get your country's name
itemToCreate["Country"] = flvRDS;
itemToCreate.Update();
destContext.ExecuteQuery();
}
Feel free to add some more previous code if you want an answer more suited for your specific issue.

Returning an Object[][] gives NullPointerException

I have an Access database which I need to retrieve all fields except the first and last and display it in a JTable. Everything works perfectly fine when I create my Object[][] but when i return it, i get a NullPointerException. I tried to find where there could be a null value in the database by printing the whole object out but that works fine and no values are null. Why would returning the Object[][] give me a NullPointerException and how can i fix it?
the stack trace is:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
public Object [] [] SetTrainingLogTable() throws SQLException
{
DatabaseConnection connection = new DatabaseConnection();
//Retrieves all the data from the TrainingLog table
ResultSet resultset = connection.SelectStatements("SELECT * FROM TrainingLog");
//Retrieves the number of entries
ResultSet numberofworkouts = connection.SelectStatements("SELECT COUNT(*) FROM TrainingLog");
int count = numberofworkouts.getInt(1);
number = count;
String[][] table = new String [count] [6];
//Number to incriment for while loops
int row = 0;
String date = "";
while(row<count)
{
date = resultset.getString(2);
table [row][0] = calculate.RefineDate(date);
table [row][1] = resultset.getString(3);
table [row][2] = resultset.getString(4);
table [row][3] = resultset.getString(5);
table [row][4] = resultset.getString(6);
table [row][5] = resultset.getString(7);
resultset.next();
row++;
}
Object[][] data = table;
connection.close();
return data;
}
I ran a debugger and it only gives the error when the return line is run.
It's best to post the stack trace and tell which line is raising the error. However, the typical way of writing such code is:
Connection con = ...;
Statement st = ...;
ResultSet rs = ...;
while (rs.next()) {
// ...
}
The result set starts out pointing before the first row. rs.next() returns whether there is a next row, and advances to it if it exists. Can you rewrite it in that style?
Other suggestions:
Can you create an actual object type instead of using Object[] to store the data from each row? Call it Workout.
Can you use a List<Workout> instead of your Object[][]?
Is the date stored in the database as a SQL DATE or TIMESTAMP? Then, don't convert it to a Java String: use java.sql.Date or java.util.Date. At work, I have a large old program that uses strings for dates, and it uses different formats to convert the values at different times. It's pretty miserable.
Don't use SELECT *. Give the names of the columns to return. Use the rs.getString("column_name") syntax.
There's no need to set one variable to the returned table and immediately set another variable to it.
Closing the connection or statement should be done in a finally block, or by try-with-resources.

Adding a mock Datatable in Unit Testing

I am Unit Testing one of my functions. Here is my code:
public void TestLabels()
{
//Step 1: Creating a mock table with columns exactly like in the real table.
DataTable table = new DataTable();
DataRow mydatarow;
mydatarow = table.NewRow();
//Step 2: Adding the row as same as the Real Data!
mydatarow["Name"] = "Test";
mydatarow["Address"] = "00000 ST.";
mydatarow["ZipCode"] = "77665";
mydatarow["Tracking#"] = "";
table.Rows.Add(mydatarow);
foreach (DataColumn column in table.Columns)
Console.WriteLine(column.ColumnName);
//Step 3: Call method we are testing.
var updateTable = IceTechUPSClient.Instance.CreateLabels(table);
foreach (DataRow row in updateTable.Rows)
{
var trackingNumber = row["Tracking#"].ToString();
Assert.IsFalse(String.IsNullOrWhiteSpace(trackingNumber), "Expecting tracking number generated for every row!");
Assert.IsTrue(File.Exists(trackingNumber + ".gif"));
}
}
Now I am getting an error: Column 'Name' does not belong to table. As you can see I have specified column name "Name" here and also added that particular row. Then why I am getting this error? Any help?
Thanks!
You haven't set up your columns (unless you've missed out some code in your example).
You need to create the columns with the required names before you can access them like this:
var columnSpec = new DataColumn
{
DataType = typeof(string),
ColumnName = "Name"
};
this.table.Columns.Add(columnSpec);
When you read data from the database if you've set AutoGenerateColumns to true (the default) you don't need to do this explicitly as it's done for you behind the scenes.

Subsonic 3 - Sequence contains no matching element

I need help creating a LINQ SQL with subsonic. First the basics, this works fine:
var query = (from o in bd.concelhos
orderby o.descricao
select o);
var results = query.ToList<concelhos>();
However, I want to filter out some columns and I have created the following code:
var query = (from o in bd.concelhos
orderby o.descricao
select new FilteredConcelhos { id = o.idDistrito + "/" + o.idConcelho, descricao = o.descricao });
var results = query.ToList<FilteredConcelhos>();
which errors out in the ToList method with the description "Sequence contains no matching element"
Any help would be great with this...
update:
Turns out I was missing get set attributes in the newly declared class...
Like so
public class FilteredConcelhos
{
public string id { get; set; }
public string descricao { get; set; }
}
This clears the exception, but the resulting List is still all wrong (FilteredConcelhos.id contains nothing and FilteredConcelhos.descricao contains numbers)
Can you try to first execute the ToList and the select afterwards - then the select is performed via linq 2 objects!
Have you tried to work with an anonymous type?
var query = (from o in bd.concelhos
orderby o.descricao
select new { id = o.idDistrito + "/" + o.idConcelho,
descricao = o.descricao });
var results = query.ToList();
Unfortunately, this happened to me a lot. I'm not sure about the details of how Linq 2 Object works, but if you'll call ToList on the original object, like this:
from o in bd.concelhos.ToList()
...
It should do the trick.

Resources