mailSendService = $mailSendService; } /** * SHJ-6 サーバ死活監視処理メイン実行 * * 処理フロー: * 【処理1】サーバ死活監視(DBアクセス) * 【処理2】デバイス管理マスタを取得する * 【処理3】デバイス毎のハードウェア状態を取得する * 【処理4】プリンタ制御プログラムログを取得する * 【処理5】バッチ処理ログを作成する * ※ 異常時は共通A処理を実行 * * @return array 処理結果 */ public function executeServerMonitoring(): array { $batchLogId = null; $warnings = []; $errorDetails = []; $alertCount = 0; $totalMailSuccessCount = 0; $totalMailErrorCount = 0; $totalQueueSuccessCount = 0; // キュー登録正常終了件数(仕様書準拠) $totalQueueErrorCount = 0; // キュー登録異常終了件数(仕様書準拠) $accumulatedBatchComment = ''; // 累積バッチコメント try { // バッチ処理開始ログ作成 $batchLog = BatchLog::createBatchLog( 'shj6', BatchLog::STATUS_START, [], 'SHJ-6 サーバ死活監視処理開始' ); $batchLogId = $batchLog->id; Log::info('SHJ-6 サーバ死活監視処理開始', [ 'batch_log_id' => $batchLogId ]); // 【処理1】サーバ死活監視(DBアクセス) $dbAccessResult = $this->checkDatabaseAccessWithSettings(); if (!$dbAccessResult['success']) { // DB接続NGの場合は共通A処理実行(キュー種別:101、DB登録可否:0) $commonAResult = $this->executeCommonProcessA( $batchLogId, 'DB接続エラー: ' . $dbAccessResult['message'], self::QUE_CLASS_SERVER_ERROR, null, // park_id null, // user_id null, // contract_id 0, // DB登録可否=0(登録不可) 'サーバ死活監視:DB接続異常検出' ); // メール送信統計を集計 $totalMailSuccessCount += $commonAResult['mail_success_count'] ?? 0; $totalMailErrorCount += $commonAResult['mail_error_count'] ?? 0; $accumulatedBatchComment = $commonAResult['updated_batch_comment'] ?? ''; return [ 'success' => false, 'message' => 'データベース接続エラーが発生しました', 'error_details' => [$dbAccessResult['message']], 'batch_log_id' => $batchLogId, 'mail_success_count' => $totalMailSuccessCount, 'mail_error_count' => $totalMailErrorCount ]; } // DB登録可否フラグを取得 $dbRegisterFlag = $dbAccessResult['db_register_flag']; // 【処理2】デバイス管理マスタを取得する $devices = $this->getServerDevices(); Log::info('サーバーデバイス取得完了', [ 'device_count' => count($devices) ]); // 【処理3】デバイス毎のハードウェア状態を取得する foreach ($devices as $device) { $hardwareResult = $this->checkDeviceHardwareStatus($device, $batchLogId, $dbRegisterFlag); if ($hardwareResult['has_alert']) { $alertCount++; $warnings[] = "デバイスID {$device->device_id}: ハードウェア異常検出"; // 仕様書準拠:メール送信統計とキュー登録統計を集計 $totalMailSuccessCount += $hardwareResult['mail_success_count'] ?? 0; $totalMailErrorCount += $hardwareResult['mail_error_count'] ?? 0; $totalQueueSuccessCount += $hardwareResult['queue_success_count'] ?? 0; $totalQueueErrorCount += $hardwareResult['queue_error_count'] ?? 0; // 仕様書準拠:バッチコメントを累積 if (!empty($hardwareResult['updated_batch_comment'])) { $accumulatedBatchComment .= ($accumulatedBatchComment ? ' | ' : '') . $hardwareResult['updated_batch_comment']; } } } // 【処理4】プリンタ制御プログラムログを取得する $printerResult = $this->checkPrinterErrorLogs($batchLogId, $dbRegisterFlag); if ($printerResult['error_count'] > 0) { $alertCount += $printerResult['error_count']; $warnings[] = "プリンタエラー {$printerResult['error_count']}件検出"; // 仕様書準拠:メール送信統計とキュー登録統計を集計 $totalMailSuccessCount += $printerResult['mail_success_count'] ?? 0; $totalMailErrorCount += $printerResult['mail_error_count'] ?? 0; $totalQueueSuccessCount += $printerResult['queue_success_count'] ?? 0; $totalQueueErrorCount += $printerResult['queue_error_count'] ?? 0; // 仕様書準拠:バッチコメントを累積 if (!empty($printerResult['accumulated_batch_comment'])) { $accumulatedBatchComment .= ($accumulatedBatchComment ? ' | ' : '') . $printerResult['accumulated_batch_comment']; } } // 【処理5】バッチ処理ログを作成する - SHJ-8呼び出し // 仕様書準拠:キュー登録件数も含める $statusComment = sprintf( 'デバイス数: %d, アラート件数: %d, メール正常: %d件, メール異常: %d件, キュー登録正常: %d件, キュー登録異常: %d件', count($devices), $alertCount, $totalMailSuccessCount, $totalMailErrorCount, $totalQueueSuccessCount, $totalQueueErrorCount ); // バッチコメントが累積されている場合は追加 if (!empty($accumulatedBatchComment)) { $statusComment .= ' | ' . $accumulatedBatchComment; } $status = empty($warnings) ? BatchLog::STATUS_SUCCESS : BatchLog::STATUS_WARNING; $message = empty($warnings) ? 'SHJ-6 サーバ死活監視処理正常完了' : 'SHJ-6 サーバ死活監視処理完了(警告あり)'; // 仕様書準拠:処理2で取得したデバイスIDを連結 $deviceIds = array_map(function($device) { return $device->device_id; }, $devices); $concatenatedDeviceIds = !empty($deviceIds) ? implode(',', $deviceIds) : ''; // SHJ-8 バッチ処理ログ作成(仕様書準拠) // device_id = 処理2で取得したデバイスID(複数なら連結) // process_name = 処理4のプロセス名(プリンタログから取得、なければ'SHJ-6') // job_name = "SHJ-6サーバ死活監視" 固定 // status = 常に "success" $shj8Result = $this->createShjBatchLog([ 'device_id' => $concatenatedDeviceIds, // 処理2のデバイスID(連結) 'process_name' => $printerResult['process_name'] ?? 'SHJ-6', // 処理4のプロセス名 'job_name' => 'SHJ-6サーバ死活監視', 'status' => 'success', // 仕様書:常にsuccess 'status_comment' => $statusComment, 'mail_success_count' => $totalMailSuccessCount, 'mail_error_count' => $totalMailErrorCount, 'queue_success_count' => $totalQueueSuccessCount, // 仕様書準拠 'queue_error_count' => $totalQueueErrorCount, // 仕様書準拠 'device_count' => count($devices), 'alert_count' => $alertCount ]); // 仕様書準拠:SHJ-8の戻り値確認(処理結果 = 0以外なら異常) if (!$shj8Result['success']) { $shj8Error = $shj8Result['error'] ?? 'Unknown error'; Log::warning('SHJ-8 バッチ処理ログ作成で異常が発生しました', [ 'error' => $shj8Error ]); // 仕様書準拠:異常時はバッチコメントへ反映 $accumulatedBatchComment .= ($accumulatedBatchComment ? ' | ' : '') . sprintf('SHJ-8異常: %s', $shj8Error); // statusCommentも更新 $statusComment .= sprintf(' | SHJ-8異常: %s', $shj8Error); } // 既存のバッチログも更新 $batchLog->update([ 'status' => empty($warnings) ? BatchLog::STATUS_SUCCESS : BatchLog::STATUS_WARNING, 'end_time' => now(), 'message' => $message, 'success_count' => $totalMailSuccessCount, 'error_count' => $totalMailErrorCount ]); Log::info('SHJ-6 サーバ死活監視処理完了', [ 'batch_log_id' => $batchLogId, 'status_comment' => $statusComment, 'warnings' => $warnings, 'alert_count' => $alertCount, 'mail_success_count' => $totalMailSuccessCount, 'mail_error_count' => $totalMailErrorCount ]); return [ 'success' => true, 'message' => 'SHJ-6 サーバ死活監視処理が完了しました', 'status_comment' => $statusComment, 'warnings' => $warnings, 'alert_count' => $alertCount, 'mail_success_count' => $totalMailSuccessCount, 'mail_error_count' => $totalMailErrorCount, 'batch_log_id' => $batchLogId ]; } catch (\Exception $e) { $errorMessage = 'SHJ-6 サーバ死活監視処理でエラーが発生: ' . $e->getMessage(); if (isset($batchLog) && $batchLog) { $batchLog->update([ 'status' => BatchLog::STATUS_ERROR, 'end_time' => now(), 'message' => $errorMessage, 'error_details' => $e->getMessage(), 'success_count' => $totalMailSuccessCount, 'error_count' => $totalMailErrorCount + 1 ]); } // 例外発生時も共通A処理実行(キュー種別:101、DB登録可否:0) $commonAResult = $this->executeCommonProcessA( $batchLogId, $errorMessage, self::QUE_CLASS_SERVER_ERROR, null, null, null, 0, 'サーバ死活監視:システムエラー発生' ); $totalMailSuccessCount += $commonAResult['mail_success_count'] ?? 0; $totalMailErrorCount += $commonAResult['mail_error_count'] ?? 0; Log::error('SHJ-6 サーバ死活監視処理エラー', [ 'batch_log_id' => $batchLogId, 'exception' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return [ 'success' => false, 'message' => $errorMessage, 'error_details' => [$e->getMessage()], 'batch_log_id' => $batchLogId, 'mail_success_count' => $totalMailSuccessCount, 'mail_error_count' => $totalMailErrorCount ]; } } /** * 【処理1】サーバ死活監視(DBアクセス)- 設定マスタを使用 * * @return array アクセス結果 */ private function checkDatabaseAccessWithSettings(): array { try { // 設定マスタを取得してDB接続確認 $setting = Setting::getSettings(); if (!$setting) { return [ 'success' => false, 'message' => '設定マスタが取得できませんでした', 'db_register_flag' => 0 ]; } Log::info('データベース接続確認成功(設定マスタ取得)', [ 'setting_id' => $setting->setting_id ]); return [ 'success' => true, 'message' => 'データベース接続正常', 'db_register_flag' => 1 // DB登録可能 ]; } catch (\Exception $e) { Log::error('データベース接続エラー', [ 'error' => $e->getMessage() ]); return [ 'success' => false, 'message' => $e->getMessage(), 'db_register_flag' => 0 // DB登録不可 ]; } } /** * 【処理2】サーバーデバイスを取得する * * 条件: * - device_type = 'サーバー' * - device_work = '1' (稼働中) * - device_workstart <= 現在日付 * - device_replace IS NULL * * @return \Illuminate\Support\Collection デバイス情報 */ private function getServerDevices() { try { $devices = DB::table('device') ->select([ 'device_id', 'park_id', 'device_type', 'device_subject', 'device_identifier', 'device_work', 'device_workstart', 'device_remarks' ]) ->where('device_type', self::DEVICE_TYPE_SERVER) ->where('device_work', self::DEVICE_WORK_ACTIVE) ->where('device_workstart', '<=', now()) ->whereNull('device_replace') ->get(); Log::info('サーバーデバイス取得完了', [ 'device_count' => $devices->count() ]); return $devices; } catch (\Exception $e) { Log::error('サーバーデバイス取得エラー', [ 'error' => $e->getMessage() ]); throw $e; } } /** * 【処理3】デバイスのハードウェア状態をチェック * * 直近15分のハードウェアチェックログを確認し、異常時は共通A処理を実行 * * @param object $device デバイス情報 * @param int|null $batchLogId バッチログID * @param int $dbRegisterFlag DB登録可否 * @return array チェック結果(メール送信統計含む) */ private function checkDeviceHardwareStatus($device, ?int $batchLogId, int $dbRegisterFlag): array { try { // 直近15分のログを取得(最新1件) $fifteenMinutesAgo = Carbon::now()->subMinutes(self::MONITOR_PERIOD_MINUTES); $latestLog = DB::table('hardware_check_log') ->where('device_id', $device->device_id) ->where('created_at', '>=', $fifteenMinutesAgo) ->where('created_at', '<=', now()) ->orderBy('created_at', 'desc') ->first(); // ログが取得できない、または異常状態の場合 if (!$latestLog) { // ログが存在しない = 異常 $alertMessage = sprintf( 'ハードウェア監視異常: デバイスID=%d, デバイス名=%s, 理由=直近15分のログが存在しません', $device->device_id, $device->device_subject ?? 'N/A' ); $commonAResult = $this->executeCommonProcessA( $batchLogId, $alertMessage, self::QUE_CLASS_SERVER_ERROR, $device->park_id, null, // user_id null, // contract_id $dbRegisterFlag, 'ハードウェア監視:ログ未検出' ); return [ 'has_alert' => true, 'reason' => 'ログなし', 'mail_success_count' => $commonAResult['mail_success_count'] ?? 0, 'mail_error_count' => $commonAResult['mail_error_count'] ?? 0, 'queue_success_count' => $commonAResult['queue_success_count'] ?? 0, // 仕様書準拠 'queue_error_count' => $commonAResult['queue_error_count'] ?? 0, // 仕様書準拠 'updated_batch_comment' => $commonAResult['updated_batch_comment'] ?? '' ]; } // status != 1(正常)の場合は異常 if ($latestLog->status != HardwareCheckLog::STATUS_NORMAL) { $statusName = HardwareCheckLog::getStatusName($latestLog->status); $alertMessage = sprintf( 'ハードウェア監視異常: デバイスID=%d, デバイス名=%s, 状態=%s, コメント=%s', $device->device_id, $device->device_subject ?? 'N/A', $statusName, $latestLog->status_comment ?? 'N/A' ); $commonAResult = $this->executeCommonProcessA( $batchLogId, $alertMessage, self::QUE_CLASS_SERVER_ERROR, $device->park_id, null, null, $dbRegisterFlag, 'ハードウェア監視:異常状態検出' ); return [ 'has_alert' => true, 'reason' => '異常状態', 'mail_success_count' => $commonAResult['mail_success_count'] ?? 0, 'mail_error_count' => $commonAResult['mail_error_count'] ?? 0, 'queue_success_count' => $commonAResult['queue_success_count'] ?? 0, // 仕様書準拠 'queue_error_count' => $commonAResult['queue_error_count'] ?? 0, // 仕様書準拠 'updated_batch_comment' => $commonAResult['updated_batch_comment'] ?? '' ]; } // 正常 return [ 'has_alert' => false, 'reason' => '正常', 'mail_success_count' => 0, 'mail_error_count' => 0 ]; } catch (\Exception $e) { Log::error('ハードウェア状態チェックエラー', [ 'device_id' => $device->device_id, 'error' => $e->getMessage() ]); return [ 'has_alert' => false, 'reason' => 'エラー', 'mail_success_count' => 0, 'mail_error_count' => 0 ]; } } /** * 【処理4】プリンタエラーログをチェック * * 直近15分のプリンタエラーログ(status >= 100)を確認し、 * エラーログごとに共通A処理を実行 * * 仕様書準拠:ステータス >= 100 を条件とする * * @param int|null $batchLogId バッチログID * @param int $dbRegisterFlag DB登録可否 * @return array チェック結果 */ private function checkPrinterErrorLogs(?int $batchLogId, int $dbRegisterFlag): array { try { // 直近15分のエラーログを取得 $fifteenMinutesAgo = Carbon::now()->subMinutes(self::MONITOR_PERIOD_MINUTES); // 仕様書: ステータス >= 100 // status は varchar型のため CAST で数値変換して比較 $errorLogs = DB::table('print_job_log') ->where('created_at', '>=', $fifteenMinutesAgo) ->where('created_at', '<=', now()) ->whereRaw('CAST(status AS SIGNED) >= 100') ->orderBy('created_at', 'desc') ->get(); Log::info('プリンタエラーログ取得完了', [ 'error_count' => $errorLogs->count(), 'period_minutes' => self::MONITOR_PERIOD_MINUTES ]); // メール送信統計とキュー登録統計(仕様書準拠) $mailSuccessCount = 0; $mailErrorCount = 0; $queueSuccessCount = 0; $queueErrorCount = 0; $accumulatedBatchComment = ''; // エラーログごとに共通A処理を実行 foreach ($errorLogs as $log) { // 仕様書準拠:statusの値に応じてキュー種別を判定 // - status 200番台 → 102(プリンタエラー) // - status 300番台 → 103(スキャナエラー) // - status 400番台 → 104(プリンタ用紙残少警報) $statusValue = (int)$log->status; if ($statusValue >= 400 && $statusValue < 500) { $queClass = self::QUE_CLASS_PAPER_WARNING; // 104 正しい定数名 $errorType = 'プリンタ用紙残少警報'; } elseif ($statusValue >= 300 && $statusValue < 400) { $queClass = self::QUE_CLASS_SCANNER_ERROR; // 103 $errorType = 'スキャナエラー'; } else { $queClass = self::QUE_CLASS_PRINTER_ERROR; // 102(デフォルト) $errorType = 'プリンタエラー'; } $alertMessage = sprintf( '%s: ステータス=%s, プロセス=%s, ジョブ=%s, エラーコード=%d, コメント=%s', $errorType, $log->status ?? 'N/A', $log->process_name ?? 'N/A', $log->job_name ?? 'N/A', $log->error_code ?? 0, $log->status_comment ?? 'N/A' ); $commonAResult = $this->executeCommonProcessA( $batchLogId, $alertMessage, $queClass, // ステータス値に応じて102/103/104 $log->park_id, $log->user_id, $log->contract_id, $dbRegisterFlag, sprintf('プリンタ制御:%s検出', $errorType) ); // 仕様書準拠:メール送信結果とキュー登録結果を集計 $mailSuccessCount += $commonAResult['mail_success_count'] ?? 0; $mailErrorCount += $commonAResult['mail_error_count'] ?? 0; $queueSuccessCount += $commonAResult['queue_success_count'] ?? 0; $queueErrorCount += $commonAResult['queue_error_count'] ?? 0; // 仕様書準拠:バッチコメントを累積 if (!empty($commonAResult['updated_batch_comment'])) { $accumulatedBatchComment .= ($accumulatedBatchComment ? ' | ' : '') . $commonAResult['updated_batch_comment']; } } // 仕様書準拠:処理4のプロセス名を返却(複数件を連結) $processNames = []; foreach ($errorLogs as $log) { if (!empty($log->process_name)) { $processNames[] = $log->process_name; } } // 重複を除去して連結 $processNames = array_unique($processNames); $concatenatedProcessNames = !empty($processNames) ? implode(',', $processNames) : null; return [ 'success' => true, 'error_count' => $errorLogs->count(), 'mail_success_count' => $mailSuccessCount, 'mail_error_count' => $mailErrorCount, 'queue_success_count' => $queueSuccessCount, // 仕様書準拠 'queue_error_count' => $queueErrorCount, // 仕様書準拠 'accumulated_batch_comment' => $accumulatedBatchComment, 'process_name' => $concatenatedProcessNames // 処理4のプロセス名(複数件連結) ]; } catch (\Exception $e) { Log::error('プリンタエラーログチェックエラー', [ 'error' => $e->getMessage() ]); return [ 'success' => false, 'error_count' => 0 ]; } } /** * 共通A処理:監視結果を反映 * * 仕様書準拠: * - SHJ-7 メール送信結果を集計(正常終了件数/異常終了件数) * - 異常時はバッチコメントに SHJ-7 異常情報を追記 * - 更新されたバッチコメントでオペレータキュー登録 * * @param int|null $batchLogId バッチログID * @param string $alertMessage アラートメッセージ * @param int $queClass 対象キュー種別ID(101〜104) * @param int|null $parkId 駐輪場ID * @param int|null $userId 利用者ID * @param int|null $contractId 定期契約ID * @param int $dbRegisterFlag DB登録可否(0=不可、1=可) * @param string|null $batchComment バッチコメント * @return array 処理結果(メール送信統計含む) */ private function executeCommonProcessA( ?int $batchLogId, string $alertMessage, int $queClass, ?int $parkId, ?int $userId, ?int $contractId, int $dbRegisterFlag, ?string $batchComment ): array { // メール送信結果統計 $mailSuccessCount = 0; $mailErrorCount = 0; $mailErrorDetails = []; // キュー登録結果統計(仕様書準拠) $queueSuccessCount = 0; $queueErrorCount = 0; $registeredQueId = null; // 登録したキューID(後で更新するため) try { Log::info('共通A処理開始', [ 'batch_log_id' => $batchLogId, 'alert_message' => $alertMessage, 'que_class' => $queClass, 'park_id' => $parkId, 'db_register_flag' => $dbRegisterFlag ]); // 【共通判断1】DB反映可否判定 if ($dbRegisterFlag === 1) { // DB登録可能な場合 // 仕様書準拠:バッチコメント = 処理1.定期契約ID + 元のバッチコメント $updatedBatchComment = sprintf( '定期契約ID: %s / %s', $contractId ?? 'なし', $batchComment ?? '' ); // 【共通処理1】オペレータキューを登録する(仕様書順序準拠) // 注:SHJ-7異常情報はメール送信後に追記 $queueResult = $this->registerOperatorQueue( $alertMessage, $batchLogId, $queClass, $parkId, $userId, $contractId, $updatedBatchComment ); // 仕様書準拠:キュー登録正常終了件数/異常終了件数を更新 if ($queueResult['success']) { $queueSuccessCount++; $registeredQueId = $queueResult['que_id']; // キューIDを保存 } else { $queueErrorCount++; $updatedBatchComment .= sprintf( ' | キュー登録異常: %s', $queueResult['error'] ?? 'Unknown error' ); } // 【共通処理2】メール送信対象オペレータを取得する $operators = $this->getMailTargetOperators($queClass, $parkId); // 【共通判断2】送信対象有無 if (!empty($operators)) { foreach ($operators as $operator) { $result = $this->sendAlertMail($operator['email'], $alertMessage, 'オペレータ'); // SHJ-7 メール送信結果を集計 if ($result['success']) { $mailSuccessCount++; } else { $mailErrorCount++; $mailErrorDetails[] = sprintf( 'オペレータ[%s]へのメール送信失敗: %s', $operator['email'], $result['error'] ?? 'Unknown error' ); } } } // 【共通処理3】駐輪場管理者を取得する $parkManagers = $this->getParkManagers($parkId); // 【共通判断3】送信対象有無 if (!empty($parkManagers)) { foreach ($parkManagers as $manager) { $result = $this->sendAlertMail($manager['email'], $alertMessage, '駐輪場管理者'); // SHJ-7 メール送信結果を集計 if ($result['success']) { $mailSuccessCount++; } else { $mailErrorCount++; $mailErrorDetails[] = sprintf( '駐輪場管理者[%s]へのメール送信失敗: %s', $manager['email'], $result['error'] ?? 'Unknown error' ); } } } // 仕様書準拠:メール異常時にSHJ-7異常情報を追記 if ($mailErrorCount > 0) { $updatedBatchComment .= sprintf( ' | SHJ-7メール異常: %d件 (%s)', $mailErrorCount, implode('; ', $mailErrorDetails) ); } // 仕様書準拠:キュー登録後、SHJ-7異常情報を含めてキューコメントを更新 // キューコメント = 内部変数.バッチコメント(定期契約ID + SHJ-7異常情報) if ($registeredQueId && $mailErrorCount > 0) { try { OperatorQue::where('que_id', $registeredQueId)->update([ // 主キーはque_id 'que_comment' => $updatedBatchComment, // 仕様書:キューコメントに追記 'updated_at' => now() ]); Log::info('オペレータキューコメント更新完了(SHJ-7異常情報追記)', [ 'que_id' => $registeredQueId, 'updated_comment' => $updatedBatchComment ]); } catch (\Exception $e) { Log::error('オペレータキューコメント更新エラー', [ 'que_id' => $registeredQueId, 'error' => $e->getMessage() ]); } } } else { // DB反映NGの場合は固定メールアドレスに緊急メール送信 // 仕様書準拠:テンプレート不使用、件名固定、本文なし $result = $this->sendEmergencyMail( self::FIXED_EMAIL_ADDRESS, $alertMessage ); if ($result['success']) { $mailSuccessCount++; } else { $mailErrorCount++; $mailErrorDetails[] = sprintf( '固定アドレス[%s]への緊急メール送信失敗: %s', self::FIXED_EMAIL_ADDRESS, $result['error'] ?? 'Unknown error' ); } $updatedBatchComment = $batchComment ?? ''; if ($mailErrorCount > 0) { $updatedBatchComment .= sprintf( ' | 緊急メール異常: %d件 (%s)', $mailErrorCount, implode('; ', $mailErrorDetails) ); } } Log::info('共通A処理完了', [ 'batch_log_id' => $batchLogId, 'que_class' => $queClass, 'mail_success_count' => $mailSuccessCount, 'mail_error_count' => $mailErrorCount, 'queue_success_count' => $queueSuccessCount, 'queue_error_count' => $queueErrorCount, 'updated_batch_comment' => $updatedBatchComment ?? $batchComment ]); return [ 'success' => true, 'mail_success_count' => $mailSuccessCount, 'mail_error_count' => $mailErrorCount, 'mail_error_details' => $mailErrorDetails, 'queue_success_count' => $queueSuccessCount, // 仕様書準拠 'queue_error_count' => $queueErrorCount, // 仕様書準拠 'updated_batch_comment' => $updatedBatchComment ?? $batchComment ]; } catch (\Exception $e) { Log::error('共通A処理エラー', [ 'batch_log_id' => $batchLogId, 'que_class' => $queClass, 'error' => $e->getMessage() ]); $updatedBatchComment = ($batchComment ?? '') . ' | 共通A処理エラー: ' . $e->getMessage(); return [ 'success' => false, 'mail_success_count' => $mailSuccessCount, 'mail_error_count' => $mailErrorCount, 'mail_error_details' => $mailErrorDetails, 'queue_success_count' => $queueSuccessCount, 'queue_error_count' => $queueErrorCount, 'updated_batch_comment' => $updatedBatchComment, 'error' => $e->getMessage() ]; } } /** * オペレータキューを登録 * * 仕様書準拠: * - 定期契約IDをバッチコメントに含める * - 登録の成否とque_idを返却(後で更新するため) * * @param string $alertMessage アラートメッセージ * @param int|null $batchLogId バッチログID * @param int $queClass 対象キュー種別ID(101〜104) * @param int|null $parkId 駐輪場ID * @param int|null $userId 利用者ID * @param int|null $contractId 定期契約ID * @param string|null $batchComment バッチコメント(SHJ-7異常情報は後で追記) * @return array 登録結果 ['success' => bool, 'error' => string|null, 'que_id' => int|null] */ private function registerOperatorQueue( string $alertMessage, ?int $batchLogId, int $queClass, ?int $parkId, ?int $userId, ?int $contractId, ?string $batchComment ): array { try { // 仕様書準拠(todo/SHJ-6/SHJ-6.txt:170-182): // - キューコメント = 内部変数.バッチコメント // - キューステータスコメント = "" (空) // - 業務指示コメント = "" (空) $operatorQue = OperatorQue::create([ 'que_class' => $queClass, 'user_id' => $userId, 'contract_id' => $contractId, 'park_id' => $parkId, 'que_comment' => $batchComment ?? '', // 仕様書:内部変数.バッチコメント(SHJ-7異常情報は後で追記) 'que_status' => 1, // キュー発生 'que_status_comment' => '', // 仕様書:空文字列 'work_instructions' => '', // 仕様書:空文字列 'operator_id' => 9999999, // 仕様書準拠:固定値 'created_at' => now(), 'updated_at' => now() ]); Log::info('オペレータキュー登録完了', [ 'batch_log_id' => $batchLogId, 'que_class' => $queClass, 'que_id' => $operatorQue->que_id, // 主キーはque_id 'park_id' => $parkId, 'user_id' => $userId, 'contract_id' => $contractId ]); return [ 'success' => true, 'error' => null, 'que_id' => $operatorQue->que_id // 仕様書準拠:主キーque_idを返却 ]; } catch (\Exception $e) { Log::error('オペレータキュー登録エラー', [ 'batch_log_id' => $batchLogId, 'que_class' => $queClass, 'error' => $e->getMessage() ]); return [ 'success' => false, 'error' => $e->getMessage(), 'que_id' => null ]; } } /** * メール送信対象オペレータを取得 * * 管轄駐輪場マスタをJOINして、指定駐輪場を管轄しているオペレータのみ取得 * * キュー種別IDに応じた送信フラグをチェック: * - 101(サーバーエラー) → ope_sendalart_que10 * - 102(プリンタエラー) → ope_sendalart_que11 * - 103(スキャナエラー) → ope_sendalart_que12 * - 104(プリンタ用紙残少) → ope_sendalart_que13 * * @param int $queClass 対象キュー種別ID * @param int|null $parkId 駐輪場ID(nullの場合は全オペレータ) * @return array オペレータ一覧 */ private function getMailTargetOperators(int $queClass, ?int $parkId): array { try { // キュー種別IDに対応する送信フラグカラム名を決定 $alertFlagColumn = $this->getOperatorAlertFlagColumn($queClass); if (empty($alertFlagColumn)) { Log::warning('不正なキュー種別ID', ['que_class' => $queClass]); return []; } // 管轄駐輪場マスタをJOINしてオペレータを取得 $query = DB::table('ope as T1') ->select(['T1.ope_id', 'T1.ope_name', 'T1.ope_mail']) ->where('T1.' . $alertFlagColumn, 1) // 該当アラート送信フラグが有効 ->where('T1.ope_quit_flag', 0) // 退職していない ->whereNotNull('T1.ope_mail') ->where('T1.ope_mail', '!=', ''); // 駐輪場IDが指定されている場合は管轄駐輪場マスタでフィルタ if ($parkId !== null) { $query->join('jurisdiction_parking as T2', 'T1.ope_id', '=', 'T2.ope_id') ->where('T2.park_id', $parkId); } $operators = $query->get() ->map(function ($ope) { return [ 'ope_id' => $ope->ope_id, 'name' => $ope->ope_name, 'email' => $ope->ope_mail ]; }) ->toArray(); Log::info('メール送信対象オペレータ取得完了', [ 'que_class' => $queClass, 'park_id' => $parkId, 'alert_flag_column' => $alertFlagColumn, 'operator_count' => count($operators) ]); return $operators; } catch (\Exception $e) { Log::error('メール送信対象オペレータ取得エラー', [ 'que_class' => $queClass, 'park_id' => $parkId, 'error' => $e->getMessage() ]); return []; } } /** * キュー種別IDに対応するオペレータ送信フラグカラム名を取得 * * @param int $queClass キュー種別ID * @return string|null カラム名 */ private function getOperatorAlertFlagColumn(int $queClass): ?string { $mapping = [ 101 => 'ope_sendalart_que10', // サーバーエラー 102 => 'ope_sendalart_que11', // プリンタエラー 103 => 'ope_sendalart_que12', // スキャナエラー 104 => 'ope_sendalart_que13', // プリンタ用紙残少警報 ]; return $mapping[$queClass] ?? null; } /** * 駐輪場管理者を取得 * * 駐輪場管理者マスタから指定駐輪場の管理者を取得: * - 退職フラグ = 0(在職中) * - メールアドレスが設定されている * - 所属駐輪場ID = 指定駐輪場ID * * @param int|null $parkId 駐輪場ID(nullの場合は全管理者) * @return array 駐輪場管理者一覧 */ private function getParkManagers(?int $parkId): array { try { $query = Manager::active()->hasEmail(); // 駐輪場IDが指定されている場合はフィルタ if ($parkId !== null) { $query->where('manager_parkid', $parkId); } $managers = $query->select(['manager_id', 'manager_name', 'manager_mail', 'manager_parkid']) ->get() ->map(function ($manager) { return [ 'manager_id' => $manager->manager_id, 'name' => $manager->manager_name, 'email' => $manager->manager_mail, 'park_id' => $manager->manager_parkid ]; }) ->toArray(); Log::info('駐輪場管理者取得完了', [ 'park_id' => $parkId, 'manager_count' => count($managers) ]); return $managers; } catch (\Exception $e) { Log::error('駐輪場管理者取得エラー', [ 'park_id' => $parkId, 'error' => $e->getMessage() ]); return []; } } /** * アラートメールを送信(SHJ-7) * * 仕様書準拠: * - SHJ-7 メール送信サービスを呼び出し * - 戻り値(成功/失敗、異常情報)を返却 * * @param string $email メールアドレス * @param string $alertMessage アラートメッセージ * @param string $recipientType 受信者タイプ * @return array 送信結果 ['success' => bool, 'error' => string|null] */ private function sendAlertMail(string $email, string $alertMessage, string $recipientType): array { try { // SHJ-7 メール送信機能を使用(メールテンプレートID=202を使用) $result = $this->mailSendService->executeMailSend( $email, '', // 予備メールアドレスは空 self::SYSTEM_ALERT_MAIL_TEMPLATE_ID ); if ($result['success']) { Log::info('アラートメール送信成功', [ 'email' => $email, 'recipient_type' => $recipientType, 'alert_message' => $alertMessage ]); return [ 'success' => true, 'error' => null ]; } else { Log::error('アラートメール送信失敗', [ 'email' => $email, 'recipient_type' => $recipientType, 'error' => $result['message'] ]); return [ 'success' => false, 'error' => $result['message'] ?? 'メール送信失敗' ]; } } catch (\Exception $e) { Log::error('アラートメール送信エラー', [ 'email' => $email, 'recipient_type' => $recipientType, 'error' => $e->getMessage() ]); return [ 'success' => false, 'error' => $e->getMessage() ]; } } /** * DB反映不可時の緊急メール送信 * * 仕様書準拠: * - テンプレート不使用 * - 件名: 「So-Manager:死活監視DBアタッチエラー(SHJ-6)」固定 * - 本文: なし(空) * - 固定アドレスに直接送信 * * @param string $email 送信先メールアドレス * @param string $alertMessage アラートメッセージ(ログ用) * @return array 送信結果 ['success' => bool, 'error' => string|null] */ private function sendEmergencyMail(string $email, string $alertMessage): array { try { // 仕様書準拠:件名固定、本文なし $subject = 'So-Manager:死活監視DBアタッチエラー(SHJ-6)'; $body = ''; // 本文なし // Laravelの Mail facade を使用して直接送信 \Illuminate\Support\Facades\Mail::raw($body, function ($message) use ($email, $subject) { $message->to($email) ->subject($subject); }); Log::info('緊急メール送信成功', [ 'email' => $email, 'subject' => $subject, 'alert_message' => $alertMessage ]); return [ 'success' => true, 'error' => null ]; } catch (\Exception $e) { Log::error('緊急メール送信エラー', [ 'email' => $email, 'alert_message' => $alertMessage, 'error' => $e->getMessage() ]); return [ 'success' => false, 'error' => $e->getMessage() ]; } } /** * 【処理5】SHJ-8 バッチ処理ログ作成 * * 仕様書に基づくSHJ-8共通処理呼び出し * BatchLogシステムを使用してバッチ処理の実行ログを記録 * * @param array $statistics 処理統計情報 * @return array 処理結果 ['success' => bool, 'error' => string|null] */ private function createShjBatchLog(array $statistics): array { try { // 仕様書準拠のSHJ-8パラメータ設定 // device_id: 処理2で取得したデバイスID(複数なら連結文字列) // process_name: 処理4のプロセス名 $deviceId = $statistics['device_id']; // 連結されたデバイスID文字列 $processName = $statistics['process_name'] ?? 'SHJ-6'; $jobName = $statistics['job_name']; // "SHJ-6サーバ死活監視" 固定 $status = $statistics['status']; // 常に "success" $statusComment = $statistics['status_comment'] ?? ''; $createdDate = now()->format('Y/m/d'); $updatedDate = now()->format('Y/m/d'); Log::info('SHJ-8 バッチ処理ログ作成', [ 'device_id' => $deviceId, 'process_name' => $processName, 'job_name' => $jobName, 'status' => $status, 'status_comment' => $statusComment, 'created_date' => $createdDate, 'updated_date' => $updatedDate ]); // 共通処理 SHJ-8 バッチ処理ログ作成を呼び出し // BatchLog::createBatchLog を使用して統一的にログを記録 $batchLog = BatchLog::createBatchLog( $processName, $status, [ 'device_id' => $deviceId, 'job_name' => $jobName, 'status_comment' => $statusComment, 'statistics' => $statistics, 'shj8_params' => [ 'device_id' => $deviceId, 'process_name' => $processName, 'job_name' => $jobName, 'status' => $status, 'created_date' => $createdDate, 'updated_date' => $updatedDate ] ], $statusComment ); Log::info('SHJ-8 バッチ処理ログ作成完了', [ 'device_id' => $deviceId, 'process_name' => $processName, 'batch_log_id' => $batchLog->id ]); return [ 'success' => true, 'error' => null ]; } catch (\Exception $e) { Log::error('SHJ-8 バッチ処理ログ作成エラー', [ 'error' => $e->getMessage(), 'statistics' => $statistics ]); // 仕様書準拠:SHJ-8でエラーが発生してもメイン処理は継続 // エラー情報を返却 return [ 'success' => false, 'error' => $e->getMessage() ]; } } }