'datetime', 'persentase_pekerjaan' => 'integer', ]; // Status progres options public static $statusProgres = [ 'belum_mulai' => 'Belum Mulai', 'dalam_progres' => 'Dalam Progres', 'terhenti' => 'Terhenti', 'selesai' => 'Selesai', 'ditunda' => 'Ditunda' ]; // Boot method untuk auto update tanggal_update protected static function boot() { parent::boot(); static::creating(function ($model) { $model->tanggal_update = now(); }); static::updating(function ($model) { $model->tanggal_update = now(); }); } // Relationships public function teknisi() { return $this->belongsTo(Teknisi::class, 'id_teknisi', 'id_teknisi'); } public function penugasan() { return $this->belongsTo(Penugasan::class, 'id_penugasan', 'id_penugasan'); } // Scopes public function scopeByStatus($query, $status) { return $query->where('status_progres', $status); } public function scopeByTeknisi($query, $teknisiId) { return $query->where('id_teknisi', $teknisiId); } public function scopeByDateRange($query, $startDate = null, $endDate = null) { if ($startDate) { $query->whereDate('tanggal_update', '>=', $startDate); } if ($endDate) { $query->whereDate('tanggal_update', '<=', $endDate); } return $query; } // Accessors public function getStatusFormattedAttribute() { return self::$statusProgres[$this->status_progres] ?? 'Unknown'; } public function getStatusBadgeClassAttribute() { $badgeClasses = [ 'belum_mulai' => 'badge-secondary', 'dalam_progres' => 'badge-primary', 'terhenti' => 'badge-danger', 'selesai' => 'badge-success', 'ditunda' => 'badge-warning' ]; return $badgeClasses[$this->status_progres] ?? 'badge-secondary'; } public function getTanggalUpdateFormattedAttribute() { return $this->tanggal_update ? $this->tanggal_update->format('d/m/Y H:i') : '-'; } public function getHasFotoAttribute() { return !empty($this->foto_progress); } public function getFotoProgressUrlAttribute() { if ($this->foto_progress) { return asset('storage/progress_photos/' . $this->foto_progress); } return null; } public function getDaysSinceUpdateAttribute() { if ($this->tanggal_update) { return $this->tanggal_update->diffInDays(now()); } return 0; } // Methods public function autoUpdateStatus() { $percentage = $this->persentase_pekerjaan; if ($percentage == 0) { $newStatus = 'belum_mulai'; } elseif ($percentage > 0 && $percentage < 100) { $newStatus = 'dalam_progres'; } elseif ($percentage == 100) { $newStatus = 'selesai'; } else { return; // No change needed } // Only update if status is different if ($this->status_progres !== $newStatus) { $this->update(['status_progres' => $newStatus]); } } public function canTransitionTo($newStatus) { $allowedTransitions = [ 'belum_mulai' => ['dalam_progres', 'ditunda'], 'dalam_progres' => ['terhenti', 'selesai', 'ditunda'], 'terhenti' => ['dalam_progres', 'ditunda'], 'selesai' => [], // Cannot transition from completed 'ditunda' => ['belum_mulai', 'dalam_progres'] ]; $currentStatus = $this->status_progres; return in_array($newStatus, $allowedTransitions[$currentStatus] ?? []); } // Static methods public static function getByTeknisi($teknisiId) { return self::with(['teknisi', 'penugasan']) ->where('id_teknisi', $teknisiId) ->orderBy('tanggal_update', 'desc') ->get(); } public static function getRecentUpdates($limit = 10) { return self::with(['teknisi', 'penugasan']) ->orderBy('tanggal_update', 'desc') ->limit($limit) ->get(); } public static function getStatistics() { $total = self::count(); $byStatus = self::selectRaw('status_progres, COUNT(*) as count') ->groupBy('status_progres') ->pluck('count', 'status_progres') ->toArray(); $statistics = [ 'total' => $total, 'belum_mulai' => $byStatus['belum_mulai'] ?? 0, 'dalam_progres' => $byStatus['dalam_progres'] ?? 0, 'terhenti' => $byStatus['terhenti'] ?? 0, 'selesai' => $byStatus['selesai'] ?? 0, 'ditunda' => $byStatus['ditunda'] ?? 0, ]; // Add percentages if ($total > 0) { $statistics['completion_rate'] = round(($statistics['selesai'] / $total) * 100, 1); $statistics['in_progress_rate'] = round(($statistics['dalam_progres'] / $total) * 100, 1); } else { $statistics['completion_rate'] = 0; $statistics['in_progress_rate'] = 0; } return $statistics; } public static function getOverdueProgress($days = 7) { return self::with(['teknisi', 'penugasan']) ->whereIn('status_progres', ['dalam_progres', 'terhenti']) ->where('tanggal_update', '<', now()->subDays($days)) ->orderBy('tanggal_update', 'asc') ->get(); } public static function getProgressSummaryByTeknisi() { return self::with('teknisi') ->selectRaw('id_teknisi, status_progres, COUNT(*) as count') ->groupBy('id_teknisi', 'status_progres') ->get() ->groupBy('id_teknisi') ->map(function ($items) { $teknisi = $items->first()->teknisi; $summary = [ 'teknisi_id' => $teknisi->id_teknisi, 'teknisi_nama' => $teknisi->nama, 'total' => $items->sum('count'), 'belum_mulai' => 0, 'dalam_progres' => 0, 'terhenti' => 0, 'selesai' => 0, 'ditunda' => 0, ]; foreach ($items as $item) { $summary[$item->status_progres] = $item->count; } return $summary; }) ->values(); } }