Как изменить цену в корзине исходя из веса?

В корзине особенная логика формирования цены должна быть, и она зависит от веса (weight), а не от количества.
Если в коротко, то при достижении веса например в 400 грамм суммарно для всех товаров в корзине должна применяться для всех них скидка в 20% например.

Это нестандартная задача, обычно оптовые цены зависят от количества, а не от веса.

Я вижу решение проблемы из двух этапов:
  1. бэкэнд из плагина
  2. фронтэнд на js-кэллбэке
По первому нашел много старых примеров, например тут и тут, но все они нерабочие и плагин ругается в логи.

Сделал плагин на события msOnAddToCart, msOnBeforeAddToCart, msOnChangeInCart, msOnRemoveFromCart:

<?php
if ($modx->event->name = 'msOnBeforeAddToCart' || $modx->event->name = 'msOnChangeInCart' || $modx->event->name = 'msOnRemoveFromCart' ) {
    
    // Тут цена успешно меняется, характеристики добавляются, но для конкретного товара, но нет доступа к общей корзине
    // Но динамически это не происходит, т.к. ругается в консоль браузера на ошибки на сервере
    // Оба варианта с одинаковыми результатами
    
    // Ваниант 1
    $values = & $modx->event->returnedValues;
    $values['count'] = $count + 10;
    $values['price'] = 2;
    $values['options'] = array('size' => '99');

    // Вариант 2
    $procent = 90;
    $price = $product->get('price');
    $rate = $procent * $price / 100;
    $price = $price - $rate;
    $product->set('price', $price);
    $product->set('price', 111);

    $modx->log(modX::LOG_LEVEL_ERROR, "cart: ".print_r($product->get('price'),1) );
  
}
Приведённые 2 варианта плагина я забраковал по описанным выше причинам.

Следующий кусок плагина по логике должен был бы мне подходить, но ругается в логи сервера при попытке иницилазиации класса на строчке if($miniShop2->initialize($modx->context->key, $scriptProperties));:
<?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 '';

        // Инициализируем класс в текущий контекст
        if($miniShop2->initialize($modx->context->key, $scriptProperties));
        $total_count = $miniShop2->cart->status()['total_count'];
        $tmp = $miniShop2->cart->get();


        foreach ($tmp as $key1 => $value) {
            if ($product = $modx->getObject('msProduct', $value['id'])) {
            	$tmp[$key1]['price'] = 22222222222;
            }
        }
        
        if ($total_count > 4) { // если 5 и более товаров - оптовые цены, в интернет-магазине оптовые цены забиваются в поле article
            foreach ($tmp as $key1 => $value) {
                if ($product = $modx->getObject('msProduct', $value['id'])) {
                	$tmp[$key1]['price'] = 22222222222;
                }
            }
        }
        else {
            foreach ($tmp as $key1 => $value) {
                if ($product = $modx->getObject('msProduct', $value['id'])) {
                	$tmp[$key1]['price'] = 11111111;
                }
            }
        }
        $miniShop2->cart->set($tmp);
        break;
}
Логи:
(ERROR @ /home/s***/www/core/components/minishop2/model/minishop2/minishop2.class.php : 95) Recoverable error: Object of class msCartHandler could not be converted to string
(ERROR @ /home/s***/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?
Как заставить его работать?

Подытожу что мне нужно: у меня в плагине должен быть доступ к общим характеристикам всей корзины, а именно к общему весу. Далее мне нужно поменять изменить цену для каждого из товаров отдельно и проверить чтобы общая сумма была со скидкой.

По второму пункту (фронтенду), думаю будет ясно как поступить если будет работать первый, т.к. фронтенд вытекает из бэкэнда.
Василий Столейков
06 апреля 2017, 04:38
modx.pro
4
4 678
0
Поблагодарить автора Отправить деньги

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

PG
PG
06 апреля 2017, 08:06
+1
А зачем еще раз инициализировать minishop2?
Эти события уже получают $cart
попробуйте так:
<?php
switch ($modx->event->name) {
    case 'msOnChangeInCart': case 'msOnAddToCart': case 'msOnRemoveFromCart': 
        $total_count = $cart->status()['total_count'];
        $tmp = $cart->get();


        foreach ($tmp as $key1 => $value) {
            if ($product = $modx->getObject('msProduct', $value['id'])) {
            	$tmp[$key1]['price'] = 22222222222;
            }
        }
        
        if ($total_count > 4) { // если 5 и более товаров - оптовые цены, в интернет-магазине оптовые цены забиваются в поле article
            foreach ($tmp as $key1 => $value) {
                if ($product = $modx->getObject('msProduct', $value['id'])) {
                	$tmp[$key1]['price'] = 22222222222;
                }
            }
        }
        else {
            foreach ($tmp as $key1 => $value) {
                if ($product = $modx->getObject('msProduct', $value['id'])) {
                	$tmp[$key1]['price'] = 11111111;
                }
            }
        }
        $cart->set($tmp);
        break;
}
    Василий Столейков
    06 апреля 2017, 12:02
    1
    0
    Действительно, зачем это я… Тупое копирование с примеров, которые у других работали.
    Спасибо тебе, добрый человек, всё работает как и задумывалось!

    Вот что получилось (на будущее):
    Плагин:
    <?php
    switch ($modx->event->name) {
        case 'msOnChangeInCart': case 'msOnAddToCart': case 'msOnRemoveFromCart': 
            $total_count = $cart->status()['total_count'];
            $total_weight = $cart->status()['total_weight'];
            
            $procent = 20;
            
            $tmp = $cart->get();
            
            if ($total_weight > 400) {
                foreach ($tmp as $key1 => $value) {
                    if ($product = $modx->getObject('msProduct', $value['id'])) {
    
                        $price = $product->get('price');
                        $rate = $procent * $price / 100;
                        $price = $price - $rate;
                    	$tmp[$key1]['price'] = $price;
                        $modx->log(modX::LOG_LEVEL_ERROR, "cart: ".print_r($price,1) );
                    	
                    	
                    }
                }
            }
            else {
                foreach ($tmp as $key1 => $value) {
                    if ($product = $modx->getObject('msProduct', $value['id'])) {
                    	$tmp[$key1]['price'] = $product->get('price');
                    }
                }
            }
            $cart->set($tmp);
        break;
    }
    Ну и на фронтенде повторение функционала:
    <script>
        miniShop2.Callbacks.add('Cart.change.response.success', 'response_log', function(e) {
            var total_weight = e.data.total_weight;
            if(total_weight > 400) {      
                console.log('opt');
                $('#msCart .price .procent').text('-20%');
            } else {
                $('#msCart .price .procent').text('');
            }
        });
        miniShop2.Callbacks.add('Cart.remove.response.success', 'response_log', function(e) {
            var total_weight = e.data.total_weight;
            if(total_weight > 400) {      
                console.log('opt');
                $('#msCart .price .procent').text('-20%');
            } else {
                $('#msCart .price .procent').text('');
            }
        });
    </script>
      ruslan.p
      30 сентября 2017, 23:42
      0
      Подскажите, вы создали плагин через админку? почему то у меня ничего не происходит
        Василий Столейков
        02 октября 2017, 08:12
        1
        0
        да, через админку, на 3 события, которые указаны в начале плагина.
    Алексей Шумаев
    02 октября 2017, 13:55
    0
    А почему не сделать расширением корзины? Я так решаю подобные задачи.
    Пример в доках: docs.modx.pro/components/minishop2/development/service/connection#Пример-подключения-собственного-класса-доставки
      Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
      5