From 51436bda404551b49e27c1785cd515efb63e5023 Mon Sep 17 00:00:00 2001 From: Matt Young Date: Wed, 17 Jul 2024 18:38:03 -0500 Subject: [PATCH 1/2] Admin can forgive late fee on entry creation #38 Add ability for admin to forgive late fee on an entry --- app/Actions/Entries/CreateEntry.php | 4 +-- app/Enums/EntryFlags.php | 2 +- .../Controllers/Admin/EntryController.php | 6 +++- app/Models/Entry.php | 1 + .../views/admin/entries/create.blade.php | 12 ++++++-- .../Feature/Pages/Admin/EntiesCreateTest.php | 29 +++++++++++++++++++ 6 files changed, 47 insertions(+), 7 deletions(-) diff --git a/app/Actions/Entries/CreateEntry.php b/app/Actions/Entries/CreateEntry.php index daa6825..abc95c0 100644 --- a/app/Actions/Entries/CreateEntry.php +++ b/app/Actions/Entries/CreateEntry.php @@ -16,9 +16,9 @@ class CreateEntry /** * @throws ManageEntryException */ - public function __invoke(Student|int $student, Audition|int $audition, string|array|null $entry_for = null): void + public function __invoke(Student|int $student, Audition|int $audition, string|array|null $entry_for = null) { - $this->createEntry($student, $audition, $entry_for); + return $this->createEntry($student, $audition, $entry_for); } /** diff --git a/app/Enums/EntryFlags.php b/app/Enums/EntryFlags.php index 7cb14d4..bb87b0d 100644 --- a/app/Enums/EntryFlags.php +++ b/app/Enums/EntryFlags.php @@ -8,5 +8,5 @@ enum EntryFlags: string case DECLINED = 'declined'; case NO_SHOW = 'no_show'; case FAILED_PRELIM = 'failed_prelim'; + case LATE_FEE_WAIVED = 'late_fee_waived'; } - diff --git a/app/Http/Controllers/Admin/EntryController.php b/app/Http/Controllers/Admin/EntryController.php index 4132e73..d6025a9 100644 --- a/app/Http/Controllers/Admin/EntryController.php +++ b/app/Http/Controllers/Admin/EntryController.php @@ -102,6 +102,7 @@ class EntryController extends Controller $validData['for_seating'] = $request->get('for_seating') ? 1 : 0; $validData['for_advancement'] = $request->get('for_advancement') ? 1 : 0; + $validData['late_fee_waived'] = $request->get('late_fee_waived') ? 1 : 0; $enter_for = []; if ($validData['for_seating']) { $enter_for[] = 'seating'; @@ -111,10 +112,13 @@ class EntryController extends Controller } try { - $creator($validData['student_id'], $validData['audition_id'], $enter_for); + $entry = $creator($validData['student_id'], $validData['audition_id'], $enter_for); } catch (ManageEntryException $ex) { return redirect()->route('admin.entries.index')->with('error', $ex->getMessage()); } + if ($validData['late_fee_waived']) { + $entry->addFlag('late_fee_waived'); + } return redirect(route('admin.entries.index'))->with('success', 'The entry has been added.'); } diff --git a/app/Models/Entry.php b/app/Models/Entry.php index 1b6eaee..1670c02 100644 --- a/app/Models/Entry.php +++ b/app/Models/Entry.php @@ -91,6 +91,7 @@ class Entry extends Model 'declined' => EntryFlags::DECLINED, 'no_show' => EntryFlags::NO_SHOW, 'failed_prelim' => EntryFlags::FAILED_PRELIM, + 'late_fee_waived' => EntryFlags::LATE_FEE_WAIVED, }; $this->flags()->create(['flag_name' => $enum]); $this->load('flags'); diff --git a/resources/views/admin/entries/create.blade.php b/resources/views/admin/entries/create.blade.php index d1c4376..1614157 100644 --- a/resources/views/admin/entries/create.blade.php +++ b/resources/views/admin/entries/create.blade.php @@ -1,3 +1,4 @@ + Create Entry @@ -8,7 +9,8 @@ Student @@ -24,16 +26,20 @@
+ checked/>
+ checked/>
@else @endif +
+ +
Create Entry diff --git a/tests/Feature/Pages/Admin/EntiesCreateTest.php b/tests/Feature/Pages/Admin/EntiesCreateTest.php index 3142c0f..5e038d8 100644 --- a/tests/Feature/Pages/Admin/EntiesCreateTest.php +++ b/tests/Feature/Pages/Admin/EntiesCreateTest.php @@ -1,6 +1,7 @@ 0, ]); }); +it('can mark a late fee waived for an entry', function () { + $audition = Audition::factory()->closed()->create(['maximum_grade' => 12, 'minimum_grade' => 7]); + $student = Student::factory()->create(['grade' => 9]); + actAsAdmin(); + $response = $this->post(route('admin.entries.store'), [ + 'student_id' => $student->id, + 'audition_id' => $audition->id, + 'for_seating' => 'on', + 'late_fee_waived' => 'on', + ]); + $response->assertRedirect(route('admin.entries.index')) + ->assertSessionDoesntHaveErrors() + ->assertSessionMissing('error') + ->assertSessionHas('success', 'The entry has been added.'); + assertDatabaseHas('entries', [ + 'student_id' => $student->id, + 'audition_id' => $audition->id, + 'for_seating' => 1, + 'for_advancement' => 0, + ]); + $entry = Entry::where('student_id', $student->id)->where('audition_id', $audition->id)->first(); + + assertDatabaseHas('entry_flags', [ + 'entry_id' => 1, + 'flag_name' => 'late_fee_waived', + ]); + +}); From d522148cb9933e38a5bdef653f4cfea6cdedd6b5 Mon Sep 17 00:00:00 2001 From: Matt Young Date: Wed, 17 Jul 2024 19:31:02 -0500 Subject: [PATCH 2/2] Invoices honor late_fee_waived flag #38 Add ability for admin to forgive late fee on an entry --- app/Actions/Entries/UpdateEntry.php | 4 +++- .../Controllers/Admin/EntryController.php | 12 ++++++------ .../Invoice/InvoiceOneFeePerEntry.php | 3 ++- .../Invoice/InvoiceOneFeePerStudent.php | 3 ++- resources/views/admin/entries/edit.blade.php | 15 ++++++++++++--- tests/Feature/Pages/Admin/EntriesEditTest.php | 19 ++++++++++++++++++- 6 files changed, 43 insertions(+), 13 deletions(-) diff --git a/app/Actions/Entries/UpdateEntry.php b/app/Actions/Entries/UpdateEntry.php index eeb8d90..9fe0bba 100644 --- a/app/Actions/Entries/UpdateEntry.php +++ b/app/Actions/Entries/UpdateEntry.php @@ -86,7 +86,9 @@ class UpdateEntry if ($this->entry->scoreSheets()->count() > 0) { throw new ManageEntryException('Cannot change the audition for an entry with scores'); } - if (Entry::where('student_id', $this->entry->student_id)->where('audition_id', $audition->id)->exists()) { + 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'); } // OK we're allowed to change the audition diff --git a/app/Http/Controllers/Admin/EntryController.php b/app/Http/Controllers/Admin/EntryController.php index d6025a9..78c7d6d 100644 --- a/app/Http/Controllers/Admin/EntryController.php +++ b/app/Http/Controllers/Admin/EntryController.php @@ -161,6 +161,7 @@ class EntryController extends Controller $validData['for_seating'] = $request->get('for_seating') ? 1 : 0; $validData['for_advancement'] = $request->get('for_advancement') ? 1 : 0; + $validData['late_fee_waived'] = $request->get('late_fee_waived') ? 1 : 0; // If the audition is not set to advance to the next round, then the entry must be for seating if (! auditionSetting('advanceTo')) { @@ -171,12 +172,11 @@ class EntryController extends Controller } catch (ManageEntryException $e) { return redirect()->route('admin.entries.index')->with('error', $e->getMessage()); } - - // $entry->update([ - // 'audition_id' => $validData['audition_id'], - // 'for_seating' => $validData['for_seating'], - // 'for_advancement' => $validData['for_advancement'], - // ]); + if ($validData['late_fee_waived']) { + $entry->addFlag('late_fee_waived'); + } else { + $entry->removeFlag('late_fee_waived'); + } return to_route('admin.entries.index')->with('success', 'Entry updated successfully'); } diff --git a/app/Services/Invoice/InvoiceOneFeePerEntry.php b/app/Services/Invoice/InvoiceOneFeePerEntry.php index 1ca5b34..6577546 100644 --- a/app/Services/Invoice/InvoiceOneFeePerEntry.php +++ b/app/Services/Invoice/InvoiceOneFeePerEntry.php @@ -39,7 +39,8 @@ class InvoiceOneFeePerEntry implements InvoiceDataService foreach ($school->students as $student) { foreach ($entries[$student->id] ?? [] as $entry) { $entryFee = $entry->audition->entry_fee / 100; - $lateFee = $this->entryService->isEntryLate($entry) ? auditionSetting('late_fee') / 100 : 0; + $lateFee = ($this->entryService->isEntryLate($entry) && ! $entry->hasFlag('late_fee_waived')) + ? auditionSetting('late_fee') / 100 : 0; $invoiceData['lines'][] = [ 'student_name' => $student->full_name(true), diff --git a/app/Services/Invoice/InvoiceOneFeePerStudent.php b/app/Services/Invoice/InvoiceOneFeePerStudent.php index c5090ac..69b5fe5 100644 --- a/app/Services/Invoice/InvoiceOneFeePerStudent.php +++ b/app/Services/Invoice/InvoiceOneFeePerStudent.php @@ -41,7 +41,8 @@ class InvoiceOneFeePerStudent implements InvoiceDataService foreach ($entries[$student->id] ?? [] as $entry) { if ($firstEntryForStudent) { $entryFee = $entry->audition->entry_fee / 100; - $lateFee = $this->entryService->entryIsLate($entry) ? auditionSetting('late_fee') / 100 : 0; + $lateFee = ($this->entryService->isEntryLate($entry) && ! $entry->hasFlag('late_fee_waived')) + ? auditionSetting('late_fee') / 100 : 0; } else { $entryFee = 0; $lateFee = 0; diff --git a/resources/views/admin/entries/edit.blade.php b/resources/views/admin/entries/edit.blade.php index f34193a..8c96f7e 100644 --- a/resources/views/admin/entries/edit.blade.php +++ b/resources/views/admin/entries/edit.blade.php @@ -35,7 +35,8 @@ Audition @foreach ($auditions as $audition) @continue($entry->student->grade < $audition->minimum_grade || $entry->student->grade > $audition->maximum_grade) - @endforeach @@ -58,6 +59,12 @@ @else @endif + +
+ +
+ Edit Entry @@ -70,7 +77,8 @@ Scores - Edit Scores + Edit Scores + @@ -96,7 +104,8 @@

@endforeach

- {{ auditionSetting('auditionAbbreviation') }} Total + {{ auditionSetting('auditionAbbreviation') }} Total {{ $score->totalScore('seating')[0] }}

diff --git a/tests/Feature/Pages/Admin/EntriesEditTest.php b/tests/Feature/Pages/Admin/EntriesEditTest.php index 121d0c2..63ebfe2 100644 --- a/tests/Feature/Pages/Admin/EntriesEditTest.php +++ b/tests/Feature/Pages/Admin/EntriesEditTest.php @@ -236,7 +236,7 @@ it('has a link to delete scores', function () { // Act & Assert $scoreSheet = ScoreSheet::where('entry_id', $entry->id)->first(); actAsAdmin(); - $response = get(route('admin.entries.edit', $entry)) + get(route('admin.entries.edit', $entry)) ->assertSee(route('scores.destroy', ['score' => $scoreSheet])); }); @@ -286,3 +286,20 @@ it('does not allow an admin to delete an entry if that entries advancement is pu ->assertRedirect(route('admin.entries.index')); expect(Entry::find($this->entry->id))->not->toBeNull(); }); +it('allows an admin to waive a late fee on an entry', function () { + // Arrange + $newAudition = Audition::factory()->create(['minimum_grade' => 1, 'maximum_grade' => 20]); + actAsAdmin(); + // Act & Assert + /** @noinspection PhpUnhandledExceptionInspection */ + patch(route('admin.entries.update', $this->entry), ['audition_id' => $newAudition->id, 'late_fee_waived' => 1]) + ->assertSessionHasNoErrors() + ->assertSessionMissing('error') + ->assertSessionHas('success', 'Entry updated successfully') + ->assertRedirect(route('admin.entries.index')); + $this->entry->refresh(); + expect($this->entry->audition_id)->toBe($newAudition->id) + ->and($this->entry->for_seating)->toBe(0) + ->and($this->entry->for_advancement)->toBe(0); + $this->assertDatabaseHas('entry_flags', ['entry_id' => $this->entry->id, 'flag_name' => 'late_fee_waived']); +});