Автоматическая отправка сообщений в ВК пользователю по статусу в Битрикс24
Последние записи
Постановка задачи: нужно отправлять пользователям Вконтакте автоматические сообщения от имени группы если у ассоциированных лидов в Битрикс24 стоит определенный статус и прошло заданное кол-во времени. Если пользователь начинает общаться, то отправка должна прекратиться
Ассоциация лидов останется за скобками данного материала. Ее можно провести с помощью соответствующих плагинов Вконтакте
или вручную с помощью API
Задачу решим использованием двух скриптов. Первый будет на регулярной основе опрашивать Битрикс24 на предмет новых пользователей с искомым статутом. Второй будет отправлять этим пользователям сообщение.
Так же у нас будет таблица-прокладка в которой мы будем хранить все результаты
Структура HL
таблицы
Тип: строка; Имя: UF_NAME; Название: Имя
Тип: строка; Имя: UF_LASTNAME; Название: Фамилия
Тип: строка; Имя: UF_VK_ID; Название: ВК Id
Тип: строка; Имя: UF_VK_LINK; Название: Вк ссылка
Тип: Да/Нет; Имя: UF_1DAY_SEND; Название: 1D СМС
Тип: Да/Нет; Имя: UF_2DAY_SEND; Название: 2D СМС
Тип: Да/Нет; Имя: UF_5DAY_SEND; Название: 5D СМС
Тип: Да/Нет; Имя: UF_7DAY_SEND; Название: 7D СМС
Тип: Да/Нет; Имя: UF_30DAY_SEND; Название: 30D СМС
Тип: Дата со временем; Имя: UF_DATE_STATUS_CHANG; Название: Дата начала; Значение по умолчанию: текущее время
Тип: Целое число; Имя: UF_BITRIX24; Название: Lead ID
Тип: Строка; Имя: UF_VK_PREFIX; Название: Префикс ВК
Тип: Да/Нет; Имя: UF_ACTIVE; Название: Активность
В Битрикс24
есть кастомное поле UF_CRM_435324332
- в нем хранится кастомная группа пользователей, а так же стандартное поле WEB
в котором лежит ссылка на профиль пользователя в ВК
Так же нам понадобятся 4 небольших класса помощника
Листинг high.php
use Bitrix\Highloadblock\HighloadBlockTable;
class tHighload {
public function getHighloadData($id,$dbClass,$arFilter = array()){
$hlblock = Bitrix\Highloadblock\HighloadBlockTable::getById( $id )->fetch();
$entity = Bitrix\Highloadblock\HighloadBlockTable::compileEntity( $hlblock );
$entity_data_class = $entity->getDataClass();
$ar = array(
"filter" => $arFilter,
"select" => array('*')
);
// Данные
$arData = $entity_data_class::getList($ar);
$arData = new CDBResult($arData, $dbClass);
while($arResult = $arData->Fetch()){
$result[]=$arResult;
}
return $result;
}
/*Апдейт одиночной записи*/
public function updateHighloadData($id,$data){
$hlblock = Bitrix\Highloadblock\HighloadBlockTable::getById( $id )->fetch();
$entity = Bitrix\Highloadblock\HighloadBlockTable::compileEntity( $hlblock );
$entity_data_class = $entity->getDataClass();
$elId = $data['ID'];
unset($data['ID']);
$result = $entity_data_class::update($elId, $data);
return $result;
}
public function setHighloadData($id, $arProps){
$hlblock = Bitrix\Highloadblock\HighloadBlockTable::getById( $id )->fetch();
$entity = Bitrix\Highloadblock\HighloadBlockTable::compileEntity( $hlblock );
$entity_data_class = $entity->getDataClass();
$otvet = $entity_data_class::add($arProps);
if ($otvet->isSuccess()) {
return 'Success';
} else {
return implode(', ', $otvet->getErrors());
}
}
}
Листинг date.php
class tDate {
public function dateGap($date1, $date2)
{
$time = new DateTime($date1);
$since_time = $time->diff( new DateTime($date2) );
$A['days'] = $since_time->days;
$A['hours'] = $since_time->days * 24 + $since_time->h;
$A['minutes'] = ($since_time->days * 24 * 60) + ($since_time->h * 60) + $since_time->i;
return $A;
}
}
Листинг файла bitrix24.php
class bitrix24 {
public function getLeadList($arSelect, $arFilter){
$queryUrl = 'https://BITRIX24_SERVER/REST_API_HOOK_PATH/crm.lead.list'; //Список сделок
$queryData = http_build_query($arFilter);
$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,
));
$result = curl_exec($curl);
curl_close($curl);
return json_decode($result);
}
}
Листинг файла vk.php
class tVK
{
const TOKEN = 'TOKEN';
public function curlGet($url){
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
public function getUserInfo($user_id){
$url='https://api.vk.com/method/users.get?user_ids='.$user_id.'&fields=bdate,photo_200,status&access_token='.self::TOKEN.'&v=5.41';
$response=$this->curlGet($url);
return $response;
}
public function sendMessage($data){
$params = array(
'message' => str_replace("#Имя#", $data['USER_NAME'], $data['MESSAGE']),
'user_id' => $data['USER_ID'],
'access_token' => self::TOKEN,
'v' => '5.81'
);
$query = http_build_query($params);
return file_get_contents('https://api.vk.com/method/messages.send?' . $query);
}
}
Листинг файла getStatusFromBitrix.php
//Не забываем рассчитать правильный путь к папке сайта
$_SERVER["DOCUMENT_ROOT"] = realpath(dirname(__FILE__)."/../..");
$DOCUMENT_ROOT = $_SERVER["DOCUMENT_ROOT"];
define("NO_KEEP_STATISTIC", true);
define("NOT_CHECK_PERMISSIONS",true);
define("BX_CRONTAB", true);
define('BX_NO_ACCELERATOR_RESET', true);
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_admin_before.php");
use Bitrix\Main\Type\DateTime;
@set_time_limit(0);
@ignore_user_abort(true);
require_once ($_SERVER['DOCUMENT_ROOT'].'/PATH_TO_PROJECT/lib/bitrix24.php');
require_once ($_SERVER['DOCUMENT_ROOT'].'/PATH_TO_PROJECT/libs/high.php');
require_once ($_SERVER['DOCUMENT_ROOT'].'/PATH_TO_PROJECT/libs/vk.php');
$tHigh = new tHighload;
$tVK = new tVK;
//Текущее время по Москве
$date = new DateTime();
$hour = date("H");
$data = $common = array();
//Работаем только днем
if($hour>21 || $hour<8){die();}
//Рекурсивно перебираем всех подходящих под условие запроса пользователей
function getLeads($id=0,$arData = array()){
$bitrix24 = new bitrix24;
//Выбираем поля
$arSelect = array('ID', 'TITLE', 'NAME', 'LAST_NAME', 'ASSIGNED_BY_ID', 'UF_CRM_435324332', 'WEB');
//Фильтруем
$arFilter = array(
'order' => array('ID'=>'DESC'),
'select' => $arSelect,
"filter" => array(
'UF_CRM_435324332' => array(2078,2079), //Статус "Рассылать сообщения" и Статус "Начал общаться"
"!WEB" => false, //Ссылка заполнена
)
);
if($id!=0){
$arFilter['filter']['<ID'] = $id;
}
//Получаем список пользователей у которыех есть параметр WEB,
// и у которых статус (UF_CRM_435324332) установлен в "Рассылать сообщения"
$result = json_decode(json_encode($bitrix24->getLeadList($arSelect,$arFilter)), True);
foreach ($result['result'] as $key => $value){
$arData[] = $value;
}
if($result['next']==50){
$arData = getLeads($result['result'][49]['ID'],$arData);
}
return $arData;
}
$common = getLeads();
$bitrix24 = new bitrix24;
foreach ($common as $key => $value){
//Получаем ссылку на страницу
$link = explode('/',$value['WEB'][0]['VALUE']);
//Получаем последний индекс массива
$lastKey = key(array_slice($link, -1, 1, true));
$vkID = 0;
if($link){
//Получаем информацию о пользователе
$getId = json_decode($tVK->getUserInfo($link[$lastKey]));
$vkID = $getId->response[0]->id;
}
$arProps = array(
'UF_NAME' => $value['NAME'],
'UF_LASTNAME' => $value['LAST_NAME'],
'UF_VK_ID' => $vkID,
'UF_VK_LINK' => $value['WEB'][0]['VALUE'],
'UF_DATE_STATUS_CHANG' => $date->toString(),
'UF_BITRIX24' => $value['ID'],
'UF_VK_PREFIX' => $link[$lastKey]
);
if($value['UF_CRM_435324332']=='2078'){//Статус "Рассылать сообщения"
$arProps['UF_ACTIVE']=1;
}
if($value['UF_CRM_435324332']=='2079'){//Статус "Начал общаться"
$arProps['UF_ACTIVE']=0;
}
$user = $tHigh->getHighloadData(HL_TABLE_ID,'HL_TABLE_NAME', array('UF_BITRIX24' => $value['ID']));
//Если статусы не изменились, то ничего не делаем
if($arProps['UF_ACTIVE']==$user[0]['UF_ACTIVE']){continue;}
if($user){
$arProps['ID'] = $user[0]['ID'];
$res = $tHigh->updateHighloadData(HL_TABLE_ID, $arProps);
}else{
$res = $tHigh->setHighloadData(HL_TABLE_ID, $arProps);
}
}
Листинг файла checkIfNeedSMS.php
$_SERVER["DOCUMENT_ROOT"] = realpath(dirname(__FILE__)."/../..");
$DOCUMENT_ROOT = $_SERVER["DOCUMENT_ROOT"];
define("NO_KEEP_STATISTIC", true);
define("NOT_CHECK_PERMISSIONS",true);
define("BX_CRONTAB", true);
define('BX_NO_ACCELERATOR_RESET', true);
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_admin_before.php");
use Bitrix\Main\Type\DateTime;
@set_time_limit(0);
@ignore_user_abort(true);
require_once ($_SERVER['DOCUMENT_ROOT'].'/PATH_TO_PROJECT/libs/high.php');
require_once ($_SERVER['DOCUMENT_ROOT'].'/PATH_TO_PROJECT/libs/vk.php');
require_once ($_SERVER['DOCUMENT_ROOT'].'/PATH_TO_PROJECT/libs/date.php');
$tHigh = new tHighload;
$tVK = new tVK;
$tDate = new tDate;
//Текущее время по Москве
$date = date("Y-m-d H:i:s");
$hour = date("H");
$data = array();
//Работаем только днем
if($hour>21 || $hour<8){die();}
$messages = array(
'1' => 'Привет #Имя#. Это тестовое сообщение 1',
'2' => 'Это тестовое сообщение 2',
'3' => '#Имя#, Это тестовое сообщение 3',
'7' => 'Это тестовое сообщение 4',
'30' => 'Это тестовое сообщение 5'
);
$users = $tHigh->getHighloadData(HL_TABLE_ID,'HL_TABLE_NAME', array('UF_ACTIVE'=>'1'));
foreach ($users as $key => $u){
if(!$u['UF_VK_ID']){
//Получаем ссылку на страницу
$link = explode('/',$u['UF_VK_LINK']);
//Получаем последний индекс массива
$lastKey = key(array_slice($link, -1, 1, true));
if($link){
//Получаем информацию о пользователе
$getId = json_decode($tVK->getUserInfo($link[$lastKey]));
$u['UF_VK_ID'] = $getId->response[0]->id;
}
}
$arProps = array(
'ID' => $u['ID'],
'UF_NAME' => $u['UF_NAME'],
'UF_LASTNAME' => $u['UF_LASTNAME'],
'UF_VK_ID' => $u['UF_VK_ID'],
'UF_VK_LINK' => $u['UF_VK_LINK'],
'UF_BITRIX24' => $u['UF_BITRIX24'],
'UF_VK_PREFIX' => $u['UF_VK_PREFIX']
);
//Выясняем разницу в датах
$diff = $tDate->dateGap($u['UF_DATE_STATUS_CHANG'],$date);
$data = array(
'USER_ID' => $u['UF_VK_ID'],
'USER_NAME' => $u['UF_NAME'] ? $u['UF_NAME'] : $u['UF_LASTNAME']
);
if($u['UF_1DAY_SEND'] == 0 && $diff['hours']>24){//Спустя сутки
//Составляем параметры отправки сообщений
$data['MESSAGE'] = $messages[1];
$arProps['UF_1DAY_SEND'] = 1;
}
if($u['UF_2DAY_SEND'] == 0 && $diff['hours']>48){//Спустя двое суток
//Составляем параметры отправки сообщений
$data['MESSAGE'] = $messages[2];
$arProps['UF_2DAY_SEND'] = 1;
}
if($u['UF_3DAY_SEND'] == 0 && $diff['hours']>120){//Спустя 5 суток
//Составляем параметры отправки сообщений
$data['MESSAGE'] = $messages[3];
$arProps['UF_3DAY_SEND'] = 1;
}
if($u['UF_7DAY_SEND'] == 0 && $diff['hours']>168){//Спустя 7 суток
//Составляем параметры отправки сообщений
$data['MESSAGE'] = $messages[7];
$arProps['UF_7DAY_SEND'] = 1;
}
if($u['UF_30DAY_SEND'] == 0 && $diff['hours']>720){//Спустя 30 суток
//Составляем параметры отправки сообщений
$data['MESSAGE'] = $messages[30];
$arProps['UF_30DAY_SEND'] = 1;
}
if(isset($data['MESSAGE'])){
//Отправляем сообщение во вконтакте
$vkAnswer = json_decode($tVK->sendMessage($data));
if(!isset($vkAnswer->error)){
//Обновляем запись в БД
$tHigh->updateHighloadData(HL_TABLE_ID, $arProps);
}else{
$filename = '/tmp/checkIfNeedSMS.log';
$data = $vkAnswer->error;
file_put_contents($filename, date('[Y-m-d H:i:s] ') . print_r($data, true) . PHP_EOL, FILE_APPEND | LOCK_EX);
}
}
}
Теперь осталось настроить запуск двух последних файлов через крон. Вызов крон:
crontab -u bitrix -e
Добавляем записи с выполнением каждый час в 10 и 15 минуты
10 */1 * * * php -f /PATH_TO_YOUR_PROJECT/getStatusFromBitrix.php > /tmp/getStatusFromBitrix.log
15 */1 * * * php -f /PATH_TO_YOUR_PROJECT/checkIfNeedSMS.php > /tmp/checkIfNeedSMS.log
Обновляем крон
systemctl restart crond.service
Комментарии