Регистрируем пользователя после совершения заказа miniShop2

Недавно наткнулся на платный компонент msCustomerAutoReg (490 руб.), который позволяет регистрировать пользователей после оформления заказа. Сказать, что я удивился, это не сказать ничего. Мало того, что компонент платный, так и способ реализации задачи достаточно некорректный, с моей точки зрения. На вопрос: можно сделать лучше и штатными средствами? Я отвечу: можно! И даже нужно!

Начнем с того, что после оформления заказа miniShop2 автоматически регистрирует пользователя на сайте, только данные пользователя на почту не высылаются. В сети предлагают кучу решений данной задачи, но все они сводятся к тому, что после оформления заказа пользователю отсылается второе письмо с данными от личного кабинета. Не считаю, что два письма отсылать корректно. Поэтому делюсь своими наработками в данном направлении.

Компонент miniShop2 обладает широкими возможностями для масштабирования, за что разработчику огромное спасибо. В частности, мы можем переопределить стандартные методы классов. Что и послужит нам отличным инструментом для решения данной задачи. Нам нужно переопределить всего один метод changeOrderStatus, для этого создаем файл orderCustomHandler.class.php в директории /core/components/minishop2/custom/order/ со следующим содержимым:

<?php

class orderCustomHandler extends msOrderHandler{
	/**
     * Switch order status
     *
     * @param integer $order_id The id of msOrder
     * @param integer $status_id The id of msOrderStatus
     *
     * @return boolean|string
     */
    public function changeOrderStatus($order_id, $status_id)
    {
        /** @var msOrder $order */
        if (!$order = $this->modx->getObject('msOrder', array('id' => $order_id), false)) {
            return $this->modx->lexicon('ms2_err_order_nf');
        }

        $ctx = $order->get('context');
        $this->modx->switchContext($ctx);
        $this->initialize($ctx);
        // This method could be overwritten from custom order handler
        if (is_object($this->order) && method_exists($this->order, 'changeOrderStatus')) {
            return $this->order->changeOrderStatus($order_id, $status_id);
        }

        $error = '';
        /** @var msOrderStatus $status */
        if (!$status = $this->modx->getObject('msOrderStatus', array('id' => $status_id, 'active' => 1))) {
            $error = 'ms2_err_status_nf';
        } /** @var msOrderStatus $old_status */
        else {
            if ($old_status = $this->modx->getObject('msOrderStatus',
                array('id' => $order->get('status'), 'active' => 1))
            ) {
                if ($old_status->get('final')) {
                    $error = 'ms2_err_status_final';
                } else {
                    if ($old_status->get('fixed')) {
                        if ($status->get('rank') <= $old_status->get('rank')) {
                            $error = 'ms2_err_status_fixed';
                        }
                    }
                }
            }
        }
        if ($order->get('status') == $status_id) {
            $error = 'ms2_err_status_same';
        }

        if (!empty($error)) {
            return $this->modx->lexicon($error);
        }

        $response = $this->ms2->invokeEvent('msOnBeforeChangeOrderStatus', array(
            'order' => $order,
            'status' => $order->get('status'),
        ));
        if (!$response['success']) {
            return $response['message'];
        }

        $order->set('status', $status_id);

        if ($order->save()) {
            $this->ms2->orderLog($order->get('id'), 'status', $status_id);
            $response = $this->ms2->invokeEvent('msOnChangeOrderStatus', array(
                'order' => $order,
                'status' => $status_id,
            ));
            if (!$response['success']) {
                return $response['message'];
            }

            $lang = $this->modx->getOption('cultureKey', null, 'en', true);
            if ($tmp = $this->modx->getObject('modUserSetting', array('key' => 'cultureKey', 'user' => $order->get('user_id')))) {
                $lang = $tmp->get('value');
            }
            else if ($tmp = $this->modx->getObject('modContextSetting', array('key' => 'cultureKey', 'context_key' => $order->get('context')))) {
                $lang = $tmp->get('value');
            }
            $this->modx->setOption('cultureKey', $lang);
            $this->modx->lexicon->load($lang . ':minishop2:default', $lang . ':minishop2:cart');

            $pls = $order->toArray();
            $pls['cost'] = $this->ms2->formatPrice($pls['cost']);
            $pls['cart_cost'] = $this->ms2->formatPrice($pls['cart_cost']);
            $pls['delivery_cost'] = $this->ms2->formatPrice($pls['delivery_cost']);
            $pls['weight'] = $this->ms2->formatWeight($pls['weight']);
            $pls['payment_link'] = '';
            if ($payment = $order->getOne('Payment')) {
                if ($class = $payment->get('class')) {
                    $this->ms2->loadCustomClasses('payment');
                    if (class_exists($class)) {
                        /** @var msPaymentHandler|PayPal $handler */
                        $handler = new $class($order);
                        if (method_exists($handler, 'getPaymentLink')) {
                            $link = $handler->getPaymentLink($order);
                            $pls['payment_link'] = $link;
                        }
                    }
                }
            }
			
			$userId = $pls["user_id"];
			$user = $this->modx->getObject("modUser", $userId);
			if($user){
				$time = time();
				$newUser = 10;
				$username = $user->get("username");
				$createdon = strtotime($user->get("createdon")) + $newUser;
				if($createdon > $time){
					$length = 8;
					$pass = $this->modx->user->generatePassword($length);
					$user->set("password", $pass);
					$user->save();
					$pls["userdata"] = array(
					    "username" => $username,
					    "password" => $pass,
					);
					$user->addSessionContext("web");
				}
			}

            if ($status->get('email_manager')) {
                $subject = $this->ms2->pdoTools->getChunk('@INLINE ' . $status->get('subject_manager'), $pls);
                $tpl = '';
                if ($chunk = $this->modx->getObject('modChunk', array('id' => $status->get('body_manager')))) {
                    $tpl = $chunk->get('name');
                }
                $body = $this->modx->runSnippet('msGetOrder', array_merge($pls, array('tpl' => $tpl)));
                $emails = array_map('trim', explode(',',
                        $this->modx->getOption('ms2_email_manager', null, $this->modx->getOption('emailsender')))
                );
                if (!empty($subject)) {
                    foreach ($emails as $email) {
                        if (preg_match('#.*?@.*#', $email)) {
                            $this->ms2->sendEmail($email, $subject, $body);
                        }
                    }
                }
            }

            if ($status->get('email_user')) {
                if ($profile = $this->modx->getObject('modUserProfile', array('internalKey' => $pls['user_id']))) {
                    $subject = $this->ms2->pdoTools->getChunk('@INLINE ' . $status->get('subject_user'), $pls);
                    $tpl = '';
                    if ($chunk = $this->modx->getObject('modChunk', array('id' => $status->get('body_user')))) {
                        $tpl = $chunk->get('name');
                    }
                    $body = $this->modx->runSnippet('msGetOrder', array_merge($pls, array('tpl' => $tpl)));
                    $email = $profile->get('email');
                    if (!empty($subject) && preg_match('#.*?@.*#', $email)) {
                        $this->ms2->sendEmail($email, $subject, $body);
                    }
                }
            }
        }

        return true;
    }
}

Как видите, мы просто добавили небольшой блок, который позволяет нам вывести данные по личному кабинету прямо в письме о новом заказе. Что чертовски круто. Теперь переходим в системные настройки в разде miniShop2 и меняем значение настройки ms2_order_handler_class на orderCustomHandler.

Далее просто редактируем стандартный чанк tpl.msEmail, добавляя блок с данными о заказе (всегда мучал вопрос почему из коробки этого нет) и данными от личного кабинета:

    <div style="width:90%;margin:auto;">
        {if $user.fullname}<p><strong>Ф.И.О.:</strong> {$user.fullname}</p>{/if}
        {if $user.email}<p><strong>E-mail:</strong> {$user.email}</p>{/if}
        {if $address.phone}<p><strong>Телефон:</strong> {$address.phone}</p>{/if}
        {if $address.city}<p><strong>Город:</strong> {$address.city}</p>{/if}
        {if $address.street}<p><strong>Адрес:</strong> {$address.street}{/if} 
        {if $address.building} {$address.building}{/if}  
        {if $address.room} {$address.room}</p>{/if}
        {if $address.comment}<p><strong>Комментарии:</strong> {$address.comment}</p>{/if}
        {if $delivery.name}<p><strong>Доставка:</strong> {$delivery.name}</p>{/if}
        {if $payment.name}<p><strong>Оплата:</strong> {$payment.name}</p>{/if}
        {if $userdata}
            <h3 style="{$style.h}{$style.h3}">Данные для входа в личный кабинет:</h3>
            <div style="padding: 0 20px;">
                <strong>Логин:</strong> {$userdata.username}<br/>
                <strong>Пароль:</strong> {$userdata.password}
            </div>
        {/if}
    </div>

Вот и все! Несколько минут работы, сэкономленные 490 руб. и полученные новые навыки. Неплохо правда?

Регистрируем пользователя после совершения заказа miniShop2

0 Число голосов: 4
4
5
1
4

Комментарии ()

  1. Михаил 03 июля 2021, 12:18 # 0
    Пароль присылается на почту неправильный. Короче при входе он не подходит почему-то
    1. Денис 20 августа 2021, 11:54 # 0
      Возникает следующая ошибка, хотя все сделано по инструкции.
      [20-Aug-2021 11:40:33 Europe/Moscow] PHP Fatal error:  Uncaught Error: Call to undefined method orderCustomHandler::loadCustomClasses() in /home/site/core/components/minishop2/custom/order/orderCustomHandler.class.php:92
      Stack trace:
      #0 /home/site/core/components/minishop2/model/minishop2/minishop2.class.php(741): orderCustomHandler->changeOrderStatus(15701, 1)
      #1 /home/site/core/components/minishop2/model/minishop2/msorderhandler.class.php(475): miniShop2->changeOrderStatus(15701, 1)
      #2 /home/site/core/components/minishop2/model/minishop2/minishop2.class.php(194): msOrderHandler->submit(Array)
      #3 /home/site/core/cache/includes/elements/modplugin/14.include.cache.php(21): miniShop2->handleRequest('order/submit', Array)
      #4 /home/site/core/model/modx/modscript.class.php(76): include('/home/site/co...')
      #5 /home/site/core/model/modx/modx.class.php(1674): modScript->process(NULL)
      #6 /home/site/core/model/modx/modrequest.class.php(70): modX->invokeEvent('OnHandleRequest')
      #7 /home/site/core/model/modx/modx.class.php(1461): modRequest->handleRequest in /home/site/core/components/minishop2/custom/order/orderCustomHandler.class.php on line 92
      
                  if ($payment = $order->getOne('Payment')) {
       92-я строка:   if ($class = $payment->get('class')) {
                          $this->loadCustomClasses('payment');
                          if (class_exists($class)) {
                              /** @var msPaymentHandler|PayPal $handler */
                              $handler = new $class($order);
                              if (method_exists($handler, 'getPaymentLink')) {
                                  $link = $handler->getPaymentLink($order);
                                  $pls['payment_link'] = $link;
                              }
                          }
                      }
                  }
      
      1. Петропавловский Артем 22 августа 2021, 15:35 # 0
        В этой строке:
        $this->loadCustomClasses('payment');
        Нужно писать вот так:
        $this->ms2->loadCustomClasses('payment');
        Так как у orderHandler нет метода loadCustomClasses. Изначально это функция взята из другого класса. У меня в коде была опечатка.
      2. Вячеслав 21 августа 2021, 20:02 # 0
        У меня вообще 500 при оформлении вываливает
        1. Петропавловский Артем 22 августа 2021, 15:35 # 0
          Ответил выше
        2. Димитриус 22 октября 2021, 03:00 # 0
          changeOrderStatus находится в файле minishop.class.php, но расширяете msOrderHandler. Как это работает?
          Сейчас мне надо модифицировать sendEmail в minishop.class.php, делаю так же по вашему примеру и ничего не происходит, запускается старый метод. Подскажите куда копать
          1. Петропавловский Артем 26 октября 2021, 13:33 # 0
            Вы можете создать в этом классе свой метод sendEmail и вызывать его не так, как выше в коде:
            $this->ms2->sendEmail()
            А вот так:
            $this->sendEmail()
          2. Ivan 25 октября 2021, 05:39 # 0
            Проще купить, чем с этой фигней ковыряться походу, стоит копейки.
            1. Петропавловский Артем 26 октября 2021, 13:34 # 0
              У нас тут полностью рабочий код. При желании можно за 2 минуты все развернуть. На покупку, установку, и настройку больше времени уйдет)
            2. Александр 06 ноября 2021, 18:00 # 0
              Генерация пароля не происходит, в письмо попадает пустое поле с паролем
              1. Макс 12 сентября 2022, 13:43 # 0
                Отправка писем новому пользователю работает, генерация пароля происходит — по сгенерированному паролю юзер логинится. Но… при входе к личный кабинет — везде 404. (т.е. нет страница редактирования профиля, изменения пароля, и самого личного кабинета с историей заказов. Что не так сделал?
                1. Макс 12 сентября 2022, 13:44 # 0
                  если зарегистрироваться как положено через форму, сделать подтверждение профиля по ссылке из письма — личный кабинет работает исправно
                  1. Петропавловский Артем 12 сентября 2022, 15:07 # 0
                    Вероятно, у вас пользователь попадает не в ту группу пользователей. Вам нужно заполнить системную настройку у miniShop2 ms2_order_user_groups — написать туда ту группу, которую вы создали.
                    1. Макс 13 сентября 2022, 08:50 # 0
                      Спасибо!!! Все заработало.
                      1. Петропавловский Артем 13 сентября 2022, 15:09 # 0
                        Отлично!
                2. Данил 31 июля 2023, 16:35 # 0
                  Здравствуйте, на сегодняшний день компонент обновился и этот код не работает. Может подскажите (актуализируете) Как можно это сделать в новой версии?

                  Наши клиенты

                  Многие компании уже доверяют нам. Будьте в их числе!

                  Хотите реализовать проект?

                  Контакты

                  Напишите нам - мы расскажем вам много интересного!


                  Пермь, шоссе Космонавтов 252, офис 218