Notify transfer owners when files enter grace period.
Deploy Ladill Transfer / deploy (push) Successful in 1m0s
Deploy Ladill Transfer / deploy (push) Successful in 1m0s
Send grace-entered and countdown emails to owners alongside recipient grace milestones so unpaid transfers get clear wallet top-up reminders before deletion. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Transfer;
|
||||
|
||||
use App\Models\Transfer;
|
||||
use App\Notifications\TransferOwnerGraceNotification;
|
||||
use Carbon\CarbonInterface;
|
||||
|
||||
/** Owner emails when transfers enter grace and before files are deleted. */
|
||||
class TransferOwnerMailService
|
||||
{
|
||||
/** @return list<string> */
|
||||
public function graceMilestones(): array
|
||||
{
|
||||
return array_values(array_map(
|
||||
'strval',
|
||||
(array) config('transfer.owner_grace_email_milestones', ['grace_entered', '7', '3', '1']),
|
||||
));
|
||||
}
|
||||
|
||||
public function notifyGraceEntered(Transfer $transfer): bool
|
||||
{
|
||||
return $this->notifyOwner($transfer, 'grace_entered');
|
||||
}
|
||||
|
||||
public function processGraceReminders(): int
|
||||
{
|
||||
$sent = 0;
|
||||
|
||||
Transfer::query()
|
||||
->where('status', Transfer::STATUS_GRACE)
|
||||
->whereNotNull('grace_ends_at')
|
||||
->where('grace_ends_at', '>', now())
|
||||
->with('user')
|
||||
->chunkById(100, function ($transfers) use (&$sent) {
|
||||
foreach ($transfers as $transfer) {
|
||||
foreach ($this->dueGraceDayMilestones($transfer) as $milestone) {
|
||||
if ($this->notifyOwner($transfer, $milestone)) {
|
||||
$sent++;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return $sent;
|
||||
}
|
||||
|
||||
/** @return list<string> */
|
||||
private function dueGraceDayMilestones(Transfer $transfer): array
|
||||
{
|
||||
if (! $transfer->grace_ends_at instanceof CarbonInterface) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$daysRemaining = (int) now()->startOfDay()->diffInDays(
|
||||
$transfer->grace_ends_at->copy()->startOfDay(),
|
||||
false,
|
||||
);
|
||||
|
||||
$due = [];
|
||||
foreach (['7', '3', '1'] as $milestone) {
|
||||
if ($daysRemaining === (int) $milestone && in_array($milestone, $this->graceMilestones(), true)) {
|
||||
$due[] = $milestone;
|
||||
}
|
||||
}
|
||||
|
||||
return $due;
|
||||
}
|
||||
|
||||
private function notifyOwner(Transfer $transfer, string $milestone): bool
|
||||
{
|
||||
if (! in_array($milestone, $this->graceMilestones(), true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($transfer->ownerMilestoneSent($milestone)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$user = $transfer->user;
|
||||
if ($user === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$user->notify(new TransferOwnerGraceNotification(
|
||||
$transfer->loadMissing(['files', 'qrCode']),
|
||||
$milestone,
|
||||
));
|
||||
|
||||
$transfer->markOwnerMilestoneSent($milestone);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user