diff --git a/app/Console/Commands/ShjBatchLogCommand.php b/app/Console/Commands/ShjBatchLogCommand.php index 8d103e5..b68128e 100644 --- a/app/Console/Commands/ShjBatchLogCommand.php +++ b/app/Console/Commands/ShjBatchLogCommand.php @@ -4,54 +4,70 @@ namespace App\Console\Commands; use Illuminate\Console\Command; use Illuminate\Support\Facades\Log; -use App\Models\Batch\BatchLog; -use App\Models\Device; +use App\Services\ShjEightService; /** * SHJ-8 バッチ処理ログ登録コマンド - * - * 統一BatchLogを使用してバッチ処理の実行ログをbatch_logテーブルに登録する - * 仕様書に基づくSHJ-8の要求パラメータを受け取り、通用のログシステムで記録 + * + * bat_job_logテーブルにバッチ処理の実行ログを登録する + * ShjEightServiceを使用して実装 */ class ShjBatchLogCommand extends Command { + /** + * ShjEightService インスタンス + * + * @var ShjEightService + */ + protected $shjEightService; + /** * コンソールコマンドの名前とシグネチャ - * - * 引数: + * + * 修正版:7項目(status_comment追加) * - device_id: デバイスID (必須) - * - process_name: プロセス名 (必須) - * - job_name: ジョブ名 (必須) * - status: ステータス (必須) + * - status_comment: ステータスコメント (必須) * - created_date: 登録日時 (必須、yyyy/mm/dd形式) * - updated_date: 更新日時 (必須、yyyy/mm/dd形式) + * - process_name: プロセス名 (オプション) + * - job_name: ジョブ名 (オプション) * * @var string */ - protected $signature = 'shj:batch-log {device_id : デバイスID} {process_name : プロセス名} {job_name : ジョブ名} {status : ステータス} {created_date : 登録日時} {updated_date : 更新日時}'; + protected $signature = 'shj:batch-log + {device_id : デバイスID} + {status : ステータス} + {status_comment : ステータスコメント} + {created_date : 登録日時} + {updated_date : 更新日時} + {process_name? : プロセス名} + {job_name? : ジョブ名}'; /** * コンソールコマンドの説明 * * @var string */ - protected $description = 'SHJ-8 バッチ処理ログ登録 - バッチ処理の実行ログを登録'; + protected $description = 'SHJ-8 バッチ処理ログ登録 - bat_job_logテーブルにバッチ処理の実行ログを登録'; /** * コンストラクタ + * + * @param ShjEightService $shjEightService */ - public function __construct() + public function __construct(ShjEightService $shjEightService) { parent::__construct(); + $this->shjEightService = $shjEightService; } /** * コンソールコマンドを実行 - * + * * 処理フロー: - * 1. 入力パラメーターをチェックする - * 2. 統一BatchLogを使用してbatch_logテーブルに記録 - * 3. 仕様書準拠の処理結果を返却する + * 1. ShjEightServiceを呼び出して処理を実行 + * 2. 処理結果を返却する * * @return int */ @@ -61,12 +77,13 @@ class ShjBatchLogCommand extends Command // 開始ログ出力 $startTime = now(); $this->info('SHJ-8 バッチ処理ログ登録を開始します。'); - + // 引数取得 $deviceId = (int) $this->argument('device_id'); $processName = $this->argument('process_name'); $jobName = $this->argument('job_name'); $status = $this->argument('status'); + $statusComment = $this->argument('status_comment'); $createdDate = $this->argument('created_date'); $updatedDate = $this->argument('updated_date'); @@ -76,163 +93,71 @@ class ShjBatchLogCommand extends Command 'process_name' => $processName, 'job_name' => $jobName, 'status' => $status, + 'status_comment' => $statusComment, 'created_date' => $createdDate, 'updated_date' => $updatedDate ]); - // 【処理1】入力パラメーターをチェックする - $paramCheckResult = $this->validateParameters($deviceId, $processName, $jobName, $status, $createdDate, $updatedDate); - if (!$paramCheckResult['valid']) { - $this->error('パラメータエラー: ' . $paramCheckResult['message']); - - // 仕様書【判断1】パラメーターNG時の結果出力 - $this->line('処理結果: 1'); // 1 = 異常終了 - $this->line('異常情報: ' . $paramCheckResult['message']); - - return self::FAILURE; - } - - // 【処理2】統一BatchLogを使用してログ登録 - $batchLog = BatchLog::createBatchLog( - $processName, // 実際のプロセス名を使用 + // ShjEightServiceを呼び出して処理を実行 + $result = $this->shjEightService->execute( + $deviceId, + $processName, + $jobName, $status, - [ - 'device_id' => $deviceId, - 'job_name' => $jobName, - 'status_comment' => BatchLog::getSuccessComment(), - 'input_created_date' => $createdDate, - 'input_updated_date' => $updatedDate, - 'shj8_params' => [ - 'device_id' => $deviceId, - 'process_name' => $processName, - 'job_name' => $jobName, - 'status' => $status, - 'created_date' => $createdDate, - 'updated_date' => $updatedDate - ] - ], - $jobName . ':' . BatchLog::getSuccessComment() + $statusComment, + $createdDate, + $updatedDate ); $endTime = now(); - $this->info('SHJ-8 バッチ処理ログ登録が正常に完了しました。'); - $this->info("処理時間: {$startTime->diffInSeconds($endTime)}秒"); - - Log::info('SHJ-8 バッチ処理ログ登録完了', [ - 'end_time' => $endTime, - 'duration_seconds' => $startTime->diffInSeconds($endTime), - 'batch_log_id' => $batchLog->id - ]); - // 仕様書【処理3】正常終了時の結果出力 - $this->line('処理結果: 0'); // 0 = 正常終了 - $this->line('異常情報: '); // 正常時は空文字 + // 処理結果に応じた出力 + if ($result['result'] === 0) { + // 正常終了 + $this->info('SHJ-8 バッチ処理ログ登録が正常に完了しました。'); + $this->info("処理時間: {$startTime->diffInSeconds($endTime)}秒"); - return self::SUCCESS; + // 標準出力形式 (SHJ-8仕様書準拠) + $this->line('処理結果: 0'); + $this->line('異常情報: '); + + Log::info('SHJ-8 バッチ処理ログ登録完了', [ + 'end_time' => $endTime, + 'duration_seconds' => $startTime->diffInSeconds($endTime) + ]); + + return self::SUCCESS; + + } else { + // 異常終了 + $errorMessage = $result['error_message'] ?? '不明なエラー'; + $this->error('SHJ-8 バッチ処理ログ登録エラー: ' . $errorMessage); + + // 標準出力形式 (SHJ-8仕様書準拠) + $this->line('処理結果: 1'); + $this->line('異常情報: ' . $errorMessage); + + Log::error('SHJ-8 バッチ処理ログ登録エラー', [ + 'error_message' => $errorMessage, + 'error_code' => $result['error_code'] ?? null + ]); + + return self::FAILURE; + } } catch (\Exception $e) { $this->error('SHJ-8 バッチ処理ログ登録で予期しないエラーが発生しました: ' . $e->getMessage()); + + // 標準出力形式 (SHJ-8仕様書準拠 - 例外時) + $this->line('処理結果: 1'); + $this->line('異常情報: ' . $e->getMessage()); + Log::error('SHJ-8 バッチ処理ログ登録例外エラー', [ 'exception' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); - // 仕様書【処理3】異常終了時の結果出力 - $this->line('処理結果: 1'); // 1 = 異常終了 - $this->line('異常情報: エラー: ' . $e->getMessage()); - return self::FAILURE; } } - - /** - * 【処理1】パラメータの妥当性を検証 - * - * 仕様書に基づく検証内容: - * - デバイスID: 必須、数値、device表に存在するか - * - プロセス名: 「プロセス名」「ジョブ名」いずれか必須 - * - ジョブ名: 「プロセス名」「ジョブ名」いずれか必須 - * - ステータス: 必須 - * - 登録日時: 必須、yyyy/mm/dd形式 - * - 更新日時: 必須、yyyy/mm/dd形式 - * - * @param int $deviceId デバイスID - * @param string $processName プロセス名 - * @param string $jobName ジョブ名 - * @param string $status ステータス - * @param string $createdDate 登録日時 - * @param string $updatedDate 更新日時 - * @return array 検証結果 ['valid' => bool, 'message' => string] - */ - private function validateParameters(int $deviceId, string $processName, string $jobName, string $status, string $createdDate, string $updatedDate): array - { - // デバイスID存在チェック - if ($deviceId <= 0) { - return [ - 'valid' => false, - 'message' => 'パラメーターNG: デバイスIDは正の整数である必要があります' - ]; - } - - if (!Device::exists($deviceId)) { - return [ - 'valid' => false, - 'message' => "パラメーターNG: デバイスID {$deviceId} が存在しません" - ]; - } - - // プロセス名とジョブ名のいずれか必須チェック - if (empty($processName) && empty($jobName)) { - return [ - 'valid' => false, - 'message' => 'パラメーターNG: プロセス名またはジョブ名のいずれかは必須です' - ]; - } - - // ステータス必須チェック - if (empty($status)) { - return [ - 'valid' => false, - 'message' => 'パラメーターNG: ステータスは必須です' - ]; - } - - // 日付形式チェック - if (!$this->isValidDateFormat($createdDate)) { - return [ - 'valid' => false, - 'message' => 'パラメーターNG: 登録日時の形式が正しくありません(yyyy/mm/dd)' - ]; - } - - if (!$this->isValidDateFormat($updatedDate)) { - return [ - 'valid' => false, - 'message' => 'パラメーターNG: 更新日時の形式が正しくありません(yyyy/mm/dd)' - ]; - } - - return [ - 'valid' => true, - 'message' => 'パラメーターチェックOK' - ]; - } - - /** - * 日付形式の検証 - * - * @param string $date 日付文字列 - * @return bool 有効な日付形式かどうか - */ - private function isValidDateFormat(string $date): bool - { - // yyyy/mm/dd形式の正規表現チェック - if (!preg_match('/^\d{4}\/\d{2}\/\d{2}$/', $date)) { - return false; - } - - // 実際の日付として有効かチェック - $dateParts = explode('/', $date); - return checkdate((int)$dateParts[1], (int)$dateParts[2], (int)$dateParts[0]); - } } diff --git a/app/Console/Commands/ShjElevenCommand.php b/app/Console/Commands/ShjElevenCommand.php index 2e739f2..222efc7 100644 --- a/app/Console/Commands/ShjElevenCommand.php +++ b/app/Console/Commands/ShjElevenCommand.php @@ -51,15 +51,14 @@ class ShjElevenCommand extends Command /** * コンソールコマンドを実行 - * - * 処理フロー: - * 1. 集計単位每个の契約台数を算出する - * 2. 取得件数判定 - * 3. ゾーンマスタを取得する - * 4. 取得判定とゾーンマスタ登録 - * 5. 契約台数チェック(限界台数超過判定) - * 6. 契約台数を反映する - * 7. バッチ処理ログを作成する + * + * 処理フロー(仕様書準拠): + * 【処理1】集計単位每个の契約台数を算出する + * 【判断1】取得件数判定 + * - 取得件数 = 0 → 【処理4】バッチログ作成(「全駐輪場契約なし」)→ 終了 + * - 取得件数 ≥ 1 → 【処理2】ゾーンマスタ処理(循環)→ 終了 + * + * ※【処理4】は各レコードの処理ごとにService層で呼び出される * * @return int */ @@ -82,29 +81,37 @@ class ShjElevenCommand extends Command $this->info("取得件数: {$countResults}件"); if ($countResults === 0) { - // 対象なしの結果を設定する - $this->info('契約台数算出対象なしのため処理を終了します。'); - - // バッチ処理ログを作成 - $this->shjElevenService->createBatchLog( - 'success', - [], - '契約台数算出対象なし', - 0, - 0, - 0 - ); + // 【判断1】取得件数 = 0 の場合 + $this->info('対象なしのため処理を終了します。'); + + // 【処理4】bat_job_logに直接書き込み(取得件数=0時) + $batchLogResult = $this->shjElevenService->writeBatJobLogForNoContracts(); + + // bat_job_log書き込み結果をチェック + if (!$batchLogResult['success']) { + $this->warn('bat_job_log書き込みで異常が発生しました'); + if (isset($batchLogResult['error_message'])) { + $this->warn('error_message: ' . $batchLogResult['error_message']); + } + + Log::warning('bat_job_log書き込み失敗(対象なし)', [ + 'error_message' => $batchLogResult['error_message'] ?? null + ]); + } Log::info('SHJ-11 現在契約台数集計完了(対象なし)', [ 'end_time' => now(), - 'duration_seconds' => $startTime->diffInSeconds(now()) + 'duration_seconds' => $startTime->diffInSeconds(now()), + 'bat_job_log_success' => $batchLogResult['success'] ]); return self::SUCCESS; } - // 【処理2・3】ゾーンマスタ処理(取得・登録・更新) + // 【判断1】取得件数 ≥ 1 の場合 + // 【処理2・3・4】ゾーンマスタ処理(各レコードごとに処理4を実行) $this->info('【処理2】ゾーンマスタ処理を実行しています...'); + $this->info('※各レコードごとに【処理4】バッチログを作成します'); $processResult = $this->shjElevenService->processZoneManagement($contractCounts); // 処理結果確認 @@ -116,16 +123,10 @@ class ShjElevenCommand extends Command $this->info("ゾーン新規作成件数: {$processResult['created_zones']}件"); $this->info("ゾーン更新件数: {$processResult['updated_zones']}件"); $this->info("限界台数超過件数: {$processResult['over_capacity_count']}件"); - - // 【処理4】バッチ処理ログを作成する - $this->shjElevenService->createBatchLog( - 'success', - $processResult['parameters'], - '現在契約台数集計処理完了', - $countResults, - $processResult['created_zones'] + $processResult['updated_zones'], - 0 - ); + + if (!empty($processResult['batch_log_errors'])) { + $this->warn("バッチログエラー件数: " . count($processResult['batch_log_errors']) . "件"); + } Log::info('SHJ-11 現在契約台数集計完了', [ 'end_time' => $endTime, @@ -133,22 +134,13 @@ class ShjElevenCommand extends Command 'processed_count' => $countResults, 'created_zones' => $processResult['created_zones'], 'updated_zones' => $processResult['updated_zones'], - 'over_capacity_count' => $processResult['over_capacity_count'] + 'over_capacity_count' => $processResult['over_capacity_count'], + 'batch_log_errors' => count($processResult['batch_log_errors']) ]); return self::SUCCESS; } else { $this->error('SHJ-11 現在契約台数集計でエラーが発生しました: ' . $processResult['message']); - - // エラー時のバッチログ作成 - $this->shjElevenService->createBatchLog( - 'error', - $processResult['parameters'] ?? [], - $processResult['message'], - $countResults, - $processResult['created_zones'] ?? 0, - 1 - ); Log::error('SHJ-11 現在契約台数集計エラー', [ 'error' => $processResult['message'], @@ -160,16 +152,6 @@ class ShjElevenCommand extends Command } catch (\Exception $e) { $this->error('SHJ-11 現在契約台数集計で予期しないエラーが発生しました: ' . $e->getMessage()); - - // 例外時のバッチログ作成 - $this->shjElevenService->createBatchLog( - 'error', - [], - 'システムエラー: ' . $e->getMessage(), - 0, - 0, - 1 - ); Log::error('SHJ-11 現在契約台数集計例外エラー', [ 'exception' => $e->getMessage(), diff --git a/app/Console/Commands/ShjFiveCommand.php b/app/Console/Commands/ShjFiveCommand.php index 4fd5930..bf8a81c 100644 --- a/app/Console/Commands/ShjFiveCommand.php +++ b/app/Console/Commands/ShjFiveCommand.php @@ -5,7 +5,6 @@ namespace App\Console\Commands; use Illuminate\Console\Command; use Illuminate\Support\Facades\Log; use App\Services\ShjFiveService; -use App\Models\Batch\BatchLog; /** * SHJ-5 空き待ち通知処理コマンド @@ -66,68 +65,27 @@ class ShjFiveCommand extends Command */ public function handle() { - $batchLog = null; - try { // 開始ログ出力 $startTime = now(); $this->info('SHJ-5 空き待ち通知処理を開始します。'); - + Log::info('SHJ-5 空き待ち通知処理開始', [ 'start_time' => $startTime ]); - // SHJ-8共通処理呼び出し - 仕様書準拠 - $batchLog = BatchLog::createBatchLog( - 'SHJ-5空き待ち通知処理', - BatchLog::STATUS_START, - [ - 'device_id' => 1, // 仕様書:device_id=1 - 'process_code' => 1, // 仕様書:process_code=1 - 'status_comment' => '処理開始' // 仕様書:内部変数.ステータスコメント - ], - 'SHJ-5処理開始: 駐輪場空き状況確認と空き待ち通知処理' - ); - // SHJ-5メイン処理実行 $result = $this->shjFiveService->executeParkVacancyNotification(); $endTime = now(); $this->info('SHJ-5 空き待ち通知処理が完了しました。'); $this->info("処理時間: {$startTime->diffInSeconds($endTime)}秒"); - + // 処理結果表示 $this->displayProcessResult($result); - - // SHJ-8共通処理 - バッチログ完了記録(仕様書準拠) - $logStatus = $result['success'] ? BatchLog::STATUS_SUCCESS : BatchLog::STATUS_ERROR; - - // 仕様書準拠:サービス側で作成した完全なステータスコメントを使用 - $statusComment = $result['success'] ? - ($result['status_comment'] ?? 'ステータスコメント生成エラー') : - sprintf('処理失敗: %s', $result['message'] ?? 'エラー'); - - $batchLog->update([ - 'status' => $logStatus, - 'end_time' => $endTime, - 'message' => $result['message'], - 'parameters' => [ - 'device_id' => 1, // 仕様書:device_id=1 - 'process_code' => 1, // 仕様書:process_code=1 - 'status_comment' => $statusComment, // 仕様書:内部変数.ステータスコメント(完全版) - 'processed_parks_count' => $result['processed_parks_count'] ?? 0, - 'vacant_parks_count' => $result['vacant_parks_count'] ?? 0, - 'total_waiting_users' => $result['total_waiting_users'] ?? 0, - 'notification_success_count' => $result['notification_success_count'] ?? 0, - 'operator_queue_count' => $result['operator_queue_count'] ?? 0, - 'error_count' => $result['error_count'] ?? 0, - 'duration_seconds' => $result['duration_seconds'] ?? 0 - ], - 'execution_count' => 1, - 'success_count' => $result['notification_success_count'] ?? 0, - 'error_count' => $result['error_count'] ?? 0 - ]); - + + // バッチログはShjFiveServiceが自動的にSHJ-8経由で作成 + Log::info('SHJ-5 空き待ち通知処理完了', [ 'end_time' => $endTime, 'duration_seconds' => $startTime->diffInSeconds($endTime), @@ -138,27 +96,9 @@ class ShjFiveCommand extends Command } catch (\Exception $e) { $this->error('SHJ-5 空き待ち通知処理で予期しないエラーが発生しました: ' . $e->getMessage()); - - // SHJ-8共通処理 - エラーログ記録(仕様書準拠) - if ($batchLog) { - $statusComment = sprintf( - 'メール正常終了件数:0/メール異常終了件数:1/キュー登録正常終了件数:0/キュー登録異常終了件数:1 - 処理エラー: %s', - $e->getMessage() - ); - $batchLog->update([ - 'status' => BatchLog::STATUS_ERROR, - 'end_time' => now(), - 'message' => 'SHJ-5処理中にエラーが発生: ' . $e->getMessage(), - 'parameters' => [ - 'device_id' => 1, // 仕様書:device_id=1 - 'process_code' => 1, // 仕様書:process_code=1 - 'status_comment' => $statusComment // 仕様書:内部変数.ステータスコメント(完全版) - ], - 'error_details' => $e->getMessage(), - 'error_count' => 1 - ]); - } - + + // エラー時もShjFiveServiceが自動的にバッチログを作成 + Log::error('SHJ-5 空き待ち通知処理例外エラー', [ 'exception' => $e->getMessage(), 'trace' => $e->getTraceAsString() @@ -178,13 +118,13 @@ class ShjFiveCommand extends Command { $this->line(''); $this->info('=== 処理結果 ==='); - + if ($result['success']) { $this->info("✓ 処理実行成功: " . $result['message']); } else { $this->error("✗ 処理実行失敗: " . $result['message']); } - + $this->line(''); $this->info('=== 処理統計 ==='); $this->line(" 処理対象駐輪場数: " . ($result['processed_parks_count'] ?? 0)); @@ -204,4 +144,5 @@ class ShjFiveCommand extends Command } } } + } diff --git a/app/Console/Commands/ShjFourBCheckCommand.php b/app/Console/Commands/ShjFourBCheckCommand.php index b9f7e5e..5d62123 100644 --- a/app/Console/Commands/ShjFourBCheckCommand.php +++ b/app/Console/Commands/ShjFourBCheckCommand.php @@ -4,7 +4,8 @@ namespace App\Console\Commands; use Illuminate\Console\Command; use App\Models\SettlementTransaction; -use App\Models\Batch\BatchLog; +use App\Models\BatJobLog; +use App\Models\Device; use App\Jobs\ProcessSettlementJob; use App\Services\ShjFourBService; use Illuminate\Support\Facades\Log; @@ -77,22 +78,6 @@ class ShjFourBCheckCommand extends Command $this->info("処理制限: {$limit}件"); $this->info("対象期間: {$hours}時間以内"); - // バッチログ作成 - $batch = BatchLog::createBatchLog( - 'shj4b_check', - BatchLog::STATUS_START, - [ - 'command' => 'shj4b:check', - 'options' => [ - 'dry_run' => $isDryRun, - 'limit' => $limit, - 'hours' => $hours, - ], - 'start_time' => $startTime, - ], - 'SHJ-4B チェックコマンド開始' - ); - try { // 未処理の決済トランザクション取得 $unprocessedSettlements = $this->getUnprocessedSettlements($hours, $limit); @@ -101,13 +86,9 @@ class ShjFourBCheckCommand extends Command if ($unprocessedSettlements->isEmpty()) { $this->info("処理対象なし"); - - $batch->update([ - 'status' => BatchLog::STATUS_SUCCESS, - 'end_time' => now(), - 'message' => 'SHJ-4B チェック完了 - 処理対象なし', - 'success_count' => 0, - ]); + + // バッチログ作成 - 処理対象なし + $this->createBatchLog('success', 0, 0, 'SHJ-4B チェック完了 - 処理対象なし'); return 0; } @@ -117,14 +98,9 @@ class ShjFourBCheckCommand extends Command if ($isDryRun) { $this->info("ドライランモードのため、実際の処理はスキップします"); - - $batch->update([ - 'status' => BatchLog::STATUS_SUCCESS, - 'end_time' => now(), - 'message' => 'SHJ-4B チェック完了 - ドライラン', - 'success_count' => 0, - 'parameters' => json_encode(['targets' => $unprocessedSettlements->pluck('settlement_transaction_id')->toArray()]), - ]); + + // バッチログ作成 - ドライラン + $this->createBatchLog('success', 0, 0, 'SHJ-4B チェック完了 - ドライラン(' . $unprocessedSettlements->count() . '件検出)'); return 0; } @@ -134,14 +110,10 @@ class ShjFourBCheckCommand extends Command $this->info("処理完了: {$processed['success']}件成功, {$processed['failed']}件失敗"); - $batch->update([ - 'status' => $processed['failed'] > 0 ? BatchLog::STATUS_ERROR : BatchLog::STATUS_SUCCESS, - 'end_time' => now(), - 'message' => "SHJ-4B チェック完了 - 成功:{$processed['success']}件, 失敗:{$processed['failed']}件", - 'success_count' => $processed['success'], - 'error_count' => $processed['failed'], - 'parameters' => json_encode($processed), - ]); + // バッチログ作成 - 処理完了 + $status = $processed['failed'] > 0 ? 'error' : 'success'; + $message = "SHJ-4B チェック完了 - 成功:{$processed['success']}件, 失敗:{$processed['failed']}件"; + $this->createBatchLog($status, $processed['success'], $processed['failed'], $message); return $processed['failed'] > 0 ? 1 : 0; @@ -152,13 +124,8 @@ class ShjFourBCheckCommand extends Command 'trace' => $e->getTraceAsString(), ]); - $batch->update([ - 'status' => BatchLog::STATUS_ERROR, - 'end_time' => now(), - 'message' => 'SHJ-4B チェック失敗: ' . $e->getMessage(), - 'error_details' => $e->getTraceAsString(), - 'error_count' => 1, - ]); + // バッチログ作成 - エラー + $this->createBatchLog('error', 0, 1, 'SHJ-4B チェック失敗: ' . $e->getMessage()); return 1; } @@ -214,10 +181,10 @@ class ShjFourBCheckCommand extends Command return true; } - // 2. batch_logで処理完了記録があるかチェック - $processedInBatch = BatchLog::where('process_name', 'shj4b') - ->where('status', BatchLog::STATUS_SUCCESS) - ->where('parameters', 'like', '%"settlement_transaction_id":' . $settlement->settlement_transaction_id . '%') + // 2. bat_job_logで処理完了記録があるかチェック + $processedInBatch = BatJobLog::where('process_name', 'SHJ-4B') + ->where('status', 'success') + ->where('status_comment', 'like', '%settlement_transaction_id:' . $settlement->settlement_transaction_id . '%') ->exists(); if ($processedInBatch) { @@ -226,8 +193,8 @@ class ShjFourBCheckCommand extends Command // 3. 現在キューに入っているかチェック(簡易版) // 注: より正確にはRedis/DBキューの内容を確認する必要がある - $recentJobDispatched = BatchLog::where('process_name', 'shj4b') - ->where('parameters', 'like', '%"settlement_transaction_id":' . $settlement->settlement_transaction_id . '%') + $recentJobDispatched = BatJobLog::where('process_name', 'SHJ-4B') + ->where('status_comment', 'like', '%settlement_transaction_id:' . $settlement->settlement_transaction_id . '%') ->where('created_at', '>=', Carbon::now()->subHours(1)) ->exists(); @@ -314,4 +281,37 @@ class ShjFourBCheckCommand extends Command 'total' => $settlements->count(), ]; } + + /** + * バッチログ作成 - 直接bat_job_log書き込み + * + * @param string $status + * @param int $successCount + * @param int $errorCount + * @param string $message + */ + private function createBatchLog(string $status, int $successCount, int $errorCount, string $message): void + { + try { + $device = Device::orderBy('device_id')->first(); + $deviceId = $device ? $device->device_id : 1; + + BatJobLog::create([ + 'device_id' => $deviceId, + 'process_name' => 'SHJ-4B-CHECK', + 'job_name' => 'SHJ-4Bチェックコマンド', + 'status' => $status, + 'status_comment' => $message . " (成功:{$successCount}/失敗:{$errorCount})", + 'created_at' => now()->startOfDay(), + 'updated_at' => now()->startOfDay() + ]); + + } catch (\Exception $e) { + Log::error('SHJ-4B-CHECK バッチログ作成エラー', [ + 'error' => $e->getMessage(), + 'status' => $status, + 'message' => $message + ]); + } + } } diff --git a/app/Console/Commands/ShjMailSendCommand.php b/app/Console/Commands/ShjMailSendCommand.php index 539e806..d44e55b 100644 --- a/app/Console/Commands/ShjMailSendCommand.php +++ b/app/Console/Commands/ShjMailSendCommand.php @@ -53,12 +53,14 @@ class ShjMailSendCommand extends Command /** * コンソールコマンドを実行 - * - * 処理フロー: - * 1. 入力パラメーターをチェックする - * 2. メール送信テンプレート情報を取得する - * 3. メールを送信する - * 4. 処理結果を返却する + * + * SHJ-7 メール送信処理フロー: + * 【処理1】入力パラメーターをチェックする + * 【判断1】チェック結果 + * 【処理2】メール送信テンプレート情報を取得する + * 【判断2】取得結果 + * 【処理3】メールを送信する + * 【処理4】処理結果を返却する * * @return int */ @@ -67,8 +69,8 @@ class ShjMailSendCommand extends Command try { // 開始ログ出力 $startTime = now(); - $this->info('SHJ メール送信処理を開始します。'); - Log::info('SHJ メール送信処理開始', [ + $this->info('SHJ-7 メール送信処理を開始します。'); + Log::info('SHJ-7 メール送信処理開始', [ 'start_time' => $startTime, 'mail_address' => $this->argument('mail_address'), 'backup_mail_address' => $this->argument('backup_mail_address'), @@ -80,41 +82,36 @@ class ShjMailSendCommand extends Command $backupMailAddress = $this->argument('backup_mail_address'); $mailTemplateId = $this->argument('mail_template_id'); - // 【処理1】パラメータ検証 - if (!$this->validateParameters($mailAddress, $backupMailAddress, $mailTemplateId)) { - $this->error('パラメータが不正です。'); - return self::FAILURE; - } - - // SHJメール送信処理実行 + // SHJ-7 メール送信処理実行 $result = $this->shjMailSendService->executeMailSend($mailAddress, $backupMailAddress, $mailTemplateId); - // 処理結果確認 - if ($result['success']) { + // 【処理4】処理結果を返却する + if ($result['result'] === 0) { $endTime = now(); - $this->info('SHJ メール送信処理が正常に完了しました。'); + $this->info('SHJ-7 メール送信処理が正常に完了しました。'); $this->info("処理時間: {$startTime->diffInSeconds($endTime)}秒"); - - Log::info('SHJ メール送信処理完了', [ + + Log::info('SHJ-7 メール送信処理完了', [ 'end_time' => $endTime, 'duration_seconds' => $startTime->diffInSeconds($endTime), - 'result' => $result + 'result' => $result['result'], + 'error_info' => $result['error_info'] ]); return self::SUCCESS; } else { - $this->error('SHJ メール送信処理でエラーが発生しました: ' . $result['message']); - Log::error('SHJ メール送信処理エラー', [ - 'error' => $result['message'], - 'details' => $result['details'] ?? null + $this->error('SHJ-7 メール送信処理でエラーが発生しました: ' . $result['error_info']); + Log::error('SHJ-7 メール送信処理エラー', [ + 'result' => $result['result'], + 'error_info' => $result['error_info'] ]); return self::FAILURE; } } catch (\Exception $e) { - $this->error('SHJ メール送信処理で予期しないエラーが発生しました: ' . $e->getMessage()); - Log::error('SHJ メール送信処理例外エラー', [ + $this->error('SHJ-7 メール送信処理で予期しないエラーが発生しました: ' . $e->getMessage()); + Log::error('SHJ-7 メール送信処理例外エラー', [ 'exception' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); @@ -123,55 +120,4 @@ class ShjMailSendCommand extends Command } } - /** - * 【処理1】パラメータの妥当性を検証 - * - * 仕様書に基づく検証内容: - * - メールアドレス: 「メールアドレス」「予備メールアドレス」いずれか必須 - * - メールテンプレートID: 必須 - * - * @param mixed $mailAddress メールアドレス - * @param mixed $backupMailAddress 予備メールアドレス - * @param mixed $mailTemplateId メールテンプレートID - * @return bool 検証結果 - */ - private function validateParameters($mailAddress, $backupMailAddress, $mailTemplateId): bool - { - // メールテンプレートIDチェック - if (empty($mailTemplateId)) { - $this->error('メールテンプレートIDは必須です。'); - return false; - } - - // 数値形式チェック(メールテンプレートID) - if (!is_numeric($mailTemplateId)) { - $this->error('メールテンプレートIDは数値である必要があります。'); - return false; - } - - // 正の整数チェック(メールテンプレートID) - if ($mailTemplateId <= 0) { - $this->error('メールテンプレートIDは正の整数である必要があります。'); - return false; - } - - // メールアドレスチェック(いずれか必須) - if (empty($mailAddress) && empty($backupMailAddress)) { - $this->error('メールアドレスまたは予備メールアドレスのいずれかは必須です。'); - return false; - } - - // メールアドレス形式チェック - if (!empty($mailAddress) && !filter_var($mailAddress, FILTER_VALIDATE_EMAIL)) { - $this->error('メールアドレスの形式が正しくありません。'); - return false; - } - - if (!empty($backupMailAddress) && !filter_var($backupMailAddress, FILTER_VALIDATE_EMAIL)) { - $this->error('予備メールアドレスの形式が正しくありません。'); - return false; - } - - return true; - } } diff --git a/app/Console/Commands/ShjOneCommand.php b/app/Console/Commands/ShjOneCommand.php index 4bb40bd..adaf0a1 100644 --- a/app/Console/Commands/ShjOneCommand.php +++ b/app/Console/Commands/ShjOneCommand.php @@ -3,8 +3,8 @@ namespace App\Console\Commands; use App\Services\ShjOneService; -use App\Models\Batch\BatchLog; use Illuminate\Console\Command; +use Illuminate\Support\Facades\Log; use Exception; /** @@ -58,51 +58,32 @@ class ShjOneCommand extends Command $this->info("駐輪場ID: {$parkId}"); try { - // バッチログ開始 - SHJ-8共通処理 - $batchLog = BatchLog::createBatchLog( - 'SHJ-1本人確認自動処理', - BatchLog::STATUS_START, - $parameters, - 'SHJ-1処理開始: 利用者ID=' . $userId . ', 駐輪場ID=' . $parkId - ); - // SHJ-1 メイン処理を実行 $result = $this->shjOneService->execute($userId, $parkId); - + // 処理結果の表示 $this->displayResult($result); - - // バッチログ完了 - 実際の処理結果に基づく - $logStatus = $result['log_status'] ?? ($result['system_success'] ? BatchLog::STATUS_SUCCESS : BatchLog::STATUS_ERROR); - $batchLog->update([ - 'status' => $logStatus, - 'end_time' => now(), - 'message' => $result['message'], - 'success_count' => $result['stats']['success_count'] ?? 0, - 'error_count' => $result['stats']['error_count'] ?? 0, - 'execution_count' => $result['stats']['processed_count'] ?? 1 - ]); - + + // バッチログはShjOneServiceが自動的にSHJ-8経由で作成 + $this->info("=== SHJ-1 本人確認自動処理 完了 ==="); - + // システムエラーまたは身元確認失敗の場合は exit code 1 $isSuccess = $result['system_success'] && ($result['identity_result'] ?? '') === 'OK'; return $isSuccess ? 0 : 1; - + } catch (Exception $e) { $this->error("SHJ-1処理中にエラーが発生しました: " . $e->getMessage()); - - // エラーログ記録 - if (isset($batchLog)) { - $batchLog->update([ - 'status' => BatchLog::STATUS_ERROR, - 'end_time' => now(), - 'message' => $e->getMessage(), - 'error_details' => $e->getMessage(), - 'error_count' => 1 - ]); - } - + + // エラー時もShjOneServiceが自動的にバッチログを作成 + + Log::error('SHJ-1処理例外エラー', [ + 'user_id' => $userId, + 'park_id' => $parkId, + 'exception' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + return 1; } } @@ -114,7 +95,7 @@ class ShjOneCommand extends Command { $this->line(''); $this->info('=== 処理結果 ==='); - + if ($result['system_success']) { $this->info("✓ 処理実行成功: " . $result['message']); if (isset($result['identity_result'])) { @@ -124,13 +105,13 @@ class ShjOneCommand extends Command } else { $this->error("✗ 処理実行失敗: " . $result['message']); } - + if (isset($result['details'])) { foreach ($result['details'] as $key => $value) { $this->line(" {$key}: {$value}"); } } - + if (isset($result['stats'])) { $this->line(''); $this->info('=== 統計情報 ==='); @@ -139,4 +120,5 @@ class ShjOneCommand extends Command } } } + } diff --git a/app/Console/Commands/ShjTwelveCommand.php b/app/Console/Commands/ShjTwelveCommand.php index 10b0705..7290206 100644 --- a/app/Console/Commands/ShjTwelveCommand.php +++ b/app/Console/Commands/ShjTwelveCommand.php @@ -79,14 +79,17 @@ class ShjTwelveCommand extends Command $this->info("取得件数: {$unpaidCount}件"); if ($unpaidCount === 0) { - // 未払い者対象なしの結果を設定する - $this->info('未払い者対象なしのため処理を終了します。'); - - // バッチ処理ログを作成 + // 未払い者なしの結果を設定する + $this->info('未払い者なしのため処理を終了します。'); + + // バッチ処理ログを作成(SHJ-8仕様に合わせ job_name と status_comment を追加) $this->shjTwelveService->createBatchLog( 'success', - [], - '未払い者対象なし', + [ + 'job_name' => 'SHJ-12未払い者アラート', + 'status_comment' => '未払い者なし' + ], + '未払い者なし', 0, 0, 0 @@ -110,39 +113,73 @@ class ShjTwelveCommand extends Command $this->info('SHJ-12 未払い者通知処理が正常に完了しました。'); $this->info("処理時間: {$startTime->diffInSeconds($endTime)}秒"); $this->info("処理対象件数: {$unpaidCount}件"); - $this->info("通知送信件数: {$processResult['notification_count']}件"); - $this->info("オペレーターキュー追加件数: {$processResult['queue_count']}件"); - + $this->info("メール送信成功: {$processResult['mail_success_count']}件"); + $this->info("メール送信失敗: {$processResult['mail_error_count']}件"); + $this->info("キュー登録成功: {$processResult['queue_success_count']}件"); + $this->info("キュー登録失敗: {$processResult['queue_error_count']}件"); + // 【処理3】バッチ処理ログを作成する + $statusComment = $processResult['status_comment']; + $batchComments = $processResult['batch_comments']; + $totalSuccessCount = $processResult['mail_success_count'] + $processResult['queue_success_count']; + $totalErrorCount = $processResult['mail_error_count'] + $processResult['queue_error_count']; + + // status_commentに詳細エラー情報を付加 + $finalMessage = $statusComment; + if (!empty($batchComments)) { + $finalMessage .= "\n" . $batchComments; + } + + // SHJ-8仕様に合わせ、job_name と status_comment を parameters に追加 + $batchLogParameters = array_merge($processResult['parameters'], [ + 'job_name' => 'SHJ-12未払い者アラート', + 'status_comment' => $statusComment + ]); + $this->shjTwelveService->createBatchLog( 'success', - $processResult['parameters'], - '未払い者通知処理完了', + $batchLogParameters, + $finalMessage, $unpaidCount, - $processResult['notification_count'] + $processResult['queue_count'], - 0 + $totalSuccessCount, + $totalErrorCount ); Log::info('SHJ-12 未払い者通知処理完了', [ 'end_time' => $endTime, 'duration_seconds' => $startTime->diffInSeconds($endTime), 'processed_count' => $unpaidCount, - 'notification_count' => $processResult['notification_count'], - 'queue_count' => $processResult['queue_count'] + 'mail_success_count' => $processResult['mail_success_count'], + 'mail_error_count' => $processResult['mail_error_count'], + 'queue_success_count' => $processResult['queue_success_count'], + 'queue_error_count' => $processResult['queue_error_count'] ]); return self::SUCCESS; } else { $this->error('SHJ-12 未払い者通知処理でエラーが発生しました: ' . $processResult['message']); - + // エラー時のバッチログ作成 + $statusComment = $processResult['status_comment'] ?? 'システムエラー'; + $batchComments = $processResult['batch_comments'] ?? ''; + $finalMessage = $statusComment; + if (!empty($batchComments)) { + $finalMessage .= "\n" . $batchComments; + } + + // SHJ-8仕様に合わせ、job_name と status_comment を parameters に追加 + $batchLogParameters = array_merge($processResult['parameters'] ?? [], [ + 'job_name' => 'SHJ-12未払い者アラート', + 'status_comment' => $statusComment + ]); + $this->shjTwelveService->createBatchLog( 'error', - $processResult['parameters'] ?? [], - $processResult['message'], + $batchLogParameters, + $finalMessage, $unpaidCount, - $processResult['notification_count'] ?? 0, - 1 + ($processResult['mail_success_count'] ?? 0) + ($processResult['queue_success_count'] ?? 0), + ($processResult['mail_error_count'] ?? 0) + ($processResult['queue_error_count'] ?? 0) ); Log::error('SHJ-12 未払い者通知処理エラー', [ @@ -156,10 +193,13 @@ class ShjTwelveCommand extends Command } catch (\Exception $e) { $this->error('SHJ-12 未払い者通知処理で予期しないエラーが発生しました: ' . $e->getMessage()); - // 例外時のバッチログ作成 + // 例外時のバッチログ作成(SHJ-8仕様に合わせ job_name と status_comment を追加) $this->shjTwelveService->createBatchLog( 'error', - [], + [ + 'job_name' => 'SHJ-12未払い者アラート', + 'status_comment' => 'システムエラー' + ], 'システムエラー: ' . $e->getMessage(), 0, 0, diff --git a/app/Console/Commands/TestMailCommand.php b/app/Console/Commands/TestMailCommand.php new file mode 100644 index 0000000..27ac493 --- /dev/null +++ b/app/Console/Commands/TestMailCommand.php @@ -0,0 +1,146 @@ +mailSendService = $mailSendService; + } + + /** + * コマンド実行 + * + * @return int + */ + public function handle() + { + // パラメータ取得 + $email = $this->argument('email') ?? 'wyf_0506@hotmail.com'; + $backupEmail = $this->option('backup') ?? ''; + $templateId = (int) $this->option('template'); + + // 確認画面 + $this->info('=== SHJ-7 メール送信テスト ==='); + $this->line(''); + $this->line("送信先メールアドレス: {$email}"); + $this->line("予備メールアドレス : " . ($backupEmail ?: '(なし)')); + $this->line("テンプレートID : {$templateId}"); + $this->line(''); + + // 環境チェック + $mailDriver = config('mail.default'); + $this->warn("現在のメール設定: MAIL_MAILER={$mailDriver}"); + + if ($mailDriver === 'log') { + $this->warn('⚠ メールはログファイルにのみ記録され、実際には送信されません'); + $this->warn('⚠ 実際に送信するには .env で MAIL_MAILER=smtp 等に変更してください'); + } else { + $this->info("✓ メールは実際に送信されます({$mailDriver})"); + } + + $this->line(''); + + // 実行確認 + if (!$this->confirm('メール送信を実行しますか?', true)) { + $this->info('キャンセルしました。'); + return self::SUCCESS; + } + + // メール送信実行 + $this->line(''); + $this->info('メール送信を開始します...'); + + try { + $startTime = now(); + + // SHJ-7サービス呼び出し + $result = $this->mailSendService->executeMailSend( + $email, + $backupEmail, + $templateId + ); + + $endTime = now(); + $duration = $startTime->diffInSeconds($endTime); + + $this->line(''); + $this->info('=== 実行結果 ==='); + + if ($result['result'] === 0) { + $this->info('✓ メール送信成功'); + $this->line("処理時間: {$duration}秒"); + + if ($mailDriver === 'log') { + $this->line(''); + $this->comment('※ ログファイルを確認してください:'); + $this->comment(' storage/logs/laravel.log'); + } else { + $this->line(''); + $this->comment("※ {$email} のメールボックスを確認してください"); + } + + return self::SUCCESS; + } else { + $this->error('✗ メール送信失敗'); + $this->error("エラー情報: {$result['error_info']}"); + $this->line(''); + $this->comment('ログファイルで詳細を確認してください: storage/logs/laravel.log'); + + return self::FAILURE; + } + + } catch (\Exception $e) { + $this->error('✗ 予期しないエラーが発生しました'); + $this->error("エラー: {$e->getMessage()}"); + + Log::error('test:mail コマンドエラー', [ + 'exception' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + + return self::FAILURE; + } + } +} diff --git a/app/Jobs/ProcessSettlementJob.php b/app/Jobs/ProcessSettlementJob.php index 2d3c5f2..1b02d52 100644 --- a/app/Jobs/ProcessSettlementJob.php +++ b/app/Jobs/ProcessSettlementJob.php @@ -8,8 +8,6 @@ use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; use Illuminate\Support\Facades\Log; -use App\Models\Batch\BatchLog; -use App\Models\SettlementTransaction; use App\Services\ShjFourBService; /** @@ -78,18 +76,6 @@ class ProcessSettlementJob implements ShouldQueue public function handle() { $startTime = now(); - - // バッチログの開始記録 - $batch = BatchLog::createBatchLog( - 'shj4b', - BatchLog::STATUS_START, - [ - 'settlement_transaction_id' => $this->settlementTransactionId, - 'context' => $this->context, - 'job_id' => $this->job->getJobId(), - ], - 'SHJ-4B ProcessSettlementJob start' - ); try { Log::info('SHJ-4B ProcessSettlementJob開始', [ @@ -99,24 +85,15 @@ class ProcessSettlementJob implements ShouldQueue ]); // SHJ-4Bサービスを使用して決済トランザクション処理を実行 + // バッチログはShjFourBServiceが自動的にSHJ-8経由で作成 $shjFourBService = app(ShjFourBService::class); $result = $shjFourBService->processSettlementTransaction( $this->settlementTransactionId, $this->context ); - // 処理結果に基づいてバッチログを更新 + // 処理結果のログ記録 if ($result['success']) { - $batch->update([ - 'status' => BatchLog::STATUS_SUCCESS, - 'end_time' => now(), - 'message' => 'SHJ-4B ProcessSettlementJob completed successfully', - 'success_count' => 1, - 'parameters' => json_encode([ - 'result' => $result, - ]), - ]); - Log::info('SHJ-4B ProcessSettlementJob完了', [ 'settlement_transaction_id' => $this->settlementTransactionId, 'execution_time' => now()->diffInSeconds($startTime), @@ -124,17 +101,6 @@ class ProcessSettlementJob implements ShouldQueue ]); } else { // ビジネスロジック上の問題(エラーではない) - $batch->update([ - 'status' => BatchLog::STATUS_SUCCESS, - 'end_time' => now(), - 'message' => 'SHJ-4B ProcessSettlementJob completed with issues: ' . $result['reason'], - 'success_count' => 0, - 'parameters' => json_encode([ - 'result' => $result, - 'requires_manual_action' => true, - ]), - ]); - Log::warning('SHJ-4B ProcessSettlementJob要手動対応', [ 'settlement_transaction_id' => $this->settlementTransactionId, 'result' => $result, @@ -148,15 +114,7 @@ class ProcessSettlementJob implements ShouldQueue 'trace' => $e->getTraceAsString(), ]); - // バッチログのエラー記録 - $batch->update([ - 'status' => BatchLog::STATUS_ERROR, - 'end_time' => now(), - 'message' => 'SHJ-4B ProcessSettlementJob failed: ' . $e->getMessage(), - 'error_details' => $e->getTraceAsString(), - 'error_count' => 1, - ]); - + // エラー時もShjFourBServiceが自動的にバッチログを作成 // ジョブを失敗させて再試行を促す throw $e; } @@ -177,6 +135,7 @@ class ProcessSettlementJob implements ShouldQueue 'attempts' => $this->attempts(), ]); + // バッチログはShjFourBServiceが既に作成済み // 最終失敗時の追加処理があればここに記述 // 例:管理者への通知、障害キューへの登録など } diff --git a/app/Models/BatJobLog.php b/app/Models/BatJobLog.php new file mode 100644 index 0000000..68dd471 --- /dev/null +++ b/app/Models/BatJobLog.php @@ -0,0 +1,70 @@ + 'integer', + 'device_id' => 'integer', + 'created_at' => 'datetime', + 'updated_at' => 'datetime' + ]; + + /** + * タイムスタンプを使用 + * + * @var bool + */ + public $timestamps = true; + + /** + * deviceとのリレーション + */ + public function device() + { + return $this->belongsTo(Device::class, 'device_id', 'device_id'); + } +} diff --git a/app/Models/Batch/BatchLog.php b/app/Models/Batch/BatchLog.php deleted file mode 100644 index e8001b6..0000000 --- a/app/Models/Batch/BatchLog.php +++ /dev/null @@ -1,159 +0,0 @@ - 'integer', - 'start_time' => 'datetime', - 'end_time' => 'datetime', - 'parameters' => 'array', - 'execution_count' => 'integer', - 'success_count' => 'integer', - 'error_count' => 'integer', - 'created_at' => 'datetime', - 'updated_at' => 'datetime' - ]; - - /** - * ステータスの定数 - */ - const STATUS_START = 'start'; // 開始 - const STATUS_RUNNING = 'running'; // 実行中 - const STATUS_SUCCESS = 'success'; // 成功 - const STATUS_ERROR = 'error'; // エラー - const STATUS_WARNING = 'warning'; // 警告 - const STATUS_CANCELLED = 'cancelled'; // キャンセル - - - - /** - * 通用バッチログ作成メソッド - * - * 任意のバッチ処理で使用可能な統一ログ記録機能 - * 実際の実行コマンド名をそのまま記録 - * - * @param string $processName プロセス名(shj1, shj9:daily等) - * @param string $status ステータス - * @param array $parameters パラメーター配列 - * @param string $message メッセージ - * @param array $additionalData 追加データ(device_id等) - * @return BatchLog 作成されたバッチログ - */ - public static function createBatchLog( - string $processName, - string $status, - array $parameters = [], - string $message = '', - array $additionalData = [] - ): BatchLog { - // パラメーターに追加データをマージ - $allParameters = array_merge($parameters, $additionalData, [ - 'executed_at' => now()->toISOString() - ]); - - return self::create([ - 'process_name' => $processName, - 'status' => $status, - 'start_time' => now(), - 'end_time' => ($status === self::STATUS_SUCCESS || $status === self::STATUS_ERROR) ? now() : null, - 'parameters' => $allParameters, - 'message' => $message, - 'error_details' => ($status === self::STATUS_ERROR) ? $message : null, - 'execution_count' => 1, - 'success_count' => $status === self::STATUS_SUCCESS ? 1 : 0, - 'error_count' => $status === self::STATUS_ERROR ? 1 : 0 - ]); - } - - - - - - - - /** - * 成功時のステータスコメント生成 - * - * @return string ステータスコメント - */ - public static function getSuccessComment(): string - { - return '処理成功'; - } - - /** - * エラー時のステータスコメント生成 - * - * @param string $errorMessage エラーメッセージ - * @return string ステータスコメント - */ - public static function getErrorComment(string $errorMessage): string - { - return 'エラー: ' . $errorMessage; - } - - /** - * バッチログの文字列表現 - * - * @return string - */ - public function __toString(): string - { - return sprintf( - 'BatchLog[ID:%d, Process:%s, Status:%s, Time:%s]', - $this->id, - $this->process_name, - $this->status, - $this->start_time ? $this->start_time->format('Y-m-d H:i:s') : 'N/A' - ); - } -} \ No newline at end of file diff --git a/app/Services/ShjEightService.php b/app/Services/ShjEightService.php new file mode 100644 index 0000000..f720c1b --- /dev/null +++ b/app/Services/ShjEightService.php @@ -0,0 +1,270 @@ + 0|1, 'error_message' => string|null] + */ + public function execute( + int $deviceId, + ?string $processName, + ?string $jobName, + string $status, + string $statusComment, + string $createdDate, + string $updatedDate + ): array { + try { + Log::info('SHJ-8 バッチ処理ログ作成開始', [ + 'device_id' => $deviceId, + 'process_name' => $processName, + 'job_name' => $jobName, + 'status' => $status, + 'status_comment' => $statusComment, + 'created_date' => $createdDate, + 'updated_date' => $updatedDate + ]); + + // 【処理1】入力パラメーターをチェックする + $validationResult = $this->validateParameters( + $deviceId, + $processName, + $jobName, + $status, + $statusComment, + $createdDate, + $updatedDate + ); + + // 【判断1】チェック結果 + if (!$validationResult['valid']) { + // パラメーターNG + $errorMessage = $validationResult['error_message']; + + Log::warning('SHJ-8 パラメーターチェックNG', [ + 'error_message' => $errorMessage + ]); + + // 【処理3】異常終了の結果を返却 + return [ + 'result' => 1, + 'error_message' => $errorMessage + ]; + } + + // 【処理2】バッチ処理ログを登録する + $batJobLog = $this->createBatchJobLog( + $deviceId, + $processName, + $jobName, + $status, + $statusComment, + $createdDate, + $updatedDate + ); + + Log::info('SHJ-8 バッチ処理ログ作成完了', [ + 'job_log_id' => $batJobLog->job_log_id, + 'device_id' => $batJobLog->device_id, + 'process_name' => $batJobLog->process_name, + 'job_name' => $batJobLog->job_name + ]); + + // 【処理3】正常終了の結果を返却 + return [ + 'result' => 0 + ]; + + } catch (\Exception $e) { + Log::error('SHJ-8 バッチ処理ログ作成エラー', [ + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + + // 例外発生時の処理結果を返却 + return [ + 'result' => 1, + 'error_code' => $e->getCode(), + 'error_message' => $e->getMessage(), + 'stack_trace' => $e->getTraceAsString() + ]; + } + } + + /** + * 【処理1】入力パラメーターをチェックする + * + * 修正版:7項目チェック(status_comment追加) + * 1. デバイスID: 必須、device表に存在チェック + * 2. プロセス名: 「プロセス名」「ジョブ名」いずれか必須 + * 3. ジョブ名: 「プロセス名」「ジョブ名」いずれか必須 + * 4. ステータス: 必須 + * 5. ステータスコメント: 必須、≤255文字 + * 6. 登録日時: 日付型(yyyy/mm/dd形式) + * 7. 更新日時: 日付型(yyyy/mm/dd形式) + * + * @param int $deviceId デバイスID + * @param string|null $processName プロセス名 + * @param string|null $jobName ジョブ名 + * @param string $status ステータス + * @param string $statusComment ステータスコメント + * @param string $createdDate 登録日時 + * @param string $updatedDate 更新日時 + * @return array 検証結果 ['valid' => bool, 'error_message' => string|null] + */ + private function validateParameters( + int $deviceId, + ?string $processName, + ?string $jobName, + string $status, + string $statusComment, + string $createdDate, + string $updatedDate + ): array { + $errors = []; + + // 1. デバイスIDチェック (必須、存在チェック) + if ($deviceId <= 0) { + $errors[] = "パラメーターNG:デバイスID/{$deviceId}"; + } elseif (!Device::where('device_id', $deviceId)->exists()) { + $errors[] = "パラメーターNG:デバイスID/{$deviceId}"; + } + + // 2. プロセス名とジョブ名のいずれか必須チェック + if (empty($processName) && empty($jobName)) { + $errors[] = "パラメーターNG:プロセス名/<空>"; + $errors[] = "パラメーターNG:ジョブ名/<空>"; + } + + // 3. ステータス必須チェック + if (empty($status)) { + $errors[] = "パラメーターNG:ステータス/<空>"; + } + + // 4. ステータスコメント必須チェック、255文字以内 + if (empty($statusComment)) { + $errors[] = "パラメーターNG:ステータスコメント/<空>"; + } elseif (mb_strlen($statusComment) > 255) { + $errors[] = "パラメーターNG:ステータスコメント/長さ超過(" . mb_strlen($statusComment) . "文字)"; + } + + // 5. 登録日時の日付型チェック + if (!$this->isValidDateFormat($createdDate)) { + $errors[] = "パラメーターNG:登録日時/{$createdDate}"; + } + + // 6. 更新日時の日付型チェック + if (!$this->isValidDateFormat($updatedDate)) { + $errors[] = "パラメーターNG:更新日時/{$updatedDate}"; + } + + // エラーがある場合 + if (!empty($errors)) { + // 複数のエラーがある場合は全角カンマ(、)で連結 + $errorMessage = implode('、', $errors); + + return [ + 'valid' => false, + 'error_message' => $errorMessage + ]; + } + + // 正常終了 + return [ + 'valid' => true, + 'error_message' => null + ]; + } + + /** + * 日付形式の検証 + * + * yyyy/mm/dd形式かチェック + * + * @param string $date 日付文字列 + * @return bool 有効な日付形式かどうか + */ + private function isValidDateFormat(string $date): bool + { + // yyyy/mm/dd形式の正規表現チェック + if (!preg_match('/^\d{4}\/\d{2}\/\d{2}$/', $date)) { + return false; + } + + // 実際の日付として有効かチェック + $dateParts = explode('/', $date); + return checkdate((int)$dateParts[1], (int)$dateParts[2], (int)$dateParts[0]); + } + + /** + * 【処理2】バッチ処理ログを登録する + * + * bat_job_logテーブルにINSERT + * 修正版:ステータスコメントは呼び出し元から受け取る(固定値廃止) + * + * @param int $deviceId デバイスID + * @param string|null $processName プロセス名 + * @param string|null $jobName ジョブ名 + * @param string $status ステータス + * @param string $statusComment ステータスコメント(業務固有) + * @param string $createdDate 登録日時 (yyyy/mm/dd形式) + * @param string $updatedDate 更新日時 (yyyy/mm/dd形式) + * @return BatJobLog 作成されたバッチジョブログ + */ + private function createBatchJobLog( + int $deviceId, + ?string $processName, + ?string $jobName, + string $status, + string $statusComment, + string $createdDate, + string $updatedDate + ): BatJobLog { + // 日付文字列をdatetime型に変換(現在時刻を使用) + $createdDatetime = Carbon::createFromFormat('Y/m/d', $createdDate); + $updatedDatetime = Carbon::createFromFormat('Y/m/d', $updatedDate); + + // bat_job_logテーブルに登録(status_commentは呼び出し元から受け取った値を使用) + $batJobLog = BatJobLog::create([ + 'device_id' => $deviceId, + 'process_name' => $processName, + 'job_name' => $jobName, + 'status' => $status, + 'status_comment' => $statusComment, + 'created_at' => $createdDatetime, + 'updated_at' => $updatedDatetime + ]); + + return $batJobLog; + } +} diff --git a/app/Services/ShjElevenService.php b/app/Services/ShjElevenService.php index fe0bb23..eea4848 100644 --- a/app/Services/ShjElevenService.php +++ b/app/Services/ShjElevenService.php @@ -4,30 +4,112 @@ namespace App\Services; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; -use App\Models\Batch\BatchLog; use App\Models\RegularContract; use App\Models\Park; use App\Models\Psection; use App\Models\Ptype; +use App\Models\Setting; +use App\Models\Device; use Carbon\Carbon; /** * SHJ-11 現在契約台数集計サービス - * + * * 集計単位每个の契約台数を算出し、ゾーンマスタとの管理処理を実行 + * bat_job_logへの書き込みはSHJ-8を呼び出す */ class ShjElevenService { + /** + * ShjEightService + * + * @var ShjEightService + */ + protected $shjEightService; + + /** + * コンストラクタ + * + * @param ShjEightService $shjEightService + */ + public function __construct(ShjEightService $shjEightService) + { + $this->shjEightService = $shjEightService; + } + + /** + * バッチ処理用の有効なデバイスIDを取得 + * + * deviceテーブルから最初の有効なdevice_idを取得する。 + * データが存在しない場合は例外をスローする。 + * + * @return int 有効なdevice_id + * @throws \Exception deviceテーブルにレコードが存在しない場合 + */ + private function getBatchDeviceId(): int + { + $device = Device::orderBy('device_id')->first(); + + if (!$device) { + throw new \Exception('deviceテーブルにレコードが存在しません。SHJ-8バッチログ作成に必要なデバイスIDを取得できません。'); + } + + Log::debug('SHJ-11 バッチ用デバイスID取得', [ + 'device_id' => $device->device_id + ]); + + return $device->device_id; + } + + /** + * 現在使用中のprice主表名を取得する + * + * setting.web_master から価格マスタテーブル名を決定 + * web_master の値('_a' または '_b')から 'price_a' または 'price_b' を返す + * + * @return string price主表名('price_a' または 'price_b') + * @throws \Exception setting取得失敗時 + */ + private function getPriceTableName(): string + { + try { + $setting = Setting::getSettings(); + + if (!$setting || empty($setting->web_master)) { + throw new \Exception('setting.web_masterの取得に失敗しました'); + } + + // web_master の値:'_a' または '_b' + $webMaster = $setting->web_master; + + // 'price_' + ('_a' → 'a' / '_b' → 'b') + $priceTable = 'price_' . ltrim($webMaster, '_'); + + Log::info('SHJ-11 price主表名決定', [ + 'web_master' => $webMaster, + 'price_table' => $priceTable + ]); + + return $priceTable; + + } catch (\Exception $e) { + Log::error('SHJ-11 price主表名取得エラー', [ + 'error' => $e->getMessage() + ]); + throw $e; + } + } + /** * 【処理1】集計単位每个の契約台数を算出する - * + * * 集計単位: 駐輪場ID + 車種区分ID + 駐輪分類ID + ゾーンID - * + * * SQL仕様に基づく複雑なJOIN処理: - * - regular_contract (T1) + * - regular_contract (T1) * - park (T2) * - psection (T4) - * - price_a (T5) + * - price_a/price_b (T5) ※web_master設定により動的に決定 * - ptype (T3) * * @return array 契約台数集計結果 @@ -35,6 +117,9 @@ class ShjElevenService public function calculateContractCounts(): array { try { + // setting.web_master から使用するprice主表を決定 + $priceTable = $this->getPriceTableName(); + $query = DB::table('regular_contract as T1') ->select([ 'T1.park_id', // 駐輪場ID @@ -50,8 +135,8 @@ class ShjElevenService ->join('park as T2', 'T1.park_id', '=', 'T2.park_id') // psection テーブルとの JOIN ->join('psection as T4', 'T1.psection_id', '=', 'T4.psection_id') - // price_a テーブルとの複合条件 JOIN - ->join('price_a as T5', function($join) { + // price_a/price_b テーブルとの複合条件 JOIN(動的テーブル名) + ->join(DB::raw($priceTable . ' as T5'), function($join) { $join->on('T1.park_id', '=', 'T5.park_id') ->on('T1.price_parkplaceid', '=', 'T5.price_parkplaceid') ->on('T1.psection_id', '=', 'T5.psection_id'); @@ -59,11 +144,13 @@ class ShjElevenService // ptype テーブルとの JOIN ->join('ptype as T3', 'T5.ptype_id', '=', 'T3.ptype_id') ->where([ - ['T1.contract_flag', '=', 1], // 有効契約 - ['T2.park_close_flag', '=', 0], // 駐輪場未閉鎖 + ['T1.contract_flag', '=', 1], // 授受フラグ = 1 + ['T2.park_close_flag', '=', 0], // 閉設フラグ = 0 ]) - // 契約有効期間内の条件 - ->whereRaw("date_format(now(), '%y %m %d') BETWEEN T1.contract_periods AND T1.contract_periode") + // 契約有効期間内の条件(仕様書指定:'%y.%m.%d'形式) + ->whereRaw("date_format(now(), '%y.%m.%d') BETWEEN T1.contract_periods AND T1.contract_periode") + // zone_idがNULLのレコードは除外(ゾーンマスタ更新不可のため) + ->whereNotNull('T1.zone_id') ->groupBy([ 'T1.park_id', 'T2.park_name', @@ -77,9 +164,11 @@ class ShjElevenService Log::info('SHJ-11 契約台数算出完了', [ 'count' => $query->count(), + 'price_table' => $priceTable, 'sql_conditions' => [ 'contract_flag' => 1, 'park_close_flag' => 0, + 'date_format' => '%y.%m.%d', 'contract_period_check' => 'BETWEEN contract_periods AND contract_periode' ] ]); @@ -97,12 +186,15 @@ class ShjElevenService /** * 【処理2・3】ゾーンマスタ管理処理 - * - * 処理フロー: - * 1. ゾーンマスタを取得する - * 2. 取得判定 → 存在しない場合は新規登録 - * 3. 契約台数チェック(限界台数超過判定) - * 4. 契約台数を反映する(ゾーンマスタ更新) + * + * 処理フロー(仕様書準拠): + * 処理1の取得レコード数分繰り返し: + * 【処理2】ゾーンマスタを取得する + * 【判断2】取得判定 + * - ゾーンマスタなし → INSERT(トランザクション内) → commit → 【処理4】SHJ-8(トランザクション外) → 次へ + * - ゾーンマスタあり → 【判断3】契約台数チェック → 【処理3】UPDATE(トランザクション内) → commit → 【処理4】SHJ-8(トランザクション外) → 次へ + * + * ※SHJ-8ログは各レコード処理後に確実に記録するため、トランザクション外で実行 * * @param array $contractCounts 契約台数集計結果 * @return array 処理結果 @@ -112,27 +204,104 @@ class ShjElevenService $createdZones = 0; $updatedZones = 0; $overCapacityCount = 0; - $errors = []; - $processParameters = []; + $batchLogErrors = []; try { - DB::beginTransaction(); + // 処理1の取得レコード数分繰り返し foreach ($contractCounts as $contractData) { try { + // 【防御的チェック】必須キーがNULLの場合はスキップ + if (empty($contractData->zone_id) || empty($contractData->psection_id) || empty($contractData->ptype_id)) { + Log::warning('SHJ-11 必須キー欠落のためスキップ', [ + 'park_id' => $contractData->park_id ?? null, + 'zone_id' => $contractData->zone_id ?? null, + 'psection_id' => $contractData->psection_id ?? null, + 'ptype_id' => $contractData->ptype_id ?? null + ]); + + $batchLogErrors[] = [ + 'park_id' => $contractData->park_id ?? null, + 'zone_id' => $contractData->zone_id ?? null, + 'error' => '必須キー欠落(zone_id/psection_id/ptype_id)' + ]; + + continue; + } + + // 各レコードごとに独立したトランザクションを開始 + DB::beginTransaction(); + // 【処理2】ゾーンマスタを取得する $zoneData = $this->getZoneData($contractData); + // 【判断2】取得判定 if (!$zoneData) { - // 【判断2】ゾーンマスタが存在しない場合 → 新規登録 + // ゾーンマスタなし → INSERT $createResult = $this->createZoneData($contractData); - if ($createResult['success']) { - $createdZones++; + + if (!$createResult['success']) { + // INSERT失敗時のエラー処理 + DB::rollBack(); + + Log::error('SHJ-11 ゾーンマスタINSERT失敗', [ + 'park_id' => $contractData->park_id, + 'zone_id' => $contractData->zone_id, + 'error' => $createResult['message'] + ]); + + $batchLogErrors[] = [ + 'park_id' => $contractData->park_id, + 'zone_id' => $contractData->zone_id, + 'error' => 'INSERT失敗: ' . $createResult['message'] + ]; + + // INSERT失敗時も次の繰り返しへ + continue; } - $zoneData = $createResult['zone_data']; + + // INSERTトランザクションをcommit + DB::commit(); + + $createdZones++; + + // status_comment作成(INSERT分岐) + $statusComment = $this->formatStatusComment( + $contractData->park_name, + $contractData->ptype_subject, + $contractData->psection_subject, + $contractData->zone_id, + '' // INSERT分岐では台数アラートなし + ); + + // 【処理4】bat_job_logに直接書き込み(トランザクション外・INSERT分岐) + $batchLogResult = $this->writeBatJobLog( + $contractData, + $statusComment, + false // 限界台数超過なし + ); + + // bat_job_log書き込み結果チェック + if (!$batchLogResult['success']) { + Log::warning('bat_job_log書き込み失敗(INSERT分岐)', [ + 'park_id' => $contractData->park_id, + 'zone_id' => $contractData->zone_id, + 'error_message' => $batchLogResult['error_message'] ?? null + ]); + + // bat_job_log書き込み失敗をbatch_log_errorsに記録 + $batchLogErrors[] = [ + 'park_id' => $contractData->park_id, + 'zone_id' => $contractData->zone_id, + 'error' => 'bat_job_log書き込み失敗(INSERT分岐): ' . ($batchLogResult['error_message'] ?? 'unknown error') + ]; + } + + // INSERT分岐は【処理4】後に次の繰り返しへ + continue; } - // 【判断3】契約台数チェック(限界台数超過判定) + // ゾーンマスタあり → 【判断3】契約台数チェック $isOverCapacity = $this->checkCapacityLimit($contractData, $zoneData); if ($isOverCapacity) { $overCapacityCount++; @@ -144,57 +313,112 @@ class ShjElevenService ]); } - // 【処理3】契約台数を反映する(ゾーンマスタ更新) + // 【処理3】契約台数を反映する(UPDATE) $updateResult = $this->updateZoneContractCount($contractData); - if ($updateResult['success']) { - $updatedZones++; + + if (!$updateResult['success']) { + // UPDATE失敗時のエラー処理 + DB::rollBack(); + + Log::error('SHJ-11 ゾーンマスタUPDATE失敗', [ + 'park_id' => $contractData->park_id, + 'zone_id' => $contractData->zone_id, + 'error' => $updateResult['message'] + ]); + + $batchLogErrors[] = [ + 'park_id' => $contractData->park_id, + 'zone_id' => $contractData->zone_id, + 'error' => 'UPDATE失敗: ' . $updateResult['message'] + ]; + + // UPDATE失敗時も次の繰り返しへ + continue; } - // 処理パラメータ記録 - $processParameters[] = [ - 'park_id' => $contractData->park_id, - 'psection_id' => $contractData->psection_id, - 'ptype_id' => $contractData->ptype_id, - 'zone_id' => $contractData->zone_id, - 'contract_count' => $contractData->cnt, - 'is_over_capacity' => $isOverCapacity, - 'zone_created' => !$zoneData && $createResult['success'] ?? false, - 'zone_updated' => $updateResult['success'] ?? false - ]; + // UPDATEトランザクションをcommit + DB::commit(); + + $updatedZones++; + + // status_comment作成(UPDATE分岐) + $capacityAlert = $isOverCapacity ? '限界収容台数を超えています。' : ''; + $statusComment = $this->formatStatusComment( + $contractData->park_name, + $contractData->ptype_subject, + $contractData->psection_subject, + $contractData->zone_id, + $capacityAlert + ); + + // 【処理4】bat_job_logに直接書き込み(トランザクション外・UPDATE分岐) + $batchLogResult = $this->writeBatJobLog( + $contractData, + $statusComment, + $isOverCapacity + ); + + // bat_job_log書き込み結果チェック + if (!$batchLogResult['success']) { + Log::warning('bat_job_log書き込み失敗(UPDATE分岐)', [ + 'park_id' => $contractData->park_id, + 'zone_id' => $contractData->zone_id, + 'error_message' => $batchLogResult['error_message'] ?? null + ]); + + // bat_job_log書き込み失敗をbatch_log_errorsに記録 + $batchLogErrors[] = [ + 'park_id' => $contractData->park_id, + 'zone_id' => $contractData->zone_id, + 'error' => 'bat_job_log書き込み失敗(UPDATE分岐): ' . ($batchLogResult['error_message'] ?? 'unknown error') + ]; + } } catch (\Exception $e) { - $errors[] = [ + // 例外時はロールバック(アクティブなトランザクションがある場合のみ) + if (DB::transactionLevel() > 0) { + DB::rollBack(); + } + + // 個別レコードエラーもログ記録して次へ進む + $batchLogErrors[] = [ 'park_id' => $contractData->park_id ?? null, 'zone_id' => $contractData->zone_id ?? null, 'error' => $e->getMessage() ]; - - Log::warning('SHJ-11 個別処理エラー', [ + + Log::warning('SHJ-11 個別レコード処理エラー', [ 'park_id' => $contractData->park_id ?? null, 'zone_id' => $contractData->zone_id ?? null, 'error' => $e->getMessage() ]); + + // エラーでも次の繰り返しへ続行 + continue; } } - DB::commit(); - return [ 'success' => true, 'created_zones' => $createdZones, 'updated_zones' => $updatedZones, 'over_capacity_count' => $overCapacityCount, - 'parameters' => $processParameters, - 'errors' => $errors, + 'batch_log_errors' => $batchLogErrors, 'message' => '現在契約台数集計処理完了' ]; } catch (\Exception $e) { - DB::rollBack(); - + // 外層エラー時のロールバック + // ※各レコード処理は独立トランザクションのため、 + // ここでのrollBackは不要だが安全のため実行 + if (DB::transactionLevel() > 0) { + DB::rollBack(); + } + Log::error('SHJ-11 ゾーンマスタ管理処理全体エラー', [ 'error' => $e->getMessage(), - 'processed_count' => count($processParameters) + 'created_zones' => $createdZones, + 'updated_zones' => $updatedZones ]); return [ @@ -202,8 +426,7 @@ class ShjElevenService 'created_zones' => $createdZones, 'updated_zones' => $updatedZones, 'over_capacity_count' => $overCapacityCount, - 'parameters' => $processParameters, - 'errors' => $errors, + 'batch_log_errors' => $batchLogErrors, 'message' => 'ゾーンマスタ管理処理エラー: ' . $e->getMessage(), 'details' => $e->getTraceAsString() ]; @@ -329,7 +552,7 @@ class ShjElevenService /** * ゾーンマスタ契約台数更新 - * + * * 【処理3】現在契約台数をゾーンマスタに反映 * * @param object $contractData 契約台数集計データ @@ -341,7 +564,7 @@ class ShjElevenService $updateData = [ 'zone_number' => $contractData->cnt, // 現在契約台数を更新 'updated_at' => now(), // 更新日時 - 'ope_id' => 'SHJ-11' // 更新オペレータID + 'ope_id' => 9999999 // 更新オペレータID(INSERT時と同様、DB型int unsignedに対応) ]; $updated = DB::table('zone') @@ -365,6 +588,11 @@ class ShjElevenService 'message' => 'ゾーンマスタ契約台数を更新しました' ]; } else { + Log::warning('SHJ-11 ゾーンマスタ更新対象なし', [ + 'zone_id' => $contractData->zone_id, + 'park_id' => $contractData->park_id + ]); + return [ 'success' => false, 'message' => 'ゾーンマスタ更新対象が見つかりません' @@ -386,47 +614,176 @@ class ShjElevenService } /** - * 【処理4】バッチ処理ログを作成する - * - * 統一BatchLogシステムを使用してSHJ-11の実行ログを記録 + * status_commentを仕様書指定フォーマットで作成 * - * @param string $status ステータス - * @param array $parameters パラメータ - * @param string $message メッセージ - * @param int $executionCount 実行回数 - * @param int $successCount 成功回数 - * @param int $errorCount エラー回数 - * @return void + * フォーマット: 駐輪場名/駐輪分類名/車種区分名/ゾーンID[台数アラート] + * + * @param string $parkName 駐輪場名 + * @param string $ptypeSubject 駐輪分類名 + * @param string $psectionSubject 車種区分名 + * @param int $zoneId ゾーンID + * @param string $capacityAlert 台数アラート(「限界収容台数を超えています。」または空文字) + * @return string フォーマット済みstatus_comment */ - public function createBatchLog( - string $status, - array $parameters, - string $message, - int $executionCount = 0, - int $successCount = 0, - int $errorCount = 0 - ): void { + private function formatStatusComment( + string $parkName, + string $ptypeSubject, + string $psectionSubject, + int $zoneId, + string $capacityAlert + ): string { + $baseComment = $parkName . '/' . $ptypeSubject . '/' . $psectionSubject . '/' . $zoneId; + + if (!empty($capacityAlert)) { + return $baseComment . ' ' . $capacityAlert; + } + + return $baseComment; + } + + /** + * 【処理4】個別レコードのバッチ処理ログを作成する + * + * SHJ-11は業務固有のstatus_commentを記録するため、SHJ-8を使わずbat_job_logに直接書き込む + * + * bat_job_log登録内容: + * 1. デバイスID + * 2. プロセス名: SHJ-11 + * 3. ジョブ名: SHJ-11現在契約台数集計 + * 4. ステータス: success + * 5. ステータスコメント: 業務固有(駐輪場名/駐輪分類名/車種区分名/ゾーンID[台数アラート]) + * 6. 登録日時: 現在の日付 + * 7. 更新日時: 現在の日付 + * + * @param object $contractData 契約台数集計データ + * @param string $statusComment status_comment(台数アラート含む) + * @param bool $isOverCapacity 限界台数超過フラグ + * @return array 処理結果 ['success' => bool, 'error_message' => string|null] + */ + private function writeBatJobLog( + $contractData, + string $statusComment, + bool $isOverCapacity + ): array { try { - BatchLog::createBatchLog( - 'SHJ-11', + // SHJ-8バッチ処理ログ作成パラメータ設定 + $deviceId = $this->getBatchDeviceId(); // deviceテーブルから有効なIDを取得 + $processName = 'SHJ-11'; + $jobName = 'SHJ-11現在契約台数集計'; + $status = 'success'; + $today = now()->format('Y/m/d'); + + Log::info('SHJ-8バッチ処理ログ作成', [ + 'device_id' => $deviceId, + 'process_name' => $processName, + 'job_name' => $jobName, + 'status' => $status, + 'status_comment' => $statusComment, + 'park_id' => $contractData->park_id, + 'zone_id' => $contractData->zone_id + ]); + + // SHJ-8サービスを呼び出し + $this->shjEightService->execute( + $deviceId, + $processName, + $jobName, $status, - $parameters, - $message, - [ - 'execution_count' => $executionCount, - 'success_count' => $successCount, - 'error_count' => $errorCount, - 'process_type' => '現在契約台数集計', - 'executed_at' => now()->toISOString() - ] + $statusComment, + $today, + $today ); - } catch (\Exception $e) { - Log::error('SHJ-11 バッチログ作成エラー', [ - 'error' => $e->getMessage(), - 'status' => $status, - 'message' => $message + Log::info('SHJ-8バッチ処理ログ作成完了', [ + 'park_id' => $contractData->park_id, + 'zone_id' => $contractData->zone_id ]); + + return [ + 'success' => true, + 'error_message' => null + ]; + + } catch (\Exception $e) { + Log::error('bat_job_log書き込みエラー', [ + 'park_id' => $contractData->park_id ?? null, + 'zone_id' => $contractData->zone_id ?? null, + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + + // エラーが発生してもメイン処理は継続 + return [ + 'success' => false, + 'error_message' => $e->getMessage() + ]; + } + } + + /** + * 【判断1】取得件数=0時のバッチログ作成 + * + * 取得件数が0件の場合に呼び出される特別なバッチログ作成 + * bat_job_logに直接書き込み + * + * bat_job_log登録内容: + * 1. デバイスID + * 2. プロセス名: SHJ-11 + * 3. ジョブ名: SHJ-11現在契約台数集計 + * 4. ステータス: success + * 5. ステータスコメント: 全駐輪場契約なし + * 6. 登録日時: 現在の日付 + * 7. 更新日時: 現在の日付 + * + * @return array 処理結果 ['success' => bool, 'error_message' => string|null] + */ + public function writeBatJobLogForNoContracts(): array + { + try { + // SHJ-8バッチ処理ログ作成パラメータ設定 + $deviceId = $this->getBatchDeviceId(); // deviceテーブルから有効なIDを取得 + $processName = 'SHJ-11'; + $jobName = 'SHJ-11現在契約台数集計'; + $status = 'success'; + $statusComment = '全駐輪場契約なし'; + $today = now()->format('Y/m/d'); + + Log::info('SHJ-8バッチ処理ログ作成(対象なし)', [ + 'device_id' => $deviceId, + 'process_name' => $processName, + 'job_name' => $jobName, + 'status' => $status, + 'status_comment' => $statusComment + ]); + + // SHJ-8サービスを呼び出し + $this->shjEightService->execute( + $deviceId, + $processName, + $jobName, + $status, + $statusComment, + $today, + $today + ); + + Log::info('SHJ-8バッチ処理ログ作成完了(対象なし)'); + + return [ + 'success' => true, + 'error_message' => null + ]; + + } catch (\Exception $e) { + Log::error('bat_job_log書き込みエラー(対象なし)', [ + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + + return [ + 'success' => false, + 'error_message' => $e->getMessage() + ]; } } } diff --git a/app/Services/ShjFiveService.php b/app/Services/ShjFiveService.php index 4b4b57a..2632b21 100644 --- a/app/Services/ShjFiveService.php +++ b/app/Services/ShjFiveService.php @@ -5,16 +5,33 @@ namespace App\Services; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; use App\Models\OperatorQue; +use App\Models\Device; use Exception; /** * SHJ-5 空き待ち通知処理サービス - * + * * 駐輪場の空き状況を確認し、空き待ち予約者への通知処理を実行する * 仕様書に基づくバックグラウンド定期バッチ処理 */ class ShjFiveService { + /** + * ShjEightService + * + * @var ShjEightService + */ + protected $shjEightService; + + /** + * コンストラクタ + * + * @param ShjEightService $shjEightService + */ + public function __construct(ShjEightService $shjEightService) + { + $this->shjEightService = $shjEightService; + } /** * SHJ-5 メイン処理を実行 * @@ -181,6 +198,29 @@ class ShjFiveService $queueErrorCount ?? 0 // 実際のキュー登録失敗件数 ); + // SHJ-8 バッチ処理ログ作成 + try { + $device = Device::orderBy('device_id')->first(); + $deviceId = $device ? $device->device_id : 1; + $today = now()->format('Y/m/d'); + + $this->shjEightService->execute( + $deviceId, + 'SHJ-5', + 'SHJ-5空き待ち通知', + 'success', + $statusComment, + $today, + $today + ); + + Log::info('SHJ-8 バッチ処理ログ作成完了'); + } catch (Exception $e) { + Log::error('SHJ-8 バッチ処理ログ作成エラー', [ + 'error' => $e->getMessage() + ]); + } + return [ 'success' => true, 'message' => 'SHJ-5 空き待ち通知処理が正常に完了しました', @@ -509,15 +549,24 @@ class ShjFiveService $mailTemplateId ); + // SHJ-7の結果を標準形式に変換(result: 0=成功, 1=失敗) + $success = ($mailResult['result'] ?? 1) === 0; + Log::info('空き待ち通知メール送信試行完了', [ 'user_id' => $waitingUser->user_id, 'main_email' => $mainEmail, 'sub_email' => $subEmail, 'mail_template_id' => $mailTemplateId, - 'result_success' => $mailResult['success'] ?? false + 'result' => $mailResult['result'] ?? 1, + 'success' => $success ]); - return $mailResult; + return [ + 'success' => $success, + 'result' => $mailResult['result'] ?? 1, + 'error' => $mailResult['error_info'] ?? null, + 'message' => $success ? 'メール送信成功' : ($mailResult['error_info'] ?? 'メール送信失敗') + ]; } catch (Exception $e) { Log::error('空き待ち通知メール送信エラー', [ diff --git a/app/Services/ShjFourBService.php b/app/Services/ShjFourBService.php index ebb5a7b..e9fea8a 100644 --- a/app/Services/ShjFourBService.php +++ b/app/Services/ShjFourBService.php @@ -6,15 +6,19 @@ use App\Models\SettlementTransaction; use App\Models\RegularContract; use App\Models\Park; use App\Models\PriceA; -use App\Models\Batch\BatchLog; +use App\Models\BatJobLog; +use App\Models\Device; +use App\Models\User; use App\Services\ShjThirteenService; +use App\Services\ShjEightService; +use App\Services\ShjMailSendService; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\DB; use Carbon\Carbon; /** * SHJ-4B 定期契約更新処理サービス - * + * * SHJ-4Aで登録された決済情報を基に定期契約の更新処理を実行する * ウェルネットのPUSH通知を契機とした決済トランザクション処理 */ @@ -34,6 +38,34 @@ class ShjFourBService const CONTRACT_FLAG_UPDATED = 1; // 更新済 const CONTRACT_FLAG_ERROR = 2; // エラー状態 + /** + * SHJ-8 バッチ処理ログ作成サービス + * + * @var ShjEightService + */ + protected $shjEightService; + + /** + * SHJ-7 メール送信サービス + * + * @var ShjMailSendService + */ + protected $mailSendService; + + /** + * コンストラクタ + * + * @param ShjEightService $shjEightService + * @param ShjMailSendService $mailSendService + */ + public function __construct( + ShjEightService $shjEightService, + ShjMailSendService $mailSendService + ) { + $this->shjEightService = $shjEightService; + $this->mailSendService = $mailSendService; + } + /** * 決済トランザクション処理メイン実行 * @@ -66,22 +98,29 @@ class ShjFourBService if (!$contractResult['found']) { // 対象レコードなしの場合 - return $this->handleNoTargetRecord($settlement, $contractResult); + $result = $this->handleNoTargetRecord($settlement, $contractResult); + $this->createBatchLog($settlement, null, null, true, $result['message']); + return $result; } if ($contractResult['already_processed']) { // 登録済みの場合 - return $this->handleAlreadyProcessed($settlement, $contractResult); + $result = $this->handleAlreadyProcessed($settlement, $contractResult); + $contract = $contractResult['contract']; + $this->createBatchLog($settlement, $contract, null, true, $result['message']); + return $result; } $contract = $contractResult['contract']; - + // 【判断1】授受状態チェック $statusResult = $this->judgeReceiptStatus($settlement, $contract); - + if (!$statusResult['valid']) { // 授受状態が異常な場合 - return $this->handleInvalidStatus($settlement, $contract, $statusResult); + $result = $this->handleInvalidStatus($settlement, $contract, $statusResult); + $this->createBatchLog($settlement, $contract, null, true, $result['message']); + return $result; } // 【判断2】金額チェック @@ -105,7 +144,11 @@ class ShjFourBService ]; Log::info('SHJ-4B 決済トランザクション処理完了', $result); - + + // 【処理6】バッチ処理ログ作成(SHJ-8呼び出し) + $mailCommentSuffix = $sideEffectResult['user_mail']['batch_comment_suffix'] ?? null; + $this->createBatchLog($settlement, $contract, $amountResult, true, null, $mailCommentSuffix); + return $result; } catch (\Throwable $e) { @@ -115,7 +158,17 @@ class ShjFourBService 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString(), ]); - + + // エラー時のバッチログ作成 + try { + $settlement = SettlementTransaction::find($settlementTransactionId); + if ($settlement) { + $this->createBatchLog($settlement, null, null, false, $e->getMessage()); + } + } catch (\Throwable $logError) { + Log::error('SHJ-4B バッチログ作成エラー', ['error' => $logError->getMessage()]); + } + throw $e; } } @@ -284,16 +337,17 @@ class ShjFourBService ]; } - // 条件3: batch_logで同一決済の処理完了記録があるか - $existingBatchLog = BatchLog::where('process_name', 'shj4b') - ->where('status', BatchLog::STATUS_SUCCESS) - ->where('parameters', 'like', '%"settlement_transaction_id":' . $settlement->settlement_transaction_id . '%') + // 条件3: bat_job_logで同一決済の処理完了記録があるか + // status_commentに決済トランザクションIDが含まれているかチェック + $existingBatchLog = BatJobLog::where('process_name', 'SHJ-4B') + ->where('status', 'success') + ->where('status_comment', 'like', '%settlement_transaction_id:' . $settlement->settlement_transaction_id . '%') ->exists(); if ($existingBatchLog) { return [ 'processed' => true, - 'reason' => "batch_logに処理完了記録が存在", + 'reason' => "bat_job_logに処理完了記録が存在", ]; } @@ -820,34 +874,107 @@ class ShjFourBService } /** - * 利用者メール送信処理 + * 【処理5】利用者メール送信処理 + * + * SHJ-4B仕様準拠: + * 1. 利用者マスタよりメールアドレス、予備メールアドレスを取得 + * 2. SHJ-7メール送信を呼び出し(使用プログラムID: 205) + * 3. 処理結果判定: + * - result = 0 (正常): バッチコメントに "/メール正常終了件数:1" を追加 + * - その他: バッチコメントに "/メール異常終了件数:1、" + error_info を追加 * * @param SettlementTransaction $settlement * @param object $contract * @param array $amountResult - * @return array + * @return array 処理結果 ['success' => bool, 'mail_status' => string, 'batch_comment_suffix' => string] */ private function sendUserNotificationMail(SettlementTransaction $settlement, $contract, array $amountResult): array { - // TODO: 実際のメール送信処理を実装 - // 現在はプレースホルダー - - $mailType = ($amountResult['comparison'] === self::AMOUNT_MATCH) ? 'success' : 'error'; - - Log::info('SHJ-4B 利用者メール送信処理', [ - 'contract_id' => $contract->contract_id, - 'user_id' => $contract->user_id, - 'settlement_transaction_id' => $settlement->settlement_transaction_id, - 'mail_type' => $mailType, - 'amount_comparison' => $amountResult['comparison'], - ]); - - return [ - 'sent' => true, - 'method' => 'placeholder', - 'mail_type' => $mailType, - 'message' => '利用者メール送信処理は実装予定です', - ]; + try { + // 【処理5】利用者マスタよりメールアドレス、予備メールアドレスを取得する + $user = User::select('user_name', 'user_primemail', 'user_submail') + ->where('user_seq', $contract->user_id) + ->first(); + + if (!$user) { + Log::error('SHJ-4B 利用者メール送信処理: 利用者情報取得失敗', [ + 'user_id' => $contract->user_id, + 'contract_id' => $contract->contract_id, + ]); + + return [ + 'success' => false, + 'mail_status' => 'user_not_found', + 'batch_comment_suffix' => '/メール異常終了件数:1、利用者情報取得失敗' + ]; + } + + $mailAddress = $user->user_primemail ?? ''; + $backupMailAddress = $user->user_submail ?? ''; + + Log::info('SHJ-4B 利用者メール送信処理開始', [ + 'contract_id' => $contract->contract_id, + 'user_id' => $contract->user_id, + 'user_name' => $user->user_name, + 'settlement_transaction_id' => $settlement->settlement_transaction_id, + 'mail_address' => $mailAddress, + 'amount_comparison' => $amountResult['comparison'], + ]); + + // 共通処理「SHJ-7メール送信」を呼び出し + // 使用プログラムID: 205(仕様書準拠) + $mailResult = $this->mailSendService->executeMailSend( + $mailAddress, + $backupMailAddress, + 205 // SHJ-4B仕様: 使用プログラムID = 205 + ); + + // SHJ-7仕様準拠: result === 0 が正常、それ以外は異常 + if (($mailResult['result'] ?? 1) === 0) { + // 【正常終了】バッチコメントに "/メール正常終了件数:1" を設定 + Log::info('SHJ-4B 利用者メール送信成功', [ + 'contract_id' => $contract->contract_id, + 'user_id' => $contract->user_id, + 'mail_address' => $mailAddress, + ]); + + return [ + 'success' => true, + 'mail_status' => 'sent', + 'batch_comment_suffix' => '/メール正常終了件数:1' + ]; + } else { + // 【異常終了】バッチコメントに "/メール異常終了件数:1、" + error_info を設定 + $errorInfo = $mailResult['error_info'] ?? 'メール送信失敗'; + + Log::error('SHJ-4B 利用者メール送信失敗', [ + 'contract_id' => $contract->contract_id, + 'user_id' => $contract->user_id, + 'mail_address' => $mailAddress, + 'error_info' => $errorInfo, + ]); + + return [ + 'success' => false, + 'mail_status' => 'failed', + 'batch_comment_suffix' => "/メール異常終了件数:1、{$errorInfo}" + ]; + } + + } catch (\Exception $e) { + Log::error('SHJ-4B 利用者メール送信処理例外エラー', [ + 'contract_id' => $contract->contract_id, + 'user_id' => $contract->user_id, + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString(), + ]); + + return [ + 'success' => false, + 'mail_status' => 'exception', + 'batch_comment_suffix' => '/メール異常終了件数:1、システムエラー: ' . $e->getMessage() + ]; + } } /** @@ -864,18 +991,100 @@ class ShjFourBService array $amountResult ): array { // TODO: OperatorQue モデルを使用したキューへの登録処理を実装 - + Log::info('SHJ-4B オペレーターキュー登録処理実行', [ 'settlement_transaction_id' => $settlement->settlement_transaction_id, 'contract_id' => $contract->contract_id, 'amount_comparison' => $amountResult['comparison'], 'difference' => $amountResult['difference'], ]); - + return [ 'registered' => true, 'method' => 'placeholder', 'message' => 'オペレーターキュー登録処理は実装予定です', ]; } + + /** + * 【処理6】バッチ処理ログ作成 + * + * SHJ-8サービスを呼び出してbat_job_logに記録 + * + * @param SettlementTransaction $settlement + * @param object|null $contract + * @param array|null $amountResult + * @param bool $isSuccess + * @param string|null $errorMessage + * @param string|null $mailCommentSuffix メール送信結果コメント(例: "/メール正常終了件数:1" or "/メール異常終了件数:1、{error_info}") + * @return void + */ + private function createBatchLog( + SettlementTransaction $settlement, + $contract = null, + ?array $amountResult = null, + bool $isSuccess = true, + ?string $errorMessage = null, + ?string $mailCommentSuffix = null + ): void { + try { + $device = Device::orderBy('device_id')->first(); + $deviceId = $device ? $device->device_id : 1; + $today = now()->format('Y/m/d'); + + // ステータスコメント生成(内部変数.バッチコメント) + if ($errorMessage) { + // エラー時 + $statusComment = "支払いステータスチェック:エラー(決済トランザクションID:{$settlement->settlement_transaction_id}) - {$errorMessage}"; + } elseif ($amountResult) { + // 正常処理時 + $contractId = $contract ? $contract->contract_id : 'N/A'; + + switch ($amountResult['comparison']) { + case self::AMOUNT_MATCH: + $statusComment = "支払いステータスチェック:OK(決済トランザクションID:{$settlement->settlement_transaction_id}、契約ID:{$contractId}、金額一致)"; + break; + case self::AMOUNT_SHORTAGE: + $statusComment = "支払いステータスチェック:請求金額より授受金額が少ないです(決済トランザクションID:{$settlement->settlement_transaction_id}、契約ID:{$contractId}、差額:{$amountResult['difference']}円)"; + break; + case self::AMOUNT_EXCESS: + $statusComment = "支払いステータスチェック:請求金額より授受金額が多いです(決済トランザクションID:{$settlement->settlement_transaction_id}、契約ID:{$contractId}、差額:{$amountResult['difference']}円)"; + break; + default: + $statusComment = "支払いステータスチェック:処理完了(決済トランザクションID:{$settlement->settlement_transaction_id}、契約ID:{$contractId})"; + } + } else { + // その他のケース(対象なし、登録済み等) + $contractId = $contract ? $contract->contract_id : 'N/A'; + $statusComment = "支払いステータスチェック:処理完了(決済トランザクションID:{$settlement->settlement_transaction_id}、契約ID:{$contractId})"; + } + + // メール送信結果をバッチコメントに追加 + if ($mailCommentSuffix) { + $statusComment .= $mailCommentSuffix; + } + + // SHJ-8サービス呼び出し + $this->shjEightService->execute( + $deviceId, + 'SHJ-4B', + 'SHJ-4支払いステータスチェック', + 'success', + $statusComment, + $today, + $today + ); + + Log::info('SHJ-4B バッチ処理ログ作成完了', [ + 'settlement_transaction_id' => $settlement->settlement_transaction_id, + 'status_comment' => $statusComment, + ]); + + } catch (\Exception $e) { + Log::error('SHJ-4B バッチ処理ログ作成エラー', [ + 'error' => $e->getMessage(), + 'settlement_transaction_id' => $settlement->settlement_transaction_id, + ]); + } + } } diff --git a/app/Services/ShjFourCService.php b/app/Services/ShjFourCService.php index 63cf75e..e2f1a22 100644 --- a/app/Services/ShjFourCService.php +++ b/app/Services/ShjFourCService.php @@ -4,7 +4,7 @@ namespace App\Services; use App\Models\Park; use App\Models\RegularContract; -use App\Models\Batch\BatchLog; +use App\Models\Device; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\DB; use Carbon\Carbon; @@ -32,27 +32,27 @@ class ShjFourCService protected $contractModel; /** - * BatchLog モデル + * ShjEightService * - * @var BatchLog + * @var ShjEightService */ - protected $batchLogModel; + protected $shjEightService; /** * コンストラクタ * * @param Park $parkModel * @param RegularContract $contractModel - * @param BatchLog $batchLogModel + * @param ShjEightService $shjEightService */ public function __construct( Park $parkModel, RegularContract $contractModel, - BatchLog $batchLogModel + ShjEightService $shjEightService ) { $this->parkModel = $parkModel; $this->contractModel = $contractModel; - $this->batchLogModel = $batchLogModel; + $this->shjEightService = $shjEightService; } /** @@ -71,24 +71,11 @@ class ShjFourCService */ public function executeRoomAllocation(int $parkId, int $ptypeId, int $psectionId): array { - $batchLogId = null; - - try { - // バッチ処理開始ログ作成(実際のコマンド名を記録) - $batchLog = BatchLog::createBatchLog( - 'shj4c', - BatchLog::STATUS_START, - [ - 'park_id' => $parkId, - 'ptype_id' => $ptypeId, - 'psection_id' => $psectionId - ], - 'SHJ-4C 室割当処理開始' - ); - $batchLogId = $batchLog->id; + $statusComment = ''; + $status = 'success'; + try { Log::info('SHJ-4C 室割当処理開始', [ - 'batch_log_id' => $batchLogId, 'park_id' => $parkId, 'ptype_id' => $ptypeId, 'psection_id' => $psectionId @@ -99,20 +86,16 @@ class ShjFourCService if (empty($zoneInfo)) { $message = '対象のゾーン情報が見つかりません'; - - // バッチログ更新(通用方法使用) - $batchLog->update([ - 'status' => BatchLog::STATUS_ERROR, - 'end_time' => now(), - 'message' => $message, - 'error_details' => $message, - 'error_count' => 1 - ]); - + $status = 'error'; + $statusComment = sprintf('エラー: %s (park_id:%d, ptype_id:%d, psection_id:%d)', + $message, $parkId, $ptypeId, $psectionId); + + // バッチログ作成 + $this->createBatchLog($status, $statusComment); + return [ 'success' => false, - 'message' => $message, - 'batch_log_id' => $batchLogId + 'message' => $message ]; } @@ -122,36 +105,31 @@ class ShjFourCService if (!$allocationResult['can_allocate']) { // 割当NGの場合、対象事室番号を設定 $this->setTargetRoomNumber($allocationResult['target_room_number']); - - // バッチログ更新(警告) - $batchLog->update([ - 'status' => BatchLog::STATUS_WARNING, - 'end_time' => now(), - 'message' => '割当処理NG: ' . $allocationResult['reason'], - 'success_count' => 1 // 処理は成功したが割当NGのため - ]); - + + $status = 'warning'; + $statusComment = sprintf('割当NG: %s (park_id:%d, ptype_id:%d, psection_id:%d)', + $allocationResult['reason'], $parkId, $ptypeId, $psectionId); + + // バッチログ作成 + $this->createBatchLog($status, $statusComment); + return [ 'success' => true, 'message' => '割当判定完了(割当NG)', - 'allocation_result' => $allocationResult, - 'batch_log_id' => $batchLogId + 'allocation_result' => $allocationResult ]; } // 【処理2】割当実行(割当OKの場合) $executionResult = $this->executeAllocation($zoneInfo, $allocationResult); - // バッチ処理完了ログ更新 - $batchLog->update([ - 'status' => BatchLog::STATUS_SUCCESS, - 'end_time' => now(), - 'message' => 'SHJ-4C 室割当処理正常完了', - 'success_count' => 1 - ]); + $statusComment = sprintf('室割当処理完了 (park_id:%d, ptype_id:%d, psection_id:%d, zone_id:%s)', + $parkId, $ptypeId, $psectionId, $allocationResult['target_room_number'] ?? 'N/A'); + + // バッチログ作成 + $this->createBatchLog($status, $statusComment); Log::info('SHJ-4C 室割当処理完了', [ - 'batch_log_id' => $batchLogId, 'execution_result' => $executionResult ]); @@ -161,25 +139,19 @@ class ShjFourCService 'message' => 'SHJ-4C 室割当処理が正常に完了しました', 'zone_info' => $zoneInfo, 'allocation_result' => $allocationResult, - 'execution_result' => $executionResult, - 'batch_log_id' => $batchLogId + 'execution_result' => $executionResult ]; } catch (\Exception $e) { $errorMessage = 'SHJ-4C 室割当処理でエラーが発生: ' . $e->getMessage(); - - if (isset($batchLog) && $batchLog) { - $batchLog->update([ - 'status' => BatchLog::STATUS_ERROR, - 'end_time' => now(), - 'message' => $errorMessage, - 'error_details' => $e->getMessage(), - 'error_count' => 1 - ]); - } + $status = 'error'; + $statusComment = sprintf('例外エラー: %s (park_id:%d, ptype_id:%d, psection_id:%d)', + $e->getMessage(), $parkId, $ptypeId, $psectionId); + + // バッチログ作成 + $this->createBatchLog($status, $statusComment); Log::error('SHJ-4C 室割当処理エラー', [ - 'batch_log_id' => $batchLogId, 'exception' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); @@ -187,12 +159,52 @@ class ShjFourCService return [ 'success' => false, 'message' => $errorMessage, - 'details' => $e->getMessage(), - 'batch_log_id' => $batchLogId + 'details' => $e->getMessage() ]; } } + /** + * SHJ-8バッチ処理ログ作成 + * + * @param string $status ステータス + * @param string $statusComment ステータスコメント + * @return void + */ + private function createBatchLog(string $status, string $statusComment): void + { + try { + $device = Device::orderBy('device_id')->first(); + $deviceId = $device ? $device->device_id : 1; + + $today = now()->format('Y/m/d'); + + Log::info('SHJ-8バッチ処理ログ作成', [ + 'device_id' => $deviceId, + 'process_name' => 'SHJ-4C', + 'job_name' => 'SHJ-4C室割当', + 'status' => $status, + 'status_comment' => $statusComment + ]); + + // SHJ-8サービスを呼び出し + $this->shjEightService->execute( + $deviceId, + 'SHJ-4C', + 'SHJ-4C室割当', + $status, + $statusComment, + $today, + $today + ); + + } catch (\Exception $e) { + Log::error('SHJ-8 バッチログ作成エラー', [ + 'error' => $e->getMessage() + ]); + } + } + /** * 【処理1】ゾーン情報取得 * diff --git a/app/Services/ShjMailSendService.php b/app/Services/ShjMailSendService.php index 64d9513..dc22a35 100644 --- a/app/Services/ShjMailSendService.php +++ b/app/Services/ShjMailSendService.php @@ -3,7 +3,6 @@ namespace App\Services; use App\Models\MailTemplate; -use App\Models\Batch\BatchLog; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\DB; use Carbon\Carbon; @@ -23,32 +22,23 @@ class ShjMailSendService */ protected $mailTemplateModel; - /** - * BatchLog モデル - * - * @var BatchLog - */ - protected $batchLogModel; - /** * コンストラクタ * * @param MailTemplate $mailTemplateModel - * @param BatchLog $batchLogModel */ public function __construct( - MailTemplate $mailTemplateModel, - BatchLog $batchLogModel + MailTemplate $mailTemplateModel ) { $this->mailTemplateModel = $mailTemplateModel; - $this->batchLogModel = $batchLogModel; } /** - * SHJ メール送信処理メイン実行 - * + * SHJ-7 メール送信処理メイン実行 + * * 処理フロー: * 【処理1】入力パラメーターをチェックする + * 【判断1】チェック結果 * 【処理2】メール送信テンプレート情報を取得する * 【判断2】取得結果判定 * 【処理3】メールを送信する @@ -56,29 +46,13 @@ class ShjMailSendService * * @param string $mailAddress メールアドレス * @param string $backupMailAddress 予備メールアドレス - * @param int $mailTemplateId メールテンプレートID - * @return array 処理結果 + * @param int $mailTemplateId メールテンプレートID(使用プログラムID) + * @return array 処理結果 ['result' => 0|1, 'error_info' => string] */ public function executeMailSend(string $mailAddress, string $backupMailAddress, int $mailTemplateId): array { - $batchLogId = null; - try { - // バッチ処理開始ログ作成(実際のコマンド名を記録) - $batchLog = BatchLog::createBatchLog( - 'shj-mail-send', - BatchLog::STATUS_START, - [ - 'mail_address' => $mailAddress, - 'backup_mail_address' => $backupMailAddress, - 'mail_template_id' => $mailTemplateId - ], - 'SHJ メール送信処理開始' - ); - $batchLogId = $batchLog->id; - - Log::info('SHJ メール送信処理開始', [ - 'batch_log_id' => $batchLogId, + Log::info('SHJ-7 メール送信処理開始', [ 'mail_address' => $mailAddress, 'backup_mail_address' => $backupMailAddress, 'mail_template_id' => $mailTemplateId @@ -86,14 +60,19 @@ class ShjMailSendService // 【処理1】入力パラメーターをチェックする $paramCheckResult = $this->checkInputParameters($mailAddress, $backupMailAddress, $mailTemplateId); + + // 【判断1】チェック結果 if (!$paramCheckResult['valid']) { - $this->updateBatchLog($batchLogId, 'error', $paramCheckResult['message']); - + $errorInfo = $paramCheckResult['error_info']; + + Log::warning('SHJ-7 パラメーターチェックNG', [ + 'error_info' => $errorInfo + ]); + + // 【処理4】処理結果を返却する(異常終了) return [ - 'success' => false, - 'result_code' => 1, // 異常終了 - 'message' => $paramCheckResult['message'], - 'batch_log_id' => $batchLogId + 'result' => 1, + 'error_info' => $errorInfo ]; } @@ -102,14 +81,18 @@ class ShjMailSendService // 【判断2】取得結果判定 if (empty($templateInfo)) { - $message = "メールテンプレートが存在しません。テンプレートID: {$mailTemplateId}"; - $this->updateBatchLog($batchLogId, 'error', $message); - + // 0件の場合:取得NGの結果を設定する + $errorInfo = "メール送信NG:メール送信テンプレートが存在しません。/{$mailTemplateId}"; + + Log::warning('SHJ-7 メールテンプレート取得NG', [ + 'mail_template_id' => $mailTemplateId, + 'error_info' => $errorInfo + ]); + + // 【処理4】処理結果を返却する(異常終了) return [ - 'success' => false, - 'result_code' => 1, // 異常終了 - 'message' => $message, - 'batch_log_id' => $batchLogId + 'result' => 1, + 'error_info' => $errorInfo ]; } @@ -117,103 +100,109 @@ class ShjMailSendService $mailSendResult = $this->sendMail($mailAddress, $backupMailAddress, $templateInfo); if (!$mailSendResult['success']) { - $this->updateBatchLog($batchLogId, 'error', $mailSendResult['message']); - + $errorInfo = $mailSendResult['error_info']; + + Log::error('SHJ-7 メール送信失敗', [ + 'error_info' => $errorInfo + ]); + + // 【処理4】処理結果を返却する(異常終了) return [ - 'success' => false, - 'result_code' => 1, // 異常終了 - 'message' => $mailSendResult['message'], - 'batch_log_id' => $batchLogId + 'result' => 1, + 'error_info' => $errorInfo ]; } - // バッチ処理完了ログ更新 - $this->updateBatchLog($batchLogId, 'success', 'SHJ メール送信処理正常完了'); - - Log::info('SHJ メール送信処理完了', [ - 'batch_log_id' => $batchLogId, - 'mail_send_result' => $mailSendResult + Log::info('SHJ-7 メール送信処理完了', [ + 'to_address' => $mailSendResult['to_address'] ]); - // 【処理4】処理結果を返却する + // 【処理4】処理結果を返却する(正常終了) return [ - 'success' => true, - 'result_code' => 0, // 正常終了 - 'message' => 'SHJ メール送信処理が正常に完了しました', - 'mail_send_result' => $mailSendResult, - 'batch_log_id' => $batchLogId + 'result' => 0, + 'error_info' => '' ]; } catch (\Exception $e) { - $errorMessage = 'SHJ メール送信処理でエラーが発生: ' . $e->getMessage(); - - if ($batchLogId) { - $this->updateBatchLog($batchLogId, 'error', $errorMessage); - } + $errorInfo = 'メール送信NG:' . $e->getMessage(); - Log::error('SHJ メール送信処理エラー', [ - 'batch_log_id' => $batchLogId, + Log::error('SHJ-7 メール送信処理例外エラー', [ 'exception' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); + // 【処理4】処理結果を返却する(異常終了) return [ - 'success' => false, - 'result_code' => 1, // 異常終了 - 'message' => $errorMessage, - 'details' => $e->getMessage(), - 'batch_log_id' => $batchLogId + 'result' => 1, + 'error_info' => $errorInfo ]; } } /** * 【処理1】入力パラメーターをチェックする - * - * 仕様書に基づく詳細チェック: - * - メールアドレス形式チェック - * - テンプレートID存在性チェック + * + * SHJ-7仕様書に基づくチェック内容: + * 1. メールアドレス: 「メールアドレス」「予備メールアドレス」いずれか必須 + * 2. 予備メールアドレス: 「メールアドレス」「予備メールアドレス」いずれか必須 + * 3. 使用プログラムID: 必須 + * + * エラーメッセージ形式: "パラメーターNG: 項目名/入力値" + * 複数エラーの場合は全角カンマ(、)で連結 * * @param string $mailAddress メールアドレス * @param string $backupMailAddress 予備メールアドレス - * @param int $mailTemplateId メールテンプレートID - * @return array チェック結果 + * @param int $mailTemplateId メールテンプレートID(使用プログラムID) + * @return array チェック結果 ['valid' => bool, 'error_info' => string] */ private function checkInputParameters(string $mailAddress, string $backupMailAddress, int $mailTemplateId): array { + $errors = []; + try { - // メールアドレス存在チェック(いずれか必須) + // 1. メールアドレスと予備メールアドレスのいずれか必須チェック + // 両方とも空の場合は、それぞれ別エラーとして追加 if (empty($mailAddress) && empty($backupMailAddress)) { + $errors[] = "パラメーターNG:メールアドレス/<空>"; + $errors[] = "パラメーターNG:予備メールアドレス/<空>"; + } else { + // いずれかに値がある場合は、形式チェックを実施 + // 2. メールアドレス形式チェック(値がある場合のみ) + if (!empty($mailAddress) && !filter_var($mailAddress, FILTER_VALIDATE_EMAIL)) { + $errors[] = "パラメーターNG:メールアドレス/{$mailAddress}"; + } + + // 3. 予備メールアドレス形式チェック(値がある場合のみ) + if (!empty($backupMailAddress) && !filter_var($backupMailAddress, FILTER_VALIDATE_EMAIL)) { + $errors[] = "パラメーターNG:予備メールアドレス/{$backupMailAddress}"; + } + } + + // 4. 使用プログラムID(メールテンプレートID)必須チェック + if (empty($mailTemplateId) || $mailTemplateId <= 0) { + $errors[] = "パラメーターNG:使用プログラムID/{$mailTemplateId}"; + } + + // エラーがある場合 + if (!empty($errors)) { + // 複数のエラーがある場合は全角カンマ(、)で連結 + $errorInfo = implode('、', $errors); + + Log::warning('SHJ-7 入力パラメーターチェックNG', [ + 'mail_address' => $mailAddress, + 'backup_mail_address' => $backupMailAddress, + 'mail_template_id' => $mailTemplateId, + 'error_info' => $errorInfo + ]); + return [ 'valid' => false, - 'message' => 'パラメーターNG: メールアドレスまたは予備メールアドレスのいずれかは必須です' + 'error_info' => $errorInfo ]; } - // メールアドレス形式チェック - if (!empty($mailAddress) && !filter_var($mailAddress, FILTER_VALIDATE_EMAIL)) { - return [ - 'valid' => false, - 'message' => 'パラメーターNG: メールアドレスの形式が正しくありません' - ]; - } - - if (!empty($backupMailAddress) && !filter_var($backupMailAddress, FILTER_VALIDATE_EMAIL)) { - return [ - 'valid' => false, - 'message' => 'パラメーターNG: 予備メールアドレスの形式が正しくありません' - ]; - } - - // メールテンプレートID形式チェック - if ($mailTemplateId <= 0) { - return [ - 'valid' => false, - 'message' => 'パラメーターNG: メールテンプレートIDは正の整数である必要があります' - ]; - } - - Log::info('入力パラメーターチェック完了', [ + // 正常終了 + Log::info('SHJ-7 入力パラメーターチェックOK', [ 'mail_address' => $mailAddress, 'backup_mail_address' => $backupMailAddress, 'mail_template_id' => $mailTemplateId @@ -221,63 +210,66 @@ class ShjMailSendService return [ 'valid' => true, - 'message' => 'パラメーターチェックOK' + 'error_info' => '' ]; } catch (\Exception $e) { - Log::error('入力パラメーターチェックエラー', [ - 'error' => $e->getMessage() + $errorInfo = 'パラメーターチェック中にエラーが発生:' . $e->getMessage(); + + Log::error('SHJ-7 入力パラメーターチェック例外エラー', [ + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString() ]); return [ 'valid' => false, - 'message' => 'パラメーターチェック中にエラーが発生しました: ' . $e->getMessage() + 'error_info' => $errorInfo ]; } } /** * 【処理2】メール送信テンプレート情報を取得する - * - * 仕様書に基づくSQLクエリ: + * + * SHJ-7仕様書に基づくSQLクエリ: * SELECT エリアマネージャー同報, bccアドレス, 件名, 本文 * FROM メール送信テンプレート - * WHERE 使用プログラムID = 入力パラメーター使用プログラムID - * AND 使用フラグ = 1 + * WHERE 使用プログラムID = 入力パラメーター.使用プログラムID + * AND 使用フラグ = 1 * - * @param int $mailTemplateId メールテンプレートID(使用プログラムIDとして扱う) + * @param int $mailTemplateId メールテンプレートID(使用プログラムID) * @return MailTemplate|null メールテンプレート情報 */ private function getMailTemplateInfo(int $mailTemplateId): ?MailTemplate { try { - // 仕様書に記載されたSQLクエリに基づくメールテンプレート情報取得 - // 注意: 仕様書では「使用プログラムID」を条件にしているが、 - // 入力パラメーターは「メールテンプレートID」なので、pg_idで検索 + // SHJ-7仕様: 使用プログラムID(pg_id)で検索、使用フラグ=1 $templateInfo = $this->mailTemplateModel::where('pg_id', $mailTemplateId) ->where('use_flag', 1) ->first(); if ($templateInfo) { - Log::info('メールテンプレート情報取得完了', [ + Log::info('SHJ-7 メールテンプレート情報取得完了', [ 'mail_template_id' => $mailTemplateId, 'template_found' => true, - 'subject' => $templateInfo->getSubject() + 'subject' => $templateInfo->getSubject(), + 'mgr_cc_flag' => $templateInfo->isManagerCcEnabled(), + 'has_bcc' => !empty($templateInfo->getBccAddress()) ]); } else { - Log::warning('メールテンプレート情報取得結果', [ + Log::warning('SHJ-7 メールテンプレート情報取得結果0件', [ 'mail_template_id' => $mailTemplateId, - 'template_found' => false, - 'message' => 'テンプレートが見つかりません' + 'template_found' => false ]); } return $templateInfo; } catch (\Exception $e) { - Log::error('メールテンプレート情報取得エラー', [ + Log::error('SHJ-7 メールテンプレート情報取得エラー', [ 'mail_template_id' => $mailTemplateId, - 'error' => $e->getMessage() + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString() ]); throw $e; @@ -286,92 +278,95 @@ class ShjMailSendService /** * 【処理3】メールを送信する - * - * 仕様書に基づくmb_send_mail関数使用: - * - 送信者: 処理2で取得したメールアドレス(処理1で予備メールアドレス) - * - タイトル: 処理2で取得したタイトル - * - 本文: 処理2で取得した本文(※現在の文字列は「So-Manager一般的なWebサイト内部処理」参照) - * - 追加ヘッダ: 処理2で取得したbccアドレス(※値が設定されている場合のみ) + * + * SHJ-7仕様書に基づくmb_send_mail関数使用: + * - 送信先: 入力パラメーター.メールアドレス(空なら予備メールアドレス) + * - タイトル: 処理2.件名 + * - 本文: 処理2.本文 + * - 追加ヘッダ: 処理2.bccアドレス(※値が設定されている場合のみ) + * + * ※待ち時間: 仕様では「一定の待ち時間を設ける」とあるが、現時点では実装しない(0秒) * * @param string $mailAddress メールアドレス * @param string $backupMailAddress 予備メールアドレス * @param MailTemplate $templateInfo テンプレート情報 - * @return array 送信結果 + * @return array 送信結果 ['success' => bool, 'error_info' => string, 'to_address' => string] */ private function sendMail(string $mailAddress, string $backupMailAddress, MailTemplate $templateInfo): array { try { // 送信先アドレス決定(優先: メールアドレス、代替: 予備メールアドレス) $toAddress = !empty($mailAddress) ? $mailAddress : $backupMailAddress; - - // メール内容取得 + + // 処理2で取得したメール内容を取得 $subject = $templateInfo->getSubject() ?? ''; $message = $templateInfo->getText() ?? ''; - - // 追加ヘッダ設定 + + // 追加ヘッダ設定(BCC、From等) $headers = $this->buildMailHeaders($templateInfo); - - Log::info('メール送信準備完了', [ + + Log::info('SHJ-7 メール送信準備完了', [ 'to_address' => $toAddress, 'subject' => $subject, 'has_bcc' => !empty($templateInfo->getBccAddress()), - 'manager_cc_enabled' => $templateInfo->isManagerCcEnabled() + 'mgr_cc_flag' => $templateInfo->isManagerCcEnabled() ]); // mb_send_mail関数を使用してメール送信 $sendResult = mb_send_mail( $toAddress, // 送信先 - $subject, // 件名 + $subject, // 件名(タイトル) $message, // 本文 $headers // 追加ヘッダ ); if ($sendResult) { - Log::info('メール送信成功', [ + Log::info('SHJ-7 メール送信成功', [ 'to_address' => $toAddress, 'subject' => $subject ]); return [ 'success' => true, - 'message' => 'メール送信が正常に完了しました', - 'to_address' => $toAddress, - 'subject' => $subject + 'error_info' => '', + 'to_address' => $toAddress ]; } else { - $errorMessage = 'mb_send_mail関数でメール送信に失敗しました'; - Log::error('メール送信失敗', [ + // mb_send_mail がfalseを返した場合 + $errorInfo = 'メール送信NG:mb_send_mail関数がfalseを返しました'; + Log::error('SHJ-7 メール送信失敗', [ 'to_address' => $toAddress, 'subject' => $subject, - 'error' => $errorMessage + 'error_info' => $errorInfo ]); return [ 'success' => false, - 'message' => $errorMessage + 'error_info' => $errorInfo ]; } } catch (\Exception $e) { - $errorMessage = 'メール送信中にエラーが発生: ' . $e->getMessage(); - Log::error('メール送信エラー', [ + $errorInfo = 'メール送信NG:' . $e->getMessage(); + Log::error('SHJ-7 メール送信例外エラー', [ 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return [ 'success' => false, - 'message' => $errorMessage + 'error_info' => $errorInfo ]; } } /** * メールヘッダを構築 - * - * 仕様書に基づく設定: - * - BCCアドレス: 値が設定されている場合のみ追加 - * - エリアマネージャー同報: フラグが有効な場合の処理 + * + * SHJ-7仕様書に基づく追加ヘッダ設定: + * - 追加ヘッダ: 処理2.bccアドレス(※値が設定されている場合のみ) + * - From: システム設定から取得 + * - エリアマネージャー同報: フラグが有効な場合はログ出力のみ(実装保留) * * @param MailTemplate $templateInfo テンプレート情報 * @return string メールヘッダ @@ -380,19 +375,19 @@ class ShjMailSendService { $headers = []; - // BCCアドレス設定(値が設定されている場合のみ) + // BCCアドレス設定(値が設定されている場合のみ追加) $bccAddress = $templateInfo->getBccAddress(); if (!empty($bccAddress)) { $headers[] = "Bcc: {$bccAddress}"; } // エリアマネージャー同報フラグが有効な場合 - // ※具体的な処理内容は仕様書に詳細がないため、ログ出力のみ + // ※SHJ-7では実装しない(仕様詳細不明)。ログ出力のみ。 if ($templateInfo->isManagerCcEnabled()) { - Log::info('エリアマネージャー同報フラグが有効です', [ + Log::info('SHJ-7 エリアマネージャー同報フラグが有効', [ 'mail_template_id' => $templateInfo->mail_template_id ]); - // 実際のエリアマネージャーアドレス取得・設定処理は追加仕様が必要 + // 実際のエリアマネージャーアドレス取得・設定処理は将来実装 } // From設定(システム設定から取得) @@ -405,41 +400,6 @@ class ShjMailSendService return implode("\r\n", $headers); } - /** - * バッチログ作成 - * - * @param string $processName プロセス名 - * @param string $status ステータス - * @param array $params パラメータ - * @return int バッチログID - */ - private function createBatchLog(string $processName, string $status, array $params = []): int - { - return $this->batchLogModel->create([ - 'process_name' => $processName, - 'status' => $status, - 'start_time' => now(), - 'parameters' => json_encode($params), - 'message' => 'バッチ処理開始' - ])->id; - } - - /** - * バッチログ更新 - * - * @param int $batchLogId バッチログID - * @param string $status ステータス - * @param string $message メッセージ - * @return void - */ - private function updateBatchLog(int $batchLogId, string $status, string $message): void - { - $this->batchLogModel->where('id', $batchLogId)->update([ - 'status' => $status, - 'end_time' => now(), - 'message' => $message - ]); - } /** * SHJ-12 未払い者通知メール送信 diff --git a/app/Services/ShjNineService.php b/app/Services/ShjNineService.php index 3b54a86..b8ffec9 100644 --- a/app/Services/ShjNineService.php +++ b/app/Services/ShjNineService.php @@ -5,8 +5,8 @@ namespace App\Services; use App\Models\Park; use App\Models\EarningsSummary; use App\Models\Psection; -use App\Models\Batch\BatchLog; use App\Models\OperatorQue; +use App\Models\Device; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\DB; use Carbon\Carbon; @@ -30,10 +30,20 @@ class ShjNineService const SUMMARY_TYPE_DAILY = 3; /** - * コンストラクタ + * ShjEightService インスタンス + * + * @var ShjEightService */ - public function __construct() + protected $shjEightService; + + /** + * コンストラクタ + * + * @param ShjEightService $shjEightService + */ + public function __construct(ShjEightService $shjEightService) { + $this->shjEightService = $shjEightService; } /** @@ -54,56 +64,31 @@ class ShjNineService */ public function executeEarningsAggregation(string $type, string $aggregationDate): array { - $batchLogId = null; - $batchLog = null; $statusComments = []; // 内部変数.ステータスコメント $dataIntegrityIssues = []; // 内部変数.情報不備 - + try { // 【処理1】集計対象を設定する // パラメーター検証(日付形式チェック) if (!$this->isValidDateFormat($aggregationDate)) { // 日付形式エラー時は【処理5】へ(warning扱い) $statusComment = "売上集計(日次):パラメーターが不正です。(日付形式ではありません)"; - - $batchLog = BatchLog::createBatchLog( - 'shj9', - BatchLog::STATUS_WARNING, - ['type' => $type, 'aggregation_date' => $aggregationDate], - $statusComment - ); - $batchLogId = $batchLog->id; - + // 【処理5】オペレータキュー作成 - $this->createOperatorQueue($statusComment, $batchLogId); - + $this->createOperatorQueue($statusComment, null); + // SHJ-8 バッチ処理ログ作成 - $this->createShjBatchLog([ - 'job_name' => 'SHJ-9売上集計(日次)', - 'status' => 'success', - 'status_comment' => $statusComment - ]); - + $this->callShjEight('SHJ-9売上集計(日次)', 'success', $statusComment); + return [ 'success' => true, // 仕様上はwarningで成功扱い - 'message' => $statusComment, - 'batch_log_id' => $batchLogId + 'message' => $statusComment ]; } $targetDate = Carbon::parse($aggregationDate)->format('Y-m-d'); - - // バッチ処理開始ログ作成 - $batchLog = BatchLog::createBatchLog( - 'shj9', - BatchLog::STATUS_START, - ['type' => $type, 'target_date' => $targetDate], - "SHJ-9 売上集計処理開始(日次)- 対象日: {$targetDate}" - ); - $batchLogId = $batchLog->id; Log::info('SHJ-9 売上集計処理開始', [ - 'batch_log_id' => $batchLogId, 'type' => $type, 'target_date' => $targetDate ]); @@ -115,31 +100,18 @@ class ShjNineService if (empty($parkInfo)) { $statusComment = '売上集計(日次):駐輪場マスタが存在していません。'; $statusComments[] = $statusComment; - - // バッチログ更新 - $batchLog->update([ - 'status' => BatchLog::STATUS_WARNING, - 'end_time' => now(), - 'message' => $statusComment, - 'success_count' => 1 - ]); - + // 【処理5】オペレータキュー作成 - $this->createOperatorQueue($statusComment, $batchLogId); - + $this->createOperatorQueue($statusComment, null); + // SHJ-8 バッチ処理ログ作成 - $this->createShjBatchLog([ - 'job_name' => 'SHJ-9売上集計(日次)', - 'status' => 'success', - 'status_comment' => $statusComment - ]); - + $this->callShjEight('SHJ-9売上集計(日次)', 'success', $statusComment); + return [ 'success' => true, 'message' => $statusComment, 'processed_parks' => 0, - 'summary_records' => 0, - 'batch_log_id' => $batchLogId + 'summary_records' => 0 ]; } @@ -148,16 +120,16 @@ class ShjNineService $processedParks = 0; foreach ($parkInfo as $park) { - $result = $this->processEarningsForPark($park, $targetDate, $batchLogId); - - $processedParks++; + $result = $this->processEarningsForPark($park, $targetDate); + + $processedParks++; $summaryRecords += $result['summary_records']; - + // 対象データなしの場合のステータスコメント収集 if (!empty($result['no_data_message'])) { $statusComments[] = $result['no_data_message']; } - + // 情報不備を収集("なし"でない場合) if ($result['data_integrity_issue'] !== '情報不備:なし') { $dataIntegrityIssues[] = $result['data_integrity_issue']; @@ -165,40 +137,23 @@ class ShjNineService } // 最終ステータスコメント生成 - $finalStatusComment = "SHJ-9 売上集計処理正常完了(日次)- 対象日: {$targetDate}, 駐輪場数: {$processedParks}, 集計レコード数: {$summaryRecords}"; - if (!empty($statusComments)) { - $finalStatusComment .= "\n" . implode("\n", $statusComments); - } + $finalStatusComment = "売上集計(日次):対象日={$targetDate}、駐輪場数={$processedParks}、集計レコード数={$summaryRecords}"; if (!empty($dataIntegrityIssues)) { - $finalStatusComment .= "\n" . implode("\n", $dataIntegrityIssues); + $finalStatusComment .= "、情報不備=" . implode('、', $dataIntegrityIssues); } - // バッチ処理完了ログ更新 - $batchLog->update([ - 'status' => BatchLog::STATUS_SUCCESS, - 'end_time' => now(), - 'message' => $finalStatusComment, - 'success_count' => 1 - ]); - // 【処理5】オペレータキュー作成 // ※ 駐輪場単位で既に作成済み(processEarningsForPark内で情報不備検出時に実施) if (!empty($dataIntegrityIssues)) { Log::warning('SHJ-9 情報不備検出', [ - 'batch_log_id' => $batchLogId, 'issues' => $dataIntegrityIssues ]); } // SHJ-8 バッチ処理ログ作成 - $this->createShjBatchLog([ - 'job_name' => 'SHJ-9売上集計(日次)', - 'status' => 'success', - 'status_comment' => $finalStatusComment - ]); + $this->callShjEight('SHJ-9売上集計(日次)', 'success', $finalStatusComment); Log::info('SHJ-9 売上集計処理完了', [ - 'batch_log_id' => $batchLogId, 'processed_parks' => $processedParks, 'summary_records' => $summaryRecords, 'data_integrity_issues' => count($dataIntegrityIssues), @@ -210,36 +165,20 @@ class ShjNineService 'message' => 'SHJ-9 売上集計処理が正常に完了しました', 'processed_parks' => $processedParks, 'summary_records' => $summaryRecords, - 'data_integrity_issues' => count($dataIntegrityIssues), - 'batch_log_id' => $batchLogId + 'data_integrity_issues' => count($dataIntegrityIssues) ]; } catch (\Exception $e) { - $errorMessage = 'SHJ-9 売上集計処理でエラーが発生: ' . $e->getMessage(); - - if (isset($batchLog) && $batchLog) { - $batchLog->update([ - 'status' => BatchLog::STATUS_ERROR, - 'end_time' => now(), - 'message' => $errorMessage, - 'error_details' => $e->getMessage(), - 'error_count' => 1 - ]); - } + $errorMessage = '売上集計(日次):エラー発生 - ' . $e->getMessage(); // SHJ-8 バッチ処理ログ作成(エラー時も作成) try { - $this->createShjBatchLog([ - 'job_name' => 'SHJ-9売上集計(日次)', - 'status' => 'error', - 'status_comment' => $errorMessage - ]); + $this->callShjEight('SHJ-9売上集計(日次)', 'error', $errorMessage); } catch (\Exception $shjException) { Log::error('SHJ-8呼び出しエラー', ['error' => $shjException->getMessage()]); } Log::error('SHJ-9 売上集計処理エラー', [ - 'batch_log_id' => $batchLogId, 'exception' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); @@ -247,8 +186,7 @@ class ShjNineService return [ 'success' => false, 'message' => $errorMessage, - 'details' => $e->getMessage(), - 'batch_log_id' => $batchLogId + 'details' => $e->getMessage() ]; } } @@ -301,21 +239,20 @@ class ShjNineService /** * 駐輪場毎の売上集計処理 - * + * * @param object $park 駐輪場情報 * @param string $targetDate 集計対象日(YYYY-MM-DD) - * @param int $batchLogId バッチログID * @return array 処理結果 ['summary_records' => int, 'data_integrity_issue' => string, 'no_data_message' => string|null] */ - private function processEarningsForPark($park, string $targetDate, int $batchLogId): array + private function processEarningsForPark($park, string $targetDate): array { try { // 0. 情報不備チェック $dataIntegrityIssue = $this->checkDataIntegrity($park->park_id, $targetDate); - + // 情報不備がある場合、駐輪場単位でオペレータキュー作成(仕様 todo/SHJ-9/SHJ-9.txt:253-263) if ($dataIntegrityIssue !== '情報不備:なし') { - $this->createOperatorQueue($dataIntegrityIssue, $batchLogId, $park->park_id); + $this->createOperatorQueue($dataIntegrityIssue, $park->park_id); } // ① 定期契約データ取得(車種区分・分類名1・定期有効月数毎) @@ -784,7 +721,7 @@ class ShjNineService /** * 【処理5】オペレータキュー作成(駐輪場単位・情報不備がある場合のみ) - * + * * 仕様 todo/SHJ-9/SHJ-9.txt:253-280 * - que_class: 14(集計対象エラー) * - que_comment: 空文字("") @@ -793,13 +730,12 @@ class ShjNineService * - work_instructions: 情報不備メッセージ * - park_id: 駐輪場ID(仕様 "処理1.駐輪場ID"、パラメータエラー時はnull) * - operator_id: 9999999(バッチ処理固定値) - * + * * @param string $message 情報不備メッセージ - * @param int $batchLogId バッチログID * @param int|null $parkId 駐輪場ID(パラメータエラー時はnull) * @return void */ - private function createOperatorQueue(string $message, int $batchLogId, ?int $parkId = null): void + private function createOperatorQueue(string $message, ?int $parkId = null): void { try { DB::table('operator_que')->insert([ @@ -815,19 +751,17 @@ class ShjNineService 'created_at' => now(), 'updated_at' => now() ]); - + Log::info('オペレータキュー作成完了', [ - 'batch_log_id' => $batchLogId, 'park_id' => $parkId, 'que_class' => 14, 'que_status' => 1, 'operator_id' => self::BATCH_OPERATOR_ID, 'work_instructions' => $message ]); - + } catch (\Exception $e) { Log::error('オペレータキュー作成エラー', [ - 'batch_log_id' => $batchLogId, 'park_id' => $parkId, 'error' => $e->getMessage() ]); @@ -836,64 +770,45 @@ class ShjNineService /** * SHJ-8 バッチ処理ログ作成 - * + * * 仕様 todo/SHJ-9/SHJ-9.txt:289-300 * 共通処理「SHJ-8 バッチ処理ログ作成」を呼び出す * - * @param array $statistics 処理統計情報 + * @param string $jobName ジョブ名 + * @param string $status ステータス (success/error) + * @param string $statusComment 業務固有のステータスコメント * @return void */ - private function createShjBatchLog(array $statistics): void + private function callShjEight(string $jobName, string $status, string $statusComment): void { try { - // SHJ-8 パラメータ設定 - $deviceId = 9999999; // バッチ処理用固定デバイスID - $processName = 'SHJ-9'; - $jobName = $statistics['job_name']; - $status = $statistics['status']; - $statusComment = $statistics['status_comment'] ?? ''; - - $createdDate = now()->format('Y/m/d'); - $updatedDate = now()->format('Y/m/d'); + $device = Device::orderBy('device_id')->first(); + $deviceId = $device ? $device->device_id : 1; - Log::info('SHJ-8 バッチ処理ログ作成', [ - 'device_id' => $deviceId, - 'process_name' => $processName, - 'job_name' => $jobName, - 'status' => $status, - 'status_comment' => $statusComment - ]); + $today = now()->format('Y/m/d'); - // 共通処理 SHJ-8 バッチ処理ログ作成を呼び出し - // BatchLog システムを使用してバッチ処理の実行ログを記録 - BatchLog::createBatchLog( - $processName, + $this->shjEightService->execute( + $deviceId, + 'SHJ-9', + $jobName, $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 + $statusComment, + $today, + $today ); + Log::info('SHJ-8 バッチ処理ログ作成完了', [ + 'job_name' => $jobName, + 'status' => $status + ]); + } catch (\Exception $e) { Log::error('SHJ-8 バッチ処理ログ作成エラー', [ 'error' => $e->getMessage(), - 'statistics' => $statistics + 'job_name' => $jobName, + 'status_comment' => $statusComment ]); - - // SHJ-8でエラーが発生してもメイン処理は継続 - // エラーログのみ出力 + throw $e; } } } diff --git a/app/Services/ShjOneService.php b/app/Services/ShjOneService.php index 4091f57..7932e59 100644 --- a/app/Services/ShjOneService.php +++ b/app/Services/ShjOneService.php @@ -7,9 +7,11 @@ use App\Models\Usertype; use App\Models\Park; use App\Models\RegularContract; use App\Models\OperatorQue; +use App\Models\Device; use App\Services\GoogleVisionService; use App\Services\GoogleMapsService; use App\Services\ShjMailSendService; +use App\Services\ShjEightService; use Exception; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\DB; @@ -22,15 +24,18 @@ class ShjOneService protected $googleVisionService; protected $googleMapsService; protected $mailSendService; + protected $shjEightService; public function __construct( GoogleVisionService $googleVisionService, GoogleMapsService $googleMapsService, - ShjMailSendService $mailSendService + ShjMailSendService $mailSendService, + ShjEightService $shjEightService ) { $this->googleVisionService = $googleVisionService; $this->googleMapsService = $googleMapsService; $this->mailSendService = $mailSendService; + $this->shjEightService = $shjEightService; } /** @@ -55,11 +60,13 @@ class ShjOneService 'user_id' => $userId, 'park_id' => $parkId ]); - return [ + $result = [ 'system_success' => false, 'message' => '利用者が見つかりません', 'stats' => ['error_count' => 1, 'processed_count' => 0] ]; + $this->createBatchLog($userId, null, null, $result); + return $result; } Log::info('SHJ-1 【処理1】成功: 利用者データ取得', [ @@ -79,11 +86,13 @@ class ShjOneService 'user_idcard_chk_flag' => $user->user_idcard_chk_flag, 'reason' => '免許証以外または写真なしまたは既に処理済み' ]); - return [ + $result = [ 'system_success' => false, 'message' => '処理対象外の利用者です(免許証以外または写真なし)', 'stats' => ['error_count' => 1, 'processed_count' => 0] ]; + $this->createBatchLog($userId, $user->user_name, null, $result); + return $result; } $park = $this->getParkRecord($parkId); @@ -91,11 +100,13 @@ class ShjOneService Log::error('SHJ-1 駐輪場データ取得失敗', [ 'park_id' => $parkId ]); - return [ + $result = [ 'system_success' => false, 'message' => '駐輪場が見つかりません', 'stats' => ['error_count' => 1, 'processed_count' => 0] ]; + $this->createBatchLog($userId, $user->user_name, null, $result); + return $result; } Log::info('SHJ-1 駐輪場データ取得成功', [ @@ -119,6 +130,7 @@ class ShjOneService ]); $result = $this->processNonTargetUser($user, $categoryCheck['category_name']); DB::commit(); // 対象外処理後はコミット + $this->createBatchLog($userId, $user->user_name, null, $result); return $result; } @@ -130,9 +142,12 @@ class ShjOneService // 【処理2】本人確認自動処理+800Mチェック処理 Log::info('SHJ-1 【処理2】開始: 本人確認自動処理'); $identityResult = $this->processIdentityVerification($user, $park); - + DB::commit(); - + + // バッチ処理ログ作成 + $this->createBatchLog($userId, $user->user_name, $identityResult['similarity_rate'] ?? null, $identityResult); + return $identityResult; } catch (Exception $e) { @@ -142,12 +157,17 @@ class ShjOneService 'park_id' => $parkId, 'error' => $e->getMessage() ]); - - return [ + + $result = [ 'system_success' => false, 'message' => 'システムエラーが発生しました: ' . $e->getMessage(), 'stats' => ['error_count' => 1, 'processed_count' => 0] ]; + + // エラー時もバッチログ作成 + $this->createBatchLog($userId, null, null, $result); + + return $result; } } @@ -803,6 +823,7 @@ class ShjOneService 'system_success' => true, 'identity_result' => 'OK', 'message' => '本人確認自動処理が成功しました', + 'similarity_rate' => $ocrResult['similarity'] ?? 0, 'details' => [ 'user_id' => $user->user_seq, 'park_id' => $park->park_id, @@ -856,6 +877,7 @@ class ShjOneService 'system_success' => true, 'identity_result' => 'NG', 'message' => '本人確認自動処理NGのため手動処理キューを作成しました', + 'similarity_rate' => $ocrResult['similarity'] ?? 0, 'details' => [ 'user_id' => $user->user_seq, 'park_id' => $park->park_id, @@ -914,13 +936,29 @@ class ShjOneService private function sendSuccessEmail(User $user, Park $park): void { try { - $this->mailSendService->executeMailSend( + // SHJ-7 メール送信処理 + $mailResult = $this->mailSendService->executeMailSend( $user->user_primemail, $user->user_submail, config('shj1.mail.program_id_success') ); + + // SHJ-7仕様準拠: result === 0 が正常、それ以外は異常 + if (($mailResult['result'] ?? 1) === 0) { + Log::info('SHJ-1 成功メール送信成功', [ + 'user_id' => $user->user_seq, + 'email' => $user->user_primemail + ]); + } else { + // 仕様準拠: error_info をログに記録 + Log::error('SHJ-1 成功メール送信失敗', [ + 'user_id' => $user->user_seq, + 'email' => $user->user_primemail, + 'error_info' => $mailResult['error_info'] ?? 'メール送信失敗' + ]); + } } catch (Exception $e) { - Log::error('Success email sending failed', [ + Log::error('SHJ-1 成功メール送信例外エラー', [ 'user_id' => $user->user_seq, 'error' => $e->getMessage() ]); @@ -933,13 +971,29 @@ class ShjOneService private function sendFailureEmail(User $user, Park $park): void { try { - $this->mailSendService->executeMailSend( + // SHJ-7 メール送信処理 + $mailResult = $this->mailSendService->executeMailSend( $user->user_primemail, $user->user_submail, config('shj1.mail.program_id_failure') ); + + // SHJ-7仕様準拠: result === 0 が正常、それ以外は異常 + if (($mailResult['result'] ?? 1) === 0) { + Log::info('SHJ-1 失敗メール送信成功', [ + 'user_id' => $user->user_seq, + 'email' => $user->user_primemail + ]); + } else { + // 仕様準拠: error_info をログに記録 + Log::error('SHJ-1 失敗メール送信失敗', [ + 'user_id' => $user->user_seq, + 'email' => $user->user_primemail, + 'error_info' => $mailResult['error_info'] ?? 'メール送信失敗' + ]); + } } catch (Exception $e) { - Log::error('Failure email sending failed', [ + Log::error('SHJ-1 失敗メール送信例外エラー', [ 'user_id' => $user->user_seq, 'error' => $e->getMessage() ]); @@ -971,14 +1025,14 @@ class ShjOneService { $expectedChars = mb_str_split($expected, 1, 'UTF-8'); $normalizedOcr = $this->normalizeForAnalysis($ocrText); - + $analysis = [ 'total_chars' => count($expectedChars), 'matched_chars' => 0, 'missing_chars' => [], 'match_rate' => 0 ]; - + foreach ($expectedChars as $char) { if (mb_strpos($normalizedOcr, $char, 0, 'UTF-8') !== false) { $analysis['matched_chars']++; @@ -986,10 +1040,63 @@ class ShjOneService $analysis['missing_chars'][] = $char; } } - + $analysis['match_rate'] = round(($analysis['matched_chars'] / $analysis['total_chars']) * 100, 2); - + return $analysis; } - + + /** + * バッチ処理ログ作成 + * + * SHJ-8サービスを呼び出してbat_job_logテーブルに登録 + * + * @param int $userId 利用者連番 + * @param string|null $userName 利用者名 + * @param float|null $similarityRate 類似度 + * @param array $result 処理結果 + * @return void + */ + private function createBatchLog(int $userId, ?string $userName, ?float $similarityRate, array $result): void + { + try { + $device = Device::orderBy('device_id')->first(); + $deviceId = $device ? $device->device_id : 1; + $today = now()->format('Y/m/d'); + + // ステータス判定 + $status = $result['system_success'] ? 'success' : 'error'; + + // ステータスコメント生成: {user_id}/{user_name}/{similarity_rate}% + $displayUserId = $userId; + $displayUserName = $userName ?? '不明'; + $displaySimilarity = $similarityRate !== null ? number_format($similarityRate, 1) : '0.0'; + + $statusComment = "{$displayUserId}/{$displayUserName}/{$displaySimilarity}%"; + + // SHJ-8サービス呼び出し + $this->shjEightService->execute( + $deviceId, + 'SHJ-1', + 'SHJ-1本人確認自動処理', + $status, + $statusComment, + $today, + $today + ); + + Log::info('SHJ-1 バッチ処理ログ作成完了', [ + 'user_id' => $userId, + 'status' => $status, + 'status_comment' => $statusComment + ]); + + } catch (Exception $e) { + Log::error('SHJ-1 バッチ処理ログ作成エラー', [ + 'error' => $e->getMessage(), + 'user_id' => $userId + ]); + } + } + } \ No newline at end of file diff --git a/app/Services/ShjSixService.php b/app/Services/ShjSixService.php index f1f7dd6..eee380e 100644 --- a/app/Services/ShjSixService.php +++ b/app/Services/ShjSixService.php @@ -5,12 +5,12 @@ namespace App\Services; use App\Models\Device; use App\Models\HardwareCheckLog; use App\Models\PrintJobLog; -use App\Models\Batch\BatchLog; use App\Models\OperatorQue; use App\Models\Ope; use App\Models\Manager; use App\Models\Setting; use App\Models\JurisdictionParking; +use App\Models\Park; use App\Services\ShjMailSendService; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\DB; @@ -31,6 +31,13 @@ class ShjSixService */ protected $mailSendService; + /** + * ShjEightService + * + * @var ShjEightService + */ + protected $shjEightService; + /** * 固定メールアドレス(DB反映NG時用) * @@ -74,10 +81,14 @@ class ShjSixService * コンストラクタ * * @param ShjMailSendService $mailSendService + * @param ShjEightService $shjEightService */ - public function __construct(ShjMailSendService $mailSendService) - { + public function __construct( + ShjMailSendService $mailSendService, + ShjEightService $shjEightService + ) { $this->mailSendService = $mailSendService; + $this->shjEightService = $shjEightService; } /** @@ -106,18 +117,8 @@ class ShjSixService $accumulatedBatchComment = ''; // 累積バッチコメント try { - // バッチ処理開始ログ作成 - $batchLog = BatchLog::createBatchLog( - 'shj6', - BatchLog::STATUS_START, - [], - 'SHJ-6 サーバ死活監視処理開始' - ); - $batchLogId = $batchLog->id; - - Log::info('SHJ-6 サーバ死活監視処理開始', [ - 'batch_log_id' => $batchLogId - ]); + // バッチ処理開始ログ(内部ログのみ、batch_log廃止) + Log::info('SHJ-6 サーバ死活監視処理開始'); // 【処理1】サーバ死活監視(DBアクセス) $dbAccessResult = $this->checkDatabaseAccessWithSettings(); @@ -216,15 +217,13 @@ class ShjSixService $statusComment .= ' | ' . $accumulatedBatchComment; } - $status = empty($warnings) ? BatchLog::STATUS_SUCCESS : BatchLog::STATUS_WARNING; - $message = empty($warnings) ? - 'SHJ-6 サーバ死活監視処理正常完了' : + $status = 'success'; // 仕様書:常に"success"で記録 + $message = empty($warnings) ? + 'SHJ-6 サーバ死活監視処理正常完了' : 'SHJ-6 サーバ死活監視処理完了(警告あり)'; // 仕様書準拠:処理2で取得したデバイスIDを連結 - $deviceIds = array_map(function($device) { - return $device->device_id; - }, $devices); + $deviceIds = $devices->pluck('device_id')->toArray(); $concatenatedDeviceIds = !empty($deviceIds) ? implode(',', $deviceIds) : ''; // SHJ-8 バッチ処理ログ作成(仕様書準拠) @@ -261,17 +260,7 @@ class ShjSixService $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, @@ -279,9 +268,18 @@ class ShjSixService 'mail_error_count' => $totalMailErrorCount ]); + // 監視サマリーを生成 + $monitoringSummary = sprintf( + '監視デバイス数: %d, アラート: %d件, メール成功: %d件', + count($devices), + $alertCount, + $totalMailSuccessCount + ); + return [ 'success' => true, 'message' => 'SHJ-6 サーバ死活監視処理が完了しました', + 'monitoring_summary' => $monitoringSummary, 'status_comment' => $statusComment, 'warnings' => $warnings, 'alert_count' => $alertCount, @@ -292,21 +290,10 @@ class ShjSixService } 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, + null, // batch_log廃止のためnull $errorMessage, self::QUE_CLASS_SERVER_ERROR, null, @@ -320,7 +307,6 @@ class ShjSixService $totalMailErrorCount += $commonAResult['mail_error_count'] ?? 0; Log::error('SHJ-6 サーバ死活監視処理エラー', [ - 'batch_log_id' => $batchLogId, 'exception' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); @@ -328,8 +314,8 @@ class ShjSixService return [ 'success' => false, 'message' => $errorMessage, + 'monitoring_summary' => 'エラーにより監視中断', 'error_details' => [$e->getMessage()], - 'batch_log_id' => $batchLogId, 'mail_success_count' => $totalMailSuccessCount, 'mail_error_count' => $totalMailErrorCount ]; @@ -1120,38 +1106,42 @@ class ShjSixService '', // 予備メールアドレスは空 self::SYSTEM_ALERT_MAIL_TEMPLATE_ID ); - - if ($result['success']) { + + // SHJ-7仕様準拠: result === 0 が正常、それ以外は異常 + if (($result['result'] ?? 1) === 0) { Log::info('アラートメール送信成功', [ 'email' => $email, 'recipient_type' => $recipientType, 'alert_message' => $alertMessage ]); - + return [ 'success' => true, 'error' => null ]; } else { + // 仕様準拠: error_info を使用 + $errorInfo = $result['error_info'] ?? 'メール送信失敗'; + Log::error('アラートメール送信失敗', [ 'email' => $email, 'recipient_type' => $recipientType, - 'error' => $result['message'] + 'error_info' => $errorInfo ]); - + return [ 'success' => false, - 'error' => $result['message'] ?? 'メール送信失敗' + 'error' => $errorInfo ]; } - + } catch (\Exception $e) { Log::error('アラートメール送信エラー', [ 'email' => $email, 'recipient_type' => $recipientType, 'error' => $e->getMessage() ]); - + return [ 'success' => false, 'error' => $e->getMessage() @@ -1212,9 +1202,8 @@ class ShjSixService /** * 【処理5】SHJ-8 バッチ処理ログ作成 - * + * * 仕様書に基づくSHJ-8共通処理呼び出し - * BatchLogシステムを使用してバッチ処理の実行ログを記録 * * @param array $statistics 処理統計情報 * @return array 処理結果 ['success' => bool, 'error' => string|null] @@ -1223,53 +1212,45 @@ class ShjSixService { try { // 仕様書準拠のSHJ-8パラメータ設定 - // device_id: 処理2で取得したデバイスID(複数なら連結文字列) + // device_id: 処理2で取得したデバイスID(複数ある場合は最初のIDを使用) // process_name: 処理4のプロセス名 - $deviceId = $statistics['device_id']; // 連結されたデバイスID文字列 + $deviceIdString = $statistics['device_id']; // 連結されたデバイスID文字列 "1,2,3" + + // 複数デバイスIDがある場合は最初のIDを使用(SHJ-8はint型を期待) + $deviceIdArray = !empty($deviceIdString) ? explode(',', $deviceIdString) : []; + $deviceId = !empty($deviceIdArray) ? (int)$deviceIdArray[0] : 1; + $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, + 'device_id_original' => $deviceIdString, 'process_name' => $processName, 'job_name' => $jobName, 'status' => $status, - 'status_comment' => $statusComment, - 'created_date' => $createdDate, - 'updated_date' => $updatedDate + 'status_comment' => $statusComment ]); - // 共通処理 SHJ-8 バッチ処理ログ作成を呼び出し - // BatchLog::createBatchLog を使用して統一的にログを記録 - $batchLog = BatchLog::createBatchLog( + // SHJ-8サービスを呼び出し + $this->shjEightService->execute( + $deviceId, $processName, + $jobName, $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 + $statusComment, + $createdDate, + $updatedDate ); Log::info('SHJ-8 バッチ処理ログ作成完了', [ 'device_id' => $deviceId, - 'process_name' => $processName, - 'batch_log_id' => $batchLog->id + 'process_name' => $processName ]); return [ diff --git a/app/Services/ShjTenService.php b/app/Services/ShjTenService.php index ce994b1..531ae7e 100644 --- a/app/Services/ShjTenService.php +++ b/app/Services/ShjTenService.php @@ -5,8 +5,8 @@ namespace App\Services; use App\Models\Park; use App\Models\EarningsSummary; use App\Models\Psection; -use App\Models\Batch\BatchLog; use App\Models\OperatorQue; +use App\Models\Device; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\DB; use Carbon\Carbon; @@ -42,10 +42,20 @@ class ShjTenService const SUMMARY_TYPE_MONTHLY = 2; /** - * コンストラクタ + * ShjEightService インスタンス + * + * @var ShjEightService */ - public function __construct() + protected $shjEightService; + + /** + * コンストラクタ + * + * @param ShjEightService $shjEightService + */ + public function __construct(ShjEightService $shjEightService) { + $this->shjEightService = $shjEightService; } /** @@ -67,31 +77,14 @@ class ShjTenService */ public function executeFiscalEarningsAggregation(string $type, string $target, array $fiscalPeriod): array { - $batchLogId = null; - $batchLog = null; $statusComments = []; // 内部変数.ステータスコメント $dataIntegrityIssues = []; // 内部変数.情報不備 - + try { // 【処理1】集計対象を設定する(財政年度ベース) $aggregationTarget = $this->setFiscalAggregationTarget($fiscalPeriod); - - // バッチ処理開始ログ作成 - $batchLog = BatchLog::createBatchLog( - 'shj10', - BatchLog::STATUS_START, - [ - 'type' => $type, - 'target' => $target, - 'fiscal_period' => $fiscalPeriod, - 'aggregation_target' => $aggregationTarget - ], - "SHJ-10 売上集計処理開始 ({$type}: {$fiscalPeriod['target_label']})" - ); - $batchLogId = $batchLog->id; Log::info('SHJ-10 売上集計処理開始', [ - 'batch_log_id' => $batchLogId, 'type' => $type, 'target' => $target, 'fiscal_period' => $fiscalPeriod, @@ -106,31 +99,18 @@ class ShjTenService $typeLabel = $this->getTypeLabel($type); $statusComment = "売上集計{$typeLabel}:駐輪場マスタが存在していません。"; $statusComments[] = $statusComment; - - // バッチログ更新 - $batchLog->update([ - 'status' => BatchLog::STATUS_WARNING, - 'end_time' => now(), - 'message' => $statusComment, - 'success_count' => 1 - ]); - + // 【処理5】オペレータキュー作成 - $this->createOperatorQueue($statusComment, $batchLogId); - + $this->createOperatorQueue($statusComment, null); + // SHJ-8 バッチ処理ログ作成 - $this->createShjBatchLog([ - 'job_name' => 'SHJ-10売上集計(年次・月次)', - 'status' => 'success', - 'status_comment' => $statusComment - ]); - + $this->callShjEight('SHJ-10売上集計(年次・月次)', 'success', $statusComment); + return [ 'success' => true, 'message' => $statusComment, 'processed_parks' => 0, - 'summary_records' => 0, - 'batch_log_id' => $batchLogId + 'summary_records' => 0 ]; } @@ -139,16 +119,16 @@ class ShjTenService $processedParks = 0; foreach ($parkInfo as $park) { - $result = $this->processFiscalEarningsForPark($park, $aggregationTarget, $fiscalPeriod, $batchLogId); - + $result = $this->processFiscalEarningsForPark($park, $aggregationTarget, $fiscalPeriod); + $processedParks++; $summaryRecords += $result['summary_records']; - + // 対象データなしの場合のステータスコメント収集 if (!empty($result['no_data_message'])) { $statusComments[] = $result['no_data_message']; } - + // 情報不備を収集("なし"でない場合) if ($result['data_integrity_issue'] !== '情報不備:なし') { $dataIntegrityIssues[] = $result['data_integrity_issue']; @@ -156,40 +136,24 @@ class ShjTenService } // 最終ステータスコメント生成 - $finalStatusComment = "SHJ-10 売上集計処理正常完了 ({$type}: {$fiscalPeriod['target_label']}) - 駐輪場数: {$processedParks}, 集計レコード数: {$summaryRecords}"; - if (!empty($statusComments)) { - $finalStatusComment .= "\n" . implode("\n", $statusComments); - } + $typeLabel = $this->getTypeLabel($type); + $finalStatusComment = "売上集計{$typeLabel}:対象={$fiscalPeriod['target_label']}、駐輪場数={$processedParks}、集計レコード数={$summaryRecords}"; if (!empty($dataIntegrityIssues)) { - $finalStatusComment .= "\n" . implode("\n", $dataIntegrityIssues); + $finalStatusComment .= "、情報不備=" . implode('、', $dataIntegrityIssues); } - - // バッチ処理完了ログ更新 - $batchLog->update([ - 'status' => BatchLog::STATUS_SUCCESS, - 'end_time' => now(), - 'message' => $finalStatusComment, - 'success_count' => 1 - ]); // 【処理5】オペレータキュー作成 // ※ 駐輪場単位で既に作成済み(processFiscalEarningsForPark内で情報不備検出時に実施) if (!empty($dataIntegrityIssues)) { Log::warning('SHJ-10 情報不備検出', [ - 'batch_log_id' => $batchLogId, 'issues' => $dataIntegrityIssues ]); } // SHJ-8 バッチ処理ログ作成 - $this->createShjBatchLog([ - 'job_name' => 'SHJ-10売上集計(年次・月次)', - 'status' => 'success', - 'status_comment' => $finalStatusComment - ]); + $this->callShjEight('SHJ-10売上集計(年次・月次)', 'success', $finalStatusComment); Log::info('SHJ-10 売上集計処理完了', [ - 'batch_log_id' => $batchLogId, 'processed_parks' => $processedParks, 'summary_records' => $summaryRecords, 'data_integrity_issues' => count($dataIntegrityIssues), @@ -201,36 +165,21 @@ class ShjTenService 'message' => 'SHJ-10 売上集計処理が正常に完了しました', 'processed_parks' => $processedParks, 'summary_records' => $summaryRecords, - 'data_integrity_issues' => count($dataIntegrityIssues), - 'batch_log_id' => $batchLogId + 'data_integrity_issues' => count($dataIntegrityIssues) ]; } catch (\Exception $e) { - $errorMessage = 'SHJ-10 売上集計処理でエラーが発生: ' . $e->getMessage(); - - if (isset($batchLog) && $batchLog) { - $batchLog->update([ - 'status' => BatchLog::STATUS_ERROR, - 'end_time' => now(), - 'message' => $errorMessage, - 'error_details' => $e->getMessage(), - 'error_count' => 1 - ]); - } + $typeLabel = $this->getTypeLabel($type ?? 'unknown'); + $errorMessage = "売上集計{$typeLabel}:エラー発生 - " . $e->getMessage(); // SHJ-8 バッチ処理ログ作成(エラー時も作成) try { - $this->createShjBatchLog([ - 'job_name' => 'SHJ-10売上集計(年次・月次)', - 'status' => 'error', - 'status_comment' => $errorMessage - ]); + $this->callShjEight('SHJ-10売上集計(年次・月次)', 'error', $errorMessage); } catch (\Exception $shjException) { Log::error('SHJ-8呼び出しエラー', ['error' => $shjException->getMessage()]); } Log::error('SHJ-10 売上集計処理エラー', [ - 'batch_log_id' => $batchLogId, 'exception' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); @@ -238,8 +187,7 @@ class ShjTenService return [ 'success' => false, 'message' => $errorMessage, - 'details' => $e->getMessage(), - 'batch_log_id' => $batchLogId + 'details' => $e->getMessage() ]; } } @@ -294,25 +242,24 @@ class ShjTenService /** * 駐輪場毎の財政年度売上集計処理 - * + * * @param object $park 駐輪場情報 * @param array $aggregationTarget 集計対象 * @param array $fiscalPeriod 財政期間情報 - * @param int $batchLogId バッチログID * @return array 処理結果 ['summary_records' => int, 'data_integrity_issue' => string, 'no_data_message' => string|null] */ - private function processFiscalEarningsForPark($park, array $aggregationTarget, array $fiscalPeriod, int $batchLogId): array + private function processFiscalEarningsForPark($park, array $aggregationTarget, array $fiscalPeriod): array { try { $startDate = $aggregationTarget['start_date']; $endDate = $aggregationTarget['end_date']; - + // 0. 情報不備チェック $dataIntegrityIssue = $this->checkDataIntegrity($park->park_id, $startDate, $endDate); - + // 情報不備がある場合、駐輪場単位でオペレータキュー作成(仕様 todo/SHJ-10/SHJ-10.txt:289-299) if ($dataIntegrityIssue !== '情報不備:なし') { - $this->createOperatorQueue($dataIntegrityIssue, $batchLogId, $park->park_id); + $this->createOperatorQueue($dataIntegrityIssue, $park->park_id); } // ① 定期契約データ取得(車種区分・分類名1・定期有効月数毎) @@ -800,7 +747,7 @@ class ShjTenService /** * 【処理5】オペレータキュー作成(駐輪場単位・情報不備がある場合のみ) - * + * * 仕様 todo/SHJ-10/SHJ-10.txt:289-317 * - que_class: 14(集計対象エラー) * - que_comment: 空(仕様書line 297) @@ -809,13 +756,12 @@ class ShjTenService * - work_instructions: 情報不備メッセージ(仕様書line 300) * - park_id: 駐輪場ID(仕様 "処理1.駐輪場ID"、パラメータエラー時はnull) * - operator_id: 9999999(バッチ処理固定値) - * + * * @param string $message 情報不備メッセージ - * @param int $batchLogId バッチログID * @param int|null $parkId 駐輪場ID(パラメータエラー時はnull) * @return void */ - private function createOperatorQueue(string $message, int $batchLogId, ?int $parkId = null): void + private function createOperatorQueue(string $message, ?int $parkId = null): void { try { DB::table('operator_que')->insert([ @@ -831,19 +777,17 @@ class ShjTenService 'created_at' => now(), 'updated_at' => now() ]); - + Log::info('オペレータキュー作成完了', [ - 'batch_log_id' => $batchLogId, 'park_id' => $parkId, 'que_class' => 14, 'que_status' => 1, 'operator_id' => self::BATCH_OPERATOR_ID, 'work_instructions' => $message ]); - + } catch (\Exception $e) { Log::error('オペレータキュー作成エラー', [ - 'batch_log_id' => $batchLogId, 'park_id' => $parkId, 'error' => $e->getMessage() ]); @@ -852,63 +796,44 @@ class ShjTenService /** * SHJ-8 バッチ処理ログ作成 - * + * * 共通処理「SHJ-8 バッチ処理ログ作成」を呼び出す * - * @param array $statistics 処理統計情報 + * @param string $jobName ジョブ名 + * @param string $status ステータス (success/error) + * @param string $statusComment 業務固有のステータスコメント * @return void */ - private function createShjBatchLog(array $statistics): void + private function callShjEight(string $jobName, string $status, string $statusComment): void { try { - // SHJ-8 パラメータ設定 - $deviceId = 9999999; // バッチ処理用固定デバイスID - $processName = 'SHJ-10'; - $jobName = $statistics['job_name']; - $status = $statistics['status']; - $statusComment = $statistics['status_comment'] ?? ''; - - $createdDate = now()->format('Y/m/d'); - $updatedDate = now()->format('Y/m/d'); + $device = Device::orderBy('device_id')->first(); + $deviceId = $device ? $device->device_id : 1; - Log::info('SHJ-8 バッチ処理ログ作成', [ - 'device_id' => $deviceId, - 'process_name' => $processName, - 'job_name' => $jobName, - 'status' => $status, - 'status_comment' => $statusComment - ]); + $today = now()->format('Y/m/d'); - // 共通処理 SHJ-8 バッチ処理ログ作成を呼び出し - // BatchLog システムを使用してバッチ処理の実行ログを記録 - BatchLog::createBatchLog( - $processName, + $this->shjEightService->execute( + $deviceId, + 'SHJ-10', + $jobName, $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 + $statusComment, + $today, + $today ); + Log::info('SHJ-8 バッチ処理ログ作成完了', [ + 'job_name' => $jobName, + 'status' => $status + ]); + } catch (\Exception $e) { Log::error('SHJ-8 バッチ処理ログ作成エラー', [ 'error' => $e->getMessage(), - 'statistics' => $statistics + 'job_name' => $jobName, + 'status_comment' => $statusComment ]); - - // SHJ-8でエラーが発生してもメイン処理は継続 - // エラーログのみ出力 + throw $e; } } diff --git a/app/Services/ShjThirteenService.php b/app/Services/ShjThirteenService.php index cc3f276..27195ff 100644 --- a/app/Services/ShjThirteenService.php +++ b/app/Services/ShjThirteenService.php @@ -4,17 +4,33 @@ namespace App\Services; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; -use App\Models\Batch\BatchLog; +use App\Models\Device; use Carbon\Carbon; /** * SHJ-13 契約台数追加処理サービス - * + * * 新規契約時の契約台数を park_number・zone テーブルに反映する処理 * SHJ-4B の副作用処理として実行される */ class ShjThirteenService { + /** + * ShjEightService + * + * @var ShjEightService + */ + protected $shjEightService; + + /** + * コンストラクタ + * + * @param ShjEightService $shjEightService + */ + public function __construct(ShjEightService $shjEightService) + { + $this->shjEightService = $shjEightService; + } /** * SHJ-13 契約台数追加処理実行 * @@ -146,7 +162,6 @@ class ShjThirteenService ->where('ptype_id', $contractData['ptype_id']) ->increment('park_number', 1, [ 'updated_at' => now(), - 'operator_id' => 'SHJ-13', ]); if ($parkNumberUpdated === 0) { @@ -158,7 +173,6 @@ class ShjThirteenService ->where('zone_id', $contractData['zone_id']) ->increment('zone_number', 1, [ 'updated_at' => now(), - 'ope_id' => 'SHJ-13', ]); if ($zoneUpdated === 0) { @@ -174,25 +188,19 @@ class ShjThirteenService $statusComment = $this->buildStatusComment($names['names'], $updatedZone->zone_number); // バッチ処理ログ作成(同一トランザクション内) - $currentDate = now()->format('Y/m/d'); - - $batchLog = BatchLog::createBatchLog( - 'SHJ-13', // process_name - BatchLog::STATUS_SUCCESS, - [ - 'device_id' => 1, - 'job_name' => 'SHJ-13', - 'status' => 'success', - 'status_comment' => $statusComment, - 'created_date' => $currentDate, - 'updated_date' => $currentDate, - 'contract_id' => $contractData['contract_id'] ?? null, - 'park_id' => $contractData['park_id'], - 'psection_id' => $contractData['psection_id'], - 'ptype_id' => $contractData['ptype_id'], - 'zone_id' => $contractData['zone_id'], - ], - $statusComment + // SHJ-8サービスを呼び出し + $device = Device::orderBy('device_id')->first(); + $deviceId = $device ? $device->device_id : 1; + $today = now()->format('Y/m/d'); + + $this->shjEightService->execute( + $deviceId, + 'SHJ-13', + 'SHJ-13契約台数追加', + 'success', + $statusComment, + $today, + $today ); Log::info('SHJ-13 契約台数更新・ログ作成完了', [ @@ -200,7 +208,6 @@ class ShjThirteenService 'park_number_updated' => $parkNumberUpdated, 'zone_updated' => $zoneUpdated, 'updated_count' => $updatedZone->zone_number, - 'batch_log_id' => $batchLog->id, 'status_comment' => $statusComment, ]); @@ -327,7 +334,7 @@ class ShjThirteenService /** - * エラー結果作成 + * エラー結果作成(SHJ-8ログも作成) * * @param int $errorCode * @param string $errorMessage @@ -336,6 +343,38 @@ class ShjThirteenService */ private function createErrorResult(int $errorCode, string $errorMessage, string $stackTrace = ''): array { + // エラー時もSHJ-8でバッチログを作成 + try { + $device = Device::orderBy('device_id')->first(); + $deviceId = $device ? $device->device_id : 1; + $today = now()->format('Y/m/d'); + + $statusComment = sprintf( + 'エラーコード:%d/エラーメッセージ:%s', + $errorCode, + $errorMessage + ); + + $this->shjEightService->execute( + $deviceId, + 'SHJ-13', + 'SHJ-13契約台数追加', + 'success', // 仕様書:エラー時も"success"で記録 + $statusComment, + $today, + $today + ); + + Log::info('SHJ-13 エラー時バッチログ作成完了', [ + 'error_code' => $errorCode, + 'status_comment' => $statusComment + ]); + } catch (\Exception $e) { + Log::error('SHJ-13 エラー時バッチログ作成失敗', [ + 'error' => $e->getMessage() + ]); + } + return [ 'result' => 1, 'error_code' => $errorCode, diff --git a/app/Services/ShjThreeService.php b/app/Services/ShjThreeService.php index e4306b7..2d5348b 100644 --- a/app/Services/ShjThreeService.php +++ b/app/Services/ShjThreeService.php @@ -6,7 +6,7 @@ use App\Models\Park; use App\Models\User; use App\Models\RegularContract; use App\Models\OperatorQue; -use App\Models\Batch\BatchLog; +use App\Models\Device; use App\Services\ShjMailSendService; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\DB; @@ -48,13 +48,6 @@ class ShjThreeService */ protected $operatorQueModel; - /** - * BatchLog モデル - * - * @var BatchLog - */ - protected $batchLogModel; - /** * ShjMailSendService * @@ -62,6 +55,13 @@ class ShjThreeService */ protected $mailSendService; + /** + * ShjEightService + * + * @var ShjEightService + */ + protected $shjEightService; + /** * コンストラクタ * @@ -69,23 +69,23 @@ class ShjThreeService * @param User $userModel * @param RegularContract $contractModel * @param OperatorQue $operatorQueModel - * @param BatchLog $batchLogModel * @param ShjMailSendService $mailSendService + * @param ShjEightService $shjEightService */ public function __construct( Park $parkModel, User $userModel, RegularContract $contractModel, OperatorQue $operatorQueModel, - BatchLog $batchLogModel, - ShjMailSendService $mailSendService + ShjMailSendService $mailSendService, + ShjEightService $shjEightService ) { $this->parkModel = $parkModel; $this->userModel = $userModel; $this->contractModel = $contractModel; $this->operatorQueModel = $operatorQueModel; - $this->batchLogModel = $batchLogModel; $this->mailSendService = $mailSendService; + $this->shjEightService = $shjEightService; } /** @@ -119,7 +119,10 @@ class ShjThreeService if (empty($parkList)) { $message = '対象の駐輪場マスタが見つかりません'; Log::warning($message); - + + // 駐輪場が見つからない場合でも実行ログを記録 + $this->createOverallBatchLog(0, 0, 0, 0, 0, 0); + return [ 'success' => false, 'message' => $message, @@ -245,6 +248,16 @@ class ShjThreeService 'queue_error_count' => $overallQueueErrorCount ]); + // 駐輪場が0件でも全体の実行ログを記録する + $this->createOverallBatchLog( + $overallProcessedParksCount, + $overallTotalTargetUsers, + $overallMailSuccessCount, + $overallMailErrorCount, + $overallQueueSuccessCount, + $overallQueueErrorCount + ); + return [ 'success' => true, 'message' => 'SHJ-3 定期更新リマインダー処理が正常に完了しました', @@ -263,6 +276,16 @@ class ShjThreeService 'trace' => $e->getTraceAsString() ]); + // エラー時も実行ログを記録 + $this->createOverallBatchLog( + $overallProcessedParksCount, + $overallTotalTargetUsers, + $overallMailSuccessCount, + $overallMailErrorCount, + $overallQueueSuccessCount, + $overallQueueErrorCount + ); + return [ 'success' => false, 'message' => $errorMessage, @@ -299,14 +322,20 @@ class ShjThreeService 'update_grace_period_start_time', // 更新期間開始時(例:"09:00") 'update_grace_period_end_date', // 更新期間終了日(例:"6") 'update_grace_period_end_time', // 更新期間終了時(例:"23:59") - 'reminder_type', // リマインダー種別(0=毎日,1=1日おき,2=2日おき) - 'reminder_time' // リマインダー時間(例:"09:00") + // 注意:reminder_type と reminder_time フィールドはまだ存在しない + // 暫定的に0(毎日)と開始時刻をデフォルト値として使用 ]) ->where('park_close_flag', 0) // 閉設フラグ = 0 ->orderBy('park_ruby', 'asc') // 駐輪場ふりがな 昇順 ->get() ->toArray(); + // reminder_type と reminder_time をデフォルト値で補完 + foreach ($parkInfo as $park) { + $park->reminder_type = 0; // 0=毎日 + $park->reminder_time = $park->update_grace_period_start_time; // 開始時刻を使用 + } + Log::info('駐輪場マスタ情報取得完了', [ 'park_count' => count($parkInfo) ]); @@ -628,13 +657,14 @@ class ShjThreeService $mailTemplateId ); - if ($mailResult['success']) { + // SHJ-7仕様準拠: result === 0 が正常、それ以外は異常 + if (($mailResult['result'] ?? 1) === 0) { // 仕様書:処理結果 = 0(正常)の場合 Log::info('メール送信成功', [ 'user_id' => $targetUser->利用者ID, 'contract_id' => $targetUser->定期契約ID ]); - + return [ 'type' => 'mail_success', 'success' => true, @@ -644,14 +674,16 @@ class ShjThreeService } else { // 仕様書:その他の場合(異常) // バッチコメントに「処理2.定期契約ID」+「SHJ-7 メール送信.異常情報」を設定する(後ろに足す) - $errorInfo = "定期契約ID:{$targetUser->定期契約ID} / SHJ-7 メール送信.異常情報:{$mailResult['message']}"; - + // 仕様準拠: error_info を使用 + $shjSevenErrorInfo = $mailResult['error_info'] ?? 'メール送信失敗'; + $errorInfo = "定期契約ID:{$targetUser->定期契約ID} / SHJ-7 メール送信.異常情報:{$shjSevenErrorInfo}"; + Log::warning('メール送信失敗', [ 'user_id' => $targetUser->利用者ID, 'contract_id' => $targetUser->定期契約ID, - 'error' => $mailResult['message'] + 'error_info' => $shjSevenErrorInfo ]); - + return [ 'type' => 'mail_error', 'success' => false, @@ -747,9 +779,8 @@ class ShjThreeService /** * 【処理4】SHJ-8バッチ処理ログ作成 - * + * * 仕様書に基づくSHJ-8共通処理呼び出し - * BatchLog統一システムを使用してバッチ処理の実行ログを記録 * ※各駐輪場ごとに1回実行される * * @param object $park 駐輪場情報 @@ -769,66 +800,39 @@ class ShjThreeService int $queueErrorCount ): void { try { - // 仕様書:SHJ-8パラメータ設定 - $deviceId = 9999999; // バッチ処理用固定デバイスID(他Serviceと同様) - $processName = 'SHJ-3'; - $jobName = 'SHJ-3定期更新リマインダー'; - $status = BatchLog::STATUS_SUCCESS; - + $device = Device::orderBy('device_id')->first(); + $deviceId = $device ? $device->device_id : 1; + // 仕様書:ステータスコメント生成 // 「内部変数.バッチコメント」+ "/" + 「処理1.駐輪場名」 // + ":メール正常終了件数" + 「内部変数.メール正常終了件数」 // + "、メール異常終了件数" + 「内部変数.メール異常終了件数」 // + "、キュー登録正常終了件数" + 「内部変数.キュー登録正常終了件数」 // + "、キュー登録異常終了件数" + 「内部変数.キュー登録異常終了件数」 - $statusComment = ($batchComment ? $batchComment . ' / ' : '') . - "{$park->park_name} : " . + $statusComment = ($batchComment ? $batchComment . ' / ' : '') . + "{$park->park_name}:" . "メール正常終了件数={$mailSuccessCount}、" . "メール異常終了件数={$mailErrorCount}、" . "キュー登録正常終了件数={$queueSuccessCount}、" . "キュー登録異常終了件数={$queueErrorCount}"; - - $createdDate = now()->format('Y/m/d'); - $updatedDate = now()->format('Y/m/d'); + + $today = now()->format('Y/m/d'); Log::info('SHJ-8バッチ処理ログ作成', [ 'park_id' => $park->park_id, 'park_name' => $park->park_name, - 'device_id' => $deviceId, - 'process_name' => $processName, - 'job_name' => $jobName, - 'status' => $status, 'status_comment' => $statusComment ]); - // 仕様書:共通処理「SHJ-8 バッチ処理ログ作成」を呼び出す - // BatchLog::createBatchLog を使用して統一的にログを記録 - BatchLog::createBatchLog( - $processName, - $status, - [ - 'device_id' => $deviceId, - 'job_name' => $jobName, - 'park_id' => $park->park_id, - 'park_name' => $park->park_name, - 'status_comment' => $statusComment, - 'statistics' => [ - 'mail_success_count' => $mailSuccessCount, - 'mail_error_count' => $mailErrorCount, - 'queue_success_count' => $queueSuccessCount, - 'queue_error_count' => $queueErrorCount, - 'batch_comment' => $batchComment - ], - 'shj8_params' => [ - 'device_id' => $deviceId, - 'process_name' => $processName, - 'job_name' => $jobName, - 'status' => $status, - 'created_date' => $createdDate, - 'updated_date' => $updatedDate - ] - ], - $statusComment + // SHJ-8サービスを呼び出し + $this->shjEightService->execute( + $deviceId, + 'SHJ-3', + 'SHJ-3定期更新リマインダー', + 'success', + $statusComment, + $today, + $today ); } catch (\Exception $e) { @@ -842,4 +846,64 @@ class ShjThreeService // エラーログのみ出力 } } + + /** + * 全体の実行ログを記録する + * + * 駐輪場が0件の場合でも実行記録を残すための全体サマリーログ + * + * @param int $processedParksCount 処理した駐輪場数 + * @param int $totalTargetUsers 対象者総数 + * @param int $mailSuccessCount メール成功件数 + * @param int $mailErrorCount メール失敗件数 + * @param int $queueSuccessCount キュー成功件数 + * @param int $queueErrorCount キュー失敗件数 + * @return void + */ + private function createOverallBatchLog( + int $processedParksCount, + int $totalTargetUsers, + int $mailSuccessCount, + int $mailErrorCount, + int $queueSuccessCount, + int $queueErrorCount + ): void { + try { + $device = Device::orderBy('device_id')->first(); + $deviceId = $device ? $device->device_id : 1; + + // 全体サマリーのステータスコメント + $statusComment = sprintf( + '処理駐輪場数:%d、対象者総数:%d、メール成功:%d、メール失敗:%d、キュー追加:%d', + $processedParksCount, + $totalTargetUsers, + $mailSuccessCount, + $mailErrorCount, + $queueSuccessCount + $queueErrorCount + ); + + $today = now()->format('Y/m/d'); + + Log::info('SHJ-3 全体実行ログ作成', [ + 'status_comment' => $statusComment + ]); + + // SHJ-8サービスを呼び出し + $this->shjEightService->execute( + $deviceId, + 'SHJ-3', + 'SHJ-3定期更新リマインダー', + 'success', + $statusComment, + $today, + $today + ); + + } catch (\Exception $e) { + Log::error('SHJ-3 全体実行ログ作成エラー', [ + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + } + } } diff --git a/app/Services/ShjTwelveService.php b/app/Services/ShjTwelveService.php index 3380c4c..c24df1b 100644 --- a/app/Services/ShjTwelveService.php +++ b/app/Services/ShjTwelveService.php @@ -4,7 +4,7 @@ namespace App\Services; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; -use App\Models\Batch\BatchLog; +use App\Models\Device; use App\Models\RegularContract; use App\Models\User; use App\Models\Park; @@ -25,14 +25,25 @@ class ShjTwelveService */ protected $shjMailSendService; + /** + * ShjEightService + * + * @var ShjEightService + */ + protected $shjEightService; + /** * コンストラクタ * * @param ShjMailSendService $shjMailSendService + * @param ShjEightService $shjEightService */ - public function __construct(ShjMailSendService $shjMailSendService) - { + public function __construct( + ShjMailSendService $shjMailSendService, + ShjEightService $shjEightService + ) { $this->shjMailSendService = $shjMailSendService; + $this->shjEightService = $shjEightService; } /** @@ -50,19 +61,17 @@ class ShjTwelveService try { $query = DB::table('regular_contract as T1') ->select([ - 'T1.contract_id', // 定期契約ID - 'T2.user_seq', // 利用者ID - 'T2.user_name', // 利用者名 - 'T2.user_manual_flag', // 手動登録フラグ - 'T2.user_mail', // メールアドレス - 'T2.user_mail_sub', // 予備メールアドレス - 'T2.park_id', // 駐輪場ID (userテーブルから) - 'T3.park_name', // 駐輪場名 - 'T1.billing_amount' // 請求金額 + 'T1.contract_id', // 定期契約ID + 'T2.user_seq', // 利用者ID + 'T2.user_name', // 利用者名 + 'T2.user_manual_regist_flag', // 手動登録フラグ + 'T2.user_primemail', // メールアドレス + 'T2.user_submail', // 予備メールアドレス + 'T1.park_id', // 駐輪場ID (regular_contractテーブルから) + 'T3.park_name', // 駐輪場名 + 'T1.billing_amount' // 請求金額 ]) - ->join('user as T2', function($join) { - $join->on('T1.user_seq', '=', 'T2.user_seq'); - }) + ->join('user as T2', 'T1.user_id', '=', 'T2.user_seq') ->join('park as T3', 'T1.park_id', '=', 'T3.park_id') ->where([ ['T1.contract_cancel_flag', '=', 0], // 解約フラグ = 0 @@ -93,53 +102,91 @@ class ShjTwelveService /** * 【処理2】未払い者への通知、またはオペレーターキュー追加処理 - * - * 各未払い者に対して以下の処理を実行: - * 1. メール通知の実行 (SHJ-7連携) - * 2. オペレーターキューへの追加 (opeテーブル) + * + * 仕様: + * - 手動登録フラグ = 0 (Web申込) → SHJ-7メール送信のみ + * - 手動登録フラグ ≠ 0 (その他) → オペレーターキュー追加のみ * * @param array $unpaidUsers 未払い者リスト * @return array 処理結果 */ public function processUnpaidUserNotifications(array $unpaidUsers): array { - $notificationCount = 0; - $queueCount = 0; - $errors = []; + // 内部変数(カウンタ)初期化 + $mailSuccessCount = 0; + $mailErrorCount = 0; + $queueSuccessCount = 0; + $queueErrorCount = 0; + $batchComments = []; // バッチコメント(エラー情報)累積用 $processParameters = []; try { DB::beginTransaction(); + // 処理1の取得レコード数分繰り返し foreach ($unpaidUsers as $user) { try { - // メール通知処理 - $mailResult = $this->sendNotificationMail($user); - if ($mailResult['success']) { - $notificationCount++; - } + // 【判定】手動登録フラグによる分岐 + if ($user->user_manual_regist_flag == 0) { + // Web申込 → SHJ-7メール送信 + $mailResult = $this->sendNotificationMailViaShj7($user); - // オペレーターキュー追加処理 - $queueResult = $this->addToOperatorQueue($user); - if ($queueResult['success']) { - $queueCount++; - } + // 処理結果判定: result === 0 → 正常 + if (($mailResult['result'] ?? 1) === 0) { + $mailSuccessCount++; + } else { + $mailErrorCount++; + // バッチコメントにSHJ-7異常情報を設定(後ろに足す) + $batchComments[] = sprintf( + 'SHJ-7メール送信: 契約ID:%s メール送信失敗: %s', + $user->contract_id, + $mailResult['error_info'] ?? 'Unknown error' + ); + } - // 処理パラメータ記録 - $processParameters[] = [ - 'contract_id' => $user->contract_id, - 'user_seq' => $user->user_seq, - 'billing_amount' => $user->billing_amount, - 'mail_sent' => $mailResult['success'], - 'queue_added' => $queueResult['success'] - ]; + // 処理パラメータ記録 + $processParameters[] = [ + 'contract_id' => $user->contract_id, + 'user_seq' => $user->user_seq, + 'billing_amount' => $user->billing_amount, + 'process_type' => 'mail', + 'result' => ($mailResult['result'] ?? 1) === 0 ? 'success' : 'error' + ]; + + } else { + // その他(手動登録)→ オペレーターキュー追加 + $queueResult = $this->addToOperatorQueue($user); + + if ($queueResult['success']) { + $queueSuccessCount++; + } else { + $queueErrorCount++; + // バッチコメントに異常情報を設定(後ろに足す) + $batchComments[] = sprintf( + 'キュー登録: 契約ID:%s キュー登録失敗: %s', + $user->contract_id, + $queueResult['message'] ?? 'Unknown error' + ); + } + + // 処理パラメータ記録 + $processParameters[] = [ + 'contract_id' => $user->contract_id, + 'user_seq' => $user->user_seq, + 'billing_amount' => $user->billing_amount, + 'process_type' => 'queue', + 'result' => $queueResult['success'] ? 'success' : 'error' + ]; + } } catch (\Exception $e) { - $errors[] = [ - 'contract_id' => $user->contract_id, - 'error' => $e->getMessage() - ]; - + // 個別エラーを記録して次の繰り返し処理へ + $batchComments[] = sprintf( + '契約ID:%s 処理エラー: %s', + $user->contract_id, + $e->getMessage() + ); + Log::warning('SHJ-12 個別処理エラー', [ 'contract_id' => $user->contract_id, 'user_seq' => $user->user_seq, @@ -150,18 +197,32 @@ class ShjTwelveService DB::commit(); + // ステータスコメント構築 + $statusComment = $this->buildStatusComment( + $mailSuccessCount, + $mailErrorCount, + $queueSuccessCount, + $queueErrorCount + ); + + // バッチコメント整形(最大100件、超過分は省略) + $formattedBatchComments = $this->formatBatchComments($batchComments); + return [ 'success' => true, - 'notification_count' => $notificationCount, - 'queue_count' => $queueCount, + 'mail_success_count' => $mailSuccessCount, + 'mail_error_count' => $mailErrorCount, + 'queue_success_count' => $queueSuccessCount, + 'queue_error_count' => $queueErrorCount, + 'status_comment' => $statusComment, + 'batch_comments' => $formattedBatchComments, 'parameters' => $processParameters, - 'errors' => $errors, 'message' => '未払い者通知処理完了' ]; } catch (\Exception $e) { DB::rollBack(); - + Log::error('SHJ-12 通知処理全体エラー', [ 'error' => $e->getMessage(), 'processed_count' => count($processParameters) @@ -169,10 +230,13 @@ class ShjTwelveService return [ 'success' => false, - 'notification_count' => $notificationCount, - 'queue_count' => $queueCount, + 'mail_success_count' => $mailSuccessCount, + 'mail_error_count' => $mailErrorCount, + 'queue_success_count' => $queueSuccessCount, + 'queue_error_count' => $queueErrorCount, + 'status_comment' => 'システムエラー', + 'batch_comments' => $batchComments, 'parameters' => $processParameters, - 'errors' => $errors, 'message' => '通知処理エラー: ' . $e->getMessage(), 'details' => $e->getTraceAsString() ]; @@ -180,118 +244,224 @@ class ShjTwelveService } /** - * 未払い者へのメール通知送信 - * - * SHJ-7 メール送信サービスを使用してメール通知を実行 + * SHJ-7 メール送信サービス経由でメール通知送信 + * + * 仕様書パラメータ: + * - メールアドレス: 処理1.メールアドレス + * - 予備メールアドレス: 処理1.予備メールアドレス + * - 使用プログラムID: 204 * * @param object $user 未払い者情報 - * @return array 送信結果 + * @return array SHJ-7の処理結果 (result_code: 0=正常, 1=異常) */ - private function sendNotificationMail($user): array + private function sendNotificationMailViaShj7($user): array { try { - // メールアドレスの確認 - $emailAddress = $user->user_mail ?: $user->user_mail_sub; - - if (empty($emailAddress)) { - return [ - 'success' => false, - 'message' => 'メールアドレスが設定されていません' - ]; - } + // SHJ-7 executeMailSend 呼び出し + $result = $this->shjMailSendService->executeMailSend( + (string)($user->user_primemail ?? ''), // メールアドレス + (string)($user->user_submail ?? ''), // 予備メールアドレス + 204 // 使用プログラムID + ); - // SHJ-7 メール送信サービス呼び出し - $mailParams = [ - 'to_email' => $emailAddress, - 'user_name' => $user->user_name, - 'park_name' => $user->park_name, - 'billing_amount' => $user->billing_amount, - 'contract_id' => $user->contract_id - ]; - - $result = $this->shjMailSendService->sendUnpaidNotificationMail($mailParams); - - Log::info('SHJ-12 メール送信結果', [ + Log::info('SHJ-12 SHJ-7メール送信結果', [ 'contract_id' => $user->contract_id, - 'email' => $emailAddress, - 'success' => $result['success'] + 'user_seq' => $user->user_seq, + 'result' => $result['result'] ?? 1, + 'error_info' => $result['error_info'] ?? '' ]); return $result; } catch (\Exception $e) { - Log::error('SHJ-12 メール送信エラー', [ + Log::error('SHJ-12 SHJ-7メール送信エラー', [ 'contract_id' => $user->contract_id, 'error' => $e->getMessage() ]); return [ - 'success' => false, - 'message' => 'メール送信エラー: ' . $e->getMessage() + 'result' => 1, // 異常終了 + 'error_info' => 'SHJ-7メール送信エラー: ' . $e->getMessage() ]; } } /** * オペレーターキューへの追加 - * - * opeテーブルにオペレーター処理キューとして登録 + * + * 仕様書SQL定義に基づき operator_que テーブルに登録 + * - キュー種別ID: 8 (支払い催促) + * - キューステータスID: 1 (キュー発生) + * - que_id: MAX+1方式で生成(db_now.sqlは非AUTO_INCREMENT) + * - 主キー衝突時に1回リトライ * * @param object $user 未払い者情報 * @return array 追加結果 */ private function addToOperatorQueue($user): array { - try { - $queueData = [ - 'ope_device_id' => null, // デバイスID (未設定) - 'ope_process_name' => 'SHJ-12', // プロセス名 - 'ope_job_name' => '未払い者通知', // ジョブ名 - 'ope_status' => 'pending', // ステータス - 'ope_comment' => sprintf( - '契約ID:%s ユーザー:%s 金額:%s円', - $user->contract_id, - $user->user_name, - number_format($user->billing_amount) - ), - 'ope_target_user_id' => $user->user_seq, // 対象ユーザーID - 'ope_target_contract_id' => $user->contract_id, // 対象契約ID - 'ope_billing_amount' => $user->billing_amount, // 請求金額 - 'created_at' => now(), - 'updated_at' => now() - ]; + $maxRetries = 2; // 最大2回試行(初回 + リトライ1回) + $lastException = null; - // opeテーブルに挿入 - DB::table('ope')->insert($queueData); + for ($attempt = 1; $attempt <= $maxRetries; $attempt++) { + try { + // オペレーターキューデータ構築 + // 注: que_idはAUTO_INCREMENTのため、DBに委任(手動採番しない) + $queueData = [ + // 'que_id' は削除(AUTO_INCREMENTに委任) + 'que_class' => 8, // キュー種別ID: 8=支払い催促 + 'user_id' => $user->user_seq, // 利用者ID + 'contract_id' => $user->contract_id, // 定期契約ID + 'park_id' => $user->park_id, // 駐輪場ID + 'que_comment' => '', // キューコメント (空文字) + 'que_status' => 1, // キューステータスID: 1=キュー発生 + 'que_status_comment' => '', // キューステータスコメント (空文字) + 'work_instructions' => '', // 業務指示コメント (空文字) + 'created_at' => now(), // 登録日時 + 'updated_at' => now(), // 更新日時 + 'operator_id' => null // 更新オペレータID (NULL: システム自動) + ]; - Log::info('SHJ-12 オペレーターキュー追加完了', [ - 'contract_id' => $user->contract_id, - 'user_seq' => $user->user_seq, - 'billing_amount' => $user->billing_amount - ]); + // operator_queテーブルに挿入(que_idはDBが自動採番) + $newQueId = DB::table('operator_que')->insertGetId($queueData); - return [ - 'success' => true, - 'message' => 'オペレーターキューに追加しました' - ]; + Log::info('SHJ-12 オペレーターキュー追加完了', [ + 'que_id' => $newQueId, + 'contract_id' => $user->contract_id, + 'user_seq' => $user->user_seq, + 'park_id' => $user->park_id, + 'que_class' => 8, + 'que_status' => 1, + 'attempt' => $attempt + ]); - } catch (\Exception $e) { - Log::error('SHJ-12 オペレーターキュー追加エラー', [ - 'contract_id' => $user->contract_id, - 'error' => $e->getMessage() - ]); + return [ + 'success' => true, + 'message' => 'オペレーターキュー追加成功', + 'que_id' => $newQueId + ]; - return [ - 'success' => false, - 'message' => 'オペレーターキュー追加エラー: ' . $e->getMessage() - ]; + } catch (\Illuminate\Database\QueryException $e) { + $lastException = $e; + + // 主キー重複エラー(Duplicate entry)の場合のみリトライ + // SQLSTATEコード 23000 は整合性制約違反を示す + if ($e->getCode() == 23000 && $attempt < $maxRetries) { + Log::warning('SHJ-12 que_id重複検出、リトライします', [ + 'attempt' => $attempt, + 'max_retries' => $maxRetries, + 'que_id' => $newQueId ?? null, + 'contract_id' => $user->contract_id, + 'error_code' => $e->getCode() + ]); + + // 短時間待機後に再試行(100ms) + usleep(100000); + continue; + } + + // その他のエラー、または最終試行での失敗時は例外をスロー + throw $e; + + } catch (\Exception $e) { + // QueryException以外の例外は即座にスロー + $lastException = $e; + throw $e; + } } + + // ループを抜けた場合(通常は到達しない) + Log::error('SHJ-12 オペレーターキュー追加エラー(最大リトライ回数超過)', [ + 'contract_id' => $user->contract_id, + 'user_seq' => $user->user_seq, + 'max_retries' => $maxRetries, + 'error' => $lastException ? $lastException->getMessage() : 'Unknown error', + 'trace' => $lastException ? $lastException->getTraceAsString() : '' + ]); + + return [ + 'success' => false, + 'message' => 'オペレーターキュー追加エラー(リトライ失敗): ' . + ($lastException ? $lastException->getMessage() : 'Unknown error') + ]; + } + + /** + * ステータスコメント構築 + * + * 仕様書に基づくステータスコメント形式: + * - エラーなし: "メール送信成功:X件 / キュー登録成功:Y件" + * - エラーあり: "メール送信成功:X件 / メール送信失敗:A件 / キュー登録成功:Y件 / キュー登録失敗:B件" + * + * @param int $mailSuccessCount メール正常終了件数 + * @param int $mailErrorCount メール異常終了件数 + * @param int $queueSuccessCount キュー登録正常終了件数 + * @param int $queueErrorCount キュー登録異常終了件数 + * @return string ステータスコメント + */ + private function buildStatusComment( + int $mailSuccessCount, + int $mailErrorCount, + int $queueSuccessCount, + int $queueErrorCount + ): string { + $parts = []; + + // メール送信結果 + if ($mailSuccessCount > 0 || $mailErrorCount > 0) { + if ($mailErrorCount > 0) { + $parts[] = "メール送信成功:{$mailSuccessCount}件"; + $parts[] = "メール送信失敗:{$mailErrorCount}件"; + } else { + $parts[] = "メール送信成功:{$mailSuccessCount}件"; + } + } + + // キュー登録結果 + if ($queueSuccessCount > 0 || $queueErrorCount > 0) { + if ($queueErrorCount > 0) { + $parts[] = "キュー登録成功:{$queueSuccessCount}件"; + $parts[] = "キュー登録失敗:{$queueErrorCount}件"; + } else { + $parts[] = "キュー登録成功:{$queueSuccessCount}件"; + } + } + + return implode(' / ', $parts); + } + + /** + * バッチコメント整形 + * + * エラー情報を最大100件に制限し、超過分は省略表記 + * + * @param array $batchComments エラー情報配列 + * @return string 整形済みバッチコメント + */ + private function formatBatchComments(array $batchComments): string + { + if (empty($batchComments)) { + return ''; + } + + // 最大100件に制限 + $limitedComments = array_slice($batchComments, 0, 100); + + // 超過分の件数を追加 + if (count($batchComments) > 100) { + $limitedComments[] = sprintf( + '...他%d件省略', + count($batchComments) - 100 + ); + } + + return implode("\n", $limitedComments); } /** * 【処理3】バッチ処理ログを作成する - * - * 統一BatchLogシステムを使用してSHJ-12の実行ログを記録 + * + * SHJ-8サービスを呼び出してbat_job_logテーブルに登録(業務固有のstatus_comment記録) * * @param string $status ステータス * @param array $parameters パラメータ @@ -310,22 +480,40 @@ class ShjTwelveService int $errorCount = 0 ): void { try { - BatchLog::createBatchLog( - 'SHJ-12', - $status, - $parameters, + // デバイスIDを取得 + $device = Device::orderBy('device_id')->first(); + $deviceId = $device ? $device->device_id : 1; + + // status_commentを構築(業務情報を含む) + $statusComment = sprintf( + '%s (実行:%d/成功:%d/エラー:%d)', $message, - [ - 'execution_count' => $executionCount, - 'success_count' => $successCount, - 'error_count' => $errorCount, - 'process_type' => '未払い者通知処理', - 'executed_at' => now()->toISOString() - ] + $executionCount, + $successCount, + $errorCount + ); + + $today = now()->format('Y/m/d'); + + Log::info('SHJ-8 バッチ処理ログ作成', [ + 'device_id' => $deviceId, + 'status' => $status, + 'status_comment' => $statusComment + ]); + + // SHJ-8サービスを呼び出し + $this->shjEightService->execute( + $deviceId, + 'SHJ-12', + 'SHJ-12未払い者通知', + $status, + $statusComment, + $today, + $today ); } catch (\Exception $e) { - Log::error('SHJ-12 バッチログ作成エラー', [ + Log::error('SHJ-8 バッチログ作成エラー', [ 'error' => $e->getMessage(), 'status' => $status, 'message' => $message