You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

75 lines
2.9 KiB

<?php
namespace App\Services;
use App\Models\Reservation;
use Carbon\Carbon;
use Illuminate\Support\Collection;
class ReservationExpiryService
{
/**
* 将「场次/活动日已过、仍为待核销、未核销」的预约标记为 expired。
* - 场次模式:以 activity_days.session_end_at 为准(晚于「活动日」日历的场次结束时刻)。
* - 非场次(仅日历日):仍以 activity_date 早于今天为准。
* - 抢票:入馆日 entry_date 早于今天。
*/
public function expireStalePendingReservations(): int
{
$tz = (string) config('app.timezone');
$today = Carbon::now($tz)->toDateString();
$now = Carbon::now($tz);
$ids = $this->stalePendingReservationIds($today, $now);
if ($ids->isEmpty()) {
return 0;
}
return Reservation::query()->whereIn('id', $ids)->update([
'status' => 'expired',
'updated_at' => now(),
]);
}
/**
* @return Collection<int, int>
*/
private function stalePendingReservationIds(string $today, Carbon $now): Collection
{
$idsActivity = Reservation::query()
->join('activity_days', 'activity_days.id', '=', 'reservations.activity_day_id')
->where('reservations.status', 'pending')
->whereNull('reservations.verified_at')
->whereNotNull('reservations.activity_day_id')
->where(function ($q) use ($today, $now) {
$q->where(function ($q2) use ($now) {
$q2->whereNotNull('activity_days.session_start_at')
->whereNotNull('activity_days.session_end_at')
->whereNotNull('activity_days.booking_deadline_at')
->where('activity_days.session_end_at', '<', $now);
})->orWhere(function ($q2) use ($today) {
$q2->where(function ($q3) {
$q3->whereNull('activity_days.session_start_at')
->orWhereNull('activity_days.session_end_at')
->orWhereNull('activity_days.booking_deadline_at');
})->whereDate('activity_days.activity_date', '<', $today);
});
})
->where(function ($q) {
$q->whereNull('reservations.reservation_kind')
->orWhere('reservations.reservation_kind', Reservation::KIND_ACTIVITY);
})
->pluck('reservations.id');
$idsTicketGrab = Reservation::query()
->where('reservation_kind', Reservation::KIND_TICKET_GRAB)
->where('status', 'pending')
->whereNull('verified_at')
->whereNotNull('entry_date')
->whereDate('entry_date', '<', $today)
->pluck('id');
return $idsActivity->merge($idsTicketGrab)->unique()->values();
}
}