Списание со складов
Актуально для версии 18 ревизия 85081
В системе UMI.CMS склады введены в основном для наглядности и для удобства менеджерам, обрабатывающим заказ. В этой статье мы добавим данным параметрам функциональности и организуем списание со склада.
Задача: Реализовать функционал автоматического списания или возврата товара со склада.
Внимание: Данная реализация списывает количество товаров со склада только в условии, если "Статус заказа" изменяется в самом "Свойства заказа"
Условия работы макроса:
- В модуле "Шаблоны данных" в типе данных "Заказ" должно присутствовать невидимое поле типа "Кнопка-флажок" с идентификатором current_mode
- В модуле "Шаблоны данных" в типе данных "Объекты каталога" должно присутствовать поле типа "Составное" с идентификатором stores_state ("Состояние на складах")
Реализация: Напишем обработчик события для точки вызова systemModifyObject, которое вызывается при сохранении объекта в административной панели. Вся логика списания или возврата будет находиться в обработчике события. Списание происходит, если статус заказа был изменен на "Готов" (статус 'ready'); возврат товара со склада, если статус заказа был изменен на "Отменен" (статус 'canceled').
Код состоит из четырех методов, описание которых представлено ниже:
- public function storesReact ($event): обработчик события для точки вызова systemModifyObject
- $event - параметр, экземпляр iUmiEventPoint
- protected function changeAmount($mode = 'w', $itemId, $storeId, $amount = 1): Метод списания или возврата на склад
- $mode - режим, списание - 'w', возврат 'b'
- $itemId - id объекта каталога
- $storeId - id элемента склада
- $amount - количество товара для списания или возврата
- protected function changeAllAmounts($mode='w', $data): метод списания или возврата всех товаров со складов
- $mode - режим, списание - 'w', возврат 'b'
- $data - массив, ключами которого являются id объекта каталога, а значениями количество товара для списания или возврата
- protected function getStoreId ($stores): метод определения id элемента склада, то есть с какого склада списывать
- $stores - массив, предоставляющий результат работы метода getValue('stores_state')
В директорию classes\modules\emarket добавим файл с названием custom_events.php, если у Вас новая реализация модулей то в директорию classes\components\emarket\customAdmin в файл с названием custom_events.php и содержанием:
<?php
new umiEventListener("systemModifyObject", "emarket", "storesReact");
В файл classes\modules\emarket\__custom_adm.php или classes\components\emarket\customAdmin в зависимости от реализации модулей, добавим код обработчика события:
public function storesReact($event){
$mode = $event->getMode();
if ($mode == 'after'){
$subject = $event->getRef('object');
$typesCollection = umiObjectTypesCollection::getInstance();
$umiHierarchy = umiHierarchy::getInstance();
$subjectTypeId = $subject->getTypeId();
$subjectType = $typesCollection->getType($subjectTypeId);
$subjectModule = $subjectType->getModule();
$subjectMethod = $subjectType->getMethod();
if ($subjectModule == 'emarket' && $subjectMethod == 'order'){
$subjectOrder = order::get($subject->id);
$orderStatusId = $subject->getValue('status_id');
$orderStatus = order::getCodeByStatus($orderStatusId);
$currentSwitchMode = $subject->getValue('current_mode');
if (is_null($currentSwitchMode))
$currentSwitchMode = false;
$itemsArray = $subjectOrder->getItems();
$data = array();
foreach($itemsArray as $item){
$catalogObject = $item->getItemElement();
$catalogObjectId = $catalogObject->id;
$itemAmount = $item->getAmount();
$data[$catalogObjectId] = $itemAmount;
}
if ($orderStatus == 'ready'){
if (!$currentSwitchMode){
$changed = self::changeAllAmounts('w', $data);
if ($changed)
$subject->setValue('current_mode', 1);
}
}
if ($orderStatus == 'canceled'){
if ($currentSwitchMode){
$changed = self::changeAllAmounts('b', $data);
if ($changed)
$subject->setValue('current_mode', 0);
}
}
}
}
}
protected function changeAmount($mode = 'w', $itemId, $storeId, $amount = 1){
// mode 'w' - write off
// mode 'b' - get back
$amount = intval($amount);
$umiHierarchy = umiHierarchy::getInstance();
$item = $umiHierarchy->getElement($itemId);
$data = array();
if ($item instanceof umiHierarchyElement){
$stores = $item->getValue('stores_state');
foreach ($stores as $key => $store){
if (in_array($storeId, $store)){
$currentIndex = $key;
$currentValue = $store['int'];
}
}
if (!isset($currentValue) || !isset($key))
return false;
$amountNow = $currentValue;
if ($mode == 'w')
$amountNow = $currentValue - $amount;
else
$amountNow = $currentValue + $amount;
$storesNow = array();
$stores[$currentIndex]['int'] = $amountNow;
foreach ($stores as $store){
$storesNow[] = array('int' => $store['int'], 'rel' => $store['rel']);
}
$item->setValue('stores_state', $storesNow);
return true;
}
}
protected function changeAllAmounts($mode='w', $data){
$umiHierarchy = umiHierarchy::getInstance();
foreach ($data as $id => $amount){
$catalogItem = $umiHierarchy->getElement($id);
$stores = $catalogItem->getValue('stores_state');
$storeId = self::getStoreId($stores);
$changed = self::changeAmount($mode, $id, $storeId, $amount);
}
if ($changed)
return true;
}
protected function getStoreId($stores){
if (!is_array($stores))
return false;
// Insert Your store id choosing logic
$currentKey = 0;
foreach ($stores as $key => $store){
if (intval($store['int']) > 0){
$currentKey = $key;
break;
}
}
if (is_numeric($stores[$currentKey]['rel']))
return $stores[$currentKey]['rel'];
}
В метод getStoreId() Вы можете добавить свой код для определения id склада. По умолчанию списывание происходит с первого склада, товаров на котором больше нуля.