diff --git a/include/ajax.tickets.php b/include/ajax.tickets.php index e89ceead6b9175c76dafcfd1547d845b81214d56..0338545a6d4935489c8cb31613b6154bfc712db8 100644 --- a/include/ajax.tickets.php +++ b/include/ajax.tickets.php @@ -460,7 +460,7 @@ function refer($tid, $target=null) { $ticket->getId(), $ticket->getNumber())) , - $form->getTarget()) + $form->getReferee()) ); Http::response(201, $ticket->getId()); } diff --git a/include/class.forms.php b/include/class.forms.php index 6f13a4a0ce0ef68fb6fd0ce1443e13f8c6dcd06e..c834309b4c65ea7b8daa15c4b6265af35d3fea2c 100644 --- a/include/class.forms.php +++ b/include/class.forms.php @@ -3896,7 +3896,7 @@ class CheckboxWidget extends Widget { $data = $this->field->getSource(); if (count($data)) { if (!isset($data[$this->name])) - return false; + return null; return @in_array($this->field->get('id'), $data[$this->name]); } return parent::getValue(); @@ -4479,10 +4479,8 @@ class AssignmentForm extends Form { $fields = array( 'assignee' => new AssigneeField(array( - 'id'=>1, - 'label' => __('Assignee'), - 'flags' => hexdec(0X450F3), - 'required' => true, + 'id'=>1, 'label' => __('Assignee'), + 'flags' => hexdec(0X450F3), 'required' => true, 'validator-error' => __('Assignee selection required'), 'configuration' => array( 'criteria' => array( @@ -4491,11 +4489,15 @@ class AssignmentForm extends Form { ), ) ), + 'refer' => new BooleanField(array( + 'id'=>2, 'label'=>'', 'required'=>false, + 'default'=>false, + 'configuration'=>array( + 'desc' => 'Maintain referral access to current assignees') + ) + ), 'comments' => new TextareaField(array( - 'id' => 2, - 'label'=> '', - 'required'=>false, - 'default'=>'', + 'id' => 3, 'label'=> '', 'required'=>false, 'default'=>'', 'configuration' => array( 'html' => true, 'size' => 'small', @@ -4580,6 +4582,10 @@ class AssignmentForm extends Form { function getComments() { return $this->getField('comments')->getClean(); } + + function refer() { + return $this->getField('refer')->getClean(); + } } class ClaimForm extends AssignmentForm { @@ -4633,22 +4639,60 @@ class ReferralForm extends Form { return $this->fields; $fields = array( - 'target' => new AssigneeField(array( + 'target' => new ChoiceField(array( 'id'=>1, 'label' => __('Referee'), 'flags' => hexdec(0X450F3), 'required' => true, 'validator-error' => __('Selection required'), - 'configuration' => array( - 'criteria' => array( - 'available' => true, - ), - 'prompt' => $this->_prompt, - ), - ) + 'choices' => array( + 'agent' => __('Agent'), + 'team' => __('Team'), + 'dept' => __('Department'), + ), + ) + ), + 'agent' => new ChoiceField(array( + 'id'=>2, + 'label' => '', + 'flags' => hexdec(0X450F3), + 'required' => true, + 'configuration'=>array('prompt'=>__('Select Agent')), + 'validator-error' => __('Agent selection required'), + 'visibility' => new VisibilityConstraint( + new Q(array('target__eq'=>'agent')), + VisibilityConstraint::HIDDEN + ), + ) + ), + 'team' => new ChoiceField(array( + 'id'=>3, + 'label' => '', + 'flags' => hexdec(0X450F3), + 'required' => true, + 'validator-error' => __('Team selection required'), + 'configuration'=>array('prompt'=>__('Select Team')), + 'visibility' => new VisibilityConstraint( + new Q(array('target__eq'=>'team')), + VisibilityConstraint::HIDDEN + ), + ) + ), + 'dept' => new ChoiceField(array( + 'id'=>4, + 'label' => '', + 'flags' => hexdec(0X450F3), + 'required' => true, + 'validator-error' => __('Dept. selection required'), + 'configuration'=>array('prompt'=>__('Select Department')), + 'visibility' => new VisibilityConstraint( + new Q(array('target__eq'=>'dept')), + VisibilityConstraint::HIDDEN + ), + ) ), 'comments' => new TextareaField(array( - 'id' => 2, + 'id' => 5, 'label'=> '', 'required'=>false, 'default'=>'', @@ -4661,11 +4705,6 @@ class ReferralForm extends Form { ), ); - - if (isset($this->_choices)) - $fields['target']->setChoices($this->_choices); - - $this->setFields($fields); return $this->fields; @@ -4678,27 +4717,29 @@ class ReferralForm extends Form { return $fields[$name]; } + + function isValid($include=false) { if (!parent::isValid($include) || !($f=$this->getField('target'))) return false; // Do additional assignment validation - $choice = $this->getTarget(); + $referee = $this->getReferee(); switch (true) { - case $choice instanceof Staff: + case $referee instanceof Staff: // Make sure the agent is available - if (!$choice->isAvailable()) + if (!$referee->isAvailable()) $f->addError(__('Agent is unavailable for assignment')); break; - case $choice instanceof Team: + case $referee instanceof Team: // Make sure the team is active and has members - if (!$choice->isActive()) + if (!$referee->isActive()) $f->addError(__('Team is disabled')); - elseif (!$choice->getNumMembers()) + elseif (!$referee->getNumMembers()) $f->addError(__('Team does not have members')); break; - case $choice instanceof Dept: + case $referee instanceof Dept: break; default: $f->addError(__('Unknown selection')); @@ -4722,18 +4763,31 @@ class ReferralForm extends Form { include $inc; } - function setChoices($choices, $prompt='') { - $this->_choices = $choices; - $this->_prompt = $prompt; - $this->_fields = array(); + function setChoices($field, $choices, $prompt='') { + + if (!($f= $this->getField($field))) + return; + + $f->set('choices', $choices); + + return $f; } - function getTarget() { + function getReferee() { - if (!isset($this->_target)) - $this->_target = $this->getField('target')->getClean(); + $target = $this->getField('target')->getClean(); + if (!$target || !($f=$this->getField($target))) + return null; - return $this->_target; + $id = $f->getClean(); + switch($target) { + case 'agent': + return Staff::lookup($id); + case 'team': + return Team::lookup($id); + case 'dept': + return Dept::lookup($id); + } } function getComments() { @@ -4765,8 +4819,13 @@ class TransferForm extends Form { 'validator-error' => __('Department selection is required'), ) ), + 'refer' => new BooleanField(array( + 'id'=>2, 'label'=>'', 'required'=>false, 'default'=>false, + 'configuration'=>array( + 'desc' => 'Maintain referral access to current department') + )), 'comments' => new TextareaField(array( - 'id' => 2, + 'id' => 3, 'label'=> '', 'required'=>false, 'default'=>'', @@ -4813,6 +4872,10 @@ class TransferForm extends Form { } + function refer() { + return $this->getField('refer')->getClean(); + } + function getDept() { if (!isset($this->_dept)) { diff --git a/include/class.staff.php b/include/class.staff.php index bbe66e4626d97a641ab1f75257594154b59ad0fa..5a20d35b5b24e7618143a540f9b4883cc986de71 100644 --- a/include/class.staff.php +++ b/include/class.staff.php @@ -449,7 +449,7 @@ implements AuthenticatedUser, EmailContact, TemplateVariable, Searchable { return isset($this->locale) ? $this->locale : 0; } - function getRole($dept=null) { + function getRole($dept=null, $useDefault=true) { $deptId = is_object($dept) ? $dept->getId() : $dept; if ($deptId && $deptId != $this->dept_id) { if (isset($this->_roles[$deptId])) @@ -458,7 +458,7 @@ implements AuthenticatedUser, EmailContact, TemplateVariable, Searchable { if ($access = $this->dept_access->findFirst(array('dept_id' => $deptId))) return $this->_roles[$deptId] = $access->role; - if (!$this->usePrimaryRoleOnAssignment()) + if (!$useDefault || !$this->usePrimaryRoleOnAssignment()) // View only access return new Role(array()); diff --git a/include/class.thread.php b/include/class.thread.php index bbb0d100b7feb758ecf39c74c14d533de313714e..f6dffd7a88b3fd9436c6bc9b530563ac6186547a 100644 --- a/include/class.thread.php +++ b/include/class.thread.php @@ -275,6 +275,13 @@ implements Searchable { return $this->_participants; } + function getReferral($id, $type) { + + return $this->referrals->findFirst(array( + 'object_id' => $id, + 'object_type' => $type)); + } + function refer($to) { $vars = array('thread_id' => $this->getId()); @@ -295,8 +302,6 @@ implements Searchable { return false; } - var_dump($vars); - return ThreadReferral::create($vars); } diff --git a/include/class.ticket.php b/include/class.ticket.php index f91ab94bfdca21792200e98615d050ecab633dd6..c1ad3d6c2bdffc96e7d17410cd758c9d8425656b 100644 --- a/include/class.ticket.php +++ b/include/class.ticket.php @@ -241,8 +241,25 @@ implements RestrictedAccess, Threadable, Searchable { return $this->hasState('deleted'); } - function isAssigned() { - return $this->isOpen() && ($this->getStaffId() || $this->getTeamId()); + function isAssigned($to=null) { + + if ($this->isOpen()) + return false; + + if (!$to) + return ($this->getStaffId() || $this->getTeamId()); + + switch (true) { + case $to instanceof Staff: + return ($to->getId() == $this->getStaffId() || + $to->isTeamMember($this->getTeamId())); + break; + case $to instanceof Team: + return ($to->getId() == $this->getTeamId()); + break; + } + + return false; } function isOverdue() { @@ -269,6 +286,8 @@ implements RestrictedAccess, Threadable, Searchable { && $this->isOpen() && $staff->getId() != $this->getStaffId() && !$staff->isTeamMember($this->getTeamId()) + && !$this->thread->getReferral($staff->getId(), + ObjectModel::OBJECT_TYPE_STAFF) ) { return false; } @@ -841,10 +860,21 @@ implements RestrictedAccess, Threadable, Searchable { $source = array('assignee' => array($assignee)); $form = AssignmentForm::instantiate($source, $options); - if ($assignees) $form->setAssignees($assignees); + if (($refer = $form->getField('refer'))) { + if ($assignee) { + $visibility = new VisibilityConstraint( + new Q(array()), VisibilityConstraint::HIDDEN); + $refer->set('visibility', $visibility); + } else { + $refer->configure('desc', sprintf(__('Maintain referral access to %s'), + $this->getAssigned())); + } + } + + if ($prompt && ($f=$form->getField('assignee'))) $f->configure('prompt', $prompt); @@ -854,30 +884,22 @@ implements RestrictedAccess, Threadable, Searchable { function getReferralForm($source=null, $options=array()) { - $prompt = ''; - $choices = array(); - switch (strtolower($options['target'])) { - case 'agents': - $dept = $this->getDept(); - foreach ($dept->getAssignees() as $member) - $choices['s'.$member->getId()] = $member; - $prompt = sprintf('%s %s', __('Select an'), __('Agent')); - break; - case 'teams': - if (($teams = Team::getActiveTeams())) - foreach ($teams as $id => $name) - $choices['t'.$id] = $name; - $prompt = sprintf('%s %s', __('Select a'), __('Team')); - break; - case 'departments': - foreach (Dept::getDepartments() as $k => $v) - $choices["d$k"] = $v; - $prompt = sprintf('%s %s', __('Select a'), __('Department')); - break; - } - $form = ReferralForm::instantiate($source, $options); - $form->setChoices($choices, $prompt); + $dept = $this->getDept(); + // Agents + $staff = Staff::objects()->filter(array( + 'isactive' => 1, + )) + ->filter(Q::not(array('dept_id' => $dept->getId()))); + $staff = Staff::nsort($staff); + $agents = array(); + foreach ($staff as $s) + $agents[$s->getId()] = $s; + $form->setChoices('agent', $agents); + // Teams + $form->setChoices('team', Team::getActiveTeams()); + // Depts + $form->setChoices('dept', Dept::getDepartments()); return $form; } @@ -899,7 +921,8 @@ implements RestrictedAccess, Threadable, Searchable { function getTransferForm($source=null) { if (!$source) - $source = array('dept' => array($this->getDeptId())); + $source = array('dept' => array($this->getDeptId()), + 'refer' => false); return TransferForm::instantiate($source); } @@ -2121,6 +2144,9 @@ implements RestrictedAccess, Threadable, Searchable { $_errors, $thisstaff, false); } + if ($form->refer() && $cdept) + $this->thread->refer($cdept); + //Send out alerts if enabled AND requested if (!$alert || !$cfg->alertONTransfer()) return true; //no alerts!! @@ -2243,6 +2269,7 @@ implements RestrictedAccess, Threadable, Searchable { global $thisstaff; $evd = array(); + $refer = null; $assignee = $form->getAssignee(); if ($assignee instanceof Staff) { $dept = $this->getDept(); @@ -2257,6 +2284,7 @@ implements RestrictedAccess, Threadable, Searchable { $errors['err'] = __('Permission denied'); } else { $this->staff_id = $assignee->getId(); + $refer = $this->staff ?: null; if ($thisstaff && $thisstaff->getId() == $assignee->getId()) { $alert = false; $evd['claim'] = true; @@ -2271,6 +2299,7 @@ implements RestrictedAccess, Threadable, Searchable { __('the team') ); } else { + $refer = $this->team ?: null; $this->team_id = $assignee->getId(); $evd = array('team' => $assignee->getId()); } @@ -2285,6 +2314,9 @@ implements RestrictedAccess, Threadable, Searchable { $this->onAssign($assignee, $form->getComments(), $alert); + if ($refer && $form->refer()) + $this->thread->refer($refer); + return true; } @@ -2317,52 +2349,50 @@ implements RestrictedAccess, Threadable, Searchable { global $thisstaff; $evd = array(); - $choice = $form->getTarget(); + $referee = $form->getReferee(); switch (true) { - case $choice instanceof Staff: + case $referee instanceof Staff: $dept = $this->getDept(); - if ($this->getStaffId() == $choice->getId()) { - $errors['target'] = sprintf(__('%s is assigned to %s'), + if ($this->getStaffId() == $referee->getId()) { + $errors['agent'] = sprintf(__('%s is assigned to %s'), __('Ticket'), __('the agent') ); - } elseif(!$choice->isAvailable()) { - $errors['assignee'] = sprintf(__('Agent is unavailable for %s'), + } elseif(!$referee->isAvailable()) { + $errors['agent'] = sprintf(__('Agent is unavailable for %s'), __('referral')); - } elseif ($dept->assignMembersOnly() && !$dept->isMember($choice)) { - $errors['err'] = __('Permission denied'); } else { - $evd['staff'] = array($choice->getId(), (string) $choice->getName()->getOriginal()); + $evd['staff'] = array($referee->getId(), (string) $referee->getName()->getOriginal()); } break; - case $choice instanceof Team: - if ($this->getTeamId() == $choice->getId()) { - $errors['assignee'] = sprintf(__('%s is assigned to %s'), + case $referee instanceof Team: + if ($this->getTeamId() == $referee->getId()) { + $errors['team'] = sprintf(__('%s is assigned to %s'), __('Ticket'), __('the team') ); } else { //TODO:: - $evd = array('team' => $choice->getId()); + $evd = array('team' => $referee->getId()); } break; - case $choice instanceof Dept: - if ($this->getTeamId() == $choice->getId()) { - $errors['target'] = sprintf(__('%s is already in %s'), + case $referee instanceof Dept: + if ($this->getTeamId() == $referee->getId()) { + $errors['dept'] = sprintf(__('%s is already in %s'), __('Ticket'), __('the department') ); } else { //TODO:: - $evd = array('dept' => $choice->getId()); + $evd = array('dept' => $referee->getId()); } break; default: $errors['target'] = __('Unknown referral'); } - if (!$errors && !$this->thread->refer($choice)) - $errors['err'] = __('Unable to reffer ticket'); + if (!$errors && !$this->thread->refer($referee)) + $errors['err'] = __('Unable to refer ticket'); if ($errors) return false; diff --git a/include/staff/templates/refer.tmpl.php b/include/staff/templates/refer.tmpl.php index b1c850f8a779871c6d34de2dec19049c15748a2e..6a2d991e5b7b4edf6e0d1b80e323f69aef2d34d6 100644 --- a/include/staff/templates/refer.tmpl.php +++ b/include/staff/templates/refer.tmpl.php @@ -26,17 +26,17 @@ $action = $info[':action'] ?: ('#'); $manage = (!$target); ?> <ul class="tabs" id="referral"> - <li <?php echo !$manage ? 'class="active"' : ''; ?>><a href="#refer" - ><i class="icon-exchange"></i> <?php echo __('Refer'); ?></a></li> <li <?php echo $manage ? 'class="active"' : ''; ?>><a href="#referrals" ><i class="icon-list"></i> <?php echo sprintf('%s (%d)', __('Referrals'), $thread->getNumReferrals()); ?></a></li> + <li <?php echo !$manage ? 'class="active"' : ''; ?>><a href="#refer" + ><i class="icon-exchange"></i> <?php echo __('Refer'); ?></a></li> </ul> <div id="referral_container"> <div class="tab_content <?php echo $manage ? 'hidden' : ''; ?>" id="refer" style="margin:5px;"> <form class="mass-action" method="post" name="assign" - id="<?php echo $form->getId(); ?>" + id="<?php echo $form->getFormId(); ?>" action="<?php echo $action; ?>"> <input type='hidden' name='do' value='refer'> <table width="100%"> diff --git a/include/staff/ticket-view.inc.php b/include/staff/ticket-view.inc.php index 81965fbcef6a6f8ca021d1cae63e8f296c654dd8..258dd9985fd2ed08ae0a1db1f3534ae95a631324 100644 --- a/include/staff/ticket-view.inc.php +++ b/include/staff/ticket-view.inc.php @@ -10,7 +10,7 @@ $info=($_POST && $errors)?Format::input($_POST):array(); //Get the goodies. $dept = $ticket->getDept(); //Dept -$role = $thisstaff->getRole($dept); +$role = $thisstaff->getRole($dept, $ticket->isAssigned($thisstaff)); $staff = $ticket->getStaff(); //Assigned or closed by.. $user = $ticket->getOwner(); //Ticket User (EndUser) $team = $ticket->getTeam(); //Assigned team. @@ -92,33 +92,6 @@ if($ticket->isOverdue()) data-redirect="tickets.php" href="#tickets/<?php echo $ticket->getId(); ?>/transfer"><i class="icon-share"></i></a> </span> - <span class="action-button pull-right" - data-dropdown="#action-dropdown-refer" - data-placement="bottom" - data-toggle="tooltip" - title=" <?php echo __('Refer'); ?>" - > - <i class="icon-caret-down pull-right"></i> - <a class="ticket-action" id="ticket-refer" - data-redirect="tickets.php" - href="#tickets/<?php echo $ticket->getId(); ?>/refer"><i class="icon-exchange"></i></a> - </span> - <div id="action-dropdown-refer" class="action-dropdown anchor-right"> - <ul> - <li><a class="no-pjax ticket-action" - data-redirect="tickets.php" - href="#tickets/<?php echo $ticket->getId(); ?>/refer/agents"><i - class="icon-user"></i> <?php echo __('Agent'); ?></a> - <li><a class="no-pjax ticket-action" - data-redirect="tickets.php" - href="#tickets/<?php echo $ticket->getId(); ?>/refer/teams"><i - class="icon-group"></i> <?php echo __('Team'); ?></a> - <li><a class="no-pjax ticket-action" - data-redirect="tickets.php" - href="#tickets/<?php echo $ticket->getId(); ?>/refer/departments"><i - class="icon-sitemap"></i> <?php echo __('Department'); ?></a> - </ul> - </div> <?php } ?> @@ -196,6 +169,15 @@ if($ticket->isOverdue()) <?php } } ?> + + <?php + if ($role->hasPerm(Ticket::PERM_TRANSFER)) { ?> + <li><a href="#tickets/<?php echo $ticket->getId(); + ?>/referrals" class="ticket-action" + data-redirect="tickets.php?id=<?php echo $ticket->getId(); ?>" > + <i class="icon-exchange"></i> <?php echo __('Manage Referrals'); ?></a></li> + <?php + } ?> <?php if ($role->hasPerm(Ticket::PERM_EDIT)) { ?> <li><a href="#ajax.php/tickets/<?php echo $ticket->getId();