diff --git a/app/Http/Controllers/Tabulation/EntryFlagController.php b/app/Http/Controllers/Tabulation/EntryFlagController.php index 249816b..a3ee379 100644 --- a/app/Http/Controllers/Tabulation/EntryFlagController.php +++ b/app/Http/Controllers/Tabulation/EntryFlagController.php @@ -81,14 +81,14 @@ class EntryFlagController extends Controller } DB::table('score_sheets')->where('entry_id', $entry->id)->delete(); - $entry->addFlag('no_show'); + ScoreSheet::where('entry_id', $entry->id)->delete(); - CalculatedScore::where('entry_id', $entry->id)->delete(); BonusScore::where('entry_id', $entry->id)->delete(); if (request()->input('noshow-type') == 'failprelim') { $msg = 'Failed prelim has been entered for '.$entry->audition->name.' #'.$entry->draw_number.' (ID: '.$entry->id.').'; $entry->addFlag('failed_prelim'); } else { + $entry->addFlag('no_show'); $msg = 'No Show has been entered for '.$entry->audition->name.' #'.$entry->draw_number.' (ID: '.$entry->id.').'; } diff --git a/app/Http/Controllers/Tabulation/SeatAuditionFormController.php b/app/Http/Controllers/Tabulation/SeatAuditionFormController.php index 84dcf06..f0c0307 100644 --- a/app/Http/Controllers/Tabulation/SeatAuditionFormController.php +++ b/app/Http/Controllers/Tabulation/SeatAuditionFormController.php @@ -2,163 +2,75 @@ namespace App\Http\Controllers\Tabulation; -use App\Actions\Entries\DoublerDecision; -use App\Actions\Tabulation\CalculateEntryScore; use App\Actions\Tabulation\GetAuditionSeats; -use App\Actions\Tabulation\RankAuditionEntries; -use App\Exceptions\AuditionAdminException; use App\Http\Controllers\Controller; use App\Models\Audition; -use App\Services\AuditionService; -use App\Services\DoublerService; -use App\Services\EntryService; use Illuminate\Http\Request; -use Illuminate\Support\Facades\Cache; - -use function redirect; class SeatAuditionFormController extends Controller { - protected CalculateEntryScore $calc; - - protected DoublerService $doublerService; - - protected RankAuditionEntries $ranker; - - protected EntryService $entryService; - - protected AuditionService $auditionService; - - protected DoublerDecision $decider; - - public function __construct( - CalculateEntryScore $calc, - RankAuditionEntries $ranker, - DoublerService $doublerService, - EntryService $entryService, - AuditionService $auditionService, - DoublerDecision $decider, - ) { - $this->calc = $calc; - $this->ranker = $ranker; - $this->doublerService = $doublerService; - $this->entryService = $entryService; - $this->auditionService = $auditionService; - $this->decider = $decider; - } - public function __invoke(Request $request, Audition $audition) { - // If a seating proposal was posted, deal wth it - if ($request->method() == 'POST' && $request->input('ensembleAccept')) { - $requestedEnsembleAccepts = $request->input('ensembleAccept'); - } else { - $requestedEnsembleAccepts = false; - } + // Get scored entries in order + $scored_entries = $audition->entries() + ->whereHas('totalScore') + ->with('totalScore') + ->with('student.school') + ->join('entry_total_scores', 'entries.id', '=', 'entry_total_scores.entry_id') + ->orderBy('entry_total_scores.seating_total', 'desc') + ->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[0]"), -999999) DESC') + ->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[1]"), -999999) DESC') + ->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[2]"), -999999) DESC') + ->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[3]"), -999999) DESC') + ->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[4]"), -999999) DESC') + ->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[5]"), -999999) DESC') + ->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[6]"), -999999) DESC') + ->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[7]"), -999999) DESC') + ->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[8]"), -999999) DESC') + ->orderByRaw('COALESCE(JSON_EXTRACT(entry_total_scores.seating_subscore_totals, "$[9]"), -999999) DESC') + ->select('entries.*') + ->get(); - // Deal with a mass no-show request - if ($request->input('mass-no-show')) { - $entries = $audition->entries()->forSeating()->withCount('scoreSheets')->with('flags')->get(); - foreach ($entries as $entry) { - if ($entry->scoreSheets_count == 0 && ! $entry->hasFlag('no_show')) { - $entry->addFlag('no_show'); - } - Cache::forget('entryScore-'.$entry->id.'-seating'); - Cache::forget('entryScore-'.$entry->id.'-advancement'); - } - Cache::forget('audition'.$audition->id.'seating'); - Cache::forget('audition'.$audition->id.'advancement'); - } + // Get unscored entries sorted by draw number + $unscored_entries = $audition->entries() + ->whereDoesntHave('totalScore') + ->whereDoesntHave('flags', function ($query) { + $query->where('flag_name', 'no_show'); + }) + ->whereDoesntHave('flags', function ($query) { + $query->where('flag_name', 'failed_prelim'); + }) + ->with('student.school') + ->orderBy('draw_number', 'asc') + ->get(); - $entryData = []; - $entries = $this->ranker->rank('seating', $audition); + // Get no show entries sorted by draw number + $noshow_entries = $audition->entries() + ->whereDoesntHave('totalScore') + ->whereHas('flags', function ($query) { + $query->where('flag_name', 'no_show'); + }) + ->with('student.school') + ->orderBy('draw_number', 'asc') + ->get(); - // Deal with mass decline doubler request - if ($request->input('decline-below')) { - Cache::forget('audition'.$audition->id.'seating'); - - $changes_made = false; - foreach ($entries as $entry) { - $doublerData = $this->doublerService->entryDoublerData($entry); - if ($doublerData && ! $entry->hasFlag('declined') && $entry->rank > $request->input('decline-below')) { - try { - $this->decider->decline($entry); - $changes_made = true; - } catch (AuditionAdminException $e) { - return redirect()->back()->with('error', $e->getMessage()); - } - } - } - if ($changes_made) { - $cache_key = 'event'.$audition->event_id.'doublers-seating'; - Cache::forget($cache_key); - - return redirect()->back(); - } - } - - $entries->load('student.school'); - $entries->load('student.doublerRequests'); - $seatable = [ - 'allScored' => true, - 'doublersResolved' => true, - ]; - foreach ($entries as $entry) { - $totalScoreColumn = 'No Score'; - $fullyScored = false; - if ($entry->score_totals) { - $totalScoreColumn = $entry->score_totals[0] >= 0 ? $entry->score_totals[0] : $entry->score_message; - $fullyScored = $entry->score_totals[0] >= 0; - } - // No Shows are fully scored - if ($entry->hasFlag('no_show')) { - $fullyScored = true; - } - $doublerData = $this->doublerService->entryDoublerData($entry); - - $entryData[] = [ - 'rank' => $entry->rank, - 'id' => $entry->id, - 'studentName' => $entry->student->full_name(), - 'schoolName' => $entry->student->school->name, - 'drawNumber' => $entry->draw_number, - 'totalScore' => $totalScoreColumn, - 'fullyScored' => $fullyScored, - 'hasBonusScores' => $entry->bonus_scores_count > 0, - 'doubleData' => $doublerData, - 'doublerRequest' => $entry->student->doublerRequests()->where('event_id', - $audition->event_id)->first()?->request, - ]; - // If this entries double decision isn't made, block seating - if ($doublerData && $doublerData[$entry->id]['status'] == 'undecided') { - $seatable['doublersResolved'] = false; - } - // If entry is unscored, block seating - if (! $fullyScored) { - $seatable['allScored'] = false; - } - } - - $rightPanel = $this->pickRightPanel($audition, $seatable); - $seatableEntries = []; - if ($seatable['doublersResolved'] && $seatable['allScored']) { - $seatableEntries = $entries->reject(function ($entry) { - if ($entry->hasFlag('declined')) { - return true; - } - if ($entry->hasFlag('no_show')) { - return true; - } - if ($entry->hasFlag('failed_prelim')) { - return true; - } - - return false; - }); - } + // Get failed prelim entries sorted by draw number + $failed_prelim_entries = $audition->entries() + ->whereDoesntHave('totalScore') + ->whereHas('flags', function ($query) { + $query->where('flag_name', 'failed_prelim'); + }) + ->with('student.school') + ->orderBy('draw_number', 'asc') + ->get(); return view('tabulation.auditionSeating', - compact('entryData', 'audition', 'rightPanel', 'seatableEntries', 'requestedEnsembleAccepts')); + compact('audition', + 'scored_entries', + 'unscored_entries', + 'noshow_entries', + 'failed_prelim_entries') + ); } protected function pickRightPanel(Audition $audition, array $seatable) diff --git a/app/Http/Controllers/Tabulation/SeatAuditionFormControllerOLD.php b/app/Http/Controllers/Tabulation/SeatAuditionFormControllerOLD.php new file mode 100644 index 0000000..9e27ec4 --- /dev/null +++ b/app/Http/Controllers/Tabulation/SeatAuditionFormControllerOLD.php @@ -0,0 +1,180 @@ +calc = $calc; + $this->ranker = $ranker; + $this->doublerService = $doublerService; + $this->entryService = $entryService; + $this->auditionService = $auditionService; + $this->decider = $decider; + } + + public function __invoke(Request $request, Audition $audition) + { + // If a seating proposal was posted, deal wth it + if ($request->method() == 'POST' && $request->input('ensembleAccept')) { + $requestedEnsembleAccepts = $request->input('ensembleAccept'); + } else { + $requestedEnsembleAccepts = false; + } + + // Deal with a mass no-show request + if ($request->input('mass-no-show')) { + $entries = $audition->entries()->forSeating()->withCount('scoreSheets')->with('flags')->get(); + foreach ($entries as $entry) { + if ($entry->scoreSheets_count == 0 && ! $entry->hasFlag('no_show')) { + $entry->addFlag('no_show'); + } + Cache::forget('entryScore-'.$entry->id.'-seating'); + Cache::forget('entryScore-'.$entry->id.'-advancement'); + } + Cache::forget('audition'.$audition->id.'seating'); + Cache::forget('audition'.$audition->id.'advancement'); + } + + $entryData = []; + $entries = $this->ranker->rank('seating', $audition); + + // Deal with mass decline doubler request + if ($request->input('decline-below')) { + Cache::forget('audition'.$audition->id.'seating'); + + $changes_made = false; + foreach ($entries as $entry) { + $doublerData = $this->doublerService->entryDoublerData($entry); + if ($doublerData && ! $entry->hasFlag('declined') && $entry->rank > $request->input('decline-below')) { + try { + $this->decider->decline($entry); + $changes_made = true; + } catch (AuditionAdminException $e) { + return redirect()->back()->with('error', $e->getMessage()); + } + } + } + if ($changes_made) { + $cache_key = 'event'.$audition->event_id.'doublers-seating'; + Cache::forget($cache_key); + + return redirect()->back(); + } + } + + $entries->load('student.school'); + $entries->load('student.doublerRequests'); + $seatable = [ + 'allScored' => true, + 'doublersResolved' => true, + ]; + foreach ($entries as $entry) { + $totalScoreColumn = 'No Score'; + $fullyScored = false; + if ($entry->score_totals) { + $totalScoreColumn = $entry->score_totals[0] >= 0 ? $entry->score_totals[0] : $entry->score_message; + $fullyScored = $entry->score_totals[0] >= 0; + } + // No Shows are fully scored + if ($entry->hasFlag('no_show')) { + $fullyScored = true; + } + $doublerData = $this->doublerService->entryDoublerData($entry); + + $entryData[] = [ + 'rank' => $entry->rank, + 'id' => $entry->id, + 'studentName' => $entry->student->full_name(), + 'schoolName' => $entry->student->school->name, + 'drawNumber' => $entry->draw_number, + 'totalScore' => $totalScoreColumn, + 'fullyScored' => $fullyScored, + 'hasBonusScores' => $entry->bonus_scores_count > 0, + 'doubleData' => $doublerData, + 'doublerRequest' => $entry->student->doublerRequests()->where('event_id', + $audition->event_id)->first()?->request, + ]; + // If this entries double decision isn't made, block seating + if ($doublerData && $doublerData[$entry->id]['status'] == 'undecided') { + $seatable['doublersResolved'] = false; + } + // If entry is unscored, block seating + if (! $fullyScored) { + $seatable['allScored'] = false; + } + } + + $rightPanel = $this->pickRightPanel($audition, $seatable); + $seatableEntries = []; + if ($seatable['doublersResolved'] && $seatable['allScored']) { + $seatableEntries = $entries->reject(function ($entry) { + if ($entry->hasFlag('declined')) { + return true; + } + if ($entry->hasFlag('no_show')) { + return true; + } + if ($entry->hasFlag('failed_prelim')) { + return true; + } + + return false; + }); + } + + return view('tabulation.auditionSeating', + compact('entryData', 'audition', 'rightPanel', 'seatableEntries', 'requestedEnsembleAccepts')); + } + + protected function pickRightPanel(Audition $audition, array $seatable) + { + if ($audition->hasFlag('seats_published')) { + $resultsWindow = new GetAuditionSeats; + $rightPanel['view'] = 'tabulation.auditionSeating-show-published-seats'; + $rightPanel['data'] = $resultsWindow($audition); + + return $rightPanel; + } + if ($seatable['allScored'] == false || $seatable['doublersResolved'] == false) { + $rightPanel['view'] = 'tabulation.auditionSeating-unable-to-seat-card'; + $rightPanel['data'] = $seatable; + + return $rightPanel; + } + + $rightPanel['view'] = 'tabulation.auditionSeating-right-complete-not-published'; + $rightPanel['data'] = $this->auditionService->getSeatingLimits($audition); + + return $rightPanel; + } +} diff --git a/app/Models/Audition.php b/app/Models/Audition.php index ecf32f9..c8599cb 100644 --- a/app/Models/Audition.php +++ b/app/Models/Audition.php @@ -35,7 +35,7 @@ class Audition extends Model public function unscoredEntries(): HasMany { return $this->hasMany(Entry::class) - ->whereDoesntHave('scoreSheets') + ->whereDoesntHave('totalScore') ->whereDoesntHave('flags', function ($query) { $query->where('flag_name', 'no_show'); }); diff --git a/app/Models/EntryFlag.php b/app/Models/EntryFlag.php index 4e2db12..ee1eaa0 100644 --- a/app/Models/EntryFlag.php +++ b/app/Models/EntryFlag.php @@ -15,36 +15,8 @@ class EntryFlag extends Model 'flag_name' => EntryFlags::class, ]; - protected static function boot() - { - parent::boot(); - static::created(function ($flag) { - $flag->deleteRelatedCalculatedScores(); - }); - - static::updated(function ($flag) { - $flag->deleteRelatedCalculatedScores(); - }); - - static::deleted(function ($flag) { - $flag->deleteRelatedCalculatedScores(); - }); - } - public function entry(): BelongsTo { return $this->belongsTo(Entry::class); } - - public function deleteRelatedCalculatedScores(): void - { - $entry = $this->entry; - if ($entry) { - $entry->calculatedScores()->delete(); - Cache::forget('entryScore-'.$entry->id.'-seating'); - Cache::forget('entryScore-'.$entry->id.'-advancement'); - Cache::forget('audition'.$entry->audition_id.'seating'); - Cache::forget('audition'.$entry->audition_id.'advancement'); - } - } } diff --git a/app/Models/User.php b/app/Models/User.php index 1c6907b..78968d5 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -127,7 +127,11 @@ class User extends Authenticatable implements MustVerifyEmail public function isJudge(): bool { - return $this->judgingAssignments()->count() > 0 || $this->bonusJudgingAssignments()->count() > 0; + return once(function () { + return $this->judgingAssignments()->count() > 0 + || $this->bonusJudgingAssignments()->count() > 0; + }); + } public function possibleSchools(): Collection diff --git a/resources/views/tabulation/auditionSeating.blade.php b/resources/views/tabulation/auditionSeating.blade.php index 065ae86..765c55f 100644 --- a/resources/views/tabulation/auditionSeating.blade.php +++ b/resources/views/tabulation/auditionSeating.blade.php @@ -1,29 +1,130 @@ -@inject('doublerService','App\Services\DoublerService') -@php - $blockSeating = [] -@endphp Audition Seating - {{ $audition->name }}
-
- @include('tabulation.auditionSeating-results-table') + +
{{-- Entry Ranking Table --}} + {{-- Scored Entries --}} + Scored Entries + + + + Rank + ID + Draw # + Student + Doubler + Total Score + @if($audition->bonusScore()->count() > 0) +
+
+ + Has Bonus +
+ @endif +
+ + + + @foreach($scored_entries as $entry) + + {{ $loop->iteration }} + {{ $entry->id }} + {{ $entry->draw_number }} + + {{ $entry->student->full_name() }} + {{ $entry->student->school->name }} + + Doubler to Come + {{ $entry->totalScore->seating_total }} + + @endforeach + +
+
+ + {{-- Unscored Entries --}} + Unscored Entries + + + + Draw # + ID + Student + + + + @foreach($unscored_entries as $entry) + + {{ $entry->draw_number }} + {{ $entry->id }} + + {{ $entry->student->full_name() }} + {{ $entry->student->school->name }} + + + @endforeach + + + + + {{-- No Show Entries --}} + No Show Entries + + + + Draw # + ID + Student + + + + @foreach($noshow_entries as $entry) + + {{ $entry->draw_number }} + {{ $entry->id }} + + {{ $entry->student->full_name() }} + {{ $entry->student->school->name }} + + + @endforeach + + + + + {{-- Failed Prelim Entries --}} + Failed Prelim Entries + + + + Draw # + ID + Student + + + + @foreach($failed_prelim_entries as $entry) + + {{ $entry->draw_number }} + {{ $entry->id }} + + {{ $entry->student->full_name() }} + {{ $entry->student->school->name }} + + + @endforeach + + + + +
+ +
- @include($rightPanel['view']) + Controls
-{{--
--}} -{{-- @if($audition->hasFlag('seats_published'))--}} -{{-- @include('tabulation.auditionSeating-show-published-seats')--}} -{{-- @elseif(! $auditionComplete)--}} -{{-- @include('tabulation.auditionSeating-unable-to-seat-card')--}} -{{-- @else--}} -{{-- @include('tabulation.auditionSeating-fill-seats-form')--}} -{{-- @include('tabulation.auditionSeating-show-proposed-seats')--}} -{{-- @endif--}} - - -{{--
--}}
diff --git a/resources/views/tabulation/auditionSeatingOLD.blade.php b/resources/views/tabulation/auditionSeatingOLD.blade.php new file mode 100644 index 0000000..065ae86 --- /dev/null +++ b/resources/views/tabulation/auditionSeatingOLD.blade.php @@ -0,0 +1,30 @@ +@inject('doublerService','App\Services\DoublerService') +@php + $blockSeating = [] +@endphp + + Audition Seating - {{ $audition->name }} +
+
+
+ @include('tabulation.auditionSeating-results-table') +
+
+ @include($rightPanel['view']) +
+{{--
--}} +{{-- @if($audition->hasFlag('seats_published'))--}} +{{-- @include('tabulation.auditionSeating-show-published-seats')--}} +{{-- @elseif(! $auditionComplete)--}} +{{-- @include('tabulation.auditionSeating-unable-to-seat-card')--}} +{{-- @else--}} +{{-- @include('tabulation.auditionSeating-fill-seats-form')--}} +{{-- @include('tabulation.auditionSeating-show-proposed-seats')--}} +{{-- @endif--}} + + +{{--
--}} +
+ + +