Документация для разработчиков
Темная тема

Основные пользовательские сценарии и пример

  1. Входящий звонок на АТС на внутренний номер конкретного пользователя должен показывать карточку звонка у сотрудника в Битрикс24 (Метод telephony.externalcall.register).

  2. Входящий звонок с неизвестного номера (не зарегистрированного в CRM), должен попадать в очередь обработки (список пользователей, которые должны отвечать на входящие звонки):
    • Одновременная очередь: всем сотрудникам, которые не отвечают на другие звонки в данный момент, одновременно показывается карточка звонка, когда кто-то из них начинает отвечать на звонок, у остальных карточка пропадает (сначала telephony.externalcall.register для первого в очереди, затем telephony.externalcall.show для остальных).
    • Последовательная очередь: каждому из сотрудников очереди, которые не отвечают на другие звонки в данный момент, показывается карточка звонка на какое-то время (3-5-7 секунд), если сотрудник не начинает отвечать на звонок, карточка у него пропадает, и звонок переводится на следующего в очереди (сначала telephony.externalcall.register для первого в очереди, затем telephony.externalcall.hide и telephony.externalcall.show для следующего).

  3. Входящий звонок с известного номера в виде карточки звонка отображается в Битрикс24 у менеджера, ответственного за соответствующий объект CRM. (Сначала telephony.externalcall.register с SHOW = 0, который вернет либо CREATED_LEAD в случае, если телефон не был найден в CRM и был создан новый лид, либо пару CRM_ENTITY_TYPE и CRM_ENTITY_ID с указанием найденного существующего клиента.
    Одновременно возвращается CRM_ACTIVITY_ID с идентификатором нового дела в CRM, в котором будет зафиксирован звонок в дальнейшем. Зная идентификатор объекта в CRM, можно при помощи методов REST по работе с CRM получить идентификатор менеджера, который отвечает за клиента, перевести звонок на него и показать ему карточку звонка telephony.externalcall.show)

  4. Сотрудник в Битрикс24 нажимает на номер телефона в интерфейсе CRM. Приложение инициирует исходящий звонок на указанный номер на стороне АТС (событие onexternalcallstart, сотруднику показывается карточка звонка telephony.externalcall.register).

  5. Звонок завершен (входящий или исходящий). Факт звонка и запись фиксируется в привязке к объекту CRM (telephony.externalcall.finish. Если на момент завершения звонка в АТС еще не готова запись разговора, то вместо telephony.externalcall.finish сначала просто скрываем карточку звонка telephony.externalcall.hide, а уже потом, когда запись готова, все-таки вызываем telephony.externalcall.finish).

  6. На стороне АТС произошел входящий звонок в тот момент, когда связи между АТС и Битрикс24 по каким-то причинам нет. После восстановления связи информация о произошедшем звонке фиксируется в Битрикс24 (см. 1-3, но без показа карточки звонка – последовательный вызов методов telephony.externalcall.register с параметром SHOW = 0 и telephony.externalcall.finish.)

Примечание. Чтобы запись добавлялась к звонку при сценарии обзвона, приложения должны передвать CALL_LIST_ID который им придет в событии начала звонка.

Пример:

<?php
/**
 * Created by PhpStorm.
 * User: sv
 * Date: 01.11.16
 * Time: 10:44
 */

// ini_set('display_errors','Off');

// формируем url нашего скрипта для использования в ajax-запросах из интерфейса приложения
$script_url = ($_SERVER['SERVER_PORT'] == 443 ? 'https' : 'http') . '://' . $_SERVER['SERVER_NAME'] . (in_array($_SERVER['SERVER_PORT'],
	array(80, 443)) ? '' : ':' . $_SERVER['SERVER_PORT']) . $_SERVER['SCRIPT_NAME'];

$appsConfig = array();
$b24domain = $_REQUEST['DOMAIN'];

// если нам пришло событие исходящего звонка, то авторизация передается через узел auth в массиве request
// но нам оттуда нужен только домен, авторизацию мы уже сохранили к этому моменту
if (!empty($_REQUEST['auth'])) {
	$b24domain = $_REQUEST['auth']['domain'];
}

$configFileName = '/config_' . trim(str_replace('.', '_', $b24domain)) . '.php';
echo getcwd().$configFileName."<br/>";
if (file_exists(getcwd() . $configFileName)) {
	include_once getcwd() . $configFileName;
} else {

	// сохраняем токены пользователя, устанавливающего приложение
	$appsConfig = $_REQUEST;
	saveParams($appsConfig);

	// регистрируем событие исходящего звонка
	restCommand('event.bind', array(
		"event" => 'ONEXTERNALCALLSTART',
		"handler" => $script_url."?action=outcoming",
	),
	$b24domain, $appsConfig['AUTH_ID']);

	/* тестовое событие для проверки механизма
	restCommand('event.bind', array(
		"event" => 'ONAPPTEST',
		"handler" => $script_url."?action=test",
		),
		$b24domain, $appsConfig['AUTH_ID']);
	*/

}

$action = $_REQUEST['action'];

// мы просто запустили приложение в интерфейсе Битрикс24
if ($action == '') {
?>
<html>
<head>
	<meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>

<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">

<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>

	<script src="//api.bitrix24.com/api/v1/"></script>
</head>
<body>

<div class="form-group">
	<label for="IncomingNumber">Incoming call number</label>
	<input type="text" class="form-control" id="incomingNumber" placeholder="phone">
</div>
<div class="form-group">
	<label for="user1">User 1</label>
	<input type="text" class="form-control" id="user1" placeholder="user id" value="1">
</div>
<div class="form-group">
	<label for="user2">User 2 (for call transfer)</label>
	<input type="text" class="form-control" id="user2" placeholder="user id">
</div>
<a class="btn btn-default" href="#" role="button" id="incoming">Incoming</a>
<a class="btn btn-default" href="#" role="button" id="redirect">Redirect</a>
<a class="btn btn-default" href="#" role="button" id="drop">Drop</a>
<a class="btn btn-default" href="#" role="button" id="test">Event test</a>
<div id="debug"></div>

<?
	// если любопытно, можно посмотреть, какие параметры авторизации передает Битрикс24 скрипту приложения
	// в случае выполнения приложения во фрейме внутри Битрикс24
	//echo "<pre>";
	//print_r($_REQUEST);
	//echo "</pre>";

?>
<script>
	$( "#incoming" ).on( "click", function( event ) {
		// здесь мы имитируем работу внешней АТС, в частности, получение входящего звонка
		// поэтому AJAX, передача параметров авторизации и т.д.
		// в реальной практике, REST телефонии будет вызываться со стороны АТС, а там мы уже сохранили
		// авторизационные токены (см. $appsConfig$appsConfig) и сами знаем, на какой Битрикс24 отправлять
		// вызов REST, каким пользователям показывать карточку и т.д.
		auth = BX24.getAuth();
		$.ajax({
			url: "<?=$script_url?>",
			data: {
				action: 'incoming',
				user1: $( "#user1" ).val(),
				phone: $( "#incomingNumber" ).val(),
				DOMAIN: auth['domain']
			},
			success: function( result ) {
				$( "#debug" ).html( result );
			}
		});
	});

	$( "#redirect" ).on( "click", function( event ) {
		auth = BX24.getAuth();
		$.ajax({
			url: "<?=$script_url?>",
			data: {
				action: 'redirect',
				user1: $( "#user1" ).val(),
				user2: $( "#user2" ).val(),
				DOMAIN: auth['domain']
			},
			success: function( result ) {
				$( "#debug" ).html( result );
			}
		});
	});

	$( "#drop" ).on( "click", function( event ) {
		auth = BX24.getAuth();
		$.ajax({
			url: "<?=$script_url?>",
			data: {
				action: 'drop',
				user1: $( "#user1" ).val(),
				user2: $( "#user2" ).val(),
				DOMAIN: auth['domain']
			},
			success: function( result ) {
				$( "#debug" ).html( result );
			}
		});
	});
	/* инициация тестового события на стороне серверного скрипта, ничего важного
	$( "#test" ).on( "click", function( event ) {
		auth = BX24.getAuth();
		$.ajax({
			url: "<?=$script_url?>",
			data: {
				action: 'eventtest',
				DOMAIN: auth['domain']
			},
			success: function( result ) {
				$( "#debug" ).html( result );
			}
		});
	});
	*/
</script>
</body>
</html>
<? } else {

	switch ($action) {
		case 'test': writeToLog(array('test' => $_REQUEST), 'telephony test event');
				break;

		case 'outcoming':

			writeToLog(array('outcoming' => $_REQUEST), 'telephony event');

			$result = restCommand('telephony.externalCall.register',
				array(
					"USER_ID" => $_REQUEST['data']['USER_ID'],
					"PHONE_NUMBER"   => $_REQUEST['data']['PHONE_NUMBER'],
					"TYPE" => '1',
					"CRM_CREATE" => 1
				),
				$b24domain, $appsConfig['AUTH_ID']);

			$appsConfig['CALL'] = $result['result'];


			saveParams($appsConfig);

			break;
		case 'eventtest':

			writeToLog(array('eventtest' => $_REQUEST), 'test event call');
			$result = restCommand('event.test',
				array(
				),
				$b24domain, $appsConfig['AUTH_ID']);

			echo "test event call";

			break;
		case 'incoming':

			$result = restCommand('telephony.externalCall.register',
				array(
					"USER_ID" => $_REQUEST['user1'],
					"PHONE_NUMBER"   => $_REQUEST['phone'],
					"TYPE" => '2',
					"CRM_CREATE" => true
				),
				$b24domain, $appsConfig['AUTH_ID']);

			$appsConfig['CALL'] = $result['result'];

			saveParams($appsConfig);

			echo "incoming <pre>";
			print_r($appsConfig);
			echo "</pre>";

			break;
		case 'redirect':

			echo "redirect <pre>";
			print_r($appsConfig);
			echo "</pre>";

			if ($appsConfig['CALL']['CALL_ID'] != '') {

				$result = restCommand('telephony.externalCall.hide',
					array(
						"CALL_ID" => $appsConfig['CALL']['CALL_ID'],
						"USER_ID" => $_REQUEST['user1']
					),
					$b24domain, $appsConfig['AUTH_ID']);

				$result = restCommand('telephony.externalCall.show',
					array(
						"CALL_ID" => $appsConfig['CALL']['CALL_ID'],
						"USER_ID" => $_REQUEST['user2']
					),
					$b24domain, $appsConfig['AUTH_ID']);
			}
			echo "redirected to ".$_REQUEST['user2'];
			break;
		case 'drop':
			writeToLog(array('config' => $appsConfig), 'call is finishing');

			if ($appsConfig['CALL']['CALL_ID'] != '') {

				$result = restCommand('telephony.externalCall.finish',
					array(
						"CALL_ID" => $appsConfig['CALL']['CALL_ID'],
						"USER_ID" => $_REQUEST['user1'],
						"DURATION"   => '120',
						"STATUS_CODE" => '200',
						"ADD_TO_CHAT" => true
					),
					$b24domain, $appsConfig['AUTH_ID']);

				$appsConfig['CALL'] = $result['result'];

				saveParams($appsConfig);

				echo "finished <pre>";
				print_r($appsConfig);
				echo "</pre>";

				writeToLog(array('request' => $_REQUEST, 'config' => $appsConfig), 'call is finished');
			}
			echo "dropped and saved";
			break;
	}

}

/**
 * Save application configuration.
 *
 * @param $params
 *
 * @return bool
 */
function saveParams($params) {
	$config = "<?php\n";
	$config .= "\$appsConfig = " . var_export($params, true) . ";\n";
	$config .= "?>";
	$configFileName = '/config_' . trim(str_replace('.', '_', $_REQUEST['DOMAIN'])) . '.php';
	file_put_contents(getcwd() . $configFileName, $config);
	return true;
}
/**
 * Send rest query to Bitrix24.
 *
 * @param	   $method - Rest method, ex: methods
 * @param array $params - Method params, ex: array()
 * @param array $auth   - Authorize data, ex: array('domain' => 'https://test.bitrix24.com', 'access_token' => '7inpwszbuu8vnwr5jmabqa467rqur7u6')
 *
 * @return mixed
 */
function restCommand($method, array $params = array(), $auth_domain, $access_token) {
	$queryUrl  = 'https://' . $auth_domain . '/rest/' . $method;
	$queryData = http_build_query(array_merge($params, array('auth' => $access_token)));
	writeToLog(array('URL' => $queryUrl, 'PARAMS' => array_merge($params, array("auth" => $access_token))), 'telephony send data');
	$curl = curl_init();
	curl_setopt_array($curl, array(
		CURLOPT_SSL_VERIFYPEER => 0,
		CURLOPT_POST		   => 1,
		CURLOPT_HEADER		 => 0,
		CURLOPT_RETURNTRANSFER => 1,
		CURLOPT_URL			=> $queryUrl,
		CURLOPT_POSTFIELDS	 => $queryData,
		CURLOPT_VERBOSE		 => 1
	));
	$result = curl_exec($curl);
	writeToLog(array('raw' => $result), 'telephony got data');
	curl_close($curl);
	$result = json_decode($result, 1);
	return $result;
}

/**
 * Write data to log file.
 *
 * @param mixed  $data
 * @param string $title
 *
 * @return bool
 */
function writeToLog($data, $title = '') {
	$log = "\n------------------------\n";
	$log .= date("Y.m.d G:i:s") . "\n";
	$log .= (strlen($title) > 0 ? $title : 'DEBUG') . "\n";
	$log .= print_r($data, 1);
	$log .= "\n------------------------\n";
	file_put_contents(getcwd() . '/tel.log', $log, FILE_APPEND);
	return true;
}

?>


© «Битрикс», 2001-2024, «1С-Битрикс», 2024