Rewrite tabulation #14

Merged
okorpheus merged 43 commits from rewrite-tabulation into master 2024-07-14 05:36:29 +00:00
10 changed files with 92 additions and 24 deletions
Showing only changes of commit 93c970c26e - Show all commits

View File

@ -4,13 +4,14 @@ namespace App\Http\Controllers\Tabulation;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Models\Entry; use App\Models\Entry;
use App\Models\EntryFlag;
use App\Services\DoublerService; use App\Services\DoublerService;
use App\Services\EntryService; use App\Services\EntryService;
use Illuminate\Support\Facades\Cache;
class DoublerDecisionController extends Controller class DoublerDecisionController extends Controller
{ {
protected $doublerService; protected $doublerService;
protected $entryService; protected $entryService;
public function __construct(DoublerService $doublerService, EntryService $entryService) public function __construct(DoublerService $doublerService, EntryService $entryService)
@ -29,8 +30,8 @@ class DoublerDecisionController extends Controller
} }
} }
$returnMessage = $entry->student->full_name().' accepted seating in '.$entry->audition->name; $returnMessage = $entry->student->full_name().' accepted seating in '.$entry->audition->name;
$this->clearCache($entry);
return redirect()->back()->with('success', $returnMessage); return redirect()->back()->with('success', $returnMessage);
@ -45,7 +46,16 @@ class DoublerDecisionController extends Controller
$entry->addFlag('declined'); $entry->addFlag('declined');
$returnMessage = $entry->student->full_name().' declined seating in '.$entry->audition->name; $returnMessage = $entry->student->full_name().' declined seating in '.$entry->audition->name;
$this->clearCache($entry);
return redirect()->back()->with('success', $returnMessage); return redirect()->back()->with('success', $returnMessage);
} }
protected function clearCache($entry)
{
$cacheKey = 'event'.$entry->audition->event_id.'doublers-seating';
Cache::forget($cacheKey);
$cacheKey = 'event'.$entry->audition->event_id.'doublers-advancement';
Cache::forget($cacheKey);
}
} }

View File

@ -42,7 +42,10 @@ class SeatAuditionController extends Controller
$entryData = []; $entryData = [];
$entries = $this->ranker->rank('seating', $audition); $entries = $this->ranker->rank('seating', $audition);
$entries->load('student.school'); $entries->load('student.school');
$seatable = [
'allScored' => true,
'doublersResolved' => true,
];
foreach ($entries as $entry) { foreach ($entries as $entry) {
$totalScoreColumn = 'No Score'; $totalScoreColumn = 'No Score';
$fullyScored = false; $fullyScored = false;
@ -50,6 +53,7 @@ class SeatAuditionController extends Controller
$totalScoreColumn = $entry->score_totals[0] >= 0 ? $entry->score_totals[0] : $entry->score_message; $totalScoreColumn = $entry->score_totals[0] >= 0 ? $entry->score_totals[0] : $entry->score_message;
$fullyScored = $entry->score_totals[0] >= 0; $fullyScored = $entry->score_totals[0] >= 0;
} }
$doublerData = $this->doublerService->entryDoublerData($entry);
$entryData[] = [ $entryData[] = [
'rank' => $entry->rank, 'rank' => $entry->rank,
'id' => $entry->id, 'id' => $entry->id,
@ -58,10 +62,54 @@ class SeatAuditionController extends Controller
'drawNumber' => $entry->draw_number, 'drawNumber' => $entry->draw_number,
'totalScore' => $totalScoreColumn, 'totalScore' => $totalScoreColumn,
'fullyScored' => $fullyScored, 'fullyScored' => $fullyScored,
'doubleData' => $this->doublerService->entryDoublerData($entry), 'doubleData' => $doublerData,
]; ];
// 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;
}
} }
return view('tabulation.auditionSeating', compact('entryData', 'audition')); $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;
}
return false;
});
}
return view('tabulation.auditionSeating', compact('entryData', 'audition', 'rightPanel', 'seatableEntries'));
}
protected function pickRightPanel(Audition $audition, array $seatable)
{
if ($audition->hasFlag('seats_published')) {
$rightPanel['view'] = 'tabulation.auditionSeating-show-published-seats';
$rightPanel['data'] = '';
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;
} }
} }

View File

@ -32,6 +32,7 @@ use App\Services\DoublerService;
use App\Services\DrawService; use App\Services\DrawService;
use App\Services\EntryService; use App\Services\EntryService;
use App\Services\ScoreService; use App\Services\ScoreService;
use App\Services\StudentService;
use App\Services\UserService; use App\Services\UserService;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;

View File

@ -40,20 +40,19 @@ class DoublerService
protected function findDoublersForEvent(Event $event, string $mode = 'seating'): array protected function findDoublersForEvent(Event $event, string $mode = 'seating'): array
{ {
$this->validateEvent($event); $this->validateEvent($event);
$entries = $event->entries; $entries = $event->entries()->with('audition')->with('student')->get();
$entries = match ($mode) { $entries = match ($mode) {
'seating' => $entries->filter(fn ($entry) => $entry->for_seating === 1), 'seating' => $entries->filter(fn ($entry) => $entry->for_seating === 1),
'advancement' => $entries->filter(fn ($entry) => $entry->for_advance === 1), 'advancement' => $entries->filter(fn ($entry) => $entry->for_advance === 1),
}; };
#$entries->load('student.school');
#$entries->load('audition');
$grouped = $entries->groupBy('student_id'); $grouped = $entries->groupBy('student_id');
// Filter out student groups with only one entry in the event // Filter out student groups with only one entry in the event
$grouped = $grouped->filter(fn ($s) => $s->count() > 1); $grouped = $grouped->filter(fn ($s) => $s->count() > 1);
$doubler_array = []; $doubler_array = [];
foreach ($grouped as $student_id => $entries) { foreach ($grouped as $student_id => $entries) {
$doubler_array[$student_id] = [ $doubler_array[$student_id] = [
'student' => $entries[0]->student, 'student_id' => $student_id,
'entries' => $entries, 'entries' => $entries,
]; ];
} }
@ -66,15 +65,16 @@ class DoublerService
if (! isset($this->findDoublersForEvent($primaryEntry->audition->event)[$primaryEntry->student_id])) { if (! isset($this->findDoublersForEvent($primaryEntry->audition->event)[$primaryEntry->student_id])) {
return false; return false;
} }
return $this->findDoublersForEvent($primaryEntry->audition->event)[$primaryEntry->student_id]['entries']; return $this->findDoublersForEvent($primaryEntry->audition->event)[$primaryEntry->student_id]['entries'];
} }
public function entryDoublerData(Entry $primaryEntry) public function entryDoublerData(Entry $primaryEntry)
{ {
if (! isset($this->findDoublersForEvent($primaryEntry->audition->event)[$primaryEntry->student_id])) { if (! isset($this->doublersForEvent($primaryEntry->audition->event)[$primaryEntry->student_id])) {
return false; return false;
} }
$entries = $this->findDoublersForEvent($primaryEntry->audition->event)[$primaryEntry->student_id]['entries']; $entries = $this->doublersForEvent($primaryEntry->audition->event)[$primaryEntry->student_id]['entries'];
$entryData = collect([]); $entryData = collect([]);
/** @var Collection $entries */ /** @var Collection $entries */
foreach ($entries as $entry) { foreach ($entries as $entry) {
@ -102,7 +102,7 @@ class DoublerService
'auditionName' => $entry->audition->name, 'auditionName' => $entry->audition->name,
'status' => $status, 'status' => $status,
'rank' => $this->entryService->rankOfEntry('seating', $entry), 'rank' => $this->entryService->rankOfEntry('seating', $entry),
'unscored_entries' => $entry->audition->unscoredEntries()->count(), 'unscored_entries' => $entry->audition->unscored_entries_count,
'seating_limits' => $limits, 'seating_limits' => $limits,
]; ];
} }

View File

@ -1,17 +1,20 @@
<x-card.card class="mb-3"> <x-card.card class="mb-3">
@php
@endphp
<x-card.heading>Seating</x-card.heading> <x-card.heading>Seating</x-card.heading>
<div class="py-3 px-1"> <div class="py-3 px-1">
<x-form.form method="POST" action="{{ route('tabulation.audition.seat',['audition' => $audition]) }}"> <x-form.form method="POST" action="{{ route('tabulation.audition.seat',['audition' => $audition]) }}">
@csrf @csrf
@foreach($ensembleLimits as $ensembleLimit) @foreach($rightPanel['data'] as $ensembleLimit)
@php @php
$value = $requestedEnsembleAccepts[$ensembleLimit->ensemble->id] ?? $ensembleLimit->maximum_accepted; //$value = $requestedEnsembleAccepts[$ensembleLimit->ensemble->id] ?? $ensembleLimit['limit'];
$value = $ensembleLimit['limit'];
@endphp @endphp
<x-form.field name="ensembleAccept[{{ $ensembleLimit->ensemble->id }}]" <x-form.field name="ensembleAccept[{{ $ensembleLimit['ensemble']->id }}]"
label_text="{{ $ensembleLimit->ensemble->name }} - Max: {{ $ensembleLimit->maximum_accepted }}" label_text="{{ $ensembleLimit['ensemble']->name }} - Max: {{ $ensembleLimit['limit'] }}"
type="number" type="number"
max="{{ $ensembleLimit->maximum_accepted }}" max="{{ $ensembleLimit['limit'] }}"
value="{{ $value }}" value="{{ $value }}"
class="mb-3"/> class="mb-3"/>
@endforeach @endforeach

View File

@ -0,0 +1,2 @@
@include('tabulation.auditionSeating-fill-seats-form')
@include('tabulation.auditionSeating-show-proposed-seats')

View File

@ -2,19 +2,20 @@
$seatingProposal = []; $seatingProposal = [];
@endphp @endphp
@foreach($ensembleLimits as $ensembleLimit) @foreach($rightPanel['data'] as $ensembleLimit)
<x-card.card class="mb-3"> <x-card.card class="mb-3">
<x-card.heading>{{ $ensembleLimit->ensemble->name }} - DRAFT</x-card.heading> <x-card.heading>{{ $ensembleLimit['ensemble']->name }} - DRAFT</x-card.heading>
<x-card.list.body> <x-card.list.body>
@php @php
$maxAccepted = $requestedEnsembleAccepts[$ensembleLimit->ensemble->id] ?? $ensembleLimit->maximum_accepted; // $maxAccepted = $requestedEnsembleAccepts[$ensembleLimit->ensemble->id] ?? $ensembleLimit->maximum_accepted;
$maxAccepted = $ensembleLimit['limit'];
@endphp @endphp
@for($n=1; $n <= $maxAccepted; $n++) @for($n=1; $n <= $maxAccepted; $n++)
@php @php
$entry = $seatableEntries->shift(); $entry = $seatableEntries->shift();
if (is_null($entry)) continue; if (is_null($entry)) continue;
$seatingProposal[] = [ $seatingProposal[] = [
'ensemble_id' => $ensembleLimit->ensemble->id, 'ensemble_id' => $ensembleLimit['ensemble']->id,
'audition_id' => $audition->id, 'audition_id' => $audition->id,
'seat' => $n, 'seat' => $n,
'entry_id' => $entry->id, 'entry_id' => $entry->id,

View File

@ -1,10 +1,10 @@
<x-card.card> <x-card.card>
<x-card.heading>Unable to seat this audition</x-card.heading> <x-card.heading>Unable to seat this audition</x-card.heading>
@if(! $scoringComplete) @if(! $rightPanel['data']['allScored'])
<p class="text-sm px-5 py-2">The audition cannot be seated while it has unscored entries.</p> <p class="text-sm px-5 py-2">The audition cannot be seated while it has unscored entries.</p>
@endif @endif
@if(! $doublerComplete) @if(! $rightPanel['data']['doublersResolved'])
<p class="text-sm px-5 py-2">The audition cannot be seated while it has unresolved doublers.</p> <p class="text-sm px-5 py-2">The audition cannot be seated while it has unresolved doublers.</p>
@endif @endif
</x-card.card> </x-card.card>

View File

@ -9,6 +9,9 @@
<div class="col-span-3"> <div class="col-span-3">
@include('tabulation.auditionSeating-results-table') @include('tabulation.auditionSeating-results-table')
</div> </div>
<div class="ml-4">
@include($rightPanel['view'])
</div>
{{-- <div class="ml-4">--}} {{-- <div class="ml-4">--}}
{{-- @if($audition->hasFlag('seats_published'))--}} {{-- @if($audition->hasFlag('seats_published'))--}}
{{-- @include('tabulation.auditionSeating-show-published-seats')--}} {{-- @include('tabulation.auditionSeating-show-published-seats')--}}

View File

@ -69,5 +69,5 @@ it('identifies a doubler', function () {
$response = get($this->r); $response = get($this->r);
$response->assertOk(); $response->assertOk();
$viewData = $response->viewData('entryData'); $viewData = $response->viewData('entryData');
expect($viewData[0]['isDoubler'])->toBeTrue(); expect($viewData[0]['doubleData'])->toBeTruthy();
}); });