From d522148cb9933e38a5bdef653f4cfea6cdedd6b5 Mon Sep 17 00:00:00 2001 From: Matt Young Date: Wed, 17 Jul 2024 19:31:02 -0500 Subject: [PATCH] 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']); +});