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

445 lines
17 KiB
PHP

<?php
/* +***********************************************************************************
* The contents of this file are subject to the vtiger CRM Public License Version 1.0
* ("License"); You may not use this file except in compliance with the License
* The Original Code is: vtiger CRM Open Source
* The Initial Developer of the Original Code is vtiger.
* Portions created by vtiger are Copyright (C) vtiger.
* All Rights Reserved.
* *********************************************************************************** */
require_once 'include/utils/utils.php';
require_once 'vtlib/Vtiger/Net/Client.php';
class PBXManager_PBXManager_Connector {
// SalesPlatform.ru begin hide trunk field
private static $SETTINGS_REQUIRED_PARAMETERS = array('webappurl' => 'text','outboundcontext' => 'text', 'vtigersecretkey' => 'text');
//private static $SETTINGS_REQUIRED_PARAMETERS = array('webappurl' => 'text','outboundcontext' => 'text', 'outboundtrunk' => 'text' , 'vtigersecretkey' => 'text');
// SalesPlatform.ru end
//SalesPlatform.ru begin
//private static $RINGING_CALL_PARAMETERS = array('From' => 'callerIdNumber', 'SourceUUID' => 'callUUID', 'Direction' => 'Direction');
private static $RINGING_CALL_PARAMETERS = array('From' => 'callerIdNumber', 'SourceUUID' => 'callUUID', 'Direction' => 'Direction', 'IncomingLineName' => 'connectedLineName');
//SalesPlatform.ru end
private static $NUMBERS = array();
private $webappurl;
private $outboundcontext, $outboundtrunk;
private $vtigersecretkey;
const RINGING_TYPE = 'ringing';
const ANSWERED_TYPE = 'answered';
const HANGUP_TYPE = 'hangup';
const RECORD_TYPE = 'record';
const INCOMING_TYPE = 'inbound';
const OUTGOING_TYPE = 'outbound';
const USER_PHONE_FIELD = 'phone_crm_extension';
function __construct() {
$serverModel = PBXManager_Server_Model::getInstance();
$this->setServerParameters($serverModel);
}
/**
* Function to get provider name
* returns <string>
*/
public function getGatewayName() {
return 'PBXManager';
}
public function getPicklistValues($field) {
}
public function getServer() {
return $this->webappurl;
}
public function getOutboundContext() {
return $this->outboundcontext;
}
public function getOutboundTrunk() {
return $this->outboundtrunk;
}
public function getVtigerSecretKey() {
return $this->vtigersecretkey;
}
public function getXmlResponse() {
header("Content-type: text/xml; charset=utf-8");
$response = '<?xml version="1.0" encoding="utf-8"?>';
$response .= '<Response><Authentication>';
$response .= 'Failure';
$response .= '</Authentication></Response>';
return $response;
}
/**
* Function to set server parameters
* @param <array> authdetails
*/
public function setServerParameters($serverModel) {
$this->webappurl = $serverModel->get('webappurl');
$this->outboundcontext = $serverModel->get('outboundcontext');
$this->outboundtrunk = $serverModel->get('outboundtrunk');
$this->vtigersecretkey = $serverModel->get('vtigersecretkey');
}
/**
* Function to get Settings edit view params
* returns <array>
*/
public function getSettingsParameters() {
return self::$SETTINGS_REQUIRED_PARAMETERS;
}
protected function prepareParameters($details, $type) {
switch ($type) {
case 'ringing':
foreach (self::$RINGING_CALL_PARAMETERS as $key => $value) {
$params[$key] = $details->get($value);
}
$params['GateWay'] = $this->getGatewayName();
break;
}
return $params;
}
/**
* Function to handle the dial call event
* @param <Vtiger_Request> $details
*/
public function handleDialCall($details) {
$callid = $details->get('callUUID');
$answeredby = $details->get('callerid2');
$caller = $details->get('callerid1');
// For Inbound call, answered by will be the user, we should fill the user field
// SalesPlatform.ru begin
/*
* We dont know who caller - crm user or another human. We need check this and also check inner call
* when caller and answer numbers in crm but only one matches on record model
*/
$user = PBXManager_Record_Model::getUserInfoWithNumber($caller);
if(!$user) {
$user = PBXManager_Record_Model::getUserInfoWithNumber($answeredby);
/* If no one crm user for anyone caller - no process ring */
if(!$user) {
return;
}
}
$recordModel = PBXManager_Record_Model::getInstanceBySourceUUID($callid, $user);
$params['user'] = $user['id'];
//$recordModel = PBXManager_Record_Model::getInstanceBySourceUUID($callid);
//
//$direction = $recordModel->get('direction');
//if ($direction == self::INCOMING_TYPE) {
// // For Incoming call, we should fill the user field if he answered that call
// $user = PBXManager_Record_Model::getUserInfoWithNumber($answeredby);
//
// $params['user'] = $user['id'];
// $recordModel->updateAssignedUser($user['id']);
//} else {
// $user = PBXManager_Record_Model::getUserInfoWithNumber($caller);
// if ($user) {
// $params['user'] = $user['id'];
// $recordModel->updateAssignedUser($user['id']);
// }
//}
// SalesPlatform.ru end
$params['callstatus'] = "in-progress";
// SalesPlatform.ru begin
$recordModel->updateCallDetails($params, $user);
//$recordModel->updateAssignedUser($user['id']);
//$recordModel->updateCallDetails($params);
// SalesPlatform.ru end
}
/**
* Function to handle the EndCall event
* @param <Vtiger_Request> $details
*/
public function handleEndCall($details) {
$callid = $details->get('callUUID');
// SalesPlatform.ru begin
//$recordModel = PBXManager_Record_Model::getInstanceBySourceUUID($callid);
// SalesPlatform.ru end
$params['starttime'] = $details->get('starttime');
$params['endtime'] = $details->get('endtime');
$params['totalduration'] = $details->get('duration');
$params['billduration'] = $details->get('billableseconds');
//SalesPlatform.ru begin
$userNumber = $details->get('callerNumber');
$user = PBXManager_Record_Model::getUserInfoWithNumber($userNumber);
$recordModel = PBXManager_Record_Model::getInstanceBySourceUUID($callid, $user);
$recordModel->updateCallDetails($params, $user);
//$recordModel->updateCallDetails($params);
//SalesPlatform.ru end
}
/**
* Function to handle the hangup call event
* @param <Vtiger_Request> $details
*/
public function handleHangupCall($details) {
$callid = $details->get('callUUID');
// SalesPlatform.ru begin
$userNumber = $details->get('callerIdNum');
$user = PBXManager_Record_Model::getUserInfoWithNumber($userNumber);
if(!$user) {
return;
}
$recordModel = PBXManager_Record_Model::getInstanceBySourceUUID($callid, $user);
//$recordModel = PBXManager_Record_Model::getInstanceBySourceUUID($callid);
// SalesPlatform.ru end
$hangupcause = $details->get('causetxt');
switch ($hangupcause) {
// If call is successfull
case 'Normal Clearing':
$params['callstatus'] = 'completed';
if($details->get('HangupCause') == 'NO ANSWER') {
$params['callstatus'] = 'no-answer';
}
break;
case 'User busy' :
$params['callstatus'] = 'busy';
break;
case 'Call Rejected':
$params['callstatus'] = 'busy';
break;
default :
$params['callstatus'] = $hangupcause;
break;
}
//SalesPlatform.ru begin
$totalDuration = $recordModel->get('totalduration');
$endTime = $recordModel->get('endtime');
$startTime = $recordModel->get('starttime');
if(empty($totalDuration) && empty($endTime) && !empty($startTime)) {
$currentTime = time();
$params['endtime'] = date("Y-m-d H:i:s", $currentTime);
$startTime = strtotime($startTime);
if($startTime) {
$totalDuration = $currentTime - $startTime;
if($totalDuration > 0) {
$params['totalduration'] = $totalDuration;
}
}
}
//SalesPlatform.ru end
if($details->get('EndTime') && $details->get('Duration')) {
$params['endtime'] = $details->get('EndTime');
$params['totalduration'] = $details->get('Duration');
}
// SalesPlatform.ru begin
$recordModel->updateCallDetails($params, $user);
//$recordModel->updateCallDetails($params);
// SalesPlatform.ru end
}
/**
* Function to handle record event
* @param <Vtiger_Request> $details
*/
public function handleRecording($details) {
$callid = $details->get('callUUID');
// SalesPlatform.ru begin
$userNumber = $details->get('callerNumber');
$user = PBXManager_Record_Model::getUserInfoWithNumber($userNumber);
$recordModel = PBXManager_Record_Model::getInstanceBySourceUUID($callid, $user);
$recordModel->updateCallDetails(array(
'recordingurl' => $details->get('recordinglink')
), $user);
//$recordModel = PBXManager_Record_Model::getInstanceBySourceUUID($callid);
//$params['recordingurl'] = $details->get('recordinglink');
//$recordModel->updateCallDetails($params);
// SalesPlatform.ru end
}
/**
* Function to handle AGI event
* @param <Vtiger_Request> $details
*/
public function handleStartupCall($details, $userInfo, $customerInfo) {
global $current_user;
$params = $this->prepareParameters($details, self::RINGING_TYPE);
$direction = $details->get('Direction');
// To add customer and user information in params
$params['Customer'] = $customerInfo['id'];
$params['CustomerType'] = $customerInfo['setype'];
$params['User'] = $userInfo['id'];
if ($details->get('from')) {
$params['CustomerNumber'] = $details->get('from');
} else if ($details->get('to')) {
$params['CustomerNumber'] = $details->get('to');
}
$params['starttime'] = $details->get('StartTime');
$params['callstatus'] = "ringing";
$user = CRMEntity::getInstance('Users');
// SalesPlatform.ru begin
$current_user = $user->retrieveCurrentUserInfoFromFile($userInfo['id']);
//$current_user = $user->getActiveAdminUser();
// SalesPlatform.ru end
//SalesPlatform.ru begin fix multiplication on call transfer
$recordModel = PBXManager_Record_Model::getInstanceBySourceUUID($params['SourceUUID'], $userInfo);
if($recordModel->get('pbxmanagerid') == null) {
$recordModel->saveRecordWithArrray($params);
} else {
$updateParams = array();
$updateParams['user'] = $userInfo['id'];
$updateParams['callstatus'] = 'ringing';
$updateParams['customertype'] = $params['CustomerType'];
$updateParams['customernumber'] = $params['CustomerNumber'];
$updateParams['customer'] = $customerInfo['id'];
$recordModel->updateAssignedUser($userInfo['id']);
$recordModel->updateCallDetails($updateParams, $userInfo);
}
//$recordModel = PBXManager_Record_Model::getCleanInstance();
//$recordModel->saveRecordWithArrray($params);
//SalesPlatform.ru end
//SalesPlatform.ru begin delete no-need code
//if ($direction == self::INCOMING_TYPE)
// $this->respondToIncomingCall($details);
//else
// $this->respondToOutgoingCall($params['CustomerNumber']);
//SalesPlatform.ru end
}
/**
* Function to respond for incoming calls
* @param <Vtiger_Request> $details
*/
public function respondToIncomingCall($details) {
global $current_user;
self::$NUMBERS = PBXManager_Record_Model::getUserNumbers();
header("Content-type: text/xml; charset=utf-8");
$response = '<?xml version="1.0" encoding="utf-8"?>';
$response .= '<Response><Dial><Authentication>';
$response .= 'Success</Authentication>';
if (self::$NUMBERS) {
foreach (self::$NUMBERS as $userId => $number) {
$userInstance = Users_Privileges_Model::getInstanceById($userId);
$current_user = $userInstance;
$callPermission = Users_Privileges_Model::isPermitted('PBXManager', 'ReceiveIncomingCalls');
if ($number != $details->get('callerIdNumber') && $callPermission) {
if(preg_match("/sip/", $number) || preg_match("/@/", $number)) {
$number = trim($number, "/sip:/");
$response .= '<Number>SIP/';
$response .= $number;
$response .= '</Number>';
}else {
$response .= '<Number>SIP/';
$response .= $number;
$response .= '</Number>';
}
}
}
}else {
$response .= '<ConfiguredNumber>empty</ConfiguredNumber>';
$date = date('Y/m/d H:i:s');
$params['callstatus'] = 'no-answer';
$params['starttime'] = $date;
$params['endtime'] = $date;
// SalesPlatform.ru begin
$userNumber = $details->get('dialString');
$user = PBXManager_Record_Model::getUserInfoWithNumber($userNumber);
$recordModel = PBXManager_Record_Model::getInstanceBySourceUUID($details->get('callUUID'), $user);
$recordModel->updateCallDetails($params, $user);
//$recordModel = PBXManager_Record_Model::getInstanceBySourceUUID($details->get('callUUID'));
//$recordModel->updateCallDetails($params);
// SalesPlatform.ru end
}
$response .= '</Dial></Response>';
echo $response;
}
/**
* Function to respond for outgoing calls
* @param <Vtiger_Request> $details
*/
public function respondToOutgoingCall($to) {
header("Content-type: text/xml; charset=utf-8");
$response = '<?xml version="1.0" encoding="utf-8"?>';
$response .= '<Response><Dial><Authentication>';
$response .= 'Success</Authentication>';
$numberLength = strlen($to);
if(preg_match("/sip/", $to) || preg_match("/@/", $to)) {
$to = trim($to, "/sip:/");
$response .= '<Number>SIP/';
$response .= $to;
$response .= '</Number>';
}else {
$response .= '<Number>SIP/';
$response .= $to;
if($numberLength > 5) $response .= '@'. $this->getOutboundTrunk();
$response .= '</Number>';
}
$response .= '</Dial></Response>';
echo $response;
}
/**
* Function to make outbound call
* @param <string> $number (Customer)
* @param <string> $recordid
*/
function call($number, $record) {
$user = Users_Record_Model::getCurrentUserModel();
$extension = $user->phone_crm_extension;
$webappurl = $this->getServer();
$context = $this->getOutboundContext();
$vtigerSecretKey = $this->getVtigerSecretKey();
$serviceURL = $webappurl;
$serviceURL .= '/makecall?event=OutgoingCall&';
$serviceURL .= 'secret=' . urlencode($vtigerSecretKey) . '&';
$serviceURL .= 'from=' . urlencode($extension) . '&';
$serviceURL .= 'to=' . urlencode($number) . '&';
$serviceURL .= 'context='. urlencode($context);
$httpClient = new Vtiger_Net_Client($serviceURL);
$response = $httpClient->doPost(array());
$response = trim($response);
if ($response == "Error" || $response == "" || $response == null
|| $response == "Authentication Failure" ) {
return false;
}
return true;
}
}