%PDF- %PDF-
Direktori : /proc/self/root/home/bitrix/www/bitrix/modules/sale/lib/compatible/ |
Current File : //proc/self/root/home/bitrix/www/bitrix/modules/sale/lib/compatible/discountcompatibility.php |
<?php namespace Bitrix\Sale\Compatible; use Bitrix\Main, Bitrix\Sale, Bitrix\Sale\Discount, Bitrix\Main\Localization\Loc; Loc::loadMessages(__FILE__); class DiscountCompatibility { const MODE_CLIENT = 0x0001; const MODE_MANAGER = 0x0002; const MODE_ORDER = 0x0004; const MODE_SYSTEM = 0x0008; const MODE_EXTERNAL = 0x0010; const MODE_DISABLED = 0x0020; const ERROR_ID = 'BX_SALE_DISCOUNT_COMPATIBILITY'; protected static $init = false; protected static $useMode = self::MODE_CLIENT; protected static $errors = array(); protected static $config = array(); protected static $order = null; protected static $discountUseMode = null; protected static $basketBasePrice = array(); protected static $basketDiscountList = array(); protected static $basketItemsData = array(); protected static $discountResult = array(); protected static $discountsCache = array(); protected static $couponsCache = array(); protected static $previousOrderData = array(); protected static $currentOrderData = array(); protected static $compatibleSaleDiscountResult = array(); protected static $useCompatible = false; protected static $shipmentOrder = null; protected static $shipmentId = null; protected static $basketCodes = array(); protected static $saved = false; protected static $repeatSave = false; /** * Handler for use old api. * * @param Main\Event $event Event data. * @return Main\EventResult */ public static function OnSaleBasketItemRefreshData(Main\Event $event) { if (static::isInited() && static::usedByClient()) { $parameters = $event->getParameters(); /** @var \Bitrix\Sale\BasketItem $basketItem */ $basketItem = $parameters['ENTITY']; /** @var array $values */ $values = $parameters['PREPARED_VALUES']; unset($parameters); if ( $basketItem instanceof Sale\BasketItem && $basketItem->canBuy() && !empty($values) && is_array($values) ) { static::setBasketItemData($basketItem->getBasketCode(), $values); } unset($values, $basketItem); } return new Main\EventResult(Main\EventResult::SUCCESS, null, 'sale'); } /** * Init use mode. * * @param int $mode Save discount information mode. * @param array $config Initial params (site, currency). * keys are case sensitive: * <ul> * <li>string SITE_ID Current site * <li>string CURRENCY Site currency * <li>string ORDER_ID Order id * </ul>. * @return void */ public static function initUseMode($mode = self::MODE_CLIENT, $config = array()) { $adminSection = (defined('ADMIN_SECTION') && ADMIN_SECTION === true); $mode = (int)$mode; if (!is_array($config)) $config = array(); if ($adminSection) { self::$useMode = self::MODE_SYSTEM; switch ($mode) { case self::MODE_MANAGER: if (empty($config['SITE_ID'])) self::$errors[] = Loc::getMessage('BX_SALE_DCL_ERR_SITE_ABSENT'); elseif (empty($config['CURRENCY'])) $config['CURRENCY'] = Sale\Internals\SiteCurrencyTable::getCurrency($config['SITE_ID']); if (empty($config['CURRENCY'])) self::$errors[] = Loc::getMessage('BX_SALE_DCL_ERR_CURRENCY_ABSENT'); if (empty(self::$errors)) { self::$useMode = self::MODE_MANAGER; $config['SALE_DISCOUNT_ONLY'] = (string)Main\Config\Option::get('sale', 'use_sale_discount_only'); self::$config = $config; self::$discountUseMode = Sale\Discount::USE_MODE_FULL; } break; case self::MODE_ORDER: if (empty($config['ORDER_ID'])) self::$errors[] = Loc::getMessage('BX_SALE_DCL_ERR_ORDER_ID_ABSENT'); if (empty($config['SITE_ID'])) self::$errors[] = Loc::getMessage('BX_SALE_DCL_ERR_SITE_ABSENT'); if (empty($config['CURRENCY'])) self::$errors[] = Loc::getMessage('BX_SALE_DCL_ERR_CURRENCY_ABSENT'); if (empty(self::$errors)) { self::$useMode = self::MODE_ORDER; self::$order = $config['ORDER_ID']; unset($config['ORDER_ID']); self::$config = $config; } break; case self::MODE_SYSTEM: break; default: self::$errors[] = Loc::getMessage('BX_SALE_DCL_ERR_BAD_MODE'); } } else { self::$useMode = self::MODE_SYSTEM; switch ($mode) { case self::MODE_CLIENT: self::$useMode = self::MODE_CLIENT; if (empty($config['SITE_ID'])) $config['SITE_ID'] = SITE_ID; if (empty($config['CURRENCY'])) $config['CURRENCY'] = Sale\Internals\SiteCurrencyTable::getSiteCurrency($config['SITE_ID']); $config['SALE_DISCOUNT_ONLY'] = (string)Main\Config\Option::get('sale', 'use_sale_discount_only'); self::$config = $config; self::$discountUseMode = Sale\Discount::USE_MODE_FULL; break; case self::MODE_EXTERNAL: self::$useMode = self::MODE_EXTERNAL; if (empty($config['SITE_ID'])) $config['SITE_ID'] = SITE_ID; if (empty($config['CURRENCY'])) $config['CURRENCY'] = Sale\Internals\SiteCurrencyTable::getSiteCurrency($config['SITE_ID']); $config['SALE_DISCOUNT_ONLY'] = (string)Main\Config\Option::get('sale', 'use_sale_discount_only'); self::$config = $config; self::$discountUseMode = Sale\Discount::USE_MODE_FULL; break; case self::MODE_SYSTEM: break; case self::MODE_DISABLED: self::$useMode = self::MODE_DISABLED; break; default: self::$errors[] = Loc::getMessage('BX_SALE_DCL_ERR_BAD_MODE'); break; } } } /** * Return use mode. * * @return int */ public static function getUseMode() { return self::$useMode; } /** * Check client use mode. * * @return bool */ public static function usedByClient() { return (self::$useMode == self::MODE_CLIENT); } /** * Check manager use mode. * * @return bool */ public static function usedByManager() { return (self::$useMode == self::MODE_MANAGER || self::$useMode == self::MODE_ORDER); } /** * Return saved flag (for old components only). Use ONLY kernel developers. * @internal * * @return bool */ public static function isSaved() { return self::$saved; } /** * Set save flag (for old components only). Use ONLY kernel developers. * @internal * * @param bool $save Save flag. * @return void */ public static function setSaved($save) { if ($save !== true && $save !== false) return; self::$saved = $save; } /** * Return repeat save flag (for old components only). Use ONLY kernel developers. * @internal * * @return bool */ public static function isRepeatSave() { return self::$repeatSave; } /** * Set repeat flag (for old components only). Use ONLY kernel developers. * @internal * * @param bool $repeat Repeat flag. * @return void */ public static function setRepeatSave($repeat) { if ($repeat !== true && $repeat !== false) return; self::$repeatSave = $repeat; } /** * Return result operation. * * @return bool */ public static function isSuccess() { return empty(self::$errors); } /** * Return error list. * * @return array */ public static function getErrors() { return self::$errors; } /** * Clear errors list. * * @return void */ public static function clearErrors() { self::$errors = array(); } /** * Returns configuration parameters. * * @return array */ public static function getConfig() { return self::$config; } /** * Set shipment. * * @param int $order Order id. * @param int|array $shipment Shipment id. * @return void */ public static function setShipment($order, $shipment) { self::$shipmentOrder = $order; self::$shipmentId = $shipment; } /** * Initialization discount save information. * * @param int $mode Discount manager mode. * @param array $config Initial params (site, currency, order). * @return void */ public static function init($mode = self::MODE_CLIENT, $config = array()) { if (self::$init) return; self::clearErrors(); self::initUseMode($mode, $config); if (!self::isSuccess()) return; self::$basketBasePrice = array(); self::$basketDiscountList = array(); self::$basketItemsData = array(); self::$useCompatible = true; Sale\OrderDiscountManager::setManagerConfig(self::$config); self::$saved = false; self::$repeatSave = false; self::$init = true; } /** * Reinitialization discount save information. * * @param int $mode Discount manager mode. * @param array $config Initial params (site, currency, order). * @return void */ public static function reInit($mode = self::MODE_CLIENT, $config = array()) { self::$init = false; self::init($mode, $config); } /** * Check initialization. * * @return bool */ public static function isInited() { return self::$init; } /** * Check used compatible calculate. * * @return bool */ public static function isUsed() { return self::$useCompatible; } /** * Stops usage compatible mode. It's important for situation with new API and old API. * Be careful! Don't forget revert this action. * * @internal * @return void */ public static function stopUsageCompatible() { if(self::$useCompatible) { self::$useCompatible = false; } } /** * Reverts usage compatible mode. It's important for situation with new API and old API. * * @internal * @return void */ public static function revertUsageCompatible() { if(self::$init && !self::$useCompatible) { self::$useCompatible = true; } } /** * Set base price for basket item. * * @param string|int $code Basket code. * @param float $price Price. * @param string $currency Currency. * @return void */ public static function setBasketItemBasePrice($code, $price, $currency) { if (!self::$init) self::init(); if (!self::isSuccess() || self::$useMode == self::MODE_SYSTEM || self::$useMode == self::MODE_DISABLED) return; /** @noinspection PhpMethodOrClassCallIsNotCaseSensitiveInspection */ self::$basketBasePrice[$code] = ( $currency == self::$config['CURRENCY'] ? $price : \CCurrencyRates::convertCurrency($price, $currency, self::$config['CURRENCY']) ); } /** * Set base price for all basket items. * * @param array $basket Basket. * @return void * @throws Main\ArgumentNullException */ public static function setBasketBasePrice($basket) { if (!self::$init) self::init(); if (!self::isSuccess() || self::$useMode == self::MODE_SYSTEM || self::$useMode == self::MODE_DISABLED) return; self::$basketBasePrice = array(); if (empty($basket) || !is_array($basket)) return; foreach ($basket as $code => $basketItem) { /** @noinspection PhpMethodOrClassCallIsNotCaseSensitiveInspection */ self::$basketBasePrice[$code] = ( $basketItem['CURRENCY'] == self::$config['CURRENCY'] ? $basketItem['PRICE'] : \CCurrencyRates::convertCurrency($basketItem['PRICE'], $basketItem['CURRENCY'], self::$config['CURRENCY']) ); } unset($code, $basketItem); } /** * Get base price for basket item. * * @param string|int $code Basket code. * @return float|null */ public static function getBasketItemBasePrice($code) { if (!self::$init) self::init(); return (isset(self::$basketBasePrice[$code]) ? self::$basketBasePrice[$code] : null); } /** * Set product discounts for basket item. * * @param string|int $code Basket code. * @param array $discountList Discount list. * @return void */ public static function setBasketItemDiscounts($code, $discountList) { if (!self::$init) self::init(); if (!self::isSuccess() || self::$useMode == self::MODE_SYSTEM || self::$useMode == self::MODE_DISABLED) return; if (self::$config['SALE_DISCOUNT_ONLY'] == 'Y') return; if (!is_array($discountList)) return; self::$basketDiscountList[$code] = $discountList; } /** * Get product discounts for basket item. * * @param string|int $code Basket code. * @return null|array */ public static function getBasketItemDiscounts($code) { if (!self::$init) self::init(); if (self::$config['SALE_DISCOUNT_ONLY'] == 'Y') return null; return (isset(self::$basketDiscountList[$code]) ? self::$basketDiscountList[$code] : null); } /** * @param int|string $code Basket code. * @param array $providerData Product data from provider. * @return void */ public static function setBasketItemData($code, $providerData) { if ($code == '' || empty($providerData) || !is_array($providerData)) return; if (isset($providerData['CUSTOM_PRICE']) && $providerData['CUSTOM_PRICE'] == 'Y') { static::clearBasketItemData($code); return; } if (isset($providerData['BASE_PRICE']) && isset($providerData['CURRENCY'])) static::setBasketItemBasePrice($code, $providerData['BASE_PRICE'], $providerData['CURRENCY']); if (isset($providerData['DISCOUNT_LIST'])) { if (!empty($providerData['DISCOUNT_LIST']) || isset(self::$basketDiscountList[$code])) static::setBasketItemDiscounts($code, $providerData['DISCOUNT_LIST']); } $fields['PRICE'] = static::getBasketItemBasePrice($code); if (empty($fields['PRICE'])) return; self::$basketItemsData[$code] = $providerData; $fields['DISCOUNT_PRICE'] = 0; $fields['CURRENCY'] = self::$config['CURRENCY']; if (self::$config['SALE_DISCOUNT_ONLY'] == 'Y') return; static::calculateBasketItemDiscount($code, $fields); } /** * Clear basket item data. * * @param int $code Basket code. * @return void */ public static function clearBasketItemData($code) { if (isset(self::$basketBasePrice[$code])) unset(self::$basketBasePrice[$code]); if (isset(self::$basketDiscountList[$code])) unset(self::$basketDiscountList[$code]); if (isset(self::$discountResult['BASKET'][$code])) unset(self::$discountResult['BASKET'][$code]); if (isset(self::$basketItemsData[$code])) unset(self::$basketItemsData[$code]); } /** * Clear results before calculate. * * @return void */ public static function clearDiscountResult() { self::$discountResult = array( 'BASKET' => array(), 'BASKET_ROUND' => array(), 'ORDER' => array() ); self::$compatibleSaleDiscountResult = array(); } /** * Fill base prices. * * @param array &$basket Basket data. * @return void */ public static function fillBasketData(&$basket) { if (!self::$init) self::init(); if (!self::isSuccess() || self::$useMode == self::MODE_SYSTEM || self::$useMode == self::MODE_DISABLED) return; if (empty($basket) || !is_array($basket)) return; $publicMode = self::usedByClient(); $loadBasketProperties = array(); foreach ($basket as $basketCode => $basketItem) { $code = ($publicMode ? $basketItem['ID'] : $basketCode); if (!isset($basketItem['DISCOUNT_PRICE'])) $basketItem['DISCOUNT_PRICE'] = 0; if (!isset($basketItem['BASE_PRICE'])) { $basketItem['BASE_PRICE'] = (isset(self::$basketBasePrice[$code]) ? self::$basketBasePrice[$code] : $basketItem['PRICE'] + $basketItem['DISCOUNT_PRICE'] ); } $checkProperties = true; if (self::isCustomPrice($basketItem)) { if (array_key_exists($code, self::$basketDiscountList)) unset(self::$basketDiscountList[$code]); $checkProperties = false; } if (\CSaleBasketHelper::isSetItem($basketItem)) { $basketItem['PRICE'] = $basketItem['BASE_PRICE']; $basketItem['DISCOUNT_PRICE'] = 0; $checkProperties = false; } if (isset(self::$basketItemsData[$code])) { if (isset(self::$basketItemsData[$code]['PRICE_TYPE_ID'])) $basketItem['PRICE_TYPE_ID'] = self::$basketItemsData[$code]['PRICE_TYPE_ID']; } if ($checkProperties) { if (!isset($basketItem['PROPERTIES'])) { if (isset($basketItem['PROPS'])) $basketItem['PROPERTIES'] = $basketItem['PROPS']; elseif (isset($basketItem['ID'])) { $loadBasketProperties[$basketItem['ID']] = $basketCode; $basketItem['PROPERTIES'] = array(); } } } $basketItem['ACTION_APPLIED'] = 'N'; $basket[$basketCode] = $basketItem; } if (!empty($loadBasketProperties)) { $iterator = Sale\BasketPropertiesCollection::getList(array( 'select' => array('*'), 'filter' => array('BASKET_ID' => 'ASC', 'SORT' => 'ASC', 'ID' => 'ASC') )); while ($row = $iterator->fetch()) { $id = $row['ID']; if (!isset($loadBasketProperties[$id])) continue; $basketCode = $loadBasketProperties[$id]; $basket[$basketCode]['PROPERTIES'][] = array( 'CODE' => ((string)$row['CODE'] != '' ? $row['CODE'] : $row['NAME']), 'ID' => $row['ID'], 'VALUE' => $row['VALUE'], 'SORT' => $row['SORT'], 'NAME' => $row['NAME'] ); } unset($row, $iterator); } unset($loadBasketProperties); unset($basketCode, $basketItem); } /** * Calculate basket discounts for save. * * @param array &$basket Basket items. * @return bool */ public static function calculateBasketDiscounts(&$basket) { if (!self::$init) return false; if (!self::isSuccess() || self::$useMode == self::MODE_SYSTEM || self::$useMode == self::MODE_DISABLED) return false; if (empty($basket) || !is_array($basket)) return false; Sale\DiscountCouponsManager::clearApply(); if (self::$config['SALE_DISCOUNT_ONLY'] == 'Y' || empty(self::$basketDiscountList)) return true; $publicMode = self::usedByClient(); foreach ($basket as $basketCode => $basketItem) { $code = ($publicMode ? $basketItem['ID'] : $basketCode); if (!static::calculateBasketItemDiscount($code, $basketItem)) return false; if (!empty(self::$discountResult['BASKET'][$code])) { foreach (self::$discountResult['BASKET'][$code] as $row) { if ($row['RESULT']['APPLY'] == 'Y') { $basket[$basketCode]['ACTION_APPLIED'] = 'Y'; break; } } unset($row); } } unset($basketCode, $basketItem); return true; } /** * Save apply mode information. * * @param array &$basket Basket items. * @return void */ public static function setApplyMode(&$basket) { if (!self::$init) return; if (!self::isSuccess() || self::$useMode == self::MODE_SYSTEM || self::$useMode == self::MODE_DISABLED) return; if (empty($basket) || !is_array($basket)) return; $publicMode = self::usedByClient(); switch (Sale\Discount::getApplyMode()) { case Sale\Discount::APPLY_MODE_DISABLE: case Sale\Discount::APPLY_MODE_FULL_DISABLE: foreach ($basket as $basketCode => $basketItem) { $code = ($publicMode ? $basketItem['ID'] : $basketCode); if (isset(self::$basketDiscountList[$code]) && !empty(self::$basketDiscountList[$code])) $basket[$basketCode]['LAST_DISCOUNT'] = 'Y'; unset($code); } unset($basketCode, $basketItem); break; case Sale\Discount::APPLY_MODE_LAST: case Sale\Discount::APPLY_MODE_FULL_LAST: foreach ($basket as $basketCode => $basketItem) { $code = ($publicMode ? $basketItem['ID'] : $basketCode); if (!isset(self::$basketDiscountList[$code]) || empty(self::$basketDiscountList[$code])) continue; $lastDiscount = end(self::$basketDiscountList[$code]); if (!empty($lastDiscount['LAST_DISCOUNT']) && $lastDiscount['LAST_DISCOUNT'] == 'Y') $basket[$basketCode]['LAST_DISCOUNT'] = 'Y'; } unset($basketCode, $basketItem); break; case Sale\Discount::APPLY_MODE_ADD: break; } } /** * Push to stack current order data. * * @param array $order Current order data. * @return void */ public static function setOrderData($order) { if (array_key_exists('DISCOUNT_DESCR', $order)) unset($order['DISCOUNT_DESCR']); if (array_key_exists('DISCOUNT_RESULT', $order)) unset($order['DISCOUNT_RESULT']); self::$previousOrderData = $order; } /** * Save result discount list from CSaleDiscount::DoProcessOrder. * * @param array $discountList Result from CSaleDiscount::DoProcessOrder. * @return void */ public static function setOldDiscountResult($discountList) { self::$compatibleSaleDiscountResult = $discountList; } /** * Return result discount list in old format. Compatibility only. * * @return array */ public static function getOldDiscountResult() { return self::$compatibleSaleDiscountResult; } /** * Save sale discount. * * @param array &$order Current order data. * @param array $discount Discount data. * @return bool */ public static function calculateSaleDiscount(&$order, $discount) { if (!self::$init) self::init(); if (!self::isSuccess()) return false; $order['DISCOUNT_RESULT'] = Sale\Discount\Actions::getActionResult(); $order['DISCOUNT_DESCR'] = Sale\Discount\Actions::getActionDescription(); if (!empty($order['DISCOUNT_RESULT']) && is_array($order['DISCOUNT_RESULT'])) { $stepResult = self::getStepResult($order); } else { $stepResult = self::getStepResultOld($order); if (!empty($stepResult)) { if (empty($order['DISCOUNT_DESCR']) || !is_array($order['DISCOUNT_DESCR'])) $order['DISCOUNT_DESCR'] = Discount\Result\CompatibleFormat::getDiscountDescription($stepResult); } } Sale\Discount\Actions::fillCompatibleFields($order); $applied = !empty($stepResult); $orderDiscountId = 0; $orderCouponId = ''; if ($applied) { self::correctStepResult($order, $stepResult, $discount); $discount['ACTIONS_DESCR'] = $order['DISCOUNT_DESCR']; $discountResult = self::convertDiscount($discount); if (!$discountResult->isSuccess()) return false; $orderDiscountId = $discountResult->getId(); $discountData = $discountResult->getData(); $discount['ORDER_DISCOUNT_ID'] = $orderDiscountId; if ($discountData['USE_COUPONS'] == 'Y') { if (empty($discount['COUPON'])) return false; $couponResult = self::convertCoupon($discount['COUPON']['COUPON'], $orderDiscountId); if (!$couponResult->isSuccess()) return false; $orderCouponId = $couponResult->getId(); Sale\DiscountCouponsManager::setApply($orderCouponId, $stepResult); unset($couponResult); } } unset($order['DISCOUNT_DESCR'], $order['DISCOUNT_RESULT']); self::$currentOrderData = $order; if ($applied && $orderCouponId != '') { $couponApply = Sale\DiscountCouponsManager::setApply(self::$couponsCache[$orderCouponId]['COUPON'], $stepResult); unset($couponApply); } if ($applied) { if (!empty($stepResult['BASKET'])) { $publicMode = self::usedByClient(); foreach ($order['BASKET_ITEMS'] as $basketCode => $basketItem) { $code = ($publicMode ? $basketItem['ID'] : $basketCode); if (empty($stepResult['BASKET'][$code])) continue; if ($stepResult['BASKET'][$code]['APPLY'] == 'Y') $order['BASKET_ITEMS'][$basketCode]['ACTION_APPLIED'] = 'Y'; } unset($code, $basketCode, $basketItem); unset($publicMode); } self::$discountResult['ORDER'][] = array( 'DISCOUNT_ID' => $orderDiscountId, 'COUPON_ID' => $orderCouponId, 'RESULT' => $stepResult ); return true; } return false; } /** * Return discount list description. * * @param bool $extMode Extended mode. * @return array */ public static function getApplyResult($extMode = false) { $extMode = ($extMode === true); self::getApplyDiscounts(); if ($extMode) self::remakingDiscountResult(); $result = self::$discountResult; if ($extMode) unset($result['BASKET'], $result['ORDER']); //$result['CONVERTED_ORDER'] = 'Y'; return $result; } /** * Set basket code. * * @param string|int $index Item index. * @param string|int $code Basket code. * @return void */ public static function setBasketCode($index, $code) { self::$basketCodes[$index] = $code; } /** * Return discount result for old api. * * @return array|bool */ public static function getResult() { if (!self::$init || self::$useMode == self::MODE_SYSTEM) return false; if (self::$useMode == self::MODE_ORDER) return array(); if (self::$useMode == self::MODE_DISABLED) return array(); $result = array( 'CALCULATE' => array( 'USE_MODE' => self::$discountUseMode, 'NEW_ORDER' => self::$order === null, ), 'BASE_PRICE' => array(), 'DISCOUNT_LIST' => array(), 'COUPONS_LIST' => array(), 'DISCOUNT_RESULT' => array(), 'FORWARD_BASKET_TABLE' => array(), 'REVERSE_BASKET_TABLE' => array() ); if (!empty(self::$basketBasePrice)) { foreach (self::$basketBasePrice as $index => $price) { if (!isset(self::$basketCodes[$index])) continue; $result['BASE_PRICE'][self::$basketCodes[$index]] = $price; } unset($index, $price); } if (!empty(self::$discountsCache)) $result['DISCOUNT_LIST'] = self::$discountsCache; if (!empty(self::$couponsCache)) $result['COUPONS_LIST'] = self::$couponsCache; if ( !empty(self::$discountResult['BASKET']) || !empty(self::$discountResult['ORDER']) || !empty(self::$discountResult['BASKET_ROUND']) ) { $result['DISCOUNT_RESULT']['APPLY_BLOCKS'] = array( 0 => array( 'BASKET' => array(), 'BASKET_ROUND' => array(), 'ORDER' => array() ) ); } if (!empty(self::$discountResult['BASKET'])) { foreach (self::$discountResult['BASKET'] as $index => $discountList) { if (!isset(self::$basketCodes[$index])) continue; $result['DISCOUNT_RESULT']['APPLY_BLOCKS'][0]['BASKET'][self::$basketCodes[$index]] = $discountList; } unset($index, $discountList); } if (!empty(self::$discountResult['BASKET_ROUND'])) { foreach (self::$discountResult['BASKET_ROUND'] as $index => $roundData) { if (!isset(self::$basketCodes[$index])) continue; $result['DISCOUNT_RESULT']['APPLY_BLOCKS'][0]['BASKET_ROUND'][self::$basketCodes[$index]] = $roundData; } unset($index, $roundData); } if (!empty(self::$discountResult['ORDER'])) { foreach (self::$discountResult['ORDER'] as $discountIndex => $discount) { if (!empty($discount['RESULT']['BASKET'])) { $newBasket = array(); foreach ($discount['RESULT']['BASKET'] as $index => $basketItem) { if (!isset(self::$basketCodes[$index])) continue; $basketItem['BASKET_ID'] = self::$basketCodes[$index]; $newBasket[self::$basketCodes[$index]] = $basketItem; } unset($index, $basketItem); $discount['RESULT']['BASKET'] = $newBasket; } $result['DISCOUNT_RESULT']['APPLY_BLOCKS'][0]['ORDER'][$discountIndex] = $discount; } unset($discountIndex, $discount); } if (!empty(self::$basketCodes)) { foreach (self::$basketCodes as $code => $id) { $result['FORWARD_BASKET_TABLE'][$code] = $id; $result['REVERSE_BASKET_TABLE'][$id] = $code; } unset($code, $id); } return $result; } /** * Round prices. * * @param array &$basket Basket items. * @param array $orderData Order (without basket). * @return void */ public static function roundPrices(array &$basket, array $orderData = array()) { if (empty($basket)) return; $publicMode = self::usedByClient(); $clearedBasket = array(); foreach ($basket as $basketCode => $basketItem) { if (\CSaleBasketHelper::isSetItem($basketItem)) continue; $clearedBasket[$basketCode] = $basketItem; } unset($basketCode, $basketItem); if (!empty($clearedBasket)) { $result = Sale\OrderDiscountManager::roundBasket( $clearedBasket, array(), $orderData ); foreach ($result as $basketCode => $roundResult) { if (empty($roundResult) || !is_array($roundResult)) continue; $code = ($publicMode ? $basket[$basketCode]['ID'] : $basketCode); $basket[$basketCode]['PRICE'] = $roundResult['PRICE']; $basket[$basketCode]['DISCOUNT_PRICE'] = $roundResult['DISCOUNT_PRICE']; //TODO: remove this code after create calculation percent of discount if ($basket[$basketCode]['PRICE'] > $basket[$basketCode]['BASE_PRICE']) { $basket[$basketCode]['BASE_PRICE'] = $basket[$basketCode]['PRICE']; $basket[$basketCode]['DISCOUNT_PRICE'] = 0; } if (!isset(self::$discountResult['BASKET_ROUND'])) self::$discountResult['BASKET_ROUND'] = array(); self::$discountResult['BASKET_ROUND'][$code] = array( 'APPLY' => 'Y', 'ROUND_RULE' => $roundResult['ROUND_RULE'] ); } unset($basketCode, $roundResult, $result); } unset($clearedBasket); unset($publicMode); } /** * Returns existing custom price. * * @param array $basketItem Basket item. * @return bool */ protected static function isCustomPrice($basketItem) { return ( (isset($basketItem['CUSTOM_PRICE']) && $basketItem['CUSTOM_PRICE'] == 'Y') || (array_key_exists('PRODUCT_PROVIDER_CLASS', $basketItem) && empty($basketItem['PRODUCT_PROVIDER_CLASS'])) ); } /** * Calculate basket discounts for item. * * @param string|int $code Basket code. * @param array $fields Basket data. * @return bool */ protected static function calculateBasketItemDiscount($code, $fields) { if (\CSaleBasketHelper::isSetItem($fields)) return true; if (empty(self::$basketDiscountList[$code])) return true; $itemData = array( 'MODULE_ID' => $fields['MODULE'], 'PRODUCT_ID' => $fields['PRODUCT_ID'], 'BASKET_ID' => $code ); foreach (self::$basketDiscountList[$code] as $index => $discount) { $discountResult = self::convertDiscount($discount); if (!$discountResult->isSuccess()) return false; $orderDiscountId = $discountResult->getId(); $discountData = $discountResult->getData(); $orderCouponId = ''; self::$basketDiscountList[$code][$index]['ORDER_DISCOUNT_ID'] = $orderDiscountId; if ($discountData['USE_COUPONS'] == 'Y') { if (empty($discount['COUPON'])) return false; $couponResult = self::convertCoupon($discount['COUPON'], $orderDiscountId); if (!$couponResult->isSuccess()) return false; $orderCouponId = $couponResult->getId(); Sale\DiscountCouponsManager::setApplyByProduct($itemData, array($orderCouponId)); unset($couponResult); } unset($discountData, $discountResult); if (!isset(self::$discountResult['BASKET'][$code])) self::$discountResult['BASKET'][$code] = array(); self::$discountResult['BASKET'][$code][$index] = array( 'DISCOUNT_ID' => $orderDiscountId, 'COUPON_ID' => $orderCouponId, 'RESULT' => array( 'APPLY' => 'Y', 'DESCR' => false, 'DESCR_DATA' => false ) ); $orderApplication = ( !empty(self::$discountsCache[$orderDiscountId]['APPLICATION']) ? self::$discountsCache[$orderDiscountId]['APPLICATION'] : null ); if (!empty($orderApplication)) { $fields['DISCOUNT_RESULT'] = ( !empty(self::$discountsCache[$orderDiscountId]['ACTIONS_DESCR_DATA']) ? self::$discountsCache[$orderDiscountId]['ACTIONS_DESCR_DATA'] : false ); $applyProduct = null; eval('$applyProduct='.$orderApplication.';'); if (is_callable($applyProduct)) $applyProduct($fields); unset($applyProduct); if (!empty($fields['DISCOUNT_RESULT'])) { self::$discountResult['BASKET'][$code][$index]['RESULT']['DESCR_DATA'] = $fields['DISCOUNT_RESULT']['BASKET']; self::$discountResult['BASKET'][$code][$index]['RESULT']['DESCR'] = self::formatDescription($fields['DISCOUNT_RESULT']); } unset($fields['DISCOUNT_RESULT']); } unset($orderApplication); } unset($discount, $index); return true; } /** * Convert discount for saving in order. * * @param array $discount Raw discount data. * @return Sale\Result */ protected static function convertDiscount($discount) { $result = new Sale\Result(); $discountResult = Sale\OrderDiscountManager::saveDiscount($discount, false); if (!$discountResult->isSuccess()) { $result->addErrors($discountResult->getErrors()); unset($discountResult); return $result; } $orderDiscountId = $discountResult->getId(); $discountData = $discountResult->getData(); $resultData = array( 'ORDER_DISCOUNT_ID' => $orderDiscountId, 'USE_COUPONS' => $discountData['USE_COUPONS'], 'MODULE_ID' => $discountData['MODULE_ID'], ); if (!isset(self::$discountsCache[$orderDiscountId])) { $discountData['ACTIONS_DESCR_DATA'] = false; if (!empty($discountData['ACTIONS_DESCR']) && is_array($discountData['ACTIONS_DESCR'])) { $discountData['ACTIONS_DESCR_DATA'] = $discountData['ACTIONS_DESCR']; $discountData['ACTIONS_DESCR'] = self::formatDescription($discountData['ACTIONS_DESCR']); } else { $discountData['ACTIONS_DESCR'] = false; } if (empty($discountData['ACTIONS_DESCR'])) { $discountData['ACTIONS_DESCR'] = false; $discountData['ACTIONS_DESCR_DATA'] = false; } self::$discountsCache[$orderDiscountId] = $discountData; } $result->setId($orderDiscountId); $result->setData($resultData); unset($discountData, $resultData, $orderDiscountId); return $result; } /** * Convert coupon for saving in order. * * @param string|array $coupon Coupon. * @param int $discount Order discount id. * @return Sale\Result */ protected static function convertCoupon($coupon, $discount) { $result = new Sale\Result(); if (!is_array($coupon)) { $couponData = Sale\DiscountCouponsManager::getEnteredCoupon($coupon, true); if (empty($couponData)) { $result->addError(new Main\Entity\EntityError( Loc::getMessage('BX_SALE_DISCOUNT_ERR_COUPON_NOT_FOUND'), self::ERROR_ID )); return $result; } $coupon = array( 'COUPON' => $couponData['COUPON'], 'TYPE' => $couponData['TYPE'], 'COUPON_ID' => $couponData['ID'], 'DATA' => $couponData ); unset($couponData); } $coupon['ORDER_DISCOUNT_ID'] = $discount; $coupon['ID'] = 0; $orderCouponId = $coupon['COUPON']; if (!isset(self::$couponsCache[$orderCouponId])) self::$couponsCache[$orderCouponId] = $coupon; $result->setId($orderCouponId); $result->setData($coupon); unset($coupon, $orderCouponId); return $result; } /** * Return formatted discount description. * * @param array|bool $descr Description. * @return array */ protected static function formatDescription($descr) { $result = array(); if (empty($descr) || !is_array($descr)) return $result; if (isset($descr['DELIVERY'])) { $result['DELIVERY'] = array(); foreach ($descr['DELIVERY'] as $index => $value) { $result['DELIVERY'][$index] = Sale\OrderDiscountManager::formatDescription($value); if ($result['DELIVERY'][$index] == false) unset($result['DELIVERY'][$index]); } unset($value, $index); if (!empty($result['DELIVERY'])) $result['DELIVERY'] = implode(', ', $result['DELIVERY']); } if (isset($descr['BASKET'])) { $result['BASKET'] = array(); foreach ($descr['BASKET'] as $index => $value) { $result['BASKET'][$index] = Sale\OrderDiscountManager::formatDescription($value); if ($result['BASKET'][$index] == false) unset($result['BASKET'][$index]); } unset($value, $index); if (!empty($result['BASKET'])) $result['BASKET'] = implode(', ', $result['BASKET']); } return $result; } /** * Returns result after one discount. * * @param array $order Order current data. * @return array */ protected static function getStepResult($order) { $publicMode = self::usedByClient(); $result = array(); $stepResult = &$order['DISCOUNT_RESULT']; if (!empty($stepResult['DELIVERY']) && is_array($stepResult['DELIVERY'])) { $result['DELIVERY'] = array( 'APPLY' => 'Y', 'DELIVERY_ID' => (isset($order['DELIVERY_ID']) ? $order['DELIVERY_ID'] : false), 'SHIPMENT_CODE' => (isset($order['SHIPMENT_CODE']) ? $order['SHIPMENT_CODE'] : false), 'DESCR' => Sale\OrderDiscountManager::formatArrayDescription($stepResult['DELIVERY']), 'DESCR_DATA' => $stepResult['DELIVERY'], 'ACTION_BLOCK_LIST' => array_keys($stepResult['DELIVERY']) ); if (is_array($result['DELIVERY']['DESCR'])) $result['DELIVERY']['DESCR'] = implode(', ', $result['DELIVERY']['DESCR']); } if (!empty($stepResult['BASKET']) && is_array($stepResult['BASKET'])) { if (!isset($result['BASKET'])) $result['BASKET'] = array(); foreach ($stepResult['BASKET'] as $basketCode => $basketResult) { $code = ($publicMode ? $order['BASKET_ITEMS'][$basketCode]['ID'] : $basketCode); $result['BASKET'][$code] = array( 'APPLY' => 'Y', 'DESCR' => Sale\OrderDiscountManager::formatArrayDescription($basketResult), 'DESCR_DATA' => $basketResult, 'MODULE' => $order['BASKET_ITEMS'][$basketCode]['MODULE'], 'PRODUCT_ID' => $order['BASKET_ITEMS'][$basketCode]['PRODUCT_ID'], 'BASKET_ID' => $code, 'ACTION_BLOCK_LIST' => array_keys($basketResult) ); if (is_array($result['BASKET'][$code]['DESCR'])) $result['BASKET'][$code]['DESCR'] = implode(', ', $result['BASKET'][$code]['DESCR']); } unset($code, $basketCode, $basketResult); } unset($stepResult); return $result; } /** * Returns result after one discount in old format. * * @param array $currentOrder Current order data. * @return array */ protected static function getStepResultOld($currentOrder) { $publicMode = self::usedByClient(); $result = array(); if (isset(self::$previousOrderData['PRICE_DELIVERY']) && isset($currentOrder['PRICE_DELIVERY'])) { if (self::$previousOrderData['PRICE_DELIVERY'] != $currentOrder['PRICE_DELIVERY']) { $descr = Discount\Result\CompatibleFormat::createResultDescription( $currentOrder['PRICE_DELIVERY'], self::$previousOrderData['PRICE_DELIVERY'], self::$previousOrderData['CURRENCY'] ); $result['DELIVERY'] = array( 'APPLY' => 'Y', 'DELIVERY_ID' => (isset($currentOrder['DELIVERY_ID']) ? $currentOrder['DELIVERY_ID'] : false), 'SHIPMENT_CODE' => (isset($currentOrder['SHIPMENT_CODE']) ? $currentOrder['SHIPMENT_CODE'] : false), 'DESCR' => implode(', ', Discount\Formatter::formatList($descr)), 'DESCR_DATA' => $descr ); unset($descr); } } if (!empty(self::$previousOrderData['BASKET_ITEMS']) && !empty($currentOrder['BASKET_ITEMS'])) { foreach (self::$previousOrderData['BASKET_ITEMS'] as $basketCode => $item) { if (!isset($currentOrder['BASKET_ITEMS'][$basketCode])) continue; $code = ($publicMode ? $currentOrder['BASKET_ITEMS'][$basketCode]['ID'] : $basketCode); if ($item['PRICE'] != $currentOrder['BASKET_ITEMS'][$basketCode]['PRICE']) { if (!isset($result['BASKET'])) $result['BASKET'] = array(); $descr = Discount\Result\CompatibleFormat::createResultDescription( $currentOrder['BASKET_ITEMS'][$basketCode]['PRICE'], $item['PRICE'], self::$previousOrderData['CURRENCY'] ); $result['BASKET'][$code] = array( 'APPLY' => 'Y', 'DESCR' => implode(', ', Discount\Formatter::formatList($descr)), 'DESCR_DATA' => $descr, 'MODULE' => $currentOrder['BASKET_ITEMS'][$basketCode]['MODULE'], 'PRODUCT_ID' => $currentOrder['BASKET_ITEMS'][$basketCode]['PRODUCT_ID'], 'BASKET_ID' => $code ); unset($descr); } } } return $result; } /** * Correct data for exotic coupon. * * @param array &$order Current order data. * @param array &$stepResult Currenct discount result. * @param array $discount Discount data. * @return void */ protected static function correctStepResult(&$order, &$stepResult, $discount) { if ($discount['USE_COUPONS'] == 'Y' && !empty($discount['COUPON'])) { if ( $discount['COUPON']['TYPE'] == Sale\Internals\DiscountCouponTable::TYPE_BASKET_ROW && (!empty($stepResult['BASKET']) && count($stepResult['BASKET']) > 1) ) { $publicMode = self::usedByClient(); $maxPrice = 0; $maxKey = -1; $basketId = -1; foreach (self::$previousOrderData['BASKET_ITEMS'] as $key => $item) { $resultKey = ($publicMode ? $item['ID'] : $key); if (isset($stepResult['BASKET'][$resultKey])) { if ($maxPrice < $item['PRICE']) { $maxPrice = $item['PRICE']; $maxKey = $key; $basketId = $resultKey; } } } unset($key, $item); $basketKeys = array_keys($order['BASKET_ITEMS']); foreach ($basketKeys as &$key) { if ($key == $maxKey) continue; $order['BASKET_ITEMS'][$key] = self::$previousOrderData['BASKET_ITEMS'][$key]; } unset($key); $basketKeys = array_keys($stepResult['BASKET']); foreach ($basketKeys as &$key) { if ($key == $basketId) continue; unset($stepResult['BASKET'][$key]); } unset($key); unset($basketKeys); unset($basketId, $maxKey, $maxPrice, $publicMode); } } } /** * Returns discount and coupon list. * * @return void */ protected static function getApplyDiscounts() { $discountApply = array(); $couponApply = array(); self::$discountResult['DISCOUNT_LIST'] = array(); if (!empty(self::$discountsCache)) { foreach (self::$discountsCache as $id => $discount) { self::$discountResult['DISCOUNT_LIST'][$id] = array( 'ID' => $id, 'NAME' => $discount['NAME'], 'MODULE_ID' => $discount['MODULE_ID'], 'DISCOUNT_ID' => $discount['ID'], 'USE_COUPONS' => $discount['USE_COUPONS'], 'ACTIONS_DESCR' => $discount['ACTIONS_DESCR'], 'ACTIONS_DESCR_DATA' => $discount['ACTIONS_DESCR_DATA'], 'APPLY' => 'N', 'EDIT_PAGE_URL' => $discount['EDIT_PAGE_URL'] ); $discountApply[$id] = &self::$discountResult['DISCOUNT_LIST'][$id]; } unset($id, $discount); } self::$discountResult['COUPON_LIST'] = array(); if (!empty(self::$couponsCache)) { foreach (self::$couponsCache as $id => $coupon) { self::$discountResult['COUPON_LIST'][$id] = $coupon; self::$discountResult['COUPON_LIST'][$id]['APPLY'] = 'N'; $couponApply[$id] = &self::$discountResult['COUPON_LIST'][$id]; } unset($id, $coupon); } if (!empty(self::$discountResult['BASKET'])) { foreach (self::$discountResult['BASKET'] as $basketCode => $discountList) { foreach ($discountList as $discount) { if ($discount['RESULT']['APPLY'] == 'Y') { if (isset($discountApply[$discount['DISCOUNT_ID']])) $discountApply[$discount['DISCOUNT_ID']]['APPLY'] = 'Y'; if (isset($couponApply[$discount['COUPON_ID']])) $couponApply[$discount['COUPON_ID']]['APPLY'] = 'Y'; } } unset($discount); } unset($basketCode, $discountList); } if (!empty(self::$discountResult['ORDER'])) { foreach (self::$discountResult['ORDER'] as $discount) { if (!empty($discount['RESULT']['BASKET'])) { foreach ($discount['RESULT']['BASKET'] as $basketCode => $applyList) { if ($applyList['APPLY'] == 'Y') { if (isset($discountApply[$discount['DISCOUNT_ID']])) $discountApply[$discount['DISCOUNT_ID']]['APPLY'] = 'Y'; if (isset($couponApply[$discount['COUPON_ID']])) $couponApply[$discount['COUPON_ID']]['APPLY'] = 'Y'; } } unset($basketCode, $applyList); } if (!empty($discount['RESULT']['DELIVERY']) && $discount['RESULT']['DELIVERY']['APPLY'] == 'Y') { if (isset($discountApply[$discount['DISCOUNT_ID']])) $discountApply[$discount['DISCOUNT_ID']]['APPLY'] = 'Y'; if (isset($couponApply[$discount['COUPON_ID']])) $couponApply[$discount['COUPON_ID']]['APPLY'] = 'Y'; } } unset($discount); } unset($discountApply, $couponApply); } /** * Change result format. * * @return void */ protected static function remakingDiscountResult() { $basket = array(); $delivery = array(); if (!empty(self::$discountResult['BASKET'])) { foreach (self::$discountResult['BASKET'] as $basketCode => $discountList) { if (!isset($basket[$basketCode])) $basket[$basketCode] = array(); foreach ($discountList as $discount) { $basket[$basketCode][] = array( 'DISCOUNT_ID' => $discount['DISCOUNT_ID'], 'COUPON_ID' => $discount['COUPON_ID'], 'APPLY' => $discount['RESULT']['APPLY'], 'DESCR' => $discount['RESULT']['DESCR'] ); } unset($discount); } unset($basketCode, $discountList); } if (!empty(self::$discountResult['ORDER'])) { foreach (self::$discountResult['ORDER'] as $discount) { if (!empty($discount['RESULT']['BASKET'])) { foreach ($discount['RESULT']['BASKET'] as $basketCode => $applyList) { if (!isset($basket[$basketCode])) $basket[$basketCode] = array(); $basket[$basketCode][] = array( 'DISCOUNT_ID' => $discount['DISCOUNT_ID'], 'COUPON_ID' => $discount['COUPON_ID'], 'APPLY' => $applyList['APPLY'], 'DESCR' => $applyList['DESCR'] ); } unset($basketCode, $applyList); } if (!empty($discount['RESULT']['DELIVERY'])) { $delivery[] = array( 'DISCOUNT_ID' => $discount['DISCOUNT_ID'], 'COUPON_ID' => $discount['COUPON_ID'], 'DELIVERY_ID' => $discount['RESULT']['DELIVERY']['DELIVERY_ID'], 'APPLY' => $discount['RESULT']['DELIVERY']['APPLY'], 'DESCR' => $discount['RESULT']['DELIVERY']['DESCR'] ); } } unset($discount); } unset($couponApply, $discountApply); self::$discountResult['RESULT'] = array( 'BASKET' => $basket, 'DELIVERY' => $delivery ); } }