msOptionsPrice2 и склады
Долго ломал голову, как связать msOptionsPrice2 и наличие товара на складах. В модификациях товара у меня хранятся размеры и кол-во. Искал решение или компонент, который бы позволил сделать что-то подобное. Как оказалось, искал не там… В итоге сделал всё на базе msOptionsPrice2 и костыля, как это часто бывает.
1. Опция со списком складов
Создаём miniShop2 опцию — stocks с типом Список с автодополнением. В ней у каждого товара будет храниться список складов, на которых он предположительно присутствует.
2. Отображение пустых складов
Если вам нужно отображать склад с нулевым кол-вом товара, указываем системную настройку msoptionsprice_allow_zero_count = true
Лирическое отступление
Не тратьте время, если не хотите погружаться в детали, сразу переходите к пункту 3.
В момент выбора размера на фронте, компонент msOptionsPrice2 обращается в процессор web/modification/get, в котором он получает список модификаций путём цикличного вызова метода getModificationByOptions, который в свою очередь возвращает модификацию по переданным в него опциям. К примеру, если мы передадим в этот метод 1 опцию (size), а у нашего товара все модификации с 2-мя опциями (size и stocks), то метод нам ничего не вернёт. Это нам создаёт большие проблемы на фронте, т.к. если у модификации 2 опции, а при выборе размера в процессор передаётся одна, то метод getModificationByOptions ничего не возвращает.
Чтобы решить это, у нас есть системная настройка msoptionsprice_exclude_modification_options. В ней можно указать опцию, которая не будет участвовать в запросе.
Но! При создании/обновлении модификации, компонент в процессоре вызывает тот-же самый метод getModificationByOptions. Если мы укажем опцию stocks в этой настройке, то при создании/обновлении модификации с одним и тем-же размером, но разными складами, компонент будет выдавать ошибку, т.к. для него модификация с размером уже будет существовать, ибо в этом случае он не проверяет опцию stocks.
Вот тут был основной «затык», ибо мне на миг показалось, что ничего придумать уже нельзя...
Благо в методе есть вызов события плагина msopOnBeforeGetModification, в которое мы можем «вклиниться» и временно присвоить настройке msoptionsprice_exclude_modification_options нужную опцию, когда вызов метода происходит с фронтенда, и ничего не присваивать, если метод вызывается из бекенда!
3. Плагин
$sp = &$scriptProperties;
switch ($modx->event->name) {
case 'msopOnBeforeGetModification':
if (preg_match('/^mgr.*/i', $_POST['action'])) {
break;
}
$modx->setOption('msoptionsprice_exclude_modification_options', 'stocks');
$modx->event->returnedValues['rid'] = $sp['rid'];
$modx->event->returnedValues['options'] = $sp['options'];
$modx->event->returnedValues['excludeIds'] = $sp['excludeIds'];
$modx->event->returnedValues['excludeType'] = $sp['excludeType'];
break;
}
Вешаем на событие msopOnBeforeGetModification.4.1. Фронт-энд, HTML
В шаблоне товара делаем что-то вроде этого:
<form class="[ ms2_form msoptionsprice-product ]" method="post">
<input type="hidden" name="id" value="{$_modx->resource['id']}">
<input type="hidden" name="options[stocks]" value="">
...
<div class="product-stocks [ js-stocks ]">
<table class="product-stocks__table">
{if $_modx->resource['stocks'] && $_modx->resource['stocks'][0]}
{foreach $_modx->resource['stocks'] as $v}
<tbody>
<tr data-stocks-name="{$v}" style="display:none">
<td>
<div class="product-stocks__name">{$v}</div>
</td>
<td class="product-stocks__count [ js-stocks-value ]">
-
</td>
</tr>
</tbody>
{/foreach}
{/if}
</table>
</div>
...
</form>
Важно сохранить скрытое поле options[stocks], аттрибут data-stocks-name, класс msoptionsprice-product у формы и все классы с префиксом js!4.2. Фронт-энд, JS
После подключения jQuery прописываем примерно такой JS:
$(document).on('msoptionsprice_product_action', function (e, action, form, response) {
if (action != 'modification/get') {
return;
}
if (response['success'] && response['data']) {
var $stocks = $(document).find('.js-stocks');
var modifications = response.data['modifications'];
$stocks.find('[data-stocks-name]').hide();
if (modifications['length']) {
modifications.forEach(function (modification) {
var stock = ('stocks' in modification['options']) ? modification['options']['stocks'] : '';
var $stock = $stocks.find('[data-stocks-name="' + stock + '"]');
if ($stock['length']) {
var $value = $stock.find('.js-stocks-value');
if ($value['length']) {
$value.html(modification['count']);
$stock.show();
}
}
});
}
}
});
P.S. Благодарность Володе за то, что он предусмотрел и событие плагина в нужном месте, и триггер jQuery! Если он оптимизирует компонент на работу со складами из коробки, будет очень круто!
Поблагодарить автора
Отправить деньги
Комментарии: 2
Павел, спасибо.
msOptionsPrice2 — классный компонент. Из моего опыта — я его сильно модифицировал (оптовые цены, совместимость с msDiscount) под проект и заложенный функционал сильно порадовал.
msOptionsPrice2 — классный компонент. Из моего опыта — я его сильно модифицировал (оптовые цены, совместимость с msDiscount) под проект и заложенный функционал сильно порадовал.
Да, Володя написал хороший продукт. Я уже ни раз пользуюсь нативными фишками, расширяя его функционал — modx.pro/howto/13043
Благодарю за отзыв!
Благодарю за отзыв!
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.