Your IP : 3.142.171.112


Current Path : /var/www/www-root/data/www/monolith-realty.ru/bitrix/modules/main/lib/analytics/
Upload File :
Current File : /var/www/www-root/data/www/monolith-realty.ru/bitrix/modules/main/lib/analytics/catalog.php

<?php
/**
 * Bitrix Framework
 * @package bitrix
 * @subpackage main
 * @copyright 2001-2014 Bitrix
 */

namespace Bitrix\Main\Analytics;
use Bitrix\Catalog\CatalogViewedProductTable;
use Bitrix\Main\Application;
use Bitrix\Main\Config\Option;
use Bitrix\Main\Context;
use Bitrix\Main\Event;
use Bitrix\Main\Loader;
use Bitrix\Main\UserTable;
use Bitrix\Sale\BasketItem;
use Bitrix\Sale\Order;
use Bitrix\Sale\OrderTable;

if (!Loader::includeModule('catalog'))
	return;

/**
 * @package bitrix
 * @subpackage main
 */
class Catalog
{
	protected static $cookieLogName = 'RCM_PRODUCT_LOG';

	// basket (sale:OnSaleBasketItemSaved)
	public static function catchCatalogBasket(Event $event)
	{
		$isNew = $event->getParameter("IS_NEW");

		// new items only
		if (!$isNew)
		{
			return;
		}

		// exclude empty cookie
		if (!static::getBxUserId())
		{
			return;
		}

		// alter b_sale_basket - add recommendation, update it here
		if (!static::isOn())
		{
			return;
		}

		/** @var BasketItem $basketItem */
		$basketItem = $event->getParameter("ENTITY");

		// get product id by offer id
		$iblockId = 0;
		$realProductId = $basketItem->getProductId();
		$isCatalog = $basketItem->getField('MODULE') == 'catalog';

		if ($isCatalog)
		{
			$productInfo = \CCatalogSKU::GetProductInfo($realProductId);

			if (!empty($productInfo['ID']))
			{
				$realProductId = $productInfo['ID'];
				$iblockId = $productInfo['IBLOCK_ID'];
			}
			else
			{
				// get iblock id
				$element = \Bitrix\Iblock\ElementTable::getRow(array(
					'select' => array('IBLOCK_ID'),
					'filter' => array('=ID' => $realProductId)
				));

				if (!empty($element))
				{
					$iblockId = $element['IBLOCK_ID'];
				}
			}
		}

		// select site user id & recommendation id
		$siteUserId = 0;
		$recommendationId = '';

		// first, try to find in cookies
		$recommendationCookie = Context::getCurrent()->getRequest()->getCookie(static::getCookieLogName());

		if (!empty($recommendationCookie))
		{
			$recommendations = static::decodeProductLog($recommendationCookie);

			if (is_array($recommendations) && isset($recommendations[$realProductId]))
			{
				$recommendationId = $recommendations[$realProductId][0];
			}
		}

		if (empty($recommendationId) && $isCatalog)
		{
			// ok then, lets see in views history
			//if(\COption::GetOptionString("sale", "encode_fuser_id", "N") == "Y")
			if (!is_numeric($basketItem->getFUserId()))
			{
				$filter = array('CODE' => $basketItem->getFUserId());
			}
			else
			{
				$filter = array('ID' => $basketItem->getFUserId());
			}

			$result = \CSaleUser::getList($filter);

			if (!empty($result))
			{
				$siteUserId = $result['USER_ID'];

				// select recommendation id
				$fuser = $result['ID'];

				$viewResult = CatalogViewedProductTable::getList(array(
					'select' => array('RECOMMENDATION'),
					'filter' => array(
						'=FUSER_ID' => $fuser,
						'=PRODUCT_ID' => $basketItem->getProductId()
					),
					'order' => array('DATE_VISIT' => 'DESC')
				))->fetch();

				if (!empty($viewResult['RECOMMENDATION']))
				{
					$recommendationId = $viewResult['RECOMMENDATION'];
				}
			}
		}

		// prepare data
		$data = array(
			'product_id' => $realProductId,
			'iblock_id' => $iblockId,
			'user_id' => $siteUserId,
			'bx_user_id' => static::getBxUserId(),
			'domain' => Context::getCurrent()->getServer()->getHttpHost(),
			'recommendation' => $recommendationId,
			'date' => date(DATE_ISO8601)
		);

		// debug info
		global $USER;

		$data['real_user_id'] = $USER->getId() ?: 0;
		$data['is_admin'] = (int) $USER->IsAdmin();
		$data['admin_section'] = (int) (defined('ADMIN_SECTION') && ADMIN_SECTION);
		$data['admin_panel'] = (int) \CTopPanel::shouldShowPanel();

		// try to guess unnatural baskets
		$data['artificial_basket'] = (int) (
			($data['user_id'] > 0 && $data['user_id'] != $data['real_user_id'])
			||  $data['is_admin'] || $data['admin_section'] || $data['admin_panel']
		);

		// save
		CounterDataTable::add(array(
			'TYPE' => 'basket',
			'DATA' => $data
		));

		// update basket with recommendation id
		if (!empty($recommendationId))
		{
			$conn = Application::getConnection();
			$helper = $conn->getSqlHelper();

			$conn->query(
				"UPDATE ".$helper->quote('b_sale_basket')
				." SET RECOMMENDATION='".$helper->forSql($recommendationId)."' WHERE ID=".(int) $basketItem->getId()
			);
		}
	}

	// order detailed info (sale:OnSaleOrderSaved)
	public static function catchCatalogOrder(Event $event)
	{
		if (!static::isOn())
		{
			return;
		}

		$isNew = $event->getParameter("IS_NEW");

		if (!$isNew)
		{
			// only new orders
			return;
		}

		/** @var Order $orderItem */
		$orderItem = $event->getParameter("ENTITY");

		$data = static::getOrderInfo($orderItem->getId());

		if (empty($data['products']))
		{
			return;
		}

		// add bxuid
		$data['bx_user_id'] = static::getBxUserId();

		if (empty($data['bx_user_id']) && !empty($data['user_id']))
		{
			$orderUser = UserTable::getRow(array(
				'select' => array('BX_USER_ID'),
				'filter' => array('=ID' => $data['user_id'])
			));

			if (!empty($orderUser) && !empty($orderUser['BX_USER_ID']))
			{
				$data['bx_user_id'] = $orderUser['BX_USER_ID'];
			}
		}

		// add general info
		$data['paid'] = '0';
		$data['domain'] = Context::getCurrent()->getServer()->getHttpHost();
		$data['date'] = date(DATE_ISO8601);

		// add debug info
		global $USER;

		$data['real_user_id'] = $USER->getId() ?: 0;
		$data['cookie_size'] = count($_COOKIE);
		$data['is_admin'] = (int) $USER->IsAdmin();
		$data['admin_section'] = (int) (defined('ADMIN_SECTION') && ADMIN_SECTION);
		$data['admin_panel'] = (int) \CTopPanel::shouldShowPanel();

		// try to guess unnatural orders
		$data['artificial_order'] = (int) (
			($data['user_id'] != $data['real_user_id']) || !$data['cookie_size']
			||  $data['is_admin'] || $data['admin_section'] || $data['admin_panel']
		);

		CounterDataTable::add(array(
			'TYPE' => 'order',
			'DATA' => $data
		));

		// set bxuid to the order
		if (!empty($data['bx_user_id']))
		{
			// if sale version is fresh enough
			if (OrderTable::getEntity()->hasField('BX_USER_ID'))
			{
				OrderTable::update($data['order_id'], array('BX_USER_ID' => $data['bx_user_id']));
			}
		}
	}

	// order payment (sale:OnSaleOrderPaid)
	public static function catchCatalogOrderPayment(Event $event)
	{
		if (!static::isOn())
		{
			return;
		}

		/** @var Order $orderItem */
		$orderItem = $event->getParameter("ENTITY");

		$data = static::getOrderInfo($orderItem->getId());

		if (empty($data['products']))
		{
			return;
		}

		// add bxuid
		$data['bx_user_id'] = static::getBxUserId();

		if (empty($data['bx_user_id']) && OrderTable::getEntity()->hasField('BX_USER_ID'))
		{
			$order = OrderTable::getRow(array(
				'select' => array('BX_USER_ID'),
				'filter' => array('=ID' => $orderItem->getId())
			));

			if (!empty($order) && !empty($order['BX_USER_ID']))
			{
				$data['bx_user_id'] = $order['BX_USER_ID'];
			}
		}

		// add general info
		$data['paid'] = '1';
		$data['domain'] = Context::getCurrent()->getServer()->getHttpHost();
		$data['date'] = date(DATE_ISO8601);

		CounterDataTable::add(array(
			'TYPE' => 'order_pay',
			'DATA' => $data
		));
	}

	public static function getOrderInfo($orderId)
	{
		// order itself
		$order = \CSaleOrder::getById($orderId);

		// buyer info
		$siteUserId = $order['USER_ID'];

		$phone = '';
		$phone256 = '';
		$phone256_e164 = '';

		$email = '';
		$email256 = '';

		$result = \CSaleOrderPropsValue::GetList(array(), array("ORDER_ID" => $orderId));
		while ($row = $result->fetch())
		{
			if (empty($phone) && mb_stripos($row['CODE'], 'PHONE') !== false)
			{
				$stPhone = static::normalizePhoneNumber($row['VALUE']);

				if (!empty($stPhone))
				{
					$phone = sha1($stPhone);
					$phone256 = hash('sha256', $stPhone);
					$phone256_e164 = hash('sha256', '+'.$stPhone);
				}
			}

			if (empty($email) && mb_stripos($row['CODE'], 'EMAIL') !== false)
			{
				if (!empty($row['VALUE']))
				{
					$email = sha1($row['VALUE']);
					$email256 = hash('sha256', mb_strtolower(trim($row['VALUE'])));
				}
			}
		}

		// products info
		$products = array();

		$result = \CSaleBasket::getList(
			array(), $arFilter = array('ORDER_ID' => $orderId), false, false,
			array('PRODUCT_ID', 'RECOMMENDATION', 'QUANTITY', 'PRICE', 'CURRENCY', 'MODULE')
		);

		while ($row = $result->fetch())
		{
			$realProductId = $row['PRODUCT_ID'];
			$iblockId = 0;

			// get iblock id for catalog products
			if ($row['MODULE'] == 'catalog')
			{
				$productInfo = \CCatalogSKU::GetProductInfo($row['PRODUCT_ID']);

				if (!empty($productInfo['ID']))
				{
					$realProductId = $productInfo['ID'];
					$iblockId = $productInfo['IBLOCK_ID'];
				}
				else
				{
					// get iblock id
					$element = \Bitrix\Iblock\ElementTable::getRow(array(
						'select' => array('IBLOCK_ID'),
						'filter' => array('=ID' => $realProductId)
					));

					if (!empty($element))
					{
						$iblockId = $element['IBLOCK_ID'];
					}
				}
			}

			$products[] = array(
				'product_id' => $realProductId,
				'iblock_id' => $iblockId,
				'quantity' => $row['QUANTITY'],
				'price' => $row['PRICE'],
				'currency' => $row['CURRENCY'],
				'recommendation' => $row['RECOMMENDATION']
			);
		}

		// all together
		$data = array(
			'order_id' => $orderId,
			'user_id' => $siteUserId,
			'phone' => $phone,
			'phone256' => $phone256,
			'phone256_e164' => $phone256_e164,
			'email' => $email,
			'email256' => $email256,
			'products' => $products,
			'price' => $order['PRICE'],
			'currency' => $order['CURRENCY']
		);

		return $data;
	}

	protected static function getBxUserId()
	{
		return $_COOKIE['BX_USER_ID'];
	}

	public static function normalizePhoneNumber($phone)
	{
		$phone = preg_replace('/[^\d]/', '', $phone);

		$cleanPhone = \NormalizePhone($phone, 6);

		if (mb_strlen($cleanPhone) == 10)
		{
			$cleanPhone = '7'.$cleanPhone;
		}

		return $cleanPhone;
	}

	public static function isOn()
	{
		return SiteSpeed::isOn()
			&& Option::get("main", "gather_catalog_stat", "Y") === "Y"
			&& !Application::getInstance()->getLicense()->isDemoKey()
		;
	}

	public static function getProductIdsByOfferIds($offerIds)
	{
		if (empty($offerIds))
			return array();

		$bestList = array();
		$iblockGroup = array();
		$itemIterator = \Bitrix\Iblock\ElementTable::getList(array(
			'select' => array('ID', 'IBLOCK_ID'),
			'filter' => array('@ID' => $offerIds, '=ACTIVE'=> 'Y')
		));
		while ($item = $itemIterator->fetch())
		{
			if (!isset($iblockGroup[$item['IBLOCK_ID']]))
				$iblockGroup[$item['IBLOCK_ID']] = array();
			$iblockGroup[$item['IBLOCK_ID']][] = $item['ID'];
			$bestList[$item['ID']] = array();
		}

		if (empty($iblockGroup))
		{
			return array();
		}

		$iblockSku = array();
		$iblockOffers = array();

		$iblockIterator = \Bitrix\Catalog\CatalogIblockTable::getList(array(
			'select' => array('IBLOCK_ID', 'PRODUCT_IBLOCK_ID', 'SKU_PROPERTY_ID', 'VERSION' => 'IBLOCK.VERSION'),
			'filter' => array('=IBLOCK_ID' => array_keys($iblockGroup), '!=PRODUCT_IBLOCK_ID' => 0)
		));
		while ($iblock = $iblockIterator->fetch())
		{
			$iblock['IBLOCK_ID'] = (int)$iblock['IBLOCK_ID'];
			$iblock['PRODUCT_IBLOCK_ID'] = (int)$iblock['PRODUCT_IBLOCK_ID'];
			$iblock['SKU_PROPERTY_ID'] = (int)$iblock['SKU_PROPERTY_ID'];
			$iblock['VERSION'] = (int)$iblock['VERSION'];
			$iblockSku[$iblock['IBLOCK_ID']] = $iblock;
			$iblockOffers[$iblock['IBLOCK_ID']] = $iblockGroup[$iblock['IBLOCK_ID']];
		}
		unset($iblock, $iblockIterator);

		if (empty($iblockOffers))
			return array();

		$offerLink = array();
		foreach ($iblockOffers as $iblockId => $items)
		{
			$skuProperty = 'PROPERTY_'.$iblockSku[$iblockId]['SKU_PROPERTY_ID'];
			$iblockFilter = array(
				'IBLOCK_ID' => $iblockId,
				'=ID' => $items
			);
			$iblockFields = array('ID', 'IBLOCK_ID', $skuProperty);
			$skuProperty .= '_VALUE';
			$offersIterator = \CIBlockElement::getList(
				array('ID' => 'ASC'),
				$iblockFilter,
				false,
				false,
				$iblockFields
			);

			while ($offer = $offersIterator->Fetch())
			{
				$productId = (int)$offer[$skuProperty];
				if ($productId <= 0)
				{
					unset($bestList[$offer['ID']]);
				}
				else
				{
					$bestList[$offer['ID']]['PARENT_ID'] = $productId;
					$bestList[$offer['ID']]['PARENT_IBLOCK'] = $iblockSku[$iblockId]['PRODUCT_IBLOCK_ID'];
					if (!isset($offerLink[$productId]))
						$offerLink[$productId] = array();
					$offerLink[$productId][] = $offer['ID'];
				}
			}
		}
		if (!empty($offerLink))
		{
			$productIterator = \Bitrix\Iblock\ElementTable::getList(array(
				'select' => array('ID'),
				'filter' => array('@ID' => array_keys($offerLink), '=ACTIVE' => 'N')
			));
			while ($product = $productIterator->fetch())
			{
				if (empty($offerLink[$product['ID']]))
					continue;
				foreach ($offerLink[$product['ID']] as $value)
				{
					unset($bestList[$value]);
				}
			}
		}

		if (empty($bestList))
			return array();

		$finalIds = array();
		$dublicate = array();
		foreach ($bestList as $id => $info)
		{
			if (empty($info))
			{
				if (!isset($dublicate[$id]))
					$finalIds[] = $id;
				$dublicate[$id] = true;
			}
			else
			{
				if (!isset($dublicate[$id]))
					$finalIds[] = $info['PARENT_ID'];
				$dublicate[$info['PARENT_ID']] = true;
			}
		}
		unset($id, $info, $dublicate);

		return $finalIds;
	}

	/**
	 * @param array $log
	 *
	 * @return string
	 */
	public static function encodeProductLog(array $log)
	{
		$value = array();

		foreach ($log as $itemId => $recommendation)
		{
			$rcmId = $recommendation[0];
			$rcmTime = $recommendation[1];

			$value[] = $itemId.'-'.$rcmId.'-'.$rcmTime;
		}

		return join('.', $value);
	}

	/**
	 * @param $log
	 *
	 * @return array
	 */
	public static function decodeProductLog($log)
	{
		$value = array();
		$tmp = explode('.', $log);

		foreach ($tmp as $tmpval)
		{
			$meta = explode('-', $tmpval);

			if (count($meta) > 2)
			{
				$itemId = $meta[0];
				$rcmId = $meta[1];
				$rcmTime = $meta[2];

				if ($itemId && $rcmId && $rcmTime)
				{
					$value[(int)$itemId] = array($rcmId, (int) $rcmTime);
				}
			}
		}

		return $value;
	}

	/**
	 * @return string
	 */
	public static function getCookieLogName()
	{
		return self::$cookieLogName;
	}
}