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/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/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..78c7d6d 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.');
}
@@ -157,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')) {
@@ -167,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/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/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/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 @@
+
- {{ auditionSetting('auditionAbbreviation') }} Total + {{ auditionSetting('auditionAbbreviation') }} Total {{ $score->totalScore('seating')[0] }}
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', + ]); + +}); 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']); +});