evoShop - первая альфа.

Понимаю что всем хочеться уже пощупать но пока еще довожу до ума.
Но уже можно использовать на фронте с мелкими оговорками.

И так как же потестить уже у себя?:

1. Идем сюда: evoshop.pro

— тут у нас есть линк на github где можно скачать код а так же есть раздел документации по скрипту js, сразу замечу что логика работы немного выпадает от привычной в MODX так как вся корзина работает на js + localStorage, это дает свои плюсы но есть и пару минусов к примеру вся логика работы построенна на js тоесть чанков с шаблонами у нас нет. (Есть вариант сделать проброс чанков с параметров сниппета в js но особого смысла в этом не вижу)

2. Заливаем нужный нам файлик js сюда:



/assets/snippets/evoshop/js/evoShop.min.js

Хотя можно и в любое удобное для вас место.
И подключаем js, получиться должно как то так:

<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script type="text/javascript" src="/assets/snippets/evoshop/js/evoShop.min.js"></script>


Я делаю вот так:

тоесть у меня есть сниппет evoShop с содержимым:

<?php
//подключение библиотеки js
$modx->regClientScript('/assets/snippets/evoshop/js/evoShop.min.js');
$settings = '<script type="text/javascript">
	evoShop({
		currency: "RUB",
	});
	//скрываем корзину если там пусто
	evoShop.bind("update", function(){
	  if( evoShop.quantity() === 0 ){
		$(".evoShop_cart").hide();
	  } else {
		$(".evoShop_cart").show();
	  }
	});
	//добавляем товары в корзину из локалстораже
	$(document).on("click",".evoShop_submit",function(ev){
		$(".evoShop_items_json").val( localStorage.getItem("evoShop_items").replace("}}","} }") );   
		//evoShop.empty();
	});
	
	//товар добавлен в карзину
	$(document).on("click",".item_add",function(ev){
		$(\'<span class="item_informer alert alert-success">товар добавлен в корзину</span>\').insertAfter($(this)).delay(800).fadeOut(800);
	});
	
</script>'; 
$modx->regClientScript($settings, true);

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

Собственно на этом все подключение evoShop к фрону сайта закончено.
Переходим к Бекенду.


3. Передача товаров в FormLister, отправка на почту а так же запись в базу.



Создаем вот такой вызов сниппета FormLister:

[!FormLister?
						&debug=`1`
						&formid=`orderForm`
						&to=`dmi3yy@gmail.com`
						&replyTo=`[+email.value+]`
						&prepareProcess=`evoShopFormLister`
						&protectSubmit=`0`
						&submitLimit=`0`
						&ccSender=`1`
						&subject=`Новый заказ с сайта evoShop demo`
						&errorClass=` has-error`
						&requiredClass=` has-warning`
						&rules=`{
							"name":{
								"required":"Обязательно введите имя"
							},
							"email":{
								"required":"Обязательно введите email",
								"email":"Введите email правильно"
							},
							"phone":{
								"required":"Обязательно введите номер телефона",
								"phone":"Введите номер правильно"
							}
						}`
						&formTpl=`@CODE:
							<h3>Оформление заказа:</h3>
							<form method='POST'>
								<input type="hidden" name="formid" value="orderForm">
								<input type="hidden" name="evoShop_items_json" class="evoShop_items_json" value="[+evoShop_items_json+]"/>
								<div class="form-group[+name.errorClass+][+name.requiredClass+]">
									<label for="name">Ваше имя</label>
									<input type="text" class="form-control" name="name" id="name" value="[+name.value+]">
									<div class="form-control-feedback">[+name.error+]</div>
								</div>
								<div class="form-group[+email.errorClass+][+email.requiredClass+]">
									<label for="email">Ваш email</label>
									<input type="text" class="form-control" name="email" id="email" value="[+email.value+]">
									<div class="form-control-feedback">[+email.error+]</div>
								</div>
								<div class="form-group[+phone.errorClass+][+phone.requiredClass+]">
									<label for="phone">Телефон</label>
									<input type="text" class="form-control" name="phone" id="phone" value="[+phone.value+]">
									<div class="form-control-feedback">[+phone.error+]</div>
								</div>
								<div class="form-group">
									<label for="message">Кмментарий к заказу</label>
									<textarea class="form-control" name="message" id="message" rows="3">[+message.value+]</textarea>
								</div>
								<button type="submit" class="btn btn-primary evoShop_submit">Оформить заказ</button>
							</form>			
						`
						&messagesOuterTpl=`@CODE: [+messages+]`
						&errorTpl=`@CODE: [+message+]`
						&successTpl=`@CODE: 
							<div class="alert alert-success mt-3">
								<h3>Спасибо за ваш заказ!</h3>
								<p>Наш менеджер свяжеться с вами в ближайшее время.</p>
							</div>`
						&reportTpl=`@CODE:
							<p>Имя: [+name.value+]</p>
							<p>Email: [+email.value+]</p>
							<p>Телефон: [+phone.value+]</p>
							<p>Комментарий к заказу: [+message.value+]</p>
							[+evoShop_items+]	
						`
						&ccSenderTpl=`@CODE:
							Вы оформили заказ на сайте:
							<p>Имя: [+name.value+]</p>
							<p>Email: [+email.value+]</p>
							<p>Телефон: [+phone.value+]</p>
							<p>Комментарий к заказу: [+message.value+]</p>
							[+evoShop_items+]
						`
						!]  


И добавляем вот такой сниппет evoShopFormLister:

<?php
if ($FormLister->getField('evoShop_items_json') != '') {
		$itemsArr = json_decode( $FormLister->getField('evoShop_items_json') , true);
		if (is_array($itemsArr)){
			//Подготовка к выводу в почте
			$total = '0';
			$evoShopItems = '
<h3>Состав заказа: </h3><ul>';
			foreach($itemsArr as $k => $v){
				$evoShopItems .='<li><b>'.$v['name'].'</b>    '.$v['size'].'   x'.$v['quantity'].' шт,   <b>'.$v['price'].'</b> руб</li>';
				$total = $total + ($v['quantity']*$v['price']);
			}
			$evoShopItems .= '</ul>
<h4>Сумма заказа: <b>'.$total.'</b> руб</h4>';
			//Запись в базу данных
			$short_txt = $data;
			unset($short_txt['evoShop_items_json']);
			$neworder = array('short_txt'  => json_encode($short_txt, JSON_UNESCAPED_UNICODE), 
							'content' => $FormLister->getField('evoShop_items_json'), 
							'price' => $total,  
							'currency'  => 'руб',
							'date'  => date('Y-m-d H:i:s'),
							'sentdate'  => date('Y-m-d H:i:s'),
							'note'  => $FormLister->getField('note'),
							'email'  => $FormLister->getField('email'),
							'phone'  => $FormLister->getField('phone'),
							'payment'  => $FormLister->getField('payment'),
							'delivery'  => $FormLister->getField('delivery'),
							'discount'  => $FormLister->getField('discount'),

							'status'  => '1',
							'userid'  => $_SESSION['webInternalKey'],
							'managerid'  => '',
							'1c_exchange'  => '',
							
							);   
			$orderId = $modx->db->insert( $neworder, $modx->getFullTableName( 'evoshop_orders' ) ); 
			$modx->db->insert(
			  array(
				'timestamp'     => time(),
				'managerid'     => '',
				'action'        => '1',
				'orderid'       => $orderId,
				'message'       => 'Поступил новый заказ',
				), $modx->getFullTableName('evoshop_log')
			  );
			
		}
		$FormLister->setField('evoShop_items', $evoShopItems );	
		$modx->regClientScript('<script>evoShop.empty();</script>', true);
	}


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

CREATE TABLE `modx_evoshop_orders` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `short_txt` text NOT NULL,
  `content` text,
  `price` varchar(255) NOT NULL,
  `currency` varchar(255) NOT NULL,
  `date` datetime DEFAULT NULL,
  `sentdate` datetime DEFAULT NULL,
  `note` text NOT NULL,
  `email` varchar(255) NOT NULL,
  `phone` varchar(255) NOT NULL,
  `payment` varchar(128) NOT NULL,
  `delivery` text,
  `discount` text,
  `tracking_num` varchar(32) DEFAULT NULL,
  `status` int(11) NOT NULL,
  `userid` int(11) NOT NULL,
  `managerid` int(11) NOT NULL,
  `1c_exchange` int(10) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;


На этом все! :), мы получили на фронте:
— Корзину, страничку оформление заказа
— Отправку писем админу и клиенту
— Запись в базу заказов

p.s. В препаре надо еще добавить проверку правильности цен на товары ибо сейчас такой проверки нет соответственно никто не мешает в браузере поправить цену и отправить ее в заказ. Но в дальнейшем это допишу :)

p.s.s. Для работы с доставками и скидками так же все готово + уже адаптировал evoSale для evoShop. По хорошему еще чутка довылизываю js и переключусь на модуль. Как закончу базово с модулем будет релиз с автоинсталом, примерами и видео :)

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

avatar
Я пока не успел потестировать ЭвоШоп, но вот за эти стихи твёрдое «5» :)
eCommerce solution for MODX Evolution
avatar
Поздравляю с мощной проделанной работой по переименованию simplecart в evoshop. Это серьезнейшая веха в развитии Modx Evo.
avatar
Чего ж вы раньше этого не сделали? :) Ну и переименовал и допилил так как нужно.
Бекенд так же будет на базе webix.com так что б минимум кода. Суть то не в количестве кода а в правильной работе:)
avatar
Чего ж вы раньше этого не сделали?

Собирал магазины с этой либой, даже допиливал кое-чего для совместимости с modx. Есть у нее подводные камни, но в целом для ево очень подходит.

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

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

1) В issues simplecart есть упоминание проблем с яблочными устройствами и какой-то костыль по лечению. В код либы этот костыль не был включен, но мне на одном из проектов пришлось его подставлять. Проблема в том, что косяк вылазит не на всех сайтах и не всегда, мне хватило чтобы сдать проект.

2) Очень неудобная передача параметров заказа на бекенд — в нее по-человечески влезть почти невозможно, чтобы добавить email/phone покупателя из формы заказа. Может быть вы это пофиксили уже, но проблема была.

3) Крайне редко, но корзина умудрялась переполнять localStorage. Не лечил, но на будущее пометку себе сделал

4) Неудобно передавать настройки из modx в настройки корзины. Решаемо, но 100% красивого способа я для себя не нашел

5) Открываем корзину в нескольких вкладках и получаем неактуальную информацию если делать заказы «по очереди» в разных вкладках. Не смертельно, но я подстраховывался лишним .update при добавлении в корзину

6)Вы упомянули проблему, я могу повторить — обязательная валидация данных на сервере после оформления заказа. Сам по себе пересчет неложен, но я не довел до ума идею, чтобы управлять всем этим из одного места (просто поленился, правил код в js и php отдельно)

Наверняка это не все, но это то, что накипело и запомнилось
avatar
1 я пофиксил

2 данные передаем через FormLister в него тянем с локалстораж только items + еще допишу скидку и доставку. Остальное передаем средствами FormLister потому проблемы нет

3 это общая проблема LocalStorage можно словить просто, к примеру codemirror все туда пишет поэтому если долго править 1 сайт то будет бяка а так создать заказ на 5mb сложно что б переполнить буфер

4 допилил вот так
evoshop.pro/documentation/quick-start-guide/cart-columns.html

cartColumns	: [
	{ attr: "rowTpl", label: false, view:'rowTpl'},
],
//template for cart view
rowTpl : "%name% %size% %color% %price% %test% %quantity% %summ%" + "-" + "+",

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

5 Дописали в код на добавить удалить и изменить количество еще и update? или после просто через событие?

6 это в целом уже касается бекенда но делать надо обязательно что б не было неожиданностей
avatar
5)

simpleCart.bind('beforeAdd', function(item){
        // синхронизация с другими окнами браузера
        simpleCart.load(); 
    }); 
avatar
логично зашить в ядро сразу. Надо будет проверить еще по части изменения количества в разных в кладках :)
avatar
Я уже давно этим занимался, могу ошибаться. Но да, имеет смысл этот пересчет зашить сразу в либу. Я бы там еще пару вещей поменял в плане вызова событий, а то они при некоторых условиях начинают сами себя по кругу вызывать; но сейчас уже не помню, что именно там неудобно было конкретно для моих задач.

Еще одну вещь вспомнил, которую не смог побороть напрямую: мультивалютность. Не скажу, что это базовый функционал для любого ИМ, но один раз пришлось помучаться.

Сразу могу посоветовать: организуйте курсы по обучению =) SimpleCart удобен для Ево, но он очень «не MODX» по сути. На меня стиль его написания оказал большое влияние в свое время.
avatar
по части мультивалютности хороший вопрос есть над чем подумать.

Я запилю видеоуроки + буду писать примеры что и как делать в целом там все очень просто но тем кто знает только modx будет чутка не привычно
avatar
Может быть, это и хорошо.
«А не засиделись ли хлопцы в конях?..» (Copyright)
avatar
Неа удалять нельзя.
1 Некрасиво
2 Они то сделали все это
3 Лицензия :)
avatar
там все очень просто но тем кто знает только modx будет чутка не привычно
Вот об этом я говорил. Что может и хорошо, что непривычно. Двигаться вперёд можно только преодолевая привычное.
DocLister тоже очень непривычен был сначала.
avatar
Еще одну вещь вспомнил неудобную.

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

Иными словами: иногда хочешь-не хочешь, но надо обеспечить работу localStorage с сервером напрямую, без вмешательства формы и юзера. Аякс (или как сейчас модно его называть — fetch) с simplecart дружит очень плохо. Все выливается в отдельное программирование под конкретную задачу на js.
avatar
По части скидок я уже склонировал функционал шипинга только со знаком — поэтому не вижу проблем если залогинен то выводим js с добавлением скидки и все тоесть тут танцев не будет
avatar
Речь не о скидках как таковых, а о пересчете уже заполненной корзины «на лету». SC хранит данные без скидок, надо их отправлять на сервер, там выдергивать id товаров и пересчитывать, потом возвращать в localStorage уже пересчитанную корзину. Либо писать все это на js. Либо сбрасывать корзину при авторизации, что несколько цинично по отношению к пользователю.
avatar
Яж говорю сдублировал логику shiping в discount
Теперь не нужно ничего сбрасывать и все нормально будет при авторизации ;)
avatar
Скидка не обязательно будет одинаковой для всех. И цена может отличаться для разных пользователей или групп.

В любом случае, это только пример задачи, которая требует обмена данными с сервером. SC и асинхронные действия очень плохо совместимы.
avatar
@nyfalvacqqlj:

Собирал магазины с этой либой, даже допиливал кое-чего для совместимости с modx.
А когда вы собирали магазины с этой либой, вы упоминали автора SC?
Комментарий отредактирован 2017-05-18 04:41:14 пользователем Harand
avatar
Надеюсь, придумывая эту колкость, вы смогли выкроить хотя бы часик на сон.
avatar
А в чём колкость?
Ну да ладно, потом вы от обвинений перешли к полезному общению. Это радует.
avatar
Смотрю даже специально зарегестрировались что б это написать :) Замечу что я не скрываю откуда взял код и давно уже говорил что так оно и будет )
avatar
Смотрю даже специально зарегестрировались что б это написать :)

Да чето не могу вспомнить креды для входа.

Замечу что я не скрываю откуда взял код

Но и не упоминаете.
avatar
А это по вашему что?


или вот это:


Помойму все логично все понятно ничего не скрыто.
А так посмотрите комиты за последний месяц поймете что там допилено уже довольно много. Но да база именно simplecartjs ибо зачем наступать на грабли и писать с нуля то что уже хорошо работает. В целом чего не хватало я допилил.
Комментарий отредактирован 2017-05-17 19:55:32 пользователем Dmi3yy
avatar
Задел на будущее, из того, что потом можно доработать в simplecart
1) отрисовка кастомных шаблонов корзины. Не всегда подходят дефолтные — div, table, а где уже есть своя более сложная разметка. У simplecart есть свое решение для этого случая, но очень неудобное, хотя кто-то скажет, что дело привычки =)
2) не знаю как сейчас, но у simplecart вроде были недоработки с counter, нет возможности задать float, а такие задачи бывают для интернет магазинов, где для товара добавляется не по +1 или +10 в корзину, а по +0.53, +0.23 и т.д.
Но как написал выше — это то, что можно будет расширить в функционале simplecart со временем =)
avatar
товара добавляется не по +1 или +10 в корзину, а по +0.53, +0.23

Землекопами торгуете?
avatar
трубами, фитингами и прочее =)
для продукции в строительной отрасли бывают такие «неловкости», да возможно и другие примеры найдутся

в общем, могут быть такие задачи, ну или мне так везет =)
avatar
Строительные, текстиль, еда, вообщем много чего может быть с float

Я вон делал по плитке (там хоть и через кальк но тоже метрами заказывать можно)

Опять же делал по мясу там только на вес.
avatar
1 Я уже поправил на текущий момент есть поддержка table div ul + более удобная шаблонизация выше было(параметр rowTpl). В целом если нужно можно еще добавить поддержку тегов но пока не вижу надобности.

2 Да там особых проблем не вижу, что б решить задачку. Но записал тут:
github.com/evoshop-pro/evoshop-js/issues надо будет проверить + примеры сделать. А то частая практика если товары не штучные.

p.s. в Целом подобные штуки как раз логично решать сразу а не в будущем собственно потому я так долго и ковыряю его так как рассматриваю и тестирую на проектах своих с учетом того что б потом не было неожиданно печально а то можно упереться в тупик.

Но на текущий момент пару подводных камней уже откопал и исправил. Так что уже стало лучше чем было в simpleCart. + По части фронтенда уже по функционалу обогнали SHK. Так что мне осталось догнать бекенд(по логике причесать код дописать пару вещей и вынести все в настройки) Очень надо уже :)
А с Учетом что Украина ввела санкции на 1С. Bitrix в том числе то мне очень акутально по быстрее запустить:) ибо новые клиенты с Украины битрикс не будут покупать теперь:)
avatar
Прикрутили SimpleCart? Даже дока один в один.
evoshop.pro/documentation/quick-start-guide/shipping.html
simplecartjs.org/documentation/shipping
Хотя нигде не упоминается.
Комментарий отредактирован 2017-06-03 14:57:06 пользователем zabudkin
avatar
Почитайте коменты, это уже обсуждали

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

P.s MODX тоже не с нуля делали а форкнули Etomite поэтому не вижу проблемы;)
avatar


Думаю тут все видно ;) если что
avatar
Дмитрий, один и тот же товар из каталога и с его страницы добавляется в корзину под разными позициями.
_data.id передается. Первая запись в LocalStorage формируется корректно. следующая уже не учитывает преданный ID
Не пойму логику обработки while

// set the item id
				item_id += 1;
				_data.id = _data.id || item_id_namespace + item_id;
				while (!isUndefined(sc_items[_data.id])) {
					item_id += 1;
					_data.id = item_id_namespace + item_id;
				}


К GitHub доступа нет. пишу сюда
avatar
Так выглядит запись

{"44":
	{"quantity":1,"id":"44","price":7600,"name":"KARLY ZIPPED POUCH","link":"/katalog/karly/karly_zipped_pouch.html"},
"SCI-4":
	{"quantity":1,"id":"SCI-4","price":7600,"name":"KARLY ZIPPED POUCH","link":"katalog/karly/karly_zipped_pouch.html"}
}
avatar
А можно пример товара на страничке каталога и на страничке товара
avatar
просто ссылки на добавление приведу
Каталог:
<code>
<a 
class="itemToCart" 
href="javascript:;" 
onclick="evoShop.add({link:'/katalog/karly/karly_zipped_pouch.html',name:'KARLY ZIPPED POUCH',price:7600,id:'44'});">
в корзину</a>
</code>
Страница товара:
<code>
<a 
class="itemToCart" 
href="javascript:;" 
onclick="evoShop.add({link:'katalog/karly/karly_zipped_pouch.html',name:'KARLY ZIPPED POUCH',price:7600,id:'44'});">
                                      <span>Добавить в корзину</span>
                                      </a>
</code>
Комментарий отредактирован 2017-06-04 10:28:57 пользователем maximlit
avatar
Должно быть типа такого
<div class="evoShop_shelfItem">
  <h2 class="item_name"> Awesome T-shirt </h2>
<p>  <input type="text" value="1" class="item_Quantity">
  <span class="item_price">$35.99</span>
  <a class="item_add" href="javascript:;"> Add to Cart </a></p>
</div>
avatar
да и по ссылке все работает в контексте приведенной документации. не работает только добавление одного и того же товара с разных страниц
через input тоже делалрезультата нет
avatar
Зачем вот здесь проверяется ID если потом тупо пишется namespace + инкриментированый счетчик

while (!isUndefined(sc_items[_data.id])) {
					item_id += 1;
					_data.id = item_id_namespace + item_id;
                    
				}
avatar
оно проверяет если нет такого товара то добавляет
по части добавления с разных страниц проверю во вторник и отпишусь сегодня затвра не доберусь к сожалению
avatar
я понимаю, но товар то уже есть. он проверяет его ID и все равно присваивает другой идентификатор в LS/
ок. Спасибо
avatar
github.com/wojodesign/simplecart-js/issues/339

Вот на эту тему. Допилю на неделе что б коректно работало из коробки.
avatar
У вас с точки зрения SimpleCart два разных товара. У одного атрибут link начинается со слеша, второй — нет.
avatar
Спасибо :) не заметил разницы. Ну да сравниваются полностью параметры все
avatar
Да, банальная невнимательность…
Спасибо!
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.