Компонент 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. Товары из избранного не удаляются.

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

Спасибо.

UPD 04.06.2021
Commerce давно взлетел, полет нормальный.
Доки от автора Commerce.
docs.evo.im/04_extras/commerce.html

Скрин с гита


UPD 29.04.2020

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

Скрин с гита
  • avatar
  • 14
  • +2
  • 34698

330 комментариев

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
13.2 Сегодня решал
Эвент на OnManagerBeforeOrderRender. В моём случае это была первая фотка из мульти-тв под именем photo. Имя поля в конфиге мультитв «image». Запускаем, ищем первое поле, ресайзим, выводим.

		$params['columns']['image'] = [
			'title' => 'Изображение',
			'content' => function($data, $DL, $eDL) {
				$modx = EvolutionCMS();
				$out= $modx->runSnippet('phpthumb',[
					'options'=>'w=80,h=80',
					'input'=>  $modx->runSnippet('multiTV',[
						'tvName' => 'photo',
						'docid' => $data['id'],
						'outerTpl' => '@CODE: [+wrapper+]',
						'rowTpl' => '@CODE: /[+image+]',
						'display' => 1
					])
				]);
				return "<img src=/$out>";
			},
			'sort' => 20,
		];

avatar
Спасибо!
Я уже почти переучился задавать имя параметра не img, а image)) но если переделывать другой сайт и в других случаях — несомненно пригодится.
avatar
Ну да, если это не мультитв, можно сделать runSnippet DocInfo и всё будет ещё проще.
avatar
Раньше «имя картинки» решалось так в плагине (возможно, и сейчас работает)
case 'OnManagerBeforeOrderRender':
		$e->params['config']['tvList'] = 'image_thumb';
		$e->params['config']['imageField'] = 'tv.image_thumb';


где image_thumb — это, понятно, имя tv с картинкой, отличное от image
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
лінк битий
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
Каким образом можно отследить если товар в корзине и класс добавился отменить добавление в корзину, так как и так товар в корзине? Этот код для страницы одного товара не будет работать?
Комментарий отредактирован 2020-04-08 18:09:41 пользователем Multiweb
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
Почему может не отображаться список товаров в составе заказа? Игнорируются плейсхолдеры [+products+] и [+subproducts+]


Естественно я все внимательно проверил, полностью соответствует вашим шаблонам и сниппету мое содержимое
Комментарий отредактирован 2020-10-05 12:08:48 пользователем gumoviy
avatar
Может плесхолдеры пустые?
Сверьте запросы в базу со своей базой, что где и как у вас хранится. Или составьте запросы самостоятельно, тогда будет видно и понятно, что и откуда вы тянете.

К тому же год прошел, commеrce за это время значительно продвинулся. Хотя таблицы вроде не менялись… На всякий случай еще раз с рабочего сайта
<?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;
}
avatar
Спасибо. К сожалению не помогло. Плейсхолдеры [+products+] и [+subproducts+] продолжают вырезаться. Остальные данные на месте.

Буду в таблицах смотреть.
avatar
Еще мини-просьба, не могли бы вы дать архив старого commerce-options, новый отказывается выводиться в выпадающем пункте Магазин:


Знаю, у вас точно завалялся :)
Комментарий отредактирован 2020-10-05 19:08:51 пользователем gumoviy
avatar
Завалялся, стучите в личку
Но мне кажется — это не тот путь(( Даже здесь в теме автор говорил, что эта версия commerce-options отправлена в архив. И сейчас новая, ее и надо применять с новой версией commerce. Лучше разобраться, почитать доки, может у вас просто очередность плагинов не та, кэш не очищеy, или версия php, или еще что-то в том же духе.
avatar
Ругается
Execution of a query to the database failed - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'GROUP BY o.created_at desc LIMIT 0,1' at line 7
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
avatar
А на чем у вас написан личный кабинет? Какой плагин, сниппет?
avatar
FormLister
avatar
Спасибо
avatar
Крутой магазин получился на этом решении? Можете показать пример работающий?
avatar
Не, начинать с крутого не стал, сделал один очень простенький для начала, все отлично.
С фронта там в общем-то смотреть особо нечего, но если хотите — в ЛС могу ссылку дать.
avatar
Хочу, интересно.) Я пробовал мес. 5 назад это решение но оно было не совсем готово еще и не работало многое, включая добавление в корзину товар его подсчет и т.д.
Комментарий отредактирован 2019-11-12 15:26:08 пользователем om1
avatar
Присоединяюсь
avatar
Здравствуйте. Дайтк ссылку в ЛС, пожалуйста
avatar
Выдает ошибку 500 после нескольких заказов
<code>Failed to load resource: the server responded with a status of 500 ()</code>
по ссылке (Заказы)
/manager/#?a=112&id=3&route=orders
. Статусы заказа и валюту можно менять, вкладки рабочие. Хотя после установки все отлично работало (
Комментарий отредактирован 2019-09-22 19:50:13 пользователем Multiweb
avatar
А что в логах?
Может в заказах что-то с данными не то. Можете сделать дамп таблиц commerce_orders, commerce_order_products и commerce_order_history?
avatar
Удалил все заказы из базы и все заработало. Спасибо
avatar
И тогда еще параллельный вопрос про мини-корзину для шапки. Как правильно ее вызвать? И я так понимаю, что на странице Оформить заказ вызова корзины в шапке не должно быть? В ShK была опция, не показывать корзину на странице самой корзины и в оформлении заказа.
avatar
И для шапки, и для страницы оформления заказов — вызов одинаковый, отличие только по чанкам.
На странице, в отличие от SHK, может быть несколько корзин, поэтому скрывать мини-корзину в шапке на странице оформления заказа нет необходимости.
avatar
Доброго дня всем! Не могу понять, как добавить способы оплаты и доставки. Создаю снипеты, а как их прикрутить к форме не понимаю. Планируется ли вывести способы оплаты и доставки в меню Магазин?
avatar
Это не сниппеты, а плагины. В форму добавляются плейсхолдерами delivery и payments — смотрите в чанке (папка front) order_form.tpl.
avatar
Спасибо. Про плейсхолдеры не дочитал.
avatar
Возник вопрос по валюте — как в шаблонах обернуть ее в теги?
Сейчас получается так, что если я прописываю цену, например, в 40px, то и валюта будет такой же величины. А надо, чтобы была возможность валюту форматировать отдельно от цены, чтобы на выходе получалось что-то в таком роде
<div class="price">100 <span>руб.<span></div>

Сейчас даже пробел между номиналом и валютой не сделать. Если только в модуле в поле Символ справа отступить перед написанием, но span туда не вписывается — его откусывает.
Спасибо.
  • paic
  • 0
avatar
Ну пробел там должен сохраняться, но разметку в базу не вписать, поля короткие...
Есть способ с перегрузкой метода format, набросал примерный код плагина:
class CustomCurrency extends \Commerce\Currency
{
    public function format($amount, $code = null)
    {
        // код форматирования
    }
}

if ($modx->event->name == 'OnInitializeCommerce') {
    $modx->commerce->currency = new CustomCurrency($modx);
}

Конечно не очень удобно, возможно лучше просто сделать подлиннее поля.
avatar
Спасибо.
avatar
Еще вопрос по письму, которое приходит на почту админу сайта о новом заказе и его составе. Это письмо определяется шаблоном order_report.tpl в папке lang.
Поскольку по умолчанию компонент содержит ограниченное количество контактных данных, то так и в этом шаблоне.

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

А как быть с этим письмом?
Просто дописать в шаблоне письма, например
[+order.name+], [+order.email+], [+order.phone+]
Регион: [+order.state+]
Город: [+order.city+]
Адрес доставки: [+order.street+]
Сообщение:[+order.message+]

ничего не дает.

Спасибо.
  • paic
  • 0
avatar
[+order.fields.city+] и т.д.
По умолчанию в отдельные столбцы таблицы с заказами с охраняются только name, phone и email. Все остальные поля сохраняются в столбец fields.
avatar
Спасибо.
avatar
Боже, храни этот тред. И конечно, автора магазина. Всего полтора часа назад начал его смотреть, но уже волосы шевелятся от того, насколько круто всё сделано. Правда, долго затуплял на добавлении вариантов оплаты. Такой подход еще не видел нигде. С наскока оказалось не интуитивно.
Поделитесь заготовкой плагина для админки, который берет только что размещенный заказ и что-то делает с его данными. Ну, например, дамп в файл. И такой же вариант при смене статуса заказа. Не могу начать. Так как вроде события на каждый чих есть, а массив не описан
Комментарий отредактирован 2019-11-11 20:30:01 пользователем alexbeep
avatar
Подскажите как Вы добавляли способы оплаты и доставки? А то посоздавал плагинов, а как их внедрить так и не понял
avatar
avatar
Это я видел. А как он попадает в форму заказа?
avatar
Я без прикола думаю, что моего уровня не хватит, чтобы объяснить. но я создал 2 таких плагина с произвольным именем, указал у каждого свой code и title, повесил на них событие, по которому они подтягиваются OnRegisterPayments и вуаля — они в форме



В модуле заказов


Также id ($code) по умолчанию можно прописать в настройки плагина Commerce


По логике, и код и название могут быть произвольные. Я поставил просто цифру в id
avatar
Спасибо. Уже горячо. Думаю, что и у меня получится!
avatar
Лучше все-таки делать более осмысленные идентификаторы, например cash, terminal. Самому потом легче будет
avatar
Вот событие — github.com/evolution-cms/docs/blob/master/ru/04_%D0%9A%D0%BE%D0%BC%D0%BF%D0%BE%D0%BD%D0%B5%D0%BD%D1%82%D1%8B/Commerce/10_%D0%A1%D0%B5%D1%80%D0%B2%D0%B5%D1%80%D0%BD%D1%8B%D0%B5_%D1%81%D0%BE%D0%B1%D1%8B%D1%82%D0%B8%D1%8F.md#onorderprocessed
Вот пример плагина с обработкой заказа после его создания:
if ($modx->event->name == 'OnOrderProcessed') {
    file_put_contents(MODX_BASE_PATH . '/dump.txt', print_r($order, true) . print_r($cart));
}
avatar
Спасибо за ссылку с событиями, что-то я ее не нашел изначально. Остальные вопросы задал в телеге. Дамп-то сделать получилось, а вот осознанно с ним работать — пока нет
avatar
Еще один вопрос возник — по заказам в модуле (в админке).
А как удалять заказы? Просмотр есть, Редактировать есть, Добавить есть… а Удалить нету.

Спасибо.
  • paic
  • +1
avatar
Удаления заказов нет. А зачем? Переводите в отмененные.
avatar
После тестирования остались тестовые заказы на тестовые товары, которых уже и нет. Понятно, что можно через базу удалить, но как то не очень хорошо, тем более для обычного админа. Да и вообще полезная функция, ИМХО.
avatar
Тестовые заказы можно удалить очисткой таблиц перед передачей сайта, а все остальные заказы, считаю, удалять нельзя, т.к. их идентификаторы могут использоваться во внешних сервисах, например.
avatar
верно
avatar
Теперь есть и удалить тоже.
avatar
Спасибо, буду иметь ввиду.
avatar
Добавил дополнительное поле в заказ — Адрес. Нашел где и что, чтобы плейсхолдер прописался и валидация проходила. Но вот при отправке пишет, что Не удалось отправить письмо, хотя заказ в админке формируется. Я так понимаю, поле address еще где-то нужно задействовать, чтобы форма очищалась и писалось, что Ваш заказ успешно отправлен
avatar
Включите debug и посмотрите в логах что там к чему. Ну и здесь можете вызов показать.
avatar
В общем в логах все нормально. Меня смущает, что я валидацию впихнул прямо в сниппет Order

'address' => [
'required' => $lang['order.error.address_required'],
],

Создал способы доставки, но выводится только один.
Хочется конечно же боле внятной инструкции по поводу всего этого, а не с точки зрения разработчика, который создал данный модуль.
avatar
Валидацию можно передавать в параметре rules при вызове сниппета, как в формлистере
avatar

[!Order
&deliveryTpl=`deliveryTpl`
&deliveryRowTpl=`deliveryRowTpl`
&paymentsTpl=`paymentsTpl`
&paymentsRowTpl=`paymentsRowTpl`
&reportTpl=`reportTpl`
&ccSenderTpl=`ccSenderTpl`
&debug=1
&rules = {
	"address":{
        "required":"Введите адрес"
},
"name":{
        "required":"Введите имя"
},
"email":{
        "required":"Введите email"
},
"phone":{
        "required":"Введите телефон"
}
}
!]

Все равно — Не удалось отправить письмо.
Комментарий отредактирован 2019-12-01 17:50:29 пользователем Multiweb
avatar
Создание заказа происходит до отправки письма, т.е. у вас ошибка говорит сама за себя — письмо отправить не удалось. Видимо не все чисто в логах. Попробуйте шаблоны по минимуму заместить, может там что-то напутано.
avatar
Спасибо. Методом тыка разобрался!
avatar
Но заказ попал в админку. Не происходит очистка корзины и полей
avatar
Вот таким образом добавил опции к товару — joxi.ru/ZrJzQlEcwEJ39r (супер красиво сделано). Вопрос — как эти опции вывести в карточке товара?
avatar
[[CommerceOptions]]
внутри формы добавления товара
avatar
Спасибо
avatar
А как быть, если у меня есть Цвет, Сезон и Размер и я хочу выбрать цвет, сезон и размер и после этого добавить в корзину? А то на скрине видно, что можно выбрать лишь один из всех — joxi.ru/brRzaWdc7KyzJr
avatar
Это уже разбирали — modx.im//blog/questions/5976.html#comment52963
Вы на каждый вариант товара добавили только одно значение из одной опции, а надо по одному значению из каждой опции.
avatar
Опции товара в админке — joxi.ru/Dr8Rd5oiow4nj2
Опции на странице с товаром — joxi.ru/E2pEz4MF7l9VDA
Сезон не выводится (
avatar
Было бы неплохо записать видео. А если не 2, а 3 и более характеристик? И если добавлять опции через сниппет, то как отобразить опции в админке в заказах, а также в письме, которое приходит на почту,
Комментарий отредактирован 2019-12-03 11:49:13 пользователем Multiweb
avatar
Так хоть 10 характеристик, ничего не изменится. Все это рассматривали выше.
Видео я записывать не буду, более того, этот модуль я уже отправил в архив, т.к. он не учитывает важных потребностей в разрезе работы с вариантами товаров.
avatar
Спасибо. Буду использовать тогда размер. Цвет и сезон будет забит жестко у товара.
avatar
более того, этот модуль я уже отправил в архив
а что будет взамен, или может быть, уже есть?
avatar
В разработке
avatar
Также интересует, что нужно сделать. чтобы при выборе атрибута товара пересчитывалась цена? При добавлении в корзину все нормально, а вот на странице самого товара ничего не происходит.
avatar
Проверьте, чтобы разметка была такая же — github.com/mnoskov/commerce-options/blob/master/README.md
avatar
Разобрался
<span data-commerce-price>[!PriceFormat? &price=`[*price*]` &convert=`1`!]</span>
avatar
Вот еще вопрос по размерности возник (единицы измерения товара). Разный товар имеет цену за разную величину, т.е. цена может быть за шт., за кг, за м погонный, за м квадратный. и чтобы это отражалось и в корзине? Примерно так

Спасибо
  • paic
  • 0
avatar
а что мешает просто хранить единицы измерения в tv?
avatar
С тв понятно, на SHk так и делал, но этот компонент новый и мало изведанный, находится в активном развитии — вижу автор постоянно обновляет, может и для этой фишки есть или планируется что-то другое и более удобное. А там еще потянутся другие пожелания от заказчиков, типа чтобы если в шт — то градация выбора через 1, а если в кг — то через 100г, а если в метрах — то через 10см, ну и т.п. (фантазия бывает богатой))
avatar
ну учитывая, что товары по прежнему остаются ресурсами. и от единиц измерения логика работы не меняется. и наличие ТЕ3, которым можно настроить форму в админке.
т.е. я хочу сказать, что единица измерения в том виде, что описали вы — это «вшитая TV», которая не нужна большинству, а сделать ее — 5-15 минут времени.
предложения по плюшкам это хорошо. но конкретно единицы измерения — это дополнительный код без дополнительного функционала
avatar
Да, единицы измерения храните в тв. В корзине выводите стандартными средствами доклистера.
Есть еще один путь, чтобы не подтягивать тв каждый раз при выводе корзины — плагином при добавлении товара добавлять в мета-данные единицы измерения. В корзине выводить как то так: [+meta.measures_units+].
С разными шагами изменения количества то же самое — выводить напрямую из тв или добавлять плагином. В корзине добавить к кнопкам изменения количества атрибут data-count. Это будет работать со следующей версии.
avatar
Спасибо за разъяснения.
avatar
Еще вопрос, как передать цену в корзину, если она не одна?

Сейчас поясню, цены используются так, пока 3 варианта:
1. Есть товар, у него 2 цены.
TV price — цена с самовывозом, она за 1 м3, но подается поддонами.Количество на поддоне тоже задается в TV. Шаг count равен количеству м3 на поддоне.
TV price2 — цена с доставкой, она тоже за 1 м3, но продается машинами. Количество загрузки машины тоже задается в другом TV. Шаг count равен количеству м3 в машине.
На странице товара — переключатель цены (самовывоз или доставка), соответственно в выбор количества подставляются нормы загрузки на поддон или в машину, и выбранная цена в указанном воличестве летит в корзину.
Выглядит так

переключил

На странице все это управляется скриптом, по количеству и нормам загрузки (они же шаг count) вопросов нет. А вот с ценой разрулиться не могу. Корзина со сниппетом PriceFormat признают только одну цену — price.
На странице есть еще скрытoe полe с name=price_id и div с id=showPrice, туда скриптом подставляются выбранные значения id цены и выбранной цены соответственно. По идее, именно их надо использовать для корзины. Но у меня не получается ни подменить, ни с препаре, помогите пожалуйста.

Еще варианты:
2. Есть товар, у которого одна цена — price2 за 1 м3, т.е. товар только с доставкой с машинами по норме их загрузки (как вторая цена в п.1). Шаг count равен количеству м3 в машине.
3. Есть товар, у котого одна цена — price за 1 шт, здесь шаг count=1, т.е. это обычный вариант.

Кроме страницы товара, он выводится в чанке для eFilter, но одной ценой — для п.1 и 3 — это price, для п.2 — price2, но count должен быть.

P.S. В SHk когда-то что-то подобное делал в плагине на событие OnSHKgetProductPrice.
Здесь круче, за последние месяцы много чего добавилось. В доках описаны серверные и клиентстсие события, одним местом чую, что мою проблему можно разрулить с помощью них. Но, увы, все еще в стадии освоения и просветления (как у йогов), не наступило.
Помогайте, плиз.

Спасибо.

P.S.2. За окно подтверждения автору отдельное спасибо!
avatar
Я во все не вникал, но чувствую, что вам надо дополнительно передавать в поле meta[price_type] самовывоз это или доставка. И по событию OnBeforeCartItemAdding это поле доставать ($params['item']['meta']['price_type']) и менять цену в зависимости от него.
Т.е. вы будете менять цену при добавлении товара, а не при выводе корзины.
avatar
Спасибо, буду думать.
avatar
Идею понял. Сделал скрытое поле
<input type="hidden" name="meta[price_id]" value="">

Здесь в value скриптом в зависимости от радио-переключателя подставляется значение 5 — для цены с самовывозом (хранится в price) или 3 — для цены с доставкой (price2). В консоле вижу, что нужное число скрипт подставляет.

Создал плагин

switch ($modx->event->name) {
    case 'OnBeforeCartItemAdding': {
	$price2 = $modx->getTemplateVarOutput(array("price2"), $params['item']['id']);
	$price = $price['price2'];
        if ($params['item']['meta']['price_id'] = 3) {
            $params['item']['price'] = $price;
        }
        break;
    }
}

Но он не видит сравнение, т.е. вне зависимости что в поле 3 или 5 в любом случае меняет цену с price на price2. Даже если не скриптом, а вручную прописать.
avatar
не =, а ==
avatar
Спасибо, уже сообразил))
avatar
Вот так получилось
switch ($modx->event->name) {
    case 'OnBeforeCartItemAdding': {
		$price = $modx->getTemplateVarOutput(array("price2"), $params['item']['id']);
		$price = $price['price2'];
        if ($params['item']['meta']['price_id'] == '3') {
            $params['item']['price'] = $price;
        }
        break;
    }
}
avatar
По хорошему еще бы getTemplateVarOutput переместить под условие, и проверять, есть ли вообще $params['item']['meta']['price_id'].
avatar
Это надо осмыслить… по поводу проверки, я уже дописал в value=6, чтобы не было пустым для других типов товаров, так что по умолчанию будет лететь price
avatar
Как добавить в корзину произвольный товар, у которого нет документа — просто строчка в таблице, например. Не всегда имеет смысл заводить отдельный документ, если нет наполнения. Если заводить строчку как опцию — как оно будет приходить в пиcьме?
avatar
Неактуально. Товар можно сделать один, а цену и название менять из multitv. Каждая строчка будет отдельной строкой в таблице.
gist.github.com/sashabeep/4b6c920a0910cded5c622d7c119be704
avatar
Пример плагина с двумя вариантами доставок — самовывоз и курьером. Доставка курьером бесплатная от какой-то суммы заказа. Необходимо было реализовать пересчет стоимости курьерской доставки в зависимости от суммы

$title = 'Доставка курьером';
$price = ci()->currency->convertToActive(100);

switch ($modx->Event->name) {
    case 'OnRegisterDelivery': {
        $params['rows']['fixed'] = [
            'title' => $title,
            'price' => $price,
        ];
		$params['rows']['sam'] = [
            'title' => "Самовывоз",
            'price' => ci()->currency->convertToActive(0),
        ];
        break;
    }

    case 'OnCollectSubtotals': {
		$processor = $modx->commerce->loadProcessor();
		if ($processor->getCurrentDelivery() == 'fixed' && intval($params['total']) < 350) {
			$params['total'] += $price;
			$params['rows']['fixed'] = [
				'title' => $title,
				'price' => $price,
			];
		}
        break;
    }
}
avatar
Всем привет. Кто может подсказать как вывести опции товара (которые через TV) в корзину и в сам заказ?
avatar
<input type="hidden" name="options[myoption]" value="">

– это написано в тексте топика.
Как их оформить в модуле есть выше в комментариях. В корзине и в письме просто строка.
Комментарий отредактирован 2020-04-13 10:18:46 пользователем alexbeep
avatar
Спасибо. Видимо нужно магазин переставить, так как все эти инпуты и строки есть.
avatar
А есть возможность перед добавлением товара в корзину — очищать ее? Хочу сделать что бы в корзине был только один товар при оформлении счета.
<a href="#" data-commerce-action="clean" data-commerce-action="add" data-id="[+id+]">заказать</a>

пробовал так, но так конечно же не работает.
Наверняка есть какой-то более правильный способ.
Комментарий отредактирован 2020-04-28 18:40:20 пользователем JoniDES
avatar
Нашел такое решение:
В файле /assets/plugins/commerce/src/Commerce.php
после строки 531:
case 'cart/add': {

добавил функцию
$cart->clean();

Что бы корзина очищалась перед добавлением товара. Возможно не самое лучшее решение, но работает.
avatar
Добрый день, подскажите как активировать плагины Delivery Fixed, Delivery Pickup, Discount example, Payment OnDelivery. Установил Сommerce через Extras, на вкладке плагины только один Commerce. В документации нашёл «Обратите внимание — часть плагинов отключена» а вот как их подключить не понятно, в разделе Плагины у меня нет отключенных плагинов, может как-то в ручную можно поставить?
avatar
avatar
Нету там информации про эти плагины Delivery Fixed, Delivery Pickup, Discount example, Payment OnDelivery
avatar
Эти плагины ранее входили в дистрибутив, теперь их там нет.
Качайте и ставьте отдельно, ссылки прямо в репозитории на гите частично, частично можно тут по примерам покопаться, с той же доставкой есть готовые вещи.
avatar
Спасибо за подсказку, качал тут ссылка но там тоже не нашёл, может не там ищу?
avatar
У нас давно в панели управления есть Extras. Да, это один и тот же дистрибутив, но лучше пользоваться нормальными способами установки.
Я не понимаю, что и как надо делать, чтобы не было плагинов. Вот они в дистрибутиве же.
avatar
Сложновато конечно, первый раз с этим компонентном работаю, но буду изучать доки, если кто подскажет по поводу доставки (как с ней работать, можно ли создавать варианты доставки в модуле или только в шаблонах).
avatar
Может кто сталкивался, не работает редактирование заказа, не могу добавить дополнительный товар в заказ, древо страниц открывается а вот раскрыть каталог через + не получается он не раскрывается. Пробовал в разных браузерах.
avatar
avatar
Спасибо, помогло!
avatar
Добрый день. Возник вопрос вывода TV-параметра товара в шаблоне письма. Пробовал [+tv.coll_price+] и в вызове корзины &tvList=`coll_price`. Пусто. Неужели какой-то хитрый способ вывода должен быть?
avatar
Здравствуйте.
никак не получается прикрутить «PayKeeper». Плагин Payment Paykeeper установлен, Payment url указан. Заполняю форму, выбираю форму оплаты, жму на кнопку «Оформить заказ» и вижу ошибку «Error: Call to undefined method Commerce\Payments\PaykeeperPayment::createPaymentRedirect()»
Скриншот
При этом в модуль заказ добавляется…
Пожалуйста, подскажите, куда копать? Что я упускаю?
  • CheD
  • 0
avatar
Извините, за этот лишний вопрос. Проблема была в старой версии Payment.php всего лишь. Жалко, что здесь нельзя удалять свои сообщения))
avatar
Здравствуйте!
подскажите как убрать в PriceFormat десятичные
менял в lang common.inc.php 'currency.decimals' => '0',
не помогло
avatar
Это в настройках валюты в модуле магазина. Нажмите кнопку Редактировать — там есть параметр «Число знаков после запятой», поставьте 0.
avatar
Всем добрый день. Продолжаю осваивать и чем могу — делюсь))
Появилось несколько вопросов, подскажите, пожалуйста:
1. В шаблоне order_reportback.tpl есть плейсхолдер [+extra+] — что в него должно выводиться? Как то не нашел, и не выводится ничего. В аналогичном шаблоне order_report.tpl такого плейсхолдера нет.

2. В указанных выше шаблонах разнятся плейсхолдеры оплаты и доставки [+delivery_method_title+] и [+payment_method_title+] в шаблоне order_report.tpl, [+order.fields.delivery_method_title+] и [+order.fields.payment_method_title+] в шаблоне order_reportback.tpl. Срабатывают оба варианта, а в чем разница?

3. Не хватает пустого шаблона для сниппета Order, как его можно сделать или может у кого есть решение? Смысл в том, что на сайте есть и страница Корзина, и страница Оформление заказа. На странице оформления заказа я сниппет Cart вызываю в чанке order_form для сниппета Order (так по дизайну — сначала форма, потом корзина, потом кнопка Отправить заказ). И получается. что если в корзине ничего нет, то страница Оформление заказа девственно чистая. На странице с корзиной — там все нормально, шаблон для пустой корзины есть и его можно стилизовать под дизайн сайта. Хотелось бы примерно так же и на странице Оформление заказа иметь шаблон пустого заказа.

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

4.а. Страница категории. В итоге в категориях сделал с помощью препаре LinkActiveDL от автора
$lists = $_extDocLister->getStore('commercelists');

if ($lists === null) {
    $carts = ci()->carts;
    $lists = [
        'products'   => $carts->getCart('products')->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;

И все бы хорошо, но при добавлении товара в корзину не происходит ничего, поэтому пришлось добавить скрипт
$(document).on('cart-add-complete.commerce', function(e, params) {
	if (params.response.status == 'success') {
        $('.btn-cart[data-id="' + params.data.id + '"]').addClass(' active');
    }
});

а в кнопку атрибут data, кнопка в форме теперь выглядит так
<button type="submit" class="btn-cart[+products_class+]" data-id="[+id+]"><span></span></button>

И все стало работать как надо — и сразу при добавлении, и при серфинге по сайту ничего не пропадает.
Надписи в кнопку меняются стилями
.btn-cart span::before {
    content: "Купить";
}
.btn-cart.active span::before {
    content: "В корзине";

}
Не знаю, плохо ли или хорошо, но вроде работает, покритикуйте ежели что или предложите свой другой вариант))

4.б. Страница товара. Здесь у меня пока не получается и прошу «помощь зала».
Уже известно, что на странице товара доступны плейсхолдеры [+products_active+], [+products_contains+], [+products_count+]. Но при аяксе они не срабатывают (здесь можно тот же скрипт, что в 4а), а если страница кэшируемая (а она кэшируема), то все-равно глухо — индикация слетает. А плагин на OnWebPageInit, как ранее советовал kassio, из варианта препаре для DL, у меня не получился.

Подскажите как сделать переключатель кнопки В корзину/Товар в корзине на странице товара? Может у кого уже есть рабочий вариант.

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

$products = ci()->carts->getCart('products')->getItems();
$ids = array_flip(array_column($products, 'id'));
    
if (isset($ids[$modx->documentIdentifier])) {
    return 'active';
}
avatar
ага, понял, спасибо.
avatar
Можно еще проще, кстати:
if (ci()->carts->getCart('products')->has($modx->documentIdentifier)) {
    return 'active';
}
avatar
спасибо, попробую и так
avatar
Так тоже работает.
Сделал через плагин и плейсхолдер для единообразия
switch ($modx->Event->name) {
    case 'OnWebPageInit': {
		if (ci()->carts->getCart('products')->has($modx->documentIdentifier)) {
			$modx->setPlaceholder('products_class','active');
		}
	}
	break;	
}

Планин в списке вызовов поставил последним.
Остальное как п. 4а (скрипт и кнопка + стили). В общем, красота, спасибо за компонент и за помощь в освоении.
avatar
avatar
Спасибо.
Гит требует авторизоваться, пошел искать свои доступы
avatar
Да не обязательно, я понял задачу
avatar
Спасибо.
avatar
Подскажите может кто сталкивался с похожей задачей, есть категория А с товарами, и категория Б с доп. товарами. Необходимо изменять цену для товаров категории Б (параметр tv c price на price2) при одновременной покупке товаров из Б вместе с товаром из А.
avatar
Шикарный компонент, но столкнулся с проблемой commerce-options.
Чистая установка и не появляется «Атрибуты опций» у «магазина» и у плагина нет ни каких настроек в конфигурации. А как я понимаю должно быть вот так примерно
Кто-то сталкивался? Очень хочется разобраться, Спасибо.
avatar
Вроде опции новые через TV-параметр делаются уже
avatar
Странно, что ни где про это не нашёл.
Создал TV «test» с типом commerce_options в товаре появилась вкладка «опции товара», но пустота… prntscr.com/v81l0r
avatar
Надо в твшке заполнить возможные значения, затем в товаре выбрать нужные.
avatar
Спасибо. Моя невнимательность. Точнее и не думал, что у ТВшки есть «значение параметра». Разобрался. Только один момент — использую templateedit3 и получается у меня есть и ТВ параметр с выбором опций в товаре и вкладка «Опции товара». При том в разных вариантах вывода так непосредственно ТВ и так во кладке «Опции товара». Хотелось бы возможность выбирать/настраивать варианты отображения в админке товара.
avatar
Да, с te3 пока не дружит
avatar
Здравствуйте, компонент отличный, большое спасибо! Из коробки заработал это очень хорошо, но исчерпывающей документации не хватает.

Обнаружил проблему — в модуле при просмотре заказа с несколькими товарами у меня отображает только один товар, при этом в таблице commerce_order_products они все есть. Нашел что здесь в SimpleCart.php при заполнении массива товаров, uniqid() возможно не успевает создать уникальные идентификаторы. Не знаю как на хостинге, а у меня на локальном openServer видимо пролетает за микросекунду и они все одинаковые. Особо тут не соображаю, поэтому костыль сделал такой:
///$row = uniqid();
$row++;

пока работает, может кому пригодится до официального исправления.
Спасибо!
  • Red
  • +1
avatar
Попробуйте заменить на это
$row = ci()->commerce->generateRandomString(16);
avatar
Спасибо, тоже работает )
avatar
Добрий вечір. Таке питання. Я не знайшов по документації приклада вивода чанка в сніпетті Order — чанк reportTpl. Я знайшов як виводить FormLister типу:
<code><p>Имя: [+name.value+]</p>
<p>Телефон: [+phone.value+]</p>
<p>Email: <a href="mailto:[+email.value+]">[+email.value+]</a></p>
<p>Вариант оплаты: [+payments.value+]</p>
<p>Вариант доставки: [+delivery.value+]</p>
<p>Сообщение: [+message:strip_tags:nl2br+]</p></code>
********
Але питання в іншому, не має хіба плейсхолдера, як в Shopkeeper:
<code><p>В интернет-магазине сделан заказ.</p>

<p>Номер заказа: [+orderID+]</p>

<b>Состав заказа:</b>

[+orderData+]</code>

Чи потрібно писати сніппет окремо?
Комментарий отредактирован 2020-12-06 16:20:27 пользователем hreshnik
avatar
Этот чанк в папке lang, и да — в нем такого плейсхолдера нет, хотя лично я неудобств из-за этого не замечал.
avatar
такого чанку не існує в папках Commerce. Так відразу вивести клієнту список товарів в запомленні і номер запомлення, яке падає на емейл пошту. Це було зручно. А так доведеттся писати сніпет. Просто навіть номер замовлення не виводить, урізаний якийсь він=)
avatar
існує, только вижу, что переехал в другое место
github.com/mnoskov/commerce/blob/master/assets/plugins/commerce/templates/front/russian-UTF8/order_report.tpl
avatar
дякую
avatar
На гитхабе был пример как сделать всплывающее модальное окно при добавлении в корзину. Ну иногда окно — это слишком круто, иногда нужно только уведомление, которое само исчезает, в бутстрапе называется toast
Подключаем бутстрап, из css можно только такой код
.toast {
  -ms-flex-preferred-size: 350px;
  flex-basis: 350px;
  max-width: 350px;
  font-size: 0.875rem;
  background-color: rgba(255, 255, 255, 0.95);
  background-clip: padding-box;
  border: 1px solid rgba(0, 0, 0, 0.1);
  box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.1);
  opacity: 0;
  border-radius: 0.25rem;
position: fixed;
top:20px;
right:20px;
}

.toast:not(:last-child) {
  margin-bottom: 0.75rem;
}

.toast.showing {
  opacity: 1;
}

.toast.show {
  display: block;
  opacity: 1;
}

.toast.hide {
  display: none;
}

.toast-header {
  display: -ms-flexbox;
  display: flex;
  -ms-flex-align: center;
  align-items: center;
  padding: 0.25rem 0.75rem;
  color: #6c757d;
  background-color: rgba(255, 255, 255, 0.85);
  background-clip: padding-box;
  border-bottom: 1px solid rgba(0, 0, 0, 0.05);
  border-top-left-radius: calc(0.25rem - 1px);
  border-top-right-radius: calc(0.25rem - 1px);
}

.toast-body {
  padding: 0.75rem;
}
button.ml-2.mb-1.close {
    border: none;
    background: none;
}


js


<script>
$(document).on('cart-add-complete.commerce', function(e, params) {
     $("#tost").toast('show');
	
});
</script>
Код самого уведомления

<code><div class="toast" id="tost"  role="alert" aria-live="polite" aria-atomic="true" data-delay="3000">
    <div class="toast-header">
        <strong class="mr-auto"><i class="fa fa-grav"></i> Товар добавлен в корзину!</strong>
        <button type="button" class="ml-2 mb-1 close" data-dismiss="toast">×</button>
    </div>
    <div class="toast-body">
		Вы можете продолжить покупки или <a href="[~26~]">оформить заказ</a>
    </div>
</div>
Комментарий отредактирован 2020-12-18 20:23:38 пользователем argalkin
avatar
code в начале не надо
Комментарий отредактирован 2020-12-18 20:25:27 пользователем argalkin
avatar
Еще такой момент, если для избранного нужно другое уведомление, с другим текстом, то тогда пишем такой код:
<script>
$(document).on('cart-add.commerce', function(e, params) {
    if (params.cart.instance == 'products') {
          $("#tost").toast('show');
  } else {    
   $("#tost2").toast('show');
  }
});
</script>


#tost — id окна для товаров
#tost2 — id для избранного

Также можно сделать для сравнения
avatar
По идее instance для избранного должно быть wishlist, для сравнения comparison, тогда и без if?
avatar
так в примере было, в документации, именно c if
avatar
имелось ввиду if/else

В частном случае можно, конечно, и так, но к избранному ваш скрипт отношения строго говоря не имеет — он с таким же успехом сработает и для сравнения. А если будет и избранное, и сравнение? Имхо, надо проверять каждый instance.
Или через switch — выше kassio пример приводил.
avatar
Согласен, можно так:
<script>
$(document).on('cart-add.commerce', function(e, params) {
    if (params.cart.instance == 'products') {
          $("#tost").toast('show');
  }
if (params.cart.instance == 'wishlist') {
          $("#tost2").toast('show');
  }
if (params.cart.instance == 'comparison') {
          $("#tost3").toast('show');
  }
 
});
</script>
avatar
Такой вопрос, вот есть разметка товара

<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="Белый">
   ---
    <button type="submit">Add to cart</button>
</form>

Могу ли я через новый input закинуть в корзину какое-нибудь значение?
Например:
<input type="hidden" name="MYname" value="MYvalue">

И выводить потом в корзине [+MYvalue+]
Просто name=«options[]» не подходит, тут нужно одиночное значение, которого не будет в TV, я туда его через JS закину например.
avatar
Совершенно не обязательно хранить параметр в TV
Добавьте
<input type="hidden" name="options[myoption]" value="something">
avatar
Но в таком случае все доп опции выводит списком по шаблону
<span data-key="[+key+]">[+option+]</span>

Я же так не выведу потом в корзине [+option.myoption+]
avatar
На днях для одного проекта проггер с чата по Evo *Bilbo Baggins* сделал плагин, который добавляет опцию в корзину для каждого товара, а также в карточку товара. Опция добавляет стоимость в subtotals.
Итак для этого надо:
В чанке шаблона DocLister добавить
<input type="checkbox" name="options[sborka]" value="Нужна сборка"> Нужна сборка


В шаблон строчки корзины cart_row.tpl добавить
<input type="checkbox" data-sborka="[+row+]" [!helpers?&action=`checkSborka`&rowid=`[+row+]`!]> Нужна сборка


Для вывода суммы за доп.опции пишем в шаблоне корзины [+subtotals+]

Сниппет helpers (Проверяет выбрана ли опция и отмечает галочку)
<?php
if(!isset($action) || empty($action)) return '';

switch($action) {

		
	case 'checkSborka':
		$cart = ci()->carts->getCart('products');
		$items = $cart->getItems();
		if(isset($rowid) && isset($items[$rowid]['options']['sborka'])) {
			return 'checked';
		}
		if(isset($docid)) {
			foreach($items as $hash=>$item) {
				if($item['id']==$docid && isset($item['options']['sborka'])) {
					return 'checked';
				}
			}
		}
		break;
		
	default:
		break;
}


Плагин доп.опции, выставляем событие OnCollectSubtotals и OnPageNotFound
switch ($modx->event->name) {
	case 'OnPageNotFound': {
		switch($_GET['q']){     
			case 'cartSborka':	
				$doc_hash = $_POST['doc_hash'];
				$sborka = $_POST['sborka'];	

				$cart = ci()->carts->getCart('products');
				$items = $cart->getItems();
				if($sborka>0) {
					$items[$doc_hash]['options']['sborka'] = '1';
				} else {
					unset($items[$doc_hash]['options']['sborka']);
				}

				$cart->setItems($items);
				echo json_encode(['status'=>'ok']);
				die();
				break;
		}
	}
	case 'OnCollectSubtotals': {
		$cart = ci()->carts->getCart('products');
		$items = $cart->getItems();

		$sborkaTotal = 0;
		foreach($items as $hash=>$item) {
			if(isset($item['options']['sborka'])) {

				$sborkaTotal = $sborkaTotal + (500*$item['count']);
				$params['rows']['sborka'] = [
					'title' => 'Сборка',
					'price' => $sborkaTotal,
				];

			}
		}
		$params['total'] += $sborkaTotal;
	}
}


и сам js скрипт для срабатывания плагина и чекбокса:
$(document).on('change', '[data-sborka]', function() {
        var doc_hash = $(this).data('sborka');
        if($(this).is(':checked')) {
            var value = 1;
        } else {
            var value = 0;
        }

        $.ajax({
            url: '/cartSborka',
            type: 'post',
            dataType: 'json',
            data: {doc_hash: doc_hash, sborka: value},
        })
        .done(function(res) {
            if(res.status && res.status=='ok') {
                Commerce.reloadCarts();
            }
        });
        
    });  

Все!
avatar
Где можно глянуть результат работы?
avatar
Разобрался как в input подставлять одиночное значение например:
<input type="hidden" name="options[img]" value="img/img_1.jpg">

Нужно в вызове корзины добавить &defaultOptionsRender=`0`
и тогда в шаблоне можно вызвать [+options.img+]
А если &defaultOptionsRender=`1` — тогда так [+_options.img+]
Комментарий отредактирован 2021-01-19 19:52:36 пользователем Galaydas
avatar
Здравствуйте.
Не соображу как сделать, чтобы если пользователь, после того как он нажал «Оформить заказ» и его перекинуло на страницу оплаты товара, то корзина не очищалась?
А то, если нажать «Отказаться от оплаты» то, вернувшись в магазин, он увидит пустую корзину, а письмо с «подтверждением заказа» уже придёт.
То есть, чтобы корзина очищалась и письмо с подтверждением отправлялось, только после успешной оплаты.
Комментарий отредактирован 2021-01-21 11:43:15 пользователем CheD
  • CheD
  • 0
avatar
Здравствуйте!
После нажатия на «Оформить заказ» — он создаётся для клиента и попадает в БД, поэтому логично, что корзина очищается, т.к. заказ уже есть у клиента и его надо только оплатить.

Если хотите реализовать нестандартную логику, то можно написать плагин, например, на событие «OnBeforeOrderProcessing». Оно вызывается после валидации данных заказа, до создания самого заказа и позволяет модифицировать как данные покупателя, так и состав корзины заказа. Подробнее тут: docs.evo.im/04_extras/commerce/10_servernye_sobytiya.html

Либо можете попробовать на стороне клиента для js-события cart-clean сделать return false, но тогда даже после успешной оплаты корзина очищаться не будет.
avatar
Спасибо за развернутый ответ.
Хотя я бы не вполне согласился насчёт полной логичности. Возможен же вариант, что пользователь уже перешел на страницу платёжной системы, потом вспомнил, что забыл что-то, вернулся, а корзины его уже нет. И корзину по новой собирать ( а если там много позиций?) и платёж не совершил.
Вполне возможная ситуация мне кажется.
avatar
Здравствуйте. А подскажите, пожалуйста, как можно считать остатки товара. У меня есть тв-параметр, в котором храниться кол-во товара на складе. Но я никак не могу сообразить, как уменьшать его после оплаты заказа. На какое именно событие повесить плагин, и как оттуда вытащить id оплаченного товара?
avatar
Либо после оформления заказа — OnOrderProcessed, либо при изменении статуса заказа (например, если при отгрузке менеджер меняет статус на «Отправлен») — OnBeforeOrderHistoryUpdate. Все события здесь — docs.evo.im/04_extras/commerce/10_servernye_sobytiya.html
avatar
Пусть и не после оплаты, а всего лишь после сохранения заказа в базу данных (OnOrderSaved), у меня получилось изменять количество оставшегося товара.
Но вот как при увеличении/уменьшении количества товара в корзине менять размер остатка этого товара, и при удалении товара из корзины возвращать его к первоначальной величине — это так и осталось для меня загадкой.
Комментарий отредактирован 2021-02-11 13:58:13 пользователем Sagrana
avatar
Подскажите пожалуйста, почему в файле pdf (счет для клиента) нет изображения печати или подписи, хотя они прописаны в шаблоне.
Плагин «commerce-payment-bill»
Выводится вот такое вместо картинок, скрин.
Комментарий отредактирован 2021-02-18 08:18:08 пользователем nt90
  • nt90
  • 0
avatar
Можно попробовать убрать начальные слэши у изображений
avatar
не помогает, пробовал разные варианты:
— ./*
site.ru/*
— /*
avatar
теперь работает, скачал с гитхаба обновление, спасибо за оперативность )
Комментарий отредактирован 2021-02-20 13:04:02 пользователем nt90
avatar
С чем может быть связано что не работает смена статуса у заказа, если для статуса выставлена отметка об уведомлении на почту?
Ошибка «Ошибка при изменении статуса!»
Если галочку убрать в статусе «Уведомить покупателя о смене статуса заказа» то ошибки не возникает.
  • nt90
  • 0
avatar
А вообще отправка почты с сайта работает? Email в заказе правильный?
avatar
Да. Ставил простой скрипт отправки писем через mail, уходят, из консоли отсылал письма тоже работает. Дело в commerce но не понятно в чем, лога ошибок нет, не в самом модуле если включить все ошибки не в /var/log/apache2 & nginx & mysql
avatar
php 7.4, 7.3, 7.2, 7.1 не отправляется везде
avatar
А письма с заказом отправляются? Или если простые формы делать, используя formlister?
avatar
Да, отправляются письма с заказами. Formlister работает.
Комментарий отредактирован 2021-02-20 05:45:08 пользователем nt90
avatar
так и не работает, ошибка осталась, проверял на 3 разных серверах
avatar
Здравствуйте. Подскажите как лучше поступит в следующей ситуации. Есть раздел каталога с USB флэшками. У каждой флэшки есть своя базовая цена за 32Гб. На странице изделия можно выбрать версию с большей емкостью за отдельную доплату. Стоимость опции прибавляется к базовой цене — {32Gb==0руб||64Gb==200руб||128Gb==600руб}. Все флэшки в разделе имеют одинаковое соотношение емкость-доплата.

Дополнение commerce-options позволяет решить эту задачу, но есть такие моменты:
1) не смотря на то, что соотношение емкость-доплата у всех флэшек одинаковое, но для каждого товара нужно зайти на вкладку «ОПЦИИ ТОВАРА» и нажать «Добавить все значения».
2) В случае если наценка для флэшки на 128Gb изменилась, то недостаточно только изменить цену для опции в соответствующем TV, нужно еще пройтись по всем изделиям очистить старые опции и загрузить новые. Когда таких изделий за 50шт, то это будет напрягать.
3) Аналогично п.2 если, например, добавилась новая опция на 256Гб.

Может быть есть возможность автоматически подгружать данные в «Опции товара» на странице изделия из TV и автоматически их обновлять в случае изменения в TV?
avatar
Нет, такой возможности нет. Врядли это можно реализовать в каком-то универсальном виде, но в вашем случае это можно решить плагином на сохранение тв. В плагине брать значения из тв, раскидывать по товарам.
avatar
Спасибо!
avatar
Немного обновил документацию, добавил информацию по работе со страницей «Спасибо», и несколько других примеров. docs.evo.im/04_extras/commerce.html
avatar
Спасибо!
avatar
Спасибо!
avatar
Добрый день! В магазине есть доставка, доступная от определенной суммы в корзине. Для меньшей суммы она не должна отображаться. Пытаюсь сделать это плагином
switch ($modx->event->name) {
    case 'OnBeforeOrderAddonsRender': {
		if ($params['total'] < 300) {
        // если сумма заказа меньше 300, убираем способ доставки xfixed
        unset($params['delivery']['xfixed']);
    }

    break;
    }
}

Не могу понять как получить $params['total']. Подскажите, пожалуйста, куда копать. Спасибо
avatar
Здравствуйте!
Скажите пожалуйста — тестовый магазин есть? можно ли просить, может у кого есть сборка, чтобы можно было установить и посмотреть как внутри все устроено.
Спасибо!
  • tmih
  • 0
avatar
что то не пойму — может ему нужен JQuery?
я поставил на нулёвый модкс и запустил в шаблоне minimal_template
[!Order
    &formTpl=`formTpl`
    &deliveryTpl=`deliveryTpl`
    &deliveryRowTpl=`deliveryRowTpl`
    &paymentsTpl=`paymentsTpl`
    &paymentsRowTpl=`paymentsRowTpl`
    &reportTpl=`reportTpl`
    &ccSenderTpl=``
!]

чанки есть — а вывод пусто…
avatar
ver. 1.4.15
avatar
первый вопрос понял — надо добавить структуру HTML
сейчас ловил баг — в письме не переданы данные, код чанка
<table style="border-collapse: collapse;">
    <tr>
        <td style="border: 1px solid #ddd; padding: 5px 10px; background: #f6f6f6;">[%cart.item_title%]</td>
        <td style="border: 1px solid #ddd; padding: 5px 10px; background: #f6f6f6; text-align: center;">[%cart.count%]</td>
        <td style="border: 1px solid #ddd; padding: 5px 10px; background: #f6f6f6; text-align: right;">[%cart.item_price%]</td>
        <td style="border: 1px solid #ddd; padding: 5px 10px; background: #f6f6f6; text-align: right;">[%cart.item_summary%]</td>
    </tr>

    [+dl.wrap+]

    [+subtotals+]

    <tr>
        <td style="border: 1px solid #ddd; padding: 5px 10px;" colspan="3">[%cart.total%]:</td>
        <td style="border: 1px solid #ddd; padding: 5px 10px; text-align: right; white-space: nowrap;">[[PriceFormat? &price=`[+total+]` &convert=`0`]]</td>
    </tr>
</table>

скрин
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.