'date', 'violation_time' => 'datetime:H:i', 'is_verified' => 'boolean', 'verified_at' => 'datetime', 'handled_at' => 'datetime', 'points' => 'integer', ]; } public function student(): BelongsTo { return $this->belongsTo(Student::class); } public function violationType(): BelongsTo { return $this->belongsTo(ViolationType::class, 'violation_type_id'); } public function recorder(): BelongsTo { return $this->belongsTo(User::class, 'recorded_by'); } public function verifier(): BelongsTo { return $this->belongsTo(User::class, 'verified_by'); } public function evidences(): HasMany { return $this->hasMany(ViolationEvidence::class); } public function notifications(): HasMany { return $this->hasMany(ViolationNotification::class); } /** * Bangun notifikasi WA untuk orang tua/wali. * * @return array{0: string, 1: string}|null [nomor_wa, pesan] — null bila HP ortu belum diisi */ public function buildWaNotification(): ?array { $student = $this->student; if (! $student || ! $student->parent_phone) { return null; } // Normalisasi nomor Indonesia: 08xx / 8xx → 628xx $phone = preg_replace('/\D/', '', $student->parent_phone); if (str_starts_with($phone, '0')) { $phone = '62'.substr($phone, 1); } elseif (str_starts_with($phone, '8')) { $phone = '62'.$phone; } if (strlen($phone) < 10) { return null; } $template = trim((string) \App\Models\Setting::getValue('wa_notification_template', '')); if ($template === '') { $template = "Yth. Bapak/Ibu Wali dari {nama_siswa} ({kelas}),\n\n" ."Dengan hormat, kami informasikan bahwa ananda tercatat melakukan pelanggaran:\n" ."• Jenis: {jenis}\n" ."• Tanggal: {tanggal}\n" ."• Poin: {poin}\n\n" ."Total poin ananda saat ini: {total_poin}.\n\n" ."Demikian disampaikan, atas perhatian dan kerja samanya kami ucapkan terima kasih.\n\n" ."Tim Ketertiban\n{sekolah}"; } $placeholders = [ '{nama_siswa}' => $student->full_name, '{nisn}' => $student->nisn, '{kelas}' => $student->class_name, '{jenis}' => $this->violationType?->name ?? '-', '{tanggal}' => $this->violation_date ? $this->violation_date->format('d/m/Y') : '-', '{waktu}' => $this->violation_time ? $this->violation_time->format('H:i') : '-', '{poin}' => (string) $this->points, '{total_poin}' => (string) ($student->total_points ?? 0), '{lokasi}' => $this->location ?: '-', '{deskripsi}' => $this->description ?: '-', '{sekolah}' => (string) \App\Models\Setting::getValue('school_name', 'SMKN 1 Wonorejo'), ]; return [$phone, strtr($template, $placeholders)]; } public function handlings(): HasMany { return $this->hasMany(ViolationHandling::class); } public function handler(): BelongsTo { return $this->belongsTo(User::class, 'handled_by'); } public function isUnhandled(): bool { return $this->handling_status === 'unhandled'; } public function isInProgress(): bool { return $this->handling_status === 'in_progress'; } public function isResolved(): bool { return $this->handling_status === 'resolved'; } }