app/Models/Contact/Reminder.php (90 lines of code) (raw):
<?php
namespace App\Models\Contact;
use Carbon\Carbon;
use App\Models\User\User;
use App\Helpers\DateHelper;
use App\Models\Account\Account;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use App\Models\ModelBindingHasherWithContact as Model;
/**
* A reminder has two states: active and inactive.
* An inactive reminder is basically a one_time reminder that has already be
* sent once and has been marked inactive so we don't schedule it again.
*
* @property string $next_expected_date_human_readable
* @property string $next_expected_date
*/
class Reminder extends Model
{
/**
* The attributes that aren't mass assignable.
*
* @var array
*/
protected $guarded = ['id'];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'is_birthday' => 'boolean',
'delible' => 'boolean',
'initial_date' => 'date:Y-m-d',
];
/**
* Valid value for frequency type.
*
* @var array
*/
public static $frequencyTypes = [
'one_time', 'week', 'month', 'year',
];
/**
* Get the account record associated with the reminder.
*
* @return BelongsTo
*/
public function account()
{
return $this->belongsTo(Account::class);
}
/**
* Get the contact record associated with the reminder.
*
* @return BelongsTo
*/
public function contact()
{
return $this->belongsTo(Contact::class);
}
/**
* Get the Reminder Outbox records associated with the account.
*
* @return HasMany
*/
public function reminderOutboxes()
{
return $this->hasMany(ReminderOutbox::class);
}
/**
* Scope a query to only include active reminders.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeActive($query)
{
return $query->where('inactive', false);
}
/**
* Calculate the next expected date for this reminder.
*
* @return Carbon
*/
public function calculateNextExpectedDate($date = null)
{
if (is_null($date)) {
$date = $this->initial_date;
}
while ($date->isPast()) {
$date = DateHelper::addTimeAccordingToFrequencyType($date, $this->frequency_type, $this->frequency_number);
}
if ($date->isToday()) {
$date = DateHelper::addTimeAccordingToFrequencyType($date, $this->frequency_type, $this->frequency_number);
}
return $date;
}
/**
* Calculate the next expected date using user timezone for this reminder.
*
* @return Carbon
*/
public function calculateNextExpectedDateOnTimezone()
{
$date = $this->initial_date;
$date = Carbon::create($date->year, $date->month, $date->day, 0, 0, 0,
DateHelper::getTimezone() ?? config('app.timezone'));
return $this->calculateNextExpectedDate($date);
}
/**
* Schedule the reminder to be sent.
*
* @param User $user
* @return void
*/
public function schedule(User $user)
{
// remove any existing scheduled reminders
$this->reminderOutboxes->each->delete();
// when should we send this reminder?
$triggerDate = $this->calculateNextExpectedDate();
// schedule the reminder in the outbox, one for each user of the account
ReminderOutbox::create([
'account_id' => $this->account_id,
'reminder_id' => $this->id,
'user_id' => $user->id,
'planned_date' => $triggerDate,
'nature' => 'reminder',
]);
$this->scheduleNotifications($triggerDate, $user);
}
/**
* Create all the notifications that are supposed to be sent
* 30 and 7 days prior to the actual reminder.
*
* @param Carbon $triggerDate
* @param User $user
* @return void
*/
public function scheduleNotifications(Carbon $triggerDate, User $user)
{
$date = $triggerDate->toDateString();
$reminderRules = $this->account->reminderRules()->where('active', 1)->get();
foreach ($reminderRules as $reminderRule) {
$datePrior = Carbon::createFromFormat('Y-m-d', $date);
$datePrior->subDays($reminderRule->number_of_days_before);
if ($datePrior->lessThanOrEqualTo(now())) {
continue;
}
ReminderOutbox::create([
'account_id' => $this->account_id,
'reminder_id' => $this->id,
'user_id' => $user->id,
'planned_date' => $datePrior->toDateString(),
'nature' => 'notification',
'notification_number_days_before' => $reminderRule->number_of_days_before,
]);
}
}
}