Live Demo: Try this and other plugins live — no installation, no risk: demo.markus-michalski.net
| Property | Value |
|---|---|
| Composer package | mmd/oxid7-voucherrules |
| Module ID | mmd_voucherrules |
| Namespace | Mmd\VoucherRules (PSR-4, directory src/) |
| Target directory | mmd/voucherrules |
| Metadata version | 2.1 |
| Events | onActivate creates the tables, onDeactivate is intentionally empty |
The central check lives in VoucherValidationService::validate(). It is called from the extended Voucher class after OXID's standard check has passed. The rules run in this order, and the first exception thrown ends the check:
Consequence of the order: as long as a payment or delivery rule is still pending, the rules after it (for example the time window) are not evaluated yet.
| Rule | Condition | Result |
|---|---|---|
| Payment | Restriction present, no payment method in the session | reserved (hint "payment pending") |
| Payment | Restriction present, payment method not allowed | reserved (hint "payment not matching") |
| Delivery | analogous to payment | reserved |
| First order | Option set and the user has non-cancelled orders (OXSTORNO = 0, same shop); without a user ID nothing is checked |
rejected |
| Time window | Active windows exist, none matches weekday and time of day | rejected |
| Combination | Maximum > 0 and number of distinct series of the other applied vouchers (excluding the voucher itself, reserved ones not counted) >= maximum, or a blocked pair with an applied voucher | rejected |
| Min order value | Entries exist, no payment/delivery method selected | reserved |
| Min order value | Entry for the selected payment/delivery method, basket value lower | reserved (hint with amount) |
The weekday is determined with date('N'), the time of day with the database's CURTIME(). The window check is CURTIME() BETWEEN STARTTIME AND ENDTIME, so a window entered as HH:MM ends at second 00.
A voucher with an open condition raises a VoucherRulePendingException. The class Extension\Model\Voucher catches it, remembers the voucher number and stores a hint. The exception is re-thrown so that OXID applies no discount. A VoucherRuleViolationException removes the reservation and rejects the voucher. Both exceptions extend OXID's VoucherException.
Data is stored in the session under two keys: mmd_voucherrules_pending (list of voucher numbers) and mmd_voucherrules_hints (hints with key and minimum value). The session values paymentid and sShipSet are read.
Auto-activation only runs if a payment or delivery method is set in the session. After Order::finalizeOrder(), reservations, hints as well as paymentid and sShipSet are deleted. With an empty basket (Basket::calculateBasket()), only reservations and hints are deleted.
| OXID class | Module class | Purpose |
|---|---|---|
Voucher |
Extension\Model\Voucher |
Extended check in checkVoucherAvailability() and checkBasketVoucherAvailability(), reservation |
VoucherSerie |
Extension\Model\VoucherSerie |
Access to the first-order flag and the maximum |
Basket |
Extension\Model\Basket |
Auto-activation and hints in calculateBasket(), hides red error banners for reservations |
BasketController |
Extension\Controller\BasketController |
addVoucher() without error banner for a reservation, action removePendingVoucher |
ViewConfig |
Extension\Core\ViewConfig |
getVoucherRulesHints(), getPendingVouchers(), hasPendingVouchers() for templates |
Order |
Extension\Model\Order |
Cleanup in finalizeOrder() |
| Controller ID | Class | Tab ID in menu.xml |
|---|---|---|
mmd_voucherrules_main |
VoucherRulesMain |
tbclvoucherserie_rules_main |
mmd_voucherrules_timewindow |
VoucherRulesTimeWindow |
tbclvoucherserie_rules_timewindow |
mmd_voucherrules_combination |
VoucherRulesCombination |
tbclvoucherserie_rules_combination |
mmd_voucherrules_payment_minval |
VoucherRulesPaymentMinVal |
tbclvoucherserie_rules_payment_minval |
The tabs are attached to the menu item mxvouchers (main menu mxshopsett). All writing actions check the session challenge; deleting and changing additionally verify the series and shop of the entry.
The services and repositories are marked public in the Symfony container (services.yaml) and can be fetched through the ContainerFactory: VoucherValidationService, FirstOrderCheckService, TimeWindowCheckService, CombinationCheckService, VoucherRestrictionHintService as well as the repositories VoucherRulesConfigRepository, PaymentRestrictionRepository, DeliveryRestrictionRepository, TimeWindowRepository, CombinationRepository, PaymentMinValueRepository and DeliveryMinValueRepository. There is no documented extension API and no events.
For the Apex theme the module ships two template extensions:
layout/base.html.twig includes the stylesheet css/voucherrules.css in the block base_style.page/checkout/inc/summary_sidebar.html.twig adds the hint box to the block checkout_basketcontents_grandtotal. It uses oViewConf.getPendingVouchers() and oViewConf.getVoucherRulesHints(); the remove link calls index.php?cl=basket&fnc=removePendingVoucher with voucherNr and the session token.For other themes the same pattern can be implemented in the theme's checkout summary.
Seven tables with the prefix mmd_voucherrules_, all with OXSHOPID; the voucher series is stored in OXVOUCHERSERIEID:
| Table | Purpose | Key columns |
|---|---|---|
mmd_voucherrules_config |
Settings per series (unique per series and shop) | FIRSTORDERONLY, MAXCOMBINED |
mmd_voucherrules_payment |
Allowed payment methods | OXPAYMENTID |
mmd_voucherrules_delivery |
Allowed delivery methods | OXDELIVERYSETID |
mmd_voucherrules_timewindow |
Time windows | WEEKDAYS (bitmask bit 0 = Monday to bit 6 = Sunday, 127 = all), STARTTIME, ENDTIME, ACTIVE |
mmd_voucherrules_combination |
Blocked pairs, series IDs stored in sorted order | OXVOUCHERSERIEID_A, OXVOUCHERSERIEID_B |
mmd_voucherrules_payment_minval |
Minimum order value per payment method | OXPAYMENTID, MINORDERVALUE |
mmd_voucherrules_delivery_minval |
Minimum order value per delivery method | OXDELIVERYSETID, MINORDERVALUE |
The tables are created on activation with
CREATE TABLE IF NOT EXISTS. Data is kept on deactivation.