Developer notes
Data model
Section titled “Data model”| Table | Contents |
|---|---|
cscart_kv_ppc_products |
One row per currency-priced product: product_id, company_id, currency_code, price and list_price in the product currency (4 decimals), rounding ('' store rule, N none), rate and converted_at of the last conversion. |
cscart_kv_ppc_tiers |
Quantity and customer group prices in the product currency: product_id, usergroup_id, lower_limit, type (A absolute, P percent), value. The base price (quantity 1, all customers) is the product row itself. |
cscart_kv_ppc_rates |
Per currency: the rate last applied to all its products, and the cursor of an interrupted run. A difference to cscart_currencies.coefficient means “rate changed”. |
cscart_kv_ppc_log, cscart_kv_ppc_log_items |
Runs (trigger, currency, rates, counts, status) and the changed products with old and new primary prices. |
The add-on writes nothing to cscart_storage_data and has no storefront output.
Conversion
Section titled “Conversion”primary = round(source × coefficient) with the store rounding rule (Rounding::apply()), for the base price, the list price and absolute tiers; percent tiers keep their percentage (core stores them with the base price). Prices are written through core fn_update_product_prices() (so the update_product_prices hook of other add-ons fires), the list price and updated_timestamp with one UPDATE. On CS-Cart (Ultimate), the rows of cscart_ult_product_prices of every storefront the product is shared with are rewritten too. Only products whose stored prices differ are written.
A run (Recalculator::run()) walks the products of a currency in batches of 200 with a time budget; a run that runs out of time stores a cursor and continues later (cron, Recalculate now). When a run touches more than 100 products and the price history add-on is installed, KV_OPH_NO_SHUTDOWN is defined so that add-on records the changes in its own cron instead of at the end of the request.
| Hook | Use |
|---|---|
update_product_pre |
kv_price_currency in the product data: validated, saved later, converted values put into price, list_price and prices so core saves them. Without it, a change of price, list_price or prices of a currency-priced product is a direct edit (converted back, or replaced by the conversion). |
update_product_post |
Saves the currency prices, logs the change, applies the currency to variations. |
update_currency_post |
Rate changes: recalculates the currencies whose coefficient differs from the rate last applied. |
global_update_products_post |
Products → Global update. |
variation_group_save_group |
New variations inherit the parent’s currency. |
clone_product, delete_product_post |
Copy / remove the currency prices. |
get_products |
Filter kv_price_currency (EUR, any, primary) for the admin list and the REST API. |
get_products_post, get_product_data_post |
REST API only (API defined): adds kv_price_currency. |
Every handler runs inside fn_kv_product_price_currency_safe(): an error is logged and never breaks the product save.
Product data / REST field
Section titled “Product data / REST field”kv_price_currency: { currency_code: "EUR" | "" (remove), price, list_price, // in the product currency rounding: "default" | "none", tiers: [{lower_limit, usergroup_id, type: "A" | "P", value}], apply_variations: "Y" // optional, product form}Read-only in responses: rate, converted_at.
Import / export
Section titled “Import / export”schemas/exim/products.post.php adds the columns Price currency, Currency price, Currency list price (process_put buffers, post_processing fn_kv_product_price_currency_exim_apply() applies after the rows are saved). schemas/advanced_import/products.post.php adds example values.
php admin.php --dispatch=kv_product_price_currency.cron or index.php?dispatch=kv_product_price_currency.cron&cron_key=<key>: Recalculator::cron() (pending currencies and rate drift, log pruning). Returns JSON.
File map
Section titled “File map”app/addons/kv_product_price_currency/ addon.xml init.php func.php controllers/backend/kv_product_price_currency.php Price currencies page, Recalculate now, bulk, log, console cron controllers/backend/products.post.php data of the product block, list column, search filter controllers/frontend/kv_product_price_currency.php cron URL schemas/menu/menu.post.php schemas/permissions/admin.post.php schemas/exim/products.post.php schemas/advanced_import/products.post.php schemas/settings/variants.functions.post.php currencies for vendors Tygh/Addons/KvProductPriceCurrency/ Config.php Rounding.php Converter.php Store.php Writer.php Recalculator.php Bulk.php Hooks.php Exim.php Log.php License/ Upgrade/design/backend/templates/addons/kv_product_price_currency/ hooks/products/product_update_price.post.tpl price currency block hooks/products/list_price.post.tpl list column hooks/products/search_form.post.tpl search filter hooks/products/update_qty_discounts.pre.tpl note on the Quantity discounts tab views/kv_product_price_currency/ manage.tpl, log.tpl, components/ settings/cron_info.tpl license/design/backend/css/addons/kv_product_price_currency/styles.lessjs/addons/kv_product_price_currency/func.js live preview, tiers, read-only core price fieldsvar/langs/en/addons/kv_product_price_currency.poLicense
Section titled “License”The add-on ships the generated License\Client. Gated (nothing happens without a valid license): conversions on product save, direct-edit handling, recalculation on rate changes, cron and Recalculate now, bulk assignment, the import columns and REST writes. Not gated: stored data, product prices, admin pages (read-only), cloning and deleting products.