Your IP : 18.219.83.70


Current Path : /var/www/axolotl/data/www/arhangelsk.axolotls.ru/a537b/
Upload File :
Current File : /var/www/axolotl/data/www/arhangelsk.axolotls.ru/a537b/binding.tar

dealcontact.php000066400000037060150044450540007547 0ustar00<?php
/**
 * Bitrix Framework
 * @package bitrix
 * @subpackage crm
 * @copyright 2001-2016 Bitrix
 */
namespace Bitrix\Crm\Binding;

use Bitrix\Main;
use Bitrix\Main\Entity;
use Bitrix\Crm;

class DealContactTable extends Entity\DataManager
{
	/**
	 * Get table name.
	 * @return string
	 */
	public static function getTableName()
	{
		return 'b_crm_deal_contact';
	}
	/**
	 * Get table fields map.
	 * @return array
	 */
	public static function getMap()
	{
		return array(
			'DEAL_ID' => array('primary' => true, 'data_type' => 'integer'),
			'CONTACT_ID' => array('primary' => true, 'data_type' => 'integer'),
			'SORT' => array('data_type' => 'integer', 'default_value' => 0),
			'ROLE_ID' => array('data_type' => 'integer', 'default_value' => 0),
			'IS_PRIMARY' => array('data_type' => 'boolean', 'values' => array('N', 'Y'), 'default_value' => 'N')
		);
	}
	/**
	 * Execute UPSERT operation.
	 * @param array $data Field data.
	 * @return void
	 */
	public static function upsert(array $data)
	{
		$dealID = isset($data['DEAL_ID']) ? (int)$data['DEAL_ID'] : 0;
		if($dealID <= 0)
		{
			throw new Main\ArgumentException('Must contains DEAL_ID field.', 'data');
		}

		$contactID = isset($data['CONTACT_ID']) ? (int)$data['CONTACT_ID'] : 0;
		if($contactID <= 0)
		{
			throw new Main\ArgumentException('Must contains CONTACT_ID field.', 'data');
		}

		$sort = isset($data['SORT']) ? (int)$data['SORT'] : 0;
		$roleID = isset($data['ROLE_ID']) ? (int)$data['ROLE_ID'] : 0;
		$primary = isset($data['IS_PRIMARY']) && strtoupper($data['IS_PRIMARY']) === 'Y' ? 'Y' : 'N';

		$connection = Main\Application::getConnection();
		$queries = $connection->getSqlHelper()->prepareMerge(
			'b_crm_deal_contact',
			array('DEAL_ID', 'CONTACT_ID'),
			array('DEAL_ID' => $dealID, 'CONTACT_ID' => $contactID, 'SORT' => $sort, 'ROLE_ID' => $roleID, 'IS_PRIMARY' => $primary),
			array('SORT' => $sort, 'ROLE_ID' => $roleID, 'IS_PRIMARY' => $primary)
		);

		foreach($queries as $query)
		{
			$connection->queryExecute($query);
		}
	}
	/**
	 * Get deal IDs are bound to specified contact.
	 * @param int $contactID Contact ID.
	 * @return array
	 * @throws Main\ArgumentException
	 */
	public static function getContactDealIDs($contactID)
	{
		$contactID = (int)$contactID;
		if($contactID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'contactID');
		}

		$dbResult =  Main\Application::getConnection()->query(
			/** @lang text*/
			"SELECT DEAL_ID FROM b_crm_deal_contact WHERE CONTACT_ID = {$contactID}"
		);

		$results = array();
		while($ary = $dbResult->fetch())
		{
			$results[] = (int)$ary['DEAL_ID'];
		}
		return $results;
	}
	/**
	 * Get contact IDs are bound to specified deal.
	 * @param int $dealID Deal ID.
	 * @return array
	 * @throws Main\ArgumentException
	 */
	public static function getDealContactIDs($dealID)
	{
		$dealID = (int)$dealID;
		if($dealID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'dealID');
		}

		$dbResult = Main\Application::getConnection()->query(
			/** @lang text*/
			"SELECT CONTACT_ID FROM b_crm_deal_contact WHERE DEAL_ID = {$dealID} ORDER BY SORT ASC"
		);

		$results = array();
		while($ary = $dbResult->fetch())
		{
			$results[] = (int)$ary['CONTACT_ID'];
		}
		return $results;
	}
	/**
	 * Get deal's bindings.
	 * @param int $dealID Deal ID.
	 * @return array
	 * @throws Main\ArgumentException
	 */
	public static function getDealBindings($dealID)
	{
		$dealID = (int)$dealID;
		if($dealID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'dealID');
		}

		$dbResult = Main\Application::getConnection()->query(
			/** @lang text*/
			"SELECT CONTACT_ID, SORT, ROLE_ID, IS_PRIMARY FROM b_crm_deal_contact WHERE DEAL_ID = {$dealID} ORDER BY SORT"
		);

		$results = array();
		while($ary = $dbResult->fetch())
		{
			$results[] = array(
				'CONTACT_ID' => (int)$ary['CONTACT_ID'],
				'SORT' => (int)$ary['SORT'],
				'ROLE_ID' => (int)$ary['ROLE_ID'],
				'IS_PRIMARY' => $ary['IS_PRIMARY']
			);
		}
		return $results;
	}
	/**
	 * Get binding map for deal's collection.
	 * @param array $dealIDs Array of Deal IDs.
	 * @return array
	 * @throws Main\ArgumentException
	 * @throws Main\ObjectPropertyException
	 * @throws Main\SystemException
	 */
	public static function getBulkDealBindings(array $dealIDs)
	{
		$bindingMap = array();
		foreach($dealIDs as $dealID)
		{
			$bindingMap[$dealID] = array();
		}

		$dbResult = self::getList(
			array(
				'filter' => array('@DEAL_ID' => $dealIDs),
				'select' => array('DEAL_ID', 'CONTACT_ID', 'SORT', 'ROLE_ID', 'IS_PRIMARY'),
				'order' => array('DEAL_ID' => 'ASC', 'SORT' => 'ASC')
			)
		);
		while($ary = $dbResult->fetch())
		{
			$bindingMap[$ary['DEAL_ID']][] = array(
				'CONTACT_ID' => (int)$ary['CONTACT_ID'],
				'SORT' => (int)$ary['SORT'],
				'ROLE_ID' => (int)$ary['ROLE_ID'],
				'IS_PRIMARY' => $ary['IS_PRIMARY']
			);
		}
		return $bindingMap;
	}
	/**
	 *  Get deal's binding count.
	 * @param $dealID
	 * @return int
	 * @throws Main\ArgumentException
	 */
	public static function getDealBindingCount($dealID)
	{
		$dealID = (int)$dealID;
		if($dealID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'dealID');
		}

		$dbResult = Main\Application::getConnection()->query(
			/** @lang text*/
			"SELECT COUNT(*) CNT FROM b_crm_deal_contact WHERE DEAL_ID = {$dealID}"
		);

		$ary = $dbResult->fetch();
		return is_array($ary) ? (int)$ary['CNT'] : 0;
	}
	/**
	 * Check if deal has contacts.
	 * @param int $dealID Deal ID.
	 * @return bool
	 * @throws Main\ArgumentException
	 */
	public static function hasContacts($dealID)
	{
		$dealID = (int)$dealID;
		if($dealID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'dealID');
		}

		$result = self::getList(
			array(
				'select' => array('DEAL_ID'),
				'filter' => array('=DEAL_ID' => $dealID),
				'limit' => 1
			)
		);

		return is_array($result->fetch());
	}
	/**
	 * Bind deal to contacts are specified by ID.
	 * @param int $dealID Deal ID.
	 * @param array $contactIDs Array of contact IDs.
	 * @return void
	 */
	public static function bindContactIDs($dealID, array $contactIDs)
	{
		$bindings = EntityBinding::prepareEntityBindings(\CCrmOwnerType::Contact, $contactIDs);
		$qty = count($bindings);
		if($qty > 0)
		{
			for($i = 0; $i < $qty; $i++)
			{
				if($i === 0)
				{
					$bindings[$i]['IS_PRIMARY'] = 'Y';
				}
				$bindings[$i]['SORT'] = 10 * ($i + 1);
			}
			self::bindContacts($dealID, $bindings);
		}
	}
	/**
	 * Bind deal to contacts.
	 * @param int $dealID Deal ID.
	 * @param array $bindings Array of contact bindings.
	 * @return void
	 * @throws Main\ArgumentException
	 */
	public static function bindContacts($dealID, array $bindings)
	{
		$dealID = (int)$dealID;
		if($dealID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'dealID');
		}

		$qty = count($bindings);
		if($qty === 0)
		{
			return;
		}

		$processed = 0;
		for($i = 0; $i < $qty; $i++)
		{
			$binding = $bindings[$i];
			if(!is_array($binding))
			{
				continue;
			}

			$contactID = isset($binding['CONTACT_ID']) ? (int)$binding['CONTACT_ID'] : 0;
			if($contactID <= 0)
			{
				continue;
			}

			self::upsert(
				array(
					'DEAL_ID' => $dealID,
					'CONTACT_ID' => $contactID,
					'SORT' => isset($binding['SORT']) ? (int)$binding['SORT'] : (10 * ($i + 1)),
					'ROLE_ID' => isset($binding['ROLE_ID']) ? (int)$binding['ROLE_ID'] : EntityBinding::ROLE_UNDEFINED,
					'IS_PRIMARY' => isset($binding['IS_PRIMARY']) ? $binding['IS_PRIMARY'] : ''
				)
			);
			$processed++;
		}

		if($processed > 0)
		{
			Main\Application::getConnection()->queryExecute(
				/** @lang text*/
				"UPDATE b_crm_deal SET CONTACT_ID =
				(SELECT MIN(CONTACT_ID) FROM b_crm_deal_contact WHERE IS_PRIMARY = 'Y' AND DEAL_ID = {$dealID})
				WHERE ID = {$dealID}"
			);
		}
	}
	/**
	 * Unbind specified deal from specified contacts.
	 * @param int $dealID Deal ID.
	 * @param array $contactIDs Array of contact IDs.
	 * @return void
	 * @throws Main\ArgumentException
	 */
	public static function unbindContactIDs($dealID, array $contactIDs)
	{
		$dealID = (int)$dealID;
		if($dealID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'dealID');
		}

		$contactIDs = array_filter($contactIDs);
		if(empty($contactIDs))
		{
			return;
		}

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

		$values = implode(',', $contactIDs);
		$connection->queryExecute(
			/** @lang text */
			"DELETE FROM b_crm_deal_contact WHERE DEAL_ID = {$dealID} AND CONTACT_ID IN({$values})"
		);

		$connection->queryExecute(
			/** @lang text*/
			"UPDATE b_crm_deal SET CONTACT_ID =
			(SELECT MIN(CONTACT_ID) FROM b_crm_deal_contact WHERE IS_PRIMARY = 'Y' AND DEAL_ID = {$dealID})
			WHERE ID = {$dealID}"
		);
	}
	/**
	 * Unbind specified deal from specified contacts.
	 * @param int $dealID Deal ID.
	 * @param array $bindings Array of bindings.
	 * @return void
	 * @throws Main\ArgumentException
	 */
	public static function unbindContacts($dealID, array $bindings)
	{
		$dealID = (int)$dealID;
		if($dealID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'dealID');
		}

		self::unbindContactIDs($dealID, EntityBinding::prepareEntityIDs(\CCrmOwnerType::Contact, $bindings));
	}
	/**
	 * Unbind specified deal from all contacts.
	 * @param int $dealID Deal ID.
	 * @return void
	 * @throws Main\ArgumentException
	 */
	public static function unbindAllContacts($dealID)
	{
		$dealID = (int)$dealID;
		if($dealID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'dealID');
		}

		$connection = Main\Application::getConnection();
		$connection->queryExecute(
			/** @lang text */
			"DELETE FROM b_crm_deal_contact WHERE DEAL_ID = {$dealID}"
		);
		$connection->queryExecute(
			/** @lang text */
			"UPDATE b_crm_deal SET CONTACT_ID = NULL WHERE ID = {$dealID}"
		);
	}
	/**
	 * Unbind specified contact from all deals.
	 * @param int $contactID Contact ID.
	 * @return void
	 * @throws Main\ArgumentException
	 */
	public static function unbindAllDeals($contactID)
	{
		$contactID = (int)$contactID;
		if($contactID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'contactID');
		}

		$connection = Main\Application::getConnection();
		$connection->queryExecute(
		/** @lang text */
			"DELETE FROM b_crm_deal_contact WHERE CONTACT_ID = {$contactID}"
		);
		$connection->queryExecute(
		/** @lang text */
			"UPDATE b_crm_deal SET CONTACT_ID =
			(SELECT MIN(CONTACT_ID) FROM b_crm_deal_contact t WHERE t.DEAL_ID = b_crm_deal.ID)
			WHERE CONTACT_ID = {$contactID}"
		);
	}
	/**
	 * Prepage SQL join filter condition for specified entity.
	 * @param int $entityTypeID Entity type ID for filter.
	 * @param int $entityID Entity ID for filter.
	 * @param string $tableAlias Alias of primary table.
	 * @return string
	 * @throws Main\ArgumentException
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\NotSupportedException
	 */
	public static function prepareFilterJoinSql($entityTypeID, $entityID, $tableAlias)
	{
		if(!is_int($entityTypeID))
		{
			$entityTypeID = (int)$entityTypeID;
		}

		if(!\CCrmOwnerType::IsDefined($entityTypeID))
		{
			throw new Main\ArgumentOutOfRangeException('entityTypeID',
				\CCrmOwnerType::FirstOwnerType,
				\CCrmOwnerType::LastOwnerType
			);
		}

		if($entityTypeID !== \CCrmOwnerType::Contact && $entityTypeID !== \CCrmOwnerType::Deal)
		{
			$entityTypeName = \CCrmOwnerType::ResolveName($entityTypeID);
			throw new Main\NotSupportedException("Entity type: '{$entityTypeName}' is not supported in current context");
		}

		$entityIDs = is_array($entityID) ? $entityID : array($entityID);
		$effectiveIDs = array();
		foreach($entityIDs as $ID)
		{
			$ID = (int)$ID;
			if($ID > 0)
			{
				$effectiveIDs[] = $ID;
			}
		}

		$qty = count($effectiveIDs);
		if($qty > 1)
		{
			$slug = implode(',', $effectiveIDs);
			if($entityTypeID === \CCrmOwnerType::Contact)
			{
				return "INNER JOIN b_crm_deal_contact DC ON DC.CONTACT_ID IN({$slug}) AND DC.DEAL_ID = {$tableAlias}.ID";
			}
			else//if($entityTypeID === \CCrmOwnerType::Deal)
			{
				return "INNER JOIN b_crm_deal_contact DC ON DC.DEAL_ID IN({$slug}) AND DC.CONTACT_ID = {$tableAlias}.ID";
			}
		}
		elseif($qty === 1)
		{
			if($entityTypeID === \CCrmOwnerType::Contact)
			{
				return "INNER JOIN b_crm_deal_contact DC ON DC.CONTACT_ID = {$effectiveIDs[0]} AND DC.DEAL_ID = {$tableAlias}.ID";
			}
			else//if($entityTypeID === \CCrmOwnerType::Deal)
			{
				return "INNER JOIN b_crm_deal_contact DC ON DC.DEAL_ID = {$effectiveIDs[0]} AND DC.CONTACT_ID = {$tableAlias}.ID";
			}
		}
		return "";
	}
	/**
	 * Unbind all contacts from seed deal and bind to target deal
	 * @param int $seedDealID Seed deal ID.
	 * @param int $targDealID Target deal ID.
	 * @throws Main\ArgumentException
	 */
	public static function rebindAllContacts($seedDealID, $targDealID)
	{
		$seedDealID = (int)$seedDealID;
		if($seedDealID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'seedDealID');
		}

		$targDealID = (int)$targDealID;
		if($targDealID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'targDealID');
		}

		//Combine contacts from seed and target and bind to target.
		$connection = Main\Application::getConnection();
		$dbResult = $connection->query(
		/** @lang text */
			"SELECT CONTACT_ID FROM b_crm_deal_contact
				WHERE DEAL_ID IN ({$seedDealID}, {$targDealID}) GROUP BY CONTACT_ID"
		);

		$contactIDs = array();
		while($fields = $dbResult->fetch())
		{
			$contactIDs[] = (int)$fields['CONTACT_ID'];
		}

		if(!empty($contactIDs))
		{
			self::bindContactIDs($targDealID, $contactIDs);
		}

		//Clear seed bindings
		$connection->queryExecute(
		/** @lang text */
			"DELETE FROM b_crm_deal_contact WHERE DEAL_ID = {$seedDealID}"
		);
	}
	/**
	 * Unbind all deals from seed contact and bind to target contact
	 * @param int $seedContactID Seed contact ID.
	 * @param int $targContactID Target contact ID.
	 * @throws Main\ArgumentException
	 */
	public static function rebindAllDeals($seedContactID, $targContactID)
	{
		$seedContactID = (int)$seedContactID;
		if($seedContactID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'seedContactID');
		}

		$targContactID = (int)$targContactID;
		if($targContactID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'targContactID');
		}

		if($seedContactID === $targContactID)
		{
			return;
		}

		$connection = Main\Application::getConnection();
		$dbResult = $connection->query(
			/** @lang text */
			"SELECT DEAL_ID FROM b_crm_deal_contact WHERE CONTACT_ID = {$seedContactID}"
		);

		while($fields = $dbResult->fetch())
		{
			$dealID = (int)$fields['DEAL_ID'];
			$bindings = self::getDealBindings($dealID);
			$seedIndex = $targIndex = -1;
			for($i = 0, $l = count($bindings); $i < $l; $i++)
			{
				$binding = $bindings[$i];
				$contactID = (int)$binding['CONTACT_ID'];
				if($contactID === $seedContactID)
				{
					$seedIndex = $i;
				}
				elseif($contactID === $targContactID)
				{
					$targIndex = $i;
				}

				if($seedIndex >= 0 && $targIndex >= 0)
				{
					break;
				}
			}

			$seedBinding = $seedIndex >= 0 ? $bindings[$seedIndex] : null;
			$targBinding = $targIndex >= 0 ? $bindings[$targIndex] : null;

			if(!is_array($seedBinding))
			{
				continue;
			}

			self::unbindContactIDs($dealID, array($seedContactID));

			$isPrimary = isset($seedBinding['IS_PRIMARY']) && $seedBinding['IS_PRIMARY'] === 'Y';
			if(!is_array($targBinding))
			{
				$seedBinding['CONTACT_ID'] = $targContactID;
				self::bindContacts($dealID, array($seedBinding));
			}
			elseif($isPrimary)
			{
				$targBinding['IS_PRIMARY'] = 'Y';
				self::bindContacts($dealID, array($targBinding));
			}
		}
	}
}quotecontact.php000066400000034757150044450540010011 0ustar00<?php
/**
 * Bitrix Framework
 * @package bitrix
 * @subpackage crm
 * @copyright 2001-2016 Bitrix
 */
namespace Bitrix\Crm\Binding;

use Bitrix\Main;
use Bitrix\Main\Entity;

class QuoteContactTable extends Entity\DataManager
{
	/**
	 * Get table name.
	 * @return string
	 */
	public static function getTableName()
	{
		return 'b_crm_quote_contact';
	}
	/**
	 * Get table fields map.
	 * @return array
	 */
	public static function getMap()
	{
		return array(
			'QUOTE_ID' => array('primary' => true, 'data_type' => 'integer'),
			'CONTACT_ID' => array('primary' => true, 'data_type' => 'integer'),
			'SORT' => array('data_type' => 'integer', 'default_value' => 0),
			'ROLE_ID' => array('data_type' => 'integer', 'default_value' => 0),
			'IS_PRIMARY' => array('data_type' => 'boolean', 'values' => array('N', 'Y'), 'default_value' => 'N')
		);
	}
	/**
	 * Execute UPSERT operation.
	 * @param array $data Field data.
	 * @return void
	 */
	public static function upsert(array $data)
	{
		$quoteID = isset($data['QUOTE_ID']) ? (int)$data['QUOTE_ID'] : 0;
		if($quoteID <= 0)
		{
			throw new Main\ArgumentException('Must contains QUOTE_ID field.', 'data');
		}

		$contactID = isset($data['CONTACT_ID']) ? (int)$data['CONTACT_ID'] : 0;
		if($contactID <= 0)
		{
			throw new Main\ArgumentException('Must contains CONTACT_ID field.', 'data');
		}

		$sort = isset($data['SORT']) ? (int)$data['SORT'] : 0;
		$roleID = isset($data['ROLE_ID']) ? (int)$data['ROLE_ID'] : 0;
		$primary = isset($data['IS_PRIMARY']) && strtoupper($data['IS_PRIMARY']) === 'Y' ? 'Y' : 'N';

		$connection = Main\Application::getConnection();
		$queries = $connection->getSqlHelper()->prepareMerge(
			'b_crm_quote_contact',
			array('QUOTE_ID', 'CONTACT_ID'),
			array('QUOTE_ID' => $quoteID, 'CONTACT_ID' => $contactID, 'SORT' => $sort, 'ROLE_ID' => $roleID, 'IS_PRIMARY' => $primary),
			array('SORT' => $sort, 'ROLE_ID' => $roleID, 'IS_PRIMARY' => $primary)
		);

		foreach($queries as $query)
		{
			$connection->queryExecute($query);
		}
	}
	/**
	 * Get quote IDs are bound to specified contact.
	 * @param int $contactID Contact ID.
	 * @return array
	 * @throws Main\ArgumentException
	 */
	public static function getContactQuotesIDs($contactID)
	{
		$contactID = (int)$contactID;
		if($contactID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'contactID');
		}

		$dbResult =  Main\Application::getConnection()->query(
			/** @lang text*/
			"SELECT QUOTE_ID FROM b_crm_quote_contact WHERE CONTACT_ID = {$contactID}"
		);

		$results = array();
		while($ary = $dbResult->fetch())
		{
			$results[] = (int)$ary['QUOTE_ID'];
		}
		return $results;
	}
	/**
	 * Get contact IDs are bound to specified quote.
	 * @param int $quoteID Quote ID.
	 * @return array
	 * @throws Main\ArgumentException
	 */
	public static function getQuoteContactIDs($quoteID)
	{
		$quoteID = (int)$quoteID;
		if($quoteID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'quoteID');
		}

		$dbResult = Main\Application::getConnection()->query(
			/** @lang text*/
			"SELECT CONTACT_ID FROM b_crm_quote_contact WHERE QUOTE_ID = {$quoteID} ORDER BY SORT ASC"
		);

		$results = array();
		while($ary = $dbResult->fetch())
		{
			$results[] = (int)$ary['CONTACT_ID'];
		}
		return $results;
	}
	/**
	 * Get quote's bindings.
	 * @param int $quoteID Quote ID.
	 * @return array
	 * @throws Main\ArgumentException
	 */
	public static function getQuoteBindings($quoteID)
	{
		$quoteID = (int)$quoteID;
		if($quoteID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'quoteID');
		}

		$dbResult = Main\Application::getConnection()->query(
			/** @lang text*/
			"SELECT CONTACT_ID, SORT, ROLE_ID, IS_PRIMARY FROM b_crm_quote_contact WHERE QUOTE_ID = {$quoteID} ORDER BY SORT"
		);

		$results = array();
		while($ary = $dbResult->fetch())
		{
			$results[] = array(
				'CONTACT_ID' => (int)$ary['CONTACT_ID'],
				'SORT' => (int)$ary['SORT'],
				'ROLE_ID' => (int)$ary['ROLE_ID'],
				'IS_PRIMARY' => $ary['IS_PRIMARY']
			);
		}
		return $results;
	}
	/**
	 * Get binding map for quote's collection.
	 * @param array $quoteIDs Array of Quote IDs.
	 * @return array
	 * @throws Main\ArgumentException
	 * @throws Main\ObjectPropertyException
	 * @throws Main\SystemException
	 */
	public static function getBulkQuoteBindings(array $quoteIDs)
	{
		$bindingMap = array();
		foreach($quoteIDs as $quoteID)
		{
			$bindingMap[$quoteID] = array();
		}

		$dbResult = self::getList(
			array(
				'filter' => array('@QUOTE_ID' => $quoteIDs),
				'select' => array('QUOTE_ID', 'CONTACT_ID', 'SORT', 'ROLE_ID', 'IS_PRIMARY'),
				'order' => array('QUOTE_ID' => 'ASC', 'SORT' => 'ASC')
			)
		);
		while($ary = $dbResult->fetch())
		{
			$bindingMap[$ary['QUOTE_ID']][] = array(
				'CONTACT_ID' => (int)$ary['CONTACT_ID'],
				'SORT' => (int)$ary['SORT'],
				'ROLE_ID' => (int)$ary['ROLE_ID'],
				'IS_PRIMARY' => $ary['IS_PRIMARY']
			);
		}
		return $bindingMap;
	}
	/**
	 *  Get quote's binding count.
	 * @param int $quoteID Quote ID.
	 * @return int
	 * @throws Main\ArgumentException
	 */
	public static function getQuoteBindingCount($quoteID)
	{
		$quoteID = (int)$quoteID;
		if($quoteID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'quoteID');
		}

		$dbResult = Main\Application::getConnection()->query(
			/** @lang text*/
			"SELECT COUNT(*) CNT FROM b_crm_quote_contact WHERE QUOTE_ID = {$quoteID}"
		);

		$ary = $dbResult->fetch();
		return is_array($ary) ? (int)$ary['CNT'] : 0;
	}
	/**
	 * Check if quote has contacts.
	 * @param int $quoteID Quote ID.
	 * @return bool
	 * @throws Main\ArgumentException
	 */
	public static function hasContacts($quoteID)
	{
		$quoteID = (int)$quoteID;
		if($quoteID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'quoteID');
		}

		$result = self::getList(
			array(
				'select' => array('QUOTE_ID'),
				'filter' => array('=QUOTE_ID' => $quoteID),
				'limit' => 1
			)
		);

		return is_array($result->fetch());
	}
	/**
	 * Bind quote to contacts are specified by ID.
	 * @param int $quoteID Quote ID.
	 * @param array $contactIDs Array of contact IDs.
	 * @return void
	 */
	public static function bindContactIDs($quoteID, array $contactIDs)
	{
		$bindings = EntityBinding::prepareEntityBindings(\CCrmOwnerType::Contact, $contactIDs);
		$qty = count($bindings);
		if($qty > 0)
		{
			for($i = 0; $i < $qty; $i++)
			{
				if($i === 0)
				{
					$bindings[$i]['IS_PRIMARY'] = 'Y';
				}
				$bindings[$i]['SORT'] = 10 * ($i + 1);
			}
			self::bindContacts($quoteID, $bindings);
		}
	}
	/**
	 * Bind quote to contacts.
	 * @param int $quoteID Quote ID.
	 * @param array $bindings Array of contact bindings.
	 * @return void
	 * @throws Main\ArgumentException
	 */
	public static function bindContacts($quoteID, array $bindings)
	{
		$quoteID = (int)$quoteID;
		if($quoteID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'quoteID');
		}

		$qty = count($bindings);
		if($qty === 0)
		{
			return;
		}

		$processed = 0;
		for($i = 0; $i < $qty; $i++)
		{
			$binding = $bindings[$i];

			$contactID = isset($binding['CONTACT_ID']) ? (int)$binding['CONTACT_ID'] : 0;
			if($contactID <= 0)
			{
				continue;
			}

			self::upsert(
				array(
					'QUOTE_ID' => $quoteID,
					'CONTACT_ID' => $contactID,
					'SORT' => isset($binding['SORT']) ? (int)$binding['SORT'] : (10 * ($i + 1)),
					'ROLE_ID' => isset($binding['ROLE_ID']) ? (int)$binding['ROLE_ID'] : EntityBinding::ROLE_UNDEFINED,
					'IS_PRIMARY' => isset($binding['IS_PRIMARY']) ? $binding['IS_PRIMARY'] : ''
				)
			);
			$processed++;
		}

		if($processed > 0)
		{
			Main\Application::getConnection()->queryExecute(
				/** @lang text*/
				"UPDATE b_crm_quote SET CONTACT_ID =
				(SELECT MIN(CONTACT_ID) FROM b_crm_quote_contact WHERE IS_PRIMARY = 'Y' AND QUOTE_ID = {$quoteID})
				WHERE ID = {$quoteID}"
			);
		}
	}
	/**
	 * Unbind specified quote from specified contacts.
	 * @param int $quoteID Quote ID.
	 * @param array $contactIDs Array of contact IDs.
	 * @return void
	 * @throws Main\ArgumentException
	 */
	public static function unbindContactIDs($quoteID, array $contactIDs)
	{
		$quoteID = (int)$quoteID;
		if($quoteID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'quoteID');
		}

		$contactIDs = array_filter($contactIDs);
		if(empty($contactIDs))
		{
			return;
		}

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

		$values = implode(',', $contactIDs);
		$connection->queryExecute(
			/** @lang text */
			"DELETE FROM b_crm_quote_contact WHERE QUOTE_ID = {$quoteID} AND CONTACT_ID IN({$values})"
		);

		$connection->queryExecute(
			/** @lang text*/
			"UPDATE b_crm_quote SET CONTACT_ID =
			(SELECT MIN(CONTACT_ID) FROM b_crm_quote_contact WHERE IS_PRIMARY = 'Y' AND QUOTE_ID = {$quoteID})
			WHERE ID = {$quoteID}"
		);
	}
	/**
	 * Unbind specified quote from specified contacts.
	 * @param int $quoteID Quote ID.
	 * @param array $bindings Array of bindings.
	 * @return void
	 * @throws Main\ArgumentException
	 */
	public static function unbindContacts($quoteID, array $bindings)
	{
		$quoteID = (int)$quoteID;
		if($quoteID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'quoteID');
		}

		self::unbindContactIDs($quoteID, EntityBinding::prepareEntityIDs(\CCrmOwnerType::Contact, $bindings));
	}
	/**
	 * Unbind specified quote from all contacts.
	 * @param int $quoteID Quote ID.
	 * @return void
	 * @throws Main\ArgumentException
	 */
	public static function unbindAllContacts($quoteID)
	{
		$quoteID = (int)$quoteID;
		if($quoteID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'quoteID');
		}

		$connection = Main\Application::getConnection();
		$connection->queryExecute(
			/** @lang text */
			"DELETE FROM b_crm_quote_contact WHERE QUOTE_ID = {$quoteID}"
		);
		$connection->queryExecute(
			/** @lang text */
			"UPDATE b_crm_quote SET CONTACT_ID = NULL WHERE ID = {$quoteID}"
		);
	}
	/**
	 * Unbind specified contact from all quotes.
	 * @param int $contactID Contact ID.
	 * @return void
	 * @throws Main\ArgumentException
	 */
	public static function unbindAllQuotes($contactID)
	{
		$contactID = (int)$contactID;
		if($contactID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'contactID');
		}

		$connection = Main\Application::getConnection();
		$connection->queryExecute(
		/** @lang text */
			"DELETE FROM b_crm_quote_contact WHERE CONTACT_ID = {$contactID}"
		);
		$connection->queryExecute(
		/** @lang text */
			"UPDATE b_crm_quote SET CONTACT_ID =
			(SELECT MIN(CONTACT_ID) FROM b_crm_quote_contact t WHERE t.QUOTE_ID = b_crm_quote.ID)
			WHERE CONTACT_ID = {$contactID}"
		);
	}
	/**
	 * Prepage SQL join filter condition for specified entity.
	 * @param int $entityTypeID Entity type ID for filter.
	 * @param int $entityID Entity ID for filter.
	 * @param string $tableAlias Alias of primary table.
	 * @return string
	 * @throws Main\ArgumentException
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\NotSupportedException
	 */
	public static function prepareFilterJoinSql($entityTypeID, $entityID, $tableAlias)
	{
		if(!is_int($entityTypeID))
		{
			$entityTypeID = (int)$entityTypeID;
		}

		if(!\CCrmOwnerType::IsDefined($entityTypeID))
		{
			throw new Main\ArgumentOutOfRangeException('entityTypeID',
				\CCrmOwnerType::FirstOwnerType,
				\CCrmOwnerType::LastOwnerType
			);
		}

		if($entityTypeID !== \CCrmOwnerType::Contact && $entityTypeID !== \CCrmOwnerType::Quote)
		{
			$entityTypeName = \CCrmOwnerType::ResolveName($entityTypeID);
			throw new Main\NotSupportedException("Entity type: '{$entityTypeName}' is not supported in current context");
		}

		$entityIDs = is_array($entityID) ? $entityID : array($entityID);
		$effectiveIDs = array();
		foreach($entityIDs as $ID)
		{
			$ID = (int)$ID;
			if($ID > 0)
			{
				$effectiveIDs[] = $ID;
			}
		}

		$qty = count($effectiveIDs);
		if($qty > 1)
		{
			$slug = implode(',', $effectiveIDs);
			if($entityTypeID === \CCrmOwnerType::Contact)
			{
				return "INNER JOIN b_crm_quote_contact QC ON QC.CONTACT_ID IN({$slug}) AND QC.QUOTE_ID = {$tableAlias}.ID";
			}
			else//if($entityTypeID === \CCrmOwnerType::Quote)
			{
				return "INNER JOIN b_crm_quote_contact QC ON QC.QUOTE_ID IN({$slug}) AND QC.CONTACT_ID = {$tableAlias}.ID";
			}
		}
		elseif($qty === 1)
		{
			if($entityTypeID === \CCrmOwnerType::Contact)
			{
				return "INNER JOIN b_crm_quote_contact QC ON QC.CONTACT_ID = {$effectiveIDs[0]} AND QC.QUOTE_ID = {$tableAlias}.ID";
			}
			else//if($entityTypeID === \CCrmOwnerType::Quote)
			{
				return "INNER JOIN b_crm_quote_contact QC ON QC.QUOTE_ID = {$effectiveIDs[0]} AND QC.CONTACT_ID = {$tableAlias}.ID";
			}
		}
		return "";
	}
	/**
	 * Unbind all quotes from seed contact and bind to target contact
	 * @param int $seedContactID Seed contact ID.
	 * @param int $targContactID Target contact ID.
	 * @throws Main\ArgumentException
	 */
	public static function rebindAllQuotes($seedContactID, $targContactID)
	{
		$seedContactID = (int)$seedContactID;
		if($seedContactID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'seedContactID');
		}

		$targContactID = (int)$targContactID;
		if($targContactID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'targContactID');
		}

		if($seedContactID === $targContactID)
		{
			return;
		}

		$connection = Main\Application::getConnection();
		$dbResult = $connection->query(
		/** @lang text */
			"SELECT QUOTE_ID FROM b_crm_quote_contact WHERE CONTACT_ID = {$seedContactID}"
		);

		while($fields = $dbResult->fetch())
		{
			$quoteID = (int)$fields['QUOTE_ID'];
			$bindings = self::getQuoteBindings($quoteID);
			$seedIndex = $targIndex = -1;
			for($i = 0, $l = count($bindings); $i < $l; $i++)
			{
				$binding = $bindings[$i];
				$contactID = (int)$binding['CONTACT_ID'];
				if($contactID === $seedContactID)
				{
					$seedIndex = $i;
				}
				elseif($contactID === $targContactID)
				{
					$targIndex = $i;
				}

				if($seedIndex >= 0 && $targIndex >= 0)
				{
					break;
				}
			}

			$seedBinding = $seedIndex >= 0 ? $bindings[$seedIndex] : null;
			$targBinding = $targIndex >= 0 ? $bindings[$targIndex] : null;

			if(!is_array($seedBinding))
			{
				continue;
			}

			self::unbindContactIDs($quoteID, array($seedContactID));

			$isPrimary = isset($seedBinding['IS_PRIMARY']) && $seedBinding['IS_PRIMARY'] === 'Y';
			if(!is_array($targBinding))
			{
				$seedBinding['CONTACT_ID'] = $targContactID;
				self::bindContacts($quoteID, array($seedBinding));
			}
			elseif($isPrimary)
			{
				$targBinding['IS_PRIMARY'] = 'Y';
				self::bindContacts($quoteID, array($targBinding));
			}
		}
	}
}bindinghelper.php000066400000017362150044450540010103 0ustar00<?php
/**
 * Bitrix Framework
 * @package bitrix
 * @subpackage crm
 * @copyright 2001-2016 Bitrix
 */
namespace Bitrix\Crm\Binding;

use Bitrix\Main;
use Bitrix\Main\Localization\Loc;

class BindingHelper
{
	public static function prepareBindingInfos($ownerTypeID, $ownerID, $entityTypeID, $formID)
	{
		Loc::loadMessages(__FILE__);

		$userPermissions = \CCrmPerms::GetCurrentUserPermissions();

		$formFieldNames = \CCrmViewHelper::getFormFieldNames($formID);
		$entityIDs = null;
		if($ownerTypeID === \CCrmOwnerType::Contact && $entityTypeID === \CCrmOwnerType::Company)
		{
			$entityIDs = ContactCompanyTable::getContactCompanyIDs($ownerID);
		}
		elseif($ownerTypeID === \CCrmOwnerType::Deal && $entityTypeID === \CCrmOwnerType::Contact)
		{
			$entityIDs = DealContactTable::getDealContactIDs($ownerID);
		}
		elseif($ownerTypeID === \CCrmOwnerType::Quote && $entityTypeID === \CCrmOwnerType::Contact)
		{
			$entityIDs = QuoteContactTable::getQuoteContactIDs($ownerID);
		}

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

		$prefix = \CCrmOwnerTypeAbbr::ResolveByTypeID($entityTypeID);
		$map = array();
		if($entityTypeID === \CCrmOwnerType::Company)
		{
			$dbRes = \CCrmCompany::GetListEx(
				array(),
				array('@ID' => $entityIDs, 'CHECK_PERMISSIONS' => 'N'),
				false,
				false,
				array('ID', 'TITLE', 'LOGO')
			);

			if(is_object($dbRes))
			{
				$file = new \CFile();
				while($fields = $dbRes->Fetch())
				{
					$entityID = (int)$fields['ID'];
					$isEntityReadPermitted = \CCrmCompany::CheckReadPermission($entityID, $userPermissions);

					if(!$isEntityReadPermitted)
					{
						$info = array(
							'ENTITY_TYPE_NAME' => \CCrmOwnerType::CompanyName,
							'ENTITY_ID' => $entityID,
							'ENABLE_MULTIFIELDS' => false,
							'NAME' => Loc::getMessage('BINDING_HLP_HIDDEN_COMPANY')
						);
					}
					else
					{
						$info = array(
							'ENTITY_TYPE_NAME' => \CCrmOwnerType::CompanyName,
							'ENTITY_ID' => $entityID,
							'NAME' => isset($fields['TITLE']) ? $fields['TITLE'] : '',
							'DESCRIPTION' => '',
							'SHOW_URL' => \CCrmOwnerType::GetEntityShowPath(\CCrmOwnerType::Company, $fields['ID'], false),
						);
						$imageID = isset($fields['LOGO']) ? (int)$fields['LOGO'] : 0;
						if($imageID <= 0)
						{
							$info['IMAGE_URL'] = '';
						}
						else
						{
							$fileInfo = $file->ResizeImageGet(
								$imageID,
								array('width' => 48, 'height' => 31),
								BX_RESIZE_IMAGE_PROPORTIONAL
							);
							$info['IMAGE_URL'] = is_array($fileInfo) && isset($fileInfo['src']) ? $fileInfo['src'] : '';
						}

						$multiFieldDbRes = \CCrmFieldMulti::GetList(
							array('ID' => 'asc'),
							array('ENTITY_ID' => \CCrmOwnerType::CompanyName, 'ELEMENT_ID' => $entityID)
						);


						$multiFieldData = array();
						while($multiFields = $multiFieldDbRes->Fetch())
						{
							$multiFieldData[$multiFields['TYPE_ID']][$multiFields['ID']] = array('VALUE' => $multiFields['VALUE'], 'VALUE_TYPE' => $multiFields['VALUE_TYPE']);
						}

						if(isset($multiFieldData['PHONE']))
						{
							$info['PHONE'] = self::prepareMultiFields(
								$multiFieldData['PHONE'],
								\CCrmOwnerType::CompanyName,
								$entityID,
								'PHONE',
								$formFieldNames
							);
						}

						if(isset($multiFieldData['EMAIL']))
						{
							$info['EMAIL'] = self::prepareMultiFields(
								$multiFieldData['EMAIL'],
								\CCrmOwnerType::CompanyName,
								$entityID,
								'EMAIL',
								$formFieldNames
							);
						}
					}

					$map["{$prefix}_{$entityID}"] = array('type' => 'client', 'data' => $info);
				}
			}
		}
		elseif($entityTypeID === \CCrmOwnerType::Contact)
		{
			$dbRes = \CCrmContact::GetListEx(
				array(),
				array('@ID' => $entityIDs, 'CHECK_PERMISSIONS' => 'N'),
				false,
				false,
				array('ID', 'HONORIFIC', 'NAME', 'SECOND_NAME', 'LAST_NAME', 'POST', 'PHOTO')
			);

			if(is_object($dbRes))
			{
				$file = new \CFile();
				while($fields = $dbRes->Fetch())
				{
					$entityID = (int)$fields['ID'];
					$isEntityReadPermitted = \CCrmContact::CheckReadPermission($entityID, $userPermissions);

					if(!$isEntityReadPermitted)
					{
						$info = array(
							'ENTITY_TYPE_NAME' => \CCrmOwnerType::ContactName,
							'ENTITY_ID' => $entityID,
							'ENABLE_MULTIFIELDS' => false,
							'NAME' => Loc::getMessage('BINDING_HLP_HIDDEN_CONTACT')
						);
					}
					else
					{
						$info = array(
							'ENTITY_TYPE_NAME' => \CCrmOwnerType::ContactName,
							'ENTITY_ID' => $entityID,
							'NAME' => \CCrmContact::PrepareFormattedName($fields),
							'DESCRIPTION' => isset($fields['POST']) ? $fields['POST'] : '',
							'SHOW_URL' => \CCrmOwnerType::GetEntityShowPath(\CCrmOwnerType::Contact, $fields['ID'], false),
						);
						$imageID = isset($fields['PHOTO']) ? (int)$fields['PHOTO'] : 0;
						if($imageID <= 0)
						{
							$info['IMAGE_URL'] = '';
						}
						else
						{
							$fileInfo = $file->ResizeImageGet(
								$imageID,
								array('width' => 38, 'height' => 38),
								BX_RESIZE_IMAGE_EXACT
							);
							$info['IMAGE_URL'] = is_array($fileInfo) && isset($fileInfo['src']) ? $fileInfo['src'] : '';
						}

						$multiFieldDbRes = \CCrmFieldMulti::GetList(
							array('ID' => 'asc'),
							array('ENTITY_ID' => \CCrmOwnerType::ContactName, 'ELEMENT_ID' => $entityID)
						);


						$multiFieldData = array();
						while($multiFields = $multiFieldDbRes->Fetch())
						{
							$multiFieldData[$multiFields['TYPE_ID']][$multiFields['ID']] = array('VALUE' => $multiFields['VALUE'], 'VALUE_TYPE' => $multiFields['VALUE_TYPE']);
						}

						if(isset($multiFieldData['PHONE']))
						{
							$info['PHONE'] = self::prepareMultiFields(
								$multiFieldData['PHONE'],
								\CCrmOwnerType::ContactName,
								$entityID,
								'PHONE',
								$formFieldNames
							);
						}

						if(isset($multiFieldData['EMAIL']))
						{
							$info['EMAIL'] = self::prepareMultiFields(
								$multiFieldData['EMAIL'],
								\CCrmOwnerType::ContactName,
								$entityID,
								'EMAIL',
								$formFieldNames
							);
						}
					}

					$map["{$prefix}_{$entityID}"] = array('type' => 'client', 'data' => $info);
				}
			}
		}

		$results = array();
		foreach($entityIDs as $entityID)
		{
			$key = "{$prefix}_{$entityID}";
			if(isset($map[$key]))
			{
				$results[] = $map[$key];
			}
		}
		return $results;
	}
	private static function prepareMultiFields(array $multiFields, $entityTypeName, $entityID, $typeID, array $formFieldNames = null)
	{
		if(empty($multiFields))
		{
			return null;
		}

		$arEntityTypeInfos = \CCrmFieldMulti::GetEntityTypeInfos();
		$arEntityTypes = \CCrmFieldMulti::GetEntityTypes();
		$sipConfig =  array(
			'STUB' => GetMessage('CRM_ENTITY_QPV_MULTI_FIELD_NOT_ASSIGNED'),
			'ENABLE_SIP' => true,
			'SIP_PARAMS' => array(
				'ENTITY_TYPE' => 'CRM_'.$entityTypeName,
				'ENTITY_ID' => $entityID)
		);

		$typeInfo = isset($arEntityTypeInfos[$typeID]) ? $arEntityTypeInfos[$typeID] : array();
		$caption = isset($typeInfo['NAME']) ? $typeInfo['NAME'] : $typeID;
		if(is_array($formFieldNames) && isset($formFieldNames[$typeID]))
		{
			$caption = $formFieldNames[$typeID];
		}

		$result = array(
			'type' => 'multiField',
			'caption' => $caption,
			'data' => array('type'=> $typeID, 'items'=> array())
		);
		foreach($multiFields as $multiField)
		{
			$value = isset($multiField['VALUE']) ? $multiField['VALUE'] : '';
			$valueType = isset($multiField['VALUE_TYPE']) ? $multiField['VALUE_TYPE'] : '';

			$entityType = $arEntityTypes[$typeID];
			$valueTypeInfo = isset($entityType[$valueType]) ? $entityType[$valueType] : null;

			$params = array('VALUE' => $value, 'VALUE_TYPE_ID' => $valueType, 'VALUE_TYPE' => $valueTypeInfo);
			$result['data']['items'][] = \CCrmViewHelper::PrepareMultiFieldValueItemData($typeID, $params, $sipConfig);
		}
		return $result;
	}
}entitybinding.php000066400000036662150044450540010144 0ustar00<?php
/**
 * Bitrix Framework
 * @package bitrix
 * @subpackage crm
 * @copyright 2001-2016 Bitrix
 */
namespace Bitrix\Crm\Binding;

use Bitrix\Main;

class EntityBinding
{
	const ROLE_UNDEFINED = 0;

	/**
	 * Verify binding structure.
	 * @param int $entityTypeID Entity Type ID.
	 * @param array $binding Source binding.
	 * @return bool
	 */
	public static function verifyEntityBinding($entityTypeID, array $binding)
	{
		if(!is_int($entityTypeID))
		{
			$entityTypeID = (int)$entityTypeID;
		}

		if(!\CCrmOwnerType::IsDefined($entityTypeID))
		{
			return false;
		}

		if($entityTypeID === \CCrmOwnerType::Company)
		{
			$fieldName = 'COMPANY_ID';
		}
		elseif($entityTypeID === \CCrmOwnerType::Contact)
		{
			$fieldName = 'CONTACT_ID';
		}
		else
		{
			return false;
		}

		return is_array($binding) && isset($binding[$fieldName]) && $binding[$fieldName] > 0;
	}

	public static function normalizeEntityBindings($entityTypeID, array &$bindings)
	{
		if(!is_int($entityTypeID))
		{
			$entityTypeID = (int)$entityTypeID;
		}

		if(!\CCrmOwnerType::IsDefined($entityTypeID))
		{
			throw new Main\ArgumentOutOfRangeException('entityTypeID',
				\CCrmOwnerType::FirstOwnerType,
				\CCrmOwnerType::LastOwnerType
			);
		}

		if($entityTypeID === \CCrmOwnerType::Company)
		{
			$fieldName = 'COMPANY_ID';
		}
		elseif($entityTypeID === \CCrmOwnerType::Contact)
		{
			$fieldName = 'CONTACT_ID';
		}
		else
		{
			$entityTypeName = \CCrmOwnerType::ResolveName($entityTypeID);
			throw new Main\NotSupportedException("Entity type: '{$entityTypeName}' is not supported in current context");
		}

		$effectiveBindings = array();
		$primaryBindingIndex = -1;
		for($i = 0, $l = count($bindings); $i < $l; $i++)
		{
			$binding = $bindings[$i];
			if(!is_array($binding))
			{
				continue;
			}

			$entityID = isset($binding[$fieldName]) ? (int)$binding[$fieldName] : 0;
			if($entityID <= 0)
			{
				continue;
			}

			if(!(isset($binding['SORT']) && $binding['SORT'] > 0))
			{
				$binding['SORT'] = ($i + 1) * 10;
			}

			if(isset($binding['IS_PRIMARY']))
			{
				if($binding['IS_PRIMARY'] === 'Y' && $primaryBindingIndex < 0)
				{
					$primaryBindingIndex = $i;
				}
				else
				{
					unset($binding['IS_PRIMARY']);
				}
			}
			$effectiveBindings[] = $binding;
		}

		if($primaryBindingIndex < 0 && count($effectiveBindings) > 0)
		{
			$effectiveBindings[0]['IS_PRIMARY'] = 'Y';
		}
		$bindings = $effectiveBindings;
	}

	public static function addEntityBinding($entityTypeID, $entityID, array &$bindings)
	{
		if(!is_int($entityTypeID))
		{
			$entityTypeID = (int)$entityTypeID;
		}

		if(!\CCrmOwnerType::IsDefined($entityTypeID))
		{
			throw new Main\ArgumentOutOfRangeException('entityTypeID',
				\CCrmOwnerType::FirstOwnerType,
				\CCrmOwnerType::LastOwnerType
			);
		}

		if($entityTypeID === \CCrmOwnerType::Company)
		{
			$fieldName = 'COMPANY_ID';
		}
		elseif($entityTypeID === \CCrmOwnerType::Contact)
		{
			$fieldName = 'CONTACT_ID';
		}
		else
		{
			$entityTypeName = \CCrmOwnerType::ResolveName($entityTypeID);
			throw new Main\NotSupportedException("Entity type: '{$entityTypeName}' is not supported in current context");
		}

		$bindings[] = array($fieldName => (int)$entityID);

		$maxSort = 0;
		foreach($bindings as $binding)
		{
			$sort = isset($binding['SORT']) ? (int)$binding['SORT'] : 0;
			if($sort > $maxSort)
			{
				$maxSort = $sort;
			}
			elseif($sort <= 0)
			{
				$maxSort += 10;
				$binding['SORT'] = $maxSort;
			}
		}
	}

	public static function removeEntityBinding($entityTypeID, $entityID, array &$bindings)
	{
		if(!is_int($entityTypeID))
		{
			$entityTypeID = (int)$entityTypeID;
		}

		if(!\CCrmOwnerType::IsDefined($entityTypeID))
		{
			throw new Main\ArgumentOutOfRangeException('entityTypeID',
				\CCrmOwnerType::FirstOwnerType,
				\CCrmOwnerType::LastOwnerType
			);
		}

		$index = self::findBindingIndexByEntityID($entityTypeID, $entityID, $bindings);
		if($index >= 0)
		{
			unset($bindings[$index]);
			$bindings = array_values($bindings);
		}
	}

	/**
	 * Prepare entity bindings from array of entity IDs.
	 * @param int $entityTypeID Entity Type ID.
	 * @param array $entityIDs Entity IDs.
	 * @return array
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\NotSupportedException
	 */
	public static function prepareEntityBindings($entityTypeID, array $entityIDs)
	{
		if(!is_int($entityTypeID))
		{
			$entityTypeID = (int)$entityTypeID;
		}

		if(!\CCrmOwnerType::IsDefined($entityTypeID))
		{
			throw new Main\ArgumentOutOfRangeException('entityTypeID',
				\CCrmOwnerType::FirstOwnerType,
				\CCrmOwnerType::LastOwnerType
			);
		}

		if($entityTypeID === \CCrmOwnerType::Company)
		{
			$fieldName = 'COMPANY_ID';
		}
		elseif($entityTypeID === \CCrmOwnerType::Contact)
		{
			$fieldName = 'CONTACT_ID';
		}
		else
		{
			$entityTypeName = \CCrmOwnerType::ResolveName($entityTypeID);
			throw new Main\NotSupportedException("Entity type: '{$entityTypeName}' is not supported in current context");
		}

		$bindings = array();
		$entityIDs = array_filter($entityIDs);
		$sort = 0;
		foreach($entityIDs as $entityID)
		{
			if($entityID > 0)
			{
				$sort += 10;
				$bindings[] = array($fieldName => (int)$entityID, 'SORT' => $sort);
			}
		}
		return $bindings;
	}
	/**
	 * Extract entity IDs from bindings.
	 * @param int $entityTypeID Entity Type ID.
	 * @param array $bindings Bindings.
	 * @return array
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\NotSupportedException
	 */
	public static function prepareEntityIDs($entityTypeID, array $bindings)
	{
		if(!is_int($entityTypeID))
		{
			$entityTypeID = (int)$entityTypeID;
		}

		if(!\CCrmOwnerType::IsDefined($entityTypeID))
		{
			throw new Main\ArgumentOutOfRangeException('entityTypeID',
				\CCrmOwnerType::FirstOwnerType,
				\CCrmOwnerType::LastOwnerType
			);
		}

		if($entityTypeID === \CCrmOwnerType::Company)
		{
			$fieldName = 'COMPANY_ID';
		}
		elseif($entityTypeID === \CCrmOwnerType::Contact)
		{
			$fieldName = 'CONTACT_ID';
		}
		else
		{
			$entityTypeName = \CCrmOwnerType::ResolveName($entityTypeID);
			throw new Main\NotSupportedException("Entity type: '{$entityTypeName}' is not supported in current context");
		}

		$entityIDs = array();
		foreach($bindings as $binding)
		{
			if(!is_array($binding))
			{
				continue;
			}

			$entityID = is_array($binding) && isset($binding[$fieldName]) ? (int)$binding[$fieldName] : 0;
			if($entityID > 0)
			{
				$entityIDs[] = $entityID;
			}
		}
		return $entityIDs;
	}
	/**
	 * Extract entity ID from binding.
	 * @param int $entityTypeID Entity Type ID.
	 * @param array $binding Bindings.
	 * @return int
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\NotSupportedException
	 */
	public static function prepareEntityID($entityTypeID, array $binding)
	{
		if(!is_int($entityTypeID))
		{
			$entityTypeID = (int)$entityTypeID;
		}

		if(!\CCrmOwnerType::IsDefined($entityTypeID))
		{
			throw new Main\ArgumentOutOfRangeException('entityTypeID',
				\CCrmOwnerType::FirstOwnerType,
				\CCrmOwnerType::LastOwnerType
			);
		}

		if($entityTypeID === \CCrmOwnerType::Company)
		{
			$fieldName = 'COMPANY_ID';
		}
		elseif($entityTypeID === \CCrmOwnerType::Contact)
		{
			$fieldName = 'CONTACT_ID';
		}
		else
		{
			$entityTypeName = \CCrmOwnerType::ResolveName($entityTypeID);
			throw new Main\NotSupportedException("Entity type: '{$entityTypeName}' is not supported in current context");
		}

		return isset($binding[$fieldName]) ? (int)$binding[$fieldName] : 0;
	}
	/**
	 * Extract entity ID from first binding.
	 * @param int $entityTypeID Entity Type ID.
	 * @param array $bindings Bindings.
	 * @return array|int
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\NotSupportedException
	 */
	public static function getFirstEntityID($entityTypeID, array $bindings)
	{
		if(!(isset($bindings[0]) && is_array($bindings[0])))
		{
			return 0;
		}

		return self::prepareEntityID($entityTypeID, $bindings[0]);
	}
	/**
	 * Extract entity ID from last binding.
	 * @param int $entityTypeID Entity Type ID.
	 * @param array $bindings Bindings.
	 * @return array|int
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\NotSupportedException
	 */
	public static function getLastEntityID($entityTypeID, array $bindings)
	{
		if(empty($bindings))
		{
			return 0;
		}

		$index = count($bindings) - 1;
		return is_array($bindings[$index]) ? self::prepareEntityID($entityTypeID, $bindings[$index]) : 0;
	}
	/**
	 * Mark first binding as primary.
	 * @param array &$bindings Bindings.
	 */
	public static function markFirstAsPrimary(array &$bindings)
	{
		$qty = count($bindings);
		if($qty === 0)
		{
			return;
		}

		if(is_array($bindings[0]))
		{
			$bindings[0]['IS_PRIMARY'] = 'Y';
		}

		for($i = 1; $i < $qty; $i++)
		{
			if(is_array($bindings[$i]))
			{
				unset($bindings[$i]['IS_PRIMARY']);
			}
		}
	}
	/**
	 * Mark binding as primary.
	 * @param array &$bindings Bindings.
	 * @param int $entityTypeID Entity Type ID.
	 * @param int $entityID Entity ID.
	 */
	public static function markAsPrimary(array &$bindings, $entityTypeID, $entityID)
	{
		if($entityTypeID === \CCrmOwnerType::Company)
		{
			$fieldName = 'COMPANY_ID';
		}
		elseif($entityTypeID === \CCrmOwnerType::Contact)
		{
			$fieldName = 'CONTACT_ID';
		}
		else
		{
			$entityTypeName = \CCrmOwnerType::ResolveName($entityTypeID);
			throw new Main\NotSupportedException("Entity type: '{$entityTypeName}' is not supported in current context");
		}

		$qty = count($bindings);
		for($i = 0; $i < $qty; $i++)
		{
			if(!is_array($bindings[$i]))
			{
				continue;
			}

			if(isset($bindings[$i][$fieldName]) && $bindings[$i][$fieldName] == $entityID)
			{
				$bindings[$i]['IS_PRIMARY'] = 'Y';
			}
			else
			{
				unset($bindings[$i]['IS_PRIMARY']);
			}
		}
	}
	public static function isPrimary(array $binding)
	{
		return isset($binding['IS_PRIMARY']) && $binding['IS_PRIMARY'] === 'Y';
	}
	/**
	 * Try find primary binding.
	 * @param array $bindings Bindings.
	 * @return array|null
	 */
	public static function findPrimaryBinding(array $bindings)
	{
		foreach($bindings as $binding)
		{
			if(!is_array($binding))
			{
				continue;
			}

			if(isset($binding['IS_PRIMARY']) && $binding['IS_PRIMARY'] === 'Y')
			{
				return $binding;
			}
		}
		return null;
	}
	public static function findBindingIndexByEntityID($entityTypeID, $entityID, array $bindings)
	{
		$fieldName = self::resolveEntityFieldName($entityTypeID);
		if($fieldName === '')
		{
			return -1;
		}

		for($i = 0, $l = count($bindings); $i < $l; $i++)
		{
			if(!is_array($bindings[$i]))
			{
				continue;
			}

			if(isset($bindings[$i][$fieldName]) && $bindings[$i][$fieldName] == $entityID)
			{
				return $i;
			}
		}
		return -1;
	}
	public static function findBindingByEntityID($entityTypeID, $entityID, array $bindings)
	{
		$index = self::findBindingIndexByEntityID($entityTypeID, $entityID, $bindings);
		return $index >= 0 ? $bindings[$index] : null;
	}
	/**
	 * Prepare binding changes.
	 * @param int $entityTypeID Entity Type ID.
	 * @param array $origin Origin bindings.
	 * @param array $current Current bindings.
	 * @param array &$added Added bindings (output parameter).
	 * @param array &$removed Removed bindings (output parameter).
	 * @return void
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\NotSupportedException
	 */
	public static function prepareBindingChanges($entityTypeID, array $origin, array $current, array &$added, array &$removed)
	{
		if(!is_int($entityTypeID))
		{
			$entityTypeID = (int)$entityTypeID;
		}

		if(!\CCrmOwnerType::IsDefined($entityTypeID))
		{
			throw new Main\ArgumentOutOfRangeException('entityTypeID',
				\CCrmOwnerType::FirstOwnerType,
				\CCrmOwnerType::LastOwnerType
			);
		}

		if($entityTypeID === \CCrmOwnerType::Company)
		{
			$fieldName = 'COMPANY_ID';
		}
		elseif($entityTypeID === \CCrmOwnerType::Contact)
		{
			$fieldName = 'CONTACT_ID';
		}
		else
		{
			$entityTypeName = \CCrmOwnerType::ResolveName($entityTypeID);
			throw new Main\NotSupportedException("Entity type: '{$entityTypeName}' is not supported in current context");
		}

		$maxSort = 0;

		$originMap = array();
		$originPrimaryID = 0;
		foreach($origin as $binding)
		{
			$ID = isset($binding[$fieldName]) ? (int)$binding[$fieldName] : 0;
			if($ID > 0)
			{
				$originMap[$ID] = $binding;

				if(isset($binding['SORT']) && $binding['SORT'] > $maxSort)
				{
					$maxSort = (int)$binding['SORT'];
				}

				if(isset($binding['IS_PRIMARY']) && $binding['IS_PRIMARY'] === 'Y')
				{
					$originPrimaryID = $ID;
				}
			}
		}

		$currentMap = array();
		$currentPrimaryID = 0;
		foreach($current as $binding)
		{
			$ID = isset($binding[$fieldName]) ? (int)$binding[$fieldName] : 0;
			if($ID <= 0)
			{
				continue;
			}

			$currentMap[$ID] = $binding;
			if(isset($binding['IS_PRIMARY']) && $binding['IS_PRIMARY'] === 'Y')
			{
				$currentPrimaryID = $ID;
			}
		}

		$originIDs = array_keys($originMap);
		$currentIDs = array_keys($currentMap);

		if(!empty($removed))
		{
			$removed = array();
		}
		foreach(array_diff($originIDs, $currentIDs) as $ID)
		{
			$removed[$ID] = $originMap[$ID];
		}

		if(!empty($added))
		{
			$added = array();
		}
		foreach(array_diff($currentIDs, $originIDs) as $ID)
		{
			$binding = $currentMap[$ID];
			if($maxSort > 0 && !isset($binding['SORT']))
			{
				$maxSort += 10;
				$binding['SORT'] = $maxSort;
			}
			$added[$ID] = $binding;
		}

		foreach($current as $currentBinding)
		{
			$ID = isset($currentBinding[$fieldName]) ? (int)$currentBinding[$fieldName] : 0;
			if($ID <= 0)
			{
				continue;
			}

			if(isset($added[$ID]) || isset($removed[$ID]))
			{
				continue;
			}

			$originBinding = isset($originMap[$ID]) ? $originMap[$ID] : null;
			if(!is_array($originBinding))
			{
				continue;
			}

			$originSort = isset($originBinding["SORT"]) ? (int)$originBinding["SORT"] : 0;
			$currentSort = isset($currentBinding["SORT"]) ? (int)$currentBinding["SORT"] : 0;

			if($originSort !== $currentSort)
			{
				$added[$ID] = $currentBinding;
			}
		}

		if(($originPrimaryID > 0 || $currentPrimaryID > 0) && $originPrimaryID !== $currentPrimaryID)
		{
			if($currentPrimaryID > 0 && !isset($added[$currentPrimaryID]))
			{
				$added[$currentPrimaryID] = array_merge(
					$currentMap[$currentPrimaryID],
					array('IS_PRIMARY' => 'Y')
				);
			}

			if($originPrimaryID > 0 && !isset($removed[$originPrimaryID]))
			{
				$added[$originPrimaryID] = array_merge(
					$currentMap[$originPrimaryID],
					array('IS_PRIMARY' => 'N')
				);
			}
		}

		$removed = array_values($removed);
		$added = array_values($added);
	}

	/**
	 * Resolve field name for specified entity type.
	 * @param int $entityTypeID Entity type ID.
	 * @return string
	 */
	public static function resolveEntityFieldName($entityTypeID)
	{
		if($entityTypeID === \CCrmOwnerType::Company)
		{
			return 'COMPANY_ID';
		}
		elseif($entityTypeID === \CCrmOwnerType::Contact)
		{
			return 'CONTACT_ID';
		}
		return '';
	}

	public static function resolveEntityID($entityTypeID, array $binding)
	{
		$fieldName = self::resolveEntityFieldName($entityTypeID);
		if($fieldName === '')
		{
			return 0;
		}

		return isset($binding[$fieldName]) ? (int)$binding[$fieldName] : 0;
	}

	public static function getPrimaryOrDefault(array $bindings)
	{
		if(empty($bindings))
		{
			return null;
		}

		$binding = self::findPrimaryBinding($bindings);
		if(!is_array($binding))
		{
			$binding = $bindings[0];
		}

		return $binding;
	}
	public static function getPrimaryEntityID($entityTypeID, array $bindings)
	{
		$primaryBinding = self::getPrimaryOrDefault($bindings);
		return is_array($primaryBinding) ? self::prepareEntityID($entityTypeID, $primaryBinding) : 0;
	}
}contactcompany.php000066400000052650150044450540010312 0ustar00<?php
/**
 * Bitrix Framework
 * @package bitrix
 * @subpackage crm
 * @copyright 2001-2016 Bitrix
 */
namespace Bitrix\Crm\Binding;

use Bitrix\Main;
use Bitrix\Main\Entity;

class ContactCompanyTable extends Entity\DataManager
{
	/**
	 * Get table name.
	 * @return string
	 */
	public static function getTableName()
	{
		return 'b_crm_contact_company';
	}
	/**
	 * Get table fields map.
	 * @return array
	 */
	public static function getMap()
	{
		return array(
			'CONTACT_ID' => array('primary' => true, 'data_type' => 'integer'),
			'COMPANY_ID' => array('primary' => true, 'data_type' => 'integer'),
			'SORT' => array('data_type' => 'integer', 'default_value' => 0),
			'ROLE_ID' => array('data_type' => 'integer', 'default_value' => 0),
			'IS_PRIMARY' => array('data_type' => 'boolean', 'values' => array('N', 'Y'), 'default_value' => 'N')
		);
	}
	/**
	 * Execute UPSERT operation.
	 * @param array $data Field data.
	 * @return void
	 */
	public static function upsert(array $data)
	{
		$contactID = isset($data['CONTACT_ID']) ? (int)$data['CONTACT_ID'] : 0;
		if($contactID <= 0)
		{
			throw new Main\ArgumentException('Must contains CONTACT_ID field.', 'data');
		}

		$companyID = isset($data['COMPANY_ID']) ? (int)$data['COMPANY_ID'] : 0;
		if($contactID <= 0)
		{
			throw new Main\ArgumentException('Must contains COMPANY_ID field.', 'data');
		}

		$sort = isset($data['SORT']) ? (int)$data['SORT'] : 0;
		$roleID = isset($data['ROLE_ID']) ? (int)$data['ROLE_ID'] : 0;
		$primary = isset($data['IS_PRIMARY']) && strtoupper($data['IS_PRIMARY']) === 'Y' ? 'Y' : 'N';

		$connection = Main\Application::getConnection();
		$queries = $connection->getSqlHelper()->prepareMerge(
			'b_crm_contact_company',
			array('CONTACT_ID', 'COMPANY_ID'),
			array('CONTACT_ID' => $contactID, 'COMPANY_ID' => $companyID, 'SORT' => $sort, 'ROLE_ID' => $roleID, 'IS_PRIMARY' => $primary),
			array('SORT' => $sort, 'ROLE_ID' => $roleID, 'IS_PRIMARY' => $primary)
		);

		foreach($queries as $query)
		{
			$connection->queryExecute($query);
		}
	}
	/**
	 * Get company IDs are bound to specified contact.
	 * @param int $contactID Contact ID.
	 * @return array
	 * @throws Main\ArgumentException
	 */
	public static function getContactCompanyIDs($contactID)
	{
		$contactID = (int)$contactID;
		if($contactID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'contactID');
		}

		$dbResult =  Main\Application::getConnection()->query(
			/** @lang text*/
			"SELECT COMPANY_ID FROM b_crm_contact_company WHERE CONTACT_ID = {$contactID} ORDER BY SORT ASC"
		);

		$results = array();
		while($ary = $dbResult->fetch())
		{
			$results[] = (int)$ary['COMPANY_ID'];
		}
		return $results;
	}
	/**
	 * Get contact IDs are bound to specified company.
	 * @param int $companyID Company ID.
	 * @return array
	 * @throws Main\ArgumentException
	 */
	public static function getCompanyContactIDs($companyID)
	{
		$companyID = (int)$companyID;
		if($companyID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'companyID');
		}

		$dbResult = Main\Application::getConnection()->query(
			/** @lang text*/
			"SELECT CONTACT_ID FROM b_crm_contact_company WHERE COMPANY_ID = {$companyID} ORDER BY CONTACT_ID ASC"
		);

		$results = array();
		while($ary = $dbResult->fetch())
		{
			$results[] = (int)$ary['CONTACT_ID'];
		}
		return $results;
	}
	/**
	 * Get contacts's bindings.
	 * @param int $contactID Contact ID.
	 * @return array
	 * @throws Main\ArgumentException
	 */
	public static function getContactBindings($contactID)
	{
		$contactID = (int)$contactID;
		if($contactID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'dealID');
		}

		$dbResult = Main\Application::getConnection()->query(
			/** @lang text*/
			"SELECT COMPANY_ID, SORT, ROLE_ID, IS_PRIMARY FROM b_crm_contact_company WHERE CONTACT_ID = {$contactID} ORDER BY SORT"
		);

		$results = array();
		while($ary = $dbResult->fetch())
		{
			$results[] = array(
				'COMPANY_ID' => (int)$ary['COMPANY_ID'],
				'SORT' => (int)$ary['SORT'],
				'ROLE_ID' => (int)$ary['ROLE_ID'],
				'IS_PRIMARY' => $ary['IS_PRIMARY']
			);
		}
		return $results;
	}
	/**
	 * Get binding map for contact's collection.
	 * @param array $contactIDs Array of Contact IDs.
	 * @return array
	 * @throws Main\ArgumentException
	 * @throws Main\ObjectPropertyException
	 * @throws Main\SystemException
	 */
	public static function getBulkContactBindings(array $contactIDs)
	{
		$bindingMap = array();
		foreach($contactIDs as $contactID)
		{
			$bindingMap[$contactID] = array();
		}

		$dbResult = self::getList(
			array(
				'filter' => array('@CONTACT_ID' => $contactIDs),
				'select' => array('COMPANY_ID', 'CONTACT_ID', 'SORT', 'ROLE_ID', 'IS_PRIMARY'),
				'order' => array('CONTACT_ID' => 'ASC', 'SORT' => 'ASC')
			)
		);
		while($ary = $dbResult->fetch())
		{
			$bindingMap[$ary['CONTACT_ID']][] = array(
				'COMPANY_ID' => (int)$ary['COMPANY_ID'],
				'SORT' => (int)$ary['SORT'],
				'ROLE_ID' => (int)$ary['ROLE_ID'],
				'IS_PRIMARY' => $ary['IS_PRIMARY']
			);
		}
		return $bindingMap;
	}
	/**
	 *  Get contact's binding count.
	 * @param int $contactID Contact ID.
	 * @return int
	 * @throws Main\ArgumentException
	 */
	public static function getContactBindingCount($contactID)
	{
		$contactID = (int)$contactID;
		if($contactID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'contactID');
		}

		$dbResult = Main\Application::getConnection()->query(
			/** @lang text*/
			"SELECT COUNT(*) CNT FROM b_crm_contact_company WHERE CONTACT_ID = {$contactID}"
		);

		$ary = $dbResult->fetch();
		return is_array($ary) ? (int)$ary['CNT'] : 0;
	}
	/**
	 * Get company's bindings.
	 * @param int $companyID Company ID.
	 * @return array
	 * @throws Main\ArgumentException
	 */
	public static function getCompanyBindings($companyID)
	{
		$contactID = (int)$companyID;
		if($contactID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'companyID');
		}

		$dbResult = Main\Application::getConnection()->query(
		/** @lang text*/
			"SELECT CONTACT_ID, SORT, ROLE_ID, IS_PRIMARY FROM b_crm_contact_company WHERE COMPANY_ID = {$companyID} ORDER BY SORT"
		);

		$results = array();
		while($ary = $dbResult->fetch())
		{
			$results[] = array(
				'CONTACT_ID' => (int)$ary['CONTACT_ID'],
				'SORT' => (int)$ary['SORT'],
				'ROLE_ID' => (int)$ary['ROLE_ID'],
				'IS_PRIMARY' => $ary['IS_PRIMARY']
			);
		}
		return $results;
	}
	/**
	 * Check if contact has companies.
	 * @param int $contactID Contact ID.
	 * @return bool
	 * @throws Main\ArgumentException
	 */
	public static function hasCompanies($contactID)
	{
		$contactID = (int)$contactID;
		if($contactID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'contactID');
		}

		$result = self::getList(
			array(
				'select' => array('CONTACT_ID'),
				'filter' => array('=CONTACT_ID' => $contactID),
				'limit' => 1
			)
		);

		return is_array($result->fetch());
	}
	/**
	 * Bind contact to companies are specified by ID.
	 * @param int $contactID Contact ID.
	 * @param array $companyIDs Array of company IDs.
	 * @return void
	 */
	public static function bindCompanyIDs($contactID, array $companyIDs)
	{
		$bindings = EntityBinding::prepareEntityBindings(\CCrmOwnerType::Company, $companyIDs);
		$qty = count($bindings);
		if($qty > 0)
		{
			for($i = 0; $i < $qty; $i++)
			{
				if($i === 0)
				{
					$bindings[$i]['IS_PRIMARY'] = 'Y';
				}
				$bindings[$i]['SORT'] = 10 * ($i + 1);
			}
			self::bindCompanies($contactID, $bindings);
		}
	}
	/**
	 * Bind company to contacts specified by ID.
	 * @param int $companyID Company ID.
	 * @param array $contactIDs Array of contact IDs.
	 * @return void
	 */
	public static function bindContactIDs($companyID, array $contactIDs)
	{
		$bindings = EntityBinding::prepareEntityBindings(\CCrmOwnerType::Contact, $contactIDs);
		$qty = count($bindings);
		if($qty > 0)
		{
			for($i = 0; $i < $qty; $i++)
			{
				$bindings[$i]['IS_PRIMARY'] = 'Y';
				$bindings[$i]['SORT'] = 10;
			}
			self::bindContacts($companyID, $bindings);
		}
	}
	/**
	 * Bind contact to companies.
	 * @param int $contactID Contact ID.
	 * @param array $bindings Array of company bindings.
	 * @return void
	 * @throws Main\ArgumentException
	 */
	public static function bindCompanies($contactID, array $bindings)
	{
		$contactID = (int)$contactID;
		if($contactID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'contactID');
		}

		$qty = count($bindings);
		if($qty === 0)
		{
			return;
		}

		$processed = 0;
		for($i = 0; $i < $qty; $i++)
		{
			$binding = $bindings[$i];

			$companyID = isset($binding['COMPANY_ID']) ? (int)$binding['COMPANY_ID'] : 0;
			if($companyID <= 0)
			{
				continue;
			}

			self::upsert(
				array(
					'CONTACT_ID' => $contactID,
					'COMPANY_ID' => $companyID,
					'SORT' => isset($binding['SORT']) ? (int)$binding['SORT'] : (10 * ($i + 1)),
					'ROLE_ID' => isset($binding['ROLE_ID']) ? (int)$binding['ROLE_ID'] : EntityBinding::ROLE_UNDEFINED,
					'IS_PRIMARY' => isset($binding['IS_PRIMARY']) ? $binding['IS_PRIMARY'] : ''
				)
			);
			$processed++;
		}

		if($processed > 0)
		{
			Main\Application::getConnection()->queryExecute(
				/** @lang text*/
				"UPDATE b_crm_contact SET COMPANY_ID =
				(SELECT MIN(COMPANY_ID) FROM b_crm_contact_company WHERE IS_PRIMARY = 'Y' AND CONTACT_ID = {$contactID})
				WHERE ID = {$contactID}"
			);
		}
	}
	/**
	 * Bind company to contacts.
	 * @param int $companyID Company ID.
	 * @param array $bindings Array of company bindings.
	 * @return void
	 * @throws Main\ArgumentException
	 */
	public static function bindContacts($companyID, array $bindings)
	{
		$companyID = (int)$companyID;
		if($companyID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'companyID');
		}

		$qty = count($bindings);
		if($qty === 0)
		{
			return;
		}

		$affectedIDs = array();
		for($i = 0; $i < $qty; $i++)
		{
			$binding = $bindings[$i];

			$contactID = isset($binding['CONTACT_ID']) ? (int)$binding['CONTACT_ID'] : 0;
			if($contactID <= 0)
			{
				continue;
			}

			self::upsert(
				array(
					'CONTACT_ID' => $contactID,
					'COMPANY_ID' => $companyID,
					'SORT' => isset($binding['SORT']) ? (int)$binding['SORT'] : (10 * ($i + 1)),
					'ROLE_ID' => isset($binding['ROLE_ID']) ? (int)$binding['ROLE_ID'] : EntityBinding::ROLE_UNDEFINED,
					'IS_PRIMARY' => isset($binding['IS_PRIMARY']) ? $binding['IS_PRIMARY'] : ''
				)
			);
			$affectedIDs[] = $contactID;
		}

		if(!empty($affectedIDs))
		{
			$values = implode(',', $affectedIDs);

			Main\Application::getConnection()->queryExecute(
			/** @lang text*/
				"UPDATE b_crm_contact_company SET IS_PRIMARY =
				(CASE WHEN COMPANY_ID = {$companyID} THEN 'Y' ELSE 'N' END)
				WHERE CONTACT_ID IN({$values})"
			);

			Main\Application::getConnection()->queryExecute(
				/** @lang text*/
				"UPDATE b_crm_contact SET COMPANY_ID =
				(SELECT MIN(COMPANY_ID) FROM b_crm_contact_company t WHERE t.IS_PRIMARY = 'Y' AND t.CONTACT_ID = b_crm_contact.ID)
				WHERE ID IN({$values})"
			);
		}
	}
	/**
	 * Unbind specified contact from specified companies.
	 * @param int $contactID Contact ID.
	 * @param array $companyIDs Array of company IDs.
	 * @return void
	 * @throws Main\ArgumentException
	 */
	public static function unbindCompanyIDs($contactID, array $companyIDs)
	{
		$contactID = (int)$contactID;
		if($contactID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'contactID');
		}

		$companyIDs = array_filter($companyIDs);
		if(empty($companyIDs))
		{
			return;
		}

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

		$values = implode(',', $companyIDs);
		$connection->queryExecute(
			/** @lang text */
			"DELETE FROM b_crm_contact_company WHERE CONTACT_ID = {$contactID} AND COMPANY_ID IN({$values})"
		);

		$connection->queryExecute(
			/** @lang text */
			"UPDATE b_crm_contact SET COMPANY_ID =
			(SELECT MIN(COMPANY_ID) FROM b_crm_contact_company t WHERE t.IS_PRIMARY = 'Y' AND t.CONTACT_ID = b_crm_contact.ID)
			WHERE ID = {$contactID}"
		);
	}
	/**
	 * Unbind specified contact from specified companies.
	 * @param int $contactID Contact ID.
	 * @param array $bindings Array of bindings.
	 * @return void
	 * @throws Main\ArgumentException
	 */
	public static function unbindCompanies($contactID, array $bindings)
	{
		$contactID = (int)$contactID;
		if($contactID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'contactID');
		}

		self::unbindCompanyIDs($contactID, EntityBinding::prepareEntityIDs(\CCrmOwnerType::Company, $bindings));
	}
	/**
	 * Unbind specified contact from all companies.
	 * @param int $contactID Contact ID.
	 * @throws Main\ArgumentException
	 * @throws Main\NotSupportedException
	 */
	public static function unbindAllCompanies($contactID)
	{
		$contactID = (int)$contactID;
		if($contactID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'ID');
		}

		$connection = Main\Application::getConnection();
		$connection->queryExecute(
			/** @lang text */
			"DELETE FROM b_crm_contact_company WHERE CONTACT_ID = {$contactID}"
		);
		$connection->queryExecute(
			/** @lang text */
			"UPDATE b_crm_contact SET COMPANY_ID = NULL WHERE ID = {$contactID}"
		);
	}
	/**
	 * Unbind specified company from specified contacts.
	 * @param int $companyID Company ID.
	 * @param array $contactIDs Array of contact IDs.
	 * @return void
	 * @throws Main\ArgumentException
	 */
	public static function unbindContactIDs($companyID, array $contactIDs)
	{
		$companyID = (int)$companyID;
		if($companyID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'companyID');
		}

		$contactIDs = array_filter($contactIDs);
		if(empty($contactIDs))
		{
			return;
		}

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

		$values = implode(',', $contactIDs);
		$connection->queryExecute(
			/** @lang text */
			"DELETE FROM b_crm_contact_company WHERE COMPANY_ID = {$companyID} AND CONTACT_ID IN({$values})"
		);

		$connection->queryExecute(
			/** @lang text */
			"UPDATE b_crm_contact SET COMPANY_ID =
			(SELECT MIN(COMPANY_ID) FROM b_crm_contact_company t WHERE t.CONTACT_ID = b_crm_contact.ID)
			WHERE COMPANY_ID = {$companyID} AND ID IN({$values})"
		);
	}
	/**
	 * Unbind specified company from specified contacts.
	 * @param int $companyID Company ID.
	 * @param array $bindings Array of bindings.
	 * @return void
	 * @throws Main\ArgumentException
	 */
	public static function unbindContacts($companyID, array $bindings)
	{
		$companyID = (int)$companyID;
		if($companyID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'quoteID');
		}

		self::unbindContactIDs($companyID, EntityBinding::prepareEntityIDs(\CCrmOwnerType::Contact, $bindings));
	}
	/**
	 * Unbind specified company from all contacts.
	 * @param int $companyID Company ID.
	 * @return void
	 * @throws Main\ArgumentException
	 */
	public static function unbindAllContacts($companyID)
	{
		$companyID = (int)$companyID;
		if($companyID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'companyID');
		}

		$connection = Main\Application::getConnection();
		$connection->queryExecute(
			/** @lang text */
			"DELETE FROM b_crm_contact_company WHERE COMPANY_ID = {$companyID}"
		);
		$connection->queryExecute(
			/** @lang text */
			"UPDATE b_crm_contact SET COMPANY_ID =
			(SELECT MIN(COMPANY_ID) FROM b_crm_contact_company t WHERE t.CONTACT_ID = b_crm_contact.ID)
			WHERE COMPANY_ID = {$companyID}"
		);
	}
	/**
	 * Prepare SQL join filter condition for specified entity.
	 * @param int $entityTypeID Entity type ID for filter.
	 * @param int $entityID Entity ID for filter.
	 * @param string $tableAlias Alias of primary table.
	 * @return string
	 * @throws Main\ArgumentException
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\NotSupportedException
	 */
	public static function prepareFilterJoinSql($entityTypeID, $entityID, $tableAlias)
	{
		if(!is_int($entityTypeID))
		{
			$entityTypeID = (int)$entityTypeID;
		}

		if(!\CCrmOwnerType::IsDefined($entityTypeID))
		{
			throw new Main\ArgumentOutOfRangeException('entityTypeID',
				\CCrmOwnerType::FirstOwnerType,
				\CCrmOwnerType::LastOwnerType
			);
		}

		if(!is_int($entityID))
		{
			$entityID = (int)$entityID;
		}

		if($entityID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'entityID');
		}

		if($entityTypeID === \CCrmOwnerType::Company)
		{
			return "INNER JOIN b_crm_contact_company CC ON CC.COMPANY_ID = {$entityID} AND CC.CONTACT_ID = {$tableAlias}.ID";
		}
		elseif($entityTypeID === \CCrmOwnerType::Contact)
		{
			return "INNER JOIN b_crm_contact_company CC ON CC.CONTACT_ID = {$entityID} AND CC.COMPANY_ID = {$tableAlias}.ID";
		}

		$entityTypeName = \CCrmOwnerType::ResolveName($entityTypeID);
		throw new Main\NotSupportedException("Entity type: '{$entityTypeName}' is not supported in current context");
	}

	/**
	 * Prepare SQL join filter condition for specified entity by entity title.
	 * @param int $entityTypeID Entity type ID for filter.
	 * @param string $entityTitle Entity Title for filter.
	 * @param string $tableAlias Alias of primary table.
	 * @return string
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\NotSupportedException
	 */
	public static function prepareFilterJoinSqlByTitle($entityTypeID, $entityTitle, $tableAlias)
	{
		if(!is_int($entityTypeID))
		{
			$entityTypeID = (int)$entityTypeID;
		}

		if(!\CCrmOwnerType::IsDefined($entityTypeID))
		{
			throw new Main\ArgumentOutOfRangeException('entityTypeID',
				\CCrmOwnerType::FirstOwnerType,
				\CCrmOwnerType::LastOwnerType
			);
		}

		if(!is_string($entityTitle))
		{
			$entityTitle = (string)$entityTitle;
		}

		if($entityTitle === '')
		{
			return '';
		}

		$entityTitle = \CSQLWhere::ForLIKE($entityTitle);
		if($entityTypeID === \CCrmOwnerType::Company)
		{
			return "INNER JOIN (
				SELECT CC.CONTACT_ID FROM b_crm_contact_company CC INNER JOIN b_crm_company C 
					ON C.ID = CC.COMPANY_ID AND C.TITLE LIKE '{$entityTitle}%' ESCAPE '!' GROUP BY CC.CONTACT_ID
			) CC ON {$tableAlias}.ID = CC.CONTACT_ID";
		}

		$entityTypeName = \CCrmOwnerType::ResolveName($entityTypeID);
		throw new Main\NotSupportedException("Entity type: '{$entityTypeName}' is not supported in current context");
	}
	/**
	 * Unbind all contacts from seed company and bind to target company
	 * @param int $seedCompanyID Seed company ID.
	 * @param int $targCompanyID Target company ID.
	 * @throws Main\ArgumentException
	 */
	public static function rebindAllContacts($seedCompanyID, $targCompanyID)
	{
		$seedCompanyID = (int)$seedCompanyID;
		if($seedCompanyID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'seedCompanyID');
		}

		$targCompanyID = (int)$targCompanyID;
		if($targCompanyID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'targCompanyID');
		}

		//Combine contacts from seed and target and bind to target.
		$connection = Main\Application::getConnection();
		$dbResult = $connection->query(
		/** @lang text */
			"SELECT CONTACT_ID FROM b_crm_contact_company
				WHERE COMPANY_ID IN ({$seedCompanyID}, {$targCompanyID}) GROUP BY CONTACT_ID"
		);

		$contactIDs = array();
		while($fields = $dbResult->fetch())
		{
			$contactIDs[] = (int)$fields['CONTACT_ID'];
		}

		if(!empty($contactIDs))
		{
			self::bindContactIDs($targCompanyID, $contactIDs);
		}

		//Clear seed bindings
		$connection->queryExecute(
		/** @lang text */
			"DELETE FROM b_crm_contact_company WHERE COMPANY_ID = {$seedCompanyID}"
		);

		$connection->queryExecute(
		/** @lang text */
			"UPDATE b_crm_contact SET COMPANY_ID = {$targCompanyID} WHERE COMPANY_ID = {$seedCompanyID}"
		);
	}
	/**
	 * Unbind all companies from seed contact and bind to target contact
	 * @param int $seedContactID Seed contact ID.
	 * @param int $targContactID Target contact ID.
	 * @throws Main\ArgumentException
	 */
	public static function rebindAllCompanies($seedContactID, $targContactID)
	{
		$seedContactID = (int)$seedContactID;
		if($seedContactID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'seedContactID');
		}

		$targContactID = (int)$targContactID;
		if($targContactID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'targContactID');
		}

		if($seedContactID === $targContactID)
		{
			return;
		}

		$connection = Main\Application::getConnection();
		$dbResult = $connection->query(
		/** @lang text */
			"SELECT COMPANY_ID FROM b_crm_contact_company WHERE CONTACT_ID = {$seedContactID}"
		);

		while($fields = $dbResult->fetch())
		{
			$companyID = (int)$fields['COMPANY_ID'];
			$bindings = self::getCompanyBindings($companyID);
			$seedIndex = $targIndex = -1;
			for($i = 0, $l = count($bindings); $i < $l; $i++)
			{
				$binding = $bindings[$i];
				$contactID = (int)$binding['CONTACT_ID'];
				if($contactID === $seedContactID)
				{
					$seedIndex = $i;
				}
				elseif($contactID === $targContactID)
				{
					$targIndex = $i;
				}

				if($seedIndex >= 0 && $targIndex >= 0)
				{
					break;
				}
			}

			$seedBinding = $seedIndex >= 0 ? $bindings[$seedIndex] : null;
			$targBinding = $targIndex >= 0 ? $bindings[$targIndex] : null;

			if(!is_array($seedBinding))
			{
				continue;
			}

			self::unbindContactIDs($companyID, array($seedContactID));

			$isPrimary = isset($seedBinding['IS_PRIMARY']) && $seedBinding['IS_PRIMARY'] === 'Y';
			if(!is_array($targBinding))
			{
				$seedBinding['CONTACT_ID'] = $targContactID;
				self::bindContacts($companyID, array($seedBinding));
			}
			elseif($isPrimary)
			{
				$targBinding['IS_PRIMARY'] = 'Y';
				self::bindContacts($companyID, array($targBinding));
			}
		}
	}
}orderdealtable.php000066400000005355150044450540010241 0ustar00<?php
/**
 * Bitrix Framework
 * @package bitrix
 * @subpackage crm
 * @copyright 2001-2018 Bitrix
 */
namespace Bitrix\Crm\Binding;

use Bitrix\Main;
use Bitrix\Main\ORM\Fields\IntegerField;
use Bitrix\Main\ORM\Fields\Relations\Reference;

/**
 * Class OrderContactCompanyTable
 * @package Bitrix\Crm\Binding
 */
class OrderDealTable extends Main\ORM\Data\DataManager
{
	/**
	 * Get table name.
	 * @return string
	 */
	public static function getTableName()
	{
		return 'b_crm_order_deal';
	}
	/**
	 * Get table fields map.
	 * @return array
	 */
	public static function getMap()
	{
		return [
			new IntegerField('DEAL_ID', [
				'primary' => true,
				'unique' => true,
			]),
			new IntegerField('ORDER_ID', [
				'primary' => true,
			]),
			new Reference('ORDER', '\Bitrix\Sale\Internals\Order',
				['=this.ORDER_ID' => 'ref.ID']
			),
			new Reference('DEAL', '\Bitrix\Crm\Deal',
				['=this.DEAL_ID' => 'ref.ID']
			),
		];
	}

	/**
	 * @param $orderId
	 * @return int|false
	 * @throws Main\ArgumentException
	 * @throws Main\ObjectPropertyException
	 * @throws Main\SystemException
	 */
	public static function getDealIdByOrderId($orderId)
	{
		$orderId = intval($orderId);
		if($orderId > 0)
		{
			$item = static::getList([
				'select' => ['DEAL_ID'],
				'filter' => [
					'=ORDER_ID' => $orderId,
				],
			])->fetch();
			if($item)
			{
				return $item['DEAL_ID'];
			}
		}

		return false;
	}

	/**
	 * @param $dealId
	 * @return array
	 * @throws Main\ArgumentException
	 * @throws Main\ObjectPropertyException
	 * @throws Main\SystemException
	 */
	public static function getDealOrders($dealId)
	{
		$result = [];

		$dealId = intval($dealId);
		if($dealId > 0)
		{
			$items = static::getList([
				'select' => ['ORDER_ID'],
				'filter' => [
					'=DEAL_ID' => $dealId,
				],
			]);
			while($item = $items->fetch())
			{
				$result[] = $item['ORDER_ID'];
			}
		}

		return $result;
	}

	/**
	 * @param $orderId
	 * @return Main\ORM\Data\DeleteResult
	 * @throws Main\ArgumentException
	 * @throws Main\ObjectPropertyException
	 * @throws Main\SystemException
	 */
	public static function deleteByOrderId($orderId)
	{
		$dealId = static::getDealIdByOrderId($orderId);
		if($dealId)
		{
			return static::delete([
				'ORDER_ID' => $orderId,
				'DEAL_ID' => $dealId,
			]);
		}

		return new Main\ORM\Data\DeleteResult();
	}

	/**
	 * @param $dealId
	 * @return Main\ORM\Data\DeleteResult
	 * @throws Main\ArgumentException
	 * @throws Main\ObjectPropertyException
	 * @throws Main\SystemException
	 */
	public static function deleteByDealId($dealId)
	{
		$orderIds = static::getDealOrders($dealId);
		foreach($orderIds as $orderId)
		{
			static::delete([
				'ORDER_ID' => $orderId,
				'DEAL_ID' => $dealId,
			]);
		}

		return new Main\ORM\Data\DeleteResult();
	}
}ordercontactcompany.php000066400000042336150044450540011346 0ustar00<?php
/**
 * Bitrix Framework
 * @package bitrix
 * @subpackage crm
 * @copyright 2001-2018 Bitrix
 */
namespace Bitrix\Crm\Binding;

use Bitrix\Main;
use Bitrix\Main\Entity;
use Bitrix\Crm\Order;

/**
 * Class OrderContactCompanyTable
 * @package Bitrix\Crm\Binding
 */
class OrderContactCompanyTable extends Entity\DataManager
{
	/**
	 * Get table name.
	 * @return string
	 */
	public static function getTableName()
	{
		return 'b_crm_order_contact_company';
	}
	/**
	 * Get table fields map.
	 * @return array
	 */
	public static function getMap()
	{
		return array(
			'ID' => array(
				'primary' => true,
				'data_type' => 'integer'
			),
			'ORDER_ID' => array(
				'data_type' => 'integer'
			),
			'ORDER' => array(
				'data_type' => '\Bitrix\Sale\Order',
				'reference' => array(
					'=this.ORDER_ID' => 'ref.ID'
				)
			),
			'ENTITY_ID' => array(
				'data_type' => 'integer'
			),
			'ENTITY_TYPE_ID' => array(
				'data_type' => 'integer'
			),
			'SORT' => array(
				'data_type' => 'integer',
				'default_value' => 0
			),
			'ROLE_ID' => array(
				'data_type' => 'integer',
				'default_value' => 0
			),
			'IS_PRIMARY' => array(
				'data_type' => 'boolean',
				'values' => array('N', 'Y'),
				'default_value' => 'N'
			)
		);
	}
	/**
	 * Execute UPSERT operation.
	 * @param array $data Field data.
	 * @return void
	 * @throws Main\ArgumentException
	 * @throws Main\Db\SqlQueryException
	 */
	public static function upsert(array $data)
	{
		$orderId = isset($data['ORDER_ID']) ? (int)$data['ORDER_ID'] : 0;
		if($orderId <= 0)
		{
			throw new Main\ArgumentException('Must contains ORDER_ID field.', 'data');
		}

		$contactID = isset($data['ENTITY_ID']) ? (int)$data['ENTITY_ID'] : 0;
		if($contactID <= 0)
		{
			throw new Main\ArgumentException('Must contains ENTITY_ID field.', 'data');
		}

		$sort = isset($data['SORT']) ? (int)$data['SORT'] : 0;
		$roleID = isset($data['ROLE_ID']) ? (int)$data['ROLE_ID'] : 0;
		$primary = isset($data['IS_PRIMARY']) && strtoupper($data['IS_PRIMARY']) === 'Y' ? 'Y' : 'N';

		$connection = Main\Application::getConnection();
		$queries = $connection->getSqlHelper()->prepareMerge(
			'b_crm_order_contact',
			array('ORDER_ID', 'ENTITY_ID'),
			array('ORDER_ID' => $orderId, 'ENTITY_ID' => $contactID, 'SORT' => $sort, 'ROLE_ID' => $roleID, 'IS_PRIMARY' => $primary),
			array('SORT' => $sort, 'ROLE_ID' => $roleID, 'IS_PRIMARY' => $primary)
		);

		foreach($queries as $query)
		{
			$connection->queryExecute($query);
		}
	}
	/**
	 * Get order IDs are bound to specified contact.
	 * @param int $contactID Contact ID.
	 * @return array
	 * @throws Main\ArgumentException
	 * @throws Main\Db\SqlQueryException
	 */
	public static function getContactOrderIDs($contactID)
	{
		$contactID = (int)$contactID;
		if($contactID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'contactID');
		}

		$dbResult =  Main\Application::getConnection()->query(
			/** @lang text*/
			"SELECT ORDER_ID FROM b_crm_order_contact_company WHERE ENTITY_ID = {$contactID}"
		);

		$results = array();
		while($ary = $dbResult->fetch())
		{
			$results[] = (int)$ary['ORDER_ID'];
		}
		return $results;
	}

	/**
	 * Get contact IDs are bound to specified order.
	 * @param int $orderId order ID.
	 * @return array
	 * @throws Main\ArgumentException
	 * @throws Main\Db\SqlQueryException
	 */
	public static function getOrderContactIDs($orderId)
	{
		$orderId = (int)$orderId;
		if($orderId <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'orderId');
		}

		$dbResult = Main\Application::getConnection()->query(
			/** @lang text*/
			"SELECT ENTITY_ID FROM b_crm_order_contact_company WHERE ORDER_ID = {$orderId} ORDER BY SORT ASC"
		);

		$results = array();
		while($ary = $dbResult->fetch())
		{
			$results[] = (int)$ary['ENTITY_ID'];
		}
		return $results;
	}

	/**
	 * Get order's bindings.
	 * @param int $orderId Order ID.
	 * @return array
	 * @throws Main\ArgumentException
	 * @throws Main\Db\SqlQueryException
	 */
	public static function getOrderBindings($orderId)
	{
		$orderId = (int)$orderId;
		if($orderId <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'order');
		}

		$dbResult = Main\Application::getConnection()->query(
			/** @lang text*/
			"SELECT ENTITY_ID, SORT, ROLE_ID, IS_PRIMARY FROM b_crm_order_contact_company WHERE ORDER_ID = ".$orderId." AND ENTITY_TYPE_ID = ".\CCrmOwnerType::Contact." ORDER BY SORT"
		);

		$results = array();
		while($ary = $dbResult->fetch())
		{
			$results[] = array(
				'CONTACT_ID' => (int)$ary['ENTITY_ID'],
				'SORT' => (int)$ary['SORT'],
				'ROLE_ID' => (int)$ary['ROLE_ID'],
				'IS_PRIMARY' => $ary['IS_PRIMARY']
			);
		}
		return $results;
	}

	/**
	 * Get order's binding count.
	 * @param int $orderId order ID.
	 * @return int
	 * @throws Main\ArgumentException
	 * @throws Main\Db\SqlQueryException
	 */
	public static function getOrderBindingCount($orderId)
	{
		$orderId = (int)$orderId;
		if($orderId <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'orderId');
		}

		$dbResult = Main\Application::getConnection()->query(
			/** @lang text*/
			"SELECT COUNT(*) CNT FROM b_crm_order_contact_company WHERE ORDER_ID = {$orderId}"
		);

		$ary = $dbResult->fetch();
		return is_array($ary) ? (int)$ary['CNT'] : 0;
	}

	/**
	 * Check if order has contacts.
	 * @param int $orderId Order ID.
	 * @return bool
	 * @throws Main\ArgumentException
	 * @throws Main\ObjectPropertyException
	 * @throws Main\SystemException
	 */
	public static function hasContacts($orderId)
	{
		$orderId = (int)$orderId;
		if($orderId <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'orderId');
		}

		$result = self::getList(
			array(
				'select' => array('ORDER_ID'),
				'filter' => array('=ORDER_ID' => $orderId),
				'limit' => 1
			)
		);

		return is_array($result->fetch());
	}

	/**
	 * Bind order to contacts are specified by ID.
	 * @param int $orderId Order ID.
	 * @param array $contactIDs Array of contact IDs.
	 * @return void
	 * @throws Main\ArgumentException
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\Db\SqlQueryException
	 * @throws Main\LoaderException
	 * @throws Main\NotSupportedException
	 * @throws Main\SystemException
	 */
	public static function bindContactIDs($orderId, array $contactIDs)
	{
		$bindings = EntityBinding::prepareEntityBindings(\CCrmOwnerType::Contact, $contactIDs);
		$qty = count($bindings);
		if($qty > 0)
		{
			for($i = 0; $i < $qty; $i++)
			{
				if($i === 0)
				{
					$bindings[$i]['IS_PRIMARY'] = 'Y';
				}
				$bindings[$i]['SORT'] = 10 * ($i + 1);
			}
			self::bindContacts($orderId, $bindings);
		}
	}

	/**
	 * Bind order to contacts.
	 * @param int $orderId order id.
	 * @param array $bindings Array of contact bindings.
	 * @return void
	 * @throws Main\ArgumentException
	 * @throws Main\Db\SqlQueryException
	 * @throws Main\SystemException
	 * @throws Main\LoaderException
	 */
	public static function bindContacts($orderId, array $bindings)
	{
		if(!Main\Loader::includeModule('sale'))
			throw new Main\SystemException('Can\'t include module "sale"');

		$orderId = (int)$orderId;
		if($orderId <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'orderId');
		}

		$qty = count($bindings);
		if($qty === 0)
		{
			return;
		}

		$processed = 0;
		for($i = 0; $i < $qty; $i++)
		{
			$binding = $bindings[$i];

			$contactID = isset($binding['ENTITY_ID']) ? (int)$binding['ENTITY_ID'] : 0;
			if($contactID <= 0)
			{
				continue;
			}

			self::upsert(
				array(
					'ORDER_ID' => $orderId,
					'ENTITY_ID' => $contactID,
					'SORT' => isset($binding['SORT']) ? (int)$binding['SORT'] : (10 * ($i + 1)),
					'ROLE_ID' => isset($binding['ROLE_ID']) ? (int)$binding['ROLE_ID'] : EntityBinding::ROLE_UNDEFINED,
					'IS_PRIMARY' => isset($binding['IS_PRIMARY']) ? $binding['IS_PRIMARY'] : ''
				)
			);
			$processed++;
		}

		if($processed > 0)
		{
			Main\Application::getConnection()->queryExecute(
				/** @lang text*/
				"UPDATE b_sale_order SET ENTITY_ID =
				(SELECT MIN(ENTITY_ID) FROM b_crm_order_contact_company WHERE IS_PRIMARY = 'Y' AND ORDER_ID = {$orderId})
				WHERE ID = {$orderId}"
			);
		}
	}

	/**
	 * Unbind specified order from specified contacts.
	 * @param int $orderId order id.
	 * @param array $contactIDs Array of contact IDs.
	 * @return void
	 * @throws Main\ArgumentException
	 * @throws Main\Db\SqlQueryException
	 * @throws Main\LoaderException
	 * @throws Main\SystemException
	 */
	public static function unbindContactIDs($orderId, array $contactIDs)
	{
		if(!Main\Loader::includeModule('sale'))
			throw new Main\SystemException('Can\'t include module "sale"');

		$orderId = (int)$orderId;
		if($orderId <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'orderId');
		}

		$contactIDs = array_filter($contactIDs);
		if(empty($contactIDs))
		{
			return;
		}

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

		$values = implode(',', $contactIDs);
		$connection->queryExecute(
			/** @lang text */
			"DELETE FROM b_crm_order_contact_company WHERE ORDER_ID = {$orderId} AND ENTITY_ID IN({$values})"
		);

		$connection->queryExecute(
			/** @lang text*/
			"UPDATE b_sale_order SET ENTITY_ID =
			(SELECT MIN(ENTITY_ID) FROM b_crm_order_contact_company WHERE IS_PRIMARY = 'Y' AND ORDER_ID = {$orderId})
			WHERE ID = {$orderId}"
		);
	}

	/**
	 * Unbind specified order from specified contacts.
	 * @param int $orderId Order ID.
	 * @param array $bindings Array of bindings.
	 * @return void
	 * @throws Main\ArgumentException
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\Db\SqlQueryException
	 * @throws Main\LoaderException
	 * @throws Main\NotSupportedException
	 * @throws Main\SystemException
	 */
	public static function unbindContacts($orderId, array $bindings)
	{
		$orderId = (int)$orderId;
		if($orderId <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'orderId');
		}

		self::unbindContactIDs($orderId, EntityBinding::prepareEntityIDs(\CCrmOwnerType::Contact, $bindings));
	}

	/**
	 * Unbind specified order from all contacts.
	 * @param int $orderId Order ID.
	 * @return void
	 * @throws Main\ArgumentException
	 * @throws Main\Db\SqlQueryException
	 * @throws Main\LoaderException
	 * @throws Main\SystemException
	 */
	public static function unbindAllContacts($orderId)
	{
		if(!Main\Loader::includeModule('sale'))
			throw new Main\SystemException('Can\'t include module "sale"');

		$orderId = (int)$orderId;
		if($orderId <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'orderId');
		}

		$connection = Main\Application::getConnection();
		$connection->queryExecute(
			/** @lang text */
			"DELETE FROM b_crm_order_contact_company WHERE ORDER_ID = {$orderId}"
		);
		$connection->queryExecute(
			/** @lang text */
			"UPDATE b_sale_order SET ENTITY_ID = NULL WHERE ID = {$orderId}"
		);
	}

	/**
	 * Unbind specified contact from all orders.
	 * @param int $contactID Contact ID.
	 * @return void
	 * @throws Main\ArgumentException
	 * @throws Main\Db\SqlQueryException
	 * @throws Main\LoaderException
	 * @throws Main\SystemException
	 */
	public static function unbindAllOrders($contactID)
	{
		if(!Main\Loader::includeModule('sale'))
			throw new Main\SystemException('Can\'t include module "sale"');

		$contactID = (int)$contactID;
		if($contactID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'contactID');
		}

		$connection = Main\Application::getConnection();
		$connection->queryExecute(
		/** @lang text */
			"DELETE FROM b_crm_order_contact_company WHERE ENTITY_ID = {$contactID}"
		);
		$connection->queryExecute(
		/** @lang text */
			"UPDATE b_sale_order SET ENTITY_ID =
			(SELECT MIN(ENTITY_ID) FROM b_crm_order_contact_company t WHERE t.ORDER_ID = b_sale_order.ID)
			WHERE ENTITY_ID = {$contactID}"
		);
	}

	/**
	 * Prepage SQL join filter condition for specified entity.
	 * @param int $entityTypeID Entity type ID for filter.
	 * @param int $entityID Entity ID for filter.
	 * @param string $tableAlias Alias of primary table.
	 * @return string
	 * @throws Main\ArgumentException
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\NotSupportedException
	 */
	public static function prepareFilterJoinSql($entityTypeID, $entityID, $tableAlias)
	{
		if(!is_int($entityTypeID))
		{
			$entityTypeID = (int)$entityTypeID;
		}

		if(!\CCrmOwnerType::IsDefined($entityTypeID))
		{
			throw new Main\ArgumentOutOfRangeException('entityTypeID',
				\CCrmOwnerType::FirstOwnerType,
				\CCrmOwnerType::LastOwnerType
			);
		}

		if($entityTypeID !== \CCrmOwnerType::Contact && $entityTypeID !== \CCrmOwnerType::Order)
		{
			$entityTypeName = \CCrmOwnerType::ResolveName($entityTypeID);
			throw new Main\NotSupportedException("Entity type: '{$entityTypeName}' is not supported in current context");
		}

		$entityIDs = is_array($entityID) ? $entityID : array($entityID);
		$effectiveIDs = array();
		foreach($entityIDs as $ID)
		{
			$ID = (int)$ID;
			if($ID > 0)
			{
				$effectiveIDs[] = $ID;
			}
		}

		$qty = count($effectiveIDs);
		if($qty > 1)
		{
			$slug = implode(',', $effectiveIDs);
			if($entityTypeID === \CCrmOwnerType::Contact)
			{
				return "INNER JOIN b_crm_order_contact_company QC ON QC.ENTITY_ID IN({$slug}) AND QC.ORDER_ID = {$tableAlias}.ID";
			}
			else//if($entityTypeID === \CCrmOwnerType::Order)
			{
				return "INNER JOIN b_crm_order_contact_company QC ON QC.ORDER_ID IN({$slug}) AND QC.ENTITY_ID = {$tableAlias}.ID";
			}
		}
		elseif($qty === 1)
		{
			if($entityTypeID === \CCrmOwnerType::Contact)
			{
				return "INNER JOIN b_crm_order_contact_company QC ON QC.ENTITY_ID = {$effectiveIDs[0]} AND QC.ORDER_ID = {$tableAlias}.ID";
			}
			else//if($entityTypeID === \CCrmOwnerType::Order)
			{
				return "INNER JOIN b_crm_order_contact_company QC ON QC.ORDER_ID = {$effectiveIDs[0]} AND QC.ENTITY_ID = {$tableAlias}.ID";
			}
		}
		return "";
	}

	/**
	 * Unbind all orders from seed contact and bind to target contact
	 * @param int $seedContactID Seed contact ID.
	 * @param int $targContactID Target contact ID.
	 * @throws Main\ArgumentException
	 * @throws Main\Db\SqlQueryException
	 * @throws Main\LoaderException
	 * @throws Main\SystemException
	 */

	public static function rebindAllOrders($seedContactID, $targContactID)
	{
		$seedContactID = (int)$seedContactID;
		if($seedContactID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'seedContactID');
		}

		$targContactID = (int)$targContactID;
		if($targContactID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'targContactID');
		}

		if($seedContactID === $targContactID)
		{
			return;
		}

		$connection = Main\Application::getConnection();
		$dbResult = $connection->query(
		/** @lang text */
			"SELECT ORDER_ID FROM b_crm_order_contact_company WHERE ENTITY_ID = {$seedContactID}"
		);

		while($fields = $dbResult->fetch())
		{
			$orderId = (int)$fields['ORDER_ID'];
			$bindings = self::getOrderBindings($orderId);
			$seedIndex = $targIndex = -1;
			for($i = 0, $l = count($bindings); $i < $l; $i++)
			{
				$binding = $bindings[$i];
				$contactID = (int)$binding['ENTITY_ID'];
				if($contactID === $seedContactID)
				{
					$seedIndex = $i;
				}
				elseif($contactID === $targContactID)
				{
					$targIndex = $i;
				}

				if($seedIndex >= 0 && $targIndex >= 0)
				{
					break;
				}
			}

			$seedBinding = $seedIndex >= 0 ? $bindings[$seedIndex] : null;
			$targBinding = $targIndex >= 0 ? $bindings[$targIndex] : null;

			if(!is_array($seedBinding))
			{
				continue;
			}

			self::unbindContactIDs($orderId, array($seedContactID));

			$isPrimary = isset($seedBinding['IS_PRIMARY']) && $seedBinding['IS_PRIMARY'] === 'Y';
			if(!is_array($targBinding))
			{
				$seedBinding['ENTITY_ID'] = $targContactID;
				self::bindContacts($orderId, array($seedBinding));
			}
			elseif($isPrimary)
			{
				$targBinding['IS_PRIMARY'] = 'Y';
				self::bindContacts($orderId, array($targBinding));
			}
		}
	}

	/**
	 * Get orders by entities.
	 * <p>$entities:
	 * [
	 *    ['TYPE_ID' => \CCrmOwnerType::Contact, 'ID' => 123],
	 *    ['TYPE_ID' => \CCrmOwnerType::Company, 'ID' => 321],
	 * ]
	 * </p>
	 *
	 * @param array $entities Entity list with type ID and entity ID.
	 * @param bool $isPrimary Return only primary results.
	 * @return int[]
	 */
	public static function getOrdersByEntities(array $entities, $isPrimary = true)
	{
		$list = [];
		foreach ($entities as $entity)
		{
			$typeId = isset($entity['TYPE_ID']) ? (int) $entity['TYPE_ID'] : null;
			$id = isset($entity['ID']) ? (int) $entity['ID'] : null;

			if (!$typeId || !$id)
			{
				continue;
			}

			if (!isset($list[$typeId]))
			{
				$list[$typeId] = [];
			}
			$list[$typeId][] = $id;
		}

		if (empty($list))
		{
			return [];
		}

		$result = [];

		$filter = [
			'=ENTITY_TYPE_ID' => array_keys($list),
			'=ENTITY_ID' => array_unique(array_reduce(array_values($list), 'array_merge', [])),
			'=ORDER.STATUS_ID' => Order\OrderStatus::getSemanticProcessStatuses(),
		];
		if ($isPrimary)
		{
			$filter['=IS_PRIMARY'] = 'Y';
		}
		$orders = static::getList([
			'select' => ['ORDER_ID', 'ENTITY_TYPE_ID', 'ENTITY_ID'],
			'filter' => $filter
		])->fetchAll();
		foreach ($orders as $item)
		{
			$typeId = (int) $item['ENTITY_TYPE_ID'];
			$id = (int) $item['ENTITY_ID'];

			if (!in_array($id, $list[$typeId]))
			{
				continue;
			}

			$result[] = (int) $item['ORDER_ID'];
		}

		return $result;
	}
}leadcontact.php000066400000034553150044450540007553 0ustar00<?php
/**
 * Bitrix Framework
 * @package bitrix
 * @subpackage crm
 * @copyright 2001-2018 Bitrix
 */
namespace Bitrix\Crm\Binding;

use Bitrix\Main;
use Bitrix\Main\Entity;

class LeadContactTable extends Entity\DataManager
{
	/**
	 * Get table name.
	 * @return string
	 */
	public static function getTableName()
	{
		return 'b_crm_lead_contact';
	}
	/**
	 * Get table fields map.
	 * @return array
	 */
	public static function getMap()
	{
		return array(
			'LEAD_ID' => array('primary' => true, 'data_type' => 'integer'),
			'CONTACT_ID' => array('primary' => true, 'data_type' => 'integer'),
			'SORT' => array('data_type' => 'integer', 'default_value' => 0),
			'ROLE_ID' => array('data_type' => 'integer', 'default_value' => 0),
			'IS_PRIMARY' => array('data_type' => 'boolean', 'values' => array('N', 'Y'), 'default_value' => 'N')
		);
	}
	/**
	 * Execute UPSERT operation.
	 * @param array $data Field data.
	 * @return void
	 */
	public static function upsert(array $data)
	{
		$leadID = isset($data['LEAD_ID']) ? (int)$data['LEAD_ID'] : 0;
		if($leadID <= 0)
		{
			throw new Main\ArgumentException('Must contains LEAD_ID field.', 'data');
		}

		$contactID = isset($data['CONTACT_ID']) ? (int)$data['CONTACT_ID'] : 0;
		if($contactID <= 0)
		{
			throw new Main\ArgumentException('Must contains CONTACT_ID field.', 'data');
		}

		$sort = isset($data['SORT']) ? (int)$data['SORT'] : 0;
		$roleID = isset($data['ROLE_ID']) ? (int)$data['ROLE_ID'] : 0;
		$primary = isset($data['IS_PRIMARY']) && strtoupper($data['IS_PRIMARY']) === 'Y' ? 'Y' : 'N';

		$connection = Main\Application::getConnection();
		$queries = $connection->getSqlHelper()->prepareMerge(
			'b_crm_lead_contact',
			array('LEAD_ID', 'CONTACT_ID'),
			array('LEAD_ID' => $leadID, 'CONTACT_ID' => $contactID, 'SORT' => $sort, 'ROLE_ID' => $roleID, 'IS_PRIMARY' => $primary),
			array('SORT' => $sort, 'ROLE_ID' => $roleID, 'IS_PRIMARY' => $primary)
		);

		foreach($queries as $query)
		{
			$connection->queryExecute($query);
		}
	}
	/**
	 * Get Lead IDs are bound to specified contact.
	 * @param int $contactID Contact ID.
	 * @return array
	 * @throws Main\ArgumentException
	 */
	public static function getContactLeadIDs($contactID)
	{
		$contactID = (int)$contactID;
		if($contactID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'contactID');
		}

		$dbResult =  Main\Application::getConnection()->query(
		/** @lang text*/
			"SELECT LEAD_ID FROM b_crm_lead_contact WHERE CONTACT_ID = {$contactID}"
		);

		$results = array();
		while($ary = $dbResult->fetch())
		{
			$results[] = (int)$ary['LEAD_ID'];
		}
		return $results;
	}
	/**
	 * Get Contact IDs are bound to specified Lead.
	 * @param int $leadID Lead ID.
	 * @return array
	 * @throws Main\ArgumentException
	 */
	public static function getLeadContactIDs($leadID)
	{
		$leadID = (int)$leadID;
		if($leadID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'leadID');
		}

		$dbResult = Main\Application::getConnection()->query(
		/** @lang text*/
			"SELECT CONTACT_ID FROM b_crm_lead_contact WHERE LEAD_ID = {$leadID} ORDER BY SORT ASC"
		);

		$results = array();
		while($ary = $dbResult->fetch())
		{
			$results[] = (int)$ary['CONTACT_ID'];
		}
		return $results;
	}
	/**
	 * Get Lead's bindings.
	 * @param int $leadID Lead ID.
	 * @return array
	 * @throws Main\ArgumentException
	 */
	public static function getLeadBindings($leadID)
	{
		$leadID = (int)$leadID;
		if($leadID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'leadID');
		}

		$dbResult = Main\Application::getConnection()->query(
		/** @lang text*/
			"SELECT CONTACT_ID, SORT, ROLE_ID, IS_PRIMARY FROM b_crm_lead_contact WHERE LEAD_ID = {$leadID} ORDER BY SORT"
		);

		$results = array();
		while($ary = $dbResult->fetch())
		{
			$results[] = array(
				'CONTACT_ID' => (int)$ary['CONTACT_ID'],
				'SORT' => (int)$ary['SORT'],
				'ROLE_ID' => (int)$ary['ROLE_ID'],
				'IS_PRIMARY' => $ary['IS_PRIMARY']
			);
		}
		return $results;
	}
	/**
	 * Get binding map for lead's collection.
	 * @param array $leadsIDs Array of Lead IDs.
	 * @return array
	 * @throws Main\ArgumentException
	 * @throws Main\ObjectPropertyException
	 * @throws Main\SystemException
	 */
	public static function getBulkLeadBindings(array $leadsIDs)
	{
		$bindingMap = array();
		foreach($leadsIDs as $leadID)
		{
			$bindingMap[$leadID] = array();
		}

		$dbResult = self::getList(
			array(
				'filter' => array('@LEAD_ID' => $leadsIDs),
				'select' => array('LEAD_ID', 'CONTACT_ID', 'SORT', 'ROLE_ID', 'IS_PRIMARY'),
				'order' => array('LEAD_ID' => 'ASC', 'SORT' => 'ASC')
			)
		);
		while($ary = $dbResult->fetch())
		{
			$bindingMap[$ary['LEAD_ID']][] = array(
				'CONTACT_ID' => (int)$ary['CONTACT_ID'],
				'SORT' => (int)$ary['SORT'],
				'ROLE_ID' => (int)$ary['ROLE_ID'],
				'IS_PRIMARY' => $ary['IS_PRIMARY']
			);
		}
		return $bindingMap;
	}
	/**
	 *  Get Lead's binding count.
	 * @param $leadID
	 * @return int
	 * @throws Main\ArgumentException
	 */
	public static function getLeadBindingCount($leadID)
	{
		$leadID = (int)$leadID;
		if($leadID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'leadID');
		}

		$dbResult = Main\Application::getConnection()->query(
		/** @lang text*/
			"SELECT COUNT(*) CNT FROM b_crm_lead_contact WHERE LEAD_ID = {$leadID}"
		);

		$ary = $dbResult->fetch();
		return is_array($ary) ? (int)$ary['CNT'] : 0;
	}
	/**
	 * Check if Lead has Contacts.
	 * @param int $leadID Lead ID.
	 * @return bool
	 * @throws Main\ArgumentException
	 */
	public static function hasContacts($leadID)
	{
		$leadID = (int)$leadID;
		if($leadID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'leadID');
		}

		$result = self::getList(
			array(
				'select' => array('LEAD_ID'),
				'filter' => array('=LEAD_ID' => $leadID),
				'limit' => 1
			)
		);

		return is_array($result->fetch());
	}
	/**
	 * Bind Lead to Contacts are specified by ID.
	 * @param int $leadID Lead ID.
	 * @param array $contactIDs Array of contact IDs.
	 * @return void
	 */
	public static function bindContactIDs($leadID, array $contactIDs)
	{
		$bindings = EntityBinding::prepareEntityBindings(\CCrmOwnerType::Contact, $contactIDs);
		$qty = count($bindings);
		if($qty > 0)
		{
			for($i = 0; $i < $qty; $i++)
			{
				if($i === 0)
				{
					$bindings[$i]['IS_PRIMARY'] = 'Y';
				}
				$bindings[$i]['SORT'] = 10 * ($i + 1);
			}
			self::bindContacts($leadID, $bindings);
		}
	}
	/**
	 * Bind Lead to Contacts.
	 * @param int $leadID Lead ID.
	 * @param array $bindings Array of contact bindings.
	 * @return void
	 * @throws Main\ArgumentException
	 */
	public static function bindContacts($leadID, array $bindings)
	{
		$leadID = (int)$leadID;
		if($leadID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'leadID');
		}

		$qty = count($bindings);
		if($qty === 0)
		{
			return;
		}

		$processed = 0;
		for($i = 0; $i < $qty; $i++)
		{
			$binding = $bindings[$i];
			if(!is_array($binding))
			{
				continue;
			}

			$contactID = isset($binding['CONTACT_ID']) ? (int)$binding['CONTACT_ID'] : 0;
			if($contactID <= 0)
			{
				continue;
			}

			self::upsert(
				array(
					'LEAD_ID' => $leadID,
					'CONTACT_ID' => $contactID,
					'SORT' => isset($binding['SORT']) ? (int)$binding['SORT'] : (10 * ($i + 1)),
					'ROLE_ID' => isset($binding['ROLE_ID']) ? (int)$binding['ROLE_ID'] : EntityBinding::ROLE_UNDEFINED,
					'IS_PRIMARY' => isset($binding['IS_PRIMARY']) ? $binding['IS_PRIMARY'] : ''
				)
			);
			$processed++;
		}

		if($processed > 0)
		{
			Main\Application::getConnection()->queryExecute(
			/** @lang text*/
				"UPDATE b_crm_lead SET CONTACT_ID =
				(SELECT MIN(CONTACT_ID) FROM b_crm_lead_contact WHERE IS_PRIMARY = 'Y' AND LEAD_ID = {$leadID})
				WHERE ID = {$leadID}"
			);
		}
	}
	/**
	 * Unbind specified Lead from specified contacts.
	 * @param int $leadID Lead ID.
	 * @param array $contactIDs Array of contact IDs.
	 * @return void
	 * @throws Main\ArgumentException
	 */
	public static function unbindContactIDs($leadID, array $contactIDs)
	{
		$leadID = (int)$leadID;
		if($leadID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'leadID');
		}

		$contactIDs = array_filter($contactIDs);
		if(empty($contactIDs))
		{
			return;
		}

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

		$values = implode(',', $contactIDs);
		$connection->queryExecute(
		/** @lang text */
			"DELETE FROM b_crm_lead_contact WHERE LEAD_ID = {$leadID} AND CONTACT_ID IN({$values})"
		);

		$connection->queryExecute(
		/** @lang text*/
			"UPDATE b_crm_lead SET CONTACT_ID =
			(SELECT MIN(CONTACT_ID) FROM b_crm_lead_contact WHERE IS_PRIMARY = 'Y' AND LEAD_ID = {$leadID})
			WHERE ID = {$leadID}"
		);
	}
	/**
	 * Unbind specified Lead from specified Contacts.
	 * @param int $leadID Lead ID.
	 * @param array $bindings Array of bindings.
	 * @return void
	 * @throws Main\ArgumentException
	 */
	public static function unbindContacts($leadID, array $bindings)
	{
		$leadID = (int)$leadID;
		if($leadID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'leadID');
		}

		self::unbindContactIDs($leadID, EntityBinding::prepareEntityIDs(\CCrmOwnerType::Contact, $bindings));
	}
	/**
	 * Unbind specified Lead from all contacts.
	 * @param int $leadID Lead ID.
	 * @return void
	 * @throws Main\ArgumentException
	 */
	public static function unbindAllContacts($leadID)
	{
		$leadID = (int)$leadID;
		if($leadID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'leadID');
		}

		$connection = Main\Application::getConnection();
		$connection->queryExecute(
		/** @lang text */
			"DELETE FROM b_crm_lead_contact WHERE LEAD_ID = {$leadID}"
		);
		$connection->queryExecute(
		/** @lang text */
			"UPDATE b_crm_lead SET CONTACT_ID = NULL WHERE ID = {$leadID}"
		);
	}
	/**
	 * Unbind specified Contact from all Leads.
	 * @param int $contactID Contact ID.
	 * @return void
	 * @throws Main\ArgumentException
	 */
	public static function unbindAllLeads($contactID)
	{
		$contactID = (int)$contactID;
		if($contactID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'contactID');
		}

		$connection = Main\Application::getConnection();
		$connection->queryExecute(
		/** @lang text */
			"DELETE FROM b_crm_lead_contact WHERE CONTACT_ID = {$contactID}"
		);
		$connection->queryExecute(
		/** @lang text */
			"UPDATE b_crm_lead SET CONTACT_ID =
			(SELECT MIN(CONTACT_ID) FROM b_crm_lead_contact t WHERE t.LEAD_ID = b_crm_lead.ID)
			WHERE CONTACT_ID = {$contactID}"
		);
	}
	/**
	 * Prepare SQL join filter condition for specified entity.
	 * @param int $entityTypeID Entity type ID for filter.
	 * @param int $entityID Entity ID for filter.
	 * @param string $tableAlias Alias of primary table.
	 * @return string
	 * @throws Main\ArgumentException
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\NotSupportedException
	 */
	public static function prepareFilterJoinSql($entityTypeID, $entityID, $tableAlias)
	{
		if(!is_int($entityTypeID))
		{
			$entityTypeID = (int)$entityTypeID;
		}

		if(!\CCrmOwnerType::IsDefined($entityTypeID))
		{
			throw new Main\ArgumentOutOfRangeException('entityTypeID',
				\CCrmOwnerType::FirstOwnerType,
				\CCrmOwnerType::LastOwnerType
			);
		}

		if($entityTypeID !== \CCrmOwnerType::Contact && $entityTypeID !== \CCrmOwnerType::Lead)
		{
			$entityTypeName = \CCrmOwnerType::ResolveName($entityTypeID);
			throw new Main\NotSupportedException("Entity type: '{$entityTypeName}' is not supported in current context");
		}

		$entityIDs = is_array($entityID) ? $entityID : array($entityID);
		$effectiveIDs = array();
		foreach($entityIDs as $ID)
		{
			$ID = (int)$ID;
			if($ID > 0)
			{
				$effectiveIDs[] = $ID;
			}
		}

		$qty = count($effectiveIDs);
		if($qty > 1)
		{
			$slug = implode(',', $effectiveIDs);
			if($entityTypeID === \CCrmOwnerType::Contact)
			{
				return "INNER JOIN b_crm_lead_contact DC ON DC.CONTACT_ID IN({$slug}) AND DC.LEAD_ID = {$tableAlias}.ID";
			}
			else//if($entityTypeID === \CCrmOwnerType::Lead)
			{
				return "INNER JOIN b_crm_lead_contact DC ON DC.LEAD_ID IN({$slug}) AND DC.CONTACT_ID = {$tableAlias}.ID";
			}
		}
		elseif($qty === 1)
		{
			if($entityTypeID === \CCrmOwnerType::Contact)
			{
				return "INNER JOIN b_crm_lead_contact DC ON DC.CONTACT_ID = {$effectiveIDs[0]} AND DC.LEAD_ID = {$tableAlias}.ID";
			}
			else//if($entityTypeID === \CCrmOwnerType::Lead)
			{
				return "INNER JOIN b_crm_lead_contact DC ON DC.LEAD_ID = {$effectiveIDs[0]} AND DC.CONTACT_ID = {$tableAlias}.ID";
			}
		}
		return "";
	}
	/**
	 * Unbind all Leads from seed Contact and bind to target Contact
	 * @param int $seedContactID Seed contact ID.
	 * @param int $targContactID Target contact ID.
	 * @throws Main\ArgumentException
	 */
	public static function rebindAllLeads($seedContactID, $targContactID)
	{
		$seedContactID = (int)$seedContactID;
		if($seedContactID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'seedContactID');
		}

		$targContactID = (int)$targContactID;
		if($targContactID <= 0)
		{
			throw new Main\ArgumentException('Must be greater than zero', 'targContactID');
		}

		if($seedContactID === $targContactID)
		{
			return;
		}

		$connection = Main\Application::getConnection();
		$dbResult = $connection->query(
		/** @lang text */
			"SELECT LEAD_ID FROM b_crm_lead_contact WHERE CONTACT_ID = {$seedContactID}"
		);

		while($fields = $dbResult->fetch())
		{
			$leadID = (int)$fields['LEAD_ID'];
			$bindings = self::getLeadBindings($leadID);
			$seedIndex = $targIndex = -1;
			for($i = 0, $l = count($bindings); $i < $l; $i++)
			{
				$binding = $bindings[$i];
				$contactID = (int)$binding['CONTACT_ID'];
				if($contactID === $seedContactID)
				{
					$seedIndex = $i;
				}
				elseif($contactID === $targContactID)
				{
					$targIndex = $i;
				}

				if($seedIndex >= 0 && $targIndex >= 0)
				{
					break;
				}
			}

			$seedBinding = $seedIndex >= 0 ? $bindings[$seedIndex] : null;
			$targBinding = $targIndex >= 0 ? $bindings[$targIndex] : null;

			if(!is_array($seedBinding))
			{
				continue;
			}

			self::unbindContactIDs($leadID, array($seedContactID));

			$isPrimary = isset($seedBinding['IS_PRIMARY']) && $seedBinding['IS_PRIMARY'] === 'Y';
			if(!is_array($targBinding))
			{
				$seedBinding['CONTACT_ID'] = $targContactID;
				self::bindContacts($leadID, array($seedBinding));
			}
			elseif($isPrimary)
			{
				$targBinding['IS_PRIMARY'] = 'Y';
				self::bindContacts($leadID, array($targBinding));
			}
		}
	}
}