Компонент Commerce для интернет-магазина

Недавно присоветовали обратить внимание на Commerce. Ввиду того что SHk уже 2 пенсии заработал, я а его все еще юзаю(((

В общем, сегодня выдался свободный день и я решил протестить Commerce, находится здесь
github.com/mnoskov/commerce
кое-что по докам есть здесь
github.com/evolution-cms/docs/tree/master/ru/04_%D0%9A%D0%BE%D0%BC%D0%BF%D0%BE%D0%BD%D0%B5%D0%BD%D1%82%D1%8B/Commerce

В целом осталось хорошее впечатление, автору огромный респект. Автору доков тоже спасибо. Очень жаль что на modx.im ничего ранее по Commerce ничего не было, во всяком случае для меня это стало открытием.

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

Но есть и много вопросов, если кто что знает из ответов, прошу поделиться.

1. При добавлении в корзину (при нажатии на кнопку Купить)ничего не происходит, в смысле никакого хелпера типа «Ваш заказ добавлен в корзину». Сам заказ, разумеется, добавляется.

2. В сниппете корзины Cart есть параметры instance=products и theme, по ним что как и почему пока не понял.

3. В малой корзине не нашел, как очистить всю корзину. Как удалить один товар — с этим разобрался.

4. По дополнительным параметрам, это в этом
<form action="#" data-commerce-action="add">
    <input type="hidden" name="id" value="[*id*]">
    <input type="hidden" name="count" value="1">
    <input type="hidden" name="options[color]" value="White">
    <input type="hidden" name="options[services][]" value="Uplift">
    <input type="hidden" name="options[services][]" value="Assembling">
    <input type="hidden" name="meta[key]" value="value">
    <button type="submit">Add to cart</button>
</form>

options[color] и аналогичное — разобрался, а что такое options[services] не очень понятно, по виду как множественный чекбокс, и в принципе работает в этом варианте, но в корзину выводится в непривычном виде и не воспринимает кириллицу (что-то у него с кодировками). А может это что-то другое?

5. Не понятно как быть с выбором параметра, если у него есть дополнительная цена. Ну, например, товар — это дверь (само полотно), а к нему — коробка, наличники, доборы. И все эти косплектующие имеют по несколько вариантов (покупатель выбирает нужное). У SHK это все замечательно добавляется в цену товара. А как здесь пока не понятно.

6. Оформление заказа — не удалось прикрутить капчу и чекбокс с agree, хотя должно, учитывая что сниппет Order обертка FL.

7. После отправления заказа корзина (ни большая, ни маленькая) не очищаются.

8. Модуль замечательный, хотелось бы еще к нему статистику и печать товарного чека.

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

10. Товары из избранного не удаляются.

Наверняка будут и другие вопросы, пока это первый подход.

Спасибо.
  • avatar
  • 7
  • +2
  • 1800

152 комментария

avatar
Я про Commerce также случайно услышал где-то в телеге. И тоже было бы интересно. SHK по нынешним временам уж очень корявенько выглядит.
avatar
Будем надеяться, что автор найдет немного времени проанонсировать свою разработку в разделе готовых дополнений, даже если какие-то нюансы пока и не готовы. Задаст нужные векторы.

Может кто из «первопроходцев» чем поделится.

Или гуру выскажут свое мнение.
avatar
он сильно сырой.
avatar
он работает в принципе, а внешний вид это решаемо…
avatar
очень корявенько выглядит
Я естественно не внешний вид имел в виду, а внутреннюю структуру.
Комментарий отредактирован 2019-08-18 14:48:26 пользователем Aharito
avatar
Хочется уже более нового решения для магазина, пускай оно будет платным, но работать не хуже, чем Joomshopping под Joomla. Но думаю, что вряд ли кто-то будет тратить свое время на столь объемный проект.
avatar
Вот интересное решение. //modx.im/blog/addons/5779.html
мне идея понравилась
avatar
Ну кстати да, тоже достойно внимания. Я видел его, но уже позабыл. Да и автор что-то не обновляет.
avatar
Еще вопрос.

11. По умолчанию шаблон формы заказа содержит всего 3 поля — имя, телефон и email. Добавить недостающие, например, регион, город, адрес доставки, сообщение — не проблема. Добавляются, в сниппет Order валидация прописываются и в таблицу commerce_orders все поля в колонку fields записываются. Но в модуль управления заказов не выводятся, и соответствующего шаблона для модуля нет. Порылся по файлам, получается что вроде как недостающие поля надо будет прописывать вручную в контроллере и других файлах, но до конца как и куда дописывать пока не разобрался.

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

P.S. Для информации — есть языковые файлы, туда тоже надо вносить дополнения.
  • paic
  • 0
avatar
Не надо менять исходники компонента.
Задача решается плагином на событие OnManagerBeforeOrderRender.

Например:

$params['groups']['contact']['fields']['address'] = 
  [
  'title'   => 'Адрес',
  'content' => function($data) {
    return $data['fields']['address'];
  },
  'sort'    => 40,
 ];

Информация из заказа будет отображена в модуле в блоке «Данные покупателя».

Так же можно добавить опции в таблицу с товарами:

$params['columns']['options'] = [
  'title' => 'Опции товара',
  'content' => function($data, $DL, $eDL) {
    if (!empty($data['options'])) {
      $out = '';
// Какие-то манипуляции
      return $out;
    }
    return '';
  },
  'sort' => 40,
  ];
Комментарий отредактирован 2019-08-19 10:52:44 пользователем akool
avatar
Спасибо, с первым плагином понял, второй — надо еще подразобраться и поэкспериментировать.
avatar
Еще вопросы

12. При установке в админке добавляется меню Магазин. В нем — Заказы, Статусы заказов, Валюта. Если включены глобальные вкладки — пока не закроешь одно, второе не открывается. Если глобальные вкладки отключены — работает нормально.

13. Модуль заказов. Это список заказов в таком виде

Если нажать Просмотр, например, заказ 3, откроется вкладка Содержимое заказа

13.1. Виджет Данные покупателя. Как ранее сообщал, из данных покупателя — только Имя, телефон и email (в таблице commerce_orders они в отдельных колонках), остальные данные в колонке fields, их вывод не прописан (я не нашел), в этой колонке записывается так
{"formid":"order","state":"Наш регион","city":"Наш город","street":"Наш адрес","delivery_price_pickup":"0","delivery_method":"fixed","delivery_price_fixed":"400","payment_method":"on_delivery","message":"Тестовое сообщение","agree":"Да","vericode":"","submit":"","payment_method_title":"Оплата курьеру при получении","delivery_method_title":"Доставка по городу"}


13.2. Виджет Содержимое корзины.
Есть нюанс по названию ТВ изображения — жестко прописан image, чтобы поменять на другое название, например, на img нужно внести изменения в файл src/Module/Controllers/OrdersController.php стр. 87,88. Остальные правки — в шаблонах, там все ок.

13.3. Виджет Содержимое корзины. Вроде как глюк((
В моем заказе №3 — 2 товара, а выводится только один. Все танцы с бубном типа почистить кэш сайта, браузера и пр. ни к чему не привели, из порядка 20 попыток только один раз выдало как положено 2 заказа и то не понял, после какой манипуляции это случилось.
Ну и опции товара будет как-то не очень привычно для рядового админа.
  • paic
  • 0
avatar
14. Мультивалютность. Добавил валюту, добавил переключатель валют — сниппет CurrencySelect. Все работает, цена пересчитывается по установленному курсу везде, за исключением страницы товара. Т.е. валюта визуально переключается, но сам номинал по курсу не пересчитывается. Методом тыка оказалось, что для страницы товара и чанка товара в каталог вызов сниппета PriceFormat нужно делать с параметром convert=2. В общем вопрос по параметру convert — где какие значения и в каких случаях указывать.

Но вообще-то штука удобная. Давно мультивалютных магазинов не делал, но вспоминая былые проекты — здесь очень даже неплохо!
  • paic
  • 0
avatar
15. Из дополнительных плагинов протестил Delivery Fixed, Delivery Pickup, Discount example, Payment OnDelivery — вроде как все работает и все понятно.

Но вот по Delivery Fixed (доставка с фиксированной ценой) есть вопрос (скорее пожелание). А если таких доставок несколько?

Поясню, если есть Доставка по городу = 400 руб, то все ок.

А если надо типа такого:
Доставка район Северный = 400 руб
Доставка район Южный = 500 руб
Доставка район Восточный = 600 руб
и т.д. тогда как?

Имхо, было бы неплохо сделать это в модуле, типа как Валюты, с возможностью добавлять фиксированные доставки с фиксированной ценой.

15.1. И по плагину Discount example — неплохо было бы его параметры вынести хотя бы в конфигурацию (сумма корзины от которой начисляется скидка и размер скидки в %).
  • paic
  • 0
avatar
16. Перенес на хостинг. Все сообщения при заказе и изменения статуса товара отправляются. Глюк из п.13.3 на хостинге не отмечается, но появился другой. Связан с тем что при отправлении заказа корзина не очищается.

Так вот — отправил заказ, зашел в админку проверил модуль, потом проверил почтовые ящики, а потом возвращаюсь на сайт на страницу заказа (которая не очистилась) и решил изменить валюту. И вдруг бах — слышу сигнал что на почтовый ящик пришло письмо, и это оказался новый заказ — т.е. при смене валюты заказ продублировался еще раз, но уже в другой валюте. Выглядит так (мне понравилось дублирование в основной валюте)

Сделал страницу оформления заказа не кэшируемой — стало лучше, при смене валюты корзина очистилась. Т.е. корзины очищаются при отправлении заказа при перезагрузке, и похоже что нужно с настройках плагина Commerce все же ставить переадресацию на страницу Спасибо за заказ.

Что-то я притомился, надо сходить проведать холодильник))
  • paic
  • 0
avatar
Что-то тишина пока в ответ )
Комментарий отредактирован 2019-08-18 14:53:58 пользователем Aharito
avatar
«еще не вечер»))

В целом, впечатление благоприятное, я думаю — он взлетит. Во всяком случае, хочется ему этого пожелать.
avatar
В заключение несколько скриншотов.

1. Модуль заказов уже показывал выше, не показывал еще одну вкладку

Как видно на скриншоте — можно уведомлять покупателя при любом статусе, тут же сопровождая каким-либо текстом.

2. Меню Магазин в админке


3. Валюты
Основная вкладка


Редактирование


4. Статусы
Основная вкладка


Редактирование


5. Письмо администратору


6. Письмо покупателю при заказе — такого шаблона по умолчанию для параметра ccSenderTpl сниппета Order нет, но там все как в FormLister — что напишете, то и получит, например
&ccSenderTpl=`@CODE:<p>Здравствуйте, [+name.value+]! Ваш заказ получен и будет рассмотрен в кратчайшие сроки.</p>`
  • paic
  • +1
avatar
Фактически уже пол-доки есть. Ты крут ))
avatar
На самом деле здесь нет ничего героического, как и написал в первом сообщении — многие вещи интуитивно понятные. Могу только добавить, что любой кто ранее пользовался SHK разберется без проблем — по аналогии. А то с чем не разобрался или не понял — то здесь и спрашиваю. Скриншоты в конце — это просто для понимания о чем речь, тем кто этого еще не видел))

Могу, конечно, еще и некоторые примеры опубликовать или из того что выяснилось «по ходу пьесы». Но раздел называется «Вопросы» — хотелось бы для начала какие-то ответы получить.
avatar
Попробую поотвечать, так как использовал дополнение, разбирался, остался доволен.

1. Вопрос про хелперы.
Хелперы реализуются на js. Commerce инициирует события, в своём коде вы на них подписываетесь и выполняете нужные действия.
Базовый пример реализации есть в коде компонента

Можно подписаться на различные события:
добавление в корзину: cart-add-complete.commerce;
обновление корзины: cart-update-complete.commerce;
удаление из корзины: cart-remove-complete.commerce;
обновление формы оформления заказа: order-data-updated
и другие.

В событиях с корзиной в обработчике события будут доступны данные ответа от сервера:
status: success, либо failed;
instance: название экземпляра корзины: products, либо wishlist, либо comparison;
row: хеш экземпляра корзины;

Пример с хелпером при добавлении товара в корзину.
Надо разместить на странице код хелпера стилизованного на своё усмотрение.
В своём js добавить обработчик события, для показа своего хелпера. Например:
$document.on('cart-add-complete.commerce', function(e, data){
  if (data.response.status === 'success' && data.response.instance === 'products') {
    $('#helper-to-cart').show();
  }
});
avatar
Спасибо. Я наверное не очень понятно сформулировал вопрос по хелперу. В том виде хелперы как в SHK лично мне не нужны — я их обычно почти все отключаю, за исключением подтверждалку-уведомление, что «Товар добавлен в корзину» с появлением на секунду и самостоятельным исчезновением. Я думаю, такое можно было бы включить непосредственно в commerce.js вместе с div id=helper-to-cart. Аналогично для «Добавлено в сравнение» и «Добавлено в избранное».

А если выносить что-то в свой js, то это мне напоминает — был такой расхожий скрипт для SHK, где при каждом добавлении в корзину выскакивает окно с двумя кнопками «Продолжить покупки» и Оформить заказ":
function fillCartCallback(form){
    if($('#goToOrderForm').size()>0) $('#goToOrderForm').remove();
    if($('#goToOrderForm_ovarlay').size()>0) $('#goToOrderForm_ovarlay').remove();
    var win_html = '<div id="goToOrderForm">'
    +'<p>Товар добавлен в корзину.<br /> Вы можете продолжить покупки или перейти на страницу оформления заказа.</p>'
    +'    <button class="btn btn-default btn-lg">Продолжить</button>  '
    +'    <button class="btn btn-default btn-lg">Оформить заказ</button>'
    +'</div>';
    var win_width = 500;
    var win_height = 150;
    var win_padding = 20;
    $(document.body).append('<div id="goToOrderForm_ovarlay"></div>');
    $(document.body).append(win_html);
    $('#goToOrderForm').css({
        'width': win_width+'px',
        'height': win_height+'px',
        'background': '#50423C',
        'border': '1px solid #e86276',
        'text-align': 'center',
		'color': '#fff',
        'padding': win_padding+'px',
        'position': 'fixed',
        'top': '50%',
        'left': '50%',
        'z-index': '1000',
        'margin-top': 0-((win_height/2)+win_padding)+'px',
        'margin-left': 0-((win_width/2)+win_padding)+'px'
    });
    $('#goToOrderForm_ovarlay').css({
        'width': $(window).width()+'px',
        'height': $(document).height()+'px',
        'background-color': '#000',
        'opacity': 0.8,
        'position': 'absolute',
        'left': 0,
        'top': 0,
        'z-index': 110
    });
    $('button:eq(0)','#goToOrderForm')
    .css('width','170px')
    .click(function(){
        $('#goToOrderForm_ovarlay').fadeOut(500,function(){
            $(this).remove();
            $('#goToOrderForm').remove();
        });
    });
    $('button:eq(1)','#goToOrderForm')
    .css('width','170px')
    .click(function(){
        window.location.href = '/'+shkOptions.orderFormPage;
    });
}

Такое тоже в будущем может пригодиться (есть любители), но это потом.
avatar
Не совсем они так работают.
Чисто добавление товара по-моему отсутствует.
Вот этот код, скажем, сработает как при добавлении, так и при изменении количества

<code>$(document).on('action-complete.commerce', function(e, data){
  if (data.response.status === 'success' && data.response.instance === 'products') {
    console.log(data);
  }
});</code>
Так и не выцепил, где брать событие чисто добавления. Ну или в лоб — смотреть что пришло в data.action и уже от него плясать?

Ну если это ещё как-то решаемо, то вот с удалением уже проблема — как тормознуть эвент, чтобы юзер мог передумать, увидев некий хелпер, я не знаю — он сначала удалит, а потом уже будет data.action cart/remove
Есть идеи?
Комментарий отредактирован 2019-08-19 21:07:04 пользователем 1px
avatar
Спасибо за первые доки!
avatar
Война — херня, главное манёвры.
Главное, шум поднят, дальше дело техники. Постепенно допишем.
avatar
Вижу — уже дописываете. За пару дней доки существенно расширились и дополнились. Спасибо.

Кстати, добавьте что есть еще instance=order и шаблоны в папке lang/russian-UTF8.
avatar
Параметр instance по-умолчанию принимает только три параметра products, wishlist или comparison.
В документации есть подробности.
avatar
А это?
github.com/mnoskov/commerce/blob/master/assets/plugins/commerce/lang/nederlands-utf8/order_report.tpl

Пользуясь случаем, что такое urlScheme?
avatar
Согласен. Экземпляр order создаётся в OrdersProcessor.php
avatar
Абсолютные или относительные ссылки
avatar
ок, понял, это из DocLister
avatar
Названия js-событий складываются динамически из названий действий, например
cart-add.commerce
cart-add-complete.commerce
cart-remove.commerce
cart-remove-complete.commerce
и т.д.

Сейчас отменить действие нельзя, требуется доработка.
avatar
Попробовал отменить действие. Получилось. Свой скрипт добавил после commerce.js. В нём отменил всплытие, отменил стандартное действие и сделал свои действия.
avatar
Можно посмотреть?
avatar
Примерно так:
$('.cart-item__remove').on('click', function(e){
e.stopPropagation();
e.preventDefault();
console.info('not removed');
});
avatar
Событие чисто добавления:
cart-add-complete.commerce
avatar
Поправлю сам себя.

В общем вот как подписаться на нужные эвенты:

$(document).on('cart-add-complete.commerce', function(e, data){
	console.log('Добавление товара');
});
$(document).on('cart-update-complete.commerce', function(e, data){
	console.log('Пересчёт корзины');
});
$(document).on('cart-remove-complete.commerce', function(e, data){
	console.log('Удалили из корзины');
});
$(document).on('order-data-updated.commerce', function(e, data){
	console.log('Обновили форму заказа');
});
avatar
2. Вопрос про instance.
В компоненте Commerce имеется функционал для одновременной работы нескольких «корзин»: products, wishlist, comparison. Все они вызываются сниппетом Cart с указанием параметра instance.
На одной странице сайта могут быть вызваны сколько угодно сниппетов Cart нужного содержания и вида. Например:

<header>
[!Cart 
  &instance=`wishlist`
!]
[!Cart 
  &instance=`products` 
  &tpl=`minicart_row`
  &ownerTPL=`minicart_wrap`
!]
<header>
<main>
[!Cart 
  &instance=`products` 
!]
</main>


Параметр theme.
Если посмотреть на код сниппета Cart, то станет понятно, что параметр theme позволяет указать путь к папке с индивидуальными шаблонами элементов корзины и оформления заказа.
В директории assets/plugins/commerce/templates/front/ можно создать новую директорию, поместить в неё свои шаблоны корзины. А при вызове сниппета указать только название директории в параметре theme вместо указания пяти разных параметров для шаблонов.
Комментарий отредактирован 2019-08-18 23:34:27 пользователем akool
avatar
Спасибо, понял, т.е. виджеты для количества добавленных в сравнение и добавленных в избранное реализуется как и малая корзина, только с другими соответствующими instance)) Это классно.

Еще бы понять как отмечать товар, добавленный в сравнение (избранное). В былые впемена там был чекбокс и с ним все понятно, а здесь — ссылка.
avatar
8.
Статистика: github.com/mnoskov/commerce-dashboard
Для чека, возможно, подойдёт: github.com/mnoskov/commerce-billpayment
avatar
Спасибо, посмотрю.
avatar
7. и 10.
Похоже вы что-то сделали не так. Очищение корзины и удаление товаров нормально работают.

9.
Выше, отвечая на вопросы 1 и 2, ответил как вызвать несколько видов корзин и как сделать хелперы.
avatar
Спасибо, 7 и 10 перепроверю. 9 уже понял из Вашего предыдущего ответа.
avatar
4. options и meta могут хранить в себе дополнительную информацию о товаре, в базе сохраняются в виде json. По идее options — это опции товара, которые выбирает покупатель, или близкое по смыслу, а meta — управляющая информация о товаре, не видимая покупателю, и нужная для работы каких-то плагинов, например. Что туда сохранять — личное дело каждого. И options в информации о заказе показывается просто в виде json, т.к. предполагается, что если там что-то есть, значит какой-либо плагин уберет эту колонку и заменит чем то своим.

5. для опций товара я делал отдельный модуль — github.com/mnoskov/commerce-options, но в виду того, что опции мне не нигде пригодились, модуль пока крайне сырой.

6. капчу не пробовал, а с чекбоксом проблем не было.
avatar
Добрый день, еще раз огромное спасибо за этот компонент, и за разъяснения.

4. Так и не понял, что такое options[services][] и что у него с кодировками, но еще посмотрю модуль п.5.
И поделюсь, если опции (параметры) не имеют дополнительной цены, то можно выводить так
modx.im/blog/questions/2935.html
можно не только селект, но подправить и под чекбокc, и под радио. Уже протестил — работает и здесь. Например
<?php
$id = $id;      
$str = $input;
$data = explode(",", $str);
foreach ($data as $value) {
	$output .= '<option value="Цвет: '.$value.'">'.$value.'</option>';
}
return $output;

на странице товара

<select class="" name="options[color]">
    <option value="Цвет: не выбрано">Выберите цвет</option>
    [[size_select? &input=`[*color*]` &id=`[*id*]`]]
</select>


А вот что вместо того что в SHK называлось paramEdit (потом было решение на multiTV) — или это и есть модуль commerce-options?

6. Да, с чекбоксами я поторопился, просто я пытался прописать как у FL formControls, а оказалось что как раз не надо — без него работает.

А вот капчу прописать не удалось — вставлял и в вызов Order, и непосредственно в код сниппета как params — и там и там все ломается и сниппет вообще не работает.
avatar
Вы капчей совсем хотите отбить желание что-либо покупать?
avatar
Не я)) Иногда (даже частенько) заказчики настоятельно просят поставить не взирая ни на какие аргументы.
avatar
5. После установки — админка «слетела»:

Fatal error: Call to undefined function ci() in D:\OSPanel\domains\shop-4.ru\manager\includes\document.parser.class.inc.php(1919): eval()'d code on line 54

реанимировать не получается, придется откатываться

Версия EVO 1.4.9
avatar
Как предложение, по параметрам (опициям) из commerce-options — добавить возможность их вывода для сравнения в Comparison.
avatar
11. все поля формы сохраняются в виде json в поле fields. чтобы их вывести в просмотре заказа, нужно создать плагин на событие OnManagerBeforeOrderRender и подправить массив $params['groups'].

12. да, модуль не работает с глобальными вкладками, и я считаю, что проблема не в модуле.

13.2 См. п.11, то же самое событие, правим массив $params['config'] — это конфиг, который пойдет в вызов DocLister
avatar
11. Понял, выше akool и пример дал. Но может все же сразу прописать, названия полей — из таблиц веб-пользователя… Во-первых, более привычно, во-вторых — их все-равно прописывать, а так получается — сам компонент ставится за 2 часа, а потом еще пару дней всякими плагинами обвешивать (не каждый и сможет, т.е. повторяемость снижается).

12. Ок.

13.2. Ок, как по мне — то проще в файле перепрописать, знаю что плохо при обновлениях, но здесь главное знать что такой нюанс есть, а там уже каждый для себя определит что лучше.
avatar
14. мультивалютность также сделана без реальной личной необходимости, поэтому крайне нуждается в тестировании. Параметр convert означает, нужно ли значение конвертировать в текущую валюту или нет. Т.е. 0 либо 1. По умолчанию — 1.

15. Можно просто продублировать плагин, и заменить идентификатор на fixed2 например. Там простой и понятный код, данные плагины включены для примера, чтобы было от чего плясать. В идеале было бы хорошо, если бы был какой-нибудь конструктор доставок, но лично мне проще в том виде, какой есть сейчас.
avatar
14. Понял. Но вроде работает, с учетом моего ничем не предусмотренного convert=2((
Попробую еще раз расставить правильно. И еще если кто будет тестить или реально делать — переключатель валют вызывать некэшируемым [!CurrencySelect!].

15. Понял, спасибо, продублировать — это я так сразу и попытался, даже в языковый файл добавил delivery.fixed_title_two, но насчет fixed2 не допер)) Сейчас подправил — все отлично работает.
avatar
По мультивалютности еще раз протестил, получается так:
1. В корзинах — так как Вы и написали: 0 — конвертировать, 1 — не конвертировать, т.е. оно все равно что-то пересчитывает и валюту изменяет, но хз как и неправильно.

2. На странице товара и в чанках — с точностью до наоборот: 1- конвертировать, 0 — не конвертировать. По умолчанию 1 — конвертирует.

3. Избранное — в чанке wishlist_row convert не прописан (т.е. по умолчанию), если прописывать — будет как и в п.2.

4. Сравнение. Функционал мультивалютности вообще не реализован. Даже денежного формата нет.

5. commerceoptions — какие-то попытки есть, но не работает.
avatar
Параметр convert не меняет значение по умолчанию в зависимости от места вызова, он всегда равен 1, и означает, что цену нужно конвертировать.

В корзинах PriceFormat вызывается с параметром convert=0, т.к. в корзинах цены хранятся уже в текущей валюте.

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

В сравнении да, не реализован — это можно сделать через prepare.
avatar
Спасибо.
Параметр convert не меняет значение по умолчанию в зависимости от места вызова, он всегда равен 1
тестами подтверждается.
и означает, что цену нужно конвертировать.
тестами для корзины — не подтверждается, т.е. если этот параметр не указывать — действительно будет 1, но для корзины это НЕ конвертировать, оно и не конвертируется.
avatar
Еще раз скажу, что конвертору без разницы, в корзине он или еще где. Если параметр convert=1, значит он будет конвертировать, если 0 — не будет. Других вариантов нет.

В вашем случае скорее всего дело либо в исходных данных, либо где-то ошибка.
avatar
Исходные данные — это курс, прописан так, через точку



В админке в товарах номиналы в рублях. Что еще может повлиять (( буду искать
avatar
Как делать препаре для сниппета Comparison не понятно, уже пытался но пока не разобрался.

Например для DL заменить || на, обычно дела такой препаре
<?php
$data['color_format'] = str_replace("||",", ",$data['color']);
return $data;

где color — название TV, а в чанке вместо него — плейсхолдер color_format.

Но в Comparison нет же индивируальных чанков для каждого TV.
Пытался это сделать непосредственно в коде, где идет выборка value из таблицы site_tmplvar_contentvalues, но безуспешно.
avatar
Если параметр tvPrefix не меняли, значит надо писать tv.color_format
avatar
Не помогло(( и это плейсхолдер и мне не понятно, куда его вписывать и соответственно он никуда не вписан. Т.е. препаре есть, в вызове в параметре prepare он указан, а плейсхолдер никуда не вставлен — чанка нет.

Ну или как вариант — ваш покорный слуга прочно встал на ручник и никак не может сняться (((
avatar
Вот так работает

<?php
$data['tv.color'] = str_replace("||",", ",$data['tv.color']);
return $data;
avatar
Видел обновление, спасибо, уже и поставил.
1. В Comparison теперь с мультивалютностью порядок.

2. Обновил и Wishlist и появилась непонятная проблема с img. В предыдущей версии прописывал прямо в сниппете
'tvList' => 'price,img',

Теперь же попытался прописать как и в Comparison — в вызове
&tvList=`img`

Вроде код как и в Comparison, и там это работает, а в Wishlist не хочет((
Пока прописал так как было, т.е. в коде
$params['tvList'] = 'price,img';


3. По удалению товаров из списка избранных (отложенных), теперь работает, но «перелет» — нажимая кнопку «удалить» одного товара — исчезают все. Т.е. по факту удаляется 1, и в виджете тоже показывает на 1 меньше — но исчезают все. Если страницу перезагрузить — неудаленные появляются. И перестало из избранного добавляться в корзину. Совсем.
avatar
Продолжаю разбираться, несколько примеров благодаря оказанной выше помощи.

Сравнение и избранное
1. На странице товара добавляется ссылками
<a href="#" data-commerce-action="add" data-id="[*id*]" data-instance="wishlist">Добавить в избранное</a>
<a href="#" data-commerce-action="add" data-id="[*id*]" data-instance="comparison">Добавить в сравнение</a>

в чанке товара — аналогично
<a href="#" data-commerce-action="add" data-id="[+id+]" data-instance="wishlist">Добавить в избранное</a>
<a href="#" data-commerce-action="add" data-id="[+id+]" data-instance="comparison">Добавить в сравнение</a>


2. В шапке сайта (или другом месте) соответствующие виджеты с указанием количества добавленных товаров.
Сравнение
[!Cart
&instance=`comparison`
&ownerTPL=`@CODE: <div data-commerce-cart="[+hash+]"><a href=[~7~]>Сравнение: [+count+]</a></div>`
!]

Избранное
[!Cart
&instance=`wishlist`
&ownerTPL=`@CODE: <div data-commerce-cart="[+hash+]"><a href=[~6~]>Избранное: [+count+]</a></div>`
!]

Все, кликая по ссылке товар добавляется в избранное или в сравнение. Если ничего не добавлено — отображается 0. Типа упрощенного варианта корзины.

4. На странице.
Сравнение. Пример дан прямо в тексте сниппета

[!Comparison
      &showCategories=`1`
      &tvCategory=`10`
      &excludeTV=`category`
      &includeTV=`price`
      &checkBoundingList=`0`
      &categoryItemClass=`btn-secondary`
      &categoryActiveClass=`btn-primary`
!]


Избранное, примеров никаких нет, просто вызвал.
[!Wishlist!]
Все шаблоны есть в папке templates/front, по умолчанию — оттуда, своих для теста не делал.

А дальше опять вопросы:

17. По сравнению хотелось бы получить пояснения по параметрам Comparison и вообще по принципу работы. Он отличается от Compare.
Единственно что понял — в отличие от Compare этот сниппет не тащит все подряд ТВ-шки и потом надо прописывать те что надо исключить. Здесь вроде как наоборот — какие прописал в includeTV — те и выведет для сравнения.
Есть, наверное, какие-то ограничения, чтобы не сравнивать велосипед с холодильником. Ну и другие особенности.
И так же как в Compare множественный параметр выводится через сепаратор || и по-видимому надо будет препаре писать (препаре поддерживаются?).

18. По удалению из сравнения — все ОК. Принажатии на кнопку Удалить страница перегружается и при этом удаляется и товар со страницы, и на 1 уменьшается количество товаров в виджете.
А в вот с избранным история другая, как и писал ранее п.10. При удалении какого либо товара страница не перегружается и удаленный товар остается на странице, хотя фактически он удален и в виджете количество товаров уменьшилось на единичку. Товар визуально исчезает только после перезагрузки страницы. Возможно, шаблону wishlist_wrap не хватает каконо-нибудь data-…

19. Опять по индикации на сранице и чанке товара, добавленного в избранное (в сравнение). И удаление из избранного (из сравнения). Понял, что удалять можно так
<a href="#" data-commerce-action="remove" data-instance="wishlist" data-id="[*id*]">Удалить из избранного</a>
<a href="#" data-commerce-action="remove" data-instance="comparison" data-id="[*id*]">Удалить из сравнения</a>

Но как это все облачить в удобоваримую (и главное — компактную) форму. Получается, что какие-то дополнительны скрипты писать. Или есть что-то уже заложенное?
  • paic
  • 0
avatar
17.
&showCategories - разделять товары по родительской категории или выводить все вместе
&tvCategory - ограничить вывод категориями тв-параметров, идентификаторы через запятую
&includeTV - включить данные тв-параметры, имена через запятую
&checkBoundingList - выводить только тв-параметры, указанные в родительской категории в поле tovarparams (тот, который из eFilter)
&excludeTV - исключить данные тв-параметры, имена через запятую
&categoryItemClass - css-класс категории
&categoryActiveClass - css-класс активной категории

Prepare поддерживается, || обрабатывать через него.
avatar
Спасибо, теперь вроде понятно
avatar
19. Индикация добавления (пример с рабочего сайта):
$(document).on('cart-add-complete.commerce', function(e, data) {
    switch (data.data.cart.instance) {
        case 'wishlist':
        case 'comparison': {
            data.initiator.addClass('active').tooltip({
                title: 'Товар добавлен в ' + (data.data.instance == 'wishlist' ? 'отложенные товары' : 'сравнение'),
                trigger: 'manual'
            }).tooltip('show');

            setTimeout(function() {
                data.initiator.tooltip('hide');
            }, 2000);

            break;
        }
    }
});

Индикация при выводе товаров с помощью доклистера:
<?php

$lists = $_extDocLister->getStore('commercelists');

if ($lists === null) {
    $carts = ci()->carts;
    $lists = [
        'wishlist'   => $carts->getCart('wishlist')->getItems(),
        'comparison' => $carts->getCart('comparison')->getItems(),
    ];
    $_extDocLister->setStore('commercelists', $lists);
}

foreach ($lists as $list => $ids) {
    if (isset($ids[$data['id']])) {
        $data[$list . '_class'] = ' active';
    }
}
avatar
Спасибо, по скрипту все понятно, работает.
А по сниппету — увы, нужны дополнительные пояснения
avatar
Все же и по скрипту есть вопрос — он в том что ему надо наверное куки добавить или что-то в этом роде, т.к. добавленный класс active нигде не сохраняется (страницу перезагрузил или перешел на другую, а потом вернулся, особенно в каталоге). А так все хорошо (для bootstrap), добавил сюда же и кейс для products (уведомление о добавлении в корзину).
avatar
Не надо куки, нахождение товара в сравнении или отложенных как раз делает приведенный сниппет. Просто реализаций будет две — для списка товаров и для страницы товара. В первом случае это препаре, во втором — плагин на OnWebPageInit. В коде получаем списки товаров, и проверяем вхождение текущего. Если есть, ставим плейсхолдеры для css-класса. Ну или еще что-то, зависит от потребности.
avatar
Идею понял, но запустить все-равно не удалось((
Поясните, что такое commercelists и где он должен быть, чтобы DL из него что-то извлек (сохранил)?
Может надо что-то во что-то обернуть (сам список, товары в списке)? Или доклистеру что то добавить (екстендер, параметр)?
avatar
Я не полностью скопировал, оказывается. Вот верный вариант:
<?php
$lists = $_extDocLister->getStore('commercelists');

if ($lists === null) {
    $carts = ci()->carts;
    $lists = [
        'wishlist'   => $carts->getCart('wishlist')->getItems(),
        'comparison' => $carts->getCart('comparison')->getItems(),
    ];
	
    foreach ($lists as $list => $items) {
        $lists[$list] = array_flip(array_column($items, 'id'));
    }
	
    $_extDocLister->setStore('commercelists', $lists);
}

foreach ($lists as $list => $ids) {
    if (isset($ids[$data['id']])) {
        $data[$list . '_class'] = ' active';
    }
}

return $data;

commercelists это ключ кеширования — DocLister может кешировать тяжелые данные на время выполнения сниппета. Т.е. мы берем из кеша по ключу commercelists, и если вернулся null — получаем идентификаторы товаров в сравнении и отложенных и сохраняем их в кеш. Затем просто проверяем на вхождение
avatar
Спасибо, теперь работает))
avatar
Дополнительные контакты покупателя в модуль заказов.
Плагин

//<?php
/**
 * OrderContacts
 * 
 * Добавление контактов покупателя в модуль заказов
 * 
 * @category    plugin
 * @version     1.0.0
 * @internal    @events OnManagerBeforeOrderRender
 * @internal    @modx_category Commerce
**/
$e = $modx->Event;
if(($e->name == 'OnManagerBeforeOrderRender')){
$params['groups']['contact']['fields']['state'] = 
  [
  'title'   => 'Регион',
  'content' => function($data) {
    return $data['fields']['state'];
  },
  'sort'    => 40,
 ];
$params['groups']['contact']['fields']['city'] = 
  [
  'title'   => 'Город',
  'content' => function($data) {
    return $data['fields']['city'];
  },
  'sort'    => 50,
 ];
$params['groups']['contact']['fields']['street'] = 
  [
  'title'   => 'Адрес',
  'content' => function($data) {
    return $data['fields']['street'];
  },
  'sort'    => 60,
 ];
$params['groups']['contact']['fields']['message'] = 
  [
  'title'   => 'Сообщение',
  'content' => function($data) {
    return $data['fields']['message'];
  },
  'sort'    => 70,
 ];
}

Наименование полей должны быть из формы заказа order_form.
  • paic
  • +1
avatar
Скриншот, как выглядят данные покупателя с плагином (без плагина было выше)
avatar
Плагин для добавления, а скорее «причесывания» опций товара в модуле заказов (содержимое корзины)

//<?php
/**
 * OrderOptions
 * 
 * Добавление опций товара в модуль заказов
 * 
 * @category    plugin
 * @version     1.0.0
 * @internal    @events OnManagerBeforeOrderRender
 * @internal    @modx_category Commerce
**/
$e = $modx->Event;
if(($e->name == 'OnManagerBeforeOrderRender')){
$params['columns']['options'] = [
  'title' => 'Опции товара',
  'content' => function($data, $DL, $eDL) {
    if (!empty($data['options'])) {
      $out = 'Сезон: '.$data['options']['season'].'
Цвет: '.$data['options']['color'].'
Размер: '.json_encode($data['options']['size']);
    }
      return $out;
  },
  'sort' => 40,
  ];
}


Здесь:
Цвет (ТВ с названием color) — выбор в выпадающем списке
Сезон (ТВ с названием season) — выбор в радиокнопках
Размер (ТВ с названием size) — выбор в чекбоксах (можно выбрать несколько вариантов)

Скриншот — вид по-умолчанию


Так выглядит с плагином


Хотя с размером, как по мне, все-равно не очень, но он так и в корзине во фронте выглядит(( И как уже сообщал — что-то с кодировкой множественного чекбокса, здесь он еще как-то выглядит, потому что цифры, а если будет кириллица, будет так


Впрочем, вижу на гитхабе вчера и сегодня вносились изменения, наверняка уже что-то поменялось к лучшему, надеюсь, автор сообщит))
  • paic
  • 0
avatar
Так может просто проверять на «массив» и делать ему implode вместо json_encode
is_array($data['options']['size']) ? implode(", ", $data['options']['size']) : $data['options']['size']


Ну а чтобы получать «человеческую» кирилицу в json уже давно придумали флаг JSON_UNESCAPED_UNICODE :)
avatar
Спасибо, теперь все отлично, исправил так

    if (!empty($data['options'])) {
	$size = is_array($data['options']['size']) ? implode(", ", $data['options']['size']) : $data['options']['size'];
      	$out = 'Сезон: '.$data['options']['season'].'
Цвет: '.$data['options']['color'].'
Размер: '.$size;
    }


По кодировке тоже спасибо, учту на будущее. Но здесь выше уже очень даже справедливо советовали не лезть в исходный код. Там и без моих кривых рук есть кому поправить))
avatar
В любом случае для «промышленного» применения эти опции нужно как-то автоматизировать, т.к. могут быть товары с совершенно разными характеристиками. Потому надо:
1. предварительно собрать массив с именами и названиями опций (например из таблицы ТВ, если они идут оттуда)
2. проходить массив $data['options'] через foreach и заменять названия на нужные, попутно преобразуя массивы значений (если встретились).

Т.е. каким-то таким путем
$out = '';
$options = ['size' => 'Размер', 'color' => 'Цвет', 'season' => 'Сезон' ... и т.п.];
if (!empty($data['options']) && is_array($data['options'])) {
    foreach ($data['options'] as $k => $v) {
        $out .= (!empty($options[$k]) ? $options[$k] : $k) . ': ' . (is_array($v) ? implode(', ', $v) : $v) . PHP_EOL;
    }
}
return $out;


Т.к. в функцию передает $eDL (наверно это объект $_extDocLister) — то там должны быть доступны и его методы setStore/getStore — т.е. массив опций может быть получен один раз и не надо будет постоянно туда что-то дописывать при появлении новых опций.
avatar
Спасибо. Конечно, с foreach лучше, на это и akool намекал выше, как я понял. Но делать не стал по следующим причинам:
1. Рецидив SHK, понятно что от него надо избавлять и принимать новые подходы, но вольно или не вольно все-равно клонит к тому что привык((
2. Как я понял, многие «обвесы» здесь делаются вручную, может оно и лучше, пока рано судить. Но если какие-то вещи прописываются под конкретный проект, то зачем делать лишнее.
3. Как сказал автор, есть модуль по опциям, хоть и сырой. Но это он сегодня сырой. Но еще будет «завтра»))

Хотя, наверное, это было бы удобно, по образу и подобию как сделано у вас в eFilter — закинул в нужную категорию ТВ — и сниппет (плагин) его тут же добавил в список параметров на странице товара (как у вас tovarParams).

По _extDocLister — тут у меня пробел. Конечно, доки я читал, но когда не сталкиваешься одного «читал» мало. А столкнулся первый раз в примере, которым поделился kassio / И то он для DL, а как на странице я пока и не разобрался.
avatar
Обновился. Много чего добавлено, исправлено.

1. Добавились шаблоны чанков и во фронт, и в модуль, в том числе чанк пустой корзины, теперь if отпал за ненужностью.
2. В заказах добавилась возможность редактирования заказов, скриншоты ниже.
3. Добавилась очистка корзины.
4. В модуль Commerce добавились поля, по ним пока информации нет.
5. Капчу в форму заказа теперь можно добавлять.

Это то что бросилось в глаза, наверное и еще есть.
Кодировки пока остались в старом варианте((

По самому обновлению — вроде без замечаний, все перезаписалось, за исключением плагина Commerce — установилась новая версия, при этом старая версия плагина не отключилась, получилось 2.

скриншот 1


скриншот 2
  • paic
  • 0
avatar
После обновления перестал работать аякс при изменении Способа доставки и способа оплаты как между собой, так и с корзиной.

Корзина и форма заказа у меня на одной странице,
Cart page ID
Order page ID
в конфигурации плагина id этой страницы указал.

До обновления работало отлично, только корзина автоматически не очищалась после отправки заказа, но она и сейчас не очищается.

Или я какие-то изменения не разглядел и не внес.
Комментарий отредактирован 2019-08-22 18:56:30 пользователем paic
  • paic
  • 0
avatar
Как оказалось — из-за капчи.
Если убрать из сниппета Order
include_once MODX_BASE_PATH. 'assets/snippets/FormLister/__autoload.php';
и из вызова

&captcha=`modxCaptcha`
&captchaParams=`{
"width":140,
"height":50
}`

то все работает ок (((
avatar
Поставил этот плагин для статистики
github.com/mnoskov/commerce-dashboard

Стал с пол-оборота, никаких настроек вроде и нет. Админку перезагрузил — и вот они — два виджета на стартовой странице админки, все как на скриншоте по ссылке.
Все замечательно, спасибо.

Я, конечно, не маркетолог, но этого ИМХО, как было выше сказано «для промышленного применения» маловато будет. Это не критика (прав таких не имею), это пожелание если компонент будет развиваться — надо статистику не только по дням за текущий месяц (пусть и по сравнению с предыдущим), но и по месяцам, по годам.
И не только по заказам, но и по продажам (исполненным заказам).
И по другим — которые до исполнения не дошли, сколько и каких.
В натуральных выражениях и процентах.
  • paic
  • 0
avatar
Лучше всего будет взять и доделать, чего не хватает, или хотя бы проспонсировать разработку. Я сомневаюсь, что этот плагин появился от того, что Михаилу нечего было делать (:
avatar
Так я и не против, в том числе и пронспонсировать, и не только плагин, а и вообще весь Commerce.

Думаю, и другие присоединятся, если автор где-нибудь свои кошельки опубликует.

Касательно этого топика — просто разбираюсь сам, если попутно это каким — то образом популяризирует этот компонент, ну и хорошо))

Касательно этого плагина — заказчики порой сами не очень представляют, что должно быть в модуле (как и вообще в магазине), поэтому было бы интересно мнение более искушенных людей, свое скромное мнение я высказал.

Ну, а если в дальнейшем будет совсем туго — то и в лс постучусь))
avatar
Ну это все-таки виджеты на главной. Можно было бы сделать отдельный модуль по статистике, и все подробности выводить в нем.
avatar
Все ок, спасибо за виджеты. И так огромная работа проделана))

А планируется ли что-то для личного кабинета? Сам личный кабинет вполне достойно собирается на FL, а вот то что касается заказов, их отслеживания, изменений статусов и самих заказов, опять же статистики покупателя и др.
avatar
Пока только в планах
avatar
Спасибо, тоже хорошо, что планы такие есть.

Как предложение, уже сейчас предусмотреть в таблицах поле c записью id зарегистрированного пользователя, тогда в личном кабинете можно было бы что-то вывести своим снипетом или DL.

Я вижу, что есть поле user_id в таблице commerce_order_history, но я так понимаю, туда записывается менеджер, изменивший статус товара.
avatar
Хорошо
avatar
Поставил этот плагин
github.com/mnoskov/commerce-billpayment
Этот плагин добавляет способ оплаты по выставленному счету.
Т.е. в форме заказа в разделе Способ оплаты появляется пункт «Выставить счет». Если покупатель его выбирает, то после отправки формы автоматически скачивается файл bill.pdf с реквизитами для оплаты и списком товаров, с печатью, с фотографией директора и т.п.

Но файл у меня не создается. И соответственно при скачивании — ошибка.
Причины не нашел — ставил и новый пакет mpdf через модуль Composer, и брал уже готовый от этого компонента с ранее сделанного рабочего сайта — безрезультатно. Хотя плагин mpdf видит, ошибок в логах нет.
Сайт на локалке OpenServer.

Настройки плагина выглядят так


И по нему вопрос — нужно ли прописывать чанки, если нужно, то куда какой из тех что в папке? или если их не прописывать, то по умолчанию из указанной папки? Может из-за этого и файл pdf не создается? И где он вообще должен создаваться?
  • paic
  • 0
avatar
Судя по флагу I он и не должен создаваться — файл сразу отдается в поток. Можно попробовать флаг S поставить тут в качестве эксперимента (вроде с ним makePDF лучше работал).

Плюс неплохо бы выставить заголовок ответа
header("Content-type:application/pdf");

перед печатью самого файла тут. А потом рассказать, что получилось :)
avatar
Как предложения автору- мне кажется что нужно создавать физический файл (флаг F), а уже потом отправлять его пользователю. Потому что часто так случается типа «я счет потерял, дайте мне его еще раз» — а взять то его и негде :)
avatar
И к названию файла добавлять id заказа и складывать в отдельную папочку, доступную для админа (менеджера), например bill_25.pdf, плюс и перезаписываться не будут.
avatar
ок, но уже завтра
avatar
Докладываю: не помогло.



может где опечатка — в стр. 79 написано счет.pdf, а скачивается bill.pdf, исправил но не помогло.

Попробовал и флаг F, изменил путь на assets/images/bill — физический файл тоже не создается.
Комментарий отредактирован 2019-08-24 09:31:29 пользователем paic
avatar
Может быть дело в порядке вызова плагинов? На событии OnPageNotFound плагин Commerce должен идти впереди.
avatar
Точно!
Я при установке Commerce это проверял, а уже потом устанавливал дополнительные плагины кто куда как сам устанавливался((
avatar
Обратил внимание, что этот плагин обновился
github.com/mnoskov/commerce-options
ну, сразу и поставил.
На этот раз установился без проблем.

1. Плагин Commerce Options, в конфигурации — только шаблон страницы товара.

2. В меню магазин — появился еще один пункт — Атрибуты опций


3. Вкладка с атрибутами


4. Режим редактирования


5. На странице товара в админке появилась дополнительная вкладка


6. Режим редактирования

Заполнил один параметр (т.е. это уже и не параметр в привычном понимании)- все работает, здесь видно что цена пересчиталась (выше — цена из стандартного варианта)

Выводится сниппетом — пример по ссылке вначале поста.

Все красиво, но есть и ряд как вопросов:

1. Вообще поменялась концепция, что параметры должны быть в TV, а к этому все в MODx привязано, все компоненты.
Я когда только поставил, подумал что это будет похоже на eList (из состава eFilter), а оказалось что нет. И как к такому магазину прикручивать тот же eFilter пока не понятно — параметров же нет, по чем фильтровать((

2. Как-то много дублирующей писанины — сначала заполнил вкладки в меню (атрибуты), а потом почти то же самое, только с изменением цен — на странице товара. Может, я очередность заполнения не ту применил, или просто с непривычки…

3. На странице товара — если выбрал один атрибут, то его уже не изменить — другие становятся неактивными. И картинки не появились, зря загружал(( Но с картинками — это хорошо будет, типа цвет картинками задавать, или как у меня в примере сезоны.

4. В корзину летит товар с правильной ценой, но без выбранного атрибута (опции), но это я может что-то недопрописал.
  • paic
  • 0
avatar
По п.3 и 4 чуть подправил сниппет и вместо чекбокса сделал радио (п.4.) — ИМХО, если параметр с изменением цены, то чекбокс и не нужен.

'valueTpl'  => '@CODE:<li data-comoptions-value="[+id+]"><label><input type="radio" name="options[season]" value="[+title+]">[+title+]</label>',

а из строки 18 убрал плейсхолдер hidden, как оказалось — это он запрещает повторный выбор (п.3.).
avatar
Но если добавить еще и цвет — фигня получается.
avatar
Кажется, понял, как это должно работать. Нужно делать сопряженные параметры (или подчиненные, не знаю как это правильно назвать.
Смысл в том, что если есть сезон зима, то нужно указывать не просто цвета, а именно те цвета, которые есть по этому сезону, как на скриншоте



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



Круто!

Но может еще чего и не разгадал, было бы неплохо доки почитать по этому компоненту))
avatar
Не сразу обратил внимание. Есть еще такая фишка: если никакая опция не выбрана — кнопка «Купить» не активна.
avatar
Вывод картинок можно прописать в чанке valueTpl сниппета CommerceOptions, например
<img src="[[phpthumb? &input=`[+image+]` &options=`w=40,h=30,far=C,bg=FFFFFF`]]" alt="[+title+]">

где [+image+] — это внутренний плейсхолдер компонента, не путать с ТВ и не изменять.
avatar
Увидел обновление Commerce и commercebillpayment. Спасибо автору. Ну и сразу обновился.
Изменений много, но не все запустилось ((
Из положительного.
1. По избранному — теперь все работает, товары из избранного уже удаляются корректно.
2. Кодировка в корзине множественных параметров исправлена, но выводится в таком виде:
["зима","белый"]

3. Вроде как добавилось создание физического файла pdf (счета) и ссылка для скачивания, но не работает. Путь в настройках плагина прописал в таком виде assets/files
4. Вроде как добавился веб-пользователь, но поле customer_id для него в таблице заказов не увидел (при обновлении оно не добавилось).
5. Хотелось бы и по плейсхолдеру разъяснения, что, для чего, куда и как.
Все же объяснений не хватает — компонент обрастает новыми функциями, хотя бы пару слов не помешало.

Добавились новые шероховатости, ранее не замеченные:
1. Никакой реакции на выбор способа по счету. Идет стандарная отправки формы и в конце — Спасибо за заказ. Никакого скачивания или ссылки на скачивание счета нет. Более того — заказ по факту не отправляется, т.е. в базу данных не записывается(( Ну и по-прежнему после отправления заказа корзины (большая и маленькая) не очищаются.
2. Если у товара есть опции, то такой товар в корзину из каталога не добавляется. Попробовал в чан прописать вызов сниппета CommerceOptions — безрезультатно, он в чанке DL просто не работает — никаких опций не выводится. Так же и на странице самого товара — даже если из шаблона убрать вызов CommerceOptions — товар в корзину не добавляется.
3. Недоразумения с капчей пока сохранились.
  • paic
  • +2
avatar
2. Да, такой вид по умолчанию — неизвестно ведь, что вы и в каком виде будете там хранить.
3. Установил плагин на чистую систему, работает нормально, с таким же путем.
4. Да, запутался в обновлениях. Сейчас вроде пофиксил, колонка должна добавляться.
5. Какой плейсхолдер?

1. Можете в личку дать ссылку, погляжу. Корзина очищается, просто не обновляется на странице.
2. В доклистере нужно дополнительно указывать идентификатор вот так:
[[CommerceOptions? &docid=`[+id+]`]]
Ну и в форме, естественно, делать.
При добавлении товара производится проверка, и если добавляется без опций, а у товара есть опции, то происходит переадресация на страницу товара — подразумевается, что на странице товара точно есть выбор опций. Возможно это нужно вынести в настройки плагина…
avatar
2. Ну, не знаю, а что там еще можно хранить кроме параметров товара, и в каком виде?
3.Мне вчера внутренний голос тоже бубнил на ухо: сделай новую чистую установку, сделай новую установку. Не послушался — накатил на старое, хотел посмотреть как проходит обновление. Но, наверное, пора сделать новую.
5. product page placeholders


2. Это меня заклинило, я пытался с id, а с docid и не попробовал(( В общем, выводится.
Переадресация не срабатывала. И даже не догадывался, что такое может быть.
avatar
2. Так не знаю, может у вас параметры с большой вложенностью, или еще что-то.
5. На странице товара доступны плейсхолдеры [+products_contains+] = 1, [+products_active+] = ' active', [+products_count+] и такие же для wishlist и comparison.
avatar
2. Хорошо бы вообще понимать заложенную логику и алгоритм CommerceOptions. Разгадывание ребусов занятие конечно интересное, но не всегда дает 100-процентный результат. Я вот, например, не могу представить, как можно с помощью CommerceOptions сделать такое. Может, фантазии не хватает, а может просто не знаю что в CommerceOptions заложено

Это страница товара Дверь на SHK, здесь цвет выводится из eLists (без изменения цены), а все остальное — на multiTV вместо (в режиме) paramEdit. Выбирая нужную комплектацию их стоимость добавляется к цене. Не эталон, конечно, просто как пример возможного применения.

5. Если можно, что такое products_contains и products_count? По products_active вроде понятно, т.к. обсуждалось ранее.
avatar
Нечто подобное можно сделать, но у вас ближе к изготовлению дверей на заказ, а в commerceoptions идея ближе к продаже готовых.
Т.е. надо каждую дверь занести в админку и указать параметры, которыми она отличается.
Я не говорю, что это лучше или удобнее, просто вот так было нужно.

5. products_contains — есть ли этот товар в корзине, products_count — сколько этого товара в корзине.
avatar
Нет, корзина не очищается.
avatar
Она очищалась (без обновления), еще в первом варианте, с которого начинал тестирование, а уже во втором варианте и это пропало. Это если считать нынешнее обновление третьим.
avatar
А письмо отправляется?
avatar
В первом и втором варианте — отправлялось, в третьем — не знаю, я его на хостинг не заливал, но в базу не записывалось.

Приготовил новую инсталяшку уже с личным кабинетом, начну с нуля, по одному компоненту, начиная с commerce и добавляя по одному commerce-billpayment, commerceoptions, commercedashboard. Потом отпишусь.
avatar
Капчу исправил вроде бы, но там проблема в том, что как будто сбрасывает код при изменении способа доставки или оплаты, а изображение не меняется.
avatar
Код меняется при любой отправке формы. Если для изменения доставки/оплаты нужно форму целиком отправлять, то лучше использовать api-режим и брать из ответа обновленную капчу.
avatar
Сделал новую установку сегодняшней версии — только сам commerce, без прицепов.

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

<a href="#" class="link[+wishlist_active+]" data-commerce-action="add" data-id="[*id*]" data-instance="wishlist">Добавить в избранное</a>
<a href="#" class="link[+comparison_active+]" data-commerce-action="add" data-id="[*id*]" data-instance="comparison">Добавить в сравнение</a>

Проверил — работает, класс active подключается. Но не отключается другими ссылками, для удаления из избранного и сравнения
<a href="#" class="link" data-commerce-action="remove" data-instance="wishlist" data-id="[*id*]">Удалить из избранного</a>
<a href="#" class="link" data-commerce-action="remove" data-instance="comparison" data-id="[*id*]">Удалить из сравнения</a>

3. Добавил на страницу товара форму и малую корзину. Проверил — работает.
4. Оказалось — «слетели» плейсхолдеры, класс active перестал подключаться.
5. Добавил к кнопке «Купить» тоже плейсхолдер
[+products_active+]

хоть он там и не нужен, но начал подлючаться класс active к ссылкам добавить в избранное и в сравнение.
6. Поставил препаре для аналогичных действий в каталоге при выводе DL, чанке так

<a href="#" class="link[+wishlist_class+]" data-commerce-action="add" data-id="[+id+]" data-instance="wishlist">Добавить в избранное</a>
<a href="#" class="link[+comparison_class+]" data-commerce-action="add" data-id="[+id+]" data-instance="comparison">Добавить в сравнение</a>

Проверил — работает.
7. Вернулся на страницу товара — не работает. Удалил препаре — заработало. Опять подключил препаре, вроде не отвалилось.
8. Очистил и избранное, и сравнение, зашел на страницу товара — а там плейсхолдеры не очистились.
В остальном вроде нормально.
P.S. В качестве хелпера используется такой скрипт из предыдущих разборов, может он как-то пагубно влияет?
$(document).on('cart-add-complete.commerce', function(e, data) {
    switch (data.data.cart.instance) {
		
        case 'wishlist':
        case 'comparison': {
            data.initiator.addClass('active').tooltip({
                title: 'Товар добавлен в ' + (data.data.instance == 'wishlist' ? 'отложенные товары' : 'сравнение'),
                trigger: 'manual'
            }).tooltip('show');
			
            setTimeout(function() {
                data.initiator.tooltip('hide');
            }, 1000);

            break;
        }
		case 'products': {
            data.initiator.tooltip({
                title: 'Товар добавлен в корзину',
                trigger: 'manual'
            }).tooltip('show');
			
            setTimeout(function() {
                data.initiator.tooltip('hide');
            }, 1000);

            break;
        }
    }
});

9. Другие плейсхолдеры (products_contains и products_count) не проверял, куда их применить пока не понятно.
10. Сделал страницу оформления заказа (и корзина, и форма на одной странице).
Еще при установке формы заметил, что чанки по-умолчанию (те что в папке front) не подключаются. Подключил свои через параметры.
11. Сначала решил протестить без капчи.
Заполнил форму, нажал кнопку Отправить — все осталось на месте (и корзина, и форма), выдалось сообщение: Не удалось отправить письмо. Хотя все поля заполнены.
Как оказалось, и валидация отвалилось (никак не индицируется сознательно не заполненное обязательное поле).
11. Добавил доставку и оплату курьеру. Подумал, может из-за пустых плейсхолдеров. Оказалось нет.
12. Зашел в модуль управления заказами. БА! Пока я тренировался, оказалось, что заказы-то при всем при этом отправляются (имеется ввиду в базу записываются, сайт на локалке).
13. Поставил капчу. Появилась валидаця, но отправить письмо не удалось (и в базу ничего не записалось), как и говорил автор — не совпадают значения поля кода капчи с капчей. Но взаимодействие между доставкой и оплатой как внутри формы так и с корзиной работает!
14. Поле для зарегистрированного пользователя не добавилось (может его просто сразу в инсталяяшку прописать?). Но я все же попытался отправить заказ как авторизованный веб-пользователь. Нигде ничего.

Пока все.
  • paic
  • 0
avatar
п.14 не числить, нашел, есть такое поле в evo_commerce_orders, id веб-пользователя в него записалось. Осталось найти, выводится ли он как-то в модуль управления заказами.
avatar
Нет, не выводится.
avatar
Я не учел то, что страницы кешируются, и все эти плейсхолдеры вместе с ними. Что с этим делать пока не понятно.
avatar
Затрудняюсь что-то подсказать, кроме как перенести в сниппет и вызвать его некэшируемым на странице товара, но это наверное не очень хорошо((

Может кто из гуру что более дельное подскажет или поможет кодом для общего дела — отправить SHK на заслуженный отдых.
avatar
Еще можно придумать свои теги и заменять их перед парсером, но не знаю, какие подводные камни тут могут быть.
avatar
здесь же такой нюанс, что выглядеть это желательно должно в виде привычной кнопки (иконки): нажал — добавилось, отжал — убавилось. Я имею ввиду сравнение и избранное (отложенное). Понятно, что есть стили и пр. Но все же.
avatar
Кое-что приятное из тестов.

У сниппета Cart есть очень удобный параметр theme

В дополнение к докам и пояснениям akool выше приведу еще и примеры, как это на практике.

1. Вариант папки. На странице оформлении заказа вызывается так
[!Cart
&instance=`products`
&theme=`test/`
&tvList=`image`
!]

В директории assets/plugins/commerce/templates/front/ создается папка test и туда копируются все необходимые чанки из папки front. Теперь их можно редактировать под свои нужды, не боясь что эти корректуры затрутся при обновлении. Ну и писанины в вызове меньше, и свои чанки в админке можно не создавать.
А при следующем проекте — просто скопировал все эту папку в новый проект, отредактировал под новую верстку — и все.
Очень удобно!

2. Вариант префикса. Он уже реализован по умолчанию, это использования префикса для маленькой корзины, вызывается так
[!Cart
&instance=`products`
&theme=`mini`
&tvList=`image`
!]

При этом все шаблоны для мини корзины подключатся из папки front. Удобно, но не достаточно.

3. Вариант папки и префикса. Чтобы эти шаблоны (п.2) не затерлись при очередном обновлении (а в них как правило больше всего изменений), эти шаблоны нужно тоже скопировать в папку test и уже там откорректировать под свой дизайн и шаблон.
Вызываться в этом случае будет так
[!Cart
&instance=`products`
&theme=`test/mini`
&tvList=`image`
!]
  • paic
  • +1
avatar
Если кто будет это применять — обратите внимание, что в комплекте mimi не хватает одного чанка minicart_row_options_row.tpl — его нужно создать (скопировать cart_row_options_row.tpl и переименовать, он такой же), иначе в маленькую корзину не буду выводиться доп. параметры.
avatar
Сниппет Order поддерживает (пока поддерживает, желательно чтобы осталось в окончательно варианте) параметр
&defaultsSources=`user:web`

Поэтому, если заказ оформляет зарегистрированный (и авторизованный) пользователь, его данные из профиля будут подставляться в форму заказа. Разумеется, наименования полей (плейсхолдеров) должны совпадать с профилем и это нужно учитывать изначально.
  • paic
  • 0
avatar
Это ж вроде по сути Формлистер. Он все котоплюшки должен поддерживать =)
avatar
Вроде да. Но, например, капчу не поддерживает, поэтому на всякий случай написал.
avatar
Увидел обновление, внес на тестовый сайт изменения (новую установку не делал):
— удалены все дополнительные плагины
— капча формой заказа не воспринимается
остальное все так же, как и в предыдущем варианте.
  • paic
  • 0
avatar
Протестил крайнюю версиию Commerce 0.3.5 и Оплату по счету 0.1.1

На этот раз все замечательно:
1. Корзины после отправки формы очищаются.
2. Форма заказа (и сам заказ) отправляется.
3. Счет скачивается с названием bill.pdf
4. Физический файл в указанной папке (в конфигурации плагина) создается с названием id.pdf, где id — номер заказа.
Маленькая шероховатость — при скачивании файла счета выводится сообщение: Ожидайте скачивания счета для оплаты… И оно не исчезает после скачивания файла.
Ну, и в вызов сниппета Order добавил (как для FL)
&protectSubmit=`0`
&submitLimit=`0`

Иначе если покупатель захочет что-то докупить — ему придется долго курить.

По-прежнему не работает капча.
По плейсхолдерам добавить/удалить в избранное/сравнение изменений тоже не увидел.

Как уже сообщал ранее — из установочного комплекта исчезли дополнительные плагины, по ним (из того что нашел) — базовые примеры теперь есть в доках, а из платежных систем github.com/mnoskov/commerce-payment-paymaster
  • paic
  • 0
avatar
Еще несколько моментов.

1. Повторился эффект, который описывал здесь п.13.3. Кроме потери товара в виджете Содержимое корзины модуля, товар так же теряется и в счете pdf. Хотя в базу «потерянные» товары записываются и в итоговую сумму заказа их стоимость добавляется. Перенес на хостинг — нормально. Не знаю, как к этому относиться.

3. Добавил один множественный TV-параметр. Как оказалось, в шаблоне счета по умолчанию опции товара не прописаны. Добавил их так в шаблоне bill_products_row.tpl в колонку с названием товара
<td style="border: 1px solid #555; padding: 5px; text-align: left;">[+pagetitle+]<br ><small>[+options+]</small></td>


2. В корзины (большую и маленькую) и в счет, как уже обсуждалось выше, параметры (опции) выводятся в json и выглядит так

В файле commerce/src/Controllers/Cart.php
строка 211 заменил
'option' => htmlentities(is_scalar($option) ? $option : json_encode($option, JSON_UNESCAPED_UNICODE)),

на
'option' => htmlentities(is_scalar($option) ? $option : implode(", ", $option)),

Теперь выводится так

Негативных последствий вроде пока не обнаружил, хотя может и не правильно. А как правильно? Эксперименты с препаре пока не увенчались успехом((
avatar
Правильно отключить рендеринг опций (&defaultOptionsRender=`0`), и рендерить их самому, в препаре.
avatar
Спасибо
avatar
Установил Commerce Options.
В модуле создал две опции — Цвет и Размер.

1. На странице товара на вкладке Опции товара заполнил эти опции, используя принцип взаимозависимости, т.е. все опции — двойные

Это и быстрее — накидал опций, а потом выставил какая комбинация как влияет на цену. Так и быстрее, и наверное, правильнее.

2. На странице товара ранее созданный ТВ-параметр отключил, а вывел опции
<span data-commerce-price>[!PriceFormat? &price=`[*price*]` &convert=`1`!]</span>
[!CommerceOptions!]

Выглядит так

Работает просто замечательно:
— если выбрать какую-то опцию, то автоматически для дальнейшего выбора останутся только возможные варианты, а все остальные станут неактивными

— не выбрав обе опции — ничего в корзину не добавишь. Кнопка Купить становится активной только при полном выборе опций.

3. На странице каталога (категории), если в чанке не выводятся опции, при нажатии на кнопку Купить перебрасывает на страницу товара, где эти опции есть.
Пример вывода в чанке
<span data-commerce-price>[!PriceFormat? &price=`[+price+]` &convert=`1`!]</span>
[!CommerceOptions? &docid=`[+id+]`!]


4. Мультивалютность уже работает (только на гитхабе надо пример поправить)

5. Опции в корзине в случае использования Commerce Options выводятся корректно (не json) без дополнительных плясок, как для ТВ (предыдущий пост). Ну а плагин для модуля в админке упрощается до примерно такого
//<?php
/**
 * OrderOptions
 * 
 * Добавление опций товара в модуль заказов
 * 
 * @category    plugin
 * @version     1.0.0
 * @internal    @events OnManagerBeforeOrderRender
 * @internal    @modx_category Commerce
**/
$e = $modx->Event;
if(($e->name == 'OnManagerBeforeOrderRender')){
$params['columns']['options'] = [
  'title' => 'Опции товара',
  'content' => function($data, $DL, $eDL) {
	if (!empty($data['options'])) {
        $out = implode(', ', $data['options']);
	}
	return $out;
  },
  'sort' => 40,
  ];
}


Одним словом — автору Браво!
  • paic
  • 0
avatar
В дополнение:

В п.2 сообщал, что ранее созданный ТВ-параметр я отключил. Так вот теперь я его включил. Оказалось, что если товар имеет заполненные опции на вкладке Опции товара, то параметры из ТВ-параметров в корзину не добавляются.

И по-прежнему не ясно, как эти опции добавлять в сравнение, если в сравнении — ТВ.
avatar
Обновился

  • paic
  • 0
avatar
А какая версия php?
avatar
5.6.32
avatar
Сегодняшняя версия commerce-options тоже не стала, сначала очень долго крутился loader, не дождавись пошел на перекур. Возврщаюсь и вижу белый экран и

Fatal error: Call to undefined function ci() in D:\OSPanel\domains\shop-5.ru\manager\includes\document.parser.class.inc.php(1919): eval()'d code on line 85

avatar
Это больше похоже на порядок вызова плагинов
avatar
Может быть, попозже попытаюсь еще раз.

Я сначала обновил сам commerce и конечно уже знал, что он станет в конце и нужно его перемещать в начало, но чтобы 2 раза не заниматься одним и тем же (ровнять порядок вызова) решил сразу обновить и commerce-options, а уже потом все сразу поправить в порядке вызовов плагинов.
Вообще если и так, то как-то напряжно будут проходить обновления((
avatar
Обновил сначала commerce-options, подравнял порядок вызова плагинов, потом обновил commerce.
Обновилось нормально.
avatar
Внесу и я свою лепту по js-событиям. События корзины условно протекают по следующему сценарию:
1. action-start.commerce — самое начало любого события
2. cart-add.commerce — до события добавления товара в корзину
3. cart-add-complete.commerce — после события добавления товара в корзину
4. action-complete.commerce — общее завершению любого события.

Как видим, пункт 1 и 4 в принципе понятны. Осталось разобраться, откуда берутся события в пунктах 2 и 3. Для этого смотрим на action (что запрашивает наш js-объект Commerce). И видим:
1. cart/add
2. cart/remove
3. cart/update
4. cart/clean
На примере cart/add мы уже видели — генерируются два события cart-add.commerce (до) и cart-add-complete.commerce (после). Аналогично и для остальных событий будут пары до и после.

Для лучшего понимания, небольшой кейс с подтверждением удаления товара из корзины и очистки корзины (думаю, после него станет окончательно ясно что к чему).
<script>
$(document).ready(function(){
	$(document).on('cart-remove.commerce', function(e, data) {
		return (confirm('вы уверены, что хотите удалить товар?'));
	});
	$(document).on('cart-clean.commerce', function(e, data) {
		return (confirm('вы уверены, что хотите очистить корзину?'));
	});
})
</script>
avatar
По вчерашнему обновлению.
1. commerce
Теперь в корзину, если на странице есть и опции, и TV-параметры, добавляются и те и другие

в базу записывается так
{"season":["зима","лето"],"0":"белый, 48"}

где season — название TV

2. commerce-options
В конфигурации плагина добавился еще один параметр — Добавление (в корзину) товара без опций

Варианты
— запретить
— запретить, ничего не делать
— запретить, перенаправить на страницу продукта.
Т.е. это для страницы каталога, если в него не выводятся опции.

Это то что заметил, а может и еще что-то есть.

P.S. Сегодня тоже вышло обновление commerce, установил, но видимых изменений не обнаружил, в доках тоже давненько ничего не корректировалось.

3. Вчерашний скрипт от webber тоже протестил, работает, ясности добавилось.
  • paic
  • 0
avatar
Прикинул на первый случай (пока у автора дойдут планы) небольшой личный кабинет, в составе:
1. Страница текущих заказов
2. Страница архивных заказов
3. Страница просмотра одного заказа
4. Виджет со статистикой (например, в боковую колонку или еще куда).

1.
[!DocLister? &idField=`id` &prepare=`status_name` &idType=`documents` &controller=`onetable` &table=`commerce_orders` &sortBy=`id` &sortDir=`DESC` &addWhereList=`customer_id = '[!userId!]' AND status_id != '6'` &debug=`0` &ignoreEmpty=`1` &selectFields=`*` &tpl=`orders_tpl` &noneWrapOuter=`0`
&ownerTPL=`@CODE:
	    <div class="table-responsive">
                <table class="table data">
                    <thead>
                        <tr>
                             <td>Заказ №</td>
                             <td>Дата заказа</td>
                             <td>Наименование товаров</td>
                             <td>Сумма</td>
                             <td>Статус</td>
                             <td></td>
                        </tr>
                    </thead>
                    <tbody>	
    		        [+dl.wrap+]
		    </tbody>
                </table>
            </div>`
&noneTPL=`@CODE:
	    <div class="alert alert-success" role="alert">
            	<h3 class="alert-heading">У Вас еще нет заказов!</h3>
                <p>Чтобы начать покупки перейдите в <a href="[~2~]">каталог</a>.</p>
	    </div>`
!]

К нему:
Препаре status_name — вывод статуса заказа
<?php
$data['status_name'] = $modx->db->getValue('SELECT title FROM '.$modx->getFullTableName('commerce_order_statuses').'  where id='.$data['status_id']);
return $data;

Сниппет list_products — список товаров в заказе
<?php
$table = $modx->getFullTableName('commerce_order_products');

$res = $modx->db->query("SELECT product_id FROM $table WHERE order_id = $id AND product_id > '0'");
if(!empty($res)){
	while ($row = $modx->db->getRow($res)) {
		$ids[] = $row['product_id'];
	}

    foreach ($ids as $id){
        $name.= '<a href="[~'.$id.'~]">'.$modx->getPageInfo($id)['pagetitle'].'</a>
 ';
    }
}
return $name;

Сниппет userId — id веб-пользователя (чтобы чужие не выводились)
<?php
return $modx->getLoginUserID(web);

Чанк orders_tpl

    <tr>
	<td>[+id+]</td>
        <td>[+created_at+]</td>
        <td>[[list_products? &id=`[+id+]`]]</td>
        <td>[!PriceFormat? &price=`[+amount+]` &convert=`1`!]</td>
        <td>[+status_name+]
<small>[+updated_at+]</small></td>
        <td><a href="[~24~]?id=[+id+]" class="btn btn-primary">Просмотр</a></td>
    </tr>

где id=24 — Страница просмотра одного заказа.

Выглядит так



2.
То же, что и п.1, только status_id = '6' ну и можно пагинацию добавить.
  • paic
  • +1
avatar
1-2. То же самое, только все объединено в сниппет-обертку:

<?php
/**
 * order_all
 * 
 * Вывод заказа ЛК
 * 
 * @category    snippet
 * @version     1.0.4
**/
// id веб-пользователя
$uid = $modx->getLoginUserID('web');
// Значения дополнительного параметра статуса
switch ($params['status']) {
	case '0': // все заказы
		$status = "";
		break;
	case '1': // текущие заказы
		$status = " AND status_id != 6";
		break;
	case '2': // архивные заказы
		$status = " AND status_id = 6";
		break;
}
$params['idField'] = 'id';
$params['idType'] = 'documents';
$params['controller'] = 'onetable'; 
$params['table'] = 'commerce_orders'; 
$params['addWhereList']='customer_id = '.$uid.''.$status.'';
$params['ignoreEmpty'] = '1';
$params['selectFields'] = '*';
$params['prepare'] = [function($data, $modx, $_DL){
// Имя дополнительного параметра
	$status = in_array($data['id'], $_DL->getCfgDef('status', [])); 
// Имя статуса заказа
	$data['status_name'] = $modx->db->getValue('SELECT title FROM '.$modx->getFullTableName('commerce_order_statuses').'  where id='.$data['status_id']);
// Список товаров в заказе
	$order_id = $data['id'];
	$res = $modx->db->query('SELECT product_id FROM '.$modx->getFullTableName('commerce_order_products').' WHERE order_id = '.$order_id.' AND product_id > 0');
	if(!empty($res)){
		while ($row = $modx->db->getRow($res)) {
			$ids[] = $row['product_id'];
		}
    	foreach ($ids as $id){
        	$data['products'] .= '<a href="[~'.$id.'~]">'.$modx->getPageInfo($id)['pagetitle'].'</a>
 ';
    	}
	}
return $data;
}];
return $modx->runSnippet("DocLister", $params);


Вызов

[!order_all?
&tpl=`orders_tpl`
&status=`1`
...
!]

Параметр status может иметь значение:
0 — вывод всех заказов
1 — вывод текущих заказов
2 — вывод архивных заказов

чанк orders_tpl немного изменился

    <tr>
        <td>[+id+]</td>
        <td>[+created_at+]</td>
        <td>[+products+]</td>
        <td>[!PriceFormat? &price=`[+amount+]` &convert=`1`!]</td>
        <td>[+status_name+]
<small>[+updated_at+]</small></td>
        <td><a href="[~24~]?id=[+id+]" class="btn btn-primary">Просмотр</a></td>
    </tr>


Остальные параметры — пагинация, ownerTPL, noneWrapOuter, noneTPL — как для DocLister
avatar
3.
Сниппет order_one, вызов на странице
[!order_one?
&OrderTpl=`order_one_tpl`
&ProductsTpl=`order_body_tpl`
&SubProductsTpl=`order_footer_tpl`
!]

order_one_tpl — общий чанк и данные заказа
order_body_tpl — список товаров, вставляется в общий чанк плейсхолдером products
order_footer_tpl — скидка и доставка, вставляется в общий чанк плейсхолдером subproducts

Код сниппета
<?php
/**
 * order_one
 * 
 * Вывод данных одного заказа
 * 
 * @category    snippet
 * @version     1.0.3
**/

include_once(MODX_BASE_PATH.'assets/snippets/DocLister/lib/DLTemplate.class.php');
$DLTemplate = DLTemplate::getInstance($modx);

$t1 = $modx->getFullTableName('commerce_orders');
$t2 = $modx->getFullTableName('commerce_order_products');
$t3 = $modx->getFullTableName('commerce_order_statuses');
$t4 = $modx->getFullTableName('site_tmplvar_contentvalues');
$t5 = $modx->getFullTableName('web_users');

$uid = $modx->getLoginUserID('web');
$id_order = $_GET['id'];
$imgid = "5"; // id TV изображения
if(!empty($id_order)) {
	// Сведения о заказе
$sql = 'SELECT o.id,o.customer_id,o.name,o.phone,o.email,o.amount,o.fields,o.status_id,o.created_at,o.updated_at,s.title as s_title,u.username FROM '.$t1.' as o
LEFT JOIN '.$t3.' as s
ON s.id = o.status_id
LEFT JOIN '.$t5.' as u
ON u.id = o.customer_id
WHERE o.id = '.$id_order.' AND u.id = '.$uid.'
GROUP BY o.created_at desc
LIMIT 0,1';
$res = $modx->db->query($sql);
	
$out='';
while($row = $modx->db->getRow($res))
{
	$row['delivery']= json_decode($row['fields']) -> delivery_method_title;
	$row['payment']= json_decode($row['fields']) -> payment_method_title;
	$row['state']= json_decode($row['fields']) -> state;
	$row['city']= json_decode($row['fields']) -> city;
	$row['street']= json_decode($row['fields']) -> street;
	$row['message']= json_decode($row['fields']) -> message;

	$out = $DLTemplate->parseChunk($OrderTpl, $row);
}
	// Сведения о товаре
$sql2 = 'SELECT p.product_id,p.title,p.price,p.count,p.options,p.meta,p.position,t.value as image FROM '.$t2.' as p
LEFT JOIN '.$t4.' as t
ON t.contentid = p.product_id
WHERE p.order_id = '.$id_order.'  AND t.tmplvarid = '.$imgid.'
GROUP BY p.position asc';
$res2 = $modx->db->query($sql2);
	
$out2='';
while($row = $modx->db->getRow($res2))
{
	$row['total'] = $row['price']*$row['count'];
	$out2 .= $DLTemplate->parseChunk($ProductsTpl, $row);
}
	// Сведения о скидках и наценках
$sql3 = 'SELECT p.product_id,p.title,p.price,p.count,p.options,p.meta,p.position,t.value FROM '.$t2.' as p
LEFT JOIN '.$t4.' as t
ON t.contentid = p.product_id
WHERE p.order_id = '.$id_order.' AND p.product_id is NULL
GROUP BY p.position asc';
$res3 = $modx->db->query($sql3);
	
$out3='';
while($row = $modx->db->getRow($res3))
{
	$out3 .= $DLTemplate->parseChunk($SubProductsTpl, $row);
}
	// Установка плейсхолдеров в основной чанк
$modx->setPlaceholder('products', $out2);
$modx->setPlaceholder('subproducts', $out3);

return $out;
}
  • paic
  • +1
avatar
3. продолжение

Чанк order_one_tpl

    <div class="row">
	<div class="col-md-3">
            <div class="sectionHeader panel panel-default">
                <div class="panel-heading">
    		    <h4 class="panel-title">Сведения о заказе</h4>
		</div>
		<div class="sectionBody">
		    <table class="table data group-fields">
			<tbody>
			    <tr>
				<td>Номер заказа:</td>
				<td><strong>#[+id+]</strong></td>
			    </tr>
			    <tr>
				<td>Дата и время создания:</td>
				<td>[+created_at+]</td>
			    </tr>
			    <tr>
				<td>Статус:<br >[+s_title+]</td>
				<td>[+updated_at+]</td>
			    </tr>
			</tbody>
		    </table>
		</div>
	    </div>
	</div>
	<div class="col-md-3">
	    <div class="panel panel-default">
		<div class="panel-heading">
    		    <h4 class="panel-title">Данные покупателя</h4>
		</div>
                <div class="sectionBody">
                    <table class="table data group-fields">
			<tbody>
			    <tr>
                                <td>Имя:</td>
                                <td>[+name+]</td>
                            </tr>
                            <tr>
                                <td>Телефон:</td>
                                <td>[+phone+]</td>
                           </tr>
			    <tr>
                                <td>Email:</td>
                                <td><a href="mailto:[+email+]">[+email+]</a></td>
                            </tr>
			</tbody>
		    </table>
                 </div>
	      </div>
	    </div>
	    <div class="col-md-3">
                 <div class="panel panel-default">
                      <div class="panel-heading">
    			    <h4 class="panel-title">Адрес доставки</h4>
			</div>
                    	<div class="sectionBody">
                            <table class="table data group-fields">
				<tbody>
				    <tr>
                                    	<td>Регион:</td>
                                    	<td>[+state+]</td>
                                    </tr>
				    <tr>
                                    	<td>Город:</td>
                                    	<td>[+city+]</td>
                                    </tr>
				    <tr>
                                    	<td>Адрес:</td>
                                    	<td>[+street+]</td>
                                    </tr>
				    <tr>
                                    	<td>Сообщение:</td>
                                    	<td>[+message+]</td>
                                    </tr>
				</tbody>
			    </table>
                    	</div>
		    </div>
		</div>
		<div class="col-md-3">
                    <div class="panel panel-default">
                    	<div class="panel-heading">
    			    <h4 class="panel-title">Способ оплаты и доставки</h4>
			</div>
                    	<div class="sectionBody">
                            <table class="table data group-fields">
				<tbody>
				    <tr>
                                    	<td>К оплате:</td>
                                    	<td><strong>[[PriceFormat? &price=`[+amount+]` &convert=`1`]]</strong></td>
                                    </tr>
				    <tr>
                                    	<td>Способ доставки:</td>
                                    	<td>[+delivery+]</td>
                                    </tr>
				    <tr>
                                    	<td>Способ оплаты:</td>
					<td>[+payment+]
					[[if? &is=`[+payment+]:=:Выставить счет` &then=`<a href="assets/files/[+id+].pdf" target="_blank">скачать счет</a>`]</td>
                                    </tr>
				</tbody>
			    </table>
                    	</div>
		    </div>
                </div>
	    </div>
	    
	    <div class="table-responsive">
                <table class="table data">
                    <thead>
                        <tr>
                            <td style="width: 1%;">#</td>
                                <td>Изображение</td>
                                <td>Название</td>
                               	<td>Опции товара</td>
                                <td>Кол-во</td>
                                <td>Цена</td>
                                <td style="text-align: right; white-space: nowrap;">Всего</td>
                            </tr>
                        </thead>
                    <tbody>
			[+products+]
		    </tbody>
		</table>

            <table class="table data">
		<thead>
		    <tr>
		        <td>Название</td>
                        <td style="text-align: right; white-space: nowrap;">Цена</td>
		    </tr>
		</thead>
		<tbody>
		    [+subproducts+]
		<tr>
		    <td>Итого к оплате</td>
                    <td style="text-align: right; white-space: nowrap;">[[PriceFormat? &price=`[+amount+]` &convert=`1`]]</td>
		</tr>
	    </tbody>
	</table>
    </div>

Чанк order_body_tpl

			    <tr>
                               <td>[+position+]</td>
                               <td><img src="[+image+]" alt="" style="width: 100px;"></td>
                               <td><a href="[~[+product_id+]~]" target="_blank">[+title+]</a></td>
                               <td>[+options+]</td>
                               <td>[+count+]</td>
                               <td>[[PriceFormat? &price=`[+price+]` &convert=`1`]]</td>
                               <td style="text-align: right; white-space: nowrap;">[[PriceFormat? &price=`[+total+]` &convert=`1`]]</td>
                            </tr>


Чанк order_footer_tpl

                                <tr>
                                  <td>[+title+]</td>
                                  <td style="text-align: right; white-space: nowrap;">[[PriceFormat? &price=`[+price+]` &convert=`1`]]</td>
                               </tr>


Выглядит примерно так как и в модуле.
Добавил ссылку для скачивания счета (для потерявших) и очень просилось внизу таблицы Итого.

Но можно и компактнее, кому как нравится и сколько места есть на странице, внешний вид зависит от чанков.

avatar
4.
Сниппет OrderStatistics, выводится так
[!OrderStatistics!]
<p>[+orders+]</p>
<p>[+sumorders+]</p>

Почти ничего не придумывал — такое было для SHK, чуть переделал для Commerse.

Код сниппета

<?php
$table = $modx->getFullTableName('commerce_orders');
$user = $modx->getLoginUserID(); // id пользователя

$result = $modx->db->query("SELECT id,amount FROM $table WHERE status_id='6' AND customer_id='$user' ");

// количество заказов
$orders = $total_rows = $modx->db->getRecordCount( $result );

// сумма заказов
$this->modx = $modx;
while( $row = $this->modx->db->getRow( $result ) ) {
	$sumorders = $this->total_sum += $row['amount'];
}
// сумма заказов с конвертацией
$params['price'] = $sumorders;
$params['convert'] = '1';
$sumorders = $modx->runSnippet("PriceFormat", $params);

// плэйсхолдеры с информацией о заказах пользователя
$modx->setPlaceholder('orders', "Количество покупок: $orders");
$modx->setPlaceholder('sumorders', "Общая сумма покупок: $sumorders");


P.S.
1. Мультивалютность в ЛК везде поддерживается, спасибо автору Commerce.
2. Если у кого будут замечания, предложения, дополнения — буду рад.

Но вообще логичнее было бы все это сделать в общей канве Commerce, типа дополнить Cart instance=profile или что-то в этом роде, да и функций побольше.
  • paic
  • +1
avatar
Я думаю, выглядит это все вполне достойно, и вам стоит сделать установочный пакет, только включить туда уже готовую структуру личного кабинета в дереве ресурсов.
avatar
Есть еще что совершенствовать:

1. На страницы текущих заказов и архивных лучше или для DL сделать сниппет-обертку и убрать внешний «обвес» во внутрь этого сниппета, или сделать свой сниппет, как для страницы одного заказа, с добавлением пагинации.

2. Сниппет order_one на страницу одного заказа — очень хотелось сделать через 1 вызов в базу, или хотя бы 2, но увы — одного желания оказалось мало((

3. Причесать вывод параметров и опций (как и везде).

4. Добавить функционал. У того же SHKUserProfile и то побольше — есть функции Повторить заказа (для архивных) и Отменить заказ (для текущих).

5. Для скачивания счета — сейчас можно скачать счет, если при заказе был выбран способ оплаты «Выставить счет» (ссылка на скачивание выводится через if). А если был выбран другой способ оплаты — то и скачивать нечего. Для таких случаев тоже надо что-то предусмотреть, например, можно или прикрутить makepdf, или, что более логично — как-то задействовать уже существующий вариант в Commerce.

6. Наверное, есть и другие полезные фишки для личного кабинета, о которых я и не подозреваю))

А так да, использовать можно.

Структура личного кабинета может быть любой, у меня сейчас так
Комментарий отредактирован 2019-09-13 08:16:39 пользователем paic
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.