class.SWIFT_Ticket.php

Amarjeet Kaur, 12/25/2012 12:19 am

Download (201.1 kB)

 
1
<?php
2
/**
3
 * ###############################################
4
 *
5
 * SWIFT Framework
6
 * _______________________________________________
7
 *
8
 * @author                Varun Shoor
9
 *
10
 * @package                SWIFT
11
 * @copyright        Copyright (c) 2001-2012, Kayako
12
 * @license                http://www.kayako.com/license
13
 * @link                http://www.kayako.com
14
 *
15
 * ###############################################
16
 */
17
18
/**
19
 * The Ticket Model Class
20
 *
21
 * @author Varun Shoor
22
 */
23
class SWIFT_Ticket extends SWIFT_Model
24
{
25
        const TABLE_NAME                =        'tickets';
26
        const PRIMARY_KEY                =        'ticketid';
27
28
        const TABLE_STRUCTURE        =        "ticketid I PRIMARY AUTO NOTNULL,
29
                                                                ticketmaskid C(20) DEFAULT '' NOTNULL,
30
                                                                departmentid I DEFAULT '0' NOTNULL,
31
                                                                departmenttitle C(255) DEFAULT '' NOTNULL,
32
                                                                ticketstatusid I DEFAULT '0' NOTNULL,
33
                                                                ticketstatustitle C(255) DEFAULT '' NOTNULL,
34
                                                                priorityid I DEFAULT '0' NOTNULL,
35
                                                                prioritytitle C(255) DEFAULT '' NOTNULL,
36
                                                                emailqueueid I DEFAULT '0' NOTNULL,
37
                                                                userid I DEFAULT '0' NOTNULL,
38
                                                                staffid I DEFAULT '0' NOTNULL,
39
                                                                ownerstaffid I DEFAULT '0' NOTNULL,
40
                                                                ownerstaffname C(255) DEFAULT '' NOTNULL,
41
                                                                assignstatus I2 DEFAULT '0' NOTNULL,
42
43
                                                                fullname C(225) DEFAULT '' NOTNULL,
44
                                                                email C(150) DEFAULT '' NOTNULL,
45
                                                                lastreplier C(255) DEFAULT '' NOTNULL,
46
                                                                replyto C(150) DEFAULT '' NOTNULL,
47
                                                                subject C(255) DEFAULT '' NOTNULL,
48
                                                                dateline I DEFAULT '0' NOTNULL,
49
                                                                lastactivity I DEFAULT '0' NOTNULL,
50
                                                                laststaffreplytime I DEFAULT '0' NOTNULL,
51
                                                                lastuserreplytime I DEFAULT '0' NOTNULL,
52
                                                                slaplanid I DEFAULT '0' NOTNULL,
53
                                                                ticketslaplanid I DEFAULT '0' NOTNULL,
54
                                                                duetime I DEFAULT '0' NOTNULL,
55
                                                                totalreplies I DEFAULT '0' NOTNULL,
56
                                                                ipaddress C(50) DEFAULT '0.0.0.0' NOTNULL,
57
                                                                flagtype I2 DEFAULT '0' NOTNULL,
58
                                                                hasnotes I2 DEFAULT '0' NOTNULL,
59
                                                                hasattachments I2 DEFAULT '0' NOTNULL,
60
                                                                isemailed I2 DEFAULT '0' NOTNULL,
61
                                                                edited I2 DEFAULT '0' NOTNULL,
62
                                                                editedbystaffid I DEFAULT '0' NOTNULL,
63
                                                                editeddateline I DEFAULT '0' NOTNULL,
64
                                                                creator I2 DEFAULT '0' NOTNULL,
65
                                                                charset C(100) DEFAULT '' NOTNULL,
66
                                                                transferencoding C(50) DEFAULT '' NOTNULL,
67
                                                                timeworked I DEFAULT '0' NOTNULL,
68
                                                                timebilled I DEFAULT '0' NOTNULL,
69
                                                                dateicon I DEFAULT '0' NOTNULL,
70
                                                                lastpostid I DEFAULT '0' NOTNULL,
71
                                                                firstpostid I DEFAULT '0' NOTNULL,
72
                                                                tgroupid I DEFAULT '0' NOTNULL,
73
                                                                messageid C(17) DEFAULT '' NOTNULL,
74
                                                                escalationruleid I DEFAULT '0' NOTNULL,
75
                                                                hasdraft I2 DEFAULT '0' NOTNULL,
76
                                                                hasbilling I2 DEFAULT '0' NOTNULL,
77
                                                                isphonecall I2 DEFAULT '0' NOTNULL,
78
                                                                isescalated I2 DEFAULT '0' NOTNULL,
79
                                                                isescalatedvolatile I2 DEFAULT '0' NOTNULL,
80
                                                                phoneno C(255) DEFAULT '' NOTNULL,
81
82
                                                                isautoclosed I2 DEFAULT '0' NOTNULL,
83
                                                                autocloseruleid I DEFAULT '0' NOTNULL,
84
                                                                autoclosestatus I2 DEFAULT '0' NOTNULL,
85
                                                                autoclosetimeline I DEFAULT '0' NOTNULL,
86
87
                                                                escalatedtime I DEFAULT '0' NOTNULL,
88
                                                                followupcount I DEFAULT '0' NOTNULL,
89
                                                                hasfollowup I2 DEFAULT '0' NOTNULL,
90
91
                                                                hasratings I2 DEFAULT '0' NOTNULL,
92
                                                                tickethash C(50) DEFAULT '' NOTNULL,
93
                                                                islinked I2 DEFAULT '0' NOTNULL,
94
                                                                trasholddepartmentid I DEFAULT '0' NOT NULL,
95
                                                                tickettype I2 DEFAULT '0' NOTNULL,
96
                                                                tickettypeid I DEFAULT '0' NOTNULL,
97
                                                                tickettypetitle C(255) DEFAULT '' NOTNULL,
98
                                                                creationmode I2 DEFAULT '0' NOTNULL,
99
100
                                                                isfirstcontactresolved I2 DEFAULT '0' NOTNULL,
101
                                                                wasreopened I2 DEFAULT '0' NOTNULL,
102
                                                                reopendateline I DEFAULT '0' NOTNULL,
103
                                                                resolutiondateline I DEFAULT '0' NOTNULL,
104
                                                                escalationlevelcount I DEFAULT '0' NOTNULL,
105
                                                                resolutionseconds I DEFAULT '0' NOTNULL,
106
                                                                resolutionlevel I DEFAULT '0' NOTNULL,
107
                                                                repliestoresolution I DEFAULT '0' NOTNULL,
108
109
                                                                averageresponsetime I DEFAULT '0' NOTNULL,
110
                                                                averageresponsetimehits I DEFAULT '0' NOTNULL,
111
                                                                firstresponsetime I DEFAULT '0' NOTNULL,
112
113
                                                                resolutionduedateline I DEFAULT '0' NOTNULL,
114
                                                                isresolved I2 DEFAULT '0' NOTNULL,
115
                                                                iswatched I2 DEFAULT '0' NOTNULL,
116
117
                                                                oldeditemailaddress C(255) DEFAULT '' NOTNULL,
118
119
                                                                linkkbarticleid I DEFAULT '0' NOTNULL,
120
                                                                linkticketmacroid I DEFAULT '0' NOTNULL,
121
                                                                bayescategoryid I DEFAULT '0' NOTNULL";
122
123
        const INDEX_TICKETCOUNT        =        'departmentid, ticketstatusid, ownerstaffid, lastactivity';
124
        const INDEX_1                        =        'userid, email, replyto, departmentid, isresolved';
125
        const INDEX_2                        =        'slaplanid, duetime, ticketstatusid';
126
        const INDEX_3                        =        'departmentid, ticketstatusid, lastactivity';
127
        const INDEX_4                        =        'email';
128
        const INDEX_5                        =        'departmentid, ticketstatusid, userid';
129
        const INDEX_6                        =        'departmentid, ticketstatusid, duetime';
130
        const INDEX_7                        =        'dateline';
131
        const INDEX_8                        =        'departmentid, ticketstatusid, lastuserreplytime';
132
        const INDEX_9                        =        'duetime, resolutionduedateline, isescalatedvolatile, isresolved';
133
        const INDEX_10                        =        'ticketmaskid, ticketid, departmentid';
134
        const INDEX_11                        =        'departmentid, ticketstatusid, duetime, resolutionduedateline';
135
        const INDEX_12                        =        'isresolved, departmentid';
136
        const INDEX_13                        =        'ticketstatusid, departmentid, priorityid, tickettypeid';
137
        const INDEX_14                        =        'isescalatedvolatile, isresolved';
138
        const INDEX_15                        =        'ticketid, departmentid'; // Used by Staff API Protocol
139
        const INDEX_16                        =        'ticketid, isresolved, autoclosestatus, lastactivity'; // Used by Auto Close
140
        const INDEX_17                        =        'autoclosestatus, autocloseruleid, autoclosetimeline'; // Used by Auto Close
141
        const INDEX_18                        =        'lastactivity'; // Unified Search
142
143
144
        const COLUMN_RENAME_HASBENCHMARKS = 'hasratings';
145
146
        protected $_dataStore = array();
147
148
        // Attachments
149
        static protected $_attachmentsContainer = array();
150
        static protected $_notificationAttachmentsContainer = array();
151
152
        // Notification Stuff
153
        public $Notification = false;
154
        public $NotificationManager = false;
155
        static protected $_notificationExecutionCache = array();
156
157
        // Workflow Queue Related Variables
158
        static protected $_isWorkflowQueueActive = false;
159
        static protected $_workflowQueue = array();
160
161
        // Watcher
162
        static protected $_watcherPendingCache = array();
163
        static protected $_watcherExecutedCache = array();
164
        protected $_watchNotificationMessage = '';
165
        protected $_lastPostNotificationMessage = '';
166
        protected $_watcherCustomName = '';
167
168
        protected $_noAlerts = false;
169
170
        /**
171
         * @var bool This property decides whether the SLA calculation has been queued on shutdown
172
         */
173
        protected $_slaOverdueQueued = -1;
174
175
        /**
176
         * @var bool This property is used to prevent the execution of SLA calculation.
177
         */
178
        protected $_noSLACalculation = false;
179
180
        /**
181
         * @var SWIFT_User This property is used to cache the user object
182
         */
183
        protected $_UserObject = false;
184
185
        /**
186
         * @var SWIFT_UserOrganization This property is used to cache the user organization object
187
         */
188
        protected $_UserOrganizationObject = false;
189
190
        /**
191
         * @var SWIFT_UserGroup This property is used to cache the user group object
192
         */
193
        protected $_UserGroupObject = false;
194
195
        /**
196
         * @var bool This property is used to determine the cache flag for the user object
197
         */
198
        protected $_isUserObjectCached = false;
199
200
        /**
201
         * @var bool This property is used to determine the cache flag for the user group object
202
         */
203
        protected $_isUserGroupObjectCached = false;
204
205
        /**
206
         * @var bool This property is used to determine the cache flag for the user organization object
207
         */
208
        protected $_isUserOrganizationObjectCached = false;
209
210
        /**
211
         * @var bool Is used to determine if the status was changed in this object
212
         */
213
        protected $_hasStatusChanged = false;
214
215
        /**
216
         * @var array Is used to keep old Ticket Properties.
217
         */
218
        protected $_oldTicketProperties = array();
219
220
        // Core Constants
221
        const CREATOR_STAFF = 1;
222
        const CREATOR_USER = 2;
223
        const CREATOR_CLIENT = 2;
224
225
        const CREATIONMODE_SUPPORTCENTER = 1;
226
        const CREATIONMODE_STAFFCP = 2;
227
        const CREATIONMODE_EMAIL = 3;
228
        const CREATIONMODE_API = 4;
229
        const CREATIONMODE_SITEBADGE = 5;
230
        const CREATIONMODE_MOBILE = 6;
231
        const CREATIONMODE_STAFFAPI = 7;
232
233
        const TYPE_DEFAULT = 1;
234
        const TYPE_PHONE = 2;
235
236
        const MAIL_NOTIFICATION = 1;
237
        const MAIL_CLIENT = 2;
238
        const MAIL_THIRDPARTY = 3;
239
240
        const AUTOCLOSESTATUS_NONE = 0;
241
        const AUTOCLOSESTATUS_PENDING = 1;
242
        const AUTOCLOSESTATUS_CLOSED = 2;
243
244
        /**
245
         * Constructor
246
         *
247
         * @author Varun Shoor
248
         * @param SWIFT_Data $_SWIFT_DataObject The SWIFT_Data Object
249
         * @return bool "true" on Success, "false" otherwise
250
         * @throws SWIFT_Ticket_Exception If the Record could not be loaded
251
         */
252
        public function __construct(SWIFT_Data $_SWIFT_DataObject)
253
        {
254
                parent::__construct();
255
256
                if (!$_SWIFT_DataObject instanceof SWIFT_Data || !$_SWIFT_DataObject->GetIsClassLoaded() || !$this->LoadData($_SWIFT_DataObject)) {
257
                        throw new SWIFT_Ticket_Exception('Failed to load Ticket Object');
258
259
                        $this->SetIsClassLoaded(false);
260
261
                        return false;
262
                }
263
264
                $this->Load->Library('Ticket:TicketManager');
265
266
                $this->Notification = new SWIFT_TicketNotification($this);
267
                $this->NotificationManager = new SWIFT_NotificationManager($this);
268
269
                register_shutdown_function(array($this, 'ProcessNotifications'));
270
271
                if ($this->GetProperty('iswatched') == '1') {
272
                        register_shutdown_function(array($this, 'ProcessWatchers'));
273
                }
274
275
                return true;
276
        }
277
278
        /**
279
         * Destructor
280
         *
281
         * @author Varun Shoor
282
         * @return bool "true" on Success, "false" otherwise
283
         */
284
        public function __destruct()
285
        {
286
                chdir(SWIFT_BASEPATH);
287
288
                if ($this->_slaOverdueQueued != -1) {
289
                        $this->ProcessSLAOverdue($this->_slaOverdueQueued);
290
                }
291
292
                if ($this->GetProperty('iswatched') == '1') {
293
                        $this->ProcessWatchers();
294
                }
295
296
                $this->ProcessUpdatePool();
297
298
                parent::__destruct();
299
300
                return true;
301
        }
302
303
        /**
304
         * Execute SLA If pending
305
         *
306
         * @author Varun Shoor
307
         * @param bool $_processResolutionDue (OPTIONAL) Whether to process the resolution due dateline
308
         * @param bool $_dontQueue (OPTIONAL) Dont queue the SLA execution
309
         * @return bool "true" on Success, "false" otherwise
310
         * @throws SWIFT_Exception If the Class is not Loaded
311
         */
312
        public function ExecuteSLA($_processResolutionDue = true, $_dontQueue = false) {
313
                if (!$this->GetIsClassLoaded()) {
314
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
315
316
                        return false;
317
                }
318
319
                $this->ProcessUpdatePool();
320
321
                if ($this->_slaOverdueQueued != -1 || $_dontQueue == true) {
322
                        $this->ProcessSLAOverdue($_processResolutionDue);
323
324
                        if ($_dontQueue) {
325
                                $this->ProcessUpdatePool();
326
                        }
327
                } else {
328
                        $this->QueueSLAOverdue($_processResolutionDue);
329
                }
330
331
                return true;
332
        }
333
334
        /**
335
         * Processes the Update Pool Data
336
         *
337
         * @author Varun Shoor
338
         * @return bool "true" on Success, "false" otherwise
339
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
340
         */
341
        public function ProcessUpdatePool()
342
        {
343
                if (!$this->GetIsClassLoaded()) {
344
                        return false;
345
                } else if (!_is_array($this->GetUpdatePool())) {
346
                        return false;
347
                }
348
349
                $this->Database->AutoExecute(TABLE_PREFIX . 'tickets', $this->GetUpdatePool(), 'UPDATE', "ticketid = '" . intval($this->GetTicketID()) .
350
                                "'");
351
352
                $this->ClearUpdatePool();
353
354
                return true;
355
        }
356
357
        /**
358
         * Retrieves the Ticket ID
359
         *
360
         * @author Varun Shoor
361
         * @return mixed "ticketid" on Success, "false" otherwise
362
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
363
         */
364
        public function GetTicketID()
365
        {
366
                if (!$this->GetIsClassLoaded())
367
                {
368
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
369
370
                        return false;
371
                }
372
373
                return $this->_dataStore['ticketid'];
374
        }
375
376
        /**
377
         * Load the Data
378
         *
379
         * @author Varun Shoor
380
         * @param SWIFT_Data $_SWIFT_DataObject The SWIFT_Data Object
381
         * @return bool "true" on Success, "false" otherwise
382
         * @throws SWIFT_Ticket_Exception If Invalid Data is Provided
383
         */
384
        protected function LoadData($_SWIFT_DataObject)
385
        {
386
                $_SWIFT = SWIFT::GetInstance();
387
388
                // Is it a ID?
389
                if ($_SWIFT_DataObject instanceof SWIFT_DataID && $_SWIFT_DataObject->GetIsClassLoaded())
390
                {
391
                        $_dataStore = $this->Database->QueryFetch("SELECT * FROM " . TABLE_PREFIX . "tickets WHERE ticketid = '" .
392
                                        intval($_SWIFT_DataObject->GetDataID()) . "'");
393
                        if (isset($_dataStore['ticketid']) && !empty($_dataStore['ticketid']))
394
                        {
395
                                $this->_dataStore = $_dataStore;
396
                                $this->_dataStore['displayticketid'] = IIF($_SWIFT->Settings->Get('t_eticketid') == 'seq', $this->_dataStore['ticketid'], $this->_dataStore['ticketmaskid']);
397
398
                                return true;
399
                        }
400
401
                // Is it a Store?
402
                } else if ($_SWIFT_DataObject instanceof SWIFT_DataStore && $_SWIFT_DataObject->GetIsClassLoaded()) {
403
                        $this->_dataStore = $_SWIFT_DataObject->GetDataStore();
404
                        $this->_dataStore['displayticketid'] = IIF($_SWIFT->Settings->Get('t_eticketid') == 'seq', $this->_dataStore['ticketid'], $this->_dataStore['ticketmaskid']);
405
406
                        if (!isset($this->_dataStore['ticketid']) || empty($this->_dataStore['ticketid']))
407
                        {
408
                                throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
409
                        }
410
411
                        return true;
412
                }
413
414
                throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
415
416
                return false;
417
        }
418
419
        /**
420
         * Returns the Data Store Array
421
         *
422
         * @author Varun Shoor
423
         * @return mixed "_dataStore" Array on Success, "false" otherwise
424
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
425
         */
426
        public function GetDataStore()
427
        {
428
                if (!$this->GetIsClassLoaded())
429
                {
430
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
431
432
                        return false;
433
                }
434
435
                return $this->_dataStore;
436
        }
437
438
        /**
439
         * Retrieves a Property Value from Data Store
440
         *
441
         * @author Varun Shoor
442
         * @param string $_key The Key Identifier
443
         * @return mixed Property Data on Success, "false" otherwise
444
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
445
         */
446
        public function GetProperty($_key)
447
        {
448
                if (!$this->GetIsClassLoaded())
449
                {
450
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
451
452
                        return false;
453
                } else if (!isset($this->_dataStore[$_key])) {
454
                        throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
455
456
                        return false;
457
                }
458
459
                return $this->_dataStore[$_key];
460
        }
461
462
        /**
463
         * Check to see if its a valid creator type
464
         *
465
         * @author Varun Shoor
466
         * @param constant $_creatorType The Creator Type
467
         * @return bool "true" on Success, "false" otherwise
468
         */
469
        static public function IsValidCreatorType($_creatorType)
470
        {
471
                if ($_creatorType == self::CREATOR_STAFF || $_creatorType == self::CREATOR_USER)
472
                {
473
                        return true;
474
                }
475
476
                return false;
477
        }
478
479
        /**
480
         * Check to see if its a valid creation mode
481
         *
482
         * @author Varun Shoor
483
         * @param constant $_creationMode The Creation Mode
484
         * @return bool "true" on Success, "false" otherwise
485
         */
486
        static public function IsValidCreationMode($_creationMode)
487
        {
488
                if ($_creationMode == self::CREATIONMODE_SUPPORTCENTER || $_creationMode == self::CREATIONMODE_STAFFCP ||
489
                                $_creationMode == self::CREATIONMODE_EMAIL || $_creationMode == self::CREATIONMODE_API ||
490
                                $_creationMode == self::CREATIONMODE_SITEBADGE || $_creationMode == self::CREATIONMODE_MOBILE ||
491
                                $_creationMode == self::CREATIONMODE_STAFFAPI)
492
                {
493
                        return true;
494
                }
495
496
                return false;
497
        }
498
499
        /**
500
         * Check to see if its a valid ticket type
501
         *
502
         * @author Varun Shoor
503
         * @param constant $_ticketType The Ticket Type
504
         * @return bool "true" on Success, "false" otherwise
505
         */
506
        static public function IsValidTicketType($_ticketType)
507
        {
508
                if ($_ticketType == self::TYPE_DEFAULT || $_ticketType == self::TYPE_PHONE)
509
                {
510
                        return true;
511
                }
512
513
                return false;
514
        }
515
516
        /**
517
         * Get or Create a User ID based on given info
518
         *
519
         * @author Varun Shoor
520
         * @param string $_fullName The User Full Name
521
         * @param string $_email the User Email
522
         * @param int $_userGroupID The User Group ID
523
         * @param int $_languageID (OPTIONAL) The Language ID
524
         * @param bool $_checkGeoIP (OPTIONAL) Check GeoIP for User
525
         * @return int The User ID on Success, "false" otherwise
526
         * @throws SWIFT_Ticket_Exception If Invalid Data is Provided
527
         */
528
        static public function GetOrCreateUserID($_fullName, $_email, $_userGroupID, $_languageID = false, $_checkGeoIP = false) {
529
                $_SWIFT = SWIFT::GetInstance();
530
531
                // User processing.. no user specified?
532
                $_userIDFromEmail = SWIFT_UserEmail::RetrieveUserIDOnUserEmail($_email);
533
534
                $_userID = false;
535
                if (!empty($_userIDFromEmail)) {
536
                        $_userID = $_userIDFromEmail;
537
                } else {
538
                        $_SWIFT_UserObject = SWIFT_User::Create($_userGroupID, false, SWIFT_User::SALUTATION_NONE, $_fullName, '', '', true,
539
                                        false, array($_email), false, $_languageID, false, false, false, false, false, true, true, $_checkGeoIP);
540
541
                        $_userID = $_SWIFT_UserObject->GetUserID();
542
                }
543
544
                return $_userID;
545
        }
546
547
        /**
548
         * Create a new Ticket
549
         *
550
         * @author Varun Shoor
551
         * @param string $_subject The Ticket Subject
552
         * @param string $_fullName The Full Name of Creator
553
         * @param string $_email The Email of Creator
554
         * @param string $_contents The Ticket Contents
555
         * @param int $_departmentID The Department ID
556
         * @param int $_ticketStatusID The Ticket Status ID
557
         * @param int $_ticketPriorityID The Ticket Priority ID
558
         * @param int $_ticketTypeID The Ticket Type ID
559
         * @param int $_userID The User ID (If creator is user)
560
         * @param int $_staffID The Staff ID (If creator is staff)
561
         * @param constant $_ticketType The Ticket Type (Default/Phone)
562
         * @param constant $_creatorType The Creator Type
563
         * @param constant $_creationMode The Creation Mode
564
         * @param string $_phoneNumber (OPTIONAL) The Phone Number of User
565
         * @param int $_emailQueueID (OPTIONAL) The Email Queue ID
566
         * @param bool $_dispatchAutoResponder (OPTIONAL) Whether to dispatch the autoresponder msg
567
         * @param string $_emailTo (OPTIONAL) Only to be used when creating tickets from staff cp and using send mail option. Signifies the destination email address.
568
         * @param bool $_isPrivate (OPTIONAL) Whether private ticket post
569
         * @return mixed "_SWIFT_TicketObject" (OBJECT) on Success, "false" otherwise
570
         * @throws SWIFT_Ticket_Exception If Invalid Data is Provided or If the Object could not be created
571
         */
572
        static public function Create($_subject, $_fullName, $_email, $_contents, $_departmentID, $_ticketStatusID, $_ticketPriorityID, $_ticketTypeID,
573
                        $_userID, $_staffID, $_ticketType, $_creatorType, $_creationMode, $_phoneNumber = '', $_emailQueueID = 0, $_dispatchAutoResponder = true,
574
                        $_emailTo = '', $_isHTML = false, $_date = DATENOW, $_isPrivate = false)
575
        {
576
                $_SWIFT = SWIFT::GetInstance();
577
578
                $_departmentID = intval($_departmentID);
579
                $_ticketStatusID = intval($_ticketStatusID);
580
                $_ticketPriorityID = intval($_ticketPriorityID);
581
                $_userID = intval($_userID);
582
                $_ticketTypeID = intval($_ticketTypeID);
583
584
                $_ticketTypeCache = $_SWIFT->Cache->Get('tickettypecache');
585
                if(empty($_ticketTypeID)) {
586
                        // Set default ticket type ID
587
                        foreach ($_ticketTypeCache as $_ticketTypeID => $_ticketTypeContainer) {
588
                                break;
589
                        }
590
591
                }
592
593
                if ($_subject == '' || empty($_fullName) || empty($_email) || $_contents == '' || empty($_departmentID) || empty($_ticketStatusID) ||        !self::IsValidCreatorType($_creatorType)
594
                                || !self::IsValidCreationMode($_creationMode) || !self::IsValidTicketType($_ticketType))
595
                {
596
                        throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
597
598
                        return false;
599
                }
600
601
602
                // Sanity check.. IMPORTANT
603
                $_departmentCache = $_SWIFT->Cache->Get('departmentcache');
604
                $_ticketStatusCache = $_SWIFT->Cache->Get('statuscache');
605
                $_ticketPriorityCache = $_SWIFT->Cache->Get('prioritycache');
606
607
                if (!isset($_departmentCache[$_departmentID]) || !isset($_ticketStatusCache[$_ticketStatusID]) ||
608
                                !isset($_ticketPriorityCache[$_ticketPriorityID]) || !isset($_ticketTypeCache[$_ticketTypeID])) {
609
                        throw new SWIFT_Ticket_Exception('Invalid Core Data: Department, Status, Priority, Type');
610
                } else if ($_departmentCache[$_departmentID]['departmentapp'] != APP_TICKETS) {
611
                        throw new SWIFT_Ticket_Exception('Invalid Department App');
612
                }
613
614
                $_ticketMaskID = GenerateUniqueMask();
615
616
                $_isPhoneCall = false;
617
                if ($_ticketType == self::TYPE_PHONE)
618
                {
619
                        $_isPhoneCall = true;
620
                }
621
622
                $_replyToEmail = $_email;
623
                if (!empty($_emailTo))
624
                {
625
                        $_replyToEmail = $_emailTo;
626
                }
627
628
                $_isEmailed = false;
629
                if ($_creationMode == self::CREATIONMODE_EMAIL)
630
                {
631
                        $_isEmailed = true;
632
                }
633
634
                $_ipAddress = '';
635
                if ($_SWIFT->Interface->GetInterface() != SWIFT_Interface::INTERFACE_CRON && $_SWIFT->Interface->GetInterface() != SWIFT_Interface::INTERFACE_CONSOLE)
636
                {
637
                        $_ipAddress = SWIFT::Get('IP');
638
                }
639
640
                $_SWIFT_BayesianObject = new SWIFT_Bayesian();
641
                $_finalBayesCategoryID = 0;
642
                $_probabilityContainer = $_SWIFT_BayesianObject->Get($_subject . ' ' . $_contents);
643
                if (_is_array($_probabilityContainer))
644
                {
645
                        $_finalBayesBenchmark = 0;
646
                        foreach ($_probabilityContainer[0] as $_bayesCategoryID => $_probability)
647
                        {
648
                                if ($_probability['combined'] >= 0.500 && $_probability['combined'] > $_finalBayesBenchmark)
649
                                {
650
                                        $_finalBayesCategoryID = $_bayesCategoryID;
651
                                        $_finalBayesBenchmark = $_probability['combined'];
652
                                }
653
                        }
654
                }
655
656
                $_SWIFT->Database->AutoExecute(TABLE_PREFIX . 'tickets', array('ticketmaskid' => $_ticketMaskID, 'departmentid' => intval($_departmentID),
657
                        'ticketstatusid' => intval($_ticketStatusID), 'priorityid' => intval($_ticketPriorityID), 'emailqueueid' => intval($_emailQueueID),
658
                        'userid' => intval($_userID), 'staffid' => intval($_staffID), 'fullname' => $_fullName, 'email' => mb_strtolower($_email), 'lastreplier' => $_fullName,
659
                        'replyto' => $_replyToEmail, 'subject' => $_subject, 'dateline' => $_date, 'lastactivity' => DATENOW, 'ipaddress' => $_ipAddress,
660
                        'isemailed' => intval($_isEmailed), 'isphonecall' => intval($_isPhoneCall), 'creator' => intval($_creatorType),
661
                        'tickettype' => intval($_ticketType), 'phoneno' => $_phoneNumber, 'tickettypeid' => intval($_ticketTypeID), 'tickethash' => substr(BuildHash(), 0, 12),
662
                        'creationmode' => intval($_creationMode), 'bayescategoryid' => intval($_finalBayesCategoryID)), 'INSERT');
663
                $_ticketID = $_SWIFT->Database->Insert_ID();
664
665
                if (!$_ticketID)
666
                {
667
                        throw new SWIFT_Ticket_Exception(SWIFT_CREATEFAILED);
668
669
                        return false;
670
                }
671
672
                $_SWIFT_TicketObject = new SWIFT_Ticket(new SWIFT_DataID($_ticketID));
673
                if (!$_SWIFT_TicketObject instanceof SWIFT_Ticket || !$_SWIFT_TicketObject->GetIsClassLoaded())
674
                {
675
                        throw new SWIFT_Ticket_Exception(SWIFT_CREATEFAILED);
676
677
                        return false;
678
                }
679
680
                $_departmentTitle = $_departmentCache[$_departmentID]['title'];
681
                $_statusTitle = $_ticketStatusCache[$_ticketStatusID]['title'];
682
                $_typeTitle = $_ticketTypeCache[$_ticketTypeID]['title'];
683
                $_priorityTitle = $_ticketPriorityCache[$_ticketPriorityID]['title'];
684
685
                $_SWIFT_TicketObject->UpdatePool('departmenttitle', $_departmentTitle);
686
                $_SWIFT_TicketObject->UpdatePool('ticketstatustitle', $_statusTitle);
687
                $_SWIFT_TicketObject->UpdatePool('tickettypetitle', $_typeTitle);
688
                $_SWIFT_TicketObject->UpdatePool('prioritytitle', $_priorityTitle);
689
690
                // Create the ticket post..
691
                $_creatorID = $_staffID;
692
                if ($_creatorType == self::CREATOR_CLIENT) {
693
                        $_creatorID = $_userID;
694
                }
695
696
                // Get Email Queue Name
697
                $_emailQueueCache = $_SWIFT->Cache->Get('queuecache');
698
                $_emailQueueAddress = '';
699
                if (isset($_emailQueueCache['list'][$_emailQueueID])) {
700
                        $_emailQueueAddress = $_emailQueueCache['list'][$_emailQueueID]['email'];
701
                }
702
703
                // Create Audit Log
704
705
                /*
706
                 * BUG FIX - Varun Shoor
707
                 *
708
                 * SWIFT-1657 Audit Log does not show email queue address via which ticket is created
709
                 *
710
                 * Comments: None
711
                 */
712
                if (!empty($_emailQueueAddress)) {
713
                        SWIFT_TicketAuditLog::AddToLog($_SWIFT_TicketObject, null, SWIFT_TicketAuditLog::ACTION_NEWTICKET, sprintf($_SWIFT->Language->Get('al_newticket_queue'), $_fullName, $_email, $_subject, $_emailQueueAddress),
714
                                SWIFT_TicketAuditLog::VALUE_NONE, 0, '', 0, '');
715
                } else {
716
                        SWIFT_TicketAuditLog::AddToLog($_SWIFT_TicketObject, null, SWIFT_TicketAuditLog::ACTION_NEWTICKET, sprintf($_SWIFT->Language->Get('al_newticket'), $_fullName, $_email, $_subject),
717
                                SWIFT_TicketAuditLog::VALUE_NONE, 0, '', 0, '');
718
                }
719
720
                $_ticketPostID = SWIFT_TicketPost::Create($_SWIFT_TicketObject, $_fullName, $_email, $_contents, $_creatorType, $_creatorID, $_creationMode,
721
                        $_subject, $_emailTo, $_isHTML, false, false, $_date, $_isPrivate);
722
723
                $_SWIFT_TicketObject->UpdatePool('firstpostid', $_ticketPostID);
724
                $_SWIFT_TicketObject->UpdatePool('lastpostid', $_ticketPostID);
725
                $_SWIFT_TicketObject->UpdatePool('totalreplies', '0');
726
727
728
                /*
729
                 * BUG FIX - Varun Shoor
730
                 *
731
                 * SWIFT-965 When a new ticket is created with status "closed", 'Clear due time' setting does not work
732
                 *
733
                 * Comments: None
734
                 */
735
736
                // SLA & Status Properties
737
                $_ticketStatusContainer = $_ticketStatusCache[$_ticketStatusID];
738
                if ($_ticketStatusContainer['resetduetime'] == '1') {
739
                        $_SWIFT_TicketObject->UpdatePool('duetime', '0');
740
                        $_SWIFT_TicketObject->_noSLACalculation = true;
741
                }
742
743
                if ($_ticketStatusContainer['markasresolved'] == '1')
744
                {
745
                        $_SWIFT_TicketObject->UpdatePool('isresolved', '1');
746
                        $_SWIFT_TicketObject->UpdatePool('resolutiondateline', DATENOW);
747
                        $_SWIFT_TicketObject->UpdatePool('repliestoresolution', $_SWIFT_TicketObject->GetProperty('totalreplies'));
748
749
                        // How much time did it take to resolve this ticket?
750
                        $_SWIFT_TicketObject->UpdatePool('resolutionseconds', DATENOW-$_SWIFT_TicketObject->GetProperty('dateline'));
751
                }
752
753
                // If the status is set to resolved then we reset the resolution due time
754
                $_processResolutionDue = false;
755
                if ($_ticketStatusContainer['markasresolved'] == '1') {
756
                        $_SWIFT_TicketObject->UpdatePool('resolutionduedateline', '0');
757
                        $_SWIFT_TicketObject->UpdatePool('duetime', '0');
758
759
                        $_SWIFT_TicketObject->_noSLACalculation = true;
760
761
                // Otherwise if its not, and resolutionduedateline is 0 then we force it to recalculate the resolution due time
762
                } else if ($_ticketStatusContainer['markasresolved'] == '0' && $_SWIFT_TicketObject->GetProperty('resolutionduedateline') == '0') {
763
                        $_processResolutionDue = true;
764
                }
765
766
                $_SWIFT_TicketObject->ProcessSLAOverdue($_processResolutionDue);
767
768
                // Notification Event
769
                $_SWIFT_TicketObject->NotificationManager->SetEvent('newticket');
770
771
                // Load and Process Workflow Rules
772
                self::AddToWorkflowQueue($_SWIFT_TicketObject);
773
774
                // Recount the cache
775
                SWIFT_TicketManager::Recount(false);
776
777
                if ($_dispatchAutoResponder == true)
778
                {
779
                        $_SWIFT_TicketObject->DispatchAutoresponder();
780
                }
781
782
                return $_SWIFT_TicketObject;
783
        }
784
785
        /**
786
         * Update the Ticket Record
787
         *
788
         * @author Varun Shoor
789
         * @param string $_subject The Ticket Subject
790
         * @param string $_fullName The Ticket Fullname
791
         * @param string $_email The Ticket Email
792
         * @return bool "true" on Success, "false" otherwise
793
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded or If Invalid Data is Provided
794
         */
795
        public function Update($_subject, $_fullName, $_email)
796
        {
797
                $_SWIFT = SWIFT::GetInstance();
798
799
                if (!$this->GetIsClassLoaded())
800
                {
801
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
802
803
                        return false;
804
                }
805
806
                // Create Audit Log
807
                SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATETICKET,
808
                        sprintf($_SWIFT->Language->Get('al_updateproperties'), StripName($this->GetProperty('subject'), 60), StripName($_subject, 60), StripName($this->GetProperty('fullname'), 30),
809
                        StripName($_fullName, 30), StripName($this->GetProperty('email'), 40), StripName($_email, 40)), SWIFT_TicketAuditLog::VALUE_NONE, 0, '', 0, '');
810
811
                $this->UpdatePool('subject', $_subject);
812
                $this->UpdatePool('fullname', $_fullName);
813
814
                $_ticketEmailAddress = $this->GetProperty('email');
815
                if ($this->GetProperty('replyto') != '')
816
                {
817
                        $_ticketEmailAddress = $this->GetProperty('replyto');
818
                }
819
820
                $this->UpdatePool('oldeditemailaddress', $_ticketEmailAddress);
821
                $this->UpdatePool('email', $_email);
822
                $this->UpdatePool('replyto', $_email);
823
824
                // Load and Process Workflow Rules
825
                self::AddToWorkflowQueue($this);
826
827
                return true;
828
        }
829
830
        /**
831
         * Delete the Ticket record
832
         *
833
         * @author Varun Shoor
834
         * @return bool "true" on Success, "false" otherwise
835
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
836
         */
837
        public function Delete()
838
        {
839
                if (!$this->GetIsClassLoaded())
840
                {
841
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
842
843
                        return false;
844
                }
845
846
                self::DeleteList(array($this->GetTicketID()));
847
848
                $this->SetIsClassLoaded(false);
849
850
                return true;
851
        }
852
853
        /**
854
         * Delete a list of Tickets
855
         *
856
         * @author Varun Shoor
857
         * @param array $_ticketIDList The Ticket ID List
858
         * @return bool "true" on Success, "false" otherwise
859
         */
860
        static public function DeleteList($_ticketIDList)
861
        {
862
                $_SWIFT = SWIFT::GetInstance();
863
864
                if (!_is_array($_ticketIDList))
865
                {
866
                        return false;
867
                }
868
869
                $_finalTicketIDList = $_departmentIDList = array();
870
                $_SWIFT->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickets WHERE ticketid IN (" . BuildIN($_ticketIDList) . ")");
871
                while ($_SWIFT->Database->NextRecord())
872
                {
873
                        $_finalTicketIDList[] = intval($_SWIFT->Database->Record['ticketid']);
874
875
                        $_departmentIDList[] = intval($_SWIFT->Database->Record['departmentid']);
876
877
                        $_SWIFT_TicketObject = new SWIFT_Ticket(new SWIFT_DataSTore($_SWIFT->Database->Record));
878
879
                        // Create Audit Log
880
                        SWIFT_TicketAuditLog::AddToLog($_SWIFT_TicketObject, null, SWIFT_TicketAuditLog::ACTION_DELETETICKET,
881
                                sprintf($_SWIFT->Language->Get('al_deleteticket'), $_SWIFT_TicketObject->GetTicketDisplayID(), $_SWIFT->Database->Record['subject'],
882
                                                $_SWIFT->Database->Record['fullname'], $_SWIFT->Database->Record['email']),
883
                                SWIFT_TicketAuditLog::VALUE_NONE, 0, '', 0, '');
884
                }
885
886
                if (!count($_finalTicketIDList))
887
                {
888
                        return false;
889
                }
890
891
                $_SWIFT->Database->Query("DELETE FROM " . TABLE_PREFIX . "tickets WHERE ticketid IN (" . BuildIN($_finalTicketIDList) . ")");
892
893
                // Clear Ticket Posts
894
                SWIFT_TicketPost::DeleteOnTicket($_finalTicketIDList);
895
896
                // Clear Attachments
897
                SWIFT_Attachment::DeleteOnTicket($_finalTicketIDList);
898
899
                // Clear Notes
900
                SWIFT_TicketNote::DeleteOnTicket($_finalTicketIDList);
901
902
                // Clear Ticket Drafts
903
                SWIFT_TicketDraft::DeleteOnTicket($_finalTicketIDList);
904
905
                // Release the Locks
906
                SWIFT_TicketLock::DeleteOnTicket($_finalTicketIDList);
907
                SWIFT_TicketPostLock::DeleteOnTicket($_finalTicketIDList);
908
909
                // Clear the Recipients
910
                SWIFT_TicketRecipient::DeleteOnTicket($_finalTicketIDList);
911
912
                // Clear the Audit Logs
913
                SWIFT_TicketAuditLog::DeleteOnTicket($_finalTicketIDList);
914
915
                // Clear the Time Track entries
916
                SWIFT_TicketTimeTrack::DeleteOnTicket($_finalTicketIDList);
917
918
                // Clear the Message IDs
919
                SWIFT_TicketMessageID::DeleteOnTicket($_finalTicketIDList);
920
921
                // Clear the Linked Table IDs
922
                SWIFT_TicketLinkedTable::DeleteOnTicket($_finalTicketIDList);
923
924
                // Clear the ticket watchers
925
                SWIFT_TicketWatcher::DeleteOnTicket($_finalTicketIDList);
926
927
                // Clear the chains
928
                SWIFT_TicketLinkChain::DeleteOnTicket($_finalTicketIDList);
929
930
                // Delete the merge logs
931
                SWIFT_TicketMergeLog::DeleteOnTicket($_finalTicketIDList);
932
933
                // Delete the Ticket Follow-Up's
934
                SWIFT_TicketFollowUp::DeleteOnTicket($_finalTicketIDList);
935
936
                // Delete the Ticket Escalation Paths
937
                SWIFT_EscalationPath::DeleteOnTicket($_finalTicketIDList);
938
939
                // Delete the Ticket Recurrence
940
                SWIFT_TicketRecurrence::DeleteOnTicket($_finalTicketIDList);
941
942
                // Delete the tags
943
                SWIFT_TagLink::DeleteOnLinkList(SWIFT_TagLink::TYPE_TICKET, $_finalTicketIDList);
944
945
                // Rebuild count cache
946
                SWIFT_TicketManager::RebuildCache();
947
948
                return true;
949
        }
950
951
        /**
952
         * Un-Delete a list of Tickets
953
         *
954
         * @author Varun Shoor
955
         * @param array $_ticketIDList The Ticket ID List
956
         * @return bool "true" on Success, "false" otherwise
957
         */
958
        static public function UnDeleteList($_ticketIDList)
959
        {
960
                $_SWIFT = SWIFT::GetInstance();
961
962
                if (!_is_array($_ticketIDList))
963
                {
964
                        return false;
965
                }
966
967
                $_finalTicketIDList = $_departmentIDList = $_ticketContainer = array();
968
                $_SWIFT->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickets WHERE ticketid IN (" . BuildIN($_ticketIDList) . ")");
969
                while ($_SWIFT->Database->NextRecord())
970
                {
971
                        $_ticketContainer[$_SWIFT->Database->Record['ticketid']] = $_SWIFT->Database->Record;
972
973
                        $_finalTicketIDList[] = intval($_SWIFT->Database->Record['ticketid']);
974
975
                        $_departmentIDList[] = intval($_SWIFT->Database->Record['departmentid']);
976
977
                        $_SWIFT_TicketObject = new SWIFT_Ticket(new SWIFT_DataSTore($_SWIFT->Database->Record));
978
979
                        // Create Audit Log
980
                        SWIFT_TicketAuditLog::AddToLog($_SWIFT_TicketObject, null, SWIFT_TicketAuditLog::ACTION_DELETETICKET,
981
                                sprintf($_SWIFT->Language->Get('al_untrashticket'), $_SWIFT_TicketObject->GetTicketDisplayID(), $_SWIFT->Database->Record['subject'],
982
                                                $_SWIFT->Database->Record['fullname'], $_SWIFT->Database->Record['email']),
983
                                SWIFT_TicketAuditLog::VALUE_NONE, 0, '', 0, '');
984
                }
985
986
                if (!count($_finalTicketIDList))
987
                {
988
                        return false;
989
                }
990
991
                foreach ($_finalTicketIDList as $_ticketID)
992
                {
993
                        $_SWIFT->Database->AutoExecute(TABLE_PREFIX . 'tickets', array('departmentid' => intval($_ticketContainer[$_ticketID]['trasholddepartmentid'])), 'UPDATE', "ticketid = '" . intval($_ticketID) . "'");
994
                }
995
996
                // Rebuild count cache
997
                SWIFT_TicketManager::RebuildCache();
998
999
                return true;
1000
        }
1001
1002
        /**
1003
         * Merge a list of tickets together
1004
         *
1005
         * @author Varun Shoor
1006
         * @param array $_ticketIDList The Ticket ID List
1007
         * @param int $_parentTicketID (OPTIONAL) The Parent Ticket ID
1008
         * @return bool "true" on Success, "false" otherwise
1009
         * @throws SWIFT_Ticket_Exception If Invalid Data is Provided
1010
         */
1011
        static public function Merge($_ticketIDList, $_parentTicketID = false, $_staffID = false) {
1012
                $_SWIFT = SWIFT::GetInstance();
1013
1014
                if (!_is_array($_ticketIDList) || (count($_ticketIDList) < 2 && empty($_parentTicketID))) {
1015
                        return false;
1016
                }
1017
1018
                $_departmentIDList = $_ticketMaskIDList = $_mergeTicketIDList = $_mergeEmailList = array();
1019
1020
                if (!$_parentTicketID) {
1021
                        $_parentTicketID = $_ticketIDList[0];
1022
                }
1023
1024
                // Load the parent ticket
1025
                $_SWIFT_ParentTicketObject = new SWIFT_Ticket(new SWIFT_DataID($_parentTicketID));
1026
                if (!$_SWIFT_ParentTicketObject instanceof SWIFT_Ticket || !$_SWIFT_ParentTicketObject->GetIsClassLoaded()) {
1027
                        throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
1028
                }
1029
1030
                $_departmentIDList[] = $_SWIFT_ParentTicketObject->GetProperty('departmentid');
1031
1032
                // Load the other objects
1033
                $_ticketObjectContainer = array();
1034
                $_SWIFT->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickets WHERE ticketid IN (" . BuildIN($_ticketIDList) . ")");
1035
                while ($_SWIFT->Database->NextRecord()) {
1036
                        if ($_SWIFT->Database->Record['ticketid'] == $_parentTicketID) {
1037
                                continue;
1038
                        }
1039
1040
                        $_ticketObjectContainer[$_SWIFT->Database->Record['ticketid']] = new SWIFT_Ticket(new SWIFT_DataStore($_SWIFT->Database->Record));
1041
1042
                        // Create Audit Log
1043
                        $_SWIFT_TicketObject_Merge = $_ticketObjectContainer[$_SWIFT->Database->Record['ticketid']];
1044
                        SWIFT_TicketAuditLog::AddToLog($_SWIFT_TicketObject_Merge, null, SWIFT_TicketAuditLog::ACTION_MERGETICKET,
1045
                                sprintf($_SWIFT->Language->Get('al_merge'), $_SWIFT_TicketObject_Merge->GetTicketDisplayID(), $_SWIFT->Database->Record['subject'],
1046
                                                $_SWIFT->Database->Record['fullname'], $_SWIFT->Database->Record['email']),
1047
                                SWIFT_TicketAuditLog::VALUE_NONE, 0, '', 0, '');
1048
1049
                        if (!in_array($_SWIFT->Database->Record['departmentid'], $_departmentIDList)) {
1050
                                $_departmentIDList[] = $_SWIFT->Database->Record['departmentid'];
1051
                        }
1052
1053
                        $_ticketMaskIDList[] = $_SWIFT->Database->Record['ticketmaskid'];
1054
1055
                        $_mergeTicketIDList[] = $_SWIFT->Database->Record['ticketid'];
1056
1057
                        if (!in_array($_SWIFT->Database->Record['email'], $_mergeEmailList) &&
1058
                                        $_SWIFT->Database->Record['email'] != $_SWIFT_ParentTicketObject->GetProperty('email')) {
1059
                                $_mergeEmailList[] = $_SWIFT->Database->Record['email'];
1060
                        }
1061
                }
1062
1063
                /**
1064
                 * @todo Raise Alert Here
1065
                 */
1066
1067
                // By now we have the parent ticket and the child tickets, we need to start the merge process now.
1068
1069
                // Update Notes. !! IMPORTANT: This needs to be called before ticket posts are updated. !!
1070
                SWIFT_TicketNoteManager::ReplaceTicket($_mergeTicketIDList, $_SWIFT_ParentTicketObject);
1071
1072
                // Update Ticket Posts
1073
                SWIFT_TicketPost::ReplaceTicket($_mergeTicketIDList, $_SWIFT_ParentTicketObject);
1074
1075
                // Update Attachments
1076
                SWIFT_Attachment::ReplaceTicket($_mergeTicketIDList, $_SWIFT_ParentTicketObject);
1077
1078
                // Update the Recipients
1079
                SWIFT_TicketRecipient::ReplaceTicket($_mergeTicketIDList, $_SWIFT_ParentTicketObject);
1080
1081
                // Update the Audit Logs
1082
                SWIFT_TicketAuditLog::ReplaceTicket($_mergeTicketIDList, $_SWIFT_ParentTicketObject);
1083
1084
                // Update the Time Track entries
1085
                SWIFT_TicketTimeTrack::ReplaceTicket($_mergeTicketIDList, $_SWIFT_ParentTicketObject);
1086
1087
                // Update the Ticket Follow-Up's
1088
                SWIFT_TicketFollowUp::ReplaceTicket($_mergeTicketIDList, $_SWIFT_ParentTicketObject);
1089
1090
                // Add all the recipients if needed
1091
                if ($_SWIFT->Settings->Get('t_mergrecip') == 1 && count($_mergeEmailList))
1092
                {
1093
                        SWIFT_TicketRecipient::Create($_SWIFT_ParentTicketObject, SWIFT_TicketRecipient::TYPE_CC, $_mergeEmailList);
1094
                }
1095
1096
                // Recaclulate all properties
1097
                $_SWIFT_ParentTicketObject->RebuildProperties();
1098
1099
                /**
1100
                 * @todo Add Audit Log Entry
1101
                 */
1102
1103
                // First add the Merge Log List.. this is used to route replies to the right ticket.
1104
                foreach ($_ticketObjectContainer as $_ticketID => $_SWIFT_TicketObject) {
1105
                        SWIFT_TicketMergeLog::Create($_SWIFT_ParentTicketObject, $_SWIFT_TicketObject->GetTicketID(),
1106
                                        $_SWIFT_TicketObject->GetProperty('ticketmaskid'), $_staffID);
1107
                }
1108
1109
                // Delete JUST the ticket entries
1110
                $_SWIFT->Database->Query("DELETE FROM " . TABLE_PREFIX . "tickets WHERE ticketid IN (" . BuildIN($_mergeTicketIDList) . ")");
1111
1112
                // Clear Ticket Drafts
1113
                SWIFT_TicketDraft::DeleteOnTicket($_mergeTicketIDList);
1114
1115
                // Release the Locks
1116
                SWIFT_TicketLock::DeleteOnTicket($_mergeTicketIDList);
1117
                SWIFT_TicketPostLock::DeleteOnTicket($_mergeTicketIDList);
1118
1119
                // Clear the Message IDs
1120
                SWIFT_TicketMessageID::DeleteOnTicket($_mergeTicketIDList);
1121
1122
                // Clear the Linked Table IDs
1123
                SWIFT_TicketLinkedTable::DeleteOnTicket($_mergeTicketIDList);
1124
1125
                // Clear the ticket watchers
1126
                SWIFT_TicketWatcher::DeleteOnTicket($_mergeTicketIDList);
1127
1128
                // Clear the chains
1129
                SWIFT_TicketLinkChain::DeleteOnTicket($_mergeTicketIDList);
1130
1131
                // Delete the Ticket Escalation Paths
1132
                SWIFT_EscalationPath::DeleteOnTicket($_mergeTicketIDList);
1133
1134
                // Delete the Ticket Recurrence
1135
                SWIFT_TicketRecurrence::DeleteOnTicket($_mergeTicketIDList);
1136
1137
                // Delete the tags
1138
                SWIFT_TagLink::DeleteOnLinkList(SWIFT_TagLink::TYPE_TICKET, $_mergeTicketIDList);
1139
1140
                // Time for a recount
1141
                SWIFT_TicketManager::RebuildCache();
1142
1143
                return true;
1144
        }
1145
1146
        /**
1147
         * Move the Ticket record to trash
1148
         *
1149
         * @author Varun Shoor
1150
         * @return bool "true" on Success, "false" otherwise
1151
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
1152
         */
1153
        public function Trash()
1154
        {
1155
                if (!$this->GetIsClassLoaded())
1156
                {
1157
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
1158
1159
                        return false;
1160
                }
1161
1162
                self::TrashList(array($this->GetTicketID()));
1163
1164
                return true;
1165
        }
1166
1167
        /**
1168
         * Trash a list of Tickets
1169
         *
1170
         * @author Varun Shoor
1171
         * @param array $_ticketIDList The Ticket ID List
1172
         * @return bool "true" on Success, "false" otherwise
1173
         */
1174
        static public function TrashList($_ticketIDList)
1175
        {
1176
                $_SWIFT = SWIFT::GetInstance();
1177
1178
                if (!_is_array($_ticketIDList))
1179
                {
1180
                        return false;
1181
                }
1182
1183
                $_finalTicketIDList = $_departmentIDList = array();
1184
                $_SWIFT->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickets WHERE ticketid IN (" . BuildIN($_ticketIDList) . ")");
1185
                while ($_SWIFT->Database->NextRecord())
1186
                {
1187
                        $_SWIFT_TicketObject = new SWIFT_Ticket(new SWIFT_DataStore($_SWIFT->Database->Record));
1188
                        $_SWIFT_TicketObject->UpdateTrashDepartment();
1189
1190
                        $_finalTicketIDList[] = intval($_SWIFT->Database->Record['ticketid']);
1191
1192
                        $_departmentIDList[] = intval($_SWIFT->Database->Record['departmentid']);
1193
1194
                        // Create Audit Log
1195
                        SWIFT_TicketAuditLog::AddToLog($_SWIFT_TicketObject, null, SWIFT_TicketAuditLog::ACTION_TRASHTICKET,
1196
                                sprintf($_SWIFT->Language->Get('al_trashticket'), $_SWIFT_TicketObject->GetTicketDisplayID(), $_SWIFT->Database->Record['subject'],
1197
                                                $_SWIFT->Database->Record['fullname'], $_SWIFT->Database->Record['email']),
1198
                                SWIFT_TicketAuditLog::VALUE_NONE, 0, '', 0, '');
1199
                }
1200
1201
                if (!count($_finalTicketIDList))
1202
                {
1203
                        return false;
1204
                }
1205
1206
                $_SWIFT->Database->AutoExecute(TABLE_PREFIX . 'tickets', array('departmentid' => '0'), 'UPDATE', "ticketid IN (" .
1207
                                BuildIN($_finalTicketIDList) . ")");
1208
1209
                // Rebuild count cache
1210
                SWIFT_TicketManager::RebuildCache();
1211
1212
                return true;
1213
        }
1214
1215
        /**
1216
         * Update the trash department
1217
         *
1218
         * @author Varun Shoor
1219
         * @return bool "true" on Success, "false" otherwise
1220
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
1221
         */
1222
        public function UpdateTrashDepartment() {
1223
                if (!$this->GetIsClassLoaded()) {
1224
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
1225
1226
                        return false;
1227
                }
1228
1229
                /*
1230
                 * BUG FIX - Varun Shoor
1231
                 *
1232
                 * SWIFT-1781 Help desk is not removing the SLA while moving the tickets in Trash folder
1233
                 *
1234
                 */
1235
                $this->ClearOverdue();
1236
                $this->ClearResolutiondue();
1237
                $this->UpdatePool('slaplanid', '0');
1238
                $this->UpdatePool('trasholddepartmentid', $this->GetProperty('departmentid'));
1239
                $this->ProcessUpdatePool();
1240
1241
                return true;
1242
        }
1243
1244
        /**
1245
         * Ban the creator of this ticket
1246
         *
1247
         * @author Varun Shoor
1248
         * @return bool "true" on Success, "false" otherwise
1249
         * @param int $_staffID (OPTIONAL) The Staff ID initiating the Ban
1250
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
1251
         */
1252
        public function Ban($_staffID = 0)
1253
        {
1254
                if (!$this->GetIsClassLoaded())
1255
                {
1256
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
1257
1258
                        return false;
1259
                }
1260
1261
                self::BanList(array($this->GetTicketID()), $_staffID);
1262
1263
                return true;
1264
        }
1265
1266
        /**
1267
         * Ban a list of ticket ids
1268
         *
1269
         * @author Varun Shoor
1270
         * @param array $_ticketIDList The Ticket ID List to ban
1271
         * @param int $_staffID (OPTIONAL) The Staff ID initiating the Ban
1272
         * @return bool "true" on Success, "false" otherwise
1273
         */
1274
        static public function BanList($_ticketIDList, $_staffID = 0)
1275
        {
1276
                $_SWIFT = SWIFT::GetInstance();
1277
1278
                if (!_is_array($_ticketIDList))
1279
                {
1280
                        return false;
1281
                }
1282
1283
                $_staffCache = $_SWIFT->Cache->Get('staffcache');
1284
                $_emailQueueCache = $_SWIFT->Cache->Get('queuecache');
1285
                $_rejectEmailList = array();
1286
1287
                foreach ($_staffCache as $_key => $_val)
1288
                {
1289
                        $_rejectEmailList[] = mb_strtolower($_val['email']);
1290
                }
1291
1292
                if (_is_array($_emailQueueCache) && isset($_emailQueueCache['list']) && _is_array($_emailQueueCache['list']))
1293
                {
1294
                        foreach ($_emailQueueCache['list'] as $_key => $_val)
1295
                        {
1296
                                $_rejectEmailList[] = mb_strtolower($_val['email']);
1297
                        }
1298
                }
1299
1300
                $_finalEmailBanList = array();
1301
                $_SWIFT->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickets WHERE ticketid IN (" . BuildIN($_ticketIDList) . ")");
1302
                while ($_SWIFT->Database->NextRecord())
1303
                {
1304
                        $_SWIFT_TicketObject = new SWIFT_Ticket(new SWIFT_DataStore($_SWIFT->Database->Record));
1305
1306
                        // Create Audit Log
1307
                        SWIFT_TicketAuditLog::AddToLog($_SWIFT_TicketObject, null, SWIFT_TicketAuditLog::ACTION_BAN,
1308
                                sprintf($_SWIFT->Language->Get('al_ban'), $_SWIFT_TicketObject->GetTicketDisplayID(), $_SWIFT->Database->Record['email']),
1309
                                SWIFT_TicketAuditLog::VALUE_NONE, 0, '', 0, '');
1310
1311
                        if (!in_array(mb_strtolower($_SWIFT->Database->Record['email']), $_finalEmailBanList) &&
1312
                                        !in_array(mb_strtolower($_SWIFT->Database->Record['email']), $_rejectEmailList))
1313
                        {
1314
                                $_finalEmailBanList[] = mb_strtolower($_SWIFT->Database->Record['email']);
1315
                        }
1316
                }
1317
1318
                if (!count($_finalEmailBanList))
1319
                {
1320
                        return false;
1321
                }
1322
1323
                SWIFT_Loader::LoadModel('Ban:ParserBan', APP_PARSER);
1324
1325
                if (class_exists('SWIFT_ParserBan', false))
1326
                {
1327
                        foreach ($_finalEmailBanList as $_key => $_val)
1328
                        {
1329
                                SWIFT_ParserBan::Create($_val, $_staffID);
1330
                        }
1331
                }
1332
1333
                return true;
1334
        }
1335
1336
        /**
1337
         * Recaculates the 'hasattachment' property of the given tickets
1338
         *
1339
         * @author Varun Shoor
1340
         * @param array $_ticketIDList The Ticket ID List
1341
         * @return bool "true" on Success, "false" otherwise
1342
         * @throws SWIFT_Ticket_Exception If Invalid Data is Provided
1343
         */
1344
        static public function RecalculateHasAttachmentProperty($_ticketIDList) {
1345
                $_SWIFT = SWIFT::GetInstance();
1346
1347
                if (!_is_array($_ticketIDList)) {
1348
                        return false;
1349
                }
1350
1351
                $_finalTicketIDList = array();
1352
                $_SWIFT->Database->Query("SELECT ticketid FROM " . TABLE_PREFIX . "tickets WHERE ticketid IN (" . BuildIN($_ticketIDList) . ")");
1353
                while ($_SWIFT->Database->NextRecord()) {
1354
                        $_finalTicketIDList[] = $_SWIFT->Database->Record['ticketid'];
1355
                }
1356
1357
                if (!count($_finalTicketIDList)) {
1358
                        return false;
1359
                }
1360
1361
                // Now we calculate attachments
1362
                $_attachmentCountContainer = array();
1363
                $_SWIFT->Database->Query("SELECT COUNT(*) AS totalitems, ticketid FROM " . TABLE_PREFIX . "attachments GROUP BY ticketid HAVING ticketid IN (" . BuildIN($_finalTicketIDList) . ")");
1364
                while ($_SWIFT->Database->NextRecord()) {
1365
                        $_attachmentCountContainer[$_SWIFT->Database->Record['ticketid']] = intval($_SWIFT->Database->Record['totalitems']);
1366
                }
1367
1368
                $_attachmentTicketIDList = array();
1369
                foreach ($_attachmentCountContainer as $_key => $_val) {
1370
                        if ($_val > 0) {
1371
                                $_attachmentTicketIDList[] = $_key;
1372
                        }
1373
                }
1374
1375
                $_nonAttachmentTicketIDList = array();
1376
                foreach ($_finalTicketIDList as $_ticketID) {
1377
                        if (!in_array($_ticketID, $_attachmentTicketIDList)) {
1378
                                $_nonAttachmentTicketIDList[] = $_ticketID;
1379
                        }
1380
                }
1381
1382
                $_SWIFT->Database->AutoExecute(TABLE_PREFIX . 'tickets', array('hasattachments' => '1'), 'UPDATE', "ticketid IN (" . BuildIN($_attachmentTicketIDList) . ")");
1383
1384
                if (count($_nonAttachmentTicketIDList)) {
1385
                        $_SWIFT->Database->AutoExecute(TABLE_PREFIX . 'tickets', array('hasattachments' => '0'), 'UPDATE', "ticketid IN (" . BuildIN($_nonAttachmentTicketIDList) . ")");
1386
                }
1387
1388
                return true;
1389
        }
1390
1391
        /**
1392
         * Retrieve the User Group ID based on User ID
1393
         *
1394
         * @author Varun Shoor
1395
         * @return bool "true" on Success, "false" otherwise
1396
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
1397
         */
1398
        public function GetUserGroupID() {
1399
                if (!$this->GetIsClassLoaded()) {
1400
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
1401
1402
                        return false;
1403
                }
1404
1405
                $_userID = intval($this->GetProperty('userid'));
1406
                if (empty($_userID)) {
1407
                        return false;
1408
                }
1409
1410
                try {
1411
                        $_SWIFT_UserObject = $this->GetUserObject();
1412
1413
                        if ($_SWIFT_UserObject instanceof SWIFT_User && $_SWIFT_UserObject->GetIsClassLoaded()) {
1414
                                return $_SWIFT_UserObject->GetProperty('usergroupid');
1415
                        }
1416
1417
                } catch (SWIFT_Exception $_SWIFT_ExceptionObject) {
1418
                        return false;
1419
                }
1420
1421
                return false;
1422
        }
1423
1424
        /**
1425
         * Retrieve the SLA properties. This array is used to process the SLA rules and the value should match the criteria specified for SWIFT_SLA
1426
         *
1427
         * @author Varun Shoor
1428
         * @return mixed "_slaProperties" (ARRAY) on Success, "false" otherwise
1429
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
1430
         */
1431
        public function GetSLAProperties() {
1432
                if (!$this->GetIsClassLoaded()) {
1433
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
1434
1435
                        return false;
1436
                }
1437
1438
                $_slaProperties = array();
1439
                $_slaProperties[SWIFT_SLA::SLA_TICKETSTATUS] = $this->GetProperty('ticketstatusid');
1440
                $_slaProperties[SWIFT_SLA::SLA_TICKETPRIORITY] = $this->GetProperty('priorityid');
1441
                $_slaProperties[SWIFT_SLA::SLA_TICKETDEPARTMENT] = $this->GetProperty('departmentid');
1442
                $_slaProperties[SWIFT_SLA::SLA_TICKETOWNER] = $this->GetProperty('ownerstaffid');
1443
                $_slaProperties[SWIFT_SLA::SLA_TICKETEMAILQUEUE] = $this->GetProperty('emailqueueid');
1444
                $_slaProperties[SWIFT_SLA::SLA_TICKETFLAGTYPE] = $this->GetProperty('flagtype');
1445
                $_slaProperties[SWIFT_SLA::SLA_TICKETCREATOR] = $this->GetProperty('creator');
1446
                $_slaProperties[SWIFT_SLA::SLA_TICKETUSERGROUP] = $this->GetUserGroupID();
1447
1448
                $_slaProperties[SWIFT_SLA::SLA_TICKETFULLNAME] = $this->GetProperty('fullname');
1449
                $_slaProperties[SWIFT_SLA::SLA_TICKETEMAIL] = $this->GetProperty('email');
1450
                $_slaProperties[SWIFT_SLA::SLA_TICKETLASTREPLIER] = $this->GetProperty('lastreplier');
1451
                $_slaProperties[SWIFT_SLA::SLA_TICKETSUBJECT] = $this->GetProperty('subject');
1452
                $_slaProperties[SWIFT_SLA::SLA_TICKETCHARSET] = $this->GetProperty('charset');
1453
1454
                $_slaProperties[SWIFT_SLA::SLA_TICKETTEMPLATEGROUP] = $this->GetProperty('tgroupid');
1455
                $_slaProperties[SWIFT_SLA::SLA_TICKETISRESOLVED] = $this->GetProperty('isresolved');
1456
                $_slaProperties[SWIFT_SLA::SLA_TICKETTYPE] = $this->GetProperty('tickettypeid');
1457
                $_slaProperties[SWIFT_SLA::SLA_TICKETWASREOPENED] = $this->GetProperty('wasreopened');
1458
                $_slaProperties[SWIFT_SLA::SLA_TICKETTOTALREPLIES] = $this->GetProperty('totalreplies');
1459
                $_slaProperties[SWIFT_SLA::SLA_TICKETBAYESCATEGORY] = $this->GetProperty('bayescategoryid');
1460
1461
                return $_slaProperties;
1462
        }
1463
1464
        /**
1465
         * process the SLA Overdue time
1466
         *
1467
         * @author Varun Shoor
1468
         * @param bool $_processResolutionDue (OPTIONAL) Whether to process the resolution due dateline
1469
         * @return bool "true" on Success, "false" otherwise
1470
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
1471
         */
1472
        public function ProcessSLAOverdue($_processResolutionDue = false) {
1473
                $_SWIFT = SWIFT::GetInstance();
1474
                chdir(SWIFT_BASEPATH);
1475
                if (!$this->GetIsClassLoaded()) {
1476
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
1477
1478
                        return false;
1479
                }
1480
1481
                if ($this->_noSLACalculation == true) {
1482
                        return false;
1483
                }
1484
1485
                $this->Load->Library('SLA:SLAManager');
1486
1487
                $_slaManagerResult = $this->SLAManager->GetDueTime($this);
1488
                if (count($_slaManagerResult) != 2) {
1489
                        throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
1490
                }
1491
1492
                $_SWIFT_SLAPlanObject = $_slaManagerResult[0];
1493
                $_overDueSeconds = $_slaManagerResult[1];
1494
1495
                if ($_SWIFT_SLAPlanObject instanceof SWIFT_SLA && $_SWIFT_SLAPlanObject->GetIsClassLoaded()) {
1496
                        // Notification Rule
1497
                        $this->NotificationManager->Changed(SWIFT_NotificationRule::CRITERIA_SLAPLAN, $this->GetProperty('slaplanid'), $_SWIFT_SLAPlanObject->GetSLAPlanID());
1498
1499
                        /*
1500
                         * BUG FIX - Varun Shoor
1501
                         *
1502
                         * SWIFT-970 Resolution time is not updated according to SLA plan, while changing the ticket department using Mass Action
1503
                         *
1504
                         * Comments: We now force resolution due time recalculation if SLA plan changes
1505
                         */
1506
                        if ($this->GetProperty('slaplanid') != $_SWIFT_SLAPlanObject->GetSLAPlanID()) {
1507
                                $_processResolutionDue = true;
1508
                        }
1509
1510
                        $this->UpdatePool('slaplanid', $_SWIFT_SLAPlanObject->GetSLAPlanID());
1511
                        $this->UpdatePool('isescalatedvolatile', '0');
1512
1513
1514
                        /**
1515
                         * BUG FIX - Parminder Singh
1516
                         *
1517
                         * SWIFT-795: Issue with SLA plan retention
1518
                         *
1519
                         * Comments: If no SLA found then clear the exising one.
1520
                         */
1521
                } else {
1522
                        // $this->UpdatePool('slaplanid', '0');
1523
                }
1524
1525
                /**
1526
                 * BUG FIX - Parminder Singh
1527
                 *
1528
                 * SWIFT-1583: "Clear the Due Time" setting under Ticket Statuses settings, does not work properly
1529
                 *
1530
                 * Comments: If the setting 'Clear the Due Time' is disabled and overdue seconds ($_overDueSeconds) are coming blank then no need for SLA/ overdue hours.
1531
                 */
1532
                $_ticketStatusCache = $this->Cache->Get('statuscache');
1533
                if (isset($_ticketStatusCache[$this->GetProperty('ticketstatusid')])) {
1534
                        $_ticketStatusContainer = $_ticketStatusCache[$this->GetProperty('ticketstatusid')];
1535
                        if ($_ticketStatusContainer['resetduetime'] == '0' && empty($_overDueSeconds) && $this->GetProperty('duetime') != '0') {
1536
                                $this->_noSLACalculation = true;
1537
1538
                                return true;
1539
                        }
1540
                }
1541
1542
                // Create Audit Log
1543
                $_renderedDate = SWIFT_Date::Get(SWIFT_Date::TYPE_DATETIME, $_overDueSeconds);
1544
                if (empty($_overDueSeconds)) {
1545
                        $_renderedDate = $this->Language->Get('duetimecleared');
1546
                }
1547
1548
                SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATETICKET,
1549
                        sprintf($_SWIFT->Language->Get('al_due'), $_renderedDate),
1550
                        SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('duetime'), '', $_overDueSeconds, '');
1551
1552
                $this->UpdatePool('duetime', intval($_overDueSeconds));
1553
1554
                if ($_processResolutionDue == true) {
1555
                        if (!$_SWIFT_SLAPlanObject instanceof SWIFT_SLA || !$_SWIFT_SLAPlanObject->GetIsClassLoaded())
1556
                        {
1557
                                $_SWIFT_SLAPlanObject = null;
1558
                        }
1559
1560
                        $_slaManagerResult_ResolutionDue = $this->SLAManager->GetResolutionTime($this, $_SWIFT_SLAPlanObject);
1561
                        $_resolutionOverDueSeconds = $_slaManagerResult_ResolutionDue[1];
1562
1563
                        // Create Audit Log
1564
                        $_resolutionRenderedDate = SWIFT_Date::Get(SWIFT_Date::TYPE_DATETIME, $_resolutionOverDueSeconds);
1565
                        if (empty($_resolutionOverDueSeconds)) {
1566
                                $_resolutionRenderedDate = $this->Language->Get('duetimecleared');
1567
                        }
1568
                        SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATETICKET,
1569
                                sprintf($_SWIFT->Language->Get('al_resolutiondue'), $_resolutionRenderedDate),
1570
                                SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('resolutionduedateline'), '', $_resolutionOverDueSeconds, '');
1571
1572
                        $this->UpdatePool('resolutionduedateline', intval($_resolutionOverDueSeconds));
1573
                }
1574
1575
                $this->_noSLACalculation = true;
1576
1577
                return true;
1578
        }
1579
1580
        /**
1581
         * Queue the SLA Overdue calculation on shutdown
1582
         *
1583
         * @author Varun Shoor
1584
         * @param bool $_processResolutionDue (OPTIONAL) Whether to process the resolution due dateline
1585
         * @return bool "true" on Success, "false" otherwise
1586
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
1587
         */
1588
        public function QueueSLAOverdue($_processResolutionDue = false) {
1589
                if (!$this->GetIsClassLoaded()) {
1590
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
1591
1592
                        return false;
1593
                }
1594
1595
                if ($this->_slaOverdueQueued != -1) {
1596
                        return true;
1597
                }
1598
1599
                $this->_slaOverdueQueued = $_processResolutionDue;
1600
1601
                register_shutdown_function(array($this, 'ProcessSLAOverdue'), $this->_slaOverdueQueued);
1602
1603
                return true;
1604
        }
1605
1606
        /**
1607
         * Set a fixed SLA Plan for this Ticket
1608
         *
1609
         * @author Varun Shoor
1610
         * @param SWIFT_SLA $_SWIFT_SLAObject The SWIFT_SLA Object Pointer
1611
         * @return bool "true" on Success, "false" otherwise
1612
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded or If Invalid Data is Provided
1613
         */
1614
        public function SetSLA(SWIFT_SLA $_SWIFT_SLAObject) {
1615
                $_SWIFT = SWIFT::GetInstance();
1616
1617
                if (!$this->GetIsClassLoaded()) {
1618
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
1619
1620
                        return false;
1621
                } else if (!$_SWIFT_SLAObject instanceof SWIFT_SLA || !$_SWIFT_SLAObject->GetIsClassLoaded()) {
1622
                        throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
1623
                }
1624
1625
                // If the current sla plan and the one provided matches then bail out
1626
                if ($this->GetProperty('ticketslaplanid') == $_SWIFT_SLAObject->GetSLAPlanID()) {
1627
                        return true;
1628
                }
1629
1630
                $_slaPlanCache = $this->Cache->Get('slaplancache');
1631
1632
                // Create Audit Log
1633
                SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATESLA,
1634
                        sprintf($_SWIFT->Language->Get('al_sla'), $_SWIFT_SLAObject->GetProperty('title')),
1635
                        SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('ticketslaplanid'), '', $_SWIFT_SLAObject->GetSLAPlanID(), '');
1636
1637
                // Notification Rule
1638
                $this->NotificationManager->Changed(SWIFT_NotificationRule::CRITERIA_SLAPLAN, $this->GetProperty('ticketslaplanid'), $_SWIFT_SLAObject->GetSLAPlanID());
1639
1640
                // Notification Update
1641
                $_oldTicketSLAPlanID = $this->GetProperty('ticketslaplanid');
1642
                $_oldSLATitle = $_newSLATitle = '';
1643
                if ($_oldTicketSLAPlanID != '0') {
1644
                        if (isset($_slaPlanCache[$_oldTicketSLAPlanID])) {
1645
                                $_oldSLATitle = $_slaPlanCache[$_oldTicketSLAPlanID]['title'];
1646
                        } else {
1647
                                $_oldSLATitle = $this->Language->Get('na');
1648
                        }
1649
                }
1650
1651
                $_newSLATitle = $_SWIFT_SLAObject->GetProperty('title');
1652
1653
                $this->Notification->Update($this->Language->Get('notification_sla'), $_oldSLATitle, $_newSLATitle);
1654
1655
                $this->UpdatePool('ticketslaplanid', intval($_SWIFT_SLAObject->GetSLAPlanID()));
1656
                $this->UpdatePool('slaplanid', intval($_SWIFT_SLAObject->GetSLAPlanID()));
1657
                $this->UpdatePool('isescalatedvolatile', '0');
1658
1659
                // We set these to 0 and expect the sla processing engine to set the correct values
1660
//                $this->UpdatePool('duetime', '0');
1661
//                $this->UpdatePool('resolutionduedateline', '0');
1662
1663
                $this->_noSLACalculation = false;
1664
                $this->ProcessSLAOverdue(true);
1665
//                $this->QueueSLAOverdue(true);
1666
1667
                // Load and Process Workflow Rules
1668
                self::AddToWorkflowQueue($this);
1669
1670
                return true;
1671
        }
1672
1673
        /**
1674
         * Clear the fixed Ticket SLA Plan
1675
         *
1676
         * @author Varun Shoor
1677
         * @return bool "true" on Success, "false" otherwise
1678
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
1679
         */
1680
        public function ClearSLA() {
1681
                $_SWIFT = SWIFT::GetInstance();
1682
1683
                if (!$this->GetIsClassLoaded()) {
1684
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
1685
1686
                        return false;
1687
                }
1688
1689
                if ($this->GetProperty('ticketslaplanid') == '0') {
1690
                        return true;
1691
                }
1692
1693
                $_slaPlanCache = $this->Cache->Get('slaplancache');
1694
1695
                // Create Audit Log
1696
                SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATESLA,
1697
                        $_SWIFT->Language->Get('al_slaclear'),
1698
                        SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('ticketslaplanid'), '', 0, '');
1699
1700
                // Notification Update
1701
                $_oldTicketSLAPlanID = $this->GetProperty('ticketslaplanid');
1702
                $_oldSLATitle = $_newSLATitle = '';
1703
                if ($_oldTicketSLAPlanID != '0') {
1704
                        if (isset($_slaPlanCache[$_oldTicketSLAPlanID])) {
1705
                                $_oldSLATitle = $_slaPlanCache[$_oldTicketSLAPlanID]['title'];
1706
                        } else {
1707
                                $_oldSLATitle = $this->Language->Get('na');
1708
                        }
1709
                }
1710
1711
                $_newSLATitle = $this->Language->Get('notificationcleared');
1712
1713
                $this->Notification->Update($this->Language->Get('notification_sla'), $_oldSLATitle, $_newSLATitle);
1714
1715
                $this->UpdatePool('ticketslaplanid', 0);
1716
1717
                $this->QueueSLAOverdue();
1718
1719
                // Load and Process Workflow Rules
1720
                self::AddToWorkflowQueue($this);
1721
1722
                return true;
1723
        }
1724
1725
        /**
1726
         * Escalate this Ticket
1727
         *
1728
         * @author Varun Shoor
1729
         * @param SWIFT_EscalationRule $_SWIFT_EscalationRuleObject
1730
         * @return bool "true" on Success, "false" otherwise
1731
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded or If Invalid Data is Provided
1732
         */
1733
        public function Escalate(SWIFT_EscalationRule $_SWIFT_EscalationRuleObject) {
1734
                $_SWIFT = SWIFT::GetInstance();
1735
1736
                if (!$this->GetIsClassLoaded()) {
1737
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
1738
1739
                        return false;
1740
                } else if (!$_SWIFT_EscalationRuleObject instanceof SWIFT_EscalationRule || !$_SWIFT_EscalationRuleObject->GetIsClassLoaded()) {
1741
                        throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
1742
                }
1743
1744
                $_staffCache = $this->Cache->Get('staffcache');
1745
1746
                // We execute this before all arguments so that if a custom SLA plan is set, it can override this value.
1747
                $this->UpdatePool('isescalatedvolatile', '1');
1748
1749
                SWIFT_EscalationPath::Create($this, $this->GetProperty('slaplanid'), $_SWIFT_EscalationRuleObject->GetEscalationRuleID(),
1750
                                $this->GetProperty('ownerstaffid'), $this->GetProperty('departmentid'), $this->GetProperty('ticketstatusid'),
1751
                                $this->GetProperty('priorityid'), $this->GetProperty('tickettypeid'), $this->GetProperty('flagtype'));
1752
1753
                if ($_SWIFT_EscalationRuleObject->GetProperty('staffid') != '-1' && $_SWIFT_EscalationRuleObject->GetProperty('staffid') != '0' && isset($_staffCache[$_SWIFT_EscalationRuleObject->GetProperty('staffid')]))
1754
                {
1755
                        $this->SetOwner($_SWIFT_EscalationRuleObject->GetProperty('staffid'));
1756
                }
1757
1758
                if ($_SWIFT_EscalationRuleObject->GetProperty('departmentid') != '0' && $_SWIFT_EscalationRuleObject->GetProperty('departmentid') != '-1')
1759
                {
1760
                        $this->SetDepartment($_SWIFT_EscalationRuleObject->GetProperty('departmentid'));
1761
                }
1762
1763
                if ($_SWIFT_EscalationRuleObject->GetProperty('ticketstatusid') != '0' && $_SWIFT_EscalationRuleObject->GetProperty('ticketstatusid') != '-1')
1764
                {
1765
                        $this->SetStatus($_SWIFT_EscalationRuleObject->GetProperty('ticketstatusid'));
1766
                }
1767
1768
                if ($_SWIFT_EscalationRuleObject->GetProperty('priorityid') != '0' && $_SWIFT_EscalationRuleObject->GetProperty('priorityid') != '-1')
1769
                {
1770
                        $this->SetPriority($_SWIFT_EscalationRuleObject->GetProperty('priorityid'));
1771
                }
1772
1773
                if ($_SWIFT_EscalationRuleObject->GetProperty('tickettypeid') != '0' && $_SWIFT_EscalationRuleObject->GetProperty('tickettypeid') != '-1')
1774
                {
1775
                        $this->SetType($_SWIFT_EscalationRuleObject->GetProperty('tickettypeid'));
1776
                }
1777
1778
                if ($_SWIFT_EscalationRuleObject->GetProperty('flagtype') != '0' && $_SWIFT_EscalationRuleObject->GetProperty('flagtype') != '-1')
1779
                {
1780
                        $this->SetFlag($_SWIFT_EscalationRuleObject->GetProperty('flagtype'));
1781
                }
1782
1783
                if ($_SWIFT_EscalationRuleObject->GetProperty('newslaplanid') != '0' && $_SWIFT_EscalationRuleObject->GetProperty('newslaplanid') != '-1')
1784
                {
1785
                        $this->SetSLA(new SWIFT_SLA(new SWIFT_DataID($_SWIFT_EscalationRuleObject->GetProperty('newslaplanid'))));
1786
                }
1787
1788
                if ($_SWIFT_EscalationRuleObject->GetProperty('addtags') != '')
1789
                {
1790
                        $_tagContainer = json_decode($_SWIFT_EscalationRuleObject->GetProperty('addtags'));
1791
                        if (is_array($_tagContainer)) {
1792
                                SWIFT_Tag::AddTags(SWIFT_TagLink::TYPE_TICKET, $this->GetTicketID(),
1793
                                                $_tagContainer, false);
1794
                        }
1795
                }
1796
1797
                if ($_SWIFT_EscalationRuleObject->GetProperty('removetags') != '')
1798
                {
1799
                        $_tagContainer = json_decode($_SWIFT_EscalationRuleObject->GetProperty('removetags'));
1800
                        if (is_array($_tagContainer)) {
1801
                                SWIFT_Tag::RemoveTags(SWIFT_TagLink::TYPE_TICKET, array($this->GetTicketID()),
1802
                                        $_tagContainer, false);
1803
                        }
1804
1805
                }
1806
1807
                $this->UpdatePool('escalationruleid', $_SWIFT_EscalationRuleObject->GetEscalationRuleID());
1808
                $this->UpdatePool('isescalated', '1');
1809
                $this->UpdatePool('escalatedtime', DATENOW);
1810
                $this->UpdatePool('escalationlevelcount', ($this->GetProperty('escalationlevelcount')+1));
1811
1812
                // Load and Process Workflow Rules
1813
                self::AddToWorkflowQueue($this);
1814
1815
                return true;
1816
        }
1817
1818
        /**
1819
         * Mark the ticket as watched
1820
         *
1821
         * @author Varun Shoor
1822
         * @return bool "true" on Success, "false" otherwise
1823
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
1824
         */
1825
        public function MarkAsWatched() {
1826
                $_SWIFT = SWIFT::GetInstance();
1827
1828
                if (!$this->GetIsClassLoaded()) {
1829
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
1830
1831
                        return false;
1832
                }
1833
1834
                $this->UpdatePool('iswatched', '1');
1835
1836
                return true;
1837
        }
1838
1839
        /**
1840
         * Mark the ticket as overdue
1841
         *
1842
         * @author Varun Shoor
1843
         * @return bool "true" on Success, "false" otherwise
1844
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
1845
         */
1846
        public function MarkAsDue() {
1847
                $_SWIFT = SWIFT::GetInstance();
1848
1849
                if (!$this->GetIsClassLoaded()) {
1850
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
1851
1852
                        return false;
1853
                }
1854
1855
                // Create Audit Log
1856
                SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATETICKET,
1857
                        $_SWIFT->Language->Get('al_duestaffoverdue'),
1858
                        SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('duetime'), '', DATENOW, '');
1859
1860
                // Notification Update
1861
                $_newDueDate = SWIFT_Date::Get(SWIFT_Date::TYPE_DATETIME, DATENOW);
1862
                $this->Notification->Update($this->Language->Get('notification_due'), '', $_newDueDate);
1863
1864
1865
                $this->UpdatePool('duetime', DATENOW);
1866
1867
                // Prevent SLA Calculation
1868
                $this->_noSLACalculation = true;
1869
1870
                // Load and Process Workflow Rules
1871
                self::AddToWorkflowQueue($this);
1872
1873
                return true;
1874
        }
1875
1876
        /**
1877
         * Clear the overdue time
1878
         *
1879
         * @author Varun Shoor
1880
         * @return bool "true" on Success, "false" otherwise
1881
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
1882
         */
1883
        public function ClearOverdue() {
1884
                $_SWIFT = SWIFT::GetInstance();
1885
1886
                if (!$this->GetIsClassLoaded()) {
1887
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
1888
1889
                        return false;
1890
                }
1891
1892
                if ($this->GetProperty('duetime') == '0') {
1893
                        return true;
1894
                }
1895
                // Create Audit Log
1896
                SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATETICKET,
1897
                        $_SWIFT->Language->Get('al_duestaffclear'),
1898
                        SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('duetime'), '', 0, '');
1899
1900
                // Notification Update
1901
                $_oldDueDate = SWIFT_Date::Get(SWIFT_Date::TYPE_DATETIME, $this->GetProperty('duetime'));
1902
                $_newDueDate = $this->Language->Get('notificationcleared');
1903
1904
                $this->Notification->Update($this->Language->Get('notification_due'), $_oldDueDate, $_newDueDate);
1905
1906
                $this->UpdatePool('duetime', '0');
1907
1908
                // Prevent calculation of SLA due time on this ticket
1909
                $this->_noSLACalculation = true;
1910
1911
                // Load and Process Workflow Rules
1912
                self::AddToWorkflowQueue($this);
1913
1914
                return true;
1915
        }
1916
1917
        /**
1918
         * Set the Template Group
1919
         *
1920
         * @author Varun Shoor
1921
         * @param int $_templateGroupID The Template Group ID
1922
         * @return bool "true" on Success, "false" otherwise
1923
         * @throws SWIFT_Exception If the Class is not Loaded
1924
         */
1925
        public function SetTemplateGroup($_templateGroupID)
1926
        {
1927
                if (!$this->GetIsClassLoaded())
1928
                {
1929
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
1930
1931
                        return false;
1932
                }
1933
1934
                $this->UpdatePool('tgroupid', intval($_templateGroupID));
1935
1936
                return true;
1937
        }
1938
1939
        /**
1940
         * Clear the resolution time
1941
         *
1942
         * @author Varun Shoor
1943
         * @return bool "true" on Success, "false" otherwise
1944
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
1945
         */
1946
        public function ClearResolutionDue() {
1947
                $_SWIFT = SWIFT::GetInstance();
1948
1949
                if (!$this->GetIsClassLoaded()) {
1950
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
1951
1952
                        return false;
1953
                }
1954
1955
                if ($this->GetProperty('resolutionduedateline') == '0') {
1956
                        return true;
1957
                }
1958
1959
                // Create Audit Log
1960
                SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATETICKET,
1961
                        $_SWIFT->Language->Get('al_resduestaffclear'),
1962
                        SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('resolutionduedateline'), '', 0, '');
1963
1964
                // Notification Update
1965
                $_oldDueDate = SWIFT_Date::Get(SWIFT_Date::TYPE_DATETIME, $this->GetProperty('resolutionduedateline'));
1966
                $_newDueDate = $this->Language->Get('notificationcleared');
1967
1968
                $this->Notification->Update($this->Language->Get('notification_resolutiondue'), $_oldDueDate, $_newDueDate);
1969
1970
                $this->UpdatePool('resolutionduedateline', '0');
1971
1972
                // Prevent calculation of SLA due time on this ticket
1973
                $this->_noSLACalculation = true;
1974
1975
                // Load and Process Workflow Rules
1976
                self::AddToWorkflowQueue($this);
1977
1978
                return true;
1979
        }
1980
1981
        /**
1982
         * Set a flag on this ticket
1983
         *
1984
         * @author Varun Shoor
1985
         * @param constant $_flagType The Flag Type
1986
         * @return bool "true" on Success, "false" otherwise
1987
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded or If Invalid Data is Provided
1988
         */
1989
        public function SetFlag($_flagType) {
1990
                $_SWIFT = SWIFT::GetInstance();
1991
1992
                if (!$this->GetIsClassLoaded()) {
1993
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
1994
1995
                        return false;
1996
                }
1997
1998
                $this->Load->Library('Flag:TicketFlag');
1999
                $_flagContainer = $this->TicketFlag->GetFlagContainer();
2000
2001
                if ($_flagType == '0') {
2002
                        // Notification Update
2003
                        $_oldFlagTitle = '';
2004
                        if (isset($_flagContainer[$this->GetProperty('flagtype')])) {
2005
                                $_oldFlagTitle = $_flagContainer[$this->GetProperty('flagtype')][0];
2006
                        }
2007
                        $_newFlagTitle = $this->Language->Get('notificationcleared');
2008
2009
                        $this->Notification->Update($this->Language->Get('notification_flag'), $_oldFlagTitle, $_newFlagTitle);
2010
2011
                        $this->UpdatePool('flagtype', '0');
2012
2013
                        $this->QueueSLAOverdue();
2014
2015
                        return true;
2016
                }
2017
2018
                if (!SWIFT_TicketFlag::IsValidFlagType($_flagType)) {
2019
                        throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
2020
                }
2021
2022
                // If this ticket already has a flag set which matches the one specified.. then move on
2023
                if ($this->GetProperty('flagtype') == $_flagType) {
2024
                        return true;
2025
                }
2026
2027
                // Create Audit Log
2028
                $_flagTitle = $_flagContainer[$_flagType][0];
2029
2030
                SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATEFLAG,
2031
                        sprintf($_SWIFT->Language->Get('al_flag'), $_flagTitle),
2032
                        SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('flagtype'), '', $_flagType, '');
2033
2034
                // Notification Rule
2035
                $this->NotificationManager->Changed(SWIFT_NotificationRule::CRITERIA_FLAGTYPE, $this->GetProperty('flagtype'), $_flagType);
2036
2037
                // Notification Update
2038
                $_oldFlagTitle = '';
2039
                if (isset($_flagContainer[$this->GetProperty('flagtype')])) {
2040
                        $_oldFlagTitle = $_flagContainer[$this->GetProperty('flagtype')][0];
2041
                }
2042
                $_newFlagTitle = $_flagTitle;
2043
2044
                $this->Notification->Update($this->Language->Get('notification_flag'), $_oldFlagTitle, $_newFlagTitle);
2045
2046
                $this->UpdatePool('flagtype', intval($_flagType));
2047
2048
                $this->QueueSLAOverdue();
2049
2050
                // Load and Process Workflow Rules
2051
                self::AddToWorkflowQueue($this);
2052
2053
                return true;
2054
        }
2055
2056
        /**
2057
         * Clear a flag on a ticket
2058
         *
2059
         * @author Varun Shoor
2060
         * @return bool "true" on Success, "false" otherwise
2061
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
2062
         */
2063
        public function ClearFlag() {
2064
                $_SWIFT = SWIFT::GetInstance();
2065
2066
                if (!$this->GetIsClassLoaded()) {
2067
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
2068
2069
                        return false;
2070
                }
2071
2072
                // If there is no flag set, then ignore.
2073
                if ($this->GetProperty('flagtype') == '0') {
2074
                        return true;
2075
                }
2076
2077
                $_SWIFT_TicketFlagObject = new SWIFT_TicketFlag();
2078
                $_flagContainer = $_SWIFT_TicketFlagObject->GetFlagContainer();
2079
2080
                // Create Audit Log
2081
                SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATEFLAG,
2082
                        $_SWIFT->Language->Get('al_flagclear'),
2083
                        SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('flagtype'), '', 0, '');
2084
2085
                // Notification Update
2086
                $_oldFlagTitle = '';
2087
                if (isset($_flagContainer[$this->GetProperty('flagtype')])) {
2088
                        $_oldFlagTitle = $_flagContainer[$this->GetProperty('flagtype')][0];
2089
                }
2090
                $_newFlagTitle = $this->Language->Get('notificationcleared');
2091
2092
                $this->Notification->Update($this->Language->Get('notification_flag'), $_oldFlagTitle, $_newFlagTitle);
2093
2094
                $this->UpdatePool('flagtype', 0);
2095
2096
                $this->QueueSLAOverdue();
2097
2098
                // Load and Process Workflow Rules
2099
                self::AddToWorkflowQueue($this);
2100
2101
                return true;
2102
        }
2103
2104
        /**
2105
         * Change the department for the ticket
2106
         *
2107
         * @author Varun Shoor
2108
         * @param int $_departmentID The department id
2109
         * @return bool "true" on Success, "false" otherwise
2110
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded or if Invalid Data is Provided
2111
         */
2112
        public function SetDepartment($_departmentID) {
2113
                $_SWIFT = SWIFT::GetInstance();
2114
2115
                if (!$this->GetIsClassLoaded()) {
2116
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
2117
2118
                        return false;
2119
                } else if (empty($_departmentID)) {
2120
                        throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
2121
                }
2122
2123
                $_departmentCache = $this->Cache->Get('departmentcache');
2124
                if (!isset($_departmentCache[$_departmentID])) {
2125
                        throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
2126
                }
2127
2128
                // If the ticket is already in this department then bail out
2129
                if ($this->GetProperty('departmentid') == $_departmentID) {
2130
                        return true;
2131
                }
2132
2133
                // Add old and new department to recount queue
2134
//                SWIFT_TicketManager::Recount($this->GetProperty('departmentid'));
2135
//                SWIFT_TicketManager::Recount($_departmentID);
2136
                SWIFT_TicketManager::Recount(false);
2137
2138
                // Create Audit Log
2139
                $_oldDepartmentTitle = $_newDepartmentTitle = '';
2140
                if (isset($_departmentCache[$this->GetProperty('departmentid')])) {
2141
                        $_oldDepartmentTitle = $_departmentCache[$this->GetProperty('departmentid')]['title'];
2142
                }
2143
2144
                if ($this->GetProperty('departmentid') == '0') {
2145
                        $_oldDepartmentTitle = $this->Language->Get('trash');
2146
                }
2147
2148
                $_newDepartmentTitle = $_departmentCache[$_departmentID]['title'];
2149
2150
                SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATEDEPARTMENT,
2151
                        sprintf($_SWIFT->Language->Get('al_department'), $_oldDepartmentTitle, $_newDepartmentTitle),
2152
                        SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('departmentid'), '', $_departmentID, '');
2153
2154
                // Notification Rule
2155
                $this->NotificationManager->Changed(SWIFT_NotificationRule::CRITERIA_DEPARTMENT, $this->GetProperty('departmentid'), $_departmentID);
2156
2157
                // Notification Update
2158
                $_oldNotificationDepartmentTitle = $_newNotificationDepartmentTitle = '';
2159
                if ($_oldDepartmentTitle == '') {
2160
                        $_oldNotificationDepartmentTitle = $this->Language->Get('na');
2161
                } else {
2162
                        $_oldNotificationDepartmentTitle = $_oldDepartmentTitle;
2163
                }
2164
2165
                $_newNotificationDepartmentTitle = $_newDepartmentTitle;
2166
2167
                $_oldUserNotificationDepartmentTitle = $_oldNotificationDepartmentTitle;
2168
                $_newUserNotificationDepartmentTitle = $_newNotificationDepartmentTitle;
2169
2170
                if (isset($_departmentCache[$this->GetProperty('departmentid')]) && $_departmentCache[$this->GetProperty('departmentid')]['departmenttype'] == SWIFT_PRIVATE) {
2171
                        $_oldUserNotificationDepartmentTitle = $this->Language->Get('private');
2172
                }
2173
2174
                if (isset($_departmentCache[$_departmentID]) && $_departmentCache[$_departmentID]['departmenttype'] == SWIFT_PRIVATE) {
2175
                        $_newUserNotificationDepartmentTitle = $this->Language->Get('private');
2176
                }
2177
2178
                $this->Notification->Update($this->Language->Get('notification_department'), $_oldNotificationDepartmentTitle, $_newNotificationDepartmentTitle, $_oldUserNotificationDepartmentTitle, $_newUserNotificationDepartmentTitle);
2179
2180
                $this->UpdatePool('departmentid', intval($_departmentID));
2181
                $this->UpdatePool('departmenttitle', $_newDepartmentTitle);
2182
2183
                $this->QueueSLAOverdue();
2184
2185
                // Load and Process Workflow Rules
2186
                self::AddToWorkflowQueue($this);
2187
2188
                return true;
2189
        }
2190
2191
        /**
2192
         * Set the Ticket Type
2193
         *
2194
         * @author Varun Shoor
2195
         * @param int $_ticketTypeID The Ticket Type ID
2196
         * @return bool "true" on Success, "false" otherwise
2197
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded or If Invalid Data is Provided
2198
         */
2199
        public function SetType($_ticketTypeID) {
2200
                $_SWIFT = SWIFT::GetInstance();
2201
2202
                if (!$this->GetIsClassLoaded()) {
2203
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
2204
2205
                        return false;
2206
                } else if (empty($_ticketTypeID)) {
2207
                        throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
2208
                }
2209
2210
                // Verify value of ticket type
2211
                $_ticketTypeCache = $this->Cache->Get('tickettypecache');
2212
                if (!isset($_ticketTypeCache[$_ticketTypeID])) {
2213
                        throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
2214
                }
2215
2216
                $_ticketTypeContainer = $_ticketTypeCache[$_ticketTypeID];
2217
2218
                // If current ticket type is same as the new type then bail out
2219
                if ($this->GetProperty('tickettypeid') == $_ticketTypeID) {
2220
                        return true;
2221
                }
2222
2223
                // Verify the department id link of ticket type
2224
2225
                /*
2226
                 * BUG FIX - Varun Shoor
2227
                 *
2228
                 * SWIFT-1298 Issue with ticket types and ticket statuses, if they are linked with Parent department
2229
                 *
2230
                 * Comments: None
2231
                 */
2232
                $_departmentCache = $this->Cache->Get('departmentcache');
2233
                $_parentDepartmentID = false;
2234
                if (isset($_departmentCache[$this->GetProperty('departmentid')])) {
2235
                        $_parentDepartmentID = $_departmentCache[$this->GetProperty('departmentid')]['parentdepartmentid'];
2236
                }
2237
2238
                if ($_ticketTypeContainer['departmentid'] != '0' && $_ticketTypeContainer['departmentid'] != $this->GetProperty('departmentid') && $_ticketTypeContainer['departmentid'] != $_parentDepartmentID) {
2239
                        throw new SWIFT_Ticket_Exception('Ticket Type (' . intval($_ticketTypeID) . ') & Department ID (' . intval($this->GetProperty('departmentid')) . ') Mismatch');
2240
                }
2241
2242
                // Create Audit Log
2243
                $_oldTypeTitle = $_newTypeTitle = '';
2244
                if (isset($_ticketTypeCache[$this->GetProperty('tickettypeid')])) {
2245
                        $_oldTypeTitle = $_ticketTypeCache[$this->GetProperty('tickettypeid')]['title'];
2246
                }
2247
2248
                $_newTypeTitle = $_ticketTypeCache[$_ticketTypeID]['title'];
2249
2250
                SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATETYPE,
2251
                        sprintf($_SWIFT->Language->Get('al_type'), $_oldTypeTitle, $_newTypeTitle),
2252
                        SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('tickettypeid'), '', $_ticketTypeID, '');
2253
2254
                // Notification Rule
2255
                $this->NotificationManager->Changed(SWIFT_NotificationRule::CRITERIA_TICKETTYPE, $this->GetProperty('tickettypeid'), $_ticketTypeID);
2256
2257
                // Notification Update
2258
                $_oldNotificationTypeTitle = $_newNotificationTypeTitle = '';
2259
                if ($_oldTypeTitle == '') {
2260
                        $_oldNotificationTypeTitle = $this->Language->Get('na');
2261
                } else {
2262
                        $_oldNotificationTypeTitle = $_oldTypeTitle;
2263
                }
2264
2265
                $_newNotificationTypeTitle = $_newTypeTitle;
2266
2267
                $_oldUserNotificationTypeTitle = $_oldNotificationTypeTitle;
2268
                $_newUserNotificationTypeTitle = $_newNotificationTypeTitle;
2269
2270
                if ($_ticketTypeCache[$this->GetProperty('tickettypeid')]['type'] == SWIFT_PRIVATE) {
2271
                        $_oldUserNotificationTypeTitle = $this->Language->Get('private');
2272
                }
2273
2274
                if ($_ticketTypeCache[$_ticketTypeID]['type'] == SWIFT_PRIVATE) {
2275
                        $_newUserNotificationTypeTitle = $this->Language->Get('private');
2276
                }
2277
2278
                $this->Notification->Update($this->Language->Get('notification_type'), $_oldNotificationTypeTitle, $_newNotificationTypeTitle, $_oldUserNotificationTypeTitle, $_newUserNotificationTypeTitle);
2279
2280
2281
                $this->UpdatePool('tickettypeid', intval($_ticketTypeID));
2282
                $this->UpdatePool('tickettypetitle', $_newTypeTitle);
2283
2284
//                SWIFT_TicketManager::Recount($this->GetProperty('departmentid'));
2285
                SWIFT_TicketManager::Recount(false);
2286
2287
                $this->QueueSLAOverdue();
2288
2289
                // Load and Process Workflow Rules
2290
                self::AddToWorkflowQueue($this);
2291
2292
                return true;
2293
        }
2294
2295
        /**
2296
         * Set the Has Status Changed Property
2297
         *
2298
         * @author Varun Shoor
2299
         * @param bool $_hasStatusChanged
2300
         * @return bool "true" on Success, "false" otherwise
2301
         * @throws SWIFT_Exception If the Class is not Loaded
2302
         */
2303
        protected function SetHasStatusChanged($_hasStatusChanged)
2304
        {
2305
                if (!$this->GetIsClassLoaded()) {
2306
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
2307
2308
                        return false;
2309
                }
2310
2311
                $this->_hasStatusChanged = $_hasStatusChanged;
2312
2313
                return true;
2314
        }
2315
2316
        /**
2317
         * Retrieve the Has Status Changed Property
2318
         *
2319
         * @author Varun Shoor
2320
         * @return bool "true" on Success, "false" otherwise
2321
         * @throws SWIFT_Exception If the Class is not Loaded
2322
         */
2323
        public function GetHasStatusChanged()
2324
        {
2325
                if (!$this->GetIsClassLoaded()) {
2326
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
2327
2328
                        return false;
2329
                }
2330
2331
                return $this->_hasStatusChanged;
2332
        }
2333
2334
        /**
2335
         * Set the Ticket Status
2336
         *
2337
         * @author Varun Shoor
2338
         * @param int $_ticketStatusID The Ticket Status ID
2339
         * @param bool $_isViaAutoClose (OPTIONAL) If the status change is via auto close
2340
         * @param bool $_suppressSurveyEmail (OPTIONAL) Whether to suppress survey email
2341
         * @return bool "true" on Success, "false" otherwise
2342
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded or If Invalid Data is Provided
2343
         */
2344
        public function SetStatus($_ticketStatusID, $_isViaAutoClose = false, $_suppressSurveyEmail = false) {
2345
                $_SWIFT = SWIFT::GetInstance();
2346
2347
                if (!$this->GetIsClassLoaded()) {
2348
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
2349
2350
                } else if (empty($_ticketStatusID)) {
2351
                        throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
2352
                }
2353
2354
                $_ticketStatusCache = $this->Cache->Get('statuscache');
2355
                if (!isset($_ticketStatusCache[$_ticketStatusID])) {
2356
                        throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
2357
                }
2358
2359
                $_ticketStatusContainer = $_ticketStatusCache[$_ticketStatusID];
2360
2361
                $this->SetHasStatusChanged(true);
2362
2363
                // If the current ticket status id matches then bail out
2364
                if ($this->GetProperty('ticketstatusid') == $_ticketStatusID) {
2365
                        return true;
2366
                }
2367
2368
                // Verify the department id link of ticket status
2369
2370
                /*
2371
                 * BUG FIX - Varun Shoor
2372
                 *
2373
                 * SWIFT-1298 Issue with ticket types and ticket statuses, if they are linked with Parent department
2374
                 *
2375
                 * Comments: None
2376
                 */
2377
                $_departmentCache = $this->Cache->Get('departmentcache');
2378
                $_parentDepartmentID = false;
2379
                if (isset($_departmentCache[$this->GetProperty('departmentid')])) {
2380
                        $_parentDepartmentID = $_departmentCache[$this->GetProperty('departmentid')]['parentdepartmentid'];
2381
                }
2382
2383
                if ($_ticketStatusContainer['departmentid'] != '0' && $_ticketStatusContainer['departmentid'] != $this->GetProperty('departmentid') && $_ticketStatusContainer['departmentid'] != $_parentDepartmentID) {
2384
                        throw new SWIFT_Ticket_Exception('Ticket Status (' . intval($_ticketStatusID) . ') & Department ID (' . intval($this->GetProperty('departmentid')) . ') Mismatch');
2385
                }
2386
2387
                // Create Audit Log
2388
                $_oldStatusTitle = $_newStatusTitle = '';
2389
                if (isset($_ticketStatusCache[$this->GetProperty('ticketstatusid')])) {
2390
                        $_oldStatusTitle = $_ticketStatusCache[$this->GetProperty('ticketstatusid')]['title'];
2391
                }
2392
2393
                $_newStatusTitle = $_ticketStatusCache[$_ticketStatusID]['title'];
2394
2395
                $_statusLanguageKey = 'al_status';
2396
                if ($_isViaAutoClose) {
2397
                        $_statusLanguageKey = 'al_statusautoclose';
2398
                }
2399
2400
                SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATESTATUS,
2401
                        sprintf($_SWIFT->Language->Get($_statusLanguageKey), $_oldStatusTitle, $_newStatusTitle),
2402
                        SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('ticketstatusid'), '', $_ticketStatusID, '');
2403
2404
                // Notification Rule
2405
                $this->NotificationManager->Changed(SWIFT_NotificationRule::CRITERIA_TICKETSTATUS, $this->GetProperty('ticketstatusid'), $_ticketStatusID);
2406
2407
                // Notification Update
2408
                $_oldNotificationStatusTitle = $_newNotificationStatusTitle = '';
2409
                if ($_oldStatusTitle == '') {
2410
                        $_oldNotificationStatusTitle = $this->Language->Get('na');
2411
                } else {
2412
                        $_oldNotificationStatusTitle = $_oldStatusTitle;
2413
                }
2414
2415
                $_newNotificationStatusTitle = $_newStatusTitle;
2416
2417
                $_oldUserNotificationStatusTitle = $_oldNotificationStatusTitle;
2418
                $_newUserNotificationStatusTitle = $_newNotificationStatusTitle;
2419
2420
                if ($_ticketStatusCache[$this->GetProperty('ticketstatusid')]['statustype'] == SWIFT_PRIVATE) {
2421
                        $_oldUserNotificationStatusTitle = $this->Language->Get('private');
2422
                }
2423
2424
                if ($_ticketStatusCache[$_ticketStatusID]['statustype'] == SWIFT_PRIVATE) {
2425
                        $_newUserNotificationStatusTitle = $this->Language->Get('private');
2426
                }
2427
2428
                $this->Notification->Update($this->Language->Get('notification_status'), $_oldNotificationStatusTitle, $_newNotificationStatusTitle, $_oldUserNotificationStatusTitle, $_newUserNotificationStatusTitle);
2429
2430
                $this->UpdatePool('ticketstatusid', intval($_ticketStatusID));
2431
                $this->UpdatePool('ticketstatustitle', $_newStatusTitle);
2432
2433
//                SWIFT_TicketManager::Recount($this->GetProperty('departmentid'));
2434
                SWIFT_TicketManager::Recount(false);
2435
2436
                // Was reopened?
2437
                if ($_ticketStatusContainer['markasresolved'] == '0' && $this->GetProperty('isresolved') == '1') {
2438
                        $this->UpdatePool('wasreopened', '1');
2439
                        $this->UpdatePool('reopendateline', DATENOW);
2440
                }
2441
2442
                if ($_ticketStatusContainer['resetduetime'] == '1') {
2443
                        $this->ClearOverdue();
2444
                }
2445
2446
                if ($_ticketStatusContainer['markasresolved'] == '1')
2447
                {
2448
                        $this->UpdatePool('isresolved', '1');
2449
                        $this->UpdatePool('resolutiondateline', DATENOW);
2450
                        $this->UpdatePool('repliestoresolution', $this->GetProperty('totalreplies'));
2451
2452
                        // How much time did it take to resolve this ticket?
2453
                        $this->UpdatePool('resolutionseconds', DATENOW-$this->GetProperty('dateline'));
2454
                } else {
2455
                        $this->UpdatePool('isresolved', '0');
2456
2457
                        // Are we changing to an unresolved status and ticket is marked as auto closed or pending closure?
2458
                        if ($this->GetProperty('autoclosestatus') != self::AUTOCLOSESTATUS_NONE) {
2459
                                $this->UpdatePool('autoclosestatus', self::AUTOCLOSESTATUS_NONE);
2460
                                $this->UpdatePool('isautoclosed', '0');
2461
                                $this->UpdatePool('autoclosetimeline', '0');
2462
                        }
2463
                }
2464
2465
                // If the status is set to resolved then we reset the resolution due time
2466
                $_processResolutionDue = false;
2467
                if ($_ticketStatusContainer['markasresolved'] == '1') {
2468
                        $this->UpdatePool('resolutionduedateline', '0');
2469
                        $this->UpdatePool('duetime', '0');
2470
                        $this->UpdatePool('slaplanid', '0');
2471
2472
                        $this->_noSLACalculation = true;
2473
2474
                // Otherwise if its not, and resolutionduedateline is 0 then we force it to recalculate the resolution due time
2475
                } else if ($_ticketStatusContainer['markasresolved'] == '0' && $this->GetProperty('resolutionduedateline') == '0') {
2476
                        $_processResolutionDue = true;
2477
                }
2478
2479
                // Do we have to trigger a survey?
2480
                if ($_ticketStatusContainer['triggersurvey'] == '1' && !$_suppressSurveyEmail)
2481
                {
2482
                        $this->Load->Library('Ticket:TicketEmailDispatch', array($this));
2483
                        $this->TicketEmailDispatch->DispatchSurvey();
2484
                }
2485
2486
                $this->QueueSLAOverdue($_processResolutionDue);
2487
2488
                // Is First Contact Resolved?
2489
                if ($this->GetProperty('totalreplies') == '0' && $_ticketStatusContainer['markasresolved'] == '1' && $this->GetProperty('isfirstcontactresolved') == '0') {
2490
                        $this->UpdatePool('isfirstcontactresolved', '1');
2491
                }
2492
2493
                // Load and Process Workflow Rules
2494
                self::AddToWorkflowQueue($this);
2495
2496
                return true;
2497
        }
2498
2499
        /**
2500
         * Set the Ticket Priority
2501
         *
2502
         * @author Varun Shoor
2503
         * @param int $_ticketPriorityID The Ticket Priority ID
2504
         * @return bool "true" on Success, "false" otherwise
2505
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded or If Invalid Data is Provided
2506
         */
2507
        public function SetPriority($_ticketPriorityID) {
2508
                $_SWIFT = SWIFT::GetInstance();
2509
2510
                if (!$this->GetIsClassLoaded()) {
2511
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
2512
2513
                        return false;
2514
                } else if (empty($_ticketPriorityID)) {
2515
                        throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
2516
                }
2517
2518
                $_ticketPriorityCache = $this->Cache->Get('prioritycache');
2519
                if (!isset($_ticketPriorityCache[$_ticketPriorityID])) {
2520
                        throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
2521
                }
2522
2523
                $_ticketPriorityContainer = $_ticketPriorityCache[$_ticketPriorityID];
2524
2525
                // If the current ticket priority id matches then bail out
2526
                if ($this->GetProperty('priorityid') == $_ticketPriorityID) {
2527
                        return true;
2528
                }
2529
2530
                // Create Audit Log
2531
                $_oldPriorityTitle = $_newPriorityTitle = '';
2532
                if (isset($_ticketPriorityCache[$this->GetProperty('priorityid')])) {
2533
                        $_oldPriorityTitle = $_ticketPriorityCache[$this->GetProperty('priorityid')]['title'];
2534
                }
2535
2536
                $_newPriorityTitle = $_ticketPriorityCache[$_ticketPriorityID]['title'];
2537
2538
                SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATEPRIORITY,
2539
                        sprintf($_SWIFT->Language->Get('al_priority'), $_oldPriorityTitle, $_newPriorityTitle),
2540
                        SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('priorityid'), '', $_ticketPriorityID, '');
2541
2542
                // Notification Rule
2543
                $this->NotificationManager->Changed(SWIFT_NotificationRule::CRITERIA_TICKETPRIORITY, $this->GetProperty('priorityid'), $_ticketPriorityID);
2544
2545
                // Notification Update
2546
                $_oldNotificationPriorityTitle = $_newNotificationPriorityTitle = '';
2547
                if ($_oldPriorityTitle == '') {
2548
                        $_oldNotificationPriorityTitle = $this->Language->Get('na');
2549
                } else {
2550
                        $_oldNotificationPriorityTitle = $_oldPriorityTitle;
2551
                }
2552
2553
                $_newNotificationPriorityTitle = $_newPriorityTitle;
2554
2555
                $_oldUserNotificationPriorityTitle = $_oldNotificationPriorityTitle;
2556
                $_newUserNotificationPriorityTitle = $_newNotificationPriorityTitle;
2557
2558
                if ($_ticketPriorityCache[$this->GetProperty('priorityid')]['type'] == SWIFT_PRIVATE) {
2559
                        $_oldUserNotificationPriorityTitle = $this->Language->Get('private');
2560
                }
2561
2562
                if ($_ticketPriorityCache[$_ticketPriorityID]['type'] == SWIFT_PRIVATE) {
2563
                        $_newUserNotificationPriorityTitle = $this->Language->Get('private');
2564
                }
2565
2566
                $this->Notification->Update($this->Language->Get('notification_priority'), $_oldNotificationPriorityTitle, $_newNotificationPriorityTitle, $_oldUserNotificationPriorityTitle, $_newUserNotificationPriorityTitle);
2567
2568
                $this->UpdatePool('priorityid', intval($_ticketPriorityID));
2569
                $this->UpdatePool('prioritytitle', $_newPriorityTitle);
2570
2571
//                SWIFT_TicketManager::Recount($this->GetProperty('departmentid'));
2572
                SWIFT_TicketManager::Recount(false);
2573
2574
                $this->QueueSLAOverdue();
2575
2576
                // Load and Process Workflow Rules
2577
                self::AddToWorkflowQueue($this);
2578
2579
                return true;
2580
        }
2581
2582
        /**
2583
         * Set the Ticket Owner
2584
         *
2585
         * @author Varun Shoor
2586
         * @param int $_staffID The Owner Staff ID
2587
         * @return bool "true" on Success, "false" otherwise
2588
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded or If Invalid Data is Provided
2589
         */
2590
        public function SetOwner($_staffID) {
2591
                $_SWIFT = SWIFT::GetInstance();
2592
2593
                if (!$this->GetIsClassLoaded()) {
2594
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
2595
2596
                        return false;
2597
                }
2598
2599
                $_staffCache = $this->Cache->Get('staffcache');
2600
                if ($_staffID != 0 && !isset($_staffCache[$_staffID])) {
2601
                        throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
2602
                }
2603
2604
                // If the current owner matches the one provided then bail out
2605
                if ($this->GetProperty('ownerstaffid') == $_staffID) {
2606
                        return true;
2607
                }
2608
2609
                // Create Audit Log
2610
                $_oldOwnerTitle = $_newOwnerTitle = '';
2611
                if (isset($_staffCache[$this->GetProperty('ownerstaffid')])) {
2612
                        $_oldOwnerTitle = $_staffCache[$this->GetProperty('ownerstaffid')]['fullname'];
2613
                }
2614
2615
                if ($this->GetProperty('ownerstaffid') == '0') {
2616
                        $_oldOwnerTitle = $this->Language->Get('unassigned');
2617
                }
2618
2619
                if ($_staffID == '0') {
2620
                        $_newOwnerTitle = $this->Language->Get('unassigned');
2621
                } else {
2622
                        $_newOwnerTitle = $_staffCache[$_staffID]['fullname'];
2623
                }
2624
2625
                SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATEOWNER,
2626
                        sprintf($_SWIFT->Language->Get('al_owner'), $_oldOwnerTitle, $_newOwnerTitle),
2627
                        SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('ownerstaffid'), '', $_staffID, '');
2628
2629
                // Notification Event
2630
                $this->NotificationManager->SetEvent('ticketassigned');
2631
2632
                // Notification Rule
2633
                $this->NotificationManager->Changed(SWIFT_NotificationRule::CRITERIA_OWNER, $this->GetProperty('ownerstaffid'), $_staffID);
2634
2635
                // Notification Update
2636
                $_oldNotificationOwnerTitle = $_newNotificationOwnerTitle = '';
2637
                if ($_oldOwnerTitle == '') {
2638
                        $_oldNotificationOwnerTitle = $this->Language->Get('na');
2639
                } else {
2640
                        $_oldNotificationOwnerTitle = $_oldOwnerTitle;
2641
                }
2642
2643
                $_newNotificationOwnerTitle = $_newOwnerTitle;
2644
2645
                $this->Notification->Update($this->Language->Get('notification_staff'), $_oldNotificationOwnerTitle, $_newNotificationOwnerTitle);
2646
2647
2648
                $this->UpdatePool('ownerstaffid', intval($_staffID));
2649
2650
                $_staffName = '';
2651
                if (isset($_staffCache[$_staffID])) {
2652
                        $_staffName = $_staffCache[$_staffID]['fullname'];
2653
                }
2654
2655
                $this->UpdatePool('ownerstaffname', $_staffName);
2656
2657
                // How many owners did it take to resolve this ticket?
2658
                $this->UpdatePool('resolutionlevel', intval($this->GetProperty('resolutionlevel'))+1);
2659
2660
//                SWIFT_TicketManager::Recount($this->GetProperty('departmentid'));
2661
                SWIFT_TicketManager::Recount(false);
2662
2663
                $this->QueueSLAOverdue();
2664
2665
                // Load the last notification message for ticket assigned alert
2666
                $this->LoadLastPostNotificationMessage();
2667
2668
                // Load and Process Workflow Rules
2669
                self::AddToWorkflowQueue($this);
2670
2671
                return true;
2672
        }
2673
2674
        /**
2675
         * Set the Due Time
2676
         *
2677
         * @author Varun Shoor
2678
         * @param string $_dueDateline The Due Dateline
2679
         * @return bool "true" on Success, "false" otherwise
2680
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
2681
         */
2682
        public function SetDue($_dueDateline) {
2683
                $_SWIFT = SWIFT::GetInstance();
2684
2685
                if (!$this->GetIsClassLoaded()) {
2686
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
2687
2688
                        return false;
2689
                } else if (empty($_dueDateline)) {
2690
                        return false;
2691
                }
2692
2693
                SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATETICKET,
2694
                        sprintf($_SWIFT->Language->Get('al_due'), SWIFT_Date::Get(SWIFT_Date::TYPE_DATETIME, $_dueDateline)),
2695
                        SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('duetime'), '', $_dueDateline, '');
2696
2697
                // Notification Update
2698
                $_oldNotificationDueTitle = $_newNotificationDueTitle = '';
2699
                if ($this->GetProperty('duetime') == '0') {
2700
                        $_oldNotificationDueTitle = $this->Language->Get('na');
2701
                } else {
2702
                        $_oldNotificationDueTitle = SWIFT_Date::Get(SWIFT_Date::TYPE_DATETIME, $this->GetProperty('duetime'));
2703
                }
2704
2705
                $_newNotificationDueTitle = SWIFT_Date::Get(SWIFT_Date::TYPE_DATETIME, $_dueDateline);
2706
2707
                $this->Notification->Update($this->Language->Get('notification_due'), $_oldNotificationDueTitle, $_newNotificationDueTitle);
2708
2709
                // Prevent calculation of SLA due time on this ticket
2710
                $this->_noSLACalculation = true;
2711
2712
                $this->UpdatePool('duetime', intval($_dueDateline));
2713
2714
                return true;
2715
        }
2716
2717
        /**
2718
         * Set the Resolution Due Time
2719
         *
2720
         * @author Varun Shoor
2721
         * @param string $_dueDateline The Due Dateline
2722
         * @return bool "true" on Success, "false" otherwise
2723
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
2724
         */
2725
        public function SetResolutionDue($_dueDateline) {
2726
                $_SWIFT = SWIFT::GetInstance();
2727
2728
                if (!$this->GetIsClassLoaded()) {
2729
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
2730
2731
                        return false;
2732
                } else if (empty($_dueDateline)) {
2733
                        return false;
2734
                }
2735
2736
                SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATETICKET,
2737
                        sprintf($_SWIFT->Language->Get('al_resolutiondue'), SWIFT_Date::Get(SWIFT_Date::TYPE_DATETIME, $_dueDateline)),
2738
                        SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('duetime'), '', $_dueDateline, '');
2739
2740
                // Notification Update
2741
                $_oldNotificationDueTitle = $_newNotificationDueTitle = '';
2742
                if ($this->GetProperty('resolutionduedateline') == '0') {
2743
                        $_oldNotificationDueTitle = $this->Language->Get('na');
2744
                } else {
2745
                        $_oldNotificationDueTitle = SWIFT_Date::Get(SWIFT_Date::TYPE_DATETIME, $this->GetProperty('resolutionduedateline'));
2746
                }
2747
2748
                $_newNotificationDueTitle = SWIFT_Date::Get(SWIFT_Date::TYPE_DATETIME, $_dueDateline);
2749
2750
                $this->Notification->Update($this->Language->Get('notification_resolutiondue'), $_oldNotificationDueTitle, $_newNotificationDueTitle);
2751
2752
                // Prevent calculation of SLA due time on this ticket
2753
                $this->_noSLACalculation = true;
2754
2755
                $this->UpdatePool('resolutionduedateline', intval($_dueDateline));
2756
2757
                return true;
2758
        }
2759
2760
        /**
2761
         * Retrieve the linked tickets in the active chain
2762
         *
2763
         * @author Varun Shoor
2764
         * @return array The Linked Ticket Container
2765
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
2766
         */
2767
        public function GetLinks() {
2768
                if (!$this->GetIsClassLoaded()) {
2769
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
2770
2771
                        return false;
2772
                }
2773
2774
                if ($this->GetProperty('islinked') == '0') {
2775
                        return array();
2776
                }
2777
2778
                // First get all the chain hashes where this ticket is part of
2779
                $_chainHashList = array();
2780
                $this->Database->Query("SELECT chainhash FROM " . TABLE_PREFIX . "ticketlinkchains WHERE ticketid = '" . intval($this->GetTicketID()) .
2781
                                "'");
2782
                while ($this->Database->NextRecord()) {
2783
                        $_chainHashList[] = $this->Database->Record['chainhash'];
2784
                }
2785
2786
                if (!count($_chainHashList)) {
2787
                        return array();
2788
                }
2789
2790
                // Now get all the tickets that are part of the chain hashes
2791
                $_ticketLinkContainer = array();
2792
                $this->Database->Query("SELECT tickets.*, ticketlinkchains.ticketlinktypeid FROM " . TABLE_PREFIX . "ticketlinkchains AS ticketlinkchains
2793
                        LEFT JOIN " . TABLE_PREFIX . "tickets AS tickets ON (ticketlinkchains.ticketid = tickets.ticketid) WHERE
2794
                        chainhash IN (" . BuildIN($_chainHashList) . ")");
2795
                while ($this->Database->NextRecord()) {
2796
                        if ($this->Database->Record['ticketid'] == $this->GetTicketID()) {
2797
                                continue;
2798
                        }
2799
2800
                        $_ticketLinkContainer[$this->Database->Record['ticketlinktypeid']][$this->Database->Record['ticketid']] =
2801
                                        new SWIFT_Ticket(new SWIFT_DataStore($this->Database->Record));
2802
                }
2803
2804
                return $_ticketLinkContainer;
2805
        }
2806
2807
        /**
2808
         * Mark ticket as linked
2809
         *
2810
         * @author Varun Shoor
2811
         * @return bool "true" on Success, "false" otherwise
2812
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
2813
         */
2814
        public function MarkAsLinked() {
2815
                if (!$this->GetIsClassLoaded()) {
2816
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
2817
2818
                        return false;
2819
                }
2820
2821
                $this->UpdatePool('islinked', '1');
2822
2823
                return true;
2824
        }
2825
2826
        /**
2827
         * Mark ticket as unlinked
2828
         *
2829
         * @author Varun Shoor
2830
         * @return bool "true" on Success, "false" otherwise
2831
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
2832
         */
2833
        public function MarkAsUnlinked() {
2834
                if (!$this->GetIsClassLoaded()) {
2835
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
2836
2837
                        return false;
2838
                }
2839
2840
                $this->UpdatePool('islinked', '0');
2841
2842
                return true;
2843
        }
2844
2845
        /**
2846
         * Lock a Ticket
2847
         *
2848
         * @author Varun Shoor
2849
         * @param SWIFT_Staff $_SWIFT_StaffObject The SWIFT_Staff Object Pointer
2850
         * @return bool "true" on Success, "false" otherwise
2851
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded or If Invalid Data is Provided
2852
         */
2853
        public function Lock(SWIFT_Staff $_SWIFT_StaffObject) {
2854
                if (!$this->GetIsClassLoaded()) {
2855
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
2856
2857
                        return false;
2858
                } else if (!$_SWIFT_StaffObject instanceof SWIFT_Staff || !$_SWIFT_StaffObject->GetIsClassLoaded()) {
2859
                        throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
2860
                }
2861
2862
                SWIFT_TicketLock::Create($this, $_SWIFT_StaffObject);
2863
2864
                return true;
2865
        }
2866
2867
        /**
2868
         * Unlock the ticket completely
2869
         *
2870
         * @author Varun Shoor
2871
         * @return bool "true" on Success, "false" otherwise
2872
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
2873
         */
2874
        public function Unlock() {
2875
                if (!$this->GetIsClassLoaded()) {
2876
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
2877
2878
                        return false;
2879
                }
2880
2881
                SWIFT_TicketLock::DeleteOnTicket(array($this->GetTicketID()));
2882
2883
                return true;
2884
        }
2885
2886
        /**
2887
         * Rebuild the Ticket Properties (hasnotes, hasattachments etc.)
2888
         *
2889
         * @author Varun Shoor
2890
         * @return bool "true" on Success, "false" otherwise
2891
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
2892
         */
2893
        public function RebuildProperties() {
2894
                if (!$this->GetIsClassLoaded()) {
2895
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
2896
2897
                        return false;
2898
                }
2899
2900
                $_ticketStatusCache = $this->Cache->Get('statuscache');
2901
2902
                /**
2903
                 * BUG FIX - Parminder Singh
2904
                 *
2905
                 * SWIFT-1894: 'Trash' count does not clear the ticket count in case a department is deleted
2906
                 *
2907
                 */
2908
2909
                $_departmentCache = $this->Cache->Get('departmentcache');
2910
2911
                if ($this->GetProperty('trasholddepartmentid') != '0' && !isset($_departmentCache[$this->GetProperty('trasholddepartmentid')])) {
2912
                        $this->UpdatePool('trasholddepartmentid', '0');
2913
                }
2914
2915
                // First Post, Last Post & Total Replies
2916
                $_ticketPostIDContainer = $this->Database->QueryFetch("SELECT MIN(ticketpostid) AS firstpostid, MAX(ticketpostid) AS lastpostid,
2917
                        COUNT(*) AS totalreplies FROM " . TABLE_PREFIX . "ticketposts WHERE ticketid = '" . intval($this->GetTicketID()) . "'");
2918
                if (isset($_ticketPostIDContainer['firstpostid']) && !empty($_ticketPostIDContainer['firstpostid']))
2919
                {
2920
                        $this->UpdatePool('firstpostid', intval($_ticketPostIDContainer['firstpostid']));
2921
                }
2922
2923
                if (isset($_ticketPostIDContainer['lastpostid']) && !empty($_ticketPostIDContainer['lastpostid']))
2924
                {
2925
                        $this->UpdatePool('lastpostid', intval($_ticketPostIDContainer['lastpostid']));
2926
2927
                        $_lastTicketPostContainer = $this->Database->QueryFetch("SELECT fullname, dateline FROM " . TABLE_PREFIX . "ticketposts WHERE
2928
                                ticketpostid = '" . intval($_ticketPostIDContainer['lastpostid']) . "'");
2929
2930
                        if (isset($_lastTicketPostContainer['fullname']) && !empty($_lastTicketPostContainer['fullname']))
2931
                        {
2932
                                $this->UpdatePool('lastreplier', $_lastTicketPostContainer['fullname']);
2933
                        }
2934
2935
                        if (isset($_lastTicketPostContainer['dateline']) && $_lastTicketPostContainer['dateline'] > $this->GetProperty('lastactivity'))
2936
                        {
2937
                                $this->UpdatePool('lastactivity', intval($_lastTicketPostContainer['dateline']));
2938
                        }
2939
                }
2940
2941
                if (isset($_ticketPostIDContainer['totalreplies']))
2942
                {
2943
                        // We deduct by 1 to ignore the original ticket post as a reply
2944
                        if ($_ticketPostIDContainer['totalreplies'] > 0)
2945
                        {
2946
                                $_ticketPostIDContainer['totalreplies']--;
2947
                        }
2948
2949
                        $this->UpdatePool('totalreplies', intval($_ticketPostIDContainer['totalreplies']));
2950
                }
2951
2952
                // Has Notes?
2953
                $_hasNotesContainer = $this->Database->QueryFetch("SELECT COUNT(*) AS totalnotes FROM " . TABLE_PREFIX . "ticketnotes WHERE
2954
                        linktypeid = '" . intval($this->GetTicketID()) . "' AND linktype = '" . SWIFT_TicketNoteManager::LINKTYPE_TICKET . "'");
2955
2956
                $this->UpdatePool('hasnotes', IIF($_hasNotesContainer['totalnotes'] > 0, '1', '0'));
2957
2958
                // Has Attachments?
2959
                $_hasAttachmentsContainer = $this->Database->QueryFetch("SELECT COUNT(*) AS totalattachments FROM " . TABLE_PREFIX . "attachments WHERE ticketid = '" . intval($this->GetTicketID()) . "'");
2960
2961
                $this->UpdatePool('hasattachments', IIF($_hasAttachmentsContainer['totalattachments'] > 0, '1', '0'));
2962
2963
                /**
2964
                 * BUG FIX - Saloni Dhall
2965
                 *
2966
                 * SWIFT-2576: 'hasattachments' field is not getting saved if ticket is having attachments
2967
                 *
2968
                 */
2969
                $_storeTicketIDList = $this->GetTicketPostIDList();
2970
                if (is_array($_storeTicketIDList) && !empty($_storeTicketIDList)) {
2971
                        foreach ($_storeTicketIDList as $_ticketPostID)
2972
                        {
2973
                                $_hasAttachmentsContainer = $this->Database->QueryFetch("SELECT COUNT(*) as attachmentcount FROM " . TABLE_PREFIX . "attachments WHERE linktypeid = '" . $_ticketPostID . "'");
2974
                                $_SWIFT_TicketPostObject = new SWIFT_TicketPost(new SWIFT_DataID($_ticketPostID));
2975
                                $_SWIFT_TicketPostObject->UpdatePool('hasattachments', IIF($_hasAttachmentsContainer['attachmentcount'] > 0, '1', '0'));
2976
                        }
2977
                }
2978
2979
                // Has Draft?
2980
                $_hasDraftContainer = $this->Database->QueryFetch("SELECT COUNT(*) AS totalitems FROM " . TABLE_PREFIX . "ticketdrafts WHERE
2981
                        ticketid = '" . intval($this->GetTicketID()) . "'");
2982
2983
                $this->UpdatePool('hasdraft', IIF($_hasDraftContainer['totalitems'] > 0, '1', '0'));
2984
2985
                // Has Billing Entries?
2986
                $_hasBillingContainer = $this->Database->QueryFetch("SELECT COUNT(*) AS totalitems FROM " . TABLE_PREFIX . "tickettimetracks WHERE
2987
                        ticketid = '" . intval($this->GetTicketID()) . "'");
2988
2989
                $this->UpdatePool('hasbilling', IIF($_hasBillingContainer['totalitems'] > 0, '1', '0'));
2990
2991
                // Has Follow-Up's?
2992
                $_hasFollowUpContainer = $this->Database->QueryFetch("SELECT COUNT(*) AS totalitems FROM " . TABLE_PREFIX . "ticketfollowups WHERE
2993
                        ticketid = '" . intval($this->GetTicketID()) . "'");
2994
2995
                $this->UpdatePool('hasfollowup', IIF($_hasFollowUpContainer['totalitems'] > 0, '1', '0'));
2996
                $this->UpdatePool('followupcount', intval($_hasFollowUpContainer['totalitems']));
2997
2998
                // Update time worked + time billed
2999
                $_ticketTimeWorked = $_ticketTimeBillable = 0;
3000
                $this->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickettimetracks WHERE ticketid = '" . intval($this->GetTicketID()) . "'");
3001
                while ($this->Database->NextRecord())
3002
                {
3003
                        $_ticketTimeWorked += intval($this->Database->Record['timespent']);
3004
                        $_ticketTimeBillable += intval($this->Database->Record['timebillable']);
3005
                }
3006
3007
                $this->UpdateTimeTrack($_ticketTimeWorked, $_ticketTimeBillable);
3008
3009
                // Is Resolved
3010
                if (isset($_ticketStatusCache[$this->GetProperty('ticketstatusid')])) {
3011
                        if ($_ticketStatusCache[$this->GetProperty('ticketstatusid')]['markasresolved'] == '1')
3012
                        {
3013
                                $this->UpdatePool('isresolved', '1');
3014
                                $this->UpdatePool('repliestoresolution', $this->GetProperty('totalreplies'));
3015
                        } else {
3016
                                $this->UpdatePool('isresolved', '0');
3017
                        }
3018
                }
3019
3020
                // Rebuild the titles & names
3021
                $this->RebuildTitles();
3022
3023
                // Calculate the additional properties
3024
                $this->CalculateProperties();
3025
3026
                // Load and Process Workflow Rules
3027
                self::AddToWorkflowQueue($this);
3028
3029
                return true;
3030
        }
3031
3032
        /**
3033
         * Rebuilds the titles associated with the ticket
3034
         *
3035
         * @author Varun Shoor
3036
         * @return bool "true" on Success, "false" otherwise
3037
         * @throws SWIFT_Exception If the Class is not Loaded
3038
         */
3039
        protected function RebuildTitles()
3040
        {
3041
                if (!$this->GetIsClassLoaded()) {
3042
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
3043
3044
                        return false;
3045
                }
3046
3047
                $_departmentCache = $this->Cache->Get('departmentcache');
3048
                $_staffCache = $this->Cache->Get('staffcache');
3049
                $_ticketStatusCache = $this->Cache->Get('statuscache');
3050
                $_ticketPriorityCache = $this->Cache->Get('prioritycache');
3051
                $_ticketTypeCache = $this->Cache->Get('tickettypecache');
3052
                $_slaPlanCache = $this->Cache->Get('slaplancache');
3053
                $_escalationRuleCache = $this->Cache->Get('escalationrulecache');
3054
3055
                // Build local properties
3056
                if (isset($_departmentCache[$this->GetProperty('departmentid')])) {
3057
                        $this->UpdatePool('departmenttitle', $_departmentCache[$this->GetProperty('departmentid')]['title']);
3058
                }
3059
3060
                if (isset($_staffCache[$this->GetProperty('ownerstaffid')])) {
3061
                        $this->UpdatePool('ownerstaffname', $_staffCache[$this->GetProperty('ownerstaffid')]['fullname']);
3062
                }
3063
3064
                if (isset($_ticketStatusCache[$this->GetProperty('ticketstatusid')])) {
3065
                        $this->UpdatePool('ticketstatustitle', $_ticketStatusCache[$this->GetProperty('ticketstatusid')]['title']);
3066
                }
3067
3068
                if (isset($_ticketPriorityCache[$this->GetProperty('priorityid')])) {
3069
                        $this->UpdatePool('prioritytitle', $_ticketPriorityCache[$this->GetProperty('priorityid')]['title']);
3070
                }
3071
3072
                if (isset($_ticketTypeCache[$this->GetProperty('tickettypeid')])) {
3073
                        $this->UpdatePool('tickettypetitle', $_ticketTypeCache[$this->GetProperty('tickettypeid')]['title']);
3074
                }
3075
3076
                // Ticket Drafts
3077
                $_ticketDraftUpdateContainer = array();
3078
                $this->Database->Query("SELECT * FROM " . TABLE_PREFIX . "ticketdrafts WHERE ticketid = '" . $this->GetTicketID() . "'");
3079
                while ($this->Database->NextRecord()) {
3080
                        $_ticketDraftUpdateContainer[$this->Database->Record['ticketdraftid']] = $this->Database->Record;
3081
3082
                        if (isset($_staffCache[$this->Database->Record['staffid']])) {
3083
                                $_ticketDraftUpdateContainer[$this->Database->Record['staffname']] = $_staffCache[$this->Database->Record['staffid']]['fullname'];
3084
                        }
3085
3086
                        if (isset($_staffCache[$this->Database->Record['editedbystaffid']])) {
3087
                                $_ticketDraftUpdateContainer[$this->Database->Record['editedstaffname']] = $_staffCache[$this->Database->Record['editedbystaffid']]['fullname'];
3088
                        }
3089
                }
3090
3091
                foreach ($_ticketDraftUpdateContainer as $_ticketDraftID => $_ticketDraft) {
3092
                        SWIFT_TicketDraft::UpdateStaffName($_ticketDraftID, $_ticketDraft['staffname'], $_ticketDraft['editedstaffname']);
3093
                }
3094
                unset($_ticketDraftUpdateContainer);
3095
3096
                // Ticket Audit Logs
3097
                $_ticketAuditLogUpdateContainer = array();
3098
                $this->Database->Query("SELECT * FROM " . TABLE_PREFIX . "ticketauditlogs WHERE ticketid = '" . intval($this->GetTicketID()) . "'");
3099
                while ($this->Database->NextRecord()) {
3100
                        $_ticketAuditLogUpdateContainer[$this->Database->Record['ticketauditlogid']] = $this->Database->Record;
3101
3102
                        if (isset($_departmentCache[$this->Database->Record['departmentid']])) {
3103
                                $_ticketAuditLogUpdateContainer[$this->Database->Record['ticketauditlogid']]['departmenttitle'] = $_departmentCache[$this->Database->Record['departmentid']]['title'];
3104
                        }
3105
3106
                        if ($this->Database->Record['creatortype'] == SWIFT_TicketAuditLog::CREATOR_STAFF && isset($_staffCache[$this->Database->Record['creatorid']])) {
3107
                                $_ticketAuditLogUpdateContainer[$this->Database->Record['ticketauditlogid']]['creatorfullname'] = $_staffCache[$this->Database->Record['creatorid']]['fullname'];
3108
                        }
3109
                }
3110
3111
                foreach ($_ticketAuditLogUpdateContainer as $_ticketAuditLogID => $_ticketAuditLog) {
3112
                        SWIFT_TicketAuditLog::UpdateProperties($_ticketAuditLogID, $_ticketAuditLog['departmenttitle'], $_ticketAuditLog['creatorfullname']);
3113
                }
3114
                unset($_ticketAuditLogUpdateContainer);
3115
3116
                // Ticket Notes
3117
                $_ticketNoteUpdateContainer = array();
3118
                $this->Database->Query("SELECT * FROM " . TABLE_PREFIX . "ticketnotes
3119
                        WHERE linktype = '" . SWIFT_TicketNote::LINKTYPE_TICKET . "' AND linktypeid = '" . intval($this->GetTicketID()) . "'");
3120
                while ($this->Database->NextRecord()) {
3121
                        $_ticketNoteUpdateContainer[$this->Database->Record['ticketnoteid']] = $this->Database->Record;
3122
3123
                        if (isset($_staffCache[$this->Database->Record['staffid']])) {
3124
                                $_ticketNoteUpdateContainer[$this->Database->Record['ticketnoteid']]['staffname'] = $_staffCache[$this->Database->Record['staffid']]['fullname'];
3125
                        }
3126
3127
                        if (isset($_staffCache[$this->Database->Record['editedstaffid']])) {
3128
                                $_ticketNoteUpdateContainer[$this->Database->Record['ticketnoteid']]['editedstaffname'] = $_staffCache[$this->Database->Record['editedstaffid']]['fullname'];
3129
                        }
3130
                }
3131
3132
                foreach ($_ticketNoteUpdateContainer as $_ticketNoteID => $_ticketNote) {
3133
                        SWIFT_TicketNoteManager::UpdateProperties($_ticketNoteID, $_ticketNote['staffname'], $_ticketNote['editedstaffname']);
3134
                }
3135
3136
                unset($_ticketNoteUpdateContainer);
3137
3138
                // Ticket Time Tracks
3139
                $_ticketTimeTrackUpdateContainer = array();
3140
                $this->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickettimetracks WHERE ticketid = '" . intval($this->GetTicketID()) . "'");
3141
                while ($this->Database->NextRecord()) {
3142
                        $_ticketTimeTrackUpdateContainer[$this->Database->Record['tickettimetrackid']] = $this->Database->Record;
3143
3144
                        if (isset($_staffCache[$this->Database->Record['creatorstaffid']])) {
3145
                                $_ticketTimeTrackUpdateContainer[$this->Database->Record['tickettimetrackid']]['creatorstaffname'] = $_staffCache[$this->Database->Record['creatorstaffid']]['fullname'];
3146
                        }
3147
3148
                        if (isset($_staffCache[$this->Database->Record['editedstaffid']])) {
3149
                                $_ticketTimeTrackUpdateContainer[$this->Database->Record['tickettimetrackid']]['editedstaffname'] = $_staffCache[$this->Database->Record['editedstaffid']]['fullname'];
3150
                        }
3151
3152
                        if (isset($_staffCache[$this->Database->Record['workerstaffid']])) {
3153
                                $_ticketTimeTrackUpdateContainer[$this->Database->Record['tickettimetrackid']]['workerstaffname'] = $_staffCache[$this->Database->Record['workerstaffid']]['fullname'];
3154
                        }
3155
                }
3156
3157
                foreach ($_ticketTimeTrackUpdateContainer as $_ticketTimeTrackID => $_ticketTimeTrack) {
3158
                        SWIFT_TicketTimeTrack::UpdateProperties($_ticketTimeTrackID, $_ticketTimeTrack['creatorstaffname'], $_ticketTimeTrack['editedstaffname'], $_ticketTimeTrack['workerstaffname']);
3159
                }
3160
                unset($_ticketTimeTrackUpdateContainer);
3161
3162
                // Escalation Paths
3163
                $_escalationPathUpdateContainer = array();
3164
                $this->Database->Query("SELECT * FROM " . TABLE_PREFIX . "escalationpaths WHERE ticketid = '" . intval($this->GetTicketID()) . "'");
3165
                while ($this->Database->NextRecord()) {
3166
                        $_escalationPathUpdateContainer[$this->Database->Record['escalationpathid']] = $this->Database->Record;
3167
3168
                        if (isset($_slaPlanCache[$this->Database->Record['slaplanid']])) {
3169
                                $_escalationPathUpdateContainer[$this->Database->Record['escalationpathid']]['slaplantitle'] = $_slaPlanCache[$this->Database->Record['slaplanid']]['title'];
3170
                        }
3171
3172
                        if (isset($_escalationRuleCache[$this->Database->Record['escalationruleid']])) {
3173
                                $_escalationPathUpdateContainer[$this->Database->Record['escalationpathid']]['escalationruletitle'] = $_escalationRuleCache[$this->Database->Record['escalationruleid']]['title'];
3174
                        }
3175
3176
                        if (isset($_staffCache[$this->Database->Record['ownerstaffid']])) {
3177
                                $_escalationPathUpdateContainer[$this->Database->Record['escalationpathid']]['ownerstaffname'] = $_staffCache[$this->Database->Record['ownerstaffid']]['fullname'];
3178
                        }
3179
3180
                        if (isset($_departmentCache[$this->Database->Record['departmentid']])) {
3181
                                $_escalationPathUpdateContainer[$this->Database->Record['escalationpathid']]['departmenttitle'] = $_departmentCache[$this->Database->Record['departmentid']]['title'];
3182
                        }
3183
3184
                        if (isset($_ticketStatusCache[$this->Database->Record['ticketstatusid']])) {
3185
                                $_escalationPathUpdateContainer[$this->Database->Record['escalationpathid']]['ticketstatustitle'] = $_ticketStatusCache[$this->Database->Record['ticketstatusid']]['title'];
3186
                        }
3187
3188
                        if (isset($_ticketPriorityCache[$this->Database->Record['priorityid']])) {
3189
                                $_escalationPathUpdateContainer[$this->Database->Record['escalationpathid']]['prioritytitle'] = $_ticketPriorityCache[$this->Database->Record['priorityid']]['title'];
3190
                        }
3191
3192
                        if (isset($_ticketTypeCache[$this->Database->Record['tickettypeid']])) {
3193
                                $_escalationPathUpdateContainer[$this->Database->Record['escalationpathid']]['tickettypetitle'] = $_ticketTypeCache[$this->Database->Record['tickettypeid']]['title'];
3194
                        }
3195
                }
3196
3197
                foreach ($_escalationPathUpdateContainer as $_escalationPathID => $_escalationPath) {
3198
                        SWIFT_EscalationPath::UpdateProperties($_escalationPathID, $_escalationPath['slaplantitle'], $_escalationPath['escalationruletitle'], $_escalationPath['ownerstaffname'],
3199
                                        $_escalationPath['departmenttitle'], $_escalationPath['ticketstatustitle'], $_escalationPath['prioritytitle'], $_escalationPath['tickettypetitle']);
3200
                }
3201
                unset($_escalationPathUpdateContainer);
3202
3203
                return true;
3204
        }
3205
3206
        /**
3207
         * Calculate the Ticket Properties like is firstcontactresolved etc.
3208
         *
3209
         * @author Varun Shoor
3210
         * @return bool "true" on Success, "false" otherwise
3211
         * @throws SWIFT_Exception If the Class is not Loaded
3212
         */
3213
        public function CalculateProperties() {
3214
                if (!$this->GetIsClassLoaded()) {
3215
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
3216
3217
                        return false;
3218
                }
3219
3220
                $_SWIFT_TicketPostObject_Last = false;
3221
                try {
3222
                        $_SWIFT_TicketPostObject_Last = new SWIFT_TicketPost(new SWIFT_DataID($this->GetProperty('lastpostid')));
3223
                } catch (SWIFT_Exception $_SWIFT_ExceptionObject) {
3224
                }
3225
3226
                // Is First Contact Resolved?
3227
                if ($this->GetProperty('totalreplies') == '1' && $_SWIFT_TicketPostObject_Last instanceof SWIFT_TicketPost && $_SWIFT_TicketPostObject_Last->GetIsClassLoaded() && $_SWIFT_TicketPostObject_Last->GetProperty('creator') == SWIFT_TicketPost::CREATOR_STAFF
3228
                                && $this->GetProperty('isresolved') == '1' && $this->GetProperty('isfirstcontactresolved') == '0') {
3229
                        $this->UpdatePool('isfirstcontactresolved', '1');
3230
                }
3231
3232
                $_lastActivity = $this->GetProperty('lastactivity');
3233
                $_lastPostActivity = $_lastActivity;
3234
                if ($_SWIFT_TicketPostObject_Last instanceof SWIFT_TicketPost && $_SWIFT_TicketPostObject_Last->GetIsClassLoaded()) {
3235
                        $_lastPostActivity = $_SWIFT_TicketPostObject_Last->GetProperty('dateline');
3236
                }
3237
3238
                $_finalLastActivity = $_lastActivity;
3239
                if ($_lastPostActivity > $_finalLastActivity) {
3240
                        $_finalLastActivity = $_lastPostActivity;
3241
                }
3242
3243
                if ($this->GetProperty('isresolved') == '1') {
3244
                        $this->UpdatePool('resolutiondateline', $_finalLastActivity);
3245
3246
                        // How much time did it take to resolve this ticket?
3247
                        $this->UpdatePool('resolutionseconds', $_finalLastActivity-$this->GetProperty('dateline'));
3248
                } else {
3249
                        $this->UpdatePool('resolutiondateline', '0');
3250
                        $this->UpdatePool('resolutionseconds', '0');
3251
                }
3252
3253
                // Is watched?
3254
                $_ticketWatcherCountContainer = $this->Database->QueryFetch("SELECT COUNT(*) AS totalitems FROM " . TABLE_PREFIX . "ticketwatchers WHERE ticketid = '" . intval($this->GetTicketID()) . "'");
3255
                if (isset($_ticketWatcherCountContainer['totalitems']) && $_ticketWatcherCountContainer['totalitems'] > 0) {
3256
                        $this->UpdatePool('iswatched', '1');
3257
                } else {
3258
                        $this->UpdatePool('iswatched', '0');
3259
                }
3260
3261
                // Calculate the average response time
3262
                $this->UpdatePool('averageresponsetime', '0');
3263
                $this->UpdatePool('averageresponsetimehits', '0');
3264
3265
                $_ticketPostContainer = array();
3266
                $_oldPostDateline = $_lastPostDateline = 0;
3267
                $this->Database->Query("SELECT ticketpostid, dateline, creator FROM " . TABLE_PREFIX . "ticketposts WHERE ticketid = '" . intval($this->GetTicketID()) . "' ORDER BY ticketpostid ASC");
3268
                while ($this->Database->NextRecord()) {
3269
                        $_ticketPostContainer[$this->Database->Record['ticketpostid']] = $this->Database->Record;
3270
                }
3271
3272
                $_firstResponseTime = 0;
3273
3274
                foreach ($_ticketPostContainer as $_ticketPostID => $_ticketPost) {
3275
                        if (!empty($_lastPostDateline)) {
3276
                                $_responseTime = $_ticketPost['dateline'] - $_lastPostDateline;
3277
3278
                                $_postFirstResponseTime = 0;
3279
3280
                                if (empty($_firstResponseTime) && $_ticketPost['creator'] == SWIFT_TicketPost::CREATOR_STAFF) {
3281
                                        $_firstResponseTime = $_ticketPost['dateline'] - $this->GetProperty('dateline');
3282
                                        $_postFirstResponseTime = $_firstResponseTime;
3283
                                }
3284
3285
                                $_updateContainer = array();
3286
                                $_updateContainer['responsetime'] = $_responseTime;
3287
3288
                                if (!empty($_postFirstResponseTime)) {
3289
                                        $_updateContainer['firstresponsetime'] = $_postFirstResponseTime;
3290
                                }
3291
3292
                                $this->Database->AutoExecute(TABLE_PREFIX . 'ticketposts', $_updateContainer, 'UPDATE', "ticketpostid = '" . intval($_ticketPostID) . "'");
3293
                        }
3294
3295
                        if ($_ticketPost['creator'] != SWIFT_TicketPost::CREATOR_STAFF) {
3296
                                $_oldPostDateline = $_ticketPost['dateline'];
3297
                        } else if (!empty($_oldPostDateline) && $_ticketPost['creator'] == SWIFT_TicketPost::CREATOR_STAFF) {
3298
                                $_responseTime = $_ticketPost['dateline']-$_oldPostDateline;
3299
                                $this->UpdateAverageResponseTime($_responseTime);
3300
3301
                                $_oldPostDateline = 0;
3302
                        }
3303
3304
                        $_lastPostDateline = $_ticketPost['dateline'];
3305
                }
3306
3307
                if (!empty($_firstResponseTime)) {
3308
                        $this->UpdatePool('firstresponsetime', intval($_firstResponseTime));
3309
                }
3310
3311
                return true;
3312
        }
3313
3314
        /**
3315
         * Change the ticket's hasattachments property to true
3316
         *
3317
         * @author Varun Shoor
3318
         * @return bool "true" on Success, "false" otherwise
3319
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
3320
         */
3321
        public function MarkHasAttachments() {
3322
                if (!$this->GetIsClassLoaded()) {
3323
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
3324
3325
                        return false;
3326
                }
3327
3328
                $this->UpdatePool('hasattachments', '1');
3329
3330
                return true;
3331
        }
3332
3333
        /**
3334
         * Change the ticket's hasratings property to true
3335
         *
3336
         * @author Varun Shoor
3337
         * @return bool "true" on Success, "false" otherwise
3338
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
3339
         */
3340
        public function MarkHasRatings() {
3341
                if (!$this->GetIsClassLoaded()) {
3342
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
3343
3344
                        return false;
3345
                }
3346
3347
                $this->UpdatePool('hasratings', '1');
3348
3349
                return true;
3350
        }
3351
3352
        /**
3353
         * Change the ticket's hasfollowup property to true
3354
         *
3355
         * @author Varun Shoor
3356
         * @return bool "true" on Success, "false" otherwise
3357
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
3358
         */
3359
        public function MarkHasFollowUp() {
3360
                if (!$this->GetIsClassLoaded()) {
3361
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
3362
3363
                        return false;
3364
                }
3365
3366
                $this->UpdatePool('hasfollowup', '1');
3367
3368
                return true;
3369
        }
3370
3371
        /**
3372
         * Change the ticket's hasdraft property to true
3373
         *
3374
         * @author Varun Shoor
3375
         * @return bool "true" on Success, "false" otherwise
3376
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
3377
         */
3378
        public function MarkHasDraft() {
3379
                if (!$this->GetIsClassLoaded()) {
3380
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
3381
3382
                        return false;
3383
                }
3384
3385
                $this->UpdatePool('hasdraft', '1');
3386
3387
                return true;
3388
        }
3389
3390
        /**
3391
         * Change the ticket's hasdraft property to false
3392
         *
3393
         * @author Varun Shoor
3394
         * @return bool "true" on Success, "false" otherwise
3395
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
3396
         */
3397
        public function ClearHasDraft() {
3398
                if (!$this->GetIsClassLoaded()) {
3399
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
3400
3401
                        return false;
3402
                }
3403
3404
                $this->UpdatePool('hasdraft', '0');
3405
3406
                return true;
3407
        }
3408
3409
        /**
3410
         * Change the ticket's hasnotes property to true
3411
         *
3412
         * @author Varun Shoor
3413
         * @return bool "true" on Success, "false" otherwise
3414
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
3415
         */
3416
        public function MarkHasNotes() {
3417
                if (!$this->GetIsClassLoaded()) {
3418
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
3419
3420
                        return false;
3421
                }
3422
3423
                $this->UpdatePool('hasnotes', '1');
3424
3425
                return true;
3426
        }
3427
3428
        /**
3429
         * Change the ticket's hasbilling property to true
3430
         *
3431
         * @author Varun Shoor
3432
         * @return bool "true" on Success, "false" otherwise
3433
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
3434
         */
3435
        public function MarkHasBilling() {
3436
                if (!$this->GetIsClassLoaded()) {
3437
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
3438
3439
                        return false;
3440
                }
3441
3442
                $this->UpdatePool('hasbilling', '1');
3443
3444
                return true;
3445
        }
3446
3447
        /**
3448
         * Update the time tracking information
3449
         *
3450
         * @author Varun Shoor
3451
         * @param int $_timeSpent The Time Spent
3452
         * @param int $_timeBilled The Time Billed
3453
         * @return bool "true" on Success, "false" otherwise
3454
         * @throws SWIFT_Exception If the Class is not Loaded
3455
         */
3456
        public function UpdateTimeTrack($_timeSpent, $_timeBilled)
3457
        {
3458
                if (!$this->GetIsClassLoaded())
3459
                {
3460
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
3461
3462
                        return false;
3463
                }
3464
3465
                $this->UpdatePool('timeworked', intval($_timeSpent));
3466
                $this->UpdatePool('timebilled', intval($_timeBilled));
3467
3468
                return true;
3469
        }
3470
3471
        /**
3472
         * Set the Message ID for this Ticket
3473
         *
3474
         * @author Varun Shoor
3475
         * @param string $_messageID The Message ID
3476
         * @return bool "true" on Success, "false" otherwise
3477
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded or If Invalid Data is Provided
3478
         */
3479
        public function SetMessageID($_messageID) {
3480
                if (!$this->GetIsClassLoaded()) {
3481
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
3482
3483
                        return false;
3484
                } else if (empty($_messageID)) {
3485
                        throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
3486
                }
3487
3488
                $this->UpdatePool('messageid', $_messageID);
3489
3490
                return true;
3491
        }
3492
3493
        /**
3494
         * Check to see if the given staff/user can access the ticket
3495
         *
3496
         * @author Varun Shoor
3497
         * @param SWIFT_Base $_SWIFT_BaseObject The SWIFT_Base Object Pointer
3498
         * @return bool "true" on Success, "false" otherwise
3499
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded or If Invalid Data is Provided
3500
         */
3501
        public function CanAccess($_SWIFT_BaseObject) {
3502
                if (!$this->GetIsClassLoaded()) {
3503
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
3504
3505
                        return false;
3506
                } else if ((!$_SWIFT_BaseObject instanceof SWIFT_Staff || !$_SWIFT_BaseObject->GetIsClassLoaded()) &&
3507
                                (!$_SWIFT_BaseObject instanceof SWIFT_User || !$_SWIFT_BaseObject->GetIsClassLoaded())) {
3508
                        return false;
3509
                }
3510
3511
                // Staff Check
3512
                if ($_SWIFT_BaseObject instanceof SWIFT_Staff)
3513
                {
3514
                        $_assignedDepartmentIDList = $_SWIFT_BaseObject->GetAssignedDepartments(APP_TICKETS);
3515
3516
                        if (in_array($this->GetProperty('departmentid'), $_assignedDepartmentIDList)) {
3517
                                return true;
3518
                        } else if ($this->GetProperty('departmentid') == '0'
3519
                                        && ($this->GetProperty('trasholddepartmentid') == '0' || in_array($this->GetProperty('trasholddepartmentid'), $_assignedDepartmentIDList))) {
3520
                                return true;
3521
                        }
3522
3523
                // User Check
3524
                } else if ($_SWIFT_BaseObject instanceof SWIFT_User) {
3525
                        $_userEmailList = array();
3526
                        $_userID = $_SWIFT_BaseObject->GetUserID();
3527
                        $_userEmailList = array_merge($_userEmailList, $_SWIFT_BaseObject->GetEmailList());
3528
3529
                        $_userIDList = array($_SWIFT_BaseObject->GetUserID());
3530
3531
                        // Does this user have a shared organization or he is a manager in an organization?
3532
                        $_SWIFT_UserOrganizationObject = $_SWIFT_BaseObject->GetOrganization();
3533
3534
                        if (($_SWIFT_BaseObject->GetProperty('userrole') == SWIFT_User::ROLE_MANAGER && $_SWIFT_UserOrganizationObject instanceof SWIFT_UserOrganization && $_SWIFT_UserOrganizationObject->GetIsClassLoaded()) ||
3535
                                        ($_SWIFT_UserOrganizationObject instanceof SWIFT_UserOrganization && $_SWIFT_UserOrganizationObject->GetIsClassLoaded() && $_SWIFT_UserOrganizationObject->GetProperty('organizationtype') == SWIFT_UserOrganization::TYPE_SHARED))
3536
                        {
3537
                                $_userIDList_Organization = array();
3538
                                $this->Database->Query("SELECT userid FROM " . TABLE_PREFIX . "users
3539
                                        WHERE userorganizationid = '" . intval($_SWIFT_UserOrganizationObject->GetUserOrganizationID()) . "'");
3540
                                while ($this->Database->NextRecord())
3541
                                {
3542
                                        $_userIDList_Organization[] = $this->Database->Record['userid'];
3543
3544
                                        $_userIDList[] = $this->Database->Record['userid'];
3545
                                }
3546
3547
                                $_userEmailList = array_merge($_userEmailList, SWIFT_UserEmail::RetrieveListOnUserIDList($_userIDList_Organization));
3548
                        }
3549
3550
                        if ($this->GetProperty('userid') != '0' && in_array($this->GetProperty('userid'), $_userIDList))
3551
                        {
3552
                                return true;
3553
                        } else if (in_array(mb_strtolower($this->GetProperty('email')), $_userEmailList)) {
3554
                                return true;
3555
                        } else if ($this->GetProperty('creator') == SWIFT_Ticket::CREATOR_STAFF && in_array(mb_strtolower($this->GetProperty('replyto')), $_userEmailList)) {
3556
                                return true;
3557
                        }
3558
                }
3559
3560
                return false;
3561
        }
3562
3563
        /**
3564
         * Return the Ticket ID to be displayed according to relevant setting
3565
         *
3566
         * @author Varun Shoor
3567
         * @return mixed Ticket Mask ID or Ticket ID
3568
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
3569
         */
3570
        public function GetTicketDisplayID() {
3571
                if (!$this->GetIsClassLoaded()) {
3572
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
3573
3574
                        return false;
3575
                }
3576
3577
                return IIF($this->Settings->Get('t_eticketid') == 'seq', $this->GetProperty('ticketid'), $this->GetProperty('ticketmaskid'));
3578
        }
3579
3580
        /**
3581
         * Recalculate the Ticket Link Property
3582
         *
3583
         * @author Varun Shoor
3584
         * @param array $_ticketIDList The Ticket ID List
3585
         * @return bool "true" on Success, "false" otherwise
3586
         * @throws SWIFT_Ticket_Exception If Invalid Data is Provided
3587
         */
3588
        static public function RecalculateTicketLinkProperty($_ticketIDList) {
3589
                $_SWIFT = SWIFT::GetInstance();
3590
3591
                if (!_is_array($_ticketIDList)) {
3592
                        return false;
3593
                }
3594
3595
                $_ticketContainer = $_ticketLinkStatus = array();
3596
                $_SWIFT->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickets WHERE ticketid IN (" . BuildIN($_ticketIDList) . ")");
3597
                while ($_SWIFT->Database->NextRecord()) {
3598
                        $_ticketContainer[$_SWIFT->Database->Record['ticketid']] = new SWIFT_Ticket(new SWIFT_DataStore($_SWIFT->Database->Record));
3599
                }
3600
3601
                // Calculate the link chains
3602
                $_SWIFT->Database->Query("SELECT * FROM " . TABLE_PREFIX . "ticketlinkchains WHERE ticketid IN (" . BuildIN($_ticketIDList) . ")");
3603
                while ($_SWIFT->Database->NextRecord()) {
3604
                        $_ticketLinkStatus[] = $_SWIFT->Database->Record['ticketid'];
3605
                }
3606
3607
                foreach ($_ticketContainer as $_ticketID => $_SWIFT_TicketObject) {
3608
                        if (in_array($_ticketID, $_ticketLinkStatus)) {
3609
                                $_SWIFT_TicketObject->MarkAsLinked();
3610
                        } else {
3611
                                $_SWIFT_TicketObject->MarkAsUnlinked();
3612
                        }
3613
                }
3614
3615
                return true;
3616
        }
3617
3618
        /**
3619
         * Get the ticket post count
3620
         *
3621
         * @author Varun Shoor
3622
         * @return int The Ticket Post Count
3623
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
3624
         */
3625
        public function GetTicketPostCount() {
3626
                if (!$this->GetIsClassLoaded()) {
3627
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
3628
3629
                        return false;
3630
                }
3631
3632
                $_totalCount = 0;
3633
3634
                $_totalItemContainer = $this->Database->QueryFetch("SELECT COUNT(*) AS totalitems FROM " . TABLE_PREFIX . "ticketposts WHERE ticketid = '" .
3635
                                intval($this->GetTicketID()) . "'");
3636
                if (isset($_totalItemContainer['totalitems'])) {
3637
                        $_totalCount = intval($_totalItemContainer['totalitems']);
3638
                }
3639
3640
                return $_totalCount;
3641
        }
3642
3643
        /**
3644
         * Retrieve the ticket posts associated with this ticket
3645
         *
3646
         * @author Varun Shoor
3647
         * @param int $_offset (OPTIONAL) The Starting Offset
3648
         * @param int $_limit (OPTIONAL) The Number of Results to Return
3649
         * @param string $_sortOrder (OPTIONAL) ASC/DESC The Sort Order
3650
         * @param constant $_creator (OPTIONAL) Filter by the Creator
3651
         * @return array The Ticket Post Object Container
3652
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
3653
         */
3654
        public function GetTicketPosts($_offset = 0, $_limit = false, $_sortOrder = 'ASC', $_creator = false) {
3655
                $_SWIFT = SWIFT::GetInstance();
3656
3657
                if (!$this->GetIsClassLoaded()) {
3658
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
3659
3660
                        return false;
3661
                }
3662
3663
                $_ticketPostObjectContainer = array();
3664
3665
                $_sqlQuery = "SELECT * FROM " . TABLE_PREFIX . "ticketposts WHERE ticketid = '" . intval($this->GetTicketID()) . "' ORDER BY ticketpostid " .
3666
                                $_sortOrder;
3667
                if (!empty($_limit)) {
3668
                        $this->Database->QueryLimit($_sqlQuery, $_limit, $_offset);
3669
                } else {
3670
                        $this->Database->Query($_sqlQuery);
3671
                }
3672
3673
                while ($this->Database->NextRecord()) {
3674
                        if (!empty($_creator) && $_creator != $this->Database->Record['creator']) {
3675
                                continue;
3676
                        }
3677
3678
                        $_ticketPostObjectContainer[$this->Database->Record['ticketpostid']] = new SWIFT_TicketPost(new SWIFT_DataStore($this->Database->Record));
3679
                }
3680
3681
                return $_ticketPostObjectContainer;
3682
        }
3683
3684
        /**
3685
         * Train the given tickets
3686
         *
3687
         * @author Varun Shoor
3688
         * @param array $_ticketIDList The Ticket ID List
3689
         * @return bool "true" on Success, "false" otherwise
3690
         * @throws SWIFT_Ticket_Exception If Invalid Data is Provided
3691
         */
3692
        static public function TrainBayesList($_ticketIDList, $_bayesCategoryID) {
3693
                $_SWIFT = SWIFT::GetInstance();
3694
3695
                if (!_is_array($_ticketIDList)) {
3696
                        return false;
3697
                } else if (empty($_bayesCategoryID)) {
3698
                        throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
3699
                }
3700
3701
                $_bayesianCategoryCache = $_SWIFT->Cache->Get('bayesiancategorycache');
3702
3703
                $_SWIFT_BayesianObject = new SWIFT_Bayesian();
3704
                if (!$_SWIFT_BayesianObject instanceof SWIFT_Bayesian || !$_SWIFT_BayesianObject->GetIsClassLoaded()) {
3705
                        throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
3706
                }
3707
3708
                if (!isset($_bayesianCategoryCache[$_bayesCategoryID]))
3709
                {
3710
                        throw new SWIFT_Ticket_Exception('Bayesian Category does not exist');
3711
                }
3712
3713
                $_ticketObjectContainer = array();
3714
                $_SWIFT->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickets WHERE ticketid IN (" . BuildIN($_ticketIDList) . ")");
3715
                while ($_SWIFT->Database->NextRecord()) {
3716
                        $_ticketObjectContainer[$_SWIFT->Database->Record['ticketid']] = new SWIFT_Ticket(new SWIFT_DataStore($_SWIFT->Database->Record));
3717
                }
3718
3719
                foreach ($_ticketObjectContainer as $_ticketID => $_SWIFT_TicketObject) {
3720
                        $_ticketPostContainer = $_SWIFT_TicketObject->GetTicketPosts(0, false, 'ASC', SWIFT_Ticket::CREATOR_CLIENT);
3721
                        if (!_is_array($_ticketPostContainer)) {
3722
                                continue;
3723
                        }
3724
3725
                        $_finalTicketPostText = $_SWIFT_TicketObject->GetProperty('subject');
3726
                        foreach ($_ticketPostContainer as $_ticketPostID => $_SWIFT_TicketPostObject) {
3727
                                $_finalTicketPostText .= $_SWIFT_TicketPostObject->GetProperty('contents') . SWIFT_CRLF;
3728
                        }
3729
3730
                        $_SWIFT_BayesianObject->Train($_ticketID, $_bayesCategoryID, $_finalTicketPostText);
3731
                }
3732
3733
                return true;
3734
        }
3735
3736
        /**
3737
         * Train the Bayesian
3738
         *
3739
         * @author Varun Shoor
3740
         * @param int $_bayesCategoryID The Bayesian Category ID
3741
         * @return bool "true" on Success, "false" otherwise
3742
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded or If Invalid Data is Provided
3743
         */
3744
        public function TrainBayes($_bayesCategoryID)
3745
        {
3746
                if (!$this->GetIsClassLoaded())
3747
                {
3748
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
3749
3750
                        return false;
3751
                } else if (empty($_bayesCategoryID)) {
3752
                        throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
3753
                }
3754
3755
                self::TrainBayesList(array($this->GetTicketID()), $_bayesCategoryID);
3756
3757
                return true;
3758
        }
3759
3760
        /**
3761
         * Mark the given ticket ids as spam
3762
         *
3763
         * @author Varun Shoor
3764
         * @param array $_ticketIDList The Ticket ID List
3765
         * @return bool "true" on Success, "false" otherwise
3766
         * @throws SWIFT_Ticket_Exception If Invalid Data is Provided
3767
         */
3768
        static public function MarkAsSpamList($_ticketIDList) {
3769
                $_SWIFT = SWIFT::GetInstance();
3770
3771
                if (!_is_array($_ticketIDList)) {
3772
                        return false;
3773
                }
3774
3775
                $_bayesianCategoryCache = $_SWIFT->Cache->Get('bayesiancategorycache');
3776
3777
                $_SWIFT_BayesianObject = new SWIFT_Bayesian();
3778
                if (!$_SWIFT_BayesianObject instanceof SWIFT_Bayesian || !$_SWIFT_BayesianObject->GetIsClassLoaded()) {
3779
                        throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
3780
                }
3781
3782
                $_bayesCategoryID = false;
3783
                foreach ($_bayesianCategoryCache as $_bayesianCategoryID => $_bayesianCategoryContainer) {
3784
                        if ($_bayesianCategoryContainer['categorytype'] == SWIFT_BayesianCategory::CATEGORY_SPAM) {
3785
                                $_bayesCategoryID = $_bayesianCategoryContainer['bayescategoryid'];
3786
3787
                                break;
3788
                        }
3789
                }
3790
3791
                if (!$_bayesCategoryID) {
3792
                        throw new SWIFT_Ticket_Exception('Spam Bayesian Category not found');
3793
                }
3794
3795
                $_ticketObjectContainer = array();
3796
3797
                $_SWIFT->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickets WHERE ticketid IN (" . BuildIN($_ticketIDList) . ")");
3798
                while ($_SWIFT->Database->NextRecord()) {
3799
                        $_ticketObjectContainer[$_SWIFT->Database->Record['ticketid']] = new SWIFT_Ticket(new SWIFT_DataStore($_SWIFT->Database->Record));
3800
                }
3801
3802
                foreach ($_ticketObjectContainer as $_ticketID => $_SWIFT_TicketObject) {
3803
                        $_ticketPostContainer = $_SWIFT_TicketObject->GetTicketPosts(0, false, 'ASC', SWIFT_Ticket::CREATOR_CLIENT);
3804
                        if (!_is_array($_ticketPostContainer)) {
3805
                                continue;
3806
                        }
3807
3808
                        $_finalTicketPostText = $_SWIFT_TicketObject->GetProperty('subject');
3809
                        foreach ($_ticketPostContainer as $_ticketPostID => $_SWIFT_TicketPostObject) {
3810
                                $_finalTicketPostText .= $_SWIFT_TicketPostObject->GetProperty('contents') . SWIFT_CRLF;
3811
                        }
3812
3813
                        $_SWIFT_BayesianObject->Train($_ticketID, $_bayesCategoryID, $_finalTicketPostText);
3814
                }
3815
3816
                if ($_SWIFT->Settings->Get('t_spammovetotrash') == '1') {
3817
                        self::TrashList($_ticketIDList);
3818
                }
3819
3820
                if ($_SWIFT->Settings->Get('t_spamban') == '1') {
3821
                        self::BanList($_ticketIDList, $_SWIFT->Staff->GetStaffID());
3822
                }
3823
3824
                return true;
3825
        }
3826
3827
        /**
3828
         * Watch a ticket list
3829
         *
3830
         * @author Varun Shoor
3831
         * @param array $_ticketIDList The Ticket ID List
3832
         * @return bool "true" on Success, "false" otherwise
3833
         * @throws SWIFT_Ticket_Exception If Invalid Data is Provided
3834
         */
3835
        static public function Watch($_ticketIDList, SWIFT_Staff $_SWIFT_StaffObject) {
3836
                $_SWIFT = SWIFT::GetInstance();
3837
3838
                if (!$_SWIFT_StaffObject instanceof SWIFT_Staff || !$_SWIFT_StaffObject->GetIsClassLoaded()) {
3839
                        throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
3840
                } else if (!_is_array($_ticketIDList)) {
3841
                        return false;
3842
                }
3843
3844
                $_ticketObjectContainer = array();
3845
                $_SWIFT->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickets WHERE ticketid IN (" . BuildIN($_ticketIDList) . ")");
3846
                while ($_SWIFT->Database->NextRecord()) {
3847
                        $_ticketObjectContainer[$_SWIFT->Database->Record['ticketid']] = new SWIFT_Ticket(new SWIFT_DataStore($_SWIFT->Database->Record));
3848
                }
3849
3850
                if (!count($_ticketObjectContainer)) {
3851
                        return false;
3852
                }
3853
3854
                foreach ($_ticketObjectContainer as $_ticketID => $_SWIFT_TicketObject) {
3855
                        // Create Audit Log
3856
                        SWIFT_TicketAuditLog::AddToLog($_SWIFT_TicketObject, null, SWIFT_TicketAuditLog::ACTION_WATCH,
3857
                                sprintf($_SWIFT->Language->Get('al_watch'), $_SWIFT_TicketObject->GetTicketDisplayID(), $_SWIFT_StaffObject->GetProperty('fullname')),
3858
                                SWIFT_TicketAuditLog::VALUE_NONE, 0, '', 0, '');
3859
3860
                        SWIFT_TicketWatcher::Create($_SWIFT_TicketObject, $_SWIFT_StaffObject);
3861
                }
3862
3863
                return true;
3864
        }
3865
3866
        /**
3867
         * Unwatch a ticket list
3868
         *
3869
         * @author Varun Shoor
3870
         * @param array $_ticketIDList The Ticket ID List
3871
         * @return bool "true" on Success, "false" otherwise
3872
         * @throws SWIFT_Ticket_Exception If Invalid Data is Provided
3873
         */
3874
        static public function UnWatch($_ticketIDList, SWIFT_Staff $_SWIFT_StaffObject) {
3875
                $_SWIFT = SWIFT::GetInstance();
3876
3877
                if (!$_SWIFT_StaffObject instanceof SWIFT_Staff || !$_SWIFT_StaffObject->GetIsClassLoaded()) {
3878
                        throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
3879
                } else if (!_is_array($_ticketIDList)) {
3880
                        return false;
3881
                }
3882
3883
                SWIFT_TicketWatcher::DeleteOnTicket($_ticketIDList, array($_SWIFT_StaffObject->GetStaffID()));
3884
3885
                return true;
3886
        }
3887
3888
        /**
3889
         * Add the object to the active workflow queue
3890
         *
3891
         * @author Varun Shoor
3892
         * @param SWIFT_Ticket $_SWIFT_TicketObject The SWIFT_Ticket Object Pointer
3893
         * @return bool "true" on Success, "false" otherwise
3894
         * @throws SWIFT_Ticket_Exception If Invalid Data is Provided
3895
         */
3896
        static public function AddToWorkflowQueue(SWIFT_Ticket $_SWIFT_TicketObject) {
3897
                $_SWIFT = SWIFT::GetInstance();
3898
3899
                if (!$_SWIFT_TicketObject instanceof SWIFT_Ticket || !$_SWIFT_TicketObject->GetIsClassLoaded()) {
3900
                        throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
3901
                } else if (isset(self::$_workflowQueue[$_SWIFT_TicketObject->GetTicketID()])) {
3902
                        return true;
3903
                }
3904
3905
                self::$_workflowQueue[$_SWIFT_TicketObject->GetTicketID()] = $_SWIFT_TicketObject;
3906
3907
                if (self::$_isWorkflowQueueActive) {
3908
                        return true;
3909
                }
3910
3911
                self::$_isWorkflowQueueActive = true;
3912
3913
                SWIFT::Shutdown('SWIFT_Ticket', 'ProcessWorkflowQueue', 9, false);
3914
3915
                return true;
3916
        }
3917
3918
        /**
3919
         * Process the workflow queue for each active ticket
3920
         *
3921
         * @author Varun Shoor
3922
         * @return bool "true" on Success, "false" otherwise
3923
         * @throws SWIFT_Ticket_Exception If Invalid Data is Provided
3924
         */
3925
        static public function ProcessWorkflowQueue() {
3926
                $_SWIFT = SWIFT::GetInstance();
3927
3928
                if (!count(self::$_workflowQueue)) {
3929
                        return true;
3930
                }
3931
3932
                $_ticketWorkflowIDContainer = $_ticketObjectContainer = $_ticketIDList = array();
3933
3934
                foreach (self::$_workflowQueue as $_ticketID => $_SWIFT_TicketObject) {
3935
                        $_ticketWorkflowIDList = SWIFT_TicketWorkflow::ExecuteAll($_SWIFT_TicketObject);
3936
                        $_ticketWorkflowIDContainer[$_SWIFT_TicketObject->GetTicketID()] = $_ticketWorkflowIDList;
3937
                        $_ticketObjectContainer[$_SWIFT_TicketObject->GetTicketID()] = $_SWIFT_TicketObject;
3938
3939
                        $_ticketIDList[] = $_SWIFT_TicketObject->GetTicketID();
3940
                }
3941
3942
                if (!count($_ticketWorkflowIDContainer)) {
3943
                        self::$_workflowQueue = array();
3944
                        self::$_isWorkflowQueueActive = false;
3945
3946
                        return false;
3947
                }
3948
3949
                SWIFT_TicketLinkedTable::DeleteOnTicket($_ticketIDList, SWIFT_TicketLinkedTable::LINKTYPE_WORKFLOW);
3950
3951
                foreach ($_ticketWorkflowIDContainer as $_ticketID => $_ticketWorkflowIDList) {
3952
                        if (!isset($_ticketObjectContainer[$_ticketID])) {
3953
                                throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
3954
                        }
3955
3956
                        $_SWIFT_TicketObject = $_ticketObjectContainer[$_ticketID];
3957
                        // Add the workflows to the ticket
3958
                        if (_is_array($_ticketWorkflowIDList)) {
3959
                                $_ticketLinkContainer = array();
3960
                                $_ticketLinkContainer[SWIFT_TicketLinkedTable::LINKTYPE_WORKFLOW] = $_ticketWorkflowIDList;
3961
3962
                                SWIFT_TicketLinkedTable::CreateIfNotExists($_SWIFT_TicketObject, $_ticketLinkContainer);
3963
                        }
3964
                }
3965
3966
                self::$_workflowQueue = array();
3967
                self::$_isWorkflowQueueActive = false;
3968
3969
                return true;
3970
        }
3971
3972
        /**
3973
         * Processes the POST attachment field (ticketattachments) and adds the attachments to the ticket
3974
         *
3975
         * @author Varun Shoor
3976
         * @param SWIFT_TicketPost $_SWIFT_TicketPostObject (OPTIONAL) The Ticket Post Object
3977
         * @param string $_fieldName (OPTIONAL) The Custom Field Name
3978
         * @return bool "true" on Success, "false" otherwise
3979
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded or If Invalid Data is Provided
3980
         */
3981
        public function ProcessPostAttachments(SWIFT_TicketPost $_SWIFT_TicketPostObject = null, $_fieldName = '') {
3982
                if (!$this->GetIsClassLoaded()) {
3983
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
3984
3985
                        return false;
3986
                }
3987
3988
                $_finalFieldName = 'ticketattachments';
3989
                if (!empty($_fieldName))
3990
                {
3991
                        $_finalFieldName = $_fieldName;
3992
                }
3993
3994
                $_listFieldName = $_finalFieldName . 'list';
3995
3996
                // Link with first post if none specified
3997
                if ($_SWIFT_TicketPostObject == null) {
3998
                        $_SWIFT_TicketPostObject = new SWIFT_TicketPost(new SWIFT_DataID($this->GetProperty('firstpostid')));
3999
                }
4000
4001
                if (!$_SWIFT_TicketPostObject instanceof SWIFT_TicketPost || !$_SWIFT_TicketPostObject->GetIsClassLoaded()) {
4002
                        throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
4003
                }
4004
4005
                $_attachmentCount = 0;
4006
4007
                if (isset($_POST[$_listFieldName]) && _is_array($_POST[$_listFieldName]))
4008
                {
4009
                        foreach ($_POST[$_listFieldName] as $_attachmentID)
4010
                        {
4011
                                $_SWIFT_AttachmentObject = new SWIFT_Attachment($_attachmentID);
4012
4013
                                SWIFT_Attachment::CloneOnTicket($this, $_SWIFT_TicketPostObject, $_SWIFT_AttachmentObject);
4014
4015
                                $this->AddToNotificationAttachments($_SWIFT_AttachmentObject->GetProperty('filename'), $_SWIFT_AttachmentObject->GetProperty('filetype'),
4016
                                                $_SWIFT_AttachmentObject->Get());
4017
4018
                                $_attachmentCount++;
4019
4020
                        }
4021
4022
                        if ($_attachmentCount > 0) {
4023
                                $this->UpdatePool('hasattachments', '1');
4024
                        }
4025
4026
                        unset($_POST[$_listFieldName]);
4027
                }
4028
4029
                if (!isset($_FILES[$_finalFieldName]) || !_is_array($_FILES[$_finalFieldName]) || !_is_array($_FILES[$_finalFieldName]['name'])) {
4030
                        return false;
4031
                }
4032
4033
                // Create the attachments
4034
                foreach ($_FILES[$_finalFieldName]['name'] as $_fileIndex => $_fileName) {
4035
                        if (empty($_fileName) || empty($_FILES[$_finalFieldName]['type'][$_fileIndex]) || empty($_FILES[$_finalFieldName]['size'][$_fileIndex]) ||
4036
                                        !is_uploaded_file($_FILES[$_finalFieldName]['tmp_name'][$_fileIndex]))
4037
                        {
4038
                                continue;
4039
                        }
4040
4041
                        $_SWIFT_AttachmentStoreObject = new SWIFT_AttachmentStoreFile($_FILES[$_finalFieldName]['tmp_name'][$_fileIndex],
4042
                                        $_FILES[$_finalFieldName]['type'][$_fileIndex], $_fileName);
4043
4044
                        $_SWIFT_AttachmentObject = SWIFT_Attachment::CreateOnTicket($this, $_SWIFT_TicketPostObject, $_SWIFT_AttachmentStoreObject);
4045
4046
                        $this->AddToNotificationAttachments($_fileName, $_FILES[$_finalFieldName]['type'][$_fileIndex], file_get_contents($_FILES[$_finalFieldName]['tmp_name'][$_fileIndex]));
4047
4048
                        $_attachmentCount++;
4049
                }
4050
4051
                if ($_attachmentCount > 0) {
4052
                        $this->UpdatePool('hasattachments', '1');
4053
                }
4054
4055
                return true;
4056
        }
4057
4058
        /**
4059
         * Checks for valid input for attachments
4060
         *
4061
         * @author Varun Shoor
4062
         * @param string $_inputType The Input Type (staff/supportcenter/parser)
4063
         * @return array (result - bool, invalid file list)
4064
         * @throws SWIFT_Ticket_Exception If Invalid Data is Provided
4065
         */
4066
        static public function CheckForValidAttachments($_inputType) {
4067
                $_SWIFT = SWIFT::GetInstance();
4068
4069
                // Always accept staff input
4070
                if ($_inputType == 'staff') {
4071
                        return true;
4072
                }
4073
4074
                // If its coming from support center and we cant find anything then return true
4075
                if ($_inputType == 'supportcenter' && (!isset($_FILES['ticketattachments']) || !_is_array($_FILES['ticketattachments']) || !_is_array($_FILES['ticketattachments']['name']))) {
4076
                        return true;
4077
                }
4078
4079
                $_fileTypeCache = $_SWIFT->Cache->Get('filetypecache');
4080
                $_fileTypeCacheMap = array();
4081
4082
                // Do we need to sanitize the data?
4083
                if ($_SWIFT->Settings->Get('tickets_resattachments') == '0') {
4084
                        return true;
4085
                }
4086
4087
                // Sanitize the data.. do we need to sanitize the data?
4088
                foreach ($_fileTypeCache as $_ticketFileTypeID => $_ticketFileTypeContainer) {
4089
                        $_fileTypeCacheMap[mb_strtolower($_ticketFileTypeContainer['extension'])] = $_ticketFileTypeContainer;
4090
                }
4091
4092
                $_resultArray = array();
4093
                $_result = true;
4094
4095
                // Check the attachments
4096
                foreach ($_FILES['ticketattachments']['name'] as $_fileIndex => $_fileName) {
4097
                        $_fileExtension = mb_strtolower(substr($_fileName, (strrpos($_fileName, '.')+1)));
4098
4099
                        // Extension isnt added in the list? || Check whether we can accept it from support center? || Invalid File Size?
4100
                        if (!isset($_fileTypeCacheMap[$_fileExtension]) ||
4101
                                        ($_inputType == 'supportcenter' && $_fileTypeCacheMap[$_fileExtension]['acceptsupportcenter'] == '0') ||
4102
                                        ($_inputType == 'parser' && $_fileTypeCacheMap[$_fileExtension]['acceptmailparser'] == '0') ||
4103
                                        ($_fileTypeCacheMap[$_fileExtension]['maxsize'] != '0' && ($_FILES['ticketattachments']['size'][$_fileIndex]/1024) >= $_fileTypeCacheMap[$_fileExtension]['maxsize']))
4104
                        {
4105
                                $_result = false;
4106
                                $_resultArray[] = $_fileName;
4107
                        }
4108
                }
4109
4110
                return array($_result, $_resultArray);
4111
        }
4112
4113
        /**
4114
         * Retrieve the ticket attachment container
4115
         *
4116
         * @author Varun Shoor
4117
         * @return array $_ticketAttachmentContainer
4118
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
4119
         */
4120
        public function GetAttachmentContainer() {
4121
                if (!$this->GetIsClassLoaded()) {
4122
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
4123
4124
                        return false;
4125
                }
4126
4127
                $_ticketAttachmentContainer = array();
4128
4129
                $this->Database->Query("SELECT * FROM " . TABLE_PREFIX . "attachments WHERE ticketid = '" . intval($this->GetTicketID()) . "'");
4130
                while ($this->Database->NextRecord()) {
4131
                        $_ticketAttachmentContainer[$this->Database->Record['linktypeid']][$this->Database->Record['attachmentid']] = $this->Database->Record;
4132
                }
4133
4134
                return $_ticketAttachmentContainer;
4135
        }
4136
4137
        /**
4138
         * Retrieve the history count for this user based on his userid & email address
4139
         *
4140
         * @author Varun Shoor
4141
         * @return int The History Count
4142
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
4143
         */
4144
        public function GetHistoryCount() {
4145
                if (!$this->GetIsClassLoaded()) {
4146
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
4147
4148
                        return false;
4149
                }
4150
4151
                $_userID = '-1';
4152
                if ($this->GetProperty('userid') != '0')
4153
                {
4154
                        $_userID = intval($this->GetProperty('userid'));
4155
                }
4156
4157
                $_countContainer = $this->Database->QueryFetch("SELECT COUNT(*) AS totalitems FROM " . TABLE_PREFIX . "tickets WHERE userid = '" .
4158
                                intval($_userID) . "' OR email = '" . $this->Database->Escape($this->GetProperty('email')) . "'");
4159
4160
                if (isset($_countContainer['totalitems']) && intval($_countContainer['totalitems']) > 0) {
4161
                        return $_countContainer['totalitems'] - 1;
4162
                }
4163
4164
                return 0;
4165
        }
4166
4167
        /**
4168
         * Retrieve the history for this ticket
4169
         *
4170
         * @author Varun Shoor
4171
         * @return array The History Container
4172
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
4173
         */
4174
        public function RetrieveHistory() {
4175
                if (!$this->GetIsClassLoaded()) {
4176
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
4177
4178
                        return false;
4179
                }
4180
4181
                $_historyContainer = array();
4182
4183
                $_sqlExtend = '';
4184
                if ($this->GetProperty('userid') != '0')
4185
                {
4186
                        $_sqlExtend = " OR userid = '" . intval($this->GetProperty('userid')) . "'";
4187
                }
4188
4189
                $this->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickets WHERE email = '" . $this->Database->Escape($this->GetProperty('email')) . "'" . $_sqlExtend . " ORDER BY dateline DESC");
4190
                while ($this->Database->NextRecord()) {
4191
                        $_historyContainer[$this->Database->Record['ticketid']] = new SWIFT_Ticket(new SWIFT_DataStore($this->Database->Record));
4192
                }
4193
4194
                return $_historyContainer;
4195
        }
4196
4197
        /**
4198
         * Retrieve the relevant user object
4199
         *
4200
         * @author Varun Shoor
4201
         * @return mixed "SWIFT_User" (OBJECT) on Success, "false" otherwise
4202
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
4203
         */
4204
        public function GetUserObject() {
4205
                if (!$this->GetIsClassLoaded()) {
4206
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
4207
4208
                        return false;
4209
                }
4210
4211
                // Have we already cached the user object?
4212
                if ($this->_isUserObjectCached == true) {
4213
                        return $this->_UserObject;
4214
                }
4215
4216
                $_SWIFT_UserObject = false;
4217
                if ($this->GetProperty('userid') != '0') {
4218
                        try {
4219
                                $_SWIFT_UserObject = new SWIFT_User(new SWIFT_DataID($this->GetProperty('userid')));
4220
                        } catch (SWIFT_Exception $_SWIFT_ExceptionObject) {
4221
4222
                                return false;
4223
                        }
4224
                }
4225
4226
                $this->_UserObject = $_SWIFT_UserObject;
4227
                $this->_isUserObjectCached = true;
4228
4229
                return $_SWIFT_UserObject;
4230
        }
4231
4232
        /**
4233
         * Retrieve the relevant user group object
4234
         *
4235
         * @author Varun Shoor
4236
         * @return mixed "SWIFT_UserGroup" (OBJECT) on Success, "false" otherwise
4237
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
4238
         */
4239
        public function GetUserGroupObject() {
4240
                if (!$this->GetIsClassLoaded()) {
4241
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
4242
4243
                        return false;
4244
                }
4245
4246
                // Have we already cached the user object?
4247
                if ($this->_isUserGroupObjectCached == true) {
4248
                        return $this->_UserGroupObject;
4249
                }
4250
4251
                $_SWIFT_UserObject = $this->GetUserObject();
4252
                $_SWIFT_UserGroupObject = false;
4253
4254
                if ($_SWIFT_UserObject instanceof SWIFT_User && $_SWIFT_UserObject->GetIsClassLoaded())
4255
                {
4256
                        try {
4257
                                $_SWIFT_UserGroupObject = new SWIFT_UserGroup($_SWIFT_UserObject->GetProperty('usergroupid'));
4258
                        } catch (SWIFT_Exception $_SWIFT_ExceptionObject) {
4259
4260
                                return false;
4261
                        }
4262
                }
4263
4264
                $this->_UserGroupObject = $_SWIFT_UserGroupObject;
4265
                $this->_isUserGroupObjectCached = true;
4266
4267
                return $_SWIFT_UserGroupObject;
4268
        }
4269
4270
        /**
4271
         * Retrieve the user organization object associated with this ticket
4272
         *
4273
         * @author Varun Shoor
4274
         * @return mixed "SWIFT_UserOrganization" (OBJECT) on Success, "false" otherwise
4275
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
4276
         */
4277
        public function GetUserOrganizationObject() {
4278
                if (!$this->GetIsClassLoaded()) {
4279
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
4280
4281
                        return false;
4282
                }
4283
4284
                // Have we already cached the user organization object?
4285
                if ($this->_isUserOrganizationObjectCached == true) {
4286
                        return $this->_UserOrganizationObject;
4287
                }
4288
4289
                $_SWIFT_UserOrganizationObject = false;
4290
4291
                $_SWIFT_UserObject = $this->GetUserobject();
4292
4293
                if ($_SWIFT_UserObject instanceof SWIFT_User && $_SWIFT_UserObject->GetIsClassLoaded() &&
4294
                                $_SWIFT_UserObject->GetProperty('userorganizationid') != '0')
4295
                {
4296
                        try
4297
                        {
4298
                                $_SWIFT_UserOrganizationObject = new SWIFT_UserOrganization($_SWIFT_UserObject->GetProperty('userorganizationid'));
4299
                        } catch (SWIFT_Exception $_SWIFT_ExceptionObject) {
4300
4301
                        }
4302
                }
4303
4304
                $this->_UserOrganizationObject = $_SWIFT_UserOrganizationObject;
4305
                $this->_isUserOrganizationObjectCached = true;
4306
4307
                return $_SWIFT_UserOrganizationObject;
4308
        }
4309
4310
        /**
4311
         * Get the relevant mail subject based on mail type
4312
         *
4313
         * @author Varun Shoor
4314
         * @param constant $_mailType The Mail Type
4315
         * @param string $_customSubject (OPTIONAL) The Custom Subject
4316
         * @return mixed "Mail Subject" on Success, "false" otherwise
4317
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
4318
         */
4319
        public function GetMailSubject($_mailType, $_customSubject = '') {
4320
                $_SWIFT = SWIFT::GetInstance();
4321
4322
                if (!$this->GetIsClassLoaded()) {
4323
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
4324
4325
                        return false;
4326
                }
4327
4328
                $_emailQueueCache = $_SWIFT->Cache->Get('queuecache');
4329
                $_emailQueueID = $this->GetProperty('emailqueueid');
4330
                $_templateGroupID = $this->GetProperty('tgroupid');
4331
4332
                /*
4333
                 * BUG FIX - Varun Shoor
4334
                 *
4335
                 * SWIFT-1327 From name and From email address improvements in autoresponder email, if visitor sends an offline message and help desk create the ticket
4336
                 * SWIFT-1651 From Email Address (in autoresponder email) should set according to the template group under email queue, if ticket is created from client support center in case of multi-domain installation
4337
                 *
4338
                 * Comments: None
4339
                 */
4340
4341
                // First try to load up the email queue based on template group & department match
4342
                if (empty($_emailQueueID) && isset($_emailQueueCache['list']) && _is_array($_emailQueueCache['list']))
4343
                {
4344
                        foreach ($_emailQueueCache['list'] as $_emailQueueContainer)
4345
                        {
4346
                                if ($_emailQueueContainer['departmentid'] == $this->GetProperty('departmentid') && $_emailQueueContainer['tgroupid'] == $_templateGroupID)
4347
                                {
4348
                                        $_emailQueueID = $_emailQueueContainer['emailqueueid'];
4349
4350
                                        break;
4351
                                }
4352
                        }
4353
                }
4354
4355
                // No Queue Prefix set, itterate through queues looking for one for ONLY this department
4356
                if (empty($_emailQueueID) && isset($_emailQueueCache['list']) && _is_array($_emailQueueCache['list']))
4357
                {
4358
                        foreach ($_emailQueueCache['list'] as $_emailQueueContainer)
4359
                        {
4360
                                if ($_emailQueueContainer['departmentid'] == $this->GetProperty('departmentid'))
4361
                                {
4362
                                        $_emailQueueID = $_emailQueueContainer['emailqueueid'];
4363
4364
                                        break;
4365
                                }
4366
                        }
4367
                }
4368
4369
                $_subjectPrefix = $_finalSubjectPrefix = '';
4370
                if (isset($_emailQueueCache['list'][$_emailQueueID]))
4371
                {
4372
                        $_emailQueueContainer = $_emailQueueCache['list'][$_emailQueueID];
4373
4374
                        $_subjectPrefix = $_emailQueueContainer['prefix'];
4375
                }
4376
4377
                if (!empty($_subjectPrefix))
4378
                {
4379
                        $_finalSubjectPrefix = $_subjectPrefix . ' ';
4380
                }
4381
4382
                $_finalSubject = $this->GetProperty('subject');
4383
                if (!empty($_customSubject)) {
4384
                        $_finalSubject = $_customSubject;
4385
                }
4386
4387
                if ($this->Settings->Get('t_cleanmailsubjects') == '1') {
4388
                        return $_finalSubject;
4389
                }
4390
4391
                switch ($_mailType) {
4392
                        case self::MAIL_NOTIFICATION:
4393
                                return '[' . $_finalSubjectPrefix . '!' . $this->GetTicketDisplayID() . ']: ' . $_finalSubject;
4394
                                break;
4395
4396
                        case self::MAIL_CLIENT:
4397
                                return '[' . $_finalSubjectPrefix . '#' . $this->GetTicketDisplayID() . ']: ' . $_finalSubject;
4398
                                break;
4399
4400
                        case self::MAIL_THIRDPARTY:
4401
                                return '[' . $_finalSubjectPrefix . '~' . $this->GetTicketDisplayID() . ']: ' . $_finalSubject;
4402
                                break;
4403
4404
                        default:
4405
                                break;
4406
                }
4407
4408
                return false;
4409
        }
4410
4411
        /**
4412
         * Retrieve the default from name for the email
4413
         *
4414
         * @author Varun Shoor
4415
         * @param SWIFT_Staff $_SWIFT_StaffObject (OPTIONAL) The SWIFT_Staff Object Pointer
4416
         * @return string The Default From Name
4417
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
4418
         */
4419
        public function GetMailFromName(SWIFT_Staff $_SWIFT_StaffObject = null)
4420
        {
4421
                $_SWIFT = SWIFT::GetInstance();
4422
4423
                if (!$this->GetIsClassLoaded())
4424
                {
4425
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
4426
4427
                        return false;
4428
                }
4429
4430
                $_emailQueueCache = $_SWIFT->Cache->Get('queuecache');
4431
                $_emailQueueID = $this->GetProperty('emailqueueid');
4432
                $_templateGroupID = $this->GetProperty('tgroupid');
4433
                if (empty($_templateGroupID) && isset($_SWIFT->TemplateGroup) && $_SWIFT->TemplateGroup instanceof SWIFT_TemplateGroup) {
4434
            $_templateGroupID = $_SWIFT->TemplateGroup->GetTemplateGroupID();
4435
        }
4436
4437
4438
                /*
4439
                 * BUG FIX - Varun Shoor
4440
                 *
4441
                 * SWIFT-1327 From name and From email address improvements in autoresponder email, if visitor sends an offline message and help desk create the ticket
4442
                 * SWIFT-1651 From Email Address (in autoresponder email) should set according to the template group under email queue, if ticket is created from client support center in case of multi-domain installation
4443
                 *
4444
                 * Comments: None
4445
                 */
4446
4447
                // First try to lookup based on department and template group
4448
                if (empty($_emailQueueID) && isset($_emailQueueCache['list']) && _is_array($_emailQueueCache['list']))
4449
                {
4450
                        foreach ($_emailQueueCache['list'] as $_emailQueueContainer)
4451
                        {
4452
                                if ($_emailQueueContainer['departmentid'] == $this->GetProperty('departmentid') && $_emailQueueContainer['tgroupid'] == $_templateGroupID)
4453
                                {
4454
                                        $_emailQueueID = $_emailQueueContainer['emailqueueid'];
4455
4456
                                        break;
4457
                                }
4458
                        }
4459
                }
4460
4461
                // No Queue Prefix set, itterate through queues looking for one for ONLY this department
4462
                if (empty($_emailQueueID) && isset($_emailQueueCache['list']) && _is_array($_emailQueueCache['list']))
4463
                {
4464
                        foreach ($_emailQueueCache['list'] as $_emailQueueContainer)
4465
                        {
4466
                                if ($_emailQueueContainer['departmentid'] == $this->GetProperty('departmentid'))
4467
                                {
4468
                                        $_emailQueueID = $_emailQueueContainer['emailqueueid'];
4469
4470
                                        break;
4471
                                }
4472
                        }
4473
                }
4474
4475
                // Name Priority: Template Group > Settings > Staff > Email Queue
4476
4477
                $_defaultFromName = SWIFT::Get('companyname');
4478
                if (empty($_defaultFromName))
4479
                {
4480
                        $_defaultFromName = $this->Settings->Get('general_companyname');
4481
                }
4482
4483
                if ($_SWIFT_StaffObject instanceof SWIFT_Staff && $_SWIFT_StaffObject->GetIsClassLoaded())
4484
                {
4485
                        $_defaultFromName = $_SWIFT_StaffObject->GetProperty('fullname');
4486
                }
4487
4488
                if (isset($_emailQueueCache['list'][$_emailQueueID]))
4489
                {
4490
                        $_emailQueueContainer = $_emailQueueCache['list'][$_emailQueueID];
4491
4492
                        if (!empty($_emailQueueContainer['customfromname']))
4493
                        {
4494
                                $_defaultFromName = $_emailQueueContainer['customfromname'];
4495
                        }
4496
                }
4497
4498
                return $_defaultFromName;
4499
        }
4500
4501
        /**
4502
         * Retrieve the default from email
4503
         *
4504
         * @author Varun Shoor
4505
         * @return string The Default Return Email
4506
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
4507
         */
4508
        public function GetMailFromEmail()
4509
        {
4510
                $_SWIFT = SWIFT::GetInstance();
4511
4512
                if (!$this->GetIsClassLoaded())
4513
                {
4514
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
4515
4516
                        return false;
4517
                }
4518
4519
                $_emailQueueCache = $_SWIFT->Cache->Get('queuecache');
4520
                $_emailQueueID = $this->GetProperty('emailqueueid');
4521
                $_templateGroupID = $this->GetProperty('tgroupid');
4522
                if (empty($_templateGroupID) && isset($_SWIFT->TemplateGroup) && $_SWIFT->TemplateGroup instanceof SWIFT_TemplateGroup) {
4523
            $_templateGroupID = $_SWIFT->TemplateGroup->GetTemplateGroupID();
4524
        }
4525
4526
                /*
4527
                 * BUG FIX - Varun Shoor
4528
                 *
4529
                 * SWIFT-1327 From name and From email address improvements in autoresponder email, if visitor sends an offline message and help desk create the ticket
4530
                 * SWIFT-1651 From Email Address (in autoresponder email) should set according to the template group under email queue, if ticket is created from client support center in case of multi-domain installation
4531
                 *
4532
                 * Comments: None
4533
                 */
4534
4535
                // First check against the template group id and department id
4536
                if (empty($_emailQueueID) && isset($_emailQueueCache['list']) && _is_array($_emailQueueCache['list']))
4537
                {
4538
                        foreach ($_emailQueueCache['list'] as $_emailQueueContainer)
4539
                        {
4540
                                if ($_emailQueueContainer['departmentid'] == $this->GetProperty('departmentid') && $_templateGroupID == $_emailQueueContainer['tgroupid'])
4541
                                {
4542
                                        $_emailQueueID = $_emailQueueContainer['emailqueueid'];
4543
4544
                                        break;
4545
                                }
4546
                        }
4547
                }
4548
4549
                // No Queue Prefix set, itterate through queues looking for one for ONLY this department
4550
                if (empty($_emailQueueID) && isset($_emailQueueCache['list']) && _is_array($_emailQueueCache['list']))
4551
                {
4552
                        foreach ($_emailQueueCache['list'] as $_emailQueueContainer)
4553
                        {
4554
                                if ($_emailQueueContainer['departmentid'] == $this->GetProperty('departmentid'))
4555
                                {
4556
                                        $_emailQueueID = $_emailQueueContainer['emailqueueid'];
4557
4558
                                        break;
4559
                                }
4560
                        }
4561
                }
4562
4563
                // Email Priority: Settings > Email Queue
4564
                $_defaultFromEmail = $this->Settings->Get('general_returnemail');
4565
4566
                if (isset($_emailQueueCache['list'][$_emailQueueID]))
4567
                {
4568
                        $_emailQueueContainer = $_emailQueueCache['list'][$_emailQueueID];
4569
                        if (!empty($_emailQueueContainer['customfromemail']))
4570
                        {
4571
                                $_defaultFromEmail = $_emailQueueContainer['customfromemail'];
4572
                        } else {
4573
                                $_defaultFromEmail = $_emailQueueContainer['email'];
4574
                        }
4575
                }
4576
4577
                return $_defaultFromEmail;
4578
        }
4579
4580
        /**
4581
         * Load the Core Language Table
4582
         *
4583
         * @author Varun Shoor
4584
         * @return bool "true" on Success, "false" otherwise
4585
         */
4586
        static public function LoadLanguageTable() {
4587
                $_SWIFT = SWIFT::GetInstance();
4588
4589
                $_SWIFT->Language->Load('tickets_notifications', SWIFT_LanguageEngine::TYPE_FILE);
4590
                $_SWIFT->Language->Load('tickets_auditlogs', SWIFT_LanguageEngine::TYPE_FILE);
4591
4592
                return true;
4593
        }
4594
4595
        /**
4596
         * Retrieve the signature for this based on associated queue or given staff/user
4597
         *
4598
         * @author Varun Shoor
4599
         * @param bool $_isHTML Whether the reply is HTML
4600
         * @param object $_SWIFT_StaffObject (OPTIONAL) The SWIFT_Staff Object
4601
         * @return bool "true" on Success, "false" otherwise
4602
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
4603
         */
4604
        public function GetSignature($_isHTML, $_SWIFT_StaffObject = null)
4605
        {
4606
                $_SWIFT = SWIFT::GetInstance();
4607
4608
                if (!$this->GetIsClassLoaded())
4609
                {
4610
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
4611
4612
                        return false;
4613
                }
4614
4615
                $_emailQueueCache = $_SWIFT->Cache->Get('queuecache');
4616
4617
                $_emailQueueID = $this->GetProperty('emailqueueid');
4618
4619
                $_signatureContents = '';
4620
4621
                if ($_isHTML == true)
4622
                {
4623
                        $_signatureContents = '<br />';
4624
                } else {
4625
                        $_signatureContents = SWIFT_CRLF;
4626
                }
4627
4628
                // First priority is given to Staff signature
4629
                if ($_SWIFT_StaffObject instanceof SWIFT_Staff && $_SWIFT_StaffObject->GetIsClassLoaded())
4630
                {
4631
                        $_staffSignatureContents = '';
4632
                        try {
4633
                                $_staffSignatureContents = $_SWIFT_StaffObject->GetProperty('signature');
4634
                        } catch (SWIFT_Exception $_SWIFT_ExceptionObject) {
4635
                        }
4636
4637
                        if ($_isHTML == true)
4638
                        {
4639
                                $_signatureContents .= nl2br($_staffSignatureContents);
4640
                        } else {
4641
                                $_signatureContents .= preg_replace("#(\r\n|\r|\n)#s", SWIFT_CRLF, $_staffSignatureContents);
4642
                        }
4643
                }
4644
4645
                if (_is_array($_emailQueueCache) && isset($_emailQueueCache['list'][$_emailQueueID])) {
4646
                        $_emailQueueContainer = $_emailQueueCache['list'][$_emailQueueID];
4647
                        if ($_isHTML == true)
4648
                        {
4649
                                $_signatureContents .= nl2br($_emailQueueContainer['contents']);
4650
                        } else {
4651
                                $_signatureContents .= preg_replace("#(\r\n|\r|\n)#s", SWIFT_CRLF, $_emailQueueContainer['contents']);
4652
                        }
4653
                }
4654
4655
                return $_signatureContents;
4656
        }
4657
4658
        /**
4659
         * Dispatch the auto responder msg
4660
         *
4661
         * @author Varun Shoor
4662
         * @return bool "true" on Success, "false" otherwise
4663
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
4664
         */
4665
        public function DispatchAutoresponder()
4666
        {
4667
                if (!$this->GetIsClassLoaded())
4668
                {
4669
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
4670
4671
                        return false;
4672
                }
4673
4674
                // We dispatch the auto responder to ALL registered emails of the user
4675
                $_ccEmailList = $this->GetCCUserEmails();
4676
4677
                $this->Load->Library('Ticket:TicketEmailDispatch', array($this));
4678
                $this->TicketEmailDispatch->DispatchAutoresponder('', $_ccEmailList);
4679
4680
                return true;
4681
        }
4682
4683
        /**
4684
         * Retrieves all other emails of the user excluding the one that was used to create the ticket
4685
         *
4686
         * @author Varun Shoor
4687
         * @return array The Email List
4688
         * @throws SWIFT_Exception If the Class is not Loaded
4689
         */
4690
        public function GetCCUserEmails()
4691
        {
4692
                if (!$this->GetIsClassLoaded())
4693
                {
4694
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
4695
4696
                        return false;
4697
                }
4698
4699
                $_SWIFT_UserObject = $this->GetUserObject();
4700
4701
                $_ccEmailList = array();
4702
                if ($_SWIFT_UserObject instanceof SWIFT_User && $_SWIFT_UserObject->GetIsClassLoaded())
4703
                {
4704
                        $_userEmailList = $_SWIFT_UserObject->GetEmailList();
4705
                        if (_is_array($_userEmailList))
4706
                        {
4707
                                foreach ($_userEmailList as $_emailAddress)
4708
                                {
4709
                                        if (mb_strtolower($_emailAddress) != mb_strtolower($this->GetProperty('email')))
4710
                                        {
4711
                                                $_ccEmailList[] = $_emailAddress;
4712
                                        }
4713
                                }
4714
                        }
4715
                }
4716
4717
                return $_ccEmailList;
4718
        }
4719
4720
        /**
4721
         * Retrieve the first ticket post object
4722
         *
4723
         * @author Varun Shoor
4724
         * @return SWIFT_TicketPost The SWIFT_TicketPost Object
4725
         * @throws SWIFT_Exception If the Class is not Loaded or If Invalid Data is Provided
4726
         */
4727
        public function GetFirstPostObject()
4728
        {
4729
                if (!$this->GetIsClassLoaded())
4730
                {
4731
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
4732
4733
                        return false;
4734
                }
4735
4736
                $_SWIFT_TicketPostObject = new SWIFT_TicketPost(new SWIFT_DataID($this->GetProperty('firstpostid')));
4737
                if (!$_SWIFT_TicketPostObject instanceof SWIFT_TicketPost || !$_SWIFT_TicketPostObject->GetIsClassLoaded())
4738
                {
4739
                        throw new SWIFT_Exception(SWIFT_INVALIDDATA);
4740
                }
4741
4742
                return $_SWIFT_TicketPostObject;
4743
        }
4744
4745
        /**
4746
         * Retrieve the time tracking count for the ticket
4747
         *
4748
         * @author Varun Shoor
4749
         * @return int The Count
4750
         * @throws SWIFT_Exception If the Class is not Loaded
4751
         */
4752
        public function GetTimeTrackCount()
4753
        {
4754
                if (!$this->GetIsClassLoaded())
4755
                {
4756
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
4757
4758
                        return false;
4759
                }
4760
4761
                $_timeTrackCount = $this->Database->QueryFetch("SELECT COUNT(*) AS totalitems FROM " . TABLE_PREFIX . "tickettimetracks WHERE ticketid = '" . intval($this->GetTicketID()) . "'");
4762
                if (isset($_timeTrackCount['totalitems']))
4763
                {
4764
                        return intval($_timeTrackCount['totalitems']);
4765
                }
4766
4767
                return 0;
4768
        }
4769
4770
        /**
4771
         * Retrieve the list of all possible ticket ids created by a given user
4772
         *
4773
         * @author Varun Shoor
4774
         * @param SWIFT_User $_SWIFT_UserObject The SWIFT_User Object Pointer
4775
         * @return array The Ticket ID List
4776
         * @throws SWIFT_Exception If Invalid Data is Provided
4777
         */
4778
        static public function GetTicketIDListOnUser(SWIFT_User $_SWIFT_UserObject)
4779
        {
4780
                $_SWIFT = SWIFT::GetInstance();
4781
4782
                if (!$_SWIFT_UserObject instanceof SWIFT_User || !$_SWIFT_UserObject->GetIsClassLoaded())
4783
                {
4784
                        throw new SWIFT_Exception(SWIFT_INVALIDDATA);
4785
                }
4786
4787
                $_ticketIDList = array();
4788
4789
                $_SWIFT->Database->Query("SELECT ticketid FROM " . TABLE_PREFIX . "tickets WHERE userid = '" . intval($_SWIFT_UserObject->GetUserID()) . "' OR email IN (" . BuildIN($_SWIFT_UserObject->GetEmailList()) . ")");
4790
                while ($_SWIFT->Database->NextRecord())
4791
                {
4792
                        $_ticketIDList[] = intval($_SWIFT->Database->Record['ticketid']);
4793
                }
4794
4795
                return $_ticketIDList;
4796
        }
4797
4798
        /**
4799
         * Create a Note
4800
         *
4801
         * @author Varun Shoor
4802
         * @param SWIFT_User $_SWIFT_UserObject (OPTIONAL) The User Object
4803
         * @param string $_noteContents The Note Contents
4804
         * @param int $_noteColor The Note Color
4805
         * @param string $_noteType The Note Type
4806
         * @param int $_forStaffID (OPTIONAL) Restrict view to a given staff
4807
         * @param SWIFT_Staff $_SWIFT_StaffObject (OPTIONAL) The Staff Object to create note as
4808
         * @return bool "true" on Success, "false" otherwise
4809
         * @throws SWIFT_Exception If the Class is not Loaded
4810
         */
4811
        public function CreateNote($_SWIFT_UserObject, $_noteContents, $_noteColor, $_noteType, $_forStaffID = false, $_SWIFT_StaffObject = false) {
4812
                $_SWIFT = SWIFT::GetInstance();
4813
4814
                if (!$this->GetIsClassLoaded()) {
4815
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
4816
4817
                        return false;
4818
                }
4819
4820
                $_isOrganizationNote = false;
4821
                $_SWIFT_UserOrganizationObject = $this->GetUserOrganizationObject();
4822
4823
                if ($_SWIFT_UserOrganizationObject instanceof SWIFT_UserOrganization && $_SWIFT_UserOrganizationObject->GetIsClassLoaded() &&
4824
                                isset($_noteType) && $_noteType == 'userorganization')
4825
                {
4826
                        $_isOrganizationNote = true;
4827
                }
4828
4829
                // Add notes
4830
                if (!empty($_noteContents))
4831
                {
4832
                        if ($_isOrganizationNote)
4833
                        {
4834
                                SWIFT_UserOrganizationNote::Create($_SWIFT_UserOrganizationObject, $_noteContents, intval($_noteColor));
4835
4836
                                SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_NEWNOTE,
4837
                                        $_SWIFT->Language->Get('al_usernote'),
4838
                                        SWIFT_TicketAuditLog::VALUE_NONE, 0, '', 0, '');
4839
                        } else if ($_SWIFT_UserObject instanceof SWIFT_User && $_SWIFT_UserObject->GetIsClassLoaded() && isset($_noteType) && $_noteType == 'user') {
4840
                                SWIFT_UserNote::Create($_SWIFT_UserObject, $_noteContents, intval($_noteColor));
4841
4842
                                SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_NEWNOTE,
4843
                                        $_SWIFT->Language->Get('al_usernote'),
4844
                                        SWIFT_TicketAuditLog::VALUE_NONE, 0, '', 0, '');
4845
                        } else {
4846
4847
                                $_staffID = 0;
4848
                                $_staffName = $this->Language->Get('system');
4849
                                if ($_SWIFT_StaffObject instanceof SWIFT_Staff && $_SWIFT_StaffObject->GetIsClassLoaded()) {
4850
                                        $_staffID = $_SWIFT_StaffObject->GetStaffID();
4851
                                        $_staffName = $_SWIFT_StaffObject->GetProperty('fullname');
4852
                                } else if ($_SWIFT->Staff instanceof SWIFT_Staff && $_SWIFT->Staff->GetIsClassLoaded()) {
4853
                                        $_staffID = $_SWIFT->Staff->GetStaffID();
4854
                                        $_staffName = $_SWIFT->Staff->GetProperty('fullname');
4855
                                }
4856
4857
                                SWIFT_TicketNote::Create($this, intval($_forStaffID), $_staffID, $_staffName, $_noteContents, intval($_noteColor));
4858
4859
                                SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_NEWNOTE, $_SWIFT->Language->Get('al_ticketnote'), SWIFT_TicketAuditLog::VALUE_NONE, 0, '', 0, '');
4860
                        }
4861
4862
                        if ( $this->Settings->Get('t_ticketnoteresetsupdatetime') == 1 ) {
4863
                                $this->UpdatePool('lastactivity', DATENOW);
4864
                        }
4865
4866
                }
4867
4868
                return true;
4869
        }
4870
4871
        /**
4872
         * Retrieve the Ticket ID from a Ticket Mask ID
4873
         *
4874
         * @author Varun Shoor
4875
         * @param string $_ticketMaskID The Ticket Mask ID
4876
         * @return int The Ticket ID
4877
         * @throws SWIFT_Exception If Invalid Data is Provided
4878
         */
4879
        static public function GetTicketIDFromMask($_ticketMaskID)
4880
        {
4881
                $_SWIFT = SWIFT::GetInstance();
4882
4883
                if (empty($_ticketMaskID))
4884
                {
4885
                        throw new SWIFT_Exception(SWIFT_INVALIDDATA);
4886
                }
4887
4888
                $_ticketIDContainer = $_SWIFT->Database->QueryFetch("SELECT ticketid FROM " . TABLE_PREFIX . "tickets WHERE ticketmaskid = '" . $_SWIFT->Database->Escape($_ticketMaskID) . "'");
4889
                if (isset($_ticketIDContainer['ticketid']) &&  !empty($_ticketIDContainer['ticketid']))
4890
                {
4891
                        return $_ticketIDContainer['ticketid'];
4892
                }
4893
4894
                return false;
4895
        }
4896
4897
        /**
4898
         * Retrieve the history count for this user based on his userid & email addresses
4899
         *
4900
         * @author Varun Shoor
4901
         * @param SWIFT_User $_SWIFT_UserObject
4902
         * @param array $_userEmailList
4903
         * @return int The History Count
4904
         * @throws SWIFT_Ticket_Exception If Invalid Data is Provided
4905
         */
4906
        static public function GetHistoryCountOnUser($_SWIFT_UserObject, $_userEmailList = array()) {
4907
                $_SWIFT = SWIFT::GetInstance();
4908
4909
                $_userID = '-1';
4910
                if ($_SWIFT_UserObject instanceof SWIFT_User && $_SWIFT_UserObject->GetIsClassLoaded())
4911
                {
4912
                        $_userID = $_SWIFT_UserObject->GetUserID();
4913
                }
4914
4915
                if (!_is_array($_userEmailList))
4916
                {
4917
                        $_userEmailList = $_SWIFT_UserObject->GetEmailList();
4918
                }
4919
4920
                $_countContainer = $_SWIFT->Database->QueryFetch("SELECT COUNT(*) AS totalitems FROM " . TABLE_PREFIX . "tickets WHERE userid = '" .
4921
                                intval($_userID) . "' OR email IN (" . BuildIN($_userEmailList) . ")");
4922
4923
                if (isset($_countContainer['totalitems']) && intval($_countContainer['totalitems']) > 0) {
4924
                        return $_countContainer['totalitems'];
4925
                }
4926
4927
                return 0;
4928
        }
4929
4930
        /**
4931
         * Retrieve the history for this user
4932
         *
4933
         * @author Varun Shoor
4934
         * @param SWIFT_User $_SWIFT_UserObject
4935
         * @param array $_emailList The Email List
4936
         * @param string $_sortBy (OPTIONAL) The Custom Sort By
4937
         * @param string $_sortOrder (OPTIONAL) The Custom Sort Order
4938
         * @return array The History Container
4939
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
4940
         */
4941
        static public function RetrieveHistoryOnUser($_SWIFT_UserObject, $_emailList = array(), $_sortBy = false, $_sortOrder = false) {
4942
                $_SWIFT = SWIFT::GetInstance();
4943
4944
                $_userID = '-1';
4945
                $_userEmailList = $_emailList;
4946
                if ($_SWIFT_UserObject instanceof SWIFT_User && $_SWIFT_UserObject->GetIsClassLoaded())
4947
                {
4948
                        $_userID = $_SWIFT_UserObject->GetUserID();
4949
                        $_userEmailList = array_merge($_userEmailList, $_SWIFT_UserObject->GetEmailList());
4950
                }
4951
4952
                $_historyContainer = array();
4953
4954
                $_ticketSortBy = 'dateline';
4955
                $_ticketSortOrder = 'DESC';
4956
                if (!empty($_sortBy) && !empty($_sortOrder))
4957
                {
4958
                        $_ticketSortBy = $_sortBy;
4959
                        $_ticketSortOrder = $_sortOrder;
4960
                }
4961
4962
                $_SWIFT->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickets WHERE userid = '" . intval($_userID) .
4963
                                "' OR email IN (" . BuildIN($_userEmailList) . ") ORDER BY " . $_ticketSortBy . " " . $_ticketSortOrder);
4964
                while ($_SWIFT->Database->NextRecord()) {
4965
                        $_historyContainer[$_SWIFT->Database->Record['ticketid']] = new SWIFT_Ticket(new SWIFT_DataStore($_SWIFT->Database->Record));
4966
                }
4967
4968
                return $_historyContainer;
4969
        }
4970
4971
        /**
4972
         * Retrieve the Support Center Tickets for this user
4973
         *
4974
         * @author Varun Shoor
4975
         * @param SWIFT_User $_SWIFT_UserObject
4976
         * @param string $_sortBy (OPTIONAL) The Custom Sort By
4977
         * @param string $_sortOrder (OPTIONAL) The Custom Sort Order
4978
         * @param int $_offset (OPTIONAL) The Starting Offset
4979
         * @param int $_limit (OPTIONAL) The Number of Results to Return
4980
         * @param bool $_excludeResolved
4981
         * @return array The History Container
4982
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
4983
         */
4984
        static public function RetrieveSCTicketsOnUser(SWIFT_User $_SWIFT_UserObject, $_sortBy = false, $_sortOrder = false, $_offset = 0, $_limit = false, $_excludeResolved = false) {
4985
                $_SWIFT = SWIFT::GetInstance();
4986
4987
                $_userID = '-1';
4988
                $_userEmailList = array();
4989
                if ($_SWIFT_UserObject instanceof SWIFT_User && $_SWIFT_UserObject->GetIsClassLoaded())
4990
                {
4991
                        $_userID = $_SWIFT_UserObject->GetUserID();
4992
                        $_userEmailList = array_merge($_userEmailList, $_SWIFT_UserObject->GetEmailList());
4993
                }
4994
4995
                $_historyContainer = array();
4996
4997
                $_ticketSortBy = 'dateline';
4998
                $_ticketSortOrder = 'DESC';
4999
                if (!empty($_sortBy) && !empty($_sortOrder))
5000
                {
5001
                        $_ticketSortBy = $_sortBy;
5002
                        $_ticketSortOrder = $_sortOrder;
5003
                }
5004
5005
                $_userIDList = array($_SWIFT_UserObject->GetUserID());
5006
5007
                // Does this user have a shared organization or he is a manager in an organization?
5008
                $_SWIFT_UserOrganizationObject = $_SWIFT_UserObject->GetOrganization();
5009
5010
                if (($_SWIFT_UserObject->GetProperty('userrole') == SWIFT_User::ROLE_MANAGER && $_SWIFT_UserOrganizationObject instanceof SWIFT_UserOrganization && $_SWIFT_UserOrganizationObject->GetIsClassLoaded()) ||
5011
                                ($_SWIFT_UserOrganizationObject instanceof SWIFT_UserOrganization && $_SWIFT_UserOrganizationObject->GetIsClassLoaded() && $_SWIFT_UserOrganizationObject->GetProperty('organizationtype') == SWIFT_UserOrganization::TYPE_SHARED))
5012
                {
5013
                        $_userIDList_Organization = array();
5014
                        $_SWIFT->Database->Query("SELECT userid FROM " . TABLE_PREFIX . "users WHERE userorganizationid = '" . intval($_SWIFT_UserOrganizationObject->GetUserOrganizationID()) . "'");
5015
                        while ($_SWIFT->Database->NextRecord())
5016
                        {
5017
                                $_userIDList_Organization[] = $_SWIFT->Database->Record['userid'];
5018
5019
                                $_userIDList[] = $_SWIFT->Database->Record['userid'];
5020
                        }
5021
5022
                        $_userEmailList = array_merge($_userEmailList, SWIFT_UserEmail::RetrieveListOnUserIDList($_userIDList_Organization));
5023
                }
5024
5025
                $_whereExtended = '';
5026
                if ($_excludeResolved) {
5027
                        $_whereExtended .= ' AND isresolved = "0"';
5028
                }
5029
                if ($_limit) {
5030
                        $_SWIFT->Database->QueryLimit("SELECT * FROM " . TABLE_PREFIX . "tickets
5031
                        WHERE (userid IN (" . BuildIN($_userIDList) . ") OR email IN (" . BuildIN($_userEmailList) . ") OR replyto IN (" . BuildIN($_userEmailList) . "))
5032
                        AND departmentid <> '0'
5033
                        " . $_whereExtended . "
5034
                        ORDER BY " . $_ticketSortBy . " " . $_ticketSortOrder, $_limit, $_offset);
5035
                } else {
5036
                        $_SWIFT->Database->QueryLimit("SELECT * FROM " . TABLE_PREFIX . "tickets
5037
                        WHERE (userid IN (" . BuildIN($_userIDList) . ") OR email IN (" . BuildIN($_userEmailList) . ") OR replyto IN (" . BuildIN($_userEmailList) . "))
5038
                        AND departmentid <> '0'
5039
                        " . $_whereExtended . "
5040
                        ORDER BY " . $_ticketSortBy . " " . $_ticketSortOrder);
5041
                }
5042
5043
                while ($_SWIFT->Database->NextRecord()) {
5044
                        if ($_SWIFT->Database->Record['creator'] == SWIFT_Ticket::CREATOR_STAFF && !in_array(mb_strtolower($_SWIFT->Database->Record['replyto']), $_userEmailList))
5045
                        {
5046
                                continue;
5047
                        }
5048
5049
                        $_historyContainer[$_SWIFT->Database->Record['ticketid']] = new SWIFT_Ticket(new SWIFT_DataStore($_SWIFT->Database->Record));
5050
                }
5051
5052
                return $_historyContainer;
5053
        }
5054
5055
        /**
5056
         * Retrieve the Support Center Tickets count for this user
5057
         *
5058
         * @author Varun Shoor
5059
         * @param SWIFT_User $_SWIFT_UserObject
5060
         * @param bool $_excludeResolved
5061
         * @param bool $_resolvedOnly
5062
         * @return int The History Count
5063
         * @throws SWIFT_Ticket_Exception If Invalid Data is Provided
5064
         */
5065
        static public function RetrieveSCTicketsCountOnUser($_SWIFT_UserObject, $_excludeResolved = false, $_resolvedOnly = false) {
5066
                $_SWIFT = SWIFT::GetInstance();
5067
5068
                $_userID = '-1';
5069
                $_userEmailList = array();
5070
                if ($_SWIFT_UserObject instanceof SWIFT_User && $_SWIFT_UserObject->GetIsClassLoaded())
5071
                {
5072
                        $_userID = $_SWIFT_UserObject->GetUserID();
5073
                        $_userEmailList = array_merge($_userEmailList, $_SWIFT_UserObject->GetEmailList());
5074
                }
5075
5076
                $_userIDList = array($_SWIFT_UserObject->GetUserID());
5077
5078
                // Does this user have a shared organization or he is a manager in an organization?
5079
                $_SWIFT_UserOrganizationObject = $_SWIFT_UserObject->GetOrganization();
5080
5081
                if (($_SWIFT_UserObject->GetProperty('userrole') == SWIFT_User::ROLE_MANAGER && $_SWIFT_UserOrganizationObject instanceof SWIFT_UserOrganization && $_SWIFT_UserOrganizationObject->GetIsClassLoaded()) ||
5082
                                ($_SWIFT_UserOrganizationObject instanceof SWIFT_UserOrganization && $_SWIFT_UserOrganizationObject->GetIsClassLoaded() && $_SWIFT_UserOrganizationObject->GetProperty('organizationtype') == SWIFT_UserOrganization::TYPE_SHARED))
5083
                {
5084
                        $_userIDList_Organization = array();
5085
                        $_SWIFT->Database->Query("SELECT userid FROM " . TABLE_PREFIX . "users WHERE userorganizationid = '" . intval($_SWIFT_UserOrganizationObject->GetUserOrganizationID()) . "'");
5086
                        while ($_SWIFT->Database->NextRecord())
5087
                        {
5088
                                $_userIDList_Organization[] = $_SWIFT->Database->Record['userid'];
5089
5090
                                $_userIDList[] = $_SWIFT->Database->Record['userid'];
5091
                        }
5092
5093
                        $_userEmailList = array_merge($_userEmailList, SWIFT_UserEmail::RetrieveListOnUserIDList($_userIDList_Organization));
5094
                }
5095
5096
                $_whereExtended = '';
5097
                if ($_excludeResolved) {
5098
                        $_whereExtended = ' AND isresolved = "0"';
5099
                }
5100
5101
                if ($_resolvedOnly) {
5102
                        $_whereExtended = ' AND isresolved = "1"';
5103
                }
5104
5105
                $_countContainer = $_SWIFT->Database->QueryFetch("SELECT COUNT(*) AS totalitems FROM " . TABLE_PREFIX . "tickets
5106
                        WHERE (userid = '" . intval($_userID) . "' OR email IN (" . BuildIN($_userEmailList) . ") OR replyto IN (" . BuildIN($_userEmailList) . "))
5107
                        AND departmentid <> '0'
5108
                        " . $_whereExtended . "
5109
                                ");
5110
5111
                if (isset($_countContainer['totalitems']) && intval($_countContainer['totalitems']) > 0) {
5112
                        return $_countContainer['totalitems'];
5113
                }
5114
5115
                return 0;
5116
        }
5117
5118
        /**
5119
         * Set the Watcher Notification Message
5120
         *
5121
         * @author Varun Shoor
5122
         * @param string $_watcherName The Watcher Name
5123
         * @param string $_watcherMessage The Watcher Message
5124
         * @return bool "true" on Success, "false" otherwise
5125
         * @throws SWIFT_Exception If the Class is not Loaded
5126
         */
5127
        public function SetWatcherProperties($_watcherName, $_watcherMessage)
5128
        {
5129
                if (!$this->GetIsClassLoaded())
5130
                {
5131
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
5132
5133
                        return false;
5134
                }
5135
5136
                $this->_watcherCustomName = $_watcherName;
5137
                $this->_watchNotificationMessage = $_watcherMessage;
5138
5139
                return true;
5140
        }
5141
5142
        /**
5143
         * Process the Notification for Ticket Watchers
5144
         *
5145
         * @author Varun Shoor
5146
         * @return bool "true" on Success, "false" otherwise
5147
         * @throws SWIFT_Exception If the Class is not Loaded
5148
         */
5149
        public function ProcessWatchers()
5150
        {
5151
                chdir(SWIFT_BASEPATH);
5152
                $_ticketID = $this->GetTicketID();
5153
5154
                if (!$this->GetIsClassLoaded())
5155
                {
5156
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
5157
5158
                        return false;
5159
                } else if (isset(self::$_watcherExecutedCache[$_ticketID]) && self::$_watcherExecutedCache[$_ticketID] == 1) {
5160
                        return true;
5161
                }
5162
5163
                $_staffCache = $this->Cache->Get('staffcache');
5164
5165
                $_emailList = array();
5166
                $_ticketWatchContainer = SWIFT_TicketWatcher::RetrieveOnTicket($this);
5167
                if (_is_array($_ticketWatchContainer))
5168
                {
5169
                        foreach ($_ticketWatchContainer as $_ticketWatch)
5170
                        {
5171
                                $_staffID = $_ticketWatch['staffid'];
5172
5173
                                if (!isset($_staffCache[$_staffID]))
5174
                                {
5175
                                        continue;
5176
                                }
5177
5178
                                $_emailList[] = $_staffCache[$_staffID]['email'];
5179
                        }
5180
                }
5181
5182
                if (!count($_emailList))
5183
                {
5184
                        return false;
5185
                }
5186
5187
                $this->Notification->Dispatch(SWIFT_TicketNotification::TYPE_CUSTOM, $_emailList, $this->GetProperty('subject'), $this->_watchNotificationMessage, $this->_watcherCustomName, '', true);
5188
5189
                self::$_watcherExecutedCache[$_ticketID] = 1;
5190
5191
                return true;
5192
        }
5193
5194
        /**
5195
         * Queue the Watcher Execution
5196
         *
5197
         * @author Varun Shoor
5198
         * @return bool "true" on Success, "false" otherwise
5199
         * @throws SWIFT_Exception If the Class is not Loaded
5200
         */
5201
        public function QueueWatcherExecution()
5202
        {
5203
                $_ticketID = $this->GetTicketID();
5204
5205
                if (!$this->GetIsClassLoaded())
5206
                {
5207
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
5208
5209
                        return false;
5210
                } else if (isset(self::$_watcherPendingCache[$_ticketID]) && self::$_watcherPendingCache[$_ticketID] == '1') {
5211
                        return true;
5212
                }
5213
5214
//                SWIFT::Shutdown($this, 'ProcessWatchers', -1, false);
5215
5216
                self::$_watcherPendingCache[$_ticketID] = 1;
5217
5218
                return true;
5219
        }
5220
5221
        /**
5222
         * Process the Notification Rules
5223
         *
5224
         * @author Varun Shoor
5225
         * @return bool "true" on Success, "false" otherwise
5226
         * @throws SWIFT_Exception If the Class is not Loaded
5227
         */
5228
        public function ProcessNotifications()
5229
        {
5230
                chdir(SWIFT_BASEPATH);
5231
                $_ticketID = $this->GetTicketID();
5232
5233
                if (!$this->GetIsClassLoaded())
5234
                {
5235
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
5236
5237
                        return false;
5238
                } else if (isset(self::$_notificationExecutionCache[$_ticketID]) && self::$_notificationExecutionCache[$_ticketID] == '1') {
5239
                        return true;
5240
                }
5241
5242
                $this->NotificationManager->Trigger();
5243
5244
                self::$_notificationExecutionCache[$_ticketID] = 1;
5245
5246
                return true;
5247
        }
5248
5249
        /**
5250
         * Dispatch a Notification via Email on this Ticket
5251
         *
5252
         * @author Varun Shoor
5253
         * @param constant $_notificationType The Notification Type
5254
         * @param array $_customEmailList The Custom Email List
5255
         * @param string $_emailPrefix (OPTIONAL) The Custom Email Prefix
5256
         * @param string $_notificationEvent (OPTIONAL) The Notification Event
5257
         * @return bool "true" on Success, "false" otherwise
5258
         * @throws SWIFT_Exception If the Class is not Loaded
5259
         */
5260
        public function DispatchNotification($_notificationType, $_customEmailList, $_emailPrefix = '', $_notificationEvent = '')
5261
        {
5262
                if (!$this->GetIsClassLoaded())
5263
                {
5264
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
5265
5266
                        return false;
5267
                }
5268
5269
                $_finalEmailPrefix = '';
5270
                if (!empty($_emailPrefix))
5271
                {
5272
                        $_finalEmailPrefix = $_emailPrefix . ' - ';
5273
                }
5274
5275
                $_notificationMessage = $this->_watchNotificationMessage;
5276
                if (empty($_notificationMessage)) {
5277
                        $_notificationMessage = $this->_lastPostNotificationMessage;
5278
                }
5279
5280
                $this->Notification->Dispatch($_notificationType, $_customEmailList, $_finalEmailPrefix . $this->GetProperty('subject'), $_notificationMessage, $this->_watcherCustomName, '', false, $_notificationEvent);
5281
5282
                return true;
5283
        }
5284
5285
        /**
5286
         * Dispatch a Notification via Pool (DESKTOP APP) on this Ticket
5287
         *
5288
         * @author Varun Shoor
5289
         * @param constant $_notificationType The Notification Type
5290
         * @param array $_customStaffIDList The Custom Staff ID List
5291
         * @param string $_notificationEvent (OPTIONAL) The Notification Event
5292
         * @return bool "true" on Success, "false" otherwise
5293
         * @throws SWIFT_Exception If the Class is not Loaded
5294
         */
5295
        public function DispatchNotificationPool($_notificationType, $_customStaffIDList, $_notificationEvent = '')
5296
        {
5297
                if (!$this->GetIsClassLoaded())
5298
                {
5299
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
5300
5301
                        return false;
5302
                }
5303
5304
//                $this->Notification->DispatchPool($_notificationType, $_customStaffIDList, $this->GetProperty('subject'), $this->_watchNotificationMessage, $this->_watcherCustomName);
5305
5306
                return true;
5307
        }
5308
5309
        /**
5310
         * Add to Attachments
5311
         *
5312
         * @author Varun Shoor
5313
         * @param string $_fileName The File Name
5314
         * @param string $_fileType The File Type
5315
         * @param string $_fileContents The File Contents
5316
         * @return bool "true" on Success, "false" otherwise
5317
         * @throws SWIFT_Exception If the Class is not Loaded
5318
         */
5319
        public function AddToAttachments($_fileName, $_fileType, $_fileContents)
5320
        {
5321
                if (!$this->GetIsClassLoaded())
5322
                {
5323
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
5324
5325
                        return false;
5326
                }
5327
5328
                if (!isset(self::$_attachmentsContainer[$this->GetTicketID()]))
5329
                {
5330
                        self::$_attachmentsContainer[$this->GetTicketID()] = array();
5331
                }
5332
5333
                self::$_attachmentsContainer[$this->GetTicketID()][] = array('name' => $_fileName, 'type' => $_fileType, 'contents' => $_fileContents);
5334
5335
                return true;
5336
        }
5337
5338
        /**
5339
         * Retrieve the Attachments Container
5340
         *
5341
         * @author Varun Shoor
5342
         * @return array The Attachments Container
5343
         * @throws SWIFT_Exception If the Class is not Loaded
5344
         */
5345
        public function GetAttachments()
5346
        {
5347
                if (!$this->GetIsClassLoaded())
5348
                {
5349
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
5350
5351
                        return false;
5352
                }
5353
5354
                if (!isset(self::$_attachmentsContainer[$this->GetTicketID()]))
5355
                {
5356
                        return false;
5357
                }
5358
5359
                return self::$_attachmentsContainer[$this->GetTicketID()];
5360
        }
5361
5362
        /**
5363
         * Add to Active Attachments (for notifications)
5364
         *
5365
         * @author Varun Shoor
5366
         * @param string $_fileName The File Name
5367
         * @param string $_fileType The File Type
5368
         * @param string $_fileContents The File Contents
5369
         * @return bool "true" on Success, "false" otherwise
5370
         * @throws SWIFT_Exception If the Class is not Loaded
5371
         */
5372
        public function AddToNotificationAttachments($_fileName, $_fileType, $_fileContents)
5373
        {
5374
                if (!$this->GetIsClassLoaded())
5375
                {
5376
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
5377
5378
                        return false;
5379
                }
5380
5381
                if (!isset(self::$_notificationAttachmentsContainer[$this->GetTicketID()]))
5382
                {
5383
                        self::$_notificationAttachmentsContainer[$this->GetTicketID()] = array();
5384
                }
5385
5386
                self::$_notificationAttachmentsContainer[$this->GetTicketID()][] = array('name' => $_fileName, 'type' => $_fileType, 'contents' => $_fileContents);
5387
5388
                return true;
5389
        }
5390
5391
        /**
5392
         * Retrieve the Attachments Container
5393
         *
5394
         * @author Varun Shoor
5395
         * @return array The Attachments Container
5396
         * @throws SWIFT_Exception If the Class is not Loaded
5397
         */
5398
        public function GetNotificationAttachments()
5399
        {
5400
                if (!$this->GetIsClassLoaded())
5401
                {
5402
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
5403
5404
                        return false;
5405
                }
5406
5407
                if (!isset(self::$_notificationAttachmentsContainer[$this->GetTicketID()]))
5408
                {
5409
                        return false;
5410
                }
5411
5412
                return self::$_notificationAttachmentsContainer[$this->GetTicketID()];
5413
        }
5414
5415
        /**
5416
         * Move the tickets to trash
5417
         *
5418
         * @author Varun Shoor
5419
         * @param array $_departmentIDList The Department ID List
5420
         * @return bool "true" on Success, "false" otherwise
5421
         */
5422
        static public function MoveToTrashBulk($_departmentIDList) {
5423
                $_SWIFT = SWIFT::GetInstance();
5424
5425
                if (!_is_array($_departmentIDList)) {
5426
                        return false;
5427
                }
5428
5429
                /**
5430
                 * BUG FIX - Parminder Singh
5431
                 *
5432
                 * SWIFT-1894: 'Trash' count does not clear the ticket count in case a department is deleted
5433
                 *
5434
                 */
5435
5436
                $_SWIFT->Database->AutoExecute(TABLE_PREFIX . 'tickets', array('departmentid' => '0', 'trasholddepartmentid' => '0'), 'UPDATE', "departmentid IN (" . BuildIN($_departmentIDList) . ") OR trasholddepartmentid IN (" . BuildIN($_departmentIDList) . ")");
5437
5438
                return true;
5439
        }
5440
5441
        /**
5442
         * Move the tickets status to trash
5443
         *
5444
         * @author Varun Shoor
5445
         * @param array $_ticketStatusIDList The Ticket Status ID List
5446
         * @return bool "true" on Success, "false" otherwise
5447
         */
5448
        static public function ChangeStatusToTrash($_ticketStatusIDList) {
5449
                $_SWIFT = SWIFT::GetInstance();
5450
5451
                if (!_is_array($_ticketStatusIDList)) {
5452
                        return false;
5453
                }
5454
5455
                $_SWIFT->Database->AutoExecute(TABLE_PREFIX . 'tickets', array('ticketstatusid' => '0'), 'UPDATE', "ticketstatusid IN (" . BuildIN($_ticketStatusIDList) . ")");
5456
5457
                return true;
5458
        }
5459
5460
        /**
5461
         * Update the User record
5462
         *
5463
         * @author Varun Shoor
5464
         * @param int $_userID The User ID
5465
         * @return bool "true" on Success, "false" otherwise
5466
         * @throws SWIFT_Exception If the Class is not Loaded
5467
         */
5468
        public function UpdateUser($_userID)
5469
        {
5470
                if (!$this->GetIsClassLoaded())
5471
                {
5472
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
5473
5474
                        return false;
5475
                }
5476
5477
                $this->UpdatePool('userid', $_userID);
5478
                $this->ProcessUpdatePool();
5479
5480
                return true;
5481
        }
5482
5483
        /**
5484
         * Retrieve the last post contents
5485
         *
5486
         * @author Varun Shoor
5487
         * @return string The last post contents
5488
         * @throws SWIFT_Exception If the Class is not Loaded
5489
         */
5490
        public function GetLastPostContents()
5491
        {
5492
                if (!$this->GetIsClassLoaded())
5493
                {
5494
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
5495
5496
                        return false;
5497
                }
5498
5499
                try {
5500
                        $_SWIFT_TicketPostObject = new SWIFT_TicketPost(new SWIFT_DataID($this->GetProperty('lastpostid')));
5501
5502
                        if ($_SWIFT_TicketPostObject->GetProperty('ticketid') == $this->GetTicketID())
5503
                        {
5504
                                return $_SWIFT_TicketPostObject->GetDisplayContents();
5505
                        }
5506
5507
                } catch (SWIFT_Exception $_SWIFT_ExceptionObject) {
5508
5509
5510
                        return '';
5511
                }
5512
5513
5514
5515
                return '';
5516
        }
5517
5518
        /**
5519
         * Retrieve the Ticket Post IDs linked with this ticket
5520
         *
5521
         * @author Varun Shoor
5522
         * @param bool $_ignoreForwardedPosts (OPTIONAL) Whether to ignore forwarded posts
5523
         * @return array The Ticket Post ID List
5524
         * @throws SWIFT_Exception If the Class is not Loaded
5525
         */
5526
        public function GetTicketPostIDList($_ignoreForwardedPosts = false)
5527
        {
5528
                if (!$this->GetIsClassLoaded())
5529
                {
5530
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
5531
5532
                        return false;
5533
                }
5534
5535
                $_ticketPostIDList = array();
5536
5537
                /*
5538
                 * BUG FIX - Parminder Singh
5539
                 *
5540
                 * SWIFT-2286 Staff creates a ticket with attachment. When forward, attachment does not go with the ticket.
5541
                 *
5542
                 */
5543
                $this->Database->Query("SELECT ticketpostid, creator, emailto, isthirdparty FROM " . TABLE_PREFIX . "ticketposts WHERE ticketid = '" . intval($this->GetTicketID()) . "'");
5544
                while ($this->Database->NextRecord()) {
5545
                        if ($_ignoreForwardedPosts == true && $this->Database->Record['creator'] == SWIFT_TicketPost::CREATOR_STAFF && $this->Database->Record['emailto'] != '' && $this->Database->Record['isthirdparty'] == '1')
5546
                        {
5547
                                continue;
5548
                        }
5549
5550
                        $_ticketPostIDList[] = $this->Database->Record['ticketpostid'];
5551
                }
5552
5553
                return $_ticketPostIDList;
5554
        }
5555
5556
        /**
5557
         * Update the Average Response Time
5558
         *
5559
         * @author Varun Shoor
5560
         * @param int $_responseTime
5561
         * @return bool "true" on Success, "false" otherwise
5562
         * @throws SWIFT_Exception If the Class is not Loaded
5563
         */
5564
        public function UpdateAverageResponseTime($_responseTime) {
5565
                if (!$this->GetIsClassLoaded()) {
5566
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
5567
5568
                        return false;
5569
                }
5570
5571
                $_oldHitCount = intval($this->GetProperty('averageresponsetimehits'));
5572
                $_oldAverageResponseTime = intval($this->GetProperty('averageresponsetime'));
5573
5574
                $_newHitCount = $_oldHitCount + 1;
5575
5576
                $_newAverageResponseTime = (($_oldAverageResponseTime*$_oldHitCount)+$_responseTime)/$_newHitCount;
5577
5578
                $this->UpdatePool('averageresponsetime', intval($_newAverageResponseTime));
5579
                $this->UpdatePool('averageresponsetimehits', intval($_newHitCount));
5580
5581
                return true;
5582
        }
5583
5584
        /**
5585
         * Update the Email Queue
5586
         *
5587
         * @author Varun Shoor
5588
         * @param int $_emailQueueID The Email Queue ID
5589
         * @return bool "true" on Success, "false" otherwise
5590
         * @throws SWIFT_Exception If the Class is not Loaded
5591
         */
5592
        public function UpdateQueue($_emailQueueIDIncoming) {
5593
                $_SWIFT = SWIFT::GetInstance();
5594
5595
                if (!$this->GetIsClassLoaded()) {
5596
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
5597
5598
                        return false;
5599
                } else if ($this->GetProperty('emailqueueid') == $_emailQueueIDIncoming) {
5600
                        return true;
5601
                }
5602
5603
                $_emailQueueCache = $this->Cache->Get('queuecache');
5604
                $_templateGroupCache = $this->Cache->Get('templategroupcache');
5605
                $_emailQueueID = 0;
5606
                if (isset($_emailQueueCache['list'][$_emailQueueIDIncoming]))
5607
                {
5608
                        $_emailQueueID = $_emailQueueIDIncoming;
5609
                }
5610
5611
                $_emailQueueContainer = false;
5612
                if (isset($_emailQueueCache['list'][$_emailQueueID]))
5613
                {
5614
                        $_emailQueueContainer = $_emailQueueCache['list'][$_emailQueueID];
5615
                }
5616
5617
                $_templateGroupID = SWIFT_TemplateGroup::GetDefaultGroupID();
5618
5619
                if (_is_array($_emailQueueContainer) && isset($_templateGroupCache[$_emailQueueContainer['tgroupid']]))
5620
                {
5621
                        $_templateGroupID = $_emailQueueContainer['tgroupid'];
5622
                }
5623
5624
                $this->UpdatePool('emailqueueid', intval($_emailQueueID));
5625
                $this->UpdatePool('tgroupid', intval($_templateGroupID));
5626
5627
                return true;
5628
        }
5629
5630
        /**
5631
         * Load the Last Post Notification Message
5632
         *
5633
         * @author Varun Shoor
5634
         * @return bool "true" on Success, "false" otherwise
5635
         * @throws SWIFT_Exception If the Class is not Loaded
5636
         */
5637
        protected function LoadLastPostNotificationMessage() {
5638
                if (!$this->GetIsClassLoaded()) {
5639
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
5640
5641
                        return false;
5642
                }
5643
5644
                try {
5645
                        $_SWIFT_TicketPostObject = new SWIFT_TicketPost(new SWIFT_DataID($this->GetProperty('lastpostid')));
5646
                        $this->_lastPostNotificationMessage = $_SWIFT_TicketPostObject->GetProperty('contents');
5647
                } catch (SWIFT_Exception $_SWIFT_ExceptionObject) {
5648
5649
                        return false;
5650
                }
5651
5652
                return true;
5653
        }
5654
5655
        /**
5656
         * Retrieve the Ticket ID Object on the provided Ticket ID
5657
         *
5658
         * @author Varun Shoor
5659
         * @param mixed $_ticketID The Numeric or Mask Ticket ID
5660
         * @return SWIFT_Ticket
5661
         */
5662
        static public function GetObjectOnID($_ticketID)
5663
        {
5664
                $_SWIFT = SWIFT::GetInstance();
5665
5666
                $_SWIFT_TicketObject = false;
5667
5668
                if (is_numeric($_ticketID)) {
5669
                        try {
5670
                                $_SWIFT_TicketObject = new SWIFT_Ticket(new SWIFT_DataID($_ticketID));
5671
                        } catch (SWIFT_Exception $_SWIFT_ExceptionObject) {
5672
                        }
5673
                } else {
5674
                        $_ticketID = SWIFT_Ticket::GetTicketIDFromMask($_ticketID);
5675
                        if (empty($_ticketID)) {
5676
                                return false;
5677
                        }
5678
5679
                        try {
5680
                                $_SWIFT_TicketObject = new SWIFT_Ticket(new SWIFT_DataID($_ticketID));
5681
                        } catch (SWIFT_Exception $_SWIFT_ExceptionObject) {
5682
                        }
5683
                }
5684
5685
                if ($_SWIFT_TicketObject instanceof SWIFT_Ticket && $_SWIFT_TicketObject->GetIsClassLoaded()) {
5686
                        return $_SWIFT_TicketObject;
5687
                }
5688
5689
                // By now we couldnt get the ticket object, we have to lookup the merge logs
5690
                $_mergeTicketID = false;
5691
                if (is_numeric($_ticketID)) {
5692
                        $_mergeTicketID = SWIFT_TicketMergeLog::GetTicketIDFromMergedTicketID($_ticketID);
5693
                } else {
5694
                        $_mergeTicketID = SWIFT_TicketMergeLog::GetTicketIDFromMergedTicketMaskID($_ticketID);
5695
                }
5696
5697
                if (!empty($_mergeTicketID)) {
5698
                        try
5699
                        {
5700
                                $_SWIFT_TicketObject = new SWIFT_Ticket(new SWIFT_DataID($_mergeTicketID));
5701
                        } catch (SWIFT_Exception $_SWIFT_ExceptionObject) {
5702
                        }
5703
5704
                        if ($_SWIFT_TicketObject instanceof SWIFT_Ticket && $_SWIFT_TicketObject->GetIsClassLoaded())
5705
                        {
5706
                                return $_SWIFT_TicketObject;
5707
                        }
5708
                }
5709
5710
                return false;
5711
        }
5712
5713
        /**
5714
         * Mark the Tickets as Pending Auto Closure
5715
         *
5716
         * @author Varun Shoor
5717
         * @param array $_ticketIDList
5718
         * @param SWIFT_AutoCloseRule $_SWIFT_AutoCloseRuleObject
5719
         * @return bool "true" on Success, "false" otherwise
5720
         * @throws SWIFT_Exception If Invalid Data is Provided
5721
         */
5722
        static public function MarkAsAutoClosePending($_ticketIDList, SWIFT_AutoCloseRule $_SWIFT_AutoCloseRuleObject)
5723
        {
5724
                $_SWIFT = SWIFT::GetInstance();
5725
5726
                if (!$_SWIFT_AutoCloseRuleObject instanceof SWIFT_AutoCloseRule || !$_SWIFT_AutoCloseRuleObject->GetIsClassLoaded()) {
5727
                        throw new SWIFT_Exception(SWIFT_INVALIDDATA);
5728
                }
5729
5730
                $_SWIFT->Database->AutoExecute(TABLE_PREFIX . 'tickets', array('isautoclosed' => '0', 'autocloseruleid' => intval($_SWIFT_AutoCloseRuleObject->GetAutoCloseRuleID()),
5731
                        'autoclosestatus' => self::AUTOCLOSESTATUS_PENDING, 'autoclosetimeline' => DATENOW), 'UPDATE', "ticketid IN (" . BuildIN($_ticketIDList) . ")");
5732
5733
                // Do we need to send the pending notification?
5734
                if ($_SWIFT_AutoCloseRuleObject->GetProperty('sendpendingnotification') == '0') {
5735
                        return true;
5736
                }
5737
5738
                $_ticketsContainer = array();
5739
                $_SWIFT->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickets
5740
                        WHERE ticketid IN (" . BuildIN($_ticketIDList) . ")");
5741
                while ($_SWIFT->Database->NextRecord()) {
5742
                        $_ticketsContainer[$_SWIFT->Database->Record['ticketid']] = new SWIFT_Ticket(new SWIFT_DataStore($_SWIFT->Database->Record));
5743
                }
5744
5745
                foreach ($_ticketsContainer as $_SWIFT_TicketObject) {
5746
                        if (!$_SWIFT_TicketObject instanceof SWIFT_Ticket || !$_SWIFT_TicketObject->GetIsClassLoaded()) {
5747
                                continue;
5748
                        }
5749
5750
                        $_SWIFT_TicketEmailDispatch = new SWIFT_TicketEmailDispatch($_SWIFT_TicketObject);
5751
                        $_SWIFT_TicketEmailDispatch->DispatchPendingAutoClose($_SWIFT_AutoCloseRuleObject);
5752
                }
5753
5754
                return true;
5755
        }
5756
5757
        /**
5758
         * Mark the Tickets as Closed via Auto Closed
5759
         *
5760
         * @author Varun Shoor
5761
         * @param array $_ticketIDList
5762
         * @param SWIFT_AutoCloseRule $_SWIFT_AutoCloseRuleObject
5763
         * @return bool "true" on Success, "false" otherwise
5764
         * @throws SWIFT_Exception If Invalid Data is Provided
5765
         */
5766
        static public function MarkAsAutoClosed($_ticketIDList, SWIFT_AutoCloseRule $_SWIFT_AutoCloseRuleObject)
5767
        {
5768
                $_SWIFT = SWIFT::GetInstance();
5769
5770
                if (!$_SWIFT_AutoCloseRuleObject instanceof SWIFT_AutoCloseRule || !$_SWIFT_AutoCloseRuleObject->GetIsClassLoaded()) {
5771
                        throw new SWIFT_Exception(SWIFT_INVALIDDATA);
5772
                }
5773
5774
                $_ticketsContainer = array();
5775
                $_SWIFT->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickets
5776
                        WHERE ticketid IN (" . BuildIN($_ticketIDList) . ")");
5777
                while ($_SWIFT->Database->NextRecord()) {
5778
                        $_ticketsContainer[$_SWIFT->Database->Record['ticketid']] = new SWIFT_Ticket(new SWIFT_DataStore($_SWIFT->Database->Record));
5779
                }
5780
5781
                $_SWIFT->Database->AutoExecute(TABLE_PREFIX . 'tickets', array('isautoclosed' => '1', 'autocloseruleid' => intval($_SWIFT_AutoCloseRuleObject->GetAutoCloseRuleID()),
5782
                        'autoclosestatus' => self::AUTOCLOSESTATUS_CLOSED, 'autoclosetimeline' => DATENOW), 'UPDATE', "ticketid IN (" . BuildIN($_ticketIDList) . ")");
5783
5784
                foreach ($_ticketsContainer as $_SWIFT_TicketObject) {
5785
                        if (!$_SWIFT_TicketObject instanceof SWIFT_Ticket || !$_SWIFT_TicketObject->GetIsClassLoaded()) {
5786
                                continue;
5787
                        }
5788
5789
                        $_SWIFT_TicketObject->SetStatus($_SWIFT_AutoCloseRuleObject->GetProperty('targetticketstatusid'), true, $_SWIFT_AutoCloseRuleObject->GetProperty('suppresssurveyemail'));
5790
5791
                        // Do we need to send the final notification?
5792
                        if ($_SWIFT_AutoCloseRuleObject->GetProperty('sendfinalnotification') == '1') {
5793
                                $_SWIFT_TicketEmailDispatch = new SWIFT_TicketEmailDispatch($_SWIFT_TicketObject);
5794
                                $_SWIFT_TicketEmailDispatch->DispatchFinalAutoClose($_SWIFT_AutoCloseRuleObject);
5795
                        }
5796
5797
                        $_SWIFT_TicketObject->RebuildProperties();
5798
                }
5799
5800
                return true;
5801
        }
5802
5803
        /**
5804
         * Retrieve the from email with proper suffix
5805
         *
5806
         * @author Varun Shoor
5807
         * @param string $_fromEmailAddress
5808
         * @param constant $_mailType
5809
         * @return bool "true" on Success, "false" otherwise
5810
         * @throws SWIFT_Exception If the Class is not Loaded
5811
         */
5812
        public function RetrieveFromEmailWithSuffix($_fromEmailAddress, $_mailType)
5813
        {
5814
                if (!$this->GetIsClassLoaded()) {
5815
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
5816
5817
                        return false;
5818
                }
5819
5820
                // Have we enabled clean subjects?
5821
                if ($this->Settings->Get('t_cleanmailsubjects') != '1') {
5822
                        return $_fromEmailAddress;
5823
                }
5824
5825
                $_finalReturnEmailAddress = '';
5826
5827
                $_matches = array();
5828
                if (preg_match('/^(.*?)@(.*?)$/i', $_fromEmailAddress, $_matches)) {
5829
                        $_dispatchType = 'r';
5830
                        if ($_mailType == self::MAIL_NOTIFICATION) {
5831
                                $_dispatchType = 'a';
5832
                        } else if ($_mailType == self::MAIL_THIRDPARTY) {
5833
                                $_dispatchType = 't';
5834
                        }
5835
5836
                        $_hashChunk = substr($this->GetProperty('tickethash'), 0, 5);
5837
5838
                        $_finalReturnEmailAddress = $_matches[1] . '+' . $_dispatchType . '.' . $_hashChunk . '.' . $this->GetTicketID() . '@' . $_matches[2];
5839
5840
                } else {
5841
                        return $_fromEmailAddress;
5842
                }
5843
5844
5845
                return $_finalReturnEmailAddress;
5846
        }
5847
5848
        /**
5849
         * Reset SLA Calculations
5850
         *
5851
         * @author Mahesh Salaria
5852
         * @return bool "true" on Success, "false" otherwise
5853
         * @throws SWIFT_Exception If the Class is not Loaded
5854
         */
5855
        public function ResetSLA()
5856
        {
5857
                if (!$this->GetIsClassLoaded())         {
5858
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
5859
5860
                        return false;
5861
                }
5862
5863
                $this->_noSLACalculation = false;
5864
5865
                return true;
5866
        }
5867
5868
        /**
5869
         * Return the total ticket count
5870
         *
5871
         * @author Varun Shoor
5872
         * @return int The Total Ticket Count
5873
         */
5874
        static public function GetTicketCount()
5875
        {
5876
                $_SWIFT = SWIFT::GetInstance();
5877
5878
                $_ticketCountContainer = $_SWIFT->Database->QueryFetch("SELECT COUNT(*) AS totalitems FROM " . TABLE_PREFIX . "tickets");
5879
                if (isset($_ticketCountContainer['totalitems']) && !empty($_ticketCountContainer['totalitems'])) {
5880
                        return intval($_ticketCountContainer['totalitems']);
5881
                }
5882
5883
                return 0;
5884
        }
5885
5886
        /**
5887
         * Update the global property on all tickets, used to update stuff like departmentname etc.
5888
         *
5889
         * @author Varun Shoor
5890
         * @param string $_updateFieldName
5891
         * @param string $_updateFieldValue
5892
         * @param string $_whereFieldName
5893
         * @param string $_whereFieldValue
5894
         * @return bool "true" on Success, "false" otherwise
5895
         */
5896
        static public function UpdateGlobalProperty($_updateFieldName, $_updateFieldValue, $_whereFieldName, $_whereFieldValue)
5897
        {
5898
                $_SWIFT = SWIFT::GetInstance();
5899
5900
                $_updateFieldName = $_SWIFT->Database->Escape($_updateFieldName);
5901
                $_whereFieldName = $_SWIFT->Database->Escape($_whereFieldName);
5902
                $_whereFieldValue = intval($_whereFieldValue); // Expected to be always int
5903
5904
                $_SWIFT->Database->AutoExecute(TABLE_PREFIX . 'tickets', array($_updateFieldName => $_updateFieldValue), 'UPDATE', $_whereFieldName . " = '" . $_whereFieldValue . "'");
5905
5906
                return true;
5907
        }
5908
5909
        /**
5910
        * Set alert rules for ticket
5911
        *
5912
        * @author Ruchi Kothari
5913
        * @param bool $_noAlerts Alert rules
5914
        * @return bool "true" on Success, "false" otherwise
5915
        * @throws SWIFT_Exception If the Class is not Loaded
5916
        */
5917
        public function SetNoAlerts($_noAlerts)
5918
        {
5919
                if (!$this->GetIsClassLoaded()) {
5920
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
5921
5922
                        return false;
5923
                }
5924
5925
                $this->_noAlerts = $_noAlerts;
5926
        }
5927
5928
        /**
5929
        * Get alert rules for ticket
5930
        *
5931
        * @author Ruchi Kothari
5932
        * @return bool Alert rules status
5933
        * @throws SWIFT_Exception If the Class is not Loaded
5934
        */
5935
        public function GetNoAlerts()
5936
        {
5937
                if (!$this->GetIsClassLoaded()) {
5938
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
5939
5940
                        return false;
5941
                }
5942
5943
                return $this->_noAlerts;
5944
        }
5945
5946
        /**
5947
         * Set Old Ticket properties. This array is used to Keep previous ticket properties after execution.
5948
         *
5949
         * @author Mahesh Salaria
5950
         * @return bool "true" on Success, "false" otherwise
5951
         * @throws SWIFT_Ticket_Exception If the Class is not Loaded
5952
         */
5953
        public function SetOldTicketProperties()
5954
        {
5955
                if (!$this->GetIsClassLoaded()) {
5956
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
5957
5958
                        return false;
5959
                }
5960
5961
                $this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETSTATUS] = $this->GetProperty('ticketstatusid');
5962
                $this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETPRIORITY] = $this->GetProperty('priorityid');
5963
                $this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETDEPARTMENT] = $this->GetProperty('departmentid');
5964
                $this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETOWNER] = intval($this->GetProperty('ownerstaffid'));
5965
                $this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETEMAILQUEUE] = $this->GetProperty('emailqueueid');
5966
                $this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETFLAGTYPE] = $this->GetProperty('flagtype');
5967
                $this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETCREATOR] = $this->GetProperty('creator');
5968
                $this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETUSERGROUP] = $this->GetUserGroupID();
5969
5970
                $this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETFULLNAME] = $this->GetProperty('fullname');
5971
                $this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETEMAIL] = $this->GetProperty('email');
5972
                $this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETLASTREPLIER] = $this->GetProperty('lastreplier');
5973
                $this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETSUBJECT] = $this->GetProperty('subject');
5974
                $this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETCHARSET] = $this->GetProperty('charset');
5975
5976
                $this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETTEMPLATEGROUP] = $this->GetProperty('tgroupid');
5977
                $this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETISRESOLVED] = $this->GetProperty('isresolved');
5978
                $this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETTYPE] = intval($this->GetProperty('tickettypeid'));
5979
                $this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETWASREOPENED] = $this->GetProperty('wasreopened');
5980
                $this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETTOTALREPLIES] = $this->GetProperty('totalreplies');
5981
                $this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETBAYESCATEGORY] = $this->GetProperty('bayescategoryid');
5982
5983
                return true;
5984
        }
5985
5986
        /**
5987
         * Get Old ticket properties
5988
         *
5989
         * @author Mahesh Salaria
5990
         * @return array of old ticket properties
5991
         * @throws SWIFT_Exception If the Class is not Loaded
5992
         */
5993
        public function GetOldTicketProperties()
5994
        {
5995
                if (!$this->GetIsClassLoaded()) {
5996
                        throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);
5997
5998
                        return false;
5999
                }
6000
6001
                return $this->_oldTicketProperties;
6002
        }
6003
}