Developer notes
Data model
Section titled “Data model”| Table | Contents |
|---|---|
cscart_kv_pop_options |
One row per option with a rule: code, input_type (N = number), num_min/num_max/num_step/num_default, unit, max_length, max_lines, required_visible, price_mode (none, formula, chars, words, lines, files), formula, rate, free_units, charge (U per item, O once per cart line), conditions (JSON list of {o, op, v}), cond_match (A all, O any). |
cscart_kv_pop_variants |
Formula value of a variant (variant_id, option_id, value). |
cscart_kv_pop_products |
Product formula: formula, mode (A add, R replace base price), min_price, setup_formula, status. |
cscart_kv_pop_order_fees |
One-time fees of an order (parent and sub-orders): lines (JSON), total, tax, display total. |
The breakdown of a cart item is stored in the item’s extra.kv_pop and therefore in cscart_order_details.extra (version, input hash, base, core modifiers, per-item amount, once amount, lines).
Formula language
Section titled “Formula language”Formulas are tokenised and parsed by Tygh\Addons\KvProductOptionsPricing\Expression (recursive descent) into a small tree that is evaluated by a tree walker. There is no PHP evaluation and no callback: only numbers, variables, the operators + - * / % ^ < <= > >= == != and or not ?: and the functions min max round ceil floor abs sqrt pow clamp if round_to ceil_to floor_to exist. Limits: 500 characters, 200 tokens, nesting depth 24, 10 function arguments, values up to 10^12. Division by zero, roots of negative numbers and overflows raise an error; at runtime such an amount counts as 0.
Price calculation
Section titled “Price calculation”apply_option_modifiers_pre: options hidden by their conditions are removed from the selection, so their core modifiers are not applied either.apply_option_modifiers_post(typeP): the per-item amount (product formula, option rules, minimum price) is added. It runs for every pricefn_apply_options_modifiers()calculates (price, list price, quantity tiers, cart, order management), with the value of that call asbase/price.pre_add_to_cart: server-side validation; hidden option values and files are removed and number defaults written.calculate_cart_items: the breakdown is stored inextra.kv_pop.calculate_cart(priority 140): one-time fees are added to the cart total and taxed withfn_calculate_tax_rates()(cart taxesapplies.KVPOP_<cart id>), like the core payment surcharge.place_order: the fees of each order (parent and sub-orders) are stored.- Placed orders: while an item’s options, quantity and files are unchanged (input hash), the stored amounts are used (order details, editing a placed order).
PHP: apply_option_modifiers_pre, apply_option_modifiers_post, pre_add_to_cart, calculate_cart_items, calculate_cart, gather_additional_product_data_post, apply_options_rules_post, update_product_option_post, get_product_option_data_post, delete_product_option_post, clone_product_option_post, update_product_post, clone_product, delete_product_post, get_product_data_post, place_order, get_order_info, delete_order, template_document_order_context_init. All exist with the same arguments in 4.17.2 and 4.21.2.
Templates: storefront products:product_option_content (breakdown and option configuration), checkout:product_options, checkout:checkout_totals, checkout:summary, orders:product_info, orders:order_total; admin product_options:properties, product_options:edit_product_options, products:tabs_content, orders:product_info, orders:totals_content, order_management:totals; mail orders:totals.
The product page block cache (products.view main block and product lists) gets the add-on tables as update handlers and the license state as a cache key. The breakdown printed with the page contains no session data; option changes are POST requests, so the 4.21 full page cache is not involved.
REST API
Section titled “REST API”GET /api/options/:idreturnskv_pop(the option rule) andkv_pop_valuefor each variant.PUT /api/options/:idandPOST /api/optionsacceptkv_popwith the same fields (conditionsas a list of{"o": option_id, "op": "in", "v": [variant ids]}) andvariants[n][kv_pop_value].GET /api/products/:idreturnskv_pop(formula,mode,min_price,setup_formula,status);PUT /api/products/:idaccepts it.GET /api/orders/:id: items carryextra.kv_popandkv_pop_rows; the order carrieskv_pop_fees.
File map
Section titled “File map”app/addons/kv_product_options_pricing/ addon.xml init.php func.php controllers/backend/kv_product_options_pricing.php overview, test calculator, formula check controllers/backend/products.post.php Price formula tab controllers/backend/product_options.post.php option editor data controllers/backend/kv_product_options_pricing_license.php schemas/menu/menu.post.php schemas/permissions/admin.post.php schemas/permissions/vendor_multivendor.post.php schemas/block_manager/blocks.post.php Tygh/Addons/KvProductOptionsPricing/ Expression.php ExpressionException.php formula parser and evaluator Rules.php rules storage and normalisation Engine.php visibility, validation, price calculation Hooks.php hook logic Fees.php one-time fees (cart surcharge, order storage, documents) Display.php storefront view data Admin.php product tab, test calculator, overview Config.php settings and license state License/ license client Upgrade/ synchronizerdesign/backend/templates/addons/kv_product_options_pricing/ option editor section, product tab, overview, order hooks, licensevar/themes_repository/responsive/templates/addons/kv_product_options_pricing/ breakdown, cart, order and totals hooksjs/addons/kv_product_options_pricing/func.js storefront behaviour backend.js option editor and calculatorvar/langs/en/addons/kv_product_options_pricing.poLicense
Section titled “License”License\Client::isActive() gates the storefront and cart features (Config::isActive()); placed orders and order editing work without a license. See License.