diff --git a/application/Espo/Classes/Cleanup/Reminders.php b/application/Espo/Classes/Cleanup/Reminders.php index fd45af27b6..0e6159ec94 100644 --- a/application/Espo/Classes/Cleanup/Reminders.php +++ b/application/Espo/Classes/Cleanup/Reminders.php @@ -31,18 +31,19 @@ namespace Espo\Classes\Cleanup; use Espo\Core\Cleanup\Cleanup; use Espo\Core\Utils\Config; +use Espo\Core\Utils\DateTime as DateTimeUtil; +use Espo\Modules\Crm\Entities\Reminder; use Espo\ORM\EntityManager; use DateTime; class Reminders implements Cleanup { - private $config; - - private $entityManager; - private string $cleanupRemindersPeriod = '15 days'; + private Config $config; + private EntityManager $entityManager; + public function __construct(Config $config, EntityManager $entityManager) { $this->config = $config; @@ -60,9 +61,9 @@ class Reminders implements Cleanup $delete = $this->entityManager ->getQueryBuilder() ->delete() - ->from('Reminder') + ->from(Reminder::ENTITY_TYPE) ->where([ - 'remindAt<' => $dt->format('Y-m-d'), + 'remindAt<' => $dt->format(DateTimeUtil::SYSTEM_DATE_TIME_FORMAT), ]) ->build(); diff --git a/application/Espo/Core/FieldProcessing/Reminder/Loader.php b/application/Espo/Core/FieldProcessing/Reminder/Loader.php index 7b47838f55..d7aa4960c4 100644 --- a/application/Espo/Core/FieldProcessing/Reminder/Loader.php +++ b/application/Espo/Core/FieldProcessing/Reminder/Loader.php @@ -29,13 +29,13 @@ namespace Espo\Core\FieldProcessing\Reminder; +use Espo\Modules\Crm\Entities\Reminder; +use Espo\ORM\Collection; use Espo\ORM\Entity; -use Espo\Core\{ - ORM\EntityManager, - FieldProcessing\Loader as LoaderInterface, - FieldProcessing\Loader\Params, -}; +use Espo\Core\FieldProcessing\Loader as LoaderInterface; +use Espo\Core\FieldProcessing\Loader\Params; +use Espo\Core\ORM\EntityManager; /** * @internal This class should not be removed as it's used by custom entities. @@ -43,12 +43,8 @@ use Espo\Core\{ */ class Loader implements LoaderInterface { - private $entityManager; - - public function __construct(EntityManager $entityManager) - { - $this->entityManager = $entityManager; - } + public function __construct(private EntityManager $entityManager) + {} public function process(Entity $entity, Params $params): void { @@ -75,8 +71,9 @@ class Loader implements LoaderInterface { $list = []; + /** @var Collection $collection */ $collection = $this->entityManager - ->getRDBRepository('Reminder') + ->getRDBRepository(Reminder::ENTITY_TYPE) ->select(['seconds', 'type']) ->where([ 'entityType' => $entity->getEntityType(), @@ -88,8 +85,8 @@ class Loader implements LoaderInterface foreach ($collection as $reminder) { $list[] = (object) [ - 'seconds' => $reminder->get('seconds'), - 'type' => $reminder->get('type'), + 'seconds' => $reminder->getSeconds(), + 'type' => $reminder->getType(), ]; } diff --git a/application/Espo/Core/Repositories/Event.php b/application/Espo/Core/Repositories/Event.php index 1fd09bd5e0..6e660e47e1 100644 --- a/application/Espo/Core/Repositories/Event.php +++ b/application/Espo/Core/Repositories/Event.php @@ -29,12 +29,12 @@ namespace Espo\Core\Repositories; +use Espo\Modules\Crm\Entities\Meeting; +use Espo\Modules\Crm\Entities\Reminder; use Espo\ORM\Entity; -use Espo\Core\{ - Di, - Utils\DateTime as DateTimeUtil, -}; +use Espo\Core\Di; +use Espo\Core\Utils\DateTime as DateTimeUtil; use DateTime; use DateTimeZone; @@ -55,7 +55,10 @@ class Event extends Database implements /** * @var string[] */ - protected $reminderSkippingStatusList = ['Held', 'Not Held']; + protected $reminderSkippingStatusList = [ + Meeting::STATUS_HELD, + Meeting::STATUS_NOT_HELD, + ]; /** * @param array $options @@ -93,13 +96,13 @@ class Event extends Database implements $dt = new DateTime( $this->convertDateTimeToDefaultTimezone($dateEndDate . ' 00:00:00') ); - } catch (Exception $e) { + } catch (Exception) { throw new RuntimeException("Bad date-time."); } $dt->modify('+1 day'); - $dateEnd = $dt->format('Y-m-d H:i:s'); + $dateEnd = $dt->format(DateTimeUtil::SYSTEM_DATE_TIME_FORMAT); $entity->set('dateEnd', $dateEnd); } else { @@ -120,7 +123,7 @@ class Event extends Database implements $delete = $this->entityManager->getQueryBuilder() ->delete() - ->from('Reminder') + ->from(Reminder::ENTITY_TYPE) ->where([ 'entityId' => $entity->getId(), 'entityType' => $entity->getEntityType(), @@ -140,11 +143,7 @@ class Event extends Database implements $tz = new DateTimeZone($timeZone); - $dt = DateTime::createFromFormat( - DateTimeUtil::SYSTEM_DATE_TIME_FORMAT, - $string, - $tz - ); + $dt = DateTime::createFromFormat(DateTimeUtil::SYSTEM_DATE_TIME_FORMAT, $string, $tz); if ($dt === false) { throw new RuntimeException("Could not parse date-time `{$string}`."); diff --git a/application/Espo/Modules/Crm/Entities/Reminder.php b/application/Espo/Modules/Crm/Entities/Reminder.php index 3eb7ab8b33..e8f20d20ad 100644 --- a/application/Espo/Modules/Crm/Entities/Reminder.php +++ b/application/Espo/Modules/Crm/Entities/Reminder.php @@ -29,7 +29,9 @@ namespace Espo\Modules\Crm\Entities; -class Reminder extends \Espo\Core\ORM\Entity +use Espo\Core\ORM\Entity; + +class Reminder extends Entity { public const ENTITY_TYPE = 'Reminder'; @@ -50,4 +52,14 @@ class Reminder extends \Espo\Core\ORM\Entity { return $this->get('entityType'); } + + public function getType(): ?string + { + return $this->get('type'); + } + + public function getSeconds(): int + { + return (int) $this->get('seconds'); + } } diff --git a/application/Espo/Modules/Crm/Jobs/SendEmailReminders.php b/application/Espo/Modules/Crm/Jobs/SendEmailReminders.php index 9a936e4bb1..9d682b2dd7 100644 --- a/application/Espo/Modules/Crm/Jobs/SendEmailReminders.php +++ b/application/Espo/Modules/Crm/Jobs/SendEmailReminders.php @@ -29,16 +29,14 @@ namespace Espo\Modules\Crm\Jobs; -use Espo\Core\{ - InjectableFactory, - ORM\EntityManager, - Utils\Config, - Job\JobDataLess, - Utils\Log, -}; - +use Espo\Core\InjectableFactory; +use Espo\Core\Job\JobDataLess; +use Espo\Core\ORM\EntityManager; +use Espo\Core\Utils\Config; +use Espo\Core\Utils\DateTime as DateTimeUtil; +use Espo\Core\Utils\Log; use Espo\Modules\Crm\Business\Reminder\EmailReminder; - +use Espo\Modules\Crm\Entities\Reminder; use Throwable; use DateTime; use DateInterval; @@ -47,40 +45,29 @@ class SendEmailReminders implements JobDataLess { private const MAX_PORTION_SIZE = 10; - private $injectableFactory; - - private $entityManager; - - private $config; - - private $log; - public function __construct( - InjectableFactory $injectableFactory, - EntityManager $entityManager, - Config $config, - Log $log - ) { - $this->injectableFactory = $injectableFactory; - $this->entityManager = $entityManager; - $this->config = $config; - $this->log = $log; - } + private InjectableFactory $injectableFactory, + private EntityManager $entityManager, + private Config $config, + private Log $log + ) {} public function run(): void { $dt = new DateTime(); - $now = $dt->format('Y-m-d H:i:s'); + $now = $dt->format(DateTimeUtil::SYSTEM_DATE_TIME_FORMAT); - $nowShifted = $dt->sub(new DateInterval('PT1H'))->format('Y-m-d H:i:s'); + $nowShifted = $dt + ->sub(new DateInterval('PT1H')) + ->format(DateTimeUtil::SYSTEM_DATE_TIME_FORMAT); $maxPortionSize = $this->config->get('emailReminderPortionSize') ?? self::MAX_PORTION_SIZE; $collection = $this->entityManager - ->getRDBRepository('Reminder') + ->getRDBRepository(Reminder::ENTITY_TYPE) ->where([ - 'type' => 'Email', + 'type' => Reminder::TYPE_EMAIL, 'remindAt<=' => $now, 'startAt>' => $nowShifted, ]) @@ -98,13 +85,11 @@ class SendEmailReminders implements JobDataLess $emailReminder->send($entity); } catch (Throwable $e) { - $this->log->error( - "Email reminder '{$entity->getId()}': " . $e->getMessage() - ); + $this->log->error("Email reminder '{$entity->getId()}': " . $e->getMessage()); } $this->entityManager - ->getRDBRepository('Reminder') + ->getRDBRepository(Reminder::ENTITY_TYPE) ->deleteFromDb($entity->getId()); } } diff --git a/application/Espo/Modules/Crm/Jobs/SubmitPopupReminders.php b/application/Espo/Modules/Crm/Jobs/SubmitPopupReminders.php index 05feead292..fa553d1ced 100644 --- a/application/Espo/Modules/Crm/Jobs/SubmitPopupReminders.php +++ b/application/Espo/Modules/Crm/Jobs/SubmitPopupReminders.php @@ -30,16 +30,14 @@ namespace Espo\Modules\Crm\Jobs; use Espo\Core\ORM\Entity as CoreEntity; - +use Espo\Modules\Crm\Entities\Meeting; use Espo\Modules\Crm\Entities\Reminder; - -use Espo\Core\{ - ORM\EntityManager, - Utils\Config, - WebSocket\Submission as WebSocketSubmission, - Job\JobDataLess, - Utils\Log, -}; +use Espo\Core\Job\JobDataLess; +use Espo\Core\ORM\EntityManager; +use Espo\Core\Utils\Config; +use Espo\Core\Utils\DateTime as DateTimeUtil; +use Espo\Core\Utils\Log; +use Espo\Core\WebSocket\Submission as WebSocketSubmission; use Throwable; use DateTime; @@ -48,25 +46,12 @@ class SubmitPopupReminders implements JobDataLess { private const REMINDER_PAST_HOURS = 24; - private $entityManager; - - private $config; - - private $webSocketSubmission; - - private $log; - public function __construct( - EntityManager $entityManager, - Config $config, - WebSocketSubmission $webSocketSubmission, - Log $log - ) { - $this->entityManager = $entityManager; - $this->config = $config; - $this->webSocketSubmission = $webSocketSubmission; - $this->log = $log; - } + private EntityManager $entityManager, + private Config $config, + private WebSocketSubmission $webSocketSubmission, + private Log $log + ) {} public function run(): void { @@ -75,17 +60,18 @@ class SubmitPopupReminders implements JobDataLess } $dt = new DateTime(); - - $now = $dt->format('Y-m-d H:i:s'); + $now = $dt->format(DateTimeUtil::SYSTEM_DATE_TIME_FORMAT); $pastHours = $this->config->get('reminderPastHours', self::REMINDER_PAST_HOURS); - $nowShifted = $dt->modify('-' . $pastHours . ' hours')->format('Y-m-d H:i:s'); + $nowShifted = $dt + ->modify('-' . $pastHours . ' hours') + ->format(DateTimeUtil::SYSTEM_DATE_TIME_FORMAT); $reminderList = $this->entityManager - ->getRDBRepository('Reminder') + ->getRDBRepository(Reminder::ENTITY_TYPE) ->where([ - 'type' => 'Popup', + 'type' => Reminder::TYPE_POPUP, 'remindAt<=' => $now, 'startAt>' => $nowShifted, 'isSubmitted' => false, @@ -99,13 +85,18 @@ class SubmitPopupReminders implements JobDataLess $entityType = $reminder->getTargetEntityType(); $entityId = $reminder->getTargetEntityId(); - if (!$userId || !$entityType || !$entityId) { + if ( + !$userId || + !$entityType || + !$entityId || + !$this->entityManager->hasRepository($entityType) + ) { $this->deleteReminder($reminder); continue; } - $entity = $this->entityManager->getEntity($entityType, $entityId); + $entity = $this->entityManager->getEntityById($entityType, $entityId); if (!$entity) { $this->deleteReminder($reminder); @@ -121,7 +112,7 @@ class SubmitPopupReminders implements JobDataLess $status = $entity->getLinkMultipleColumn('users', 'status', $userId); - if ($status === 'Declined') { + if ($status === Meeting::ATTENDEE_STATUS_DECLINED) { $this->deleteReminder($reminder); continue; @@ -130,36 +121,34 @@ class SubmitPopupReminders implements JobDataLess $dateAttribute = 'dateStart'; - if ($entityType === 'Task') { - $dateAttribute = 'dateEnd'; + $entityDefs = $this->entityManager->getDefs()->getEntity($entityType); + + if ($entityDefs->hasField('reminders')) { + $dateAttribute = $entityDefs + ->getField('reminders') + ->getParam('dateField') ?? $dateAttribute; } - $data = [ + $submitData[$userId] ??= []; + + $submitData[$userId][] = [ 'id' => $reminder->getId(), - 'data' => [ + 'data' => (object) [ 'id' => $entity->getId(), 'entityType' => $entityType, $dateAttribute => $entity->get($dateAttribute), 'name' => $entity->get('name'), ], - ]; - - if (!array_key_exists($userId, $submitData)) { - $submitData[$userId] = []; - } - - $submitData[$userId][] = $data; + ];; $reminder->set('isSubmitted', true); - $this->entityManager->saveEntity($reminder); } foreach ($submitData as $userId => $list) { try { - $this->webSocketSubmission->submit('popupNotifications.event', $userId, (object) [ - 'list' => $list - ]); + $this->webSocketSubmission + ->submit('popupNotifications.event', $userId, (object) ['list' => $list]); } catch (Throwable $e) { $this->log->error('Job SubmitPopupReminders: [' . $e->getCode() . '] ' .$e->getMessage()); @@ -167,8 +156,10 @@ class SubmitPopupReminders implements JobDataLess } } - protected function deleteReminder(Reminder $reminder): void + private function deleteReminder(Reminder $reminder): void { - $this->entityManager->getRDBRepository('Reminder')->deleteFromDb($reminder->getId()); + $this->entityManager + ->getRDBRepository(Reminder::ENTITY_TYPE) + ->deleteFromDb($reminder->getId()); } }