Your configurator can not only calculate the valid components and fabrications for any configuration, but also the cost, price, weight, and other attributes of that unique configuration. This is performed via Snap code in pricing rules.
Understanding Pricing Rules
One PriceObject. One or more PriceItems. Each configurator has one built-in logical structure called a PriceObject, which is the parent to one or more PriceItems. (Some people visualize the PriceObject as a container for one or more PriceItems inside it.) As your pricing rules add as many PriceItems as you need, the PriceObject automatically summarizes the overall cost, price, and other attributes from all those PriceItems. This information appears when your user clicks the price widget, usually shown in the corner of the running configurator.
Pricing rules are part of the rule cycle. When your user edits any field in the configurator, the rule cycle is triggered. Pricing rules are one of the final events in that cycle: they run after all value rule calculations have already been performed. In this way, your pricing rules can use the results of these calculations to determine what to show for price and cost to the end user.
Pricing Rules cannot change fields in a configurator. Pricing rules can read information from the fields your user and your Snap code writes to. They cannot write to fields on the configurator. By the time the rule cycle reaches Pricing Rules and Scene Rules, all edits to fields are done. If you want to change a field value, perform that task in a Value rule.
Pricing Rules run securely on the server. Even though they are part of the rule cycle, Pricing rules are performed on the server. Therefore, Snap code in pricing rules can perform database lookups and use other server-side features in your pricing calculations. Any delays due to complex pricing do not block your user: they can continue to navigate the configurator and make other edits while the pricing rules run. A simple progress animation appears in the price widget during this time.
PriceObject is not the engineering bill of materials. Out of the box, many companies use the PriceObject and its collection of PriceItems as a sort of bill of materials: they create PriceItems to represent the physical parts, labor, and other charges that helps your user understand the custom product. But remember that the PriceObject is visible to your end user: while attributes of a price item can be hidden or shown depending on your role (e.g., the cost of a screw is hidden to the end user, while the price is visible), each price item itself is always visible. So, they may not know the cost of a screw being installed into the configured product, but they do know how many screws there are and their overall price when they click the Price Widget.
Since the PriceObject and PriceItems are flexible, you can design the appropriate level of detail for your product into your pricing breakdown:
- If you want your end-user to see all the components that make up the custom product, then use the PriceObject and PriceItems as a sort of bill of materials.
- If it's better for your end-user to see none of the components, and simply a listprice or saleprice, then use Snap to create one PriceItem that has the overall cost. If you need an engineering BOM, then define your own custom type in Snap and use Value rules to populate it instead of Pricing Rules.
- If you're somewhere in-between (you want your end-user to see a list of some important options like paint color or type of wood used, but not drown in the details of screws and bolts), then create just the PriceItems you want to show. If you need an engineering BOM, then define your own custom type in Snap and use Value rules to populate it instead of Pricing Rules.
- If you integrate with the Kinetic ERP, you should use the Method of Manufacture rules to calculate your engineering BOM and other manufacturing info. Learn more in the Kinetic-CPQ integration documentation.
PriceItems can be hierarchical. Any price item can also contain more price items nested beneath it, allowing you to create a hierarchy to organize your pricing display however you'd like.
Pricing techniques are flexible. A pricing rule can be data-driven from a table or database lookup, or rule-driven from Snap logic. Since you can combine many pricing rules in your configurator, you can use the best technique for any item. For example, the base price you may calculate based on logic, but the labor fee for assembly you may look up from a table, and shipping fees you may lookup from a web service.
Price Rule Arguments
Arguments are variables passed in to the rule. You can find them by using the Get/Set variable snap blocks. In this rule type, the Get block exposes these arguments:
Name | Type | Description |
---|---|---|
clientLanguage | text | The two-character code representing the current user's preferred language. |
configurator | Configurator | The configurator the pricing rule is in. |
environment | text | Your deployment environment. Possible values are: "dev", "test", or "prod" |
priceObject | PriceObject | The one price object of the configurator. This pricing rule and all others within the configurator manipulate this one object. |
qtyInQuote | number | The quantity of this custom product on the parent quote. Note: if this configurator has not yet been saved, then it has no parent Quote, and this number will be null or 0. |
Price Item Properties
The following list shows the available properties that can be set on a price item in the pricing rule. In addition to the built in properties, you can also add custom metadata to price items.
Property | Data Type | Description |
---|---|---|
Discount | number | The value of the discount for this item. The behavior of this property depends on the DiscountType property. If DiscountType is set to percentage, then the value of the Discount property should be set as a percentage (for 5% discount set Discount to 5). If the DiscountType is set to dollar amount, then give the real dollar amount. |
Discount Type | text | The type of discount provided in the Discount property. Options are '%' for a percentage or '$' for a dollar amount. The default is '$'. |
FixedQty | boolean | If set to true, the price of this price item will only be counted once, regardless of the quantity of its parent. If the price item is in the top-level, then it will ignore the quantity of the quote product. For example, your configured product may have a flat installation fee which is the same regardless of the quantity of the products added to the quote. Changing the quantity will not adjust the fixed quantity portion of the price. |
Items | PriceItem Array | Items is the array of sub-items that are the children of this price item in the hierarchy. There can be zero or more sub-items. If you set one PriceItem to be the child of another, it will appear nested beneath the parent item, and the parent item will display with a clickable "twistie" that will show or hide the children. |
Labor Cost | number | The cost of labor for this item. Used along with the LaborMargin property to determine the LaborPrice. |
Labor Margin | number | The margin percentage to be applied to the labor cost to determine a labor price. Margin should be provided as a percentage value. For instance, for a 60% margin, set this property to 60. |
Lead Time | number | The lead time for this item in days. |
Material Cost | number | The cost of materials for this item. Used along with the MaterialMargin property to determine the MaterialPrice. |
Material Margin | number | The margin percentage to be applied to the material cost to determine a material price. Margin should be provided as a percentage value. For instance, for a 60% margin, set this property to 60. |
Unit of Measure | text | The unit of measure for this item. Default is 'ea.'. |
Use Rollup | boolean | If this line item contains sub-items, UseRollup controls whether the costing and pricing information should be a summation of all child price items, or whether you want to set these properties directly on the parent and ignore the children pricing. Defaults to true. |
Weight | number | The weight of the item (unitless). |
Custom Price Columns | as you define | You will also see any custom price columns you have defined will then appear in the dropdown of the Snap block. You can set these columns like any other property in the "Add price item" Snap block. |
Calculated Price Item Properties
Price items have some properties that are read-only and only used for reference in other rules, or for display in the "Details" button found in the top action bar. For example, you might wish to include these data in a sales proposal word document.
Property | Data Type | Description |
---|---|---|
Material Price | number | Material cost with the margin applied |
Labor Price | number | Labor cost with the margin applied |
Net Price | number | Material Price + Labor Price |
Extended Net Price | number | Net Price * Quantity |
Using Pricing rules
The "Add Price Item" Snap block only shows editable properties, not all of them. Some price item properties are calculated and read-only, you won't find them listed in your "Add Price Item" SNAP block. For example, if you want to set the Net Price in your price item, just set the Material Price or the Labor Price (or both). The Net Price will calculate as described above, and be visible on your Price Item.
There are two main techniques to using pricing rules.
- Simple pricing rules,
where you specify a SKU and the rest is looked up for you automatically. This can be useful for basic cost-based pricing, but most installations quickly outgrow this simple model. - Standard pricing rules,
with the full power of Snap to write any sort of pricing strategy such as price points, bundle pricing, price lining, value-based pricing, geographic and premium pricing.
Simple pricing rules: basic table lookup pricing
If your pricing needs are simple, you can set a mapping on the pricing rule page to map price item properties to columns in a table or database, and Epicor CPQ will fill in the data automatically. In this setup, all your rules need to do is add price items with the Sku property set, and let the mapping fill in the rest of the data for you.
Note that simple pricing rules do not allow for complex pricing logic. For most implementations, we suggest you use standard pricing rules with Snap code.
To set up your mappings:
- Select the pricing rule type in the design tree (the node with the currency icon).
- If you don't see the pricing rule type, you can make it appear by creating and deleting a pricing rule:
- Select "Rules", click the "+" icon, and click "Pricing". The pricing rule type will appear with the currency icon, and a new pricing rule will appear with the puzzle piece icon beneath it.
- If you don't see the pricing rule type, you can make it appear by creating and deleting a pricing rule:
- In the pricing rule properties screen on the right, select the type of data source you want to use (table or database), and then the specific table or database you want to connect to.
- Select the column from that data source which contains the SKUs that should match your price items. This relationship is how Epicor CPQ finds the right row of data in your data source.
- Select any other columns to map, such as descriptions, material costs, etc.
Given this mapping, then add a simple price rule that creates a new price object line item with just the SKU:
The resulting price item will have the SKU you set, along with the description (or other fields you mapped) from the row in your table with a matching SKU. While this simple technique can get you started, most administrators use the more powerful technique below.
Standard pricing rules: powerful pricing based on Snap
In almost all implementations, standard pricing rules are used. You can tap into the full power of Snap logic to calculate prices in a number of different ways.
1. Flat BOM Example
Here, the price item for an example product is made up of three components, each with their own prices. Note that in this simple example, the prices are hard coded, however you can use logic or database sources to set prices dynamically.
This pricing rule results in the following table when the user clicks on the price in the configurator when it runs.
Customize which of these columns in the table are displayed to which users in the price columns settings. For example, you may show the cost columns to your internal engineers, but hide those columns from your customers.
2. Hierarchical BOM example
Price items are a tree-like structure, where each item can have other items as children. This is a useful construct for building hierarchical BOM's and more advanced pricing algorithms. This example will walk you through how to create a hierarchy in your pricing rule.
If you are using nested configurators, you might want to use automatic nesting of price objects as described in the next example.
This example builds a pricing rule for a shelving system, which can contain multiple individual shelving units. In our final price object, we want each shelving unit to show up as a price item, and have the piece parts of that price item show up as children of the parent shelving unit.
The 'Add price item as child of' block is used to add a price item as a child of another price item in the hierarchy. Your pricing rule will likely involve more logic that conditionally adds price items, calculates descriptions, etc. This example is kept simple for clarity.
When the configurator is run, you can click on the price to see the details. This will show the hierarchy of price items we setup in the rule.
3. Nested Configurators example
When you are using nested or child configurators, typically you will want a hierarchical BOM in your price object, where the nested configurator items are shown as children of higher level items. KBMax supports this natively through a flag in the Referenced Configurator section on the parent configurator.
In this example, we have a top-level configurator which represents a shelving system, which can have 1 or many shelving units inside of it. The shelving units themselves can be organized into different layouts.
- In the parent "Shelving System" configurator, select the referenced configurator in the admin tree referring to the child "Shelving Unit" configurator.
- Set the 'Nest price object' checkbox to true. This will automatically add all the price items from the child configurator into your parent configurator's price object.
Save your work in the parent. Edit the "Shelving Unit" child configurator to create a pricing rule that adds the piece parts that make up a shelving unit as price items (such as platforms, brackets, fasteners, etc.). (Typically, your pricing rules will involve more logic than this, where you conditionally add items, calculate Sku's / Descriptions, but in this example we are keeping the rule simple for clarity.)
When the nested configurator is added as a price item in our parent configurator, it creates a price item in the parent to contain all the price items from this nested configurator. What's the Sku of this item? The SKU comes from the name of the child configurator. You can set the name of a child configurator in two ways:
- Set the child's name in a naming rule, running in that child.
This is preferred. Best practice is for each configurator to work when launched on its own. However, this can result in two child configurators having the same name in the parent PriceItem. For many products, this is acceptable.
- Set the child's name in a value rule running on the parent.
Parent configurators can name each child when it is being created, overriding the child. Look at this walkthrough for an example of such a rule. Since you're running at the parent level, all child configurators are an array which you can count. In this way, you can create unique SKUs such as Shelf-1, Shelf-2, Shelf-3, and so on
Now we are ready to run our top level Shelving System configurator. Run the configurator, and add some shelving units to it using the UI in the running configurator.
Clicking on the price in the top right corner will reveal the price details, and we will see our hierarchy.
4. Looking up pricing from a table
This is the most common way to price parts or labor in your configured product.
- Create a table of component parts and costs. At a minimum, each row in the table should have a SKU or other item identifier, along with a cost in the currency of your company. Usually, this is a simple extraction from your ERP system. For mocking up a quick prototype, you can use a local table. However, for production use, we suggest storing sensitive cost data in a database table.
5. Looping through all price items to apply logic to each
After creating your PriceItems, you can then loop through them to apply business logic to each. For example, consider this pricing rule:
5. Custom Price Columns Example
The PriceItem has standard attributes (we call them columns, as they most often appear to your user in a table format). However, you can create your own custom price columns. Once created, you can refer to them through the "columns" map of the PriceItem.
- Note that data returned from a lookup to a map is always text: here, since we want a number, we use the "cast" Snap block to use it "as number".
- Standard column names you pick from a list, but custom column names you need to type. Use the name, not the label of the custom column.
- Note the disabled "write log" Snap block: enabling it will show the entire PriceItem in the server logs, so you can confirm the spelling.
Showing the PriceObject without showing the price
In some applications, you want your user to be able to see a "bill of materials" – a detailed list of the Price Items currently in the PriceObject – but without showing any costs or prices. Perform this in two steps:
- Ensure field security is correct.
Click Products > Price Columns to see a list of all the columns. For any price column, you can:- Ensure that the "visible" checkbox is set correctly: a fast way to show or hide this column from everyone.
- Ensure the list of Roles listed on that price column are correct: a detailed way to hide the column from some roles, but leave it visible to others.
- Replace the "Details..." button (that shows a price) with a custom action (that shows no price).
- Find the configurator for which you want to hide the the standard "Details..." button.
- In the properties of that configurator, scroll to the "User Interface" section and un-check "Show Price". Now, when you run this configurator, the "Details..." button in the corner is hidden.
- In the actions of that configurator, create a new action called "Show BOM", and give it a name and icon. The rule for this action is just one block, called "Show Price Details". Add that block to the rule, and save your action.
Troubleshooting Pricing Rules
No prices appearing when you run your configurator?
- Look at your configurator's properties. In the layout section, see if the layout assigned to this configurator has a "show price" property. If so, it should be set to true.
- Look at your configurator's pricing rules. There should be at least one rule that creates at least one price item.
- Test the pricing rules by clicking the "Run" triangle at the bottom of the configurator you're editing. A new window appears: with every field you edit in this new window, the pricing rules will run.
It is not necessary to use the "Test Pricing" button at the bottom of the configurator being tested. Just edit a field. (The "test pricing" button is useful only for debugging this server-side code in your local browser. If your pricing rules have any server-side functions, such as database lookups, they won't be included when you click this button.)
Snap rules run in a specific order, and in response to specific events. Learn more about rule execution order.