Newer
Older
$authtoken = sprintf('%s%dx%s',
($user->getId() == $this->getOwnerId() ? 'o' : 'c'),
$algo,
Base32::encode(pack('VV',$user->getId(), $this->getId())));
switch($algo) {
case 1:
$authtoken .= substr(base64_encode(
md5($user->getId().$this->getCreateDate().$this->getId().SECRET_SALT, true)), 8);
break;
default:
return null;
}
return $authtoken;
}
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
function sendAccessLink($user) {
global $ost;
if (!($email = $ost->getConfig()->getDefaultEmail())
|| !($content = Page::lookupByType('access-link')))
return;
$vars = array(
'url' => $ost->getConfig()->getBaseUrl(),
'ticket' => $this,
'user' => $user,
'recipient' => $user,
);
$lang = $user->getLanguage(UserAccount::LANG_MAILOUTS);
$msg = $ost->replaceTemplateVariables(array(
'subj' => $content->getLocalName($lang),
'body' => $content->getLocalBody($lang),
), $vars);
$email->send($user, Format::striptags($msg['subj']),
$msg['body']);
}
/* -------------------- Setters --------------------- */
function setLastMsgId($msgid) {
return $this->lastMsgId=$msgid;
}
function setLastMessage($message) {
$this->last_message = $message;
$this->setLastMsgId($message->getId());
}
//DeptId can NOT be 0. No orphans please!
Peter Rotich
committed
function setDeptId($deptId) {
if(!($dept=Dept::lookup($deptId)) || $dept->getId()==$this->getDeptId())
Peter Rotich
committed
$sql='UPDATE '.TICKET_TABLE.' SET updated=NOW(), dept_id='.db_input($deptId)
.' WHERE ticket_id='.db_input($this->getId());
return (db_query($sql) && db_affected_rows());
}
Peter Rotich
committed
//Set staff ID...assign/unassign/release (id can be 0)
function setStaffId($staffId) {
if(!is_numeric($staffId)) return false;
Peter Rotich
committed
$sql='UPDATE '.TICKET_TABLE.' SET updated=NOW(), staff_id='.db_input($staffId)
.' WHERE ticket_id='.db_input($this->getId());
if (!db_query($sql) || !db_affected_rows())
return false;
Peter Rotich
committed
$this->staff = null;
$this->ht['staff_id'] = $staffId;
}
function setSLAId($slaId) {
if ($slaId == $this->getSLAId()) return true;
'UPDATE '.TICKET_TABLE.' SET sla_id='.db_input($slaId)
.' WHERE ticket_id='.db_input($this->getId()))
&& db_affected_rows();
if ($rv) {
$this->ht['sla_id'] = $slaId;
$this->sla = null;
}
return $rv;
}
/**
* Selects the appropriate service-level-agreement plan for this ticket.
* When tickets are transfered between departments, the SLA of the new
* department should be applied to the ticket. This would be useful,
* for instance, if the ticket is transferred to a different department
* which has a shorter grace period, the ticket should be considered
* overdue in the shorter window now that it is owned by the new
* department.
*
* $trump - if received, should trump any other possible SLA source.
* This is used in the case of email filters, where the SLA
* specified in the filter should trump any other SLA to be
* considered.
*/
function selectSLAId($trump=null) {
global $cfg;
# XXX Should the SLA be overridden if it was originally set via an
# email filter? This method doesn't consider such a case
if ($trump && is_numeric($trump)) {
} elseif ($this->getDept() && $this->getDept()->getSLAId()) {
} elseif ($this->getTopic() && $this->getTopic()->getSLAId()) {
$slaId = $this->getTopic()->getSLAId();
} else {
$slaId = $cfg->getDefaultSLAId();
}
return ($slaId && $this->setSLAId($slaId)) ? $slaId : false;
}
//Set team ID...assign/unassign/release (id can be 0)
Peter Rotich
committed
Peter Rotich
committed
$sql='UPDATE '.TICKET_TABLE.' SET updated=NOW(), team_id='.db_input($teamId)
.' WHERE ticket_id='.db_input($this->getId());
return (db_query($sql) && db_affected_rows());
function setStatus($status, $comments='', &$errors=array(), $set_closing_agent=true) {
if ($thisstaff && !($role=$thisstaff->getRole($this->getDeptId())))
if ($status && is_numeric($status))
$status = TicketStatus::lookup($status);
if (!$status || !$status instanceof TicketStatus)
return false;
// Double check permissions (when changing status)
if ($role && $this->getStatusId()) {
switch ($status->getState()) {
case 'closed':
if (!($role->hasPerm(TicketModel::PERM_CLOSE)))
return false;
break;
case 'deleted':
// XXX: intercept deleted status and do hard delete
if ($role->hasPerm(TicketModel::PERM_DELETE))
return $this->delete($comments);
// Agent doesn't have permission to delete tickets
if ($this->getStatusId() == $status->getId())
return true;
$sql = 'UPDATE '.TICKET_TABLE.' SET updated=NOW() '.
' ,status_id='.db_input($status->getId());
$ecb = null;
switch($status->getState()) {
if ($this->getMissingRequiredFields()) {
$errors['err'] = sprintf(__(
'This ticket is missing data on %s one or more required fields %s and cannot be closed'),
'', '');
return false;
}
$sql.=', closed=NOW(), lastupdate=NOW(), duedate=NULL ';
$sql.=', staff_id='.db_input($thisstaff->getId());
Anthony Lawrence
committed
$this->clearOverdue();
$ecb = function($t) {
$t->reload();
$t->logEvent('closed');
$t->deleteDrafts();
};
break;
case 'open':
// TODO: check current status if it allows for reopening
$sql .= ',closed=NULL, lastupdate=NOW(), reopened=NOW() ';
$t->logEvent('reopened', false, 'closed');
// If the ticket is not open then clear answered flag
if (!$this->isOpen())
$sql .= ', isanswered = 0 ';
default:
return false;
$sql.=' WHERE ticket_id='.db_input($this->getId());
if (!db_query($sql) || !db_affected_rows())
return false;
// Log status change b4 reload — if currently has a status. (On new
// ticket, the ticket is opened and thereafter the status is set to
// the requested status).
if ($current_status = $this->getStatus()) {
$note = sprintf(__('Status changed from %1$s to %2$s by %3$s'),
$this->getStatus(),
$status,
$thisstaff ?: 'SYSTEM');
$alert = false;
if ($comments) {
$note .= sprintf('<hr>%s', $comments);
// Send out alerts if comments are included
$alert = true;
$this->logNote(__('Status Changed'), $note, $thisstaff, $alert);
if ($ecb)
$ecb($this);
elseif ($hadStatus)
// Don't log the initial status change
$this->logEvent('edited', array('status' => $status->getId()));
}
function setState($state, $alerts=false) {
switch(strtolower($state)) {
case 'open':
return $this->setStatus('open');
break;
case 'closed':
return $this->setStatus('closed');
break;
case 'answered':
return $this->setAnsweredState(1);
break;
case 'unanswered':
return $this->setAnsweredState(0);
break;
case 'overdue':
return $this->markOverdue();
break;
case 'notdue':
return $this->clearOverdue();
break;
case 'unassined':
return $this->unassign();
}
return false;
}
function setAnsweredState($isanswered) {
$sql='UPDATE '.TICKET_TABLE.' SET isanswered='.db_input($isanswered)
.' WHERE ticket_id='.db_input($this->getId());
return (db_query($sql) && db_affected_rows());
}
if (!$this->isClosed())
return false;
// Set status to open based on current closed status settings
// If the closed status doesn't have configured "reopen" status then use the
// the default ticket status.
if (!($status=$this->getStatus()->getReopenStatus()))
$status = $cfg->getDefaultTicketStatusId();
return $status ? $this->setStatus($status, 'Reopened') : false;
}
function onNewTicket($message, $autorespond=true, $alertstaff=true) {
global $cfg;
//Log stuff here...
Peter Rotich
committed
if(!$autorespond && !$alertstaff) return true; //No alerts to send.
/* ------ SEND OUT NEW TICKET AUTORESP && ALERTS ----------*/
Peter Rotich
committed
if(!$cfg
|| !($dept=$this->getDept())
|| !($tpl = $dept->getTemplate())
|| !($email=$dept->getAutoRespEmail())) {
return false; //bail out...missing stuff.
}
$options = array();
if ($message instanceof ThreadEntry) {
$options += array(
'inreplyto'=>$message->getEmailMessageId(),
'references'=>$message->getEmailReferences(),
'thread'=>$message
);
}
else {
$options += array(
'thread' => $this->getThread(),
);
}
if($autorespond
&& $cfg->autoRespONNewTicket()
Peter Rotich
committed
&& $dept->autoRespONNewTicket()
Peter Rotich
committed
$msg = $this->replaceVars($msg->asArray(),
'recipient' => $this->getOwner(),
'signature' => ($dept && $dept->isPublic())?$dept->getSignature():'')
);
$email->sendAutoReply($this->getOwner(), $msg['subj'], $msg['body'],
Peter Rotich
committed
Peter Rotich
committed
&& $cfg->alertONNewTicket()
&& ($email=$dept->getAlertEmail())
&& ($msg=$tpl->getNewTicketAlertMsgTemplate())) {
Peter Rotich
committed
$msg = $this->replaceVars($msg->asArray(), array('message' => $message));
//Exclude the auto responding email just incase it's from staff member.
if ($message instanceof ThreadEntry && $message->isAutoReply())
$sentlist[] = $this->getEmail();
//Alert admin??
if($cfg->alertAdminONNewTicket()) {
$alert = $this->replaceVars($msg, array('recipient' => 'Admin'));
$email->sendAlert($cfg->getAdminEmail(), $alert['subj'], $alert['body'], null, $options);
Peter Rotich
committed
//Only alerts dept members if the ticket is NOT assigned.
if($cfg->alertDeptMembersONNewTicket() && !$this->isAssigned()) {
if(($members=$dept->getMembersForAlerts()))
$recipients=array_merge($recipients, $members);
}
Peter Rotich
committed
if($cfg->alertDeptManagerONNewTicket() && $dept && ($manager=$dept->getManager()))
$recipients[]= $manager;
Peter Rotich
committed
// Account manager
if ($cfg->alertAcctManagerONNewMessage()
&& ($org = $this->getOwner()->getOrganization())
&& ($acct_manager = $org->getAccountManager())) {
if ($acct_manager instanceof Team)
$recipients = array_merge($recipients, $acct_manager->getMembers());
else
$recipients[] = $acct_manager;
}
Peter Rotich
committed
foreach( $recipients as $k=>$staff) {
if(!is_object($staff) || !$staff->isAvailable() || in_array($staff->getEmail(), $sentlist)) continue;
$alert = $this->replaceVars($msg, array('recipient' => $staff));
$email->sendAlert($staff, $alert['subj'], $alert['body'], null, $options);
Peter Rotich
committed
global $ost, $cfg;
//Log the limit notice as a warning for admin.
$msg=sprintf(_S('Maximum open tickets (%1$d) reached for %2$s'),
$cfg->getMaxOpenTickets(), $this->getEmail());
$ost->logWarning(sprintf(_S('Maximum Open Tickets Limit (%s)'),$this->getEmail()),
$msg);
if(!$sendNotice || !$cfg->sendOverLimitNotice())
return true;
if(($dept = $this->getDept())
&& ($tpl=$dept->getTemplate())
&& ($msg=$tpl->getOverlimitMsgTemplate())
&& ($email=$dept->getAutoRespEmail())) {
Peter Rotich
committed
$msg = $this->replaceVars($msg->asArray(),
array('signature' => ($dept && $dept->isPublic())?$dept->getSignature():''));
Peter Rotich
committed
$email->sendAutoReply($this->getOwner(), $msg['subj'], $msg['body']);
$user = $this->getOwner();
Peter Rotich
committed
//Alert admin...this might be spammy (no option to disable)...but it is helpful..I think.
$alert=sprintf(__('Maximum open tickets reached for %s.'), $this->getEmail())."\n"
.sprintf(__('Open tickets: %d'), $user->getNumOpenTickets())."\n"
.sprintf(__('Max allowed: %d'), $cfg->getMaxOpenTickets())
."\n\n".__("Notice sent to the user.");
Peter Rotich
committed
$ost->alertAdmin(__('Overlimit Notice'), $alert);
Peter Rotich
committed
db_query('UPDATE '.TICKET_TABLE.' SET isanswered=1, lastresponse=NOW(), updated=NOW() WHERE ticket_id='.db_input($this->getId()));
$this->reload();
$vars = array_merge($options,
array(
'activity' => _S('New Response'),
'threadentry' => $response));
$this->onActivity($vars);
/*
* Notify collaborators on response or new message
*
*/
function notifyCollaborators($entry, $vars = array()) {
if (!$entry instanceof ThreadEntry
|| !($dept=$this->getDept())
|| !($tpl=$dept->getTemplate())
|| !($msg=$tpl->getActivityNoticeMsgTemplate())
|| !($email=$dept->getEmail()))
return;
//Who posted the entry?
$skip = array();
if ($entry instanceof Message) {
$poster = $entry->getUser();
// Skip the person who sent in the message
$skip[$entry->getUserId()] = 1;
// Skip all the other recipients of the message
foreach ($entry->getAllEmailRecipients() as $R) {
foreach ($recipients as $R2) {
if (0 === strcasecmp($R2->getEmail(), $R->mailbox.'@'.$R->host)) {
$skip[$R2->getUserId()] = true;
break;
}
}
}
$poster = $entry->getStaff();
// Skip the ticket owner
$skip[$this->getUserId()] = 1;
$vars = array_merge($vars, array(
'message' => (string) $entry,
'poster' => $poster ?: _S('A collaborator'),
)
);
$msg = $this->replaceVars($msg->asArray(), $vars);
$attachments = $cfg->emailAttachments()?$entry->getAttachments():array();
$options = array('inreplyto' => $entry->getEmailMessageId(),
'thread' => $entry);
foreach ($recipients as $recipient) {
// Skip folks who have already been included on this part of
// the conversation
if (isset($skip[$recipient->getUserId()]))
continue;
$notice = $this->replaceVars($msg, array('recipient' => $recipient));
$email->send($recipient, $notice['subj'], $notice['body'], $attachments,
$options);
}
return;
function onMessage($message, $autorespond=true) {
db_query('UPDATE '.TICKET_TABLE.' SET isanswered=0,lastupdate=NOW(),lastmessage=NOW() WHERE ticket_id='.db_input($this->getId()));
Peter Rotich
committed
// Auto-assign to closing staff or last respondent
// If the ticket is closed and auto-claim is not enabled then put the
// ticket back to unassigned pool.
if ($this->isClosed() && !$cfg->autoClaimTickets()) {
$this->setStaffId(0);
} elseif(!($staff=$this->getStaff()) || !$staff->isAvailable()) {
// Ticket has no assigned staff - if auto-claim is enabled then
// try assigning it to the last respondent (if available)
// otherwise leave the ticket unassigned.
if ($cfg->autoClaimTickets() //Auto claim is enabled.
&& ($lastrep=$this->getLastRespondent())
&& $lastrep->isAvailable()) {
$this->setStaffId($lastrep->getId()); //direct assignment;
} else {
$this->setStaffId(0); //unassign - last respondent is not available.
}
}
// Reopen if closed AND reopenable
// We're also checking autorespond flag because we don't want to
// reopen closed tickets on auto-reply from end user. This is not to
// confused with autorespond on new message setting
if ($autorespond && $this->isClosed() && $this->isReopenable())
// Figure out the user
if ($this->getOwnerId() == $message->getUserId())
$user = new TicketOwner(
User::lookup($message->getUserId()), $this);
else
$user = Collaborator::lookup(array(
'user_id' => $message->getUserId(),
'thread_id' => $this->getThreadId()));
/********** double check auto-response ************/
if (!$user)
$autorespond=false;
elseif ($autorespond && (Email::getIdByEmail($user->getEmail())))
elseif ($autorespond && ($dept=$this->getDept()))
$autorespond=$dept->autoRespONNewMessage();
if(!$autorespond
|| !$cfg->autoRespONNewMessage()
|| !$message) return; //no autoresp or alerts.
$dept = $this->getDept();
$email = $dept->getAutoRespEmail();
Peter Rotich
committed
//If enabled...send confirmation to user. ( New Message AutoResponse)
if($email
&& ($tpl=$dept->getTemplate())
&& ($msg=$tpl->getNewMessageAutorepMsgTemplate())) {
$msg = $this->replaceVars($msg->asArray(),
array(
'recipient' => $user,
'signature' => ($dept && $dept->isPublic())?$dept->getSignature():''));
'inreplyto'=>$message->getEmailMessageId(),
'thread'=>$message);
$email->sendAutoReply($user, $msg['subj'], $msg['body'],
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
function onActivity($vars, $alert=true) {
global $cfg, $thisstaff;
//TODO: do some shit
if (!$alert // Check if alert is enabled
|| !$cfg->alertONNewActivity()
|| !($dept=$this->getDept())
|| !($email=$cfg->getAlertEmail())
|| !($tpl = $dept->getTemplate())
|| !($msg=$tpl->getNoteAlertMsgTemplate()))
return;
// Alert recipients
$recipients=array();
//Last respondent.
if ($cfg->alertLastRespondentONNewActivity())
$recipients[] = $this->getLastRespondent();
// Assigned staff / team
if ($cfg->alertAssignedONNewActivity()) {
if (isset($vars['assignee'])
&& $vars['assignee'] instanceof Staff)
$recipients[] = $vars['assignee'];
elseif ($this->isOpen() && ($assignee = $this->getStaff()))
$recipients[] = $assignee;
if ($team = $this->getTeam())
$recipients = array_merge($recipients, $team->getMembers());
}
// Dept manager
if ($cfg->alertDeptManagerONNewActivity() && $dept && $dept->getManagerId())
$recipients[] = $dept->getManager();
$options = array();
$staffId = $thisstaff ? $thisstaff->getId() : 0;
if ($vars['threadentry'] && $vars['threadentry'] instanceof ThreadEntry) {
$options = array(
'inreplyto' => $vars['threadentry']->getEmailMessageId(),
'references' => $vars['threadentry']->getEmailReferences(),
'thread' => $vars['threadentry']);
// Activity details
if (!$vars['comments'])
$vars['comments'] = $vars['threadentry'];
// Staff doing the activity
$staffId = $vars['threadentry']->getStaffId() ?: $staffId;
}
$msg = $this->replaceVars($msg->asArray(),
array(
'note' => $vars['threadentry'], // For compatibility
'activity' => $vars['activity'],
'comments' => $vars['comments']));
$isClosed = $this->isClosed();
$sentlist=array();
foreach ($recipients as $k=>$staff) {
if (!is_object($staff)
// Don't bother vacationing staff.
|| !$staff->isAvailable()
// No need to alert the poster!
|| $staffId == $staff->getId()
// No duplicates.
|| isset($sentlist[$staff->getEmail()])
// Make sure staff has access to ticket
|| ($isClosed && !$this->checkStaffPerm($staff))
)
continue;
$alert = $this->replaceVars($msg, array('recipient' => $staff));
$email->sendAlert($staff, $alert['subj'], $alert['body'], null, $options);
$sentlist[$staff->getEmail()] = 1;
}
}
function onAssign($assignee, $comments, $alert=true) {
if($this->isClosed()) $this->reopen(); //Assigned tickets must be open - otherwise why assign?
//Assignee must be an object of type Staff or Team
if(!$assignee || !is_object($assignee)) return false;
$comments = $comments ?: _S('Ticket assignment');
$assigner = $thisstaff ?: _S('SYSTEM (Auto Assignment)');
Peter Rotich
committed
//Log an internal note - no alerts on the internal note.
if ($user_comments) {
$note = $this->logNote(
sprintf(_S('Ticket Assigned to %s'), $assignee->getName()),
$comments, $assigner, false);
}
//See if we need to send alerts
if(!$alert || !$cfg->alertONAssignment()) return true; //No alerts!
$dept = $this->getDept();
if(!$dept
|| !($tpl = $dept->getTemplate())
|| !($email = $dept->getAlertEmail()))
//recipients
$recipients=array();
if ($assignee instanceof Staff) {
if ($cfg->alertStaffONAssignment())
} elseif (($assignee instanceof Team) && $assignee->alertsEnabled()) {
if ($cfg->alertTeamMembersONAssignment() && ($members=$assignee->getMembers()))
$recipients = array_merge($recipients, $members);
elseif ($cfg->alertTeamLeadONAssignment() && ($lead=$assignee->getTeamLead()))
if ($recipients
&& ($msg=$tpl->getAssignedAlertMsgTemplate())) {
$msg = $this->replaceVars($msg->asArray(),
array('comments' => $comments,
'assignee' => $assignee,
'assigner' => $assigner
'inreplyto'=>$note->getEmailMessageId(),
'references'=>$note->getEmailReferences(),
'thread'=>$note);
Peter Rotich
committed
if(!is_object($staff) || !$staff->isAvailable() || in_array($staff->getEmail(), $sentlist)) continue;
$alert = $this->replaceVars($msg, array('recipient' => $staff));
$email->sendAlert($staff, $alert['subj'], $alert['body'], null, $options);
function onOverdue($whine=true, $comments="") {
if($whine && ($sla=$this->getSLA()) && !$sla->alertOnOverdue())
$whine = false;
if(!$whine
|| !$cfg->alertONOverdueTicket()
|| !($dept = $this->getDept()))
return true;
//Get the message template
if(($tpl = $dept->getTemplate())
&& ($msg=$tpl->getOverdueAlertMsgTemplate())
&& ($email = $dept->getAlertEmail())) {
Peter Rotich
committed
$msg = $this->replaceVars($msg->asArray(),
array('comments' => $comments));
//recipients
$recipients=array();
//Assigned staff or team... if any
if($this->isAssigned() && $cfg->alertAssignedONOverdueTicket()) {
if($this->getStaffId())
$recipients[]=$this->getStaff();
elseif($this->getTeamId() && ($team=$this->getTeam()) && ($members=$team->getMembers()))
$recipients=array_merge($recipients, $members);
} elseif($cfg->alertDeptMembersONOverdueTicket() && !$this->isAssigned()) {
//Only alerts dept members if the ticket is NOT assigned.
if ($members = $dept->getMembersForAlerts())
$recipients = array_merge($recipients, $members);
}
//Always alert dept manager??
if($cfg->alertDeptManagerONOverdueTicket() && $dept && ($manager=$dept->getManager()))
$recipients[]= $manager;
$sentlist=array();
Peter Rotich
committed
foreach( $recipients as $k=>$staff) {
if(!is_object($staff) || !$staff->isAvailable() || in_array($staff->getEmail(), $sentlist)) continue;
$alert = $this->replaceVars($msg, array('recipient' => $staff));
$email->sendAlert($staff, $alert['subj'], $alert['body'], null);
Peter Rotich
committed
Peter Rotich
committed
// TemplateVariable interface
function asVar() {
return $this->getNumber();
if($tag && is_callable(array($this, 'get'.ucfirst($tag))))
return call_user_func(array($this, 'get'.ucfirst($tag)));
switch(mb_strtolower($tag)) {
case 'phone_number':
return $this->getPhoneNumber();
break;
case 'auth_token':
return $this->getOldAuthToken();
return sprintf('%s/view.php?t=%s',
$cfg->getBaseUrl(), $this->getNumber());
break;
case 'staff_link':
return sprintf('%s/scp/tickets.php?id=%d', $cfg->getBaseUrl(), $this->getId());
break;
case 'create_date':
return new FormattedDate($this->getCreateDate());
if ($due = $this->getEstDueDate())
return new FormattedDate($due);
if ($this->isClosed())
return new FormattedDate($this->getCloseDate());
case 'last_update':
return new FormattedDate($this->last_update);
case 'user':
return $this->getOwner();
default:
if (isset($this->_answers[$tag]))
// The answer object is retrieved here which will
// automatically invoke the toString() method when the
// answer is coerced into text
return $this->_answers[$tag];
static function getVarScope() {
$base = array(
'assigned' => __('Assigned agent and/or team'),
'class' => 'FormattedDate', 'desc' => __('Date Closed'),
),
'create_date' => array(
'class' => 'FormattedDate', 'desc' => __('Date created'),
'class' => 'Dept', 'desc' => __('Department'),
'class' => 'FormattedDate', 'desc' => __('Due Date'),
'email' => __('Default email address of ticket owner'),
'name' => array(
'class' => 'PersonsName', 'desc' => __('Name of ticket owner'),
),
'number' => __('Ticket number'),
'phone' => __('Phone number of ticket owner'),
'class' => 'Priority', 'desc' => __('Priority'),
),
'recipients' => array(
'class' => 'UserList', 'desc' => __('List of all recipient names'),
'source' => __('Source'),
'class' => 'TicketStatus', 'desc' => __('Status'),
),
'staff' => array(
'class' => 'Staff', 'desc' => __('Assigned/closing agent'),
),
'subject' => 'Subject',
'team' => array(
'class' => 'Team', 'desc' => __('Assigned/closing team'),
),
'thread' => array(
'class' => 'TicketThread', 'desc' => __('Ticket Thread'),
'class' => 'Topic', 'desc' => __('Help topic'),
),
// XXX: Isn't lastreponse and lastmessage more useful
'last_update' => array(
'class' => 'FormattedDate', 'desc' => __('Time of last update'),
),
'user' => array(
'class' => 'User', 'desc' => __('Ticket owner'),
),
);
$extra = VariableReplacer::compileFormScope(TicketForm::getInstance());
return $base + $extra;
}
//Replace base variables.
function replaceVars($input, $vars = array()) {
global $ost;
$vars = array_merge($vars, array('ticket' => $this));
return $ost->replaceTemplateVariables($input, $vars);
}
function markUnAnswered() {
return (!$this->isAnswered() || $this->setAnsweredState(0));
}
function markAnswered() {
return ($this->isAnswered() || $this->setAnsweredState(1));
}
function markOverdue($whine=true) {
Peter Rotich
committed
Peter Rotich
committed
if($this->isOverdue())
return true;
$sql='UPDATE '.TICKET_TABLE.' SET isoverdue=1, updated=NOW() '
.' WHERE ticket_id='.db_input($this->getId());
if(!db_query($sql) || !db_affected_rows())
return false;
$this->logEvent('overdue');
Peter Rotich
committed
if(!$this->isOverdue())
Peter Rotich
committed
//NOTE: Previously logged overdue event is NOT annuled.
$sql='UPDATE '.TICKET_TABLE.' SET isoverdue=0, updated=NOW() ';
Peter Rotich
committed
if($this->getDueDate() && Misc::db2gmtime($this->getDueDate()) <= Misc::gmtime())
Peter Rotich
committed
//Clear SLA if est. due date is in the past
if($this->getSLADueDate() && Misc::db2gmtime($this->getSLADueDate()) <= Misc::gmtime())
Peter Rotich
committed
$sql.=', sla_id=0 ';
$sql.=' WHERE ticket_id='.db_input($this->getId());
return (db_query($sql) && db_affected_rows());
}
Peter Rotich
committed
//Dept Tranfer...with alert.. done by staff
function transfer($deptId, $comments, $alert = true) {
Peter Rotich
committed
Peter Rotich
committed
if (!$this->checkStaffPerm($thisstaff, TicketModel::PERM_TRANSFER))
$currentDept = $this->getDeptName(); //Current department
if(!$deptId || !$this->setDeptId($deptId))
return false;
Peter Rotich
committed
// Reopen ticket if closed
if($this->isClosed()) $this->reopen();
$this->reload();
// Set SLA of the new department
if(!$this->getSLAId() || $this->getSLA()->isTransient())
$this->selectSLAId();
Peter Rotich
committed
// Make sure the new department allows assignment to the
// currently assigned agent (if any)
if ($this->isAssigned()
&& ($staff=$this->getStaff())
&& $dept->assignMembersOnly()
&& !$dept->isMember($staff)) {
$this->setStaffId(0);
}
/*** log the transfer comments as internal note - with alerts disabled - ***/
$title=sprintf(_S('Ticket transferred from %1$s to %2$s'),
$currentDept, $this->getDeptName());
if ($comments) {
$note = $this->logNote($title, $comments, $thisstaff, false);
}
$comments = $comments ?: $title;
Peter Rotich
committed
return true; //no alerts!!
if (($email = $dept->getAlertEmail())
&& ($tpl = $dept->getTemplate())
&& ($msg=$tpl->getTransferAlertMsgTemplate())) {
Peter Rotich
committed
$msg = $this->replaceVars($msg->asArray(),
array('comments' => $comments, 'staff' => $thisstaff));
Peter Rotich
committed
//recipients