diff --git a/app/Actions/Entries/DoublerDecision.php b/app/Actions/Entries/DoublerDecision.php index bb580d3..54158be 100644 --- a/app/Actions/Entries/DoublerDecision.php +++ b/app/Actions/Entries/DoublerDecision.php @@ -3,19 +3,12 @@ namespace App\Actions\Entries; use App\Exceptions\AuditionAdminException; +use App\Models\Doubler; use App\Models\Entry; -use App\Services\DoublerService; use Illuminate\Support\Facades\Cache; class DoublerDecision { - protected DoublerService $doublerService; - - public function __construct(DoublerService $doublerService) - { - $this->doublerService = $doublerService; - } - /** * @throws AuditionAdminException */ @@ -41,18 +34,46 @@ class DoublerDecision } + /** + * Accepts an entry for the given audition. + * + * This method ensures the entry is not already declined, and that the + * audition is not in a state where seats or advancement are published. + * If the entry is already declined, this method does nothing. + * If the audition is in a state where seats or advancement are published, + * this method throws an exception. + * + * This method also declines all other entries in the same audition, + * clearing the rank cache for the audition. + * + * @throws AuditionAdminException + */ public function accept(Entry $entry): void { - Cache::forget('audition'.$entry->audition_id.'seating'); - Cache::forget('audition'.$entry->audition_id.'advancement'); + if ($entry->hasFlag('declined')) { + throw new AuditionAdminException('Entry '.$entry->id.' is already declined'); + } + if ($entry->audition->hasFlag('seats_published')) { + throw new AuditionAdminException('Cannot accept an entry in an audition where seats are published'); + } + if ($entry->audition->hasFlag('advancement_published')) { + throw new AuditionAdminException('Cannot accept an entry in an audition where advancement is published'); + } + Cache::forget('rank_seating_'.$entry->audition_id); - // Decline all other entries and clear rank cache - $doublerInfo = $this->doublerService->simpleDoubleInfo($entry); - foreach ($doublerInfo as $doublerEntry) { - Cache::forget('audition'.$doublerEntry->audition_id.'seating'); - /** @var Entry $doublerEntry */ - if ($doublerEntry->id !== $entry->id) { - $doublerEntry->addFlag('declined'); + // Process student entries + $doublerData = Doubler::findDoubler($entry->student_id, $entry->audition->event_id); + // Check each entry and see if it is unscored. We can't accept this entry if that is the case. + foreach ($doublerData->entries() as $doublerEntry) { + if (! $doublerEntry->totalScore && ! $doublerEntry->hasFlag('declined') && ! $doublerEntry->hasFlag('no_show') && ! $doublerEntry->hasFlag('failed_prelim')) { + throw new AuditionAdminException('Cannot accept seating for '.$entry->student->full_name().' because student has unscored entries'); + } + } + // Decline all other entries + foreach ($doublerData->entries() as $doublerEntry) { + Cache::forget('rank_seating_'.$doublerEntry->audition_id); + if ($doublerEntry->id !== $entry->id && ! $doublerEntry->hasFlag('no_show') && ! $doublerEntry->hasFlag('failed_prelim') && ! $doublerEntry->hasFlag('declined')) { + $this->decline($doublerEntry); } } } @@ -62,12 +83,14 @@ class DoublerDecision */ public function decline($entry): void { - Cache::forget('audition'.$entry->audition_id.'seating'); - Cache::forget('audition'.$entry->audition_id.'advancement'); + // Entry cannot decline a seat twice if ($entry->hasFlag('declined')) { - throw new AuditionAdminException('Entry is already declined'); + throw new AuditionAdminException('Entry '.$entry->id.' is already declined'); } - Cache::forget('audition'.$entry->audition_id.'seating'); + // Flag this entry $entry->addFlag('declined'); + + // Clear rank cache + Cache::forget('rank_seating_'.$entry->audition_id); } } diff --git a/app/Http/Controllers/Tabulation/SeatAuditionFormController.php b/app/Http/Controllers/Tabulation/SeatAuditionFormController.php index a212aa2..8220438 100644 --- a/app/Http/Controllers/Tabulation/SeatAuditionFormController.php +++ b/app/Http/Controllers/Tabulation/SeatAuditionFormController.php @@ -131,12 +131,18 @@ class SeatAuditionFormController extends Controller public function massDecline(Audition $audition) { + $decider = app(DoublerDecision::class); $validData = request()->validate([ 'decline-below' => ['required', 'integer', 'min:0'], ]); $ranker = app(RankAuditionEntries::class); // Get scored entries in order - $scored_entries = $ranker($audition, 'seating'); + try { + $scored_entries = $ranker($audition, 'seating'); + } catch (AuditionAdminException $e) { + return redirect()->route('seating.audition', ['audition' => $audition->id]) + ->with('error', $e->getMessage()); + } $scored_entries->load(['student.doublers', 'student.school']); foreach ($scored_entries as $entry) { Debugbar::info('Starting entry '.$entry->student->full_name()); @@ -160,30 +166,27 @@ class SeatAuditionFormController extends Controller continue; } - $entry->addFlag('declined'); + try { + $decider->decline($entry); + } catch (AuditionAdminException $e) { + return redirect()->route('seating.audition', ['audition' => $audition->id]) + ->with('error', $e->getMessage()); + } } - Cache::forget('rank_seating_'.$entry->audition_id); + Cache::forget('rank_seating_'.$audition->id); return redirect()->route('seating.audition', ['audition' => $audition->id]); } - public function acceptSeat( - Audition $audition, - Entry $entry - ) { - $doublerData = Doubler::findDoubler($entry->student_id, $audition->event_id); - foreach ($doublerData->entries() as $doublerEntry) { - if (! $doublerEntry->totalScore && ! $doublerEntry->hasFlag('declined') && ! $doublerEntry->hasFlag('no_show') && ! $doublerEntry->hasFlag('failed_prelim')) { - return redirect()->route('seating.audition', ['audition' => $audition->id])->with('error', - 'Cannot accept seating for '.$entry->student->full_name().' because student has unscored entries'); - } - } - foreach ($doublerData->entries() as $doublerEntry) { - Cache::forget('rank_seating_'.$doublerEntry->audition_id); - if ($doublerEntry->id !== $entry->id && ! $doublerEntry->hasFlag('no_show') && ! $doublerEntry->hasFlag('failed_prelim') && ! $doublerEntry->hasFlag('declined')) { - $doublerEntry->addFlag('declined'); - } + public function acceptSeat(Audition $audition, Entry $entry) + { + $decider = app(DoublerDecision::class); + try { + $decider->accept($entry); + } catch (AuditionAdminException $e) { + return redirect()->route('seating.audition', ['audition' => $audition->id]) + ->with('error', $e->getMessage()); } return redirect()->route('seating.audition', ['audition' => $audition->id])->with('success', @@ -214,15 +217,20 @@ class SeatAuditionFormController extends Controller 'ensemble.*' => ['required', 'integer', 'min:0'], ]); $proposedSeatingArray = []; - $rankedEntries = $ranker($audition, 'seating'); + try { + $rankedEntries = $ranker($audition, 'seating'); + } catch (AuditionAdminException $e) { + return redirect()->route('seating.audition', ['audition' => $audition->id]) + ->with('error', $e->getMessage()); + } $rankedEntries = $rankedEntries->reject(function ($entry) { return $entry->hasFlag('declined'); }); $rankedEntries->load(['student.school']); - $rankedEnembles = Ensemble::orderBy('rank')->where('event_id', $audition->event_id)->get(); + $rankedEnsembles = Ensemble::orderBy('rank')->where('event_id', $audition->event_id)->get(); $ensembleRankOn = 1; - foreach ($rankedEnembles as $ensemble) { + foreach ($rankedEnsembles as $ensemble) { if (! Arr::has($validated['ensemble'], $ensemble->id)) { continue; } @@ -245,7 +253,7 @@ class SeatAuditionFormController extends Controller $ensembleRankOn++; } $sessionKeyName = 'proposedSeatingArray-'.$audition->id; - $request->session()->put($sessionKeyName, $proposedSeatingArray, 10); + $request->session()->put($sessionKeyName, $proposedSeatingArray); return redirect()->route('seating.audition', ['audition' => $audition->id]); }