Обработка заказов
Обработка заказов в Shop-Script состоит в том, что над заказом выполняется действие, которое либо изменяет статус заказа, либо оставляет его статус без изменения. Действие может выполнять и другие операции на усмотрение разработчика. Информация о выполненном действии сохраняется в историю обработки заказа.
Все действия и статусы, настроенные в магазине, называются потоком. Настройки потока хранятся в конфигурационном файле wa-config/apps/shop/workflow.php. Если этого файла нет, то используется стандартный файл wa-apps/shop/lib/config/data/workflow.php.
Статус заказа
Статус заказа определяет то, какое текстовое обозначение написано рядом с номером заказа в бекенде и в личном кабинете покупателя. В бекенде статус влияет также на то, какие действия можно совершать с заказом в данный момент.
Каждый статус — это запись в актуальном файле workflow.php.
Пример
array(
'name' => 'Какой-то статус',
'options' => array(
// CSS-класс иконки статуса
'icon' => 'icon16 ss new',
// CSS-стили для показа заказов в этом статусе
'style' => array(
'color' => '#009900',
'font-weight' => 'bold',
),
),
// действия, доступные в этом статусе
'available_actions' => array(
'process',
'pay',
'ship',
'complete',
'comment',
'edit',
'editshippingdetails',
'message',
'delete',
),
// стандартное имя класса статуса, которое обычно не стоит изменять
'classname' => 'shopWorkflowState',
),
Действие с заказом
Действие определяет:
- как нужно изменить статус заказа,
- должен ли пользователь заполнить форму при выполнении действия,
- должно ли произойти что-то еще, кроме или вместо смены статуса заказа.
От настроек действия зависит, чем оно должно выполняться: кнопкой или ссылкой, и где именно на странице заказа в бекенде должен находиться этот элемент.
Действия могут выполняться пользователями явно либо скрытым образом, без прямого участия пользователя. Например, действия «Редактировать» или «В обработку» выполняются пользователем. А действия «Создать» и «Ответ платежной системы (callback)» выполняются программным способом — для их выполнения нет отдельных кнопок в интерфейсе пользователя .
Простое действие со стандартной функциональностью — это только запись в файле workflow.php.
Пример
array(
'name' => 'Обработать',
'options' => array(
// Где размещать кнопку или ссылку на действие на странице заказа
// '': кнопка действия с цветовой рамкой
// 'top': ссылка с иконкой в боковой панели
// 'bottom': ссылка с иконкой над историей заказа
'position' => 'bottom',
// CSS-класс иконки действия
'icon' => 'add',
// CSS-класс кнопки или ссылки
'button_class' => 'inline-link',
// Описание действия в истории обработки заказа
'log_record' => 'Добавлен комментарий к заказу',
// Если указать true, действие сразу покажет форму
// на странице заказа вместо кнопки или ссылки
'head' => false,
// Если указать true, то после нажатия на кнопку
// действие покажет веб-форму для ввода данных
'html' => false,
),
// В какой статус переводить заказ
// null: оставить статус без изменения
'state' => null,
// true: пометить действие как системное,
// не предназначенное для выполнения пользователем
'internal' => false,
// PHP-класс действия
'classname' => 'shopWorkflowAction',
),
Стандартная логика выполнения действия описана в классе shopWorkflowAction. Имя этого класса по умолчанию добавляется в запись о каждом новом действии в файл workflow.php, как показано в примере.
Нестандартные действия
Если вам нужна нестандартная логика для действия с заказами, замените для него в файле workflow.php имя базового класса shopWorkflowAction на собственный класс, унаследованный от него.
Если новое действие с собственным классом добавляется плагином, то плагин должен корректно обновить конфигурацию потока на случай удаления плагина. Иначе в файле workflow.php останутся ссылки на более не существующий класс удаленного плагина, а это вызовет ошибку в работе магазина.
В собственном классе действия нужно реализовать обязательный публичный метод execute(). Реализовывать и переопределять другие методы необязательно.
public function execute ($params = null)
В этом методе должен быть описан основной код, запускаемый при выполнении действия с заказом. Аргумент $params содержит ID заказа, с которым выполняется действие.
Если действие использует веб-форму для получения данных от пользователя, то в методе execute() эти данные доступны при помощи вызова waRequest::post(). Как показать пользователю веб-форму при выполнении действия, рассказано в описании метода getHTML().
Если действие выполнилось успешно, то метод должен вернуть непустой результат — он будет передан в качестве аргумента для вызова метода postExecute(). В противном случае postExecute() вызван не будет.
Стандартный метод postExecute() рассылает уведомления, настроенные для данного действия, и вызывает событие 'order_action.***' для плагинов.
public function postExecute ($order_id = null, $result = null)
Этому методу в качестве аргумента передается ID заказа и непустой результат, который вернул метод execute().
Полученный результат должен представлять собой ассоциативный массив. Необязательный элемент этого массива, который по умолчанию поддерживается методом postExecute() — это элемент с ключом 'update', который должен содержать подмассив элементов с ключами полей таблицы shop_order и дополнительным ключом 'params' — для сохранения параметров заказа в таблицу shop_order_params.
Массив $result также передается в качестве аргумента методам shopNotifications::sendEmail() и shopNotifications::sendSms(). Эти методы используют содержимое массива, чтобы сформировать текст уведомления, настроенного для данного действия. Содержимое массива $result вместе с результатом, который вернул метод execute(), доступно в Smarty-шаблонах уведомлений в виде переменной {$action_data}.
public function getButton()
Возвращает HTML-код кнопки или ссылки для отображения на странице заказа в бекенде, с помощью которой пользователь выполняет действие.
public function isAvailable ($order)
Выполняет дополнительную поверку доступности действия для данного заказа. Аргумент $order содержит ассоциативный массив свойств заказа. Доступность действия может зависеть, например, от статуса заказа, его состава и свойств покупателя.
Этот метод срабатывает, только если в настройках потока данное действие входит в число доступных для текущего статуса заказа.
public function getHTML ($order_id)
Показывает на странице заказа форму для ввода данных при выполнении действия, если значение параметра ['options']['html'] в свойствах действия равно true.
array(
'name' => 'Мое действие',
'options' => array(
'html' => true,
//...
),
//...
),
Значения, введенные пользователем в форму, доступны в коде метода execute() класса действия при помощи вызова waRequest::post().
Собственная веб-форма при выполнении действия
Для отображения формы по умолчанию используется стандартный шаблон wa-apps/shop/lib/workflow/templates/Action.html. Для того чтобы использовать собственный шаблон, добавьте в эту же директорию файл с именем вида [Action_id]Action.html. Форма должна отправлять данные методом post по адресу ?module=workflow&action=perform.
Форма должна содержать 2 поля типа hidden: id (номер заказа) и action_id (идентификатор действия).
При показе формы все видимые кнопки других действий автоматически скрываются. Поэтому в форме должна быть предусмотрена возможность скрыть ее и снова показать кнопки других действий.
Переопределять метод getHTML() стоит, только если нужно изменить стандартную логику метода родительского класса, а не только шаблон формы.
Поток
Программное изменение настроек потока
Пользовательские изменения настроек потока записываются в файл wa-config/apps/shop/workflow.php. Для этого удобно использовать статический метод shopWorkflow::setConfig($config). Он принимает в качестве аргумента массив, который должен стать содержимым конфигурационного файла.
Для чтения настроек потока используйте статический метод shopWorkflow::getConfig().
Чтобы выполнять действия, описанные в настройках потока, или получать информацию о них, нужно получить экземпляр класса shopWorkflow.
$workflow = new shopWorkflow();
Примеры работы с потоком
/**
* Получить список всех действий и информацию о каждом из них
*
* @var $actions array: action_id => shopWorkflowAction
*/
$actions = $workflow->getAllActions();
foreach ($actions as $action) {
$action->getId();
$action->getName();
$action->getOptions();
$action->getOption('icon');
}
/**
* Получить список всех статусов и информацию о каждом из них
*
* @var $actions array: state_id => shopWorkflowState
*/
$states = $workflow->getAllStates();
foreach($states as $state) {
$state->getId();
$state->getName();
$state->getOptions();
$state->getOption('icon');
}
/**
* Выполнить действие с заказом, если оно доступно для текущего статуса
*/
// 1. Получить информацию о заказе по ID
$order_model = new shopOrderModel();
$order = $order_model->getById($order_id);
// 2. Получить экземпляр класса потока
// и массив доступных действий для заказа по его статусу
$workflow = new shopWorkflow();
$actions = $workflow->getStateById($order['state_id'])->getActions($order);
// 3. Выполнить действие, если оно доступно для заказа в текущем статусе
if (isset($actions[$action_id])) {
$workflow->getActionById($action_id)->run($order_id);
}
/**
* Добавить новый статус в поток
*
* @var $new_state_id string e.g., 'some_state'
* @var $new_state_settings array
*/
$workflow = shopWorkflow::getConfig();
$workflow['states'][$new_state_id] = $new_state_settings;
shopWorkflow::setConfig($workflow);
/**
* Добавить новое действие в поток
*
* @var $new_action_id string e.g., 'some_action'
* @var $new_action_settings array
* @var $enabled_state_ids array e.g., array('new', 'processing', 'paid', 'shipped')
*/
// 1. Добавить действие
$workflow = shopWorkflow::getConfig();
$workflow['actions'][$new_action_id] = $new_action_settings;
// 2. Разрешить действие в перечисленных статусах
foreach($enabled_state_ids as $state_id) {
if (isset($workflow['states'][$state_id]['available_actions'])
&& !in_array($new_action_id, $workflow['states'][$state_id]['available_actions'])) {
$workflow['states'][$state_id]['available_actions'][] = $new_action_id;
}
}
// 3. Сохранить изменения
shopWorkflow::setConfig($workflow);









