Skip to content
Snippets Groups Projects
class.ticket.php 98.3 KiB
Newer Older
Jared Hancock's avatar
Jared Hancock committed
            $recipients=$sentlist=array();
            //Exclude the auto responding email just incase it's from staff member.
            if ($message->isAutoReply())
                $sentlist[] = $this->getEmail();

Jared Hancock's avatar
Jared Hancock committed
            //Alert admin??
            if($cfg->alertAdminONNewTicket()) {
                $alert = $this->replaceVars($msg, array('recipient' => 'Admin'));
                $email->sendAlert($cfg->getAdminEmail(), $alert['subj'], $alert['body'], null, $options);
Jared Hancock's avatar
Jared Hancock committed
                $sentlist[]=$cfg->getAdminEmail();
            }
Jared Hancock's avatar
Jared Hancock committed
            //Only alerts dept members if the ticket is NOT assigned.
            if($cfg->alertDeptMembersONNewTicket() && !$this->isAssigned()) {
                if(($members=$dept->getMembersForAlerts()))
Jared Hancock's avatar
Jared Hancock committed
                    $recipients=array_merge($recipients, $members);
            }
Jared Hancock's avatar
Jared Hancock committed
            if($cfg->alertDeptManagerONNewTicket() && $dept && ($manager=$dept->getManager()))
                $recipients[]= $manager;
            // 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;
            }

            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->getEmail(), $alert['subj'], $alert['body'], null, $options);
Peter Rotich's avatar
Peter Rotich committed
                $sentlist[] = $staff->getEmail();
Jared Hancock's avatar
Jared Hancock committed
        return true;
    }

    function onOpenLimit($sendNotice=true) {

        //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;

        //Send notice to user.
        if(($dept = $this->getDept())
            && ($tpl=$dept->getTemplate())
            && ($msg=$tpl->getOverlimitMsgTemplate())
            && ($email=$dept->getAutoRespEmail())) {
            $msg = $this->replaceVars($msg->asArray(),
                        array('signature' => ($dept && $dept->isPublic())?$dept->getSignature():''));
            $email->sendAutoReply($this->getEmail(), $msg['subj'], $msg['body']);
        $user = $this->getOwner();
        //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.");
        $ost->alertAdmin(__('Overlimit Notice'), $alert);
        db_query('UPDATE '.TICKET_TABLE.' SET isanswered=1, lastresponse=NOW(), updated=NOW() WHERE ticket_id='.db_input($this->getId()));
        $this->reload();
    }

    /*
     * Notify collaborators on response or new message
     *
     */

    function  notifyCollaborators($entry, $vars = array()) {
        if (!$entry instanceof ThreadEntry
                || !($recipients=$this->getRecipients())
                || !($dept=$this->getDept())
                || !($tpl=$dept->getTemplate())
                || !($msg=$tpl->getActivityNoticeMsgTemplate())
                || !($email=$dept->getEmail()))
            return;

        //Who posted the entry?
        $uid = 0;
        if ($entry instanceof Message) {
            $poster = $entry->getUser();
            // Skip the person who sent in the message
            $uid = $entry->getUserId();
            $poster = $entry->getStaff();
            // Skip the ticket owner
            $uid = $this->getUserId();
        }
        $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) {
            if ($uid == $recipient->getUserId()) continue;
            $options['references'] =  $entry->getEmailReferencesForUser($recipient);
            $notice = $this->replaceVars($msg, array('recipient' => $recipient));
            $email->send($recipient->getEmail(), $notice['subj'], $notice['body'], $attachments,
    function onMessage($message, $autorespond=true) {
Jared Hancock's avatar
Jared Hancock committed
        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 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()) {
Jared Hancock's avatar
Jared Hancock committed
                $this->setStaffId($lastrep->getId()); //direct assignment;
            } else {
                $this->setStaffId(0); //unassign - last respondent is not available.
            }
        }

        // Reopen if closed AND reopenable
        if ($this->isClosed() && $this->isReopenable())
            $this->reopen();
Jared Hancock's avatar
Jared Hancock committed

       /**********   double check auto-response  ************/
        if (!($user = $message->getUser()))
            $autorespond=false;
        elseif ($autorespond && (Email::getIdByEmail($user->getEmail())))
Jared Hancock's avatar
Jared Hancock committed
            $autorespond=false;
        elseif ($autorespond && ($dept=$this->getDept()))
Jared Hancock's avatar
Jared Hancock committed
            $autorespond=$dept->autoRespONNewMessage();


        if(!$autorespond
                || !$cfg->autoRespONNewMessage()
                || !$message) return;  //no autoresp or alerts.

Jared Hancock's avatar
Jared Hancock committed
        $this->reload();
        $dept = $this->getDept();
        $email = $dept->getAutoRespEmail();
Jared Hancock's avatar
Jared Hancock 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(),
                'references' => $message->getEmailReferencesForUser($user),
                'thread'=>$message);
            $email->sendAutoReply($user->getEmail(), $msg['subj'], $msg['body'],
    function onAssign($assignee, $comments, $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?

        //Assignee must be an object of type Staff or Team
        if(!$assignee || !is_object($assignee)) return false;

Jared Hancock's avatar
Jared Hancock committed
        $this->reload();

        $comments = $comments ?: _S('Ticket assignment');
        $assigner = $thisstaff ?: _S('SYSTEM (Auto Assignment)');
        //Log an internal note - no alerts on the internal note.
        $note = $this->logNote(
            sprintf(_S('Ticket Assigned to %s'), $assignee->getName()),
            $comments, $assigner, false);
Jared Hancock's avatar
Jared Hancock committed

        //See if we need to send alerts
        if(!$alert || !$cfg->alertONAssignment()) return true; //No alerts!

        $dept = $this->getDept();
        if(!$dept
                || !($tpl = $dept->getTemplate())
                || !($email = $cfg->getAlertEmail()))
            return true;

        //recipients
        $recipients=array();
        if ($assignee instanceof Staff) {
            if ($cfg->alertStaffONAssignment())
                $recipients[] = $assignee;
        } elseif (($assignee instanceof Team) && $assignee->alertsEnabled()) {
            if ($cfg->alertTeamMembersONAssignment() && ($members=$assignee->getMembers()))
                $recipients = array_merge($recipients, $members);
            elseif ($cfg->alertTeamLeadONAssignment() && ($lead=$assignee->getTeamLead()))
                $recipients[] = $lead;
        }
Jared Hancock's avatar
Jared Hancock committed

        //Get the message template
        if ($recipients
                && ($msg=$tpl->getAssignedAlertMsgTemplate())) {
            $msg = $this->replaceVars($msg->asArray(),
                        array('comments' => $comments,
                              'assignee' => $assignee,
                              'assigner' => $assigner
Jared Hancock's avatar
Jared Hancock committed
            //Send the alerts.
            $sentlist=array();
                'inreplyto'=>$note->getEmailMessageId(),
                'references'=>$note->getEmailReferences(),
                'thread'=>$note);
            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->getEmail(), $alert['subj'], $alert['body'], null, $options);
Peter Rotich's avatar
Peter Rotich committed
                $sentlist[] = $staff->getEmail();
Jared Hancock's avatar
Jared Hancock committed
   function onOverdue($whine=true, $comments="") {
Jared Hancock's avatar
Jared Hancock committed
        global $cfg;

        if($whine && ($sla=$this->getSLA()) && !$sla->alertOnOverdue())
            $whine = false;
Jared Hancock's avatar
Jared Hancock committed

        //check if we need to send alerts.
        if(!$whine
                || !$cfg->alertONOverdueTicket()
                || !($dept = $this->getDept()))
Jared Hancock's avatar
Jared Hancock committed
            return true;

        //Get the message template
        if(($tpl = $dept->getTemplate())
                && ($msg=$tpl->getOverdueAlertMsgTemplate())
                && ($email=$cfg->getAlertEmail())) {
            $msg = $this->replaceVars($msg->asArray(),
                array('comments' => $comments));
Jared Hancock's avatar
Jared Hancock committed

            //recipients
            $recipients=array();
            //Assigned staff or team... if any
            if($this->isAssigned() && $cfg->alertAssignedONOverdueTicket()) {
Jared Hancock's avatar
Jared Hancock committed
                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);
Jared Hancock's avatar
Jared Hancock committed
            }
            //Always alert dept manager??
            if($cfg->alertDeptManagerONOverdueTicket() && $dept && ($manager=$dept->getManager()))
                $recipients[]= $manager;

            $sentlist=array();
            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->getEmail(), $alert['subj'], $alert['body'], null);
Peter Rotich's avatar
Peter Rotich committed
                $sentlist[] = $staff->getEmail();
    //ticket obj as variable = ticket number.
    function asVar() {
       return $this->getNumber();
    function getVar($tag) {
Jared Hancock's avatar
Jared Hancock committed
        global $cfg;

        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->getAuthToken();
                break;
            case 'client_link':
                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 Format::datetime($this->getCreateDate(), true, 'UTC');
                break;
             case 'due_date':
                $duedate ='';
                if($this->getEstDueDate())
                    $duedate = Format::datetime($this->getEstDueDate(), true, 'UTC');

                return $duedate;
                break;
M. Hagen's avatar
M. Hagen committed
            case 'close_date':
                $closedate ='';
                if($this->isClosed())
                    $closedate = Format::datetime($this->getCloseDate(), true, 'UTC');

                return $closedate;
                break;
            case 'user':
                return $this->getOwner();
                break;
Jared Hancock's avatar
Jared Hancock committed
            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];

        return false;
    }

    //Replace base variables.
    function replaceVars($input, $vars = array()) {
        global $ost;

        $vars = array_merge($vars, array('ticket' => $this));

        return $ost->replaceTemplateVariables($input, $vars);
Jared Hancock's avatar
Jared Hancock committed
    }

    function markUnAnswered() {
        return (!$this->isAnswered() || $this->setAnsweredState(0));
    }

    function markAnswered() {
        return ($this->isAnswered() || $this->setAnsweredState(1));
    }

    function markOverdue($whine=true) {
Jared Hancock's avatar
Jared Hancock committed
        global $cfg;
Jared Hancock's avatar
Jared Hancock committed
        if($this->isOverdue())
            return true;

        $sql='UPDATE '.TICKET_TABLE.' SET isoverdue=1, updated=NOW() '
Jared Hancock's avatar
Jared Hancock committed
            .' WHERE ticket_id='.db_input($this->getId());

        if(!db_query($sql) || !db_affected_rows())
            return false;

        $this->logEvent('overdue');
Jared Hancock's avatar
Jared Hancock committed
        $this->onOverdue($whine);
Jared Hancock's avatar
Jared Hancock committed
        return true;
    }

Peter Rotich's avatar
Peter Rotich committed
    function clearOverdue() {

Peter Rotich's avatar
Peter Rotich committed
            return true;

        //NOTE: Previously logged overdue event is NOT annuled.

Peter Rotich's avatar
Peter Rotich committed
        $sql='UPDATE '.TICKET_TABLE.' SET isoverdue=0, updated=NOW() ';
Peter Rotich's avatar
Peter Rotich committed
        //clear due date if it's in the past
        if($this->getDueDate() && Misc::db2gmtime($this->getDueDate()) <= Misc::gmtime())
Peter Rotich's avatar
Peter Rotich committed
            $sql.=', duedate=NULL';

        //Clear SLA if est. due date is in the past
        if($this->getSLADueDate() && Misc::db2gmtime($this->getSLADueDate()) <= Misc::gmtime())
Peter Rotich's avatar
Peter Rotich committed
        $sql.=' WHERE ticket_id='.db_input($this->getId());

        return (db_query($sql) && db_affected_rows());
    }

    //Dept Tranfer...with alert.. done by staff
Jared Hancock's avatar
Jared Hancock committed
    function transfer($deptId, $comments, $alert = true) {
Jared Hancock's avatar
Jared Hancock committed
        global $cfg, $thisstaff;
        if(!$thisstaff || !$thisstaff->canTransferTickets())
Jared Hancock's avatar
Jared Hancock committed
            return false;

        $currentDept = $this->getDeptName(); //Current department

        if(!$deptId || !$this->setDeptId($deptId))
            return false;
        if($this->isClosed()) $this->reopen();

        $this->reload();
Jared Hancock's avatar
Jared Hancock committed
        if(!$this->getSLAId() || $this->getSLA()->isTransient())
        /*** log the transfer comments as internal note - with alerts disabled - ***/
        $title=sprintf(_S('Ticket transferred from %1$s to %2$s'),
            $currentDept, $this->getDeptName());
        $note = $this->logNote($title, $comments, $thisstaff, false);
        $this->logEvent('transferred');
        //Send out alerts if enabled AND requested
        if(!$alert || !$cfg->alertONTransfer() || !($dept=$this->getDept()))
            return true; //no alerts!!
         if(($email=$cfg->getAlertEmail())
                     && ($tpl = $dept->getTemplate())
                     && ($msg=$tpl->getTransferAlertMsgTemplate())) {
            $msg = $this->replaceVars($msg->asArray(),
                array('comments' => $comments, 'staff' => $thisstaff));
Jared Hancock's avatar
Jared Hancock committed
            $recipients=array();
            //Assigned staff or team... if any
            if($this->isAssigned() && $cfg->alertAssignedONTransfer()) {
                if($this->getStaffId())
                    $recipients[]=$this->getStaff();
                elseif($this->getTeamId() && ($team=$this->getTeam()) && ($members=$team->getMembers()))
                    $recipients = array_merge($recipients, $members);
Jared Hancock's avatar
Jared Hancock committed
            } elseif($cfg->alertDeptMembersONTransfer() && !$this->isAssigned()) {
                //Only alerts dept members if the ticket is NOT assigned.
                if(($members=$dept->getMembersForAlerts()))
                    $recipients = array_merge($recipients, $members);
Jared Hancock's avatar
Jared Hancock committed
            }

            //Always alert dept manager??
            if($cfg->alertDeptManagerONTransfer() && $dept && ($manager=$dept->getManager()))
                $recipients[]= $manager;
Jared Hancock's avatar
Jared Hancock committed
            $sentlist=array();
                'inreplyto'=>$note->getEmailMessageId(),
                'references'=>$note->getEmailReferences(),
                'thread'=>$note);
            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->getEmail(), $alert['subj'], $alert['body'], null, $options);
Peter Rotich's avatar
Peter Rotich committed
                $sentlist[] = $staff->getEmail();
Jared Hancock's avatar
Jared Hancock committed
            }
         }

         return true;
    }

    function assignToStaff($staff, $note, $alert=true) {

        if(!is_object($staff) && !($staff=Staff::lookup($staff)))
            return false;
        if (!$staff->isAvailable() || !$this->setStaffId($staff->getId()))
Jared Hancock's avatar
Jared Hancock committed
            return false;

        $this->onAssign($staff, $note, $alert);
        $this->logEvent('assigned');
Jared Hancock's avatar
Jared Hancock committed

        return true;
    }

    function assignToTeam($team, $note, $alert=true) {

        if(!is_object($team) && !($team=Team::lookup($team)))
            return false;

        if (!$team->isActive() || !$this->setTeamId($team->getId()))
Jared Hancock's avatar
Jared Hancock committed
            return false;

        //Clear - staff if it's a closed ticket
        //  staff_id is overloaded -> assigned to & closed by.
        if($this->isClosed())
            $this->setStaffId(0);

        $this->onAssign($team, $note, $alert);
        $this->logEvent('assigned');
Jared Hancock's avatar
Jared Hancock committed

        return true;
    }

    //Assign ticket to staff or team - overloaded ID.
    function assign($assignId, $note, $alert=true) {
        global $thisstaff;

        $rv=0;
        $id=preg_replace("/[^0-9]/", "", $assignId);
Jared Hancock's avatar
Jared Hancock committed
        if($assignId[0]=='t') {
            $rv=$this->assignToTeam($id, $note, $alert);
        } elseif($assignId[0]=='s' || is_numeric($assignId)) {
Peter Rotich's avatar
Peter Rotich committed
            $alert=($alert && $thisstaff && $thisstaff->getId()==$id)?false:$alert; //No alerts on self assigned tickets!!!
Jared Hancock's avatar
Jared Hancock committed
            //We don't care if a team is already assigned to the ticket - staff assignment takes precedence
            $rv=$this->assignToStaff($id, $note, $alert);
        }

        return $rv;
    }
Jared Hancock's avatar
Jared Hancock committed
    //unassign primary assignee
    function unassign() {

        if(!$this->isAssigned()) //We can't release what is not assigned buddy!
            return true;

Peter Rotich's avatar
Peter Rotich committed
        //We can only unassigned OPEN tickets.
        if($this->isClosed())
            return false;
Peter Rotich's avatar
Peter Rotich committed
        //Unassign staff (if any)
        if($this->getStaffId() && !$this->setStaffId(0))
            return false;

        //unassign team (if any)
        if($this->getTeamId() && !$this->setTeamId(0))
            return false;
Peter Rotich's avatar
Peter Rotich committed
        $this->reload();

        return true;
    }
Jared Hancock's avatar
Jared Hancock committed
    function release() {
        return $this->unassign();
    }

    //Change ownership
    function changeOwner($user) {
        global $thisstaff;

        if (!$user
                || ($user->getId() == $this->getOwnerId())
                || !$thisstaff->canEditTickets())
            return false;

        $sql ='UPDATE '.TICKET_TABLE.' SET updated = NOW() '
            .', user_id = '.db_input($user->getId())
            .' WHERE ticket_id = '.db_input($this->getId());

        if (!db_query($sql) || !db_affected_rows())
            return false;

        $this->ht['user_id'] = $user->getId();
        $this->user = null;
        $this->collaborators = null;
        $this->recipients = null;

        //Log an internal note
        $note = sprintf(_S('%s changed ticket ownership to %s'),
                $thisstaff->getName(), $user->getName());

        //Remove the new owner from list of collaborators
        $c = Collaborator::lookup(array('userId' => $user->getId(),
                    'ticketId' => $this->getId()));
        if ($c && $c->remove())
            $note.= ' '._S('(removed as collaborator)');
        $this->logNote('Ticket ownership changed', $note);
Jared Hancock's avatar
Jared Hancock committed
    //Insert message from client
    function postMessage($vars, $origin='', $alerts=true) {
Jared Hancock's avatar
Jared Hancock committed
        global $cfg;
Peter Rotich's avatar
Peter Rotich committed
        $vars['origin'] = $origin;
        if(isset($vars['ip']))
            $vars['ip_address'] = $vars['ip'];
        elseif(!$vars['ip_address'] && $_SERVER['REMOTE_ADDR'])
            $vars['ip_address'] = $_SERVER['REMOTE_ADDR'];
        $errors = array();
        if(!($message = $this->getThread()->addMessage($vars, $errors)))
            return null;
        $this->setLastMessage($message);
        //Add email recipients as collaborators...
        if ($vars['recipients']
                && (strtolower($origin) != 'email' || ($cfg && $cfg->addCollabsViaEmail()))
                //Only add if we have a matched local address
            //New collaborators added by other collaborators are disable --
            // requires staff approval.
            $info = array(
                    'isactive' => ($message->getUserId() == $this->getUserId())? 1: 0);
            $collabs = array();
            foreach ($vars['recipients'] as $recipient) {
                // Skip virtual delivered-to addresses
                if (strcasecmp($recipient['source'], 'delivered-to') === 0)
                    continue;

                if (($user=User::fromVars($recipient)))
                    if ($c=$this->addCollaborator($user, $info, $errors))
                        $collabs[] = sprintf('%s%s',
                            (string) $c,
                            $recipient['source']
                                ? " ".sprintf(_S('via %s'), $recipient['source'])
                                : ''
                            );
            }
            //TODO: Can collaborators add others?
            if ($collabs) {
                //TODO: Change EndUser to name of  user.
                $this->logNote(_S('Collaborators added by end user'),
                        implode("<br>", $collabs), _S('End User'), false);
        if(!$alerts) return $message; //Our work is done...
        // Do not auto-respond to bounces and other auto-replies
        $autorespond = isset($vars['flags'])
            ? !$vars['flags']['bounce'] && !$vars['flags']['auto-reply']
            : true;
        if ($autorespond && $message->isAutoReply())
            $autorespond = false;
        $this->onMessage($message, $autorespond); //must be called b4 sending alerts to staff.
        if ($autorespond && $cfg && $cfg->notifyCollabsONNewMessage())
            $this->notifyCollaborators($message, array('signature' => ''));

        $dept = $this->getDept();

        $variables = array(
                'message' => $message,
                'poster' => ($vars['poster'] ? $vars['poster'] : $this->getName())
                );
        $options = array(
                'inreplyto' => $message->getEmailMessageId(),
                'references' => $message->getEmailReferences(),
                'thread'=>$message);
Jared Hancock's avatar
Jared Hancock committed
        //If enabled...send alert to staff (New Message Alert)
        if($cfg->alertONNewMessage()
                && ($email = $cfg->getAlertEmail())
                && ($tpl = $dept->getTemplate())
                && ($msg = $tpl->getNewMessageAlertMsgTemplate())) {
            $msg = $this->replaceVars($msg->asArray(), $variables);
Jared Hancock's avatar
Jared Hancock committed

            //Build list of recipients and fire the alerts.
            $recipients=array();
            //Last respondent.
            if($cfg->alertLastRespondentONNewMessage() || $cfg->alertAssignedONNewMessage())
                $recipients[]=$this->getLastRespondent();
Jared Hancock's avatar
Jared Hancock committed
            //Assigned staff if any...could be the last respondent
Jared Hancock's avatar
Jared Hancock committed
            if($this->isAssigned() && ($staff=$this->getStaff()))
                $recipients[]=$staff;
Jared Hancock's avatar
Jared Hancock committed
            //Dept manager
            if($cfg->alertDeptManagerONNewMessage() && $dept && ($manager=$dept->getManager()))
                $recipients[]=$manager;
            // 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;
            }

Jared Hancock's avatar
Jared Hancock committed
            $sentlist=array(); //I know it sucks...but..it works.
Peter Rotich's avatar
Peter Rotich committed
                if(!$staff || !$staff->getEmail() || !$staff->isAvailable() || in_array($staff->getEmail(), $sentlist)) continue;
                $alert = $this->replaceVars($msg, array('recipient' => $staff));
                $email->sendAlert($staff->getEmail(), $alert['subj'], $alert['body'], null, $options);
Peter Rotich's avatar
Peter Rotich committed
                $sentlist[] = $staff->getEmail();
    function postCannedReply($canned, $msgId, $alert=true) {
Peter Rotich's avatar
Peter Rotich committed
        global $ost, $cfg;

        if((!is_object($canned) && !($canned=Canned::lookup($canned))) || !$canned->isEnabled())
            return false;

        $files = array();
        foreach ($canned->attachments->getAll() as $file)
            $files[] = $file['id'];

Peter Rotich's avatar
Peter Rotich committed
        if ($cfg->isHtmlThreadEnabled())
            $response = new HtmlThreadBody(
                    $this->replaceVars($canned->getHtml()));
        else
Peter Rotich's avatar
Peter Rotich committed
            $response = new TextThreadBody(
Peter Rotich's avatar
Peter Rotich committed
                    $this->replaceVars($canned->getPlainText()));

        $info = array('msgId' => $msgId,
                      'poster' => __('SYSTEM (Canned Reply)'),
Peter Rotich's avatar
Peter Rotich committed
                      'response' => $response,
                      'cannedattachments' => $files);

Peter Rotich's avatar
Peter Rotich committed
        $errors = array();
        if(!($response=$this->postReply($info, $errors, false)))
            return null;
Peter Rotich's avatar
Peter Rotich committed

        $this->markUnAnswered();

        if(!$alert) return $response;
Peter Rotich's avatar
Peter Rotich committed

        $dept = $this->getDept();

        if(($email=$dept->getEmail())
                && ($tpl = $dept->getTemplate())
                && ($msg=$tpl->getAutoReplyMsgTemplate())) {
Peter Rotich's avatar
Peter Rotich committed

            if($dept && $dept->isPublic())
                $signature=$dept->getSignature();
            else
                $signature='';

            $msg = $this->replaceVars($msg->asArray(),
                    array(
                        'response' => $response,
                        'signature' => $signature,
                        'recipient' => $this->getOwner(),
                        ));
            $attachments =($cfg->emailAttachments() && $files)?$response->getAttachments():array();
                'inreplyto'=>$response->getEmailMessageId(),
                'references'=>$response->getEmailReferences(),
                'thread'=>$response);
            $email->sendAutoReply($this->getEmail(), $msg['subj'], $msg['body'], $attachments,
                $options);
Peter Rotich's avatar
Peter Rotich committed
    function postReply($vars, &$errors, $alert = true) {
        global $thisstaff, $cfg;
        if(!$vars['poster'] && $thisstaff)
            $vars['poster'] = $thisstaff;
        if(!$vars['staffId'] && $thisstaff)
            $vars['staffId'] = $thisstaff->getId();
        if(!($response = $this->getThread()->addResponse($vars, $errors)))
            return null;
        // Set status - if checked.
        if ($vars['reply_status_id']
                && $vars['reply_status_id'] != $this->getStatusId())
            $this->setStatus($vars['reply_status_id']);
        if($thisstaff && $this->isOpen() && !$this->getStaffId()
                && $cfg->autoClaimTickets())
            $this->setStaffId($thisstaff->getId()); //direct assignment;

Jared Hancock's avatar
Jared Hancock committed
        $this->onResponse(); //do house cleaning..

        /* email the user??  - if disabled - then bail out */
        if(!$alert) return $response;
        $dept = $this->getDept();

        if($thisstaff && $vars['signature']=='mine')
            $signature=$thisstaff->getSignature();
        elseif($vars['signature']=='dept' && $dept && $dept->isPublic())
            $signature=$dept->getSignature();
        else
            $signature='';
        $variables = array(
                'response' => $response,
                'signature' => $signature,
                'staff' => $thisstaff,
                'poster' => $thisstaff);
        $options = array(
                'inreplyto' => $response->getEmailMessageId(),
                'references' => $response->getEmailReferences(),
                'thread'=>$response);
        if(($email=$dept->getEmail())
                && ($tpl = $dept->getTemplate())
                && ($msg=$tpl->getReplyMsgTemplate())) {
            $msg = $this->replaceVars($msg->asArray(),
                    $variables + array('recipient' => $this->getOwner()));
            $attachments = $cfg->emailAttachments()?$response->getAttachments():array();
            $email->send($this->getEmail(), $msg['subj'], $msg['body'], $attachments,
                $options);
        if($vars['emailcollab'])
            $this->notifyCollaborators($response,
                    array('signature' => $signature));
Jared Hancock's avatar
Jared Hancock committed
    }

    //Activity log - saved as internal notes WHEN enabled!!
Peter Rotich's avatar
Peter Rotich committed
        return $this->logNote($title, $note, 'SYSTEM', false);
    // History log -- used for statistics generation (pretty reports)
    function logEvent($state, $annul=null, $staff=null) {
        global $thisstaff;

        if ($staff === null) {
            if ($thisstaff) $staff=$thisstaff->getUserName();
            else $staff='SYSTEM';               # XXX: Security Violation ?
        }
        # Annul previous entries if requested (for instance, reopening a
        # ticket will annul an 'closed' entry). This will be useful to
        # easily prevent repeated statistics.
        if ($annul) {
            db_query('UPDATE '.TICKET_EVENT_TABLE.' SET annulled=1'
                .' WHERE ticket_id='.db_input($this->getId())
                  .' AND state='.db_input($annul));
        }
        return db_query('INSERT INTO '.TICKET_EVENT_TABLE
            .' SET ticket_id='.db_input($this->getId())
            .', staff_id='.db_input($this->getStaffId())
            .', team_id='.db_input($this->getTeamId())
            .', dept_id='.db_input($this->getDeptId())
            .', topic_id='.db_input($this->getTopicId())
            .', timestamp=NOW(), state='.db_input($state)
            .', staff='.db_input($staff))
            && db_affected_rows() == 1;
    }

Peter Rotich's avatar
Peter Rotich committed
    //Insert Internal Notes
    function logNote($title, $note, $poster='SYSTEM', $alert=true) {
Peter Rotich's avatar
Peter Rotich committed
        $errors = array();
        //Unless specified otherwise, assume HTML
        if ($note && is_string($note))
            $note = new HtmlThreadBody($note);

Peter Rotich's avatar
Peter Rotich committed
        return $this->postNote(
Peter Rotich's avatar
Peter Rotich committed
                $errors,
                $poster,
    function postNote($vars, &$errors, $poster, $alert=true) {
Peter Rotich's avatar
Peter Rotich committed
        global $cfg, $thisstaff;

        //Who is posting the note - staff or system?
        $vars['staffId'] = 0;
        $vars['poster'] = 'SYSTEM';
        if($poster && is_object($poster)) {
            $vars['staffId'] = $poster->getId();
            $vars['poster'] = $poster->getName();
        }elseif($poster) { //string
            $vars['poster'] = $poster;
        if(!($note=$this->getThread()->addNote($vars, $errors)))
            return null;
        $alert = $alert && (
            isset($vars['flags'])
            // No alerts for bounce and auto-reply emails
            ? !$vars['flags']['bounce'] && !$vars['flags']['auto-reply']
            : true
        );
        // Get assigned staff just in case the ticket is closed.
        $assignee = $this->getStaff();

        if ($vars['note_status_id']
                && ($status=TicketStatus::lookup($vars['note_status_id']))) {
            if ($this->setStatus($status))
Peter Rotich's avatar
Peter Rotich committed
                $this->reload();
        }
Jared Hancock's avatar
Jared Hancock committed
        // If alerts are not enabled then return a success.
        if(!$alert || !$cfg->alertONNewNote() || !($dept=$this->getDept()))
        if(($email=$cfg->getAlertEmail())
                && ($tpl = $dept->getTemplate())
                && ($msg=$tpl->getNoteAlertMsgTemplate())) {
            $msg = $this->replaceVars($msg->asArray(),
                array('note' => $note));
Jared Hancock's avatar
Jared Hancock committed
            $recipients=array();
Jared Hancock's avatar
Jared Hancock committed
            //Last respondent.
            if ($cfg->alertLastRespondentONNewNote())
                $recipients[] = $this->getLastRespondent();

            // Assigned staff / team
            if ($cfg->alertAssignedONNewNote()) {

                if ($assignee && $assignee instanceof Staff)
                    $recipients[] = $assignee;
                if ($team = $this->getTeam())
                    $recipients = array_merge($recipients, $team->getMembers());
            }
            // Dept manager
            if ($cfg->alertDeptManagerONNewNote() && $dept && $dept->getManagerId())
                $recipients[] = $dept->getManager();
                'inreplyto'=>$note->getEmailMessageId(),
                'references'=>$note->getEmailReferences(),
                'thread'=>$note);

            $isClosed = $this->isClosed();
Jared Hancock's avatar
Jared Hancock committed
            $sentlist=array();
            foreach( $recipients as $k=>$staff) {
                        // Don't bother vacationing staff.
                        || !$staff->isAvailable()
                        // No duplicates.
                        || isset($sentlist[$staff->getEmail()])
                        // No need to alert the poster!
                        || $note->getStaffId() == $staff->getId()
                        // Make sure staff has access to ticket
                        || ($isClosed && !$this->checkStaffAccess($staff))
                        )
                $alert = $this->replaceVars($msg, array('recipient' => $staff));
                $email->sendAlert($staff->getEmail(), $alert['subj'], $alert['body'], null, $options);
                $sentlist[$staff->getEmail()] = 1;