Skip to content

Developer notes

Table Contents
?:kv_rp_codes user_id, code (unique, upper case), last_ip (self-referral check)
?:kv_rp_clicks owner_id, visitor (random id), ip_hash, day (unique per owner, visitor and day), landing, referrer_host
?:kv_rp_referrals friend_id, referrer_id, source (link, code, invite), status (J joined, O ordered, R rewarded, X not eligible), welcome coupon code, promotion, state (A active, U used, E expired), expiry
?:kv_rp_orders order_id, parent_order_id, checkout_id, owner_id, kind (R referral, A affiliate), method (cookie, form, code, account), code, customer_id
?:kv_rp_ledger entry_id, uniq, type (R reward, C commission, A adjustment), user_id (beneficiary), friend_id, friend_email, order_id, checkout_id, base, rate, amount, points, method (wallet, points, coupon, cash), status (P, W, A, D, R), hold_until, flags, coupon_code, ref, payout_id, note
?:kv_rp_affiliates user_id, status (P, A, D, S), website, promotion, payout_method, payout_details, rate_type, rate_value, admin_note
?:kv_rp_rates category_id, rate (%)
?:kv_rp_payouts payout_id, user_id, amount, status (R requested, D paid, X rejected), method, details, reference, note
?:kv_rp_invites invite_id, user_id, email (normalised), joined_user_id

uniq makes entries idempotent: R:<md5 of the friend's normalised e-mail> (one reward per friend), C:<order_id>, A:<entry_id>.

  • Capture. window.kvRpConfig is printed in index:footer (built in dispatch_before_display, the same for every visitor). js/addons/kv_referral_program/func.js reads ?ref=, stores CODE.timestamp in the kv_rp cookie (consent-aware via window.kvConsent) or sessionStorage, posts a click beacon to kv_referral_program.click (writes only ?:kv_rp_clicks, returns the welcome bar text) and adds the hidden field kv_rp_ref to POST forms. No session or ?:storage_data writes from storefront GETs.
  • Attribution. place_order: the code comes from the kv_rp_code field, the kv_rp_ref field or the cookie (storefront only), else from the customer’s referrer (?:kv_rp_referrals, also for admin orders). Vendor orders copy the parent’s row. Order edits and API orders are not attributed. Suspended affiliates and own links are ignored.
  • Entries. Leaf orders get a commission (approved affiliate) or the friend’s referral reward (first checkout per mailbox). Fraud flags (Fraud::check(), Fraud::duplicateFriend()), caps and the existing-customer check run here.
  • Hold. change_order_status_post: a paid status sets hold_until; a refund/cancel status rejects (reward: when all vendor orders of the checkout are in such a status); a paid commission gets an adjustment. Engine::release() (scheduler, or at once with hold 0) recomputes the reward base from the paid vendor orders, checks the minimum, sends flagged/manual entries to review and delivers rewards (fn_kv_customer_wallet_credit(), fn_change_user_points(), or a code of the promotion).
  • Coupons. Coupons::issue() appends a code to the promotion’s auto_coupons condition under a named DB lock; codes used in an order (place_order, $cart['coupons']) or expired are withdrawn. The hook promotion_apply_before_get_promotions (priority 2000) drops the core’s per-request cache of cart promotions after a code list changed.

place_order, change_order_status_post, delete_order, update_profile (new storefront customer), post_delete_user, dispatch_before_display (script configuration, menu flags), before_dispatch (scheduler fallback), promotion_apply_before_get_promotions. Signatures are identical in 4.17.2 and 4.21.2.

Template hooks: index:scripts, index:footer, profiles:my_account_menu, profiles:account_info (referral code field on registration).

fn_kv_referral_program_get_code($user_id); // the customer's code ('' when the add-on is off)
fn_kv_referral_program_get_referrer($user_id); // who referred the customer (user id or 0)

JavaScript: window.kvRp.get() returns the stored code of the visitor or ''.

Request Returns
GET /api/kv_referrals ledger entries; filters type, status, user_id, order_id, page, items_per_page
GET /api/kv_referrals/<entry_id> one entry
GET /api/kv_affiliates affiliates with status, code, rate, clicks, orders, balance, paid, pending; filter status
GET /api/kv_affiliates/<user_id> one affiliate

Privilege: View referral program. Other methods are refused.

Store Credit Wallet (rewards with source = kv_referral_program, payouts), Reward points (points with a readable reason), Cookie Consent Mode (kvConsent.get()/on('change')), Order Source & UTM Attribution (UTM tags utm_source=referral_program, utm_medium=referral|affiliate), Loyalty Program with VIP Tiers and core promotions work side by side. Full page cache: guests get identical pages; per-visitor data comes from the beacon response.

app/addons/kv_referral_program/
addon.xml, init.php, func.php
controllers/backend/kv_referral_program.php ledger, affiliates, affiliate page, payouts, rates, referrers,
approve/reject, payouts, CSV, quick promotion, console cron
controllers/backend/kv_referral_program_license.php
controllers/frontend/kv_referral_program.php Refer a friend, Affiliate program, invite, apply, payout request,
link builder, click beacon, cron URL
schemas/menu, permissions, settings, security (CSRF of the account forms)
Tygh/Addons/KvReferralProgram/ Config, Codes, Coupons, Tracking, Referrals, Engine, Fraud,
Commission, Rewards, Ledger, Affiliates, Payouts, Invites, Notifier,
Scheduler, Account, Install, StorageData, License/, Upgrade/Synchronizer
Tygh/Api/Entities/KvReferrals.php, KvAffiliates.php
design/backend/templates/addons/kv_referral_program/ views (manage, affiliates, affiliate, payouts, rates, referrers),
components, settings/cron_info.tpl, hooks, license/
design/backend/css/addons/kv_referral_program/ styles.less, license.less
var/themes_repository/responsive/templates/addons/kv_referral_program/ views (view, affiliate), hooks (index, profiles)
var/themes_repository/responsive/css/addons/kv_referral_program/styles.less
js/addons/kv_referral_program/func.js
var/langs/en/addons/kv_referral_program.po

The add-on ships the generated License\Client. Gated (switched off without a valid license): the storefront script configuration and click recording, new attributions at checkout and sign-up, welcome coupons, invitations, affiliate applications and the Refer a friend page. Not gated: releasing and reversing existing entries, admin approval and rejection, the affiliate dashboard and payout requests of existing balances, marking payouts paid, CSV and the REST API.