Files
crm.clientright.ru/modules/ITS4YouMultiCompany/models/CustomRecordNumbering.php
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

495 lines
18 KiB
PHP

<?php
/*+**********************************************************************************
The content of this file is subject to the ITS4YouMultiCompany license.
* ("License"); You may not use this file except in compliance with the License
* The Initial Developer of the Original Code is IT-Solutions4You s.r.o.
* Portions created by IT-Solutions4You s.r.o. are Copyright(C) IT-Solutions4You s.r.o.
* All Rights Reserved.
************************************************************************************/
class ITS4YouMultiCompany_CustomRecordNumbering_Model extends Vtiger_Module_Model
{
protected $focus;
protected $db;
protected $numberTable;
protected $numberColumn;
/**
* Function to ger Supported modules for Custom record numbering
* @return array list of supported modules <Vtiger_Module_Model>
*/
public static function getSupportedModules()
{
$db = PearDatabase::getInstance();
$modulesModels = array();
$sql = "SELECT tabid, name, tab_id FROM vtiger_tab LEFT JOIN its4you_multicompany4you_cn_modules ON tab_id=tabid WHERE isentitytype = ? AND presence = ? AND tabid IN (SELECT DISTINCT tabid FROM vtiger_field WHERE uitype = ?) ORDER BY name ASC";
$result = $db->pquery($sql, array(1, 0, 4));
while ($row = $db->fetchByAssoc($result)) {
if ($row['name'] != 'ITS4YouMultiCompany') {
if (vtlib_isModuleActive($row['name'])) {
$modulesModels[$row['tabid']] = $row;
}
}
}
return $modulesModels;
}
public static function getAllowedModules()
{
$db = PearDatabase::getInstance();
$sql = "SELECT tabid, name FROM its4you_multicompany4you_cn_modules INNER JOIN vtiger_tab ON tabid=tab_id WHERE isentitytype = ? AND presence = ?";
$result = $db->pquery($sql, array(1, 0));
$numOfRows = $db->num_rows($result);
$modulesModels = array();
for ($i = 0; $i < $numOfRows; $i++) {
$tabId = $db->query_result($result, $i, 'tabid');
$modulesModels[$tabId] = ITS4YouMultiCompany_CustomRecordNumbering_Model::getInstance($db->query_result($result, $i, 'name'), $tabId);
}
return $modulesModels;
}
/**
* @param string $moduleName
* @param int|false $tabId
* @return ITS4YouMultiCompany_CustomRecordNumbering_Model
*/
public static function getInstance($moduleName, $tabId = false)
{
$moduleModel = new self();
$moduleModel->db = PearDatabase::getInstance();
$moduleModel->name = $moduleName;
if ($tabId) {
$moduleModel->id = $tabId;
}
return $moduleModel;
}
public static function getCompanyForUser($user_id)
{
return self::getCompanyForRole(self::getCompanyRoleForUser($user_id));
}
public static function getCompanyForRole($role_id)
{
$adb = PearDatabase::getInstance();
$companyid = '';
$res = $adb->pquery("SELECT companyid FROM its4you_multicompany4you
INNER JOIN vtiger_crmentity ON vtiger_crmentity.crmid = its4you_multicompany4you.companyid
WHERE its4you_multicompany4you.mc_role=? AND vtiger_crmentity.deleted = 0", array($role_id));
if ($adb->num_rows($res) > 0) {
$row = $adb->fetchByAssoc($res);
$companyid = $row['companyid'];
}
return $companyid;
}
public static function getCompanyRoleForUser($user_id = '')
{
if ($user_id == '') {
global $current_user;
$user_id = $current_user->id;
}
$adb = PearDatabase::getInstance();
$foundrole = '';
$roleres = $adb->pquery("SELECT parentrole FROM vtiger_user2role INNER JOIN vtiger_role ON vtiger_role.roleid=vtiger_user2role.roleid WHERE userid=?", array($user_id));
if ($adb->num_rows($roleres) > 0) {
$row = $adb->fetchByAssoc($roleres);
$parentrole = $row['parentrole'];
$UsedRoles = array();
$used_roles_res = $adb->pquery("SELECT parentrole FROM vtiger_role WHERE roleid IN (SELECT mc_role FROM its4you_multicompany4you WHERE mc_role IS NOT NULL)");
while ($used_roles_row = $adb->fetchByAssoc($used_roles_res)) {
$UsedRoles[] = $used_roles_row['parentrole'];
}
$Exploded = explode('::', $parentrole);
$nextrole = '';
foreach ($Exploded as $addtorole) {
if ($nextrole != '') {
$nextrole .= '::';
}
$nextrole .= $addtorole;
if (in_array($nextrole, $UsedRoles)) {
$foundrole = $addtorole;
}
}
}
return $foundrole;
}
public static function getUsedRoles()
{
$adb = PearDatabase::getInstance();
$UsedRoles = array();
$used_roles_res = $adb->pquery("SELECT roleid, parentrole FROM vtiger_role WHERE roleid IN (SELECT mc_role FROM its4you_multicompany4you INNER JOIN vtiger_crmentity on vtiger_crmentity.crmid = its4you_multicompany4you.companyid WHERE its4you_multicompany4you.mc_role IS NOT NULL AND vtiger_crmentity.deleted = ?)", array(0));
while ($used_roles_row = $adb->fetchByAssoc($used_roles_res)) {
$roleId = $used_roles_row['roleid'];
$UsedRoles[$roleId] = Settings_Roles_Record_Model::getInstanceById($roleId);
}
return $UsedRoles;
}
public function getEditNumberingUrl()
{
return "index.php?module=ITS4YouMultiCompany&view=EditNumbering";
}
/**
* Function to get module custom numbering data
* @return <Array> data of custom numbering data
*/
public function getModuleCustomNumberingData($companyId = '')
{
$adb = PearDatabase::getInstance();
if ($companyId < 1) {
$companyId = $_REQUEST['record'];
}
$result = $adb->pquery("SELECT start_id, cur_id, prefix FROM its4you_multicompany4you_cn WHERE tab_id=? AND companyid=? AND active = 1", array(getTabId($this->getName()), $companyId));
return $adb->fetchByAssoc($result);
}
/**
* Function to set Module sequence
* @param string $companyid Id of company
* @return array <Array> result of success
*/
public function setModuleSequence($companyid = '')
{
if ($companyid < 1) {
$companyid = $_REQUEST['companyid'];
}
$moduleName = $this->getName();
$prefix = $this->get('prefix');
$sequenceNumber = $this->get('sequenceNumber');
$status = $this->setModuleSeqNumber('configure', $moduleName, $prefix, $sequenceNumber, $companyid);
$success = array('success' => $status);
if (!$status) {
$db = PearDatabase::getInstance();
$result = $db->pquery("SELECT cur_id FROM its4you_multicompany4you_cn WHERE tab_id = ? AND companyid=? AND prefix = ?", array(getTabId($moduleName), $companyid, $prefix));
$success['sequenceNumber'] = $db->query_result($result, 0, 'cur_id');
}
return $success;
}
/**
* @throws Exception
*/
public function setModuleSeqNumber($mode, $module, $req_str = '', $req_no = '', $companyId = 0)
{
global $adb;
$module = $this->getName();
$tabId = getTabId($module);
//when we configure the invoice number in Settings this will be used
if ('configure' === $mode && !empty($req_no)) {
$check = $adb->pquery('SELECT cur_id FROM its4you_multicompany4you_cn WHERE tab_id=? AND prefix = ? AND companyid=?',
array($tabId, $req_str, $companyId)
);
if (!$adb->num_rows($check)) {
$adb->pquery('UPDATE its4you_multicompany4you_cn SET active=0 where tab_id=? and active=1 AND companyid=?',
array($tabId, $companyId)
);
$adb->pquery('INSERT into its4you_multicompany4you_cn values(?,?,?,?,?,?)',
array($companyId, $tabId, $req_str, $req_no, $req_no, 1)
);
return true;
} else {
$num_check = $adb->query_result($check, 0, 'cur_id');
if ($req_no < $num_check) {
return false;
} else {
$adb->pquery('UPDATE its4you_multicompany4you_cn SET active=0 WHERE active=1 AND tab_id=? AND companyid=?',
array($tabId, $companyId)
);
$adb->pquery('UPDATE its4you_multicompany4you_cn SET cur_id=?, active = 1 WHERE prefix=? AND tab_id=? AND companyid=?',
array($req_no, $req_str, $tabId, $companyId)
);
return true;
}
}
} elseif ('increment' === $mode) {
$check = $adb->pquery('SELECT cur_id, prefix FROM its4you_multicompany4you_cn WHERE tab_id=? AND active = 1 AND companyid=?',
array($tabId, $companyId)
);
$checkData = $adb->fetchByAssoc($check, 0);
if (empty($checkData['prefix'])) {
return false;
}
$prefix = str_replace(
array('$year$', '$month$', '$week$', '$day$'),
array(date('Y'), date('m'), date('W'), date('d')),
$checkData['prefix']
);
$cur_id = $checkData['cur_id'];
$prev_inv_no = $prefix . $cur_id;
$strip = strlen($cur_id) - strlen($cur_id + 1);
if ($strip < 0) {
$strip = 0;
}
$temp = str_repeat('0', $strip);
$req_no .= $temp . ($cur_id + 1);
$adb->pquery('UPDATE its4you_multicompany4you_cn SET cur_id=? WHERE cur_id=? AND active=1 AND tab_id=? AND companyid=?',
array($req_no, $cur_id, $tabId, $companyId)
);
return decode_html($prev_inv_no);
}
return false;
}
/**
* @param string $moduleName
* @return void
* @throws Exception
*/
public function decrementStandardNumbering($moduleName)
{
$adb = PearDatabase::getInstance();
$result = $adb->pquery(
'SELECT cur_id FROM vtiger_modentity_num WHERE semodule=? AND active=?',
array($moduleName, 1)
);
$stringVal = $adb->query_result($result, 0, 'cur_id');
$intVal = intval(ltrim($stringVal, '0')) - 1;
$strip = strlen(strval($stringVal)) - strlen(strval($intVal));
if ($strip < 0) {
$strip = 0;
}
$currentId = str_repeat('0', $strip) . $intVal;
if ($currentId) {
$adb->pquery(
'UPDATE vtiger_modentity_num SET cur_id=? WHERE semodule=? AND active=?',
array($currentId, $moduleName, 1)
);
}
}
/**
* Function to update record sequences which are under this module
* @return <Array> result of success
*/
public function updateRecordsWithSequence($companyid)
{
//return $this->getFocus()->updateMissingSeqNumber($this->getName());
return $this->updateMissingSeqNumber($this->getName(), $companyid);
}
private function updateMissingSeqNumber($module, $companyid)
{
global $log, $adb;
vtlib_setup_modulevars($module, $this);
if (!$this->isModuleSequenceConfigured($module, $companyid)) {
return;
}
$tabid = getTabid($module);
$fieldinfo = $adb->pquery("SELECT * FROM vtiger_field WHERE tabid = ? AND uitype = 4", array($tabid));
$returninfo = array();
if ($fieldinfo && $adb->num_rows($fieldinfo)) {
// TODO: We assume the following for module sequencing field
// 1. There will be only field per module
// 2. This field is linked to module base table column
$fld_table = $adb->query_result($fieldinfo, 0, 'tablename');
$fld_column = $adb->query_result($fieldinfo, 0, 'columnname');
if ($fld_table == $this->table_name) {
$records = $adb->query("SELECT $this->table_index AS recordid FROM $this->table_name " .
"WHERE $fld_column = '' OR $fld_column is NULL");
if ($records && $adb->num_rows($records)) {
$returninfo['totalrecords'] = $adb->num_rows($records);
$returninfo['updatedrecords'] = 0;
$modseqinfo = $this->getModuleSeqInfo($module, $companyid);
$prefix = str_replace(array('$year$', '$month$', '$week$', '$day$'), array(date('Y'), date('m'), date('W'), date('d')), $modseqinfo[0]);
$cur_id = $modseqinfo[1];
$old_cur_id = $cur_id;
while ($recordinfo = $adb->fetch_array($records)) {
$value = "$prefix" . "$cur_id";
$adb->pquery("UPDATE $fld_table SET $fld_column = ? WHERE $this->table_index = ?", array($value, $recordinfo['recordid']));
// $cur_id += 1;
$strip = strlen($cur_id) - strlen($cur_id + 1);
if ($strip < 0) {
$strip = 0;
}
$temp = str_repeat("0", $strip);
$cur_id = $temp . ($cur_id + 1);
$returninfo['updatedrecords'] = $returninfo['updatedrecords'] + 1;
}
if ($old_cur_id != $cur_id) {
$adb->pquery("UPDATE its4you_multicompany4you_cn set cur_id=? where tab_id=? and active=1 AND companyid=?", array($cur_id, getTabId($module), $companyid));
}
}
} else {
$log->fatal("Updating Missing Sequence Number FAILED! REASON: Field table and module table mismatching.");
}
}
return $returninfo;
}
private function isModuleSequenceConfigured($module, $companyid)
{
$adb = PearDatabase::getInstance();
$result = $adb->pquery('SELECT 1 FROM its4you_multicompany4you_cn WHERE tab_id = ? AND active = 1 AND companyid=?', array(getTabId($module), $companyid));
if ($result && $adb->num_rows($result) > 0) {
return true;
}
return false;
}
private function getModuleSeqInfo($module, $companyid)
{
global $adb;
$check = $adb->pquery("select cur_id, prefix from its4you_multicompany4you_cn where tab_id=? and active = 1 AND companyid=?", array(getTabId($module), $companyid));
$prefix = $adb->query_result($check, 0, 'prefix');
$curid = $adb->query_result($check, 0, 'cur_id');
return array($prefix, $curid);
}
public function getNumberFieldInfo()
{
$tabId = getTabid($this->name);
$adb = PearDatabase::getInstance();
$result = $adb->pquery('SELECT tablename, columnname FROM vtiger_field WHERE tabid = ? AND uitype = ?', array($tabId, 4));
if ($adb->num_rows($result)) {
return $adb->query_result_rowdata($result);
}
return false;
}
public function isPrimaryTable($table)
{
return $this->focus->table_name === $table;
}
public function retrieveFocus()
{
$this->focus = CRMEntity::getInstance($this->name);
}
public function retrieveNumberFieldInfo()
{
$info = $this->getNumberFieldInfo();
$this->numberTable = $info['tablename'];
$this->numberColumn = $info['columnname'];
}
/**
* @return string
*/
public function getNumberColumn()
{
return $this->numberColumn;
}
/**
* @return string
*/
public function getNumberTable()
{
return $this->numberTable;
}
/**
* @throws Exception
*/
public function updateEmptyCompanyField()
{
$this->retrieveFocus();
$this->retrieveNumberFieldInfo();
if ($this->isPrimaryTable($this->getNumberTable()) && $this->isCompanyColumnExists()) {
$recordsResult = $this->db->query(sprintf('SELECT %s AS recordid FROM %s WHERE its4you_company="" OR its4you_company is NULL', $this->focus->table_index, $this->focus->table_name));
while ($row = $this->db->fetchByAssoc($recordsResult)) {
if (!isRecordExists($row['recordid'])) {
continue;
}
$recordModel = Vtiger_Record_Model::getInstanceById($row['recordid']);
$companyId = self::getCompanyForUser($recordModel->get('assigned_user_id'));
if ($companyId) {
$this->updateCompanyField($recordModel, $companyId);
}
}
}
}
/**
* @throws Exception
*/
public function updateNumberField($recordModel, $companyId)
{
$next = $this->setModuleSeqNumber('increment', $this->name, '', '', $companyId);
if ($next) {
$this->db->pquery(sprintf('UPDATE %s SET %s=? WHERE %s=?', $this->focus->table_name, $this->getNumberColumn(), $this->focus->table_index), [$next, $recordModel->getId()]);
$this->decrementStandardNumbering($this->name);
}
}
public function isCompanyColumnExists()
{
return columnExists('its4you_company', $this->focus->table_name);
}
public function updateCompanyField($recordModel, $companyId)
{
$this->db->pquery(sprintf('UPDATE %s SET its4you_company=? WHERE %s=?', $this->focus->table_name, $this->focus->table_index), [$companyId, $recordModel->getId()]);
}
}