Подготавливаем ЛК для "ГдеПосылка"

Это продолжение статей по работе с заказами MS2, в последней статье я обещал, что расскажу как интегрировать сервис «ГдеПосылка» в Minishop2, а пока я жду пока очухается администрация «ГдеПосылка» чтобы дать мне доступ к API подготовим почву для интеграции, что мы будем делать:
- Добавим новое поле в заказы minishop2
 - Сделаем вывод для пользователей их историю заказов без extJS и каких либо дополнений, на чистом pdoTools
 - Научимся делать leftJoin и select на pdoTools и pdoFetch
 - Бонусом идут сразу готовые стили для всего этого добра и написанный JS
 
За объяснением кода — под кат, за кодом на GitHub
Требования к фронту сайта:
- Jquery
 - FontAwesome (не обязательно)
 - FancyBox 3
 

А теперь перейдем собственно к разработке:
Первое и самое важное — это добавляем новое поле к заказам MS2. Для этого воспользуемся разделом о плагинах товаров MS2 в официальной доке там написано как расширить свойства товара, но способ работает для любой модели MS2, это нам необходимо для того, чтобы MODX и MS2 увидел и мог работать с кастомными столбцами в БД.
Первым делом нам надо прописать новую карту объекта, для этого создадим index.php и msOrder.inc.php в index.php мы указываем карту какого объекта MS2 мы расширяем, а в msOrder.inc.php мы указываем какие поля добовляем, объяснять не вижу смысла, просто покажу файлы тут, если будут вопросы по ним — задавайте в комментариях
core/components/orderCustomField/index.php
<?php
return array(
    'map' => array(
        'msOrder' => require_once 'msOrder.inc.php',
    ),
);core/components/orderCustomField/msOrder.inc.php<?php 
return array(
    'fields' => array (
        'track' => NULL,
      ),
    'fieldMeta' => array(
        'track' => array (
          'dbtype' => 'varchar',
          'precision' => '100',
          'phptype' => 'string',
          'null' => true,
        ),
      ),
);Также нам нужно добавить поле track в таблицу modx_ms2_orders, для этого в консоле выполним код:$table = $modx->getTableName('msOrder');
$sql = 'ALTER TABLE ' . $table . '  ADD `track` VARCHAR(255) NULL;';
$modx->exec($sql);Для того, чтобы minishop2 подхватил наш плагин — нам нужно выполнить код в консоле:if ($miniShop2 = $modx->getService('miniShop2')) {
    $miniShop2->addPlugin('orderCustomField', '{core_path}components/orderCustomField/index.php');
}На данном этапе MS2 уже полностью видит наше поле, вы можете с ним полноценно работать, добавлять его в письма к клиентам или обрабатывать на фронте, везде, где доступны данные заказов, но нам нужно само поле в админку, для этого создадим новый плагин на событие msOnManagerCustomCssJs с вот таким содержимым:<?php
switch ($modx->event->name) {
    case 'msOnManagerCustomCssJs':
	//проверяем на какой странице мы находимся, если это страница orders, то добавляем наш html
        if ($page != 'orders') return;
	    $modx->controller->addHtml("
            <script type='text/javascript'>
                Ext.ComponentMgr.onAvailable('minishop2-window-order-update', function(){
                    this.fields.items[0].items[3].items[0].items.push(
                            {xtype: 'textfield', name: 'track', fieldLabel: 'Трек - номер', anchor: '100%'}
                        );     
                });           
            </script>");
    break;
}Тут код не вижу смысла объяснять, он прост как три рубля, мы просто добавляем в массив extJS наш объект, скажу лишь только то, что если вы хотите добавить в какое-то другое место, то дебажте расположение элементов вот так: console.log(this.fields)А там уже по дереву объектов смотрите где находятся нужные вам поля и пуште в нужный массив ваш объект.На этом добавление поля закончилось, перейдем к более интересному — выводу заказов пользователя!
Для вывода заказов мы будем использовать только pdoTools и pdoFetch, подразумевается, что у ваших пользователей уже есть ЛК и страница отведенная под историю заказов
На странице отведенную под историю заказов копируем содержимое файла:
/assets/components/MyCustomOrders/chunk/chunk.tpl.html
html и css я не вижу смысла рассматривать, а вот вызов pdoTools думаю будет многим интересен:
[[!pdoResources?
      &class=`msOrder`
      &sortby=`createdon`
      &leftJoin=`{
        "msDelivery":{"class":"msDelivery", "on":"msDelivery.id = msOrder.delivery"},
        "msPayment":{"class":"msPayment", "on":"msPayment.id = msOrder.payment"},
        "msOrderStatus":{"class":"msOrderStatus", "on":"msOrderStatus.id = msOrder.status"},
        "msOrderAddress":{"class":"msOrderAddress", "on":"msOrderAddress.id = msOrder.address"}
      }`
      &select=`{
        "msOrder": "*",
        "msDelivery": "msDelivery.name as deliveryName",
        "msPayment": "msPayment.name as paymentName",
        "msOrderStatus": "msOrderStatus.name as statusName, msOrderStatus.color",
        "msOrderAddress": "*"
      }`
      &where=`{"msOrder.user_id":[[+modx.user.id]]}`
      &showLog=`0`
      &limit=`9999`
      &tpl=`order_row`
    ]]И так, что же мы делаем в этом вызове?Первым делом мы обращаемся к модели msOrder и достаем из нее только те записи, которые соответствуют id текущего пользователя, за это отвечает параметр where
&where=`{"msOrder.user_id":[[+modx.user.id]]}`Далее мы подключаем таблицы msDelivery, msPayment, msOrderStatus и msOrderAddress через leftJoin msDelivery нам нужен для того, чтобы узнать название метода доставки, msPayment для названия метода оплаты, а msOrderStatus нам нужен для названия статуса и для выбранного цвета текущего статуса (все эти пункты в msOrder лежат как id и по id текущего заказа мы достаем массив статуса, доставки и оплаты). В msOrderAddress лежат все поля введенные пользователем на моменте оформления заказа.
Теперь перейдем к select. В селекте мы указываем то, какие поля нам нужны от каждой таблицы, пойдем по порядку:
msOrder — выбираем все поля
msDelivery — нужно только название, его и выбираем и даем ему псевдоним deliveryName
msPayment — аналогично с msDelivery
msOrderStatus — выбираем имя, даем псевдоним и выбираем цвет
msOrderAddress — выбираем все
Чанк order_row лежит тут
Вот в принципе и все, копируем разметку, не забываем подключить JS и стили, единственное что можно рассмотреть отдельно, это то, как в модалке мы получаем данные, для этого у нас в js есть ajax запрос на контроллер, который через pdoFetch запускает выборку с аналогичными параметрами, что и pdoTools ну и еще одну выборку по msProductData, чтобы подтянуть позиции заказа.
Как то слишком сумбурный туториал получился, потому что я не особо понимаю что нужно разжевывать, а что и так очевидно, если возникли вопросы — задавайте в комментариях, главная цель, с которой писалась эта статья, это НАУЧИТЬ НОВИЧИКОВ, по этому непонятные вам вещи можем разобрать в комментариях.
P.s. кто ждет статьи про интеграцию «где посылка» советую сразу оставить заявку на доступ к их API, потому что думают они очень долго и только пару дней назад дали доступ, хотя оставил я заявку 2 недели назад
            
                Поблагодарить автора            
            
                 Отправить деньги            
        
        
            Комментарии: 46
За стилизацию заказов я брал пример с modstore, я надеюсь никто не обидится, потому что мне кажется что у нового дизайна модстора очень удачное стиливое решение истории заказовБез проблем. Приятно, что нравится!
—
Выкладывай уже свой первый доп к нам ;)
                Скоро, если по времени все получится :)            
                    Требования к фронту сайта:Третий бутстрап c jQuery выше 2.2.4 не работает… Мне кажется, что бутстрап — это одна из must have в плане поддержки для компонентов.
Jquery 3+ (на более низких версиях не тестировалось)
                На jquery ниже третей я не проверял просто, скорее всего будет работать.
По поводу бутстрапа промолчу, я считаю хенжество тянуть такие вещи как бутстрп, в проект, когда есть flexbox
                    По поводу бутстрапа промолчу, я считаю хенжество тянуть такие вещи как бутстрп, в проект, когда есть flexbox
                github.com/pavel-one/Modx-Custom-Orders-MS2/blob/master/assets/components/MyCustomOrders/js/customOrders.js
Решил код глянуть и в первой же строчке проблема есть…
                    Решил код глянуть и в первой же строчке проблема есть…
                В чем проблема?            
                    
                jquery.com/upgrade-guide/3.0/#deprecated-document-ready-handlers-other-than-jquery-function
В общем, начиная с 3 версии в jQuery иначе реализовано многое и я сталкивался со случаями, когда не работает:
                    В общем, начиная с 3 версии в jQuery иначе реализовано многое и я сталкивался со случаями, когда не работает:
$(document).ready(function() {Если я не ошибаюсь, то все из-за того, что раньше ready был event, а сейчас это Promise. Лично я пишу так:$.when($.ready).then(function(){...});            
                Да ладно? Даже на 1.12 jquery работает все нормально с реди
Вот пример:
codepen.io/pavel_one/pen/RLdbEG
Проверяйте пожалуйста, прежде чем написать что-то
                    Вот пример:
codepen.io/pavel_one/pen/RLdbEG
Проверяйте пожалуйста, прежде чем написать что-то
                Естественно, что на 1.12 пашет, т.к. ДО 3 был ready, а после уже нет.
                    Deprecated: document-ready handlers other than jQuery(function)
Due to historical compatibility issues there are a multitude of ways to set a document ready handler. All of the following are equivalent and call the function fn when the document is ready:
$(fn);
$().ready(fn);
$(document).ready(fn);
$(«selector»).ready(fn);
As of jQuery 3.0 the recommended way to add a ready handler is the first method, $(fn). As noted in the Event section, the $(document).on(«ready», fn) event form has slightly different semantics and was removed in jQuery 3.0.
                Вот этого не знал, спасибо            
                    
                Не за что. Очень распространенная ошибка на самом деле. Раньше у document был event на готовность, а теперь Promise. Но как бы оно ни было в данном случае ВООБЩЕ по фигу, т.к. у тебя просто обработку на клик вешает, а для этого вообще дожидаться готовности не нужно да нет никаких причин ждать чего либо вообще, кроме загрузки непосредственного самого jQuery :-)
Короче, тупо убери document и просто click оставь и будет счастье
                    Короче, тупо убери document и просто click оставь и будет счастье
                Все последние работы делаю на Bootstrap 3 + jQuery v3.2.1, если не требуется mSearch2
Я, правда, многое вырезаю, но основной функционал оставляю.
Вот пример, дабы не быть голословным.
mSearch2 с jQuery v3.2.1 — это да, некорректная работа
                    Я, правда, многое вырезаю, но основной функционал оставляю.
Вот пример, дабы не быть голословным.
mSearch2 с jQuery v3.2.1 — это да, некорректная работа
"msOrderAddress":{"class":"msOrderAddress", "on":"msOrderAddress.id = msOrder.id"}Ошибка. У них связь:"msOrderAddress":{"class":"msOrderAddress", "on":"msOrderAddress.address= msOrder.id"}            
                Да ладно? joxi.ru/zANd1x3IBWMJjm
Код скопирован с продакшена и прямо сейчас работает на одном сайте, можете сделать в консоле выборку через pdoFetch и убедиться что вы неправы
                    Код скопирован с продакшена и прямо сейчас работает на одном сайте, можете сделать в консоле выборку через pdoFetch и убедиться что вы неправы
                github.com/bezumkin/miniShop2/blob/e8d674f0ebf80450c3bb3830dfd49413f44a84ff/core/components/minishop2/model/schema/minishop2.mysql.schema.xml#L278
Вот, пожалуйста…
                    Вот, пожалуйста…
Код скопирован с продакшена и прямо сейчас работает на одном сайтеТы фортовый, что тут еще скажешь :-) Видимо ошибка не всплыла, т.к. во всех заказах по одному товару и поэтому ID в таблицах шли вровень :-)
                Еще раз прошу проверять что-то, перед тем как написать, joxi.ru/D2PK71nTp9LjOm            
                    
                Вот тут вообще не понял, о чем вы? :)            
                    
                'on' => 'msOrderAddress.id = msOrder.id'
На гите косяк у связи
                    На гите косяк у связи
                В какой строке я то понял, а как должно быть по вашему, вот этого я понять не могу            
                    'on' => 'msOrderAddress.id = msOrder.id'В msOrder поле для связи address!
На гите косяк у связи
'on' => 'msOrderAddress.id = msOrder.address'для pdoResources"msOrderAddress":{"class":"msOrderAddress", "on":"msOrderAddress.id = msOrder.address"}            
                А, вот теперь понял, спасибо, да, не заметил этого            
                    
                И снова не за что :-) 
Ну и последнее… Напиши правильно для кого адресована статья :-) Что за Новчики? :-)
                    Ну и последнее… Напиши правильно для кого адресована статья :-) Что за Новчики? :-)
это НАУЧИТЬ НОВЧИКОВ
                github.com/bezumkin/miniShop2/blob/e8d674f0ebf80450c3bb3830dfd49413f44a84ff/core/components/minishop2/model/minishop2/mysql/msorder.map.inc.php#L277
Снова ссылка на github… Обрати внимание чей он ;-)
                    Снова ссылка на github… Обрати внимание чей он ;-)
как должно быть по вашему, вот этого я понять не могуТак что не только по-моему ;-)
                Более того на github у тебя снова:

github.com/pavel-one/Modx-Custom-Orders-MS2/blob/7f37b69d4bcf1515a5dde3e191dd812e8c6aeedb/assets/components/MyCustomOrders/action/getOrder.php#L32
А Еще
github.com/pavel-one/Modx-Custom-Orders-MS2/blob/7f37b69d4bcf1515a5dde3e191dd812e8c6aeedb/assets/components/MyCustomOrders/action/getOrder.php#L43
и
github.com/pavel-one/Modx-Custom-Orders-MS2/blob/7f37b69d4bcf1515a5dde3e191dd812e8c6aeedb/assets/components/MyCustomOrders/action/getOrder.php#L9
Не продуман момент для случаев, когда контекст не web
            
                    
github.com/pavel-one/Modx-Custom-Orders-MS2/blob/7f37b69d4bcf1515a5dde3e191dd812e8c6aeedb/assets/components/MyCustomOrders/action/getOrder.php#L32
А Еще
github.com/pavel-one/Modx-Custom-Orders-MS2/blob/7f37b69d4bcf1515a5dde3e191dd812e8c6aeedb/assets/components/MyCustomOrders/action/getOrder.php#L43
и
github.com/pavel-one/Modx-Custom-Orders-MS2/blob/7f37b69d4bcf1515a5dde3e191dd812e8c6aeedb/assets/components/MyCustomOrders/action/getOrder.php#L9
Не продуман момент для случаев, когда контекст не web
А ЕщеА тут что не так?
github.com/pavel-one/Modx-Custom-Orders-MS2/blob/7f37b69d4bcf1515a5dde3e191dd812e8c6aeedb/assets/components/MyCustomOrders/action/getOrder.php#L43
и
github.com/pavel-one/Modx-Custom-Orders-MS2/blob/7f37b69d4bcf1515a5dde3e191dd812e8c6aeedb/assets/components/MyCustomOrders/action/getOrder.php#L9
Не продуман момент для случаев, когда контекст не webУж такие вещи для обучающей статьи продумывать не имеет смысла, статья находится в разделе «Пошаговые инструкции», а не в разделе «Готовые решения»
А ЕщеВсе таки еще раз что тут не так? Пока ты не ушел)
github.com/pavel-one/Modx-Custom-Orders-MS2/blob/7f37b69d4bcf1515a5dde3e191dd812e8c6aeedb/assets/components/MyCustomOrders/action/getOrder.php#L43
и
github.com/pavel-one/Modx-Custom-Orders-MS2/blob/7f37b69d4bcf1515a5dde3e191dd812e8c6aeedb/assets/components/MyCustomOrders/action/getOrder.php#L9
                Ок. Через минут скину сюда код            
                    
                Нашел еще ошибку:
в getOrder.php ты вначале:
define('MODX_API_MODE', true);
Далее во-первых нет проверки на пустой id в POST
Ну а во-вторых ты sendRedirect делаешь, если не AJAX.
Что интересно: MODX_API_MODE не даст запустить handleRequest… Не понятен redirect. Нужно сразу exit хотя бы или т.п.
                    в getOrder.php ты вначале:
define('MODX_API_MODE', true);
Далее во-первых нет проверки на пустой id в POST
Ну а во-вторых ты sendRedirect делаешь, если не AJAX.
Что интересно: MODX_API_MODE не даст запустить handleRequest… Не понятен redirect. Нужно сразу exit хотя бы или т.п.
                Редирект отлично срабатывает
ТЫК
                    ТЫК
                Короче, вместо него $modx->sendErrorPage();            
                    
                Я знаю метод на редирект страницы ошибки, и если бы мне нужно было бы редиректить на страницу ошибки, я бы его использовал %)            
                    Далее во-первых нет проверки на пустой id в POSTА зачем она нужна? Если пользователь не подхватил ID то и запрос у него не пойдет, а если кто-то решит шаловливыми ручками поэксперементировать, то ему во первых не составит труда подставить туда любое значение чтобы обойти проверку, а во вторых ничего страшного не случится если id не придет
                ну давай я передам в console не число а массив… Или что там в pdoFetch передается, чтобы преобразовать в более сложный where?            
                    
                И ничего не произойдет, представляешь?) Однако если бы даже был бы шанс чему то произойти, то проверка на пустоту не оберегла бы от атаки, проверка на число — уберегла бы, но в нашем случае не произойдет ровным счетом ничего даже если массив придет. К слову нельзя передать массив через POST, он просто придет строкой            
                    Теперь нам нужно добавить собственно наше поле «track» в нашу БДЕсли будет писаться компонент в modstore, то вместо этого надо:
Через phpMyAdmin перейдем в таблицу modx_ms2_orders -> структура и добавим поле в самый конец:
Имя: track
Тип: varchar
Длина: 255
Null: true
$manager = $modx->getManager();
и уже им таблицу изменять
                Этот компонент писаться в modstore не будет, иначе бы и статей небыло бы            
                    
                Все сделал по инструкции, в итоге на странице заказов белый лист и в логе 
                    [2018-02-26 08:23:39] (ERROR @ /home/s1111/www/core/components/pdotools/model/pdotools/pdotools.class.php : 977) Unexpected token ':' in c307b02e5743bce69f94649b8a8d7c6d line 78, near '{"class":' <- thereКуда рыть?            
                переписал так и все заработало:
                    [[!pdoResources?
      &class=`msOrder`
      &sortby=`createdon`
      &leftJoin=`{
        "msDelivery":{
        "class":"msDelivery", "on":"msDelivery.id = msOrder.delivery"
        },
        "msPayment":{
        "class":"msPayment", "on":"msPayment.id = msOrder.payment"
        },
        "msOrderStatus":{
        "class":"msOrderStatus", "on":"msOrderStatus.id = msOrder.status"
        },
        "msOrderAddress":{
        "class":"msOrderAddress", "on":"msOrderAddress.id = msOrder.address"
        }
      }`
      &select=`{
        "msOrder": "*",
        "msDelivery": "msDelivery.name as deliveryName",
        "msPayment": "msPayment.name as paymentName",
        "msOrderStatus": "msOrderStatus.name as statusName, msOrderStatus.color",
        "msOrderAddress": "*"
      }`
      &where=`{
      "msOrder.user_id":[[+modx.user.id]]
      }`
      &showLog=`0`
      &limit=`9999`
      &tpl=`order_row`
    ]]            
                Заметил, что если в заказе будет больше 10 товаров, то выводятся только 10, остальные не выводятся.
Фиксанул вот таким образом:
joxi.ru/n2Yb80aCZOzkaA
                    Фиксанул вот таким образом:
joxi.ru/n2Yb80aCZOzkaA
                Для этого в pdoResources существует такой параметр как limit, также можно выводить через pdoPage для пагинации            
                    
                Спасибо! А как можно получить изображения товаров при открытии popup в заказе? В response их нет, как их можно достать?            
                    
                Вам нужно приджойнить таблицу msProductFile по аналогии с другими            
                    
                А можете подсказать, как это правильно сделать? Пробую вот так в файле getOrder.php
                    // get images
    'msProductFile' => array(
      'class' => 'msProductFile',
        'on' => array(
        'msProduct.id = msProductFile.product_id',
        'msProductFile.parent' => 0,
        'msProductFile.type' => 'image',
       )
      )
    ),
    'select' => array(
      'msOrder' => '*',
      'msDelivery' => 'msDelivery.name as deliveryName',
      'msOrderStatus' => 'msOrderStatus.name as statusName',
      'msPayment' => 'msPayment.name as paymentName',
      'msOrderAddress' => '*',
      //
      'msProductFile' => 'all'
      ),            
                Ребята, что делать если в {$track} в уведомлении о движении посылки на работает, на почту он приходит как есть — {$track}.
Еще вопрос, можно ли как то вывести поле с треком на страницу заказа?
                    Еще вопрос, можно ли как то вывести поле с треком на страницу заказа?
                            Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
                    
            
                    
                    
                