Acumatica: Getting the current state of an object

A quick tip for today. You can check the state of an object by using the GetStatus method of  a PXCache instance. This returns a PXEntryStatus as defined below.

// Summary:
// This enumeration specifies the status of a data record. The status of a data
// record changes as a result of manipulations with the data record: inserting,
// updating, or deleting.
public enum PXEntryStatus
// Summary:
// The data record has not been modified since it was placed in the PXCache object
// or since the last time the Save action was invoked (triggering execution of BLC's
// Actions.PressSave()).
Notchanged = 0,
// Summary:
// The data record has been modified, and the Save action has not been invoked.
// After the changes are saved to the database, the data record status changes to
// Notchanged.
Updated = 1,
// Summary:
// The data record is new and has been added to the PXCache object, and the Save
// action has not been invoked. After the changes are saved to the database, the
// data record status changes to Notchanged.
Inserted = 2,
// Summary:
// The data record is not new and has been marked as Deleted within the PXCache
// object. After the changes are saved, the data record is deleted from the database
// and removed from the PXCache object.
Deleted = 3,
// Summary:
// The data record is new and has been added to the PXCache object and then marked
// as Deleted within the PXCache object. After the changes are saved, the data record
// is removed from the PXCache object.
InsertedDeleted = 4,
// Summary:
// An Unchanged data record can be marked as Held within the PXCache object to avoid
// being collected during memory cleanup. Updated, Inserted, Deleted, InsertedDeleted,
// or Held data records are never collected during memory cleanup. Any Notchanged
// data record can be removed from the PXCache object during memory cleanup.
Held = 5,
Modified = 6


Using the GetStatus method, you can execute conditional logic based on the status of the data record.

For example, let’s say you have a grid with an add button. When the user adds a new record, that record has a status of Inserted until the save button is Pressed or it is deleted. If it is deleted, it’s status changes to InsertedDeleted.

As an example, consider that you want to disable a particular field until a user saves an inserted record.

You could achieve this in the RowSelected event as follows:

protected void MyView_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
MyDAC row = e.Row as MyDAC;
if (row == null)

if (MyView.Cache.GetStatus(row) == PXEntryStatus.Inserted)
PXUIFieldAttribute.SetEnabled<MyDAC.myField>(sender, row, false);



Posted in Acumatica, Uncategorized | Leave a comment

Acumatica: Refresh the UI elements

In order to get the best performance, Acumatica  has optimizations on which UI items it refreshes.

For example, if you capture the delete event of a grid, and you want to update another row in the same grid, you will find that your changes are not reflected in the UI. So let’s say that you have Rows with a Title Field. And the Title Field of your three rows is ‘one’, ‘two’, ‘three’.

Let’s say that row ‘two’ is deleted and you want to update row ‘three’ to set the title as ‘two’.

If you do this in the graph you will find that the UI is not updated to reflect the change. This is because of an Acumatica optimization that would only refresh the deleted row and remove it but does not refresh the other rows.

The fix is simple just call the View.RequestRefresh() operation of your data view and it will updated accordingly. Voila!

Posted in Acumatica | Tagged | Leave a comment

Acumatica: Copy DAC

There could be situations where you need to insert a new DAC which is the same or very similar to another DAC.

Acumatica has a function that meets this exact requirement. Meet the CreateCopy function of the PXCache object.

What’s important to keep in mind is that the CreateCopy creates an exact copy of the DAC, including the IDs. Therefore, if you want to insert  a new entry, you have to null the IDs, such as the following example.


MyDAC myDAC = PXCache<MyDAC>.CreateCopy(sourceDAC);
myDAC.ID = null; // null the ID
myDAC.Title = "A new DAC"; //update any fields
myGraph.Entries.Insert(myDAC); //update the Graph

Posted in Acumatica | Tagged | 4 Comments

Acumatica: Capturing command events in Javascript

Disclaimer: Today’s blog describes how you can extend Acumatica through Javascript. Using Javascript may not fully supported by Acumatica and may cause additional work during upgrades.

A typical scenario that an Acumatica developer may encounter, is the need to add some particular logic on the client-side when a specific command completes. For example, after the user has clicked on a grid button and the action has completed.

In order to support this, we can use the ClientEvents functionality of the DataSource. An example where this is used in Acumatica, is in the page SM208000.

As can be seen below, the ClientEvents element of the PXDataSource has a CommandPerformed property which takes the name of a Javascript function.

<px:PXDataSource ID="ds" runat="server" Visible="True"
<ClientEvents CommandPerformed="commandResult" />


The Javascript function takes 2 parameters: the datasource and the context. In this case of the SM208000, this page uses the context.command property to identify which of the grid button was clicked. It then highlights the next/previous row depending on whether the user has clicked on the move up or the move down button.


function commandResult(ds, context)


// grdFilterID and grdResultsID is registered by server

var grid = null;

var row = null;

if (context.command == "MoveDownFilter" || context.command == "MoveUpFilter")

grid = px_all[grdFilterID];

else if (context.command == "MoveDownResults" || context.command == "MoveUpResults")

grid = px_all[grdResultsID];

else if (context.command == "MoveDownSortings" || context.command == "MoveUpSortings")

grid = px_all[grdSortsID];

else if (context.command == "MoveDownCondition" || context.command == "MoveUpCondition")

grid = px_all[grdWheresID];

else if (context.command == "MoveDownRelations" || context.command == "MoveUpRelations")

grid = px_all[grdJoinsID];

else if (context.command == "MoveDownOn" || context.command == "MoveUpOn")

grid = px_all[grdOnsID];

else if (context.command == "MoveDownGroupBy" || context.command == "MoveUpGroupBy")

grid = px_all[grdGroupByID];



if (context.command == "MoveDownFilter" || context.command == "MoveDownResults" || context.command == "MoveDownSortings"

|| context.command == "MoveDownCondition" || context.command == "MoveDownRelations" || context.command == "MoveDownOn" || context.command == "MoveDownGroupBy")

row = grid.activeRow.nextRow();

else if (context.command == "MoveUpFilter" || context.command == "MoveUpResults" || context.command == "MoveUpSortings"

|| context.command == "MoveUpCondition" || context.command == "MoveUpRelations" || context.command == "MoveUpOn" || context.command == "MoveUpGroupBy")

row = grid.activeRow.prevRow();

if (row)





The above represents just one application of the CommandPerformed property. This can be used in other circumstances, typically whenever client side logic needs to be added after a command has completed.


Posted in Uncategorized | Tagged | Leave a comment

SQL Basics: the order of logical query processing

Syntax vs Processing order

An important aspect is that the order of keywords in the syntax is different from the order in which it is processed.

The Syntax order is as follows:

  2. FROM
  3. WHERE

However, the processing order is different

  1. FROM
  2. WHERE

This means that the processing engine starts executing from 1 to 6, and  it can only refer to elements in previous steps. For example, if the engine is at “stage 2 WHERE”, it cannot refer to fields created by the SELECT. The following would throw an error Invalid column name ”Fullname”.

Select age, name + surname as FullName
from dbo.tblPeople
where FullName = 'Joseph Caruana'

Although Fullname is a valid column, the WHERE clause does not know about it yet and that it is why the error is “Invalid column name”.

This basic ordering concept explains several other things. For example, it describes why you cannot filter a GROUP by value (such as SUM) based on the WHERE clause.

Posted in Uncategorized | Leave a comment