diff --git a/app/Actions/Entries/UpdateEntry.php b/app/Actions/Entries/UpdateEntry.php
index 4926dc8..9d94992 100644
--- a/app/Actions/Entries/UpdateEntry.php
+++ b/app/Actions/Entries/UpdateEntry.php
@@ -2,6 +2,7 @@
namespace App\Actions\Entries;
+use App\Exceptions\AuditionAdminException;
use App\Exceptions\ManageEntryException;
use App\Models\Audition;
use App\Models\AuditLogEntry;
@@ -27,7 +28,7 @@ class UpdateEntry
/**
* @throws ManageEntryException
*/
- public function __invoke(Entry $entry, array $updateData): void
+ public function __invoke(Entry|int $entry, array $updateData): void
{
$this->updateEntry($entry, $updateData);
}
@@ -41,7 +42,7 @@ class UpdateEntry
$entry = Entry::find($entry);
}
if (! $entry || ! $entry->exists) {
- throw new ManageEntryException('Invalid entry provided');
+ throw new AuditionAdminException('Invalid entry provided');
}
$this->entry = $entry;
if (array_key_exists('for_seating', $updateData)) {
@@ -81,34 +82,34 @@ class UpdateEntry
$audition = Audition::find($audition);
}
if (! $audition || ! $audition->exists) {
- throw new ManageEntryException('Invalid audition provided');
+ throw new AuditionAdminException('Invalid audition provided');
}
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')) {
- 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')) {
- 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')) {
- 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) {
- 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) {
- 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) {
- 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 &&
Entry::where('student_id', $this->entry->student_id)
->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
if ($this->entry->audition_id == $audition->id) {
@@ -139,13 +140,13 @@ class UpdateEntry
}
if ($forSeating) {
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->log_message .= 'Entry '.$this->entry->id.' is entered for seating '.'
';
} else {
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->log_message .= 'Entry '.$this->entry->id.' is NOT entered for seating '.'
';
@@ -162,13 +163,13 @@ class UpdateEntry
}
if ($forAdvancement) {
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->log_message .= 'Entry '.$this->entry->id.' is entered for '.auditionSetting('advanceTo').'
';
} else {
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->log_message .= 'Entry '.$this->entry->id.' is NOT entered for '.auditionSetting('advanceTo').'
';
diff --git a/app/Http/Controllers/Admin/EntryController.php b/app/Http/Controllers/Admin/EntryController.php
index 79ac829..b25e840 100644
--- a/app/Http/Controllers/Admin/EntryController.php
+++ b/app/Http/Controllers/Admin/EntryController.php
@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Admin;
use App\Actions\Entries\CreateEntry;
use App\Actions\Entries\UpdateEntry;
+use App\Exceptions\AuditionAdminException;
use App\Exceptions\ManageEntryException;
use App\Http\Controllers\Controller;
use App\Models\Audition;
@@ -192,7 +193,7 @@ class EntryController extends Controller
}
try {
$updater($entry, $validData);
- } catch (ManageEntryException $e) {
+ } catch (AuditionAdminException $e) {
return redirect()->route('admin.entries.index')->with('error', $e->getMessage());
}
if ($validData['late_fee_waived']) {
diff --git a/app/Observers/EntryObserver.php b/app/Observers/EntryObserver.php
index 72268bc..e89e4ed 100644
--- a/app/Observers/EntryObserver.php
+++ b/app/Observers/EntryObserver.php
@@ -34,8 +34,7 @@ class EntryObserver
// Update doubler table when an entry is updated
Doubler::syncForEvent($entry->audition->event_id);
if ($entry->wasChanged('audition_id')) {
- $originalData = $entry->getOriginal();
- Doubler::syncForEvent($originalData->audition->event_id);
+ Doubler::syncDoublers();
}
}
diff --git a/tests/Feature/app/Actions/Entries/UpdateEntryTest.php b/tests/Feature/app/Actions/Entries/UpdateEntryTest.php
new file mode 100644
index 0000000..6cc237f
--- /dev/null
+++ b/tests/Feature/app/Actions/Entries/UpdateEntryTest.php
@@ -0,0 +1,196 @@
+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');