Rewrite DoublerDecision action.

Rewrite SeatAuditionFormController to use the action for making doubler decisions.
This commit is contained in:
Matt Young 2025-06-30 18:26:12 -05:00
parent 3a1b03a6c7
commit 0d8d876ba7
2 changed files with 75 additions and 44 deletions

View File

@ -3,19 +3,12 @@
namespace App\Actions\Entries; namespace App\Actions\Entries;
use App\Exceptions\AuditionAdminException; use App\Exceptions\AuditionAdminException;
use App\Models\Doubler;
use App\Models\Entry; use App\Models\Entry;
use App\Services\DoublerService;
use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Cache;
class DoublerDecision class DoublerDecision
{ {
protected DoublerService $doublerService;
public function __construct(DoublerService $doublerService)
{
$this->doublerService = $doublerService;
}
/** /**
* @throws AuditionAdminException * @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 public function accept(Entry $entry): void
{ {
Cache::forget('audition'.$entry->audition_id.'seating'); if ($entry->hasFlag('declined')) {
Cache::forget('audition'.$entry->audition_id.'advancement'); 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 // Process student entries
$doublerInfo = $this->doublerService->simpleDoubleInfo($entry); $doublerData = Doubler::findDoubler($entry->student_id, $entry->audition->event_id);
foreach ($doublerInfo as $doublerEntry) { // Check each entry and see if it is unscored. We can't accept this entry if that is the case.
Cache::forget('audition'.$doublerEntry->audition_id.'seating'); foreach ($doublerData->entries() as $doublerEntry) {
/** @var Entry $doublerEntry */ if (! $doublerEntry->totalScore && ! $doublerEntry->hasFlag('declined') && ! $doublerEntry->hasFlag('no_show') && ! $doublerEntry->hasFlag('failed_prelim')) {
if ($doublerEntry->id !== $entry->id) { throw new AuditionAdminException('Cannot accept seating for '.$entry->student->full_name().' because student has unscored entries');
$doublerEntry->addFlag('declined'); }
}
// 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 public function decline($entry): void
{ {
Cache::forget('audition'.$entry->audition_id.'seating'); // Entry cannot decline a seat twice
Cache::forget('audition'.$entry->audition_id.'advancement');
if ($entry->hasFlag('declined')) { 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'); $entry->addFlag('declined');
// Clear rank cache
Cache::forget('rank_seating_'.$entry->audition_id);
} }
} }

View File

@ -131,12 +131,18 @@ class SeatAuditionFormController extends Controller
public function massDecline(Audition $audition) public function massDecline(Audition $audition)
{ {
$decider = app(DoublerDecision::class);
$validData = request()->validate([ $validData = request()->validate([
'decline-below' => ['required', 'integer', 'min:0'], 'decline-below' => ['required', 'integer', 'min:0'],
]); ]);
$ranker = app(RankAuditionEntries::class); $ranker = app(RankAuditionEntries::class);
// Get scored entries in order // 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']); $scored_entries->load(['student.doublers', 'student.school']);
foreach ($scored_entries as $entry) { foreach ($scored_entries as $entry) {
Debugbar::info('Starting entry '.$entry->student->full_name()); Debugbar::info('Starting entry '.$entry->student->full_name());
@ -160,30 +166,27 @@ class SeatAuditionFormController extends Controller
continue; 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]); return redirect()->route('seating.audition', ['audition' => $audition->id]);
} }
public function acceptSeat( public function acceptSeat(Audition $audition, Entry $entry)
Audition $audition, {
Entry $entry $decider = app(DoublerDecision::class);
) { try {
$doublerData = Doubler::findDoubler($entry->student_id, $audition->event_id); $decider->accept($entry);
foreach ($doublerData->entries() as $doublerEntry) { } catch (AuditionAdminException $e) {
if (! $doublerEntry->totalScore && ! $doublerEntry->hasFlag('declined') && ! $doublerEntry->hasFlag('no_show') && ! $doublerEntry->hasFlag('failed_prelim')) { return redirect()->route('seating.audition', ['audition' => $audition->id])
return redirect()->route('seating.audition', ['audition' => $audition->id])->with('error', ->with('error', $e->getMessage());
'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');
}
} }
return redirect()->route('seating.audition', ['audition' => $audition->id])->with('success', return redirect()->route('seating.audition', ['audition' => $audition->id])->with('success',
@ -214,15 +217,20 @@ class SeatAuditionFormController extends Controller
'ensemble.*' => ['required', 'integer', 'min:0'], 'ensemble.*' => ['required', 'integer', 'min:0'],
]); ]);
$proposedSeatingArray = []; $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) { $rankedEntries = $rankedEntries->reject(function ($entry) {
return $entry->hasFlag('declined'); return $entry->hasFlag('declined');
}); });
$rankedEntries->load(['student.school']); $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; $ensembleRankOn = 1;
foreach ($rankedEnembles as $ensemble) { foreach ($rankedEnsembles as $ensemble) {
if (! Arr::has($validated['ensemble'], $ensemble->id)) { if (! Arr::has($validated['ensemble'], $ensemble->id)) {
continue; continue;
} }
@ -245,7 +253,7 @@ class SeatAuditionFormController extends Controller
$ensembleRankOn++; $ensembleRankOn++;
} }
$sessionKeyName = 'proposedSeatingArray-'.$audition->id; $sessionKeyName = 'proposedSeatingArray-'.$audition->id;
$request->session()->put($sessionKeyName, $proposedSeatingArray, 10); $request->session()->put($sessionKeyName, $proposedSeatingArray);
return redirect()->route('seating.audition', ['audition' => $audition->id]); return redirect()->route('seating.audition', ['audition' => $audition->id]);
} }