You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
cosmopet-architecture/wp-content/themes/cosmopet/modules/forms/module-controller.php

587 lines
21 KiB

<?php
abstract class FormHandler {
protected $nextHandler;
public function __construct($nextHandler = null) {
$this->nextHandler = $nextHandler;
}
public function handle($data, $crmData) {
if ($this->nextHandler) {
return $this->nextHandler->handle($data, $crmData);
}
return ['success' => true, 'message' => 'Форма обработана'];
}
public function formatData($data) {
if (is_string($data)) {
parse_str($data, $parsedData); // Преобразуем строку в массив
$data = $parsedData;
}
$formattedMessage = "Данные формы:\n\n";
// Проходим по всем полям данных и добавляем их в сообщение
foreach ($data as $key => $value) {
$formattedMessage .= sprintf("%s: %s\n", $key, $value);
}
return $formattedMessage;
}
}
define('WEBHOOK_URL', 'https://b24-f0tsii.bitrix24.ru/rest/10/z5k521mjfkmk7pqj/');
$utm_data = get_utm_data();
class b24Handler extends FormHandler {
public function handle($data, $crmData) {
$this->b24_add_lead(
$crmData['phone'],
$crmData['name'],
$crmData['email'],
$crmData['msg'],
$crmData['url'],
$crmData['stage'],
$crmData['fName'],
$crmData['order_total'],
$crmData['user_id'],
$crmData['method'],
$crmData['form_title'],
$crmData['is_subscribe'],
$crmData['order_id'],
);
error_log('----------CRM_DATA----------------');
error_log(json_encode($crmData));
error_log('----------CRM_DATA----------------');
// Вызываем следующий обработчик в цепочке
return parent::handle($data, $crmData);
}
function b24_get_or_create_contact($phone, $name, $email, $userID = null, $isSubscribe) {
$contactId = null;
$error = null;
$foundContacts = [];
if (empty($email) && empty($phone) && empty($userID)) {
return ['contact_id' => null, 'error' => 'Не указаны контактные данные'];
}
// Получаем telegram username если указан userID
$tg_username = '';
if (!empty($userID)) {
$tg_username = get_user_meta($userID, 'tg_username', true);
}
// 1. Поиск по всем возможным комбинациям (включая userID)
$searchFilters = [];
if (!empty($userID)) {
$searchFilters[] = ['UF_CRM_1744373080655' => $userID];
}
if (!empty($phone)) $searchFilters[] = ['PHONE' => $phone];
if (!empty($email)) $searchFilters[] = ['EMAIL' => $email];
foreach ($searchFilters as $filter) {
$response = $this->b24_request('crm.contact.list', [
'filter' => $filter,
'select' => ['ID', 'NAME', 'PHONE', 'EMAIL', 'UF_CRM_1744373080655', 'IM']
]);
if (!empty($response['result'])) {
$foundContacts = array_merge($foundContacts, $response['result']);
}
}
// 2. Обработка найденных контактов
if (!empty($foundContacts)) {
$bestMatch = null;
$maxMatches = 0;
foreach ($foundContacts as $contact) {
$matches = 0;
if (!empty($userID) && isset($contact['UF_CRM_1744373080655']) && $contact['UF_CRM_1744373080655'] == $userID) {
$matches += 3;
}
if (!empty($phone) && $this->valueExists($contact['PHONE'] ?? [], $phone)) $matches++;
if (!empty($email) && $this->valueExists($contact['EMAIL'] ?? [], $email)) $matches++;
if ($matches > $maxMatches) {
$maxMatches = $matches;
$bestMatch = $contact;
}
}
if ($bestMatch) {
$contactId = $bestMatch['ID'];
$updateFields = [];
if ($name && (empty($bestMatch['NAME']) || $bestMatch['NAME'] != $name)) {
$updateFields['NAME'] = $name;
}
if (!empty($phone) && !$this->valueExists($bestMatch['PHONE'] ?? [], $phone)) {
$updateFields['PHONE'][] = ['VALUE' => $phone, 'VALUE_TYPE' => 'MOBILE'];
}
if (!empty($email) && !$this->valueExists($bestMatch['EMAIL'] ?? [], $email)) {
$updateFields['EMAIL'][] = ['VALUE' => $email, 'VALUE_TYPE' => 'WORK'];
}
// Добавляем Telegram если есть username и его еще нет в контакте
if (!empty($tg_username) && !imExists($bestMatch['IM'] ?? [], $tg_username)) {
$updateFields['IM'][] = [
'VALUE' => $tg_username,
'VALUE_TYPE' => 'TELEGRAM',
'TYPE_ID' => 'TELEGRAM'
];
}
if (!empty($utm)) {
$updateFields['UTM_SOURCE'] = $utm;
}
if (!empty($userID) && (!isset($bestMatch['UF_CRM_1744373080655']) || $bestMatch['UF_CRM_1744373080655'] != $userID)) {
$updateFields['UF_CRM_1744373080655'] = $userID;
}
if ($isSubscribe) {
$updateFields['UF_CRM_1744562461053'] = true;
}
if (!empty($updateFields)) {
$updateResponse = $this->b24_request('crm.contact.update', [
'id' => $contactId,
'fields' => $updateFields
]);
if (!empty($updateResponse['error'])) {
$error = 'Ошибка обновления: '.$updateResponse['error'];
}
}
}
}
// 3. Создание нового контакта если не найдено совпадений
else {
$utm_source = get_utm_data()['utm_source'] ?? '';
$utm_medium = get_utm_data()['utm_medium'] ?? '';
$utm_campaign = get_utm_data()['utm_campaign'] ?? '';
$utm_content = get_utm_data()['utm_content'] ?? '';
$utm_term = get_utm_data()['utm_term'] ?? '';
$newContact = [
'fields' => [
'NAME' => $name,
'SOURCE_ID' => "WEB",
'TYPE_ID' => "CLIENT",
'OPENED' => "Y",
'UTM_SOURCE' => $utm_source,
'UTM_MEDIUM' => $utm_medium,
'UTM_CAMPAIGN' => $utm_campaign,
'UTM_CONTENT' => $utm_content,
'UTM_TERM' => $utm_term,
]
];
if (!empty($phone)) {
$newContact['fields']['PHONE'][] = ['VALUE' => $phone, 'VALUE_TYPE' => 'MOBILE'];
}
if (!empty($email)) {
$newContact['fields']['EMAIL'][] = ['VALUE' => $email, 'VALUE_TYPE' => 'WORK'];
}
if (!empty($utm)) {
$newContact['fields']['UTM_SOURCE'] = $utm_source;
}
if (!empty($userID)) {
$newContact['fields']['UF_CRM_1744373080655'] = $userID;
}
if ($isSubscribe) {
$newContact['fields']['UF_CRM_1744562461053'] = true;
}
// Добавляем Telegram при создании нового контакта
if (!empty($tg_username)) {
$newContact['fields']['IM'][] = [
'VALUE' => $tg_username,
'VALUE_TYPE' => 'TELEGRAM',
'TYPE_ID' => 'TELEGRAM'
];
}
$response = $this->b24_request('crm.contact.add', $newContact);
$contactId = $response['result'] ?? null;
$error = $response['error'] ?? null;
}
return ['contact_id' => $contactId, 'error' => $error];
}
// Вспомогательная функция для проверки значений
function valueExists($items, $value) {
foreach ($items as $item) {
if ($item['VALUE'] == $value) return true;
}
return false;
}
function b24_request($method, $params = []) {
$url = WEBHOOK_URL . $method; // ТУТ ВСТАВЛЯЕМ ХУК ОТ ИНТЕГРАТОРА
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($params),
CURLOPT_TIMEOUT => 3, // Максимальное время выполнения запроса (в секундах)
CURLOPT_CONNECTTIMEOUT => 2, // Максимальное время ожидания соединения (в секундах)
]);
$response = curl_exec($curl);
if ($response === false) {
// Обработка ошибок
return ['error' => curl_error($curl)];
}
error_log('CURL URL: ' . $url);
error_log('CURL RESP: ' . $response);
curl_close($curl);
return json_decode($response, true);
}
function b24_send_lead($contactId, $msg, $stage, $fName, $order_total, $method, $form_title, $order_id) {
// Собираем UTM-метки из URL или POST данных
$utm_data = get_utm_data();
$utm_source = $utm_data['utm_source'] ?? '';
$utm_medium = $utm_data['utm_medium'] ?? '';
$utm_campaign = $utm_data['utm_campaign'] ?? '';
$utm_content = $utm_data['utm_content'] ?? '';
$utm_term = $utm_data['utm_term'] ?? '';
// Подготавливаем данные для сделки
$dealData = [
'fields' => [
'TITLE' => $form_title . ' - ' . $_SERVER['HTTP_HOST'],
"STAGE_ID"=> $stage,
'CONTACT_ID' => $contactId,
'CATEGORY_ID' => $fName,
'SOURCE_ID' => "WEB",
'SOURCE_DESCRIPTION' => '',
'UTM_SOURCE' => $utm_source,
'UTM_MEDIUM' => $utm_medium,
'UTM_CAMPAIGN' => $utm_campaign,
'UTM_CONTENT' => $utm_content,
'UTM_TERM' => $utm_term,
'COMMENTS' => $msg,
'OPPORTUNITY' => $order_total,
]
];
if ($order_id){
$dealData['fields']['UF_CRM_1745741833259'] = $order_id;
}
error_log('DEAL DATA: ' . json_encode($dealData));
// Отправляем данные в Bitrix24
$newDealResponse = $this->b24_request($method, $dealData);
error_log('DEAL RESP: ' . json_encode($newDealResponse));
// Обработка ответа
$error = null;
if (!empty($newDealResponse['error'])) {
$error = $newDealResponse['error'];
} elseif (empty($newDealResponse['result'])) {
$error = 'Ошибка создания сделки';
}
return [
'success' => empty($error),
'contact_id' => $contactId,
'error' => $error,
'utm' => [
'source' => $utm_source,
'medium' => $utm_medium,
'campaign' => $utm_campaign,
'content' => $utm_content,
'term' => $utm_term
]
];
}
// Function to add lead (wraps b24_get_or_create_contact and b24_send_lead)
function b24_add_lead($phone, $name, $email, $msg, $url, $stage, $fName, $order_total = 0, $userID = null, $method = 'crm.deal.add', $form_title, $isSubscribe = false, $order_id = '') {
$contact = $this->b24_get_or_create_contact($phone, $name, $email, $userID, $isSubscribe);
error_log(json_encode($contact));
if (!empty($contact['contact_id'])) {
$contactId = $contact['contact_id'];
} else {
return ['error' => $contact['error']];
}
$msg = $msg . "\nОтправлено со страницы: " . $url;
return $this->b24_send_lead($contactId, $msg, $stage, $fName, $order_total, $method, $form_title, $order_id);
}
// Function to update contact based on userID
function b24_update_contact_by_user_id($userID, $newData) {
if (empty($userID)) {
return ['success' => false, 'error' => 'Не указан ID пользователя'];
}
$user = get_user_by('ID', $userID);
if (!$user) {
return ['success' => false, 'error' => 'Пользователь не найден'];
}
// Получаем telegram username
$tg_username = get_user_meta($userID, 'tg_username', true);
// Ищем контакт по ID пользователя
$response = $this->b24_request('crm.contact.list', [
'filter' => ['UF_CRM_1744373080655' => $userID],
'select' => ['ID', 'NAME', 'PHONE', 'EMAIL', 'UF_CRM_1744373080655', 'IM', 'UF_CRM_1744562461053']
]);
if (empty($response['result'])) {
return ['success' => false, 'error' => 'Контакт не найден в Bitrix24'];
}
$contact = $response['result'][0];
$contactId = $contact['ID'];
$updateFields = [];
// Update name if changed
if (isset($newData['name']) && $newData['name'] !== $contact['NAME']) {
$updateFields['NAME'] = $newData['name'];
}
// Update phone if changed
if (isset($newData['phone'])) {
$phoneExists = false;
foreach ($contact['PHONE'] ?? [] as $phoneItem) {
if ($phoneItem['VALUE'] === $newData['phone']) {
$phoneExists = true;
break;
}
}
if (!$phoneExists) {
$updateFields['PHONE'] = [['VALUE' => $newData['phone'], 'VALUE_TYPE' => 'MOBILE']];
}
}
// Update email if changed
if (isset($newData['email'])) {
$emailExists = false;
foreach ($contact['EMAIL'] ?? [] as $emailItem) {
if ($emailItem['VALUE'] === $newData['email']) {
$emailExists = true;
break;
}
}
if (!$emailExists) {
$updateFields['EMAIL'] = [['VALUE' => $newData['email'], 'VALUE_TYPE' => 'WORK']];
}
}
// Update Telegram if changed
if (!empty($tg_username) && !imExists($contact['IM'] ?? [], $tg_username)) {
$updateFields['IM'][] = [
'VALUE' => $tg_username,
'VALUE_TYPE' => 'TELEGRAM',
'TYPE_ID' => 'TELEGRAM'
];
}
if (empty($updateFields)) {
return ['success' => true, 'message' => 'Нет изменений для обновления'];
}
// Send update request
$updateResponse = $this->b24_request('crm.contact.update', [
'id' => $contactId,
'fields' => $updateFields
]);
if (!empty($updateResponse['error'])) {
return ['success' => false, 'error' => 'Ошибка обновления: '.$updateResponse['error']];
}
return ['success' => true, 'contact_id' => $contactId];
}
}
class zohoHandler extends FormHandler {
public function handle($data, $crmData) {
// Логика отправки в HubSpot
error_log("Отправка в Zoho: " . json_encode($data));
return parent::handle($data, $crmData);
}
}
class tgHandler extends FormHandler {
public function handle($data, $crmData) {
global $site_env;
if ($site_env->site_region == 'ru'){
$botToken = '7689949404:AAHLTKmopffoNkndHJt-rOmAIZ7Hb6aKf80';
$chatId = '-1002591296904';
}
else if ($site_env->site_region == 'ae'){
$botToken = '7589204557:AAHh2qa5mUwRBq4fUyjQzqARpk4jDfUu5Yc';
$chatId = '-1002537433508';
}
// Форматируем данные для отправки в Telegram
$message = strip_tags($this->formatData($data));
// Отправляем сообщение в Telegram
$this->sendToTelegram($botToken, $chatId, $message);
// Вызываем следующий обработчик в цепочке
return parent::handle($data, $crmData);
}
// Функция для отправки данных в Telegram
private function sendToTelegram($botToken, $chatId, $message) {
$url = "https://api.telegram.org/bot$botToken/sendMessage";
$maxLength = 4096;
// Разбиваем сообщение на части, если оно длиннее лимита
$messages = str_split($message, $maxLength);
foreach ($messages as $msgPart) {
$data = [
'chat_id' => $chatId,
'text' => $msgPart,
'parse_mode' => 'HTML',
];
$options = [
'http' => [
'method' => 'POST',
'header' => "Content-Type: application/x-www-form-urlencoded\r\n",
'content' => http_build_query($data),
],
];
$context = stream_context_create($options);
$response = file_get_contents($url, false, $context);
// Логируем HTTP-код и тело ответа
$httpCode = isset($http_response_header[0]) ? $http_response_header[0] : 'No HTTP response';
}
}
}
class emailHandler extends FormHandler {
public function handle($data, $crmData) {
$to = 'pro@cosmopet.shop'; // Укажите email, на который нужно отправить данные
$subject = 'Форма обработана'; // Тема письма
$message = $this->formatData($data); // Форматируем данные
$headers = ['Content-Type: text/plain; charset=UTF-8']; // Заголовки письма
// Отправляем письмо
wp_mail($to, $subject, $message, $headers);
// Вызываем следующий обработчик в цепочке
return parent::handle($data, $crmData);
}
}
class FormHandlerFactory {
public static function getHandler(array $enabledHandlers) {
global $site_env;
$handler = null;
if (in_array('email', $enabledHandlers)) {
$handler = new emailHandler($handler);
}
if (in_array('zoho', $enabledHandlers)) {
$handler = new zohoHandler($handler);
}
if (in_array('tg', $enabledHandlers)) {
$handler = new tgHandler($handler);
}
if (in_array('b24', $enabledHandlers) && $site_env->site_region == 'ru') {
$handler = new b24Handler($handler);
}
return $handler ?: new DefaultHandler();
}
}
// // Пример обработки обновления профиля пользователя
// add_action('profile_update', 'handle_profile_update', 10, 2);
// function handle_profile_update($userID, $old_user_data) {
// $user = get_user_by('ID', $userID);
// $email = $user->user_email;
// $phone = get_user_meta($userID, 'billing_phone', true);
// $first_name = get_user_meta($userID, 'first_name', true);
// $last_name = get_user_meta($userID, 'last_name', true);
// $name = trim($first_name . ' ' . $last_name);
// $newData = [
// 'name' => $name,
// 'email' => $email,
// 'phone' => $phone,
// ];
// $result = b24_update_contact_by_user_id($userID, $newData);
// if (!$result['success']) {
// error_log('Ошибка обновления контакта в Bitrix24: ' . $result['error']);
// }
// }
// add_action('woocommerce_thankyou', 'add_b24_tracking_script', 10, 1);
// function add_b24_tracking_script($order_id) {
// if (!$order_id) return;
// $order = wc_get_order($order_id);
// echo '<script>
// (window.b24order = window.b24order || []).push({
// id: "' . $order_id . '",
// sum: "' . $order->get_total() . '"
// });
// </script>';
// }
function get_utm_data() {
$utm_data = [];
$utm_params = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'];
foreach ($utm_params as $param) {
$utm_data[$param] = $_GET[$param] ?? $_COOKIE[$param] ?? '';
}
return $utm_data;
}
// Функция для сохранения UTM в куки (если нужно хранить между сессиями)
function save_utm_to_cookies() {
$utm_params = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'];
foreach ($utm_params as $param) {
if (isset($_GET[$param])) {
setcookie($param, $_GET[$param], time() + 3600 * 24 * 30, '/');
}
}
}
save_utm_to_cookies();