This commit is contained in:
Saufi
2026-06-16 15:04:58 +08:00
commit 77a87fbdf1
171 changed files with 21225 additions and 0 deletions

View File

@@ -0,0 +1,529 @@
<?php
namespace Database\Seeders;
use App\Enums\ApplicationStatus;
use App\Enums\UserRole;
use App\Models\ApplicationHistory;
use App\Models\AuditTrail;
use App\Models\Department;
use App\Models\EmailLog;
use App\Models\ImportBatch;
use App\Models\InstallmentApplication;
use App\Models\InstallmentSchedule;
use App\Models\Payment;
use App\Models\PropertyAccount;
use App\Models\Role;
use App\Models\RolePermission;
use App\Models\SystemNotification;
use App\Models\SystemSetting;
use App\Models\Task;
use App\Models\User;
use App\Models\UserProfile;
use Illuminate\Database\Seeder;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Hash;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*/
public function run(): void
{
$roles = collect([
UserRole::ADMIN->value => Role::create([
'name' => 'Admin',
'slug' => UserRole::ADMIN->value,
'description' => 'Akses penuh pemantauan, laporan dan tetapan sistem.',
]),
UserRole::STAFF->value => Role::create([
'name' => 'Staff',
'slug' => UserRole::STAFF->value,
'description' => 'Semak permohonan, input jadual manual dan cetak borang.',
]),
UserRole::PUBLIC->value => Role::create([
'name' => 'Pengguna Awam',
'slug' => UserRole::PUBLIC->value,
'description' => 'Mohon ansuran, lihat jadual manual dan buat bayaran dummy.',
]),
]);
foreach ([
UserRole::ADMIN->value => [
'Dashboard' => ['view'],
'Pengurusan Pengguna' => ['view', 'create', 'edit', 'reset_password'],
'Laporan' => ['view', 'export'],
'Audit Trail' => ['view'],
],
UserRole::STAFF->value => [
'Dashboard Staff' => ['view'],
'Permohonan' => ['view', 'review', 'print'],
'Kemaskini Bayaran Pukal' => ['view', 'upload'],
'Import Excel' => ['view', 'upload'],
],
UserRole::PUBLIC->value => [
'Dashboard Pengguna Awam' => ['view'],
'Permohonan Saya' => ['view', 'create'],
'Bayaran Dummy JomPAY' => ['view', 'pay'],
],
] as $roleSlug => $permissions) {
foreach ($permissions as $module => $access) {
RolePermission::create([
'role_id' => $roles[$roleSlug]->id,
'module' => $module,
'permissions' => $access,
]);
}
}
$department = Department::create([
'name' => 'Unit Hasil & Tunggakan',
'code' => 'UHT',
'description' => 'Bahagian pengurusan tunggakan cukai harta dan ansuran.',
]);
$admin = User::create([
'name' => 'Admin MyAnsuran',
'email' => 'admin@myansuran.test',
'password' => Hash::make('password'),
'role_id' => $roles[UserRole::ADMIN->value]->id,
'department_id' => $department->id,
'last_login_at' => now()->subHours(2),
]);
$staff = User::create([
'name' => 'Pegawai Semakan',
'email' => 'staff@myansuran.test',
'password' => Hash::make('password'),
'role_id' => $roles[UserRole::STAFF->value]->id,
'department_id' => $department->id,
'last_login_at' => now()->subHour(),
]);
$publicUser = User::create([
'name' => 'Nur Balqis',
'email' => 'user@myansuran.test',
'password' => Hash::make('password'),
'role_id' => $roles[UserRole::PUBLIC->value]->id,
'last_login_at' => now()->subMinutes(20),
]);
UserProfile::create([
'user_id' => $publicUser->id,
'public_name' => 'Nur Balqis Binti Rahman',
'identification_type' => 'MyKad',
'identification_number' => '920101-01-2345',
'country_code' => '+60',
'mobile_no' => '123456789',
'correspondence_address' => 'No. 88, Jalan Setia 3, Taman Setia Indah, Johor Bahru, Johor',
'workplace_address' => 'Pejabat Pengurusan BizHub, Iskandar Puteri, Johor',
'occupation' => 'Eksekutif Operasi',
'monthly_income' => 4200.00,
]);
$this->seedSystemSettings();
if (! app()->environment('testing')) {
return;
}
$importBatch = ImportBatch::create([
'filename' => 'property-accounts-demo.xlsx',
'stored_path' => 'imports/property-accounts-demo.xlsx',
'import_type' => 'arrears',
'uploaded_by' => $staff->id,
'total_processed' => 10,
'total_new' => 10,
'total_updated' => 0,
'total_missing' => 0,
'total_failed' => 0,
'summary' => ['seeded' => true],
]);
$propertyAccounts = collect([
['A1001', 'NBE1001', 'Nur Balqis Binti Rahman', 'Johor Bahru', 'Taman Setia Indah', 'Banglo', '4.5%', 1200, 'Kediaman'],
['A1002', 'NBE1002', 'Syarikat Maju Bina Sdn Bhd', 'Iskandar Puteri', 'Kawasan Perindustrian Gelang Patah', 'Kilang', '6.0%', 4500, 'Industri'],
['A1003', 'NBE1003', 'Kedai Seri Jaya Enterprise', 'Johor Bahru', 'Taman Molek', 'Kedai Pejabat', '5.5%', 7800, 'Perdagangan'],
['A1004', 'NBE1004', 'Puan Salmah Binti Jusoh', 'Skudai', 'Taman Universiti', 'Teres', '4.0%', 1600, 'Kediaman'],
['A1005', 'NBE1005', 'Warisan Teguh Industries', 'Pasir Gudang', 'Kawasan Industri Tanjung Langsat', 'Gudang', '6.8%', 9800, 'Industri'],
['A1006', 'NBE1006', 'Restoran Selera Selatan', 'Johor Bahru', 'Bandar Dato Onn', 'Premis Niaga', '5.2%', 3100, 'Perdagangan'],
['A1007', 'NBE1007', 'Encik Azhar Bin Jaafar', 'Kulai', 'Taman Putri', 'Teres', '4.1%', 1400, 'Kediaman'],
['A1008', 'NBE1008', 'Mutiara Logistic Sdn Bhd', 'Iskandar Puteri', 'Nusajaya Tech Park', 'Lot Industri', '6.4%', 8600, 'Industri'],
['A1009', 'NBE1009', 'Butik Anggun Mawar', 'Johor Bahru', 'Taman Mount Austin', 'Lot Komersial', '5.1%', 2600, 'Perdagangan'],
['A1010', 'NBE1010', 'Puan Hajar Binti Osman', 'Skudai', 'Taman Sri Pulai', 'Apartment', '3.9%', 900, 'Kediaman'],
])->map(function (array $row) use ($importBatch) {
[$noAkaun, $noAkaunTunggakan, $pemilik, $bandar, $taman, $rupacara, $kadar, $tunggakan, $category] = $row;
return PropertyAccount::create([
'no_akaun' => $noAkaun,
'no_akaun_tunggakan' => $noAkaunTunggakan,
'no_bgnn' => 'BGN-'.str($noAkaun)->after('A'),
'nama_jalan' => 'Jalan Demo '.str($noAkaun)->after('A'),
'pemilik' => $pemilik,
'warganegara' => 'Ya',
'pelanggan' => 'Aktif',
'status' => 'Tunggakan',
'bandar' => $bandar,
'taman' => $taman,
'rupacara' => $rupacara,
'kadar' => $kadar,
'cukai_harta' => round($tunggakan * 0.35, 2),
'aktif' => 'Ya',
'tunggakan' => $tunggakan,
'jenis_lot' => 'Komersial / Kediaman',
'no_lot' => 'LOT-'.str($noAkaun)->after('A'),
'jenis_dhm' => 'Hakmilik Kekal',
'no_dhm' => 'DHM-'.str($noAkaun)->after('A'),
'no_syarikat' => str($pemilik)->contains('Sdn Bhd') ? '201901234567' : null,
'alamat_harta' => $taman.', '.$bandar.', Johor',
'category' => $category,
'status_data' => 'Aktif',
'last_imported_at' => now(),
'import_batch_id' => $importBatch->id,
]);
});
$activeApplication = InstallmentApplication::create([
'user_id' => $publicUser->id,
'property_account_id' => $propertyAccounts[0]->id,
'assigned_staff_id' => $staff->id,
'application_no' => 'MYA-202605-0001',
'no_akaun' => $propertyAccounts[0]->no_akaun,
'no_akaun_tunggakan' => $propertyAccounts[0]->no_akaun_tunggakan,
'category' => 'Kediaman',
'installment_months' => 4,
'total_arrears' => 1200.00,
'status' => ApplicationStatus::ACTIVE->value,
'schedule_status' => 'disahkan',
'schedule_total' => 1200.00,
'staff_remarks' => 'Permohonan lengkap. Bayaran pertama dipandu pada kadar minimum 30%.',
'reviewed_by' => $staff->id,
'reviewed_at' => now()->subDays(5),
'approved_at' => now()->subDays(5),
'identification_type' => 'MyKad',
'identification_number' => '920101-01-2345',
'no_lot' => $propertyAccounts[0]->no_lot,
'no_dhm' => $propertyAccounts[0]->no_dhm,
'no_syarikat' => $propertyAccounts[0]->no_syarikat,
'alamat_harta' => $propertyAccounts[0]->no_bgnn.', '.$propertyAccounts[0]->nama_jalan,
'alamat_surat_menyurat' => 'No. 88, Jalan Setia 3, Taman Setia Indah, Johor Bahru, Johor',
'country_code' => '+60',
'mobile_no' => '123456789',
'email' => $publicUser->email,
'alamat_tempat_bekerja' => 'Pejabat Pengurusan BizHub, Iskandar Puteri, Johor',
'pekerjaan' => 'Eksekutif Operasi',
'pendapatan_sebulan' => 4200.00,
'declaration_name' => 'Nur Balqis Binti Rahman',
'declaration_identification_type' => 'MyKad',
'declaration_identification_number' => '920101-01-2345',
'declaration_date' => now()->subDays(6)->toDateString(),
'declaration_accepted' => true,
'printed_at' => now()->subDays(4),
'created_at' => now()->subDays(6),
'updated_at' => now()->subDays(4),
]);
collect([
[1, 360.00, now()->subDays(4)->toDateString(), 'dibayar'],
[2, 280.00, now()->addDays(5)->toDateString(), 'belum_bayar'],
[3, 280.00, now()->addMonth()->toDateString(), 'belum_bayar'],
[4, 280.00, now()->addMonths(2)->toDateString(), 'belum_bayar'],
])->each(function (array $schedule) use ($activeApplication, $staff) {
InstallmentSchedule::create([
'installment_application_id' => $activeApplication->id,
'installment_no' => $schedule[0],
'amount' => $schedule[1],
'due_date' => $schedule[2],
'payment_status' => $schedule[3],
'paid_at' => $schedule[3] === 'dibayar' ? now()->subDays(3) : null,
'is_confirmed' => true,
'created_by' => $staff->id,
]);
});
$processingApplication = InstallmentApplication::create([
'user_id' => $publicUser->id,
'property_account_id' => $propertyAccounts[1]->id,
'assigned_staff_id' => $staff->id,
'application_no' => 'MYA-202605-0002',
'no_akaun' => $propertyAccounts[1]->no_akaun,
'no_akaun_tunggakan' => $propertyAccounts[1]->no_akaun_tunggakan,
'category' => 'Industri',
'installment_months' => 3,
'total_arrears' => 4500.00,
'status' => ApplicationStatus::PROCESSING->value,
'schedule_status' => 'draf',
'schedule_total' => 0,
'identification_type' => 'MyKad',
'identification_number' => '920101-01-2345',
'no_lot' => $propertyAccounts[1]->no_lot,
'no_dhm' => $propertyAccounts[1]->no_dhm,
'no_syarikat' => $propertyAccounts[1]->no_syarikat,
'alamat_harta' => $propertyAccounts[1]->no_bgnn.', '.$propertyAccounts[1]->nama_jalan,
'alamat_surat_menyurat' => 'No. 88, Jalan Setia 3, Taman Setia Indah, Johor Bahru, Johor',
'country_code' => '+60',
'mobile_no' => '123456789',
'email' => $publicUser->email,
'alamat_tempat_bekerja' => 'Pejabat Pengurusan BizHub, Iskandar Puteri, Johor',
'pekerjaan' => 'Eksekutif Operasi',
'pendapatan_sebulan' => 4200.00,
'declaration_name' => 'Nur Balqis Binti Rahman',
'declaration_identification_type' => 'MyKad',
'declaration_identification_number' => '920101-01-2345',
'declaration_date' => now()->subDays(2)->toDateString(),
'declaration_accepted' => true,
'created_at' => now()->subDays(2),
'updated_at' => now()->subDays(2),
]);
$failedApplication = InstallmentApplication::create([
'user_id' => $publicUser->id,
'property_account_id' => $propertyAccounts[2]->id,
'assigned_staff_id' => $staff->id,
'application_no' => 'MYA-202604-0003',
'no_akaun' => $propertyAccounts[2]->no_akaun,
'no_akaun_tunggakan' => $propertyAccounts[2]->no_akaun_tunggakan,
'category' => 'Perdagangan',
'installment_months' => 2,
'total_arrears' => 7800.00,
'status' => ApplicationStatus::FAILED->value,
'schedule_status' => 'draf',
'schedule_total' => 5000.00,
'staff_remarks' => 'Dokumen sokongan tidak lengkap. Sila kemukakan semula salinan IC yang jelas.',
'reviewed_by' => $staff->id,
'reviewed_at' => now()->subMonth(),
'rejected_at' => now()->subMonth(),
'rejection_reason' => 'Dokumen sokongan tidak lengkap.',
'identification_type' => 'MyKad',
'identification_number' => '920101-01-2345',
'no_lot' => $propertyAccounts[2]->no_lot,
'no_dhm' => $propertyAccounts[2]->no_dhm,
'no_syarikat' => $propertyAccounts[2]->no_syarikat,
'alamat_harta' => $propertyAccounts[2]->no_bgnn.', '.$propertyAccounts[2]->nama_jalan,
'alamat_surat_menyurat' => 'No. 88, Jalan Setia 3, Taman Setia Indah, Johor Bahru, Johor',
'country_code' => '+60',
'mobile_no' => '123456789',
'email' => $publicUser->email,
'alamat_tempat_bekerja' => 'Pejabat Pengurusan BizHub, Iskandar Puteri, Johor',
'pekerjaan' => 'Eksekutif Operasi',
'pendapatan_sebulan' => 4200.00,
'declaration_name' => 'Nur Balqis Binti Rahman',
'declaration_identification_type' => 'MyKad',
'declaration_identification_number' => '920101-01-2345',
'declaration_date' => now()->subMonth()->toDateString(),
'declaration_accepted' => true,
'printed_at' => now()->subMonth()->addDay(),
'created_at' => now()->subMonth()->subDays(2),
'updated_at' => now()->subMonth()->addDay(),
]);
$completedApplication = InstallmentApplication::create([
'user_id' => $publicUser->id,
'property_account_id' => $propertyAccounts[3]->id,
'assigned_staff_id' => $staff->id,
'application_no' => 'MYA-202603-0004',
'no_akaun' => $propertyAccounts[3]->no_akaun,
'no_akaun_tunggakan' => $propertyAccounts[3]->no_akaun_tunggakan,
'category' => 'Kediaman',
'installment_months' => 2,
'total_arrears' => 1600.00,
'status' => ApplicationStatus::COMPLETED->value,
'schedule_status' => 'disahkan',
'schedule_total' => 1600.00,
'staff_remarks' => 'Semua bayaran telah dijelaskan.',
'reviewed_by' => $staff->id,
'reviewed_at' => now()->subMonths(2),
'approved_at' => now()->subMonths(2),
'identification_type' => 'MyKad',
'identification_number' => '920101-01-2345',
'no_lot' => $propertyAccounts[3]->no_lot,
'no_dhm' => $propertyAccounts[3]->no_dhm,
'no_syarikat' => $propertyAccounts[3]->no_syarikat,
'alamat_harta' => $propertyAccounts[3]->no_bgnn.', '.$propertyAccounts[3]->nama_jalan,
'alamat_surat_menyurat' => 'No. 88, Jalan Setia 3, Taman Setia Indah, Johor Bahru, Johor',
'country_code' => '+60',
'mobile_no' => '123456789',
'email' => $publicUser->email,
'alamat_tempat_bekerja' => 'Pejabat Pengurusan BizHub, Iskandar Puteri, Johor',
'pekerjaan' => 'Eksekutif Operasi',
'pendapatan_sebulan' => 4200.00,
'declaration_name' => 'Nur Balqis Binti Rahman',
'declaration_identification_type' => 'MyKad',
'declaration_identification_number' => '920101-01-2345',
'declaration_date' => now()->subMonths(2)->toDateString(),
'declaration_accepted' => true,
'printed_at' => now()->subMonths(2)->addDays(2),
'created_at' => now()->subMonths(2)->subDays(3),
'updated_at' => now()->subMonth(),
]);
collect([
[$completedApplication, 1, 800.00, now()->subMonths(2)->addDays(5)->toDateString()],
[$completedApplication, 2, 800.00, now()->subMonth()->toDateString()],
])->each(function (array $schedule) use ($staff) {
InstallmentSchedule::create([
'installment_application_id' => $schedule[0]->id,
'installment_no' => $schedule[1],
'amount' => $schedule[2],
'due_date' => $schedule[3],
'payment_status' => 'dibayar',
'paid_at' => Carbon::parse($schedule[3])->endOfDay(),
'is_confirmed' => true,
'created_by' => $staff->id,
]);
});
Task::insert([
[
'installment_application_id' => $processingApplication->id,
'assigned_to' => $staff->id,
'assigned_by' => $admin->id,
'title' => 'Semak permohonan '.$processingApplication->application_no,
'description' => 'Permohonan baharu menunggu input amaun ansuran manual.',
'priority' => 'tinggi',
'status' => 'belum_selesai',
'due_at' => now()->addDay(),
'created_at' => now(),
'updated_at' => now(),
],
[
'installment_application_id' => $activeApplication->id,
'assigned_to' => $staff->id,
'assigned_by' => $admin->id,
'title' => 'Pantau baki ansuran '.$activeApplication->application_no,
'description' => 'Semak kemasukan bayaran ansuran bulan kedua.',
'priority' => 'normal',
'status' => 'belum_selesai',
'due_at' => now()->addWeek(),
'created_at' => now(),
'updated_at' => now(),
],
]);
$activePaymentSchedule = $activeApplication->schedules()->first();
Payment::create([
'installment_application_id' => $activeApplication->id,
'installment_schedule_id' => $activePaymentSchedule?->id,
'user_id' => $publicUser->id,
'transaction_no' => 'TRX-DEMO-1001',
'receipt_no' => 'RCPT-DEMO-1001',
'ref_1' => $activeApplication->no_akaun,
'ref_2' => $publicUser->email,
'amount' => 360.00,
'status' => 'success',
'payload' => ['channel' => 'JomPAY Dummy'],
'paid_at' => now()->subDays(3),
'remarks' => 'Bayaran pertama berjaya.',
]);
foreach ($completedApplication->schedules as $index => $schedule) {
Payment::create([
'installment_application_id' => $completedApplication->id,
'installment_schedule_id' => $schedule->id,
'user_id' => $publicUser->id,
'transaction_no' => 'TRX-DEMO-200'.($index + 1),
'receipt_no' => 'RCPT-DEMO-200'.($index + 1),
'ref_1' => $completedApplication->no_akaun,
'ref_2' => $publicUser->email,
'amount' => $schedule->amount,
'status' => 'success',
'payload' => ['channel' => 'JomPAY Dummy'],
'paid_at' => $schedule->paid_at,
'remarks' => 'Bayaran ansuran selesai.',
]);
}
foreach ([
[$activeApplication, $publicUser, 'permohonan_dihantar', null, ApplicationStatus::ACTIVE->value, 'Permohonan diterima dan jadual manual disahkan.'],
[$processingApplication, $publicUser, 'permohonan_dihantar', null, ApplicationStatus::PROCESSING->value, 'Permohonan sedang diproses oleh staff.'],
[$failedApplication, $staff, 'permohonan_ditolak', ApplicationStatus::PROCESSING->value, ApplicationStatus::FAILED->value, 'Dokumen sokongan tidak lengkap.'],
[$completedApplication, $staff, 'akaun_ansuran_selesai', ApplicationStatus::ACTIVE->value, ApplicationStatus::COMPLETED->value, 'Semua ansuran telah dibayar.'],
] as $history) {
ApplicationHistory::create([
'installment_application_id' => $history[0]->id,
'user_id' => $history[1]->id,
'action' => $history[2],
'old_status' => $history[3],
'new_status' => $history[4],
'remarks' => $history[5],
'metadata' => ['seeded' => true],
'created_at' => now(),
'updated_at' => now(),
]);
}
foreach ([
['Permohonan diterima', 'Permohonan MYA-202605-0001 telah disahkan dan jadual bayaran dipaparkan.', $activeApplication],
['Permohonan masih diproses', 'Permohonan MYA-202605-0002 sedang disemak oleh staff.', $processingApplication],
['Permohonan ditolak', 'Permohonan MYA-202604-0003 ditolak. Sila semak ulasan pegawai.', $failedApplication],
] as $notification) {
SystemNotification::create([
'user_id' => $publicUser->id,
'type' => 'application',
'title' => $notification[0],
'message' => $notification[1],
'action_url' => '/portal/applications/'.$notification[2]->id,
]);
}
foreach ([
['Permohonan diterima', 'Jadual bayaran manual untuk MYA-202605-0001 telah disahkan.', $activeApplication],
['Permohonan ditolak', 'Permohonan MYA-202604-0003 memerlukan semakan semula dokumen.', $failedApplication],
] as $email) {
EmailLog::create([
'user_id' => $publicUser->id,
'installment_application_id' => $email[2]->id,
'recipient_email' => $publicUser->email,
'subject' => $email[0],
'body' => $email[1],
'status' => 'sent',
'sent_at' => now(),
]);
}
foreach ([
[$admin, 'login', 'Authentication', 'Admin log masuk ke sistem.'],
[$publicUser, 'hantar_permohonan', 'Permohonan Ansuran', 'Pengguna menghantar permohonan baharu.'],
[$staff, 'semak_permohonan', 'Semakan Staff', 'Staff mengesahkan jadual ansuran manual.'],
[$staff, 'upload_excel', 'Import Excel', 'Staff memuat naik Excel data akaun cukai harta.'],
[$publicUser, 'bayaran_dummy', 'Pembayaran', 'Pengguna membuat bayaran dummy melalui JomPAY.'],
] as $audit) {
AuditTrail::create([
'user_id' => $audit[0]->id,
'installment_application_id' => $activeApplication->id,
'action' => $audit[1],
'module' => $audit[2],
'description' => $audit[3],
'old_values' => ['seeded' => true],
'new_values' => ['seeded' => true],
'ip_address' => '127.0.0.1',
'user_agent' => 'Seeder',
'created_at' => now(),
'updated_at' => now(),
]);
}
}
protected function seedSystemSettings(): void
{
foreach ([
['general', 'max_installment_months', 'Jumlah maksimum ansuran', '6', 'Had maksimum tempoh ansuran yang dibenarkan.'],
['general', 'minimum_first_payment_residential', 'Kediaman - Panduan Bayaran Awal', '30', 'Peratus panduan bayaran pertama untuk kediaman.'],
['general', 'minimum_first_payment_industrial', 'Industri - Panduan Bayaran Awal', '50', 'Peratus panduan bayaran pertama untuk industri.'],
['general', 'minimum_first_payment_commercial', 'Perdagangan - Panduan Bayaran Awal', '50', 'Peratus panduan bayaran pertama untuk perdagangan.'],
['department', 'department_name', 'Nama Jabatan', 'Majlis Bandaraya Iskandar Puteri', 'Nama jabatan untuk paparan portal.'],
['payment', 'jompay_biller_code', 'Biller Code JomPAY', '37317', 'Kod pengebil untuk demo pembayaran JomPAY.'],
] as $setting) {
SystemSetting::updateOrCreate(
['key' => $setting[1]],
[
'group' => $setting[0],
'label' => $setting[2],
'value' => $setting[3],
'description' => $setting[4],
],
);
}
}
}