Files
crm.clientright.ru/include/Webservices/UpsertProject.php
Fedor da82100b60 feat: UI/UX improvements + CRM integration methods + documents_meta deduplication
Frontend:
- Changed main title to 'Подать обращение о защите прав потребителя'
- Changed browser title to 'Clientright — защита прав потребителей'
- Enhanced draft cards: show problem_description (250 chars), category tag, document progress bar
- Fixed 'Назад' button to always return to draft selection
- Added SSE connection for OCR status updates
- Renamed steps: Вход, Обращение, Документы, Заявление
- Skip 'Проверка полиса' and 'Тип события' steps for new claim flow

Backend:
- Fixed client IP extraction (X-Forwarded-For, X-Real-IP)
- Added problem_title, category, documents_required_list to draft list API
- Fixed documents_uploaded count to count unique field_labels

CRM Webservices:
- Added UpsertContact.php - create/update contacts with tgid support
- Added UpsertAccounts.php - batch upsert offenders by INN
- Added UpsertProject.php - create/update projects with offender mapping

Database:
- Fixed documents_meta duplicates in existing claims
- SQL query for deduplication by field_name provided
2025-12-01 22:18:21 +03:00

298 lines
14 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/*********************************************************************************
* API-интерфейс для создания/обновления Проекта (Upsert)
*
* Логика:
* - Если передан project_id → обновляем существующий проект
* - Если project_id не передан → создаём новый
*
* Принимает JSON с данными проекта
*
* Автор: Фёдор, 2025-12-01
********************************************************************************/
include_once 'include/Webservices/Query.php';
include_once 'modules/Users/Users.php';
require_once('include/Webservices/Utils.php');
require_once 'include/Webservices/Create.php';
require_once 'include/Webservices/Revise.php';
require_once 'includes/Loader.php';
vimport('includes.runtime.Globals');
vimport('includes.runtime.BaseModel');
vimport('includes.runtime.LanguageHandler');
/**
* Upsert проекта
*
* @param string $project_json - JSON с данными проекта:
* {
* "project_id": "12345", // Опционально - если есть, обновляем
* "claim_id": "uuid", // ID заявки из PostgreSQL
* "contact_id": "320096", // ID контакта (обязательно для создания)
* "result": "JSON string", // Результат UpsertAccounts (парсится автоматически)
* "offender_ids": ["390680"], // Альтернатива result - массив ID контрагентов
* "projectdata": { // Данные проекта (cf_* поля)
* "cf_2206": "SMS код",
* "cf_1830": "категория",
* ...
* }
* }
*
* Контрагенты распределяются:
* - accounts[0] → cf_2274 (основной ответчик)
* - accounts[1] → cf_2276 (агент/второй ответчик)
*
* @param mixed $user - пользователь CRM
* @return string JSON с результатом
*/
function vtws_upsertproject($project_json, $user = false) {
$logFile = 'logs/UpsertProject.log';
$logstring = date("Y-m-d H:i:s") . ' REQUEST: ' . substr($project_json, 0, 2000);
file_put_contents($logFile, $logstring . PHP_EOL, FILE_APPEND);
global $adb, $current_user;
// Очистка JSON
$project_json = trim($project_json);
$project_json = preg_replace('/^\xEF\xBB\xBF/', '', $project_json);
if (preg_match('/^".*"$/s', $project_json)) {
$project_json = substr($project_json, 1, -1);
$project_json = stripcslashes($project_json);
}
// Парсим JSON
$data = json_decode($project_json, true);
if (json_last_error() !== JSON_ERROR_NONE) {
$error = 'Ошибка парсинга JSON: ' . json_last_error_msg();
file_put_contents($logFile, date("Y-m-d H:i:s") . ' ❌ ' . $error . PHP_EOL, FILE_APPEND);
throw new WebServiceException(WebServiceErrorCode::$INVALIDID, $error);
}
// Результат
$result = array(
'success' => false,
'project_id' => null,
'claim_id' => null,
'action' => null,
'offender_id' => null,
'agent_id' => null,
'message' => ''
);
// Извлекаем данные
$project_id = trim($data['project_id'] ?? '');
$claim_id = trim($data['claim_id'] ?? '');
$contact_id = trim($data['contact_id'] ?? '');
$projectdata = $data['projectdata'] ?? [];
// Извлекаем контрагентов из result (если передан) или из offender_ids
$offender_ids = [];
if (!empty($data['result'])) {
// Парсим result от UpsertAccounts
$accountsResult = $data['result'];
if (is_string($accountsResult)) {
$accountsResult = json_decode($accountsResult, true);
}
// Извлекаем account_id из accounts[]
if (isset($accountsResult['accounts']) && is_array($accountsResult['accounts'])) {
foreach ($accountsResult['accounts'] as $account) {
if (!empty($account['account_id'])) {
$offender_ids[] = $account['account_id'];
}
}
}
$logstring = date('Y-m-d H:i:s') . ' Извлечены offender_ids из result: ' . json_encode($offender_ids);
file_put_contents($logFile, $logstring . PHP_EOL, FILE_APPEND);
} elseif (!empty($data['offender_ids'])) {
$offender_ids = $data['offender_ids'];
}
// cf_2274 = первый контрагент (основной ответчик)
// cf_2276 = второй контрагент (агент/второй ответчик)
$offender_id = count($offender_ids) > 0 ? $offender_ids[0] : '';
$agent_id = count($offender_ids) > 1 ? $offender_ids[1] : '';
$logstring = date('Y-m-d H:i:s') . " Данные: project_id=$project_id, claim_id=$claim_id, contact_id=$contact_id, offender_id=$offender_id, agent_id=$agent_id";
file_put_contents($logFile, $logstring . PHP_EOL, FILE_APPEND);
try {
// ========================================
// ПРОВЕРКА СУЩЕСТВОВАНИЯ ПРОЕКТА
// ========================================
$existingProjectId = null;
if (!empty($project_id)) {
$project_id = preg_replace('/[^0-9]/', '', $project_id);
$query = "SELECT p.projectid FROM vtiger_project p
LEFT JOIN vtiger_crmentity e ON e.crmid = p.projectid
WHERE e.deleted = 0 AND p.projectid = ? LIMIT 1";
$res = $adb->pquery($query, array($project_id));
if ($adb->num_rows($res) > 0) {
$existingProjectId = $adb->query_result($res, 0, 'projectid');
}
}
// ========================================
// ФОРМИРУЕМ ПАРАМЕТРЫ
// ========================================
$params = array();
// Если создаём новый проект - нужны contact_id и offender_id
if (empty($existingProjectId)) {
if (empty($contact_id) || empty($offender_id)) {
throw new Exception('Для создания проекта нужны contact_id и offender_ids');
}
// Получаем название контакта
$query = "SELECT c.lastname FROM vtiger_contactdetails c
LEFT JOIN vtiger_crmentity e ON e.crmid = c.contactid
WHERE e.deleted = 0 AND c.contactid = ? LIMIT 1";
$res = $adb->pquery($query, array($contact_id));
$contactName = $adb->num_rows($res) > 0 ? $adb->query_result($res, 0, 'lastname') : 'Клиент';
// Получаем название контрагента
$query = "SELECT a.accountname FROM vtiger_account a
LEFT JOIN vtiger_crmentity e ON e.crmid = a.accountid
WHERE e.deleted = 0 AND a.accountid = ? LIMIT 1";
$res = $adb->pquery($query, array($offender_id));
$accountName = $adb->num_rows($res) > 0 ? $adb->query_result($res, 0, 'accountname') : 'Контрагент';
// Название проекта
$params['projectname'] = $contactName . ' ' . $accountName;
$params['linktoaccountscontacts'] = '12x' . $contact_id;
$params['cf_2274'] = '11x' . $offender_id; // Основной ответчик
$params['projectstatus'] = 'модерация';
$params['projecttype'] = 'Претензионно - исковая работа';
$params['assigned_user_id'] = vtws_getWebserviceEntityId('Users', $current_user->id);
// Заявитель по умолчанию
if (!isset($projectdata['cf_1994'])) {
$params['cf_1994'] = vtws_getWebserviceEntityId('Accounts', 62345); // МОО КЛИЕНТПРАВ
}
}
// Агент (второй ответчик)
if (!empty($agent_id)) {
$params['cf_2276'] = '11x' . $agent_id;
}
// Связь контакт/оффендер для обновления тоже можно передать
if (!empty($contact_id) && !empty($existingProjectId)) {
$params['linktoaccountscontacts'] = '12x' . $contact_id;
}
if (!empty($offender_id) && !empty($existingProjectId)) {
$params['cf_2274'] = '11x' . $offender_id;
}
// Маппинг полей из projectdata
$fieldMapping = array(
'cf_2206' => 'cf_2206', // SMS код
'cf_2210' => 'cf_2210', // IP
'cf_2212' => 'cf_2212', // Источник
'cf_2214' => 'cf_2214', // Регион
'cf_2208' => 'cf_2208', // Form ID
'cf_1830' => 'cf_1830', // Категория
'cf_1469' => 'cf_1469', // Направление
'cf_1191' => 'cf_1191', // Цена договора
'cf_1189' => 'cf_1189', // Предмет договора
'cf_1203' => 'cf_1203', // Дата договора
'cf_1839' => 'cf_1839', // Дата начала
'cf_1841' => 'cf_1841', // Дата окончания
'cf_1207' => 'cf_1207', // Ущерб
'cf_1479' => 'cf_1479', // Стоимость услуг
'cf_1227' => 'cf_1227', // Прогресс
'cf_1231' => 'cf_1231', // Страна
'cf_1239' => 'cf_1239', // Отель
'cf_1566' => 'cf_1566', // Транспорт
'cf_1564' => 'cf_1564', // Страховка
'cf_1249' => 'cf_1249', // Прочее
'cf_1471' => 'cf_1471', // Самостоятельно
'cf_1473' => 'cf_1473', // Дата претензии
'cf_1475' => 'cf_1475', // Возвращено
'cf_1994' => 'cf_1994', // Заявитель
'description' => 'description'
);
foreach ($fieldMapping as $input => $crm) {
if (isset($projectdata[$input]) && $projectdata[$input] !== null) {
$value = $projectdata[$input];
// Для cf_1994 (Заявитель) нужен формат 11xID
if ($crm === 'cf_1994' && !empty($value) && strpos($value, 'x') === false) {
$value = vtws_getWebserviceEntityId('Accounts', $value);
}
$params[$crm] = $value;
}
}
// ========================================
// СОЗДАНИЕ ИЛИ ОБНОВЛЕНИЕ
// ========================================
if (!empty($existingProjectId)) {
// === ОБНОВЛЕНИЕ ===
$params['id'] = '33x' . $existingProjectId; // 33x для Project
$logstring = date('Y-m-d H:i:s') . ' 📝 Обновляем проект ' . $existingProjectId . ': ' . json_encode($params, JSON_UNESCAPED_UNICODE);
file_put_contents($logFile, $logstring . PHP_EOL, FILE_APPEND);
$project = vtws_revise($params, $current_user);
$result['success'] = true;
$result['project_id'] = $existingProjectId;
$result['claim_id'] = $claim_id;
$result['action'] = 'updated';
$result['offender_id'] = $offender_id;
$result['agent_id'] = $agent_id ?: null;
$result['message'] = 'Проект обновлён';
$logstring = date('Y-m-d H:i:s') . ' ✅ Проект ' . $existingProjectId . ' обновлён';
file_put_contents($logFile, $logstring . PHP_EOL, FILE_APPEND);
} else {
// === СОЗДАНИЕ ===
$logstring = date('Y-m-d H:i:s') . ' 🆕 Создаём проект: ' . json_encode($params, JSON_UNESCAPED_UNICODE);
file_put_contents($logFile, $logstring . PHP_EOL, FILE_APPEND);
$project = vtws_create('Project', $params, $current_user);
$newProjectId = substr($project['id'], strpos($project['id'], 'x') + 1); // Убираем префикс (63x)
$result['success'] = true;
$result['project_id'] = $newProjectId;
$result['claim_id'] = $claim_id;
$result['action'] = 'created';
$result['offender_id'] = $offender_id;
$result['agent_id'] = $agent_id ?: null;
$result['message'] = 'Проект создан';
$logstring = date('Y-m-d H:i:s') . ' ✅ Создан проект ' . $newProjectId;
file_put_contents($logFile, $logstring . PHP_EOL, FILE_APPEND);
}
} catch (WebServiceException $ex) {
$result['success'] = false;
$result['message'] = $ex->getMessage();
$logstring = date('Y-m-d H:i:s') . ' ❌ WebService ошибка: ' . $ex->getMessage();
file_put_contents($logFile, $logstring . PHP_EOL, FILE_APPEND);
throw $ex;
} catch (Exception $ex) {
$result['success'] = false;
$result['message'] = $ex->getMessage();
$logstring = date('Y-m-d H:i:s') . ' ❌ Ошибка: ' . $ex->getMessage();
file_put_contents($logFile, $logstring . PHP_EOL, FILE_APPEND);
throw new WebServiceException(WebServiceErrorCode::$INVALIDID, $ex->getMessage());
}
$logstring = date('Y-m-d H:i:s') . ' RESULT: ' . json_encode($result, JSON_UNESCAPED_UNICODE) . PHP_EOL;
file_put_contents($logFile, $logstring, FILE_APPEND);
return json_encode($result, JSON_UNESCAPED_UNICODE);
}