Developer Tips & Tricks (Part III): Using the PXFormula Attribute to Simplify your Code

Mark Franks | August 21, 2017

One of the most highly rated sessions delivered in our Virtual DevCon was Sergey Marenich’s Advanced Framework Tips & Tricks. He did a masterful job flushing out a number very useful activities that a developer on our platform can do to be more efficient and productive as well as some good coding practices.  Since different individuals learn and benefit from a variety of modalities, we thought it would be good to share Sergey’s wisdom in written form as well.  I’ll distribute the content in bite size chunks over the next several blogs posts.

Last week, I focused on Configuring Your Tools & Disabling Web Site Compilation. Today, I will spend time exploring Sergey’s Programming Best Practices Tips: Automating calculations by using the PXFormula Attribute to simplify your code – Tip # 6.

As a review, below are the tips we are discussing in this series. And as a reminder, I’m skipping Finding More Information Through Communities (Tip 3) since I have covered this topic in a past post. Also, I have covered Tip 5, Debugging Acumatica Code in an earlier post.  You can read it here.

Tip 1 – Configuring Your Acumatica Instance

Tip 2 – Configuring Your Tools

Tip 3 – Finding More Information Through Communities

Tip 4 – Disabling Web Site Compilation

Tip 5 – Debugging Acumatica Code

Tip 6 – Auto-Calc with Formulas

Tip 7 – Minimize Duplication

Tip 8 – Benefits of Using Events

Tip 9 – Reuse of BQL Queries

Tip 10 – Modifying Selectors

Tip 11 – Fields from Different Views

The first set of programming tips for you to take advantage of when you are coding is taking advantage of Formulas to simply your code.  With the use of the PXFormula Attribute, you can use a field from the same data record or sets in an aggregation expression to calculate a parent data record field from child data record fields. These calculations happen at run time. The Framework extensively uses attributes and thus we approach programming in a very declarative manner. By placing attributes in the proper places, they simplify your programming tasks, reducing the lines of code you need to write.  Simply stated: less code, fewer mistakes.

The Validate Formula Attribute

An easy to illustrate example is the Validate formula attribute which raises the FieldVerifying event for the field to which the PXFormula attribute is attached once the specified field changes.

Example code:

//Validate
[PXFormula(typeof(Validate<Batch.finPeriodID>))]
public virtual void Batch_Date_CacheAttached(PXCache sender) { }

The Validate formula attribute raises the field validation automatically when the current field when the current field is changed where the formula is attached.

Another example:

//Validate
[PXFormula(typeof(Validate<ContractItem.maxQty, ContractItem.minQty>))]
public decimal? DefaultQty {get; set;}

For further reference and examples, see the API Reference section of the Acumatica Framework Developer Guide.

The Parent Constructor & Current Parameter

Remember, you can place an attribute on any field of the child DAC. The primary goal of the attribute is to perform a cascading deletion of the child records once a parent data record is deleted. Usually, the query includes a Where clause for the parent’s key fields to equal the child’s key fields. In this case, the values of child data record key fields are specified using the Current parameter.

Using static methods to retrieve specific parent data or child data records, or get and set some attribute parameters. Once the PXParent attribute is added to some DAC field, you can use the PXFormula attribute to define set calculations for parent data record fields from child data record fields.

The PXParent attribute fetches the field value from the parent data record as defined by PXParentAttribute residing in the current DAC. It initializes a new instance that defines the parent data record using the provided BQL query.

For example,

//Parent
PXParent(typeof(Select<INRegister,
   Where<INRegister.docType, Equal<Current<INTran.docType>>
   And<INRegister.refNbr, Equal<Current<INTran.RefNbr>>>>>))]

[PXFormula(typeof(Parent<INRegister.origModule>))]
public virtual void INTran_OrigModule_CacheAttached(PXCache sender) { }

For the Current parameter, the example below specifies a query for selecting the parent Document data record for a given child DocTransaction data record.

//Current
[PXParent(typeof(Select<Document,
   Where<Document.docNbr, Equal<Current<DocTransaction.docNbr>>,
   And<Document.docType, Equal<Current<DocTransaction.docType>>>>>))]
public virtual string DocNbr {get; set;}

This provides you access to the data access class (DAC) that is not your current DAC.  Using the Current Parameter with the Formula Attribute allows you to find the cache and using the doc type or reference number.

The code below illustrates this nicely:

//Current
PXFormula(typeof(Switch<Case
<Where<
ARAdjust.adjgDocType, Equal<Current<ARPayment.docType>>,
   And<ARAdjust.adjgRefNbr, Equal<Current<ARPayment.refNbr>>>>,
ERActivity.classIcon>,
EPActivity.classIcon>))]
protected virtual void ARAdjust_ClassIcon_CacheAttached(PXCache sender) { }

Instead of using the FieldUpdated Event or some other event, you can use the formula attribute in this case.

For more information, see the API Reference section of Acumatica Framework Developer Guide.

IsTableEmpty Parameter

To determine if a table is empty, you can use the IsTableEmpty parameter with PXFormula returns true if the DB table corresponding to the specified DAC contains no records.

//IsTableEmpty
PXFormula(typeof (Swich<Case
<Where<IsTableEmpty<APSetupApproval>, Equal<True>>, True,
   Case<Where<APRegister.requestApproval, Equal<true>>, False>>, True>
))]
public virtual void APRegister_ContApprove_CacheAttached(PXCache sender) { }

The Selector Parameter

When you use the Selector Parameter with the Formula Attribute, you can select the related record. In the APVendorPrice DAC, select the InventoryID through the selector and through the InventoryItem any field. Instead of using FieldUpdating or RowUpdating, and writing the code to get the related data in the data access class, you can use formulas.

Here’s the simple code illustrating this point:

//Selector
PXFormula(typeof(Selector<APVendorPrice.inventoryID, InventoryItem.purchaseUnit>))]
public virtual void APVendorPrice_UOM_CacheAttached(PXCache sender) { }
}
}

These examples, using formula attributes and parameters, illustrate ways in which you can streamline and simplify your code.  Next time, I’ll continue exploring Sergey’s programming best practices theme and discuss ways in which you can minimize duplication in your code using our Framework.

To reinforce what was discussed here and to view the wonderful presentation of these Tips that Sergey Marenich shared with us at our Virtual DevCon, go here and enjoy.

Mark Franks

As a Platform Evangelist, Mark is responsible for showing people the specifics about what makes Acumatica’s Cloud Development Plaform wonderfully attractive to ISV & Partners. He's also passionate about Running, Latin, and his family. | E-mail: mfranks@acumatica.com | Skype: mfranks |

Subscribe to our bi-weekly newsletter

Subscribe