Skip to content
  1. Компоненты
  2. msProductDiscounts
  3. Кейсы

Кейсы использования

Акция "Купи два - получи третий в подарок"

При заказе больше двух штук одного товара, третий будет бесплатным, но добавить его покупатель должен сам.

Акция "Купи два - получи третий в подарок"

Акция "Черная пятница"

Скидка на все товары в течение одних суток в определённый день недели.

Акция "Черная пятница"

Акция "Техника Bosch со скидкой"

Скидка на все товары производителя.

Акция "Техника Bosch со скидкой"

Акция "Мебель за полцены"

Скидка на определённую категорию товаров.

Акция "Мебель за полцены"

Акция "Ликвидация остатков"

Скидка на определённые товары.

Акция "Ликвидация остатков"

Акция "Зарегистрируйся и купи дешевле"

Скидка только для зарегистрированных и авторизованных пользователей.

Акция "Зарегистрируйся и купи дешевле"

Акция "Скидка при покупке от 1000 рублей"

Скидка с ограничением по минимальной сумме заказа.

Акция "Скидка при покупке от 1000 рублей"

Акция "Летняя распродажа"

Скидка на все товары в течение определенного периода.

Акция "Летняя распродажа"

Акция "Попробуй новое и сэкономь"

Скидка на товары с активным свойством "Новый".

Акция "Попробуй новое и сэкономь"

Промокоды

Встроенного функционала нет, но его можно создать под ваши нужды. Ниже приведён один из вариантов реализации.

  1. Создадим новую опцию promocode. Создадим новую опцию

  2. Создадим новую скидку-промокод. Здесь важно добавить опцию promocode со значением промокода. Создадим новую скидку-промокод

  3. Вероятно, Вам захочется сделать ограниченное число промокодов. Установите компонент Migx. Создайте конфигурацию promocodes_count (название может быть любым) с полями promocode и count (название полей строго такие). Создайте конфигурацию

  4. Создайте TV с именем promocodes_count (название может быть любым) и присвойте любому удобному шаблону, я присвоил шаблону 1 (это нам понадобится дальше).

  5. Заполните созданное TV тем значением, которое указали при создании скидки в п.2 и укажите доступное количество промокодов.

  6. Теперь нам нужна форма для ввода промокода. Я использовал компонент AjaxFormitLogin и вызвал форму на странице корзины. Вызов выглядит так

    fenom
    {'!AjaxFormitLogin' | snippet:[
      'form' => '@FILE promocodeForm.tpl',
      'hooks' => 'applyPromocode',
      'customValidators' => 'promocode',
      'validate' => 'promocode:required:promocode=^1|promocodes_count^',
      'aliases' => 'promocode==Промокод',
      'promocode.vTextRequired' => 'Не передан.',
      'successMessage' => 'Промокод применён',
      'transmittedParams' => '{"success" : "", "error" : "aliases"}'
    ]}

    Чанк формы promocodeForm.tpl имеет следующее содержимое

    html
    <form class="">
      <div class="input-group mb-3">
        <input type="text" class="form-control" placeholder="Введите промокод" name="promocode">
        <button class="btn btn-success" type="submit">Применить</button>
      </div>
    </form>
  7. Также потребуется проверка введённого промокода. Проверять будем применён ли уже этот промокод текущим пользователем, существует и активна ли скидка связанная с промокодом, остаток промокодов. Для этого создадим свой сниппет-валидатор promocode со следующим содержимым

    php
    require_once MODX_CORE_PATH . 'elements/promocodes.class.php';
    
    $params = explode('|', $param);
    $promocodeHandler = new Promocodes($modx, $value, $params[0], $params[1]);
    $msg = $promocodeHandler->validate();
    if(is_string($msg)){
        $validator->addError($key, $msg);
        return false;
    }
    return true;
  8. Кроме того после применения проммокода, нужно изменять остаток и обновлять корзину. Это мы сделаем в сниппите-хуке applyPromocode с таким кодом

    php
    require_once MODX_CORE_PATH . 'elements/promocodes.class.php';
    
    preg_match('/promocode=\^(.*?)\^/', $hook->formit->config['validate'], $matches);
    $params = explode('|', $matches[1]);
    $promocodeHandler = new Promocodes($modx, $_POST['promocode'], $params[0], $params[1]);
    $promocodeHandler->process();
    return true;
  9. Чтобы сниппеты работали нужно создать класс Promocodes в файле elements/promocodes.class.php с кодом

    php
    class Promocodes
    {
      public function __construct($modx, $promocode, $rid, $tvname)
      {
        $this->modx = $modx;
        $this->modx->getService('mspdDiscounts', 'mspdDiscounts', MODX_CORE_PATH . 'components/msproductdiscounts/model/');
        $this->promocode = $promocode;
        $this->rid = $rid;
        $this->tvname = $tvname;
        $this->init();
      }
    
      private function init()
      {
        $tableName = $this->modx->getTableName('mspdOption');
        $q = $this->modx->newQuery('mspdDiscount');
        $q->where("active = 1 AND id = (SELECT did FROM $tableName WHERE option_value = '$this->promocode')");
        $this->query = $q;
    
        if ($this->resource = $this->modx->getObject('modResource', $this->rid)) {
          if ($codes = $this->resource->getTVValue($this->tvname)) {
            $this->codes = $this->reformatMIGX(json_decode($codes, 1));
          }
        }
      }
    
      private function reformatMIGX($migx)
      {
        $output = array();
        foreach ($migx as $item) {
          $output[$item['promocode']] = $item['count'];
        }
        return $output;
      }
    
      public function validate()
      {
        if ($this->isApplied()) return ' Уже применён Вами.';
        if (!$this->isActive()) return ' Не найден.';
        if (!$this->validateCount()) return ' Количество исчерпано.';
        return true;
      }
    
      private function isApplied()
      {
        return $_SESSION['promocode'] === $this->promocode;
      }
    
      private function isActive()
      {
        return (bool)$this->modx->getCount('mspdOption', $this->query);
      }
    
      private function validateCount()
      {
        if (empty($this->codes)) return false;
        return $this->codes[$this->promocode] > 0;
      }
    
      public function process(){
        $_SESSION['promocode'] = $this->promocode;
        $this->updateCount();
        $this->updateCart();
      }
    
      private function updateCount(){
        $this->codes[$this->promocode] = ($this->codes[$this->promocode] - 1 >= 0) ? $this->codes[$this->promocode] - 1 : 0;
    
        if($codes = $this->resource->getTVValue($this->tvname)){
          $codes = json_decode($codes,1);
          foreach($codes as $k => $item){
            if($item['promocode'] === $this->promocode){
              $codes[$k]['count'] = $this->codes[$this->promocode];
            }
          }
          $this->resource->setTVValue($this->tvname, json_encode($codes));
          $this->resource->save();
        }
      }
    
      private function updateCart(){
        $ms2 = $this->modx->getService('minishop2');
        $ms2->initialize($this->modx->context->get('key'));
        if($tmp = $ms2->cart->get()){
          foreach($tmp as $k => $item){
            $tmp[$k]['options']['promocode'] = $this->promocode;
          }
    
          uasort($tmp, function ($a, $b) {
              $aprice = $_SESSION['start_cart_state'][$a['key']]['price'] ?: $a['price'];
            $bprice = $_SESSION['start_cart_state'][$b['key']]['price'] ?: $b['price'];
            if ($aprice == $bprice) {
              return 0;
            }
            return ($aprice > $bprice) ? -1 : 1;
          });
    
          $tmp = $this->modx->mspdDiscounts->prepareProductDiscounts($tmp);
          $ms2->cart->set($tmp);
        }
      }
    }
  10. Чтобы после применения промокода скидка применялась ко вновь добавляемым в корзину товарам, нам понадобится ещё плагин

    php
    switch ($modx->event->name) {
      case 'msOnAddToCart':
        $tmp = $cart->get();
        $tmp[$key]['options']['promocode'] = $_SESSION['promocode'];
        $cart->set($tmp);
        break;
    }

Теперь Вы можете создавать какие угодно промокоды в каком угодно количестве и гибко настраивать к каким товарам их применять.