Your IP : 18.118.9.147


Current Path : /home/bitrix/ext_www/crm.klimatlend.ua/bitrix/modules/crm/lib/volume/
Upload File :
Current File : /home/bitrix/ext_www/crm.klimatlend.ua/bitrix/modules/crm/lib/volume/activity.php

<?php

namespace Bitrix\Crm\Volume;

use Bitrix\Crm;
use Bitrix\Crm\Volume;
use Bitrix\Disk;
use Bitrix\Main;
use Bitrix\Main\ORM;
use Bitrix\Main\Localization\Loc;


class Activity
	extends Volume\Base
	implements Volume\IVolumeClear, Volume\IVolumeUrl
{

	/** @var array */
	protected static $entityList = array(
		Crm\ActivityTable::class,
		Crm\ActivityBindingTable::class,
		Crm\ActivityElementTable::class,
		Crm\Activity\MailMetaTable::class,
		Crm\Activity\Entity\CustomTypeTable::class,
		Crm\UserActivityTable::class,
		Crm\Statistics\Entity\ActivityStatisticsTable::class,
		Crm\Statistics\Entity\ActivityChannelStatisticsTable::class,
		Crm\Activity\Entity\AppTypeTable::class,
		Crm\Activity\MailMetaTable::class,
	);


	/** @var array */
	protected static $filterFieldAlias = array(
		'DEAL_STAGE_SEMANTIC_ID' => 'DEAL.STAGE_SEMANTIC_ID',
		'LEAD_STAGE_SEMANTIC_ID' => 'LEAD.STATUS_SEMANTIC_ID',
		'QUOTE_STATUS_ID' => 'QUOTE.STATUS_ID',
		'INVOICE_STATUS_ID' => 'INVOICE.STATUS_ID',
		'DEAL_DATE_CREATE' => 'DEAL.DATE_CREATE',
		'LEAD_DATE_CREATE' => 'LEAD.DATE_CREATE',
		'QUOTE_DATE_CREATE' => 'QUOTE.DATE_CREATE',
		'INVOICE_DATE_CREATE' => 'INVOICE.DATE_INSERT',
		'DEAL_DATE_CLOSE' => 'DEAL.CLOSEDATE',
		'LEAD_DATE_CLOSE' => 'LEAD.DATE_CLOSED',
		'QUOTE_DATE_CLOSE' => 'QUOTE.CLOSEDATE',
		'DATE_CREATE' => 'CREATED',
		'SORT_ID' => 'ID',
	);

	/**
	 * Returns title of the indicator.
	 * @return string
	 */
	public function getTitle()
	{
		return Loc::getMessage('CRM_VOLUME_ACTIVITY_TITLE');
	}


	/**
	 * Returns Socialnetwork log entity list attached to disk object.
	 * @param string $entityClass Class name of entity.
	 * @return string|null
	 */
	public static function getLiveFeedConnector($entityClass)
	{
		$attachedEntityList = array();
		if (parent::isModuleAvailable('socialnetwork') && parent::isModuleAvailable('disk'))
		{
			$attachedEntityList[Crm\ActivityTable::class] = \CCrmLiveFeedEntity::Activity;
		}

		return $attachedEntityList[$entityClass] ? : null;
	}

	/**
	 * Returns table list corresponding to indicator.
	 * @return string[]
	 */
	public function getTableList()
	{
		$tableNames = parent::getTableList();

		$tableNames[] = \CCrmActivity::COMMUNICATION_TABLE_NAME;

		return $tableNames;
	}

	/**
	 * Returns availability to drop entity.
	 *
	 * @return boolean
	 */
	public function canClearEntity()
	{
		// @see: Using of \CCrmActivity::CheckItemDeletePermission()
		return true;
	}

	/**
	 * Can filter applied to the indicator.
	 * @return boolean
	 */
	public function canBeFiltered()
	{
		return true;
	}

	/**
	 * Get entity list path.
	 * @return string
	 */
	public function getUrl()
	{
		static $entityListPath;
		if($entityListPath === null)
		{
			$entityListPath = \CComponentEngine::MakePathFromTemplate(
				\Bitrix\Main\Config\Option::get('crm', 'path_to_activity_list', '/crm/activity/')
			);
		}

		return $entityListPath;
	}

	/**
	 * Get filter reset parems for entity grid.
	 * @return array
	 */
	public function getGridFilterResetParam()
	{
		$entityListReset = array(
			'FILTER_ID' => 'CRM_ACTIVITY_LIST_MY_ACTIVITIES',
			'GRID_ID' => 'CRM_ACTIVITY_LIST_MY_ACTIVITIES',
			'FILTER_FIELDS' => 'CREATED',
		);

		return $entityListReset;
	}

	/**
	 * Get filter alias for url to entity list path.
	 * @return array
	 */
	public function getFilterAlias()
	{
		return array(
			'DATE_CREATE' => 'CREATED',
		);
	}

	/**
	 * Component action list for measure process.
	 *
	 * @param array $componentCommandAlias Command alias.
	 *
	 * @return array
	 */
	public function getActionList($componentCommandAlias)
	{
		return $this->prepareRangeActionList(
			Crm\ActivityTable::class,
			'CREATED',
			array(
				'MEASURE_ENTITY' => $componentCommandAlias['MEASURE_ENTITY'],
				'MEASURE_FILE' => $componentCommandAlias['MEASURE_FILE'],
			)
		);
	}



	/**
	 * Returns query.
	 * @param string $indicator Volume indicator class name.
	 * @param  array $entityGroupField Fileds for groupping.
	 * @return Main\ORM\Query\Query
	 */
	public function prepareQuery($indicator = '', $entityGroupField = array())
	{
		$query = Crm\ActivityTable::query();

		if (
			$indicator == Volume\Company::class
		)
		{
			$companyRelation = new ORM\Fields\Relations\Reference(
				'COMPANY',
				Crm\CompanyTable::class,
				ORM\Query\Join::on('this.BINDINGS.OWNER_ID', 'ref.ID')->where('this.BINDINGS.OWNER_TYPE_ID', \CCrmOwnerType::Company),
				array('join_type' => 'INNER')
			);
			$query->registerRuntimeField($companyRelation);
		}
		elseif (
			$indicator == Volume\Contact::class
		)
		{
			$contactRelation = new ORM\Fields\Relations\Reference(
				'CONTACT',
				Crm\ContactTable::class,
				ORM\Query\Join::on('this.BINDINGS.OWNER_ID', 'ref.ID')->where('this.BINDINGS.OWNER_TYPE_ID', \CCrmOwnerType::Contact),
				array('join_type' => 'INNER')
			);
			$query->registerRuntimeField($contactRelation);
		}
		else
		{
			//---- Deal
			$dealRelation = new ORM\Fields\Relations\Reference(
				'DEAL',
				Crm\DealTable::class,
				ORM\Query\Join::on('this.BINDINGS.OWNER_ID', 'ref.ID')->where('this.BINDINGS.OWNER_TYPE_ID', \CCrmOwnerType::Deal),
				array('join_type' => ($indicator == Volume\Deal::class ? 'INNER' : 'LEFT'))
			);
			$query->registerRuntimeField($dealRelation);

			//---- Lead
			$leadRelation = new ORM\Fields\Relations\Reference(
				'LEAD',
				Crm\LeadTable::class,
				ORM\Query\Join::on('this.BINDINGS.OWNER_ID', 'ref.ID')->where('this.BINDINGS.OWNER_TYPE_ID', \CCrmOwnerType::Lead),
				array('join_type' => ($indicator == Volume\Lead::class ? 'INNER' : 'LEFT'))
			);
			$query->registerRuntimeField($leadRelation);

			//---- Quote
			$quoteRelation = new ORM\Fields\Relations\Reference(
				'QUOTE',
				Crm\QuoteTable::class,
				ORM\Query\Join::on('this.BINDINGS.OWNER_ID', 'ref.ID')->where('this.BINDINGS.OWNER_TYPE_ID', \CCrmOwnerType::Quote),
				array('join_type' => ($indicator == Volume\Quote::class ? 'INNER' : 'LEFT'))
			);
			$query->registerRuntimeField($quoteRelation);

			// STAGE_SEMANTIC_ID
			Volume\Quote::registerStageField($query, 'QUOTE', 'QUOTE_STAGE_SEMANTIC_ID');


			$invoiceRelation = new ORM\Fields\Relations\Reference(
				'INVOICE',
				Crm\InvoiceTable::class,
				ORM\Query\Join::on('this.BINDINGS.OWNER_ID', 'ref.ID')->where('this.BINDINGS.OWNER_TYPE_ID', \CCrmOwnerType::Invoice),
				array('join_type' => ($indicator == Volume\Invoice::class ? 'INNER' : 'LEFT'))
			);
			$query->registerRuntimeField($invoiceRelation);

			$dayField = new ORM\Fields\ExpressionField(
				'INVOICE_DATE_CREATE_SHORT',
				'DATE(%s)',
				'INVOICE.DATE_INSERT'
			);
			$query->registerRuntimeField($dayField);

			// STAGE_SEMANTIC_ID
			Volume\Invoice::registerStageField($query, 'INVOICE', 'INVOICE_STAGE_SEMANTIC_ID');

			$stageField = new ORM\Fields\ExpressionField(
				'STAGE_SEMANTIC_ID',
				'case '.
				' when %s is not null then %s '.
				' when %s is not null then %s '.
				' when (%s) is not null then (%s) '.
				' when (%s) is not null then (%s) '.
				' else \'-\' '.
				'end',
				array(
					'DEAL.STAGE_SEMANTIC_ID', 'DEAL.STAGE_SEMANTIC_ID',
					'LEAD.STATUS_SEMANTIC_ID', 'LEAD.STATUS_SEMANTIC_ID',
					'QUOTE_STAGE_SEMANTIC_ID', 'QUOTE_STAGE_SEMANTIC_ID',
					'INVOICE_STAGE_SEMANTIC_ID', 'INVOICE_STAGE_SEMANTIC_ID'
				)
			);
			$query->registerRuntimeField($stageField);
		}

		return $query;
	}

	/**
	 * Returns query.
	 * @param string $indicator Volume indicator class name.
	 * @param  array $entityGroupField Fileds for groupping.
	 * @return ORM\Query\Query
	 */
	public function prepareFileQuery($indicator = '', $entityGroupField = array())
	{
		$queryBindings = Crm\ActivityBindingTable::query();

		$activityRelation = new ORM\Fields\Relations\Reference(
			'ACTIVITY',
			Crm\ActivityTable::class,
			ORM\Query\Join::on('this.ACTIVITY_ID', 'ref.ID'),
			array('join_type' => 'INNER')
		);
		$queryBindings->registerRuntimeField($activityRelation);

		$entityStageSemanticField = '';

		if (
			$indicator == Volume\Company::class
		)
		{
			$companyRelation = new ORM\Fields\Relations\Reference(
				'COMPANY',
				Crm\CompanyTable::class,
				ORM\Query\Join::on('this.OWNER_ID', 'ref.ID')->where('this.OWNER_TYPE_ID', \CCrmOwnerType::Company),
				array('join_type' => 'INNER')
			);
			$queryBindings->registerRuntimeField($companyRelation);
		}
		elseif (
			$indicator == Volume\Contact::class
		)
		{
			$contactRelation = new ORM\Fields\Relations\Reference(
				'CONTACT',
				Crm\ContactTable::class,
				ORM\Query\Join::on('this.OWNER_ID', 'ref.ID')->where('this.OWNER_TYPE_ID', \CCrmOwnerType::Contact),
				array('join_type' => 'INNER')
			);
			$queryBindings->registerRuntimeField($contactRelation);
		}
		else
		{
			//----- Deal
			$dealRelation = new ORM\Fields\Relations\Reference(
				'DEAL',
				Crm\DealTable::class,
				ORM\Query\Join::on('this.OWNER_ID', 'ref.ID')->where('this.OWNER_TYPE_ID', \CCrmOwnerType::Deal),
				array('join_type' => ($indicator == Volume\Deal::class ? 'INNER' : 'LEFT'))
			);
			$queryBindings->registerRuntimeField($dealRelation);

			if ($indicator === Volume\Deal::class)
			{
				$entityStageSemanticField = 'DEAL_STAGE_SEMANTIC_ID';
				$queryBindings
					->registerRuntimeField(new ORM\Fields\ExpressionField($entityStageSemanticField, 'MAX(%s)', 'DEAL.STAGE_SEMANTIC_ID'))
					->addSelect($entityStageSemanticField);
			}
			else
			{
				$queryBindings
					->registerRuntimeField(new ORM\Fields\ExpressionField('DEAL_STAGE_SEMANTIC_ID', '%s', 'DEAL.STAGE_SEMANTIC_ID'));
			}


			//----- Lead
			$leadRelation = new ORM\Fields\Relations\Reference(
				'LEAD',
				Crm\LeadTable::class,
				ORM\Query\Join::on('this.OWNER_ID', 'ref.ID')->where('this.OWNER_TYPE_ID', \CCrmOwnerType::Lead),
				array('join_type' => ($indicator == Volume\Lead::class ? 'INNER' : 'LEFT'))
			);
			$queryBindings->registerRuntimeField($leadRelation);

			if ($indicator === Volume\Lead::class)
			{
				$entityStageSemanticField = 'LEAD_STATUS_SEMANTIC_ID';
				$queryBindings
					->registerRuntimeField(new ORM\Fields\ExpressionField($entityStageSemanticField, 'MAX(%s)', 'LEAD.STATUS_SEMANTIC_ID'))
					->addSelect($entityStageSemanticField);
			}
			else
			{
				$queryBindings
					->registerRuntimeField(new ORM\Fields\ExpressionField('LEAD_STATUS_SEMANTIC_ID', '%s', 'LEAD.STATUS_SEMANTIC_ID'));
			}


			//---- Quote
			$quoteRelation = new ORM\Fields\Relations\Reference(
				'QUOTE',
				Crm\QuoteTable::class,
				ORM\Query\Join::on('this.OWNER_ID', 'ref.ID')->where('this.OWNER_TYPE_ID', \CCrmOwnerType::Quote),
				array('join_type' => ($indicator == Volume\Quote::class ? 'INNER' : 'LEFT'))
			);
			$queryBindings->registerRuntimeField($quoteRelation);

			if ($indicator === Volume\Quote::class)
			{
				$entityStageSemanticField = 'QUOTE_STAGE_SEMANTIC_ID';
				Volume\Quote::registerStageField($queryBindings, 'QUOTE', 'QUOTE_STAGE_SRC');

				$queryBindings
					->registerRuntimeField(new ORM\Fields\ExpressionField($entityStageSemanticField, 'MAX(%s)', 'QUOTE_STAGE_SRC'))
					->addSelect($entityStageSemanticField);
			}
			else
			{
				// QUOTE_STAGE_SEMANTIC_ID
				Volume\Quote::registerStageField($queryBindings, 'QUOTE', 'QUOTE_STAGE_SEMANTIC_ID');
			}


			//----- Invoice
			$invoiceRelation = new ORM\Fields\Relations\Reference(
				'INVOICE',
				Crm\InvoiceTable::class,
				ORM\Query\Join::on('this.OWNER_ID', 'ref.ID')->where('this.OWNER_TYPE_ID', \CCrmOwnerType::Invoice),
				array('join_type' => ($indicator == Volume\Invoice::class ? 'INNER' : 'LEFT'))
			);
			$queryBindings->registerRuntimeField($invoiceRelation);

			if ($indicator === Volume\Invoice::class)
			{
				$entityStageSemanticField = 'INVOICE_STAGE_SEMANTIC_ID';
				Volume\Invoice::registerStageField($queryBindings, 'INVOICE', 'INVOICE_STAGE_SRC');

				$queryBindings
					->registerRuntimeField(new ORM\Fields\ExpressionField($entityStageSemanticField, 'MAX(%s)', 'INVOICE_STAGE_SRC'))
					->addSelect($entityStageSemanticField);
			}
			else
			{
				// INVOICE_STAGE_SEMANTIC_ID
				Volume\Invoice::registerStageField($queryBindings, 'INVOICE', 'INVOICE_STAGE_SEMANTIC_ID');
			}


			if ($indicator === Volume\Activity::class)
			{
				$entityStageSemanticField = 'STAGE_SEMANTIC_ID_MAX';
				// STAGE_SEMANTIC_ID
				$stageField = new ORM\Fields\ExpressionField(
					'ACT_STAGE_SEMANTIC_ID',
					'CASE '.
					' when %s is not null then %s '.
					' when %s is not null then %s '.
					' when %s is not null then %s '.
					' when %s is not null then %s '.
					'END',
					array(
						'DEAL_STAGE_SEMANTIC_ID', 'DEAL_STAGE_SEMANTIC_ID',
						'LEAD_STATUS_SEMANTIC_ID', 'LEAD_STATUS_SEMANTIC_ID',
						'QUOTE_STAGE_SEMANTIC_ID', 'QUOTE_STAGE_SEMANTIC_ID',
						'INVOICE_STAGE_SEMANTIC_ID', 'INVOICE_STAGE_SEMANTIC_ID',
					)
				);
				$queryBindings
					->registerRuntimeField($stageField)
					->registerRuntimeField(new ORM\Fields\ExpressionField($entityStageSemanticField, 'MAX(%s)', 'ACT_STAGE_SEMANTIC_ID'))
					->addSelect($entityStageSemanticField);
			}
		}

		$queryBindings
			->registerRuntimeField(new ORM\Fields\ExpressionField('DATE_CREATE_SHORT_MAX', 'MAX(%s)', 'ACTIVITY.DATE_CREATED_SHORT'))
			->addSelect('DATE_CREATE_SHORT_MAX')

			->registerRuntimeField(new ORM\Fields\ExpressionField('ACTIVITY_ID_MAX', 'MAX(%s)', 'ACTIVITY_ID'))
			->addSelect('ACTIVITY_ID_MAX')

			// group by
			->addGroup('ACTIVITY_ID')
			// having
			->registerRuntimeField(new ORM\Fields\ExpressionField('CNT', 'COUNT(*)'))
			->addFilter('>CNT', 0)
		;

		// filter here

		$subEntityBindings = Main\ORM\Entity::getInstanceByQuery($queryBindings);
		$bindings = new Main\ORM\Fields\Relations\Reference('BIND', $subEntityBindings, ORM\Query\Join::on('this.ID', 'ref.ACTIVITY_ID_MAX'));

		$query = Crm\ActivityTable::query();
		$query
			->registerRuntimeField($bindings)
			->registerRuntimeField(new ORM\Fields\ExpressionField('DATE_CREATED_SHORT', '%s', 'BIND.DATE_CREATE_SHORT_MAX'))
		;

		if ($entityStageSemanticField !== '')
		{
			$query->registerRuntimeField(new ORM\Fields\ExpressionField('STAGE_SEMANTIC_ID', '%s', 'BIND.'.$entityStageSemanticField));
		}

		return $query;
	}

	/**
	 * Setups filter params into query.
	 * @param ORM\Query\Query $query Query.
	 * @return boolean
	 */
	public function prepareFilter(ORM\Query\Query $query)
	{
		$isAllValueApplied = true;
		$filter = $this->getFilter();

		foreach ($filter as $key => $value)
		{
			if (empty($value))
			{
				continue;
			}
			$key0 = trim($key, '<>!=');
			if ($key0 === 'QUOTE_STAGE_SEMANTIC_ID')
			{
				$statuses = Volume\Quote::getStatusSemantics($value);
				$query->where('QUOTE.STATUS_ID', 'in', $statuses);
			}
			elseif ($key0 === 'INVOICE_STAGE_SEMANTIC_ID')
			{
				$statuses = Volume\Invoice::getStatusSemantics($value);
				$query->where('INVOICE.STATUS_ID', 'in', $statuses);
			}
			elseif (isset(static::$filterFieldAlias[$key0]))
			{
				$key1 = str_replace($key0, static::$filterFieldAlias[$key0], $key);
				if (is_array($value))
				{
					$query->where($key1, 'in', $value);
				}
				else
				{
					$query->addFilter($key1, $value);
				}
			}
			else
			{
				$isAllValueApplied = $this->addFilterEntityField($query, $query->getEntity(), $key, $value);
			}
		}

		return $isAllValueApplied;
	}


	/**
	 * Returns query to measure files attached to activity.
	 * @param string $indicator Volume indicator class name.
	 * @param  array $entityGroupField Fileds for groupping.
	 * @return ORM\Query\Query
	 */
	public function getActivityFileMeasureQuery($indicator, $entityGroupField = array())
	{
		$query = $this->prepareFileQuery($indicator, $entityGroupField);

		$this->prepareFilter($query);

		// file type
		$subQueryFile = Main\FileTable::query();
		$elementCrmFile = new ORM\Fields\Relations\Reference(
			'elem',
			Crm\ActivityElementTable::class,
			ORM\Query\Join::on('this.ID', 'ref.ELEMENT_ID')
							 ->where('ref.STORAGE_TYPE_ID', Crm\Integration\StorageType::File),
			array('join_type' => 'INNER')
		);
		$subQueryFile
			->registerRuntimeField($elementCrmFile)

			->registerRuntimeField(new ORM\Fields\ExpressionField('SIZE', 'MAX(%s)', 'FILE_SIZE'))
			->addSelect('SIZE')

			->registerRuntimeField(new ORM\Fields\ExpressionField('ACTIVITY_ID', 'MAX(%s)', 'elem.ACTIVITY_ID'))
			->addSelect('ACTIVITY_ID')

			->registerRuntimeField(new ORM\Fields\ExpressionField('FILE_COUNT', 'COUNT(DISTINCT(%s))', 'elem.ELEMENT_ID'))
			->addSelect('FILE_COUNT')

			// group by
			->addGroup('elem.ELEMENT_ID')

			// having count(*) > 0
			->registerRuntimeField(new ORM\Fields\ExpressionField('CNT', 'COUNT(*)'))
			->addFilter('>CNT', 0)
		;

		// file type
		$subEntityFile = Main\ORM\Entity::getInstanceByQuery($subQueryFile);
		$file = new Main\ORM\Fields\Relations\Reference('FILE', $subEntityFile, ORM\Query\Join::on('this.ID', 'ref.ACTIVITY_ID'));
		$query->registerRuntimeField($file);

		// disk type
		if (parent::isModuleAvailable('disk'))
		{
			$subQueryDisk = Disk\Internals\FileTable::query();
			$elementCrmDisk = new ORM\Fields\Relations\Reference(
				'elem',
				Crm\ActivityElementTable::class,
				ORM\Query\Join::on('this.ID', 'ref.ELEMENT_ID')
								->where('ref.STORAGE_TYPE_ID', Crm\Integration\StorageType::Disk)
								->where('this.TYPE', '=', \Bitrix\Disk\Internals\ObjectTable::TYPE_FILE),
				array('join_type' => 'INNER')
			);
			$subQueryDisk
				->registerRuntimeField($elementCrmDisk)

				->registerRuntimeField(new ORM\Fields\ExpressionField('DISK_SIZE', 'MAX(%s)', 'SIZE'))
				->addSelect('DISK_SIZE')

				->registerRuntimeField(new ORM\Fields\ExpressionField('ACTIVITY_ID', 'MAX(%s)', 'elem.ACTIVITY_ID'))
				->addSelect('ACTIVITY_ID')

				->registerRuntimeField(new ORM\Fields\ExpressionField('DISK_COUNT', 'COUNT(DISTINCT(%s))', 'elem.ELEMENT_ID'))
				->addSelect('DISK_COUNT')

				// group by
				->addGroup('elem.ELEMENT_ID')

				// having count(*) > 0
				->registerRuntimeField(new ORM\Fields\ExpressionField('CNT', 'COUNT(*)'))
				->addFilter('>CNT', 0)
			;

			// disk type
			$subEntityDisk = Main\ORM\Entity::getInstanceByQuery($subQueryDisk);
			$diskFile = new Main\ORM\Fields\Relations\Reference('DISK_FILE', $subEntityDisk, ORM\Query\Join::on('this.ID', 'ref.ACTIVITY_ID'));
			$query->registerRuntimeField($diskFile);

			$diskSize = new ORM\Fields\ExpressionField('DISK_SIZE', 'SUM(IFNULL(%s, 0))', 'DISK_FILE.DISK_SIZE');
			$diskCount = new ORM\Fields\ExpressionField('DISK_COUNT', 'SUM(IFNULL(%s, 0))', 'DISK_FILE.DISK_COUNT');
			$query
				->registerRuntimeField($diskSize)
				->registerRuntimeField($diskCount);

			$fileSize = new ORM\Fields\ExpressionField('FILE_SIZE', 'SUM(IFNULL(%s, 0)) + SUM(IFNULL(%s, 0))', array('FILE.SIZE', 'DISK_FILE.DISK_SIZE'));
			$fileCount = new ORM\Fields\ExpressionField('FILE_COUNT', 'SUM(IFNULL(%s, 0)) + SUM(IFNULL(%s, 0))', array('FILE.FILE_COUNT', 'DISK_FILE.DISK_COUNT'));
			$query
				->registerRuntimeField($fileSize)
				->registerRuntimeField($fileCount);

			$query
				->addSelect('FILE_SIZE')
				->addSelect('FILE_COUNT')
				->addSelect('DISK_SIZE')
				->addSelect('DISK_COUNT');
		}
		else
		{
			$fileSize = new ORM\Fields\ExpressionField('FILE_SIZE', 'SUM(IFNULL(%s, 0))', 'FILE.SIZE');
			$fileCount = new ORM\Fields\ExpressionField('FILE_COUNT', 'SUM(IFNULL(%s, 0))', 'FILE.FILE_COUNT');
			$query
				->registerRuntimeField($fileSize)
				->addSelect('FILE_SIZE')
				->registerRuntimeField($fileCount)
				->addSelect('FILE_COUNT');
		}

		return $query;
	}

	/**
	 * Runs measure test for tables.
	 * @return self
	 */
	public function measureEntity()
	{
		self::loadTablesInformation();

		$query = $this->prepareQuery();

		if ($this->prepareFilter($query))
		{
			$avgActivityTableRowLength = (double)self::$tablesInformation[Crm\ActivityTable::getTableName()]['AVG_SIZE'];

			$connection = \Bitrix\Main\Application::getConnection();

			$this->checkTemporally();

			$data = array(
				'INDICATOR_TYPE' => '',
				'OWNER_ID' => '',
				'DATE_CREATE' => new \Bitrix\Main\Type\Date(),
				'STAGE_SEMANTIC_ID' => '',
				'ENTITY_COUNT' => '',
				'ENTITY_SIZE' => '',
			);

			$insert = $connection->getSqlHelper()->prepareInsert(Crm\VolumeTmpTable::getTableName(), $data);

			$sqlIns = 'INSERT INTO '.$connection->getSqlHelper()->quote(Crm\VolumeTmpTable::getTableName()). '('. $insert[0]. ') ';

			$query
				->registerRuntimeField(new ORM\Fields\ExpressionField('INDICATOR_TYPE', '\''.static::getIndicatorId().'\''))
				->addSelect('INDICATOR_TYPE')

				->registerRuntimeField(new ORM\Fields\ExpressionField('OWNER_ID', '\''.$this->getOwner().'\''))
				->addSelect('OWNER_ID')

				//date
				->addSelect('DATE_CREATED_SHORT', 'DATE_CREATE')
				->addGroup('DATE_CREATED_SHORT')

				// STAGE_SEMANTIC_ID
				->addSelect('STAGE_SEMANTIC_ID')
				->addGroup('STAGE_SEMANTIC_ID')

				->registerRuntimeField(new ORM\Fields\ExpressionField('ENTITY_COUNT', 'COUNT(DISTINCT %s)', 'ID'))
				->addSelect('ENTITY_COUNT')

				->registerRuntimeField(new ORM\Fields\ExpressionField('ENTITY_SIZE', 'COUNT(DISTINCT %s) * '.$avgActivityTableRowLength, 'ID'))
				->addSelect('ENTITY_SIZE');

			$querySql = $sqlIns. $query->getQuery();

			$connection->queryExecute($querySql);

			if ($this->collectEntityRowSize)
			{
				$entityList = self::getEntityList();
				foreach ($entityList as $entityClass)
				{
					if ($entityClass == Crm\ActivityTable::class || $entityClass == Crm\ActivityBindingTable::class)
					{
						continue;
					}
					/**
					 * @var \Bitrix\Main\ORM\Data\DataManager $entityClass
					 */
					$entityEntity = $entityClass::getEntity();

					$fieldName = 'ACTIVITY_ID';
					if ($entityEntity->hasField($fieldName))
					{
						$query = $this->prepareQuery();

						if ($this->prepareFilter($query))
						{
							$reference = new ORM\Fields\Relations\Reference(
								'RefEntity',
								$entityClass,
								array('this.ID' => 'ref.'.$fieldName),
								array('join_type' => 'INNER')
							);
							$query->registerRuntimeField($reference);

							$primary = $entityEntity->getPrimary();
							if (is_array($primary) && !empty($primary))
							{
								array_walk($primary, function (&$item) {
									$item = 'RefEntity.'.$item;
								});
							}
							elseif (!empty($primary))
							{
								$primary = array('RefEntity.'.$primary);
							}

							$query
								//primary
								->registerRuntimeField(new ORM\Fields\ExpressionField('COUNT_REF', 'COUNT(*)'))
								->addSelect('COUNT_REF')
								->setGroup($primary)

								//date
								->addSelect('DATE_CREATED_SHORT', 'DATE_CREATE')
								->addGroup('DATE_CREATED_SHORT')

								// STAGE_SEMANTIC_ID
								->addSelect('STAGE_SEMANTIC_ID')
								->addGroup('STAGE_SEMANTIC_ID');

							$avgTableRowLength = (double)self::$tablesInformation[$entityClass::getTableName()]['AVG_SIZE'];

							$query1 = new ORM\Query\Query($query);
							$query1
								->registerRuntimeField(new ORM\Fields\ExpressionField('INDICATOR_TYPE', '\''.static::getIndicatorId().'\''))
								->addSelect('INDICATOR_TYPE')
								->registerRuntimeField(new ORM\Fields\ExpressionField('OWNER_ID', '\''.$this->getOwner().'\''))
								->addSelect('OWNER_ID')

								//date
								->addSelect('DATE_CREATE')
								->addGroup('DATE_CREATE')

								// STAGE_SEMANTIC_ID
								->addSelect('STAGE_SEMANTIC_ID')
								->addGroup('STAGE_SEMANTIC_ID')
								->registerRuntimeField(new ORM\Fields\ExpressionField('REF_SIZE', 'SUM(COUNT_REF) * '.$avgTableRowLength))
								->addSelect('REF_SIZE');

							Crm\VolumeTmpTable::updateFromSelect(
								$query1,
								array('ENTITY_SIZE' => 'destination.ENTITY_SIZE + source.REF_SIZE'),
								array(
									'INDICATOR_TYPE',
									'OWNER_ID',
									'DATE_CREATE',
									'STAGE_SEMANTIC_ID',
								)
							);
						}
					}
				}
			}
			$this->copyTemporallyData();
		}

		return $this;
	}

	/**
	 * Runs measure test for files.
	 * @return self
	 */
	public function measureFiles()
	{
		$querySql = $this->prepareRelationQuerySql(array(
			'DATE_CREATE' => 'DATE_CREATED_SHORT',
			'STAGE_SEMANTIC_ID' => 'STAGE_SEMANTIC_ID',
		));

		if ($querySql != '')
		{
			$querySql = "
				SELECT 
					'".static::getIndicatorId()."' as INDICATOR_TYPE,
					'".$this->getOwner()."' as OWNER_ID,
					DATE_CREATE,
					STAGE_SEMANTIC_ID, 
					SUM(FILE_SIZE) as FILE_SIZE,
					SUM(FILE_COUNT) as FILE_COUNT,
					SUM(DISK_SIZE) as DISK_SIZE,
					SUM(DISK_COUNT) as DISK_COUNT
				FROM 
				(
					{$querySql}
				) src
				GROUP BY
					DATE_CREATE,
					STAGE_SEMANTIC_ID
				HAVING 
					SUM(FILE_COUNT) > 0
			";

			Crm\VolumeTable::updateFromSelect(
				$querySql,
				array(
					'FILE_SIZE' => 'destination.FILE_SIZE + source.FILE_SIZE',
					'FILE_COUNT' => 'destination.FILE_COUNT + source.FILE_COUNT',
					'DISK_SIZE' => 'destination.DISK_SIZE + source.DISK_SIZE',
					'DISK_COUNT' => 'destination.DISK_COUNT + source.DISK_COUNT',
				),
				array(
					'INDICATOR_TYPE',
					'OWNER_ID',
					'DATE_CREATE',
					'STAGE_SEMANTIC_ID',
				)
			);
		}

		return $this;
	}


	/**
	 * Returns count of entities.
	 * @return int
	 */
	public function countEntity()
	{
		$count = -1;

		$query = $this->prepareQuery();

		if ($this->prepareFilter($query))
		{
			$count = 0;

			$countField = new ORM\Fields\ExpressionField('CNT', 'COUNT(DISTINCT %s)', 'ID');
			$query
				->registerRuntimeField($countField)
				->addSelect('CNT');


			$res = $query->exec();
			if ($row = $res->fetch())
			{
				$count = $row['CNT'];
				$this->activityCount = $row['CNT'];
			}
		}

		return $count;
	}

	/**
	 * Performs dropping entity.
	 *
	 * @return boolean
	 */
	public function clearEntity()
	{
		if (!$this->canClearEntity())
		{
			return false;
		}

		$query = $this->prepareQuery();

		$success = true;

		if ($this->prepareFilter($query))
		{
			$userPermissions = \CCrmPerms::GetUserPermissions($this->getOwner());

			$query
				->setSelect(array('ID', 'OWNER_TYPE_ID', 'OWNER_ID'))
				->setLimit(self::MAX_ENTITY_PER_INTERACTION)
				->setOrder(array('ID' => 'ASC'));

			if ($this->getProcessOffset() > 0)
			{
				$query->where('ID', '>', $this->getProcessOffset());
			}

			$res = $query->exec();

			while ($activity = $res->fetch())
			{
				$this->setProcessOffset($activity['ID']);

				if (\CCrmActivity::CheckItemDeletePermission($activity, $userPermissions))
				{
					if (!\CCrmActivity::DeleteStorageElements($activity['ID']))
					{
						$this->collectError(new Main\Error(\CCrmActivity::GetLastErrorMessage(), self::ERROR_DELETION_FAILED));
					}
					if (\CCrmActivity::Delete($activity['ID'], false, false))
					{
						$this->incrementDroppedEntityCount();
					}
					else
					{
						$this->collectError(new Main\Error('Deletion failed with activity #'.$activity['ID'], self::ERROR_DELETION_FAILED));
						$this->incrementFailCount();
					}
				}
				else
				{
					$this->collectError(new Main\Error('Access denied to activity #'.$activity['ID'], self::ERROR_PERMISSION_DENIED));
					$this->incrementFailCount();
				}

				if ($this->hasTimeLimitReached())
				{
					$success = false;
					break;
				}
			}
		}

		return $success;
	}

	/**
	 * Gets SQL query code for activity count.
	 *
	 * @param array $entityGroupField Entity fields to group by.
	 *
	 * @return string
	 */
	private function prepareRelationQuerySql(array $entityGroupField = array())
	{
		$query = $this->prepareQuery();
		if ($this->prepareFilter($query))
		{
			$activityVolume = new Volume\Activity();
			$activityVolume->setFilter($this->getFilter());
		}
		else
		{
			return '';
		}

		//-----------

		$activityQuery = $activityVolume->prepareQuery(static::className());
		$activityVolume->prepareFilter($activityQuery);

		$fileCount = new ORM\Fields\ExpressionField('FILE_SIZE', '0');
		$fileBindingCount = new ORM\Fields\ExpressionField('FILE_COUNT', '0');
		$activityQuery
			->registerRuntimeField($fileCount)
			->registerRuntimeField($fileBindingCount)
			->addSelect('FILE_SIZE')
			->addSelect('FILE_COUNT');

		if (self::isModuleAvailable('disk'))
		{
			$diskCount = new ORM\Fields\ExpressionField('DISK_SIZE', '0');
			$diskBindingCount = new ORM\Fields\ExpressionField('DISK_COUNT', '0');
			$activityQuery
				->registerRuntimeField($diskCount)
				->registerRuntimeField($diskBindingCount)
				->addSelect('DISK_SIZE')
				->addSelect('DISK_COUNT');
		}

		$activityCount = new ORM\Fields\ExpressionField('ACTIVITY_COUNT', 'COUNT(DISTINCT %s)', 'ID');
		$activityBindingCount = new ORM\Fields\ExpressionField('BINDINGS_COUNT', 'COUNT(%s)', 'BINDINGS.ID');
		$activityQuery
			->registerRuntimeField($activityCount)
			->registerRuntimeField($activityBindingCount)
			->addSelect('ACTIVITY_COUNT')
			->addSelect('BINDINGS_COUNT');

		foreach ($entityGroupField as $alias => $field)
		{
			$activityQuery->addSelect($field, $alias);
			$activityQuery->addGroup($field);
		}

		//-----------

		$activityFileQuery = $activityVolume->getActivityFileMeasureQuery(static::className(), $entityGroupField);

		$activityCount = new ORM\Fields\ExpressionField('ACTIVITY_COUNT', '0');
		$activityBindingCount = new ORM\Fields\ExpressionField('BINDINGS_COUNT', '0');
		$activityFileQuery
			->registerRuntimeField($activityCount)
			->registerRuntimeField($activityBindingCount)
			->addSelect('ACTIVITY_COUNT')
			->addSelect('BINDINGS_COUNT');

		foreach ($entityGroupField as $alias => $field)
		{
			$field = str_replace('.', '_', $field);
			$activityFileQuery->addSelect($field, $alias);
			$activityFileQuery->addGroup($field);
		}

		$sqlQuery =
			$activityQuery->getQuery().
			' UNION '.
			$activityFileQuery->getQuery();

		return $sqlQuery;
	}
}