Untitled diff

Created Diff never expires
<?php
<?php
/*********************************************************************
/*********************************************************************
class.ticket.php
class.ticket.php


The most important class! Don't play with fire please.
The most important class! Don't play with fire please.


Peter Rotich <peter@osticket.com>
Peter Rotich <peter@osticket.com>
Copyright (c) 2006-2013 osTicket
Copyright (c) 2006-2013 osTicket
http://www.osticket.com
http://www.osticket.com


Released under the GNU General Public License WITHOUT ANY WARRANTY.
Released under the GNU General Public License WITHOUT ANY WARRANTY.
See LICENSE.TXT for details.
See LICENSE.TXT for details.


vim: expandtab sw=4 ts=4 sts=4:
vim: expandtab sw=4 ts=4 sts=4:
**********************************************************************/
**********************************************************************/
include_once(INCLUDE_DIR.'class.thread.php');
include_once(INCLUDE_DIR.'class.thread.php');
include_once(INCLUDE_DIR.'class.staff.php');
include_once(INCLUDE_DIR.'class.staff.php');
include_once(INCLUDE_DIR.'class.client.php');
include_once(INCLUDE_DIR.'class.client.php');
include_once(INCLUDE_DIR.'class.team.php');
include_once(INCLUDE_DIR.'class.team.php');
include_once(INCLUDE_DIR.'class.email.php');
include_once(INCLUDE_DIR.'class.email.php');
include_once(INCLUDE_DIR.'class.dept.php');
include_once(INCLUDE_DIR.'class.dept.php');
include_once(INCLUDE_DIR.'class.topic.php');
include_once(INCLUDE_DIR.'class.topic.php');
include_once(INCLUDE_DIR.'class.lock.php');
include_once(INCLUDE_DIR.'class.lock.php');
include_once(INCLUDE_DIR.'class.file.php');
include_once(INCLUDE_DIR.'class.file.php');
include_once(INCLUDE_DIR.'class.export.php');
include_once(INCLUDE_DIR.'class.export.php');
include_once(INCLUDE_DIR.'class.attachment.php');
include_once(INCLUDE_DIR.'class.attachment.php');
include_once(INCLUDE_DIR.'class.banlist.php');
include_once(INCLUDE_DIR.'class.banlist.php');
include_once(INCLUDE_DIR.'class.template.php');
include_once(INCLUDE_DIR.'class.template.php');
include_once(INCLUDE_DIR.'class.variable.php');
include_once(INCLUDE_DIR.'class.variable.php');
include_once(INCLUDE_DIR.'class.priority.php');
include_once(INCLUDE_DIR.'class.priority.php');
include_once(INCLUDE_DIR.'class.sla.php');
include_once(INCLUDE_DIR.'class.sla.php');
include_once(INCLUDE_DIR.'class.canned.php');
include_once(INCLUDE_DIR.'class.canned.php');
require_once(INCLUDE_DIR.'class.dynamic_forms.php');
require_once(INCLUDE_DIR.'class.dynamic_forms.php');
require_once(INCLUDE_DIR.'class.user.php');
require_once(INCLUDE_DIR.'class.user.php');
require_once(INCLUDE_DIR.'class.collaborator.php');
require_once(INCLUDE_DIR.'class.collaborator.php');
require_once(INCLUDE_DIR.'class.task.php');
require_once(INCLUDE_DIR.'class.task.php');
require_once(INCLUDE_DIR.'class.faq.php');
require_once(INCLUDE_DIR.'class.faq.php');


class TicketModel extends VerySimpleModel {
class TicketModel extends VerySimpleModel {
static $meta = array(
static $meta = array(
'table' => TICKET_TABLE,
'table' => TICKET_TABLE,
'pk' => array('ticket_id'),
'pk' => array('ticket_id'),
'joins' => array(
'joins' => array(
'user' => array(
'user' => array(
'constraint' => array('user_id' => 'User.id')
'constraint' => array('user_id' => 'User.id')
),
),
'status' => array(
'status' => array(
'constraint' => array('status_id' => 'TicketStatus.id')
'constraint' => array('status_id' => 'TicketStatus.id')
),
),
'lock' => array(
'lock' => array(
'constraint' => array('lock_id' => 'Lock.lock_id'),
'constraint' => array('lock_id' => 'Lock.lock_id'),
'null' => true,
'null' => true,
),
),
'dept' => array(
'dept' => array(
'constraint' => array('dept_id' => 'Dept.id'),
'constraint' => array('dept_id' => 'Dept.id'),
),
),
'sla' => array(
'sla' => array(
'constraint' => array('sla_id' => 'Sla.id'),
'constraint' => array('sla_id' => 'Sla.id'),
'null' => true,
'null' => true,
),
),
'staff' => array(
'staff' => array(
'constraint' => array('staff_id' => 'Staff.staff_id'),
'constraint' => array('staff_id' => 'Staff.staff_id'),
'null' => true,
'null' => true,
),
),
'tasks' => array(
'tasks' => array(
'reverse' => 'Task.ticket',
'reverse' => 'Task.ticket',
),
),
'team' => array(
'team' => array(
'constraint' => array('team_id' => 'Team.team_id'),
'constraint' => array('team_id' => 'Team.team_id'),
'null' => true,
'null' => true,
),
),
'topic' => array(
'topic' => array(
'constraint' => array('topic_id' => 'Topic.topic_id'),
'constraint' => array('topic_id' => 'Topic.topic_id'),
'null' => true,
'null' => true,
),
),
'thread' => array(
'thread' => array(
'reverse' => 'TicketThread.ticket',
'reverse' => 'TicketThread.ticket',
'list' => false,
'list' => false,
'null' => true,
'null' => true,
),
),
'cdata' => array(
'cdata' => array(
'reverse' => 'TicketCData.ticket',
'reverse' => 'TicketCData.ticket',
'list' => false,
'list' => false,
),
),
'entries' => array(
'entries' => array(
'constraint' => array(
'constraint' => array(
"'T'" => 'DynamicFormEntry.object_type',
"'T'" => 'DynamicFormEntry.object_type',
'ticket_id' => 'DynamicFormEntry.object_id',
'ticket_id' => 'DynamicFormEntry.object_id',
),
),
'list' => true,
'list' => true,
),
),
)
)
);
);


const PERM_CREATE = 'ticket.create';
const PERM_CREATE = 'ticket.create';
const PERM_EDIT = 'ticket.edit';
const PERM_EDIT = 'ticket.edit';
const PERM_ASSIGN = 'ticket.assign';
const PERM_ASSIGN = 'ticket.assign';
const PERM_TRANSFER = 'ticket.transfer';
const PERM_TRANSFER = 'ticket.transfer';
const PERM_REPLY = 'ticket.reply';
const PERM_REPLY = 'ticket.reply';
const PERM_CLOSE = 'ticket.close';
const PERM_CLOSE = 'ticket.close';
const PERM_DELETE = 'ticket.delete';
const PERM_DELETE = 'ticket.delete';




static protected $perms = array(
static protected $perms = array(
self::PERM_CREATE => array(
self::PERM_CREATE => array(
'title' =>
'title' =>
/* @trans */ 'Create',
/* @trans */ 'Create',
'desc' =>
'desc' =>
/* @trans */ 'Ability to open tickets on behalf of users'),
/* @trans */ 'Ability to open tickets on behalf of users'),
self::PERM_EDIT => array(
self::PERM_EDIT => array(
'title' =>
'title' =>
/* @trans */ 'Edit',
/* @trans */ 'Edit',
'desc' =>
'desc' =>
/* @trans */ 'Ability to edit tickets'),
/* @trans */ 'Ability to edit tickets'),
self::PERM_ASSIGN => array(
self::PERM_ASSIGN => array(
'title' =>
'title' =>
/* @trans */ 'Assign',
/* @trans */ 'Assign',
'desc' =>
'desc' =>
/* @trans */ 'Ability to assign tickets to agents or teams'),
/* @trans */ 'Ability to assign tickets to agents or teams'),
self::PERM_TRANSFER => array(
self::PERM_TRANSFER => array(
'title' =>
'title' =>
/* @trans */ 'Transfer',
/* @trans */ 'Transfer',
'desc' =>
'desc' =>
/* @trans */ 'Ability to transfer tickets between departments'),
/* @trans */ 'Ability to transfer tickets between departments'),
self::PERM_REPLY => array(
self::PERM_REPLY => array(
'title' =>
'title' =>
/* @trans */ 'Post Reply',
/* @trans */ 'Post Reply',
'desc' =>
'desc' =>
/* @trans */ 'Ability to post a ticket reply'),
/* @trans */ 'Ability to post a ticket reply'),
self::PERM_CLOSE => array(
self::PERM_CLOSE => array(
'title' =>
'title' =>
/* @trans */ 'Close',
/* @trans */ 'Close',
'desc' =>
'desc' =>
/* @trans */ 'Ability to close tickets'),
/* @trans */ 'Ability to close tickets'),
self::PERM_DELETE => array(
self::PERM_DELETE => array(
'title' =>
'title' =>
/* @trans */ 'Delete',
/* @trans */ 'Delete',
'desc' =>
'desc' =>
/* @trans */ 'Ability to delete tickets'),
/* @trans */ 'Ability to delete tickets'),
);
);


// Ticket Sources
// Ticket Sources
static protected $sources = array(
static protected $sources = array(
'Phone' =>
'Phone' =>
/* @trans */ 'Phone',
/* @trans */ 'Phone',
'Email' =>
'Email' =>
/* @trans */ 'Email',
/* @trans */ 'Email',


'Web' =>
'Web' =>
/* @trans */ 'Web',
/* @trans */ 'Web',
'API' =>
'API' =>
/* @trans */ 'API',
/* @trans */ 'API',
'Other' =>
'Other' =>
/* @trans */ 'Other',
/* @trans */ 'Other',
);
);


function getId() {
function getId() {
return $this->ticket_id;
return $this->ticket_id;
}
}


function getEffectiveDate() {
function getEffectiveDate() {
return Format::datetime(max(
return Format::datetime(max(
strtotime($this->thread->lastmessage),
strtotime($this->thread->lastmessage),
strtotime($this->closed),
strtotime($this->closed),
strtotime($this->reopened),
strtotime($this->reopened),
strtotime($this->created)
strtotime($this->created)
));
));
}
}


static function registerCustomData(DynamicForm $form) {
static function registerCustomData(DynamicForm $form) {
if (!isset(static::$meta['joins']['cdata+'.$form->id])) {
if (!isset(static::$meta['joins']['cdata+'.$form->id])) {
$cdata_class = <<<EOF
$cdata_class = <<<EOF
class DynamicForm{$form->id} extends DynamicForm {
class DynamicForm{$form->id} extends DynamicForm {
static function getInstance() {
static function getInstance() {
static \$instance;
static \$instance;
if (!isset(\$instance))
if (!isset(\$instance))
\$instance = static::lookup({$form->id});
\$instance = static::lookup({$form->id});
return \$instance;
return \$instance;
}
}
}
}
class TicketCdataForm{$form->id}
class TicketCdataForm{$form->id}
extends VerySimpleModel {
extends VerySimpleModel {
static \$meta = array(
static \$meta = array(
'view' => true,
'view' => true,
'pk' => array('ticket_id'),
'pk' => array('ticket_id'),
'joins' => array(
'joins' => array(
'ticket' => array(
'ticket' => array(
'constraint' => array('ticket_id' => 'TicketModel.ticket_id'),
'constraint' => array('ticket_id' => 'TicketModel.ticket_id'),
),
),
)
)
);
);
static function getQuery(\$compiler) {
static function getQuery(\$compiler) {
return '('.DynamicForm{$form->id}::getCrossTabQuery('T', 'ticket_id').')';
return '('.DynamicForm{$form->id}::getCrossTabQuery('T', 'ticket_id').')';
}
}
}
}
EOF;
EOF;
eval($cdata_class);
eval($cdata_class);
$join = array(
$join = array(
'constraint' => array('ticket_id' => 'TicketCdataForm'.$form->id.'.ticket_id'),
'constraint' => array('ticket_id' => 'TicketCdataForm'.$form->id.'.ticket_id'),
'list' => true,
'list' => true,
);
);
// This may be necessary if the model has already been inspected
// This may be necessary if the model has already been inspected
if (static::$meta instanceof ModelMeta)
if (static::$meta instanceof ModelMeta)
static::$meta->addJoin('cdata+'.$form->id, $join);
static::$meta->addJoin('cdata+'.$form->id, $join);
else {
else {
static::$meta['joins']['cdata+'.$form->id] = array(
static::$meta['joins']['cdata+'.$form->id] = array(
'constraint' => array('ticket_id' => 'TicketCdataForm'.$form->id.'.ticket_id'),
'constraint' => array('ticket_id' => 'TicketCdataForm'.$form->id.'.ticket_id'),
'list' => true,
'list' => true,
);
);
}
}
}
}
}
}


static function getPermissions() {
static function getPermissions() {
return self::$perms;
return self::$perms;
}
}


static function getSources() {
static function getSources() {
static $translated = false;
static $translated = false;
if (!$translated) {
if (!$translated) {
foreach (static::$sources as $k=>$v)
foreach (static::$sources as $k=>$v)
static::$sources[$k] = __($v);
static::$sources[$k] = __($v);
}
}


return static::$sources;
return static::$sources;
}
}
}
}


RolePermission::register(/* @trans */ 'Tickets', TicketModel::getPermissions(), true);
RolePermission::register(/* @trans */ 'Tickets', TicketModel::getPermissions(), true);


class TicketCData extends VerySimpleModel {
class TicketCData extends VerySimpleModel {
static $meta = array(
static $meta = array(
'table' => TICKET_CDATA_TABLE,
'table' => TICKET_CDATA_TABLE,
'pk' => array('ticket_id'),
'pk' => array('ticket_id'),
'joins' => array(
'joins' => array(
'ticket' => array(
'ticket' => array(
'constraint' => array('ticket_id' => 'TicketModel.ticket_id'),
'constraint' => array('ticket_id' => 'TicketModel.ticket_id'),
),
),
':priority' => array(
':priority' => array(
'constraint' => array('priority' => 'Priority.priority_id'),
'constraint' => array('priority' => 'Priority.priority_id'),
'null' => true,
'null' => true,
),
),
),
),
);
);
}
}


class Ticket extends TicketModel
class Ticket extends TicketModel
implements RestrictedAccess, Threadable {
implements RestrictedAccess, Threadable {


static $meta = array(
static $meta = array(
'select_related' => array('topic', 'staff', 'user', 'team', 'dept', 'sla', 'thread',
'select_related' => array('topic', 'staff', 'user', 'team', 'dept', 'sla', 'thread',
'user__default_email'),
'user__default_email'),
);
);


var $lastMsgId;
var $lastMsgId;
var $last_message;
var $last_message;


var $owner; // TicketOwner
var $owner; // TicketOwner
var $_user; // EndUser
var $_user; // EndUser
var $_answers;
var $_answers;
var $collaborators;
var $collaborators;
var $active_collaborators;
var $active_collaborators;
var $recipients;
var $recipients;
var $lastrespondent;
var $lastrespondent;


function __onload() {
function __onload() {
$this->loadDynamicData();
$this->loadDynamicData();
}
}


function loadDynamicData($force=false) {
function loadDynamicData($force=false) {
if (!isset($this->_answers) || $force) {
if (!isset($this->_answers) || $force) {
$this->_answers = array();
$this->_answers = array();
foreach (DynamicFormEntryAnswer::objects()
foreach (DynamicFormEntryAnswer::objects()
->filter(array(
->filter(array(
'entry__object_id' => $this->getId(),
'entry__object_id' => $this->getId(),
'entry__object_type' => 'T'
'entry__object_type' => 'T'
)) as $answer
)) as $answer
) {
) {
$tag = mb_strtolower($answer->field->name)
$tag = mb_strtolower($answer->field->name)
?: 'field.' . $answer->field->id;
?: 'field.' . $answer->field->id;
$this->_answers[$tag] = $answer;
$this->_answers[$tag] = $answer;
}
}
}
}
return $this->_answers;
return $this->_answers;
}
}


function hasState($state) {
function hasState($state) {
return strcasecmp($this->getState(), $state) == 0;
return strcasecmp($this->getState(), $state) == 0;
}
}


function isOpen() {
function isOpen() {
return $this->hasState('open');
return $this->hasState('open');
}
}


function isReopened() {
function isReopened() {
return null !== $this->getReopenDate();
return null !== $this->getReopenDate();
}
}


function isReopenable() {
function isReopenable() {
return $this->getStatus()->isReopenable();
return $this->getStatus()->isReopenable();
}
}


function isClosed() {
function isClosed() {
return $this->hasState('closed');
return $this->hasState('closed');
}
}


function isCloseable() {
function isCloseable() {


if ($this->isClosed())
if ($this->isClosed())
return true;
return true;


$warning = null;
$warning = null;
if ($this->getMissingRequiredFields()) {
if ($this->getMissingRequiredFields()) {
$warning = sprintf(
$warning = sprintf(
__( '%1$s is missing data on %2$s one or more required fields %3$s and cannot be closed'),
__( '%1$s is missing data on %2$s one or more required fields %3$s and cannot be closed'),
__('This ticket'),
__('This ticket'),
'', '');
'', '');
} elseif (($num=$this->getNumOpenTasks())) {
} elseif (($num=$this->getNumOpenTasks())) {
$warning = sprintf(__('%1$s has %2$d open tasks and cannot be closed'),
$warning = sprintf(__('%1$s has %2$d open tasks and cannot be closed'),
__('This ticket'), $num);
__('This ticket'), $num);
}
}


return $warning ?: true;
return $warning ?: true;
}
}


function isArchived() {
function isArchived() {
return $this->hasState('archived');
return $this->hasState('archived');
}
}


function isDeleted() {
function isDeleted() {
return $this->hasState('deleted');
return $this->hasState('deleted');
}
}


function isAssigned() {
function isAssigned() {
return $this->isOpen() && ($this->getStaffId() || $this->getTeamId());
return $this->isOpen() && ($this->getStaffId() || $this->getTeamId());
}
}


function isOverdue() {
function isOverdue() {
return $this->ht['isoverdue'];
return $this->ht['isoverdue'];
}
}


function isAnswered() {
function isAnswered() {
return $this->ht['isanswered'];
return $this->ht['isanswered'];
}
}


function isLocked() {
function isLocked() {
return null !== $this->getLock();
return null !== $this->getLock();
}
}


function checkStaffPerm($staff, $perm=null) {
function checkStaffPerm($staff, $perm=null) {
// Must be a valid staff
// Must be a valid staff
if (!$staff instanceof Staff && !($staff=Staff::lookup($staff)))
if (!$staff instanceof Staff && !($staff=Staff::lookup($staff)))
return false;
return false;


// Check access based on department or assignment
// Check access based on department or assignment
if (($staff->showAssignedOnly()
if (($staff->showAssignedOnly()
|| !$staff->canAccessDept($this->getDeptId()))
|| !$staff->canAccessDept($this->getDeptId()))
// only open tickets can be considered assigned
// only open tickets can be considered assigned
&& $this->isOpen()
&& $this->isOpen()
&& $staff->getId() != $this->getStaffId()
&& $staff->getId() != $this->getStaffId()
&& !$staff->isTeamMember($this->getTeamId())
&& !$staff->isTeamMember($this->getTeamId())
) {
) {
return false;
return false;
}
}


// At this point staff has view access unless a specific permission is
// At this point staff has view access unless a specific permission is
// requested
// requested
if ($perm === null)
if ($perm === null)
return true;
return true;


// Permission check requested -- get role.
// Permission check requested -- get role.
if (!($role=$staff->getRole($this->getDeptId())))
if (!($role=$staff->getRole($this->getDeptId())))
return false;
return false;


// Check permission based on the effective role
// Check permission based on the effective role
return $role->hasPerm($perm);
return $role->hasPerm($perm);
}
}


function checkUserAccess($user) {
function checkUserAccess($user) {
if (!$user || !($user instanceof EndUser))
if (!$user || !($user instanceof EndUser))
return false;
return false;


// Ticket Owner
// Ticket Owner
if ($user->getId() == $this->getUserId())
if ($user->getId() == $this->getUserId())
return true;
return true;


// Organization
// Organization
if ($user->canSeeOrgTickets()
if ($user->canSeeOrgTickets()
&& ($U = $this->getUser())
&& ($U = $this->getUser())
&& ($U->getOrgId() == $user->getOrgId())
&& ($U->getOrgId() == $user->getOrgId())
) {
) {
// The owner of this ticket is in the same organization as the
// The owner of this ticket is in the same organization as the
// user in question, and the organization is configured to allow
// user in question, and the organization is configured to allow
// the user in question to see other tickets in the
// the user in question to see other tickets in the
// organization.
// organization.
return true;
return true;
}
}


// Collaborator?
// Collaborator?
// 1) If the user was authorized via this ticket.
// 1) If the user was authorized via this ticket.
if ($user->getTicketId() == $this->getId()
if ($user->getTicketId() == $this->getId()
&& !strcasecmp($user->getUserType(), 'collaborator')
&& !strcasecmp($user->getUserType(), 'collaborator')
) {
) {
return true;
return true;
}
}
// 2) Query the database to check for expanded access...
// 2) Query the database to check for expanded access...
if (Collaborator::lookup(array(
if (Collaborator::lookup(array(
'user_id' => $user->getId(),
'user_id' => $user->getId(),
'thread_id' => $this->getThreadId()))
'thread_id' => $this->getThreadId()))
) {
) {
return true;
return true;
}
}
return false;
return false;
}
}


// Getters
// Getters
function getNumber() {
function getNumber() {
return $this->number;
return $this->number;
}
}


function getOwnerId() {
function getOwnerId() {
return $this->user_id;
return $this->user_id;
}
}


function getOwner() {
function getOwner() {
if (!isset($this->owner)) {
if (!isset($this->owner)) {
$this->owner = new TicketOwner(new EndUser($this->user), $this);
$this->owner = new TicketOwner(new EndUser($this->user), $this);
}
}
return $this->owner;
return $this->owner;
}
}


function getEmail() {
function getEmail() {
if ($o = $this->getOwner()) {
if ($o = $this->getOwner()) {
return $o->getEmail();
return $o->getEmail();
}
}
return null;
return null;
}
}


function getReplyToEmail() {
function getReplyToEmail() {
//TODO: Determine the email to use (once we enable multi-email support)
//TODO: Determine the email to use (once we enable multi-email support)
return $this->getEmail();
return $this->getEmail();
}
}


// Deprecated
// Deprecated
function getOldAuthToken() {
function getOldAuthToken() {
# XXX: Support variable email address (for CCs)
# XXX: Support variable email address (for CCs)
return md5($this->getId() . strtolower($this->getEmail()) . SECRET_SALT);
return md5($this->getId() . strtolower($this->getEmail()) . SECRET_SALT);
}
}


function getName(){
function getName(){
if ($o = $this->getOwner()) {
if ($o = $this->getOwner()) {
return $o->getName();
return $o->getName();
}
}
return null;
return null;
}
}


function getSubject() {
function getSubject() {
return (string) $this->_answers['subject'];
return (string) $this->_answers['subject'];
}
}


/* Help topic title - NOT object -> $topic */
/* Help topic title - NOT object -> $topic */
function getHelpTopic() {
function getHelpTopic() {
if ($this->topic)
if ($this->topic)
return $this->topic->getFullName();
return $this->topic->getFullName();
}
}


function getCreateDate() {
function getCreateDate() {
return $this->created;
return $this->created;
}
}


function getOpenDate() {
function getOpenDate() {
return $this->getCreateDate();
return $this->getCreateDate();
}
}


function getReopenDate() {
function getReopenDate() {
return $this->reopened;
return $this->reopened;
}
}


function getUpdateDate() {
function getUpdateDate() {
return $this->updated;
return $this->updated;
}
}


function getEffectiveDate() {
function getEffectiveDate() {
return $this->lastupdate;
return $this->lastupdate;
}
}


function getDueDate() {
function getDueDate() {
return $this->duedate;
return $this->duedate;
}
}


function getSLADueDate() {
function getSLADueDate() {
if ($sla = $this->getSLA()) {
if ($sla = $this->getSLA()) {
$dt = new DateTime($this->getCreateDate());
$dt = new DateTime($this->getCreateDate());


return $dt
return $dt
->add(new DateInterval('PT' . $sla->getGracePeriod() . 'H'))
->add(new DateInterval('PT' . $sla->getGracePeriod() . 'H'))
->format('Y-m-d H:i:s');
->format('Y-m-d H:i:s');
}
}
}
}


function updateEstDueDate() {
function updateEstDueDate() {
$this->est_duedate = $this->getEstDueDate();
$this->est_duedate = $this->getEstDueDate();
$this->save();
$this->save();
}
}


function getEstDueDate() {
function getEstDueDate() {
// Real due date
// Real due date
if ($duedate = $this->getDueDate()) {
if ($duedate = $this->getDueDate()) {
return $duedate;
return $duedate;
}
}
// return sla due date (If ANY)
// return sla due date (If ANY)
return $this->getSLADueDate();
return $this->getSLADueDate();
}
}


function getCloseDate() {
function getCloseDate() {
return $this->closed;
return $this->closed;
}
}


function getStatusId() {
function getStatusId() {
return $this->status_id;
return $this->status_id;
}
}


/**
/**
* setStatusId
* setStatusId
*
*
* Forceably set the ticket status ID to the received status ID. No
* Forceably set the ticket status ID to the received status ID. No
* checks are made. Use ::setStatus() to change the ticket status
* checks are made. Use ::setStatus() to change the ticket status
*/
*/
// XXX: Use ::setStatus to change the status. This can be used as a
// XXX: Use ::setStatus to change the status. This can be used as a
// fallback if the logic in ::setStatus fails.
// fallback if the logic in ::setStatus fails.
function setStatusId($id) {
function setStatusId($id) {
$this->status_id = $id;
$this->status_id = $id;
return $this->save();
return $this->save();
}
}


function getStatus() {
function getStatus() {
return $this->status;
return $this->status;
}
}


function getState() {
function getState() {
if (!$this->getStatus()) {
if (!$this->getStatus()) {
return '';
return '';
}
}
return $this->getStatus()->getState();
return $this->getStatus()->getState();
}
}


function getDeptId() {
function getDeptId() {
return $this->dept_id;
return $this->dept_id;
}
}


function getDeptName() {
function getDeptName() {
if ($this->dept instanceof Dept)
if ($this->dept instanceof Dept)
return $this->dept->getFullName();
return $this->dept->getFullName();
}
}


function getPriorityId() {
function getPriorityId() {
global $cfg;
global $cfg;


if (($a = $this->_answers['priority'])
if (($a = $this->_answers['priority'])
&& ($b = $a->getValue())
&& ($b = $a->getValue())
) {
) {
return $b->getId();
return $b->getId();
}
}
return $cfg->getDefaultPriorityId();
return $cfg->getDefaultPriorityId();
}
}


function getPriority() {
function getPriority() {
if (($a = $this->_answers['priority']) && ($b = $a->getValue()))
if (($a = $this->_answers['priority']) && ($b = $a->getValue()))
return $b->getDesc();
return $b->getDesc();
return '';
return '';
}
}


function getPhoneNumber() {
function getPhoneNumber() {
return (string)$this->getOwner()->getPhoneNumber();
return (string)$this->getOwner()->getPhoneNumber();
}
}


function getSource() {
function getSource() {
return $this->source;
return $this->source;
}
}


function getIP() {
function getIP() {
return $this->ip_address;
return $this->ip_address;
}
}


function getHashtable() {
function getHashtable() {
return $this->ht;
return $this->ht;
}
}


function getUpdateInfo() {
function getUpdateInfo() {
global $cfg;
global $cfg;


return array(
return array(
'source' => $this->getSource(),
'source' => $this->getSource(),
'topicId' => $this->getTopicId(),
'topicId' => $this->getTopicId(),
'slaId' => $this->getSLAId(),
'slaId' => $this->getSLAId(),
'user_id' => $this->getOwnerId(),
'user_id' => $this->getOwnerId(),
'duedate' => $this->getDueDate()
'duedate' => $this->getDueDate()
? Format::date($this->getDueDate(), true,
? Format::date($this->getDueDate(), true,
$cfg->getDateFormat(true))
$cfg->getDateFormat(true))
: '',
: '',
'time' => $this->getDueDate()
'time' => $this->getDueDate()
? Format::time($this->getDueDate(), true, 'HH:mm')
? Format::time($this->getDueDate(), true, 'HH:mm')
: '',
: '',
);
);


}
}


function getLock() {
function getLock() {
$lock = $this->lock;
$lock = $this->lock;
if ($lock && !$lock->isExpired())
if ($lock && !$lock->isExpired())
return $lock;
return $lock;
}
}


function acquireLock($staffId, $lockTime=null) {
function acquireLock($staffId, $lockTime=null) {
global $cfg;
global $cfg;


if (!isset($lockTime))
if (!isset($lockTime))
$lockTime = $cfg->getLockTime();
$lockTime = $cfg->getLockTime();


if (!$staffId or !$lockTime) //Lockig disabled?
if (!$staffId or !$lockTime) //Lockig disabled?
return null;
return null;


// Check if the ticket is already locked.
// Check if the ticket is already locked.
if (($lock = $this->getLock()) && !$lock->isExpired()) {
if (($lock = $this->getLock()) && !$lock->isExpired()) {
if ($lock->getStaffId() != $staffId) //someone else locked the ticket.
if ($lock->getStaffId() != $staffId) //someone else locked the ticket.
return null;
return null;


//Lock already exits...renew it
//Lock already exits...renew it
$lock->renew($lockTime); //New clock baby.
$lock->renew($lockTime); //New clock baby.


return $lock;
return $lock;
}
}
// No lock on the ticket or it is expired
// No lock on the ticket or it is expired
$this->lock = Lock::acquire($staffId, $lockTime); //Create a new lock..
$this->lock = Lock::acquire($staffId, $lockTime); //Create a new lock..


if ($this->lock) {
if ($this->lock) {
$this->save();
$this->save();
}
}


// load and return the newly created lock if any!
// load and return the newly created lock if any!
return $this->lock;
return $this->lock;
}
}


function releaseLock($staffId=false) {
function releaseLock($staffId=false) {
if (!($lock = $this->getLock()))
if (!($lock = $this->getLock()))
return false;
return false;


if ($staffId && $lock->staff_id != $staffId)
if ($staffId && $lock->staff_id != $staffId)
return false;
return false;


if (!$lock->delete())
if (!$lock->delete())
return false;
return false;


$this->lock = null;
$this->lock = null;
return $this->save();
return $this->save();
}
}


function getDept() {
function getDept() {
global $cfg;
global $cfg;


return $this->dept ?: $cfg->getDefaultDept();
return $this->dept ?: $cfg->getDefaultDept();
}
}


function getUserId() {
function getUserId() {
return $this->getOwnerId();
return $this->getOwnerId();
}
}


function getUser() {
function getUser() {
if (!isset($this->_user) && $this->user) {
if (!isset($this->_user) && $this->user) {
$this->_user = new EndUser($this->user);
$this->_user = new EndUser($this->user);
}
}
return $this->_user;
return $this->_user;
}
}


function getStaffId() {
function getStaffId() {
return $this->staff_id;
return $this->staff_id;
}
}


function getStaff() {
function getStaff() {
return $this->staff;
return $this->staff;
}
}


function getTeamId() {
function getTeamId() {
return $this->team_id;
return $this->team_id;
}
}


function getTeam() {
function getTeam() {
return $this->team;
return $this->team;
}
}


function getAssigneeId() {
function getAssigneeId() {


if (!($assignee=$this->getAssignee()))
if (!($assignee=$this->getAssignee()))
return null;
return null;


$id = '';
$id = '';
if ($assignee instanceof Staff)
if ($assignee instanceof Staff)
$id = 's'.$assignee->getId();
$id = 's'.$assignee->getId();
elseif ($assignee instanceof Team)
elseif ($assignee instanceof Team)
$id = 't'.$assignee->getId();
$id = 't'.$assignee->getId();


return $id;
return $id;
}
}


function getAssignee() {
function getAssignee() {


if (!$this->isOpen() || !$this->isAssigned())
if (!$this->isOpen() || !$this->isAssigned())
return false;
return false;


if ($this->staff)
if ($this->staff)
return $this->staff;
return $this->staff;


if ($this->team)
if ($this->team)
return $this->team;
return $this->team;


return null;
return null;
}
}


function getAssignees() {
function getAssignees() {


$assignees = array();
$assignees = array();
if ($staff = $this->getStaff())
if ($staff = $this->getStaff())
$assignees[] = $staff->getName();
$assignees[] = $staff->getName();


if ($team = $this->getTeam())
if ($team = $this->getTeam())
$assignees[] = $team->getName();
$assignees[] = $team->getName();


return $assignees;
return $assignees;
}
}


function getAssigned($glue='/') {
function getAssigned($glue='/') {
$assignees = $this->getAssignees();
$assignees = $this->getAssignees();
return $assignees ? implode($glue, $assignees) : '';
return $assignees ? implode($glue, $assignees) : '';
}
}


function getTopicId() {
function getTopicId() {
return $this->topic_id;
return $this->topic_id;
}
}


function getTopic() {
function getTopic() {
return $this->topic;
return $this->topic;
}
}




function getSLAId() {
function getSLAId() {
return $this->sla_id;
return $this->sla_id;
}
}


function getSLA() {
function getSLA() {
return $this->sla;
return $this->sla;
}
}


function getLastRespondent() {
function getLastRespondent() {
if (!isset($this->lastrespondent)) {
if (!isset($this->lastrespondent)) {
if (!$this->thread || !$this->thread->entries)
if (!$this->thread || !$this->thread->entries)
return $this->lastrespondent = false;
return $this->lastrespondent = false;
$this->lastrespondent = Staff::objects()
$this->lastrespondent = Staff::objects()
->filter(array(
->filter(array(
'staff_id' => $this->thread->entries
'staff_id' => $this->thread->entries
->filter(array(
->filter(array(
'type' => 'R',
'type' => 'R',
'staff_id__gt' => 0,
'staff_id__gt' => 0,
))
))
->values_flat('staff_id')
->values_flat('staff_id')
->order_by('-id')
->order_by('-id')
->limit(1)
->limit(1)
))
))
->first()
->first()
?: false;
?: false;
}
}
return $this->lastrespondent;
return $this->lastrespondent;
}
}


function getLastMessageDate() {
function getLastMessageDate() {
return $this->thread->lastmessage;
return $this->thread->lastmessage;
}
}


function getLastMsgDate() {
function getLastMsgDate() {
return $this->getLastMessageDate();
return $this->getLastMessageDate();
}
}


function getLastResponseDate() {
function getLastResponseDate() {
return $this->thread->lastresponse;
return $this->thread->lastresponse;
}
}


function getLastRespDate() {
function getLastRespDate() {
return $this->getLastResponseDate();
return $this->getLastResponseDate();
}
}


function getLastMsgId() {
function getLastMsgId() {
return $this->lastMsgId;
return $this->lastMsgId;
}
}


function getLastMessage() {
function getLastMessage() {
if (!isset($this->last_message)) {
if (!isset($this->last_message)) {
if ($this->getLastMsgId())
if ($this->getLastMsgId())
$this->last_message = MessageThreadEntry::lookup(
$this->last_message = MessageThreadEntry::lookup(
$this->getLastMsgId(), $this->getThreadId());
$this->getLastMsgId(), $this->getThreadId());


if (!$this->last_message)
if (!$this->last_message)
$this->last_message = $this->getThread()->getLastMessage();
$this->last_message = $this->getThread()->getLastMessage();
}
}
return $this->last_message;
return $this->last_message;
}
}


function getNumTasks() {
function getNumTasks() {
// FIXME: Implement this after merging Tasks
// FIXME: Implement this after merging Tasks
return count($this->tasks);
return count($this->tasks);
}
}


function getNumOpenTasks() {
function getNumOpenTasks() {
return count($this->tasks->filter(array(
return count($this->tasks->filter(array(
'flags__hasbit' => TaskModel::ISOPEN)));
'flags__hasbit' => TaskModel::ISOPEN)));
}
}




function getThreadId() {
function getThreadId() {
if ($this->thread)
if ($this->thread)
return $this->thread->id;
return $this->thread->id;
}
}


function getThread() {
function getThread() {
return $this->thread;
return $this->thread;
}
}


function getThreadCount() {
function getThreadCount() {
return $this->getClientThread()->count();
return $this->getClientThread()->count();
}
}


function getNumMessages() {
function getNumMessages() {
return $this->getThread()->getNumMessages();
return $this->getThread()->getNumMessages();
}
}


function getNumResponses() {
function getNumResponses() {
return $this->getThread()->getNumResponses();
return $this->getThread()->getNumResponses();
}
}


function getNumNotes() {
function getNumNotes() {
return $this->getThread()->getNumNotes();
return $this->getThread()->getNumNotes();
}
}


function getMessages() {
function getMessages() {
return $this->getThreadEntries(array('M'));
return $this->getThreadEntries(array('M'));
}
}


function getResponses() {
function getResponses() {
return $this->getThreadEntries(array('R'));
return $this->getThreadEntries(array('R'));
}
}


function getNotes() {
function getNotes() {
return $this->getThreadEntries(array('N'));
return $this->getThreadEntries(array('N'));
}
}


function getClientThread() {
function getClientThread() {
return $this->getThreadEntries(array('M', 'R'));
return $this->getThreadEntries(array('M', 'R'));
}
}


function getThreadEntry($id) {
function getThreadEntry($id) {
return $this->getThread()->getEntry($id);
return $this->getThread()->getEntry($id);
}
}


function getThreadEntries($type=false) {
function getThreadEntries($type=false) {
$entries = $this->getThread()->getEntries();
$entries = $this->getThread()->getEntries();
if ($type && is_array($type))
if ($type && is_array($type))
$entries->filter(array('type__in' => $type));
$entries->filter(array('type__in' => $type));


return $entries;
return $entries;
}
}


//UserList of recipients (owner + collaborators)
//UserList of recipients (owner + collaborators)
function getRecipients() {
function getRecipients() {
if (!isset($this->recipients)) {
if (!isset($this->recipients)) {
$list = new UserList();
$list = new UserList();
$list->add($this->getOwner());
$list->add($this->getOwner());
if ($collabs = $this->getThread()->getActiveCollaborators()) {
if ($collabs = $this->getThread()->getActiveCollaborators()) {
foreach ($collabs as $c)
foreach ($collabs as $c)
$list->add($c);
$list->add($c);
}
}
$this->recipients = $list;
$this->recipients = $list;
}
}
return $this->recipients;
return $this->recipients;
}
}


function getAssignmentForm($source=null, $options=array()) {
function getAssignmentForm($source=null, $options=array()) {


$prompt = $assignee = '';
$prompt = $assignee = '';
// Possible assignees
// Possible assignees
$assignees = array();
$assignees = array();
switch (strtolower($options['target'])) {
switch (strtolower($options['target'])) {
case 'agents':
case 'agents':
$dept = $this->getDept();
$dept = $this->getDept();
foreach ($dept->getAssignees() as $member)
foreach ($dept->getAssignees() as $member)
$assignees['s'.$member->getId()] = $member;
$assignees['s'.$member->getId()] = $member;


if (!$source && $this->isOpen() && $this->staff)
if (!$source && $this->isOpen() && $this->staff)
$assignee = sprintf('s%d', $this->staff->getId());
$assignee = sprintf('s%d', $this->staff->getId());
$prompt = __('Select an Agent');
$prompt = __('Select an Agent');
break;
break;
case 'teams':
case 'teams':
if (($teams = Team::getActiveTeams()))
if (($teams = Team::getActiveTeams()))
foreach ($teams as $id => $name)
foreach ($teams as $id => $name)
$assignees['t'.$id] = $name;
$assignees['t'.$id] = $name;