first&last
This commit is contained in:
@@ -0,0 +1 @@
|
||||
*.sqlite*
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Enums\UserRole;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
|
||||
*/
|
||||
class UserFactory extends Factory
|
||||
{
|
||||
protected static ?string $password;
|
||||
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'name' => fake()->name(),
|
||||
'email' => fake()->unique()->safeEmail(),
|
||||
'email_verified_at' => now(),
|
||||
'password' => static::$password ??= Hash::make('password'),
|
||||
'role' => fake()->randomElement(UserRole::cases())->value,
|
||||
'phone' => '+7'.fake()->numerify('9#########'),
|
||||
'is_active' => true,
|
||||
'remember_token' => Str::random(10),
|
||||
];
|
||||
}
|
||||
|
||||
public function unverified(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'email_verified_at' => null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
use App\Enums\UserRole;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('users', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('email')->unique();
|
||||
$table->timestamp('email_verified_at')->nullable();
|
||||
$table->string('password');
|
||||
$table->string('role')->default(UserRole::CLIENT->value)->index();
|
||||
$table->string('phone', 32)->nullable();
|
||||
$table->string('avatar')->nullable();
|
||||
$table->unsignedBigInteger('department_id')->nullable()->index();
|
||||
$table->boolean('is_active')->default(true)->index();
|
||||
$table->timestamp('last_login_at')->nullable();
|
||||
$table->rememberToken();
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('users');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('password_reset_tokens', function (Blueprint $table) {
|
||||
$table->string('email')->primary();
|
||||
$table->string('token');
|
||||
$table->timestamp('created_at')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('password_reset_tokens');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('failed_jobs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('uuid')->unique();
|
||||
$table->text('connection');
|
||||
$table->text('queue');
|
||||
$table->longText('payload');
|
||||
$table->longText('exception');
|
||||
$table->timestamp('failed_at')->useCurrent();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('failed_jobs');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('personal_access_tokens', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->morphs('tokenable');
|
||||
$table->string('name');
|
||||
$table->string('token', 64)->unique();
|
||||
$table->text('abilities')->nullable();
|
||||
$table->timestamp('last_used_at')->nullable();
|
||||
$table->timestamp('expires_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('personal_access_tokens');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('departments', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name')->unique();
|
||||
$table->text('description')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('departments');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->foreign('department_id')
|
||||
->references('id')
|
||||
->on('departments')
|
||||
->nullOnDelete()
|
||||
->cascadeOnUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropForeign(['department_id']);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('equipment_categories', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('slug')->unique();
|
||||
$table->text('description')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('equipment_categories');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
use App\Enums\EquipmentCondition;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('equipment', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('serial_number')->unique();
|
||||
$table->string('inventory_number')->unique();
|
||||
$table->foreignId('category_id')
|
||||
->constrained('equipment_categories')
|
||||
->cascadeOnUpdate()
|
||||
->restrictOnDelete();
|
||||
$table->foreignId('client_id')
|
||||
->nullable()
|
||||
->constrained('users')
|
||||
->nullOnDelete()
|
||||
->cascadeOnUpdate();
|
||||
$table->date('purchase_date')->nullable();
|
||||
$table->date('warranty_until')->nullable();
|
||||
$table->string('condition')->default(EquipmentCondition::GOOD->value)->index();
|
||||
$table->text('notes')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['client_id', 'category_id']);
|
||||
$table->index('warranty_until');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('equipment');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('request_types', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name')->unique();
|
||||
$table->text('description')->nullable();
|
||||
$table->unsignedInteger('sla_hours')->default(24);
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('request_types');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('priorities', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('color_hex', 7);
|
||||
$table->unsignedTinyInteger('level')->unique();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index('level');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('priorities');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('statuses', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('color_hex', 7);
|
||||
$table->string('slug')->unique();
|
||||
$table->boolean('is_final')->default(false);
|
||||
$table->unsignedSmallInteger('sort_order')->default(0);
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['sort_order', 'is_final']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('statuses');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('requests', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('ticket_number')->unique();
|
||||
$table->string('title');
|
||||
$table->text('description');
|
||||
$table->foreignId('type_id')
|
||||
->constrained('request_types')
|
||||
->cascadeOnUpdate()
|
||||
->restrictOnDelete();
|
||||
$table->foreignId('priority_id')
|
||||
->constrained('priorities')
|
||||
->cascadeOnUpdate()
|
||||
->restrictOnDelete();
|
||||
$table->foreignId('status_id')
|
||||
->constrained('statuses')
|
||||
->cascadeOnUpdate()
|
||||
->restrictOnDelete();
|
||||
$table->foreignId('client_id')
|
||||
->constrained('users')
|
||||
->cascadeOnUpdate()
|
||||
->restrictOnDelete();
|
||||
$table->foreignId('assigned_to')
|
||||
->nullable()
|
||||
->constrained('users')
|
||||
->nullOnDelete()
|
||||
->cascadeOnUpdate();
|
||||
$table->foreignId('equipment_id')
|
||||
->nullable()
|
||||
->constrained('equipment')
|
||||
->nullOnDelete()
|
||||
->cascadeOnUpdate();
|
||||
$table->string('location')->nullable();
|
||||
$table->dateTime('planned_at')->nullable();
|
||||
$table->dateTime('deadline_at')->nullable();
|
||||
$table->dateTime('started_at')->nullable();
|
||||
$table->dateTime('completed_at')->nullable();
|
||||
$table->text('resolution_notes')->nullable();
|
||||
$table->unsignedTinyInteger('client_rating')->nullable();
|
||||
$table->text('client_comment')->nullable();
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
$table->index('type_id');
|
||||
$table->index('priority_id');
|
||||
$table->index('status_id');
|
||||
$table->index('client_id');
|
||||
$table->index('assigned_to');
|
||||
$table->index('equipment_id');
|
||||
$table->index('deadline_at');
|
||||
$table->index('created_at');
|
||||
$table->index(['status_id', 'deadline_at']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('requests');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('request_comments', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('request_id')
|
||||
->constrained('requests')
|
||||
->cascadeOnDelete()
|
||||
->cascadeOnUpdate();
|
||||
$table->foreignId('user_id')
|
||||
->constrained('users')
|
||||
->cascadeOnDelete()
|
||||
->cascadeOnUpdate();
|
||||
$table->text('body');
|
||||
$table->boolean('is_internal')->default(false)->index();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('request_comments');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('request_attachments', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('request_id')
|
||||
->constrained('requests')
|
||||
->cascadeOnDelete()
|
||||
->cascadeOnUpdate();
|
||||
$table->foreignId('user_id')
|
||||
->nullable()
|
||||
->constrained('users')
|
||||
->nullOnDelete()
|
||||
->cascadeOnUpdate();
|
||||
$table->string('filename');
|
||||
$table->string('path');
|
||||
$table->unsignedBigInteger('size');
|
||||
$table->timestamps();
|
||||
|
||||
$table->index('created_at');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('request_attachments');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('activity_logs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')
|
||||
->nullable()
|
||||
->constrained('users')
|
||||
->nullOnDelete()
|
||||
->cascadeOnUpdate();
|
||||
$table->string('model_type');
|
||||
$table->unsignedBigInteger('model_id');
|
||||
$table->string('action');
|
||||
$table->text('description')->nullable();
|
||||
$table->string('ip_address', 45)->nullable();
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
|
||||
$table->index(['model_type', 'model_id']);
|
||||
$table->index('action');
|
||||
$table->index('created_at');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('activity_logs');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('notifications', function (Blueprint $table) {
|
||||
$table->uuid('id')->primary();
|
||||
$table->string('type');
|
||||
$table->morphs('notifiable');
|
||||
$table->text('data');
|
||||
$table->timestamp('read_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('notifications');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('settings', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('key')->unique();
|
||||
$table->longText('value')->nullable();
|
||||
$table->string('type')->default('string');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('settings');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('jobs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('queue')->index();
|
||||
$table->longText('payload');
|
||||
$table->unsignedTinyInteger('attempts');
|
||||
$table->unsignedInteger('reserved_at')->nullable();
|
||||
$table->unsignedInteger('available_at');
|
||||
$table->unsignedInteger('created_at');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('jobs');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('job_batches', function (Blueprint $table) {
|
||||
$table->string('id')->primary();
|
||||
$table->string('name');
|
||||
$table->integer('total_jobs');
|
||||
$table->integer('pending_jobs');
|
||||
$table->integer('failed_jobs');
|
||||
$table->longText('failed_job_ids');
|
||||
$table->mediumText('options')->nullable();
|
||||
$table->integer('cancelled_at')->nullable();
|
||||
$table->integer('created_at');
|
||||
$table->integer('finished_at')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('job_batches');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('cache', function (Blueprint $table) {
|
||||
$table->string('key')->primary();
|
||||
$table->mediumText('value');
|
||||
$table->integer('expiration');
|
||||
});
|
||||
|
||||
Schema::create('cache_locks', function (Blueprint $table) {
|
||||
$table->string('key')->primary();
|
||||
$table->string('owner');
|
||||
$table->integer('expiration');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('cache');
|
||||
Schema::dropIfExists('cache_locks');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\ActivityLog;
|
||||
use App\Models\ServiceRequest;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class ActivityLogSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$users = User::query()->get();
|
||||
$requests = ServiceRequest::query()->latest()->limit(10)->get();
|
||||
|
||||
foreach ($requests as $request) {
|
||||
ActivityLog::query()->create([
|
||||
'user_id' => $users->random()->id,
|
||||
'model_type' => ServiceRequest::class,
|
||||
'model_id' => $request->id,
|
||||
'action' => fake()->randomElement(['updated', 'assigned', 'status_changed']),
|
||||
'description' => fake()->sentence(),
|
||||
'ip_address' => '127.0.0.1',
|
||||
'created_at' => now()->subHours(rand(1, 72)),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class DatabaseSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$this->call([
|
||||
DepartmentSeeder::class,
|
||||
EquipmentCategorySeeder::class,
|
||||
RequestTypeSeeder::class,
|
||||
PrioritySeeder::class,
|
||||
StatusSeeder::class,
|
||||
UserSeeder::class,
|
||||
EquipmentSeeder::class,
|
||||
ServiceRequestSeeder::class,
|
||||
ActivityLogSeeder::class,
|
||||
SettingSeeder::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Department;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class DepartmentSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$departments = [
|
||||
['name' => 'Сервисный отдел', 'description' => 'Ремонт, диагностика и обслуживание оборудования.'],
|
||||
['name' => 'IT Helpdesk', 'description' => 'Поддержка пользователей и обработка обращений.'],
|
||||
];
|
||||
|
||||
foreach ($departments as $department) {
|
||||
Department::query()->updateOrCreate(
|
||||
['name' => $department['name']],
|
||||
$department
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\EquipmentCategory;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class EquipmentCategorySeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$categories = [
|
||||
['name' => 'Ноутбуки', 'description' => 'Мобильные рабочие станции и ноутбуки.'],
|
||||
['name' => 'Настольные ПК', 'description' => 'Офисные персональные компьютеры.'],
|
||||
['name' => 'Сетевое оборудование', 'description' => 'Роутеры, коммутаторы, точки доступа.'],
|
||||
['name' => 'Принтеры и МФУ', 'description' => 'Печатная техника и многофункциональные устройства.'],
|
||||
];
|
||||
|
||||
foreach ($categories as $category) {
|
||||
EquipmentCategory::query()->updateOrCreate(
|
||||
['slug' => Str::slug($category['name'])],
|
||||
[
|
||||
'name' => $category['name'],
|
||||
'slug' => Str::slug($category['name']),
|
||||
'description' => $category['description'],
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Enums\EquipmentCondition;
|
||||
use App\Enums\UserRole;
|
||||
use App\Models\Equipment;
|
||||
use App\Models\EquipmentCategory;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class EquipmentSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$categories = EquipmentCategory::query()->get();
|
||||
$clients = User::query()->where('role', UserRole::CLIENT)->get();
|
||||
|
||||
for ($i = 1; $i <= 10; $i++) {
|
||||
$category = $categories->random();
|
||||
$client = $clients->random();
|
||||
|
||||
Equipment::query()->updateOrCreate(
|
||||
['inventory_number' => sprintf('INV-%04d', $i)],
|
||||
[
|
||||
'name' => fake()->randomElement([
|
||||
'Ноутбук Dell Latitude',
|
||||
'HP ProDesk',
|
||||
'Cisco Router',
|
||||
'Brother MFC Printer',
|
||||
'Lenovo ThinkPad',
|
||||
]).' '.$i,
|
||||
'serial_number' => sprintf('SN-%08d', 10000000 + $i),
|
||||
'category_id' => $category->id,
|
||||
'client_id' => $client->id,
|
||||
'purchase_date' => now()->subMonths(rand(6, 48))->toDateString(),
|
||||
'warranty_until' => now()->addDays(rand(-90, 365))->toDateString(),
|
||||
'condition' => fake()->randomElement(EquipmentCondition::cases())->value,
|
||||
'notes' => fake()->sentence(),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Priority;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class PrioritySeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$priorities = [
|
||||
['name' => 'Низкий', 'color_hex' => '#10B981', 'level' => 1],
|
||||
['name' => 'Средний', 'color_hex' => '#3B82F6', 'level' => 2],
|
||||
['name' => 'Высокий', 'color_hex' => '#F59E0B', 'level' => 3],
|
||||
['name' => 'Критический', 'color_hex' => '#EF4444', 'level' => 4],
|
||||
];
|
||||
|
||||
foreach ($priorities as $priority) {
|
||||
Priority::query()->updateOrCreate(['level' => $priority['level']], $priority);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\RequestType;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class RequestTypeSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$types = [
|
||||
['name' => 'Диагностика', 'description' => 'Первичная диагностика и выявление неисправности.', 'sla_hours' => 24],
|
||||
['name' => 'Аппаратный ремонт', 'description' => 'Замена или ремонт аппаратных компонентов.', 'sla_hours' => 48],
|
||||
['name' => 'Программная поддержка', 'description' => 'Настройка ОС, ПО, устранение программных ошибок.', 'sla_hours' => 12],
|
||||
['name' => 'Плановое обслуживание', 'description' => 'Профилактические и регламентные работы.', 'sla_hours' => 72],
|
||||
['name' => 'Сетевая проблема', 'description' => 'Проблемы с сетью и доступом к ресурсам.', 'sla_hours' => 8],
|
||||
];
|
||||
|
||||
foreach ($types as $type) {
|
||||
RequestType::query()->updateOrCreate(['name' => $type['name']], $type);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\ActivityLog;
|
||||
use App\Models\Equipment;
|
||||
use App\Models\Priority;
|
||||
use App\Models\RequestComment;
|
||||
use App\Models\RequestType;
|
||||
use App\Models\ServiceRequest;
|
||||
use App\Models\Status;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class ServiceRequestSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$types = RequestType::query()->get();
|
||||
$priorities = Priority::query()->orderBy('level')->get();
|
||||
$statuses = Status::query()->get();
|
||||
$clients = User::query()->where('role', 'client')->get();
|
||||
$techs = User::query()->where('role', 'technician')->get();
|
||||
$equipment = Equipment::query()->get();
|
||||
|
||||
for ($i = 1; $i <= 25; $i++) {
|
||||
$type = $types->random();
|
||||
$priority = $priorities->random();
|
||||
$status = $statuses->random();
|
||||
$client = $clients->random();
|
||||
$assignee = $techs->random();
|
||||
$createdAt = now()->subDays(rand(0, 20))->subHours(rand(0, 23));
|
||||
$deadlineAt = (clone $createdAt)->addHours($type->sla_hours);
|
||||
|
||||
$request = ServiceRequest::query()->create([
|
||||
'ticket_number' => sprintf('SRV-%04d', $i),
|
||||
'title' => fake()->randomElement([
|
||||
'Не включается рабочая станция',
|
||||
'Проблема с печатью документов',
|
||||
'Нет доступа к корпоративной сети',
|
||||
'Требуется установка ПО',
|
||||
'Сильный шум вентилятора',
|
||||
]),
|
||||
'description' => fake()->paragraph(3),
|
||||
'type_id' => $type->id,
|
||||
'priority_id' => $priority->id,
|
||||
'status_id' => $status->id,
|
||||
'client_id' => $client->id,
|
||||
'assigned_to' => $assignee->id,
|
||||
'equipment_id' => rand(0, 100) > 20 ? $equipment->random()?->id : null,
|
||||
'location' => fake()->randomElement(['Офис 101', 'Офис 204', 'Склад', 'Переговорная 2']),
|
||||
'planned_at' => rand(0, 100) > 50 ? $createdAt->copy()->addHours(rand(2, 24)) : null,
|
||||
'deadline_at' => $deadlineAt,
|
||||
'started_at' => rand(0, 100) > 40 ? $createdAt->copy()->addHours(rand(1, 8)) : null,
|
||||
'completed_at' => $status->is_final ? $deadlineAt->copy()->subHours(rand(0, 6)) : null,
|
||||
'resolution_notes' => $status->slug === 'resolved' || $status->slug === 'closed'
|
||||
? fake()->sentence(12)
|
||||
: null,
|
||||
'client_rating' => $status->slug === 'closed' ? rand(3, 5) : null,
|
||||
'client_comment' => $status->slug === 'closed' ? fake()->sentence() : null,
|
||||
'created_at' => $createdAt,
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
for ($commentIndex = 1; $commentIndex <= rand(1, 3); $commentIndex++) {
|
||||
$author = rand(0, 1) ? $client : $assignee;
|
||||
RequestComment::query()->create([
|
||||
'request_id' => $request->id,
|
||||
'user_id' => $author->id,
|
||||
'body' => fake()->sentence(rand(10, 20)),
|
||||
'is_internal' => $author->role !== 'client' && rand(0, 100) > 60,
|
||||
'created_at' => $createdAt->copy()->addHours($commentIndex),
|
||||
'updated_at' => $createdAt->copy()->addHours($commentIndex),
|
||||
]);
|
||||
}
|
||||
|
||||
ActivityLog::query()->create([
|
||||
'user_id' => $assignee->id,
|
||||
'model_type' => ServiceRequest::class,
|
||||
'model_id' => $request->id,
|
||||
'action' => 'created',
|
||||
'description' => "Создана заявка {$request->ticket_number}",
|
||||
'ip_address' => '127.0.0.1',
|
||||
'created_at' => $createdAt,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Setting;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class SettingSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$defaults = [
|
||||
['key' => 'company_name', 'value' => 'Computer Service', 'type' => 'string'],
|
||||
['key' => 'company_logo', 'value' => null, 'type' => 'string'],
|
||||
['key' => 'timezone', 'value' => 'Asia/Yekaterinburg', 'type' => 'string'],
|
||||
['key' => 'default_sla_hours', 'value' => '24', 'type' => 'integer'],
|
||||
['key' => 'maintenance_mode', 'value' => '0', 'type' => 'boolean'],
|
||||
[
|
||||
'key' => 'email_notifications',
|
||||
'value' => json_encode([
|
||||
'assigned' => true,
|
||||
'status_changed' => true,
|
||||
'comment_added' => true,
|
||||
'overdue' => true,
|
||||
'sla_warning' => true,
|
||||
], JSON_THROW_ON_ERROR),
|
||||
'type' => 'json',
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($defaults as $setting) {
|
||||
Setting::query()->updateOrCreate(
|
||||
['key' => $setting['key']],
|
||||
[
|
||||
'value' => $setting['value'],
|
||||
'type' => $setting['type'],
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Enums\StatusSlug;
|
||||
use App\Models\Status;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class StatusSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$statuses = [
|
||||
['name' => 'Новая', 'slug' => StatusSlug::NEW->value, 'color_hex' => '#3B82F6', 'is_final' => false, 'sort_order' => 1],
|
||||
['name' => 'В работе', 'slug' => StatusSlug::IN_PROGRESS->value, 'color_hex' => '#F59E0B', 'is_final' => false, 'sort_order' => 2],
|
||||
['name' => 'Ожидание', 'slug' => StatusSlug::WAITING->value, 'color_hex' => '#6366F1', 'is_final' => false, 'sort_order' => 3],
|
||||
['name' => 'Решена', 'slug' => StatusSlug::RESOLVED->value, 'color_hex' => '#10B981', 'is_final' => false, 'sort_order' => 4],
|
||||
['name' => 'Закрыта', 'slug' => StatusSlug::CLOSED->value, 'color_hex' => '#6B7280', 'is_final' => true, 'sort_order' => 5],
|
||||
['name' => 'Отменена', 'slug' => StatusSlug::CANCELLED->value, 'color_hex' => '#EF4444', 'is_final' => true, 'sort_order' => 6],
|
||||
];
|
||||
|
||||
foreach ($statuses as $status) {
|
||||
Status::query()->updateOrCreate(['slug' => $status['slug']], $status);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Enums\UserRole;
|
||||
use App\Models\Department;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
class UserSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$serviceDepartment = Department::query()->where('name', 'Сервисный отдел')->first();
|
||||
$helpdeskDepartment = Department::query()->where('name', 'IT Helpdesk')->first();
|
||||
|
||||
User::query()->updateOrCreate(
|
||||
['email' => 'admin@service.local'],
|
||||
[
|
||||
'name' => 'Главный администратор',
|
||||
'password' => Hash::make('password'),
|
||||
'role' => UserRole::ADMIN,
|
||||
'phone' => '+79990000001',
|
||||
'department_id' => $helpdeskDepartment?->id,
|
||||
'is_active' => true,
|
||||
'email_verified_at' => now(),
|
||||
]
|
||||
);
|
||||
|
||||
User::query()->updateOrCreate(
|
||||
['email' => 'manager@service.local'],
|
||||
[
|
||||
'name' => 'Сервис-менеджер',
|
||||
'password' => Hash::make('password'),
|
||||
'role' => UserRole::MANAGER,
|
||||
'phone' => '+79990000002',
|
||||
'department_id' => $serviceDepartment?->id,
|
||||
'is_active' => true,
|
||||
'email_verified_at' => now(),
|
||||
]
|
||||
);
|
||||
|
||||
$technicians = [
|
||||
['name' => 'Иван Петров', 'email' => 'tech1@service.local'],
|
||||
['name' => 'Алексей Сидоров', 'email' => 'tech2@service.local'],
|
||||
['name' => 'Ольга Смирнова', 'email' => 'tech3@service.local'],
|
||||
];
|
||||
|
||||
foreach ($technicians as $technician) {
|
||||
User::query()->updateOrCreate(
|
||||
['email' => $technician['email']],
|
||||
[
|
||||
'name' => $technician['name'],
|
||||
'password' => Hash::make('password'),
|
||||
'role' => UserRole::TECHNICIAN,
|
||||
'phone' => '+7999'.fake()->numerify('######'),
|
||||
'department_id' => $serviceDepartment?->id,
|
||||
'is_active' => true,
|
||||
'email_verified_at' => now(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
for ($i = 1; $i <= 5; $i++) {
|
||||
User::query()->updateOrCreate(
|
||||
['email' => "client{$i}@service.local"],
|
||||
[
|
||||
'name' => "Клиент {$i}",
|
||||
'password' => Hash::make('password'),
|
||||
'role' => UserRole::CLIENT,
|
||||
'phone' => '+7991'.str_pad((string) $i, 6, '0', STR_PAD_LEFT),
|
||||
'department_id' => null,
|
||||
'is_active' => true,
|
||||
'email_verified_at' => now(),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user