Rewrite tabulation #14

Merged
okorpheus merged 43 commits from rewrite-tabulation into master 2024-07-14 05:36:29 +00:00
5 changed files with 219 additions and 7 deletions
Showing only changes of commit 98b466beb6 - Show all commits

View File

@ -1,13 +1,67 @@
<?php
/** @noinspection PhpUnhandledExceptionInspection */
namespace App\Actions\Tabulation;
use App\Exceptions\TabulationException;
use App\Models\Entry;
class AllJudgesCount implements CalculateEntryScore
{
protected CalculateScoreSheetTotal $calculator;
public function __construct()
{
$this->calculator = new CalculateScoreSheetTotal();
}
public function calculate(string $mode, Entry $entry): array
{
return ['vinita'=>'hornets'];
$this->basicValidation($mode, $entry);
$this->areAllJudgesIn($entry);
$this->areAllJudgesValid($entry);
return $this->getJudgeTotals($mode, $entry);
}
protected function getJudgeTotals($mode, Entry $entry)
{
$scores = [];
foreach ($entry->audition->judges as $judge) {
$scores[] = $this->calculator->__invoke($mode, $entry, $judge);
}
for ($i = 0; $i < count($scores[0]); $i++) {
$sums[] = $scores[0][$i] + $scores[1][$i];
}
return $sums;
}
protected function basicValidation($mode, $entry): void
{
if ($mode !== 'seating' && $mode !== 'advancement') {
throw new TabulationException('Mode must be seating or advancement');
}
if (! $entry->exists()) {
throw new TabulationException('Invalid entry specified');
}
}
protected function areAllJudgesIn(Entry $entry): void
{
$assignedJudgeCount = $entry->audition->judges->count();
if ($entry->scoreSheets->count() !== $assignedJudgeCount) {
throw new TabulationException('Not all score sheets are in');
}
}
protected function areAllJudgesValid(Entry $entry): void
{
$validJudgeIds = $entry->audition->judges->pluck('id')->sort()->toArray();
$existingJudgeIds = $entry->scoreSheets->pluck('user_id')->sort()->toArray();
if ($validJudgeIds !== $existingJudgeIds) {
throw new TabulationException('Score exists from a judge not assigned to this audition');
}
}
}

View File

@ -3,6 +3,7 @@
namespace App\Http\Controllers;
use App\Actions\Tabulation\CalculateEntryScore;
use App\Exceptions\TabulationException;
use App\Models\Entry;
class TestController extends Controller
@ -15,8 +16,29 @@ class TestController extends Controller
public function flashTest()
{
$test = $this->bigCalc->calculate('seating', Entry::find(1127))['vinita'];
$entries = Entry::forSeating()->with('student')->where('audition_id', 19)->get();
$rows = [];
foreach ($entries as $entry) {
try {
$totalScore = $this->bigCalc->calculate('seating', $entry)[0];
} catch (TabulationException $ex){
$totalScore = '--';
}
$rows[] = [
'name' => $entry->student->full_name(),
'totalScore' => $totalScore,
];
}
return view('test', compact('test'));
// try {
// $test = $this->bigCalc->calculate('seating', Entry::find(1061))[0];
// } catch (TabulationException $ex) {
// dd($ex);
// }
return view('test', compact('rows'));
}
}

View File

@ -4,6 +4,7 @@ namespace App\Providers;
use App\Actions\Tabulation\AllJudgesCount;
use App\Actions\Tabulation\CalculateEntryScore;
use App\Actions\Tabulation\CalculateScoreSheetTotal;
use Illuminate\Support\ServiceProvider;
class CalculateEntryScoreProvider extends ServiceProvider
@ -13,6 +14,7 @@ class CalculateEntryScoreProvider extends ServiceProvider
*/
public function register(): void
{
$this->app->singleton(CalculateScoreSheetTotal::class, CalculateScoreSheetTotal::class);
$this->app->singleton(CalculateEntryScore::class, AllJudgesCount::class);
}

View File

@ -7,9 +7,8 @@
@inject('drawService', 'App\Services\DrawService')
<x-layout.app>
<x-slot:page_title>Test Page</x-slot:page_title>
@php
@endphp
Test value: {{ $test }}
@foreach($rows as $row)
{{ $row['name'] }} - {{ $row['totalScore'] }}<hr>
@endforeach
</x-layout.app>

View File

@ -0,0 +1,135 @@
<?php
/** @noinspection PhpUnhandledExceptionInspection */
use App\Actions\Tabulation\AllJudgesCount;
use App\Exceptions\TabulationException;
use App\Models\Entry;
use App\Models\Room;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
it('throws an exception if mode is not seating or advancement', function () {
$calculator = new AllJudgesCount();
$calculator->calculate('WRONG', Entry::factory()->create());
})->throws(TabulationException::class, 'Mode must be seating or advancement');
it('throws an exception if entry is not valid', function () {
// Arrange
$calculator = new AllJudgesCount();
// Act
$calculator->calculate('seating', Entry::factory()->make());
// Assert
})->throws(TabulationException::class, 'Invalid entry specified');
it('throws an exception if entry is missing judge scores', function () {
// Arrange
loadSampleAudition();
$judge1 = User::factory()->create();
$judge2 = User::factory()->create();
Room::find(1000)->addJudge($judge1);
Room::find(1000)->addJudge($judge2);
$entry = Entry::factory()->create(['audition_id' => 1000]);
$scores = [
1001 => 50,
1002 => 60,
1003 => 70,
1004 => 80,
1005 => 90,
];
$calculator = new AllJudgesCount();
enterScore($judge1, $entry, $scores);
// Act
$calculator->calculate('seating', $entry);
// Assert
})->throws(TabulationException::class, 'Not all score sheets are in');
it('throws an exception if a score exists from an invalid judge', function () {
// Arrange
loadSampleAudition();
$judge1 = User::factory()->create();
$judge2 = User::factory()->create();
$judge3 = User::factory()->create();
Room::find(1000)->addJudge($judge1);
Room::find(1000)->addJudge($judge2);
$entry = Entry::factory()->create(['audition_id' => 1000]);
$scores = [
1001 => 50,
1002 => 60,
1003 => 70,
1004 => 80,
1005 => 90,
];
$calculator = new AllJudgesCount();
enterScore($judge1, $entry, $scores);
$scoreSheetToSpoof = enterScore($judge2, $entry, $scores);
$scoreSheetToSpoof->update(['user_id' => $judge3->id]);
// Act
$calculator->calculate('seating', $entry);
// Assert
})->throws(TabulationException::class, 'Score exists from a judge not assigned to this audition');
it('correctly calculates scores for seating', function () {
// Arrange
loadSampleAudition();
$judge1 = User::factory()->create();
$judge2 = User::factory()->create();
Room::find(1000)->addJudge($judge1);
Room::find(1000)->addJudge($judge2);
$entry = Entry::factory()->create(['audition_id' => 1000]);
$scores = [
1001 => 50,
1002 => 60,
1003 => 70,
1004 => 80,
1005 => 90,
];
$scores2 = [
1001 => 55,
1002 => 65,
1003 => 75,
1004 => 85,
1005 => 95,
];
$calculator = new AllJudgesCount();
enterScore($judge1, $entry, $scores);
enterScore($judge2, $entry, $scores2);
// Act
$finalScores = $calculator->calculate('seating', $entry);
// Assert
$expectedScores = [142.5, 165, 125, 145, 105];
expect($finalScores)->toBe($expectedScores);
});
it('correctly calculates scores for advancement', function () {
// Arrange
loadSampleAudition();
$judge1 = User::factory()->create();
$judge2 = User::factory()->create();
Room::find(1000)->addJudge($judge1);
Room::find(1000)->addJudge($judge2);
$entry = Entry::factory()->create(['audition_id' => 1000]);
$scores = [
1001 => 50,
1002 => 60,
1003 => 70,
1004 => 80,
1005 => 90,
];
$scores2 = [
1001 => 55,
1002 => 65,
1003 => 75,
1004 => 85,
1005 => 95,
];
$calculator = new AllJudgesCount();
enterScore($judge1, $entry, $scores);
enterScore($judge2, $entry, $scores2);
// Act
$finalScores = $calculator->calculate('advancement', $entry);
// Assert
$expectedScores = [152.5, 185, 165, 125, 145];
expect($finalScores)->toBe($expectedScores);
});