UpdateEntry tests

This commit is contained in:
Matt Young 2025-07-01 02:30:06 -05:00
parent 2f3c46973f
commit 30862271f2
4 changed files with 215 additions and 18 deletions

View File

@ -2,6 +2,7 @@
namespace App\Actions\Entries; namespace App\Actions\Entries;
use App\Exceptions\AuditionAdminException;
use App\Exceptions\ManageEntryException; use App\Exceptions\ManageEntryException;
use App\Models\Audition; use App\Models\Audition;
use App\Models\AuditLogEntry; use App\Models\AuditLogEntry;
@ -27,7 +28,7 @@ class UpdateEntry
/** /**
* @throws ManageEntryException * @throws ManageEntryException
*/ */
public function __invoke(Entry $entry, array $updateData): void public function __invoke(Entry|int $entry, array $updateData): void
{ {
$this->updateEntry($entry, $updateData); $this->updateEntry($entry, $updateData);
} }
@ -41,7 +42,7 @@ class UpdateEntry
$entry = Entry::find($entry); $entry = Entry::find($entry);
} }
if (! $entry || ! $entry->exists) { if (! $entry || ! $entry->exists) {
throw new ManageEntryException('Invalid entry provided'); throw new AuditionAdminException('Invalid entry provided');
} }
$this->entry = $entry; $this->entry = $entry;
if (array_key_exists('for_seating', $updateData)) { if (array_key_exists('for_seating', $updateData)) {
@ -81,34 +82,34 @@ class UpdateEntry
$audition = Audition::find($audition); $audition = Audition::find($audition);
} }
if (! $audition || ! $audition->exists) { if (! $audition || ! $audition->exists) {
throw new ManageEntryException('Invalid audition provided'); throw new AuditionAdminException('Invalid audition provided');
} }
if ($this->entry->audition->hasFlag('seats_published')) { if ($this->entry->audition->hasFlag('seats_published')) {
throw new ManageEntryException('Cannot change the audition for an entry where seating for that entry\'s current audition is published'); throw new AuditionAdminException('Cannot change the audition for an entry where seating for that entry\'s current audition is published');
} }
if ($this->entry->audition->hasFlag('advancement_published')) { if ($this->entry->audition->hasFlag('advancement_published')) {
throw new ManageEntryException('Cannot change the audition for an entry where advancement for that entry\'s current audition is published'); throw new AuditionAdminException('Cannot change the audition for an entry where advancement for that entry\'s current audition is published');
} }
if ($audition->hasFlag('seats_published')) { if ($audition->hasFlag('seats_published')) {
throw new ManageEntryException('Cannot change the entry to an audition with published seating'); throw new AuditionAdminException('Cannot change the entry to an audition with published seating');
} }
if ($audition->hasFlag('advancement_published')) { if ($audition->hasFlag('advancement_published')) {
throw new ManageEntryException('Cannot change the entry to an audition with published advancement'); throw new AuditionAdminException('Cannot change the entry to an audition with published advancement');
} }
if ($this->entry->student->grade > $audition->maximum_grade) { if ($this->entry->student->grade > $audition->maximum_grade) {
throw new ManageEntryException('The grade of the student exceeds the maximum for that audition'); throw new AuditionAdminException('The student is too old to enter that audition');
} }
if ($this->entry->student->grade < $audition->minimum_grade) { if ($this->entry->student->grade < $audition->minimum_grade) {
throw new ManageEntryException('The grade of the student does not meet the minimum for that audition'); throw new AuditionAdminException('The student is too young to enter that audition');
} }
if ($this->entry->scoreSheets()->count() > 0) { if ($this->entry->scoreSheets()->count() > 0) {
throw new ManageEntryException('Cannot change the audition for an entry with scores'); throw new AuditionAdminException('Cannot change the audition for an entry with scores');
} }
if ($audition->id !== $this->entry->audition_id && if ($audition->id !== $this->entry->audition_id &&
Entry::where('student_id', $this->entry->student_id) Entry::where('student_id', $this->entry->student_id)
->where('audition_id', $audition->id)->exists()) { ->where('audition_id', $audition->id)->exists()) {
throw new ManageEntryException('That student is already entered in that audition'); throw new AuditionAdminException('That student is already entered in that audition');
} }
// Escape if we're not actually making a change // Escape if we're not actually making a change
if ($this->entry->audition_id == $audition->id) { if ($this->entry->audition_id == $audition->id) {
@ -139,13 +140,13 @@ class UpdateEntry
} }
if ($forSeating) { if ($forSeating) {
if ($this->entry->audition->hasFlag('seats_published')) { if ($this->entry->audition->hasFlag('seats_published')) {
throw new ManageEntryException('Cannot add seating to an entry in an audition where seats are published'); throw new AuditionAdminException('Cannot add seating to an entry in an audition where seats are published');
} }
$this->entry->for_seating = 1; $this->entry->for_seating = 1;
$this->log_message .= 'Entry '.$this->entry->id.' is entered for seating '.'<br>'; $this->log_message .= 'Entry '.$this->entry->id.' is entered for seating '.'<br>';
} else { } else {
if ($this->entry->audition->hasFlag('seats_published')) { if ($this->entry->audition->hasFlag('seats_published')) {
throw new ManageEntryException('Cannot remove seating from an entry in an audition where seats are published'); throw new AuditionAdminException('Cannot remove seating from an entry in an audition where seats are published');
} }
$this->entry->for_seating = 0; $this->entry->for_seating = 0;
$this->log_message .= 'Entry '.$this->entry->id.' is NOT entered for seating '.'<br>'; $this->log_message .= 'Entry '.$this->entry->id.' is NOT entered for seating '.'<br>';
@ -162,13 +163,13 @@ class UpdateEntry
} }
if ($forAdvancement) { if ($forAdvancement) {
if ($this->entry->audition->hasFlag('advancement_published')) { if ($this->entry->audition->hasFlag('advancement_published')) {
throw new ManageEntryException('Cannot add advancement to an entry in an audition where advancement is published'); throw new AuditionAdminException('Cannot add advancement to an entry in an audition where advancement is published');
} }
$this->entry->for_advancement = 1; $this->entry->for_advancement = 1;
$this->log_message .= 'Entry '.$this->entry->id.' is entered for '.auditionSetting('advanceTo').'<br>'; $this->log_message .= 'Entry '.$this->entry->id.' is entered for '.auditionSetting('advanceTo').'<br>';
} else { } else {
if ($this->entry->audition->hasFlag('advancement_published')) { if ($this->entry->audition->hasFlag('advancement_published')) {
throw new ManageEntryException('Cannot remove advancement from an entry in an audition where advancement is published'); throw new AuditionAdminException('Cannot remove advancement from an entry in an audition where advancement is published');
} }
$this->entry->for_advancement = 0; $this->entry->for_advancement = 0;
$this->log_message .= 'Entry '.$this->entry->id.' is NOT entered for '.auditionSetting('advanceTo').'<br>'; $this->log_message .= 'Entry '.$this->entry->id.' is NOT entered for '.auditionSetting('advanceTo').'<br>';

View File

@ -4,6 +4,7 @@ namespace App\Http\Controllers\Admin;
use App\Actions\Entries\CreateEntry; use App\Actions\Entries\CreateEntry;
use App\Actions\Entries\UpdateEntry; use App\Actions\Entries\UpdateEntry;
use App\Exceptions\AuditionAdminException;
use App\Exceptions\ManageEntryException; use App\Exceptions\ManageEntryException;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Models\Audition; use App\Models\Audition;
@ -192,7 +193,7 @@ class EntryController extends Controller
} }
try { try {
$updater($entry, $validData); $updater($entry, $validData);
} catch (ManageEntryException $e) { } catch (AuditionAdminException $e) {
return redirect()->route('admin.entries.index')->with('error', $e->getMessage()); return redirect()->route('admin.entries.index')->with('error', $e->getMessage());
} }
if ($validData['late_fee_waived']) { if ($validData['late_fee_waived']) {

View File

@ -34,8 +34,7 @@ class EntryObserver
// Update doubler table when an entry is updated // Update doubler table when an entry is updated
Doubler::syncForEvent($entry->audition->event_id); Doubler::syncForEvent($entry->audition->event_id);
if ($entry->wasChanged('audition_id')) { if ($entry->wasChanged('audition_id')) {
$originalData = $entry->getOriginal(); Doubler::syncDoublers();
Doubler::syncForEvent($originalData->audition->event_id);
} }
} }

View File

@ -0,0 +1,196 @@
<?php
/** @noinspection PhpUnhandledExceptionInspection */
use App\Actions\Development\FakeScoresForEntry;
use App\Actions\Entries\UpdateEntry;
use App\Exceptions\AuditionAdminException;
use App\Models\Audition;
use App\Models\AuditionFlag;
use App\Models\Entry;
use App\Models\Room;
use App\Models\ScoringGuide;
use App\Models\Student;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
beforeEach(function () {
$this->entryScribe = app(UpdateEntry::class);
$this->audition = Audition::factory()->create(
[
'minimum_grade' => 9, 'maximum_grade' => 10,
'name' => 'Flute',
]);
$this->student = Student::factory()->create(['grade' => 9]);
$this->entry = Entry::factory()->create([
'student_id' => $this->student->id,
'audition_id' => $this->audition->id,
]);
});
it('throws an exception when an invalid entry is provided', function () {
($this->entryScribe)(35, []);
})->throws(AuditionAdminException::class, 'Invalid entry provided');
it('throws an exception when a non-existent entry is provided', function () {
$newEntry = Entry::factory()->make();
($this->entryScribe)($newEntry, []);
})->throws(AuditionAdminException::class, 'Invalid entry provided');
it('will not modify an entry in an audition with published seats', function () {
$this->entry->audition->addFlag('seats_published');
$newAudition = Audition::factory()->create(['event_id' => $this->entry->audition->event_id]);
($this->entryScribe)($this->entry, ['audition_id' => $newAudition->id]);
})->throws(AuditionAdminException::class,
'Cannot change the audition for an entry where seating for that entry\'s current audition is published');
it('will not modify an entry in an audition with published advancement', function () {
$this->entry->audition->addFlag('advancement_published');
$newAudition = Audition::factory()->create(['event_id' => $this->entry->audition->event_id]);
($this->entryScribe)($this->entry, ['audition_id' => $newAudition->id]);
})->throws(AuditionAdminException::class,
'Cannot change the audition for an entry where advancement for that entry\'s current audition is published');
it('will not move an entry to an audition with published seating', function () {
$newAudition = Audition::factory()->create(['event_id' => $this->entry->audition->event_id]);
$newAudition->addFlag('seats_published');
($this->entryScribe)($this->entry, ['audition_id' => $newAudition->id]);
})->throws(AuditionAdminException::class, 'Cannot change the entry to an audition with published seating');
it('will not move an entry to an audition with published advancement', function () {
$newAudition = Audition::factory()->create(['event_id' => $this->entry->audition->event_id]);
$newAudition->addFlag('advancement_published');
($this->entryScribe)($this->entry, ['audition_id' => $newAudition->id]);
})->throws(AuditionAdminException::class, 'Cannot change the entry to an audition with published advancement');
it('will not move to an audition for which the student is too young', function () {
$newAudition = Audition::factory()->create([
'event_id' => $this->entry->audition->event_id,
'minimum_grade' => 10,
]);
$this->entry->student->update(['grade' => 9]);
($this->entryScribe)($this->entry, ['audition_id' => $newAudition->id]);
})->throws(AuditionAdminException::class, 'The student is too young to enter that audition')->skip('test needs work');
it('will not move to an audition for which the student is too old', function () {
$newAudition = Audition::factory()->create([
'event_id' => $this->entry->audition->event_id,
'maximum_grade' => 8,
]);
$this->entry->student->update(['grade' => 9]);
($this->entryScribe)($this->entry, ['audition_id' => $newAudition->id]);
})->throws(AuditionAdminException::class, 'The student is too old to enter that audition')->skip('test needs work');
it('will not change auditions for an entry with scores', function () {
$scoreFaker = app(FakeScoresForEntry::class);
$newAudition = Audition::factory()->create([
'event_id' => $this->entry->audition->event_id,
'minimum_grade' => 9,
'maximum_grade' => 10,
]);
$scoringGuide = ScoringGuide::factory()->create();
$judge1 = User::factory()->create();
$judge2 = User::factory()->create();
$room = Room::factory()->create();
$room->addJudge($judge1);
$room->addJudge($judge2);
$this->entry->audition->update([
'scoring_guide_id' => $scoringGuide->id,
'room_id' => $room->id,
'order_in_room' => 1,
]);
$scoreFaker($this->entry);
($this->entryScribe)($this->entry, ['audition_id' => $newAudition->id]);
})->throws(AuditionAdminException::class, 'Cannot change the audition for an entry with scores');
it(('will not change the audition to one in which the student is already entered'), function () {
$newAudition = Audition::factory()->create(['minimum_grade' => 9, 'maximum_grade' => 10]);
Entry::create([
'student_id' => $this->student->id,
'audition_id' => $newAudition->id,
]);
($this->entryScribe)($this->entry, ['audition_id' => $newAudition->id]);
})->throws(AuditionAdminException::class, 'That student is already entered in that audition');
it('will not set a draw number if the new audition is not drawn', function () {
$newAudition = Audition::factory()->create(['minimum_grade' => 9, 'maximum_grade' => 10]);
($this->entryScribe)($this->entry, ['audition_id' => $newAudition->id]);
$this->entry->refresh();
expect($this->entry->draw_number)->toBeNull();
});
it('will assign the next draw number if the new audition is drawn', function () {
$newAudition = Audition::factory()
->has(Entry::factory()->count(5))
->create(['minimum_grade' => 9, 'maximum_grade' => 10]);
AuditionFlag::create(['audition_id' => $newAudition->id, 'flag_name' => 'drawn']);
$n = 1;
foreach ($newAudition->entries as $entry) {
$entry->update(['draw_number' => $n]);
$n++;
}
($this->entryScribe)($this->entry, ['audition_id' => $newAudition->id]);
expect($this->entry->draw_number)->toBe($n);
});
it('can change and entries audition', function () {
$newAudition = Audition::factory()->create(['minimum_grade' => 9, 'maximum_grade' => 10]);
($this->entryScribe)($this->entry, ['audition' => $newAudition]);
$this->entry->refresh();
$freshEntry = Entry::find($this->entry->id);
expect($freshEntry->audition_id)->toBe($newAudition->id);
});
it('can remove forAdvancement from the entry', function () {
($this->entryScribe)($this->entry, ['for_advancement' => false]);
expect($this->entry->for_advancement)->toBeFalsy();
});
it('can add forAdvancement to the entry', function () {
$this->entry->update(['for_advancement' => false]);
expect($this->entry->for_advancement)->toBeFalsy();
($this->entryScribe)($this->entry, ['for_advancement' => true]);
expect($this->entry->for_advancement)->toBeTruthy();
});
it('cannot remove forAdvancement if advancement is published', function () {
$this->entry->audition->addFlag('advancement_published');
($this->entryScribe)($this->entry, ['for_advancement' => false]);
})->throws(AuditionAdminException::class,
'Cannot remove advancement from an entry in an audition where advancement is published');
it('cannot add forAdvancement if advancement is published', function () {
$this->entry->update(['for_advancement' => false]);
expect($this->entry->for_advancement)->toBeFalsy();
$this->entry->audition->addFlag('advancement_published');
($this->entryScribe)($this->entry, ['for_advancement' => true]);
})->throws(AuditionAdminException::class,
'Cannot add advancement to an entry in an audition where advancement is published');
it('can remove forSeating from the entry', function () {
($this->entryScribe)($this->entry, ['for_seating' => false]);
expect($this->entry->for_seating)->toBeFalsy();
});
it('can add forSeating to the entry', function () {
$this->entry->update(['for_seating' => false]);
expect($this->entry->for_seating)->toBeFalsy();
($this->entryScribe)($this->entry, ['for_seating' => true]);
expect($this->entry->for_seating)->toBeTruthy();
});
it('cannot remove forSeating if seating is published', function () {
$this->entry->audition->addFlag('seats_published');
($this->entryScribe)($this->entry, ['for_seating' => false]);
})->throws(AuditionAdminException::class,
'Cannot remove seating from an entry in an audition where seats are published');
it('cannot add forSeating if seating is published', function () {
$this->entry->update(['for_seating' => false]);
expect($this->entry->for_seating)->toBeFalsy();
$this->entry->audition->addFlag('seats_published');
($this->entryScribe)($this->entry, ['for_seating' => true]);
})->throws(AuditionAdminException::class,
'Cannot add seating to an entry in an audition where seats are published');