option('dry-run'); $counts = ['payment_failed' => 0, 'cancelled' => 0, 'deactivated' => 0, 'paused' => 0]; UserAbo::withTrashed() ->whereNull('status_reason') ->whereIn('status', [3, 4, 6]) ->orderBy('id') ->chunkById(500, function ($abos) use (&$counts, $dryRun): void { foreach ($abos as $abo) { [$reason, $bucket] = match ((int) $abo->status) { 3 => [UserAbo::REASON_PAYMENT_FAILED, 'payment_failed'], 4 => [UserAbo::REASON_PREFIX_CANCELLED.$this->actorFromHistory($abo, UserAboStatusHistory::ACTION_CANCELLED), 'cancelled'], default => [UserAbo::REASON_PREFIX_DEACTIVATED.$this->actorFromHistory($abo, UserAboStatusHistory::ACTION_DEACTIVATED), 'deactivated'], }; $counts[$bucket]++; if (! $dryRun) { UserAbo::withTrashed()->whereKey($abo->id)->toBase()->update(['status_reason' => $reason]); } } }); UserAbo::query() ->whereNull('paused_until') ->where('status', 2) ->where('active', true) ->where('pause_count', '>', 0) ->whereNotNull('last_pause_date') ->orderBy('id') ->chunkById(500, function ($abos) use (&$counts, $dryRun): void { foreach ($abos as $abo) { $until = $abo->pausedUntil(); if ($until === null || $until->lt(Carbon::today())) { continue; } $counts['paused']++; if (! $dryRun) { UserAbo::whereKey($abo->id)->toBase()->update([ 'paused_until' => $until->toDateString(), 'status_reason' => $abo->status_reason ?: UserAbo::REASON_PREFIX_PAUSED.$this->actorFromHistory($abo, UserAboStatusHistory::ACTION_PAUSED), ]); } } }); $this->table(['Zustand', 'Abos'], [ ['Zahlung fehlgeschlagen', $counts['payment_failed']], ['Gekuendigt', $counts['cancelled']], ['Deaktiviert', $counts['deactivated']], ['Pausiert (laufend)', $counts['paused']], ]); $this->info($dryRun ? 'DRY-RUN, nichts geschrieben.' : 'Nachtrag abgeschlossen.'); return self::SUCCESS; } private function actorFromHistory(UserAbo $abo, string $action): string { $entry = UserAboStatusHistory::query() ->where('user_abo_id', $abo->id) ->where('action', $action) ->orderByDesc('id') ->first(); return UserAbo::reasonActorFromView($entry?->view); } }