Как сделать скидки от количества товара?

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




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




Первое что пришло в голову, это установить MIGX и по средством TV параметра, скажем discount выгружать количество товара и скидок от которых они зависят, вот что получилось:

<?php
$dis = $modx->resource->getTVValue('discount');
$a = json_decode($dis, true);

foreach ($a as $discount => $value) {
    $count = $value["count"];
    $price = $value["price"];
    
    echo '<p>'.$count.' шт. - '.$price.'%</p>';
}

На странице мы видим вот такой список:
5 шт. — 0%
10 шт. — 5%
30 шт. — 10%
100 шт. — 20%
500 шт. — 30%

Нашёл в сообществе решение и решил на его базе сделать то, что мне нужно. Написать плагин с названием cartProcessing и системными событиями msOnAddToCart, msOnChangeInCart и msOnRemoveFromCart:
<?php
switch ($modx->event->name) {
    case 'msOnChangeInCart': case 'msOnAddToCart': case 'msOnRemoveFromCart':
        $miniShop2 = $modx->getService('minishop2','miniShop2',
        	MODX_CORE_PATH . 'components/minishop2/model/minishop2/', $scriptProperties);
        if (!($miniShop2 instanceof miniShop2)) return '';
        
        // Инициализируем класс в текущий контекст
        $miniShop2->initialize($modx->context->key, $scriptProperties);
        $total_count = $miniShop2->cart->status()['total_count'];
        $tmp = $miniShop2->cart->get();
        
        $dis = $modx->resource->getTVValue('discount');
        $a = json_decode($dis, true);
        
        foreach ($a as $discount => $value) {
            $count = $value["count"];
            $price = $value["price"];
            
            echo '<p>'.$count.' - '.$price.'</p>';
            
            if ($total_count > $count) { // если 5 и более товаров
                foreach ($tmp as $key1 => $value) {
                    if ($product = $modx->getObject('msProduct', $value['id'])) {
                    	$realPrice = $product->get('price');
                    	$tmp[$key1]['price'] = $price;
                    }
                }
            }
            else {
                foreach ($tmp as $key1 => $value) {
                    if ($product = $modx->getObject('msProduct', $value['id'])) {
                    	$realPrice = $product->get('price');
                    	$tmp[$key1]['price'] = $realPrice;
                    }
                }
            }
        }
        $miniShop2->cart->set($tmp);
        break;
}
Помогите пожалуйста, не умею я писать плагины из-за того, что не до конца понимаю принцип их работы.
Андрей Копп
10 октября 2015, 22:00
modx.pro
7
5 887
0

Комментарии: 13

Максим Кузнецов
11 октября 2015, 23:39
0
$dis = $modx->resource->getTVValue('discount');
Проблема как минимум в этой строчке, т.к. вам нужно получить не тв-поле текущего ресурса, а тв-поле товара.

У вас есть как минимум 2 способа реализовать данную задачу — через систему плагинов или через расширение класса корзины.

В обоих случаях принцип работы примерно такой:
— при требуемых событиях (добавление товара, изменение количества, удаление товара и тд) для каждого конкретного товара или циклом во всей корзине получаем параметры товаров
— из полученных данных выбираем id и запрашиваем для каждого товара кастомное тв-поле со списком скидок
— если тв-поле присутствует, то в отсортированным по необходимому для скидки количеству массиве, через цикл сверяем значение с количеством товара в корзине. Так получаем соответствующую скидку по количеству для каждого товара.
— умножаем скидку на исходную цену товара
— возвращаем значение
    Андрей Копп
    15 октября 2015, 17:11
    0
    Сделал через систему плагинов, плагин вот такой получился, по ощущениям всё правильно должно быть, но он не считает почему-то:

    <?php
    switch ($modx->event->name) {
        case 'msOnChangeInCart': case 'msOnAddToCart': case 'msOnRemoveFromCart':
            $miniShop2 = $modx->getService('minishop2','miniShop2',
            	MODX_CORE_PATH . 'components/minishop2/model/minishop2/', $scriptProperties);
            if (!($miniShop2 instanceof miniShop2)) return '';
            
            // Инициализируем класс в текущий контекст
            $miniShop2->initialize($modx->context->key, $scriptProperties);
            $total_count = $miniShop2->cart->status()['total_count'];
            $tmp = $miniShop2->cart->get();
            if ($total_count > 4) { // если 5 и более товаров - оптовые цены, в интернет-магазине оптовые цены забиваются в поле article
                foreach ($tmp as $key1 => $value) {
                    if ($product = $modx->getObject('msProduct', $value['id'])) {
                    	$realPrice = $product->get('price');
                    	$discount1 = $product->get('discount1');
                    	$opt = $realPrice*$discount1/100;
                        $optPrice = $realPrice-$opt;
                    	$tmp[$key1]['price'] = $optPrice;
                    }
                }
            }
            elseif ($total_count > 9) { // если 10 и более товаров - оптовые цены, в интернет-магазине оптовые цены забиваются в поле article
                foreach ($tmp as $key1 => $value) {
                    if ($product = $modx->getObject('msProduct', $value['id'])) {
                    	$realPrice = $product->get('price');
                    	$discount2 = $product->get('discount2');
                    	$opt = $realPrice*$discount2/100;
                        $optPrice = '';
                    	$tmp[$key1]['price'] = $optPrice;
                    }
                }
            }
            elseif ($total_count > 29) { // если 30 и более товаров - оптовые цены, в интернет-магазине оптовые цены забиваются в поле article
                foreach ($tmp as $key1 => $value) {
                    if ($product = $modx->getObject('msProduct', $value['id'])) {
                    	$realPrice = $product->get('price');
                    	$discount3 = $product->get('discount3');
                    	$opt = $realPrice*$discount3/100;
                        $optPrice = $realPrice-$opt;
                    	$tmp[$key1]['price'] = $optPrice;
                    }
                }
            }
            elseif ($total_count > 99) { // если 100 и более товаров - оптовые цены, в интернет-магазине оптовые цены забиваются в поле article
                foreach ($tmp as $key1 => $value) {
                    if ($product = $modx->getObject('msProduct', $value['id'])) {
                    	$realPrice = $product->get('price');
                    	$discount4 = $product->get('discount4');
                    	$opt = $realPrice*$discount4/100;
                        $optPrice = $realPrice-$opt;
                    	$tmp[$key1]['price'] = $optPrice;
                    }
                }
            }
            elseif ($total_count > 499) { // если 500 и более товаров - оптовые цены, в интернет-магазине оптовые цены забиваются в поле article
                foreach ($tmp as $key1 => $value) {
                    if ($product = $modx->getObject('msProduct', $value['id'])) {
                    	$realPrice = $product->get('price');
                    	$discount5 = $product->get('discount5');
                    	$opt = $realPrice*$discount5/100;
                        $optPrice = $realPrice-$opt;
                    	$tmp[$key1]['price'] = $optPrice;
                    }
                }
            }
            else {
                foreach ($tmp as $key1 => $value) {
                    if ($product = $modx->getObject('msProduct', $value['id'])) {
                    	$realPrice = $product->get('price');
                    	$tmp[$key1]['price'] = $realPrice;
                    }
                }
            }
            $miniShop2->cart->set($tmp);
            break;
    }
    Андрей Копп
    15 октября 2015, 20:07
    2
    0
    Рабочий вариант плагина:

    <?php
    switch ($modx->event->name) {
        case 'msOnChangeInCart': case 'msOnAddToCart': case 'msOnRemoveFromCart':
            $miniShop2 = $modx->getService('minishop2','miniShop2',
            	MODX_CORE_PATH . 'components/minishop2/model/minishop2/', $scriptProperties);
            if (!($miniShop2 instanceof miniShop2)) return '';
            
            // Инициализируем класс в текущий контекст
            $miniShop2->initialize($modx->context->key, $scriptProperties);
            $total_count = $miniShop2->cart->status()['total_count'];
            $tmp = $miniShop2->cart->get();
            if ($total_count > 499) { // если 5 и более товаров - оптовые цены, в интернет-магазине оптовые цены забиваются в поле article
                foreach ($tmp as $key1 => $value) {
                    if ($product = $modx->getObject('msProduct', $value['id'])) {
                    	$realPrice = $product->get('price');
                    	$discount5 = $product->get('discount5');
                    	$opt = $realPrice*$discount5/100;
                        $optPrice = $realPrice-$opt;
                    	$tmp[$key1]['price'] = $optPrice;
                    }
                }
            }
            elseif ($total_count > 99) { // если 10 и более товаров - оптовые цены, в интернет-магазине оптовые цены забиваются в поле article
                foreach ($tmp as $key1 => $value) {
                    if ($product = $modx->getObject('msProduct', $value['id'])) {
                    	$realPrice = $product->get('price');
                    	$discount4 = $product->get('discount4');
                    	$opt = $realPrice*$discount4/100;
                        $optPrice = $realPrice-$opt;
                    	$tmp[$key1]['price'] = $optPrice;
                    }
                }
            }
            elseif ($total_count > 29) { // если 30 и более товаров - оптовые цены, в интернет-магазине оптовые цены забиваются в поле article
                foreach ($tmp as $key1 => $value) {
                    if ($product = $modx->getObject('msProduct', $value['id'])) {
                    	$realPrice = $product->get('price');
                    	$discount3 = $product->get('discount3');
                    	$opt = $realPrice*$discount3/100;
                        $optPrice = $realPrice-$opt;
                    	$tmp[$key1]['price'] = $optPrice;
                    }
                }
            }
            elseif ($total_count > 9) { // если 100 и более товаров - оптовые цены, в интернет-магазине оптовые цены забиваются в поле article
                foreach ($tmp as $key1 => $value) {
                    if ($product = $modx->getObject('msProduct', $value['id'])) {
                    	$realPrice = $product->get('price');
                    	$discount2 = $product->get('discount2');
                    	$opt = $realPrice*$discount2/100;
                        $optPrice = $realPrice-$opt;
                    	$tmp[$key1]['price'] = $optPrice;
                    }
                }
            }
            elseif ($total_count > 4) { // если 500 и более товаров - оптовые цены, в интернет-магазине оптовые цены забиваются в поле article
                foreach ($tmp as $key1 => $value) {
                    if ($product = $modx->getObject('msProduct', $value['id'])) {
                    	$realPrice = $product->get('price');
                    	$discount1 = $product->get('discount1');
                    	$opt = $realPrice*$discount1/100;
                        $optPrice = $realPrice-$opt;
                    	$tmp[$key1]['price'] = $optPrice;
                    }
                }
            }
            else {
                foreach ($tmp as $key1 => $value) {
                    if ($product = $modx->getObject('msProduct', $value['id'])) {
                    	$realPrice = $product->get('price');
                    	$tmp[$key1]['price'] = $realPrice;
                    }
                }
            }
            $miniShop2->cart->set($tmp);
            break;
    }
    Осталось теперь придумать как это всё менять на лету, на странице с товаром и в корзине при оформлении заказа, может кто-нибудь в курсе как дописать этот скрипт, чтобы считалось всё на лету?

    <script type="text/javascript">
    $('#msCart input[name="count"]').change(function(){
    	var count = $(this).val(); 
    	var singlePrice = parseInt($(this).closest('.tab_row').children(".tab_sum").text());
    
    	$(this).closest('.tab_row').children(".tab_pr").children("span").html(count * singlePrice);
    });
    </script>
      Артем
      16 октября 2015, 02:37
      0
      что бы отображаемая цена менялась?
        SEQUEL.ONE
        16 октября 2015, 08:07
        0
        Было бы очень не плохо.
          Артем
          16 октября 2015, 10:55
          1
          0
          я на странице товара js'ом меняю, а в корзине сделал событие которое при изменении количества подгружает ajax'ом обновленную div с корзиной с другой страницы.
          Есть еще такой вариант modx.pro/solutions/3942-dynamic-update-of-the-basic-basket/
          но он у меня не пошел, все время что-то отваливается и работает не так.
            Андрей Воробей
            30 ноября 2015, 14:12
            1
            0
            Артём а можете подсказать, как вы реализовали динамическую смену цены в корзине. И ещё вопрос как можно делать скидку именно для определённой категории
        Василий Столейков
        31 марта 2017, 11:43
        0
        Этот плагин ещё работает?

        У меня плагин ругается при попытке инициализации класса:
        [2017-03-31 11:34:26] (ERROR @ /home/s7102/www/core/components/minishop2/model/minishop2/minishop2.class.php : 95) Recoverable error: Object of class msCartHandler could not be converted to string
        [2017-03-31 11:34:26] (ERROR @ /home/s7102/www/core/components/minishop2/model/minishop2/minishop2.class.php : 104) Recoverable error: Object of class msCartHandler could not be converted to string

        В файле minishop2.class.php на этих строчках регистрация клиентского скрипта:
        $this->modx->regClientCSS(str_replace($config['pl'], $config['vl'], $css)); // 95 строчка
        $this->modx->regClientScript(str_replace($config['pl'], $config['vl'], $js)); // 104 строчка

        И понятное дело плагин не срабатывает как задумывалось. В чём может быть проблема? Или minishop2 с тех пор настолько изменился что конфликтует?
          Василий Столейков
          31 марта 2017, 11:45
          0
          Ругается именно на эту строчку в плагине:
          $miniShop2->initialize($modx->context->key, $scriptProperties);
            Дмитрий Суворов
            31 марта 2017, 12:26
            0
            уже есть компонент для этого дела: modstore.pro/packages/ecommerce/mssaleprice
              Василий Столейков
              31 марта 2017, 13:29
              0
              Неа, не подходит. У меня своя логика формирования цены должна быть, и она зависит от веса (weight), а не от количества.
              Если в коротко, то при достижении например 400 грамм суммарно для всех товаров в корзине должна применяться для всех них скидка в 20% например.
              Этот плагин идеально подходил бы к моей задаче, если бы не плевался в логи…
      Василий Наумкин
      16 октября 2015, 04:13
      0
      Уже обсуждали, и не один раз:
      modx.pro/work/3953-the-price-of-the-goods-depending-on-the-number/
      modx.pro/help/987/
      modx.pro/help/3200/
      Думаю, можно найти еще.
        Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
        13