Skip to main content
Lesson 3

Implementing the Update and Validation of

Back to T190: QuickStartInCustomization

Lesson 3: Implementing the Update and Validation of

Field Values

In this lesson, you will modify the business logic of the Services and Prices (RS203000) and Repair Work Orders (RS301000) forms. The Repair Items tab of the Services and Prices (RS203000) form lists the repair items that are used to perform this particular service on the specific device. When a user adds a repair item to the list, the user selects the inventory ID (in the Inventory ID column) that corresponds to the needed repair item. To display consistent data on the form, for a particular row, if a value is selected in the Inventory ID column, the values in the Repair Item Type and Price columns must be changed to the repair item type and base price (respectively) of the selected stock item, as specified on the Stock Items (IN202500) form. The Repair Work Orders (RS301000) form is a data entry form on which users create and manage work orders for repairs. The system uses the data defined on the Services and Prices (RS203000) form for this particular service on the specified device to automatically fill in the default values of particular elements on the Repair Work Orders (RS301000) form and validate the values of particular elements. On the Labor tab of the form, the user entering the order lists the services to be provided and their quantities. For each row on the Labor tab, the value in the Quantity column must satisfy the following conditions:

  • The value must be greater than or equal to 0.
  • The value must be greater than or equal to the value in the Quantity column specified for the corresponding record on the Labor tab of the Services and Prices form (that is, the record that has the same inventory ID, service ID, and device ID on the Services and Prices form as the current row on the Labor tab of the Repair Work Orders (RS301000) form). The system must display an error if the value is less than 0. It also needs to display a warning and correct the value if the value is less than the value specified for the corresponding record on the Labor tab of the Services and Prices (RS203000) form.

Lesson Objectives

As you complete this lesson, you will learn how to do the following:

  • Update the fields of a data record on update of a field of this record
  • Validate the value of a field that does not depend on the values of other fields of the same record

Step 3.1: Updating Fields of a Record on Update of a Field of This Record (with FieldUpdated and FieldDefaulting)

In this step, you will add code that does the following when the RSSVRepairItem.InventoryID value is changed: It copies the RSSVRepairItem.BasePrice and RSSVRepairItem.RepairItemType values from the stock item record that has the ID equal to the new RSSVRepairItem.InventoryID value. You will use the FieldUpdated event handler for the RSSVRepairItem.InventoryID field to update the values of the following fields of the same record:

  • RSSVRepairItem.RepairItemType: Instead of directly assigning the value to this field, you will call the SetValueExt method to assign the value and invoke the FieldUpdated event handler for this field.
  • RSSVRepairItem.BasePrice: You will trigger the FieldDefaulting event for this field by using the SetDefaultExt method of PXCache. You will assign the value of the RSSVRepairItem.BasePrice field in the FieldDefaulting event handler. Lesson 3: Implementing the Update and Validation of Field Values | 34
                   You will not assign the value of the RSSVRepairItem.BasePrice field in the
                   FieldUpdated event handler, because this field may depend on multiple fields of the same
                   record. For example, the price can depend on not only the item selected in the line but also the
                   discount specified for this line. In this example, the RSSVRepairItem.BasePrice field
                   depends only on the RSSVRepairItem.InventoryID value, but we recommend that you
                   use this approach for the fields that may depend on multiple fields of the same record.
    

    In the FieldUpdated and FieldDefaulting handlers, you will use the PXSelectorAttribute.Select<>() method to select the stock item record with the inventory ID that has been selected in the updated field. The PXSelectorAttribute.Select<>() method uses the BQL query from PXSelector on the specified field. In the FieldDefaulting handler, you will use the PK.Find() method, which selects a record by using the values of the key fields of the record, to retrieve the value of the base price of the stock item. For details about definition of primary keys, see Relationship Between Data with PrimaryKeyOf and ForeignKeyOf.

Updating Fields of the Same Record

To update multiple fields of the same record, do the following:

  1. In the RSSVRepairPriceMaint.cs file, add the PX.Objects.IN using directive.
  2. Define the FieldUpdated event handler for the RSSVRepairItem.InventoryID field in the RSSVRepairPriceMaint class as follows.
                   //Update the price and repair item type when the inventory ID of
                   //the repair item is updated.
                   protected void _(Events.FieldUpdated<RSSVRepairItem,
                       RSSVRepairItem.inventoryID> e)
                   {
                       RSSVRepairItem row = e.Row;
    
                        if (row.InventoryID != null && row.RepairItemType == null)
                        {
                            //Use the PXSelector attribute to select the stock item.
                            var item = PXSelectorAttribute.
                                Select<RSSVRepairItem.inventoryID>(e.Cache, row)
                                as InventoryItem;
                            //Copy the repair item type from the stock item to the row.
                            var itemExt = item?.GetExtension<InventoryItemExt>();
                            if (itemExt != null)
                               e.Cache.SetValueExt<RSSVRepairItem.repairItemType>(
                                row, itemExt.UsrRepairItemType);
                        }
                        //Trigger the FieldDefaulting event handler for basePrice.
                        e.Cache.SetDefaultExt<RSSVRepairItem.basePrice>(e.Row);
                   }
    
  3. Define the FieldDefaulting event handler for the RSSVRepairItem.basePrice field in the RSSVRepairPriceMaint class as follows to calculate the default value of the field.
                   //Set the value of the Price column.
                   protected void _(Events.FieldDefaulting<RSSVRepairItem,
                       RSSVRepairItem.basePrice> e)
                   {
                       RSSVRepairItem row = e.Row;
                       if (row.InventoryID != null)
                       {
    

Lesson 3: Implementing the Update and Validation of Field Values | 35

                            //Use the PXSelector attribute to select the stock item.
                            var item = PXSelectorAttribute.
                                Select<RSSVRepairItem.inventoryID>(e.Cache, row)
                                as InventoryItem;
                            //Retrieve the base price for the stock item.
                            var curySettings =
                                InventoryItemCurySettings.PK.Find(
                                this, item?.InventoryID, Accessinfo.BaseCuryID ?? "USD");
                            //Copy the base price from the stock item to the row.
                            if (curySettings != null) e.NewValue = curySettings.BasePrice;
                       }
                 }

4. Build the project. 5. On the RS203000.aspx page (in the Pages\RS folder of the site), for the InventoryID control of the Repair Items tab item, set the CommitChanges property to True to enable a callback for the control. 6. Save your changes to the page. 7. Publish the customization project.

Testing the Logic

On the Services and Prices (RS203000) form, do the following:

  1. In the Summary area, select the Battery Replacement service and the Nokia 3310 device.
  2. On the Repair Items tab, add a row, and select Battery in the Repair Item Type column and BAT3310 in the Inventory ID column. Shi the focus away from the column. Make sure the system has filled in values in the Description and Price columns.
  3. Save the record.
    Related Links
  • Access to a Custom Field
  • PXSelectorAttribute Class

Step 3.2: Validating an Independent Field Value (with FieldVerifying)

In this step, you will implement the validation of the value in the Quantity column on the Labor tab of the Repair Work Orders (RS301000) form. For each row on this tab, the value in the Quantity column must be greater than or equal to 0. The value also must be greater than or equal to the value specified for the corresponding record on the Labor tab of the Services and Prices (RS203000) form (that is, the record that has the same inventory ID, service ID, and device ID on the Services and Prices (RS203000) form as the current row on the Labor tab of the Repair Work Orders (RS301000) form). Thus, a nonnegative quantity must be specified for each row, and the value specified for the labor on the Labor tab of the Services and Prices (RS203000) form (for the same service and device as those selected on the Repair Work Orders form) will function as a minimum quantity. You will implement the FieldVerifying event handler for the Quantity field of the RSSVWorkOrderLabor DAC. This event handler is intended for field validation that is independent of other fields in the same data record. For details about the validation of independent field values, see Data Validation: Validation of Field Values. In the event handler, you will do the following:

  • When the new value in the Quantity column is negative, you will throw an exception (by using PXSetPropertyException) to cancel the assignment of the new value to the Quantity field. Lesson 3: Implementing the Update and Validation of Field Values | 36
  • When the value is not negative but is smaller than the default quantity specified on the Services and Prices form (in the RSSVLabor.Quantity field), you will attach the exception to the field by using the RaiseExceptionHandling method and exit the method normally. This method will display a warning for the validated data field but will not raise an exception, so that the method finishes normally and e.NewValue is set. To attach a warning to the control, you will specify PXErrorLevel.Warning in the PXSetPropertyException constructor.
                   RaiseExceptionHandling, which is used to prevent the saving of a record or to
                   display an error or warning on the form, cannot be invoked on a PXCache instance in the
                   following event handlers: FieldDefaulting, FieldSelecting, RowSelecting, and
                   RowPersisted.
    

    To select the default data record from the RSSVLabor DAC, you will configure a fluent BQL query with three required parameters. In the fluent BQL statement, you will refer to each required parameter by using the P.AsType class, where Type is Int for an integer parameter. In the Select() method that executes the query, as the parameters, you will pass the values of RSSVWorkOrder.ServiceID, RSSVWorkOrder.DeviceID, and RSSVWorkOrderLabor.InventoryID from the row for which the event is triggered. To use parameters in a fluent BQL query, you need to add the PX.Data.BQL using directive to the code. For details about the parameters in fluent BQL, see Parameters in Fluent BQL.

Validating the Value of the Quantity Field

To validate the value of the Quantity field, do the following:

  1. In the Messages.cs file, add the following constants to the Messages class.
                  public const string QuantityCannotBeNegative =
                      "The value in the Quantity column cannot be negative.";
                  public const string QuantityTooSmall = @"The value in the Quantity column
                      has been corrected to the minimum possible value.";
    
  2. In the RSSVWorkOrderEntry.cs file, add the following using directive (if it has not been added yet).
        using PX.Data.BQL;
    
  3. Add the following FieldVerifying event handler to the RSSVWorkOrderEntry graph.
                  //Validate that Quantity is greater than or equal to 0 and
                  //correct the value to the default if the value is less than the default.
                  protected virtual void _(Events.FieldVerifying<RSSVWorkOrderLabor,
                      RSSVWorkOrderLabor.quantity> e)
                  {
                      if (e.Row == null || e.NewValue == null) return;
    
                       if ((decimal)e.NewValue < 0)
                       {
                           //Throwing an exception to cancel the assignment
                           //of the new value to the field
                           throw new PXSetPropertyException(e.Row,
                               Messages.QuantityCannotBeNegative);
                       }
    
                       var workOrder = WorkOrders.Current;
                       if (workOrder != null)
                       {
                           //Retrieving the default labor item related to the work order labor
    

Lesson 3: Implementing the Update and Validation of Field Values | 37

                           RSSVLabor labor = SelectFrom<RSSVLabor>.
                               Where<RSSVLabor.serviceID.IsEqual<@P.AsInt>.
                                   And<RSSVLabor.deviceID.IsEqual<@P.AsInt>>.
                                   And<RSSVLabor.inventoryID.IsEqual<@P.AsInt>>>
                               .View.Select(this, workOrder.ServiceID, workOrder.DeviceID,
                               e.Row.InventoryID);
                           if (labor != null && (decimal)e.NewValue < labor.Quantity)
                           {
                               //Correcting the LineQty value
                               e.NewValue = labor.Quantity;
                               //Raising the ExceptionHandling event for the Quantity field
                               //to attach the exception object to the field
                               e.Cache.RaiseExceptionHandling<RSSVWorkOrderLabor.quantity>(
                                   e.Row, e.NewValue, new PXSetPropertyException(e.Row,
                                       Messages.QuantityTooSmall, PXErrorLevel.Warning));
                           }
                      }
                 }

4. Build the project. 5. In the Screen Editor or in the ASPX code in Visual Studio, make sure that CommitChanges is set to True for the Quantity field in the grid of the Labor tab on the Repair Work Orders (RS301000) form. 6. Save your changes on the page. 7. Publish the customization project.

Testing the Validation

To check the validation, on the Repair Work Orders (RS301000) form, do the following:

  1. Select the work order with the 000001 order number.
  2. On the Labor tab, in the row for the CONSULT labor item, change the value in the Quantity column to -1 and press Enter. Make sure the error is displayed, as shown in the following screenshot. Lesson 3: Implementing the Update and Validation of Field Values | 38
    Figure: The error for a negative value
  3. Change the value to 0.5, which is smaller than the default value of 1. Make sure that the warning message is generated on the control and the value is corrected to 1, as shown in the following screenshot.
    Figure: The warning message
  4. Change the value to 2. Make sure no warning or error is displayed.
  5. Save the changes.
  • Data Validation: Validation of Field Values
  • Data Validation: Validation of a Data Record Lesson 3: Implementing the Update and Validation of Field Values | 39
  • Parameters in Fluent BQL
  • PXCache.RaiseExceptionHandling Method

Lesson Summary

In this lesson, you have defined the business logic scenarios on the Repair Items tab of the Services and Prices (RS203000) form and on the Labor tab of the Repair Work Orders (RS301000) form. You have used the FieldUpdated and FieldDefaulting event handlers to modify the values of a detail record on update of the Inventory ID column of this detail record. In the FieldUpdated event handler, you have used the PXSelectorAttribute.Select<>() method to obtain the stock item record with the inventory ID selected in the updated field. To verify the value of a field that does not depend on other fields of the same record, you have used the FieldVerifying event handler. In this event handler, you have thrown an exception by using PXSetPropertyException to display an error and cancel the assignment of the new value. To display a warning, you have attached the exception to the field by using the RaiseExceptionHandling method. The implementation of this business logic is shown in the following diagram. Lesson 3: Implementing the Update and Validation of Field Values | 40

Additional Information: Data Querying

In this lesson, you have used fluent BQL for data querying. Details about the data querying in Acumatica Framework are outside of the scope of this course but may be useful to some readers.

Data Querying in Acumatica Framework

In Acumatica Framework, you generally use business query language (BQL) to query data from the database. BQL statements represent specific SQL queries and are translated into SQL by Acumatica Framework, which helps you to avoid the specifics of the database provider and validate the queries at the time of compilation. Acumatica Framework provides two dialects of BQL: traditional BQL and fluent BQL. To query data from the database, you can also use language-integrated query (LINQ), which is a part of the .NET Framework. In the code of Acumatica Framework-based applications, you can use both the standard query operators (provided by LINQ libraries) and the Acumatica Framework-specific operators that are designed to query database data. For details about building queries, see the following chapters in the documentation:

  • Creating Fluent BQL Queries
  • Creating Traditional BQL Queries
  • Creating LINQ Queries For a comparison of these approaches in data querying, see Comparison of Fluent BQL, Traditional BQL, and LINQ.

Execution of Data Queries in Acumatica Framework

If you want to know how data queries are executed in the system, such as how a BQL statement is converted to an SQL query, see the following topics in the documentation:

  • Data Query Execution
  • Translation of a BQL Command to SQL
  • Merge of the Records with PXCache

Additional Information: Use of Event Handlers

In this lesson, you have learned in which situations you can use the FieldUpdated and FieldVerifying event handlers. Although the use of other event handlers is outside of the scope of this course, you can find information about how to use other event handlers, along with examples, in the following training courses:

  • T200 Maintenance Forms
  • T210 Customized Forms and Master-Detail Relationship
  • T220 Data Entry and Setup Forms
  • T230 Actions
  • Activity 1.1: To Define an Action for a Form Lesson 4: Creating an Acumatica ERP Entity Corresponding to a Custom Entity | 41