Вывод модификаций msOptionsPrice2 в окне заказа minishop2, при добавлении товара.

Всем привет, столкнулся с задачей сделать выбор модификаций компонента msOptionsPrice2, при добавлении товара в заказ минишопа, в админке. Корректность моего кода не гарантирую, поэтому, если будут какие-то замечания или советы буду только рад. За помощь в некоторых моментах, спасибо Павлу Зарубину.



Вывод нового поля в заказе


Для начала нам нужно вывести комбобокс в окне добавления товара. Для этого нам нужно подключить свой js для админки.

Создаем плагин с любым названием и пишем в нем этот код:

switch ($modx->event->name) {
    case 'msOnManagerCustomCssJs':
        if ($page != 'orders') return;
        	$modx->controller->addLastJavascript(MODX_ASSETS_URL.'components/customJs/default.js');
    break;
}

Ставим ему событие msOnManagerCustomCssJs.

Далее по пути assets/components/ создаем папку customJs и в этой папке создаем файл default.js.

Открываем файл default.js и вставляем в него этот код

//создаем переменную с нашим будущим классом


Ext.ComponentMgr.onAvailable('minishop2-window-orderproduct-update', function(){

  let id = 0;
  if (!this.record.product_id) {
    id = this.record.id;
  } else {
    id = this.record.product_id;
  }


  let addProduct = function (config) {
    config = config || {};

    //Устанавливаем свойства этого класса
    Ext.applyIf(config, {
      name: 'modlist',
      fieldLabel: config.name || 'Модификации',
      hiddenName: config.name || 'modlist',
      displayField: 'name',
      valueField: 'id',
      anchor: '99%',
      fields: ['name','id'],
      pageSize: 20,
      typeAhead: false,
      editable: true,
      allowBlank: false,
      url: '/assets/components/helpers/connector.php',
      baseParams: {
        action: 'order/addproduct',
        combo: false,
        id: id
      },
      tpl: new Ext.XTemplate('\
            <tpl for=".">\
                <div class="x-combo-list-item">\
                    <span>\
                        <b>{name}</b>\
                    </span>\
                </div>\
            </tpl>',
        {compiled: true}
      ),

    });
    //Инициализируем класс
    addProduct.superclass.constructor.call(this, config);

  };
//Говорим ExtJs'у что мы будем расширять нашим классом класс MODx.combo.ComboBox 
  Ext.extend(addProduct, MODx.combo.ComboBox);
//Регистрируем наш класс как xtype
  Ext.reg('addProduct-xtype', addProduct);
  var options = this.record;

  var modifications = {
    border: false,
    layout: 'column',
    items: [
      {
        border: false,
        columnWidth: 0.5,
        autoHeight: true,
        layout: 'form',
        items: {
          xtype: 'addProduct-xtype',
        }
      }
    ]
  };

  this.fields.push(modifications); // Добавляем наше поле в окно товара

});

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

Создаем файл connector.php по пути assets/components/helpers/ и помещаем в него следующий код:

<?php
/** @noinspection PhpIncludeInspection */
require_once dirname(dirname(dirname(dirname(__FILE__)))) . '/config.core.php';
/** @noinspection PhpIncludeInspection */
require_once MODX_CORE_PATH . 'config/' . MODX_CONFIG_KEY . '.inc.php';
/** @noinspection PhpIncludeInspection */
require_once MODX_CONNECTORS_PATH . 'index.php';

$scriptProperties = $_REQUEST;
$path = MODX_CORE_PATH . 'elements/processors/';

$path = $modx->getOption('processorsPath', $scriptProperties, $path);
/** @var modConnectorRequest $request */
$request = $modx->request;
$request->handleRequest(array(
    'processors_path' => $path,
    'location' => '',
));

Теперь процессор.
В директории core/elements/processors/order создаем файл addproduct.class.php
и помещаем в него код:

<?php
// Расширяем класс 
class GetModification extends modProcessor
{
  public $msop;
  public $mod;
  public $id;
  public $ms2;

  public function initialize()
  {
    // Иициализируем компонент msoptionprice
    $this->msop = $this->modx->getService('msoptionsprice');
    $this->msop->initialize($this->getProperty('context', $this->modx->context->key));
    // Получаем id товара
    $this->id = $this->getProperty('id');



    return parent::initialize();
  }

  public function process()
  {
     // Получаем модификации этого товара
    $q = ['rid' => $this->id];
    $mod = $this->modx->getCollection('msopModification', $q);
    if ($mod){
      foreach ($mod as $v){
        $qi = ['mid' => $v->get('id')];
        $opt = $this->modx->getObject('msopModificationOption', $qi);
        $val = '';
        if ($opt){
          $val .= $v->get('name').'-'.$opt->get('value');
        }
        $arr[] = $mod = [
          'id' => $v->get('id'),
          'name' => $val,
        ];
      };

      return $this->outputArray($arr);
    }

  }

}

return 'GetModification';

Теперь в окне редактирования товара появился наш селект и если у товара будут модификации, то они попадут в комбобокс.

Далее мы создадим плагин, назовем его customOrderRemains и назначим ему такие события:

  • msOnBeforeCreateOrderProduct
  • msOnBeforeUpdateOrderProduct
  • msOnBeforeRemoveOrderProduct
И поместим в него следующий код:

<?php

switch ($modx->event->name) {

  case "msOnBeforeCreateOrderProduct":

    $mid = $object->get('modlist');
    $prod_id = $object->get('product_id');
    $prod_cost = $object->get('cost');
    $order_id = $object->get('order_id');
    $prod_price = $object->get('price');
    $prod_count = $object->get('count');
    $modpar = array(
      'rid' => $prod_id
    );
    $par = array(
      'mid' => $mid
    );
    $mods = $modx->getCollection('msopModification', $modpar);

    foreach ($mods as $item) {
      if ($item->get('id') == $mid) {
        $count = $item->get('count');
        $modprice = $item->get('price');
        $type = $item->get('type');
        if ($count < 1) {
          $modx->event->output("Нет доступного количества");
          break;
        }
        $newCount = $count - $prod_count;
        $item->set('count', $newCount);
        if ($type == 1) {
          $prod_sum = $prod_price = $modprice;
        };
        if ($type == 2) {
          $prod_sum = $prod_price + $prod_price;
        }
        $item->save();
        $opt = $modx->getObject('msopModificationOption', $par);
        $options = [
          $opt->get('key') => $opt->get('value')
        ];
        $prod_newcost = $prod_sum * $prod_count;
        $object->set('options', $options);
        $object->set('price', $prod_sum);
        $object->set('cost', $prod_newcost);
        $object->save();

      }

    };

    break;
  case "msOnBeforeUpdateOrderProduct" :
    $mid = $object->get('modlist');
    $prod_id = $object->get('product_id');
    $order_id = $object->get('order_id');
    $prod_price = $object->get('price');
    $prod_count = $object->get('count');
    $prod_cost = $object->get('cost');
    $modpar = array(
      'rid' => $prod_id
    );
    $par = array(
      'mid' => $mid
    );
    $mods = $modx->getCollection('msopModification', $modpar);
    $order = $modx->getObject('msOrder', $order_id);
    $opt = $modx->getObject('msopModificationOption', $par);
    $option = $object->get('options');
    foreach ($mods as $item) {

      foreach ($option as $k => $v) {
        if ($k == $opt->get('key') && $v == $opt->get('value')) {
          return false;
          break;
        }
      }
      if ($item->get('id') == $mid) {
        $count = $item->get('count');
        $modprice = $item->get('price');
        $type = $item->get('type');
        if ($count < 1) {
          $modx->event->output("Нет доступного количества");
          break;
        }
        $newCount = $count - $prod_count;
        $item->set('count', $newCount);
        if ($type == 1) {
          $prod_sum = $prod_price = $modprice;
        };
        if ($type == 2) {
          $prod_sum = $prod_price + $prod_price;
        }
        $item->save();

        $options = [
          $opt->get('key') => $opt->get('value')
        ];
        $prod_newcost = $prod_sum * $prod_count;
        $object->set('options', $options);
        $object->set('price', $prod_sum);
        $object->set('cost', $prod_newcost);
        $object->save();

      }

    };

    break;

  case "msOnBeforeRemoveOrderProduct" :

    $prod_id = $object->get('product_id');
    $order_id = $object->get('order_id');
    $prod_price = $object->get('price');
    $prod_count = $object->get('count');
    $option = $object->get('options');

    foreach ($option as $k => $v) {
      if ($i <= 1){
        $par[] = array(
          'rid' => $prod_id,
          'key' => $k,
          'value' => $v
        );

      }

    }
    $opt = $modx->getObject('msopModificationOption', $par[0]);
    $modpar = array(
      'rid' => $prod_id
    );

    $mods = $modx->getObject('msopModification', $modpar);

    if ($mods->get('id') == $opt->get('mid')) {
      $count = $mods->get('count');
      $newCount = $count + $prod_count;
      $mods->set('count', $newCount);
      $mods->save();
    }

    break;

}

Как это работает


При добавлении товара в заказ, в админке, в окне редактирования товара появляется селект, который подгружает к себе в значения модификации товаров. Перед сохранением, редактированием или удалением, плагин проверяет наличие остатков у этой модификации и если их нет, то выводит ошибку, а если они есть, то вычитает количество товара из остатков модификации и сохраняет товар в заказ. Так же, в зависимости от типа модификации (+ к цене, = цене), плагин подставляет стоимость товара.

Ну вот и все, надеюсь будет кому-нибудь полезно, спасибо :)
Vlad Brise
08 декабря 2018, 09:28
modx.pro
9
2 991
+6
Поблагодарить автора Отправить деньги

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

Павел Гвоздь
08 декабря 2018, 18:11
+2
А при обновлении товара в заказе, тот модификатор, который ранее был применён, получает обратно свои остатки или происходит только вычитание? Грубо говоря:
1) Юзер оформил заказ с неправильным модификатором товара, кол-во в наличии у модификатора уменьшилось,
2) Менеджер уже на стороне бекэнда при помощи вашего решения изменил неверный модификатор на верный, кол-во в наличии у «верного» модификатора уменьшилось.
Итого мы получаем двойное вычитание кол-ва.

P.S.: Решение хорошее. Было бы вообще круто, если бы вы название компонента, для которого решение пилилось, корректно написали. Не «msOptionPrice2» а «msOptionsPrice2». =)
    Vlad Brise
    08 декабря 2018, 19:51
    +3
    Да, этот момент я упустил, спасибо за комментарий, я допилю эту функцию. А про название дополнения, я постоянно забываю про эту S, даже при разработке, моя невнимательность :)
    Дарина
    27 июня 2019, 21:38
    0
    А кто-нибудь в курсе множественные значение для одной опции можно задавать?
    у меня вот лестницы и много вариантов длины у каждой, одну задаю, а вторая почему то не создается, материться, что с таким полем есть уже значение…
      Евгений
      28 августа 2019, 13:26
      0
      А этот код работает вообще? У меня процессор отдает ошибку с текстом GetModification
        Vlad Brise
        28 августа 2019, 14:11
        0
        .class не прописал наверное
        Sergey (Sentinel)
        26 марта 2020, 23:39
        0
        Классное решение! Спасибо
        Есть два вопроса:
        1. При добавлении модификации все равно пишет is.gd/KDtOnO
        2. Как то можно из плагина убрать проверку остатков? просто на сайте стоит msProductRemains компонент и с ним ваше решение не работает
          Vlad Brise
          27 марта 2020, 00:37
          0
          Спасибо большое. По поводу скрина не понял, у меня нет никаких фасовок, скорее всего у вас другой компонент еще стоит.
          Проверку остатков можно отключить в системных настройках дополнения, в плагин лезть не надо.
            Sergey (Sentinel)
            27 марта 2020, 00:39
            0
            Да, стоит msProductRemains
              Vlad Brise
              27 марта 2020, 01:02
              +1
              ну я рассчитывал только на работу с msOptionsPrice, с остальными компонентами работать попросту не может. Тут помочь не могу
              Sergey (Sentinel)
              27 марта 2020, 12:32
              0
              А можете подсказать какой там параметр?
            Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
            10