PluginProbe
SupportCandy – AI Customer Support Ticket System & Live Chatbot Agent / 3.5.4
SupportCandy – AI Customer Support Ticket System & Live Chatbot Agent v3.5.4
3.5.4 3.5.3 3.5.2 3.5.1 3.4.9 3.5.0 3.4.8 3.4.7 trunk 2.3.1 3.3.6 3.3.7 3.3.8 3.3.9 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.4.5 3.4.6
supportcandy / includes / models / class-wpsc-agent.php

class-wpsc-agent.php in SupportCandy – AI Customer Support Ticket System & Live Chatbot Agent 3.5.4, at includes/models/class-wpsc-agent.php

1,240 lines 31.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) {
3 exit; // Exit if accessed directly!
4 }
5
6 if ( ! class_exists( 'WPSC_Agent' ) ) :
7
8 final class WPSC_Agent {
9
10 /**
11 * Object data in key => val pair.
12 *
13 * @var array
14 */
15 private $data = array();
16
17 /**
18 * Set whether or not current object properties modified
19 *
20 * @var boolean
21 */
22 private $is_modified = false;
23
24 /**
25 * Schema for this model
26 *
27 * @var array
28 */
29 public static $schema = array();
30
31 /**
32 * Prevent fields to modify
33 *
34 * @var array
35 */
36 public static $prevent_modify = array();
37
38 /**
39 * DB object caching
40 *
41 * @var array
42 */
43 private static $cache = array();
44
45 /**
46 * Initialize this class
47 *
48 * @return void
49 */
50 public static function init() {
51
52 // Apply schema for this model.
53 add_action( 'init', array( __CLASS__, 'apply_schema' ), 2 );
54
55 // Get object of this class.
56 add_filter( 'wpsc_load_ref_classes', array( __CLASS__, 'load_ref_class' ) );
57
58 // after profile update.
59 add_action( 'profile_update', array( __CLASS__, 'agent_profile_update' ), 10, 2 );
60
61 // reset missing count.
62 add_action( 'init', array( __CLASS__, 'reset_count_check' ), 200 );
63 add_action( 'wpsc_reset_missing_counts', array( __CLASS__, 'reset_missing_counts' ) );
64
65 // create ticket event to reset unresolved and workload counts of related agents to the ticket.
66 add_action( 'wpsc_create_new_ticket', array( __CLASS__, 'create_new_ticket' ), 500 );
67
68 // change status event to reset unresolved and workload counts of related agents to the ticket.
69 add_action( 'wpsc_change_ticket_status', array( __CLASS__, 'change_status' ), 500, 4 );
70
71 // assigned agent event to reset unresolved and workload counts of related agents to the ticket.
72 add_action( 'wpsc_change_assignee', array( __CLASS__, 'change_assignee' ), 500, 4 );
73
74 // change raised by event to reset unresolved and workload counts of related agents to the ticket.
75 add_action( 'wpsc_change_raised_by', array( __CLASS__, 'change_raised_by' ), 500, 4 );
76
77 // archive/restore/delete ticket event to reset unresolved and workload counts of related agents to the ticket.
78 add_action( 'wpsc_delete_ticket', array( __CLASS__, 'reset_agent_unresolved_count' ), 500 );
79 add_action( 'wpsc_ticket_restore', array( __CLASS__, 'reset_agent_unresolved_count' ), 500 );
80 add_action( 'wpsc_ticket_delete_permanently', array( __CLASS__, 'reset_agent_unresolved_count' ), 500 );
81 add_action( 'wpsc_ticket_archive', array( __CLASS__, 'reset_agents_unresolved_count' ), 500, 2 );
82 add_action( 'wpsc_archive_ticket_restore', array( __CLASS__, 'reset_agents_unresolved_count' ), 500, 2 );
83
84 // agent autocomplete admin access only.
85 add_action( 'wp_ajax_wpsc_agent_autocomplete_admin_access', array( __CLASS__, 'agent_autocomplete_admin_access' ) );
86
87 // reset unresolved count after agent role update.
88 add_action( 'wpsc_agent_role_update', array( __CLASS__, 'agent_role_update' ) );
89 }
90
91 /**
92 * Apply schema for this model
93 *
94 * @return void
95 */
96 public static function apply_schema() {
97
98 $schema = array(
99 'id' => array(
100 'has_ref' => false,
101 'ref_class' => '',
102 'has_multiple_val' => false,
103 ),
104 'user' => array(
105 'has_ref' => true,
106 'ref_class' => 'wp_user',
107 'has_multiple_val' => false,
108 ),
109 'customer' => array(
110 'has_ref' => true,
111 'ref_class' => 'wpsc_customer',
112 'has_multiple_val' => false,
113 ),
114 'role' => array(
115 'has_ref' => false,
116 'ref_class' => '',
117 'has_multiple_val' => false,
118 ),
119 'name' => array(
120 'has_ref' => false,
121 'ref_class' => '',
122 'has_multiple_val' => false,
123 ),
124 'workload' => array(
125 'has_ref' => false,
126 'ref_class' => '',
127 'has_multiple_val' => false,
128 ),
129 'unresolved_count' => array(
130 'has_ref' => false,
131 'ref_class' => '',
132 'has_multiple_val' => false,
133 ),
134 'is_agentgroup' => array(
135 'has_ref' => false,
136 'ref_class' => '',
137 'has_multiple_val' => false,
138 ),
139 'is_active' => array(
140 'has_ref' => false,
141 'ref_class' => '',
142 'has_multiple_val' => false,
143 ),
144 );
145 self::$schema = apply_filters( 'wpsc_agent_schema', $schema );
146
147 // Prevent modify.
148 $prevent_modify = array( 'id' );
149 self::$prevent_modify = apply_filters( 'wpsc_agent_prevent_modify', $prevent_modify );
150 }
151
152 /**
153 * Model constructor
154 *
155 * @param int $id - Optional. Data record id to retrive object for.
156 */
157 public function __construct( $id = 0 ) {
158
159 global $wpdb;
160
161 $id = intval( $id );
162
163 if ( isset( self::$cache[ $id ] ) ) {
164 $this->data = self::$cache[ $id ]->data;
165 return;
166 }
167
168 if ( $id > 0 ) {
169
170 $agent = $wpdb->get_row( "SELECT * FROM {$wpdb->prefix}psmsc_agents WHERE id = " . $id, ARRAY_A );
171 if ( ! is_array( $agent ) ) {
172 return;
173 }
174
175 foreach ( $agent as $key => $val ) {
176 $this->data[ $key ] = $val !== null ? $val : '';
177 }
178
179 self::$cache[ $id ] = $this;
180 }
181 }
182
183 /**
184 * Convert object into an array
185 *
186 * @return array
187 */
188 public function to_array() {
189
190 return $this->data;
191 }
192
193 /**
194 * Magic get function to use with object arrow function
195 *
196 * @param string $var_name - variable name.
197 * @return mixed
198 */
199 public function __get( $var_name ) {
200
201 if ( ! isset( $this->data[ $var_name ] ) ||
202 $this->data[ $var_name ] == null ||
203 $this->data[ $var_name ] == ''
204 ) {
205 return self::$schema[ $var_name ]['has_multiple_val'] ? array() : '';
206 }
207
208 if ( self::$schema[ $var_name ]['has_multiple_val'] ) {
209
210 $response = array();
211 $values = $this->data[ $var_name ] ? explode( '|', $this->data[ $var_name ] ) : array();
212 foreach ( $values as $val ) {
213 $response[] = self::$schema[ $var_name ]['has_ref'] ?
214 WPSC_Functions::get_object( self::$schema[ $var_name ]['ref_class'], $val ) :
215 $val;
216 }
217 return $response;
218
219 } else {
220
221 return self::$schema[ $var_name ]['has_ref'] && $this->data[ $var_name ] ?
222 WPSC_Functions::get_object( self::$schema[ $var_name ]['ref_class'], $this->data[ $var_name ] ) :
223 $this->data[ $var_name ];
224 }
225 }
226
227 /**
228 * Magic function to use setting object field with arrow function
229 *
230 * @param string $var_name - (Required) property slug.
231 * @param mixed $value - (Required) value to set for a property.
232 * @return void
233 */
234 public function __set( $var_name, $value ) {
235
236 if ( ! isset( $this->data[ $var_name ] ) ) {
237 return;
238 }
239
240 if ( in_array( $var_name, self::$prevent_modify ) ) {
241 return;
242 }
243
244 $data_val = '';
245 if ( self::$schema[ $var_name ]['has_multiple_val'] ) {
246
247 $data_vals = array_map(
248 fn( $val ) => is_object( $val ) ? WPSC_Functions::set_object( self::$schema[ $var_name ]['ref_class'], $val ) : $val,
249 $value
250 );
251
252 $data_val = $data_vals ? implode( '|', $data_vals ) : '';
253
254 } else {
255
256 $data_val = is_object( $value ) ? WPSC_Functions::set_object( self::$schema[ $var_name ]['ref_class'], $value ) : $value;
257 }
258
259 if ( isset( $this->data[ $var_name ] ) && $this->data[ $var_name ] == $data_val ) {
260 return;
261 }
262
263 $this->data[ $var_name ] = $data_val;
264 $this->is_modified = true;
265 }
266
267 /**
268 * Save changes made
269 *
270 * @return boolean
271 */
272 public function save() {
273
274 global $wpdb;
275
276 if ( ! $this->is_modified ) {
277 return true;
278 }
279
280 $data = $this->data;
281 $data['is_active'] = intval( $data['is_active'] );
282
283 $success = true;
284
285 unset( $data['id'] );
286 $success = $wpdb->update(
287 $wpdb->prefix . 'psmsc_agents',
288 $data,
289 array( 'id' => $this->data['id'] )
290 );
291
292 $this->is_modified = false;
293 self::$cache[ $this->id ] = $this;
294 return $success ? true : false;
295 }
296
297 /**
298 * Insert new record
299 *
300 * @param array $data - record data.
301 * @return WPSC_Agent
302 */
303 public static function insert( $data ) {
304
305 global $wpdb;
306
307 $success = $wpdb->insert(
308 $wpdb->prefix . 'psmsc_agents',
309 $data
310 );
311
312 if ( ! $success ) {
313 return false;
314 }
315
316 $agent = new WPSC_Agent( $wpdb->insert_id );
317 self::$cache[ $agent->id ] = $agent;
318 return $agent;
319 }
320
321 /**
322 * Make it inactive so that garbage collector will delete files associated in
323 * background and then delete the record. This will improve its performance.
324 *
325 * @param WPSC_Agent $agent - agent model.
326 * @return boolean
327 */
328 public static function destroy( $agent ) {
329
330 global $wpdb;
331 $agent->is_active = 0;
332 $agent->save();
333 return true;
334 }
335
336 /**
337 * Set data to create new object using direct data. Used in find method
338 *
339 * @param array $data - data to set for object.
340 * @return void
341 */
342 private function set_data( $data ) {
343
344 foreach ( $data as $var_name => $val ) {
345 $this->data[ $var_name ] = $val !== null ? $val : '';
346 }
347 self::$cache[ $this->id ] = $this;
348 }
349
350 /**
351 * Find records based on given filters
352 *
353 * @param array $filter - array containing array items like search, where, orderby, order, page_no, items_per_page, etc.
354 * @param boolean $is_object - return data as array or object. Default object.
355 * @return mixed
356 */
357 public static function find( $filter = array(), $is_object = true ) {
358
359 global $wpdb;
360
361 $filter['items_per_page'] = isset( $filter['items_per_page'] ) ? $filter['items_per_page'] : 20;
362 $filter['page_no'] = isset( $filter['page_no'] ) ? $filter['page_no'] : 1;
363 $filter['orderby'] = isset( $filter['orderby'] ) ? $filter['orderby'] : 'name';
364 $filter['order'] = isset( $filter['order'] ) ? $filter['order'] : 'ASC';
365
366 // orderby.
367 $filter['orderby'] = apply_filters( 'wpsc_agent_orderby_string', $filter['orderby'] );
368
369 // Add table alice to orderby.
370 $filter['orderby'] = 'a.' . $filter['orderby'];
371
372 $sql = 'SELECT a.* FROM ' . $wpdb->prefix . 'psmsc_agents a ';
373 $order = WPSC_Functions::parse_order( $filter );
374 $limit = WPSC_Functions::parse_limit( $filter );
375 $join = self::get_joins( $filter );
376 $where = self::get_where( $filter );
377
378 $group_by = 'GROUP BY a.id ';
379
380 $sql = $sql . $join . $where . $group_by . $order . $limit;
381 $results = $wpdb->get_results( $sql, ARRAY_A );
382
383 // total results.
384 $sql = 'SELECT count(a.id) FROM ' . $wpdb->prefix . 'psmsc_agents a ';
385 $total_items = $wpdb->get_var( $sql . $join . $where );
386
387 $response = WPSC_Functions::parse_response( $results, $total_items, $filter );
388
389 // Return array.
390 if ( ! $is_object ) {
391 return $response;
392 }
393
394 // create and return array of objects.
395 $temp_results = array();
396 foreach ( $response['results'] as $agent ) {
397
398 $ob = new WPSC_Agent();
399 $data = array();
400 foreach ( $agent as $key => $val ) {
401 $data[ $key ] = $val;
402 }
403 $ob->set_data( $data );
404 $temp_results[] = $ob;
405
406 // set cache.
407 self::$cache[ $ob->id ] = $ob;
408 }
409 $response['results'] = $temp_results;
410
411 return $response;
412 }
413
414 /**
415 * Apply joins to the query if search is needed
416 *
417 * @param array $filter - user filter.
418 * @return array
419 */
420 private static function get_joins( $filter ) {
421
422 global $wpdb;
423
424 $joins = array();
425 $search = WPSC_Functions::get_filter_search_str( $filter );
426 if ( $search ) {
427 $joins = array( 'LEFT JOIN ' . $wpdb->users . ' u ON a.user = u.ID' );
428 }
429
430 return $joins ? implode( ' ', $joins ) . ' ' : '';
431 }
432
433 /**
434 * Get where for find method
435 *
436 * @param array $filter - user filter.
437 * @return array
438 */
439 private static function get_where( $filter ) {
440
441 $where = array( '1=1' );
442
443 // Load meta filters.
444 $meta_query = isset( $filter['meta_query'] ) ? $filter['meta_query'] : array();
445 if ( $meta_query ) {
446 $where[] = WPSC_Functions::parse_user_filters( __CLASS__, $meta_query );
447 }
448
449 // Search.
450 $search = WPSC_Functions::get_filter_search_str( $filter );
451 if ( $search ) {
452 $search_query = array(
453 'CONVERT(a.name USING utf8) LIKE \'%' . $search . '%\'',
454 'CONVERT(u.user_login USING utf8) LIKE \'%' . $search . '%\'',
455 'CONVERT(u.user_nicename USING utf8) LIKE \'%' . $search . '%\'',
456 'CONVERT(u.user_email USING utf8) LIKE \'%' . $search . '%\'',
457 'CONVERT(u.display_name USING utf8) LIKE \'%' . $search . '%\'',
458 );
459 $where[] = implode( ' OR ', $search_query );
460 }
461
462 return 'WHERE (' . implode( ') AND (', $where ) . ') ';
463 }
464
465 /**
466 * Load current class to reference classes
467 *
468 * @param array $classes - Associative array of class names indexed by its slug.
469 * @return array
470 */
471 public static function load_ref_class( $classes ) {
472
473 $classes['wpsc_agent'] = array(
474 'class' => __CLASS__,
475 'save-key' => 'id',
476 );
477 return $classes;
478 }
479
480 /**
481 * Check whether wp user of given id is an agent or not
482 *
483 * @param int $user_id - wp user id.
484 * @return boolean
485 */
486 public static function get_by_user_id( $user_id ) {
487
488 if ( ! $user_id ) {
489 return new WPSC_Agent();
490 }
491
492 $response = self::find(
493 array(
494 'meta_query' => array(
495 'relation' => 'AND',
496 array(
497 'slug' => 'user',
498 'compare' => '=',
499 'val' => $user_id,
500 ),
501 ),
502 )
503 );
504
505 return $response['results'] ? $response['results'][0] : new WPSC_Agent();
506 }
507
508 /**
509 * Get agents by role.
510 *
511 * @param int $role_id - role id.
512 * @return array.
513 */
514 public static function get_by_role( $role_id ) {
515
516 $agents = self::find(
517 array(
518 'items_per_page' => 0,
519 'meta_query' => array(
520 'relation' => 'AND',
521 array(
522 'slug' => 'role',
523 'compare' => '=',
524 'val' => $role_id,
525 ),
526 array(
527 'slug' => 'is_active',
528 'compare' => '=',
529 'val' => 1,
530 ),
531 ),
532 )
533 )['results'];
534
535 return $agents;
536 }
537
538 /**
539 * Get an agent by customer
540 *
541 * @param WPSC_Customer $customer - customer object.
542 * @return WPSC_Agent
543 */
544 public static function get_by_customer( $customer ) {
545
546 $results = self::find(
547 array(
548 'meta_query' => array(
549 'relation' => 'AND',
550 array(
551 'slug' => 'customer',
552 'compare' => '=',
553 'val' => $customer->id,
554 ),
555 array(
556 'slug' => 'is_active',
557 'compare' => '=',
558 'val' => 1,
559 ),
560 ),
561 )
562 )['results'];
563
564 return $results ? $results[0] : new WPSC_Agent();
565 }
566
567 /**
568 * Agent autocomplete callback
569 *
570 * @param array $filters - autocomplete filter.
571 * @return array
572 */
573 public static function agent_autocomplete( $filters ) {
574
575 // Whitelisted map of accepted sort_by values to actual DB columns - only
576 // the two options offered in the sort-by dropdown are valid here.
577 $sortable_columns = array(
578 'name' => 'name',
579 'workload' => 'workload',
580 );
581 $orderby = isset( $sortable_columns[ $filters['sort_by'] ] ) ?
582 $sortable_columns[ $filters['sort_by'] ] : 'name';
583
584 $args = array(
585 'search' => $filters['term'],
586 'items_per_page' => 25,
587 'orderby' => $orderby,
588 'order' => 'ASC',
589 'meta_query' => array(
590 'relation' => 'AND',
591 array(
592 'slug' => 'is_active',
593 'compare' => '=',
594 'val' => 1,
595 ),
596 ),
597 );
598
599 if ( is_numeric( $filters['isAgentgroup'] ) ) {
600 $args['meta_query'][] = array(
601 'slug' => 'is_agentgroup',
602 'compare' => '=',
603 'val' => $filters['isAgentgroup'],
604 );
605 }
606
607 $args = apply_filters( 'wpsc_agent_autocomplete_filters', $args, $filters['filter_by'] );
608 $agents = self::find( $args )['results'];
609
610 $response = array();
611
612 if ( ! $filters['isMultiple'] ) {
613 $response[] = array(
614 'id' => 0,
615 'title' => esc_attr__( 'None', 'supportcandy' ),
616 );
617 }
618
619 foreach ( $agents as $agent ) {
620 $response[] = array(
621 'id' => $agent->id,
622 'title' => $agent->name,
623 );
624 }
625
626 return $response;
627 }
628
629 /**
630 * Return whether or not agent has given capability
631 *
632 * @param string $cap - capability slug.
633 * @return boolean
634 */
635 public function has_cap( $cap ) {
636
637 $roles = get_option( 'wpsc-agent-roles', array() );
638 if ( ! isset( $roles[ $this->role ] ) ) {
639 return false;
640 }
641 $role = $roles[ $this->role ];
642 return isset( $role['caps'][ $cap ] ) && $role['caps'][ $cap ] ? true : false;
643 }
644
645 /**
646 * Get signature of the agent
647 *
648 * @return string
649 */
650 public function get_signature() {
651
652 $signature = get_user_meta( $this->user->ID, get_current_blog_id() . '_wpsc_email_signature', true );
653 return $signature ? $signature : '';
654 }
655
656 /**
657 * Set signature for the agent
658 *
659 * @param string $signature - signature string.
660 * @return void
661 */
662 public function set_signature( $signature ) {
663
664 update_user_meta( $this->user->ID, get_current_blog_id() . '_wpsc_email_signature', $signature );
665 }
666
667 /**
668 * Get default filter for the agent
669 *
670 * @return string
671 */
672 public function get_default_filter() {
673
674 $current_user = WPSC_Current_User::$current_user;
675 $default_filters = get_option( 'wpsc-atl-default-filters' );
676 $saved_filters = $current_user->get_saved_filters();
677 $agent_view = get_option( 'wpsc-tl-ms-agent-view', array() );
678
679 $default_filter = get_user_meta( $this->user->ID, get_current_blog_id() . '_wpsc_tl_default_filter', true );
680 if ( ! $default_filter ) {
681 $this->set_default_filter( $agent_view['default-filter'] );
682 return $agent_view['default-filter'];
683 }
684
685 $default_flag = preg_match( '/default-(\d*)$/', $default_filter, $default_matches );
686 $saved_flag = preg_match( '/saved-(\d*)$/', $default_filter, $saved_matches );
687
688 if (
689 ! (
690 isset( $default_filters[ $default_filter ] ) ||
691 ( $default_flag && isset( $default_filters[ $default_matches[1] ] ) ) ||
692 ( $saved_flag && isset( $saved_filters[ $saved_matches[1] ] ) )
693 ) ||
694 ( isset( $default_filters[ $default_filter ] ) && ! $default_filters[ $default_filter ]['is_enable'] ) ||
695 ( $default_flag && isset( $default_filters[ $default_matches[1] ] ) && ! $default_filters[ $default_matches[1] ]['is_enable'] )
696 ) {
697 $this->set_default_filter( $agent_view['default-filter'] );
698 return $agent_view['default-filter'];
699 }
700
701 return $default_filter;
702 }
703
704 /**
705 * Set default filter for the agent
706 *
707 * @param string $filter - filter slug.
708 * @return void
709 */
710 public function set_default_filter( $filter ) {
711
712 update_user_meta( $this->user->ID, get_current_blog_id() . '_wpsc_tl_default_filter', $filter );
713 }
714
715 /**
716 * Get default tab for the agent
717 *
718 * @return string
719 */
720 public function get_default_tab() {
721 $tab = get_user_meta( $this->user->ID, get_current_blog_id() . '_wpsc_tl_default_tab', true );
722 return $tab ? $tab : 'ticket-list';
723 }
724
725 /**
726 * Set default tab for the agent
727 *
728 * @param string $filter - filter slug.
729 * @return void
730 */
731 public function set_default_tab( $filter ) {
732
733 update_user_meta( $this->user->ID, get_current_blog_id() . '_wpsc_tl_default_tab', $filter );
734 }
735
736 /**
737 * Update name of agent if there is change in wp user meta.
738 *
739 * @param int $user_id - wp user id.
740 * @param WP_User $old_user_data - updated user object.
741 * @return void
742 */
743 public static function agent_profile_update( $user_id, $old_user_data ) {
744
745 $agent = self::get_by_user_id( $user_id );
746 if ( $agent ) {
747 $user = get_userdata( $user_id );
748 $agent->name = $user->display_name;
749 $agent->save();
750 }
751 }
752
753 /**
754 * Get working hrs of current agent
755 *
756 * @return array
757 */
758 public function get_working_hrs() {
759
760 return WPSC_Working_Hour::get( $this->id );
761 }
762
763 /**
764 * Get exceptions of current agent
765 *
766 * @return array
767 */
768 public function get_wh_exceptions() {
769
770 return WPSC_Wh_Exception::get( $this->id );
771 }
772
773 /**
774 * Reset count check
775 *
776 * @return void
777 */
778 public static function reset_count_check() {
779
780 if ( ! wp_next_scheduled( 'wpsc_reset_missing_counts' ) ) {
781 wp_schedule_event(
782 time(),
783 'wpsc_5min',
784 'wpsc_reset_missing_counts'
785 );
786 }
787 }
788
789 /**
790 * Calculate agent workloads
791 *
792 * @return void
793 */
794 public static function reset_missing_counts() {
795
796 $agents = self::find(
797 array(
798 'items_per_page' => 10,
799 'meta_query' => array(
800 'relation' => 'AND',
801 array(
802 'slug' => 'is_active',
803 'compare' => '=',
804 'val' => 1,
805 ),
806 array(
807 'slug' => 'is_agentgroup',
808 'compare' => '=',
809 'val' => 0,
810 ),
811 array(
812 'relation' => 'OR',
813 array(
814 'slug' => 'workload',
815 'compare' => 'IS',
816 'val' => null,
817 ),
818 array(
819 'slug' => 'unresolved_count',
820 'compare' => 'IS',
821 'val' => null,
822 ),
823 ),
824 ),
825 )
826 )['results'];
827
828 foreach ( $agents as $agent ) {
829 $agent->reset_unresolved_count();
830 $agent->reset_workload();
831 }
832 }
833
834 /**
835 * Reset unresolved count for the agent
836 */
837 public function reset_unresolved_count() {
838
839 // tickets filter.
840 $filters = array( 'items_per_page' => 1 );
841
842 // system query.
843 $system_query = array(
844 'relation' => 'OR',
845 array(
846 'slug' => 'customer',
847 'compare' => '=',
848 'val' => $this->customer->id,
849 ),
850 );
851 if ( $this->has_cap( 'view-assigned-me' ) ) {
852 $system_query[] = array(
853 'slug' => 'assigned_agent',
854 'compare' => '=',
855 'val' => $this->id,
856 );
857 }
858 if ( $this->has_cap( 'view-unassigned' ) ) {
859 $system_query[] = array(
860 'slug' => 'assigned_agent',
861 'compare' => '=',
862 'val' => '',
863 );
864 }
865 if ( $this->has_cap( 'view-assigned-others' ) ) {
866 $system_query[] = array(
867 'slug' => 'assigned_agent',
868 'compare' => 'NOT IN',
869 'val' => array( $this->id, '' ),
870 );
871 }
872 $filters['system_query'] = apply_filters( 'wpsc_reset_agent_unresolved_system_query', $system_query, $this );
873
874 // meta query.
875 $more_settings = get_option( 'wpsc-tl-ms-agent-view' );
876 $filters['meta_query'] = array(
877 'relation' => 'OR',
878 array(
879 'slug' => 'status',
880 'compare' => 'IN',
881 'val' => $more_settings['unresolved-ticket-statuses'],
882 ),
883 );
884
885 // get tickets.
886 $response = WPSC_Ticket::find( $filters );
887
888 // save unresolved count.
889 $this->unresolved_count = $response['total_items'];
890 $this->save();
891 }
892
893 /**
894 * Reset workload count for the agent
895 */
896 public function reset_workload() {
897
898 if ( ! empty( $this->is_agentgroup ) ) {
899 return;
900 }
901
902 $more_settings = get_option( 'wpsc-tl-ms-agent-view', array() );
903 $statuses = isset( $more_settings['unresolved-ticket-statuses'] ) ? $more_settings['unresolved-ticket-statuses'] : array();
904 if ( empty( $statuses ) ) {
905 $this->workload = 0;
906 $this->save();
907 return;
908 }
909
910 $count = WPSC_Ticket::count(
911 array(
912 'items_per_page' => 1,
913 'meta_query' => array(
914 'relation' => 'AND',
915 array(
916 'slug' => 'status',
917 'compare' => 'IN',
918 'val' => $statuses,
919 ),
920 array(
921 'slug' => 'assigned_agent',
922 'compare' => '=',
923 'val' => $this->id,
924 ),
925 ),
926 )
927 );
928
929 $this->workload = (int) $count;
930 $this->save();
931 }
932
933 /**
934 * Reset unresolved count and workload after create new ticket.
935 *
936 * @param WPSC_Ticket $ticket - ticket object.
937 * @return void
938 */
939 public static function create_new_ticket( $ticket ) {
940
941 // reset workload for applicable agents.
942 foreach ( $ticket->assigned_agent as $agent ) {
943 $agent->reset_workload();
944 }
945
946 // reset unresolved count for applicable agents.
947 $agents = $ticket->get_current_read_permission_agents();
948 foreach ( $agents as $agent ) {
949 $agent->reset_unresolved_count();
950 }
951 }
952
953
954 /**
955 * Reset unresolved count and workload after change status.
956 *
957 * @param WPSC_Ticket $ticket - ticket object.
958 * @param int $prev - previous value.
959 * @param int $new - new value.
960 * @param int $customer_id - customer object id who made this change.
961 * @return void
962 */
963 public static function change_status( $ticket, $prev, $new, $customer_id ) {
964
965 // reset workload for applicable agents.
966 foreach ( $ticket->assigned_agent as $agent ) {
967 $agent->reset_workload();
968 }
969
970 // reset unresolved for applicable agents.
971 $agents = $ticket->get_current_read_permission_agents();
972 foreach ( $agents as $agent ) {
973 $agent->reset_unresolved_count();
974 }
975 }
976
977 /**
978 * Reset unresolved count and workload after change assignee
979 *
980 * @param WPSC_Ticket $ticket - ticket object.
981 * @param int $prev - previous value.
982 * @param int $new - new value.
983 * @param int $customer_id - customer object id who made this change.
984 * @return void
985 */
986 public static function change_assignee( $ticket, $prev, $new, $customer_id ) {
987
988 // reset workload for applicable agents.
989 $agents = array_merge( $prev, $new );
990 $temp_agents = array();
991 foreach ( $agents as $agent ) {
992 if ( ! isset( $temp_agents[ $agent->id ] ) ) {
993 $temp_agents[ $agent->id ] = $agent;
994 }
995 }
996 foreach ( $temp_agents as $agent ) {
997 $agent->reset_workload();
998 }
999
1000 // reset unresolved for applicable agents.
1001 $agents = $ticket->get_current_read_permission_agents();
1002 $agents = array_merge( $agents, $ticket->get_prev_read_permission_agents( $prev ) );
1003 $temp_agents = array();
1004 foreach ( $agents as $agent ) {
1005 if ( ! isset( $temp_agents[ $agent->id ] ) ) {
1006 $temp_agents[ $agent->id ] = $agent;
1007 }
1008 }
1009 foreach ( $temp_agents as $agent ) {
1010 $agent->reset_unresolved_count();
1011 }
1012 }
1013
1014 /**
1015 * Reset unresolved count and workload after change raised by
1016 *
1017 * @param WPSC_Ticket $ticket - ticket object.
1018 * @param int $prev - previous value.
1019 * @param int $new - new value.
1020 * @param int $customer_id - customer object id who made this change.
1021 * @return void
1022 */
1023 public static function change_raised_by( $ticket, $prev, $new, $customer_id ) {
1024
1025 $agents = array();
1026
1027 $prev_user = $prev->user;
1028 if ( $prev_user ) {
1029 $prev_agent = self::get_by_user_id( $prev_user->ID );
1030 if ( $prev_agent->id && $prev_agent->is_active ) {
1031 $agents[] = $prev_agent;
1032 }
1033 }
1034
1035 $new_user = $new->user;
1036 if ( $new_user ) {
1037 $new_agent = self::get_by_user_id( $new_user->ID );
1038 if ( $new_agent->id && $new_agent->is_active ) {
1039 $agents[] = $new_agent;
1040 }
1041 }
1042
1043 if ( $agents ) {
1044 foreach ( $agents as $agent ) {
1045 $agent->reset_unresolved_count();
1046 }
1047 }
1048 }
1049
1050 /**
1051 * Reset unresolved count and workload after restore archive ticket
1052 *
1053 * @param WPSC_Ticket $ticket - ticket object.
1054 * @param WPSC_Archive_Ticket $ar_ticket - archive ticket object.
1055 * @return void
1056 */
1057 public static function reset_agents_unresolved_count( $ticket, $ar_ticket ) {
1058
1059 self::reset_agent_unresolved_count( $ticket );
1060 }
1061
1062 /**
1063 * Reset unresolved count and workload after archive/restore/delete ticket
1064 *
1065 * @param WPSC_Ticket $ticket - ticket object.
1066 * @return void
1067 */
1068 public static function reset_agent_unresolved_count( $ticket ) {
1069
1070 $tl_advanced = get_option( 'wpsc-tl-ms-advanced' );
1071 if ( in_array( $ticket->status->id, $tl_advanced['closed-ticket-statuses'] ) ) {
1072 return;
1073 }
1074
1075 // reset workload for applicable agents.
1076 foreach ( $ticket->assigned_agent as $agent ) {
1077 if ( ! $agent->is_active ) {
1078 continue;
1079 }
1080 $agent->reset_workload();
1081 }
1082
1083 // reset unresolved for applicable agents.
1084 $agents = $ticket->get_current_read_permission_agents();
1085 foreach ( $agents as $agent ) {
1086 if ( ! $agent->is_active ) {
1087 continue;
1088 }
1089 $agent->reset_unresolved_count();
1090 }
1091 }
1092
1093 /**
1094 * Get editor of the agent
1095 *
1096 * @return string
1097 */
1098 public function get_signature_editor() {
1099
1100 return get_user_meta( $this->user->ID, get_current_blog_id() . '-wpsc_agent_signature_editor', true );
1101 }
1102
1103 /**
1104 * Set editor for current user
1105 *
1106 * @param string $editor - text/html editor for signature.
1107 * @return void
1108 */
1109 public function set_signature_editor( $editor ) {
1110
1111 update_user_meta( $this->user->ID, get_current_blog_id() . '-wpsc_agent_signature_editor', $editor );
1112 }
1113
1114 /**
1115 * Agent autocomplete for admin access only
1116 */
1117 public static function agent_autocomplete_admin_access() {
1118
1119 if ( check_ajax_referer( 'wpsc_agent_autocomplete_admin_access', '_ajax_nonce', false ) !== 1 ) {
1120 wp_send_json_error( 'Unauthorized request!', 401 );
1121 }
1122
1123 if ( ! WPSC_Functions::is_site_admin() ) {
1124 wp_send_json_error( __( 'Unauthorized access!', 'supportcandy' ), 401 );
1125 }
1126
1127 $filters = array();
1128
1129 $filters['term'] = isset( $_GET['q'] ) ? sanitize_text_field( wp_unslash( $_GET['q'] ) ) : '';
1130 $filters['filter_by'] = isset( $_GET['filter_by'] ) ? sanitize_text_field( wp_unslash( $_GET['filter_by'] ) ) : 'all';
1131 $filters['sort_by'] = isset( $_GET['sort_by'] ) ? sanitize_text_field( wp_unslash( $_GET['sort_by'] ) ) : 'name';
1132 $filters['isMultiple'] = isset( $_GET['isMultiple'] ) ? intval( wp_unslash( $_GET['isMultiple'] ) ) : 0;
1133
1134 $filters['isAgentgroup'] = 0;
1135 if ( class_exists( 'WPSC_Agentgroups' ) ) {
1136 $filters['isAgentgroup'] = isset( $_GET['isAgentgroup'] ) ? intval( $_GET['isAgentgroup'] ) : null;
1137 }
1138
1139 $response = self::agent_autocomplete( $filters );
1140 wp_send_json( $response );
1141 }
1142
1143 /**
1144 * Update unresolved count after agent role capabilities are updated
1145 *
1146 * @param integer $role_id - agent role id.
1147 * @return void
1148 */
1149 public static function agent_role_update( $role_id ) {
1150
1151 if ( ! WPSC_Functions::is_site_admin() ) {
1152 wp_send_json_error( __( 'Unauthorized access!', 'supportcandy' ), 401 );
1153 }
1154
1155 $args = array(
1156 'meta_query' => array(
1157 'relation' => 'AND',
1158 array(
1159 'slug' => 'role',
1160 'compare' => '=',
1161 'val' => $role_id,
1162 ),
1163 array(
1164 'slug' => 'is_active',
1165 'compare' => '=',
1166 'val' => 1,
1167 ),
1168 ),
1169 );
1170 $agents = self::find( $args )['results'];
1171
1172 foreach ( $agents as $agent ) {
1173
1174 $agent->reset_unresolved_count();
1175 }
1176 }
1177
1178 /**
1179 * Count tickets based on given filters
1180 *
1181 * @param array $filter - array containing array items like search, where, etc.
1182 * @return int
1183 */
1184 public static function count( $filter = array() ) {
1185
1186 global $wpdb;
1187
1188 $filter['is_active'] = isset( $filter['is_active'] ) ? $filter['is_active'] : 1;
1189
1190 $sql = 'SELECT count(a.id) FROM ' . $wpdb->prefix . 'psmsc_agents a ';
1191 $joins = self::get_joins( $filter );
1192 $where = self::get_where( $filter );
1193
1194 $sql = $sql . $joins . $where;
1195
1196 return (int) $wpdb->get_var( $sql );
1197 }
1198
1199 /**
1200 * Check current user ticket access for capability
1201 *
1202 * @param WPSC_Ticket|WPSC_Archive_Ticket $ticket Ticket object.
1203 * @param string $cap - capability name.
1204 * @return boolean
1205 */
1206 public static function has_ticket_cap( $ticket, $cap ) {
1207
1208 $current_user = WPSC_Current_User::$current_user;
1209
1210 $assigned_agents = array_map(
1211 fn ( $agent ) => $agent->id,
1212 $ticket->assigned_agent
1213 );
1214
1215 $flag = false;
1216 if (
1217 (
1218 ! $ticket->assigned_agent &&
1219 $current_user->agent->has_cap( $cap . '-unassigned' )
1220 ) ||
1221 (
1222 in_array( $current_user->agent->id, $assigned_agents ) &&
1223 $current_user->agent->has_cap( $cap . '-assigned-me' )
1224 ) ||
1225 (
1226 $ticket->assigned_agent &&
1227 ! in_array( $current_user->agent->id, $assigned_agents ) &&
1228 $current_user->agent->has_cap( $cap . '-assigned-others' )
1229 )
1230 ) {
1231 $flag = true;
1232 }
1233
1234 return apply_filters( 'wpsc_it_has_ticket_cap', $flag, $ticket, $cap );
1235 }
1236 }
1237 endif;
1238
1239 WPSC_Agent::init();
1240