diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php index 5b2c14b..dc551f4 100644 --- a/app/Http/Controllers/DashboardController.php +++ b/app/Http/Controllers/DashboardController.php @@ -2,13 +2,20 @@ namespace App\Http\Controllers; -use Illuminate\Http\Request; +use App\Services\Invoice\InvoiceDataService; use Illuminate\Support\Facades\Auth; -use function dd; + use function redirect; class DashboardController extends Controller { + protected InvoiceDataService $invoiceService; + + public function __construct(InvoiceDataService $invoiceService) + { + $this->invoiceService = $invoiceService; + } + public function profile() { return view('dashboard.profile'); @@ -22,10 +29,23 @@ class DashboardController extends Controller public function my_school() { if (Auth::user()->school) { - return redirect('/schools/' . Auth::user()->school->id); + return redirect('/schools/'.Auth::user()->school->id); } $possibilities = Auth::user()->possibleSchools(); - if (count($possibilities) < 1) return view('schools.create'); + if (count($possibilities) < 1) { + return view('schools.create'); + } + return view('dashboard.select_school', ['possibilities' => $possibilities]); } + + public function my_invoice() + { + if (! Auth::user()->school_id) { + return redirect()->route('dashboard')->with('error', 'You do not have a school to get an invoice for'); + } + $invoiceData = $this->invoiceService->allData(Auth::user()->school_id); + $school = Auth::user()->school; + return view('dashboard.invoice', compact('school', 'invoiceData')); + } } diff --git a/app/Http/Controllers/TestController.php b/app/Http/Controllers/TestController.php index c24fbfe..99fc429 100644 --- a/app/Http/Controllers/TestController.php +++ b/app/Http/Controllers/TestController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers; use App\Services\AuditionService; +use App\Services\Invoice\InvoiceDataService; use App\Services\TabulationService; use Illuminate\Http\Request; use Illuminate\Support\Facades\Session; @@ -11,16 +12,22 @@ class TestController extends Controller { protected $scoringGuideCacheService; protected $tabulationService; + protected $invoiceService; - public function __construct(AuditionService $scoringGuideCacheService, TabulationService $tabulationService) - { + public function __construct( + AuditionService $scoringGuideCacheService, + TabulationService $tabulationService, + InvoiceDataService $invoiceService + ) { $this->scoringGuideCacheService = $scoringGuideCacheService; $this->tabulationService = $tabulationService; + $this->invoiceService = $invoiceService; } public function flashTest(Request $request) { - $auditions = $this->tabulationService->getAuditionsWithStatus(); - return view('test', compact('auditions')); + $lines = $this->invoiceService->getLines(12); + $totalFees = $this->invoiceService->getGrandTotal(12); + return view('test', compact('lines','totalFees')); } } diff --git a/app/Models/School.php b/app/Models/School.php index af18e16..93c886e 100644 --- a/app/Models/School.php +++ b/app/Models/School.php @@ -17,25 +17,28 @@ class School extends Model { return $this->hasMany(User::class); } + public function users(): HasMany { return $this->hasMany(User::class); } + public function emailDomains(): HasMany { return $this->hasMany(SchoolEmailDomain::class); } - public function initialLetterImageURL($bg_color = '4f46e5', $text_color='fff'): string + public function initialLetterImageURL($bg_color = '4f46e5', $text_color = 'fff'): string { $img = "https://ui-avatars.com/api/?background=$bg_color&color=$text_color&name="; - $img .= substr($this->name,0,1); + $img .= substr($this->name, 0, 1); + return $img; } public function students(): HasMany { - return $this->hasMany(Student::class); + return $this->hasMany(Student::class)->orderBy('last_name')->orderBy('first_name'); } public function entries(): HasManyThrough @@ -48,5 +51,4 @@ class School extends Model 'id', 'id'); } - } diff --git a/app/Providers/InvoiceDataServiceProvider.php b/app/Providers/InvoiceDataServiceProvider.php new file mode 100644 index 0000000..6556ed4 --- /dev/null +++ b/app/Providers/InvoiceDataServiceProvider.php @@ -0,0 +1,38 @@ +app->singleton(InvoiceDataService::class, function ($app) { + // Default binding, can be overridden in booth method + return new InvoiceOneFeePerEntry($app->make(EntryService::class)); + }); + } + + /** + * Bootstrap services. + */ + public function boot(): void + { + $this->app->singleton(InvoiceDataService::class, function ($app) { + return match (auditionSetting('fee_structure')) { + 'oneFeePerEntry' => new InvoiceOneFeePerEntry($app->make(EntryService::class)), + 'oneFeePerStudent' => new InvoiceOneFeePerStudent($app->make(EntryService::class)), + default => throw new \Exception('Unknown Invoice Method'), + }; + }); + } +} diff --git a/app/Services/Invoice/InvoiceAllStudentsPay.php b/app/Services/Invoice/InvoiceAllStudentsPay.php deleted file mode 100644 index 14adc18..0000000 --- a/app/Services/Invoice/InvoiceAllStudentsPay.php +++ /dev/null @@ -1,47 +0,0 @@ -entryService = $entryService; + } + + public function allData($schoolId) + { + static $schoolInvoiceData = []; + + if (Arr::has($schoolInvoiceData, $schoolId)) { + return $schoolInvoiceData[$schoolId]; + } + $school = School::findOrFail($schoolId); + + $invoiceData['lines'] = []; + $invoiceData['linesTotal'] = 0; + $invoiceData['lateFeesTotal'] = 0; + /** @noinspection PhpArrayIndexImmediatelyRewrittenInspection */ + $invoiceData['grandTotal'] = 0; + + $entries = $school->entries()->with('audition')->orderBy('created_at', 'desc')->get()->groupBy('student_id'); + foreach ($school->students as $student) { + foreach ($entries[$student->id] as $entry) { + $entryFee = $entry->audition->entry_fee / 100; + $lateFee = $this->entryService->entryIsLate($entry) ? auditionSetting('late_fee') / 100 : 0; + + $invoiceData['lines'][] = [ + 'student_name' => $student->full_name(true), + 'audition' => $entry->audition->name, + 'entry_timestamp' => $entry->created_at, + 'entry_fee' => $entryFee, + 'late_fee' => $lateFee, + ]; + $invoiceData['linesTotal'] += $entryFee; + $invoiceData['lateFeesTotal'] += $lateFee; + } + } + // School Fee Total + if (! auditionSetting('school_fee')) { + $invoiceData['schoolFeeTotal'] = 0; + } else { + $invoiceData['schoolFeeTotal'] = auditionSetting('school_fee') / 100; + } + + $invoiceData['grandTotal'] = $invoiceData['linesTotal'] + $invoiceData['lateFeesTotal'] + $invoiceData['schoolFeeTotal']; + $schoolInvoiceData[$school->id] = $invoiceData; + + return $invoiceData; + } + + public function getLines($schoolId) + { + return $this->allData($schoolId)['lines']; + } + + public function getLinesTotal($schoolId) + { + return $this->allData($schoolId)['linesTotal']; + } + + public function getLateFeesTotal($schoolId) + { + return $this->allData($schoolId)['lateFeesTotal']; + } + + public function getSchoolFeeTotal($schoolId) + { + return $this->allData($schoolId)['schoolFeeTotal']; + + } + + public function getGrandTotal($schoolId) + { + return $this->allData($schoolId)['grandTotal']; + } +} diff --git a/app/Services/Invoice/InvoiceOneFeePerStudent.php b/app/Services/Invoice/InvoiceOneFeePerStudent.php new file mode 100644 index 0000000..3bf9f99 --- /dev/null +++ b/app/Services/Invoice/InvoiceOneFeePerStudent.php @@ -0,0 +1,100 @@ +entryService = $entryService; + } + + public function allData($schoolId) + { + static $schoolInvoiceData = []; + + if (Arr::has($schoolInvoiceData, $schoolId)) { + return $schoolInvoiceData[$schoolId]; + } + $school = School::findOrFail($schoolId); + + $invoiceData['lines'] = []; + $invoiceData['linesTotal'] = 0; + $invoiceData['lateFeesTotal'] = 0; + /** @noinspection PhpArrayIndexImmediatelyRewrittenInspection */ + $invoiceData['grandTotal'] = 0; + + $entries = $school->entries()->with('audition')->orderBy('created_at', 'desc')->get()->groupBy('student_id'); + foreach ($school->students as $student) { + $firstEntryForStudent = true; + foreach ($entries[$student->id] as $entry) { + if ($firstEntryForStudent) { + $entryFee = $entry->audition->entry_fee / 100; + $lateFee = $this->entryService->entryIsLate($entry) ? auditionSetting('late_fee') / 100 : 0; + } else { + $entryFee = 0; + $lateFee = 0; + } + + $invoiceData['lines'][] = [ + 'student_name' => $student->full_name(true), + 'audition' => $entry->audition->name, + 'entry_timestamp' => $entry->created_at, + 'entry_fee' => $entryFee, + 'late_fee' => $lateFee, + ]; + $invoiceData['linesTotal'] += $entryFee; + $invoiceData['lateFeesTotal'] += $lateFee; + $firstEntryForStudent = false; + } + } + // School Fee Total + if (! auditionSetting('school_fee')) { + $invoiceData['schoolFeeTotal'] = 0; + } else { + $invoiceData['schoolFeeTotal'] = auditionSetting('school_fee') / 100; + } + + $invoiceData['grandTotal'] = $invoiceData['linesTotal'] + $invoiceData['lateFeesTotal'] + $invoiceData['schoolFeeTotal']; + $schoolInvoiceData[$school->id] = $invoiceData; + + return $invoiceData; + } + + public function getLines($schoolId) + { + return $this->allData($schoolId)['lines']; + } + + public function getLinesTotal($schoolId) + { + return $this->allData($schoolId)['linesTotal']; + } + + public function getLateFeesTotal($schoolId) + { + return $this->allData($schoolId)['lateFeesTotal']; + } + + public function getSchoolFeeTotal($schoolId) + { + return $this->allData($schoolId)['schoolFeeTotal']; + + } + + public function getGrandTotal($schoolId) + { + return $this->allData($schoolId)['grandTotal']; + } +} diff --git a/bootstrap/providers.php b/bootstrap/providers.php index 0ad9c57..9edefb0 100644 --- a/bootstrap/providers.php +++ b/bootstrap/providers.php @@ -3,4 +3,5 @@ return [ App\Providers\AppServiceProvider::class, App\Providers\FortifyServiceProvider::class, + App\Providers\InvoiceDataServiceProvider::class, ]; diff --git a/resources/views/dashboard/invoice.blade.php b/resources/views/dashboard/invoice.blade.php new file mode 100644 index 0000000..a8afc96 --- /dev/null +++ b/resources/views/dashboard/invoice.blade.php @@ -0,0 +1,44 @@ +@props(['school', 'invoiceData']) + + + Invoice - {{ $school->name }} + @php( dump($invoiceData )) + + Invoice + + + Student Name + Audition + Entry Timestamp + Entry Fee + Late Fee + + + + @foreach($invoiceData['lines'] as $line) + + {{ $line['student_name'] }} + {{ $line['audition'] }} + {{ $line['entry_timestamp']->setTimezone('America/Chicago')->format('m/d/Y g:i:s A') }} + ${{ number_format($line['entry_fee'],2) }} + ${{ number_format($line['late_fee'],2) }} + + @endforeach + + + + Totals + ${{ number_format($invoiceData['linesTotal'],2) }} + ${{ number_format($invoiceData['lateFeesTotal'],2) }} + + + School Fee + ${{ number_format($invoiceData['schoolFeeTotal'],2) }} + + + Grand Total + ${{ number_format($invoiceData['grandTotal'],2) }} + + + + diff --git a/resources/views/test.blade.php b/resources/views/test.blade.php index 861bdbf..ddd5fa6 100644 --- a/resources/views/test.blade.php +++ b/resources/views/test.blade.php @@ -16,9 +16,9 @@ Test Page @php - $schools = School::all(); + dump($totalFees); + dump($lines); - } @endphp diff --git a/routes/user.php b/routes/user.php index 3974d1a..8be2957 100644 --- a/routes/user.php +++ b/routes/user.php @@ -12,6 +12,7 @@ Route::middleware(['auth', 'verified'])->group(function () { Route::get('/dashboard', [DashboardController::class, 'dashboard'])->name('dashboard'); Route::get('/profile', [DashboardController::class, 'profile']); Route::get('/my_school', [DashboardController::class, 'my_school']); + Route::get('/my_invoice', [DashboardController::class, 'my_invoice'])->name('my_invoice'); }); // Entry Related Routes