Skip to content

Developer notes

CS-Cart stores quantities as integers everywhere (order_details.amount, products.amount, user_session_products.amount) and casts request amounts with intval(). Prices of order lines are decimal(12,2). The add-on changes no column and no core file:

  • A measured cart line always has amount = 1. The real quantity is extra.kv_fq.qty in 1/10000 of the unit (1.250 kg = 12500), and the line price is the exact price of that quantity. So price × amount is the line total in every place that multiplies them: taxes, promotions, order details, invoices, order editing, the REST API and the line items sent to payment services.
  • Price math: unit price (after option modifiers, quantity discounts by whole units, catalog promotions) × quantity, rounded half up to the decimals of the primary currency once.
  • Stock: products.amount keeps whole units = ceil(exact stock). The exact stock is ?:kv_fq_products.stock with stock_synced = the products.amount value the add-on wrote last. When products.amount differs from stock_synced, someone else changed the stock (admin, import, API) and products.amount wins. Order status changes pass the whole-unit delta ceil(old) − ceil(new) to fn_update_product_amount(), so low-stock e-mails and back-in-stock notifications keep working.
Table Contents
?:kv_fq_products product_id, unit (code), step, min_qty, max_qty, default_qty (ticks = 1/10000 unit), presets (comma-separated ticks), stock (exact stock in ticks), stock_synced, updated_at.

Cart line / order item extra.kv_fq: qty (ticks), unit, decimals, unit_price, unit_original, qty_text, unit_label, label; order editing adds original_qty. fn_get_order_info() adds kv_fq to each measured item (qty as a decimal string, label, unit_label, unit_price, unit_price_display).

Hook Why
pre_add_to_cart Reads the decimal amount before core casts it; step/min/max; merges with an existing line; amount = 1
add_to_cart Stores the checked quantity in the new line
update_cart_products_pre Order editor quantities; a fixed line price follows the quantity
check_amount_in_stock_before_check (priority 1100) Core min/max/step do not apply; quantity rules injected by other add-ons are read in units; exact stock check
post_check_amount_in_stock (priority 1100) Keeps amount 1 after core merges
get_cart_product_data_pre Quantity discounts by whole units (amount_total)
get_cart_product_data_post Unit price → exact line price; subtotal, discount, weight
change_order_status_before_update_product_amount, update_product_amount_pre, update_product_amount Exact stock on order status changes and returns
gather_additional_product_data_post Product page data (static per product)
get_product_data_post, update_product_post, clone_product, delete_product_post Editor, REST API, copies
get_order_info kv_fq on order items
kv_stock_texts Stock numbers printed by other add-ons (“Only 3 left” notes and labels) read the exact measured stock with its unit, see below

Signatures are identical in 4.17.2 and 4.21.2 (add_to_cart has a fourth argument $_data since 4.18; the handler makes it optional).

Stock texts for other add-ons. Core keeps whole units in products.amount (rounded up: 3.5 kg is stored as 4). An add-on that prints a stock number to shoppers can fire fn_set_hook('kv_stock_texts', $amounts, $texts) with $amounts = product_id => products.amount; for measured products this add-on fills $texts[product_id] with the exact stock and unit (“3.5 kg”). Print the text when it is set, the number otherwise. Neither add-on depends on the other. Urgency & Social Proof Kit and Product Labels & Stickers Pro use it.

Template hooks: products:qty (override, measured products only), products:prices_block (post), products:product_amount (post), products:product_additional_info (post: cart, checkout block, Multi-Vendor separate checkout), checkout:minicart_product_info (override, measured lines only); admin products:update_product_list_qty_count (post), orders:product_info (post: order page and order editor), orders:product_quantity (override, measured items only: “1.250 kg” in the quantity column of the order page; controllers/backend/orders.post.php puts the unit price in the price column).

Schemas: snippets/order_products_table.post.php and packing_slip_products_table.post.php (document product variable with units), exim/products.post.php (7 columns), block_manager/blocks.post.php (cache handlers of the product page and product lists: the add-on’s table and the enabled/licence state).

The product page output depends only on the product, its settings and the add-on state (static per product; the products.view main block and product list blocks get the add-on’s table and state as cache keys). Cart, checkout and order pages are not cacheable. Storefront requests write only to the cart and orders like core does.

app/addons/kv_fractional_quantities/
addon.xml, init.php, func.php
controllers/frontend/checkout.post.php decimal quantities and unit prices on the cart and checkout pages
controllers/frontend/orders.post.php customer order page
controllers/backend/products.post.php unit list for the product editor
controllers/backend/order_management.post.php order editor quantities
controllers/backend/orders.post.php order page (admin and vendor panel): unit price of measured items
schemas/snippets/*.post.php, schemas/exim/products.post.php, schemas/block_manager/blocks.post.php
Tygh/Addons/KvFractionalQuantities/
Qty.php quantity and money math (ticks)
Repository.php product settings and exact stock
CartHooks.php cart, price and stock hooks
View.php template data
ProductAdmin.php editor / API / import values
Exim.php import and export columns
Units.php sale units
Gate.php enabled + licence state
Documents/ProductVariable.php invoice and e-mail rows
License/, Upgrade/ licence client and self-healing upgrades
design/backend/templates/addons/kv_fractional_quantities/hooks/{products,orders}/…
var/themes_repository/responsive/templates/addons/kv_fractional_quantities/hooks/{products,checkout}/…
var/themes_repository/responsive/css/addons/kv_fractional_quantities/styles.less
js/addons/kv_fractional_quantities/func.js
var/langs/en/addons/kv_fractional_quantities.po