Files
crm.clientright.ru/include/Webservices/UpdateWebClaimV2.php

232 lines
11 KiB
PHP
Raw Normal View History

<?php
/*********************************************************************************
* API для обновления существующей Заявки (HelpDesk) из Web-формы (V2 - JSON)
* Принимает ticket_id + claim_json с полями для обновления (те же ключи, что в CreateWebClaimV2)
* Автор: Фёдор, 2026-01-23
********************************************************************************/
include_once 'include/Webservices/Query.php';
include_once 'modules/Users/Users.php';
require_once('include/Webservices/Utils.php');
require_once 'include/Webservices/Revise.php';
require_once 'includes/Loader.php';
vimport ('includes.runtime.Globals');
vimport ('includes.runtime.BaseModel');
vimport ('includes.runtime.LanguageHandler');
/**
* Обновление заявки (тикета) по ID
*
* @param string $ticket_id - ID заявки (число или 17x123)
* @param string $claim_json - JSON с полями для обновления (только переданные поля будут обновлены)
* @param object $user - пользователь (опционально)
* @return array - {"success": true, "ticket_id": "...", "ticket_number": "..."}
*/
function vtws_updatewebclaimv2($ticket_id, $claim_json, $user = false) {
$logstring = date("Y-m-d H:i:s").' REQUEST: ticket_id='.$ticket_id.' '.json_encode($_REQUEST);
file_put_contents('logs/UpdateWebClaimV2.log', $logstring.PHP_EOL, FILE_APPEND);
if (empty($ticket_id)) {
$logstring = date("Y-m-d H:i:s").' Не передан параметр ticket_id';
file_put_contents('logs/UpdateWebClaimV2.log', $logstring.PHP_EOL, FILE_APPEND);
throw new WebServiceException(WebServiceErrorCode::$INVALIDID, "Не передан параметр ticket_id");
}
if ($claim_json === '' || $claim_json === null) {
$logstring = date("Y-m-d H:i:s").' Не передан параметр claim_json';
file_put_contents('logs/UpdateWebClaimV2.log', $logstring.PHP_EOL, FILE_APPEND);
throw new WebServiceException(WebServiceErrorCode::$INVALIDID, "Не передан параметр claim_json");
}
// Параметр может прийти строкой (JSON) или уже массивом (тип encoded в БД)
if (is_array($claim_json)) {
$claimData = $claim_json;
} else {
$claimData = json_decode($claim_json, true);
if (json_last_error() !== JSON_ERROR_NONE) {
$cleanedJson = trim($claim_json);
$cleanedJson = preg_replace('/^[^{]*/', '', $cleanedJson);
$cleanedJson = preg_replace('/[^}]*$/', '', $cleanedJson);
$claimData = json_decode($cleanedJson, true);
if (json_last_error() !== JSON_ERROR_NONE) {
$logstring = date("Y-m-d H:i:s").' Ошибка парсинга JSON: '.json_last_error_msg();
file_put_contents('logs/UpdateWebClaimV2.log', $logstring.PHP_EOL, FILE_APPEND);
throw new WebServiceException(WebServiceErrorCode::$INVALIDID, "Ошибка парсинга JSON: ".json_last_error_msg());
}
}
}
$logstring = date("Y-m-d H:i:s").' claimData keys: '.implode(', ', array_keys($claimData)).PHP_EOL;
file_put_contents('logs/UpdateWebClaimV2.log', $logstring, FILE_APPEND);
global $adb, $current_user;
$ticketIdNumeric = preg_replace('/[^0-9]/', '', $ticket_id);
$ticketWsId = '17x' . $ticketIdNumeric;
// Проверяем, что запись существует и это HelpDesk
$check = $adb->pquery(
"SELECT e.crmid, e.setype FROM vtiger_crmentity e WHERE e.deleted = 0 AND e.crmid = ?",
array($ticketIdNumeric)
);
if (!$check || $adb->num_rows($check) === 0) {
$logstring = date("Y-m-d H:i:s").' Заявка с id='.$ticketIdNumeric.' не найдена';
file_put_contents('logs/UpdateWebClaimV2.log', $logstring.PHP_EOL, FILE_APPEND);
throw new WebServiceException(WebServiceErrorCode::$RECORDNOTFOUND, "Заявка не найдена");
}
$setype = $adb->query_result($check, 0, 'setype');
if ($setype !== 'HelpDesk') {
$logstring = date("Y-m-d H:i:s").' Запись '.$ticketIdNumeric.' не является заявкой (HelpDesk): '.$setype;
file_put_contents('logs/UpdateWebClaimV2.log', $logstring.PHP_EOL, FILE_APPEND);
throw new WebServiceException(WebServiceErrorCode::$INVALIDID, "Указанная запись не является заявкой");
}
$eventTypeMap = array(
'delay_flight' => 'Задержка рейса',
'cancel_flight' => 'Отмена рейса',
'miss_connection' => 'Пропуск стыковки',
'missed_connection' => 'Пропуск стыковки',
'delay_train' => 'Задержка поезда',
'cancel_train' => 'Отмена поезда',
'delay_ferry' => 'Задержка парома',
'cancel_ferry' => 'Отмена парома'
);
$element = array('id' => $ticketWsId);
// Маппинг полей из claim_json в поля CRM (только если ключ передан)
if (array_key_exists('ticket_title', $claimData)) {
$element['ticket_title'] = $claimData['ticket_title'];
}
if (array_key_exists('description', $claimData)) {
$element['description'] = $claimData['description'];
}
if (array_key_exists('ticketstatus', $claimData)) {
$element['ticketstatus'] = $claimData['ticketstatus'];
}
if (array_key_exists('project_id', $claimData) && $claimData['project_id'] !== '') {
$pid = preg_replace('/[^0-9]/', '', $claimData['project_id']);
$element['cf_2066'] = '33x' . $pid;
}
if (array_key_exists('contact_id', $claimData) && $claimData['contact_id'] !== '') {
$cid = preg_replace('/[^0-9]/', '', $claimData['contact_id']);
$element['contact_id'] = '12x' . $cid;
}
if (array_key_exists('cf_1726', $claimData)) {
$element['cf_1726'] = $claimData['cf_1726'];
$element['cf_2650'] = isset($eventTypeMap[$claimData['cf_1726']]) ? $eventTypeMap[$claimData['cf_1726']] : 'Цифровой адвокат ЕРВ';
}
if (array_key_exists('cf_2566', $claimData)) {
$element['cf_2566'] = $claimData['cf_2566'];
}
if (array_key_exists('cf_2568', $claimData)) {
$element['cf_2568'] = $claimData['cf_2568'];
}
if (array_key_exists('cf_departure_flight', $claimData)) {
$element['cf_2630'] = $claimData['cf_departure_flight'];
}
if (array_key_exists('cf_departure_date', $claimData)) {
$element['cf_2632'] = $claimData['cf_departure_date'];
}
if (array_key_exists('cf_1909', $claimData)) {
$element['cf_2636'] = $claimData['cf_1909'];
}
if (array_key_exists('cf_2502', $claimData)) {
$element['cf_2572'] = $claimData['cf_2502'];
}
if (array_key_exists('code', $claimData)) {
$element['cf_2574'] = $claimData['code'];
}
if (array_key_exists('cf_1885', $claimData)) {
$element['cf_2642'] = $claimData['cf_1885'];
}
if (array_key_exists('ip', $claimData)) {
$element['cf_2634'] = $claimData['ip'];
}
if (array_key_exists('region', $claimData)) {
$element['cf_2640'] = $claimData['region'];
}
if (array_key_exists('source', $claimData)) {
$element['cf_2638'] = $claimData['source'];
}
if (array_key_exists('cf_2508', $claimData)) {
$element['cf_2508'] = $claimData['cf_2508'];
}
if (array_key_exists('cf_2648', $claimData)) {
$element['cf_2648'] = $claimData['cf_2648'];
}
if (array_key_exists('currency_code', $claimData)) {
$element['cf_2652'] = $claimData['currency_code'];
}
if (array_key_exists('course', $claimData) && $claimData['course'] !== '' && $claimData['course'] !== null) {
$element['cf_2654'] = sprintf('%.4f', floatval($claimData['course']));
}
// Любое поле cf_XXXX из claim_json прокидываем в CRM как есть (в т.ч. cf_2662 и др.)
foreach ($claimData as $k => $v) {
if (preg_match('/^cf_\d+$/', $k) && !array_key_exists($k, $element)) {
$element[$k] = $v;
}
}
// Если передан только id — нет полей для обновления
if (count($element) === 1) {
$ticketNoRes = $adb->pquery("SELECT ticket_no FROM vtiger_troubletickets WHERE ticketid = ?", array($ticketIdNumeric));
$ticketNo = $ticketNoRes && $adb->num_rows($ticketNoRes) ? $adb->query_result($ticketNoRes, 0, 'ticket_no') : 'N/A';
$logstring = date("Y-m-d H:i:s").' В claim_json нет известных полей для обновления. Получены ключи: '.implode(', ', array_keys($claimData));
file_put_contents('logs/UpdateWebClaimV2.log', $logstring.PHP_EOL, FILE_APPEND);
return array(
'success' => true,
'ticket_id' => $ticketIdNumeric,
'ticket_number' => $ticketNo,
'updated' => false,
'message' => 'В claim_json не найдено полей для обновления. Проверьте логи UpdateWebClaimV2.log — там перечень полученных ключей.'
);
}
$logstring = date('Y-m-d H:i:s').' Элемент для revise: '.json_encode($element).PHP_EOL;
file_put_contents('logs/UpdateWebClaimV2.log', $logstring, FILE_APPEND);
try {
$entity = vtws_revise($element, $current_user);
} catch (WebServiceException $e) {
$logstring = date('Y-m-d H:i:s').' Ошибка revise: '.$e->getMessage().PHP_EOL;
file_put_contents('logs/UpdateWebClaimV2.log', $logstring, FILE_APPEND);
throw $e;
}
// Курс (cf_2654) — сохраняем напрямую в БД для точности 4 знака (как в CreateWebClaimV2)
if (array_key_exists('course', $claimData) && $claimData['course'] !== '' && $claimData['course'] !== null) {
$courseFormatted = sprintf('%.4f', floatval($claimData['course']));
try {
$adb->pquery("UPDATE vtiger_ticketcf SET cf_2654 = ? WHERE ticketid = ?", array($courseFormatted, $ticketIdNumeric));
} catch (Exception $ex) {
file_put_contents('logs/UpdateWebClaimV2.log', date('Y-m-d H:i:s').' Предупреждение: курс '.$courseFormatted.' — '.$ex->getMessage().PHP_EOL, FILE_APPEND);
}
}
$ticketNumber = isset($entity['ticket_no']) ? $entity['ticket_no'] : 'N/A';
$logstring = date('Y-m-d H:i:s').' Заявка обновлена: id='.$ticketIdNumeric.' ticket_no='.$ticketNumber.PHP_EOL;
file_put_contents('logs/UpdateWebClaimV2.log', $logstring, FILE_APPEND);
return array(
'success' => true,
'ticket_id' => $ticketIdNumeric,
'ticket_number' => $ticketNumber,
'updated' => true
);
}
/*
Регистрация операции в БД (если ещё не добавлено):
INSERT INTO vtiger_ws_operation (name, handler_path, handler_method, type, prelogin)
VALUES ('updatewebclaimv2', 'include/Webservices/UpdateWebClaimV2.php', 'vtws_updatewebclaimv2', 'POST', 0);
INSERT INTO vtiger_ws_operation_parameters (operationid, name, type, sequence)
SELECT operationid, 'ticket_id', 'string', 1 FROM vtiger_ws_operation WHERE name = 'updatewebclaimv2';
INSERT INTO vtiger_ws_operation_parameters (operationid, name, type, sequence)
SELECT operationid, 'claim_json', 'string', 2 FROM vtiger_ws_operation WHERE name = 'updatewebclaimv2';
*/