chore: stop tracking compiled blade cache
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Helpers\WhatsappHelper;
|
||||
use App\Models\{Cat, Food, Matting, Medicine, Role, Setting, Supply, User};
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class SendOperationalNotifications extends Command
|
||||
{
|
||||
protected $signature = 'ilycats:notify {--dry-run : Tampilkan kandidat tanpa mengirim WhatsApp}';
|
||||
protected $description = 'Mengirim notifikasi WhatsApp HPL, kedaluwarsa inventori, dan berat badan yang belum diperbarui.';
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
if ((Setting::where('key', 'notif_wa_status')->value('value') ?? 'inactive') !== 'active') {
|
||||
$this->info('Notifikasi WhatsApp sedang nonaktif.');
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
$this->sendHplNotifications();
|
||||
$this->sendInventoryExpiryNotifications();
|
||||
$this->sendWeightStaleNotifications();
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
private function recipients(string $settingKey)
|
||||
{
|
||||
$roleId = Setting::where('key', $settingKey)->value('value');
|
||||
$query = User::query()
|
||||
->where('is_active', true)
|
||||
->whereNotNull('phone')
|
||||
->where('phone', '!=', '');
|
||||
|
||||
if ($roleId) {
|
||||
$role = Role::find($roleId);
|
||||
$query->where(function ($q) use ($roleId, $role) {
|
||||
$q->where('role_id', $roleId);
|
||||
// Tetap dukung akun admin lama yang belum mempunyai role_id.
|
||||
if ($role?->slug === 'admin') {
|
||||
$q->orWhere('role', 'admin');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$query->where('role', 'admin');
|
||||
}
|
||||
|
||||
return $query->get();
|
||||
}
|
||||
|
||||
private function sendHplNotifications(): void
|
||||
{
|
||||
if ((Setting::where('key', 'notif_hpl_wa')->value('value') ?? 'active') !== 'active') return;
|
||||
$today = now()->startOfDay();
|
||||
$recipients = $this->recipients('notif_hpl_role_id');
|
||||
|
||||
Matting::with(['dam','sire'])->whereIn('status', ['proses','hamil'])->whereNotNull('tgl_kawin_awal')->get()->each(function ($m) use ($today, $recipients) {
|
||||
$hpl = Carbon::parse($m->tgl_kawin_awal)->startOfDay()->addDays(63);
|
||||
$days = (int) $today->diffInDays($hpl, false);
|
||||
if ($days < 0 || $days > 7) return;
|
||||
$label = $days === 0 ? 'HPL hari ini' : "H-{$days}";
|
||||
$message = "🐾 ILYCats - Pengingat HPL\n\nDam: " . ($m->dam?->nama_kucing ?? '-') . "\nSire: " . ($m->sire?->nama_kucing ?? '-') . "\nHPL: " . $hpl->format('d-m-Y') . "\nStatus: {$label}\n\nMohon pantau kondisi induk dan siapkan kebutuhan persalinan.";
|
||||
foreach ($recipients as $user) {
|
||||
$this->sendOnce("hpl:{$m->id}:{$today->toDateString()}:{$user->id}", 'hpl', $user, $message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private function sendInventoryExpiryNotifications(): void
|
||||
{
|
||||
if ((Setting::where('key', 'notif_inventory_expiry_wa')->value('value') ?? 'active') !== 'active') return;
|
||||
$today = now()->startOfDay();
|
||||
$limit = $today->copy()->addDays(14);
|
||||
$recipients = $this->recipients('notif_inventory_role_id');
|
||||
$types = [
|
||||
'obat' => [Medicine::class, 'nama_obat'],
|
||||
'makanan' => [Food::class, 'nama_makanan'],
|
||||
'perlengkapan' => [Supply::class, 'nama_perlengkapan'],
|
||||
];
|
||||
|
||||
foreach ($types as $type => [$model, $nameField]) {
|
||||
$model::whereNotNull('expired_at')->whereDate('expired_at', '>=', $today)->whereDate('expired_at', '<=', $limit)->get()->each(function ($item) use ($type, $nameField, $today, $recipients) {
|
||||
$expiry = Carbon::parse($item->expired_at)->startOfDay();
|
||||
$days = (int) $today->diffInDays($expiry, false);
|
||||
$message = "⚠️ ILYCats - Kedaluwarsa Inventori\n\nJenis: " . ucfirst($type) . "\nItem: {$item->{$nameField}}\nKedaluwarsa: " . $expiry->format('d-m-Y') . "\nSisa: {$days} hari\nStok: {$item->qty} {$item->unit}\n\nMohon cek stok dan rencanakan penggantian.";
|
||||
foreach ($recipients as $user) {
|
||||
$this->sendOnce("expiry:{$type}:{$item->id}:{$expiry->toDateString()}:{$user->id}", 'inventory_expiry', $user, $message);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private function sendWeightStaleNotifications(): void
|
||||
{
|
||||
if ((Setting::where('key', 'notif_weight_stale_wa')->value('value') ?? 'active') !== 'active') return;
|
||||
$recipients = $this->recipients('notif_weight_role_id');
|
||||
$threshold = now()->subDays(7)->startOfDay();
|
||||
|
||||
Cat::activeInCattery()->withMax('weightHistories as last_weight_at', 'tanggal_timbang')->get()->each(function ($cat) use ($threshold, $recipients) {
|
||||
$last = $cat->last_weight_at ? Carbon::parse($cat->last_weight_at)->startOfDay() : null;
|
||||
if ($last && $last->gte($threshold)) return;
|
||||
$days = $last ? $last->diffInDays(now()->startOfDay()) : null;
|
||||
$lastKey = $last?->toDateString() ?? 'none';
|
||||
$message = "⚖️ ILYCats - Berat Belum Diperbarui\n\nKucing: {$cat->nama_kucing}\nBerat terakhir: " . ($cat->berat_badan ? $cat->berat_badan . ' kg' : '-') . "\nTerakhir ditimbang: " . ($last ? $last->format('d-m-Y') . " ({$days} hari lalu)" : 'belum ada pencatatan') . "\n\nMohon lakukan penimbangan terbaru.";
|
||||
foreach ($recipients as $user) {
|
||||
$this->sendOnce("weight:{$cat->id}:{$lastKey}:{$user->id}", 'weight_stale', $user, $message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private function sendOnce(string $key, string $type, User $user, string $message): void
|
||||
{
|
||||
if (DB::table('notification_dispatches')->where('notification_key', $key)->exists()) return;
|
||||
if ($this->option('dry-run')) {
|
||||
$this->line("[DRY] {$user->name}: {$key}");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
WhatsappHelper::send($user->phone, $message);
|
||||
DB::table('notification_dispatches')->insert([
|
||||
'notification_key' => $key,
|
||||
'type' => $type,
|
||||
'user_id' => $user->id,
|
||||
'channel' => 'whatsapp',
|
||||
'sent_at' => now(),
|
||||
'message' => $message,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error("ILYCats WA notification failed [{$key}]: {$e->getMessage()}");
|
||||
$this->error("Gagal {$key}: {$e->getMessage()}");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user