Skip to content
Snippets Groups Projects
class.ticket.php 77.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • Jared Hancock's avatar
    Jared Hancock committed
    <?php
    /*********************************************************************
        class.ticket.php
    
        The most important class! Don't play with fire please.
    
        Peter Rotich <peter@osticket.com>
        Copyright (c)  2006-2012 osTicket
        http://www.osticket.com
    
        Released under the GNU General Public License WITHOUT ANY WARRANTY.
        See LICENSE.TXT for details.
    
        vim: expandtab sw=4 ts=4 sts=4:
    **********************************************************************/
    include_once(INCLUDE_DIR.'class.staff.php');
    
    include_once(INCLUDE_DIR.'class.client.php');
    
    Jared Hancock's avatar
    Jared Hancock committed
    include_once(INCLUDE_DIR.'class.team.php');
    include_once(INCLUDE_DIR.'class.email.php');
    include_once(INCLUDE_DIR.'class.dept.php');
    include_once(INCLUDE_DIR.'class.topic.php');
    include_once(INCLUDE_DIR.'class.lock.php');
    include_once(INCLUDE_DIR.'class.file.php');
    include_once(INCLUDE_DIR.'class.attachment.php');
    
    include_once(INCLUDE_DIR.'class.pdf.php');
    
    Jared Hancock's avatar
    Jared Hancock committed
    include_once(INCLUDE_DIR.'class.banlist.php');
    include_once(INCLUDE_DIR.'class.template.php');
    include_once(INCLUDE_DIR.'class.priority.php');
    
    Peter Rotich's avatar
    Peter Rotich committed
    include_once(INCLUDE_DIR.'class.sla.php');
    
    Jared Hancock's avatar
    Jared Hancock committed
    
    class Ticket{
    
        var $id;
        var $extid;
        var $email;
        var $status;
        var $created;
        var $reopened;
        var $updated;
        var $lastrespdate;
        var $lastmsgdate;
        var $duedate;
        var $priority;
        var $priority_id;
        var $fullname;
        var $staff_id;
        var $team_id;
        var $dept_id;
        var $topic_id;
        var $dept_name;
        var $subject;
        var $helptopic;
        var $overdue;
    
        var $lastMsgId;
        
        var $dept;  //Dept obj
        var $sla;   // SLA obj
        var $staff; //Staff obj
    
        var $client; //Client Obj
    
    Jared Hancock's avatar
    Jared Hancock committed
        var $team;  //Team obj
        var $topic; //Topic obj
        var $tlock; //TicketLock obj
        
        function Ticket($id){
            $this->id = 0;
            $this->load($id);
        }
        
        function load($id=0) {
    
            if(!$id && !($id=$this->getId()))
                return false;
    
            //TODO: delete helptopic field in ticket table.
           
            $sql='SELECT  ticket.*, topic.topic as helptopic, lock_id, dept_name, priority_desc '
                .' ,count(attach.attach_id) as attachments '
    
                .' ,count(DISTINCT message.id) as messages '
                .' ,count(DISTINCT response.id) as responses '
                .' ,count(DISTINCT note.id) as notes '
    
    Jared Hancock's avatar
    Jared Hancock committed
                .' FROM '.TICKET_TABLE.' ticket '
                .' LEFT JOIN '.DEPT_TABLE.' dept ON (ticket.dept_id=dept.dept_id) '
    
                .' LEFT JOIN '.TICKET_PRIORITY_TABLE.' pri ON ('
                    .'ticket.priority_id=pri.priority_id) '
                .' LEFT JOIN '.TOPIC_TABLE.' topic ON ('
                    .'ticket.topic_id=topic.topic_id) '
                .' LEFT JOIN '.TICKET_LOCK_TABLE.' tlock ON ('
                    .'ticket.ticket_id=tlock.ticket_id AND tlock.expire>NOW()) '
                .' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach ON ('
                    .'ticket.ticket_id=attach.ticket_id) '
                .' LEFT JOIN '.TICKET_THREAD_TABLE.' message ON ('
                    ."ticket.ticket_id=message.ticket_id AND message.thread_type = 'M') "
                .' LEFT JOIN '.TICKET_THREAD_TABLE.' response ON ('
                    ."ticket.ticket_id=response.ticket_id AND response.thread_type = 'R') "
                .' LEFT JOIN '.TICKET_THREAD_TABLE.' note ON ( '
                    ."ticket.ticket_id=note.ticket_id AND note.thread_type = 'N') "
    
    Jared Hancock's avatar
    Jared Hancock committed
                .' WHERE ticket.ticket_id='.db_input($id)
                .' GROUP BY ticket.ticket_id';
    
            //echo $sql;
            if(!($res=db_query($sql)) || !db_num_rows($res))
                return false;
    
            
            $this->ht=db_fetch_array($res);
            
            $this->id       = $this->ht['ticket_id'];
            $this->extid    = $this->ht['ticketID'];
             
            $this->email    = $this->ht['email'];
            $this->fullname = $this->ht['name'];
            $this->status   = $this->ht['status'];
            $this->created  = $this->ht['created'];
            $this->reopened = $this->ht['reopened'];
            $this->updated  = $this->ht['updated'];
            $this->duedate  = $this->ht['duedate'];
            $this->closed   = $this->ht['closed'];
            $this->lastmsgdate  = $this->ht['lastmessagedate'];
            $this->lastrespdate = $this->ht['lastresponsedate'];
            
            $this->lock_id  = $this->ht['lock_id'];
            $this->priority_id = $this->ht['priority_id'];
            $this->priority = $this->ht['priority_desc'];
            $this->staff_id = $this->ht['staff_id'];
            $this->team_id = $this->ht['team_id']; 
            $this->dept_id  = $this->ht['dept_id'];
            $this->dept_name = $this->ht['dept_name'];
            $this->sla_id = $this->ht['sla_id'];
            $this->topic_id = $this->ht['topic_id'];
            $this->helptopic = $this->ht['helptopic'];
            $this->subject = $this->ht['subject'];
            $this->overdue = $this->ht['isoverdue'];
            
            //Reset the sub classes (initiated ondemand)...good for reloads.
            $this->staff = null;
    
            $this->client = null;
    
    Jared Hancock's avatar
    Jared Hancock committed
            $this->team  = null;
            $this->dept = null;
            $this->sla = null;
            $this->tlock = null;
            $this->stats = null;
            $this->topic = null;
            
            return true;
        }
            
        function reload() {
            return $this->load();
        }
        
        function isOpen() {
            return (strcasecmp($this->getStatus(),'Open')==0);
        }
    
        function isReopened() {
            return ($this->getReopenDate());
        }
    
        function isClosed() {
            return (strcasecmp($this->getStatus(),'Closed')==0);
        }
    
        function isAssigned() {
            return ($this->isOpen() && ($this->getStaffId() || $this->getTeamId()));
        }
    
        function isOverdue() {
            return ($this->overdue);
        }
        
        function isAnswered() {
           return ($this->ht['isanswered']);
        }
    
        function isLocked() {
            return ($this->getLockId());
        }
    
        function checkStaffAccess($staff) {
    
            if(!is_object($staff) && !($staff=Staff::lookup($staff)))
                return false;
    
    
            return ((!$staff->showAssignedOnly() && $staff->canAccessDept($this->getDeptId()))
    
    Jared Hancock's avatar
    Jared Hancock committed
                     || ($this->getTeamId() && $staff->isTeamMember($this->getTeamId()))
                     || $staff->getId()==$this->getStaffId());
        }
    
    
        function checkClientAccess($client) {
            global $cfg;
    
            if(!is_object($client) && !($client=Client::lookup($client)))
                return false;
    
            if(!strcasecmp($client->getEmail(),$this->getEmail()))
                return true;
    
    
    Jared Hancock's avatar
    Jared Hancock committed
            return ($cfg && $cfg->showRelatedTickets() 
                && $client->getTicketId()==$this->getExtId());
    
    Jared Hancock's avatar
    Jared Hancock committed
        //Getters
        function getId(){
            return  $this->id;
        }
    
        function getExtId(){
            return  $this->extid;
        }
       
        function getEmail(){
            return $this->email;
        }
    
        function getName(){
            return $this->fullname;
        }
    
        function getSubject() {
            return $this->subject;
        }
    
        /* Help topic title  - NOT object -> $topic */
        function getHelpTopic() {
    
            if(!$this->helpTopic && ($topic=$this->getTopic()))
                $this->helpTopic = $topic->getName();
                
            return $this->helptopic;
        }
       
        function getCreateDate(){
            return $this->created;
        }
    
        function getOpenDate() {
            return $this->getCreateDate();
        }
    
        function getReopenDate() {
            return $this->reopened;
        }
        
        function getUpdateDate(){
            return $this->updated;
        }
    
        function getDueDate(){
            return $this->duedate;
        }
    
        function getCloseDate(){
            return $this->closed;
        }
    
        function getStatus(){
            return $this->status;
        }
       
        function getDeptId(){
           return $this->dept_id;
        }
       
        function getDeptName(){
           return $this->dept_name;
        }
    
        function getPriorityId() {
            return $this->priority_id;
        }
        
        function getPriority() {
            return $this->priority;
        }
         
        function getPhone() {
            return $this->ht['phone'];
        }
    
        function getPhoneExt() {
            return $this->ht['phone_ext'];
        }
    
        function getPhoneNumber() {
            $phone=Format::phone($this->getPhone());
            if(($ext=$this->getPhoneExt()))
                $phone.=" $ext";
    
            return $phone;
        }
    
        function getSource() {
            return $this->ht['source'];
        }
        
        function getIP() {
            return $this->ht['ip_address'];
        }
    
    
    Peter Rotich's avatar
    Peter Rotich committed
        function getHashtable() {
            return $this->ht;
        }
    
        function getUpdateInfo() {
    
            $info=array('name'  =>  $this->getName(),
                        'email' =>  $this->getEmail(),
                        'phone' =>  $this->getPhone(),
                        'phone_ext' =>  $this->getPhoneExt(),
                        'subject'   =>  $this->getSubject(),
                        'source'    =>  $this->getSource(),
                        'topicId'   =>  $this->getTopicId(),
                        'priorityId'    =>  $this->getPriorityId(),
                        'slaId' =>  $this->getSLAId(),
                        'duedate'   =>  $this->getDueDate()?(Format::userdate('m/d/Y', Misc::db2gmtime($this->getDueDate()))):'',
                        'time'  =>  $this->getDueDate()?(Format::userdate('G:i', Misc::db2gmtime($this->getDueDate()))):'',
                        );
                      
            return $info;
        }
    
    
    Jared Hancock's avatar
    Jared Hancock committed
        function getLockId() {
            return $this->lock_id;
        }
        
        function getLock(){
            
            if(!$this->tlock && $this->getLockId())
                $this->tlock= TicketLock::lookup($this->getLockId(),$this->getId());
            
            return $this->tlock;
        }
        
        function acquireLock($staffId, $lockTime) {
           
            if(!$staffId or !$lockTime) //Lockig disabled?
                return null;
    
            //Check if the ticket is already locked.
            if(($lock=$this->getLock()) && !$lock->isExpired()) {
                if($lock->getStaffId()!=$staffId) //someone else locked the ticket.
                    return null;
    
                //Lock already exits...renew it
                $lock->renew($lockTime); //New clock baby.
                
                return $lock;
            }
            //No lock on the ticket or it is expired
            $this->tlock=null; //clear crap
            $this->lock_id=TicketLock::acquire($this->getId(), $staffId, $lockTime); //Create a new lock..
            //load and return the newly created lock if any!
            return $this->getLock();
        }
        
        function getDept(){
            
            if(!$this->dept && $this->getDeptId())
                $this->dept= Dept::lookup($this->getDeptId());
    
            return $this->dept;
        }
    
    
        function getClient() {
    
            if(!$this->client)
                $this->client = Client::lookup($this->getExtId(), $this->getEmail());
    
            return $this->client;
        }
    
    Jared Hancock's avatar
    Jared Hancock committed
        
        function getStaffId(){
            return $this->staff_id;
        }
    
        function getStaff(){
    
            if(!$this->staff && $this->getStaffId())
                $this->staff= Staff::lookup($this->getStaffId());
    
            return $this->staff;
        }
    
        function getTeamId(){
            return $this->team_id;
        }
    
        function getTeam(){
    
            if(!$this->team && $this->getTeamId())
                $this->team = Team::lookup($this->getTeamId());
    
            return $this->team;
        }
    
        function getAssignee() {
    
            if($staff=$this->getStaff())
                return $staff->getName();
    
            if($team=$this->getTeam())
                return $team->getName();
    
            return '';
        }
    
    
    Peter Rotich's avatar
    Peter Rotich committed
        function getAssignees() {
         
    
            $assignees=array();
    
    Peter Rotich's avatar
    Peter Rotich committed
            if($staff=$this->getStaff())
    
                $assignees[] = $staff->getName();
    
    Peter Rotich's avatar
    Peter Rotich committed
                           
            if($team=$this->getTeam())
    
                $assignees[] = $team->getName();
    
    Peter Rotich's avatar
    Peter Rotich committed
    
            return $assignees;
        }
    
    Jared Hancock's avatar
    Jared Hancock committed
    
        function getTopicId(){
            return $this->topic_id;
        }
    
        function getTopic() { 
    
            if(!$this->topic && $this->getTopicId())
                $this->topic = Topic::lookup($this->getTopicId);
    
            return $this->topic;
        }
    
     
        function getSLAId() {
            return $this->sla_id;
        }
    
        function getSLA() {
    
            if(!$this->sla && $this->getSLAId())
                $this->sla = SLA::lookup($this->getSLAId);
    
            return $this->sla;
        }
    
        function getLastRespondent() {
    
            $sql ='SELECT  resp.staff_id '
    
                 .' FROM '.TICKET_THREAD_TABLE.' resp '
    
    Jared Hancock's avatar
    Jared Hancock committed
                 .' LEFT JOIN '.STAFF_TABLE. ' USING(staff_id) '
                 .' WHERE  resp.ticket_id='.db_input($this->getId()).' AND resp.staff_id>0 '
    
                 .'   AND  resp.thread_type="R"'
    
    Jared Hancock's avatar
    Jared Hancock committed
                 .' ORDER BY resp.created DESC LIMIT 1';
    
            if(!($res=db_query($sql)) || !db_num_rows($res))
                return null;
                
            list($id)=db_fetch_row($res);
    
            return Staff::lookup($id);
    
        }
    
        function getLastMessageDate() {
    
            if($this->lastmsgdate)
                return $this->lastmsgdate;
    
            //for old versions...XXX: still needed????
    
            $sql='SELECT created FROM '.TICKET_THREAD_TABLE
    
    Jared Hancock's avatar
    Jared Hancock committed
                .' WHERE ticket_id='.db_input($this->getId())
    
                ."   AND thread_type = 'M'"
    
    Jared Hancock's avatar
    Jared Hancock committed
                .' ORDER BY created DESC LIMIT 1';
            if(($res=db_query($sql)) && db_num_rows($res))
                list($this->lastmsgdate)=db_fetch_row($res);
    
            return $this->lastmsgdate;
        }
    
        function getLastMsgDate() {
            return $this->getLastMessageDate();
        }
    
        function getLastResponseDate() {
                   
            if($this->lastrespdate)
                return $this->lastrespdate;
    
    
            $sql='SELECT created FROM '.TICKET_THREAD_TABLE
    
    Jared Hancock's avatar
    Jared Hancock committed
                .' WHERE ticket_id='.db_input($this->getId())
    
                .'   AND thread_type="R"'
    
    Jared Hancock's avatar
    Jared Hancock committed
                .' ORDER BY created DESC LIMIT 1';
            if(($res=db_query($sql)) && db_num_rows($res))
                list($this->lastrespdate)=db_fetch_row($res);
    
            return $this->lastrespdate;
        }
    
        function getLastRespDate() {
            return $this->getLastResponseDate();
        }
    
            
        function getLastMsgId() {
            return $this->lastMsgId;
        }
    
        function getRelatedTicketsCount(){
    
    
            $sql='SELECT count(*)  FROM '.TICKET_TABLE
                .' WHERE email='.db_input($this->getEmail());
    
            return db_result(db_query($sql));
    
    Jared Hancock's avatar
    Jared Hancock committed
        }
    
        function getThreadCount() {
            return $this->getNumMessages() + $this->getNumResponses();
        }
    
        function getNumMessages() {
            return $this->ht['messages'];
        }
    
        function getNumResponses() {
            return $this->ht['responses'];
        }
    
        function getNumNotes() {
            return $this->ht['notes'];
        }
    
    
        function getMessages() {
            return $this->getThreadByType('M');
        }
    
        function getResponses($msgId=0) {
            return $this->getThreadByType('R', $msgID);
        }
    
        function getNotes() {
            return $this->getThreadByType('N');
    
        function getClientThread() {
    
            return $this->getThreadWithoutNotes();
    
        function getThreadWithNotes() {
            return $this->getThread(true);
        }
        
        function getThreadWithoutNotes() {
            return $this->getThread(false);
        }
    
        function getThread($includeNotes=false, $order='') {
    
            $treadtypes=array('M', 'R'); // messages and responses.
            if($includeNotes) //Include notes??
                $treadtypes[] = 'N';
    
    
            return $this->getThreadByType($treadtypes, $order);
    
            
        function getThreadByType($type, $order='ASC') {
    
            if(!$order || !in_array($order, array('DESC','ASC')))
                $order='ASC';
    
            $sql='SELECT thread.* '
                .' ,count(DISTINCT attach.attach_id) as attachments '
                .' FROM '.TICKET_THREAD_TABLE.' thread '
    
    Jared Hancock's avatar
    Jared Hancock committed
                .' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach 
    
                    ON (thread.ticket_id=attach.ticket_id 
                            AND thread.id=attach.ref_id 
                            AND thread.thread_type=attach.ref_type) '
                .' WHERE  thread.ticket_id='.db_input($this->getId());
    
            if($type && is_array($type))
                $sql.=" AND thread.thread_type IN('".implode("','", $type)."')";
    
                $sql.=' AND thread.thread_type='.db_input($type);
    
            $sql.=' GROUP BY thread.id '
                 .' ORDER BY thread.created '.$order;
    
            $thread=array();
    
    Jared Hancock's avatar
    Jared Hancock committed
            if(($res=db_query($sql)) && db_num_rows($res))
    
                while($rec=db_fetch_array($res))
                    $thread[] = $rec;
    
            return $thread;
    
    Jared Hancock's avatar
    Jared Hancock committed
        }
    
        function getAttachments($refId=0, $type=null) {
    
            if($refId && !$type)
                return NULL;
    
            //XXX: inner join the file table instead?
            $sql='SELECT a.attach_id, f.id as file_id, f.size, f.hash as file_hash, f.name '
                .' FROM '.FILE_TABLE.' f '
                .' INNER JOIN '.TICKET_ATTACHMENT_TABLE.' a ON(f.id=a.file_id) '
                .' WHERE a.ticket_id='.db_input($this->getId());
           
            if($refId) 
                $sql.=' AND a.ref_id='.db_input($refId);
    
            if($type)
                $sql.=' AND a.ref_type='.db_input($type);
    
            $attachments = array();
            if(($res=db_query($sql)) && db_num_rows($res)) {
                while($rec=db_fetch_array($res))
                    $attachments[] = $rec;
            }
    
            return $attachments;
        }
    
        function getAttachmentsLinks($refId, $type, $separator=' ',$target='') {
    
            $str='';
            foreach($this->getAttachments($refId, $type) as $attachment ) {
                /* The has here can be changed  but must match validation in attachment.php */
                $hash=md5($attachment['file_id'].session_id().$attachment['file_hash']); 
                if($attachment['size'])
    
                    $size=sprintf('<em>(%s)</em>', Format::file_size($attachment['size']));
    
    Jared Hancock's avatar
    Jared Hancock committed
                    
                $str.=sprintf('<a class="Icon file" href="attachment.php?id=%d&h=%s" target="%s">%s</a>%s&nbsp;%s',
                        $attachment['attach_id'], $hash, $target, Format::htmlchars($attachment['name']), $size, $separator);
            }
    
            return $str;
        }
    
        /* -------------------- Setters --------------------- */
        function setLastMsgId($msgid) {
            return $this->lastMsgId=$msgid;
        }
    
        function setPriority($priorityId) {
    
            //XXX: what happens to SLA priority???
            
            if(!$priorityId || $priorityId==$this->getPriorityId()) 
                return ($priorityId);
            
            $sql='UPDATE '.TICKET_TABLE.' SET updated=NOW() '
                .', priority_id='.db_input($priorityId)
                .' WHERE ticket_id='.db_input($this->getId());
    
    
    Jared Hancock's avatar
    Jared Hancock committed
            return (($res=db_query($sql)) && db_affected_rows($res));
    
    Jared Hancock's avatar
    Jared Hancock committed
        }
    
        //DeptId can NOT be 0. No orphans please!
        function setDeptId($deptId){
            
            //Make sure it's a valid department//
            if(!($dept=Dept::lookup($deptId)))
                return false;
    
          
            $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());
        }
     
        //Set staff ID...assign/unassign/release (id can be 0)
        function setStaffId($staffId){
           
    
            $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()) {
                $this->staff_id = $staffId;
                return true;
            }
            return false;
    
    Jared Hancock's avatar
    Jared Hancock committed
        }
    
        function setSLAId($slaId) {
            if ($slaId == $this->getSLAId()) return true;
            return db_query(
                 'UPDATE '.TICKET_TABLE.' SET sla_id='.db_input($slaId)
                .' WHERE ticket_id='.db_input($this->getId()))
                && db_affected_rows();
        }
        /**
         * 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 usefule,
         * 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 overwritten if it was originally set via an
            #     email filter? This method doesn't consider such a case
            if ($trump !== null) {
                $slaId = $trump;
            } elseif ($this->getDept()->getSLAId()) {
                $slaId = $this->getDept()->getSLAId();
            } elseif ($this->getTopicId() && $this->getTopic()) {
                $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)
        function setTeamId($teamId){
    
          $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());
        }
    
        //Status helper.
        function setStatus($status) {
    
            if(strcasecmp($this->getStatus(),$status)==0)
                return true; //No changes needed.
    
            switch(strtolower($status)) {
                case 'open':
                    return $this->reopen();
                    break;
                case 'closed':
                    return $this->close();
                    break;
            }
    
            return false;
        }
    
        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;
            }
    
            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());
        }
    
        //Close the ticket
        function close(){
            global $thisstaff;
            
            $sql='UPDATE '.TICKET_TABLE.' SET closed=NOW(), isoverdue=0, duedate=NULL, updated=NOW(), status='.db_input('closed');
            
            if($thisstaff) //Give the closing  staff credit. 
                $sql.=', staff_id='.db_input($thisstaff->getId());
    
            $sql.=' WHERE ticket_id='.db_input($this->getId());
    
    
            $this->logEvent('closed');
    
    Jared Hancock's avatar
    Jared Hancock committed
            return (db_query($sql) && db_affected_rows());
        }
    
        //set status to open on a closed ticket.
        function reopen($isanswered=0){
    
            $sql='UPDATE '.TICKET_TABLE.' SET updated=NOW(), reopened=NOW() '
                .' ,status='.db_input('open')
                .' ,isanswered='.db_input($isanswered)
                .' WHERE ticket_id='.db_input($this->getId());
    
            //TODO: log reopen event here 
    
    
            $this->logEvent('reopened', 'closed');
    
    Jared Hancock's avatar
    Jared Hancock committed
            return (db_query($sql) && db_affected_rows());
        }
    
        function onNewTicket($message, $autorespond=true, $alertstaff=true) {
            global $cfg;
    
            //Log stuff here...
            
            if(!$autorespond && !$alertstaff) return true; //No alerts to send.
    
            /* ------ SEND OUT NEW TICKET AUTORESP && ALERTS ----------*/
            
            $this->reload(); //get the new goodies.
            $dept= $this->getDept();
    
            if(!$dept || !($tpl = $dept->getTemplate()))
                $tpl= $cfg->getDefaultTemplate();
            
            if(!$tpl) return false;  //bail out...missing stuff.
    
            if(!$dept || !($email=$dept->getAutoRespEmail()))
                $email =$cfg->getDefaultEmail();
    
            //Send auto response - if enabled.
            if($autorespond && $email && $cfg->autoRespONNewTicket() 
                    && $dept->autoRespONNewTicket() 
                    &&  ($msg=$tpl->getAutoRespMsgTemplate())) {
                  
                $body=$this->replaceTemplateVars($msg['body']);
                $subj=$this->replaceTemplateVars($msg['subj']);
                $body = str_replace('%message', $message, $body);
                $body = str_replace('%signature',($dept && $dept->isPublic())?$dept->getSignature():'',$body);
                
                if($cfg->stripQuotedReply() && ($tag=$cfg->getReplySeparator()))
                    $body ="\n$tag\n\n".$body;
                
                //TODO: add auto flags....be nice to mail servers and sysadmins!!
                $email->send($this->getEmail(),$subj,$body);
            }
            
            if(!($email=$cfg->getAlertEmail()))
                $email =$cfg->getDefaultEmail();
              
            //Send alert to out sleepy & idle staff.
            if($alertstaff && $email
                    && $cfg->alertONNewTicket() 
                    && ($msg=$tpl->getNewTicketAlertMsgTemplate())) {
                  
                $body=$this->replaceTemplateVars($msg['body']);
                $subj=$this->replaceTemplateVars($msg['subj']);
                $body = str_replace('%message', $message, $body);
                
                $recipients=$sentlist=array();
                
                //Alert admin??
                if($cfg->alertAdminONNewTicket()) {
                    $alert = str_replace("%staff",'Admin',$body);
                    $email->send($cfg->getAdminEmail(),$subj,$alert);
                    $sentlist[]=$cfg->getAdminEmail();
                }
                  
                //Only alerts dept members if the ticket is NOT assigned.
                if($cfg->alertDeptMembersONNewTicket() && !$this->isAssigned()) {
    
    Peter Rotich's avatar
    Peter Rotich committed
                    if(($members=$dept->getMembers()))
    
    Jared Hancock's avatar
    Jared Hancock committed
                        $recipients=array_merge($recipients, $members);
                }
                
                if($cfg->alertDeptManagerONNewTicket() && $dept && ($manager=$dept->getManager()))
                    $recipients[]= $manager;
                   
                foreach( $recipients as $k=>$staff){
                    if(!is_object($staff) || !$staff->isAvailable() || in_array($staff->getEmail(),$sentlist)) continue;
                    $alert = str_replace("%staff",$staff->getFirstName(),$body);
                    $email->send($staff->getEmail(),$subj,$alert);
    
    Peter Rotich's avatar
    Peter Rotich committed
                    $sentlist[] = $staff->getEmail();
    
        function onOpenLimit($sendNotice=true) {
    
    
            //Log the limit notice as a warning for admin.
            $msg=sprintf('Max open tickets (%d) reached  for %s ', $cfg->getMaxOpenTickets(), $this->getEmail());
    
            $ost->logWarning('Max. Open Tickets Limit ('.$this->getEmail().')', $msg);
    
            if(!$sendNotice || !$cfg->sendOverLimitNotice()) return true;
    
    
            //Send notice to user.
            $dept = $this->getDept();
                        
            if(!$dept || !($tpl=$dept->getTemplate()))
                $tpl=$cfg->getDefaultTemplate();
                
            if(!$dept || !($email=$dept->getAutoRespEmail()))
                $email=$cfg->getDefaultEmail();
    
            if($tpl && ($msg=$tpl->getOverlimitMsgTemplate()) && $email) {
                $body=$this->replaceTemplateVars($msg['body']);
                $subj=$this->replaceTemplateVars($msg['subj']);
                $body = str_replace('%signature',($dept && $dept->isPublic())?$dept->getSignature():'',$body);
                $email->send($this->getEmail(), $subj, $body);
            }
    
            $client= $this->getClient();
            
            //Alert admin...this might be spammy (no option to disable)...but it is helpful..I think.
            $msg='Max. open tickets reached for '.$this->getEmail()."\n"
                .'Open ticket: '.$client->getNumOpenTickets()."\n"
                .'Max Allowed: '.$cfg->getMaxOpenTickets()."\n\nNotice sent to the user.";
                
    
            $ost->alertAdmin('Overlimit Notice', $msg);
    
    Jared Hancock's avatar
    Jared Hancock committed
        function onResponse(){
            db_query('UPDATE '.TICKET_TABLE.' SET isanswered=1,lastresponse=NOW(), updated=NOW() WHERE ticket_id='.db_input($this->getId()));
        }
    
        function onMessage($autorespond=true, $alert=true){
            global $cfg;
    
            db_query('UPDATE '.TICKET_TABLE.' SET isanswered=0,lastmessage=NOW() WHERE ticket_id='.db_input($this->getId()));
                
            //auto-assign to closing staff or last respondent 
            if(!($staff=$this->getStaff()) || !$staff->isAvailable()) {
                if($cfg->autoAssignReopenedTickets() && ($lastrep=$this->getLastRespondent()) && $lastrep->isAvailable()) {
                    $this->setStaffId($lastrep->getId()); //direct assignment;
                } else {
                    $this->setStaffId(0); //unassign - last respondent is not available.
                }
            }
    
            if($this->isClosed()) $this->reopen(); //reopen..
    
           /**********   double check auto-response  ************/
            if($autorespond && (Email::getIdByEmail($this->getEmail())))
                $autorespond=false;
            elseif($autorespond && ($dept=$this->getDept()))
                $autorespond=$dept->autoRespONNewMessage();
    
    
            if(!$autorespond && !$cfg->autoRespONNewMessage()) return;  //no autoresp or alerts.
    
            $this->reload();
    
    
    
            if(!$dept || !($tpl = $dept->getTemplate()))
    
    Jared Hancock's avatar
    Jared Hancock committed
                $tpl= $cfg->getDefaultTemplate();
           
            //If enabled...send confirmation to user. ( New Message AutoResponse)
            if($tpl && ($msg=$tpl->getNewMessageAutorepMsgTemplate())) {
                            
                $body=$this->replaceTemplateVars($msg['body']);
                $subj=$this->replaceTemplateVars($msg['subj']);
                $body = str_replace('%signature',($dept && $dept->isPublic())?$dept->getSignature():'',$body);
    
                //Reply separator tag.
                if($cfg->stripQuotedReply() && ($tag=$cfg->getReplySeparator()))
                    $body ="\n$tag\n\n".$body;
                
                if(!$dept || !($email=$dept->getAutoRespEmail()))
                    $email=$cfg->getDefaultEmail();
                
                if($email) {
    
                    $email->send($this->getEmail(),$subj,$body);
    
    Jared Hancock's avatar
    Jared Hancock committed
                }
            }
    
        }
    
        function onAssign($note, $alert=true) {
    
    Jared Hancock's avatar
    Jared Hancock committed
            global $cfg, $thisstaff;
    
    Jared Hancock's avatar
    Jared Hancock committed
    
            if($this->isClosed()) $this->reopen(); //Assigned tickets must be open - otherwise why assign?
    
            $this->reload();
    
            //Log an internal note - no alerts on the internal note.
            $note=$note?$note:'Ticket assignment';
            $this->postNote('Ticket Assigned to '.$this->getAssignee(),$note,false);
    
            //See if we need to send alerts
            if(!$alert || !$cfg->alertONAssignment()) return true; //No alerts!
    
            $dept = $this->getDept();
    
            //Get template.
    
            if(!$dept || !($tpl = $dept->getTemplate()))
    
    Jared Hancock's avatar
    Jared Hancock committed
                $tpl= $cfg->getDefaultTemplate();