SuiteCRM-Core/public/legacy/modules/Alerts/services/AddScheduledReminderAlerts.php
Clemente Raposo 1eddcb50bf [Legacy] Update AlertSchedulers alert reminder time calculation
Update calculation to on create the notification with the time that as scheduled for
2023-04-24 11:54:09 +01:00

391 lines
13 KiB
PHP

<?php
/**
* SuiteCRM is a customer relationship management program developed by SalesAgility Ltd.
* Copyright (C) 2023 SalesAgility Ltd.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by the
* Free Software Foundation with the addition of the following permission added
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
* IN WHICH THE COPYRIGHT IS OWNED BY SALESAGILITY, SALESAGILITY DISCLAIMS THE
* WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see http://www.gnu.org/licenses.
*
* In accordance with Section 7(b) of the GNU Affero General Public License
* version 3, these Appropriate Legal Notices must retain the display of the
* "Supercharged by SuiteCRM" logo. If the display of the logos is not reasonably
* feasible for technical reasons, the Appropriate Legal Notices must display
* the words "Supercharged by SuiteCRM".
*/
require_once __DIR__ . '/AddAlert.php';
class AddScheduledReminderAlerts
{
/**
* @var AddAlert
*/
protected $addAlertService;
public function __construct()
{
$this->addAlertService = new AddAlert();
}
/**
* @param $checkDecline bool
* @return void
*/
public function run($checkDecline = true): void
{
global $current_user, $timedate, $app_strings;
if (empty($current_user->id)) {
return;
}
[$dateTimeMaxStamp, $dateTimeNowStamp] = $this->getDateRange();
// Original jsAlert used to a meeting integration.
$meetingIntegration = $this->getMeetingIntegration();
$popupReminders = $this->getScheduledReminders($dateTimeNowStamp, $dateTimeMaxStamp);
if (empty($popupReminders)) {
return;
}
$i_runs = 0;
foreach ($popupReminders as $popupReminder) {
$relatedEventModule = $popupReminder->related_event_module ?? '';
$relatedEvent = BeanFactory::getBean(
$relatedEventModule,
$popupReminder->related_event_module_id
);
$dateTime = DateTime::createFromFormat($timedate->get_date_time_format(), $relatedEvent->date_start);
$relatedEventStart = $dateTime ? $dateTime->getTimestamp() : $dateTime;
if ($this->shouldUpdateExecutionTime($i_runs, $popupReminder)) {
$this->updateReminderExecutionTime($popupReminder, $relatedEventStart);
$i_runs++;
}
if (!$relatedEvent) {
continue;
}
$status = $relatedEvent->status ?? '';
if ($status !== '' && $relatedEvent->status !== 'Planned') {
continue;
}
$relatedEventStart -= $popupReminder->timer_popup;
if (!$this->isWithinExecutionDateRange($relatedEventStart, $dateTimeNowStamp, $dateTimeMaxStamp)) {
continue;
}
$user = BeanFactory::getBean('Users', $current_user->id);
if ($checkDecline && Reminder::isDecline($relatedEvent, $user)) {
continue;
}
// 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.
$invitees = $this->getInvitees($popupReminder, $current_user);
if (!$invitees) {
continue;
}
$url = $this->getURL($popupReminder);
$instructions = $this->getInstructions($app_strings['MSG_JS_ALERT_MTG_REMINDER_MEETING_MSG']);
if ($popupReminder->related_event_module === 'Meetings') {
[$url, $instructions] = $this->addMeetingOverrides($meetingIntegration, $popupReminder, $url,
$instructions);
}
$alertTitle = $this->getMeetingName($relatedEvent);
$location = $this->getLocation($relatedEvent);
$relatedToMeeting = $this->getRelatedName($popupReminder);
$description = $this->getDescription($relatedEvent, $app_strings, $relatedToMeeting);
$time = $this->getAlertTime($relatedEvent);
$alertSubtitle = $app_strings['MSG_JS_ALERT_MTG_REMINDER_TIME'] . $time;
$alertDescription = $app_strings['MSG_JS_ALERT_MTG_REMINDER_LOC'] . $location . $description . $instructions;
$this->addAlertService->run(
BeanFactory::getBeanName($relatedEvent->module_name) ?? '',
$alertTitle,
$alertDescription,
$url,
$time,
$popupReminder->id
);
}
}
/**
* @return array|null
*/
protected function getMeetingIntegration(): ?array
{
global $sugar_config;
$meetingIntegration = null;
if (isset($sugar_config['meeting_integration']) && !empty($sugar_config['meeting_integration'])) {
if (!class_exists($sugar_config['meeting_integration'])) {
require_once("modules/{$sugar_config['meeting_integration']}/{$sugar_config['meeting_integration']}.php");
}
$meetingIntegration = new $sugar_config['meeting_integration']();
}
return $meetingIntegration;
}
/**
* @param $dateTimeNowStamp
* @param $dateTimeMaxStamp
* @return SugarBean[]|null
*/
protected function getScheduledReminders($dateTimeNowStamp, $dateTimeMaxStamp): ?array
{
$popupReminders = BeanFactory::getBean('Reminders')->get_full_list(
'',
"reminders.popup = 1 AND
reminders.popup_viewed = 0 AND
(
reminders.date_willexecute = -1 OR
reminders.date_willexecute BETWEEN " . $dateTimeNowStamp . " AND " . $dateTimeMaxStamp . "
)"
);
return $popupReminders;
}
/**
* @param $relatedEvent
* @return string
*/
protected function getMeetingName($relatedEvent): string
{
global $app_strings;
$default = $app_strings['MSG_JS_ALERT_MTG_REMINDER_NO_EVENT_NAME'];
return from_html($relatedEvent->name ?? $default);
}
/**
* @param $relatedEvent
* @param array $app_strings
* @param string $relatedToMeeting
* @return string
*/
protected function getDescription($relatedEvent, array $app_strings, string $relatedToMeeting): string
{
$desc1 = from_html($relatedEvent->description ?? $app_strings['MSG_JS_ALERT_MTG_REMINDER_NO_DESCRIPTION']);
$description = empty($desc1) ? '' : $app_strings['MSG_JS_ALERT_MTG_REMINDER_AGENDA'] . $desc1 . "\n";
$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;
return $description;
}
/**
* @param $relatedEvent
* @return string
*/
protected function getLocation($relatedEvent): string
{
global $app_strings;
$default = $app_strings['MSG_JS_ALERT_MTG_REMINDER_NO_LOCATION'];
return from_html($relatedEvent->location ?? $default);
}
/**
* @param SugarBean $popupReminder
* @param $current_user
* @return SugarBean[]|null
*/
protected function getInvitees(SugarBean $popupReminder, $current_user): ?array
{
$invitees = BeanFactory::getBean('Reminders_Invitees')->get_full_list(
'',
"reminders_invitees.reminder_id = '{$popupReminder->id}' AND reminders_invitees.related_invitee_module_id = '{$current_user->id}'"
);
return $invitees;
}
/**
* To return the name of parent bean.
* @param $popupReminder
* @return string
*/
protected function getRelatedName($popupReminder): string
{
$parentType = $popupReminder->related_event_module;
$parentId = $popupReminder->related_event_module_id;
if (!empty($parentType) && !empty($parentId)) {
$parentBean = BeanFactory::getBean($parentType, $parentId);
if (($parentBean instanceof SugarBean) && isset($parentBean->name)) {
return $parentBean->name;
}
}
return '';
}
/**
* Get date range
* @return array
*/
protected function getDateRange(): array
{
global $timedate, $app_list_strings;
$reminder_max_time = $app_list_strings['reminder_max_time'] ?? 0;
$dateTimeMax = $timedate->getNow(true)->modify("+{$reminder_max_time} seconds")->asDb(false);
$dateTimeNow = $timedate->getNow(true)->asDb(false);
$dateTimeNowStamp = strtotime(Reminder::unQuoteTime($dateTimeNow));
$dateTimeMaxStamp = strtotime(Reminder::unQuoteTime($dateTimeMax));
return [$dateTimeMaxStamp, $dateTimeNowStamp];
}
/**
* @param SugarBean $popupReminder
* @param $relatedEventStart
* @return void
*/
protected function updateReminderExecutionTime(SugarBean $popupReminder, $relatedEventStart): void
{
//we have column to save data
if (!$relatedEventStart) {
$popupReminder->date_willexecute = -2;
} else {
$popupReminder->date_willexecute = $relatedEventStart;
}
$popupReminder->save();
}
/**
* @param int $i_runs
* @param SugarBean $popupReminder
* @return bool
*/
protected function shouldUpdateExecutionTime(int $i_runs, SugarBean $popupReminder): bool
{
return $i_runs < 1000 &&
isset($popupReminder->fetched_row['date_willexecute']) &&
$popupReminder->fetched_row['date_willexecute'] == -1;
}
/**
* @param $relatedEventStart
* @param $dateTimeNowStamp
* @param $dateTimeMaxStamp
* @return bool
*/
protected function isWithinExecutionDateRange($relatedEventStart, $dateTimeNowStamp, $dateTimeMaxStamp): bool
{
if (empty($relatedEventStart)) {
return false;
}
//increase time by 10 secs to make sure we calculate within the correct minute
if (($dateTimeNowStamp + 10) < $relatedEventStart) {
return false;
}
if ($relatedEventStart > $dateTimeMaxStamp) {
return false;
}
return true;
}
/**
* @param $relatedEvent
* @return mixed|string
*/
protected function getAlertTime($relatedEvent)
{
global $app_strings, $timedate, $db;
$default = $app_strings['MSG_JS_ALERT_MTG_REMINDER_NO_START_DATE'];
$dateStart = $relatedEvent->date_start ?? '';
if (!empty($dateStart)) {
$time_dbFromConvert = $db->fromConvert($dateStart, 'datetime');
$time = $timedate->to_display_date_time($time_dbFromConvert);
if (!$time) {
$time = $dateStart;
}
if (!$time) {
$time = $default;
}
} else {
$time = $default;
}
return $time;
}
/**
* @param SugarBean $popupReminder
* @return string
*/
protected function getURL(SugarBean $popupReminder): string
{
return Reminder::makeAlertURL(
$popupReminder->related_event_module,
$popupReminder->related_event_module_id
);
}
/**
* @param $MSG_JS_ALERT_MTG_REMINDER_MEETING_MSG
* @return mixed
*/
protected function getInstructions($MSG_JS_ALERT_MTG_REMINDER_MEETING_MSG)
{
return $MSG_JS_ALERT_MTG_REMINDER_MEETING_MSG;
}
/**
* @param array|null $meetingIntegration
* @param SugarBean $popupReminder
* @param $url
* @param $instructions
* @return array
*/
protected function addMeetingOverrides(
?array $meetingIntegration,
SugarBean $popupReminder,
$url,
$instructions
): array {
if (!empty($meetingIntegration) && $meetingIntegration->isIntegratedMeeting($popupReminder->related_event_module_id)) {
$url = $meetingIntegration->miUrlGetJsAlert((array)$popupReminder);
$instructions = $meetingIntegration->miGetJsAlertInstructions();
}
return [$url, $instructions];
}
}