Списание со складов

Материал из Umicms
Перейти к:навигация, поиск

Актуально для версии 18 ревизия 85081

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

Задача: Реализовать функционал автоматического списания или возврата товара со склада.

Внимание: Данная реализация списывает количество товаров со склада только в условии, если "Статус заказа" изменяется в самом "Свойстве заказа"

Условия работы макроса:

  1. В модуле "Шаблоны данных" в типе данных "Заказ" должно присутствовать невидимое поле типа "Кнопка-флажок" с идентификатором current_mode
  2. В модуле "Шаблоны данных" в типе данных "Объекты каталога" должно присутствовать поле типа "Составное" с идентификатором 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 склада. По умолчанию списывание происходит с первого склада, товаров на котором больше нуля.