Skip to content

Developer notes

For an order with total T, shipping S, payment surcharge X (inside the total) and line subtotals V1…Vn (price × quantity):

  • base = T − S − X is shared over the lines pro rata to Vi, in cents, with the largest-remainder method, so the shares add up to base exactly. Taxes and order discounts are therefore spread pro rata.
  • A deposit line keeps round(share × percent) or min(share, fixed × quantity) as its deposit and the rest as balance; other lines are paid in full now.
  • balance = Σ (share − deposit) and due now = T − balance, so due now + balance = T always.

CS-Cart computes prices, taxes, promotions and shipping as usual on the full price; the add-on never changes prices or order totals. Class: Money::split().

  • get_order_info: when fn_get_order_info() is called by fn_start_payment() or from a payment script (a file in a payments/ directory, including add-on payment scripts and their callbacks), the order total is replaced by the amount due now (first payment) or the balance. All other callers get the full total. The original total is in kv_pob_full_total.
  • finish_payment (before the status change): a paid result (statuses with payment received) of the first payment records the deposit and replaces the status with the deposit status; of the balance it records the balance; a failed balance result keeps the deposit status. For a Multi-Vendor parent order the children are mapped in change_order_status_child_order.
  • change_order_status_post: manual changes to a paid status (paid in full), to the deposit status (deposit received), to I/D/F (cancelled), back from cancelled (reopened), and the confirmation e-mail.
  • The balance page (kv_pre_orders_backorders.pay?t=<token>) changes only the order’s payment method, stores on-site card data exactly like core orders.repay (core order data, removed by the status rules), calls fn_start_payment() and routes the return to itself (order_placement_routines).
  • Token: 24 random bytes + an HMAC tag (key: config.crypt_key); the database keeps the SHA-256 hash and an encrypted copy for the admin panel.
Table Contents
kv_pob_products product_id, preorder Y/N, preorder_limit, button_text, deposit_type G/N/P/F, deposit_value, prev_oos_action
kv_pob_orders one row per (non-parent) order with pre-order or deposit items: kind P/D, state A (awaiting) / B (balance due) / F (paid) / X (cancelled), total, due_now, balance, paid_amount, deposit_paid, release_at, request_at, due_at, token_hash, token_enc, link_sent_at, reminders, overdue_at, refunded
kv_pob_order_items per order item: product, quantity, pre-order flag, release date, share, deposit
kv_pob_events order history (placed, deposit paid, link sent, reminders, released, overdue, payments, e-mails)
kv_pob_throttle rate limiter of the payment page

The release date is the core products.avail_since; pre-order mode sets products.out_of_stock_actions = 'B'.

get_order_info, place_order, finish_payment, change_order_status_child_order, change_order_status_post, delete_order, calculate_cart_post ($cart['kv_pob'] summary), pre_add_to_cart (mixed-cart rule, limits), allow_place_order_post, gather_additional_products_data_post ($product['kv_pob']), update_product_pre (release date → avail_since), update_product_post, delete_product_post, order_placement_routines, before_dispatch (schedule fallback). All exist with the same arguments in 4.17.2 and 4.21.2.

Template hooks: products:product_labels, products:buttons_block, products:product_additional_info, checkout:checkout_totals, checkout:summary, orders:order_total, orders:repay (storefront); products:tabs_content, orders:details_sidebar (admin).

  • Product output depends only on product data and settings. The block cache of product lists and of the product and category pages gets kv_pob_products as an update handler and a key with the license state, the label settings and the hour (release dates pass).
  • The button text is changed by a small script from a data attribute, so it works with the variation and common-product templates that replace the core add-to-cart block.
  • The cart, checkout, payment page and cron URL are not cacheable dispatches. Storefront GETs write nothing to storage_data; the schedule’s run marks use files while the full page cache is on.
app/addons/kv_pre_orders_backorders/
addon.xml, init.php, func.php
controllers/backend/kv_pre_orders_backorders.php list, products report, order actions, run, console cron
controllers/backend/kv_pre_orders_backorders_license.php "Check now" / license cron
controllers/backend/products.post.php Pre-order tab data
controllers/backend/orders.post.php order panel data
controllers/frontend/kv_pre_orders_backorders.php payment page, cron URL
controllers/frontend/orders.post.php customer order page data
schemas/menu/menu.post.php, menu_vendor.post.php
schemas/permissions/admin.post.php, vendor_multivendor.post.php
schemas/block_manager/blocks.post.php
schemas/settings/variants.functions.post.php
Tygh/Addons/KvPreOrdersBackorders/
Config.php Install.php Products.php Money.php Orders.php Gateway.php Cart.php
BalancePay.php Scheduler.php Notifier.php Token.php Throttle.php StorageData.php
License/Client.php License/Ed25519.php Upgrade/Synchronizer.php
design/backend/templates/addons/kv_pre_orders_backorders/
hooks/products/tabs_content.post.tpl, hooks/orders/details_sidebar.post.tpl
views/kv_pre_orders_backorders/manage.tpl, products.tpl, settings/cron_info.tpl, license/*
design/backend/css/addons/kv_pre_orders_backorders/styles.less, license.less
var/themes_repository/responsive/templates/addons/kv_pre_orders_backorders/
hooks/products/{product_labels,buttons_block,product_additional_info}.post.tpl
hooks/checkout/{checkout_totals,summary}.post.tpl, hooks/orders/order_total.post.tpl, hooks/orders/repay.pre.tpl
views/kv_pre_orders_backorders/pay.tpl
var/themes_repository/responsive/css/addons/kv_pre_orders_backorders/styles.less
js/addons/kv_pre_orders_backorders/func.js, pay.js
var/langs/en/addons/kv_pre_orders_backorders.po

The add-on ships the generated License\Client. Gated (switched off without a valid license): the storefront output (labels, info box, button text, cart and checkout summary), the mixed-cart rule, the limits and the deposit record of new orders. Not gated: the payment page, the amount handed to gateways, the payment and status mapping, the schedule (requests, reminders, overdue rule) and the admin pages, so a started customer transaction always completes.