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;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Exceptions\TabulationException;
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
|
|
||||||
use Illuminate\Database\Eloquent\Relations\HasOneThrough;
|
use Illuminate\Database\Eloquent\Relations\HasOneThrough;
|
||||||
|
|
||||||
class Entry extends Model
|
class Entry extends Model
|
||||||
{
|
{
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
|
|
||||||
protected $guarded = [];
|
protected $guarded = [];
|
||||||
|
|
||||||
protected $hasCheckedScoreSheets = false;
|
protected $hasCheckedScoreSheets = false;
|
||||||
|
|
||||||
public $final_scores_array; // Set by TabulationService
|
public $final_scores_array; // Set by TabulationService
|
||||||
|
|
||||||
public $scoring_complete; // Set by TabulationService
|
public $scoring_complete; // Set by TabulationService
|
||||||
|
|
||||||
public $is_doubler; // Set by DoublerService
|
public $is_doubler; // Set by DoublerService
|
||||||
|
|
||||||
|
protected $with = ['flags'];
|
||||||
|
|
||||||
public function student(): BelongsTo
|
public function student(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Student::class);
|
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
|
* Ensures score_sheets_count property is always available
|
||||||
*/
|
*/
|
||||||
public function getScoreSheetsCountAttribute()
|
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();
|
$this->attributes['score_sheets_count'] = $this->scoreSheets()->count();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->attributes['score_sheets_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
|
class DoublerService
|
||||||
{
|
{
|
||||||
protected $doublersCacheKey = 'doublers';
|
protected $doublersCacheKey = 'doublers';
|
||||||
|
|
||||||
protected $auditionCacheService;
|
protected $auditionCacheService;
|
||||||
|
|
||||||
protected $tabulationService;
|
protected $tabulationService;
|
||||||
|
|
||||||
protected $seatingService;
|
protected $seatingService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new class instance.
|
* Create a new class instance.
|
||||||
*/
|
*/
|
||||||
|
|
@ -24,12 +28,11 @@ class DoublerService
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a collection of students that have more than one entry
|
* Returns a collection of students that have more than one entry
|
||||||
* @return \Illuminate\Database\Eloquent\Collection
|
|
||||||
*/
|
*/
|
||||||
public function getDoublers(): \Illuminate\Database\Eloquent\Collection
|
public function getDoublers(): \Illuminate\Database\Eloquent\Collection
|
||||||
{
|
{
|
||||||
// TODO creating or destroying an entry should refresh the doubler cache
|
// 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')
|
return Student::withCount('entries')
|
||||||
->with('entries')
|
->with('entries')
|
||||||
->havingRaw('entries_count > ?', [1])
|
->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
|
* Returns an array of information about each entry for a specific doubler. Info for each entry includes
|
||||||
* auditionID
|
* auditionID
|
||||||
|
|
@ -45,25 +54,45 @@ class DoublerService
|
||||||
* unscored => How many entries remain to be scored in this audition
|
* unscored => How many entries remain to be scored in this audition
|
||||||
*
|
*
|
||||||
* @param int $studentId The ID of the doubler
|
* @param int $studentId The ID of the doubler
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
public function getDoublerInfo($studentId): 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
|
// When getting a doubler we need to know
|
||||||
// 1) What their entries are
|
// 1) What their entries are
|
||||||
// 2) For each audition they're entered in, what is their rank
|
// 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
|
// 3) For each audition they're entered in, how many entries are unscored
|
||||||
// 4) How many are accepted on that instrument
|
// 4) How many are accepted on that instrument
|
||||||
$doubler = $this->getDoublers()->firstWhere('id',$studentId);
|
// 5) Status - accepted, declined or undecided
|
||||||
|
|
||||||
$info = [];
|
$info = [];
|
||||||
|
|
||||||
foreach ($doubler->entries as $entry) {
|
foreach ($doubler->entries as $entry) {
|
||||||
|
if ($entry->hasFlag('declined')) {
|
||||||
|
$status = 'declined';
|
||||||
|
} elseif ($entry === $acceptedEntry) {
|
||||||
|
$status = 'accepted';
|
||||||
|
} else {
|
||||||
|
$status = 'undecided';
|
||||||
|
}
|
||||||
$info[$entry->id] = [
|
$info[$entry->id] = [
|
||||||
'auditionID' => $entry->audition_id,
|
'auditionID' => $entry->audition_id,
|
||||||
'auditionName' => $this->auditionCacheService->getAudition($entry->audition_id)->name,
|
'auditionName' => $this->auditionCacheService->getAudition($entry->audition_id)->name,
|
||||||
'rank' => $this->tabulationService->entryRank($entry),
|
'rank' => $this->tabulationService->entryRank($entry),
|
||||||
'unscored' => $this->tabulationService->remainingEntriesForAudition($entry->audition_id),
|
'unscored' => $this->tabulationService->remainingEntriesForAudition($entry->audition_id),
|
||||||
'limits' => $this->seatingService->getLimitForAudition($entry->audition_id),
|
'limits' => $this->seatingService->getLimitForAudition($entry->audition_id),
|
||||||
|
'status' => $status,
|
||||||
];
|
];
|
||||||
$entry->audition = $this->auditionCacheService->getAudition($entry->audition_id);
|
$entry->audition = $this->auditionCacheService->getAudition($entry->audition_id);
|
||||||
}
|
}
|
||||||
|
|
@ -71,7 +100,6 @@ class DoublerService
|
||||||
return $info;
|
return $info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if a student is a doubler based on the given student ID
|
* 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">
|
<div class="flex items-start gap-x-3">
|
||||||
<p class="text-sm font-semibold leading-6 text-gray-900">
|
<p class="text-sm font-semibold leading-6 text-gray-900">
|
||||||
<a href="/tabulation/auditions/{{ $info['auditionID'] }}">
|
<a href="/tabulation/auditions/{{ $info['auditionID'] }}">
|
||||||
{{ $info['auditionName'] }}
|
{{ $info['auditionName'] }} - {{ $info['status'] }}
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue