Acumatica - Copy last row - acumatica

So looks like seemingly easy things in Acumatica are terribly complicated to implement. All I wanna do is to copy last row of my grid as a new one. I would like the user to persist the changes himself, so my code would put it just in cache. This is my action so far:
public PXAction<SOOrder> copyLastRow;
[PXUIField(DisplayName = "Copy Last Row", MapEnableRights = PXCacheRights.Select, MapViewRights = PXCacheRights.Select)]
[PXLookupButton]
public virtual IEnumerable CopyLastRow(PXAdapter adapter)
{
SOLine line = Base.Transactions.Select().LastOrDefault();
int? lineNbr = 0;
foreach(SOLine line2 in Base.Transactions.Select())
if (line2.LineNbr > lineNbr)
lineNbr = line2.LineNbr;
line.LineNbr = lineNbr + 1;
Base.Transactions.Cache.Insert(line);
return adapter.Get();
}
So maybe I am not getting something or completely wrong in my code, but I'm getting errors no matter what I do. The grid is not getting refreshed with my row and I keep getting all sorts of errors, such as "This record cannot be saved" or "another process updated this record", etc. Also, any ideas on how to generate a new lineNbr without clunky logic I have? Much appreciated if anyone can help.

If you just want to take the line and copy all values you can use cache copy and null the lineid. Then on insert of the copied line it will get the next linenbr automatically... adding to your sample code in your question...
SOLine line = Base.Transactions.Select().LastOrDefault();
var copy = (SOLine)Base.Transactions.Cache.CreateCopy(line);
copy.LineNbr = null;
Base.Transactions.Cache.Insert(copy);
This method should also be upgrade friendly in the event new fields or customization are added to SOLine they will continue to be copied without having to selectively include all fields to be copied (using CreateCopy).

The code should be like this:
public PXAction<SOOrder> copyLastRow;
[PXUIField(DisplayName = "Copy Last Row", MapEnableRights = PXCacheRights.Select, MapViewRights = PXCacheRights.Select)]
[PXProcessButton]
public virtual IEnumerable CopyLastRow(PXAdapter adapter)
{
SOLine line = Base.Transactions.Select().LastOrDefault();
SOLine newLine = new SOLine();
... (copy all you need from line to newLine)
Base.Transactions.Cache.Insert(newLine);
Base.Actions.PressSave();
return adapter.Get();
}

It is my guess that Line Number will get automatically generated ! It is not in sequence anyway.
I suggest you create a new SOline row and transfer the enterable fields from the selected row (Last row) in the same and Insert. Should work.

If you don't want attachments or notes to copy make sure to add
copy.NoteID = null;

Related

Acumatica - Copying a row in Purchase Orders screen

We would like to copy current row in acumatica via button in Purchase Orders screen. I asked question about that earlier in Acumatica - Copy last row
None of the solutions work anymore in 2020 R1, build 20.104.0012. It appears that NoteID needs to be set to null, in addition to line ID. Ilya's solution in the link above does not create the second line at all, after the PressSave is run. Brandon's solution generates "An item with the same key has already been added." error. My updated action is below:
public PXAction<POOrder> copyRow;
[PXButton]
[PXUIField(DisplayName = "Copy Row")]
protected virtual IEnumerable CopyRow(PXAdapter adapter)
{
var row = Base.Transactions.Current;
var rowCopy = Base.Transactions.Cache.CreateCopy(row) as POLine;
rowCopy.LineNbr = null;
rowCopy.NoteID = null;
rowCopy = Base.Transactions.Insert(rowCopy);
return adapter.Get();
}
Please advise.

How to make row dynamic in Data Driven Framework

I am working on a Data Driven Project where my test data is from an excel sheet. Am able to fetch data from sheet, but I need to pass only the column value but not Row value in step defn method, so that my test case can complete one set of testing with one row and move to next row.
My code:
public static int getCellData() throws Exception{
int rowData=0;
int NumOfRows=0;
try{
NumOfRows = ExcelWSheet.getPhysicalNumberOfRows();
for(int i=2;i<NumOfRows;i++){
rowData = ExcelWSheet.getRow(i).getPhysicalNumberOfCells();}
}
catch (Exception e){}
return rowData;
}

Imported/Copied Opportunity shift one line

Lines are shifting with custom fields in the Opportunity Products grid one row down at a customized site.
Background:
We have a customization which provides unit margins and % in the header. PXFormula is used on the DAC for any dependent on a calculation.
Opportunity Products has 4 added fields:
Last Cost = Last Cost from InventoryItem
Total Cost = Qty * Last Cost
Margin = ExtAmt - ExtCost
Manual Cost, a checkbox to allow manual override of Last Cost
Opportunity has 2 added fields:
Margin Total = Sum of Margins
Margin % = Margin Total/Sales Total
Problem:
There is an issue with a customization Opportunities where lines shift one line when a record is copied from an existing Opportunity or when an Excel file is imported.
Existing Record
After Copy/Paste or Import from Excel
Code:
My current code:
public PXSelect<INItemCost,
Where<INItemCost.inventoryID,
Equal<Current<CROpportunityProducts.inventoryID>>>> Cost;
protected void CROpportunityProducts_RowInserting(PXCache cache,
PXRowInsertingEventArgs e, PXRowInserting InvokeBaseHandler)
{
if(InvokeBaseHandler != null)
InvokeBaseHandler(cache, e);
var row = (CROpportunityProducts)e.Row;
if (row == null) return;
var rowExt = cache.GetExtension<CROpportunityProductsExt>(row);
if (rowExt == null) return;
var cost = Cost.SelectSingle();
if (cache.GetValue(row, "usrManCost") == null) return;
if (cost != null && (bool)cache.GetValue(row, "usrManCost") == false)
{
cache.SetValueExt<CROpportunityProductsExt.usrLastCost>(row, cost.LastCost);
}
}
What could be causing this? I have thoughts that the RowInserting event returns 0 for the first line since the PXSelect<> statement returns 0 because InventoryItem is not in cache until the next row.
One potential solution I came up with was using RowInserted. This resolves the issue when using Copy/Paste. However, it causes Import from Excel to miscalculate Total Margin.
Could be the Current<> on your view is not really the current you need?
What happens if you simply replace the var cost = Cost.SelectSingle() line with the following to use Required<> as pass in the Inventory ID...
INItemCost cost = PXSelect<INItemCost,
Where<INItemCost.inventoryID, Equal<Required<CROpportunityProducts.inventoryID>>>>
.Select(Base, row.inventoryID);
The answer is because events in this case must be done in the RowSelecting event handler, along with PXConnectionScope().
Brendan was on the right track moving the PXSelect into the handler. My code in the question becomes the below. Also, note use of Required<> versus Current<>.
public void CROpportunityProducts_RowSelecting(PXCache cache,
PXRowSelectingEventArgs e)
{
var row = (CROpportunityProducts)e.Row;
if (row == null) return;
using (new PXConnectionScope())
{
INItemCost cost = PXSelect<INItemCost,
Where<INItemCost.inventoryID,
Equal<Required<INItemCost.inventoryID>>>>.Select(Base, row.InventoryID);
if (cost != null && (bool)cache.GetValue(row, "usrManCost") == false)
{
//decimal dbLastCost = (decimal)cost.LastCost;
var lstCost = cache.GetValue(row, "usrLastCost");
if ((decimal)cost.LastCost == (decimal)0.00)
{
cache.SetValueExt<CROpportunityProductsExt.usrLastCost>(row,
cost.LastCost);
}
}
}
}

deleting row from datagridview

I want to delete row from datagridview when user clicks the delete button.The datagridview bounded to datatable _dt so i remove the row from _dt and try to rebind the modified _dt to datagridview but instead of deleting the row gets added to the last row of the datagridview what am I doing wrong here
private void btnDelete_Click(object sender, EventArgs e)
{
if (dataGridView1 != null && dataGridView1.SelectedRows.Count == 1)
{
string key = dataGridView1.SelectedRows[0].Cells["ID"].Value.ToString();
DataColumn[] keyColumns = new DataColumn[1];
keyColumns[0] = _dt.Columns["ID"];
_dt.PrimaryKey = keyColumns;
rowToDelete = _dt.Rows.Find(key);
_dt.Rows.Remove(rowToDelete);
_dt.AcceptChanges();
SqlCommandBuilder cb = new SqlCommandBuilder(_sqlDa);
_sqlDa.Fill(_dt);
_sqlDa.Update(_dt);
dataGridView1.DataSource = null;
dataGridView1.DataSource = _dt;
}
}
No need for Fill before update and also delete this row
_dt.AcceptChanges();
because this will remove the row from memory and when you call update
only the remaining rows are updated, it will not delete the row from database.
No need to call Fill Before Update, because Fill will get data again from db and your changes will be lost. So This will work for you.
SqlCommandBuilder cb = new SqlCommandBuilder(_sqlDa);
//_sqlDa.Fill(_dt);
_sqlDa.Update(_dt);

Selecting DataGridViewRow at a selected Index

I am having problems selecting a row out of the DataGridView on a search. The data source is a DataTable from a database. I am using a search box that checks the DataGridView for a product matching the product key, and i want to select it if found.
Here is what i have:
private void search_btn_Click(object sender, EventArgs e)
{
foreach (DataGridViewRow row in products_dgv.Rows)
{
string tempCode = row.Cells[0].Value.ToString(); //Code comparing
if (tempCode == code_tb.Text) //Checks if code matchs the search code
{
//I would like to do a products_dgv.selectedIndex = row.Index but it
//doesnt work
break;
}
}
}
Any help is much appreciated. Thank You!
You can use the CurrentCell property of the DataGridView to set the selection. If you are using FullRowSelect as selection mode, just use any cells in the row that you would like to select.
For example:
...
if (tempCode == code_tb.Text) //Checks if code matchs the search code
{
products_dgv.CurrentCell = row.Cells[0];
break;
}
...

Resources