Uses of CpqAppHandlerHook

In Industries CPQ, CPQ functionality is managed by a global interface called CpqAppHandler. It includes a wide range of methods to perform CPQ processes in Industries CPQ Cart. (These methods are also available as a RESTful API, called the Cart-based APIs.) So, when you need to change the default behavior or processing of a CPQ operation, you create a custom implementation in the CpqAppHandler hook interface, which is appropriately named CpqAppHandlerHook.

In software development, hooking is a concept that allows you to modify the original behavior of the application without changing your code. By intercepting the commands, you can change the action that would have been performed originally. It is very useful in the case of adding new functionality to applications, exposing additional fields in pricing calculations or altering how products are priced, to name a few of its applications.

Industries CPQ allows you to write custom Pre-invoke and Post-invoke hooks for each interface to implement custom logic. Pre-invoke hooks get executed before the actual interface is executed whereas Post-invoke hooks get executed after the actual interface is executed.

The CpqAppHandlerHook can be used on inputs and outputs of the CPQ methods to:

  • Add, change or delete input parameters.

  • Add, change or delete output responses.

  • Debug issues by verifying the input and output are correct.

  • In some cases, provide a workaround when waiting for a patch for an issue.

In addition, you can add business logic such as:

  • Conditional processing.

  • Preload information that will be used further down the execution chain.

  • Process custom fields.

  • Implement custom functionality.

  • Do callouts.

The CpqAppHandlerHook is automatically invoked when the InvokeService is called. The InvokeService simply appends a hook string, e.g., “Hook”, to the interface name and determines if there is an active interface with that name. If there is, the InvokeService will initiate the active implementation in the hook interface. Then, it will add a .preInvoke suffix to the method name and invoke the PreInvoke method in the hook implementation. A corresponding .postInvoke method is invoked on the hook implementation after the hooked class method has completed its processing.

The graphic below provides an example of the sequence when using a CpqAppHandlerHook.

Injecting custom code is powerful when executed correctly, but you also need to be aware of the ramifications if executed poorly. Salesforce recommends the following when implementing a hook:

  • Validate that a feature doesn’t already exist that addresses your need for a hook.

  • Ensure the custom code in the hook does not cause the execution to exceed any Apex governor limits.

  • Put a try-catch around the hook code to catch any exceptions thrown by the custom code.

  • When unit testing the hook code, it may be possible to mock the inputs expected by the hook code to minimize test setup and get better code coverage. Use Test.isRunningTest() to extract the mock input from the inputMap or from a static map.

Let’s look at an example based on the following business requirement:

Users must not be allowed to order the same product more than once on the same order. And, check to see if the product exists as an active asset on the account.

Solution using a hook:

Implement a CpqAppHandlerHook to check before postCartsItems logic runs to see if the product exists in other active line items or active assets.

In the Preinvoke hook, if the product exists in active line items or assets, null the items and create a new node that will be checked in the post-hook. In the Postinvoke hook, if the new node exists display an error in the UI. When the user tries to add a duplicate product, they will get an error in the cart.

Let’s take a look at another example. Consider how pricing works in Industries CPQ Cart. You add an iPhone X to the cart. It displays a one-time charge of $1000. That’s all good, but as a customer I want to know the total price of the iPhone X, which includes the sales tax cost. How can I display the cost of the iPhone X plus applicable taxes in the one-time charge column in the Cart? You would do this by implementing a pricing hook to alter how the pricing is calculated. Instead of calculating QuantityPrice and displaying the price in the One Time Charge column, you would create a pricing hook to calculate the One Time Charge as QuantityPrice*Sales Tax Rate. What if I didn’t want to include the sales tax in the one-time charge column, but rather wanted to display it as a separate column? No problem, you can modify the cart to display a custom field for the applicable sales tax.

In the main example, we will price products using the account’s zip code. This would allow you to vary pricing for each line item based on the customer’s location, such as the billing or shipping location. To do this, we must add a custom field to store the zip code on each order line item, and then use attribute-based pricing to calculate the price for each zip code. However, the pricing service has no idea that this new field exists. So, we also must use a pricing hook to alert the pricing service to the existence of this new field and ensure that it is passed in the input map to attribute-based pricing. Then, as the icing on the cake, we’ll also expose the custom field (Billing Zip Code) in the Cart, so the user can see the values that affect the price of the line item.