Files
Fedor ac7467f0b4 Major CRM updates: AI Assistant, Court Status API, S3 integration improvements, and extensive file storage system
- Added comprehensive AI Assistant system (aiassist/ directory):
  * Vector search and embedding capabilities
  * Typebot proxy integration
  * Elastic search functionality
  * Message classification and chat history
  * MCP proxy for external integrations

- Implemented Court Status API (GetCourtStatus.php):
  * Real-time court document status checking
  * Integration with external court systems
  * Comprehensive error handling and logging

- Enhanced S3 integration:
  * Improved file backup system with metadata
  * Batch processing capabilities
  * Enhanced error logging and recovery
  * Copy operations with URL fixing

- Added Telegram contact creation API
- Improved error logging across all modules
- Enhanced callback system for AI responses
- Extensive backup file storage with timestamps
- Updated documentation and README files

- File storage improvements:
  * Thousands of backup files with proper metadata
  * Fix operations for broken file references
  * Project-specific backup and recovery systems
  * Comprehensive file integrity checking

Total: 26,461+ files added/modified including AWS SDK, vendor dependencies, and extensive backup system.
2025-10-16 11:17:21 +03:00

696 lines
23 KiB
PHP
Raw Permalink 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
/**
* Created by JetBrains PhpStorm.
* User: Stefan Warnat <support@stefanwarnat.de>
* Date: 29.07.13
* Time: 18:07
*/
if(!function_exists("wf_get_entity")) {
function wf_get_entity($entity_id, $module_name = false) {
$object = \Workflow\VTEntity::getForId($entity_id, $module_name);
$data = $object->getData();
if(is_object($data) && method_exists($data, 'getColumnFields')) {
return $data->getColumnFields();
} else {
return $data;
}
}
}
if(!function_exists("wf_get_user")) {
function wf_get_user($userid) {
$userModel = \Users_Record_Model::getInstanceById($userid, 'Users');
return $userModel->getData();
}
}
if(!function_exists("wf_recordlist")) {
function wf_recordlist($listId) {
$context = \Workflow\ExpressionParser::$INSTANCE->getContext();
$env = $context->getEnvironment($listId);
$html = $env['html'];
return $html;
}
}
if(!function_exists("wf_json_encode")) {
function wf_json_encode($value) {
echo json_encode($value);
}
}
if(!function_exists('wf_create_password')) {
function wf_create_password( $length = 8 ) {
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!_-=;!_-=;!_-=;";
$password = substr( str_shuffle( $chars ), 0, $length );
return $password;
}
}
if(!function_exists("wf_getcampaignstatus")) {
function wf_getcampaignstatus($campaignId, $recordModule, $recordId) {
if($recordModule == 'Leads') {
$sql = 'SELECT data.campaignrelstatusid, campaignrelstatus FROM vtiger_campaignleadrel as data LEFT JOIN vtiger_campaignrelstatus ON (vtiger_campaignrelstatus.campaignrelstatusid = data.campaignrelstatusid) WHERE campaignid = ? AND leadid = ?';
} elseif($recordModule == 'Contacts') {
$sql = 'SELECT data.campaignrelstatusid, campaignrelstatus FROM vtiger_campaigncontrel as data LEFT JOIN vtiger_campaignrelstatus ON (vtiger_campaignrelstatus.campaignrelstatusid = data.campaignrelstatusid) WHERE campaignid = ? AND contactid = ?';
} elseif($recordModule == 'Accounts') {
$sql = 'SELECT data.campaignrelstatusid, campaignrelstatus FROM vtiger_campaignaccountrel as data LEFT JOIN vtiger_campaignrelstatus ON (vtiger_campaignrelstatus.campaignrelstatusid = data.campaignrelstatusid) WHERE campaignid = ? AND accountid = ?';
} else {
return 0;
}
$adb = \PearDatabase::getInstance();
$result = $adb->pquery($sql, array(intval($campaignId), $recordId));
if($adb->num_rows($result) > 0) {
$data = $adb->fetchByAssoc($result);
if($data['campaignrelstatusid'] == '1') {
return '';
} else {
return $data['campaignrelstatus'];
}
}
return 0;
}
}
if(!function_exists("wf_fieldvalue")) {
function wf_fieldvalue($crmid, $moduleName, $field) {
$entity = \Workflow\VTEntity::getForId($crmid, $moduleName);
if($entity === false) {
throw new \Exception('You try to use wf_fieldvalue with a wrong crmid ('.$crmid.')');
}
return $entity->get($field);
}
}
if(!function_exists("wf_date")) {
function wf_date($value, $interval, $format = "Y-m-d") {
if(empty($interval)) {
$dateValue = strtotime($value);
} else {
$dateValue = strtotime($interval, strtotime($value));
}
return date($format, $dateValue);
}
}
if(!function_exists("wf_converttointernaldate")) {
function wf_converttointernaldate($value, $srcFormat) {
$dateTime = \DateTime::createFromFormat($srcFormat, $value);
$parts = explode(' ', $value);
if(count($parts) == 1) {
return $dateTime->format('Y-m-d');
} else {
return $dateTime->format('Y-m-d H:i:s');
}
}
}
if(!function_exists("wf_salutation")) {
function wf_salutation($value, $language = false) {
global $adb, $current_language;
if($language === false) {
$language = $current_language;
}
$mod_strings = array();
require("modules/Contacts/language/".$language.".lang.php");
return $mod_strings[$value];
}
}
if(!function_exists("wf_log")) {
function wf_log($value) {
Workflow2::$currentBlockObj->addStat($value);
}
}
if(!function_exists("wf_getenv")) {
function wf_getenv($key) {
\Workflow2::$currentWorkflowObj->getContext()->getEnvironment($key);
}
}
if(!function_exists("wf_setenv")) {
function wf_setenv($key, $value) {
\Workflow2::$currentWorkflowObj->getContext()->setEnvironment($key, $value);
// var_dump(\Workflow2::$currentWorkflowObj->getContext()->getEnvironment());
}
}
if(!function_exists("wf_setfield")) {
function wf_setfield($field, $value) {
VTWfExpressionParser::$INSTANCE->getContext()->set($field, $value);
}
}
if(!function_exists("wf_save_record")) {
function wf_save_record() {
VTWfExpressionParser::$INSTANCE->getContext()->save();
}
}
if(!function_exists("wf_recordurl")) {
function wf_recordurl($crmid) {
$crmid = intval($crmid);
$objTMP = \Workflow\VTEntity::getForId($crmid);
global $site_URL;
return $site_URL.'/index.php?module='.$objTMP->getModuleName().'&view=Detail&record='.$crmid;
}
}
if(!function_exists("wf_recordlink")) {
function wf_recordlink($crmid, $text = '') {
$url = wf_recordurl($crmid);
return '<a href="'.$url.'">'.$text.'</a>';
}
}
if(!function_exists("wf_dbquery")) {
function wf_dbquery($query) {
$adb = PearDatabase::getInstance();
$result = $adb->query($query, false);
$errorNo = $adb->database->ErrorNo();
if(!empty($errorNo)) {
Workflow2::error_handler(E_NONBREAK_ERROR, $adb->database->ErrorMsg());
} else {
if($adb->num_rows($result) > 0) {
$row = $adb->fetchByAssoc($result);
return $row;
} else {
return array();
}
}
# need vtiger Database to reset Selected DB in the case the query changed this
global $dbconfig;
$adb->database->SelectDB($dbconfig['db_name']);
}
}
if(!function_exists("wf_dbSelectAll")) {
function wf_dbSelectAll($query) {
$adb = PearDatabase::getInstance();
$result = $adb->query($query, false);
$errorNo = $adb->database->ErrorNo();
if(!empty($errorNo)) {
Workflow2::error_handler(E_NONBREAK_ERROR, $adb->database->ErrorMsg());
} else {
if($adb->num_rows($result) > 0) {
$return = array();
while($row = $adb->fetchByAssoc($result)) {
$return[] = $row;
}
return $return;
} else {
return array();
}
}
# need vtiger Database to reset Selected DB in the case the query changed this
global $dbconfig;
$adb->database->SelectDB($dbconfig['db_name']);
}
}
if(!function_exists("wf_formatcurrency")) {
function wf_formatcurrency($value) {
$currencyField = new CurrencyField($value);
return $currencyField->getDisplayValue(null, true);
}
}
if(!function_exists('wf_oldvalue')) {
function wf_oldvalue($field, $crmid) {
if(empty($crmid)) {
return false;
}
$objRecord = \Workflow\VTEntity::getForId($crmid);
return \Workflow\EntityDelta::getOldValue($objRecord->getModuleName(), $crmid, $field);
}
}
if(!function_exists('wf_haschanged')) {
function wf_haschanged($field, $crmid) {
if(empty($crmid)) {
return false;
}
$objRecord = \Workflow\VTEntity::getForId($crmid);
return \Workflow\EntityDelta::hasChanged($objRecord->getModuleName(), $crmid, $field);
}
}
if(!function_exists('wf_changedfields')) {
function wf_changedfields($crmid, $internalFields = false) {
if(empty($crmid)) {
return false;
}
$objRecord = \Workflow\VTEntity::getForId($crmid);
return \Workflow\EntityDelta::changeFields($objRecord->getModuleName(), $crmid, $internalFields);
}
}
function wf_recordlabel($crmid) {
if(empty($crmid)) {
return false;
}
return \Vtiger_Functions::getCRMRecordLabel($crmid);
}
if(!function_exists('wf_fieldlabel')) {
function wf_fieldlabel($module, $fieldName) {
if(!is_array($fieldName)) {
$fieldName = array($fieldName);
$single = true;
} else {
$single = false;
}
$tabid = getTabid($module);
foreach($fieldName as $field) {
if($field == 'crmid') {
$fieldLabel = 'CRMID';
} else {
$fieldInfo = \Workflow\VtUtils::getFieldInfo($field, $tabid);
$fieldLabel = $fieldInfo['fieldlabel'];
}
if(empty($fieldLabel)) {
$fieldLabel = $field;
}
$return[] = $fieldLabel;
}
if($single === true) {
return $return[0];
} else {
return $return;
}
}
}
if(!function_exists('wf_getproducts')) {
function wf_getproducts($crmid) {
if(is_string($crmid) && strpos($crmid, ',') !== false) {
$crmid = explode(',', $crmid);
}
if(!is_array($crmid)) {
$crmid = array($crmid);
}
$return = array();
foreach($crmid as $id) {
$context = \Workflow\VTEntity::getForId($id);
$products = getAssociatedProducts($context->getModuleName(), $context->getInternalObject());
$return[$id] = array(
'product_number' => count($products),
);
foreach($products as $product) {
$return[$id] = array_merge($return[$id], $product);
}
}
return $return;
}
}
if(!function_exists('wf_requestvalues')) {
function wf_requestvalues($fields, $label, $pausable = false, $stoppable = false) {
$currentBlock = \Workflow2::$currentBlockObj;
$currentWorkflow = \Workflow2::$currentWorkflowObj;
$blockKey = 'block_'.$currentBlock->getBlockId();
if(!$currentWorkflow->hasRequestValues($blockKey)) {
$export = array('version' => \Workflow\Preset\FormGenerator::VERSION, 'fields' => $fields);
$currentWorkflow->requestValues($blockKey, $export, $currentBlock, $label, $currentWorkflow->getContext(), $stoppable, $pausable);
return false;
}
}
}
if(!function_exists("wf_combine_comments")) {
function wf_combine_comments($crmid, $limit = null) {
global $adb, $default_charset;
$sql = "SELECT *
FROM
vtiger_modcomments
INNER JOIN vtiger_crmentity
ON (vtiger_crmentity.crmid = vtiger_modcomments.modcommentsid)
INNER JOIN vtiger_users
ON (vtiger_users.id = vtiger_crmentity.smownerid)
WHERE related_to = ".$crmid." AND vtiger_crmentity.deleted = 0 ORDER BY createdtime DESC ".(!empty($limit)?' LIMIT '.$limit:'')."";
$result = $adb->query($sql, true);
$html = "";
while($row = $adb->fetchByAssoc($result)) {
if(!empty($row['customer'])) {
}
$html .= "<div style='font-size:12px;'><strong>".(!empty($row['customer'])?Vtiger_Functions::getCRMRecordLabel($row['customer']):$row["first_name"]." ".$row["last_name"])." - ".date("d.m.Y H:i:s", strtotime($row["createdtime"]))."</strong><br>";
$html .= nl2br($row["commentcontent"])."</div><br><br>";
}
return $html;
}
}
if(!function_exists('wf_converttimezone')) {
// by user2622929
// http://stackoverflow.com/questions/3905193/convert-time-and-date-from-one-time-zone-to-another-in-php
function wf_converttimezone($time, $currentTimezone, $timezoneRequired)
{
$dayLightFlag = false;
$dayLgtSecCurrent = $dayLgtSecReq = 0;
$system_timezone = date_default_timezone_get();
$local_timezone = $currentTimezone;
date_default_timezone_set($local_timezone);
$local = date("Y-m-d H:i:s");
/* Uncomment if daylight is required */
// $daylight_flag = date("I", strtotime($time));
// if ($daylight_flag == 1) {
// $dayLightFlag = true;
// $dayLgtSecCurrent = -3600;
// }
date_default_timezone_set("GMT");
$gmt = date("Y-m-d H:i:s ");
$require_timezone = $timezoneRequired;
date_default_timezone_set($require_timezone);
$required = date("Y-m-d H:i:s ");
/* Uncomment if daylight is required */
// $daylight_flag = date("I", strtotime($time));
// if ($daylight_flag == 1) {
// $dayLightFlag = true;
// $dayLgtSecReq = +3600;
// }
date_default_timezone_set($system_timezone);
$diff1 = (strtotime($gmt) - strtotime($local));
$diff2 = (strtotime($required) - strtotime($gmt));
$date = new DateTime($time);
$date->modify("+$diff1 seconds");
$date->modify("+$diff2 seconds");
if ($dayLightFlag) {
$final_diff = $dayLgtSecCurrent + $dayLgtSecReq;
$date->modify("$final_diff seconds");
}
$timestamp = $date->format("Y-m-d H:i:s");
return $timestamp;
}
}
if(!function_exists('wf_pricelist_price')) {
function wf_pricelist_price($productid, $pricelistid) {
$adb = \PearDatabase::getInstance();
$sql = 'SELECT listprice FROM vtiger_pricebookproductrel WHERE pricebookid = ? AND productid = ?';
$result = $adb->pquery($sql, array(intval($pricelistid), intval($productid)), true);
//echo $adb->convert2Sql($sql, array(intval($pricelistid), intval($productid)));
if($adb->num_rows($result) > 0) {
return floatval($adb->query_result($result, 0, 'listprice'));
} else {
$sql = 'SELECT unit_price FROM vtiger_products WHERE productid = ?';
$result = $adb->pquery($sql, array(intval($productid)), true);
// echo $adb->convert2Sql($sql, array(intval($productid)));
return floatval($adb->query_result($result, 0, 'unit_price'));
}
}
}
if(!function_exists('wf_getproductimage')) {
function wf_getproductimage($crmid) {
$record = \Vtiger_Record_Model::getInstanceById($crmid);
return $record->getImageDetails();
}
}
if(!function_exists('wf_days_between')) {
function wf_days_between($date1, $date2)
{
$now = strtotime($date2);
$your_date = strtotime($date1);
$datediff = abs($now - $your_date);
return ceil($datediff / (60 * 60 * 24));
}
}
if(!function_exists('wf_getcourse')) {
function wf_getcourse($date, $ticker) {
// Сначала приведем дату к нужному формату: d.m.Y
$date = date('d.m.Y', strtotime($date));
// Потом вытащим страницу со всеми курсами валют на заданную дату
$url = "https://cbr.ru/currency_base/daily/?UniDbQuery.Posted=True&UniDbQuery.To=".$date;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$html = curl_exec($ch);
curl_close($ch);
// А теперь получим структуру страницы
$doc = new DOMDocument();
@$doc->loadHTML($html);
$xpath = new DOMXPath($doc);
// Находим строку таблицы с курсом доллара США
$rows = $xpath->query('//table[contains(@class, "data")]//tr');
foreach ($rows as $row) {
$cols = $row->getElementsByTagName('td');
if ($cols->length > 0 && trim($cols->item(1)->nodeValue) == $ticker) {
// Поднимаем курс искомой валюты
$course = floatval(str_replace(',', '.', trim($cols->item(4)->nodeValue)));
// Её кратность - цена указана за единицу, или за большее количество?
$multiplicity = intval(trim($cols->item(2)->nodeValue));
// Возвращаем с учетом кратности
return floatval($course / $multiplicity);
}
}
return -1; // В случае, если курс не найден
}
}
if(!function_exists('wf_send2court')) {
function wf_send2court($projectid, $version)
{
require_once 'include/utils/Debexpert.php';
file_put_contents('send2court.log', date('Y-m-d H:i:s').' - отправка Проекта '.$projectid.' в режиме '.$version.PHP_EOL, FILE_APPEND);
try {
$result = Send2Court($projectid, $version);
file_put_contents('send2court.log', date('Y-m-d H:i:s').' - Результат отправки Проекта '.$projectid.' : '.$result.PHP_EOL, FILE_APPEND);
} catch (Exception $ex) {
$result = $ex->getMessage();
file_put_contents('send2court.log', date('Y-m-d H:i:s').' - Ошибка отправки Проекта '.$projectid.'. Получен ответ: '.$result.PHP_EOL, FILE_APPEND);
}
return $result;
}
}
if(!function_exists('wf_getcookies')) {
function wf_getcookies($version)
{
require_once 'include/utils/Debexpert.php';
file_put_contents('send2court.log', date('Y-m-d H:i:s').' - отправка запроса куков в режиме '.$version.PHP_EOL, FILE_APPEND);
$result = GetCookies($version);
if ($result == 'Не удалось получить куки') {
file_put_contents('send2court.log', date('Y-m-d H:i:s').' - не удалось получить куки с госуслуг'.PHP_EOL, FILE_APPEND);
} else {
file_put_contents('send2court.log', date('Y-m-d H:i:s').' - куки получены успешно'.PHP_EOL, FILE_APPEND);
}
return $result;
}
}
if(!function_exists('wf_PDFPagesCount')) {
function wf_PDFPagesCount($id)
{
require_once 'include/utils/utils.php';
global $adb;
$query = 'select concat(a.`path`, a.attachmentsid, "_", a.storedname) as filepath
from vtiger_notes n
left join vtiger_crmentity e on e.crmid = n.notesid
left join vtiger_notescf ncf on ncf.notesid = n.notesid
left join vtiger_seattachmentsrel r2 on r2.crmid = n.notesid
left join vtiger_attachments a on a.attachmentsid = r2.attachmentsid
where n.notesid = ? and e.deleted = 0';
$result = $adb->pquery($query, array($id));
$filename = $adb->query_result($result, 0, 'filepath');
$result = getPDFPageCount($filename);
return $result;
}
}
if(!function_exists('wf_checkflithy')) {
function wf_checkflithy($text)
{
require_once 'include/utils/GPT.php';
return CheckFlithy($text);
}
}
if(!function_exists('wf_changeflithy')) {
function wf_changeflithy($text)
{
require_once 'include/utils/GPT.php';
return ChangeFlithy($text);
}
}
//функция парсинга пдф документов
if (!function_exists('wf_askpdf')) {
function wf_askpdf($pdf) {
require_once 'include/utils/GPT.php';
file_put_contents('logs/CheckPDF.log', date('Y-m-d H:i:s').' - Начинаем проверку файла '.$pdf.PHP_EOL, FILE_APPEND);
$result = AskPDF($pdf);
file_put_contents('logs/CheckPDF.log', date('Y-m-d H:i:s').' - Отправляем результат в CRM: '.json_encode($result).PHP_EOL, FILE_APPEND);
return $result;
}
}
if(!function_exists('wf_checkpdf')) {
function wf_checkpdf($pdf)
{
require_once 'include/utils/GPT.php';
file_put_contents('logs/CheckPDF.log', date('Y-m-d H:i:s').' - начинаем проверку файла '.$pdf.PHP_EOL, FILE_APPEND);
$result = CheckPDF($pdf);
file_put_contents('logs/CheckPDF.log', date('Y-m-d H:i:s').' - результат проверки нейросетью '.json_encode($result).PHP_EOL, FILE_APPEND);
return $result;
}
}
if(!function_exists('wf_cbrate')) {
function wf_cbrate($date) {
$url = 'https://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx';
$xmlRequest = <<<XML
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<KeyRateXML xmlns="http://web.cbr.ru/">
<fromDate>{$date}</fromDate>
<ToDate>{$date}</ToDate>
</KeyRateXML>
</soap:Body>
</soap:Envelope>
XML;
$headers = [
'Content-Type: text/xml; charset=utf-8',
'Content-Length: ' . strlen($xmlRequest),
'SOAPAction: "http://web.cbr.ru/KeyRateXML"',
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlRequest);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
if ($response === false) {
$rate = -1; // это будет символизировать ошибку запроса
} else {
// Создадим объект XML, чтобы вытащить из него курс из нужного тега
$xml = simplexml_load_string($response);
// Собственно достаем значение тега Rate
$rate = (string) $xml->children('soap', true)->Body->children('','')->KeyRateXMLResponse->KeyRateXMLResult->KeyRate->KR->Rate;
}
curl_close($ch);
return $rate;
}
}
if(!function_exists('wf_newmeeting')) {
function wf_newmeeting($crmid)
{
require_once 'include/utils/Kontur.php';
return NewMeeting($crmid);
}
}
if(!function_exists('wf_add2log')) {
function wf_add2log($file, $string)
{
file_put_contents($file, date('Y-m-d H:i:s').' - '.$string.PHP_EOL, FILE_APPEND);
return;
}
}
if(!function_exists('wf_getcourt')) {
function wf_getcourt($contactid, $address, $price)
{
require_once 'include/utils/Debexpert-guzzle.php';
return getCourt($contactid, $address, $price);
}
}
if(!function_exists('wf_copytos3')) {
function wf_copytos3($ticketid)
{
require_once 'include/utils/utils.php';
return CopyToS3($ticketid);
}
}
if(!function_exists('wf_sendletter')) {
function wf_sendletter($projectid, $type)
{
require_once 'include/utils/Letters.php';
$result = SendLetter($projectid, $type);
return $result;
}
}
if(!function_exists('wf_getdoc')) {
function wf_getdoc($projectid, $letter_id, $lettertype, $doctype)
{
require_once 'include/utils/Letters.php';
return getDoc($projectid, $letter_id, $lettertype, $doctype);
}
}
?>