Since espo doesn't come with an ability to make recurring calendar, I was trying to make one myself. So far progress has been going alright, but I ran into a problem. It duplicates any meeting I try making, I don't know what is causing this, so I will share everything I've been working on and screenshots of the process to show what I've done so far.
I made a base for recurring calendar items, which will be extended for each calendar item I want this to work with in /var/www/espocrm/data/espocrm/custom/Espo/Custom/Hooks/Common/RecurringBase.php:
And in /var/www/espocrm/data/espocrm/custom/Espo/Custom/Hooks/Meeting/Recurring.php:
I will be completely honest, I don't really understand how coding works in espo, my knowledge of php is very limited, and espo is very difficult to understand, so I've just been using a lot of reference material to get to where I am. I uploaded screenshots of what the process looks like and what the results are currently, and I circled the part I added into espo myself. I don't know what is causing the meeting to duplicate twice a day instead of once. This also happens when you select weekly or monthly. Can someone help me with this please?
I made a base for recurring calendar items, which will be extended for each calendar item I want this to work with in /var/www/espocrm/data/espocrm/custom/Espo/Custom/Hooks/Common/RecurringBase.php:
HTML Code:
<?php
namespace Espo\Custom\Hooks\Common;
use Espo\ORM\Entity;
use Espo\Core\Hook\Hook\AfterSave;
use Espo\ORM\EntityManager;
use Espo\ORM\Repository\Option\SaveOptions;
class RecurringBase implements AfterSave
{
protected EntityManager $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function afterSave(Entity $entity, SaveOptions $options): void
{
// Skip if not recurring or if already a generated child
if (!$entity->get('repeat') || $options->get('isRecurringChild') === true) {
return;
}
$startDate = new \DateTime($entity->get('dateStart'));
$endDate = new \DateTime($entity->get('dateEnd'));
$until = $entity->get('repeatUntil') ? new \DateTime($entity->get('repeatUntil')) : null;
$interval = (int) $entity->get('repeatInterval') ?: 1;
$repeat = $entity->get('repeat');
$count = 0;
$max = 200;
while (true) {
$count++;
$newStart = (clone $startDate);
$newEnd = (clone $endDate);
switch ($repeat) {
case 'Daily':
$newStart->modify("+{$interval} days");
$newEnd->modify("+{$interval} days");
break;
case 'Weekly':
$newStart->modify("+{$interval} weeks");
$newEnd->modify("+{$interval} weeks");
break;
case 'Monthly':
$newStart->modify("+{$interval} months");
$newEnd->modify("+{$interval} months");
break;
default:
return;
}
if ($until && $newStart > $until) {
break;
}
$duplicate = $this->em->getEntityFactory()->create($entity->getEntityType());
foreach ([
'name','description','status',
'assignedUserId','teamsIds',
'parentId','parentType',
'allDay','reminders'
] as $f) {
if ($entity->has($f)) {
$duplicate->set($f, $entity->get($f));
}
}
$duplicate->set('dateStart', $newStart->format('Y-m-d H:i:s'));
$duplicate->set('dateEnd', $newEnd->format('Y-m-d H:i:s'));
// Clear recurrence so children don’t recurse
$duplicate->set('repeat', null);
$duplicate->set('repeatInterval', null);
$duplicate->set('repeatUntil', null);
// Save with flag
$this->em->saveEntity($duplicate, ['isRecurringChild' => true]);
if ($count >= $max) {
break;
}
$startDate = $newStart;
$endDate = $newEnd;
}
}
}
HTML Code:
<?php namespace Espo\Custom\Hooks\Meeting; use Espo\Custom\Hooks\Common\RecurringBase; class Recurring extends RecurringBase {}