Everything ready for seating the audition.

This commit is contained in:
Matt Young 2025-06-25 22:51:27 -05:00
parent 0468cb5d11
commit 14b6bb61c7
10 changed files with 56 additions and 14 deletions

View File

@ -9,6 +9,7 @@ namespace App\Actions\Tabulation;
use App\Exceptions\ScoreEntryException; use App\Exceptions\ScoreEntryException;
use App\Models\AuditLogEntry; use App\Models\AuditLogEntry;
use App\Models\Entry; use App\Models\Entry;
use App\Models\EntryTotalScore;
use App\Models\ScoreSheet; use App\Models\ScoreSheet;
use App\Models\User; use App\Models\User;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
@ -28,8 +29,7 @@ class EnterScore
*/ */
public function __invoke(User $user, Entry $entry, array $scores, ScoreSheet|false $scoreSheet = false): ScoreSheet public function __invoke(User $user, Entry $entry, array $scores, ScoreSheet|false $scoreSheet = false): ScoreSheet
{ {
// TODO: Remove the CalculatedScore model and table when rewrite is complete, they'll be obsolete EntryTotalScore::where('entry_id', $entry->id)->delete();
// CalculatedScore::where('entry_id', $entry->id)->delete();
$scores = collect($scores); $scores = collect($scores);
// Basic Validity Checks // Basic Validity Checks

View File

@ -42,7 +42,7 @@ class RankAuditionEntries
private function get_seating_ranks(Audition $audition): Collection private function get_seating_ranks(Audition $audition): Collection
{ {
return $audition->entries() $sortedEntries = $audition->entries()
->whereHas('totalScore') ->whereHas('totalScore')
->with('totalScore') ->with('totalScore')
->with('student.school') ->with('student.school')
@ -61,6 +61,18 @@ class RankAuditionEntries
->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[9]"), -999999) DESC') ->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[9]"), -999999) DESC')
->select('entries.*') ->select('entries.*')
->get(); ->get();
$rankOn = 1;
foreach ($sortedEntries as $entry) {
if ($entry->hasFlag('declined')) {
$entry->seatingRank = 'declined';
} else {
$entry->seatingRank = $rankOn;
$rankOn++;
}
}
return $sortedEntries;
} }
private function get_advancement_ranks(Audition $audition): Collection private function get_advancement_ranks(Audition $audition): Collection

View File

@ -5,8 +5,8 @@ namespace App\Http\Controllers\Tabulation;
use App\Actions\Tabulation\EnterScore; use App\Actions\Tabulation\EnterScore;
use App\Exceptions\ScoreEntryException; use App\Exceptions\ScoreEntryException;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Models\CalculatedScore;
use App\Models\Entry; use App\Models\Entry;
use App\Models\EntryTotalScore;
use App\Models\ScoreSheet; use App\Models\ScoreSheet;
use App\Models\User; use App\Models\User;
use Illuminate\Http\Request; use Illuminate\Http\Request;
@ -25,7 +25,7 @@ class ScoreController extends Controller
public function destroyScore(ScoreSheet $score) public function destroyScore(ScoreSheet $score)
{ {
CalculatedScore::where('entry_id', $score->entry_id)->delete(); EntryTotalScore::where('entry_id', $score->entry_id)->delete();
if ($score->entry->audition->hasFlag('seats_published')) { if ($score->entry->audition->hasFlag('seats_published')) {
return redirect()->back()->with('error', 'Cannot delete scores for an entry where seats are published'); return redirect()->back()->with('error', 'Cannot delete scores for an entry where seats are published');
} }

View File

@ -10,6 +10,9 @@ use App\Models\Audition;
use App\Models\Doubler; use App\Models\Doubler;
use App\Models\Entry; use App\Models\Entry;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use function PHPUnit\Framework\isNull;
class SeatAuditionFormController extends Controller class SeatAuditionFormController extends Controller
{ {
@ -58,19 +61,38 @@ class SeatAuditionFormController extends Controller
->get() ->get()
->keyBy('student_id'); ->keyBy('student_id');
$auditionHasUnresolvedDoublers = false;
foreach ($doublerData as $doubler) {
if (! isNull($doubler->accepted_entry)) {
continue;
}
foreach ($doubler->entries() as $entry) {
if ($entry->audition_id === $audition->id && $entry->hasFlag('declined')) {
continue 2;
}
}
$auditionHasUnresolvedDoublers = true;
}
$canSeat = ! $auditionHasUnresolvedDoublers && $unscored_entries->count() === 0;
return view('tabulation.auditionSeating', return view('tabulation.auditionSeating',
compact('audition', compact('audition',
'scored_entries', 'scored_entries',
'unscored_entries', 'unscored_entries',
'noshow_entries', 'noshow_entries',
'failed_prelim_entries', 'failed_prelim_entries',
'doublerData') 'doublerData',
'auditionHasUnresolvedDoublers',
'canSeat',
)
); );
} }
public function declineSeat(Audition $audition, Entry $entry) public function declineSeat(Audition $audition, Entry $entry)
{ {
$entry->addFlag('declined'); $entry->addFlag('declined');
Cache::forget('rank_seating_'.$entry->audition_id);
return redirect()->route('seating.audition', ['audition' => $audition->id])->with('success', return redirect()->route('seating.audition', ['audition' => $audition->id])->with('success',
$entry->student->full_name().' has declined '.$audition->name); $entry->student->full_name().' has declined '.$audition->name);
@ -86,6 +108,7 @@ class SeatAuditionFormController extends Controller
} }
} }
foreach ($doublerData->entries() as $doublerEntry) { 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')) { if ($doublerEntry->id !== $entry->id && ! $doublerEntry->hasFlag('no_show') && ! $doublerEntry->hasFlag('failed_prelim') && ! $doublerEntry->hasFlag('declined')) {
$doublerEntry->addFlag('declined'); $doublerEntry->addFlag('declined');
} }

View File

@ -45,6 +45,11 @@ class Entry extends Model
// Get the ranked entries for this entries audition // Get the ranked entries for this entries audition
$rankedEntries = $ranker($this->audition, $type); $rankedEntries = $ranker($this->audition, $type);
// If we're looking for seating rank, return the rank from the list of ranked entries
if ($type === 'seating') {
return $rankedEntries->where('id', $this->id)->first()->seatingRank;
}
// Find position of current entry in the ranked entries (1-based index) // Find position of current entry in the ranked entries (1-based index)
$position = $rankedEntries->search(fn ($entry) => $entry->id === $this->id); $position = $rankedEntries->search(fn ($entry) => $entry->id === $this->id);

View File

@ -13,6 +13,7 @@ class EntryFlagObserver
public function created(EntryFlag $entryFlag): void public function created(EntryFlag $entryFlag): void
{ {
Doubler::syncDoublers(); Doubler::syncDoublers();
} }
/** /**

View File

@ -2,7 +2,7 @@
namespace App\Observers; namespace App\Observers;
use App\Events\ScoreSheetChange; use App\Actions\Tabulation\TotalEntryScores;
use App\Models\ScoreSheet; use App\Models\ScoreSheet;
class ScoreSheetObserver class ScoreSheetObserver
@ -12,7 +12,8 @@ class ScoreSheetObserver
*/ */
public function created(ScoreSheet $scoreSheet): void public function created(ScoreSheet $scoreSheet): void
{ {
// $calculator = app(TotalEntryScores::class);
$calculator($scoreSheet->entry, true);
} }
/** /**

View File

@ -55,7 +55,7 @@
@foreach($event_entries[$event->id] as $entry) @foreach($event_entries[$event->id] as $entry)
<tr> <tr>
<x-table.td>{{ $entry->id }}</x-table.td> <x-table.td>{{ $entry->id }}</x-table.td>
<x-table.td>{{ $entry->audition->name }}</x-table.td> <x-table.td><a href="{{ route ('seating.audition',[$entry->audition_id]) }}#entry-{{ $entry->id }}">{{ $entry->audition->name }}</a></x-table.td>
<x-table.td>{{ $entry->draw_number }}</x-table.td> <x-table.td>{{ $entry->draw_number }}</x-table.td>
<x-table.td> <x-table.td>
@if($entry->doubler_decision_frozen) @if($entry->doubler_decision_frozen)

View File

@ -1,6 +1,6 @@
<div class="border-2 border-gray-200 p-2 m-2"> {{-- Begin block for doubler entry --}} <div class="border-2 border-gray-200 p-2 m-2"> {{-- Begin block for doubler entry --}}
<div class="font-semibold mb-2"> <div class="font-semibold mb-2">
<a href="{{route('seating.audition',[$de->audition])}}">{{ $de->audition->name }}</a> #{{$de->draw_number}} <a href="{{route('seating.audition',[$de->audition])}}#entry-{{ $de->id }}">{{ $de->audition->name }}</a> #{{$de->draw_number}}
({{ $de->id }}) ({{ $de->id }})
</div> </div>
@if($de->hasFlag('no_show')) @if($de->hasFlag('no_show'))

View File

@ -27,8 +27,8 @@
</thead> </thead>
<tbody class="divide-y divide-gray-200"> <tbody class="divide-y divide-gray-200">
@foreach($scored_entries as $entry) @foreach($scored_entries as $entry)
<tr> <tr id="entry-{{ $entry->id }}">
<x-table.td class="align-top">{{ $loop->iteration }}</x-table.td> <x-table.td class="align-top">{{ $entry->seatingRank }}</x-table.td>
<x-table.td class="align-top">{{ $entry->id }}</x-table.td> <x-table.td class="align-top">{{ $entry->id }}</x-table.td>
<x-table.td class="align-top">{{ $entry->draw_number }}</x-table.td> <x-table.td class="align-top">{{ $entry->draw_number }}</x-table.td>
<x-table.td class="align-top"> <x-table.td class="align-top">
@ -165,8 +165,8 @@
Cannot seat the audition while entries are unscored. Cannot seat the audition while entries are unscored.
</x-card.card> </x-card.card>
@endif @endif
<hr>
@if($doublerData->contains('accepted_entry', null)) @if($auditionHasUnresolvedDoublers)
<x-card.card class="p-3 text-red-500"> <x-card.card class="p-3 text-red-500">
Cannot seat the audition while there are unresolved doublers. Cannot seat the audition while there are unresolved doublers.
</x-card.card> </x-card.card>