|
|
|
|
@ -4,25 +4,23 @@ namespace App\Services;
|
|
|
|
|
|
|
|
|
|
use App\Models\Reservation;
|
|
|
|
|
use Carbon\Carbon;
|
|
|
|
|
use Illuminate\Support\Collection;
|
|
|
|
|
|
|
|
|
|
class ReservationExpiryService
|
|
|
|
|
{
|
|
|
|
|
/**
|
|
|
|
|
* 将「活动日已过、仍为待核销、未核销」的预约标记为 expired(与未履约统计一致)。
|
|
|
|
|
* 将「场次/活动日已过、仍为待核销、未核销」的预约标记为 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 = 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')
|
|
|
|
|
->whereDate('activity_days.activity_date', '<', $today)
|
|
|
|
|
->pluck('reservations.id');
|
|
|
|
|
|
|
|
|
|
$ids = $this->stalePendingReservationIds($today, $now);
|
|
|
|
|
if ($ids->isEmpty()) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
@ -32,4 +30,45 @@ class ReservationExpiryService
|
|
|
|
|
'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();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|