Как реализовать резервирование товаров — различия между версиями
Материал из Umicms
Mad grant (обсуждение | вклад) |
Mad grant (обсуждение | вклад) |
||
Строка 28: | Строка 28: | ||
[[Файл:Reservation_page.png]] | [[Файл:Reservation_page.png]] | ||
+ | |||
+ | === Резервирование при работе с корзиной === | ||
+ | К сожалению, стандартный метод emarket basket() совершенно не подойдет для решения функциональности, поэтому придется создаваться кастомный, пример ниже: | ||
+ | |||
+ | <source lang="php"> | ||
+ | /* | ||
+ | * Замена стандартного метода 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()); | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | Код метода нужно поместить в файл /classes/modules/emarket/__custom.php и не забудьте про пермишены. | ||
[[category:Модуль Интернет магазин]] | [[category:Модуль Интернет магазин]] |
Версия 14:59, 14 апреля 2014
Актуально для версии 2.9.6
Содержание
Задача
Допустим у Вас есть ряд товаров, количество которых ограничено и Вам необходимо создать для них резервирование, то есть, нужно реализовать примерно следующие возможности:
- Включить резервирование товара;
- Задать количество зарезервированного товара;
- Указать дату, до которой этот товар должен быть оплачен;
- Сделать, чтобы было невозможно совершить заказов, в котором количество товаров будет превышать резерв;
- Все действия с корзиной перед покупкой (изменения количества, удаление и добавление позиций) должны сразу отражаться на количество резерва;
- Если заказ с зарезервированным товаром не был переведен в статус "Готов" до даты, заданной в 3 пункте, то товарная позиция должна быть удалена из заказа;
- Если заказ был отмене или отклонен, то у зарезервированного товара должно быть восполнено его количество.
Все эти задачи можно решить только кастомно, ниже даются примеры.
Решение
Управление резервирование у товара
Сначала создадим поля, в которых будут храниться настройки резервирования для товаров. Для этого, создадим в типе данных "объект каталога" следующие поля:
Теперь у товаров появились настройки:
Резервирование при работе с корзиной
К сожалению, стандартный метод 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 и не забудьте про пермишены.