%PDF- %PDF-
| Direktori : /home/bitrix/www/bitrix/modules/sale/lib/discount/migration/ |
| Current File : //home/bitrix/www/bitrix/modules/sale/lib/discount/migration/orderdiscountmigrator.php |
<?php
namespace Bitrix\Sale\Discount\Migration;
use Bitrix\Main,
Bitrix\Main\Localization\Loc,
Bitrix\Catalog,
Bitrix\Sale;
Loc::loadMessages(__FILE__);
final class OrderDiscountMigrator
{
const ERROR_ID = 'BX_SALE_ORDER_DISCOUNT_MIGRATOR';
private static $catalogIncluded = null;
private static $migrateDiscountsCache = array();
private static $migrateCouponsCache = array();
private static $catalogDiscountsCache = array();
/**
* Migrate discount data from b_sale_basket into new entity.
*
* @param array $order Order data.
* @return Sale\Result
*/
public static function processing(array $order)
{
static $useBasePrice = null;
if ($useBasePrice === null)
$useBasePrice = (string)Main\Config\Option::get('sale', 'get_discount_percent_from_base_price');
$process = true;
$result = new Sale\Result();
if (empty($order['ID']) || (int)$order['ID'] <= 0)
{
$process = false;
$result->addError(new Main\Entity\EntityError(
Loc::getMessage('SALE_ORDER_DISCOUNT_MIGRATOR_ERR_EMPTY_ORDER_ID'),
self::ERROR_ID
));
}
$catalogOrder = false;
$basketData = array();
if ($process)
{
$order['ID'] = (int)$order['ID'];
$basePrices = array();
$basketIterator = Sale\Internals\BasketTable::getList(array(
'select' => array(
'ID', 'DISCOUNT_COUPON', 'DISCOUNT_NAME', 'DISCOUNT_VALUE',
'MODULE', 'PRICE', 'DISCOUNT_PRICE', 'CURRENCY', 'SET_PARENT_ID', 'TYPE'
),
'filter' => array('=ORDER_ID' => $order['ID'])
));
while ($basket = $basketIterator->fetch())
{
$basket['ID'] = (int)$basket['ID'];
$basket['MODULE'] = (string)$basket['MODULE'];
$basket['DISCOUNT_COUPON'] = trim((string)$basket['DISCOUNT_COUPON']);
$basket['DISCOUNT_NAME'] = trim((string)$basket['DISCOUNT_NAME']);
$basket['SET_PARENT_ID'] = (int)$basket['SET_PARENT_ID'];
$basket['TYPE'] = (int)$basket['TYPE'];
if ($basket['MODULE'] == 'catalog')
{
$basePrices[$basket['ID']] = array(
'BASE_PRICE' => $basket['PRICE'] + $basket['DISCOUNT_PRICE'],
'BASE_PRICE_CURRENCY' => $basket['CURRENCY']
);
}
if ($basket['MODULE'] != 'catalog' || ($basket['DISCOUNT_NAME'] == '' && $basket['DISCOUNT_COUPON'] == ''))
continue;
if ($basket['SET_PARENT_ID'] > 0 && $basket['TYPE'] <= 0)
continue;
$catalogOrder = true;
$hash = md5($basket['DISCOUNT_NAME'].'|'.$basket['DISCOUNT_COUPON']);
if (!isset($basketData[$hash]))
$basketData[$hash] = array(
'DISCOUNT_NAME' => $basket['DISCOUNT_NAME'],
'DISCOUNT_COUPON' => $basket['DISCOUNT_COUPON'],
'ITEMS' => array()
);
$basketData[$hash]['ITEMS'][$basket['ID']] = $basket;
}
unset($basket, $basketIterator);
}
if ($process && $catalogOrder)
{
Sale\OrderDiscount::setManagerConfig(array(
'CURRENCY' => $order['CURRENCY'],
'SITE_ID' => $order['LID'],
'USE_BASE_PRICE' => $useBasePrice
));
foreach ($basketData as $row)
{
if (!self::migrateDiscount($order['ID'], $row))
{
$process = false;
$result->addError(new Main\Entity\EntityError(
Loc::getMessage('SALE_ORDER_DISCOUNT_MIGRATOR_ERR_SAVE_MIGRATE_DISCOUNT'),
self::ERROR_ID
));
break;
}
}
unset($row);
}
unset($basketData);
Sale\Internals\OrderDiscountDataTable::clearByOrder($order['ID']);
if ($process)
{
if (!empty($basePrices))
{
foreach ($basePrices as $basketId => $price)
{
$fields = array(
'ORDER_ID' => $order['ID'],
'ENTITY_TYPE' => Sale\Internals\OrderDiscountDataTable::ENTITY_TYPE_BASKET_ITEM,
'ENTITY_ID' => $basketId,
'ENTITY_VALUE' => $basketId,
'ENTITY_DATA' => $price,
);
$operationResult = Sale\Internals\OrderDiscountDataTable::add($fields);
if (!$operationResult->isSuccess())
{
$process = false;
$result->addErrors($operationResult->getErrors());
}
unset($operationResult);
}
unset($basketId, $price);
}
}
if ($process)
{
$fields = array(
'ORDER_ID' => $order['ID'],
'ENTITY_TYPE' => Sale\Internals\OrderDiscountDataTable::ENTITY_TYPE_ORDER,
'ENTITY_ID' => $order['ID'],
'ENTITY_VALUE' => $order['ID'],
'ENTITY_DATA' => array(
'OLD_ORDER' => 'Y'
)
);
$operationResult = Sale\Internals\OrderDiscountDataTable::add($fields);
if (!$operationResult->isSuccess())
{
$process = false;
$result->addErrors($operationResult->getErrors());
}
unset($operationResult);
}
unset($process);
return $result;
}
/**
* Convert discount for old order.
*
* @internal
* @param int $orderId Order id.
* @param array &$data Discount data.
* @return bool
* @throws Main\LoaderException
*/
private static function migrateDiscount($orderId, array &$data)
{
if (self::$catalogIncluded === null)
self::$catalogIncluded = Main\Loader::includeModule('catalog');
if (!self::$catalogIncluded)
return false;
$discountData = array(
'COUPON' => '',
'NAME' => '',
'DISCOUNT_ID' => 0
);
if ($data['DISCOUNT_NAME'] != '')
{
$discountName = array();
if (preg_match('/^\[(\d+)\][ ](.+)$/', $data['DISCOUNT_NAME'], $discountName) == 1)
{
$discountData['NAME'] = $discountName[2];
$discountData['DISCOUNT_ID'] = $discountName[1];
}
unset($discountName);
}
if ($data['DISCOUNT_COUPON'] != '')
{
$discountData['COUPON'] = $data['DISCOUNT_COUPON'];
if (!self::checkMigrateCoupon($discountData['COUPON']))
return false;
if ($discountData['DISCOUNT_ID'] == 0)
{
$discountData['NAME'] = self::$migrateCouponsCache[$discountData['COUPON']]['DISCOUNT_NAME'];
$discountData['DISCOUNT_ID'] = self::$migrateCouponsCache[$discountData['COUPON']]['DISCOUNT_ID'];
}
else
{
if (
self::$migrateCouponsCache[$discountData['COUPON']]['TYPE'] != Sale\Internals\DiscountCouponTable::TYPE_ARCHIVED
&& self::$migrateCouponsCache[$discountData['COUPON']]['DISCOUNT_ID'] >= 0
&& $discountData['DISCOUNT_ID'] != self::$migrateCouponsCache[$discountData['COUPON']]['DISCOUNT_ID']
)
$discountData['DISCOUNT_ID'] = 0;
}
}
if ($discountData['DISCOUNT_ID'] == 0)
{
if ($discountData['COUPON'] == '')
return false;
self::createEmptyDiscount($discountData);
}
else
{
self::checkMigrateDiscount($discountData);
}
$saveResult = self::saveMigrateDiscount($discountData);
if (!$saveResult->isSuccess())
return false;
$migrateDiscountData = $saveResult->getData();
unset($saveResult);
$orderDiscountId = $migrateDiscountData['ORDER_DISCOUNT_ID'];
$orderCouponId = 0;
$discountDescr = current($migrateDiscountData['ACTIONS_DESCR']['BASKET']);
if ($discountData['COUPON'] != '')
{
$couponData = self::$migrateCouponsCache[$discountData['COUPON']];
$couponData['ORDER_ID'] = $orderId;
$couponData['ORDER_DISCOUNT_ID'] = $migrateDiscountData['ORDER_DISCOUNT_ID'];
$couponData['DATA']['DISCOUNT_ID'] = $migrateDiscountData['DISCOUNT_ID'];
if (array_key_exists('DISCOUNT_ID', $couponData))
unset($couponData['DISCOUNT_ID']);
if (array_key_exists('DISCOUNT_NAME', $couponData))
unset($couponData['DISCOUNT_NAME']);
$saveResult = Sale\OrderDiscount::saveCoupon($couponData);
if (!$saveResult->isSuccess())
return false;
$migrateCoupon = $saveResult->getData();
$orderCouponId = $migrateCoupon['ID'];
}
foreach ($data['ITEMS'] as $basketItem)
{
$applyDescr = $discountDescr;
if ($basketItem['DISCOUNT_VALUE'] != '')
{
if ($applyDescr['TYPE'] == Sale\Discount\Formatter::TYPE_SIMPLE)
{
$applyDescr['DESCR'] .= ' ('.$basketItem['DISCOUNT_VALUE'].')';
}
else
{
$valueData = array();
if (preg_match('/^(|\+|-)(\d+|[.,]\d+|\d+[.,]\d+)\s?%$/', $basketItem['DISCOUNT_VALUE'], $valueData) == 1)
{
$applyDescr['RESULT_VALUE'] = (float)$basketItem['DISCOUNT_VALUE'];
$applyDescr['RESULT_UNIT'] = Sale\Discount\Formatter::VALUE_TYPE_PERCENT;
}
unset($valueData);
}
}
$ruleRow = array(
'MODULE_ID' => 'catalog',
'ORDER_DISCOUNT_ID' => $orderDiscountId,
'ORDER_ID' => $orderId,
'ENTITY_TYPE' => Sale\Internals\OrderRulesTable::ENTITY_TYPE_BASKET_ITEM,
'ENTITY_ID' => $basketItem['ID'],
'ENTITY_VALUE' => $basketItem['ID'],
'COUPON_ID' => $orderCouponId,
'APPLY' => 'Y'
);
$ruleDescr = array(
'MODULE_ID' => 'catalog',
'ORDER_DISCOUNT_ID' => $orderDiscountId,
'ORDER_ID' => $orderId,
'DESCR' => array($applyDescr)
);
$ruleResult = Sale\Internals\OrderRulesTable::add($ruleRow);
if ($ruleResult->isSuccess())
{
$ruleDescr['RULE_ID'] = $ruleResult->getId();
$descrResult = Sale\Internals\OrderRulesDescrTable::add($ruleDescr);
if (!$descrResult->isSuccess())
return false;
}
else
{
return false;
}
unset($ruleResult);
}
unset($basketItem);
return true;
}
/**
* Check coupon for convert.
*
* @internal
* @param string $coupon Coupon.
* @return bool
* @throws Main\LoaderException
*/
private static function checkMigrateCoupon($coupon)
{
if (self::$catalogIncluded === null)
self::$catalogIncluded = Main\Loader::includeModule('catalog');
if (!self::$catalogIncluded)
return false;
static $catalogCouponTypes = null;
if ($catalogCouponTypes === null)
$catalogCouponTypes = array(
Catalog\DiscountCouponTable::TYPE_ONE_ROW => Sale\Internals\DiscountCouponTable::TYPE_BASKET_ROW,
Catalog\DiscountCouponTable::TYPE_ONE_ORDER => Sale\Internals\DiscountCouponTable::TYPE_ONE_ORDER,
Catalog\DiscountCouponTable::TYPE_NO_LIMIT => Sale\Internals\DiscountCouponTable::TYPE_MULTI_ORDER
);
if (!isset(self::$migrateCouponsCache[$coupon]))
{
self::$migrateCouponsCache[$coupon] = false;
$couponIterator = Catalog\DiscountCouponTable::getList(array(
'select' => array('COUPON_ID' => 'ID', 'COUPON', 'TYPE', 'DISCOUNT_ID', 'DISCOUNT_NAME' => 'DISCOUNT.NAME'),
'filter' => array('=COUPON' => $coupon)
));
$existCoupon = $couponIterator->fetch();
unset($couponIterator);
if (!empty($existCoupon))
{
$existCoupon['TYPE'] = (
isset($catalogCouponTypes[$existCoupon['TYPE']])
? $catalogCouponTypes[$existCoupon['TYPE']]
: Sale\Internals\DiscountCouponTable::TYPE_ARCHIVED
);
$existCoupon['DATA'] = array(
'MODE' => Sale\DiscountCouponsManager::COUPON_MODE_SIMPLE,
'MODULE' => 'catalog',
'DISCOUNT_ID' => 0,
'TYPE' => Sale\Internals\DiscountCouponTable::TYPE_ARCHIVED,
'USER_INFO' => array(),
);
self::$migrateCouponsCache[$coupon] = $existCoupon;
}
else
{
self::$migrateCouponsCache[$coupon] = self::createEmptyCoupon($coupon);
}
unset($existCoupon);
}
return true;
}
/**
* Create fake coupon.
*
* @internal
* @param string $coupon Coupon.
* @return array
*/
private static function createEmptyCoupon($coupon)
{
return array(
'COUPON' => $coupon,
'TYPE' => Sale\Internals\DiscountCouponTable::TYPE_ARCHIVED,
'COUPON_ID' => 0,
'DATA' => array(
'COUPON' => $coupon,
'MODE' => Sale\DiscountCouponsManager::COUPON_MODE_SIMPLE,
'MODULE' => 'catalog',
'DISCOUNT_ID' => 0,
'TYPE' => Sale\Internals\DiscountCouponTable::TYPE_ARCHIVED,
'USER_INFO' => array(),
)
);
}
/**
* Create fake discount.
*
* @internal
* @param array &$discountData Discount data.
* @param bool $accumulate Accumulate discount.
* @return void
*/
private static function createEmptyDiscount(array &$discountData, $accumulate = false)
{
$accumulate = ($accumulate === true);
static $emptyFields = null;
if ($emptyFields === null)
{
$emptyFields = array(
'DISCOUNT_ID' => 0,
'NAME' => Loc::getMessage('SALE_ORDER_DISCOUNT_MIGRATOR_MESS_CATALOG_DISCOUNT_NAME'),
'SORT' => 100,
'PRIORITY' => 1,
'LAST_DISCOUNT' => 'Y',
'USE_COUPONS' => 'N'
);
}
static $replaceFields = null;
static $replaceKeys = null;
if ($replaceFields === null)
{
$replaceFields = array(
'MODULE_ID' => 'catalog',
'CONDITIONS' => array(
'CLASS_ID' => 'CondGroup',
'DATA' => array('All' => 'AND', 'True' => 'True'),
'CHILDREN' => array()
),
'UNPACK' => '((1 == 1))',
'ACTIONS' => array(),
'APPLICATION' => '0'
);
$replaceKeys = array(
'MODULE_ID',
'CONDITIONS',
'UNPACK',
'ACTIONS',
'APPLICATION'
);
}
static $discountDescr = null;
if ($discountDescr === null)
{
$discountDescr = Sale\Discount\Formatter::prepareRow(
Sale\Discount\Formatter::TYPE_SIMPLE,
Loc::getMessage('SALE_ORDER_DISCOUNT_MIGRATOR_MESS_CATALOG_DISCOUNT_SIMPLE_MESS')
);
}
static $accumulateDescr = null;
if ($accumulateDescr === null)
{
$accumulateDescr = Sale\Discount\Formatter::prepareRow(
Sale\Discount\Formatter::TYPE_SIMPLE,
Loc::getMessage('SALE_ORDER_DISCOUNT_MIGRATOR_MESS_TYPE_ACCUMULATE_EMPTY')
);
}
foreach ($replaceKeys as $key)
{
if (array_key_exists($key, $discountData))
unset($discountData[$key]);
}
unset($key);
$discountData = array_merge($emptyFields, $discountData);
foreach ($replaceFields as $key => $value)
{
$discountData[$key] = $value;
}
unset($key, $value);
if (empty($discountData['ACTIONS_DESCR']))
$discountData['ACTIONS_DESCR'] = array(
'BASKET' => array(
0 => ($accumulate ? $accumulateDescr : $discountDescr)
)
);
if (!$accumulate)
$discountData['USE_COUPONS'] = ($discountData['COUPON'] != '' ? 'Y' : 'N');
}
/**
* Check discount for convert.
*
* @internal
* @param array &$discountData Discount data.
* @return void
* @throws Main\ArgumentException
* @throws Main\LoaderException
*/
private static function checkMigrateDiscount(&$discountData)
{
if (self::$catalogIncluded === null)
self::$catalogIncluded = Main\Loader::includeModule('catalog');
if (!self::$catalogIncluded)
return;
$coupon = $discountData['COUPON'];
$hash = md5($discountData['DISCOUNT_ID'].'|'.$discountData['NAME']);
if (!isset(self::$catalogDiscountsCache[$hash]))
{
$discountIterator = Catalog\DiscountTable::getList(array(
'select' => array('*'),
'filter' => array('=ID' => $discountData['DISCOUNT_ID'], '=NAME' => $discountData['NAME'])
));
$existDiscount = $discountIterator->fetch();
unset($discountIterator);
if (!empty($existDiscount))
{
if ($existDiscount['NAME'] != $discountData['NAME'])
{
self::createEmptyDiscount($discountData);
}
else
{
if ($existDiscount['TYPE'] == Catalog\DiscountTable::TYPE_DISCOUNT_SAVE)
{
self::createEmptyDiscount($discountData, true);
}
else
{
$existDiscount['COUPON'] = $discountData['COUPON'];
$discountData = Catalog\Discount\DiscountManager::prepareData(
$existDiscount, Sale\OrderDiscount::getManagerConfig()
);
}
}
}
else
{
self::createEmptyDiscount($discountData);
}
unset($existDiscount);
self::$catalogDiscountsCache[$hash] = $discountData;
}
else
{
$discountData = self::$catalogDiscountsCache[$hash];
}
$discountData['COUPON'] = $coupon;
}
/**
* Save converted discount.
*
* @internal
* @param array $discountData Discount data.
* @return Sale\Result
* @throws \Exception
*/
private static function saveMigrateDiscount(array $discountData)
{
$result = new Sale\Result();
$process = true;
$hash = false;
$resultData = array();
$fields = Sale\Internals\OrderDiscountTable::prepareDiscountData($discountData);
if (empty($fields) || !is_array($fields))
{
$process = false;
$result->addError(new Main\Entity\EntityError(
Loc::getMessage('SALE_ORDER_DISCOUNT_MIGRATOR_ERR_BAD_PREPARE_DISCOUNT'),
self::ERROR_ID
));
}
if ($process)
{
$hash = Sale\Internals\OrderDiscountTable::calculateHash($fields);
if ($hash === false)
{
$process = false;
$result->addError(new Main\Entity\EntityError(
Loc::getMessage('SALE_ORDER_DISCOUNT_MIGRATOR_ERR_BAD_DISCOUNT_HASH'),
self::ERROR_ID
));
}
}
if ($process)
{
if (!isset(self::$migrateDiscountsCache[$hash]))
{
$orderDiscountIterator = Sale\Internals\OrderDiscountTable::getList(array(
'select' => array('*'),
'filter' => array('=DISCOUNT_HASH' => $hash)
));
if ($orderDiscount = $orderDiscountIterator->fetch())
self::$migrateDiscountsCache[$hash] = $orderDiscount;
unset($orderDiscount, $orderDiscountIterator);
}
if (!empty(self::$migrateDiscountsCache[$hash]))
{
$resultData = self::$migrateDiscountsCache[$hash];
$resultData['ID'] = (int)$resultData['ID'];
$resultData['NAME'] = (string)$resultData['NAME'];
$resultData['ORDER_DISCOUNT_ID'] = $resultData['ID'];
$result->setId($resultData['ID']);
}
else
{
$fields['DISCOUNT_HASH'] = $hash;
$fields['ACTIONS_DESCR'] = array();
if (isset($discountData['ACTIONS_DESCR']))
$fields['ACTIONS_DESCR'] = $discountData['ACTIONS_DESCR'];
$tableResult = Sale\Internals\OrderDiscountTable::add($fields);
if ($tableResult->isSuccess())
{
$resultData = $fields;
$resultData['ID'] = (int)$tableResult->getId();
$resultData['NAME'] = (string)$resultData['NAME'];
$resultData['ORDER_DISCOUNT_ID'] = $resultData['ID'];
$result->setId($resultData['ID']);
}
else
{
$process = false;
$result->addErrors($tableResult->getErrors());
}
unset($tableResult, $fields);
if ($process)
{
$moduleList = Sale\Internals\OrderDiscountTable::getDiscountModules($discountData);
if (!empty($moduleList))
{
$resultModule = Sale\Internals\OrderModulesTable::saveOrderDiscountModules(
$resultData['ORDER_DISCOUNT_ID'],
$moduleList
);
if (!$resultModule)
{
Sale\Internals\OrderDiscountTable::clearList($resultData['ORDER_DISCOUNT_ID']);
$resultData = array();
$process = false;
$result->addError(new Main\Entity\EntityError(
Loc::getMessage('SALE_ORDER_DISCOUNT_MIGRATOR_ERR_SAVE_DISCOUNT_MODULES'),
self::ERROR_ID
));
}
unset($resultModule);
}
unset($needDiscountModules, $moduleList);
}
}
}
if ($process)
$result->setData($resultData);
unset($resultData, $process);
return $result;
}
}