info('Starting NDT reminder checks...'); $totalNotifications = 0; // Check overdue NDT tests $totalNotifications += $this->checkOverdueTests(); // Check missing test reports $totalNotifications += $this->checkMissingReports(); // Check deadline approaching tests (within 3 days) $totalNotifications += $this->checkDeadlineApproaching(); // Check pending results $totalNotifications += $this->checkPendingResults(); $this->info("NDT reminder check completed. Sent {$totalNotifications} notifications."); return 0; } /** * Check for overdue NDT tests * Performance: Single query with multiple conditions */ private function checkOverdueTests() { $overdueThreshold = Carbon::now()->subDays(7); // 7 days overdue $nullableColumns = $this->availableColumns('weld_logs', [ 'rt_testing_date', 'ut_testing_date', 'pt_testing_date', 'mt_testing_date' ]); if (empty($nullableColumns)) { $this->info('Skipping overdue check: weld_logs table lacks test date columns.'); return 0; } $ids = DB::table('weld_logs') ->where('welding_date', '<=', $overdueThreshold) ->where(function($query) use ($nullableColumns) { foreach ($nullableColumns as $column) { $query->orWhereNull($column); } }) ->pluck('id') ->toArray(); return $this->sendWeldLogBatch( 'notification_ndt_test_overdue', 'NDT Test Overdue', '%d weld log(s) have welding dates older than 7 days without NDT testing.', $ids ); } /** * Check for missing test reports * Performance: Checks only records with test dates but no results */ private function checkMissingReports() { $checkDate = Carbon::now()->subDays(3); // 3 days after test date $rtIds = []; if ($this->columnsAvailable('weld_logs', ['rt_testing_date', 'rt_result'])) { $rtIds = DB::table('weld_logs') ->whereNotNull('rt_testing_date') ->where('rt_testing_date', '<=', $checkDate) ->where(function($query) { $query->whereNull('rt_result') ->orWhere('rt_result', ''); }) ->pluck('id') ->toArray(); } $utIds = []; if ($this->columnsAvailable('weld_logs', ['ut_testing_date', 'ut_result'])) { $utIds = DB::table('weld_logs') ->whereNotNull('ut_testing_date') ->where('ut_testing_date', '<=', $checkDate) ->where(function($query) { $query->whereNull('ut_result') ->orWhere('ut_result', ''); }) ->pluck('id') ->toArray(); } $notifications = 0; $notifications += $this->sendWeldLogBatch( 'notification_ndt_report_missing', 'RT Report Missing', '%d RT test(s) have results pending more than 3 days.', $rtIds ); $notifications += $this->sendWeldLogBatch( 'notification_ndt_report_missing', 'UT Report Missing', '%d UT test(s) have results pending more than 3 days.', $utIds ); return $notifications; } /** * Check for tests with approaching deadlines * Performance: Single query with date calculation */ private function checkDeadlineApproaching() { $warnDate = Carbon::now()->subDays(4); // Welded 4 days ago, should be tested within 7 days $graceDate = Carbon::now()->subDays(7); $dateColumns = array_filter($this->availableColumns('weld_logs', ['rt_testing_date', 'ut_testing_date'])); if (empty($dateColumns)) { $this->info('Skipping deadline approaching check: weld_logs table lacks RT/UT testing date columns.'); return 0; } $ids = DB::table('weld_logs') ->whereBetween('welding_date', [$graceDate, $warnDate]) // Fixed: older date first, newer date second ->where(function($query) use ($dateColumns) { foreach ($dateColumns as $column) { $query->orWhereNull($column); } }) ->pluck('id') ->toArray(); return $this->sendWeldLogBatch( 'notification_test_deadline_approaching', 'Test Deadline Approaching', '%d weld log(s) are approaching the 7-day NDT testing deadline.', $ids ); } /** * Check for pending test results * Performance: Optimized with specific conditions */ private function checkPendingResults() { $pendingThreshold = Carbon::now()->subDays(2); $ids = []; $rtColumnsAvailable = $this->columnsAvailable('weld_logs', ['rt_testing_date', 'rt_result']); $utColumnsAvailable = $this->columnsAvailable('weld_logs', ['ut_testing_date', 'ut_result']); if (!$rtColumnsAvailable && !$utColumnsAvailable) { $this->info('Skipping pending results check: weld_logs table lacks RT/UT result columns.'); return 0; } $query = DB::table('weld_logs') ->where(function($query) use ($pendingThreshold) { if ($this->columnsAvailable('weld_logs', ['rt_testing_date', 'rt_result'])) { $query->orWhere(function($q) use ($pendingThreshold) { $q->whereNotNull('rt_testing_date') ->where('rt_testing_date', '<=', $pendingThreshold) ->where(function($sq) { $sq->whereNull('rt_result') ->orWhere('rt_result', ''); }); }); } if ($this->columnsAvailable('weld_logs', ['ut_testing_date', 'ut_result'])) { $query->orWhere(function($q) use ($pendingThreshold) { $q->whereNotNull('ut_testing_date') ->where('ut_testing_date', '<=', $pendingThreshold) ->where(function($sq) { $sq->whereNull('ut_result') ->orWhere('ut_result', ''); }); }); } }); $ids = $query->pluck('id')->toArray(); return $this->sendWeldLogBatch( 'notification_ndt_result_pending', 'NDT Result Pending', '%d weld log(s) have completed NDT tests but results are pending more than 2 days.', $ids ); } private function sendWeldLogBatch(string $notificationCode, string $title, string $messageTemplate, array $ids): int { $ids = array_values(array_unique(array_filter($ids))); if (empty($ids)) { $this->info("No {$title} notifications to send."); return 0; } $filterParams = [ 'table' => 'weld_logs', 'conditions' => [ 'id' => $ids ] ]; sendBatchNotificationWithFilter( $notificationCode, $title, $messageTemplate, $filterParams, count($ids) ); $this->info("Sent batch notification for {$title} (" . count($ids) . " joints)."); return 1; } private function availableColumns(string $table, array $columns): array { return array_values(array_filter($columns, function($column) use ($table) { return Schema::hasColumn($table, $column); })); } private function columnsAvailable(string $table, array $columns): bool { return count($this->availableColumns($table, $columns)) === count($columns); } }