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')
+
+@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());
+ }
+}