diff --git a/app/Http/Controllers/Tabulation/BonusScoreController.php b/app/Http/Controllers/Tabulation/BonusScoreController.php
index bc8ed1a..cb2e8a8 100644
--- a/app/Http/Controllers/Tabulation/BonusScoreController.php
+++ b/app/Http/Controllers/Tabulation/BonusScoreController.php
@@ -4,7 +4,7 @@ namespace App\Http\Controllers\Tabulation;
use App\Actions\Tabulation\EnterBonusScore;
use App\Actions\Tabulation\GetBonusScoreRelatedEntries;
-use App\Exceptions\ScoreEntryException;
+use App\Exceptions\AuditionAdminException;
use App\Http\Controllers\Controller;
use App\Models\BonusScore;
use App\Models\Entry;
@@ -73,7 +73,7 @@ class BonusScoreController extends Controller
// Set the new score
try {
$saveBonusScore($judge, $entry, $validData['score']);
- } catch (ScoreEntryException $ex) {
+ } catch (AuditionAdminException $ex) {
DB::rollBack();
return redirect()->route('bonus-scores.entryBonusScoreSheet',
diff --git a/app/Observers/BonusScoreObserver.php b/app/Observers/BonusScoreObserver.php
index 10cc620..cfb1d80 100644
--- a/app/Observers/BonusScoreObserver.php
+++ b/app/Observers/BonusScoreObserver.php
@@ -14,6 +14,12 @@ class BonusScoreObserver
{
$calculator = app(TotalEntryScores::class);
$calculator($bonusScore->entry, true);
+ $message = 'Bonus Score Entered.';
+ $message .= '
Judge: '.$bonusScore->judge->full_name().' <'.$bonusScore->judge->email.'>';
+ $message .= '
Score: '.$bonusScore->score;
+ $message .= '
Scored Audition: '.$bonusScore->originallyScoredEntry->audition->name;
+ $affected = ['auditions' => [$bonusScore->entry->audition_id]];
+ auditionLog($message, $affected);
}
/**
diff --git a/tests/Feature/app/Actions/Tabulation/TotalEntryScoresTest.php b/tests/Feature/app/Actions/Tabulation/TotalEntryScoresTest.php
index 5ff9c9f..1a1225e 100644
--- a/tests/Feature/app/Actions/Tabulation/TotalEntryScoresTest.php
+++ b/tests/Feature/app/Actions/Tabulation/TotalEntryScoresTest.php
@@ -190,7 +190,7 @@ test('it correctly brings in bonus scores', function () {
}
$bonusScore = BonusScore::create([
'entry_id' => $this->entry->id,
- 'user_id' => $this->judge1,
+ 'user_id' => $this->judge1->id,
'originally_scored_entry' => $this->entry->id,
'score' => 6,
]);
diff --git a/tests/Feature/app/Http/Controllers/Tabulation/BonusScoreControllerTest.php b/tests/Feature/app/Http/Controllers/Tabulation/BonusScoreControllerTest.php
new file mode 100644
index 0000000..abf481d
--- /dev/null
+++ b/tests/Feature/app/Http/Controllers/Tabulation/BonusScoreControllerTest.php
@@ -0,0 +1,204 @@
+get(route('bonus-scores.chooseEntry'))->assertRedirect(route('home'));
+ actAsNormal();
+ $this->get(route('bonus-scores.chooseEntry'))->assertRedirect(route('dashboard'));
+ });
+ it('provides a form to enter an entry id to select an entry to score', function () {
+ actAsTab();
+ $this->get(route('bonus-scores.chooseEntry'))->assertOk();
+ actAsAdmin();
+ $this->get(route('bonus-scores.chooseEntry'))->assertOk()->assertViewIs('tabulation.choose_entry');
+ });
+});
+
+describe('BonusScoreController::entryBonusScoreSheet', function () {
+ beforeEach(function () {
+ $this->event = Event::factory()->create();
+ $this->ASaudition = Audition::factory()->create([
+ 'event_id' => $this->event->id, 'name' => 'Alto Sax',
+ ]);
+ $this->TSaudition = Audition::factory()->create([
+ 'event_id' => $this->event->id, 'name' => 'Tenor Sax',
+ ]);
+ $this->BSaudition = Audition::factory()->create([
+ 'event_id' => $this->event->id, 'name' => 'Bari Sax',
+ ]);
+ $this->student = Student::factory()->create();
+ $this->ASentry = Entry::create([
+ 'audition_id' => $this->ASaudition->id, 'student_id' => $this->student->id,
+ ]);
+ $this->TSentry = Entry::create([
+ 'audition_id' => $this->TSaudition->id, 'student_id' => $this->student->id,
+ ]);
+ $this->BSentry = Entry::create([
+ 'audition_id' => $this->BSaudition->id, 'student_id' => $this->student->id,
+ ]);
+ $this->bonusScoreDefinition = BonusScoreDefinition::create([
+ 'name' => 'Sax Improv',
+ 'max_score' => 10,
+ 'weight' => 1,
+ 'for_seating' => 1,
+ 'for_attendance' => 0,
+ ]);
+ $this->bonusScoreDefinition->auditions()->attach($this->ASaudition);
+ $this->bonusScoreDefinition->auditions()->attach($this->TSaudition);
+ $this->bonusScoreDefinition->auditions()->attach($this->BSaudition);
+ $this->judge1 = User::factory()->create();
+ $this->judge2 = User::factory()->create();
+ $this->bonusScoreDefinition->judges()->attach($this->judge1);
+ $this->bonusScoreDefinition->judges()->attach($this->judge2);
+ });
+
+ it('does not allow access to guests or normal users', function () {
+ $this->get(route('bonus-scores.entryBonusScoreSheet'))->assertRedirect(route('home'));
+ actAsNormal();
+ $this->get(route('bonus-scores.entryBonusScoreSheet'))->assertRedirect(route('dashboard'));
+ });
+
+ it('shows a form to enter bonus scores for a judge by an administrator', function () {
+ actAsAdmin();
+ $response = $this->get(route('bonus-scores.entryBonusScoreSheet', ['entry_id' => $this->TSentry->id]));
+ $response->assertOk()->assertViewIs('tabulation.bonus-score-sheet');
+ });
+ it('identifies the student', function () {
+ actAsAdmin();
+ $response = $this->get(route('bonus-scores.entryBonusScoreSheet', ['entry_id' => $this->TSentry->id]));
+ $response->assertSee($this->student->full_name())
+ ->assertSee($this->student->school->name);
+ });
+ it('makes judges available', function () {
+ actAsAdmin();
+ $response = $this->get(route('bonus-scores.entryBonusScoreSheet', ['entry_id' => $this->TSentry->id]));
+ $response->assertSee($this->judge1->full_name())
+ ->assertSee($this->judge2->full_name());
+ });
+});
+
+describe('BonusScoreController::saveEntryBonusScoreSheet', function () {
+ beforeEach(function () {
+ $this->event = Event::factory()->create();
+ $sg = ScoringGuide::factory()->create();
+ $this->ASaudition = Audition::factory()->create([
+ 'event_id' => $this->event->id, 'name' => 'Alto Sax', 'scoring_guide_id' => $sg->id,
+ ]);
+ $this->TSaudition = Audition::factory()->create([
+ 'event_id' => $this->event->id, 'name' => 'Tenor Sax', 'scoring_guide_id' => $sg->id,
+ ]);
+ $this->BSaudition = Audition::factory()->create([
+ 'event_id' => $this->event->id, 'name' => 'Bari Sax', 'scoring_guide_id' => $sg->id,
+ ]);
+ $this->student = Student::factory()->create();
+ $this->ASentry = Entry::create([
+ 'audition_id' => $this->ASaudition->id, 'student_id' => $this->student->id,
+ ]);
+ $this->TSentry = Entry::create([
+ 'audition_id' => $this->TSaudition->id, 'student_id' => $this->student->id,
+ ]);
+ $this->BSentry = Entry::create([
+ 'audition_id' => $this->BSaudition->id, 'student_id' => $this->student->id,
+ ]);
+ $this->bonusScoreDefinition = BonusScoreDefinition::create([
+ 'name' => 'Sax Improv',
+ 'max_score' => 10,
+ 'weight' => 1,
+ 'for_seating' => 1,
+ 'for_attendance' => 0,
+ ]);
+ $this->bonusScoreDefinition->auditions()->attach($this->ASaudition);
+ $this->bonusScoreDefinition->auditions()->attach($this->TSaudition);
+ $this->bonusScoreDefinition->auditions()->attach($this->BSaudition);
+ $this->judge1 = User::factory()->create();
+ $this->judge2 = User::factory()->create();
+ $this->bonusScoreDefinition->judges()->attach($this->judge1);
+ $this->bonusScoreDefinition->judges()->attach($this->judge2);
+
+ });
+ it('does not allow access to guests or normal users', function () {
+ $this->post(route('bonus-scores.saveEntryBonusScoreSheet', $this->TSentry))->assertRedirect(route('home'));
+ actAsNormal();
+ $this->post(route('bonus-scores.saveEntryBonusScoreSheet', $this->TSentry))->assertRedirect(route('dashboard'));
+ });
+ it('will not post a bonus score to a published audition', function () {
+ actAsAdmin();
+ $this->TSaudition->addFlag('seats_published');
+ $response = $this->post(route('bonus-scores.saveEntryBonusScoreSheet', $this->TSentry));
+ $response->assertRedirect(route('bonus-scores.entryBonusScoreSheet', ['entry_id' => $this->TSentry->id]))
+ ->assertSessionHas('error');
+ });
+ it('applies the bonus score to all related entries, even if a bonus score exists', function () {
+ $ASbonusScoreRecorded = BonusScore::create([
+ 'entry_id' => $this->ASentry->id,
+ 'user_id' => $this->judge1->id,
+ 'originally_scored_entry' => $this->ASentry->id,
+ 'score' => 2,
+ ]);
+ $TSbonusScoreRecorded = BonusScore::create([
+ 'entry_id' => $this->TSentry->id,
+ 'user_id' => $this->judge1->id,
+ 'originally_scored_entry' => $this->ASentry->id,
+ 'score' => 2,
+ ]);
+ $BSbonusScoreRecorded = BonusScore::create([
+ 'entry_id' => $this->BSentry->id,
+ 'user_id' => $this->judge1->id,
+ 'originally_scored_entry' => $this->ASentry->id,
+ 'score' => 2,
+ ]);
+ actAsAdmin();
+ $response = $this->post(route('bonus-scores.saveEntryBonusScoreSheet', $this->TSentry), [
+ 'judge_id' => $this->judge1->id,
+ 'entry_id' => $this->TSentry->id,
+ 'score' => 3,
+ ]);
+ foreach (Entry::all() as $entry) {
+ $bs = $entry->bonusScores()->first();
+ expect($bs->score)->toEqual(3);
+ expect($bs->originallyScoredEntry->id)->toEqual($this->TSentry->id);
+ }
+ });
+
+ it('deletes all related entries when a null score is submitted', function () {
+ $ASbonusScoreRecorded = BonusScore::create([
+ 'entry_id' => $this->ASentry->id,
+ 'user_id' => $this->judge1->id,
+ 'originally_scored_entry' => $this->ASentry->id,
+ 'score' => 2,
+ ]);
+ $TSbonusScoreRecorded = BonusScore::create([
+ 'entry_id' => $this->TSentry->id,
+ 'user_id' => $this->judge1->id,
+ 'originally_scored_entry' => $this->ASentry->id,
+ 'score' => 2,
+ ]);
+ $BSbonusScoreRecorded = BonusScore::create([
+ 'entry_id' => $this->BSentry->id,
+ 'user_id' => $this->judge1->id,
+ 'originally_scored_entry' => $this->ASentry->id,
+ 'score' => 2,
+ ]);
+ $adminUser = User::factory()->admin()->create();
+ $this->actingAs($adminUser);
+ $response = $this->post(route('bonus-scores.saveEntryBonusScoreSheet', $this->TSentry), [
+ 'judge_id' => $this->judge1->id,
+ 'entry_id' => $this->TSentry->id,
+ 'score' => null,
+ ]);
+ expect(BonusScore::all())->toHaveCount(0);
+ });
+
+});