Allow for marking no-shows en-masse

Closes #82
This commit is contained in:
Matt Young 2024-10-27 16:55:49 -05:00
parent 77c868e209
commit 34347a2e2a
4 changed files with 120 additions and 14 deletions

View File

@ -0,0 +1,66 @@
<?php
namespace App\Actions\Entries;
use App\Exceptions\AuditionAdminException;
use App\Models\Entry;
use App\Services\DoublerService;
class DoublerDecision
{
protected DoublerService $doublerService;
public function __construct(DoublerService $doublerService)
{
$this->doublerService = $doublerService;
}
/**
* @throws AuditionAdminException
*/
public function __invoke(Entry $entry, string $decision): void
{
$this->doublerDecision($entry, $decision);
}
/**
* @throws AuditionAdminException
*/
public function doublerDecision(Entry $entry, string $decision): void
{
match ($decision) {
'accept' => $this->accept($entry),
'decline' => $this->decline($entry),
default => throw new AuditionAdminException('Invalid decision specified')
};
if ($decision != 'accept' && $decision != 'decline') {
throw new AuditionAdminException('Invalid decision specified');
}
}
public function accept($entry): void
{
// Decline all other entries
$doublerInfo = $this->doublerService->simpleDoubleInfo($entry);
foreach ($doublerInfo as $doublerEntry) {
/** @var Entry $doublerEntry */
if ($doublerEntry->id !== $entry->id) {
$doublerEntry->addFlag('declined');
}
}
}
/**
* @throws AuditionAdminException
*/
public function decline($entry): void
{
if ($entry->hasFlag('declined')) {
throw new AuditionAdminException('Entry is already declined');
}
$entry->addFlag('declined');
}
}

View File

@ -2,6 +2,8 @@
namespace App\Http\Controllers\Tabulation; namespace App\Http\Controllers\Tabulation;
use App\Actions\Entries\DoublerDecision;
use App\Exceptions\AuditionAdminException;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Models\Entry; use App\Models\Entry;
use App\Services\DoublerService; use App\Services\DoublerService;
@ -14,21 +16,25 @@ class DoublerDecisionController extends Controller
protected $entryService; protected $entryService;
public function __construct(DoublerService $doublerService, EntryService $entryService) protected $decider;
public function __construct(DoublerService $doublerService, EntryService $entryService, DoublerDecision $decider)
{ {
$this->doublerService = $doublerService; $this->doublerService = $doublerService;
$this->entryService = $entryService; $this->entryService = $entryService;
$this->decider = $decider;
} }
public function accept(Entry $entry) public function accept(Entry $entry)
{ {
$doublerInfo = $this->doublerService->simpleDoubleInfo($entry); // $doublerInfo = $this->doublerService->simpleDoubleInfo($entry);
foreach ($doublerInfo as $doublerEntry) { // foreach ($doublerInfo as $doublerEntry) {
/** @var Entry $doublerEntry */ // /** @var Entry $doublerEntry */
if ($doublerEntry->id !== $entry->id) { // if ($doublerEntry->id !== $entry->id) {
$doublerEntry->addFlag('declined'); // $doublerEntry->addFlag('declined');
} // }
} // }
$this->decider->accept($entry);
$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); $this->clearCache($entry);
@ -39,12 +45,16 @@ class DoublerDecisionController extends Controller
public function decline(Entry $entry) public function decline(Entry $entry)
{ {
if ($entry->hasFlag('declined')) { // if ($entry->hasFlag('declined')) {
return redirect()->back()->with('caution', 'Entry is already declined'); // return redirect()->back()->with('caution', 'Entry is already declined');
// }
//
// $entry->addFlag('declined');
try {
$this->decider->decline($entry);
} catch (AuditionAdminException $e) {
return redirect()->back()->with('error', $e->getMessage());
} }
$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); $this->clearCache($entry);

View File

@ -2,9 +2,11 @@
namespace App\Http\Controllers\Tabulation; namespace App\Http\Controllers\Tabulation;
use App\Actions\Entries\DoublerDecision;
use App\Actions\Tabulation\CalculateEntryScore; use App\Actions\Tabulation\CalculateEntryScore;
use App\Actions\Tabulation\GetAuditionSeats; use App\Actions\Tabulation\GetAuditionSeats;
use App\Actions\Tabulation\RankAuditionEntries; use App\Actions\Tabulation\RankAuditionEntries;
use App\Exceptions\AuditionAdminException;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Models\Audition; use App\Models\Audition;
use App\Services\AuditionService; use App\Services\AuditionService;
@ -12,6 +14,8 @@ use App\Services\DoublerService;
use App\Services\EntryService; use App\Services\EntryService;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use function redirect;
class SeatAuditionFormController extends Controller class SeatAuditionFormController extends Controller
{ {
protected CalculateEntryScore $calc; protected CalculateEntryScore $calc;
@ -24,24 +28,28 @@ class SeatAuditionFormController extends Controller
protected AuditionService $auditionService; protected AuditionService $auditionService;
protected DoublerDecision $decider;
public function __construct( public function __construct(
CalculateEntryScore $calc, CalculateEntryScore $calc,
RankAuditionEntries $ranker, RankAuditionEntries $ranker,
DoublerService $doublerService, DoublerService $doublerService,
EntryService $entryService, EntryService $entryService,
AuditionService $auditionService, AuditionService $auditionService,
DoublerDecision $decider,
) { ) {
$this->calc = $calc; $this->calc = $calc;
$this->ranker = $ranker; $this->ranker = $ranker;
$this->doublerService = $doublerService; $this->doublerService = $doublerService;
$this->entryService = $entryService; $this->entryService = $entryService;
$this->auditionService = $auditionService; $this->auditionService = $auditionService;
$this->decider = $decider;
} }
public function __invoke(Request $request, Audition $audition) public function __invoke(Request $request, Audition $audition)
{ {
// If a seating proposal was posted, deal wth it // If a seating proposal was posted, deal wth it
if ($request->method() == 'POST') { if ($request->method() == 'POST' && $request->input('ensembleAccept')) {
$requestedEnsembleAccepts = $request->input('ensembleAccept'); $requestedEnsembleAccepts = $request->input('ensembleAccept');
} else { } else {
$requestedEnsembleAccepts = false; $requestedEnsembleAccepts = false;
@ -60,6 +68,23 @@ class SeatAuditionFormController extends Controller
$entryData = []; $entryData = [];
$entries = $this->ranker->rank('seating', $audition); $entries = $this->ranker->rank('seating', $audition);
if ($request->input('decline-below')) {
$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) {
return redirect()->back();
}
}
$entries->load('student.school'); $entries->load('student.school');
$entries->load('student.doublerRequests'); $entries->load('student.doublerRequests');
$seatable = [ $seatable = [
@ -78,6 +103,7 @@ class SeatAuditionFormController extends Controller
$fullyScored = true; $fullyScored = true;
} }
$doublerData = $this->doublerService->entryDoublerData($entry); $doublerData = $this->doublerService->entryDoublerData($entry);
$entryData[] = [ $entryData[] = [
'rank' => $entry->rank, 'rank' => $entry->rank,
'id' => $entry->id, 'id' => $entry->id,

View File

@ -12,5 +12,9 @@
@endif @endif
@if(! $rightPanel['data']['doublersResolved']) @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>
<x-form.form method="POST" action="{{route('seating.audition',['audition' => $audition])}}">
<x-form.field name="decline-below" label_text="Decline Doublers Ranked Below" type="number" class="mb-3" />
<x-form.button class="mb-3">Decline Doublers</x-form.button>
</x-form.form>
@endif @endif
</x-card.card> </x-card.card>