Completed
Push — master ( a75ecc...97ae17 )
by Adam
71:21 queued 52:34
created

Reminder::sendEmailReminders()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 13
rs 8.8571
cc 5
eloc 8
nc 4
nop 3
1
<?php
2
/*********************************************************************************
3
 * SugarCRM Community Edition is a customer relationship management program developed by
4
 * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
5
 *
6
 * SuiteCRM is an extension to SugarCRM Community Edition developed by Salesagility Ltd.
7
 * Copyright (C) 2011 - 2016 Salesagility Ltd.
8
 *
9
 * This program is free software; you can redistribute it and/or modify it under
10
 * the terms of the GNU Affero General Public License version 3 as published by the
11
 * Free Software Foundation with the addition of the following permission added
12
 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
13
 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
14
 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
15
 *
16
 * This program is distributed in the hope that it will be useful, but WITHOUT
17
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18
 * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
19
 * details.
20
 *
21
 * You should have received a copy of the GNU Affero General Public License along with
22
 * this program; if not, see http://www.gnu.org/licenses or write to the Free
23
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24
 * 02110-1301 USA.
25
 *
26
 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
27
 * SW2-130, Cupertino, CA 95014, USA. or at email address [email protected].
28
 *
29
 * The interactive user interfaces in modified source and object code versions
30
 * of this program must display Appropriate Legal Notices, as required under
31
 * Section 5 of the GNU Affero General Public License version 3.
32
 *
33
 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
34
 * these Appropriate Legal Notices must retain the display of the "Powered by
35
 * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
36
 * reasonably feasible for  technical reasons, the Appropriate Legal Notices must
37
 * display the words  "Powered by SugarCRM" and "Supercharged by SuiteCRM".
38
 ********************************************************************************/
39
40
/**
41
 * Reminder class
42
 *
43
 */
44
class Reminder extends Basic
45
{
46
47
    const UPGRADE_VERSION = '7.4.3';
48
49
    var $name;
50
51
    var $new_schema = true;
52
    var $module_dir = 'Reminders';
53
    var $object_name = 'Reminder';
54
    var $table_name = 'reminders';
55
    var $tracker_visibility = false;
56
    var $importable = false;
57
    var $disable_row_level_security = true;
58
59
    var $popup;
60
    var $email;
61
    var $email_sent = false;
62
    var $timer_popup;
63
    var $timer_email;
64
    var $related_event_module;
65
    var $related_event_module_id;
66
67
    private static $remindersData = array();
68
69
    public function __construct()
70
    {
71
        parent::Basic();
72
    }
73
74
    public function bean_implements($interface)
75
    {
76
        switch ($interface) {
77
            case 'ACL':
78
                return true;
79
        }
80
        return false;
81
    }
82
83
    // ---- save and load remainders on EditViews
84
85
    /**
86
     * Save multiple reminders data from clients Meetings/Calls EditView.
87
     * Call this static function in save action.
88
     *
89
     * @param string $eventModule Event Bean module name (e.g. Meetings, Calls)
90
     * @param string $eventModuleId Event Bean GUID
91
     * @param string $remindersDataJson Remainders data as Json string from POST data.
92
     * @throws Exception throw an Exception if json format is invalid.
93
     */
94
    public static function saveRemindersDataJson($eventModule, $eventModuleId, $remindersDataJson)
95
    {
96
        $reminderData = json_decode($remindersDataJson);
97
        if (!json_last_error()) {
98
            Reminder::saveRemindersData($eventModule, $eventModuleId, $reminderData);
99
        } else {
100
            throw new Exception(json_last_error_msg());
101
        }
102
    }
103
104
    private static function saveRemindersData($eventModule, $eventModuleId, $remindersData)
105
    {
106
        $savedReminderIds = array();
107
        foreach ($remindersData as $reminderData) {
108
            if (isset($_POST['isDuplicate']) && $_POST['isDuplicate']) $reminderData->id = '';
109
            $reminderBean = BeanFactory::getBean('Reminders', $reminderData->id);
110
            $reminderBean->popup = $reminderData->popup;
111
            $reminderBean->email = $reminderData->email;
112
            $reminderBean->timer_popup = $reminderData->timer_popup;
113
            $reminderBean->timer_email = $reminderData->timer_email;
114
            $reminderBean->related_event_module = $eventModule;
115
            $reminderBean->related_event_module_id = $eventModuleId;
116
            $reminderBean->save();
117
            $savedReminderIds[] = $reminderBean->id;
118
            $reminderId = $reminderBean->id;
119
            Reminder_Invitee::saveRemindersInviteesData($reminderId, $reminderData->invitees);
120
        }
121
        $reminders = BeanFactory::getBean('Reminders')->get_full_list("", "reminders.related_event_module = '$eventModule' AND reminders.related_event_module_id = '$eventModuleId'");
122
        if ($reminders) {
123
            foreach ($reminders as $reminder) {
124
                if (!in_array($reminder->id, $savedReminderIds)) {
125
                    Reminder_Invitee::deleteRemindersInviteesMultiple($reminder->id);
126
                    $reminder->mark_deleted($reminder->id);
127
                    $reminder->save();
128
                }
129
            }
130
        }
131
        unset(self::$remindersData[$eventModule][$eventModuleId]);
132
    }
133
134
    /**
135
     * Load multiple reminders JSON data for related Event module EditViews.
136
     * Call this function in module display function.
137
     *
138
     * @param string $eventModule Related event module name (Meetings/Calls)
139
     * @param string $eventModuleId Related event GUID
140
     * @return string JSON string contains the remainders
141
     * @throws Exception
142
     */
143
    public static function loadRemindersDataJson($eventModule, $eventModuleId, $isDuplicate = false)
144
    {
145
        $remindersData = self::loadRemindersData($eventModule, $eventModuleId, $isDuplicate);
146
        $remindersDataJson = json_encode($remindersData);
147
        if (!$remindersDataJson && json_last_error()) {
148
            throw new Exception(json_last_error_msg());
149
        }
150
        return $remindersDataJson;
151
    }
152
153
    /**
154
     * Load multiple reminders data for related Event module EditViews.
155
     * Call this function in module display function.
156
     *
157
     * @param string $eventModule Related event module name (Meetings/Calls)
158
     * @param string $eventModuleId Related event GUID
159
     * @return array contains the remainders
160
     * @throws Exception
161
     */
162
    public static function loadRemindersData($eventModule, $eventModuleId, $isDuplicate = false)
163
    {
164
        if (!isset(self::$remindersData[$eventModule][$eventModuleId]) || !$eventModuleId || $isDuplicate) {
165
            $ret = array();
166
            $reminders = BeanFactory::getBean('Reminders')->get_full_list("reminders.date_entered", "reminders.related_event_module = '$eventModule' AND reminders.related_event_module_id = '$eventModuleId'");
167
            if ($reminders) {
168
                foreach ($reminders as $reminder) {
169
                    $ret[] = array(
170
                        'id' => $isDuplicate ? null : $reminder->id,
171
                        'popup' => $reminder->popup,
172
                        'email' => $reminder->email,
173
                        'timer_popup' => $reminder->timer_popup,
174
                        'timer_email' => $reminder->timer_email,
175
                        'invitees' => Reminder_Invitee::loadRemindersInviteesData($reminder->id, $isDuplicate),
176
                    );
177
                }
178
            }
179
            self::$remindersData[$eventModule][$eventModuleId] = $ret;
180
        }
181
        return self::$remindersData[$eventModule][$eventModuleId];
182
    }
183
184
    // ---- sending email reminders
185
186
    /**
187
     * Sending multiple email reminders.
188
     * Call in EmainReminder and use original EmailRemainder class for sending.
189
     *
190
     * @param EmailReminder $emailReminder Caller EmailReminder
191
     * @param Administration $admin Administration module for EmailRemainder->sendReminders() function
192
     * @param boolean $checkDecline (optional) Send email if user accept status is not decline. Default is TRUE.
193
     */
194
    public static function sendEmailReminders(EmailReminder $emailReminder, Administration $admin, $checkDecline = true)
195
    {
196
        if ($reminders = self::getUnsentEmailReminders()) {
197
            foreach ($reminders as $reminderId => $reminder) {
198
                $recipients = self::getEmailReminderInviteesRecipients($reminderId, $checkDecline);
199
                $eventBean = BeanFactory::getBean($reminder->related_event_module, $reminder->related_event_module_id);
200
                if ($eventBean && $emailReminder->sendReminders($eventBean, $admin, $recipients)) {
201
                    $reminder->email_sent = 1;
202
                    $reminder->save();
203
                }
204
            }
205
        }
206
    }
207
208
    private static function getEmailReminderInviteesRecipients($reminderId, $checkDecline = true)
209
    {
210
        $emails = array();
211
        $reminder = BeanFactory::getBean('Reminders', $reminderId);
212
        $eventModule = $reminder->related_event_module;
213
        $eventModuleId = $reminder->related_event_module_id;
214
        $event = BeanFactory::getBean($eventModule, $eventModuleId);
215
        if ($event && (!isset($event->status) || $event->status != 'Held')) {
216
            $invitees = BeanFactory::getBean('Reminders_Invitees')->get_full_list('', "reminders_invitees.reminder_id = '$reminderId'");
217
            foreach ($invitees as $invitee) {
0 ignored issues
show
Bug introduced by
The expression $invitees of type array<integer,object>|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
218
                $inviteeModule = $invitee->related_invitee_module;
219
                $inviteeModuleId = $invitee->related_invitee_module_id;
220
                $personBean = BeanFactory::getBean($inviteeModule, $inviteeModuleId);
221
                // The original email reminders check the accept_status field in related users/leads/contacts etc. and filtered these users who not decline this event.
222
                if ($checkDecline && !self::isDecline($event, $personBean)) {
223
                    if (!empty($personBean->email1)) {
224
                        $arr = array(
225
                            'type' => $inviteeModule,
226
                            'name' => $personBean->full_name,
227
                            'email' => $personBean->email1,
228
                        );
229
                        $emails[] = $arr;
230
                    }
231
                }
232
            }
233
        }
234
        return $emails;
235
    }
236
237
    private static function getUnsentEmailReminders()
238
    {
239
        global $db;
240
        $reminders = array();
241
        $reminderBeans = BeanFactory::getBean('Reminders')->get_full_list('', "reminders.email = 1 AND reminders.email_sent = 0");
242
        if (!empty($reminderBeans)) {
243
            foreach ($reminderBeans as $reminderBean) {
244
                $eventBean = BeanFactory::getBean($reminderBean->related_event_module, $reminderBean->related_event_module_id);
245
                $dateStart = $eventBean->date_start;
246
                $time = strtotime($db->fromConvert($dateStart, 'datetime'));
247
                $dateStart = date(TimeDate::DB_DATETIME_FORMAT, $time);
248
                $remind_ts = $GLOBALS['timedate']->fromDb($db->fromConvert($dateStart, 'datetime'))->modify("-{$reminderBean->timer_email} seconds")->ts;
249
                $now_ts = $GLOBALS['timedate']->getNow()->ts;
250
                if ($now_ts >= $remind_ts) {
251
                    $reminders[$reminderBean->id] = $reminderBean;
252
                }
253
            }
254
        }
255
        return $reminders;
256
    }
257
258
    // ---- popup and alert reminders
259
260
    /**
261
     * Show a popup and/or desktop notification alert for related users with related Event information.
262
     * Call in jsAlerts class and use original jsAlerts for show notifications.
263
     *
264
     * @global ??? $current_user
265
     * @global ??? $timedate
266
     * @global ??? $app_list_strings
267
     * @global ??? $db
268
     * @global ??? $sugar_config
269
     * @global ??? $app_strings
270
     * @param jsAlerts $alert caller jsAlerts object
271
     * @param boolean $checkDecline (optional) Send email if user accept status is not decline. Default is TRUE.
272
     * @return ???
0 ignored issues
show
Documentation introduced by
The doc-type ??? could not be parsed: Unknown type name "???" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
273
     */
274
    public static function addNotifications(jsAlerts $alert, $checkDecline = true)
275
    {
276
        global $current_user, $timedate, $app_list_strings, $db, $sugar_config, $app_strings;
277
278
        if (empty($current_user->id)) {
279
            return;
280
        }
281
282
        //Create separate variable to hold timedate value
283
        $alertDateTimeNow = $timedate->nowDb();
284
285
        // cn: get a boundary limiter
286
        $dateTimeMax = $timedate->getNow()->modify("+{$app_list_strings['reminder_max_time']} seconds")->asDb();
287
        $dateTimeNow = $timedate->nowDb();
288
289
        $dateTimeNow = $db->convert($db->quoted($dateTimeNow), 'datetime');
290
        $dateTimeMax = $db->convert($db->quoted($dateTimeMax), 'datetime');
291
292
        // Original jsAlert used to a meeting integration.
293
294
        ///////////////////////////////////////////////////////////////////////
295
        ////	MEETING INTEGRATION
296
        $meetingIntegration = null;
297
        if (isset($sugar_config['meeting_integration']) && !empty($sugar_config['meeting_integration'])) {
298
            if (!class_exists($sugar_config['meeting_integration'])) {
299
                require_once("modules/{$sugar_config['meeting_integration']}/{$sugar_config['meeting_integration']}.php");
300
            }
301
            $meetingIntegration = new $sugar_config['meeting_integration']();
302
        }
303
        ////	END MEETING INTEGRATION
304
        ///////////////////////////////////////////////////////////////////////
305
306
        $popupReminders = BeanFactory::getBean('Reminders')->get_full_list('', "reminders.popup = 1");
307
308
        if ($popupReminders) {
309
            foreach ($popupReminders as $popupReminder) {
310
                $relatedEvent = BeanFactory::getBean($popupReminder->related_event_module, $popupReminder->related_event_module_id);
311
                if ($relatedEvent &&
312
                    (!isset($relatedEvent->status) || $relatedEvent->status == 'Planned') &&
313
                    (!isset($relatedEvent->date_start) || (strtotime($relatedEvent->date_start) >= strtotime(self::unQuoteTime($dateTimeNow)) && strtotime($relatedEvent->date_start) <= strtotime(self::unQuoteTime($dateTimeMax)))) &&
314
                    (!$checkDecline || ($checkDecline && !self::isDecline($relatedEvent, BeanFactory::getBean('Users', $current_user->id))))
315
                ) {
316
                    // The original popup/alert reminders check the accept_status field in related users/leads/contacts etc. and filtered these users who not decline this event.
317
                    $invitees = BeanFactory::getBean('Reminders_Invitees')->get_full_list('', "reminders_invitees.reminder_id = '{$popupReminder->id}' AND reminders_invitees.related_invitee_module_id = '{$current_user->id}'");
318
                    if ($invitees) {
319
                        foreach ($invitees as $invitee) {
320
                            // need to concatenate since GMT times can bridge two local days
321
                            $timeStart = strtotime($db->fromConvert(isset($relatedEvent->date_start) ? $relatedEvent->date_start : date(TimeDate::DB_DATETIME_FORMAT), 'datetime'));
322
                            $timeRemind = $popupReminder->timer_popup;
323
                            $timeStart -= $timeRemind;
324
325
                            $url = 'index.php?action=DetailView&module=' . $popupReminder->related_event_module . '&record=' . $popupReminder->related_event_module_id;
326
                            $instructions = $app_strings['MSG_JS_ALERT_MTG_REMINDER_MEETING_MSG'];
327
328
                            if ($popupReminder->related_event_module == 'Meetings') {
329
                                ///////////////////////////////////////////////////////////////////
330
                                ////	MEETING INTEGRATION
331
                                if (!empty($meetingIntegration) && $meetingIntegration->isIntegratedMeeting($popupReminder->related_event_module_id)) {
332
                                    $url = $meetingIntegration->miUrlGetJsAlert((array)$popupReminder);
333
                                    $instructions = $meetingIntegration->miGetJsAlertInstructions();
334
                                }
335
                                ////	END MEETING INTEGRATION
336
                                ///////////////////////////////////////////////////////////////////
337
                            }
338
339
                            $meetingName = from_html(isset($relatedEvent->name) ? $relatedEvent->name : $app_strings['MSG_JS_ALERT_MTG_REMINDER_NO_EVENT_NAME']);
340
                            $desc1 = from_html(isset($relatedEvent->description) ? $relatedEvent->description : $app_strings['MSG_JS_ALERT_MTG_REMINDER_NO_DESCRIPTION']);
341
                            $location = from_html(isset($relatedEvent->location) ? $relatedEvent->location : $app_strings['MSG_JS_ALERT_MTG_REMINDER_NO_LOCATION']);
342
343
                            $relatedToMeeting = $alert->getRelatedName($popupReminder->related_event_module, $popupReminder->related_event_module_id);
344
345
                            $description = empty($desc1) ? '' : $app_strings['MSG_JS_ALERT_MTG_REMINDER_AGENDA'] . $desc1 . "\n";
346
                            $description = $description . "\n" . $app_strings['MSG_JS_ALERT_MTG_REMINDER_STATUS'] . (isset($relatedEvent->status) ? $relatedEvent->status : '') . "\n" . $app_strings['MSG_JS_ALERT_MTG_REMINDER_RELATED_TO'] . $relatedToMeeting;
347
348
349
                            if (isset($relatedEvent->date_start)) {
350
                                $time_dbFromConvert = $db->fromConvert($relatedEvent->date_start, 'datetime');
351
                                $time = $timedate->to_display_date_time($time_dbFromConvert);
352
                                if (!$time) {
353
                                    $time = $relatedEvent->date_start;
354
                                }
355
                                if (!$time) {
356
                                    $time = $app_strings['MSG_JS_ALERT_MTG_REMINDER_NO_START_DATE'];
357
                                }
358
                            } else {
359
                                $time = $app_strings['MSG_JS_ALERT_MTG_REMINDER_NO_START_DATE'];
360
                            }
361
362
                            // standard functionality
363
                            $alert->addAlert($app_strings['MSG_JS_ALERT_MTG_REMINDER_MEETING'], $meetingName,
364
                                $app_strings['MSG_JS_ALERT_MTG_REMINDER_TIME'] . $time,
365
                                $app_strings['MSG_JS_ALERT_MTG_REMINDER_LOC'] . $location .
366
                                $description .
367
                                $instructions,
368
                                $timeStart - strtotime($alertDateTimeNow),
369
                                $url
370
                            );
371
                        }
372
                    }
373
                }
374
            }
375
        }
376
    }
377
378
    private static function unQuoteTime($timestr)
379
    {
380
        $ret = '';
381
        for ($i = 0; $i < strlen($timestr); $i++) {
382
            if ($timestr[$i] != "'") $ret .= $timestr[$i];
383
        }
384
        return $ret;
385
    }
386
387
    // --- test for accept status decline is?
388
389
    private static function isDecline(SugarBean $event, SugarBean $person)
390
    {
391
        return self::testEventPersonAcceptStatus($event, $person, 'decline');
392
    }
393
394
    private static function testEventPersonAcceptStatus(SugarBean $event, SugarBean $person, $acceptStatus = 'decline')
395
    {
396
        if ($acceptStats = self::getEventPersonAcceptStatus($event, $person)) {
397
            $acceptStatusLower = strtolower($acceptStatus);
398
            foreach ((array)$acceptStats as $acceptStat) {
399
                if (strtolower($acceptStat) == $acceptStatusLower) {
400
                    return true;
401
                }
402
            }
403
        }
404
        return false;
405
    }
406
407
    private static function getEventPersonAcceptStatus(SugarBean $event, SugarBean $person)
408
    {
409
        global $db;
410
        $rel_person_table_Key = "rel_{$person->table_name}_table";
411
        $rel_person_table_Value = "{$event->table_name}_{$person->table_name}";
412
        if (isset($event->$rel_person_table_Key) && $event->$rel_person_table_Key == $rel_person_table_Value) {
413
            $query = self::getEventPersonQuery($event, $person);
414
            $re = $db->query($query);
415
            $ret = array();
416
            while ($row = $db->fetchByAssoc($re)) {
417
                if (!isset($row['accept_status'])) {
418
                    return null;
419
                }
420
                $ret[] = $row['accept_status'];
421
            }
422
            return $ret;
423
        }
424
        return null;
425
    }
426
427
    private function upgradeEventPersonQuery(SugarBean $event, $person_table)
428
    {
429
        $eventIdField = strtolower($event->object_name) . '_id';
430
        $query = "
431
			SELECT * FROM {$event->table_name}_{$person_table}
432
			WHERE
433
				{$eventIdField} = '{$event->id}' AND
434
				deleted = 0
435
		";
436
        return $query;
437
    }
438
439
    private static function getEventPersonQuery(SugarBean $event, SugarBean $person)
440
    {
441
        $eventIdField = array_search($event->table_name, $event->relationship_fields);
442
        if (!$eventIdField) {
443
            $eventIdField = strtolower($event->object_name . '_id');
444
        }
445
        $personIdField = strtolower($person->object_name) . '_id';
446
        $query = "
447
			SELECT * FROM {$event->table_name}_{$person->table_name}
448
			WHERE
449
				{$eventIdField} = '{$event->id}' AND
450
				{$personIdField} = '{$person->id}' AND
451
				deleted = 0
452
		";
453
        return $query;
454
    }
455
456
    // --- user preferences as default values in reminders
457
458
    /**
459
     * Default values for Reminders from User Preferences
460
     * @return string JSON encoded default values
461
     * @throws Exception on json_encode error
462
     */
463
    public static function loadRemindersDefaultValuesDataJson()
464
    {
465
        $ret = json_encode(self::loadRemindersDefaultValuesData());
466
        if (!$ret && json_last_error()) {
467
            throw new Exception(json_last_error_msg());
468
        }
469
        return $ret;
470
    }
471
472
    /**
473
     * Default values for Reminders from User Preferences
474
     * @return array default values
475
     */
476
    public static function loadRemindersDefaultValuesData()
477
    {
478
        global $current_user;
479
480
        $preferencePopupReminderTime = $current_user->getPreference('reminder_time');
481
        $preferenceEmailReminderTime = $current_user->getPreference('email_reminder_time');
482
        $preferencePopupReminderChecked = $current_user->getPreference('reminder_checked');
483
        $preferenceEmailReminderChecked = $current_user->getPreference('email_reminder_checked');
484
485
        return array(
486
            'popup' => $preferencePopupReminderChecked,
487
            'email' => $preferenceEmailReminderChecked,
488
            'timer_popup' => $preferencePopupReminderTime,
489
            'timer_email' => $preferenceEmailReminderTime,
490
        );
491
    }
492
493
    // --- upgrade
494
495
    /**
496
     * Reminders upgrade, old reminders migrate to multiple-reminders.
497
     * @throws Exception unknown event type or any error
498
     */
499
    public static function upgrade()
500
    {
501
        self::upgradeUserPreferences();
502
        self::upgradeEventReminders('Calls');
503
        self::upgradeEventReminders('Meetings');
504
        self::upgradeRestoreReminders();
505
    }
506
507
    private static function upgradeRestoreReminders()
508
    {
509
        if ($reminders = BeanFactory::getBean('Reminders')->get_full_list('', 'reminders.deleted = 1')) {
510
            foreach ($reminders as $reminder) {
511
                $reminder->deleted = 0;
512
                $reminder->save();
513
            }
514
        }
515
        if ($reminderInvitees = BeanFactory::getBean('Reminders_Invitees')->get_full_list('', 'reminders_invitees.deleted = 1')) {
516
            foreach ($reminderInvitees as $invitee) {
517
                $invitee->deleted = 0;
518
                $invitee->save();
519
            }
520
        }
521
        global $db;
522
        $q = "UPDATE reminders SET deleted = 0";
523
        $db->query($q);
524
        $q = "UPDATE reminders_invitees SET deleted = 0";
525
        $db->query($q);
526
    }
527
528
    private static function upgradeUserPreferences()
529
    {
530
        $users = User::getActiveUsers();
531
        foreach ($users as $user_id => $user_name) {
532
            $user = new User();
533
            $user->retrieve($user_id);
534
535
            $preferencePopupReminderTime = $user->getPreference('reminder_time');
536
            $preferenceEmailReminderTime = $user->getPreference('email_reminder_time');
537
538
            $preferencePopupReminderChecked = $preferencePopupReminderTime > -1;
539
            $preferenceEmailReminderChecked = $preferenceEmailReminderTime > -1;
540
            $user->setPreference('reminder_checked', $preferencePopupReminderChecked);
541
            $user->setPreference('email_reminder_checked', $preferenceEmailReminderChecked);
542
543
        }
544
    }
545
546
    /**
547
     * @param string $eventModule 'Calls' or 'Meetings'
548
     */
549
    private static function upgradeEventReminders($eventModule)
550
    {
551
552
        $eventBean = BeanFactory::getBean($eventModule);
553
        $events = BeanFactory::getBean($eventModule)->get_full_list('', "{$eventBean->table_name}.date_start >  '2015-11-01 00:00:00' AND ({$eventBean->table_name}.reminder_time != -1 OR ({$eventBean->table_name}.email_reminder_time != -1 AND {$eventBean->table_name}.email_reminder_sent != 1))");
554
        if ($events) {
555
            foreach ($events as $event) {
556
557
                $oldReminderPopupChecked = false;
558
                $oldReminderPopupTimer = null;
559
                if ($event->reminder_time != -1) {
560
                    $oldReminderPopupChecked = true;
561
                    $oldReminderPopupTimer = $event->reminder_time;
562
                }
563
564
                $oldReminderEmailChecked = false;
565
                $oldReminderEmailTimer = null;
566
                if ($event->email_reminder_time != -1) {
567
                    $oldReminderEmailChecked = true;
568
                    $oldReminderEmailTimer = $event->email_reminder_time;
569
                }
570
571
                $oldReminderEmailSent = $event->email_reminder_sent;
572
573
                if (($oldInvitees = self::getOldEventInvitees($event)) && ($event->reminder_time != -1 || ($event->email_reminder_time != -1 && $event->email_reminder_sent != 1))) {
574
575
                    self::migrateReminder(
576
                        $eventModule,
577
                        $event->id,
578
                        $oldReminderPopupChecked,
579
                        $oldReminderPopupTimer,
580
                        $oldReminderEmailChecked,
581
                        $oldReminderEmailTimer,
582
                        $oldReminderEmailSent,
583
                        $oldInvitees
584
                    );
585
586
                }
587
            }
588
        }
589
590
    }
591
592
593
    private static function getOldEventInvitees(SugarBean $event)
594
    {
595
        global $db;
596
        $ret = array();
597
        $persons = array('users', 'contacts', 'leads');
598
        foreach ($persons as $person) {
599
            $query = self::upgradeEventPersonQuery($event, $person);
600
            $re = $db->query($query);
601
            while ($row = $db->fetchByAssoc($re)) {
602
                $ret[] = $row;
603
            }
604
        }
605
        return $ret;
606
    }
607
608
    /**
609
     * @param string $eventModule 'Calls' or 'Meetings'
610
     * @param string $eventModuleId
611
     * @param bool $oldReminderPopupChecked
612
     * @param int $oldReminderPopupTimer
613
     * @param bool $oldReminderEmailChecked
614
     * @param int $oldReminderEmailTimer
615
     * @param array $oldInvitees
616
     */
617
    private static function migrateReminder($eventModule, $eventModuleId, $oldReminderPopupChecked, $oldReminderPopupTimer, $oldReminderEmailChecked, $oldReminderEmailTimer, $oldReminderEmailSent, $oldInvitees)
618
    {
619
620
        $reminder = BeanFactory::getBean('Reminders');
621
        $reminder->popup = $oldReminderPopupChecked;
622
        $reminder->email = $oldReminderEmailChecked;
623
        $reminder->email_sent = $oldReminderEmailSent;
624
        $reminder->timer_popup = $oldReminderPopupTimer;
625
        $reminder->timer_email = $oldReminderEmailTimer;
626
        $reminder->related_event_module = $eventModule;
627
        $reminder->related_event_module_id = $eventModuleId;
628
        $reminder->save();
629
        $reminderId = $reminder->id;
630
        self::migrateReminderInvitees($reminderId, $oldInvitees);
631
632
        self::removeOldReminder($eventModule, $eventModuleId);
633
    }
634
635
    private static function migrateReminderInvitees($reminderId, $invitees)
636
    {
637
        $ret = array();
638
        foreach ((array)$invitees as $invitee) {
639
            $newInvitee = BeanFactory::getBean('Reminders_Invitees');
640
            $newInvitee->reminder_id = $reminderId;
641
            $newInvitee->related_invitee_module = self::getRelatedInviteeModuleFromInviteeArray($invitee);
642
            $newInvitee->related_invitee_module_id = self::getRelatedInviteeModuleIdFromInviteeArray($invitee);
643
            $newInvitee->save();
644
        }
645
        return $ret;
646
    }
647
648
    private static function getRelatedInviteeModuleFromInviteeArray($invitee)
649
    {
650
        if (array_key_exists('user_id', $invitee)) {
651
            return 'Users';
652
        }
653
        if (array_key_exists('lead_id', $invitee)) {
654
            return 'Leads';
655
        }
656
        if (array_key_exists('contact_id', $invitee)) {
657
            return 'Contacts';
658
        }
659
        // TODO:!!!!
660
        throw new Exception('Unknown invitee module type');
661
        //return null;
662
    }
663
664
    private static function getRelatedInviteeModuleIdFromInviteeArray($invitee)
665
    {
666
        if (array_key_exists('user_id', $invitee)) {
667
            return $invitee['user_id'];
668
        }
669
        if (array_key_exists('lead_id', $invitee)) {
670
            return $invitee['lead_id'];
671
        }
672
        if (array_key_exists('contact_id', $invitee)) {
673
            return $invitee['contact_id'];
674
        }
675
        // TODO:!!!!
676
        throw new Exception('Unknown invitee type');
677
        //return null;
678
    }
679
680
    /**
681
     * @param string $eventModule 'Calls' or 'Meetings'
682
     * @param string $eventModuleId
683
     */
684
    private static function removeOldReminder($eventModule, $eventModuleId)
685
    {
686
        $event = BeanFactory::getBean($eventModule, $eventModuleId);
687
        $event->reminder_time = -1;
688
        $event->email_reminder_time = -1;
689
        $event->email_reminder_sent = 0;
690
        $event->save();
691
    }
692
693
    // --- reminders list on detail views
694
695
    /**
696
     * Return a list of related reminders for specified event (Calls/Meetings). Call it from DetailViews.
697
     * @param SugarBean $event a Call or Meeting Bean
698
     * @return mixed|string|void output of list (html)
699
     * @throws Exception on json error in Remainders
700
     */
701
    public static function getRemindersListView(SugarBean $event)
702
    {
703
        global $mod_strings, $app_list_strings;
704
        $tpl = new Sugar_Smarty();
705
        $tpl->assign('MOD', $mod_strings);
706
        $tpl->assign('reminder_time_options', $app_list_strings['reminder_time_options']);
707
        $tpl->assign('remindersData', Reminder::loadRemindersData($event->module_name, $event->id));
708
        $tpl->assign('remindersDataJson', Reminder::loadRemindersDataJson($event->module_name, $event->id));
709
        $tpl->assign('remindersDefaultValuesDataJson', Reminder::loadRemindersDefaultValuesDataJson());
710
        $tpl->assign('remindersDisabled', json_encode(true));
711
        return $tpl->fetch('modules/Reminders/tpls/reminders.tpl');
712
    }
713
714
    /*
715
     * @todo implenent it
716
     */
717
    public static function getRemindersListInlineEditView(SugarBean $event)
718
    {
719
        // TODO: getEditFieldHTML() function in InlineEditing.php:218 doesn't pass the Bean ID to this custom inline edit view function but we have to know which Bean are in the focus to editing.
720
        if (!$event->id) {
721
            throw new Exception("No GUID for edit.");
722
        }
723
    }
724
725
}
726
727
?>