* SPDX-License-Identifier: AGPL-3.0-only
************************************/
//crmv@203484 removed including file
class HelpDesk extends CRMEntity {
var $log;
var $db;
var $table_name;
var $table_index= 'ticketid';
var $tab_name = Array();
var $tab_name_index = Array();
/**
* Mandatory table for supporting custom fields.
*/
var $customFieldTable = Array();
var $column_fields = Array();
//Pavani: Assign value to entity_table
var $entity_table;
var $sortby_fields = Array('title','status','priority','crmid','firstname','smownerid','parent_id'); //crmv@7214s
var $list_fields = Array(
//Module Sequence Numbering
//'Ticket ID'=>Array('crmentity'=>'crmid'),
'Ticket No'=>Array('troubletickets'=>'ticket_no'),
// END
'Subject'=>Array('troubletickets'=>'title'),
'Related to'=>Array('troubletickets'=>'parent_id'),
'Status'=>Array('troubletickets'=>'status'),
'Priority'=>Array('troubletickets'=>'priority'),
'Assigned To'=>Array('crmentity'=>'smownerid')
);
var $list_fields_name = Array(
//'Ticket ID'=>'',
'Ticket No'=>'ticket_no',
'Subject'=>'ticket_title',
'Related to'=>'parent_id',
'Status'=>'ticketstatus',
'Priority'=>'ticketpriorities',
'Assigned To'=>'assigned_user_id'
);
var $list_link_field= 'ticket_title';
var $range_fields = Array(
'ticketid',
'title',
'firstname',
'lastname',
'parent_id',
'productid',
'productname',
'priority',
'severity',
'status',
'category',
'description',
'solution',
'modifiedtime',
'createdtime'
);
var $search_fields = Array();
var $search_fields_name = Array(
'Ticket No' => 'ticket_no',
'Title'=>'ticket_title',
);
//Specify Required fields
var $required_fields = array();
// Used when enabling/disabling the mandatory fields for the module.
// Refers to vte_field.fieldname values.
var $mandatory_fields = Array('assigned_user_id', 'createdtime', 'modifiedtime', 'ticket_title');
//Added these variables which are used as default order by and sortorder in ListView
var $default_order_by = 'modifiedtime';
var $default_sort_order = 'DESC';
//crmv@10759
var $search_base_field = 'ticket_title';
//crmv@10759 e
//var $groupTable = Array('vte_ticketgrouprelation','ticketid');
//crmv@2043m crmv@126830
var $waitForResponseStatus = 'Wait For Response';
var $answeredByCustomerStatus = 'Answered by customer';
//crmv@2043me crmv@126830e
public $sendPortalEmails = true; // crmv@142597
public $confidentialInfoRequest = array(); // crmv@160733
/** Constructor which will set the column_fields in this object
*/
function __construct()
{
global $table_prefix;
parent::__construct(); // crmv@37004
$this->table_name = $table_prefix."_troubletickets";
$this->tab_name = Array($table_prefix.'_crmentity',$table_prefix.'_troubletickets',$table_prefix.'_ticketcf');
$this->tab_name_index = Array($table_prefix.'_crmentity'=>'crmid',$table_prefix.'_troubletickets'=>'ticketid',$table_prefix.'_ticketcf'=>'ticketid',$table_prefix.'_ticketcomments'=>'ticketid');
$this->customFieldTable = Array($table_prefix.'_ticketcf', 'ticketid');
$this->entity_table = $table_prefix."_crmentity";
$this->search_fields = Array(
//'Ticket ID' => Array($table_prefix.'_crmentity'=>'crmid'),
'Ticket No' =>Array($table_prefix.'_troubletickets'=>'ticket_no'),
'Title' => Array($table_prefix.'_troubletickets'=>'title')
);
$this->log =LoggerManager::getLogger('helpdesk');
$this->log->debug("Entering HelpDesk() method ...");
$this->db = PearDatabase::getInstance();
$this->column_fields = getColumnFields('HelpDesk');
$this->log->debug("Exiting HelpDesk method ...");
}
// crmv@137993
function save($module_name,$longdesc=false,$offline_update=false,$triggerEvent=true) {
global $adb;
// get the value of some fields before being saved
if ($this->mode == 'edit') {
$this->old_status = null;
$this->old_solution = null;
$res = $adb->pquery("SELECT status, solution FROM {$this->table_name} WHERE {$this->table_index} = ?", array($this->id));
if ($res && $adb->num_rows($res) > 0) {
$this->old_status = $adb->query_result_no_html($res, 0, 'status');
$this->old_solution = $adb->query_result_no_html($res, 0, 'solution');
}
}
parent::save($module_name,$longdesc,$offline_update,$triggerEvent);
}
// crmv@137993e
function save_module($module)
{
//crmv@27146
//Inserting into Ticket Comment Table
if(isset($_REQUEST['action']) && $_REQUEST['action'] != 'MassEditSave'){
$this->insertIntoTicketCommentTable($table_prefix."_ticketcomments",'HelpDesk');
}
//Inserting into vte_attachments
//$this->insertIntoAttachment($this->id,'HelpDesk');
//crmv@27146e
// crmv@142597
if ($this->sendPortalEmails) {
$this->sendPortalReply(); // crmv@137993
}
// crmv@142597e
/* commento altrimenti passa per la save_related_module sia qui che nella CRMEntity
$return_action = $_REQUEST['return_action'];
$for_module = $_REQUEST['return_module'];
$for_crmid = $_REQUEST['return_id'];
if ($return_action && $for_module && $for_crmid) {
if ($for_module != 'Accounts' && $for_module != 'Contacts' && $for_module != 'Products') {
$on_focus = CRMEntity::getInstance($for_module);
$on_focus->save_related_module($for_module, $for_crmid, $module, $this->id);
}
}
*/
}
// crmv@137993
/**
* Check and send the email to alert the portal user
*/
function sendPortalReply() {
global $adb, $table_prefix;
$parent_id = $this->column_fields['parent_id'];
// do nothing if the ticket is not linked to anything
if (empty($parent_id)) return;
//crmv@93276
$mail_status = '';
$emailoptout = 1;
$isactive = 0;
// crmv@26821
$parent_module = getSalesEntityType($parent_id);
if($parent_module == 'Contacts') {
$result = $adb->pquery("select firstname,lastname,email,emailoptout from ".$table_prefix."_contactdetails where contactid=?", array($parent_id));
$emailoptout = $adb->query_result_no_html($result,0,'emailoptout');
$parentname = $adb->query_result($result,0,'firstname').' '.$adb->query_result($result,0,'lastname');
$contact_mailid = $adb->query_result($result,0,'email');
//Get the status of the vte_portal user. if the customer is active then send the vte_portal link in the mail
if ($contact_mailid != '' && $emailoptout == 0) {
$sql = "select isactive from ".$table_prefix."_portalinfo where id=?";
$isactive = $adb->query_result_no_html($adb->pquery($sql, array($parent_id)),0,'isactive');
}
} elseif ($parent_module == 'Accounts') {
$result = $adb->pquery("select accountname,emailoptout from ".$table_prefix."_account where accountid=?", array($parent_id));
$emailoptout = $adb->query_result_no_html($result,0,'emailoptout');
$parentname = $adb->query_result($result,0,'accountname');
if($emailoptout == 0){
// find the first active portal contact (no specific order)
$result_cnt = $adb->pquery("select contactid from ".$table_prefix."_contactdetails where accountid=?", array($parent_id));
while($row_cnt = $adb->fetchByAssoc($result_cnt)){
$result1 = $adb->pquery("select email,emailoptout from ".$table_prefix."_contactdetails where contactid=?", array($row_cnt['contactid']));
$emailoptout_cnt = $adb->query_result_no_html($result1,0,'emailoptout');
$contact_mailid_cnt = $adb->query_result($result1,0,'email');
if ($contact_mailid_cnt != '' && $emailoptout_cnt == 0) {
$sql = "select isactive from ".$table_prefix."_portalinfo where id=?";
$isactive = $adb->query_result_no_html($adb->pquery($sql, array($row_cnt['contactid'])),0,'isactive');
if($isactive) break;
}
}
}
}
// Leads can't be used, since there's no link with contacts
//crmv@87556
if ($this->column_fields['comments'] != '' && !empty($this->column_fields['mailscanner_action'])) {
$mail_status = $this->sendMailScannerReply();
//crmv@87556e
} elseif ($emailoptout == 0 && $isactive && $this->shouldSendPortalReply()) {
require_once('modules/Emails/mail.php');
// get the parent address
$parent_email = getParentMailId($parent_module,$parent_id);
// prepare the email
$emailinfo = $this->getPortalEmail($parent_email, $parentname);
// send the email
$mail_tmp = ''; // crmv@129149
$mail_status = send_mail('HelpDesk',$emailinfo['recipient'],$emailinfo['from_name'],$emailinfo['from_email'],$emailinfo['subject'],$emailinfo['body'],'','','','','','',$mail_tmp,'','',true); // crmv@129149
$mail_status_str = $parent_email."=".$mail_status."&&&";
} else {
$adb->println("'".$parentname."' doesn't want to receive emails about the ticket details as emailoptout is selected or portal not active");
}
// crmv@26821e
$this->portal_email_status = $mail_status;
if ($mail_status != '' && $mail_status != 1) { // crmv@104782
$this->portal_email_error = getMailErrorString($mail_status_str);;
}
//crmv@93276e
return $mail_status;
}
/**
* Return true if the portal email should be sent (provided the ticket is linked to a valid contact/account)
* By default the email is sent:
* in creation mode OR status changed to "Closed" OR comment added OR solution changed
*/
function shouldSendPortalReply() {
$cond = (
$this->mode != 'edit' ||
($this->column_fields['ticketstatus'] != $this->old_status && $this->column_fields['ticketstatus'] == 'Closed') ||
$this->column_fields['comments'] != '' ||
($this->column_fields['solution'] != $this->old_solution && !empty($this->column_fields['solution']))
);
return $cond;
}
// crmv@142358
// TODO: use real email templates or split this function
/**
* Prepare the email template to be sent to the portal user or to the customer
* There are several emails sent in different cases:
* 1. customer creates ticket from portal -> email to customer & notification to portal user
* 2. customer adds a comment from portal -> notifiy ticket owner and followers
* 3. customer closes ticket form portal -> notifiy ticket owner and followers
* 4. vte user create/edit ticket from vte -> email to customer
*/
function getPortalEmail($parent_email, $parentname) {
global $PORTAL_URL, $HELPDESK_SUPPORT_NAME, $HELPDESK_SUPPORT_EMAIL_ID;
if ($this->mode == 'edit') {
if (requestFromPortal()) {
// the customer added a comment, mail to ticket owner
$subject = getTranslatedString('LBL_RESPONDTO_TICKETID', 'HelpDesk')."##". $this->id."##". getTranslatedString('LBL_CUSTOMER_PORTAL', 'HelpDesk');
} else {
// the user changed the ticket, mail to the customer
$subject = '[ '.getTranslatedString('LBL_TICKET_ID', 'HelpDesk').' : '.$this->id.' ] '.'Re : '.$this->column_fields['ticket_title'];
}
} else {
if (requestFromPortal()) {
$subject = "[From Portal] " .$this->column_fields['ticket_no'].' [ '.getTranslatedString('LBL_TICKET_ID', 'HelpDesk').' : '.$this->id.' ] '.$this->column_fields['ticket_title'];
} else {
$subject = '[ '.getTranslatedString('LBL_TICKET_ID', 'HelpDesk').' : '.$this->id.' ] '.$this->column_fields['ticket_title'];
}
}
$bodysubject =
getTranslatedString('Ticket No', 'HelpDesk').': '.$this->column_fields['ticket_no']."
\n".
getTranslatedString('LBL_TICKET_ID', 'HelpDesk').': '.$this->id."
\n".
getTranslatedString('LBL_SUBJECT', 'HelpDesk').' '.$this->column_fields['ticket_title'];
if (requestFromPortal()) {
if ($this->mode == 'edit') {
$email_body_portal = getTranslatedString('Dear', 'HelpDesk')." ".getTranslatedString('user', 'HelpDesk').","."
"
.getTranslatedString('LBL_CUSTOMER_COMMENTS', 'HelpDesk')."
".nl2br($this->column_fields['comments'])."
"
.getTranslatedString('LBL_RESPOND', 'HelpDesk')."
"
.getTranslatedString('LBL_REGARDS', 'HelpDesk')."
"
.getTranslatedString('LBL_SUPPORT_ADMIN', 'HelpDesk');
} else {
$email_body_portal = $bodysubject.'
'.$this->column_fields['description'];
}
} else {
$url = "".getTranslatedString('LBL_TICKET_DETAILS', 'HelpDesk').""; //crmv@82517
$email_body_portal = $bodysubject.'
'.getPortalInfo_Ticket($this->id,$this->column_fields['ticket_title'],$parentname,$url,$this->mode);
}
$ret = array(
'recipient' => $parent_email,
'from_name' => $HELPDESK_SUPPORT_NAME,
'from_email' => $HELPDESK_SUPPORT_EMAIL_ID,
'subject' => $subject,
'body' => $email_body_portal,
);
return $ret;
}
// crmv@142358e
function getPortalEmailStatus() {
return array(
'status' => $this->portal_email_status,
'error' => $this->portal_email_error
);
}
// crmv@137993e
/** Function to insert values in vte_ticketcomments for the specified tablename and module
* @param $table_name -- table name:: Type varchar
* @param $module -- module:: Type varchar
*/
function insertIntoTicketCommentTable($table_name, $module, $ownertype=null, $ownerid=null)
{
global $log;
$log->info("in insertIntoTicketCommentTable ".$table_name." module is ".$module);
global $adb;
global $table_prefix;
global $current_user;
$current_time = $adb->formatDate(date('Y-m-d H:i:s'), true);
if (empty($ownertype)) $ownertype = 'user';
if (empty($ownerid)) $ownerid = $current_user->id;
if($this->column_fields['comments'] != '')
$comment = $this->column_fields['comments'];
else
$comment = $_REQUEST['comments'];
// crmv@160733
if (isset($this->confidentialInfoRequest['mode'])) {
$cimode = $this->confidentialInfoRequest['mode'];
if ($cimode == 'request') {
$comment .= $this->getConfidentialRequestText(($comment == ''));
} elseif ($cimode == 'provide') {
$comment = str_replace('@DELETEME@', '', $comment);
if ($comment != '') $comment .= "\n\n";
$comment .= $this->getConfidentialReplyText();
}
}
if ($comment != '') {
$comid = $adb->getUniqueID($table_prefix.'_ticketcomments');
$sql = "insert into ".$table_prefix."_ticketcomments (commentid,ticketid,ownerid,ownertype,createdtime,comments) values(?,?,?,?,?,".$adb->getEmptyClob(true).")";
$params = array($comid, $this->id, $ownerid, $ownertype, $current_time);
$adb->pquery($sql, $params);
$adb->updateClob($table_prefix.'_ticketcomments','comments',"commentid=$comid",from_html($comment));
$this->lastInsertedCommentId = $comid; // crmv@49398
if ($cimode) {
if ($cimode == 'request') {
$pwd = $this->confidentialInfoRequest['pwd'];
$data = $this->confidentialInfoRequest['data'];
$this->setConfidentialPwd($comid, $pwd, $data);
} elseif ($cimode == 'provide') {
$requestComment = intval($this->confidentialInfoRequest['request_commentid']);
$data = $this->confidentialInfoRequest['data'];
$r = $this->setConfidentialData($comid, $data, $requestComment);
if (!$r) throw new Exception('Password not saved correctly');
}
}
}
// crmv@160733e
}
/**
* This function is used to add the vte_at".$table_prefix."nts. This will call the function uploadAndSaveFile which will upload the attachment into the server and save that attachment information in the database.
* @param int $id - entity id to which the vte_files to be uploaded
* @param string $module - the current module name
*/
function insertIntoAttachment($id,$module)
{
global $log, $adb;
$log->debug("Entering into insertIntoAttachment($id,$module) method.");
$file_saved = false;
foreach($_FILES as $fileindex => $files)
{
if($files['name'] != '' && $files['size'] > 0)
{
$files['original_name'] = vtlib_purify($_REQUEST[$fileindex.'_hidden']);
$file_saved = $this->uploadAndSaveFile($id,$module,$files);
}
}
$log->debug("Exiting from insertIntoAttachment($id,$module) method.");
}
// crmv@49398
/** Function to get the ticket comments as a array
* @param int $ticketid - ticketid
* @return array $output - array(
[$i][comments] => comments
[$i][owner] => name of the user or customer who made the comment
[$i][createdtime] => the comment created time
)
where $i = 0,1,..n which are all made for the ticket
**/
function get_ticket_comments_list($ticketid) {
global $log, $adb, $table_prefix;
$log->debug("Entering get_ticket_comments_list(".$ticketid.") method ...");
$output = array();
$sql = "select * from {$table_prefix}_ticketcomments where ticketid=? order by createdtime DESC";
$result = $this->db->pquery($sql, array($ticketid));
$noofrows = $this->db->num_rows($result);
for ($i=0; $i<$noofrows; ++$i) {
$row = $this->db->FetchByAssoc($result);
// crmv@34559
if ($row['ownertype'] == 'user') {
$name = getUserName($row['ownerid']);
} elseif ($row['ownertype'] == 'customer') {
$name = getContactName($row['ownerid']);
} else {
$name = '';
}
// crmv@34559e
$row['owner'] = $name;
$row['comments'] = nl2br($row['comments']);
// crmv@160733
// get the plaintext for the additional info requested
if ($row['conf_status'] == 1 && !empty($row['conf_data'])) {
$row['conf_data_plain'] = $this->getConfidentialDataComment($row['commentid']);
}
// hide some sensitive info
unset($row['conf_password'], $row['conf_data']);
// crmv@160733e
$output[] = $row;
}
$log->debug("Exiting get_ticket_comments_list method ...");
return $output;
}
// crmv@49398e
/** Function to form the query which will give the list of tickets based on customername and id ie., contactname and contactid
* @param string $user_name - name of the customer ie., contact name
* @param int $id - contact id
* @return array - return an array which will be returned from the function process_list_query
**/
function get_user_tickets_list($user_name,$id,$where='',$match='')
{
global $log;
global $table_prefix;
$log->debug("Entering get_user_tickets_list(".$user_name.",".$id.",".$where.",".$match.") method ...");
$this->db->println("where ==> ".$where);
// crmv@150773
$query = "select ".$table_prefix."_crmentity.crmid, ".$table_prefix."_troubletickets.*, ".$table_prefix."_crmentity.smownerid, ".$table_prefix."_crmentity.createdtime, ".$table_prefix."_crmentity.modifiedtime, ".$table_prefix."_contactdetails.firstname, ".$table_prefix."_contactdetails.lastname, ".$table_prefix."_products.productid, ".$table_prefix."_products.productname, ".$table_prefix."_ticketcf.*
from ".$table_prefix."_troubletickets
inner join ".$table_prefix."_ticketcf on ".$table_prefix."_ticketcf.ticketid = ".$table_prefix."_troubletickets.ticketid
inner join ".$table_prefix."_crmentity on ".$table_prefix."_crmentity.crmid=".$table_prefix."_troubletickets.ticketid
left join ".$table_prefix."_contactdetails on ".$table_prefix."_troubletickets.parent_id=".$table_prefix."_contactdetails.contactid
left join ".$table_prefix."_products on ".$table_prefix."_products.productid = ".$table_prefix."_troubletickets.product_id
left join ".$table_prefix."_users on ".$table_prefix."_crmentity.smownerid=".$table_prefix."_users.id
where ".$table_prefix."_crmentity.deleted=0 and ".$table_prefix."_contactdetails.email='".$user_name."' and ".$table_prefix."_troubletickets.parent_id = '".$id."'";
if(trim($where) != '')
{
if($match == 'all' || $match == '')
{
$join = " and ";
}
elseif($match == 'any')
{
$join = " or ";
}
$where = explode("&&&",$where);
$count = count($where);
$count --;
$where_conditions = "";
foreach($where as $key => $value)
{
$this->db->println('key : '.$key.'...........value : '.$value);
$val = explode(" = ",$value);
$this->db->println('val0 : '.$val[0].'...........val1 : '.$val[1]);
if($val[0] == $table_prefix.'_troubletickets.title')
{
$where_conditions .= $val[0]." ".$val[1];
if($count != $key) $where_conditions .= $join;
}
elseif($val[1] != '' && $val[1] != 'Any')
{
$where_conditions .= $val[0]." = ".$val[1];
if($count != $key) $where_conditions .= $join;
}
}
if($where_conditions != '')
$where_conditions = " and ( ".$where_conditions." ) ";
$query .= $where_conditions;
$this->db->println("where condition for customer portal tickets search : ".$where_conditions);
}
$query .= " order by ".$table_prefix."_crmentity.crmid desc";
$log->debug("Exiting get_user_tickets_list method ...");
return $this->process_list_query($query);
}
/** Function to process the list query and return the result with number of rows
* @param string $query - query
* @return array $response - array( list => array(
$i => array(key => val)
),
row_count => '',
next_offset => '',
previous_offset =>''
)
where $i=0,1,..n & key = ticketid, title, firstname, ..etc(range_fields) & val = value of the key from db retrieved row
**/
function process_list_query($query, $row_offset, $limit= -1, $max_per_page = -1) // crmv@146653
{
global $log;
$log->debug("Entering process_list_query(".$query.") method ...");
$result =& $this->db->query($query,true,"Error retrieving $this->object_name list: ");
$list = Array();
$rows_found = $this->db->getRowCount($result);
if($rows_found != 0)
{
$ticket = Array();
for($index = 0 , $row = $this->db->fetchByAssoc($result, $index); $row && $index <$rows_found;$index++, $row = $this->db->fetchByAssoc($result, $index))
{
foreach($this->range_fields as $columnName)
{
if (isset($row[$columnName]))
{
$ticket[$columnName] = $row[$columnName];
}
else
{
$ticket[$columnName] = "";
}
}
$list[] = $ticket;
}
}
$response = Array();
$response['list'] = $list;
$response['row_count'] = $rows_found;
$response['next_offset'] = $next_offset;
$response['previous_offset'] = $previous_offset;
$log->debug("Exiting process_list_query method ...");
return $response;
}
// crmv@186735 - removed code
/** Function to get the list of comments for the given ticket id
* @param int $ticketid - Ticket id
* @return list $list - return the list of comments and comment informations as a html output where as these comments and comments informations will be formed in div tag.
**/
function getCommentInformation($ticketid)
{
global $log;
global $table_prefix;
$log->debug("Entering getCommentInformation(".$ticketid.") method ...");
global $adb;
global $mod_strings, $default_charset;
$sql = "select * from ".$table_prefix."_ticketcomments where ticketid=?";
$result = $adb->pquery($sql, array($ticketid));
$noofrows = $adb->num_rows($result);
//In ajax save we should not add this div
if($_REQUEST['fldName'] != 'comments')
{
$list .= '