Flags for entries to store declined. Seating page will correctly display doubler status
This commit is contained in:
parent
30c2813ecf
commit
f9e936fd07
|
|
@ -2,23 +2,28 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Exceptions\TabulationException;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOneThrough;
|
||||
|
||||
class Entry extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $guarded = [];
|
||||
|
||||
protected $hasCheckedScoreSheets = false;
|
||||
|
||||
public $final_scores_array; // Set by TabulationService
|
||||
|
||||
public $scoring_complete; // Set by TabulationService
|
||||
|
||||
public $is_doubler; // Set by DoublerService
|
||||
|
||||
protected $with = ['flags'];
|
||||
|
||||
public function student(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Student::class);
|
||||
|
|
@ -46,14 +51,27 @@ class Entry extends Model
|
|||
|
||||
}
|
||||
|
||||
/*
|
||||
public function flags(): HasMany
|
||||
{
|
||||
return $this->hasMany(EntryFlag::class);
|
||||
}
|
||||
|
||||
public function hasFlag($flag)
|
||||
{
|
||||
// return true if any flag in $this->flags has a flag_name of declined without making another db query if flags are loaded
|
||||
return $this->flags->contains('flag_name', $flag);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures score_sheets_count property is always available
|
||||
*/
|
||||
public function getScoreSheetsCountAttribute()
|
||||
{
|
||||
if (!isset($this->attributes['score_sheets_count'])) {
|
||||
if (! isset($this->attributes['score_sheets_count'])) {
|
||||
$this->attributes['score_sheets_count'] = $this->scoreSheets()->count();
|
||||
}
|
||||
|
||||
return $this->attributes['score_sheets_count'];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class EntryFlag extends Model
|
||||
{
|
||||
// Possible flags include
|
||||
// - declined: used if a doubler declines a seat in this audition. Checked by DoublerService
|
||||
public function entry(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Entry::class);
|
||||
}
|
||||
}
|
||||
|
|
@ -9,9 +9,13 @@ use Illuminate\Support\Facades\Cache;
|
|||
class DoublerService
|
||||
{
|
||||
protected $doublersCacheKey = 'doublers';
|
||||
|
||||
protected $auditionCacheService;
|
||||
|
||||
protected $tabulationService;
|
||||
|
||||
protected $seatingService;
|
||||
|
||||
/**
|
||||
* Create a new class instance.
|
||||
*/
|
||||
|
|
@ -24,12 +28,11 @@ class DoublerService
|
|||
|
||||
/**
|
||||
* Returns a collection of students that have more than one entry
|
||||
* @return \Illuminate\Database\Eloquent\Collection
|
||||
*/
|
||||
public function getDoublers(): \Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
// TODO creating or destroying an entry should refresh the doubler cache
|
||||
return Cache::remember($this->doublersCacheKey, 3600, function () {
|
||||
return Cache::remember($this->doublersCacheKey, 60, function () {
|
||||
return Student::withCount('entries')
|
||||
->with('entries')
|
||||
->havingRaw('entries_count > ?', [1])
|
||||
|
|
@ -37,6 +40,12 @@ class DoublerService
|
|||
});
|
||||
}
|
||||
|
||||
public function refreshDoublerCache()
|
||||
{
|
||||
Cache::forget($this->doublersCacheKey);
|
||||
$this->getDoublers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of information about each entry for a specific doubler. Info for each entry includes
|
||||
* auditionID
|
||||
|
|
@ -45,25 +54,45 @@ class DoublerService
|
|||
* unscored => How many entries remain to be scored in this audition
|
||||
*
|
||||
* @param int $studentId The ID of the doubler
|
||||
* @return array
|
||||
*/
|
||||
public function getDoublerInfo($studentId): array
|
||||
{
|
||||
$doubler = $this->getDoublers()->firstWhere('id', $studentId);
|
||||
|
||||
// Split $doubler->entries into two arrays based on the result of hasFlag('declined')
|
||||
$undecidedEntries = $doubler->entries->filter(function ($entry) {
|
||||
return ! $entry->hasFlag('declined');
|
||||
});
|
||||
$acceptedEntry = null;
|
||||
if ($undecidedEntries->count() == 1) {
|
||||
$acceptedEntry = $undecidedEntries->first();
|
||||
}
|
||||
// TODO can I rewrite this?
|
||||
|
||||
// When getting a doubler we need to know
|
||||
// 1) What their entries are
|
||||
// 2) For each audition they're entered in, what is their rank
|
||||
// 3) For each audition they're entered in, how many entries are unscored
|
||||
// 4) How many are accepted on that instrument
|
||||
$doubler = $this->getDoublers()->firstWhere('id',$studentId);
|
||||
// 5) Status - accepted, declined or undecided
|
||||
|
||||
$info = [];
|
||||
|
||||
foreach ($doubler->entries as $entry) {
|
||||
if ($entry->hasFlag('declined')) {
|
||||
$status = 'declined';
|
||||
} elseif ($entry === $acceptedEntry) {
|
||||
$status = 'accepted';
|
||||
} else {
|
||||
$status = 'undecided';
|
||||
}
|
||||
$info[$entry->id] = [
|
||||
'auditionID' => $entry->audition_id,
|
||||
'auditionName' => $this->auditionCacheService->getAudition($entry->audition_id)->name,
|
||||
'rank' => $this->tabulationService->entryRank($entry),
|
||||
'unscored' => $this->tabulationService->remainingEntriesForAudition($entry->audition_id),
|
||||
'limits' => $this->seatingService->getLimitForAudition($entry->audition_id),
|
||||
'status' => $status,
|
||||
];
|
||||
$entry->audition = $this->auditionCacheService->getAudition($entry->audition_id);
|
||||
}
|
||||
|
|
@ -71,7 +100,6 @@ class DoublerService
|
|||
return $info;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if a student is a doubler based on the given student ID
|
||||
*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Entry;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('entry_flags', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignIdFor(Entry::class)->constrained()->cascadeOnUpdate()->cascadeOnDelete();
|
||||
$table->string('flag_name');
|
||||
$table->unique(['entry_id', 'flag_name']);
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('entry_flags');
|
||||
}
|
||||
};
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
<div class="flex items-start gap-x-3">
|
||||
<p class="text-sm font-semibold leading-6 text-gray-900">
|
||||
<a href="/tabulation/auditions/{{ $info['auditionID'] }}">
|
||||
{{ $info['auditionName'] }}
|
||||
{{ $info['auditionName'] }} - {{ $info['status'] }}
|
||||
</a>
|
||||
</p>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue