Skip to content
Snippets Groups Projects
class.ticket.php 74.8 KiB
Newer Older
Jared Hancock's avatar
Jared Hancock committed
            $email=null;
            $source='Email';
        }
        //Last minute checks
        if (!$form->getAnswer('priority'))
            $form->setAnswer('priority', null, $cfg->getDefaultPriorityId());
Jared Hancock's avatar
Jared Hancock committed
        $deptId=$deptId?$deptId:$cfg->getDefaultDeptId();
        $topicId=$vars['topicId']?$vars['topicId']:0;
        $ipaddress=$vars['ip']?$vars['ip']:$_SERVER['REMOTE_ADDR'];
Jared Hancock's avatar
Jared Hancock committed
        //We are ready son...hold on to the rails.
        $extId=Ticket::genExtRandID();
        $sql='INSERT INTO '.TICKET_TABLE.' SET created=NOW() '
            .' ,lastmessage= NOW()'
            .' ,user_id='.db_input($user->id)
            .' ,user_email_id='.db_input($user_email->id)
Jared Hancock's avatar
Jared Hancock committed
            .' ,ticketID='.db_input($extId)
            .' ,dept_id='.db_input($deptId)
            .' ,topic_id='.db_input($topicId)
Jared Hancock's avatar
Jared Hancock committed
            .' ,source='.db_input($source);

        //Make sure the origin is staff - avoid firebug hack!
        if($vars['duedate'] && !strcasecmp($origin,'staff'))
             $sql.=' ,duedate='.db_input(date('Y-m-d G:i',Misc::dbtime($vars['duedate'].' '.$vars['time'])));


        if(!db_query($sql) || !($id=db_insert_id()) || !($ticket =Ticket::lookup($id)))
            return null;

        /* -------------------- POST CREATE ------------------------ */
Jared Hancock's avatar
Jared Hancock committed
            //Sequential ticketIDs support really..really suck arse.
            $extId=$id; //To make things really easy we are going to use autoincrement ticket_id.
            db_query('UPDATE '.TICKET_TABLE.' SET ticketID='.db_input($extId).' WHERE ticket_id='.$id.' LIMIT 1');
Jared Hancock's avatar
Jared Hancock committed
            //TODO: RETHING what happens if this fails?? [At the moment on failure random ID is used...making stuff usable]
        // Save the (common) dynamic form
        $form->setTicketId($id);
        $form->save();

        $dept = $ticket->getDept();
Jared Hancock's avatar
Jared Hancock committed
        //post the message.
        unset($vars['cannedattachments']); //Ticket::open() might have it set as part of  open & respond.
        $vars['title'] = $vars['subject']; //Use the initial subject as title of the post.
        $message = $ticket->postMessage($vars , $origin, false);
Jared Hancock's avatar
Jared Hancock committed

        // Configure service-level-agreement for this ticket
        $ticket->selectSLAId($vars['slaId']);

        //Auto assign staff or team - auto assignment based on filter rules.
        if($vars['staffId'] && !$vars['assignId'])
             $ticket->assignToStaff($vars['staffId'], 'Auto Assignment');
Jared Hancock's avatar
Jared Hancock committed
        if($vars['teamId'] && !$vars['assignId'])
            $ticket->assignToTeam($vars['teamId'], 'Auto Assignment');
Jared Hancock's avatar
Jared Hancock committed

        /**********   double check auto-response  ************/
        //Override auto responder if the FROM email is one of the internal emails...loop control.
Jared Hancock's avatar
Jared Hancock committed
        if($autorespond && (Email::getIdByEmail($ticket->getEmail())))
            $autorespond=false;

        # Messages that are clearly auto-responses from email systems should
        # not have a return 'ping' message
        if ($autorespond && $message && $message->isAutoResponse())
Jared Hancock's avatar
Jared Hancock committed
            $autorespond=false;

        //Don't auto respond to mailer daemons.
        if( $autorespond &&
            (strpos(strtolower($vars['email']),'mailer-daemon@')!==false
             || strpos(strtolower($vars['email']),'postmaster@')!==false)) {
            $autorespond=false;
        }

        //post canned auto-response IF any (disables new ticket auto-response).
        if ($vars['cannedResponseId']
            && $ticket->postCannedReply($vars['cannedResponseId'], $message->getId(), $autorespond)) {
                $ticket->markUnAnswered(); //Leave the ticket as unanswred.
                $autorespond = false;
        //Check department's auto response settings
        // XXX: Dept. setting doesn't affect canned responses.
        if($autorespond && $dept && !$dept->autoRespONNewTicket())
            $autorespond=false;

        /***** See if we need to send some alerts ****/
        $ticket->onNewTicket($message, $autorespond, $alertstaff);
        /************ check if the user JUST reached the max. open tickets limit **********/
        if($cfg->getMaxOpenTickets()>0
                    && ($client=$ticket->getClient())
                    && ($client->getNumOpenTickets()==$cfg->getMaxOpenTickets())) {
            $ticket->onOpenLimit(($autorespond && strcasecmp($origin, 'staff')));
        }
        /* Start tracking ticket lifecycle events */
        $ticket->logEvent('created');

        /* Phew! ... time for tea (KETEPA) */

Jared Hancock's avatar
Jared Hancock committed
        return $ticket;
    }

    function open($vars, &$errors) {
Jared Hancock's avatar
Jared Hancock committed

        if(!$thisstaff || !$thisstaff->canCreateTickets()) return false;

        if($vars['source'] && !in_array(strtolower($vars['source']),array('email','phone','other')))
            $errors['source']='Invalid source - '.Format::htmlchars($vars['source']);

Jared Hancock's avatar
Jared Hancock committed
        if(!($ticket=Ticket::create($vars, $errors, 'staff', false, (!$vars['assignId']))))
            return false;

        $vars['msgId']=$ticket->getLastMsgId();
Jared Hancock's avatar
Jared Hancock committed
        // post response - if any
        $response = null;
        if($vars['response'] && $thisstaff->canPostReply()) {
            $vars['response'] = $ticket->replaceVars($vars['response']);
            if(($response=$ticket->postReply($vars, $errors, false))) {
Jared Hancock's avatar
Jared Hancock committed
                //Only state supported is closed on response
                if(isset($vars['ticket_state']) && $thisstaff->canCloseTickets())
                    $ticket->setState($vars['ticket_state']);
            }
        }
Jared Hancock's avatar
Jared Hancock committed
        //Post Internal note
Jared Hancock's avatar
Jared Hancock committed
        if($vars['assignId'] && $thisstaff->canAssignTickets()) { //Assign ticket to staff or team.
            $ticket->assign($vars['assignId'], $vars['note']);
Jared Hancock's avatar
Jared Hancock committed
        } elseif($vars['note']) { //Not assigned...save optional note if any
Peter Rotich's avatar
Peter Rotich committed
            $ticket->logNote('New Ticket', $vars['note'], $thisstaff, false);
Jared Hancock's avatar
Jared Hancock committed
        } else { //Not assignment and no internal note - log activity
            $ticket->logActivity('New Ticket by Staff','Ticket created by staff -'.$thisstaff->getName());
        }

        $ticket->reload();
        if(!$cfg->notifyONNewStaffTicket() || !isset($vars['alertuser']))
Jared Hancock's avatar
Jared Hancock committed
            return $ticket; //No alerts.

        //Send Notice to user --- if requested AND enabled!!
Jared Hancock's avatar
Jared Hancock committed
        $dept=$ticket->getDept();
        if(!$dept || !($tpl=$dept->getTemplate()))
            $tpl=$cfg->getDefaultTemplate();
Jared Hancock's avatar
Jared Hancock committed
        if(!$dept || !($email=$dept->getEmail()))
            $email =$cfg->getDefaultEmail();

        if($tpl && ($msg=$tpl->getNewTicketNoticeMsgTemplate()) && $email) {
            $message = $vars['issue'];
            if($response)
                $message.="\n\n".$response->getBody();
Jared Hancock's avatar
Jared Hancock committed

            if($vars['signature']=='mine')
                $signature=$thisstaff->getSignature();
            elseif($vars['signature']=='dept' && $dept && $dept->isPublic())
                $signature=$dept->getSignature();
            else
                $signature='';
            $attachments =($cfg->emailAttachments() && $response)?$response->getAttachments():array();

            $msg = $ticket->replaceVars($msg->asArray(),
                    array('message' => $message, 'signature' => $signature));
Jared Hancock's avatar
Jared Hancock committed

            if($cfg->stripQuotedReply() && ($tag=trim($cfg->getReplySeparator())))
                $msg['body'] ="\n$tag\n\n".$msg['body'];
            $references = $ticket->getLastMessage()->getEmailMessageId();
            if (isset($response))
                $references = array($response->getEmailMessageId(), $references);
            $options = array('references' => $references);
            $email->send($ticket->getEmail(), $msg['subj'], $msg['body'], $attachments,
                $options);
Jared Hancock's avatar
Jared Hancock committed
        }

        return $ticket;
    function checkOverdue() {
        $sql='SELECT ticket_id FROM '.TICKET_TABLE.' T1 '
            .' INNER JOIN '.SLA_TABLE.' T2 ON (T1.sla_id=T2.id AND T2.isactive=1) '
            .' WHERE status=\'open\' AND isoverdue=0 '
            .' AND ((reopened is NULL AND duedate is NULL AND TIME_TO_SEC(TIMEDIFF(NOW(),T1.created))>=T2.grace_period*3600) '
            .' OR (reopened is NOT NULL AND duedate is NULL AND TIME_TO_SEC(TIMEDIFF(NOW(),reopened))>=T2.grace_period*3600) '
            .' OR (duedate is NOT NULL AND duedate<NOW()) '
            .' ) ORDER BY T1.created LIMIT 50'; //Age upto 50 tickets at a time?
Jared Hancock's avatar
Jared Hancock committed
        //echo $sql;
        if(($res=db_query($sql)) && db_num_rows($res)) {
            while(list($id)=db_fetch_row($res)) {
Jared Hancock's avatar
Jared Hancock committed
                if(($ticket=Ticket::lookup($id)) && $ticket->markOverdue())
                    $ticket->logActivity('Ticket Marked Overdue', 'Ticket flagged as overdue by the system.');
        } else {
            //TODO: Trigger escalation on already overdue tickets - make sure last overdue event > grace_period.