Enter and store no show #13
|
|
@ -0,0 +1,11 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="tests - paralell" type="PestRunConfigurationType">
|
||||
<option name="pestRunnerSettings">
|
||||
<PestRunner directory="$PROJECT_DIR$/tests" method="" options="--parallel --recreate-databases" />
|
||||
</option>
|
||||
<option name="runnerSettings">
|
||||
<PhpTestRunnerSettings directory="$PROJECT_DIR$/tests" method="" options="--parallel --recreate-databases" />
|
||||
</option>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
|
|
@ -181,37 +181,4 @@ class AuditionController extends Controller
|
|||
|
||||
return to_route('admin.auditions.index')->with('success', 'Audition deleted successfully');
|
||||
}
|
||||
|
||||
public function prepareDraw()
|
||||
{
|
||||
if (! Auth::user()->is_admin) {
|
||||
abort(403);
|
||||
}
|
||||
$allAuditions = Audition::with('entries')->orderBy('score_order')->get();
|
||||
$nodraw_auditions = $allAuditions->filter(function ($audition) {
|
||||
return $audition->has_no_draw();
|
||||
});
|
||||
$drawn_auditions = $allAuditions->filter(function ($audition) {
|
||||
return $audition->has_complete_draw();
|
||||
});
|
||||
$partial_draw_auditions = $allAuditions->filter(function ($audition) {
|
||||
return $audition->has_partial_draw();
|
||||
});
|
||||
|
||||
return view('admin.entries.prepare_draw',
|
||||
compact('nodraw_auditions', 'drawn_auditions', 'partial_draw_auditions'));
|
||||
}
|
||||
|
||||
public function runDraw(Request $request)
|
||||
{
|
||||
if (! Auth::user()->is_admin) {
|
||||
abort(403);
|
||||
}
|
||||
$draw_auditions = Audition::with('entries')->find(array_keys($request->input('auditions')));
|
||||
foreach ($draw_auditions as $audition) {
|
||||
$audition->runDraw();
|
||||
}
|
||||
|
||||
return redirect(' / admin / auditions / run_draw');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,10 +6,8 @@ use App\Http\Controllers\Controller;
|
|||
use App\Models\Audition;
|
||||
use App\Models\School;
|
||||
use App\Models\Student;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use function abort;
|
||||
use function to_route;
|
||||
use function view;
|
||||
|
|
@ -50,7 +48,7 @@ class StudentController extends Controller
|
|||
'school_id' => ['required', 'exists:schools,id'],
|
||||
]);
|
||||
|
||||
$student = Student::create([
|
||||
Student::create([
|
||||
'first_name' => request('first_name'),
|
||||
'last_name' => request('last_name'),
|
||||
'grade' => request('grade'),
|
||||
|
|
@ -69,11 +67,12 @@ class StudentController extends Controller
|
|||
$maxGrade = Audition::max('maximum_grade');
|
||||
$schools = School::orderBy('name')->get();
|
||||
$student->loadCount('entries');
|
||||
|
||||
return view('admin.students.edit',
|
||||
['student' => $student, 'schools' => $schools, 'minGrade' => $minGrade, 'maxGrade' => $maxGrade]);
|
||||
}
|
||||
|
||||
public function update(Request $request, Student $student)
|
||||
public function update(Student $student)
|
||||
{
|
||||
if (! Auth::user()->is_admin) {
|
||||
abort(403);
|
||||
|
|
@ -105,7 +104,6 @@ class StudentController extends Controller
|
|||
|
||||
public function destroy(Student $student)
|
||||
{
|
||||
Log::debug('Deleting student '.$student->id);
|
||||
if ($student->entries()->count() > 0) {
|
||||
return to_route('admin.students.index')->with('error', 'You cannot delete a student with entries.');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,103 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Tabulation;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Entry;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
use function to_route;
|
||||
|
||||
class EntryFlagController extends Controller
|
||||
{
|
||||
public function noShowSelect()
|
||||
{
|
||||
$method = 'GET';
|
||||
$formRoute = 'entry-flags.confirmNoShow';
|
||||
|
||||
return view('tabulation.choose_entry', compact('method', 'formRoute'));
|
||||
}
|
||||
|
||||
public function noShowConfirm(Request $request)
|
||||
{
|
||||
$validData = $request->validate([
|
||||
'entry_id' => 'required|exists:entries,id',
|
||||
]);
|
||||
$entry = Entry::with('flags')->withCount('scoreSheets')->find($validData['entry_id']);
|
||||
|
||||
// If any results are published, get gone
|
||||
if ($entry->audition->hasFlag('seats_published')) {
|
||||
return to_route('entry-flags.noShowSelect')->with('error',
|
||||
'Cannot enter a no-show for an entry in an audition where seats are published');
|
||||
}
|
||||
if ($entry->audition->hasFlag('advance_published')) {
|
||||
return to_route('entry-flags.noShowSelect')->with('error',
|
||||
'Cannot enter a no-show for an entry in an audition where advancement is published');
|
||||
}
|
||||
|
||||
if ($entry->hasFlag('no_show')) {
|
||||
$formId = 'no-show-cancellation-form';
|
||||
$buttonName = 'Remove No Show';
|
||||
$submitRouteName = 'entry-flags.undoNoShow';
|
||||
$cardHeading = 'Undo No-Show';
|
||||
$method = 'DELETE';
|
||||
} else {
|
||||
$formId = 'no-show-confirmation-form';
|
||||
$buttonName = 'Confirm No Show';
|
||||
$submitRouteName = 'entry-flags.enterNoShow';
|
||||
$cardHeading = 'Confirm No-Show';
|
||||
$method = 'POST';
|
||||
}
|
||||
$scores = [];
|
||||
if ($entry->score_sheets_count > 0) {
|
||||
$scores = $entry->scoreSheets;
|
||||
$scores->load('judge');
|
||||
}
|
||||
|
||||
return view('tabulation.no_show_confirm',
|
||||
compact('entry',
|
||||
'formId',
|
||||
'buttonName',
|
||||
'submitRouteName',
|
||||
'cardHeading',
|
||||
'method',
|
||||
'scores'));
|
||||
}
|
||||
|
||||
public function enterNoShow(Entry $entry)
|
||||
{
|
||||
if ($entry->audition->hasFlag('seats_published')) {
|
||||
return to_route('entry-flags.noShowSelect')->with('error',
|
||||
'Cannot enter a no-show for an entry in an audition where seats are published');
|
||||
}
|
||||
if ($entry->audition->hasFlag('advance_published')) {
|
||||
return to_route('entry-flags.noShowSelect')->with('error',
|
||||
'Cannot enter a no-show for an entry in an audition where advancement is published');
|
||||
}
|
||||
DB::table('score_sheets')->where('entry_id', $entry->id)->delete();
|
||||
|
||||
$entry->addFlag('no_show');
|
||||
|
||||
$msg = 'No Show has been entered for '.$entry->audition->name.' #'.$entry->draw_number.' (ID: '.$entry->id.').';
|
||||
|
||||
return to_route('entry-flags.noShowSelect')->with('success', $msg);
|
||||
}
|
||||
|
||||
public function undoNoShow(Entry $entry)
|
||||
{
|
||||
if ($entry->audition->hasFlag('seats_published')) {
|
||||
return to_route('entry-flags.noShowSelect')->with('error',
|
||||
'Cannot undo a no-show for an entry in an audition where seats are published');
|
||||
}
|
||||
if ($entry->audition->hasFlag('advance_published')) {
|
||||
return to_route('entry-flags.noShowSelect')->with('error',
|
||||
'Cannot undo a no-show for an entry in an audition where advancement is published');
|
||||
}
|
||||
|
||||
$entry->removeFlag('no_show');
|
||||
|
||||
return to_route('entry-flags.noShowSelect')->with('success',
|
||||
'No Show status has been removed for '.$entry->audition->name.' #'.$entry->draw_number.' (ID: '.$entry->id.').');
|
||||
}
|
||||
}
|
||||
|
|
@ -7,15 +7,21 @@ use App\Models\Entry;
|
|||
use App\Models\ScoreSheet;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
|
||||
class ScoreController extends Controller
|
||||
{
|
||||
public function chooseEntry(Request $request)
|
||||
{
|
||||
return view('tabulation.choose_entry');
|
||||
$method = 'GET';
|
||||
$formRoute = 'scores.entryScoreSheet';
|
||||
|
||||
return view('tabulation.choose_entry', compact('method', 'formRoute'));
|
||||
}
|
||||
|
||||
public function destroyScore(ScoreSheet $score) {
|
||||
public function destroyScore(ScoreSheet $score)
|
||||
{
|
||||
$score->delete();
|
||||
|
||||
return redirect()->back()->with('success', 'Score Deleted');
|
||||
}
|
||||
|
||||
|
|
@ -36,7 +42,9 @@ class ScoreController extends Controller
|
|||
if (! $entry) {
|
||||
return redirect()->route('tabulation.chooseEntry')->with('error', 'Entry not found');
|
||||
}
|
||||
return view('tabulation.entry_score_sheet', compact('entry','judges','scoring_guide','subscores','existing_sheets'));
|
||||
|
||||
return view('tabulation.entry_score_sheet',
|
||||
compact('entry', 'judges', 'scoring_guide', 'subscores', 'existing_sheets'));
|
||||
}
|
||||
|
||||
public function saveEntryScoreSheet(Request $request, Entry $entry)
|
||||
|
|
@ -52,7 +60,8 @@ class ScoreController extends Controller
|
|||
|
||||
$scoreValidation = $scoringGuide->validateScores($request->input('judge'.$judge->id));
|
||||
if ($scoreValidation != 'success') {
|
||||
return redirect(url()->previous())->with('error', $judge->full_name() . ': ' . $scoreValidation)->with('oldScores',$request->all());
|
||||
return redirect(url()->previous())->with('error',
|
||||
$judge->full_name().': '.$scoreValidation)->with('oldScores', $request->all());
|
||||
}
|
||||
|
||||
$scoreSubmission = $request->input('judge'.$judge->id);
|
||||
|
|
@ -61,7 +70,7 @@ class ScoreController extends Controller
|
|||
$scoresToSave[$subscore->id] = [
|
||||
'subscore_id' => $subscore->id,
|
||||
'subscore_name' => $subscore->name,
|
||||
'score' => intval($scoreSubmission[$subscore->id])
|
||||
'score' => intval($scoreSubmission[$subscore->id]),
|
||||
];
|
||||
}
|
||||
$preparedScoreSheets[$judge->id]['scores'] = $scoresToSave;
|
||||
|
|
@ -72,7 +81,7 @@ class ScoreController extends Controller
|
|||
['subscores' => $sheet['scores']]
|
||||
);
|
||||
}
|
||||
return redirect()->route('scores.chooseEntry')->with('success',count($preparedScoreSheets) . " Scores saved");
|
||||
}
|
||||
|
||||
return redirect()->route('scores.chooseEntry')->with('success', count($preparedScoreSheets).' Scores saved');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ class CheckIfCanTab
|
|||
return $next($request);
|
||||
}
|
||||
|
||||
return redirect('/')->with('error', 'You do not have access to score tabulation.');
|
||||
return redirect('dashboard')->with('error', 'You are not authorized to perform this action');
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,14 +16,6 @@ class Audition extends Model
|
|||
|
||||
protected $guarded = [];
|
||||
|
||||
protected $rankedEntries = null;
|
||||
|
||||
protected static $completeAuditions = null;
|
||||
|
||||
protected $fully_scored; // Set by TabulationService
|
||||
|
||||
protected $scored_entries_count; //Set by TabulationService
|
||||
|
||||
public function event(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Event::class);
|
||||
|
|
@ -49,84 +41,6 @@ class Audition extends Model
|
|||
return '$'.number_format($this->entry_fee / 100, 2);
|
||||
}
|
||||
|
||||
public function has_no_draw(): bool
|
||||
{
|
||||
// return true if all of my entries have a null draw_number
|
||||
//return $this->entries->every(fn($entry) => is_null($entry->draw_number));
|
||||
// return $this->entries()->whereNotNull('draw_number')->doesntExist();
|
||||
if ($this->entries->count() == 0) {
|
||||
return false;
|
||||
}
|
||||
if ($this->relationLoaded('entries')) {
|
||||
return $this->entries->every(function ($entry) {
|
||||
return is_null($entry->draw_number);
|
||||
});
|
||||
} else {
|
||||
return $this->entries()->whereNotNull('draw_number')->doesntExist();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function has_complete_draw(): bool
|
||||
{
|
||||
// return true if all of my entries have a draw_number
|
||||
// return $this->entries->every(fn($entry) => !is_null($entry->draw_number));
|
||||
// return $this->entries()->whereNull('draw_number')->doesntExist();
|
||||
if ($this->entries->count() == 0) {
|
||||
return false;
|
||||
}
|
||||
if ($this->relationLoaded('entries')) {
|
||||
return $this->entries->every(function ($entry) {
|
||||
return ! is_null($entry->draw_number);
|
||||
});
|
||||
} else {
|
||||
return $this->entries()->whereNull('draw_number')->doesntExist();
|
||||
}
|
||||
}
|
||||
|
||||
public function has_partial_draw(): bool
|
||||
{
|
||||
if ($this->entries->count() == 0) {
|
||||
return false;
|
||||
}
|
||||
// return true I have at least one entry with a null draw number AND at least one entry with a non-null draw number
|
||||
//return $this->entries->contains(fn($entry) => is_null($entry->draw_number)) && $this->entries->contains(fn($entry) => !is_null($entry->draw_number));
|
||||
|
||||
//$hasNull = $this->entries()->whereNull('draw_number')->exists();
|
||||
//$hasNotNull = $this->entries()->whereNotNull('draw_number')->exists();
|
||||
//return $hasNull && $hasNotNull;
|
||||
|
||||
if ($this->relationLoaded('entries')) {
|
||||
$hasNull = $this->entries->contains(function ($entry) {
|
||||
return is_null($entry->draw_number);
|
||||
});
|
||||
|
||||
$hasNotNull = $this->entries->contains(function ($entry) {
|
||||
return ! is_null($entry->draw_number);
|
||||
});
|
||||
|
||||
return $hasNull && $hasNotNull;
|
||||
} else {
|
||||
$hasNull = $this->entries()->whereNull('draw_number')->exists();
|
||||
$hasNotNull = $this->entries()->whereNotNull('draw_number')->exists();
|
||||
|
||||
return $hasNull && $hasNotNull;
|
||||
}
|
||||
}
|
||||
|
||||
public function runDraw(): null
|
||||
{
|
||||
$entries = $this->entries->shuffle();
|
||||
|
||||
foreach ($entries as $index => $entry) {
|
||||
$entry->update(['draw_number' => $index + 1]);
|
||||
$entry->save();
|
||||
}
|
||||
|
||||
return null;
|
||||
// TODO move all draw functions to a DrawService
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BelongsToMany|User[]
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@
|
|||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Ensemble;
|
||||
use App\Models\Event;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Ensemble>
|
||||
* @extends Factory<Ensemble>
|
||||
*/
|
||||
class EnsembleFactory extends Factory
|
||||
{
|
||||
|
|
@ -17,8 +19,8 @@ class EnsembleFactory extends Factory
|
|||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'name' => $this->faker->name,
|
||||
'event_id' => \App\Models\Event::factory(),
|
||||
'name' => $this->faker->words(4, true),
|
||||
'event_id' => Event::factory(),
|
||||
'code' => $this->faker->randomLetter().$this->faker->randomLetter,
|
||||
'rank' => $this->faker->numberBetween(1, 10),
|
||||
];
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ namespace Database\Seeders;
|
|||
|
||||
use App\Models\ScoreSheet;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class ScoreAllAuditions extends Seeder
|
||||
|
|
@ -26,13 +25,13 @@ class ScoreAllAuditions extends Seeder
|
|||
$scoreArray[$subscore->id] = [
|
||||
'score' => mt_rand(0, 100),
|
||||
'subscore_id' => $subscore->id,
|
||||
'subscore_name' => $subscore->name
|
||||
'subscore_name' => $subscore->name,
|
||||
];
|
||||
}
|
||||
ScoreSheet::create([
|
||||
'user_id' => $judge->id,
|
||||
'entry_id' => $entry->id,
|
||||
'subscores' => $scoreArray
|
||||
'subscores' => $scoreArray,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
<div x-data="{ toggle: {{ $checked ? 'true':'false'}} }" class="flex items-center">
|
||||
<label {{ $attributes->merge(['class'=>'relative inline-flex items-center cursor-pointer']) }}>{{ $slot }}
|
||||
<input type="checkbox" x-model="toggle" name="{{ $name }}" class="sr-only" {{ $checked ? 'checked':''}} value="1" >
|
||||
<div :class="toggle ? 'bg-blue-600' : 'bg-gray-200'" class="w-11 h-6 rounded-full transition-colors duration-300"></div>
|
||||
<div :class="toggle ? 'bg-indigo-600' : 'bg-gray-200'" class="w-11 h-6 rounded-full transition-colors duration-300"></div>
|
||||
<div :class="toggle ? 'translate-x-6' : 'translate-x-1'" class="absolute left-1 top-1 bg-white w-4 h-4 rounded-full transition-transform duration-300"></div>
|
||||
</label>
|
||||
@error($name)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,16 @@
|
|||
@php
|
||||
/**
|
||||
* @var string $method Method for the select form
|
||||
* @var string $formRoute Route for the form action. Should be a route name
|
||||
*/
|
||||
@endphp
|
||||
|
||||
<x-layout.app>
|
||||
<x-slot:page_title>Choose Entry</x-slot:page_title>
|
||||
<x-card.card class="mx-auto max-w-sm">
|
||||
<x-card.heading>Choose Entry</x-card.heading>
|
||||
<div class="">
|
||||
<x-form.form method="GET" action="{{ route('scores.entryScoreSheet') }}" class="mb-4 mt-3">
|
||||
<x-form.form method="{{ $method }}" action="{{ route($formRoute) }}" class="mb-4 mt-3" id="entry-select-form">
|
||||
<x-form.field name="entry_id" label_text="Entry ID"></x-form.field>
|
||||
<x-form.footer >
|
||||
<x-form.button>Select</x-form.button>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
<x-layout.app x-data="{ showButton: {{ $scores ? 'false':'true' }} }">
|
||||
@if($scores)
|
||||
<x-card.card class="mx-auto max-w-2xl mb-3">
|
||||
<x-card.heading class="text-red-600">
|
||||
WARNING: Entry has existing scores
|
||||
</x-card.heading>
|
||||
<div class="grid md:grid-cols-3 px-4 space-x-3 pb-6">
|
||||
@foreach($scores as $score)
|
||||
<div>
|
||||
<div class="my-3 border-b">{{ $score->judge->full_name() }}</div>
|
||||
<ul>
|
||||
@foreach($score->subscores as $subscore)
|
||||
<div class="grid grid-cols-2 gap-x-8 border-b">
|
||||
<span>{{ $subscore['subscore_name'] }}</span>
|
||||
<span>{{ $subscore['score'] }}</span>
|
||||
</div>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
<div class="pb-5 pl-5 flex gap-1">
|
||||
<x-form.checkbox name="confirm" x-model="showButton" /> I understand that marking this entry as a no-show will delete existing scores. The scores cannot be recovered.
|
||||
</div>
|
||||
</x-card.card>
|
||||
@endif
|
||||
<x-card.card class="mx-auto max-w-md" x-show="showButton" x-cloak>
|
||||
<x-card.heading>{{ $cardHeading }}</x-card.heading>
|
||||
<x-card.list.body>
|
||||
<x-card.list.row>
|
||||
{{ $entry->student->full_name() }}
|
||||
<x-card.list.row-text-subtext>{{$entry->school->name}}</x-card.list.row-text-subtext>
|
||||
</x-card.list.row>
|
||||
<x-card.list.row>
|
||||
{{ $entry->audition->name }} #{{ $entry->draw_number ?? ' no draw number' }}
|
||||
</x-card.list.row>
|
||||
</x-card.list.body>
|
||||
<x-form.footer class="mb-4">
|
||||
<x-form.form method="{{ $method }}" action="{{route($submitRouteName, $entry)}}" id="{{ $formId }}">
|
||||
<x-form.button type="submit" >{{ $buttonName }}</x-form.button>
|
||||
</x-form.form>
|
||||
</x-form.footer>
|
||||
</x-card.card>
|
||||
</x-layout.app>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<div class="flex items-center">
|
||||
<label class="'relative inline-flex items-center cursor-pointer'">{{ $slot }}
|
||||
<input type="checkbox" x-model="toggle" name="{{ $name }}" class="sr-only" {{ $checked ? 'checked':''}} value="1" >
|
||||
<div :class="toggle ? 'bg-indigo-600' : 'bg-gray-200'" class="w-11 h-6 rounded-full transition-colors duration-300"></div>
|
||||
<div :class="toggle ? 'translate-x-6' : 'translate-x-1'" class="absolute left-1 top-1 bg-white w-4 h-4 rounded-full transition-transform duration-300"></div>
|
||||
</label>
|
||||
|
|
@ -14,6 +14,14 @@ Route::middleware(['auth', 'verified', CheckIfCanTab::class])->group(function ()
|
|||
Route::delete('/{score}', [\App\Http\Controllers\Tabulation\ScoreController::class, 'destroyScore'])->name('scores.destroy');
|
||||
});
|
||||
|
||||
// Entry Flagging
|
||||
Route::prefix('entry-flags/')->controller(\App\Http\Controllers\Tabulation\EntryFlagController::class)->group(function () {
|
||||
Route::get('/choose_no_show', 'noShowSelect')->name('entry-flags.noShowSelect');
|
||||
Route::get('/propose-no-show', 'noShowConfirm')->name('entry-flags.confirmNoShow');
|
||||
Route::post('/no-show/{entry}', 'enterNoShow')->name('entry-flags.enterNoShow');
|
||||
Route::delete('/no-show/{entry}', 'undoNoShow')->name('entry-flags.undoNoShow');
|
||||
});
|
||||
|
||||
// Generic Tabulation Routes
|
||||
Route::prefix('tabulation/')->controller(\App\Http\Controllers\Tabulation\TabulationController::class)->group(function () {
|
||||
Route::get('/status', 'status')->name('tabulation.status');
|
||||
|
|
|
|||
|
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Audition;
|
||||
use App\Models\Entry;
|
||||
use App\Models\Room;
|
||||
use App\Models\ScoringGuide;
|
||||
use App\Models\SubscoreDefinition;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Sinnbeck\DomAssertions\Asserts\AssertForm;
|
||||
|
||||
use function Pest\Laravel\get;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
it('only allows an admin or tab user to confirm a no-show', function () {
|
||||
$entry = Entry::factory()->create();
|
||||
get(route('entry-flags.confirmNoShow', ['entry_id' => $entry->id]))
|
||||
->assertRedirect(route('home'));
|
||||
actAsNormal();
|
||||
get(route('entry-flags.confirmNoShow', ['entry_id' => $entry->id]))
|
||||
->assertRedirect(route('dashboard'))
|
||||
->assertSessionHas('error', 'You are not authorized to perform this action');
|
||||
actAsTab();
|
||||
get(route('entry-flags.confirmNoShow', ['entry_id' => $entry->id]))
|
||||
->assertOk();
|
||||
actAsAdmin();
|
||||
get(route('entry-flags.confirmNoShow', ['entry_id' => $entry->id]))
|
||||
->assertOk();
|
||||
});
|
||||
it('will not work with an entry if it is in a published audition', function () {
|
||||
$entry1 = Entry::factory()->create();
|
||||
$entry2 = Entry::factory()->create();
|
||||
$entry1->audition->addFlag('seats_published');
|
||||
$entry2->audition->addFlag('advance_published');
|
||||
actAsTab();
|
||||
get(route('entry-flags.confirmNoShow', ['entry_id' => $entry1->id]))
|
||||
->assertRedirect(route('entry-flags.noShowSelect'))
|
||||
->assertSessionHas('error', 'Cannot enter a no-show for an entry in an audition where seats are published');
|
||||
get(route('entry-flags.confirmNoShow', ['entry_id' => $entry2->id]))
|
||||
->assertRedirect(route('entry-flags.noShowSelect'))
|
||||
->assertSessionHas('error', 'Cannot enter a no-show for an entry in an audition where advancement is published');
|
||||
});
|
||||
it('has information for the requested entry', function () {
|
||||
// Arrange
|
||||
$entry = Entry::factory()->create();
|
||||
// Act & Assert
|
||||
actAsTab();
|
||||
get(route('entry-flags.confirmNoShow', ['entry_id' => $entry->id]))
|
||||
->assertOk()
|
||||
->assertSee($entry->student->full_name())
|
||||
->assertSee($entry->audition->name)
|
||||
->assertSee($entry->student->school->name)
|
||||
->assertSee($entry->draw_number);
|
||||
});
|
||||
it('posts to entry-flags.enterNoShow and has a submit button', function () {
|
||||
// Arrange
|
||||
$entry = Entry::factory()->create();
|
||||
// Act & Assert
|
||||
actAsTab();
|
||||
get(route('entry-flags.confirmNoShow', ['entry_id' => $entry->id]))
|
||||
->assertOk()
|
||||
->assertFormExists('#no-show-confirmation-form', function (AssertForm $form) use ($entry) {
|
||||
$form->hasMethod('POST')
|
||||
->hasAction(route('entry-flags.enterNoShow', ['entry' => $entry->id]))
|
||||
->contains('button', ['type' => 'submit'])
|
||||
->hasCSRF();
|
||||
});
|
||||
});
|
||||
it('posts to entry-flags.undoNoShow and has a remove button if the entry is already a noshow', function () {
|
||||
// Arrange
|
||||
$entry = Entry::factory()->create();
|
||||
$entry->addFlag('no_show');
|
||||
// Act & Assert
|
||||
actAsTab();
|
||||
get(route('entry-flags.confirmNoShow', ['entry_id' => $entry->id]))
|
||||
->assertOk()
|
||||
->assertFormExists('#no-show-cancellation-form', function (AssertForm $form) use ($entry) {
|
||||
$form->hasMethod('POST')
|
||||
->hasAction(route('entry-flags.undoNoShow', ['entry' => $entry->id]))
|
||||
->contains('button', ['type' => 'submit'])
|
||||
->hasCSRF();
|
||||
});
|
||||
});
|
||||
it('shows a box with scores if the entry is scored', function () {
|
||||
// Arrange
|
||||
$judges = User::factory()->count(3)->create();
|
||||
$room = Room::factory()->create();
|
||||
$judges->each(fn($judge) => $room->addJudge($judge->id));
|
||||
$scoringGuide = ScoringGuide::factory()->create();
|
||||
SubscoreDefinition::factory()->count(5)->create(['scoring_guide_id' => $scoringGuide->id]);
|
||||
$audition = Audition::factory()->create(['room_id' => $room->id, 'scoring_guide_id' => $scoringGuide->id]);
|
||||
$entry = Entry::factory()->create(['audition_id' => $audition->id]);
|
||||
// Run the ScoreAllAuditions seeder
|
||||
Artisan::call('db:seed', ['--class' => 'ScoreAllAuditions']);
|
||||
// Act & Assert
|
||||
actAsTab();
|
||||
$response = get(route('entry-flags.confirmNoShow', ['entry_id' => $entry->id]));
|
||||
$response->assertOk()
|
||||
->assertSee('WARNING')
|
||||
->assertSee('existing scores');
|
||||
$judges->each(fn($judge) => $response->assertSee($judge->full_name()));
|
||||
|
||||
});
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Entry;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
use function Pest\Laravel\post;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
it('only allows an admin or tab user to enter a no-show', function () {
|
||||
$entry = Entry::factory()->create();
|
||||
post(route('entry-flags.enterNoShow', $entry))
|
||||
->assertRedirect(route('home'));
|
||||
actAsAdmin();
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
post(route('entry-flags.enterNoShow', $entry))
|
||||
->assertSessionHasNoErrors()
|
||||
->assertSessionHas('success',
|
||||
'No Show has been entered for '.$entry->audition->name.' #'.$entry->draw_number.' (ID: '.$entry->id.').')
|
||||
->assertRedirect(route('entry-flags.noShowSelect'));
|
||||
actAsTab();
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
post(route('entry-flags.enterNoShow', $entry))
|
||||
->assertSessionHasNoErrors()
|
||||
->assertSessionHas('success',
|
||||
'No Show has been entered for '.$entry->audition->name.' #'.$entry->draw_number.' (ID: '.$entry->id.').')
|
||||
->assertRedirect(route('entry-flags.noShowSelect'));
|
||||
});
|
||||
it('will not record an entry in a published audition as a no show', function () {
|
||||
$entry1 = Entry::factory()->create();
|
||||
$entry2 = Entry::factory()->create();
|
||||
$entry1->audition->addFlag('seats_published');
|
||||
$entry2->audition->addFlag('advance_published');
|
||||
actAsAdmin();
|
||||
post(route('entry-flags.enterNoShow', $entry1))
|
||||
->assertRedirect(route('entry-flags.noShowSelect'))
|
||||
->assertSessionHas('error', 'Cannot enter a no-show for an entry in an audition where seats are published');
|
||||
post(route('entry-flags.enterNoShow', $entry2))
|
||||
->assertRedirect(route('entry-flags.noShowSelect'))
|
||||
->assertSessionHas('error',
|
||||
'Cannot enter a no-show for an entry in an audition where advancement is published');
|
||||
});
|
||||
it('deletes all scores for an entry when a no-show is entered', function () {
|
||||
$entry = Entry::factory()->create();
|
||||
$judges = User::factory()->count(3)->create();
|
||||
$entry->scoreSheets()->create(['user_id' => $judges[0]->id, 'subscores' => 10]);
|
||||
$entry->scoreSheets()->create(['user_id' => $judges[1]->id, 'subscores' => 10]);
|
||||
$entry->scoreSheets()->create(['user_id' => $judges[2]->id, 'subscores' => 10]);
|
||||
expect($entry->scoreSheets()->count())->toBe(3);
|
||||
actAsAdmin();
|
||||
post(route('entry-flags.enterNoShow', $entry));
|
||||
expect($entry->scoreSheets()->count())->toBe(0);
|
||||
});
|
||||
it('adds a no_show flag to the entry', function () {
|
||||
// Arrange
|
||||
$entry = Entry::factory()->create();
|
||||
// Act & Assert
|
||||
actAsAdmin();
|
||||
post(route('entry-flags.enterNoShow', $entry));
|
||||
expect(Entry::find($entry->id)->hasFlag('no_show'))->toBeTrue();
|
||||
});
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Sinnbeck\DomAssertions\Asserts\AssertElement;
|
||||
use Sinnbeck\DomAssertions\Asserts\AssertForm;
|
||||
|
||||
use function Pest\Laravel\get;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
it('responds to only admin and tab users', function () {
|
||||
get(route('entry-flags.noShowSelect'))
|
||||
->assertRedirect(route('home'));
|
||||
actAsAdmin();
|
||||
get(route('entry-flags.noShowSelect'))
|
||||
->assertOk();
|
||||
actAsTab();
|
||||
get(route('entry-flags.noShowSelect'))
|
||||
->assertOk();
|
||||
actAsNormal();
|
||||
get(route('entry-flags.noShowSelect'))
|
||||
->assertRedirect(route('dashboard'))
|
||||
->assertSessionHas('error', 'You are not authorized to perform this action');
|
||||
});
|
||||
it('has an input for entry_id', function () {
|
||||
actAsAdmin();
|
||||
get(route('entry-flags.noShowSelect'))
|
||||
->assertOk()
|
||||
->assertElementExists('#entry_id', function (AssertElement $element) {
|
||||
$element->is('input');
|
||||
});
|
||||
});
|
||||
it('submits to entry-flags.confirmNoShow', function () {
|
||||
actAsAdmin();
|
||||
get(route('entry-flags.noShowSelect'))
|
||||
->assertOk()
|
||||
->assertFormExists('#entry-select-form', function (AssertForm $form) {
|
||||
$form->hasMethod('GET')
|
||||
->hasAction(route('entry-flags.confirmNoShow'));
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Entry;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
use function Pest\Laravel\delete;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
it('only allows an admin or tab user to undo a no-show', function () {
|
||||
$entry = Entry::factory()->create();
|
||||
$entry->addFlag('no_show');
|
||||
delete(route('entry-flags.undoNoShow', $entry))
|
||||
->assertRedirect(route('home'));
|
||||
actAsAdmin();
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
delete(route('entry-flags.undoNoShow', $entry))
|
||||
->assertSessionHasNoErrors()
|
||||
->assertSessionHas('success',
|
||||
'No Show status has been removed for '.$entry->audition->name.' #'.$entry->draw_number.' (ID: '.$entry->id.').')
|
||||
->assertRedirect(route('entry-flags.noShowSelect'));
|
||||
actAsTab();
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
delete(route('entry-flags.undoNoShow', $entry))
|
||||
->assertSessionHasNoErrors()
|
||||
->assertSessionHas('success',
|
||||
'No Show status has been removed for '.$entry->audition->name.' #'.$entry->draw_number.' (ID: '.$entry->id.').')
|
||||
->assertRedirect(route('entry-flags.noShowSelect'));
|
||||
});
|
||||
it('will not undo a no-show flag for an entry in a published audition', function () {
|
||||
$entry1 = Entry::factory()->create();
|
||||
$entry2 = Entry::factory()->create();
|
||||
$entry1->addFlag('no_show');
|
||||
$entry2->addFlag('no_show');
|
||||
$entry1->audition->addFlag('seats_published');
|
||||
$entry2->audition->addFlag('advance_published');
|
||||
actAsAdmin();
|
||||
delete(route('entry-flags.undoNoShow', $entry1))
|
||||
->assertRedirect(route('entry-flags.noShowSelect'))
|
||||
->assertSessionHas('error', 'Cannot undo a no-show for an entry in an audition where seats are published');
|
||||
delete(route('entry-flags.undoNoShow', $entry2))
|
||||
->assertRedirect(route('entry-flags.noShowSelect'))
|
||||
->assertSessionHas('error',
|
||||
'Cannot undo a no-show for an entry in an audition where advancement is published');
|
||||
});
|
||||
|
||||
it('removes a no_show flag to the entry', function () {
|
||||
// Arrange
|
||||
$entry = Entry::factory()->create();
|
||||
$entry->addFlag('no_show');
|
||||
// Act & Assert
|
||||
actAsAdmin();
|
||||
delete(route('entry-flags.undoNoShow', $entry));
|
||||
expect(Entry::find($entry->id)->hasFlag('no_show'))->toBeFalse();
|
||||
});
|
||||
Loading…
Reference in New Issue