Торговля электронными книгами на UMI.CMS

torgovlya-elektronnymi-knigami-na-umi-cms-0

После покупок электронных книг в магазине пришла идея реализовать подобный функционал на UMI.CMS.
Как оказалась, задача очень легко реализуема.

Логика работы:

  • Происходит оплата на сайте и меняется статус оплаты на «принята» или «подтверждена»;
  • Отлавливается событие изменение статуса оплаты;
  • В ответном письме приходят купленные книги.

Подготовка:

Для начала нужно создать новый тип данных или уже работать с существующим, не принципиально. В него добавить поля (Тема письма subjectstring | Контент письма letter_content):

torgovlya-elektronnymi-knigami-na-umi-cms

После этого, создать страницу, которая будет использовать данный тип данных и заполнить созданные поля:

torgovlya-elektronnymi-knigami-na-umi-cms-1

Я создал тип данных дочерний к «Страница контента»

Текст для полей:

Ваши книги из заказа №%order_id%

и

Книги из вашего заказа №%order_id% приложены к письму.

Вы заказали: %books_list%

Спасибо за ваш заказа. Читайте с удовольствием!

Я постарался дать возможность администратору сайта изменять сообщения, которые будут отправляться пользователю. Макросы %order_id% и %books_list% содержать в себе номер заказа и список купленных книг. Автозамена происходить автоматически, когда срабатывает функция.

Далее, нужно добавить поле «Статус отправки файла (sent_status)» в шаблон данных «Заказ». Добавить можно в секцию «Свойства заказа»:

torgovlya-elektronnymi-knigami-na-umi-cms-5

torgovlya-elektronnymi-knigami-na-umi-cms-2

Будет автоматически создан новый справочник. В созданный справочник нужно добавить два значения(/admin/data/guide_items/):

  • Не отправлен
  • Отправлен

Нужно запомнить ID созданных названий(в моем случае это 855 и 856) они нужны для того, чтобы совершать отправку либо нет, далее будет ясно:

torgovlya-elektronnymi-knigami-na-umi-cms-4

torgovlya-elektronnymi-knigami-na-umi-cms-3

Теперь нужно дать возможность прикрепить файл к объекту каталога. В шаблоне данных «Объект каталога» нужно добавить 1 или 2 поля, все зависит от того, какое кол-во файлов вам нужно будет прикреплять (Файл 1 fajl_1 | Файл 2 fajl_2):

torgovlya-elektronnymi-knigami-na-umi-cms-6

torgovlya-elektronnymi-knigami-na-umi-cms-7

Можете зайти в каталог и прикрепить несколько файлов в ваши товарам.

Программирование:
Если вы используете новый формат хранения шаблонов, то у вас в шаблоне должна присутствовать следующая иерархия папок - templates\[название_шаблона]\classes\modules\emarket\.
В папке emarket должно быть 3 файла:

  • events.php
  • permissions.php
  • class.php

Если у вас остался старый формат хранения шаблонов, вам нужно в папке \classes\modules\emarket\ создать три файла, если еще нет :

  • custom_events.php
  • permissions.custom.php
  • __custom.php

Содержание файла events.php (custom_events.php)

<?php
new umiEventListener('order-payment-status-changed', 'emarket', 'onChangeOrderStatusProp');
new umiEventListener('systemModifyPropertyValue', 'emarket', 'onChangeOrderStatusProp');
?>

Содержание файла permissions.php (permissions.custom.php)

<?php
$permissions = array(
    'purchasing' => array(
        'onChangeOrderStatusProp',
        'onChangePaymentStatusSendFileToUser'
    )
);
?>

Содержание файла class.php (__custom.php)

<?php
class emarket_custom extends def_module {
    public function onChangeOrderStatusProp(iUmiEventPoint $event) {
        $old_status = $event->getParam("oldValue");
        $new_status = $event->getParam("newValue");

        $object = $event->getRef("entity");
        $oid = $object->getId();

        // При изменение статуса оплаты
        if ($event->getParam("property") == 'payment_status_id' && $new_status != $old_status) {
            if($event->getMode() == "before") return true;
            else {
                $this->onChangePaymentStatusSendFileToUser($oid, $new_status);
            }
        }
    }

    public function onChangePaymentStatusSendFileToUser($oid, $new_status) {
        // Получает текущий заказ
        $order = order::get($oid);

        if($order instanceof order == false)
            throw new publicException("Order #{$oid} doesn't exists");

        // Получение текущего статуса файла из заказа
        $sent_status = $order->getValue('sent_status');

        if( $new_status == '47' && $sent_status != '856' || $new_status == '49' && $sent_status != '856' ) {
            // Получение объектов текущего заказа
            $order_items = $order->getItems();

            // Получение пользователя из системы
            $customer = umiObjectsCollection::getInstance()->getObject($order->getCustomerId());

            // Получение email
            $email = $customer->email ? $customer->email : $customer->getValue("e-mail");

            // Получение имени
            $name = $customer->lname . " " .$customer->fname . " " . $customer->father_name;

            // Получение страницы с опциями
            $opt_item = umiHierarchy::getInstance()->getElement(35);

            // Формирование темы для письма
            $subjectString = str_replace("%order_id%", $oid, $opt_item->getValue('subjectstring'));
            // Содержание письма
            $letter_content = $opt_item->getValue('letter_content');
            $letter_content = str_replace("%order_id%", $oid, $letter_content);

            // Получение domainid
            $regedit = regedit::getInstance();
            $cmsController = cmsController::getInstance();
            $domains = domainsCollection::getInstance();
            $domainId = $cmsController->getCurrentDomain()->getId();
            $defaultDomainId = $domains->getDefaultDomain()->getId();

            // Формирование fromMail и fromName
            if ($regedit->getVal("//modules/emarket/from-email/{$domainId}")) {
                $fromMail = $regedit->getVal("//modules/emarket/from-email/{$domainId}");
                $fromName = $regedit->getVal("//modules/emarket/from-name/{$domainId}");

            } elseif ($regedit->getVal("//modules/emarket/from-email/{$defaultDomainId}")) {
                $fromMail = $regedit->getVal("//modules/emarket/from-email/{$defaultDomainId}");
                $fromName = $regedit->getVal("//modules/emarket/from-name/{$defaultDomainId}");

            } else {
                $fromMail = $regedit->getVal("//modules/emarket/from-email");
                $fromName = $regedit->getVal("//modules/emarket/from-name");
            }

            $letter = new umiMail();
            $letter->addRecipient($email, $name);
            $letter->setFrom($fromMail, $fromName);
            $letter->setSubject($subjectString);

            $html = '<ul>';
            foreach($order_items as $order_item) {
                $item = $order_item->getItemElement();

                $html .= "<li>" . $item->getValue('h1') . "</li>";

                // Получение файлов из объекта каталога
                if(iconv_strlen($item->getValue('fajl_1')) > 0) {
                    $f = '.' . $item->getValue('fajl_1');

                    $oFile = new umiFile($f);
                    if (!$oFile->getIsBroken())  //Возвращает false, если файл существует и доступен скрипту на чтение.
                        $letter->attachFile($oFile); // Прикрепление файлов к письму
                }

                // Получение файлов из объекта каталога
                if(iconv_strlen($item->getValue('fajl_2')) > 0) {
                    $f = '.' . $item->getValue('fajl_2');

                    $oFile = new umiFile($f);
                    if (!$oFile->getIsBroken())  //Возвращает false, если файл существует и доступен скрипту на чтение.
                        $letter->attachFile($oFile); // Прикрепление файлов к письму
                }
            }
            $html .= '</ul>';

            $letter_content = str_replace("%books_list%", $html, $letter_content);

            // Текст письма
            $letter->setContent($letter_content);

            // Отправка письма
            $letter->commit();
            $letter->send();

            // Установка значения в поле статус отправки - заказ
            $order->setValue('sent_status', '856');
            $order->commit();
        }
    }
}
?>

Информация по коду.

В строке 029 происходит проверка полей статус оплаты и статус заказа. Если «статус оплаты» = «принят» и «статут отправки файла» = «не отправлен» или «статус оплаты» = «принят» и «статут отправки файла» = «не отправлен» то код будет отрабатываться.

if( $new_status == '47' && $sent_status != '856' || $new_status == '49' && $sent_status != '856' ) {

ID для данных переменных вы сможете найти в своих справочниках.

Участок кода:

$html = '<ul>';
foreach($order_items as $order_item) {
    $item = $order_item->getItemElement();

    $html .= "<li>" . $item->getValue('h1') . "</li>";

    // Получение файлов из объекта каталога
    if(iconv_strlen($item->getValue('fajl_1')) > 0) {
        $f = '.' . $item->getValue('fajl_1');

        $oFile = new umiFile($f);
        if (!$oFile->getIsBroken())  //Возвращает false, если файл существует и доступен скрипту на чтение.
            $letter->attachFile($oFile); // Прикрепление файлов к письму
    }

    // Получение файлов из объекта каталога
    if(iconv_strlen($item->getValue('fajl_2')) > 0) {
        $f = '.' . $item->getValue('fajl_2');
        $oFile = new umiFile($f);
        if (!$oFile->getIsBroken())  //Возвращает false, если файл существует и доступен скрипту на чтение.
            $letter->attachFile($oFile); // Прикрепление файлов к письму
    }
}
$html .= '</ul>';

Здесь вы можете добавлять доп. файлы для отправки в письме

И наконец:

// Установка значения в поле статус отправки - заказ
$order->setValue('sent_status', '856');
$order->commit();

Если письмо отправлено, то изменяется статус отправки файла на «отправлен».

Если вдруг в коде есть ошибки, и не работает, вы всегда можете найти на bitbucket.org последнюю версию шаблона.

Если вам понравился новый формат хранения шаблонов в UMI.CMS, то подробнее о подключении вы можете почитать в документации

Bookmark the permalink.

Также может быть интересно:

  • Артём

    Хорошая статья, только лучше не писать:

    «У вас в шаблоне должна присутствовать следующая иерархия папок — templatesdemodizzyclassesmodules»

    «demodizzy» это один из демошаблонов, совершенно не обязательно, что у каждого окажется такая папка, конечно, опытный разработчик вынесет из статьи все, что ему нужно, а новичок будет пытаться найти такую иерархию папок и его может постигнуть неудача)

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

    Нужно описать реализацию для старого и нового формата хранения шаблонов, или хотя бы упомянуть, что она подходит только на для нового формата и сделать сноску на документацию api.docs.umi-cms.ru/razra...iya_funkcionala/.

    • Спасибо за уточнение, Артем.

      Ваше пожелание учтено и в статью добавлен старый формат хранения шаблонов.

  • St.eV

    Добрый день!

    Мне нужно не отсылать письмо с файлом, а давать ссылку на скачивание. Причем с запретом скачивания для остальных пользователей и ограничением доступа на 2 скачивания. Как такое реализовать?

    И ещё вопрос — реально ли через 1 корзину продавать сразу 2 типа товаров — электронный (без доставки) и физический?

    • Реализовать конечно можно. Сложного ничего нет, ну или я по крайней мере не вижу.

      По поводу второго вопроса — опишите детальнее задачу, пожалуйста.

      • St.eV

        Можно — вот выдержка из ТЗ: umihelp.ru/forum/index.ph...845.msg7982.html

        • Данный функционал очень серьезный(в первом комментарии ошибся), и прямо скажу не готов реализовывать, а после расписывать в статье 🙁

          Сейчас даже сложно оценить объем работ.

          • St.eV

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