Calculation Authoring
- Version
- 3.x
- Updated
A functional description of how an admin builds calculations — the named, product-scoped
formulas that produce a number (a price, a recurring price, a weight, or a min/max bound). This is the
authoring/usage view: what you can express and how you build it. For how calculations are stored and
evaluated, see technical/com_configbox_calculation_engine.md.
A calculation answers "given the customer's current selections, what number should this be?" It does nothing on its own — it only takes effect once assigned to a question/answer (as its price, recurring price or weight), used as a validation bound on a numeric question, referenced by another calculation, or referenced by a rule (the "Results of calculations" condition).
1. Creating a calculation
Each calculation belongs to one product and has:
- Name — how you'll recognize and reference it (e.g. "Area price", "Volume discount factor").
- Product — the product it applies to.
- Type — the authoring style: Formula, Code, or Matrix (below). The type determines which editor you get.
You typically create several small calculations and compose them (one calculation can reference another), rather than one giant formula.
Picking the type comes down to the shape of the logic:
2. Where a calculation is used (how it takes effect)
A calculation only matters once it's referenced. The places an admin assigns a calculation:
- Question → Price / Recurring Price / Weight Calculation — the question's contribution is computed by the calculation (instead of a static price).
- Answer → Price / Recurring Price / Weight Calculation — overrides the answer's price/weight for that question with a calculation.
- Question → Calculated Minimum / Maximum Value — a numeric/text question's allowed range is computed (e.g. "max length depends on the chosen material").
- Inside another calculation — as a building block (the "Calculation" term/macro).
- Inside a rule — the "Results of calculations" condition compares a calculation's result to a value (see the rule-authoring doc).
The number a calculation returns is the raw value. Currency conversion, customer-group price overrides and tax are applied automatically afterwards by the pricing layer — you author in the base currency and don't handle tax in the formula.
All the attachment points at a glance:
3. Authoring style A — Formula (visual builder)
A drag-and-drop editor where you assemble an arithmetic expression from terms. The Number box and the operator buttons sit above a picker: a list of the product's questions on the left (with a page filter and a title search once the product has more than ten questions), and below it Other terms for the sources that are not a question. Click a question and the terms it offers appear on the right, grouped the way the rule editor groups conditions; drag them into the formula area, arrange them left-to-right, and group with brackets.
As the editor renders it (
views/admincalcformula/tmpl/default.php): the Number box and the+ − * /operator buttons come first; the picker is prompted "Pick a question to see its terms"; Other terms lists Regarding Question, Functions, Calculations and Customer. Each placed term shows an inline "or [fallback]" box, and the form lists where the calculation is in use (e.g. "Answer price calculation – 5/6/7").
Available term types (the building blocks):
- Number — a literal value you type (e.g.
12,0.25). - Operator —
+,−,×,÷and parentheses. These connect the other terms; normal arithmetic precedence applies, and brackets force grouping. - A question's field — a value taken from a question in the same product. Pick the question
in the list, then which field:
- Entry in … — the value the customer entered (a question without answers; an answer id is not a number, so a question with answers has no entry term).
- Price of … / Recurring Price of … / Weight of … — that question's computed figures.
- Base price of answer in … / Weight of answer in …: the selected answer's own columns (a question with answers).
- The question's custom fields, and the selected answer's custom fields (assignment-level and global).
- Whatever the question's type adds, under a heading of its own: a dimensions question offers its width, height and area, a quantities question its totals and the quantity of each answer.
- Regarding Question (under Other terms) stands for the question this calculation is assigned to, so one calculation can be reused on many questions and always read "its own".
- A fallback value is used when the question has no value.
- Calculation — the result of another calculation in the product (lets you compose; e.g. a "base area" calc reused by a "price" calc).
- Customer Group field — a value from the current customer's group (a group custom field), so a formula can vary by customer segment.
- Function — a function applied to its parameters (each parameter is itself a little formula you
drop terms into):
- Round — round a number (optionally to N decimal places).
- Lowest value (min) / Highest value (max) — pick the smallest/largest of 2–4 values.
- Custom functions — additional functions a developer has registered (see the technical doc); they appear under Functions in Other terms with named parameter slots.
Worked example — price = (width × height in m²) × €65, rounded to 2 decimals, where width and height are slider questions:
Round(Entry in "Width" × Entry in "Height" ÷ 1000000 × 65, 2 )
You'd drop a Round function, and inside its first parameter build
[Entry in Width] [×] [Entry in Height] [÷] [Number 1000000] [×] [Number 65], with 2 in the second
parameter.
The same example as the terms you'd actually place:
Use Formula when the logic is arithmetic and benefits from being readable/reusable.
4. Authoring style B — Code (expression)
A free-text expression for when a formula is faster to type than to drag. You write normal math using:
- Placeholders A–D — each bound (in the form) to a question; at runtime each becomes that question's entered value. (Set "Question for placeholder A/B/C/D".)
- Macros:
- Total / TotalRecurring — the running product total (regular / recurring).
- QuestionSelection(
) — a question's entered value. - QuestionPrice(
) / QuestionPriceRecurring() — a question's price. - Calculation(
) — another calculation's result. - QuestionProperty(…) / RegardingQuestion(…) — attribute access / the assigned question.
- Standard operators and parentheses.
Legacy spellings: CBX 3.x called these
ElementEntry(),ElementPrice(),ElementPriceRecurring(),ElementAttribute()andRegardingElement(). The rename is a hard one — there are no aliases; the 3.5.2 update rewrote stored calc code in place, and any code arriving from outside (a customization, a hand-written import) has to be rewritten too. Seemigration-to-cb4/element-question-rename.md.
Worked examples:
- Area pricing (A = width mm, B = height mm):
A * B / 1000000 * 65 - A surcharge of 25% of the order:
Total * .25 - Combine:
Calculation(42) + QuestionPrice(37) * 2
The question's Price Multiplicator (set on the question) is applied to the code result, so you can keep the code per-unit and multiply by quantity at the question level.
Use Code for quick mathematical expressions, especially ones referencing totals or several questions.
5. Authoring style C — Matrix (lookup table)
A 2-D lookup table for "price depends on the combination of two inputs" (e.g. size × material, weight × zone). You define:
- Column input and Row input, each either a Question (the customer's selection/value is the key) or another Calculation (its result is the key). (Set "…parameter type" = Question or Calculation, then pick the question/calc for rows and columns.)
- The grid — the cell values, which you can type in or import from an
.xls/.xlsxspreadsheet (handy for large tables). - Lookup Value (matching mode): Exact Value, Next higher value, or Next lower value — how an input that doesn't exactly hit a row/column header is matched (e.g. round up to the next size bracket).
- Round Values to — snap the inputs to a step before matching (for numeric inputs).
- Multipliers — the looked-up cell can be multiplied by a static multiplicator, by a question selection (a quantity question), and/or by a calculated multiplier (another calculation).
How a matrix turns its two inputs into a number:
Worked example — "Glass price" matrix: columns = "Width bracket", rows = "Thickness", cells = €/m²; lookup = Next higher value so an in-between width uses the next bracket up; multiply the cell by the "Quantity" question.
Use Matrix when pricing is naturally a table and doesn't follow a clean formula.
6. Composition, "regarding", and reuse
- Compose small calculations: a calculation can reference others (formula "Calculation" term,
code
Calculation(id), or a matrix row/column input). Build a library of named pieces. - "Regarding" element lets one calculation be assigned to many questions/answers and always read the value/price of the question it's attached to — so you don't need a separate calc per question.
- Calculations are product-scoped; copying a product copies its calculations and re-points all the internal references automatically.
A typical small library, composed:
7. Element attributes you can reference (quick list)
When a formula reads from a question, the available fields are: the entered value (a question
without answers), the price, recurring price and weight, the question's custom
fields, the selected answer's base price, weight and custom fields (assignment-level and
global-option-level), and any field the question's type declares (a dimensions question's area,
say). Custom-field labels come from global Configuration, so they appear under your own names. The
code editor's QuestionProperty(...) macro reads the question record by attribute path instead.
8. Custom functions (extension)
Beyond Round/Min/Max, a developer can register additional functions (e.g. ceilTo, an external price
lookup) that then appear under Functions in the Formula editor's Other terms with named parameter slots — so
admins can use them like built-ins. (How to add them: technical calc-engine doc.)
9. Practical notes
- Calculations run on every selection change (live pricing), so keep them reasonably simple; deeply nested calc graphs cost performance.
- Author in the base currency, ignore tax — conversion and tax happen after the result.
- Numeric results — calculations are expected to return numbers (used as money/weight/bounds).
- Validation bounds — a "Calculated Minimum/Maximum Value" on a question lets allowed input depend on other selections (e.g. max quantity depends on chosen package).
10. Notes for the refactor (functional observations)
- Three authoring styles for one concept. Formula, Code and Matrix all produce "a number from selections." A refactor could unify them behind one calculation concept with interchangeable editors (visual / expression / table) rather than three separate types.
- "Regarding" + reuse is valuable — the ability to write one calculation usable across many questions should be preserved (it's what keeps configurators maintainable).
- Composition is a strength — calculations referencing calculations form a small dependency graph; making that graph explicit (and cycle-checked) would help.
- Matrix is really "tabular pricing" with lookup semantics (exact/next-higher/next-lower) + multipliers + Excel import — a well-scoped feature worth keeping as a first-class option.
- Regular vs. recurring are parallel everywhere; consider modeling "price kinds" generically.
- Raw-number output with currency/tax applied afterwards is the right separation to keep.