'datetime',
'updated_at' => 'datetime',
];
/**
* Generator ID Kustom (S001, S002, ...)
*/
protected static function boot()
{
parent::boot();
static::creating(function ($model) {
if (empty($model->id_santri)) {
$last = Santri::orderBy('id', 'desc')->first();
$num = $last ? intval(substr($last->id_santri, 1)) + 1 : 1;
$model->id_santri = 'S' . str_pad($num, 3, '0', STR_PAD_LEFT);
}
});
}
/**
* Relasi: Santri memiliki satu User Account (hasOne)
*/
public function user()
{
return $this->hasOne(User::class, 'role_id', 'id_santri')
->where('role', 'santri');
}
/**
* Relasi: Santri memiliki banyak data kesehatan
*/
public function kesehatanSantri()
{
return $this->hasMany(KesehatanSantri::class, 'id_santri', 'id_santri');
}
/**
* Relasi: Kesehatan santri yang masih dirawat
*/
public function kesehatanAktif()
{
return $this->hasMany(KesehatanSantri::class, 'id_santri', 'id_santri')
->where('status', 'dirawat');
}
/**
* Relasi: Santri memiliki banyak data kepulangan
*/
public function kepulangan()
{
return $this->hasMany(Kepulangan::class, 'id_santri', 'id_santri');
}
/**
* Relasi: Kepulangan yang sedang aktif
*/
public function kepulanganAktif()
{
return $this->hasMany(Kepulangan::class, 'id_santri', 'id_santri')
->where('status', 'Disetujui')
->whereDate('tanggal_pulang', '<=', now())
->whereDate('tanggal_kembali', '>=', now());
}
/**
* Relasi: Santri memiliki banyak berita (Many-to-Many)
*/
public function berita()
{
return $this->belongsToMany(Berita::class, 'berita_santri', 'id_santri', 'id_berita', 'id_santri', 'id_berita')
->withPivot('sudah_dibaca', 'tanggal_baca')
->withTimestamps();
}
/**
* Relasi: Santri memiliki banyak riwayat pelanggaran
*/
public function riwayatPelanggaran()
{
return $this->hasMany(RiwayatPelanggaran::class, 'id_santri', 'id_santri');
}
/**
* Relasi: Santri memiliki banyak pembayaran SPP
*/
public function pembayaranSpp()
{
return $this->hasMany(PembayaranSpp::class, 'id_santri', 'id_santri');
}
/**
* Relasi: SPP yang belum lunas
*/
public function sppBelumLunas()
{
return $this->hasMany(PembayaranSpp::class, 'id_santri', 'id_santri')
->where('status', 'Belum Lunas');
}
/**
* Relasi: SPP yang telat
*/
public function sppTelat()
{
return $this->hasMany(PembayaranSpp::class, 'id_santri', 'id_santri')
->where('status', 'Belum Lunas')
->where('batas_bayar', '<', now());
}
/**
* Relasi: Santri memiliki banyak transaksi uang saku
*/
public function uangSaku()
{
return $this->hasMany(UangSaku::class, 'id_santri', 'id_santri');
}
/**
* Relasi: Santri memiliki banyak absensi kegiatan (BARU)
*/
public function absensiKegiatans()
{
return $this->hasMany(AbsensiKegiatan::class, 'id_santri', 'id_santri');
}
/**
* Accessor untuk mendapatkan nama kelas lengkap
*/
public function getKelasLengkapAttribute()
{
$kelasMap = [
'PB' => 'Pembinaan (PB)',
'Lambatan' => 'Lambatan',
'Cepatan' => 'Cepatan',
];
return $kelasMap[$this->kelas] ?? $this->kelas;
}
/**
* Accessor untuk mendapatkan badge HTML status
*/
public function getStatusBadgeAttribute()
{
$badges = [
'Aktif' => ' Aktif',
'Lulus' => ' Lulus',
'Tidak Aktif' => ' Tidak Aktif',
];
return $badges[$this->status] ?? $this->status;
}
/**
* Accessor: Total poin pelanggaran
*/
public function getTotalPoinPelanggaranAttribute()
{
return $this->riwayatPelanggaran()->sum('poin');
}
/**
* Accessor: Total tunggakan SPP
*/
public function getTotalTunggakanAttribute()
{
return $this->sppBelumLunas()->sum('nominal');
}
/**
* Accessor: Saldo uang saku terakhir
*/
public function getSaldoUangSakuAttribute()
{
$transaksiTerakhir = $this->uangSaku()
->orderBy('tanggal_transaksi', 'desc')
->orderBy('created_at', 'desc')
->first();
return $transaksiTerakhir ? $transaksiTerakhir->saldo_sesudah : 0;
}
/**
* Accessor: Total pemasukan uang saku
*/
public function getTotalPemasukanUangSakuAttribute()
{
return $this->uangSaku()->where('jenis_transaksi', 'pemasukan')->sum('nominal');
}
/**
* Accessor: Total pengeluaran uang saku
*/
public function getTotalPengeluaranUangSakuAttribute()
{
return $this->uangSaku()->where('jenis_transaksi', 'pengeluaran')->sum('nominal');
}
/**
* Accessor: Status RFID (BARU)
*/
public function getHasRfidAttribute()
{
return !empty($this->rfid_uid);
}
/**
* Accessor: Total kehadiran kegiatan (BARU)
*/
public function getTotalKehadiranAttribute()
{
return $this->absensiKegiatans()->where('status', 'Hadir')->count();
}
/**
* Scope untuk filter santri aktif
*/
public function scopeAktif($query)
{
return $query->where('status', 'Aktif');
}
/**
* Scope untuk filter santri lulus
*/
public function scopeLulus($query)
{
return $query->where('status', 'Lulus');
}
/**
* Scope untuk filter santri tidak aktif
*/
public function scopeTidakAktif($query)
{
return $query->where('status', 'Tidak Aktif');
}
/**
* Scope untuk filter berdasarkan kelas
*/
public function scopeKelas($query, $kelas)
{
return $query->where('kelas', $kelas);
}
/**
* Scope untuk search santri
*/
public function scopeSearch($query, $search)
{
return $query->where(function($q) use ($search) {
$q->where('nama_lengkap', 'like', "%{$search}%")
->orWhere('nis', 'like', "%{$search}%")
->orWhere('id_santri', 'like', "%{$search}%");
});
}
/**
* Relasi: Santri memiliki banyak capaian
*/
public function capaian()
{
return $this->hasMany(Capaian::class, 'id_santri', 'id_santri');
}
/**
* Get rata-rata capaian per semester
*/
public function getRataRataCapaianAttribute()
{
return $this->capaian()->avg('persentase') ?? 0;
}
}