diff --git a/app/Http/Controllers/admin/Catalog/Direction/CostController.php b/app/Http/Controllers/admin/Catalog/Direction/CostController.php new file mode 100644 index 0000000..2c452b8 --- /dev/null +++ b/app/Http/Controllers/admin/Catalog/Direction/CostController.php @@ -0,0 +1,90 @@ +validated(); + + $cost = new Cost(); + $cost->position = $validated['position']; + $cost->description = $validated['description']; + $cost->cost = $validated['cost']; + $cost->education_form_id = $validated['education_form_id']; + $cost->direction_id = $validated['direction_id']; + $cost->save(); + + return redirect()->route('costs.index'); + } + + public function show(Cost $cost): View + { + return view('admin.catalog.direction.cost.show', compact('cost')); + } + + public function edit(Cost $cost): View + { + $directions = Direction::pluck('name', 'id'); + $educationForms = EducationForm::pluck('name', 'id'); + return view( + 'admin.catalog.direction.cost.edit', + compact( + 'cost', + 'directions', + 'educationForms', + ) + ); + } + + public function update(UpdateCostRequest $request, Cost $cost): RedirectResponse + { + $validated = $request->validated(); + + $cost->position = $validated['position']; + $cost->description = $validated['description']; + $cost->cost = $validated['cost']; + $cost->education_form_id = $validated['education_form_id']; + $cost->direction_id = $validated['direction_id']; + $cost->save(); + + return redirect()->route('costs.index'); + } + + public function destroy(Cost $cost): RedirectResponse + { + $cost->delete(); + return redirect()->route('costs.index'); + } +} diff --git a/app/Http/Requests/admin/Catalog/Direction/StoreCostRequest.php b/app/Http/Requests/admin/Catalog/Direction/StoreCostRequest.php new file mode 100644 index 0000000..7a40512 --- /dev/null +++ b/app/Http/Requests/admin/Catalog/Direction/StoreCostRequest.php @@ -0,0 +1,24 @@ + 'required|int|numeric|max:255', + 'description' => 'string', + 'cost' => 'required|int|numeric|max:1000000', + 'education_form_id' => 'required|int|numeric|max:255', + 'direction_id' => 'required|int|numeric|max:255', + ]; + } +} diff --git a/app/Http/Requests/admin/Catalog/Direction/UpdateCostRequest.php b/app/Http/Requests/admin/Catalog/Direction/UpdateCostRequest.php new file mode 100644 index 0000000..9d37a11 --- /dev/null +++ b/app/Http/Requests/admin/Catalog/Direction/UpdateCostRequest.php @@ -0,0 +1,24 @@ + 'required|int|numeric|max:255', + 'description' => 'string', + 'cost' => 'required|int|numeric|max:1000000', + 'education_form_id' => 'required|int|numeric|max:255', + 'direction_id' => 'required|int|numeric|max:255', + ]; + } +} diff --git a/app/Models/Cost.php b/app/Models/Cost.php new file mode 100644 index 0000000..d5db76b --- /dev/null +++ b/app/Models/Cost.php @@ -0,0 +1,32 @@ +belongsTo(Direction::class); + } + + public function educationForm(): BelongsTo + { + return $this->belongsTo(EducationForm::class); + } +} diff --git a/app/Models/Direction.php b/app/Models/Direction.php index f6db97f..05b57e8 100644 --- a/app/Models/Direction.php +++ b/app/Models/Direction.php @@ -44,4 +44,9 @@ class Direction extends Model { return $this->hasMany('App\Models\Place', 'direction_id'); } + + public function costs(): HasMany + { + return $this->hasMany('App\Models\Cost', 'direction_id'); + } } diff --git a/app/Models/EducationForm.php b/app/Models/EducationForm.php index 0c1fa1f..d243076 100644 --- a/app/Models/EducationForm.php +++ b/app/Models/EducationForm.php @@ -26,4 +26,9 @@ class EducationForm extends Model { return $this->hasMany('App\Models\Place', 'education_form_id'); } + + public function costs(): HasMany + { + return $this->hasMany('App\Models\Cost', 'education_form_id'); + } } diff --git a/database/factories/CostFactory.php b/database/factories/CostFactory.php new file mode 100644 index 0000000..611d6d7 --- /dev/null +++ b/database/factories/CostFactory.php @@ -0,0 +1,19 @@ + 1, + 'description' => fake()->text(), + 'cost' => fake()->randomDigit(), + 'education_form_id' => 1, + 'direction_id' => 1, + ]; + } +} diff --git a/database/migrations/2024_02_26_055033_create_costs_table.php b/database/migrations/2024_02_26_055033_create_costs_table.php new file mode 100644 index 0000000..b00033d --- /dev/null +++ b/database/migrations/2024_02_26_055033_create_costs_table.php @@ -0,0 +1,32 @@ +id(); + $table->integer('position'); + $table->integer('cost'); + $table->foreignId('education_form_id')->constrained('education_forms'); + $table->foreignId('direction_id')->constrained('directions'); + $table->text('description')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('costs'); + } +}; diff --git a/database/seeders/CostSeeder.php b/database/seeders/CostSeeder.php new file mode 100644 index 0000000..bf2de4a --- /dev/null +++ b/database/seeders/CostSeeder.php @@ -0,0 +1,30 @@ +insert([ + [ + 'position' => 1, + 'cost' => 103000, + 'education_form_id' => 1, + 'direction_id' => 1, + 'description' => 'стоимость обучения 103 000 руб', + ], + [ + 'position' => 2, + 'cost' => 42000, + 'education_form_id' => 2, + 'direction_id' => 1, + 'description' => 'стоимость обучения 42 000 руб', + ], + ]); + } +} diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 62dc513..c61277f 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -34,6 +34,7 @@ class DatabaseSeeder extends Seeder EntranceExaminationSeeder::class, PlaceTypeSeeder::class, PlaceSeeder::class, + CostSeeder::class, ]); $this->call([ diff --git a/resources/views/admin/catalog/direction/cost/create.blade.php b/resources/views/admin/catalog/direction/cost/create.blade.php new file mode 100644 index 0000000..d3c0e4b --- /dev/null +++ b/resources/views/admin/catalog/direction/cost/create.blade.php @@ -0,0 +1,79 @@ +@extends('layouts.admin_layout') +@section('content') + @auth() +
+
+

Создать стоимость

+ {{ Form::open(['url' => route('costs.store'), 'method' => 'POST', 'class' => '']) }} +
+ +
+ {{ Form::label('position', 'Позиция') }} +
+
+ {{ Form::text('position', '', ['class' => 'form-control']) }} +
+
+ @if ($errors->any()) + {{ $errors->first('position') }} + @endif +
+ +
+ {{ Form::label('description', 'Описание') }} +
+
+ {{ Form::text('description', '', ['class' => 'form-control']) }} +
+
+ @if ($errors->any()) + {{ $errors->first('description') }} + @endif +
+ +
+ {{ Form::label('cost', 'стоимость') }} +
+
+ {{ Form::text('cost', '', ['class' => 'form-control']) }} +
+
+ @if ($errors->any()) + {{ $errors->first('cost') }} + @endif +
+ +
+ {{ Form::label('direction_id', 'Направление подготовки') }} +
+
+ {{ Form::select('direction_id', $directions, null, ['class' => 'form-select']) }} +
+
+ @if ($errors->any()) + {{ $errors->first('direction_id') }} + @endif +
+ +
+ {{ Form::label('education_form_id', 'Форма обучения') }} +
+
+ {{ Form::select('education_form_id', $educationForms, null, ['class' => 'form-select']) }} +
+
+ @if ($errors->any()) + {{ $errors->first('education_form_id') }} + @endif +
+ + +
+ {{ Form::submit('Создать', ['class' => 'btn btn-primary']) }} +
+
+ {{ Form::close() }} +
+
+ @endauth +@endsection diff --git a/resources/views/admin/catalog/direction/cost/edit.blade.php b/resources/views/admin/catalog/direction/cost/edit.blade.php new file mode 100644 index 0000000..b25ea6e --- /dev/null +++ b/resources/views/admin/catalog/direction/cost/edit.blade.php @@ -0,0 +1,79 @@ +@extends('layouts.admin_layout') +@section('content') + @auth() +
+
+

Изменить Стоимость

+ {{ Form::open(['url' => route('costs.update', $cost), 'method' => 'PATCH', 'class' => '']) }} +
+ +
+ {{ Form::label('position', 'Позиция') }} +
+
+ {{ Form::text('position', $cost->position, ['class' => 'form-control']) }} +
+
+ @if ($errors->any()) + {{ $errors->first('position') }} + @endif +
+ +
+ {{ Form::label('description', 'Описание') }} +
+
+ {{ Form::text('description', $cost->description, ['class' => 'form-control']) }} +
+
+ @if ($errors->any()) + {{ $errors->first('description') }} + @endif +
+ +
+ {{ Form::label('cost', 'Количество мест') }} +
+
+ {{ Form::text('cost', $cost->cost, ['class' => 'form-control']) }} +
+
+ @if ($errors->any()) + {{ $errors->first('cost') }} + @endif +
+ +
+ {{ Form::label('direction_id', 'Направление подготовки') }} +
+
+ {{ Form::select('direction_id', $directions, $cost->direction->id, ['class' => 'form-select']) }} +
+
+ @if ($errors->any()) + {{ $errors->first('direction_id') }} + @endif +
+ +
+ {{ Form::label('education_form_id', 'Форма обучения') }} +
+
+ {{ Form::select('education_form_id', $educationForms, $cost->educationForm->id, ['class' => 'form-select']) }} +
+
+ @if ($errors->any()) + {{ $errors->first('education_form_id') }} + @endif +
+ + +
+ {{ Form::submit('Изменить', ['class' => 'btn btn-primary']) }} +
+
+ {{ Form::close() }} +
+
+ @endauth +@endsection diff --git a/resources/views/admin/catalog/direction/cost/index.blade.php b/resources/views/admin/catalog/direction/cost/index.blade.php new file mode 100644 index 0000000..d158ec6 --- /dev/null +++ b/resources/views/admin/catalog/direction/cost/index.blade.php @@ -0,0 +1,45 @@ +@extends('layouts.admin_layout') +@section('content') +
+

Стоимость

+
+ Создать Стоимость +
+
+ + + + + + + + + + + + + + @foreach($costs as $cost) + + + + + + + + + @endforeach + +
позицияописаниеФорма обучениянаправлениеСтоимостьдействия
{{ $cost->position }}{{ Str::words($cost->description, 10, '...') }}{{ $cost->educationForm->name }}{{ $cost->direction->name }}{{ $cost->cost }} + посмотреть + редактировать + удалить +
+
+
+
+@endsection diff --git a/resources/views/admin/catalog/direction/cost/show.blade.php b/resources/views/admin/catalog/direction/cost/show.blade.php new file mode 100644 index 0000000..cd265db --- /dev/null +++ b/resources/views/admin/catalog/direction/cost/show.blade.php @@ -0,0 +1,17 @@ +@extends('layouts.admin_layout') +@section('content') + @auth() +
+

позиция

+

{{ $cost->position }}

+

описание

+

{{ $cost->description }}

+

Форма обучения

+

{{ $cost->educationForm->name }}

+

Направление

+

{{ $cost->direction->name }}

+

Стоимость

+

{{ $cost->cost }}

+
+ @endauth +@endsection diff --git a/resources/views/admin/catalog/direction/place/edit.blade.php b/resources/views/admin/catalog/direction/place/edit.blade.php index 669dac7..0f070d8 100644 --- a/resources/views/admin/catalog/direction/place/edit.blade.php +++ b/resources/views/admin/catalog/direction/place/edit.blade.php @@ -71,7 +71,7 @@ {{ Form::label('education_form_id', 'Форма обучения') }}
- {{ Form::select('education_form_id', $educationForm, $place->educationForm->id, ['class' => 'form-select']) }} + {{ Form::select('education_form_id', $educationForms, $place->educationForm->id, ['class' => 'form-select']) }}
@if ($errors->any()) diff --git a/resources/views/layouts/admin_layout.blade.php b/resources/views/layouts/admin_layout.blade.php index a3177a3..a758b34 100644 --- a/resources/views/layouts/admin_layout.blade.php +++ b/resources/views/layouts/admin_layout.blade.php @@ -64,6 +64,7 @@
  • Типы Предметов
  • Кол-во Мест
  • Типы Мест
  • +
  • Стоимость об.
  • @yield('content')
    diff --git a/routes/admin.php b/routes/admin.php index 09f359e..3a506ba 100644 --- a/routes/admin.php +++ b/routes/admin.php @@ -2,6 +2,7 @@ use App\Http\Controllers\admin\AdmissionController; use App\Http\Controllers\admin\Catalog\DepartmentController; +use App\Http\Controllers\admin\Catalog\Direction\CostController; use App\Http\Controllers\admin\Catalog\Direction\EducationFormController; use App\Http\Controllers\admin\Catalog\Direction\EducationLevelController; use App\Http\Controllers\admin\Catalog\Direction\EntranceExaminationController; @@ -62,6 +63,7 @@ Route::middleware(['auth', 'verified'])->prefix('admin')->group(function () { ->scoped(['place_type' => 'slug']); Route::resource('/places', PlaceController::class); + Route::resource('/costs', CostController::class); Route::resources([ '/documents' => DocumentController::class, diff --git a/tests/Feature/admin/catalog/direction/CostTest.php b/tests/Feature/admin/catalog/direction/CostTest.php new file mode 100644 index 0000000..d958899 --- /dev/null +++ b/tests/Feature/admin/catalog/direction/CostTest.php @@ -0,0 +1,117 @@ +create(); + Faculty::factory()->create(); + Department::factory()->create(); + EducationLevel::factory()->create(); + EducationForm::factory()->create(); + Direction::factory()->create(); + + $this->cost = Cost::factory()->create(); + + $this->data = Cost::factory()->make()->only([ + 'position', + 'description', + 'cost', + 'education_form_id', + 'direction_id', + ]); + + $this->user = User::factory()->create([ + 'name' => 'admin', + 'email' => 'test@example.com', + 'password' => 123456 + ]); + } + + public function testIndexCostsPage(): void + { + $response = $this->actingAs($this->user) + ->withSession(['banned' => false]) + ->get(route('costs.index')); + + $response->assertOk(); + } + + public function testCreateCostPage(): void + { + $response = $this->actingAs($this->user) + ->withSession(['banned' => false]) + ->get(route('costs.create')); + + $response->assertOk(); + } + + public function testStoreCost(): void + { + $response = $this->actingAs($this->user) + ->withSession(['banned' => false]) + ->post(route('costs.store', $this->data)); + + $response->assertRedirect(route('costs.index')); + + $this->assertDatabaseHas('costs', $this->data); + } + + public function testShowCost(): void + { + $response = $this->actingAs($this->user) + ->withSession(['banned' => false]) + ->get(route('costs.show', $this->cost)); + + $response->assertOk(); + } + + public function testEditCostPage(): void + { + $response = $this->actingAs($this->user) + ->withSession(['banned' => false]) + ->get(route('costs.edit', $this->cost)); + + $response->assertOk(); + } + + public function testUpdateCost(): void + { + $response = $this->actingAs($this->user) + ->withSession(['banned' => false]) + ->patch(route('costs.update', $this->cost), $this->data); + + $response->assertRedirect(route('costs.index')); + + $this->assertDatabaseHas('costs', $this->data); + } + + public function testDestroyCost(): void + { + $response = $this->actingAs($this->user) + ->withSession(['banned' => false]) + ->delete(route('costs.destroy', $this->cost)); + + $response->assertRedirect(route('costs.index')); + + $this->assertDatabaseMissing('costs', $this->cost->toArray()); + } +}