Merge pull request #8 from okorpheus/invoicing
Invoicing Feature Complete
This commit is contained in:
commit
247656f60b
|
|
@ -21,9 +21,15 @@ class AuditionSettings extends Controller
|
||||||
'organizerName' => ['required'],
|
'organizerName' => ['required'],
|
||||||
'organizerEmail' => ['required', 'email'],
|
'organizerEmail' => ['required', 'email'],
|
||||||
'registrationCode' => ['required'],
|
'registrationCode' => ['required'],
|
||||||
'late_fee' => ['nullable', 'numeric'],
|
'fee_structure' => ['required', 'in:oneFeePerEntry,oneFeePerStudent'], // Options should align with the boot method of InvoiceDataServiceProvider
|
||||||
'school_fee' => ['nullable', 'numeric'],
|
'late_fee' => ['nullable', 'numeric', 'min:0'],
|
||||||
|
'school_fee' => ['nullable', 'numeric', 'min:0'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// Store currency values as cents
|
||||||
|
$validData['late_fee'] = $validData['late_fee'] * 100;
|
||||||
|
$validData['school_fee'] = $validData['school_fee'] * 100;
|
||||||
|
|
||||||
// TODO implement olympic scoring
|
// TODO implement olympic scoring
|
||||||
foreach ($validData as $key => $value) {
|
foreach ($validData as $key => $value) {
|
||||||
Settings::set($key, $value);
|
Settings::set($key, $value);
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ namespace App\Http\Controllers\Admin;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\School;
|
use App\Models\School;
|
||||||
use App\Models\SchoolEmailDomain;
|
use App\Models\SchoolEmailDomain;
|
||||||
|
use App\Services\Invoice\InvoiceDataService;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
|
@ -14,14 +15,25 @@ use function request;
|
||||||
|
|
||||||
class SchoolController extends Controller
|
class SchoolController extends Controller
|
||||||
{
|
{
|
||||||
|
protected $invoiceService;
|
||||||
|
|
||||||
|
public function __construct(InvoiceDataService $invoiceController)
|
||||||
|
{
|
||||||
|
$this->invoiceService = $invoiceController;
|
||||||
|
}
|
||||||
|
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
if (! Auth::user()->is_admin) {
|
if (! Auth::user()->is_admin) {
|
||||||
abort(403);
|
abort(403);
|
||||||
}
|
}
|
||||||
$schools = School::with(['users', 'students', 'entries'])->orderBy('name')->get();
|
$schools = School::with(['users', 'students', 'entries'])->orderBy('name')->get();
|
||||||
|
$schoolTotalFees = [];
|
||||||
|
foreach ($schools as $school) {
|
||||||
|
$schoolTotalFees[$school->id] = $this->invoiceService->getGrandTotal($school->id);
|
||||||
|
}
|
||||||
|
|
||||||
return view('admin.schools.index', ['schools' => $schools]);
|
return view('admin.schools.index', compact('schools', 'schoolTotalFees'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function show(Request $request, School $school)
|
public function show(Request $request, School $school)
|
||||||
|
|
@ -122,4 +134,11 @@ class SchoolController extends Controller
|
||||||
// return a redirect to the previous URL
|
// return a redirect to the previous URL
|
||||||
return redirect()->back();
|
return redirect()->back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function viewInvoice(Request $request, School $school)
|
||||||
|
{
|
||||||
|
$invoiceData = $this->invoiceService->allData($school->id);
|
||||||
|
|
||||||
|
return view('dashboard.invoice', compact('school', 'invoiceData'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,20 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use Illuminate\Http\Request;
|
use App\Services\Invoice\InvoiceDataService;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use function dd;
|
|
||||||
use function redirect;
|
use function redirect;
|
||||||
|
|
||||||
class DashboardController extends Controller
|
class DashboardController extends Controller
|
||||||
{
|
{
|
||||||
|
protected InvoiceDataService $invoiceService;
|
||||||
|
|
||||||
|
public function __construct(InvoiceDataService $invoiceService)
|
||||||
|
{
|
||||||
|
$this->invoiceService = $invoiceService;
|
||||||
|
}
|
||||||
|
|
||||||
public function profile()
|
public function profile()
|
||||||
{
|
{
|
||||||
return view('dashboard.profile');
|
return view('dashboard.profile');
|
||||||
|
|
@ -25,7 +32,20 @@ class DashboardController extends Controller
|
||||||
return redirect('/schools/'.Auth::user()->school->id);
|
return redirect('/schools/'.Auth::user()->school->id);
|
||||||
}
|
}
|
||||||
$possibilities = Auth::user()->possibleSchools();
|
$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]);
|
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'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,20 +4,20 @@ namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Models\Entry;
|
use App\Models\Entry;
|
||||||
use App\Models\Seat;
|
use App\Models\Seat;
|
||||||
use App\Services\AuditionCacheService;
|
use App\Services\AuditionService;
|
||||||
use App\Services\SeatingService;
|
use App\Services\SeatingService;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
|
||||||
class ResultsPage extends Controller
|
class ResultsPage extends Controller
|
||||||
{
|
{
|
||||||
protected $auditionCacheService;
|
protected $auditionService;
|
||||||
|
|
||||||
protected $seatingService;
|
protected $seatingService;
|
||||||
|
|
||||||
public function __construct(AuditionCacheService $auditionCacheService, SeatingService $seatingService)
|
public function __construct(AuditionService $auditionService, SeatingService $seatingService)
|
||||||
{
|
{
|
||||||
$this->auditionCacheService = $auditionCacheService;
|
$this->auditionService = $auditionService;
|
||||||
$this->seatingService = $seatingService;
|
$this->seatingService = $seatingService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -26,7 +26,7 @@ class ResultsPage extends Controller
|
||||||
*/
|
*/
|
||||||
public function __invoke(Request $request)
|
public function __invoke(Request $request)
|
||||||
{
|
{
|
||||||
$publishedAuditions = $this->auditionCacheService->getPublishedAuditions();
|
$publishedAuditions = $this->auditionService->getPublishedAuditions();
|
||||||
$resultsSeatList = Cache::rememberForever('resultsSeatList', function () use ($publishedAuditions) {
|
$resultsSeatList = Cache::rememberForever('resultsSeatList', function () use ($publishedAuditions) {
|
||||||
$seatList = [];
|
$seatList = [];
|
||||||
// Load the $seatList in the form of $seatlist[audition_id] is an array of seats for that audition
|
// Load the $seatList in the form of $seatlist[audition_id] is an array of seats for that audition
|
||||||
|
|
@ -51,7 +51,7 @@ class ResultsPage extends Controller
|
||||||
return $seatList;
|
return $seatList;
|
||||||
});
|
});
|
||||||
|
|
||||||
$publishedAdvancementAuditions = $this->auditionCacheService->getPublishedAdvancementAuditions();
|
$publishedAdvancementAuditions = $this->auditionService->getPublishedAdvancementAuditions();
|
||||||
$resultsAdvancementList = Cache::rememberForever('resultsAdvancementList', function () use ($publishedAdvancementAuditions) {
|
$resultsAdvancementList = Cache::rememberForever('resultsAdvancementList', function () use ($publishedAdvancementAuditions) {
|
||||||
$qualifierList = [];
|
$qualifierList = [];
|
||||||
foreach ($publishedAdvancementAuditions as $audition) {
|
foreach ($publishedAdvancementAuditions as $audition) {
|
||||||
|
|
|
||||||
|
|
@ -6,14 +6,14 @@ use App\Http\Controllers\Controller;
|
||||||
use App\Models\Entry;
|
use App\Models\Entry;
|
||||||
use App\Models\EntryFlag;
|
use App\Models\EntryFlag;
|
||||||
use App\Services\DoublerService;
|
use App\Services\DoublerService;
|
||||||
use App\Services\EntryCacheService;
|
use App\Services\EntryService;
|
||||||
|
|
||||||
class DoublerDecisionController extends Controller
|
class DoublerDecisionController extends Controller
|
||||||
{
|
{
|
||||||
protected $doublerService;
|
protected $doublerService;
|
||||||
protected $entryService;
|
protected $entryService;
|
||||||
|
|
||||||
public function __construct(DoublerService $doublerService, EntryCacheService $entryService)
|
public function __construct(DoublerService $doublerService, EntryService $entryService)
|
||||||
{
|
{
|
||||||
$this->doublerService = $doublerService;
|
$this->doublerService = $doublerService;
|
||||||
$this->entryService = $entryService;
|
$this->entryService = $entryService;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ namespace App\Http\Controllers\Tabulation;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\Audition;
|
use App\Models\Audition;
|
||||||
use App\Models\Seat;
|
use App\Models\Seat;
|
||||||
use App\Services\AuditionCacheService;
|
use App\Services\AuditionService;
|
||||||
use App\Services\DoublerService;
|
use App\Services\DoublerService;
|
||||||
use App\Services\SeatingService;
|
use App\Services\SeatingService;
|
||||||
use App\Services\TabulationService;
|
use App\Services\TabulationService;
|
||||||
|
|
@ -22,17 +22,17 @@ class TabulationController extends Controller
|
||||||
|
|
||||||
protected $seatingService;
|
protected $seatingService;
|
||||||
|
|
||||||
protected $auditionCacheService;
|
protected $auditionService;
|
||||||
|
|
||||||
public function __construct(TabulationService $tabulationService,
|
public function __construct(TabulationService $tabulationService,
|
||||||
DoublerService $doublerService,
|
DoublerService $doublerService,
|
||||||
SeatingService $seatingService,
|
SeatingService $seatingService,
|
||||||
AuditionCacheService $auditionCacheService)
|
AuditionService $auditionService)
|
||||||
{
|
{
|
||||||
$this->tabulationService = $tabulationService;
|
$this->tabulationService = $tabulationService;
|
||||||
$this->doublerService = $doublerService;
|
$this->doublerService = $doublerService;
|
||||||
$this->seatingService = $seatingService;
|
$this->seatingService = $seatingService;
|
||||||
$this->auditionCacheService = $auditionCacheService;
|
$this->auditionService = $auditionService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function status()
|
public function status()
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Services\AuditionCacheService;
|
use App\Services\AuditionService;
|
||||||
|
use App\Services\Invoice\InvoiceDataService;
|
||||||
use App\Services\TabulationService;
|
use App\Services\TabulationService;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Session;
|
use Illuminate\Support\Facades\Session;
|
||||||
|
|
@ -11,16 +12,22 @@ class TestController extends Controller
|
||||||
{
|
{
|
||||||
protected $scoringGuideCacheService;
|
protected $scoringGuideCacheService;
|
||||||
protected $tabulationService;
|
protected $tabulationService;
|
||||||
|
protected $invoiceService;
|
||||||
|
|
||||||
public function __construct(AuditionCacheService $scoringGuideCacheService, TabulationService $tabulationService)
|
public function __construct(
|
||||||
{
|
AuditionService $scoringGuideCacheService,
|
||||||
|
TabulationService $tabulationService,
|
||||||
|
InvoiceDataService $invoiceService
|
||||||
|
) {
|
||||||
$this->scoringGuideCacheService = $scoringGuideCacheService;
|
$this->scoringGuideCacheService = $scoringGuideCacheService;
|
||||||
$this->tabulationService = $tabulationService;
|
$this->tabulationService = $tabulationService;
|
||||||
|
$this->invoiceService = $invoiceService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function flashTest(Request $request)
|
public function flashTest(Request $request)
|
||||||
{
|
{
|
||||||
$auditions = $this->tabulationService->getAuditionsWithStatus();
|
$lines = $this->invoiceService->getLines(12);
|
||||||
return view('test', compact('auditions'));
|
$totalFees = $this->invoiceService->getGrandTotal(12);
|
||||||
|
return view('test', compact('lines','totalFees'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,19 +3,18 @@
|
||||||
namespace App\Listeners;
|
namespace App\Listeners;
|
||||||
|
|
||||||
use App\Events\AuditionChange;
|
use App\Events\AuditionChange;
|
||||||
use App\Services\AuditionCacheService;
|
use App\Services\AuditionService;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
|
||||||
|
|
||||||
class RefreshAuditionCache
|
class RefreshAuditionCache
|
||||||
{
|
{
|
||||||
protected $auditionCacheService;
|
protected $auditionService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the event listener.
|
* Create the event listener.
|
||||||
*/
|
*/
|
||||||
public function __construct(AuditionCacheService $cacheService)
|
public function __construct(AuditionService $cacheService)
|
||||||
{
|
{
|
||||||
$this->auditionCacheService = $cacheService;
|
$this->auditionService = $cacheService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -24,9 +23,9 @@ class RefreshAuditionCache
|
||||||
public function handle(AuditionChange $event): void
|
public function handle(AuditionChange $event): void
|
||||||
{
|
{
|
||||||
if ($event->refreshCache) {
|
if ($event->refreshCache) {
|
||||||
$this->auditionCacheService->refreshCache();
|
$this->auditionService->refreshCache();
|
||||||
} else {
|
} else {
|
||||||
$this->auditionCacheService->clearCache();
|
$this->auditionService->clearCache();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,20 +4,20 @@ namespace App\Listeners;
|
||||||
|
|
||||||
use App\Events\AuditionChange;
|
use App\Events\AuditionChange;
|
||||||
use App\Events\EntryChange;
|
use App\Events\EntryChange;
|
||||||
use App\Services\AuditionCacheService;
|
use App\Services\AuditionService;
|
||||||
use App\Services\EntryCacheService;
|
use App\Services\EntryService;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
|
||||||
class RefreshEntryCache
|
class RefreshEntryCache
|
||||||
{
|
{
|
||||||
protected $entryCacheService;
|
protected $entryService;
|
||||||
/**
|
/**
|
||||||
* Create the event listener.
|
* Create the event listener.
|
||||||
*/
|
*/
|
||||||
public function __construct(EntryCacheService $cacheService)
|
public function __construct(EntryService $cacheService)
|
||||||
{
|
{
|
||||||
$this->entryCacheService = $cacheService;
|
$this->entryService = $cacheService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -26,9 +26,9 @@ class RefreshEntryCache
|
||||||
public function handle(EntryChange $event): void
|
public function handle(EntryChange $event): void
|
||||||
{
|
{
|
||||||
if ($event->auditionId) {
|
if ($event->auditionId) {
|
||||||
$this->entryCacheService->clearEntryCacheForAudition($event->auditionId);
|
$this->entryService->clearEntryCacheForAudition($event->auditionId);
|
||||||
} else {
|
} else {
|
||||||
$this->entryCacheService->clearEntryCaches();
|
$this->entryService->clearEntryCaches();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,12 @@ class School extends Model
|
||||||
{
|
{
|
||||||
return $this->hasMany(User::class);
|
return $this->hasMany(User::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function users(): HasMany
|
public function users(): HasMany
|
||||||
{
|
{
|
||||||
return $this->hasMany(User::class);
|
return $this->hasMany(User::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function emailDomains(): HasMany
|
public function emailDomains(): HasMany
|
||||||
{
|
{
|
||||||
return $this->hasMany(SchoolEmailDomain::class);
|
return $this->hasMany(SchoolEmailDomain::class);
|
||||||
|
|
@ -30,12 +32,13 @@ class School extends Model
|
||||||
{
|
{
|
||||||
$img = "https://ui-avatars.com/api/?background=$bg_color&color=$text_color&name=";
|
$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;
|
return $img;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function students(): HasMany
|
public function students(): HasMany
|
||||||
{
|
{
|
||||||
return $this->hasMany(Student::class);
|
return $this->hasMany(Student::class)->orderBy('last_name')->orderBy('first_name');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function entries(): HasManyThrough
|
public function entries(): HasManyThrough
|
||||||
|
|
@ -48,5 +51,4 @@ class School extends Model
|
||||||
'id',
|
'id',
|
||||||
'id');
|
'id');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,9 +34,9 @@ use App\Observers\SeatingLimitObserver;
|
||||||
use App\Observers\StudentObserver;
|
use App\Observers\StudentObserver;
|
||||||
use App\Observers\SubscoreDefinitionObserver;
|
use App\Observers\SubscoreDefinitionObserver;
|
||||||
use App\Observers\UserObserver;
|
use App\Observers\UserObserver;
|
||||||
use App\Services\AuditionCacheService;
|
use App\Services\AuditionService;
|
||||||
use App\Services\DoublerService;
|
use App\Services\DoublerService;
|
||||||
use App\Services\EntryCacheService;
|
use App\Services\EntryService;
|
||||||
use App\Services\ScoreService;
|
use App\Services\ScoreService;
|
||||||
use App\Services\SeatingService;
|
use App\Services\SeatingService;
|
||||||
use App\Services\TabulationService;
|
use App\Services\TabulationService;
|
||||||
|
|
@ -50,31 +50,31 @@ class AppServiceProvider extends ServiceProvider
|
||||||
*/
|
*/
|
||||||
public function register(): void
|
public function register(): void
|
||||||
{
|
{
|
||||||
$this->app->singleton(AuditionCacheService::class, function () {
|
$this->app->singleton(AuditionService::class, function () {
|
||||||
return new AuditionCacheService();
|
return new AuditionService();
|
||||||
});
|
});
|
||||||
|
|
||||||
$this->app->singleton(SeatingService::class, function ($app) {
|
$this->app->singleton(SeatingService::class, function ($app) {
|
||||||
return new SeatingService($app->make(TabulationService::class));
|
return new SeatingService($app->make(TabulationService::class));
|
||||||
});
|
});
|
||||||
|
|
||||||
$this->app->singleton(EntryCacheService::class, function ($app) {
|
$this->app->singleton(EntryService::class, function ($app) {
|
||||||
return new EntryCacheService($app->make(AuditionCacheService::class));
|
return new EntryService($app->make(AuditionService::class));
|
||||||
});
|
});
|
||||||
|
|
||||||
$this->app->singleton(ScoreService::class, function ($app) {
|
$this->app->singleton(ScoreService::class, function ($app) {
|
||||||
return new ScoreService($app->make(AuditionCacheService::class), $app->make(EntryCacheService::class));
|
return new ScoreService($app->make(AuditionService::class), $app->make(EntryService::class));
|
||||||
});
|
});
|
||||||
|
|
||||||
$this->app->singleton(TabulationService::class, function ($app) {
|
$this->app->singleton(TabulationService::class, function ($app) {
|
||||||
return new TabulationService(
|
return new TabulationService(
|
||||||
$app->make(AuditionCacheService::class),
|
$app->make(AuditionService::class),
|
||||||
$app->make(ScoreService::class),
|
$app->make(ScoreService::class),
|
||||||
$app->make(EntryCacheService::class));
|
$app->make(EntryService::class));
|
||||||
});
|
});
|
||||||
|
|
||||||
$this->app->singleton(DoublerService::class, function ($app) {
|
$this->app->singleton(DoublerService::class, function ($app) {
|
||||||
return new DoublerService($app->make(AuditionCacheService::class), $app->make(TabulationService::class), $app->make(SeatingService::class));
|
return new DoublerService($app->make(AuditionService::class), $app->make(TabulationService::class), $app->make(SeatingService::class));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use App\Services\EntryService;
|
||||||
|
use App\Services\Invoice\InvoiceDataService;
|
||||||
|
use App\Services\Invoice\InvoiceOneFeePerEntry;
|
||||||
|
use App\Services\Invoice\InvoiceOneFeePerStudent;
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
use function auditionSetting;
|
||||||
|
|
||||||
|
class InvoiceDataServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Register services.
|
||||||
|
*/
|
||||||
|
public function register(): void
|
||||||
|
{
|
||||||
|
$this->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'),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,7 +9,7 @@ use Illuminate\Support\Facades\App;
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
use Illuminate\Support\Facades\Session;
|
use Illuminate\Support\Facades\Session;
|
||||||
|
|
||||||
class AuditionCacheService
|
class AuditionService
|
||||||
{
|
{
|
||||||
protected $cacheKey = 'auditions';
|
protected $cacheKey = 'auditions';
|
||||||
|
|
||||||
|
|
@ -11,7 +11,7 @@ class DoublerService
|
||||||
{
|
{
|
||||||
protected $doublersCacheKey = 'doublers';
|
protected $doublersCacheKey = 'doublers';
|
||||||
|
|
||||||
protected $auditionCacheService;
|
protected $auditionService;
|
||||||
|
|
||||||
protected $tabulationService;
|
protected $tabulationService;
|
||||||
|
|
||||||
|
|
@ -20,9 +20,9 @@ class DoublerService
|
||||||
/**
|
/**
|
||||||
* Create a new class instance.
|
* Create a new class instance.
|
||||||
*/
|
*/
|
||||||
public function __construct(AuditionCacheService $auditionCacheService, TabulationService $tabulationService, SeatingService $seatingService)
|
public function __construct(AuditionService $auditionService, TabulationService $tabulationService, SeatingService $seatingService)
|
||||||
{
|
{
|
||||||
$this->auditionCacheService = $auditionCacheService;
|
$this->auditionService = $auditionService;
|
||||||
$this->tabulationService = $tabulationService;
|
$this->tabulationService = $tabulationService;
|
||||||
$this->seatingService = $seatingService;
|
$this->seatingService = $seatingService;
|
||||||
}
|
}
|
||||||
|
|
@ -100,13 +100,13 @@ class DoublerService
|
||||||
$info[$entry->id] = [
|
$info[$entry->id] = [
|
||||||
'entryID' => $entry->id,
|
'entryID' => $entry->id,
|
||||||
'auditionID' => $entry->audition_id,
|
'auditionID' => $entry->audition_id,
|
||||||
'auditionName' => $this->auditionCacheService->getAudition($entry->audition_id)->name,
|
'auditionName' => $this->auditionService->getAudition($entry->audition_id)->name,
|
||||||
'rank' => $this->tabulationService->entryRank($entry),
|
'rank' => $this->tabulationService->entryRank($entry),
|
||||||
'unscored' => $this->tabulationService->remainingEntriesForAudition($entry->audition_id),
|
'unscored' => $this->tabulationService->remainingEntriesForAudition($entry->audition_id),
|
||||||
'limits' => $this->seatingService->getLimitForAudition($entry->audition_id),
|
'limits' => $this->seatingService->getLimitForAudition($entry->audition_id),
|
||||||
'status' => $status,
|
'status' => $status,
|
||||||
];
|
];
|
||||||
$entry->audition = $this->auditionCacheService->getAudition($entry->audition_id);
|
$entry->audition = $this->auditionService->getAudition($entry->audition_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $info;
|
return $info;
|
||||||
|
|
|
||||||
|
|
@ -6,14 +6,14 @@ use App\Models\Entry;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
|
||||||
class EntryCacheService
|
class EntryService
|
||||||
{
|
{
|
||||||
protected $auditionCache;
|
protected $auditionCache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new class instance.
|
* Create a new class instance.
|
||||||
*/
|
*/
|
||||||
public function __construct(AuditionCacheService $auditionCache)
|
public function __construct(AuditionService $auditionCache)
|
||||||
{
|
{
|
||||||
$this->auditionCache = $auditionCache;
|
$this->auditionCache = $auditionCache;
|
||||||
}
|
}
|
||||||
|
|
@ -89,4 +89,13 @@ class EntryCacheService
|
||||||
$this->clearEntryCacheForAudition($audition->id);
|
$this->clearEntryCacheForAudition($audition->id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function entryIsLate(Entry $entry): bool
|
||||||
|
{
|
||||||
|
if ($entry->hasFlag('wave_late_fee')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $entry->created_at > $entry->audition->entry_deadline;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\Invoice;
|
||||||
|
|
||||||
|
interface InvoiceDataService
|
||||||
|
{
|
||||||
|
public function allData($schoolId);
|
||||||
|
|
||||||
|
public function getLines($schoolId);
|
||||||
|
|
||||||
|
public function getLinesTotal($schoolId);
|
||||||
|
|
||||||
|
public function getLateFeesTotal($schoolId);
|
||||||
|
|
||||||
|
public function getSchoolFeeTotal($schoolId);
|
||||||
|
|
||||||
|
public function getGrandTotal($schoolId);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\Invoice;
|
||||||
|
|
||||||
|
use App\Models\School;
|
||||||
|
use App\Services\EntryService;
|
||||||
|
use Illuminate\Support\Arr;
|
||||||
|
|
||||||
|
use function auditionSetting;
|
||||||
|
|
||||||
|
class InvoiceOneFeePerEntry implements InvoiceDataService
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create a new class instance.
|
||||||
|
*/
|
||||||
|
protected $entryService;
|
||||||
|
|
||||||
|
public function __construct(EntryService $entryService)
|
||||||
|
{
|
||||||
|
$this->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'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,100 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\Invoice;
|
||||||
|
|
||||||
|
use App\Models\School;
|
||||||
|
use App\Services\EntryService;
|
||||||
|
use Illuminate\Support\Arr;
|
||||||
|
|
||||||
|
use function auditionSetting;
|
||||||
|
|
||||||
|
class InvoiceOneFeePerStudent implements InvoiceDataService
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create a new class instance.
|
||||||
|
*/
|
||||||
|
protected $entryService;
|
||||||
|
|
||||||
|
public function __construct(EntryService $entryService)
|
||||||
|
{
|
||||||
|
$this->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'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -20,7 +20,7 @@ class ScoreService
|
||||||
/**
|
/**
|
||||||
* Create a new class instance.
|
* Create a new class instance.
|
||||||
*/
|
*/
|
||||||
public function __construct(AuditionCacheService $auditionCache, EntryCacheService $entryCache)
|
public function __construct(AuditionService $auditionCache, EntryService $entryCache)
|
||||||
{
|
{
|
||||||
$this->auditionCache = $auditionCache;
|
$this->auditionCache = $auditionCache;
|
||||||
$this->entryCache = $entryCache;
|
$this->entryCache = $entryCache;
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,9 @@ use Illuminate\Support\Facades\Session;
|
||||||
|
|
||||||
class TabulationService
|
class TabulationService
|
||||||
{
|
{
|
||||||
protected AuditionCacheService $auditionCacheService;
|
protected AuditionService $auditionService;
|
||||||
|
|
||||||
protected EntryCacheService $entryCacheService;
|
protected EntryService $entryService;
|
||||||
|
|
||||||
protected ScoreService $scoreService;
|
protected ScoreService $scoreService;
|
||||||
|
|
||||||
|
|
@ -19,13 +19,13 @@ class TabulationService
|
||||||
* Create a new class instance.
|
* Create a new class instance.
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
AuditionCacheService $scoringGuideCacheService,
|
AuditionService $auditionService,
|
||||||
ScoreService $scoreService,
|
ScoreService $scoreService,
|
||||||
EntryCacheService $entryCacheService)
|
EntryService $entryService)
|
||||||
{
|
{
|
||||||
$this->auditionCacheService = $scoringGuideCacheService;
|
$this->auditionService = $auditionService;
|
||||||
$this->scoreService = $scoreService;
|
$this->scoreService = $scoreService;
|
||||||
$this->entryCacheService = $entryCacheService;
|
$this->entryService = $entryService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -51,8 +51,8 @@ class TabulationService
|
||||||
return $cache[$auditionId];
|
return $cache[$auditionId];
|
||||||
}
|
}
|
||||||
|
|
||||||
$audition = $this->auditionCacheService->getAudition($auditionId);
|
$audition = $this->auditionService->getAudition($auditionId);
|
||||||
$entries = $this->entryCacheService->getEntriesForAudition($auditionId, $mode);
|
$entries = $this->entryService->getEntriesForAudition($auditionId, $mode);
|
||||||
$this->scoreService->calculateScoresForAudition($auditionId);
|
$this->scoreService->calculateScoresForAudition($auditionId);
|
||||||
// TODO will need to pass a mode to the above function to only use subscores for hte appropriate mode
|
// TODO will need to pass a mode to the above function to only use subscores for hte appropriate mode
|
||||||
foreach ($entries as $entry) {
|
foreach ($entries as $entry) {
|
||||||
|
|
@ -91,7 +91,7 @@ class TabulationService
|
||||||
public function entryScoreSheetsAreValid(Entry $entry): bool
|
public function entryScoreSheetsAreValid(Entry $entry): bool
|
||||||
{
|
{
|
||||||
//TODO consider making this move the invalid score to another database for further investigation
|
//TODO consider making this move the invalid score to another database for further investigation
|
||||||
$validJudges = $this->auditionCacheService->getAudition($entry->audition_id)->judges;
|
$validJudges = $this->auditionService->getAudition($entry->audition_id)->judges;
|
||||||
foreach ($entry->scoreSheets as $sheet) {
|
foreach ($entry->scoreSheets as $sheet) {
|
||||||
if (! $validJudges->contains($sheet->user_id)) {
|
if (! $validJudges->contains($sheet->user_id)) {
|
||||||
$invalidJudge = User::find($sheet->user_id);
|
$invalidJudge = User::find($sheet->user_id);
|
||||||
|
|
@ -135,11 +135,11 @@ class TabulationService
|
||||||
return Cache::remember('auditionsWithStatus', 30, function () use ($mode) {
|
return Cache::remember('auditionsWithStatus', 30, function () use ($mode) {
|
||||||
|
|
||||||
// Retrieve auditions from the cache and load entry IDs
|
// Retrieve auditions from the cache and load entry IDs
|
||||||
$auditions = $this->auditionCacheService->getAuditions($mode);
|
$auditions = $this->auditionService->getAuditions($mode);
|
||||||
// Iterate over the auditions and calculate the scored_entries_count
|
// Iterate over the auditions and calculate the scored_entries_count
|
||||||
foreach ($auditions as $audition) {
|
foreach ($auditions as $audition) {
|
||||||
$scored_entries_count = 0;
|
$scored_entries_count = 0;
|
||||||
$entries_to_check = $this->entryCacheService->getEntriesForAudition($audition->id);
|
$entries_to_check = $this->entryService->getEntriesForAudition($audition->id);
|
||||||
|
|
||||||
switch ($mode) {
|
switch ($mode) {
|
||||||
case 'seating':
|
case 'seating':
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,5 @@
|
||||||
return [
|
return [
|
||||||
App\Providers\AppServiceProvider::class,
|
App\Providers\AppServiceProvider::class,
|
||||||
App\Providers\FortifyServiceProvider::class,
|
App\Providers\FortifyServiceProvider::class,
|
||||||
|
App\Providers\InvoiceDataServiceProvider::class,
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@
|
||||||
|
|
||||||
<x-layout.page-section>
|
<x-layout.page-section>
|
||||||
<x-slot:section_name>Scoring Settings</x-slot:section_name>
|
<x-slot:section_name>Scoring Settings</x-slot:section_name>
|
||||||
<x-slot:section_description>If students cannot advance to further honor groups, leave next event name blank</x-slot:section_description>
|
|
||||||
<x-form.body-grid columns="12" class="m-3">
|
<x-form.body-grid columns="12" class="m-3">
|
||||||
<div class="col-span-6 flex space-x-3">
|
<div class="col-span-6 flex space-x-3">
|
||||||
<x-form.toggle-checkbox name="judging_enabled"/><span>Enable score entry by judges</span>
|
<x-form.toggle-checkbox name="judging_enabled"/><span>Enable score entry by judges</span>
|
||||||
|
|
@ -37,17 +36,27 @@
|
||||||
|
|
||||||
<x-layout.page-section>
|
<x-layout.page-section>
|
||||||
<x-slot:section_name>Financial Settings</x-slot:section_name>
|
<x-slot:section_name>Financial Settings</x-slot:section_name>
|
||||||
<x-slot:section_description>If students cannot advance to further honor groups, leave next event name blank</x-slot:section_description>
|
|
||||||
<x-form.body-grid columns="12" class="m-3">
|
<x-form.body-grid columns="12" class="m-3">
|
||||||
|
|
||||||
<x-form.select name="fee_structure" colspan="6">
|
<x-form.select name="fee_structure" colspan="6">
|
||||||
<x-slot:label>Fee Structure</x-slot:label>
|
<x-slot:label>Fee Structure</x-slot:label>
|
||||||
<option>One fee per entry</option>
|
{{-- Values should be one of the options in the boot method InvoiceDataServiceProvider --}}
|
||||||
<option>One fee per student</option>
|
<option value="oneFeePerEntry" {{ auditionSetting('fee_structure') === 'oneFeePerEntry' ? 'selected':'' }}>
|
||||||
|
One fee per entry
|
||||||
|
</option>
|
||||||
|
<option value="oneFeePerStudent" {{ auditionSetting('fee_structure') === 'oneFeePerStudent' ? 'selected':'' }}>
|
||||||
|
One fee per student - one late fee per student if any of their entries are late
|
||||||
|
</option>
|
||||||
</x-form.select>
|
</x-form.select>
|
||||||
|
|
||||||
<x-form.field label_text="Late Fee" name="late_fee" colspan="3" :value="auditionSetting('late_fee')"/>
|
<x-form.field label_text="Late Fee"
|
||||||
<x-form.field label_text="School Membership Fee" name="school_fee" colspan="3" :value="auditionSetting('school_fee')"/>
|
name="late_fee"
|
||||||
|
colspan="3"
|
||||||
|
:value="number_format(auditionSetting('late_fee') / 100,2) "/>
|
||||||
|
<x-form.field label_text="School Membership Fee"
|
||||||
|
name="school_fee"
|
||||||
|
colspan="3"
|
||||||
|
:value="number_format(auditionSetting('school_fee') / 100,2)"/>
|
||||||
|
|
||||||
</x-form.body-grid>
|
</x-form.body-grid>
|
||||||
</x-layout.page-section>
|
</x-layout.page-section>
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<x-card.card>
|
<x-card.card>
|
||||||
<x-table.table with_title_area>
|
<x-table.table with_title_area>
|
||||||
<x-slot:title class="ml-3">Schools</x-slot:title>
|
<x-slot:title class="ml-3">Schools</x-slot:title>
|
||||||
<x-slot:subtitle class="ml-3">Click school name to edit</x-slot:subtitle>
|
<x-slot:subtitle class="ml-3">Click school name to edit<br>Click total fees for invoice</x-slot:subtitle>
|
||||||
<x-slot:title_block_right class="mr-3">
|
<x-slot:title_block_right class="mr-3">
|
||||||
<x-form.button href="{{ route('admin.schools.create') }}">New School</x-form.button>
|
<x-form.button href="{{ route('admin.schools.create') }}">New School</x-form.button>
|
||||||
</x-slot:title_block_right>
|
</x-slot:title_block_right>
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<x-table.th>Name</x-table.th>
|
<x-table.th>Name</x-table.th>
|
||||||
|
<x-table.th>Total Fees</x-table.th>
|
||||||
<x-table.th>Directors</x-table.th>
|
<x-table.th>Directors</x-table.th>
|
||||||
<x-table.th>Students</x-table.th>
|
<x-table.th>Students</x-table.th>
|
||||||
<x-table.th>Entries</x-table.th>
|
<x-table.th>Entries</x-table.th>
|
||||||
|
|
@ -22,6 +23,11 @@
|
||||||
@foreach($schools as $school)
|
@foreach($schools as $school)
|
||||||
<tr>
|
<tr>
|
||||||
<x-table.td><a href="/admin/schools/{{ $school->id }}">{{ $school->name }}</a></x-table.td>
|
<x-table.td><a href="/admin/schools/{{ $school->id }}">{{ $school->name }}</a></x-table.td>
|
||||||
|
<x-table.td>
|
||||||
|
<a href="{{ route('admin.schools.invoice',$school->id) }}">
|
||||||
|
${{ number_format($schoolTotalFees[$school->id],2) }}
|
||||||
|
</a>
|
||||||
|
</x-table.td>
|
||||||
<x-table.td>{{ $school->users->count() }}</x-table.td>
|
<x-table.td>{{ $school->users->count() }}</x-table.td>
|
||||||
<x-table.td>{{ $school->students->count() }}</x-table.td>
|
<x-table.td>{{ $school->students->count() }}</x-table.td>
|
||||||
<x-table.td>{{ $school->entries->count() }}</x-table.td>
|
<x-table.td>{{ $school->entries->count() }}</x-table.td>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
@props(['right_link_button_type' => 'a']) {{-- Use if the link to the right needs to be a button --}}
|
@props(['right_link_button_type' => 'a']) {{-- Use if the link to the right needs to be a button --}}
|
||||||
<li {{ $attributes->merge(['class'=>'flex items-center justify-between gap-x-6 px-4 py-5 sm:px-6']) }}>
|
<li {{ $attributes->merge(['class'=>'flex items-center justify-between gap-x-6 px-4 py-4 sm:px-6']) }}>
|
||||||
<div class="flex min-w-0 gap-x-4">
|
<div class="flex min-w-0 gap-x-4">
|
||||||
{{ $slot }}
|
{{ $slot }}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -4,4 +4,31 @@
|
||||||
@if(! Auth::user()->school_id)
|
@if(! Auth::user()->school_id)
|
||||||
You aren't currently associated with a school. <a href="/my_school" class="text-blue-600">Click here to choose or create one.</a>
|
You aren't currently associated with a school. <a href="/my_school" class="text-blue-600">Click here to choose or create one.</a>
|
||||||
@endif
|
@endif
|
||||||
|
<div class="grid sm:grid-cols-2 md:grid-cols-4">
|
||||||
|
<div>{{-- Column 1 --}}
|
||||||
|
<x-card.card>
|
||||||
|
<x-card.heading>User Options</x-card.heading>
|
||||||
|
<x-card.list.body>
|
||||||
|
<a href="{{ route('my_profile') }}">
|
||||||
|
<x-card.list.row class="hover:bg-gray-200">
|
||||||
|
My Profile
|
||||||
|
</x-card.list.row>
|
||||||
|
</a>
|
||||||
|
<a href="{{ route('my_school') }}">
|
||||||
|
<x-card.list.row class="hover:bg-gray-200">
|
||||||
|
My School
|
||||||
|
</x-card.list.row>
|
||||||
|
</a>
|
||||||
|
@if(Auth::user()->school_id)
|
||||||
|
<a href="{{ route('my_invoice') }}">
|
||||||
|
<x-card.list.row class="hover:bg-gray-200">
|
||||||
|
My Invoice
|
||||||
|
</x-card.list.row>
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
</x-card.list.body>
|
||||||
|
</x-card.card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
</x-layout.app>
|
</x-layout.app>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
@props(['school', 'invoiceData'])
|
||||||
|
|
||||||
|
<x-layout.app>
|
||||||
|
<x-slot:page_title>Invoice - {{ $school->name }}</x-slot:page_title>
|
||||||
|
<div class="">
|
||||||
|
<x-table.table class="">
|
||||||
|
<thead class="">
|
||||||
|
<tr>
|
||||||
|
<x-table.th>Student Name</x-table.th>
|
||||||
|
<x-table.th>Audition</x-table.th>
|
||||||
|
<x-table.th>Entry Timestamp</x-table.th>
|
||||||
|
<x-table.th>Entry Fee</x-table.th>
|
||||||
|
<x-table.th>Late Fee</x-table.th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<x-table.body>
|
||||||
|
@foreach($invoiceData['lines'] as $line)
|
||||||
|
<tr>
|
||||||
|
<x-table.td>{{ $line['student_name'] }}</x-table.td>
|
||||||
|
<x-table.td>{{ $line['audition'] }}</x-table.td>
|
||||||
|
<x-table.td>{{ $line['entry_timestamp']->setTimezone('America/Chicago')->format('m/d/Y g:i:s A') }}</x-table.td>
|
||||||
|
<x-table.td>${{ number_format($line['entry_fee'],2) }}</x-table.td>
|
||||||
|
<x-table.td>${{ number_format($line['late_fee'],2) }}</x-table.td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</x-table.body>
|
||||||
|
<tfoot class="">
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">
|
||||||
|
<x-table.th class="text-right">Totals</x-table.th>
|
||||||
|
<x-table.th>${{ number_format($invoiceData['linesTotal'],2) }}</x-table.th>
|
||||||
|
<x-table.th>${{ number_format($invoiceData['lateFeesTotal'],2) }}</x-table.th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="3"></td>
|
||||||
|
<x-table.th class="text-right">Total Entry Fees</x-table.th>
|
||||||
|
<x-table.th>${{ number_format($invoiceData['linesTotal'] + $invoiceData['lateFeesTotal'], 2) }}</x-table.th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<x-table.th colspan="4" class="text-right">School Fee</x-table.th>
|
||||||
|
<x-table.th >${{ number_format($invoiceData['schoolFeeTotal'],2) }}</x-table.th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<x-table.th colspan="4" class="text-right">Grand Total</x-table.th>
|
||||||
|
<x-table.th >${{ number_format($invoiceData['grandTotal'],2) }}</x-table.th>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</x-table.table>
|
||||||
|
</div>
|
||||||
|
</x-layout.app>
|
||||||
|
|
@ -18,59 +18,3 @@
|
||||||
</x-layout.page-section>
|
</x-layout.page-section>
|
||||||
</x-layout.page-section-container>
|
</x-layout.page-section-container>
|
||||||
</x-layout.app>
|
</x-layout.app>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{{--@php use Illuminate\Support\Facades\Auth; @endphp
|
|
||||||
<x-layout.app>
|
|
||||||
<x-slot:page_title>User Profile</x-slot:page_title>
|
|
||||||
<div class="space-y-10 divide-y divide-gray-900/10">
|
|
||||||
<x-layout.page-section
|
|
||||||
section_name="Personal Information"
|
|
||||||
section_description="Use a permanent address where you receive mail"
|
|
||||||
>
|
|
||||||
@if (session('status') === 'profile-information-updated')
|
|
||||||
<div class="mt-4 px-8 font-medium text-sm text-green-600">
|
|
||||||
Profile Info has been updated.
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
<form action="/user/profile-information" method="POST">
|
|
||||||
@csrf
|
|
||||||
@method('PUT')
|
|
||||||
<div class="px-4 py-6 sm:p-8">
|
|
||||||
<div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
|
|
||||||
<x-form.field name="first_name" label="First Name" value="{{ Auth::user()->first_name }}" div_classes="sm:col-span-3" />
|
|
||||||
<x-form.field name="last_name" label="Last Name" value="{{ Auth::user()->last_name }}" div_classes="sm:col-span-3" />
|
|
||||||
<x-form.field name="email" label="Email Address" value="{{ Auth::user()->email }}" div_classes="sm:col-span-3" />
|
|
||||||
<x-form.field name="cell_phone" label="Cell Phone" value="{{ Auth::user()->cell_phone }}" div_classes="sm:col-span-3" />
|
|
||||||
<x-form.field name="judging_preference" label="Judging Preference" value="{{ Auth::user()->judging_preference }}" div_classes="sm:col-span-5" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center justify-end gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8">
|
|
||||||
<x-form.button-nocolor type="button">Cancel</x-form.button-nocolor>
|
|
||||||
<x-form.button>Update Profile</x-form.button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
</x-layout.page-section>
|
|
||||||
|
|
||||||
<x-layout.page-section
|
|
||||||
section_name="Change Password"
|
|
||||||
section_description="Update your user password"
|
|
||||||
>
|
|
||||||
@if (session('status') === 'password-updated')
|
|
||||||
<div class="mt-4 px-8 font-medium text-sm text-green-600">
|
|
||||||
Password has been updated.
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
<x-form.card method="PUT" action="/user/password" cols="1" submit-button-text="Change Password">
|
|
||||||
<x-form.field name="current_password" label="Current Password" type="password" autocomplete="current-password" required />
|
|
||||||
<x-form.field name="password" label="New Password" type="password" autocomplete="new-password" required />
|
|
||||||
<x-form.field name="password_confirmation" label="Confirm New Password" autocomplete="new-password" type="password" required />
|
|
||||||
</x-form.card>
|
|
||||||
|
|
||||||
</x-layout.page-section>
|
|
||||||
</div>
|
|
||||||
</x-layout.app>--}}
|
|
||||||
|
|
|
||||||
|
|
@ -10,18 +10,16 @@
|
||||||
use Illuminate\Support\Facades\Session;
|
use Illuminate\Support\Facades\Session;
|
||||||
@endphp
|
@endphp
|
||||||
@inject('scoreservice','App\Services\ScoreService');
|
@inject('scoreservice','App\Services\ScoreService');
|
||||||
@inject('auditionService','App\Services\AuditionCacheService');
|
@inject('auditionService','App\Services\AuditionService');
|
||||||
@inject('entryService','App\Services\EntryCacheService')
|
@inject('entryService','App\Services\EntryService')
|
||||||
@inject('seatingService','App\Services\SeatingService')
|
@inject('seatingService','App\Services\SeatingService')
|
||||||
<x-layout.app>
|
<x-layout.app>
|
||||||
<x-slot:page_title>Test Page</x-slot:page_title>
|
<x-slot:page_title>Test Page</x-slot:page_title>
|
||||||
@php
|
@php
|
||||||
$schools = School::all();
|
dump($totalFees);
|
||||||
|
dump($lines);
|
||||||
|
|
||||||
}
|
|
||||||
@endphp
|
@endphp
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</x-layout.app>
|
</x-layout.app>
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,7 @@ Route::middleware(['auth', 'verified', CheckIfAdmin::class])->prefix('admin/')->
|
||||||
Route::get('/create', 'create')->name('admin.schools.create');
|
Route::get('/create', 'create')->name('admin.schools.create');
|
||||||
Route::get('/{school}', 'show')->name('admin.schools.show');
|
Route::get('/{school}', 'show')->name('admin.schools.show');
|
||||||
Route::get('/{school}/edit', 'edit')->name('admin.schools.edit');
|
Route::get('/{school}/edit', 'edit')->name('admin.schools.edit');
|
||||||
|
Route::get('/{school}/invoice', 'viewInvoice')->name('admin.schools.invoice');
|
||||||
Route::patch('/{school}', 'update')->name('admin.schools.update');
|
Route::patch('/{school}', 'update')->name('admin.schools.update');
|
||||||
Route::post('/', 'store')->name('admin.schools.store');
|
Route::post('/', 'store')->name('admin.schools.store');
|
||||||
Route::delete('/domain/{domain}', 'destroy_domain')->name('admin.schools.destroy_domain');
|
Route::delete('/domain/{domain}', 'destroy_domain')->name('admin.schools.destroy_domain');
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,9 @@ use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
Route::middleware(['auth', 'verified'])->group(function () {
|
Route::middleware(['auth', 'verified'])->group(function () {
|
||||||
Route::get('/dashboard', [DashboardController::class, 'dashboard'])->name('dashboard');
|
Route::get('/dashboard', [DashboardController::class, 'dashboard'])->name('dashboard');
|
||||||
Route::get('/profile', [DashboardController::class, 'profile']);
|
Route::get('/profile', [DashboardController::class, 'profile'])->name('my_profile');
|
||||||
Route::get('/my_school', [DashboardController::class, 'my_school']);
|
Route::get('/my_school', [DashboardController::class, 'my_school'])->name('my_school');
|
||||||
|
Route::get('/my_invoice', [DashboardController::class, 'my_invoice'])->name('my_invoice');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Entry Related Routes
|
// Entry Related Routes
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue