SIPDAM/samooapk/laravel/app/Models/Absensi.php

341 lines
8.4 KiB
PHP

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Carbon\Carbon;
use Illuminate\Support\Facades\Storage;
class Absensi extends Model
{
use HasFactory;
/**
* Nama tabel di database
*/
protected $table = 'absensis'; // PERBAIKAN: Ganti 'absensi' menjadi 'absensis'
/**
* Primary key tabel
*/
protected $primaryKey = 'id_absensi';
/**
* Field yang dapat diisi secara mass assignment
*/
protected $fillable = [
'id_teknisi',
'tanggal',
'jam_masuk',
'jam_keluar',
'foto_absen_masuk',
'foto_absen_keluar',
'latitude',
'longitude',
'status',
'keterangan'
];
/**
* Field yang akan di-cast ke tipe data tertentu
*/
protected $casts = [
'tanggal' => 'date',
'jam_masuk' => 'datetime',
'jam_keluar' => 'datetime',
'created_at' => 'datetime',
'updated_at' => 'datetime'
];
/**
* Status absensi yang valid
*/
const STATUS_HADIR = 'hadir';
const STATUS_SAKIT = 'sakit';
const STATUS_IZIN = 'izin';
/**
* Array status yang tersedia
*/
public static function getStatusOptions()
{
return [
self::STATUS_HADIR => 'Hadir',
self::STATUS_SAKIT => 'Sakit',
self::STATUS_IZIN => 'Izin'
];
}
/**
* Relasi ke model Teknisi
* Satu absensi dimiliki oleh satu teknisi
*/
public function teknisi()
{
return $this->belongsTo(Teknisi::class, 'id_teknisi', 'id_teknisi');
}
/**
* Scope untuk filter berdasarkan tanggal
*/
public function scopeFilterByDate($query, $tanggal)
{
if ($tanggal) {
return $query->whereDate('tanggal', $tanggal);
}
return $query;
}
/**
* Scope untuk filter berdasarkan status
*/
public function scopeFilterByStatus($query, $status)
{
if ($status) {
return $query->where('status', $status);
}
return $query;
}
/**
* Scope untuk filter berdasarkan teknisi
*/
public function scopeFilterByTeknisi($query, $teknisiId)
{
if ($teknisiId) {
return $query->where('id_teknisi', $teknisiId);
}
return $query;
}
/**
* Scope untuk filter berdasarkan bulan dan tahun
*/
public function scopeFilterByMonth($query, $bulan, $tahun = null)
{
if (!$tahun) {
$tahun = date('Y');
}
return $query->whereMonth('tanggal', $bulan)
->whereYear('tanggal', $tahun);
}
/**
* Scope untuk data absensi hari ini
*/
public function scopeToday($query)
{
return $query->whereDate('tanggal', Carbon::today());
}
/**
* Scope untuk data absensi minggu ini
*/
public function scopeThisWeek($query)
{
return $query->whereBetween('tanggal', [
Carbon::now()->startOfWeek(),
Carbon::now()->endOfWeek()
]);
}
/**
* Scope untuk data absensi bulan ini
*/
public function scopeThisMonth($query)
{
return $query->whereMonth('tanggal', Carbon::now()->month)
->whereYear('tanggal', Carbon::now()->year);
}
/**
* Accessor untuk format tanggal Indonesia
*/
public function getTanggalFormattedAttribute()
{
return Carbon::parse($this->tanggal)->format('d/m/Y');
}
/**
* Accessor untuk format jam masuk
*/
public function getJamMasukFormattedAttribute()
{
return $this->jam_masuk ? Carbon::parse($this->jam_masuk)->format('H:i') : '-';
}
/**
* Accessor untuk format jam keluar
*/
public function getJamKeluarFormattedAttribute()
{
return $this->jam_keluar ? Carbon::parse($this->jam_keluar)->format('H:i') : '-';
}
/**
* Accessor untuk nama status dengan format title case
*/
public function getStatusFormattedAttribute()
{
return ucfirst($this->status);
}
/**
* Accessor untuk URL foto absen masuk
*/
public function getFotoAbsenMasukUrlAttribute()
{
return $this->foto_absen_masuk ? asset('storage/' . $this->foto_absen_masuk) : null;
}
/**
* Accessor untuk URL foto absen keluar
*/
public function getFotoAbsenKeluarUrlAttribute()
{
return $this->foto_absen_keluar ? asset('storage/' . $this->foto_absen_keluar) : null;
}
/**
* Accessor untuk menghitung durasi kerja (dalam menit)
*/
public function getDurasiKerjaAttribute()
{
if ($this->jam_masuk && $this->jam_keluar) {
$masuk = Carbon::parse($this->jam_masuk);
$keluar = Carbon::parse($this->jam_keluar);
return $keluar->diffInMinutes($masuk);
}
return 0;
}
/**
* Accessor untuk durasi kerja dalam format jam:menit
*/
public function getDurasiKerjaFormattedAttribute()
{
$durasi = $this->durasi_kerja;
if ($durasi > 0) {
$jam = floor($durasi / 60);
$menit = $durasi % 60;
return sprintf('%02d:%02d', $jam, $menit);
}
return '00:00';
}
/**
* Accessor untuk menentukan apakah terlambat (asumsi jam masuk normal 08:00)
*/
/**
* Accessor untuk kategori kerja (Kerja Biasa vs Lembur)
*/
public function getKategoriKerjaAttribute()
{
if ($this->jam_masuk) {
$jamMasuk = Carbon::parse($this->jam_masuk);
$start = Carbon::parse('07:00');
$end = Carbon::parse('18:00');
if ($jamMasuk->between($start, $end)) {
return 'Kerja Biasa';
}
return 'Kerja Urgent';
}
return '-';
}
/**
* Label warna untuk kategori kerja
*/
public function getKategoriBadgeClassAttribute()
{
return $this->kategori_kerja === 'Kerja Biasa' ? 'badge-success' : 'badge-warning';
}
/**
* Logika terlambat ditiadakan sesuai permintaan user
*/
public function getIsTerlambatAttribute()
{
return false;
}
/**
* Accessor untuk CSS class badge berdasarkan status
*/
public function getStatusBadgeClassAttribute()
{
$classes = [
self::STATUS_HADIR => 'badge-success',
self::STATUS_SAKIT => 'badge-warning',
self::STATUS_IZIN => 'badge-info'
];
return $classes[$this->status] ?? 'badge-secondary';
}
/**
* Method untuk mengecek apakah absensi sudah lengkap (ada jam masuk dan keluar)
*/
public function isComplete()
{
return !empty($this->jam_masuk) && !empty($this->jam_keluar);
}
/**
* Method untuk mengecek apakah sudah absen masuk
*/
public function hasAbsenMasuk()
{
return !empty($this->jam_masuk);
}
/**
* Method untuk mengecek apakah sudah absen keluar
*/
public function hasAbsenKeluar()
{
return !empty($this->jam_keluar);
}
/**
* Static method untuk mendapatkan statistik absensi berdasarkan periode
*/
public static function getStatistik($startDate = null, $endDate = null)
{
$query = self::query();
if ($startDate && $endDate) {
$query->whereBetween('tanggal', [$startDate, $endDate]);
}
return [
'total' => $query->count(),
'hadir' => $query->where('status', self::STATUS_HADIR)->count(),
'sakit' => $query->where('status', self::STATUS_SAKIT)->count(),
'izin' => $query->where('status', self::STATUS_IZIN)->count(),
];
}
/**
* Boot method untuk event model
*/
protected static function boot()
{
parent::boot();
// Event ketika model akan dihapus
static::deleting(function ($absensi) {
// Hapus file foto jika ada
if ($absensi->foto_absen_masuk && Storage::disk('public')->exists($absensi->foto_absen_masuk)) {
Storage::disk('public')->delete($absensi->foto_absen_masuk);
}
if ($absensi->foto_absen_keluar && Storage::disk('public')->exists($absensi->foto_absen_keluar)) {
Storage::disk('public')->delete($absensi->foto_absen_keluar);
}
});
}
}