Developer notes
File map
Section titled “File map”app/addons/kv_vendor_coupons/ addon.xml settings, 2 tables, 2 privileges init.php / func.php hooks, promotion condition/bonus callbacks, settings handlers, licence helpers controllers/backend/kv_vendor_coupons.php coupon list, editor, approval, usage report (admin + vendor) controllers/backend/promotions.pre.php core promotion editor: redirects coupon promotions controllers/backend/kv_vendor_coupons_license.php "Check now" and licence cron schemas/promotions/schema.post.php condition "kv_vc_coupon" and bonus "kv_vc_discount" schemas/menu/*.post.php Marketing menu (admin, vendor panel, vendor panel configurator) schemas/permissions/*.post.php privileges, vendor access Tygh/Addons/KvVendorCoupons/ Config.php settings, vendor/plan check Coupons.php storage, validation, shadow promotion sync Engine.php condition, bonus (discount lines), free shipping, funding adjustment Usage.php usage rows, limits, first-order check, report License/, Upgrade/ licence client, self-healing upgradesdesign/backend/templates/addons/kv_vendor_coupons/ views (manage, update, usage), components, licence UIdesign/backend/css/addons/kv_vendor_coupons/ styles.less, license.lessjs/addons/kv_vendor_coupons/backend.js coupon editorvar/langs/en/addons/kv_vendor_coupons.poHow a coupon maps to core
Section titled “How a coupon maps to core”Every coupon owns one core cart promotion (?:promotions, company_id = vendor, zone = cart, priority 9000000 so it runs after marketplace promotions, status A only while the coupon is active and approved). Its conditions are coupon_code eq CODE and the add-on condition kv_vc_coupon eq <coupon_id>; its bonus is kv_vc_discount. The core then handles the coupon field and messages, cart.coupons, the order’s promotions data and the display of applied promotions.
- The condition (
Engine::check()) checks licence, status/approval, dates, vendor/plan, the vendor’s items, the minimum, total/per-customer uses and the first-order rule. While Multi-Vendor suborders are placed, core evaluates conditions against the parent order; the condition then simply returns whether the parent order has the coupon. - The bonus (
Engine::apply()) calculates per-unit discounts for the vendor’s lines and applies them with corefn_promotion_apply_discount()(by_fixedper unit), like the core “discount on products” bonus. In suborders the per-unit values stored in the parent order are re-used, so parent and vendor order always agree. The coupon data (kv_vc: coupon, vendor, code, discount, item subtotal, lines, free shipping, funding) is stored in the bonus, i.e. inorders.promotions. - With the add-on disabled, the condition and bonus are missing from the promotion schema, so core never applies the promotions.
- The promotions are hidden on the core promotion pages (
get_promotionswhileruntime.controllerispromotionsand the search is not the cart calculation) and the core editor redirects to the coupon (promotions.pre.php).
Money rules
Section titled “Money rules”- Percent:
round(price × percent / 100, decimals)per unit, on the price after marketplace catalog/product promotions; capped by the maximum percent. - Fixed amount: integer minor units; proportional shares per line, floored per unit; the rest is added one minor unit per item, lines with the smallest quantity first, as long as it fits. The total never exceeds
min(amount, cap, items). - Free shipping:
calculate_cart_content_after_shipping_calculationsets every rate of the vendor’s product group to 0; the original rate is kept inkv_vc_rateand restored when the coupon goes away. - Funding (
mve_place_order, add-on priority 2700):fn_calculate_commission_for_payout()runs again with the coupon added back to the order total, payout amount and lines (recursion-guarded). Vendor: commission = that value, capped at the order amount. Marketplace: that value minus the discount. Shared: unchanged.marketplace_profit,commission_amountandextra.kv_vendor_couponsof the payout are updated before core saves it.
Tables
Section titled “Tables”| Table | Contents |
|---|---|
?:kv_vc_coupons |
coupon_id, company_id, promotion_id, code (unique), name, discount_type (P/F/N), discount_value, free_shipping, min_subtotal, from_date, to_date, uses_total, uses_per_customer, first_order, status (A/D), approval (A/P/R), admin_note, created_at, updated_at, user_id |
?:kv_vc_usages |
usage_id, coupon_id, company_id, order_id, parent_order_id, user_id, email, code, items_subtotal, discount, shipping_saved, funding, commission_delta, created_at; unique (order_id, coupon_id) |
A use is counted while the order status is not N, F, D or I.
All hooks have identical arguments in 4.17.2 and 4.21.2.
| Hook | Use |
|---|---|
calculate_cart_items |
resets the free-shipping marks before promotions are re-applied |
calculate_cart_content_after_shipping_calculation |
free shipping of the vendor’s product group |
promotion_apply_before_get_promotions |
drops the per-request promotion cache after a coupon changed in the same request |
pre_place_order |
stops the order once when a coupon the customer saw became invalid during checkout |
mve_place_order |
funding adjustment of the vendor payout |
place_order |
usage row of each vendor order |
get_promotions |
hides coupon promotions on core promotion pages |
delete_promotions_post |
a coupon promotion deleted elsewhere disables its coupon |
delete_order, delete_company |
cleanup |
Full page cache (4.21)
Section titled “Full page cache (4.21)”No storefront output and no storefront writes on GET requests. Customers use the core coupon field on the cart and checkout pages, which are not cached.
License check
Section titled “License check”fn_kv_vendor_coupons_is_licensed() (License\Client::isActive()) gates new coupons in carts (in the condition; a coupon already applied in the previous calculation keeps working, so a started checkout is never broken) and saving coupons. Placed orders, the funding adjustment of orders with an applied coupon, lists and reports are never gated. The licence check itself runs only in the admin panel or from cron (php admin.php --dispatch=kv_vendor_coupons_license.check).
Extension points
Section titled “Extension points”- The applied coupons of a cart or order:
\Tygh\Addons\KvVendorCoupons\Engine::appliedCoupons($cart['promotions']). - The payout extra
kv_vendor_couponsholds the commission with and without the coupon and the adjustment. - Commission add-ons that use
vendor_plans_calculate_commission_for_payout_*are included in the “without coupon” calculation automatically.