Списание со складов — различия между версиями
Davidov (обсуждение | вклад) (Новая страница: «В системе UMI.CMS склады введены в основном для наглядности и для удобства менеджерам, обраба…») |
Aposio (обсуждение | вклад) |
||
(не показано 15 промежуточных версий 7 участников) | |||
Строка 1: | Строка 1: | ||
− | В системе UMI.CMS склады введены в основном для наглядности и для удобства менеджерам, обрабатывающим заказ. | + | '''Актуально для версии 18 ревизия 85081'''<br><br> |
+ | В системе UMI.CMS склады введены в основном для наглядности и для удобства менеджерам, обрабатывающим заказ. В этой статье мы добавим данным параметрам функциональности и организуем списание со склада.<br><br> | ||
− | + | '''Задача:''' Реализовать функционал автоматического списания или возврата товара со склада.<br><br> | |
− | + | '''Внимание:''' Данная реализация списывает количество товаров со склада только в условии, если "Статус заказа" изменяется в самом "Свойстве заказа"<br><br> | |
+ | '''Условия работы макроса:''' | ||
+ | <ol> | ||
+ | <li>В модуле "Шаблоны данных" в типе данных "Заказ" должно присутствовать невидимое поле типа "Кнопка-флажок" с идентификатором ''current_mode''</li> | ||
+ | <li>В модуле "Шаблоны данных" в типе данных "Объекты каталога" должно присутствовать поле типа "Составное" с идентификатором ''stores_state'' ("Состояние на складах")</li> | ||
+ | </ol> | ||
+ | <br> | ||
+ | '''Реализация:''' Напишем обработчик события для точки вызова systemModifyObject, которое вызывается при сохранении объекта в административной панели. Вся логика списания или возврата будет находиться в обработчике события. Списание происходит, если статус заказа был изменен на "Готов" (статус 'ready'); возврат товара со склада, если статус заказа был изменен на "Отменен" (статус 'canceled').<br> | ||
+ | Код состоит из четырех методов, описание которых представлено ниже: | ||
+ | <ul> | ||
+ | <li>public function '''storesReact ($event)''': обработчик события для точки вызова systemModifyObject <ul><li>$event - параметр, экземпляр iUmiEventPoint </li></ul></li> | ||
+ | <li>protected function '''changeAmount($mode = 'w', $itemId, $storeId, $amount = 1):''' Метод списания или возврата на склад | ||
+ | <ul><li>$mode - режим, списание - 'w', возврат 'b'</li> | ||
+ | <li>$itemId - id объекта каталога</li> | ||
+ | <li>$storeId - id элемента склада</li> | ||
+ | <li>$amount - количество товара для списания или возврата</li> | ||
+ | </ul></li> | ||
+ | </li> | ||
+ | <li>protected function '''changeAllAmounts($mode='w', $data):''' метод списания или возврата всех товаров со складов | ||
+ | <ul><li>$mode - режим, списание - 'w', возврат 'b'</li> | ||
+ | <li>$data - массив, ключами которого являются id объекта каталога, а значениями количество товара для списания или возврата</li> | ||
+ | |||
+ | </ul> | ||
+ | </li> | ||
+ | <li>protected function '''getStoreId ($stores):''' метод определения id элемента склада, то есть с какого склада списывать | ||
+ | <ul><li>$stores - массив, предоставляющий результат работы метода getValue('stores_state') </li></ul></li> | ||
+ | </ul> | ||
+ | <br><br> | ||
+ | Добавим в директорию classes\modules\emarket файл с названием custom_events.php или если у Вас новая реализация модулей то в директорию classes\components\emarket файл с названием custom_events.php и содержанием: | ||
<source lang="php"> | <source lang="php"> | ||
− | + | <?php | |
− | + | new umiEventListener("systemModifyObject", "emarket", "storesReact"); | |
− | + | </source> | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | В файл classes\modules\emarket\__custom_adm.php или classes\components\emarket\customAdmin.php в зависимости от реализации модулей, добавим код обработчика события: | |
− | + | <source lang="php"> | |
− | + | 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($ | + | |
− | if($ | + | 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']; | ||
} | } | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
</source> | </source> | ||
− | + | В метод getStoreId() Вы можете добавить свой код для определения id склада. По умолчанию списывание происходит с первого склада, товаров на котором больше нуля. | |
− | + | [[category:Написание кастомных макросов]] | |
− | [[ |
Текущая версия на 08:27, 22 ноября 2019
Актуально для версии 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 файл с названием custom_events.php и содержанием:
<?php
new umiEventListener("systemModifyObject", "emarket", "storesReact");
В файл classes\modules\emarket\__custom_adm.php или classes\components\emarket\customAdmin.php в зависимости от реализации модулей, добавим код обработчика события:
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 склада. По умолчанию списывание происходит с первого склада, товаров на котором больше нуля.