Как реализовать резервирование товаров — различия между версиями

Материал из Umicms
Перейти к:навигация, поиск
Строка 35: Строка 35:
 
<source lang="php">
 
<source lang="php">
 
/*
 
/*
*  Замена стандартного метода emarket basket()
+
*  Замена стандартного метода emarket basket()
*
+
*
*  Отличия от ориганала:
+
*  Отличия от ориганала:
*  1) в зависимости от $mode дополнительно вызываются:
+
*  1) в зависимости от $mode дополнительно вызываются:
*    checkAmountAndPut()  для 'put'
+
*    checkAmountAndPut()  для 'put'
*    checkAmountAndRemove()  для 'remove'
+
*    checkAmountAndRemove()  для 'remove'
*    checkAmountAndRemoveAll()  для 'remove_all'
+
*    checkAmountAndRemoveAll()  для 'remove_all'
*  2) нет тройного вызова метода refresh();
+
*  2) нет тройного вызова метода refresh();
*/
+
*/
public function smartBasket($mode = false, $itemType = false, $itemId = false){
+
public function smartBasket($mode = false, $itemType = false, $itemId = false){
$mode = $mode ? $mode : getRequest('param0');
+
$mode = $mode ? $mode : getRequest('param0');
$order = emarket::getBasketOrder(!in_array($mode, array('put', 'remove')));
+
$order = emarket::getBasketOrder(!in_array($mode, array('put', 'remove')));
$itemType = $itemType ? $itemType : getRequest('param1');
+
$itemType = $itemType ? $itemType : getRequest('param1');
$itemId = (int) ($itemId ? $itemId : getRequest('param2'));
+
$itemId = (int) ($itemId ? $itemId : getRequest('param2'));
$amount = (int) getRequest('amount');
+
$amount = (int) getRequest('amount');
$options = getRequest('options');
+
$options = getRequest('options');
  
if($mode == 'put') {
+
if($mode == 'put') {
$newElement = false;
+
$newElement = false;
if ($itemType == 'element') {
+
if ($itemType == 'element') {
$orderItem = emarket::getBasketItem($itemId, false);
+
$orderItem = emarket::getBasketItem($itemId, false);
if (!$orderItem) {
+
if (!$orderItem) {
$orderItem = emarket::getBasketItem($itemId);
+
$orderItem = emarket::getBasketItem($itemId);
$newElement = true;
+
$newElement = true;
}
+
}
} else {
+
} else {
$orderItem = order::getItem($itemId);
+
$orderItem = order::getItem($itemId);
}
+
}
  
if (!$orderItem) {
+
if (!$orderItem) {
throw new publicException("Order item is not defined");
+
throw new publicException("Order item is not defined");
}
+
}
  
if(is_array($options)) {
+
if(is_array($options)) {
if($itemType != 'element') {
+
if($itemType != 'element') {
throw new publicException("Put basket method required element id of optionedOrderItem");
+
throw new publicException("Put basket method required element id of optionedOrderItem");
}
+
}
  
// Get all orderItems
+
// Get all orderItems
$orderItems = order::getItems();
+
$orderItems = order::getItems();
  
foreach($orderItems as $tOrderItem) {
+
foreach($orderItems as $tOrderItem) {
if (!$tOrderItem instanceOf optionedOrderItem) {
+
if (!$tOrderItem instanceOf optionedOrderItem) {
$itemOptions = null;
+
$itemOptions = null;
$tOrderItem = null;
+
$tOrderItem = null;
continue;
+
continue;
}
+
}
  
$itemOptions = $tOrderItem->getOptions();
+
$itemOptions = $tOrderItem->getOptions();
  
if(sizeof($itemOptions) != sizeof($options)) {
+
if(sizeof($itemOptions) != sizeof($options)) {
$itemOptions = null;
+
$itemOptions = null;
$tOrderItem = null;
+
$tOrderItem = null;
continue;
+
continue;
}
+
}
  
if($tOrderItem->getItemElement()->id != $orderItem->getItemElement()->id) {
+
if($tOrderItem->getItemElement()->id != $orderItem->getItemElement()->id) {
$itemOptions = null;
+
$itemOptions = null;
$tOrderItem = null;
+
$tOrderItem = null;
continue;
+
continue;
}
+
}
  
// Compare each tOrderItem with options list
+
// Compare each tOrderItem with options list
foreach($options as $optionName => $optionId) {
+
foreach($options as $optionName => $optionId) {
$itemOption = getArrayKey($itemOptions, $optionName);
+
$itemOption = getArrayKey($itemOptions, $optionName);
  
if(getArrayKey($itemOption, 'option-id') != $optionId) {
+
if(getArrayKey($itemOption, 'option-id') != $optionId) {
$tOrderItem = null;
+
$tOrderItem = null;
continue 2; // If does not match, create new item using options specified
+
continue 2; // If does not match, create new item using options specified
}
 
}
 
 
 
break; // If matches, stop loop and continue to amount change
 
 
}
 
}
 +
}
  
if(!isset($tOrderItem) || is_null($tOrderItem)) {
+
break; // If matches, stop loop and continue to amount change
$tOrderItem = orderItem::create($itemId);
+
}
$order->appendItem($tOrderItem);
 
if ($newElement) {
 
$orderItem->remove();
 
}
 
}
 
  
if($tOrderItem instanceof optionedOrderItem) {
+
if(!isset($tOrderItem) || is_null($tOrderItem)) {
foreach($options as $optionName => $optionId) {
+
$tOrderItem = orderItem::create($itemId);
if($optionId) {
+
$order->appendItem($tOrderItem);
$tOrderItem->appendOption($optionName, $optionId);
+
if ($newElement) {
} else {
+
$orderItem->remove();
$tOrderItem->removeOption($optionName);
+
}
}
+
}
}
 
}
 
  
if($tOrderItem) {
+
if($tOrderItem instanceof optionedOrderItem) {
$orderItem = $tOrderItem;
+
foreach($options as $optionName => $optionId) {
 +
if($optionId) {
 +
$tOrderItem->appendOption($optionName, $optionId);
 +
} else {
 +
$tOrderItem->removeOption($optionName);
 
}
 
}
 
}
 
}
self::checkAmountAndPut($itemId, $amount, $orderItem);
+
}
  
if($itemType == 'element') {
+
if($tOrderItem) {
$order->appendItem($orderItem);
+
$orderItem = $tOrderItem;
}
 
$order->refresh();
 
 
}
 
}
 +
}
 +
self::checkAmountAndPut($itemId, $amount, $orderItem);
 +
 +
if($itemType == 'element') {
 +
$order->appendItem($orderItem);
 +
}
 +
$order->refresh();
 +
}
  
if($mode == 'remove') {
+
if($mode == 'remove') {
+
$orderItem = ($itemType == 'element') ? emarket::getBasketItem($itemId, false) : orderItem::get($itemId);
+
$orderItem = ($itemType == 'element') ? emarket::getBasketItem($itemId, false) : orderItem::get($itemId);
self::checkAmountAndRemove($itemId, $orderItem, $order, $itemType);
+
self::checkAmountAndRemove($itemId, $orderItem, $order, $itemType);
}
+
}
  
if ($mode == 'remove_all') {
+
if ($mode == 'remove_all') {
self::checkAmountAndRemoveAll($order);
+
self::checkAmountAndRemoveAll($order);
}
+
}
  
$referer = getServer('HTTP_REFERER');
+
$referer = getServer('HTTP_REFERER');
$noRedirect = getRequest('no-redirect');
+
$noRedirect = getRequest('no-redirect');
  
if($redirectUri = getRequest('redirect-uri')) {
+
if($redirectUri = getRequest('redirect-uri')) {
$this->redirect($redirectUri);
+
$this->redirect($redirectUri);
} else if (!defined('VIA_HTTP_SCHEME') && !$noRedirect && $referer) {
+
} else if (!defined('VIA_HTTP_SCHEME') && !$noRedirect && $referer) {
$current = $_SERVER['REQUEST_URI'];
+
$current = $_SERVER['REQUEST_URI'];
if(substr($referer, -strlen($current)) == $current) {
+
if(substr($referer, -strlen($current)) == $current) {
if($itemType == 'element') {
+
if($itemType == 'element') {
$referer = umiHierarchy::getInstance()->getPathById($itemId);
+
$referer = umiHierarchy::getInstance()->getPathById($itemId);
} else {
+
} else {
$referer = "/";
+
$referer = "/";
}
 
}
 
$this->redirect($referer);
 
 
}
 
}
return $this->order($order->getId());
 
 
}
 
}
 +
$this->redirect($referer);
 +
}
 +
return $this->order($order->getId());
 +
}
 
</source>
 
</source>
  
 
Код метода нужно поместить в файл /classes/modules/emarket/__custom.php и не забудьте про пермишены.
 
Код метода нужно поместить в файл /classes/modules/emarket/__custom.php и не забудьте про пермишены.
 
  [[category:Модуль Интернет магазин]]
 
  [[category:Модуль Интернет магазин]]

Версия 15:00, 14 апреля 2014

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

Задача

Допустим у Вас есть ряд товаров, количество которых ограничено и Вам необходимо создать для них резервирование, то есть, нужно реализовать примерно следующие возможности:

  • Включить резервирование товара;
  • Задать количество зарезервированного товара;
  • Указать дату, до которой этот товар должен быть оплачен;
  • Сделать, чтобы было невозможно совершить заказов, в котором количество товаров будет превышать резерв;
  • Все действия с корзиной перед покупкой (изменения количества, удаление и добавление позиций) должны сразу отражаться на количество резерва;
  • Если заказ с зарезервированным товаром не был переведен в статус "Готов" до даты, заданной в 3 пункте, то товарная позиция должна быть удалена из заказа;
  • Если заказ был отмене или отклонен, то у зарезервированного товара должно быть восполнено его количество.

Все эти задачи можно решить только кастомно, ниже даются примеры.

Решение

Управление резервирование у товара

Сначала создадим поля, в которых будут храниться настройки резервирования для товаров. Для этого, создадим в типе данных "объект каталога" следующие поля:

Reservation fields.png

Теперь у товаров появились настройки:

Reservation page.png

Резервирование при работе с корзиной

К сожалению, стандартный метод emarket basket() совершенно не подойдет для решения функциональности, поэтому придется создаваться кастомный, пример ниже:

/*
*  Замена стандартного метода emarket basket()
*
*  Отличия от ориганала:
*  1) в зависимости от $mode дополнительно вызываются:
*     checkAmountAndPut()  для 'put'
*     checkAmountAndRemove()  для 'remove'
*     checkAmountAndRemoveAll()  для 'remove_all'
*  2) нет тройного вызова метода refresh();
*/
public function smartBasket($mode = false, $itemType = false, $itemId = false){			
	$mode = $mode ? $mode : getRequest('param0');
	$order = emarket::getBasketOrder(!in_array($mode, array('put', 'remove')));
	$itemType = $itemType ? $itemType : getRequest('param1');
	$itemId = (int) ($itemId ? $itemId : getRequest('param2'));
	$amount = (int) getRequest('amount');
	$options = getRequest('options');

	if($mode == 'put') {
		$newElement = false;
		if ($itemType == 'element') {
			$orderItem = emarket::getBasketItem($itemId, false);
			if (!$orderItem) {
				$orderItem = emarket::getBasketItem($itemId);
				$newElement = true;
			}
		} else {
			$orderItem = order::getItem($itemId);
		}

		if (!$orderItem) {
			throw new publicException("Order item is not defined");
		}

		if(is_array($options)) {
			if($itemType != 'element') {
				throw new publicException("Put basket method required element id of optionedOrderItem");
			}

			// Get all orderItems
			$orderItems = order::getItems();

			foreach($orderItems as $tOrderItem) {
				if (!$tOrderItem instanceOf optionedOrderItem) {
					$itemOptions = null;
					$tOrderItem = null;
					continue;
				}

				$itemOptions = $tOrderItem->getOptions();

				if(sizeof($itemOptions) != sizeof($options)) {
					$itemOptions = null;
					$tOrderItem = null;
					continue;
				}

				if($tOrderItem->getItemElement()->id != $orderItem->getItemElement()->id) {
					$itemOptions = null;
					$tOrderItem = null;
					continue;
				}

				// Compare each tOrderItem with options list
				foreach($options as $optionName => $optionId) {
					$itemOption = getArrayKey($itemOptions, $optionName);

					if(getArrayKey($itemOption, 'option-id') != $optionId) {
						$tOrderItem = null;
						continue 2;		// If does not match, create new item using options specified
					}
				}

				break;	// If matches, stop loop and continue to amount change
			}

			if(!isset($tOrderItem) || is_null($tOrderItem)) {
				$tOrderItem = orderItem::create($itemId);
				$order->appendItem($tOrderItem);
				if ($newElement) {
					$orderItem->remove();
				}
			}

			if($tOrderItem instanceof optionedOrderItem) {
				foreach($options as $optionName => $optionId) {
					if($optionId) {
						$tOrderItem->appendOption($optionName, $optionId);
					} else {
						$tOrderItem->removeOption($optionName);
					}
				}
			}

			if($tOrderItem) {
				$orderItem = $tOrderItem;
			}
		}
		self::checkAmountAndPut($itemId, $amount, $orderItem);				

		if($itemType == 'element') {
			$order->appendItem($orderItem);
		}
		$order->refresh();
	}

	if($mode == 'remove') {
		
		$orderItem = ($itemType == 'element') ? emarket::getBasketItem($itemId, false) : orderItem::get($itemId);
		self::checkAmountAndRemove($itemId, $orderItem, $order, $itemType);
	}

	if ($mode == 'remove_all') {
		self::checkAmountAndRemoveAll($order);
	}

	$referer = getServer('HTTP_REFERER');
	$noRedirect = getRequest('no-redirect');

	if($redirectUri = getRequest('redirect-uri')) {
		$this->redirect($redirectUri);
	} else if (!defined('VIA_HTTP_SCHEME') && !$noRedirect && $referer) {
		$current = $_SERVER['REQUEST_URI'];
		if(substr($referer, -strlen($current)) == $current) {
			if($itemType == 'element') {
				$referer = umiHierarchy::getInstance()->getPathById($itemId);
			} else {
				$referer = "/";
			}
		}
		$this->redirect($referer);
	}
	return $this->order($order->getId());
}

Код метода нужно поместить в файл /classes/modules/emarket/__custom.php и не забудьте про пермишены.