first
This commit is contained in:
1
database/.gitignore
vendored
Normal file
1
database/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.sqlite*
|
||||
46
database/factories/MemberFactory.php
Normal file
46
database/factories/MemberFactory.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Member;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends Factory<Member>
|
||||
*/
|
||||
class MemberFactory extends Factory
|
||||
{
|
||||
protected $model = Member::class;
|
||||
|
||||
public function definition(): array
|
||||
{
|
||||
$jabatan = $this->faker->randomElement([
|
||||
'Khidmat Pengurusan', 'Kewangan', 'Perancangan', 'Kejuruteraan',
|
||||
'Komuniti & Ekonomi', 'Teknologi Maklumat', 'Undang-undang', 'Audit Dalam',
|
||||
'Landskap', 'Penguatkuasaan',
|
||||
]);
|
||||
|
||||
$bahagian = $this->faker->randomElement([
|
||||
'Unit A', 'Unit B', 'Unit C', 'Pentadbiran', 'Operasi', 'Sokongan',
|
||||
]);
|
||||
|
||||
// No KP Malaysia 12 digit: YYMMDD-PB-###G
|
||||
$yy = str_pad((string) $this->faker->numberBetween(60, 99), 2, '0', STR_PAD_LEFT);
|
||||
$mm = str_pad((string) $this->faker->numberBetween(1, 12), 2, '0', STR_PAD_LEFT);
|
||||
$dd = str_pad((string) $this->faker->numberBetween(1, 28), 2, '0', STR_PAD_LEFT);
|
||||
$pb = str_pad((string) $this->faker->numberBetween(1, 14), 2, '0', STR_PAD_LEFT);
|
||||
$serial = str_pad((string) $this->faker->numberBetween(0, 9999), 4, '0', STR_PAD_LEFT);
|
||||
$noKp = "{$yy}{$mm}{$dd}-{$pb}-{$serial}";
|
||||
|
||||
return [
|
||||
'no_anggota' => 'A' . str_pad((string) $this->faker->unique()->numberBetween(1, 99999), 5, '0', STR_PAD_LEFT),
|
||||
'no_pekerja' => 'MBIP' . str_pad((string) $this->faker->unique()->numberBetween(1, 99999), 5, '0', STR_PAD_LEFT),
|
||||
'no_kp' => $noKp,
|
||||
'nama' => $this->faker->name(),
|
||||
'jabatan' => $jabatan,
|
||||
'bahagian' => $bahagian,
|
||||
'telefon' => '01' . $this->faker->numberBetween(0, 9) . '-' . $this->faker->numerify('#######'),
|
||||
'status_aktif' => $this->faker->boolean(95),
|
||||
];
|
||||
}
|
||||
}
|
||||
45
database/factories/UserFactory.php
Normal file
45
database/factories/UserFactory.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* @extends Factory<User>
|
||||
*/
|
||||
class UserFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* The current password being used by the factory.
|
||||
*/
|
||||
protected static ?string $password;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'name' => fake()->name(),
|
||||
'email' => fake()->unique()->safeEmail(),
|
||||
'email_verified_at' => now(),
|
||||
'password' => static::$password ??= Hash::make('password'),
|
||||
'remember_token' => Str::random(10),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the model's email address should be unverified.
|
||||
*/
|
||||
public function unverified(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'email_verified_at' => null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
49
database/migrations/0001_01_01_000000_create_users_table.php
Normal file
49
database/migrations/0001_01_01_000000_create_users_table.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?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('users', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('email')->unique();
|
||||
$table->timestamp('email_verified_at')->nullable();
|
||||
$table->string('password');
|
||||
$table->rememberToken();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('password_reset_tokens', function (Blueprint $table) {
|
||||
$table->string('email')->primary();
|
||||
$table->string('token');
|
||||
$table->timestamp('created_at')->nullable();
|
||||
});
|
||||
|
||||
Schema::create('sessions', function (Blueprint $table) {
|
||||
$table->string('id')->primary();
|
||||
$table->foreignId('user_id')->nullable()->index();
|
||||
$table->string('ip_address', 45)->nullable();
|
||||
$table->text('user_agent')->nullable();
|
||||
$table->longText('payload');
|
||||
$table->integer('last_activity')->index();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('users');
|
||||
Schema::dropIfExists('password_reset_tokens');
|
||||
Schema::dropIfExists('sessions');
|
||||
}
|
||||
};
|
||||
35
database/migrations/0001_01_01_000001_create_cache_table.php
Normal file
35
database/migrations/0001_01_01_000001_create_cache_table.php
Normal file
@@ -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
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('cache', function (Blueprint $table) {
|
||||
$table->string('key')->primary();
|
||||
$table->mediumText('value');
|
||||
$table->bigInteger('expiration')->index();
|
||||
});
|
||||
|
||||
Schema::create('cache_locks', function (Blueprint $table) {
|
||||
$table->string('key')->primary();
|
||||
$table->string('owner');
|
||||
$table->bigInteger('expiration')->index();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('cache');
|
||||
Schema::dropIfExists('cache_locks');
|
||||
}
|
||||
};
|
||||
59
database/migrations/0001_01_01_000002_create_jobs_table.php
Normal file
59
database/migrations/0001_01_01_000002_create_jobs_table.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?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('jobs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('queue')->index();
|
||||
$table->longText('payload');
|
||||
$table->unsignedSmallInteger('attempts');
|
||||
$table->unsignedInteger('reserved_at')->nullable();
|
||||
$table->unsignedInteger('available_at');
|
||||
$table->unsignedInteger('created_at');
|
||||
});
|
||||
|
||||
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();
|
||||
});
|
||||
|
||||
Schema::create('failed_jobs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('uuid')->unique();
|
||||
$table->string('connection');
|
||||
$table->string('queue');
|
||||
$table->longText('payload');
|
||||
$table->longText('exception');
|
||||
$table->timestamp('failed_at')->useCurrent();
|
||||
|
||||
$table->index(['connection', 'queue', 'failed_at']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('jobs');
|
||||
Schema::dropIfExists('job_batches');
|
||||
Schema::dropIfExists('failed_jobs');
|
||||
}
|
||||
};
|
||||
@@ -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('members', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('no_anggota')->nullable()->index();
|
||||
$table->string('no_pekerja')->nullable()->unique();
|
||||
$table->string('no_kp')->nullable()->unique();
|
||||
$table->string('nama')->index();
|
||||
$table->string('jabatan')->nullable();
|
||||
$table->string('bahagian')->nullable();
|
||||
$table->string('telefon')->nullable();
|
||||
$table->boolean('status_aktif')->default(true);
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['jabatan', 'bahagian']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('members');
|
||||
}
|
||||
};
|
||||
@@ -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('attendance_records', function (Blueprint $table) {
|
||||
$table->id();
|
||||
// Satu rekod kehadiran sahaja bagi setiap anggota (elak double attendance)
|
||||
$table->foreignId('member_id')->unique()->constrained('members')->cascadeOnDelete();
|
||||
$table->timestamp('attended_at')->useCurrent();
|
||||
$table->foreignId('recorded_by')->nullable()->constrained('users')->nullOnDelete();
|
||||
$table->string('ip_address', 45)->nullable();
|
||||
$table->string('user_agent')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index('attended_at');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('attendance_records');
|
||||
}
|
||||
};
|
||||
@@ -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('prizes', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('kod_hadiah')->nullable()->index();
|
||||
$table->string('nama_hadiah');
|
||||
$table->string('kategori')->nullable();
|
||||
$table->decimal('nilai_anggaran', 12, 2)->nullable();
|
||||
$table->unsignedInteger('draw_order')->default(0)->index();
|
||||
$table->unsignedInteger('item_index')->default(1); // #1, #2 ... bagi kuantiti > 1
|
||||
$table->string('batch_kod')->nullable()->index(); // kumpulkan item dari satu baris import
|
||||
// belum_dicabut, sedang_dicabut, disahkan, redraw_required
|
||||
$table->string('status')->default('belum_dicabut')->index();
|
||||
$table->unsignedInteger('redraw_count')->default(0);
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('prizes');
|
||||
}
|
||||
};
|
||||
@@ -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('draw_sessions', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('nama');
|
||||
$table->boolean('is_active')->default(true);
|
||||
// Setting: masukkan semula peserta yang dibatalkan ke pool? Default: ya
|
||||
$table->boolean('return_cancelled_to_pool')->default(true);
|
||||
$table->foreignId('started_by')->nullable()->constrained('users')->nullOnDelete();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('draw_sessions');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,46 @@
|
||||
<?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('draw_results', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('draw_session_id')->constrained('draw_sessions')->cascadeOnDelete();
|
||||
$table->foreignId('prize_id')->constrained('prizes')->cascadeOnDelete();
|
||||
$table->foreignId('member_id')->constrained('members')->cascadeOnDelete();
|
||||
// pending_confirmation, confirmed, cancelled_absent, redrawn
|
||||
$table->string('status')->default('pending_confirmation')->index();
|
||||
$table->unsignedInteger('attempt_number')->default(1);
|
||||
$table->timestamp('spun_at')->useCurrent();
|
||||
$table->timestamp('confirmed_at')->nullable();
|
||||
$table->timestamp('cancelled_at')->nullable();
|
||||
$table->foreignId('confirmed_by')->nullable()->constrained('users')->nullOnDelete();
|
||||
$table->foreignId('cancelled_by')->nullable()->constrained('users')->nullOnDelete();
|
||||
$table->string('sebab_batal')->nullable();
|
||||
|
||||
// Diset oleh aplikasi (dalam transaction confirm) hanya bila status = confirmed,
|
||||
// selainnya NULL. Unique index kuatkuasakan di peringkat DB:
|
||||
// - seorang anggota hanya boleh ada SATU pengesahan (tak boleh menang lagi)
|
||||
// - sesuatu hadiah hanya boleh ada SATU pemenang disahkan
|
||||
$table->unsignedBigInteger('confirmed_member_id')->nullable();
|
||||
$table->unsignedBigInteger('confirmed_prize_id')->nullable();
|
||||
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['prize_id', 'status']);
|
||||
$table->index(['member_id', 'status']);
|
||||
$table->unique('confirmed_member_id', 'uq_confirmed_member');
|
||||
$table->unique('confirmed_prize_id', 'uq_confirmed_prize');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('draw_results');
|
||||
}
|
||||
};
|
||||
@@ -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('import_logs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('type'); // members | prizes
|
||||
$table->string('filename');
|
||||
$table->unsignedInteger('total_rows')->default(0);
|
||||
$table->unsignedInteger('success_count')->default(0);
|
||||
$table->unsignedInteger('duplicate_count')->default(0);
|
||||
$table->unsignedInteger('failed_count')->default(0);
|
||||
$table->json('errors')->nullable();
|
||||
$table->foreignId('imported_by')->nullable()->constrained('users')->nullOnDelete();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('import_logs');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
<?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('audit_logs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->nullable()->constrained('users')->nullOnDelete();
|
||||
$table->string('action')->index();
|
||||
$table->string('description')->nullable();
|
||||
$table->nullableMorphs('subject');
|
||||
$table->string('ip_address', 45)->nullable();
|
||||
$table->json('meta')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('audit_logs');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,137 @@
|
||||
<?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
|
||||
{
|
||||
$teams = config('permission.teams');
|
||||
$tableNames = config('permission.table_names');
|
||||
$columnNames = config('permission.column_names');
|
||||
$pivotRole = $columnNames['role_pivot_key'] ?? 'role_id';
|
||||
$pivotPermission = $columnNames['permission_pivot_key'] ?? 'permission_id';
|
||||
|
||||
throw_if(empty($tableNames), 'Error: config/permission.php not loaded. Run [php artisan config:clear] and try again.');
|
||||
throw_if($teams && empty($columnNames['team_foreign_key'] ?? null), 'Error: team_foreign_key on config/permission.php not loaded. Run [php artisan config:clear] and try again.');
|
||||
|
||||
/**
|
||||
* See `docs/prerequisites.md` for suggested lengths on 'name' and 'guard_name' if "1071 Specified key was too long" errors are encountered.
|
||||
*/
|
||||
Schema::create($tableNames['permissions'], static function (Blueprint $table) {
|
||||
$table->id(); // permission id
|
||||
$table->string('name');
|
||||
$table->string('guard_name');
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['name', 'guard_name']);
|
||||
});
|
||||
|
||||
/**
|
||||
* See `docs/prerequisites.md` for suggested lengths on 'name' and 'guard_name' if "1071 Specified key was too long" errors are encountered.
|
||||
*/
|
||||
Schema::create($tableNames['roles'], static function (Blueprint $table) use ($teams, $columnNames) {
|
||||
$table->id(); // role id
|
||||
if ($teams || config('permission.testing')) { // permission.testing is a fix for sqlite testing
|
||||
$table->unsignedBigInteger($columnNames['team_foreign_key'])->nullable();
|
||||
$table->index($columnNames['team_foreign_key'], 'roles_team_foreign_key_index');
|
||||
}
|
||||
$table->string('name');
|
||||
$table->string('guard_name');
|
||||
$table->timestamps();
|
||||
if ($teams || config('permission.testing')) {
|
||||
$table->unique([$columnNames['team_foreign_key'], 'name', 'guard_name']);
|
||||
} else {
|
||||
$table->unique(['name', 'guard_name']);
|
||||
}
|
||||
});
|
||||
|
||||
Schema::create($tableNames['model_has_permissions'], static function (Blueprint $table) use ($tableNames, $columnNames, $pivotPermission, $teams) {
|
||||
$table->unsignedBigInteger($pivotPermission);
|
||||
|
||||
$table->string('model_type');
|
||||
$table->unsignedBigInteger($columnNames['model_morph_key']);
|
||||
$table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_permissions_model_id_model_type_index');
|
||||
|
||||
$table->foreign($pivotPermission)
|
||||
->references('id') // permission id
|
||||
->on($tableNames['permissions'])
|
||||
->cascadeOnDelete();
|
||||
if ($teams) {
|
||||
$table->unsignedBigInteger($columnNames['team_foreign_key']);
|
||||
$table->index($columnNames['team_foreign_key'], 'model_has_permissions_team_foreign_key_index');
|
||||
|
||||
$table->primary([$columnNames['team_foreign_key'], $pivotPermission, $columnNames['model_morph_key'], 'model_type'],
|
||||
'model_has_permissions_permission_model_type_primary');
|
||||
} else {
|
||||
$table->primary([$pivotPermission, $columnNames['model_morph_key'], 'model_type'],
|
||||
'model_has_permissions_permission_model_type_primary');
|
||||
}
|
||||
});
|
||||
|
||||
Schema::create($tableNames['model_has_roles'], static function (Blueprint $table) use ($tableNames, $columnNames, $pivotRole, $teams) {
|
||||
$table->unsignedBigInteger($pivotRole);
|
||||
|
||||
$table->string('model_type');
|
||||
$table->unsignedBigInteger($columnNames['model_morph_key']);
|
||||
$table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_roles_model_id_model_type_index');
|
||||
|
||||
$table->foreign($pivotRole)
|
||||
->references('id') // role id
|
||||
->on($tableNames['roles'])
|
||||
->cascadeOnDelete();
|
||||
if ($teams) {
|
||||
$table->unsignedBigInteger($columnNames['team_foreign_key']);
|
||||
$table->index($columnNames['team_foreign_key'], 'model_has_roles_team_foreign_key_index');
|
||||
|
||||
$table->primary([$columnNames['team_foreign_key'], $pivotRole, $columnNames['model_morph_key'], 'model_type'],
|
||||
'model_has_roles_role_model_type_primary');
|
||||
} else {
|
||||
$table->primary([$pivotRole, $columnNames['model_morph_key'], 'model_type'],
|
||||
'model_has_roles_role_model_type_primary');
|
||||
}
|
||||
});
|
||||
|
||||
Schema::create($tableNames['role_has_permissions'], static function (Blueprint $table) use ($tableNames, $pivotRole, $pivotPermission) {
|
||||
$table->unsignedBigInteger($pivotPermission);
|
||||
$table->unsignedBigInteger($pivotRole);
|
||||
|
||||
$table->foreign($pivotPermission)
|
||||
->references('id') // permission id
|
||||
->on($tableNames['permissions'])
|
||||
->cascadeOnDelete();
|
||||
|
||||
$table->foreign($pivotRole)
|
||||
->references('id') // role id
|
||||
->on($tableNames['roles'])
|
||||
->cascadeOnDelete();
|
||||
|
||||
$table->primary([$pivotPermission, $pivotRole], 'role_has_permissions_permission_id_role_id_primary');
|
||||
});
|
||||
|
||||
app('cache')
|
||||
->store(config('permission.cache.store') != 'default' ? config('permission.cache.store') : null)
|
||||
->forget(config('permission.cache.key'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$tableNames = config('permission.table_names');
|
||||
|
||||
throw_if(empty($tableNames), 'Error: config/permission.php not found and defaults could not be merged. Please publish the package configuration before proceeding, or drop the tables manually.');
|
||||
|
||||
Schema::dropIfExists($tableNames['role_has_permissions']);
|
||||
Schema::dropIfExists($tableNames['model_has_roles']);
|
||||
Schema::dropIfExists($tableNames['model_has_permissions']);
|
||||
Schema::dropIfExists($tableNames['roles']);
|
||||
Schema::dropIfExists($tableNames['permissions']);
|
||||
}
|
||||
};
|
||||
65
database/seeders/DatabaseSeeder.php
Normal file
65
database/seeders/DatabaseSeeder.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\DrawSession;
|
||||
use App\Models\Member;
|
||||
use App\Models\Prize;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class DatabaseSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$this->call(RoleUserSeeder::class);
|
||||
|
||||
// Sesi cabutan aktif untuk event
|
||||
DrawSession::firstOrCreate(
|
||||
['is_active' => true],
|
||||
['nama' => 'Mesyuarat Agung Tahunan KOIPB ' . date('Y')]
|
||||
);
|
||||
|
||||
// 200 anggota dummy
|
||||
if (Member::count() === 0) {
|
||||
Member::factory()->count(200)->create();
|
||||
}
|
||||
|
||||
$this->seedPrizes();
|
||||
}
|
||||
|
||||
private function seedPrizes(): void
|
||||
{
|
||||
if (Prize::count() > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Definisi hadiah (kuantiti > 1 dipecah jadi item berasingan)
|
||||
$definitions = [
|
||||
['H01', 'Cabutan Utama - Umrah', 'Utama', 12000, 1, 1],
|
||||
['H02', 'Motosikal', 'Utama', 6000, 2, 1],
|
||||
['H03', 'Peti Sejuk 2 Pintu', 'Elektrik', 2500, 3, 1],
|
||||
['H04', 'Mesin Basuh', 'Elektrik', 1800, 4, 1],
|
||||
['H05', 'Smart TV 55"', 'Elektrik', 3200, 5, 1],
|
||||
['H06', 'Telefon Pintar', 'Gajet', 2200, 6, 2],
|
||||
['H07', 'Tablet', 'Gajet', 1500, 7, 2],
|
||||
['H08', 'Basikal', 'Sukan', 900, 8, 2],
|
||||
['H09', 'Hamper Premium', 'Hamper', 350, 9, 5],
|
||||
['H10', 'Baucar Tunai RM200', 'Baucar', 200, 10, 5],
|
||||
];
|
||||
|
||||
foreach ($definitions as [$kod, $nama, $kategori, $nilai, $drawOrder, $kuantiti]) {
|
||||
for ($n = 1; $n <= $kuantiti; $n++) {
|
||||
Prize::create([
|
||||
'kod_hadiah' => $kod,
|
||||
'nama_hadiah' => $kuantiti > 1 ? "{$nama} #{$n}" : $nama,
|
||||
'kategori' => $kategori,
|
||||
'nilai_anggaran' => $nilai,
|
||||
'draw_order' => $drawOrder,
|
||||
'item_index' => $n,
|
||||
'batch_kod' => $kod,
|
||||
'status' => Prize::STATUS_BELUM,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
38
database/seeders/RoleUserSeeder.php
Normal file
38
database/seeders/RoleUserSeeder.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Spatie\Permission\Models\Role;
|
||||
|
||||
class RoleUserSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$roles = [
|
||||
User::ROLE_ADMIN,
|
||||
User::ROLE_KAUNTER,
|
||||
User::ROLE_CABUTAN,
|
||||
];
|
||||
|
||||
foreach ($roles as $role) {
|
||||
Role::firstOrCreate(['name' => $role, 'guard_name' => 'web']);
|
||||
}
|
||||
|
||||
$users = [
|
||||
['Admin KOIPB', 'admin@koipb.test', User::ROLE_ADMIN],
|
||||
['Petugas Kaunter', 'kaunter@koipb.test', User::ROLE_KAUNTER],
|
||||
['Petugas Cabutan', 'cabutan@koipb.test', User::ROLE_CABUTAN],
|
||||
];
|
||||
|
||||
foreach ($users as [$name, $email, $role]) {
|
||||
$user = User::firstOrCreate(
|
||||
['email' => $email],
|
||||
['name' => $name, 'password' => Hash::make('password')]
|
||||
);
|
||||
$user->syncRoles([$role]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user