Developer notes
Overview · Installation · Configuration · Usage · FAQ
What is recorded
Section titled “What is recorded”One series per product and storefront (storefront_id; Multi-Vendor usually has one, Ultimate one per storefront whose company owns or shares the product). Each row is a period with unchanged values:
| Column | Meaning |
|---|---|
price |
Base price for quantity 1 and the All usergroup (fn_get_product_price(); Ultimate: the storefront’s shared price) |
list_price |
The product’s list price |
final_price |
The price a guest sees on that storefront after catalog promotions (fn_get_product_data() + fn_gather_additional_product_data() with discounts, without options, guest auth) |
valid_from, valid_to |
The period; valid_to = 0 is the current row |
source |
I initial, E product edit, S scheduled check, P promotion change, M import or mass update |
A row is written only when one of the three values changes; the previous row gets valid_to. Several changes within the same second update the row in place. Amounts are stored in the primary currency, like CS-Cart stores prices.
When it is recorded
Section titled “When it is recorded”update_product_post,update_product_prices,tools_change_status(products): the product is queued and captured at the end of the same request (shutdown) and by the next run.update_promotion_post,delete_promotions_pre,tools_change_status(catalog promotions),import_post(product patterns),global_update_products: a full check is requested.- A catalog promotion’s start or end date passed since the last run: a full check starts (scheduled promotions).
- Every Full check every (hours): a full check (changes made outside CS-Cart functions).
- Runs: the console cron
admin.php --dispatch=kv_omnibus_price_history.cron, the storefront cron URLindex.php?dispatch=kv_omnibus_price_history.cron&key=…, the admin fallback (shutdown of admin page views, at most once a minute per administrator session, 8 seconds; the check only reads and its throttle mark is kept in the session, so an admin page view without work writes nothing), Check prices now, and the installation. A run processes the queue, continues the full check from a cursor (batches of Products per batch), and prunes once a day. Run marks and the cursor are kept in?:storage_data, or in files undervar/kv_storage/kv_omnibus_price_history/while the full page cache is on (a write to?:storage_datawould purge the whole page cache). Storefront page views never write:StorageData::set()andRecorder::queue()return without writing on storefront GET/HEAD requests (only the cron URL records), and catalog promotions that start or end are picked up by the next cron run or admin page view; until then the label of an affected product is hidden, never wrong (the visitor’s price no longer matches the recorded final price). - During a capture the hook
promotion_apply_before_get_promotionsgives the core the promotions of the storefront being recorded (the core caches the request storefront’s promotions in a static variable) and restores the core’s list afterwards.
Lowest price calculation
Section titled “Lowest price calculation”- Before the reduction:
start= the latestvalid_toof a row whosefinal_pricediffers from the current one (the moment the current final price took effect). The value isMIN(final_price)of the rows that overlap[start − N days, start). Without such a row, the current final price (no_history). - Rolling:
MIN(final_price)of the rows that overlap[now − N days, now].
History::getLowest($product_ids, $storefront_id, $days, $calculation) returns current, lowest, start, since and no_history per product.
Storefront label
Section titled “Storefront label”gather_additional_products_data_post (storefront area only) adds $product.kv_oph = amount, days, in_lists, text, reduced in one batch (three indexed queries per product list plus one per product with an earlier price). The label is added only when the visitor’s base price equals the recorded base price and, without option modifiers, the visitor’s final price equals the recorded final price. A products:product_data post hook appends the label to the core price captures of common/product_data.tpl: on the product page to list_discount_<id> (printed after the price, the old price and “You save” by the Responsive, Nova and Bright product templates), in product lists to clean_price_<id> (printed after the price and the old price by the grid, list and compact list templates). The label has its own cm-reload-<id> container, so CS-Cart refreshes it when options change.
Full page cache (4.21). The full page cache serves cached pages only to guests; logged-in customers get the fpc_disable_cache cookie. The label depends only on the guest price and the history, so it is identical for all guests; currency and language are part of the cache key. No session is read and nothing is written on storefront page views.
Block cache. The main block of products.view and categories.view and the products block get kv_oph_prices and kv_oph_excluded as update handlers and the label settings plus the license state as a callable cache key.
Data model
Section titled “Data model”| Table | Purpose |
|---|---|
?:kv_oph_prices |
The history (row_id, product_id, storefront_id, price, list_price, final_price, valid_from, valid_to, source); keys (product_id, storefront_id, valid_to), (product_id, storefront_id, valid_from), (valid_to), (valid_from) |
?:kv_oph_queue |
Edited products waiting for a capture |
?:kv_oph_excluded |
Products excluded from the label |
Deleting a product deletes its history. Uninstalling drops the three tables.
Controllers and endpoints
Section titled “Controllers and endpoints”| Dispatch | Area | Purpose |
|---|---|---|
kv_omnibus_price_history.manage |
Admin | The history page |
kv_omnibus_price_history.export |
Admin | CSV of the filtered rows |
kv_omnibus_price_history.export_product?product_id= |
Admin, vendor (own products) | CSV of one product |
kv_omnibus_price_history.run (POST) |
Admin | Check prices now |
kv_omnibus_price_history.cron |
Console / storefront with key | One run (JSON summary) |
products.update (post controller) |
Admin, vendor | The Price history tab |
License check
Section titled “License check”Tygh\Addons\KvOmnibusPriceHistory\License\Client (generated) verifies the license. Gate point: the storefront label (Config::isLabelActive() in the gather hook; the license state is part of the block cache key). Not gated, by design: recording, the Price history tab, the history page and the CSV export, so the history has no gaps while a license problem is being fixed.
Not in 1.0.0
Section titled “Not in 1.0.0”Separate series per usergroup (the label is hidden for visitors with a different price), quantity discount tiers, progressive reductions as one reduction period, per-category exclusions.
File map
Section titled “File map”| Path | Purpose |
|---|---|
app/addons/kv_omnibus_price_history/addon.xml |
Settings, tables |
init.php, func.php |
Hooks, install/uninstall, admin fallback, settings info handlers, fn_kv_omnibus_price_history_is_licensed() |
Tygh/Addons/KvOmnibusPriceHistory/Recorder.php |
Capture, queue, runs, full check, prune |
History.php |
Lowest price, searches, chart data, CSV export, exclusions |
Label.php |
Storefront label data |
Config.php, StorageData.php |
Settings with limits, run marks (FPC-safe) |
License/, controllers/backend/kv_omnibus_price_history_license.php |
License check (generated) |
Upgrade/Synchronizer.php |
Self-healing upgrades (generated) |
controllers/backend/, controllers/frontend/ |
History page, exports, Price history tab, cron |
schemas/ |
Menu, permissions (vendor CSV of own products), block cache |
var/themes_repository/responsive/templates/addons/kv_omnibus_price_history/ |
The label (components/label.tpl, hooks/products/product_data.post.tpl) |
design/backend/templates/addons/kv_omnibus_price_history/ |
Tab, page, settings info templates |