Compare commits

..

No commits in common. "main" and "main_higashide" have entirely different histories.

26 changed files with 1702 additions and 2610 deletions

17
.env
View File

@ -46,16 +46,15 @@ REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null REDIS_PASSWORD=null
REDIS_PORT=6379 REDIS_PORT=6379
MAIL_MAILER=smtp MAIL_MAILER=log
#MAIL_SCHEME=null MAIL_SCHEME=null
MAIL_HOST=tomatofox9.sakura.ne.jp MAIL_HOST=127.0.0.1
MAIL_PORT=587 MAIL_PORT=2525
MAIL_USERNAME=demo@so-rin.jp MAIL_USERNAME=null
MAIL_PASSWORD=rokuchou4665 MAIL_PASSWORD=null
MAIL_ENCRYPTION=tls MAIL_FROM_ADDRESS="hp@so-manager-dev.com"
MAIL_FROM_ADDRESS=demo@so-rin.jp
MAIL_FROM_NAME="${APP_NAME}" MAIL_FROM_NAME="${APP_NAME}"
MAIL_ADMIN=demo@so-rin.jp MAIL_ADMIN=null
AWS_ACCESS_KEY_ID= AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY= AWS_SECRET_ACCESS_KEY=

View File

@ -4,70 +4,54 @@ namespace App\Console\Commands;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use App\Services\ShjEightService; use App\Models\Batch\BatchLog;
use App\Models\Device;
/** /**
* SHJ-8 バッチ処理ログ登録コマンド * SHJ-8 バッチ処理ログ登録コマンド
* *
* bat_job_logテーブルにバッチ処理の実行ログを登録する * 統一BatchLogを使用してバッチ処理の実行ログをbatch_logテーブルに登録する
* ShjEightServiceを使用して実装 * 仕様書に基づくSHJ-8の要求パラメータを受け取り、通用のログシステムで記録
*/ */
class ShjBatchLogCommand extends Command class ShjBatchLogCommand extends Command
{ {
/**
* ShjEightService インスタンス
*
* @var ShjEightService
*/
protected $shjEightService;
/** /**
* コンソールコマンドの名前とシグネチャ * コンソールコマンドの名前とシグネチャ
* *
* 修正版7項目status_comment追加 * 引数:
* - device_id: デバイスID (必須) * - device_id: デバイスID (必須)
* - process_name: プロセス名 (必須)
* - job_name: ジョブ名 (必須)
* - status: ステータス (必須) * - status: ステータス (必須)
* - status_comment: ステータスコメント (必須)
* - created_date: 登録日時 (必須、yyyy/mm/dd形式) * - created_date: 登録日時 (必須、yyyy/mm/dd形式)
* - updated_date: 更新日時 (必須、yyyy/mm/dd形式) * - updated_date: 更新日時 (必須、yyyy/mm/dd形式)
* - process_name: プロセス名 (オプション)
* - job_name: ジョブ名 (オプション)
* *
* @var string * @var string
*/ */
protected $signature = 'shj:batch-log protected $signature = 'shj:batch-log {device_id : デバイスID} {process_name : プロセス名} {job_name : ジョブ名} {status : ステータス} {created_date : 登録日時} {updated_date : 更新日時}';
{device_id : デバイスID}
{status : ステータス}
{status_comment : ステータスコメント}
{created_date : 登録日時}
{updated_date : 更新日時}
{process_name? : プロセス名}
{job_name? : ジョブ名}';
/** /**
* コンソールコマンドの説明 * コンソールコマンドの説明
* *
* @var string * @var string
*/ */
protected $description = 'SHJ-8 バッチ処理ログ登録 - bat_job_logテーブルにバッチ処理の実行ログを登録'; protected $description = 'SHJ-8 バッチ処理ログ登録 - バッチ処理の実行ログを登録';
/** /**
* コンストラクタ * コンストラクタ
*
* @param ShjEightService $shjEightService
*/ */
public function __construct(ShjEightService $shjEightService) public function __construct()
{ {
parent::__construct(); parent::__construct();
$this->shjEightService = $shjEightService;
} }
/** /**
* コンソールコマンドを実行 * コンソールコマンドを実行
* *
* 処理フロー: * 処理フロー:
* 1. ShjEightServiceを呼び出して処理を実行 * 1. 入力パラメーターをチェックする
* 2. 処理結果を返却する * 2. 統一BatchLogを使用してbatch_logテーブルに記録
* 3. 仕様書準拠の処理結果を返却する
* *
* @return int * @return int
*/ */
@ -83,7 +67,6 @@ class ShjBatchLogCommand extends Command
$processName = $this->argument('process_name'); $processName = $this->argument('process_name');
$jobName = $this->argument('job_name'); $jobName = $this->argument('job_name');
$status = $this->argument('status'); $status = $this->argument('status');
$statusComment = $this->argument('status_comment');
$createdDate = $this->argument('created_date'); $createdDate = $this->argument('created_date');
$updatedDate = $this->argument('updated_date'); $updatedDate = $this->argument('updated_date');
@ -93,71 +76,163 @@ class ShjBatchLogCommand extends Command
'process_name' => $processName, 'process_name' => $processName,
'job_name' => $jobName, 'job_name' => $jobName,
'status' => $status, 'status' => $status,
'status_comment' => $statusComment,
'created_date' => $createdDate, 'created_date' => $createdDate,
'updated_date' => $updatedDate 'updated_date' => $updatedDate
]); ]);
// ShjEightServiceを呼び出して処理を実行 // 【処理1】入力パラメーターをチェックする
$result = $this->shjEightService->execute( $paramCheckResult = $this->validateParameters($deviceId, $processName, $jobName, $status, $createdDate, $updatedDate);
$deviceId, if (!$paramCheckResult['valid']) {
$processName, $this->error('パラメータエラー: ' . $paramCheckResult['message']);
$jobName,
$status,
$statusComment,
$createdDate,
$updatedDate
);
$endTime = now(); // 仕様書【判断1】パラメーターNG時の結果出力
$this->line('処理結果: 1'); // 1 = 異常終了
// 処理結果に応じた出力 $this->line('異常情報: ' . $paramCheckResult['message']);
if ($result['result'] === 0) {
// 正常終了
$this->info('SHJ-8 バッチ処理ログ登録が正常に完了しました。');
$this->info("処理時間: {$startTime->diffInSeconds($endTime)}");
// 標準出力形式 (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; return self::FAILURE;
} }
// 【処理2】統一BatchLogを使用してログ登録
$batchLog = BatchLog::createBatchLog(
$processName, // 実際のプロセス名を使用
$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()
);
$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('異常情報: '); // 正常時は空文字
return self::SUCCESS;
} catch (\Exception $e) { } catch (\Exception $e) {
$this->error('SHJ-8 バッチ処理ログ登録で予期しないエラーが発生しました: ' . $e->getMessage()); $this->error('SHJ-8 バッチ処理ログ登録で予期しないエラーが発生しました: ' . $e->getMessage());
// 標準出力形式 (SHJ-8仕様書準拠 - 例外時)
$this->line('処理結果: 1');
$this->line('異常情報: ' . $e->getMessage());
Log::error('SHJ-8 バッチ処理ログ登録例外エラー', [ Log::error('SHJ-8 バッチ処理ログ登録例外エラー', [
'exception' => $e->getMessage(), 'exception' => $e->getMessage(),
'trace' => $e->getTraceAsString() 'trace' => $e->getTraceAsString()
]); ]);
// 仕様書【処理3】異常終了時の結果出力
$this->line('処理結果: 1'); // 1 = 異常終了
$this->line('異常情報: エラー: ' . $e->getMessage());
return self::FAILURE; 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]);
}
} }

View File

@ -52,13 +52,14 @@ class ShjElevenCommand extends Command
/** /**
* コンソールコマンドを実行 * コンソールコマンドを実行
* *
* 処理フロー(仕様書準拠): * 処理フロー:
* 【処理1】集計単位每个の契約台数を算出する * 1. 集計単位每个の契約台数を算出する
* 【判断1】取得件数判定 * 2. 取得件数判定
* - 取得件数 = 0 【処理4】バッチログ作成「全駐輪場契約なし」 終了 * 3. ゾーンマスタを取得する
* - 取得件数 1 【処理2】ゾーンマスタ処理循環 終了 * 4. 取得判定とゾーンマスタ登録
* * 5. 契約台数チェック(限界台数超過判定)
* ※【処理4】は各レコードの処理ごとにService層で呼び出される * 6. 契約台数を反映する
* 7. バッチ処理ログを作成する
* *
* @return int * @return int
*/ */
@ -81,37 +82,29 @@ class ShjElevenCommand extends Command
$this->info("取得件数: {$countResults}"); $this->info("取得件数: {$countResults}");
if ($countResults === 0) { if ($countResults === 0) {
// 【判断1】取得件数 = 0 の場合 // 対象なしの結果を設定する
$this->info('対象なしのため処理を終了します。'); $this->info('契約台数算出対象なしのため処理を終了します。');
// 【処理4】bat_job_logに直接書き込み取得件数=0時 // バッチ処理ログを作成
$batchLogResult = $this->shjElevenService->writeBatJobLogForNoContracts(); $this->shjElevenService->createBatchLog(
'success',
// bat_job_log書き込み結果をチェック [],
if (!$batchLogResult['success']) { '契約台数算出対象なし',
$this->warn('bat_job_log書き込みで異常が発生しました'); 0,
if (isset($batchLogResult['error_message'])) { 0,
$this->warn('error_message: ' . $batchLogResult['error_message']); 0
} );
Log::warning('bat_job_log書き込み失敗対象なし', [
'error_message' => $batchLogResult['error_message'] ?? null
]);
}
Log::info('SHJ-11 現在契約台数集計完了(対象なし)', [ Log::info('SHJ-11 現在契約台数集計完了(対象なし)', [
'end_time' => now(), 'end_time' => now(),
'duration_seconds' => $startTime->diffInSeconds(now()), 'duration_seconds' => $startTime->diffInSeconds(now())
'bat_job_log_success' => $batchLogResult['success']
]); ]);
return self::SUCCESS; return self::SUCCESS;
} }
// 【判断1】取得件数 ≥ 1 の場合 // 【処理2・3】ゾーンマスタ処理取得・登録・更新
// 【処理2・3・4】ゾーンマスタ処理各レコードごとに処理4を実行
$this->info('【処理2】ゾーンマスタ処理を実行しています...'); $this->info('【処理2】ゾーンマスタ処理を実行しています...');
$this->info('※各レコードごとに【処理4】バッチログを作成します');
$processResult = $this->shjElevenService->processZoneManagement($contractCounts); $processResult = $this->shjElevenService->processZoneManagement($contractCounts);
// 処理結果確認 // 処理結果確認
@ -124,9 +117,15 @@ class ShjElevenCommand extends Command
$this->info("ゾーン更新件数: {$processResult['updated_zones']}"); $this->info("ゾーン更新件数: {$processResult['updated_zones']}");
$this->info("限界台数超過件数: {$processResult['over_capacity_count']}"); $this->info("限界台数超過件数: {$processResult['over_capacity_count']}");
if (!empty($processResult['batch_log_errors'])) { // 【処理4】バッチ処理ログを作成する
$this->warn("バッチログエラー件数: " . count($processResult['batch_log_errors']) . ""); $this->shjElevenService->createBatchLog(
} 'success',
$processResult['parameters'],
'現在契約台数集計処理完了',
$countResults,
$processResult['created_zones'] + $processResult['updated_zones'],
0
);
Log::info('SHJ-11 現在契約台数集計完了', [ Log::info('SHJ-11 現在契約台数集計完了', [
'end_time' => $endTime, 'end_time' => $endTime,
@ -134,14 +133,23 @@ class ShjElevenCommand extends Command
'processed_count' => $countResults, 'processed_count' => $countResults,
'created_zones' => $processResult['created_zones'], 'created_zones' => $processResult['created_zones'],
'updated_zones' => $processResult['updated_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; return self::SUCCESS;
} else { } else {
$this->error('SHJ-11 現在契約台数集計でエラーが発生しました: ' . $processResult['message']); $this->error('SHJ-11 現在契約台数集計でエラーが発生しました: ' . $processResult['message']);
// エラー時のバッチログ作成
$this->shjElevenService->createBatchLog(
'error',
$processResult['parameters'] ?? [],
$processResult['message'],
$countResults,
$processResult['created_zones'] ?? 0,
1
);
Log::error('SHJ-11 現在契約台数集計エラー', [ Log::error('SHJ-11 現在契約台数集計エラー', [
'error' => $processResult['message'], 'error' => $processResult['message'],
'details' => $processResult['details'] ?? null 'details' => $processResult['details'] ?? null
@ -153,6 +161,16 @@ class ShjElevenCommand extends Command
} catch (\Exception $e) { } catch (\Exception $e) {
$this->error('SHJ-11 現在契約台数集計で予期しないエラーが発生しました: ' . $e->getMessage()); $this->error('SHJ-11 現在契約台数集計で予期しないエラーが発生しました: ' . $e->getMessage());
// 例外時のバッチログ作成
$this->shjElevenService->createBatchLog(
'error',
[],
'システムエラー: ' . $e->getMessage(),
0,
0,
1
);
Log::error('SHJ-11 現在契約台数集計例外エラー', [ Log::error('SHJ-11 現在契約台数集計例外エラー', [
'exception' => $e->getMessage(), 'exception' => $e->getMessage(),
'trace' => $e->getTraceAsString() 'trace' => $e->getTraceAsString()

View File

@ -5,6 +5,7 @@ namespace App\Console\Commands;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use App\Services\ShjFiveService; use App\Services\ShjFiveService;
use App\Models\Batch\BatchLog;
/** /**
* SHJ-5 空き待ち通知処理コマンド * SHJ-5 空き待ち通知処理コマンド
@ -65,6 +66,8 @@ class ShjFiveCommand extends Command
*/ */
public function handle() public function handle()
{ {
$batchLog = null;
try { try {
// 開始ログ出力 // 開始ログ出力
$startTime = now(); $startTime = now();
@ -74,6 +77,18 @@ class ShjFiveCommand extends Command
'start_time' => $startTime '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メイン処理実行 // SHJ-5メイン処理実行
$result = $this->shjFiveService->executeParkVacancyNotification(); $result = $this->shjFiveService->executeParkVacancyNotification();
@ -84,7 +99,34 @@ class ShjFiveCommand extends Command
// 処理結果表示 // 処理結果表示
$this->displayProcessResult($result); $this->displayProcessResult($result);
// バッチログはShjFiveServiceが自動的にSHJ-8経由で作成 // 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
]);
Log::info('SHJ-5 空き待ち通知処理完了', [ Log::info('SHJ-5 空き待ち通知処理完了', [
'end_time' => $endTime, 'end_time' => $endTime,
@ -97,7 +139,25 @@ class ShjFiveCommand extends Command
} catch (\Exception $e) { } catch (\Exception $e) {
$this->error('SHJ-5 空き待ち通知処理で予期しないエラーが発生しました: ' . $e->getMessage()); $this->error('SHJ-5 空き待ち通知処理で予期しないエラーが発生しました: ' . $e->getMessage());
// エラー時もShjFiveServiceが自動的にバッチログを作成 // 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
]);
}
Log::error('SHJ-5 空き待ち通知処理例外エラー', [ Log::error('SHJ-5 空き待ち通知処理例外エラー', [
'exception' => $e->getMessage(), 'exception' => $e->getMessage(),
@ -144,5 +204,4 @@ class ShjFiveCommand extends Command
} }
} }
} }
} }

View File

@ -4,8 +4,7 @@ namespace App\Console\Commands;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use App\Models\SettlementTransaction; use App\Models\SettlementTransaction;
use App\Models\BatJobLog; use App\Models\Batch\BatchLog;
use App\Models\Device;
use App\Jobs\ProcessSettlementJob; use App\Jobs\ProcessSettlementJob;
use App\Services\ShjFourBService; use App\Services\ShjFourBService;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
@ -78,6 +77,22 @@ class ShjFourBCheckCommand extends Command
$this->info("処理制限: {$limit}"); $this->info("処理制限: {$limit}");
$this->info("対象期間: {$hours}時間以内"); $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 { try {
// 未処理の決済トランザクション取得 // 未処理の決済トランザクション取得
$unprocessedSettlements = $this->getUnprocessedSettlements($hours, $limit); $unprocessedSettlements = $this->getUnprocessedSettlements($hours, $limit);
@ -87,8 +102,12 @@ class ShjFourBCheckCommand extends Command
if ($unprocessedSettlements->isEmpty()) { if ($unprocessedSettlements->isEmpty()) {
$this->info("処理対象なし"); $this->info("処理対象なし");
// バッチログ作成 - 処理対象なし $batch->update([
$this->createBatchLog('success', 0, 0, 'SHJ-4B チェック完了 - 処理対象なし'); 'status' => BatchLog::STATUS_SUCCESS,
'end_time' => now(),
'message' => 'SHJ-4B チェック完了 - 処理対象なし',
'success_count' => 0,
]);
return 0; return 0;
} }
@ -99,8 +118,13 @@ class ShjFourBCheckCommand extends Command
if ($isDryRun) { if ($isDryRun) {
$this->info("ドライランモードのため、実際の処理はスキップします"); $this->info("ドライランモードのため、実際の処理はスキップします");
// バッチログ作成 - ドライラン $batch->update([
$this->createBatchLog('success', 0, 0, 'SHJ-4B チェック完了 - ドライラン(' . $unprocessedSettlements->count() . '件検出)'); 'status' => BatchLog::STATUS_SUCCESS,
'end_time' => now(),
'message' => 'SHJ-4B チェック完了 - ドライラン',
'success_count' => 0,
'parameters' => json_encode(['targets' => $unprocessedSettlements->pluck('settlement_transaction_id')->toArray()]),
]);
return 0; return 0;
} }
@ -110,10 +134,14 @@ class ShjFourBCheckCommand extends Command
$this->info("処理完了: {$processed['success']}件成功, {$processed['failed']}件失敗"); $this->info("処理完了: {$processed['success']}件成功, {$processed['failed']}件失敗");
// バッチログ作成 - 処理完了 $batch->update([
$status = $processed['failed'] > 0 ? 'error' : 'success'; 'status' => $processed['failed'] > 0 ? BatchLog::STATUS_ERROR : BatchLog::STATUS_SUCCESS,
$message = "SHJ-4B チェック完了 - 成功:{$processed['success']}件, 失敗:{$processed['failed']}"; 'end_time' => now(),
$this->createBatchLog($status, $processed['success'], $processed['failed'], $message); 'message' => "SHJ-4B チェック完了 - 成功:{$processed['success']}件, 失敗:{$processed['failed']}",
'success_count' => $processed['success'],
'error_count' => $processed['failed'],
'parameters' => json_encode($processed),
]);
return $processed['failed'] > 0 ? 1 : 0; return $processed['failed'] > 0 ? 1 : 0;
@ -124,8 +152,13 @@ class ShjFourBCheckCommand extends Command
'trace' => $e->getTraceAsString(), 'trace' => $e->getTraceAsString(),
]); ]);
// バッチログ作成 - エラー $batch->update([
$this->createBatchLog('error', 0, 1, 'SHJ-4B チェック失敗: ' . $e->getMessage()); 'status' => BatchLog::STATUS_ERROR,
'end_time' => now(),
'message' => 'SHJ-4B チェック失敗: ' . $e->getMessage(),
'error_details' => $e->getTraceAsString(),
'error_count' => 1,
]);
return 1; return 1;
} }
@ -181,10 +214,10 @@ class ShjFourBCheckCommand extends Command
return true; return true;
} }
// 2. bat_job_logで処理完了記録があるかチェック // 2. batch_logで処理完了記録があるかチェック
$processedInBatch = BatJobLog::where('process_name', 'SHJ-4B') $processedInBatch = BatchLog::where('process_name', 'shj4b')
->where('status', 'success') ->where('status', BatchLog::STATUS_SUCCESS)
->where('status_comment', 'like', '%settlement_transaction_id:' . $settlement->settlement_transaction_id . '%') ->where('parameters', 'like', '%"settlement_transaction_id":' . $settlement->settlement_transaction_id . '%')
->exists(); ->exists();
if ($processedInBatch) { if ($processedInBatch) {
@ -193,8 +226,8 @@ class ShjFourBCheckCommand extends Command
// 3. 現在キューに入っているかチェック(簡易版) // 3. 現在キューに入っているかチェック(簡易版)
// 注: より正確にはRedis/DBキューの内容を確認する必要がある // 注: より正確にはRedis/DBキューの内容を確認する必要がある
$recentJobDispatched = BatJobLog::where('process_name', 'SHJ-4B') $recentJobDispatched = BatchLog::where('process_name', 'shj4b')
->where('status_comment', 'like', '%settlement_transaction_id:' . $settlement->settlement_transaction_id . '%') ->where('parameters', 'like', '%"settlement_transaction_id":' . $settlement->settlement_transaction_id . '%')
->where('created_at', '>=', Carbon::now()->subHours(1)) ->where('created_at', '>=', Carbon::now()->subHours(1))
->exists(); ->exists();
@ -281,37 +314,4 @@ class ShjFourBCheckCommand extends Command
'total' => $settlements->count(), '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
]);
}
}
} }

View File

@ -54,13 +54,11 @@ class ShjMailSendCommand extends Command
/** /**
* コンソールコマンドを実行 * コンソールコマンドを実行
* *
* SHJ-7 メール送信処理フロー: * 処理フロー:
* 【処理1】入力パラメーターをチェックする * 1. 入力パラメーターをチェックする
* 【判断1】チェック結果 * 2. メール送信テンプレート情報を取得する
* 【処理2】メール送信テンプレート情報を取得する * 3. メールを送信する
* 【判断2】取得結果 * 4. 処理結果を返却する
* 【処理3】メールを送信する
* 【処理4】処理結果を返却する
* *
* @return int * @return int
*/ */
@ -69,8 +67,8 @@ class ShjMailSendCommand extends Command
try { try {
// 開始ログ出力 // 開始ログ出力
$startTime = now(); $startTime = now();
$this->info('SHJ-7 メール送信処理を開始します。'); $this->info('SHJ メール送信処理を開始します。');
Log::info('SHJ-7 メール送信処理開始', [ Log::info('SHJ メール送信処理開始', [
'start_time' => $startTime, 'start_time' => $startTime,
'mail_address' => $this->argument('mail_address'), 'mail_address' => $this->argument('mail_address'),
'backup_mail_address' => $this->argument('backup_mail_address'), 'backup_mail_address' => $this->argument('backup_mail_address'),
@ -82,36 +80,41 @@ class ShjMailSendCommand extends Command
$backupMailAddress = $this->argument('backup_mail_address'); $backupMailAddress = $this->argument('backup_mail_address');
$mailTemplateId = $this->argument('mail_template_id'); $mailTemplateId = $this->argument('mail_template_id');
// SHJ-7 メール送信処理実行 // 【処理1】パラメータ検証
if (!$this->validateParameters($mailAddress, $backupMailAddress, $mailTemplateId)) {
$this->error('パラメータが不正です。');
return self::FAILURE;
}
// SHJメール送信処理実行
$result = $this->shjMailSendService->executeMailSend($mailAddress, $backupMailAddress, $mailTemplateId); $result = $this->shjMailSendService->executeMailSend($mailAddress, $backupMailAddress, $mailTemplateId);
// 【処理4】処理結果を返却する // 処理結果確認
if ($result['result'] === 0) { if ($result['success']) {
$endTime = now(); $endTime = now();
$this->info('SHJ-7 メール送信処理が正常に完了しました。'); $this->info('SHJ メール送信処理が正常に完了しました。');
$this->info("処理時間: {$startTime->diffInSeconds($endTime)}"); $this->info("処理時間: {$startTime->diffInSeconds($endTime)}");
Log::info('SHJ-7 メール送信処理完了', [ Log::info('SHJ メール送信処理完了', [
'end_time' => $endTime, 'end_time' => $endTime,
'duration_seconds' => $startTime->diffInSeconds($endTime), 'duration_seconds' => $startTime->diffInSeconds($endTime),
'result' => $result['result'], 'result' => $result
'error_info' => $result['error_info']
]); ]);
return self::SUCCESS; return self::SUCCESS;
} else { } else {
$this->error('SHJ-7 メール送信処理でエラーが発生しました: ' . $result['error_info']); $this->error('SHJ メール送信処理でエラーが発生しました: ' . $result['message']);
Log::error('SHJ-7 メール送信処理エラー', [ Log::error('SHJ メール送信処理エラー', [
'result' => $result['result'], 'error' => $result['message'],
'error_info' => $result['error_info'] 'details' => $result['details'] ?? null
]); ]);
return self::FAILURE; return self::FAILURE;
} }
} catch (\Exception $e) { } catch (\Exception $e) {
$this->error('SHJ-7 メール送信処理で予期しないエラーが発生しました: ' . $e->getMessage()); $this->error('SHJ メール送信処理で予期しないエラーが発生しました: ' . $e->getMessage());
Log::error('SHJ-7 メール送信処理例外エラー', [ Log::error('SHJ メール送信処理例外エラー', [
'exception' => $e->getMessage(), 'exception' => $e->getMessage(),
'trace' => $e->getTraceAsString() 'trace' => $e->getTraceAsString()
]); ]);
@ -120,4 +123,55 @@ 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;
}
} }

View File

@ -3,8 +3,8 @@
namespace App\Console\Commands; namespace App\Console\Commands;
use App\Services\ShjOneService; use App\Services\ShjOneService;
use App\Models\Batch\BatchLog;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
use Exception; use Exception;
/** /**
@ -58,13 +58,30 @@ class ShjOneCommand extends Command
$this->info("駐輪場ID: {$parkId}"); $this->info("駐輪場ID: {$parkId}");
try { try {
// バッチログ開始 - SHJ-8共通処理
$batchLog = BatchLog::createBatchLog(
'SHJ-1本人確認自動処理',
BatchLog::STATUS_START,
$parameters,
'SHJ-1処理開始: 利用者ID=' . $userId . ', 駐輪場ID=' . $parkId
);
// SHJ-1 メイン処理を実行 // SHJ-1 メイン処理を実行
$result = $this->shjOneService->execute($userId, $parkId); $result = $this->shjOneService->execute($userId, $parkId);
// 処理結果の表示 // 処理結果の表示
$this->displayResult($result); $this->displayResult($result);
// バッチログはShjOneServiceが自動的にSHJ-8経由で作成 // バッチログ完了 - 実際の処理結果に基づく
$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
]);
$this->info("=== SHJ-1 本人確認自動処理 完了 ==="); $this->info("=== SHJ-1 本人確認自動処理 完了 ===");
@ -75,14 +92,16 @@ class ShjOneCommand extends Command
} catch (Exception $e) { } catch (Exception $e) {
$this->error("SHJ-1処理中にエラーが発生しました: " . $e->getMessage()); $this->error("SHJ-1処理中にエラーが発生しました: " . $e->getMessage());
// エラー時もShjOneServiceが自動的にバッチログを作成 // エラーログ記録
if (isset($batchLog)) {
Log::error('SHJ-1処理例外エラー', [ $batchLog->update([
'user_id' => $userId, 'status' => BatchLog::STATUS_ERROR,
'park_id' => $parkId, 'end_time' => now(),
'exception' => $e->getMessage(), 'message' => $e->getMessage(),
'trace' => $e->getTraceAsString() 'error_details' => $e->getMessage(),
]); 'error_count' => 1
]);
}
return 1; return 1;
} }
@ -120,5 +139,4 @@ class ShjOneCommand extends Command
} }
} }
} }
} }

View File

@ -79,17 +79,14 @@ class ShjTwelveCommand extends Command
$this->info("取得件数: {$unpaidCount}"); $this->info("取得件数: {$unpaidCount}");
if ($unpaidCount === 0) { if ($unpaidCount === 0) {
// 未払い者なしの結果を設定する // 未払い者対象なしの結果を設定する
$this->info('未払い者なしのため処理を終了します。'); $this->info('未払い者対象なしのため処理を終了します。');
// バッチ処理ログを作成SHJ-8仕様に合わせ job_name と status_comment を追加) // バッチ処理ログを作成
$this->shjTwelveService->createBatchLog( $this->shjTwelveService->createBatchLog(
'success', 'success',
[ [],
'job_name' => 'SHJ-12未払い者アラート', '未払い者対象なし',
'status_comment' => '未払い者なし'
],
'未払い者なし',
0, 0,
0, 0,
0 0
@ -113,46 +110,25 @@ class ShjTwelveCommand extends Command
$this->info('SHJ-12 未払い者通知処理が正常に完了しました。'); $this->info('SHJ-12 未払い者通知処理が正常に完了しました。');
$this->info("処理時間: {$startTime->diffInSeconds($endTime)}"); $this->info("処理時間: {$startTime->diffInSeconds($endTime)}");
$this->info("処理対象件数: {$unpaidCount}"); $this->info("処理対象件数: {$unpaidCount}");
$this->info("メール送信成功: {$processResult['mail_success_count']}"); $this->info("通知送信件数: {$processResult['notification_count']}");
$this->info("メール送信失敗: {$processResult['mail_error_count']}"); $this->info("オペレーターキュー追加件数: {$processResult['queue_count']}");
$this->info("キュー登録成功: {$processResult['queue_success_count']}");
$this->info("キュー登録失敗: {$processResult['queue_error_count']}");
// 【処理3】バッチ処理ログを作成する // 【処理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( $this->shjTwelveService->createBatchLog(
'success', 'success',
$batchLogParameters, $processResult['parameters'],
$finalMessage, '未払い者通知処理完了',
$unpaidCount, $unpaidCount,
$totalSuccessCount, $processResult['notification_count'] + $processResult['queue_count'],
$totalErrorCount 0
); );
Log::info('SHJ-12 未払い者通知処理完了', [ Log::info('SHJ-12 未払い者通知処理完了', [
'end_time' => $endTime, 'end_time' => $endTime,
'duration_seconds' => $startTime->diffInSeconds($endTime), 'duration_seconds' => $startTime->diffInSeconds($endTime),
'processed_count' => $unpaidCount, 'processed_count' => $unpaidCount,
'mail_success_count' => $processResult['mail_success_count'], 'notification_count' => $processResult['notification_count'],
'mail_error_count' => $processResult['mail_error_count'], 'queue_count' => $processResult['queue_count']
'queue_success_count' => $processResult['queue_success_count'],
'queue_error_count' => $processResult['queue_error_count']
]); ]);
return self::SUCCESS; return self::SUCCESS;
@ -160,26 +136,13 @@ class ShjTwelveCommand extends Command
$this->error('SHJ-12 未払い者通知処理でエラーが発生しました: ' . $processResult['message']); $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( $this->shjTwelveService->createBatchLog(
'error', 'error',
$batchLogParameters, $processResult['parameters'] ?? [],
$finalMessage, $processResult['message'],
$unpaidCount, $unpaidCount,
($processResult['mail_success_count'] ?? 0) + ($processResult['queue_success_count'] ?? 0), $processResult['notification_count'] ?? 0,
($processResult['mail_error_count'] ?? 0) + ($processResult['queue_error_count'] ?? 0) 1
); );
Log::error('SHJ-12 未払い者通知処理エラー', [ Log::error('SHJ-12 未払い者通知処理エラー', [
@ -193,13 +156,10 @@ class ShjTwelveCommand extends Command
} catch (\Exception $e) { } catch (\Exception $e) {
$this->error('SHJ-12 未払い者通知処理で予期しないエラーが発生しました: ' . $e->getMessage()); $this->error('SHJ-12 未払い者通知処理で予期しないエラーが発生しました: ' . $e->getMessage());
// 例外時のバッチログ作成SHJ-8仕様に合わせ job_name と status_comment を追加) // 例外時のバッチログ作成
$this->shjTwelveService->createBatchLog( $this->shjTwelveService->createBatchLog(
'error', 'error',
[ [],
'job_name' => 'SHJ-12未払い者アラート',
'status_comment' => 'システムエラー'
],
'システムエラー: ' . $e->getMessage(), 'システムエラー: ' . $e->getMessage(),
0, 0,
0, 0,

View File

@ -1,146 +0,0 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
use App\Services\ShjMailSendService;
/**
* メール送信テストコマンド
*
* SHJ-7メール送信機能をテストするための便利なコマンド
* 開発・検証環境で使用することを想定
*/
class TestMailCommand extends Command
{
/**
* コンソールコマンドの名前とシグネチャ
*
* @var string
*/
protected $signature = 'test:mail
{email? : 送信先メールアドレス(省略時: wyf_0506@hotmail.com}
{--template=205 : テンプレートIDデフォルト: 205=SHJ-4B用}
{--backup= : 予備メールアドレス}';
/**
* コンソールコマンドの説明
*
* @var string
*/
protected $description = 'SHJ-7メール送信機能のテストコマンド - 指定したメールアドレスにテストメールを送信';
/**
* SHJメール送信サービス
*
* @var ShjMailSendService
*/
protected $mailSendService;
/**
* コンストラクタ
*
* @param ShjMailSendService $mailSendService
*/
public function __construct(ShjMailSendService $mailSendService)
{
parent::__construct();
$this->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;
}
}
}

View File

@ -8,6 +8,8 @@ use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use App\Models\Batch\BatchLog;
use App\Models\SettlementTransaction;
use App\Services\ShjFourBService; use App\Services\ShjFourBService;
/** /**
@ -77,6 +79,18 @@ class ProcessSettlementJob implements ShouldQueue
{ {
$startTime = now(); $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 { try {
Log::info('SHJ-4B ProcessSettlementJob開始', [ Log::info('SHJ-4B ProcessSettlementJob開始', [
'settlement_transaction_id' => $this->settlementTransactionId, 'settlement_transaction_id' => $this->settlementTransactionId,
@ -85,15 +99,24 @@ class ProcessSettlementJob implements ShouldQueue
]); ]);
// SHJ-4Bサービスを使用して決済トランザクション処理を実行 // SHJ-4Bサービスを使用して決済トランザクション処理を実行
// バッチログはShjFourBServiceが自動的にSHJ-8経由で作成
$shjFourBService = app(ShjFourBService::class); $shjFourBService = app(ShjFourBService::class);
$result = $shjFourBService->processSettlementTransaction( $result = $shjFourBService->processSettlementTransaction(
$this->settlementTransactionId, $this->settlementTransactionId,
$this->context $this->context
); );
// 処理結果のログ記録 // 処理結果に基づいてバッチログを更新
if ($result['success']) { 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完了', [ Log::info('SHJ-4B ProcessSettlementJob完了', [
'settlement_transaction_id' => $this->settlementTransactionId, 'settlement_transaction_id' => $this->settlementTransactionId,
'execution_time' => now()->diffInSeconds($startTime), 'execution_time' => now()->diffInSeconds($startTime),
@ -101,6 +124,17 @@ class ProcessSettlementJob implements ShouldQueue
]); ]);
} else { } 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要手動対応', [ Log::warning('SHJ-4B ProcessSettlementJob要手動対応', [
'settlement_transaction_id' => $this->settlementTransactionId, 'settlement_transaction_id' => $this->settlementTransactionId,
'result' => $result, 'result' => $result,
@ -114,7 +148,15 @@ class ProcessSettlementJob implements ShouldQueue
'trace' => $e->getTraceAsString(), 'trace' => $e->getTraceAsString(),
]); ]);
// エラー時もShjFourBServiceが自動的にバッチログを作成 // バッチログのエラー記録
$batch->update([
'status' => BatchLog::STATUS_ERROR,
'end_time' => now(),
'message' => 'SHJ-4B ProcessSettlementJob failed: ' . $e->getMessage(),
'error_details' => $e->getTraceAsString(),
'error_count' => 1,
]);
// ジョブを失敗させて再試行を促す // ジョブを失敗させて再試行を促す
throw $e; throw $e;
} }
@ -135,7 +177,6 @@ class ProcessSettlementJob implements ShouldQueue
'attempts' => $this->attempts(), 'attempts' => $this->attempts(),
]); ]);
// バッチログはShjFourBServiceが既に作成済み
// 最終失敗時の追加処理があればここに記述 // 最終失敗時の追加処理があればここに記述
// 例:管理者への通知、障害キューへの登録など // 例:管理者への通知、障害キューへの登録など
} }

View File

@ -1,70 +0,0 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
/**
* バッチジョブログモデル - bat_job_logテーブル
*
* SHJ-8で使用する旧バッチログテーブル
* 各バッチ処理の実行ログを記録する
*/
class BatJobLog extends Model
{
/**
* テーブル名
*
* @var string
*/
protected $table = 'bat_job_log';
/**
* プライマリキー
*
* @var string
*/
protected $primaryKey = 'job_log_id';
/**
* 一括代入可能な属性
*
* @var array
*/
protected $fillable = [
'device_id', // デバイスID
'process_name', // プロセス名
'job_name', // ジョブ名
'status', // ステータス
'status_comment', // ステータスコメント
'created_at', // 登録日時
'updated_at' // 更新日時
];
/**
* キャストする属性
*
* @var array
*/
protected $casts = [
'job_log_id' => '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');
}
}

View File

@ -0,0 +1,159 @@
<?php
namespace App\Models\Batch;
use Illuminate\Database\Eloquent\Model;
use Carbon\Carbon;
/**
* 共通バッチログモデル - batch_logテーブル
*
* 全てのSHJ系バッチ処理の実行ログを管理する統一モデル
*/
class BatchLog extends Model
{
/**
* テーブル名
*
* @var string
*/
protected $table = 'batch_log';
/**
* プライマリキー
*
* @var string
*/
protected $primaryKey = 'id';
/**
* 一括代入可能な属性
*
* @var array
*/
protected $fillable = [
'process_name', // プロセス名
'status', // ステータス
'start_time', // 開始時刻
'end_time', // 終了時刻
'parameters', // パラメータJSON形式
'message', // メッセージ
'error_details', // エラー詳細
'execution_count', // 実行回数
'success_count', // 成功回数
'error_count', // エラー回数
'created_at', // 作成日時
'updated_at' // 更新日時
];
/**
* キャストする属性
*
* @var array
*/
protected $casts = [
'id' => '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'
);
}
}

View File

@ -1,270 +0,0 @@
<?php
namespace App\Services;
use App\Models\BatJobLog;
use App\Models\Device;
use Illuminate\Support\Facades\Log;
use Carbon\Carbon;
/**
* SHJ-8 バッチ処理ログ作成サービス
*
* 概要: 入力パラメーターの情報を元にバッチ処理ログ情報を作成する
*
* 処理フロー:
* 【処理1】入力パラメーターをチェックする
* 【判断1】チェック結果
* NG パラメーターNGの結果を設定する 【処理3】
* OK 【処理2】
* 【処理2】バッチ処理ログを登録する
* 【処理3】処理結果を返却する
*/
class ShjEightService
{
/**
* SHJ-8 メイン処理実行
*
* 修正版7項目入力status_comment追加
* @param int $deviceId デバイスID (必須)
* @param string|null $processName プロセス名
* @param string|null $jobName ジョブ名
* @param string $status ステータス
* @param string $statusComment ステータスコメント (必須, ≤255文字)
* @param string $createdDate 登録日時 (yyyy/mm/dd形式)
* @param string $updatedDate 更新日時 (yyyy/mm/dd形式)
* @return array 処理結果 ['result' => 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;
}
}

View File

@ -4,102 +4,20 @@ namespace App\Services;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use App\Models\Batch\BatchLog;
use App\Models\RegularContract; use App\Models\RegularContract;
use App\Models\Park; use App\Models\Park;
use App\Models\Psection; use App\Models\Psection;
use App\Models\Ptype; use App\Models\Ptype;
use App\Models\Setting;
use App\Models\Device;
use Carbon\Carbon; use Carbon\Carbon;
/** /**
* SHJ-11 現在契約台数集計サービス * SHJ-11 現在契約台数集計サービス
* *
* 集計単位每个の契約台数を算出し、ゾーンマスタとの管理処理を実行 * 集計単位每个の契約台数を算出し、ゾーンマスタとの管理処理を実行
* bat_job_logへの書き込みはSHJ-8を呼び出す
*/ */
class ShjElevenService 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】集計単位每个の契約台数を算出する * 【処理1】集計単位每个の契約台数を算出する
* *
@ -109,7 +27,7 @@ class ShjElevenService
* - regular_contract (T1) * - regular_contract (T1)
* - park (T2) * - park (T2)
* - psection (T4) * - psection (T4)
* - price_a/price_b (T5) ※web_master設定により動的に決定 * - price_a (T5)
* - ptype (T3) * - ptype (T3)
* *
* @return array 契約台数集計結果 * @return array 契約台数集計結果
@ -117,9 +35,6 @@ class ShjElevenService
public function calculateContractCounts(): array public function calculateContractCounts(): array
{ {
try { try {
// setting.web_master から使用するprice主表を決定
$priceTable = $this->getPriceTableName();
$query = DB::table('regular_contract as T1') $query = DB::table('regular_contract as T1')
->select([ ->select([
'T1.park_id', // 駐輪場ID 'T1.park_id', // 駐輪場ID
@ -135,8 +50,8 @@ class ShjElevenService
->join('park as T2', 'T1.park_id', '=', 'T2.park_id') ->join('park as T2', 'T1.park_id', '=', 'T2.park_id')
// psection テーブルとの JOIN // psection テーブルとの JOIN
->join('psection as T4', 'T1.psection_id', '=', 'T4.psection_id') ->join('psection as T4', 'T1.psection_id', '=', 'T4.psection_id')
// price_a/price_b テーブルとの複合条件 JOIN(動的テーブル名) // price_a テーブルとの複合条件 JOIN
->join(DB::raw($priceTable . ' as T5'), function($join) { ->join('price_a as T5', function($join) {
$join->on('T1.park_id', '=', 'T5.park_id') $join->on('T1.park_id', '=', 'T5.park_id')
->on('T1.price_parkplaceid', '=', 'T5.price_parkplaceid') ->on('T1.price_parkplaceid', '=', 'T5.price_parkplaceid')
->on('T1.psection_id', '=', 'T5.psection_id'); ->on('T1.psection_id', '=', 'T5.psection_id');
@ -144,13 +59,11 @@ class ShjElevenService
// ptype テーブルとの JOIN // ptype テーブルとの JOIN
->join('ptype as T3', 'T5.ptype_id', '=', 'T3.ptype_id') ->join('ptype as T3', 'T5.ptype_id', '=', 'T3.ptype_id')
->where([ ->where([
['T1.contract_flag', '=', 1], // 授受フラグ = 1 ['T1.contract_flag', '=', 1], // 有効契約
['T2.park_close_flag', '=', 0], // 閉設フラグ = 0 ['T2.park_close_flag', '=', 0], // 駐輪場未閉鎖
]) ])
// 契約有効期間内の条件(仕様書指定:'%y.%m.%d'形式) // 契約有効期間内の条件
->whereRaw("date_format(now(), '%y.%m.%d') BETWEEN T1.contract_periods AND T1.contract_periode") ->whereRaw("date_format(now(), '%y %m %d') BETWEEN T1.contract_periods AND T1.contract_periode")
// zone_idがNULLのレコードは除外ゾーンマスタ更新不可のため
->whereNotNull('T1.zone_id')
->groupBy([ ->groupBy([
'T1.park_id', 'T1.park_id',
'T2.park_name', 'T2.park_name',
@ -164,11 +77,9 @@ class ShjElevenService
Log::info('SHJ-11 契約台数算出完了', [ Log::info('SHJ-11 契約台数算出完了', [
'count' => $query->count(), 'count' => $query->count(),
'price_table' => $priceTable,
'sql_conditions' => [ 'sql_conditions' => [
'contract_flag' => 1, 'contract_flag' => 1,
'park_close_flag' => 0, 'park_close_flag' => 0,
'date_format' => '%y.%m.%d',
'contract_period_check' => 'BETWEEN contract_periods AND contract_periode' 'contract_period_check' => 'BETWEEN contract_periods AND contract_periode'
] ]
]); ]);
@ -187,14 +98,11 @@ class ShjElevenService
/** /**
* 【処理2・3】ゾーンマスタ管理処理 * 【処理2・3】ゾーンマスタ管理処理
* *
* 処理フロー(仕様書準拠): * 処理フロー:
* 処理1の取得レコード数分繰り返し: * 1. ゾーンマスタを取得する
* 【処理2】ゾーンマスタを取得する * 2. 取得判定 存在しない場合は新規登録
* 【判断2】取得判定 * 3. 契約台数チェック(限界台数超過判定)
* - ゾーンマスタなし INSERTトランザクション内 commit 【処理4】SHJ-8(トランザクション外) 次へ * 4. 契約台数を反映する(ゾーンマスタ更新)
* - ゾーンマスタあり 【判断3】契約台数チェック 【処理3】UPDATEトランザクション内 commit 【処理4】SHJ-8(トランザクション外) 次へ
*
* ※SHJ-8ログは各レコード処理後に確実に記録するため、トランザクション外で実行
* *
* @param array $contractCounts 契約台数集計結果 * @param array $contractCounts 契約台数集計結果
* @return array 処理結果 * @return array 処理結果
@ -204,104 +112,27 @@ class ShjElevenService
$createdZones = 0; $createdZones = 0;
$updatedZones = 0; $updatedZones = 0;
$overCapacityCount = 0; $overCapacityCount = 0;
$batchLogErrors = []; $errors = [];
$processParameters = [];
try { try {
DB::beginTransaction();
// 処理1の取得レコード数分繰り返し
foreach ($contractCounts as $contractData) { foreach ($contractCounts as $contractData) {
try { 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】ゾーンマスタを取得する // 【処理2】ゾーンマスタを取得する
$zoneData = $this->getZoneData($contractData); $zoneData = $this->getZoneData($contractData);
// 【判断2】取得判定
if (!$zoneData) { if (!$zoneData) {
// ゾーンマスタなし → INSERT // 【判断2】ゾーンマスタが存在しない場合 → 新規登録
$createResult = $this->createZoneData($contractData); $createResult = $this->createZoneData($contractData);
if ($createResult['success']) {
if (!$createResult['success']) { $createdZones++;
// 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); $isOverCapacity = $this->checkCapacityLimit($contractData, $zoneData);
if ($isOverCapacity) { if ($isOverCapacity) {
$overCapacityCount++; $overCapacityCount++;
@ -313,112 +144,57 @@ class ShjElevenService
]); ]);
} }
// 【処理3】契約台数を反映するUPDATE // 【処理3】契約台数を反映するゾーンマスタ更新
$updateResult = $this->updateZoneContractCount($contractData); $updateResult = $this->updateZoneContractCount($contractData);
if ($updateResult['success']) {
if (!$updateResult['success']) { $updatedZones++;
// 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;
} }
// UPDATEトランザクションをcommit // 処理パラメータ記録
DB::commit(); $processParameters[] = [
'park_id' => $contractData->park_id,
$updatedZones++; 'psection_id' => $contractData->psection_id,
'ptype_id' => $contractData->ptype_id,
// status_comment作成UPDATE分岐 'zone_id' => $contractData->zone_id,
$capacityAlert = $isOverCapacity ? '限界収容台数を超えています。' : ''; 'contract_count' => $contractData->cnt,
$statusComment = $this->formatStatusComment( 'is_over_capacity' => $isOverCapacity,
$contractData->park_name, 'zone_created' => !$zoneData && $createResult['success'] ?? false,
$contractData->ptype_subject, 'zone_updated' => $updateResult['success'] ?? false
$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) { } catch (\Exception $e) {
// 例外時はロールバック(アクティブなトランザクションがある場合のみ) $errors[] = [
if (DB::transactionLevel() > 0) {
DB::rollBack();
}
// 個別レコードエラーもログ記録して次へ進む
$batchLogErrors[] = [
'park_id' => $contractData->park_id ?? null, 'park_id' => $contractData->park_id ?? null,
'zone_id' => $contractData->zone_id ?? null, 'zone_id' => $contractData->zone_id ?? null,
'error' => $e->getMessage() 'error' => $e->getMessage()
]; ];
Log::warning('SHJ-11 個別レコード処理エラー', [ Log::warning('SHJ-11 個別処理エラー', [
'park_id' => $contractData->park_id ?? null, 'park_id' => $contractData->park_id ?? null,
'zone_id' => $contractData->zone_id ?? null, 'zone_id' => $contractData->zone_id ?? null,
'error' => $e->getMessage() 'error' => $e->getMessage()
]); ]);
// エラーでも次の繰り返しへ続行
continue;
} }
} }
DB::commit();
return [ return [
'success' => true, 'success' => true,
'created_zones' => $createdZones, 'created_zones' => $createdZones,
'updated_zones' => $updatedZones, 'updated_zones' => $updatedZones,
'over_capacity_count' => $overCapacityCount, 'over_capacity_count' => $overCapacityCount,
'batch_log_errors' => $batchLogErrors, 'parameters' => $processParameters,
'errors' => $errors,
'message' => '現在契約台数集計処理完了' 'message' => '現在契約台数集計処理完了'
]; ];
} catch (\Exception $e) { } catch (\Exception $e) {
// 外層エラー時のロールバック DB::rollBack();
// ※各レコード処理は独立トランザクションのため、
// ここでのrollBackは不要だが安全のため実行
if (DB::transactionLevel() > 0) {
DB::rollBack();
}
Log::error('SHJ-11 ゾーンマスタ管理処理全体エラー', [ Log::error('SHJ-11 ゾーンマスタ管理処理全体エラー', [
'error' => $e->getMessage(), 'error' => $e->getMessage(),
'created_zones' => $createdZones, 'processed_count' => count($processParameters)
'updated_zones' => $updatedZones
]); ]);
return [ return [
@ -426,7 +202,8 @@ class ShjElevenService
'created_zones' => $createdZones, 'created_zones' => $createdZones,
'updated_zones' => $updatedZones, 'updated_zones' => $updatedZones,
'over_capacity_count' => $overCapacityCount, 'over_capacity_count' => $overCapacityCount,
'batch_log_errors' => $batchLogErrors, 'parameters' => $processParameters,
'errors' => $errors,
'message' => 'ゾーンマスタ管理処理エラー: ' . $e->getMessage(), 'message' => 'ゾーンマスタ管理処理エラー: ' . $e->getMessage(),
'details' => $e->getTraceAsString() 'details' => $e->getTraceAsString()
]; ];
@ -564,7 +341,7 @@ class ShjElevenService
$updateData = [ $updateData = [
'zone_number' => $contractData->cnt, // 現在契約台数を更新 'zone_number' => $contractData->cnt, // 現在契約台数を更新
'updated_at' => now(), // 更新日時 'updated_at' => now(), // 更新日時
'ope_id' => 9999999 // 更新オペレータIDINSERT時と同様、DB型int unsignedに対応 'ope_id' => 'SHJ-11' // 更新オペレータID
]; ];
$updated = DB::table('zone') $updated = DB::table('zone')
@ -588,11 +365,6 @@ class ShjElevenService
'message' => 'ゾーンマスタ契約台数を更新しました' 'message' => 'ゾーンマスタ契約台数を更新しました'
]; ];
} else { } else {
Log::warning('SHJ-11 ゾーンマスタ更新対象なし', [
'zone_id' => $contractData->zone_id,
'park_id' => $contractData->park_id
]);
return [ return [
'success' => false, 'success' => false,
'message' => 'ゾーンマスタ更新対象が見つかりません' 'message' => 'ゾーンマスタ更新対象が見つかりません'
@ -614,176 +386,47 @@ class ShjElevenService
} }
/** /**
* status_commentを仕様書指定フォーマットで作成 * 【処理4】バッチ処理ログを作成する
* *
* フォーマット: 駐輪場名駐輪分類名車種区分名ゾーンID[台数アラート] * 統一BatchLogシステムを使用してSHJ-11の実行ログを記録
* *
* @param string $parkName 駐輪場名 * @param string $status ステータス
* @param string $ptypeSubject 駐輪分類名 * @param array $parameters パラメータ
* @param string $psectionSubject 車種区分名 * @param string $message メッセージ
* @param int $zoneId ゾーンID * @param int $executionCount 実行回数
* @param string $capacityAlert 台数アラート(「限界収容台数を超えています。」または空文字) * @param int $successCount 成功回数
* @return string フォーマット済みstatus_comment * @param int $errorCount エラー回数
* @return void
*/ */
private function formatStatusComment( public function createBatchLog(
string $parkName, string $status,
string $ptypeSubject, array $parameters,
string $psectionSubject, string $message,
int $zoneId, int $executionCount = 0,
string $capacityAlert int $successCount = 0,
): string { int $errorCount = 0
$baseComment = $parkName . '' . $ptypeSubject . '' . $psectionSubject . '' . $zoneId; ): void {
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 { try {
// SHJ-8バッチ処理ログ作成パラメータ設定 BatchLog::createBatchLog(
$deviceId = $this->getBatchDeviceId(); // deviceテーブルから有効なIDを取得 'SHJ-11',
$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, $status,
$statusComment, $parameters,
$today, $message,
$today [
'execution_count' => $executionCount,
'success_count' => $successCount,
'error_count' => $errorCount,
'process_type' => '現在契約台数集計',
'executed_at' => now()->toISOString()
]
); );
Log::info('SHJ-8バッチ処理ログ作成完了', [
'park_id' => $contractData->park_id,
'zone_id' => $contractData->zone_id
]);
return [
'success' => true,
'error_message' => null
];
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error('bat_job_log書き込みエラー', [ Log::error('SHJ-11 バッチログ作成エラー', [
'park_id' => $contractData->park_id ?? null,
'zone_id' => $contractData->zone_id ?? null,
'error' => $e->getMessage(), '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' => $status,
'status_comment' => $statusComment 'message' => $message
]); ]);
// 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()
];
} }
} }
} }

View File

@ -5,7 +5,6 @@ namespace App\Services;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use App\Models\OperatorQue; use App\Models\OperatorQue;
use App\Models\Device;
use Exception; use Exception;
/** /**
@ -16,22 +15,6 @@ use Exception;
*/ */
class ShjFiveService class ShjFiveService
{ {
/**
* ShjEightService
*
* @var ShjEightService
*/
protected $shjEightService;
/**
* コンストラクタ
*
* @param ShjEightService $shjEightService
*/
public function __construct(ShjEightService $shjEightService)
{
$this->shjEightService = $shjEightService;
}
/** /**
* SHJ-5 メイン処理を実行 * SHJ-5 メイン処理を実行
* *
@ -198,29 +181,6 @@ class ShjFiveService
$queueErrorCount ?? 0 // 実際のキュー登録失敗件数 $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 [ return [
'success' => true, 'success' => true,
'message' => 'SHJ-5 空き待ち通知処理が正常に完了しました', 'message' => 'SHJ-5 空き待ち通知処理が正常に完了しました',
@ -549,24 +509,15 @@ class ShjFiveService
$mailTemplateId $mailTemplateId
); );
// SHJ-7の結果を標準形式に変換result: 0=成功, 1=失敗)
$success = ($mailResult['result'] ?? 1) === 0;
Log::info('空き待ち通知メール送信試行完了', [ Log::info('空き待ち通知メール送信試行完了', [
'user_id' => $waitingUser->user_id, 'user_id' => $waitingUser->user_id,
'main_email' => $mainEmail, 'main_email' => $mainEmail,
'sub_email' => $subEmail, 'sub_email' => $subEmail,
'mail_template_id' => $mailTemplateId, 'mail_template_id' => $mailTemplateId,
'result' => $mailResult['result'] ?? 1, 'result_success' => $mailResult['success'] ?? false
'success' => $success
]); ]);
return [ return $mailResult;
'success' => $success,
'result' => $mailResult['result'] ?? 1,
'error' => $mailResult['error_info'] ?? null,
'message' => $success ? 'メール送信成功' : ($mailResult['error_info'] ?? 'メール送信失敗')
];
} catch (Exception $e) { } catch (Exception $e) {
Log::error('空き待ち通知メール送信エラー', [ Log::error('空き待ち通知メール送信エラー', [

View File

@ -6,12 +6,8 @@ use App\Models\SettlementTransaction;
use App\Models\RegularContract; use App\Models\RegularContract;
use App\Models\Park; use App\Models\Park;
use App\Models\PriceA; use App\Models\PriceA;
use App\Models\BatJobLog; use App\Models\Batch\BatchLog;
use App\Models\Device;
use App\Models\User;
use App\Services\ShjThirteenService; use App\Services\ShjThirteenService;
use App\Services\ShjEightService;
use App\Services\ShjMailSendService;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Carbon\Carbon; use Carbon\Carbon;
@ -38,34 +34,6 @@ class ShjFourBService
const CONTRACT_FLAG_UPDATED = 1; // 更新済 const CONTRACT_FLAG_UPDATED = 1; // 更新済
const CONTRACT_FLAG_ERROR = 2; // エラー状態 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;
}
/** /**
* 決済トランザクション処理メイン実行 * 決済トランザクション処理メイン実行
* *
@ -98,17 +66,12 @@ class ShjFourBService
if (!$contractResult['found']) { if (!$contractResult['found']) {
// 対象レコードなしの場合 // 対象レコードなしの場合
$result = $this->handleNoTargetRecord($settlement, $contractResult); return $this->handleNoTargetRecord($settlement, $contractResult);
$this->createBatchLog($settlement, null, null, true, $result['message']);
return $result;
} }
if ($contractResult['already_processed']) { if ($contractResult['already_processed']) {
// 登録済みの場合 // 登録済みの場合
$result = $this->handleAlreadyProcessed($settlement, $contractResult); return $this->handleAlreadyProcessed($settlement, $contractResult);
$contract = $contractResult['contract'];
$this->createBatchLog($settlement, $contract, null, true, $result['message']);
return $result;
} }
$contract = $contractResult['contract']; $contract = $contractResult['contract'];
@ -118,9 +81,7 @@ class ShjFourBService
if (!$statusResult['valid']) { if (!$statusResult['valid']) {
// 授受状態が異常な場合 // 授受状態が異常な場合
$result = $this->handleInvalidStatus($settlement, $contract, $statusResult); return $this->handleInvalidStatus($settlement, $contract, $statusResult);
$this->createBatchLog($settlement, $contract, null, true, $result['message']);
return $result;
} }
// 【判断2】金額チェック // 【判断2】金額チェック
@ -145,10 +106,6 @@ class ShjFourBService
Log::info('SHJ-4B 決済トランザクション処理完了', $result); Log::info('SHJ-4B 決済トランザクション処理完了', $result);
// 【処理】バッチ処理ログ作成SHJ-8呼び出し
$mailCommentSuffix = $sideEffectResult['user_mail']['batch_comment_suffix'] ?? null;
$this->createBatchLog($settlement, $contract, $amountResult, true, null, $mailCommentSuffix);
return $result; return $result;
} catch (\Throwable $e) { } catch (\Throwable $e) {
@ -159,16 +116,6 @@ class ShjFourBService
'trace' => $e->getTraceAsString(), '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; throw $e;
} }
} }
@ -337,17 +284,16 @@ class ShjFourBService
]; ];
} }
// 条件3: bat_job_logで同一決済の処理完了記録があるか // 条件3: batch_logで同一決済の処理完了記録があるか
// status_commentに決済トランザクションIDが含まれているかチェック $existingBatchLog = BatchLog::where('process_name', 'shj4b')
$existingBatchLog = BatJobLog::where('process_name', 'SHJ-4B') ->where('status', BatchLog::STATUS_SUCCESS)
->where('status', 'success') ->where('parameters', 'like', '%"settlement_transaction_id":' . $settlement->settlement_transaction_id . '%')
->where('status_comment', 'like', '%settlement_transaction_id:' . $settlement->settlement_transaction_id . '%')
->exists(); ->exists();
if ($existingBatchLog) { if ($existingBatchLog) {
return [ return [
'processed' => true, 'processed' => true,
'reason' => "bat_job_logに処理完了記録が存在", 'reason' => "batch_logに処理完了記録が存在",
]; ];
} }
@ -874,107 +820,34 @@ class ShjFourBService
} }
/** /**
* 【処理5】利用者メール送信処理 * 利用者メール送信処理
*
* SHJ-4B仕様準拠:
* 1. 利用者マスタよりメールアドレス、予備メールアドレスを取得
* 2. SHJ-7メール送信を呼び出し使用プログラムID: 205
* 3. 処理結果判定:
* - result = 0 (正常): バッチコメントに "メール正常終了件数1" を追加
* - その他: バッチコメントに "メール異常終了件数1、" + error_info を追加
* *
* @param SettlementTransaction $settlement * @param SettlementTransaction $settlement
* @param object $contract * @param object $contract
* @param array $amountResult * @param array $amountResult
* @return array 処理結果 ['success' => bool, 'mail_status' => string, 'batch_comment_suffix' => string] * @return array
*/ */
private function sendUserNotificationMail(SettlementTransaction $settlement, $contract, array $amountResult): array private function sendUserNotificationMail(SettlementTransaction $settlement, $contract, array $amountResult): array
{ {
try { // TODO: 実際のメール送信処理を実装
// 【処理5】利用者マスタよりメールアドレス、予備メールアドレスを取得する // 現在はプレースホルダー
$user = User::select('user_name', 'user_primemail', 'user_submail')
->where('user_seq', $contract->user_id)
->first();
if (!$user) { $mailType = ($amountResult['comparison'] === self::AMOUNT_MATCH) ? 'success' : 'error';
Log::error('SHJ-4B 利用者メール送信処理: 利用者情報取得失敗', [
'user_id' => $contract->user_id,
'contract_id' => $contract->contract_id,
]);
return [ Log::info('SHJ-4B 利用者メール送信処理', [
'success' => false, 'contract_id' => $contract->contract_id,
'mail_status' => 'user_not_found', 'user_id' => $contract->user_id,
'batch_comment_suffix' => 'メール異常終了件数1、利用者情報取得失敗' 'settlement_transaction_id' => $settlement->settlement_transaction_id,
]; 'mail_type' => $mailType,
} 'amount_comparison' => $amountResult['comparison'],
]);
$mailAddress = $user->user_primemail ?? ''; return [
$backupMailAddress = $user->user_submail ?? ''; 'sent' => true,
'method' => 'placeholder',
Log::info('SHJ-4B 利用者メール送信処理開始', [ 'mail_type' => $mailType,
'contract_id' => $contract->contract_id, 'message' => '利用者メール送信処理は実装予定です',
'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()
];
}
} }
/** /**
@ -1005,86 +878,4 @@ class ShjFourBService
'message' => 'オペレーターキュー登録処理は実装予定です', '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,
]);
}
}
} }

View File

@ -4,7 +4,7 @@ namespace App\Services;
use App\Models\Park; use App\Models\Park;
use App\Models\RegularContract; use App\Models\RegularContract;
use App\Models\Device; use App\Models\Batch\BatchLog;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Carbon\Carbon; use Carbon\Carbon;
@ -32,27 +32,27 @@ class ShjFourCService
protected $contractModel; protected $contractModel;
/** /**
* ShjEightService * BatchLog モデル
* *
* @var ShjEightService * @var BatchLog
*/ */
protected $shjEightService; protected $batchLogModel;
/** /**
* コンストラクタ * コンストラクタ
* *
* @param Park $parkModel * @param Park $parkModel
* @param RegularContract $contractModel * @param RegularContract $contractModel
* @param ShjEightService $shjEightService * @param BatchLog $batchLogModel
*/ */
public function __construct( public function __construct(
Park $parkModel, Park $parkModel,
RegularContract $contractModel, RegularContract $contractModel,
ShjEightService $shjEightService BatchLog $batchLogModel
) { ) {
$this->parkModel = $parkModel; $this->parkModel = $parkModel;
$this->contractModel = $contractModel; $this->contractModel = $contractModel;
$this->shjEightService = $shjEightService; $this->batchLogModel = $batchLogModel;
} }
/** /**
@ -71,11 +71,24 @@ class ShjFourCService
*/ */
public function executeRoomAllocation(int $parkId, int $ptypeId, int $psectionId): array public function executeRoomAllocation(int $parkId, int $ptypeId, int $psectionId): array
{ {
$statusComment = ''; $batchLogId = null;
$status = 'success';
try { try {
// バッチ処理開始ログ作成(実際のコマンド名を記録)
$batchLog = BatchLog::createBatchLog(
'shj4c',
BatchLog::STATUS_START,
[
'park_id' => $parkId,
'ptype_id' => $ptypeId,
'psection_id' => $psectionId
],
'SHJ-4C 室割当処理開始'
);
$batchLogId = $batchLog->id;
Log::info('SHJ-4C 室割当処理開始', [ Log::info('SHJ-4C 室割当処理開始', [
'batch_log_id' => $batchLogId,
'park_id' => $parkId, 'park_id' => $parkId,
'ptype_id' => $ptypeId, 'ptype_id' => $ptypeId,
'psection_id' => $psectionId 'psection_id' => $psectionId
@ -86,16 +99,20 @@ class ShjFourCService
if (empty($zoneInfo)) { if (empty($zoneInfo)) {
$message = '対象のゾーン情報が見つかりません'; $message = '対象のゾーン情報が見つかりません';
$status = 'error';
$statusComment = sprintf('エラー: %s (park_id:%d, ptype_id:%d, psection_id:%d)',
$message, $parkId, $ptypeId, $psectionId);
// バッチログ作成 // バッチログ更新(通用方法使用)
$this->createBatchLog($status, $statusComment); $batchLog->update([
'status' => BatchLog::STATUS_ERROR,
'end_time' => now(),
'message' => $message,
'error_details' => $message,
'error_count' => 1
]);
return [ return [
'success' => false, 'success' => false,
'message' => $message 'message' => $message,
'batch_log_id' => $batchLogId
]; ];
} }
@ -106,30 +123,35 @@ class ShjFourCService
// 割当NGの場合、対象事室番号を設定 // 割当NGの場合、対象事室番号を設定
$this->setTargetRoomNumber($allocationResult['target_room_number']); $this->setTargetRoomNumber($allocationResult['target_room_number']);
$status = 'warning'; // バッチログ更新(警告)
$statusComment = sprintf('割当NG: %s (park_id:%d, ptype_id:%d, psection_id:%d)', $batchLog->update([
$allocationResult['reason'], $parkId, $ptypeId, $psectionId); 'status' => BatchLog::STATUS_WARNING,
'end_time' => now(),
// バッチログ作成 'message' => '割当処理NG: ' . $allocationResult['reason'],
$this->createBatchLog($status, $statusComment); 'success_count' => 1 // 処理は成功したが割当NGのため
]);
return [ return [
'success' => true, 'success' => true,
'message' => '割当判定完了割当NG', 'message' => '割当判定完了割当NG',
'allocation_result' => $allocationResult 'allocation_result' => $allocationResult,
'batch_log_id' => $batchLogId
]; ];
} }
// 【処理2】割当実行割当OKの場合 // 【処理2】割当実行割当OKの場合
$executionResult = $this->executeAllocation($zoneInfo, $allocationResult); $executionResult = $this->executeAllocation($zoneInfo, $allocationResult);
$statusComment = sprintf('室割当処理完了 (park_id:%d, ptype_id:%d, psection_id:%d, zone_id:%s)', // バッチ処理完了ログ更新
$parkId, $ptypeId, $psectionId, $allocationResult['target_room_number'] ?? 'N/A'); $batchLog->update([
'status' => BatchLog::STATUS_SUCCESS,
// バッチログ作成 'end_time' => now(),
$this->createBatchLog($status, $statusComment); 'message' => 'SHJ-4C 室割当処理正常完了',
'success_count' => 1
]);
Log::info('SHJ-4C 室割当処理完了', [ Log::info('SHJ-4C 室割当処理完了', [
'batch_log_id' => $batchLogId,
'execution_result' => $executionResult 'execution_result' => $executionResult
]); ]);
@ -139,19 +161,25 @@ class ShjFourCService
'message' => 'SHJ-4C 室割当処理が正常に完了しました', 'message' => 'SHJ-4C 室割当処理が正常に完了しました',
'zone_info' => $zoneInfo, 'zone_info' => $zoneInfo,
'allocation_result' => $allocationResult, 'allocation_result' => $allocationResult,
'execution_result' => $executionResult 'execution_result' => $executionResult,
'batch_log_id' => $batchLogId
]; ];
} catch (\Exception $e) { } catch (\Exception $e) {
$errorMessage = 'SHJ-4C 室割当処理でエラーが発生: ' . $e->getMessage(); $errorMessage = 'SHJ-4C 室割当処理でエラーが発生: ' . $e->getMessage();
$status = 'error';
$statusComment = sprintf('例外エラー: %s (park_id:%d, ptype_id:%d, psection_id:%d)',
$e->getMessage(), $parkId, $ptypeId, $psectionId);
// バッチログ作成 if (isset($batchLog) && $batchLog) {
$this->createBatchLog($status, $statusComment); $batchLog->update([
'status' => BatchLog::STATUS_ERROR,
'end_time' => now(),
'message' => $errorMessage,
'error_details' => $e->getMessage(),
'error_count' => 1
]);
}
Log::error('SHJ-4C 室割当処理エラー', [ Log::error('SHJ-4C 室割当処理エラー', [
'batch_log_id' => $batchLogId,
'exception' => $e->getMessage(), 'exception' => $e->getMessage(),
'trace' => $e->getTraceAsString() 'trace' => $e->getTraceAsString()
]); ]);
@ -159,52 +187,12 @@ class ShjFourCService
return [ return [
'success' => false, 'success' => false,
'message' => $errorMessage, 'message' => $errorMessage,
'details' => $e->getMessage() 'details' => $e->getMessage(),
'batch_log_id' => $batchLogId
]; ];
} }
} }
/**
* 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】ゾーン情報取得 * 【処理1】ゾーン情報取得
* *

View File

@ -3,6 +3,7 @@
namespace App\Services; namespace App\Services;
use App\Models\MailTemplate; use App\Models\MailTemplate;
use App\Models\Batch\BatchLog;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Carbon\Carbon; use Carbon\Carbon;
@ -22,23 +23,32 @@ class ShjMailSendService
*/ */
protected $mailTemplateModel; protected $mailTemplateModel;
/**
* BatchLog モデル
*
* @var BatchLog
*/
protected $batchLogModel;
/** /**
* コンストラクタ * コンストラクタ
* *
* @param MailTemplate $mailTemplateModel * @param MailTemplate $mailTemplateModel
* @param BatchLog $batchLogModel
*/ */
public function __construct( public function __construct(
MailTemplate $mailTemplateModel MailTemplate $mailTemplateModel,
BatchLog $batchLogModel
) { ) {
$this->mailTemplateModel = $mailTemplateModel; $this->mailTemplateModel = $mailTemplateModel;
$this->batchLogModel = $batchLogModel;
} }
/** /**
* SHJ-7 メール送信処理メイン実行 * SHJ メール送信処理メイン実行
* *
* 処理フロー: * 処理フロー:
* 【処理1】入力パラメーターをチェックする * 【処理1】入力パラメーターをチェックする
* 【判断1】チェック結果
* 【処理2】メール送信テンプレート情報を取得する * 【処理2】メール送信テンプレート情報を取得する
* 【判断2】取得結果判定 * 【判断2】取得結果判定
* 【処理3】メールを送信する * 【処理3】メールを送信する
@ -46,13 +56,29 @@ class ShjMailSendService
* *
* @param string $mailAddress メールアドレス * @param string $mailAddress メールアドレス
* @param string $backupMailAddress 予備メールアドレス * @param string $backupMailAddress 予備メールアドレス
* @param int $mailTemplateId メールテンプレートID使用プログラムID * @param int $mailTemplateId メールテンプレートID
* @return array 処理結果 ['result' => 0|1, 'error_info' => string] * @return array 処理結果
*/ */
public function executeMailSend(string $mailAddress, string $backupMailAddress, int $mailTemplateId): array public function executeMailSend(string $mailAddress, string $backupMailAddress, int $mailTemplateId): array
{ {
$batchLogId = null;
try { try {
Log::info('SHJ-7 メール送信処理開始', [ // バッチ処理開始ログ作成(実際のコマンド名を記録)
$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,
'mail_address' => $mailAddress, 'mail_address' => $mailAddress,
'backup_mail_address' => $backupMailAddress, 'backup_mail_address' => $backupMailAddress,
'mail_template_id' => $mailTemplateId 'mail_template_id' => $mailTemplateId
@ -60,19 +86,14 @@ class ShjMailSendService
// 【処理1】入力パラメーターをチェックする // 【処理1】入力パラメーターをチェックする
$paramCheckResult = $this->checkInputParameters($mailAddress, $backupMailAddress, $mailTemplateId); $paramCheckResult = $this->checkInputParameters($mailAddress, $backupMailAddress, $mailTemplateId);
// 【判断1】チェック結果
if (!$paramCheckResult['valid']) { if (!$paramCheckResult['valid']) {
$errorInfo = $paramCheckResult['error_info']; $this->updateBatchLog($batchLogId, 'error', $paramCheckResult['message']);
Log::warning('SHJ-7 パラメーターチェックNG', [
'error_info' => $errorInfo
]);
// 【処理4】処理結果を返却する異常終了
return [ return [
'result' => 1, 'success' => false,
'error_info' => $errorInfo 'result_code' => 1, // 異常終了
'message' => $paramCheckResult['message'],
'batch_log_id' => $batchLogId
]; ];
} }
@ -81,18 +102,14 @@ class ShjMailSendService
// 【判断2】取得結果判定 // 【判断2】取得結果判定
if (empty($templateInfo)) { if (empty($templateInfo)) {
// 0件の場合取得NGの結果を設定する $message = "メールテンプレートが存在しません。テンプレートID: {$mailTemplateId}";
$errorInfo = "メール送信NGメール送信テンプレートが存在しません。/{$mailTemplateId}"; $this->updateBatchLog($batchLogId, 'error', $message);
Log::warning('SHJ-7 メールテンプレート取得NG', [
'mail_template_id' => $mailTemplateId,
'error_info' => $errorInfo
]);
// 【処理4】処理結果を返却する異常終了
return [ return [
'result' => 1, 'success' => false,
'error_info' => $errorInfo 'result_code' => 1, // 異常終了
'message' => $message,
'batch_log_id' => $batchLogId
]; ];
} }
@ -100,41 +117,52 @@ class ShjMailSendService
$mailSendResult = $this->sendMail($mailAddress, $backupMailAddress, $templateInfo); $mailSendResult = $this->sendMail($mailAddress, $backupMailAddress, $templateInfo);
if (!$mailSendResult['success']) { if (!$mailSendResult['success']) {
$errorInfo = $mailSendResult['error_info']; $this->updateBatchLog($batchLogId, 'error', $mailSendResult['message']);
Log::error('SHJ-7 メール送信失敗', [
'error_info' => $errorInfo
]);
// 【処理4】処理結果を返却する異常終了
return [ return [
'result' => 1, 'success' => false,
'error_info' => $errorInfo 'result_code' => 1, // 異常終了
'message' => $mailSendResult['message'],
'batch_log_id' => $batchLogId
]; ];
} }
Log::info('SHJ-7 メール送信処理完了', [ // バッチ処理完了ログ更新
'to_address' => $mailSendResult['to_address'] $this->updateBatchLog($batchLogId, 'success', 'SHJ メール送信処理正常完了');
Log::info('SHJ メール送信処理完了', [
'batch_log_id' => $batchLogId,
'mail_send_result' => $mailSendResult
]); ]);
// 【処理4】処理結果を返却する正常終了 // 【処理4】処理結果を返却する
return [ return [
'result' => 0, 'success' => true,
'error_info' => '' 'result_code' => 0, // 正常終了
'message' => 'SHJ メール送信処理が正常に完了しました',
'mail_send_result' => $mailSendResult,
'batch_log_id' => $batchLogId
]; ];
} catch (\Exception $e) { } catch (\Exception $e) {
$errorInfo = 'メール送信NG' . $e->getMessage(); $errorMessage = 'SHJ メール送信処理でエラーが発生: ' . $e->getMessage();
Log::error('SHJ-7 メール送信処理例外エラー', [ if ($batchLogId) {
$this->updateBatchLog($batchLogId, 'error', $errorMessage);
}
Log::error('SHJ メール送信処理エラー', [
'batch_log_id' => $batchLogId,
'exception' => $e->getMessage(), 'exception' => $e->getMessage(),
'trace' => $e->getTraceAsString() 'trace' => $e->getTraceAsString()
]); ]);
// 【処理4】処理結果を返却する異常終了
return [ return [
'result' => 1, 'success' => false,
'error_info' => $errorInfo 'result_code' => 1, // 異常終了
'message' => $errorMessage,
'details' => $e->getMessage(),
'batch_log_id' => $batchLogId
]; ];
} }
} }
@ -142,67 +170,50 @@ class ShjMailSendService
/** /**
* 【処理1】入力パラメーターをチェックする * 【処理1】入力パラメーターをチェックする
* *
* SHJ-7仕様書に基づくチェック内容: * 仕様書に基づく詳細チェック:
* 1. メールアドレス: 「メールアドレス」「予備メールアドレス」いずれか必須 * - メールアドレス形式チェック
* 2. 予備メールアドレス: 「メールアドレス」「予備メールアドレス」いずれか必須 * - テンプレートID存在性チェック
* 3. 使用プログラムID: 必須
*
* エラーメッセージ形式: "パラメーターNG: 項目名/入力値"
* 複数エラーの場合は全角カンマ(、)で連結
* *
* @param string $mailAddress メールアドレス * @param string $mailAddress メールアドレス
* @param string $backupMailAddress 予備メールアドレス * @param string $backupMailAddress 予備メールアドレス
* @param int $mailTemplateId メールテンプレートID使用プログラムID * @param int $mailTemplateId メールテンプレートID
* @return array チェック結果 ['valid' => bool, 'error_info' => string] * @return array チェック結果
*/ */
private function checkInputParameters(string $mailAddress, string $backupMailAddress, int $mailTemplateId): array private function checkInputParameters(string $mailAddress, string $backupMailAddress, int $mailTemplateId): array
{ {
$errors = [];
try { try {
// 1. メールアドレスと予備メールアドレスのいずれか必須チェック // メールアドレス存在チェック(いずれか必須)
// 両方とも空の場合は、それぞれ別エラーとして追加
if (empty($mailAddress) && empty($backupMailAddress)) { 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 [ return [
'valid' => false, 'valid' => false,
'error_info' => $errorInfo 'message' => 'パラメーターNG: メールアドレスまたは予備メールアドレスのいずれかは必須です'
]; ];
} }
// 正常終了 // メールアドレス形式チェック
Log::info('SHJ-7 入力パラメーターチェックOK', [ 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('入力パラメーターチェック完了', [
'mail_address' => $mailAddress, 'mail_address' => $mailAddress,
'backup_mail_address' => $backupMailAddress, 'backup_mail_address' => $backupMailAddress,
'mail_template_id' => $mailTemplateId 'mail_template_id' => $mailTemplateId
@ -210,20 +221,17 @@ class ShjMailSendService
return [ return [
'valid' => true, 'valid' => true,
'error_info' => '' 'message' => 'パラメーターチェックOK'
]; ];
} catch (\Exception $e) { } catch (\Exception $e) {
$errorInfo = 'パラメーターチェック中にエラーが発生:' . $e->getMessage(); Log::error('入力パラメーターチェックエラー', [
'error' => $e->getMessage()
Log::error('SHJ-7 入力パラメーターチェック例外エラー', [
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]); ]);
return [ return [
'valid' => false, 'valid' => false,
'error_info' => $errorInfo 'message' => 'パラメーターチェック中にエラーが発生しました: ' . $e->getMessage()
]; ];
} }
} }
@ -231,45 +239,45 @@ class ShjMailSendService
/** /**
* 【処理2】メール送信テンプレート情報を取得する * 【処理2】メール送信テンプレート情報を取得する
* *
* SHJ-7仕様書に基づくSQLクエリ: * 仕様書に基づくSQLクエリ:
* SELECT エリアマネージャー同報, bccアドレス, 件名, 本文 * SELECT エリアマネージャー同報, bccアドレス, 件名, 本文
* FROM メール送信テンプレート * FROM メール送信テンプレート
* WHERE 使用プログラムID = 入力パラメーター.使用プログラムID * WHERE 使用プログラムID = 入力パラメーター使用プログラムID
* AND 使用フラグ = 1 * AND 使用フラグ = 1
* *
* @param int $mailTemplateId メールテンプレートID使用プログラムID * @param int $mailTemplateId メールテンプレートID使用プログラムIDとして扱う
* @return MailTemplate|null メールテンプレート情報 * @return MailTemplate|null メールテンプレート情報
*/ */
private function getMailTemplateInfo(int $mailTemplateId): ?MailTemplate private function getMailTemplateInfo(int $mailTemplateId): ?MailTemplate
{ {
try { try {
// SHJ-7仕様: 使用プログラムIDpg_idで検索、使用フラグ=1 // 仕様書に記載されたSQLクエリに基づくメールテンプレート情報取得
// 注意: 仕様書では「使用プログラムID」を条件にしているが、
// 入力パラメーターは「メールテンプレートID」なので、pg_idで検索
$templateInfo = $this->mailTemplateModel::where('pg_id', $mailTemplateId) $templateInfo = $this->mailTemplateModel::where('pg_id', $mailTemplateId)
->where('use_flag', 1) ->where('use_flag', 1)
->first(); ->first();
if ($templateInfo) { if ($templateInfo) {
Log::info('SHJ-7 メールテンプレート情報取得完了', [ Log::info('メールテンプレート情報取得完了', [
'mail_template_id' => $mailTemplateId, 'mail_template_id' => $mailTemplateId,
'template_found' => true, 'template_found' => true,
'subject' => $templateInfo->getSubject(), 'subject' => $templateInfo->getSubject()
'mgr_cc_flag' => $templateInfo->isManagerCcEnabled(),
'has_bcc' => !empty($templateInfo->getBccAddress())
]); ]);
} else { } else {
Log::warning('SHJ-7 メールテンプレート情報取得結果0件', [ Log::warning('メールテンプレート情報取得結果', [
'mail_template_id' => $mailTemplateId, 'mail_template_id' => $mailTemplateId,
'template_found' => false 'template_found' => false,
'message' => 'テンプレートが見つかりません'
]); ]);
} }
return $templateInfo; return $templateInfo;
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error('SHJ-7 メールテンプレート情報取得エラー', [ Log::error('メールテンプレート情報取得エラー', [
'mail_template_id' => $mailTemplateId, 'mail_template_id' => $mailTemplateId,
'error' => $e->getMessage(), 'error' => $e->getMessage()
'trace' => $e->getTraceAsString()
]); ]);
throw $e; throw $e;
@ -279,18 +287,16 @@ class ShjMailSendService
/** /**
* 【処理3】メールを送信する * 【処理3】メールを送信する
* *
* SHJ-7仕様書に基づくmb_send_mail関数使用: * 仕様書に基づくmb_send_mail関数使用:
* - 送信先: 入力パラメーター.メールアドレス(空なら予備メールアドレス) * - 送信者: 処理2で取得したメールアドレス処理1で予備メールアドレス
* - タイトル: 処理2.件名 * - タイトル: 処理2で取得したタイトル
* - 本文: 処理2.本文 * - 本文: 処理2で取得した本文※現在の文字列は「So-Manager一般的なWebサイト内部処理」参照
* - 追加ヘッダ: 処理2.bccアドレス※値が設定されている場合のみ * - 追加ヘッダ: 処理2で取得したbccアドレス※値が設定されている場合のみ
*
* ※待ち時間: 仕様では「一定の待ち時間を設ける」とあるが、現時点では実装しない0秒
* *
* @param string $mailAddress メールアドレス * @param string $mailAddress メールアドレス
* @param string $backupMailAddress 予備メールアドレス * @param string $backupMailAddress 予備メールアドレス
* @param MailTemplate $templateInfo テンプレート情報 * @param MailTemplate $templateInfo テンプレート情報
* @return array 送信結果 ['success' => bool, 'error_info' => string, 'to_address' => string] * @return array 送信結果
*/ */
private function sendMail(string $mailAddress, string $backupMailAddress, MailTemplate $templateInfo): array private function sendMail(string $mailAddress, string $backupMailAddress, MailTemplate $templateInfo): array
{ {
@ -298,64 +304,64 @@ class ShjMailSendService
// 送信先アドレス決定(優先: メールアドレス、代替: 予備メールアドレス) // 送信先アドレス決定(優先: メールアドレス、代替: 予備メールアドレス)
$toAddress = !empty($mailAddress) ? $mailAddress : $backupMailAddress; $toAddress = !empty($mailAddress) ? $mailAddress : $backupMailAddress;
// 処理2で取得したメール内容取得 // メール内容取得
$subject = $templateInfo->getSubject() ?? ''; $subject = $templateInfo->getSubject() ?? '';
$message = $templateInfo->getText() ?? ''; $message = $templateInfo->getText() ?? '';
// 追加ヘッダ設定BCC、From等 // 追加ヘッダ設定
$headers = $this->buildMailHeaders($templateInfo); $headers = $this->buildMailHeaders($templateInfo);
Log::info('SHJ-7 メール送信準備完了', [ Log::info('メール送信準備完了', [
'to_address' => $toAddress, 'to_address' => $toAddress,
'subject' => $subject, 'subject' => $subject,
'has_bcc' => !empty($templateInfo->getBccAddress()), 'has_bcc' => !empty($templateInfo->getBccAddress()),
'mgr_cc_flag' => $templateInfo->isManagerCcEnabled() 'manager_cc_enabled' => $templateInfo->isManagerCcEnabled()
]); ]);
// mb_send_mail関数を使用してメール送信 // mb_send_mail関数を使用してメール送信
$sendResult = mb_send_mail( $sendResult = mb_send_mail(
$toAddress, // 送信先 $toAddress, // 送信先
$subject, // 件名(タイトル) $subject, // 件名
$message, // 本文 $message, // 本文
$headers // 追加ヘッダ $headers // 追加ヘッダ
); );
if ($sendResult) { if ($sendResult) {
Log::info('SHJ-7 メール送信成功', [ Log::info('メール送信成功', [
'to_address' => $toAddress, 'to_address' => $toAddress,
'subject' => $subject 'subject' => $subject
]); ]);
return [ return [
'success' => true, 'success' => true,
'error_info' => '', 'message' => 'メール送信が正常に完了しました',
'to_address' => $toAddress 'to_address' => $toAddress,
'subject' => $subject
]; ];
} else { } else {
// mb_send_mail がfalseを返した場合 $errorMessage = 'mb_send_mail関数でメール送信に失敗しました';
$errorInfo = 'メール送信NGmb_send_mail関数がfalseを返しました'; Log::error('メール送信失敗', [
Log::error('SHJ-7 メール送信失敗', [
'to_address' => $toAddress, 'to_address' => $toAddress,
'subject' => $subject, 'subject' => $subject,
'error_info' => $errorInfo 'error' => $errorMessage
]); ]);
return [ return [
'success' => false, 'success' => false,
'error_info' => $errorInfo 'message' => $errorMessage
]; ];
} }
} catch (\Exception $e) { } catch (\Exception $e) {
$errorInfo = 'メール送信NG' . $e->getMessage(); $errorMessage = 'メール送信中にエラーが発生: ' . $e->getMessage();
Log::error('SHJ-7 メール送信例外エラー', [ Log::error('メール送信エラー', [
'error' => $e->getMessage(), 'error' => $e->getMessage(),
'trace' => $e->getTraceAsString() 'trace' => $e->getTraceAsString()
]); ]);
return [ return [
'success' => false, 'success' => false,
'error_info' => $errorInfo 'message' => $errorMessage
]; ];
} }
} }
@ -363,10 +369,9 @@ class ShjMailSendService
/** /**
* メールヘッダを構築 * メールヘッダを構築
* *
* SHJ-7仕様書に基づく追加ヘッダ設定: * 仕様書に基づく設定:
* - 追加ヘッダ: 処理2.bccアドレス※値が設定されている場合のみ * - BCCアドレス: 値が設定されている場合のみ追加
* - From: システム設定から取得 * - エリアマネージャー同報: フラグが有効な場合の処理
* - エリアマネージャー同報: フラグが有効な場合はログ出力のみ(実装保留)
* *
* @param MailTemplate $templateInfo テンプレート情報 * @param MailTemplate $templateInfo テンプレート情報
* @return string メールヘッダ * @return string メールヘッダ
@ -375,19 +380,19 @@ class ShjMailSendService
{ {
$headers = []; $headers = [];
// BCCアドレス設定値が設定されている場合のみ追加 // BCCアドレス設定値が設定されている場合のみ
$bccAddress = $templateInfo->getBccAddress(); $bccAddress = $templateInfo->getBccAddress();
if (!empty($bccAddress)) { if (!empty($bccAddress)) {
$headers[] = "Bcc: {$bccAddress}"; $headers[] = "Bcc: {$bccAddress}";
} }
// エリアマネージャー同報フラグが有効な場合 // エリアマネージャー同報フラグが有効な場合
// ※SHJ-7では実装しない仕様詳細不明。ログ出力のみ。 // ※具体的な処理内容は仕様書に詳細がないため、ログ出力のみ
if ($templateInfo->isManagerCcEnabled()) { if ($templateInfo->isManagerCcEnabled()) {
Log::info('SHJ-7 エリアマネージャー同報フラグが有効', [ Log::info('エリアマネージャー同報フラグが有効です', [
'mail_template_id' => $templateInfo->mail_template_id 'mail_template_id' => $templateInfo->mail_template_id
]); ]);
// 実際のエリアマネージャーアドレス取得・設定処理は将来実装 // 実際のエリアマネージャーアドレス取得・設定処理は追加仕様が必要
} }
// From設定システム設定から取得 // From設定システム設定から取得
@ -400,6 +405,41 @@ class ShjMailSendService
return implode("\r\n", $headers); 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 未払い者通知メール送信 * SHJ-12 未払い者通知メール送信

View File

@ -5,8 +5,8 @@ namespace App\Services;
use App\Models\Park; use App\Models\Park;
use App\Models\EarningsSummary; use App\Models\EarningsSummary;
use App\Models\Psection; use App\Models\Psection;
use App\Models\Batch\BatchLog;
use App\Models\OperatorQue; use App\Models\OperatorQue;
use App\Models\Device;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Carbon\Carbon; use Carbon\Carbon;
@ -29,21 +29,11 @@ class ShjNineService
*/ */
const SUMMARY_TYPE_DAILY = 3; const SUMMARY_TYPE_DAILY = 3;
/**
* ShjEightService インスタンス
*
* @var ShjEightService
*/
protected $shjEightService;
/** /**
* コンストラクタ * コンストラクタ
*
* @param ShjEightService $shjEightService
*/ */
public function __construct(ShjEightService $shjEightService) public function __construct()
{ {
$this->shjEightService = $shjEightService;
} }
/** /**
@ -64,6 +54,8 @@ class ShjNineService
*/ */
public function executeEarningsAggregation(string $type, string $aggregationDate): array public function executeEarningsAggregation(string $type, string $aggregationDate): array
{ {
$batchLogId = null;
$batchLog = null;
$statusComments = []; // 内部変数.ステータスコメント $statusComments = []; // 内部変数.ステータスコメント
$dataIntegrityIssues = []; // 内部変数.情報不備 $dataIntegrityIssues = []; // 内部変数.情報不備
@ -74,21 +66,44 @@ class ShjNineService
// 日付形式エラー時は【処理】へwarning扱い // 日付形式エラー時は【処理】へwarning扱い
$statusComment = "売上集計(日次):パラメーターが不正です。(日付形式ではありません)"; $statusComment = "売上集計(日次):パラメーターが不正です。(日付形式ではありません)";
$batchLog = BatchLog::createBatchLog(
'shj9',
BatchLog::STATUS_WARNING,
['type' => $type, 'aggregation_date' => $aggregationDate],
$statusComment
);
$batchLogId = $batchLog->id;
// 【処理5】オペレータキュー作成 // 【処理5】オペレータキュー作成
$this->createOperatorQueue($statusComment, null); $this->createOperatorQueue($statusComment, $batchLogId);
// SHJ-8 バッチ処理ログ作成 // SHJ-8 バッチ処理ログ作成
$this->callShjEight('SHJ-9売上集計日次', 'success', $statusComment); $this->createShjBatchLog([
'job_name' => 'SHJ-9売上集計日次',
'status' => 'success',
'status_comment' => $statusComment
]);
return [ return [
'success' => true, // 仕様上はwarningで成功扱い 'success' => true, // 仕様上はwarningで成功扱い
'message' => $statusComment 'message' => $statusComment,
'batch_log_id' => $batchLogId
]; ];
} }
$targetDate = Carbon::parse($aggregationDate)->format('Y-m-d'); $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 売上集計処理開始', [ Log::info('SHJ-9 売上集計処理開始', [
'batch_log_id' => $batchLogId,
'type' => $type, 'type' => $type,
'target_date' => $targetDate 'target_date' => $targetDate
]); ]);
@ -101,17 +116,30 @@ class ShjNineService
$statusComment = '売上集計(日次):駐輪場マスタが存在していません。'; $statusComment = '売上集計(日次):駐輪場マスタが存在していません。';
$statusComments[] = $statusComment; $statusComments[] = $statusComment;
// バッチログ更新
$batchLog->update([
'status' => BatchLog::STATUS_WARNING,
'end_time' => now(),
'message' => $statusComment,
'success_count' => 1
]);
// 【処理5】オペレータキュー作成 // 【処理5】オペレータキュー作成
$this->createOperatorQueue($statusComment, null); $this->createOperatorQueue($statusComment, $batchLogId);
// SHJ-8 バッチ処理ログ作成 // SHJ-8 バッチ処理ログ作成
$this->callShjEight('SHJ-9売上集計日次', 'success', $statusComment); $this->createShjBatchLog([
'job_name' => 'SHJ-9売上集計日次',
'status' => 'success',
'status_comment' => $statusComment
]);
return [ return [
'success' => true, 'success' => true,
'message' => $statusComment, 'message' => $statusComment,
'processed_parks' => 0, 'processed_parks' => 0,
'summary_records' => 0 'summary_records' => 0,
'batch_log_id' => $batchLogId
]; ];
} }
@ -120,9 +148,9 @@ class ShjNineService
$processedParks = 0; $processedParks = 0;
foreach ($parkInfo as $park) { foreach ($parkInfo as $park) {
$result = $this->processEarningsForPark($park, $targetDate); $result = $this->processEarningsForPark($park, $targetDate, $batchLogId);
$processedParks++; $processedParks++;
$summaryRecords += $result['summary_records']; $summaryRecords += $result['summary_records'];
// 対象データなしの場合のステータスコメント収集 // 対象データなしの場合のステータスコメント収集
@ -137,23 +165,40 @@ class ShjNineService
} }
// 最終ステータスコメント生成 // 最終ステータスコメント生成
$finalStatusComment = "売上集計(日次):対象日={$targetDate}、駐輪場数={$processedParks}、集計レコード数={$summaryRecords}"; $finalStatusComment = "SHJ-9 売上集計処理正常完了(日次)- 対象日: {$targetDate}, 駐輪場数: {$processedParks}, 集計レコード数: {$summaryRecords}";
if (!empty($dataIntegrityIssues)) { if (!empty($statusComments)) {
$finalStatusComment .= "、情報不備=" . implode('、', $dataIntegrityIssues); $finalStatusComment .= "\n" . implode("\n", $statusComments);
} }
if (!empty($dataIntegrityIssues)) {
$finalStatusComment .= "\n" . implode("\n", $dataIntegrityIssues);
}
// バッチ処理完了ログ更新
$batchLog->update([
'status' => BatchLog::STATUS_SUCCESS,
'end_time' => now(),
'message' => $finalStatusComment,
'success_count' => 1
]);
// 【処理5】オペレータキュー作成 // 【処理5】オペレータキュー作成
// ※ 駐輪場単位で既に作成済みprocessEarningsForPark内で情報不備検出時に実施 // ※ 駐輪場単位で既に作成済みprocessEarningsForPark内で情報不備検出時に実施
if (!empty($dataIntegrityIssues)) { if (!empty($dataIntegrityIssues)) {
Log::warning('SHJ-9 情報不備検出', [ Log::warning('SHJ-9 情報不備検出', [
'batch_log_id' => $batchLogId,
'issues' => $dataIntegrityIssues 'issues' => $dataIntegrityIssues
]); ]);
} }
// SHJ-8 バッチ処理ログ作成 // SHJ-8 バッチ処理ログ作成
$this->callShjEight('SHJ-9売上集計日次', 'success', $finalStatusComment); $this->createShjBatchLog([
'job_name' => 'SHJ-9売上集計日次',
'status' => 'success',
'status_comment' => $finalStatusComment
]);
Log::info('SHJ-9 売上集計処理完了', [ Log::info('SHJ-9 売上集計処理完了', [
'batch_log_id' => $batchLogId,
'processed_parks' => $processedParks, 'processed_parks' => $processedParks,
'summary_records' => $summaryRecords, 'summary_records' => $summaryRecords,
'data_integrity_issues' => count($dataIntegrityIssues), 'data_integrity_issues' => count($dataIntegrityIssues),
@ -165,20 +210,36 @@ class ShjNineService
'message' => 'SHJ-9 売上集計処理が正常に完了しました', 'message' => 'SHJ-9 売上集計処理が正常に完了しました',
'processed_parks' => $processedParks, 'processed_parks' => $processedParks,
'summary_records' => $summaryRecords, 'summary_records' => $summaryRecords,
'data_integrity_issues' => count($dataIntegrityIssues) 'data_integrity_issues' => count($dataIntegrityIssues),
'batch_log_id' => $batchLogId
]; ];
} catch (\Exception $e) { } catch (\Exception $e) {
$errorMessage = '売上集計(日次):エラー発生 - ' . $e->getMessage(); $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
]);
}
// SHJ-8 バッチ処理ログ作成(エラー時も作成) // SHJ-8 バッチ処理ログ作成(エラー時も作成)
try { try {
$this->callShjEight('SHJ-9売上集計日次', 'error', $errorMessage); $this->createShjBatchLog([
'job_name' => 'SHJ-9売上集計日次',
'status' => 'error',
'status_comment' => $errorMessage
]);
} catch (\Exception $shjException) { } catch (\Exception $shjException) {
Log::error('SHJ-8呼び出しエラー', ['error' => $shjException->getMessage()]); Log::error('SHJ-8呼び出しエラー', ['error' => $shjException->getMessage()]);
} }
Log::error('SHJ-9 売上集計処理エラー', [ Log::error('SHJ-9 売上集計処理エラー', [
'batch_log_id' => $batchLogId,
'exception' => $e->getMessage(), 'exception' => $e->getMessage(),
'trace' => $e->getTraceAsString() 'trace' => $e->getTraceAsString()
]); ]);
@ -186,7 +247,8 @@ class ShjNineService
return [ return [
'success' => false, 'success' => false,
'message' => $errorMessage, 'message' => $errorMessage,
'details' => $e->getMessage() 'details' => $e->getMessage(),
'batch_log_id' => $batchLogId
]; ];
} }
} }
@ -242,9 +304,10 @@ class ShjNineService
* *
* @param object $park 駐輪場情報 * @param object $park 駐輪場情報
* @param string $targetDate 集計対象日YYYY-MM-DD * @param string $targetDate 集計対象日YYYY-MM-DD
* @param int $batchLogId バッチログID
* @return array 処理結果 ['summary_records' => int, 'data_integrity_issue' => string, 'no_data_message' => string|null] * @return array 処理結果 ['summary_records' => int, 'data_integrity_issue' => string, 'no_data_message' => string|null]
*/ */
private function processEarningsForPark($park, string $targetDate): array private function processEarningsForPark($park, string $targetDate, int $batchLogId): array
{ {
try { try {
// 0. 情報不備チェック // 0. 情報不備チェック
@ -252,7 +315,7 @@ class ShjNineService
// 情報不備がある場合、駐輪場単位でオペレータキュー作成(仕様 todo/SHJ-9/SHJ-9.txt:253-263 // 情報不備がある場合、駐輪場単位でオペレータキュー作成(仕様 todo/SHJ-9/SHJ-9.txt:253-263
if ($dataIntegrityIssue !== '情報不備:なし') { if ($dataIntegrityIssue !== '情報不備:なし') {
$this->createOperatorQueue($dataIntegrityIssue, $park->park_id); $this->createOperatorQueue($dataIntegrityIssue, $batchLogId, $park->park_id);
} }
// ① 定期契約データ取得(車種区分・分類名1・定期有効月数毎) // ① 定期契約データ取得(車種区分・分類名1・定期有効月数毎)
@ -732,10 +795,11 @@ class ShjNineService
* - operator_id: 9999999(バッチ処理固定値) * - operator_id: 9999999(バッチ処理固定値)
* *
* @param string $message 情報不備メッセージ * @param string $message 情報不備メッセージ
* @param int $batchLogId バッチログID
* @param int|null $parkId 駐輪場IDパラメータエラー時はnull * @param int|null $parkId 駐輪場IDパラメータエラー時はnull
* @return void * @return void
*/ */
private function createOperatorQueue(string $message, ?int $parkId = null): void private function createOperatorQueue(string $message, int $batchLogId, ?int $parkId = null): void
{ {
try { try {
DB::table('operator_que')->insert([ DB::table('operator_que')->insert([
@ -753,6 +817,7 @@ class ShjNineService
]); ]);
Log::info('オペレータキュー作成完了', [ Log::info('オペレータキュー作成完了', [
'batch_log_id' => $batchLogId,
'park_id' => $parkId, 'park_id' => $parkId,
'que_class' => 14, 'que_class' => 14,
'que_status' => 1, 'que_status' => 1,
@ -762,6 +827,7 @@ class ShjNineService
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error('オペレータキュー作成エラー', [ Log::error('オペレータキュー作成エラー', [
'batch_log_id' => $batchLogId,
'park_id' => $parkId, 'park_id' => $parkId,
'error' => $e->getMessage() 'error' => $e->getMessage()
]); ]);
@ -774,41 +840,60 @@ class ShjNineService
* 仕様 todo/SHJ-9/SHJ-9.txt:289-300 * 仕様 todo/SHJ-9/SHJ-9.txt:289-300
* 共通処理「SHJ-8 バッチ処理ログ作成」を呼び出す * 共通処理「SHJ-8 バッチ処理ログ作成」を呼び出す
* *
* @param string $jobName ジョブ名 * @param array $statistics 処理統計情報
* @param string $status ステータス (success/error)
* @param string $statusComment 業務固有のステータスコメント
* @return void * @return void
*/ */
private function callShjEight(string $jobName, string $status, string $statusComment): void private function createShjBatchLog(array $statistics): void
{ {
try { try {
$device = Device::orderBy('device_id')->first(); // SHJ-8 パラメータ設定
$deviceId = $device ? $device->device_id : 1; $deviceId = 9999999; // バッチ処理用固定デバイスID
$processName = 'SHJ-9';
$jobName = $statistics['job_name'];
$status = $statistics['status'];
$statusComment = $statistics['status_comment'] ?? '';
$today = now()->format('Y/m/d'); $createdDate = now()->format('Y/m/d');
$updatedDate = now()->format('Y/m/d');
$this->shjEightService->execute( Log::info('SHJ-8 バッチ処理ログ作成', [
$deviceId, 'device_id' => $deviceId,
'SHJ-9', 'process_name' => $processName,
$jobName,
$status,
$statusComment,
$today,
$today
);
Log::info('SHJ-8 バッチ処理ログ作成完了', [
'job_name' => $jobName, 'job_name' => $jobName,
'status' => $status 'status' => $status,
'status_comment' => $statusComment
]); ]);
// 共通処理 SHJ-8 バッチ処理ログ作成を呼び出し
// BatchLog システムを使用してバッチ処理の実行ログを記録
BatchLog::createBatchLog(
$processName,
$status,
[
'device_id' => $deviceId,
'job_name' => $jobName,
'status_comment' => $statusComment,
'statistics' => $statistics,
'shj8_params' => [
'device_id' => $deviceId,
'process_name' => $processName,
'job_name' => $jobName,
'status' => $status,
'created_date' => $createdDate,
'updated_date' => $updatedDate
]
],
$statusComment
);
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error('SHJ-8 バッチ処理ログ作成エラー', [ Log::error('SHJ-8 バッチ処理ログ作成エラー', [
'error' => $e->getMessage(), 'error' => $e->getMessage(),
'job_name' => $jobName, 'statistics' => $statistics
'status_comment' => $statusComment
]); ]);
throw $e;
// SHJ-8でエラーが発生してもメイン処理は継続
// エラーログのみ出力
} }
} }
} }

View File

@ -7,11 +7,9 @@ use App\Models\Usertype;
use App\Models\Park; use App\Models\Park;
use App\Models\RegularContract; use App\Models\RegularContract;
use App\Models\OperatorQue; use App\Models\OperatorQue;
use App\Models\Device;
use App\Services\GoogleVisionService; use App\Services\GoogleVisionService;
use App\Services\GoogleMapsService; use App\Services\GoogleMapsService;
use App\Services\ShjMailSendService; use App\Services\ShjMailSendService;
use App\Services\ShjEightService;
use Exception; use Exception;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
@ -24,18 +22,15 @@ class ShjOneService
protected $googleVisionService; protected $googleVisionService;
protected $googleMapsService; protected $googleMapsService;
protected $mailSendService; protected $mailSendService;
protected $shjEightService;
public function __construct( public function __construct(
GoogleVisionService $googleVisionService, GoogleVisionService $googleVisionService,
GoogleMapsService $googleMapsService, GoogleMapsService $googleMapsService,
ShjMailSendService $mailSendService, ShjMailSendService $mailSendService
ShjEightService $shjEightService
) { ) {
$this->googleVisionService = $googleVisionService; $this->googleVisionService = $googleVisionService;
$this->googleMapsService = $googleMapsService; $this->googleMapsService = $googleMapsService;
$this->mailSendService = $mailSendService; $this->mailSendService = $mailSendService;
$this->shjEightService = $shjEightService;
} }
/** /**
@ -60,13 +55,11 @@ class ShjOneService
'user_id' => $userId, 'user_id' => $userId,
'park_id' => $parkId 'park_id' => $parkId
]); ]);
$result = [ return [
'system_success' => false, 'system_success' => false,
'message' => '利用者が見つかりません', 'message' => '利用者が見つかりません',
'stats' => ['error_count' => 1, 'processed_count' => 0] 'stats' => ['error_count' => 1, 'processed_count' => 0]
]; ];
$this->createBatchLog($userId, null, null, $result);
return $result;
} }
Log::info('SHJ-1 【処理1】成功: 利用者データ取得', [ Log::info('SHJ-1 【処理1】成功: 利用者データ取得', [
@ -86,13 +79,11 @@ class ShjOneService
'user_idcard_chk_flag' => $user->user_idcard_chk_flag, 'user_idcard_chk_flag' => $user->user_idcard_chk_flag,
'reason' => '免許証以外または写真なしまたは既に処理済み' 'reason' => '免許証以外または写真なしまたは既に処理済み'
]); ]);
$result = [ return [
'system_success' => false, 'system_success' => false,
'message' => '処理対象外の利用者です(免許証以外または写真なし)', 'message' => '処理対象外の利用者です(免許証以外または写真なし)',
'stats' => ['error_count' => 1, 'processed_count' => 0] 'stats' => ['error_count' => 1, 'processed_count' => 0]
]; ];
$this->createBatchLog($userId, $user->user_name, null, $result);
return $result;
} }
$park = $this->getParkRecord($parkId); $park = $this->getParkRecord($parkId);
@ -100,13 +91,11 @@ class ShjOneService
Log::error('SHJ-1 駐輪場データ取得失敗', [ Log::error('SHJ-1 駐輪場データ取得失敗', [
'park_id' => $parkId 'park_id' => $parkId
]); ]);
$result = [ return [
'system_success' => false, 'system_success' => false,
'message' => '駐輪場が見つかりません', 'message' => '駐輪場が見つかりません',
'stats' => ['error_count' => 1, 'processed_count' => 0] 'stats' => ['error_count' => 1, 'processed_count' => 0]
]; ];
$this->createBatchLog($userId, $user->user_name, null, $result);
return $result;
} }
Log::info('SHJ-1 駐輪場データ取得成功', [ Log::info('SHJ-1 駐輪場データ取得成功', [
@ -130,7 +119,6 @@ class ShjOneService
]); ]);
$result = $this->processNonTargetUser($user, $categoryCheck['category_name']); $result = $this->processNonTargetUser($user, $categoryCheck['category_name']);
DB::commit(); // 対象外処理後はコミット DB::commit(); // 対象外処理後はコミット
$this->createBatchLog($userId, $user->user_name, null, $result);
return $result; return $result;
} }
@ -145,9 +133,6 @@ class ShjOneService
DB::commit(); DB::commit();
// バッチ処理ログ作成
$this->createBatchLog($userId, $user->user_name, $identityResult['similarity_rate'] ?? null, $identityResult);
return $identityResult; return $identityResult;
} catch (Exception $e) { } catch (Exception $e) {
@ -158,16 +143,11 @@ class ShjOneService
'error' => $e->getMessage() 'error' => $e->getMessage()
]); ]);
$result = [ return [
'system_success' => false, 'system_success' => false,
'message' => 'システムエラーが発生しました: ' . $e->getMessage(), 'message' => 'システムエラーが発生しました: ' . $e->getMessage(),
'stats' => ['error_count' => 1, 'processed_count' => 0] 'stats' => ['error_count' => 1, 'processed_count' => 0]
]; ];
// エラー時もバッチログ作成
$this->createBatchLog($userId, null, null, $result);
return $result;
} }
} }
@ -823,7 +803,6 @@ class ShjOneService
'system_success' => true, 'system_success' => true,
'identity_result' => 'OK', 'identity_result' => 'OK',
'message' => '本人確認自動処理が成功しました', 'message' => '本人確認自動処理が成功しました',
'similarity_rate' => $ocrResult['similarity'] ?? 0,
'details' => [ 'details' => [
'user_id' => $user->user_seq, 'user_id' => $user->user_seq,
'park_id' => $park->park_id, 'park_id' => $park->park_id,
@ -877,7 +856,6 @@ class ShjOneService
'system_success' => true, 'system_success' => true,
'identity_result' => 'NG', 'identity_result' => 'NG',
'message' => '本人確認自動処理NGのため手動処理キューを作成しました', 'message' => '本人確認自動処理NGのため手動処理キューを作成しました',
'similarity_rate' => $ocrResult['similarity'] ?? 0,
'details' => [ 'details' => [
'user_id' => $user->user_seq, 'user_id' => $user->user_seq,
'park_id' => $park->park_id, 'park_id' => $park->park_id,
@ -936,29 +914,13 @@ class ShjOneService
private function sendSuccessEmail(User $user, Park $park): void private function sendSuccessEmail(User $user, Park $park): void
{ {
try { try {
// SHJ-7 メール送信処理 $this->mailSendService->executeMailSend(
$mailResult = $this->mailSendService->executeMailSend(
$user->user_primemail, $user->user_primemail,
$user->user_submail, $user->user_submail,
config('shj1.mail.program_id_success') 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) { } catch (Exception $e) {
Log::error('SHJ-1 成功メール送信例外エラー', [ Log::error('Success email sending failed', [
'user_id' => $user->user_seq, 'user_id' => $user->user_seq,
'error' => $e->getMessage() 'error' => $e->getMessage()
]); ]);
@ -971,29 +933,13 @@ class ShjOneService
private function sendFailureEmail(User $user, Park $park): void private function sendFailureEmail(User $user, Park $park): void
{ {
try { try {
// SHJ-7 メール送信処理 $this->mailSendService->executeMailSend(
$mailResult = $this->mailSendService->executeMailSend(
$user->user_primemail, $user->user_primemail,
$user->user_submail, $user->user_submail,
config('shj1.mail.program_id_failure') 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) { } catch (Exception $e) {
Log::error('SHJ-1 失敗メール送信例外エラー', [ Log::error('Failure email sending failed', [
'user_id' => $user->user_seq, 'user_id' => $user->user_seq,
'error' => $e->getMessage() 'error' => $e->getMessage()
]); ]);
@ -1046,57 +992,4 @@ class ShjOneService
return $analysis; 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
]);
}
}
} }

View File

@ -5,12 +5,12 @@ namespace App\Services;
use App\Models\Device; use App\Models\Device;
use App\Models\HardwareCheckLog; use App\Models\HardwareCheckLog;
use App\Models\PrintJobLog; use App\Models\PrintJobLog;
use App\Models\Batch\BatchLog;
use App\Models\OperatorQue; use App\Models\OperatorQue;
use App\Models\Ope; use App\Models\Ope;
use App\Models\Manager; use App\Models\Manager;
use App\Models\Setting; use App\Models\Setting;
use App\Models\JurisdictionParking; use App\Models\JurisdictionParking;
use App\Models\Park;
use App\Services\ShjMailSendService; use App\Services\ShjMailSendService;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
@ -31,13 +31,6 @@ class ShjSixService
*/ */
protected $mailSendService; protected $mailSendService;
/**
* ShjEightService
*
* @var ShjEightService
*/
protected $shjEightService;
/** /**
* 固定メールアドレスDB反映NG時用 * 固定メールアドレスDB反映NG時用
* *
@ -81,14 +74,10 @@ class ShjSixService
* コンストラクタ * コンストラクタ
* *
* @param ShjMailSendService $mailSendService * @param ShjMailSendService $mailSendService
* @param ShjEightService $shjEightService
*/ */
public function __construct( public function __construct(ShjMailSendService $mailSendService)
ShjMailSendService $mailSendService, {
ShjEightService $shjEightService
) {
$this->mailSendService = $mailSendService; $this->mailSendService = $mailSendService;
$this->shjEightService = $shjEightService;
} }
/** /**
@ -117,8 +106,18 @@ class ShjSixService
$accumulatedBatchComment = ''; // 累積バッチコメント $accumulatedBatchComment = ''; // 累積バッチコメント
try { try {
// バッチ処理開始ログ内部ログのみ、batch_log廃止 // バッチ処理開始ログ作成
Log::info('SHJ-6 サーバ死活監視処理開始'); $batchLog = BatchLog::createBatchLog(
'shj6',
BatchLog::STATUS_START,
[],
'SHJ-6 サーバ死活監視処理開始'
);
$batchLogId = $batchLog->id;
Log::info('SHJ-6 サーバ死活監視処理開始', [
'batch_log_id' => $batchLogId
]);
// 【処理1】サーバ死活監視DBアクセス // 【処理1】サーバ死活監視DBアクセス
$dbAccessResult = $this->checkDatabaseAccessWithSettings(); $dbAccessResult = $this->checkDatabaseAccessWithSettings();
@ -217,13 +216,15 @@ class ShjSixService
$statusComment .= ' | ' . $accumulatedBatchComment; $statusComment .= ' | ' . $accumulatedBatchComment;
} }
$status = 'success'; // 仕様書:常に"success"で記録 $status = empty($warnings) ? BatchLog::STATUS_SUCCESS : BatchLog::STATUS_WARNING;
$message = empty($warnings) ? $message = empty($warnings) ?
'SHJ-6 サーバ死活監視処理正常完了' : 'SHJ-6 サーバ死活監視処理正常完了' :
'SHJ-6 サーバ死活監視処理完了(警告あり)'; 'SHJ-6 サーバ死活監視処理完了(警告あり)';
// 仕様書準拠処理2で取得したデバイスIDを連結 // 仕様書準拠処理2で取得したデバイスIDを連結
$deviceIds = $devices->pluck('device_id')->toArray(); $deviceIds = array_map(function($device) {
return $device->device_id;
}, $devices);
$concatenatedDeviceIds = !empty($deviceIds) ? implode(',', $deviceIds) : ''; $concatenatedDeviceIds = !empty($deviceIds) ? implode(',', $deviceIds) : '';
// SHJ-8 バッチ処理ログ作成(仕様書準拠) // SHJ-8 バッチ処理ログ作成(仕様書準拠)
@ -260,7 +261,17 @@ class ShjSixService
$statusComment .= sprintf(' | SHJ-8異常: %s', $shj8Error); $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 サーバ死活監視処理完了', [ Log::info('SHJ-6 サーバ死活監視処理完了', [
'batch_log_id' => $batchLogId,
'status_comment' => $statusComment, 'status_comment' => $statusComment,
'warnings' => $warnings, 'warnings' => $warnings,
'alert_count' => $alertCount, 'alert_count' => $alertCount,
@ -268,18 +279,9 @@ class ShjSixService
'mail_error_count' => $totalMailErrorCount 'mail_error_count' => $totalMailErrorCount
]); ]);
// 監視サマリーを生成
$monitoringSummary = sprintf(
'監視デバイス数: %d, アラート: %d件, メール成功: %d件',
count($devices),
$alertCount,
$totalMailSuccessCount
);
return [ return [
'success' => true, 'success' => true,
'message' => 'SHJ-6 サーバ死活監視処理が完了しました', 'message' => 'SHJ-6 サーバ死活監視処理が完了しました',
'monitoring_summary' => $monitoringSummary,
'status_comment' => $statusComment, 'status_comment' => $statusComment,
'warnings' => $warnings, 'warnings' => $warnings,
'alert_count' => $alertCount, 'alert_count' => $alertCount,
@ -291,9 +293,20 @@ class ShjSixService
} catch (\Exception $e) { } catch (\Exception $e) {
$errorMessage = 'SHJ-6 サーバ死活監視処理でエラーが発生: ' . $e->getMessage(); $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 // 例外発生時も共通A処理実行キュー種別101、DB登録可否0
$commonAResult = $this->executeCommonProcessA( $commonAResult = $this->executeCommonProcessA(
null, // batch_log廃止のためnull $batchLogId,
$errorMessage, $errorMessage,
self::QUE_CLASS_SERVER_ERROR, self::QUE_CLASS_SERVER_ERROR,
null, null,
@ -307,6 +320,7 @@ class ShjSixService
$totalMailErrorCount += $commonAResult['mail_error_count'] ?? 0; $totalMailErrorCount += $commonAResult['mail_error_count'] ?? 0;
Log::error('SHJ-6 サーバ死活監視処理エラー', [ Log::error('SHJ-6 サーバ死活監視処理エラー', [
'batch_log_id' => $batchLogId,
'exception' => $e->getMessage(), 'exception' => $e->getMessage(),
'trace' => $e->getTraceAsString() 'trace' => $e->getTraceAsString()
]); ]);
@ -314,8 +328,8 @@ class ShjSixService
return [ return [
'success' => false, 'success' => false,
'message' => $errorMessage, 'message' => $errorMessage,
'monitoring_summary' => 'エラーにより監視中断',
'error_details' => [$e->getMessage()], 'error_details' => [$e->getMessage()],
'batch_log_id' => $batchLogId,
'mail_success_count' => $totalMailSuccessCount, 'mail_success_count' => $totalMailSuccessCount,
'mail_error_count' => $totalMailErrorCount 'mail_error_count' => $totalMailErrorCount
]; ];
@ -1107,8 +1121,7 @@ class ShjSixService
self::SYSTEM_ALERT_MAIL_TEMPLATE_ID self::SYSTEM_ALERT_MAIL_TEMPLATE_ID
); );
// SHJ-7仕様準拠: result === 0 が正常、それ以外は異常 if ($result['success']) {
if (($result['result'] ?? 1) === 0) {
Log::info('アラートメール送信成功', [ Log::info('アラートメール送信成功', [
'email' => $email, 'email' => $email,
'recipient_type' => $recipientType, 'recipient_type' => $recipientType,
@ -1120,18 +1133,15 @@ class ShjSixService
'error' => null 'error' => null
]; ];
} else { } else {
// 仕様準拠: error_info を使用
$errorInfo = $result['error_info'] ?? 'メール送信失敗';
Log::error('アラートメール送信失敗', [ Log::error('アラートメール送信失敗', [
'email' => $email, 'email' => $email,
'recipient_type' => $recipientType, 'recipient_type' => $recipientType,
'error_info' => $errorInfo 'error' => $result['message']
]); ]);
return [ return [
'success' => false, 'success' => false,
'error' => $errorInfo 'error' => $result['message'] ?? 'メール送信失敗'
]; ];
} }
@ -1204,6 +1214,7 @@ class ShjSixService
* 【処理5】SHJ-8 バッチ処理ログ作成 * 【処理5】SHJ-8 バッチ処理ログ作成
* *
* 仕様書に基づくSHJ-8共通処理呼び出し * 仕様書に基づくSHJ-8共通処理呼び出し
* BatchLogシステムを使用してバッチ処理の実行ログを記録
* *
* @param array $statistics 処理統計情報 * @param array $statistics 処理統計情報
* @return array 処理結果 ['success' => bool, 'error' => string|null] * @return array 処理結果 ['success' => bool, 'error' => string|null]
@ -1212,14 +1223,9 @@ class ShjSixService
{ {
try { try {
// 仕様書準拠のSHJ-8パラメータ設定 // 仕様書準拠のSHJ-8パラメータ設定
// device_id: 処理2で取得したデバイスID複数ある場合は最初のIDを使用 // device_id: 処理2で取得したデバイスID複数なら連結文字列
// process_name: 処理4のプロセス名 // process_name: 処理4のプロセス名
$deviceIdString = $statistics['device_id']; // 連結されたデバイスID文字列 "1,2,3" $deviceId = $statistics['device_id']; // 連結されたデバイスID文字列
// 複数デバイスIDがある場合は最初のIDを使用SHJ-8はint型を期待
$deviceIdArray = !empty($deviceIdString) ? explode(',', $deviceIdString) : [];
$deviceId = !empty($deviceIdArray) ? (int)$deviceIdArray[0] : 1;
$processName = $statistics['process_name'] ?? 'SHJ-6'; $processName = $statistics['process_name'] ?? 'SHJ-6';
$jobName = $statistics['job_name']; // "SHJ-6サーバ死活監視" 固定 $jobName = $statistics['job_name']; // "SHJ-6サーバ死活監視" 固定
$status = $statistics['status']; // 常に "success" $status = $statistics['status']; // 常に "success"
@ -1230,27 +1236,40 @@ class ShjSixService
Log::info('SHJ-8 バッチ処理ログ作成', [ Log::info('SHJ-8 バッチ処理ログ作成', [
'device_id' => $deviceId, 'device_id' => $deviceId,
'device_id_original' => $deviceIdString,
'process_name' => $processName, 'process_name' => $processName,
'job_name' => $jobName, 'job_name' => $jobName,
'status' => $status, 'status' => $status,
'status_comment' => $statusComment 'status_comment' => $statusComment,
'created_date' => $createdDate,
'updated_date' => $updatedDate
]); ]);
// SHJ-8サービスを呼び出し // 共通処理 SHJ-8 バッチ処理ログ作成を呼び出し
$this->shjEightService->execute( // BatchLog::createBatchLog を使用して統一的にログを記録
$deviceId, $batchLog = BatchLog::createBatchLog(
$processName, $processName,
$jobName,
$status, $status,
$statusComment, [
$createdDate, 'device_id' => $deviceId,
$updatedDate 'job_name' => $jobName,
'status_comment' => $statusComment,
'statistics' => $statistics,
'shj8_params' => [
'device_id' => $deviceId,
'process_name' => $processName,
'job_name' => $jobName,
'status' => $status,
'created_date' => $createdDate,
'updated_date' => $updatedDate
]
],
$statusComment
); );
Log::info('SHJ-8 バッチ処理ログ作成完了', [ Log::info('SHJ-8 バッチ処理ログ作成完了', [
'device_id' => $deviceId, 'device_id' => $deviceId,
'process_name' => $processName 'process_name' => $processName,
'batch_log_id' => $batchLog->id
]); ]);
return [ return [

View File

@ -5,8 +5,8 @@ namespace App\Services;
use App\Models\Park; use App\Models\Park;
use App\Models\EarningsSummary; use App\Models\EarningsSummary;
use App\Models\Psection; use App\Models\Psection;
use App\Models\Batch\BatchLog;
use App\Models\OperatorQue; use App\Models\OperatorQue;
use App\Models\Device;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Carbon\Carbon; use Carbon\Carbon;
@ -41,21 +41,11 @@ class ShjTenService
*/ */
const SUMMARY_TYPE_MONTHLY = 2; const SUMMARY_TYPE_MONTHLY = 2;
/**
* ShjEightService インスタンス
*
* @var ShjEightService
*/
protected $shjEightService;
/** /**
* コンストラクタ * コンストラクタ
*
* @param ShjEightService $shjEightService
*/ */
public function __construct(ShjEightService $shjEightService) public function __construct()
{ {
$this->shjEightService = $shjEightService;
} }
/** /**
@ -77,6 +67,8 @@ class ShjTenService
*/ */
public function executeFiscalEarningsAggregation(string $type, string $target, array $fiscalPeriod): array public function executeFiscalEarningsAggregation(string $type, string $target, array $fiscalPeriod): array
{ {
$batchLogId = null;
$batchLog = null;
$statusComments = []; // 内部変数.ステータスコメント $statusComments = []; // 内部変数.ステータスコメント
$dataIntegrityIssues = []; // 内部変数.情報不備 $dataIntegrityIssues = []; // 内部変数.情報不備
@ -84,7 +76,22 @@ class ShjTenService
// 【処理1】集計対象を設定する財政年度ベース // 【処理1】集計対象を設定する財政年度ベース
$aggregationTarget = $this->setFiscalAggregationTarget($fiscalPeriod); $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 売上集計処理開始', [ Log::info('SHJ-10 売上集計処理開始', [
'batch_log_id' => $batchLogId,
'type' => $type, 'type' => $type,
'target' => $target, 'target' => $target,
'fiscal_period' => $fiscalPeriod, 'fiscal_period' => $fiscalPeriod,
@ -100,17 +107,30 @@ class ShjTenService
$statusComment = "売上集計{$typeLabel}:駐輪場マスタが存在していません。"; $statusComment = "売上集計{$typeLabel}:駐輪場マスタが存在していません。";
$statusComments[] = $statusComment; $statusComments[] = $statusComment;
// バッチログ更新
$batchLog->update([
'status' => BatchLog::STATUS_WARNING,
'end_time' => now(),
'message' => $statusComment,
'success_count' => 1
]);
// 【処理5】オペレータキュー作成 // 【処理5】オペレータキュー作成
$this->createOperatorQueue($statusComment, null); $this->createOperatorQueue($statusComment, $batchLogId);
// SHJ-8 バッチ処理ログ作成 // SHJ-8 バッチ処理ログ作成
$this->callShjEight('SHJ-10売上集計年次・月次', 'success', $statusComment); $this->createShjBatchLog([
'job_name' => 'SHJ-10売上集計年次・月次',
'status' => 'success',
'status_comment' => $statusComment
]);
return [ return [
'success' => true, 'success' => true,
'message' => $statusComment, 'message' => $statusComment,
'processed_parks' => 0, 'processed_parks' => 0,
'summary_records' => 0 'summary_records' => 0,
'batch_log_id' => $batchLogId
]; ];
} }
@ -119,7 +139,7 @@ class ShjTenService
$processedParks = 0; $processedParks = 0;
foreach ($parkInfo as $park) { foreach ($parkInfo as $park) {
$result = $this->processFiscalEarningsForPark($park, $aggregationTarget, $fiscalPeriod); $result = $this->processFiscalEarningsForPark($park, $aggregationTarget, $fiscalPeriod, $batchLogId);
$processedParks++; $processedParks++;
$summaryRecords += $result['summary_records']; $summaryRecords += $result['summary_records'];
@ -136,24 +156,40 @@ class ShjTenService
} }
// 最終ステータスコメント生成 // 最終ステータスコメント生成
$typeLabel = $this->getTypeLabel($type); $finalStatusComment = "SHJ-10 売上集計処理正常完了 ({$type}: {$fiscalPeriod['target_label']}) - 駐輪場数: {$processedParks}, 集計レコード数: {$summaryRecords}";
$finalStatusComment = "売上集計{$typeLabel}:対象={$fiscalPeriod['target_label']}、駐輪場数={$processedParks}、集計レコード数={$summaryRecords}"; if (!empty($statusComments)) {
if (!empty($dataIntegrityIssues)) { $finalStatusComment .= "\n" . implode("\n", $statusComments);
$finalStatusComment .= "、情報不備=" . implode('、', $dataIntegrityIssues);
} }
if (!empty($dataIntegrityIssues)) {
$finalStatusComment .= "\n" . implode("\n", $dataIntegrityIssues);
}
// バッチ処理完了ログ更新
$batchLog->update([
'status' => BatchLog::STATUS_SUCCESS,
'end_time' => now(),
'message' => $finalStatusComment,
'success_count' => 1
]);
// 【処理5】オペレータキュー作成 // 【処理5】オペレータキュー作成
// ※ 駐輪場単位で既に作成済みprocessFiscalEarningsForPark内で情報不備検出時に実施 // ※ 駐輪場単位で既に作成済みprocessFiscalEarningsForPark内で情報不備検出時に実施
if (!empty($dataIntegrityIssues)) { if (!empty($dataIntegrityIssues)) {
Log::warning('SHJ-10 情報不備検出', [ Log::warning('SHJ-10 情報不備検出', [
'batch_log_id' => $batchLogId,
'issues' => $dataIntegrityIssues 'issues' => $dataIntegrityIssues
]); ]);
} }
// SHJ-8 バッチ処理ログ作成 // SHJ-8 バッチ処理ログ作成
$this->callShjEight('SHJ-10売上集計年次・月次', 'success', $finalStatusComment); $this->createShjBatchLog([
'job_name' => 'SHJ-10売上集計年次・月次',
'status' => 'success',
'status_comment' => $finalStatusComment
]);
Log::info('SHJ-10 売上集計処理完了', [ Log::info('SHJ-10 売上集計処理完了', [
'batch_log_id' => $batchLogId,
'processed_parks' => $processedParks, 'processed_parks' => $processedParks,
'summary_records' => $summaryRecords, 'summary_records' => $summaryRecords,
'data_integrity_issues' => count($dataIntegrityIssues), 'data_integrity_issues' => count($dataIntegrityIssues),
@ -165,21 +201,36 @@ class ShjTenService
'message' => 'SHJ-10 売上集計処理が正常に完了しました', 'message' => 'SHJ-10 売上集計処理が正常に完了しました',
'processed_parks' => $processedParks, 'processed_parks' => $processedParks,
'summary_records' => $summaryRecords, 'summary_records' => $summaryRecords,
'data_integrity_issues' => count($dataIntegrityIssues) 'data_integrity_issues' => count($dataIntegrityIssues),
'batch_log_id' => $batchLogId
]; ];
} catch (\Exception $e) { } catch (\Exception $e) {
$typeLabel = $this->getTypeLabel($type ?? 'unknown'); $errorMessage = 'SHJ-10 売上集計処理でエラーが発生: ' . $e->getMessage();
$errorMessage = "売上集計{$typeLabel}:エラー発生 - " . $e->getMessage();
if (isset($batchLog) && $batchLog) {
$batchLog->update([
'status' => BatchLog::STATUS_ERROR,
'end_time' => now(),
'message' => $errorMessage,
'error_details' => $e->getMessage(),
'error_count' => 1
]);
}
// SHJ-8 バッチ処理ログ作成(エラー時も作成) // SHJ-8 バッチ処理ログ作成(エラー時も作成)
try { try {
$this->callShjEight('SHJ-10売上集計年次・月次', 'error', $errorMessage); $this->createShjBatchLog([
'job_name' => 'SHJ-10売上集計年次・月次',
'status' => 'error',
'status_comment' => $errorMessage
]);
} catch (\Exception $shjException) { } catch (\Exception $shjException) {
Log::error('SHJ-8呼び出しエラー', ['error' => $shjException->getMessage()]); Log::error('SHJ-8呼び出しエラー', ['error' => $shjException->getMessage()]);
} }
Log::error('SHJ-10 売上集計処理エラー', [ Log::error('SHJ-10 売上集計処理エラー', [
'batch_log_id' => $batchLogId,
'exception' => $e->getMessage(), 'exception' => $e->getMessage(),
'trace' => $e->getTraceAsString() 'trace' => $e->getTraceAsString()
]); ]);
@ -187,7 +238,8 @@ class ShjTenService
return [ return [
'success' => false, 'success' => false,
'message' => $errorMessage, 'message' => $errorMessage,
'details' => $e->getMessage() 'details' => $e->getMessage(),
'batch_log_id' => $batchLogId
]; ];
} }
} }
@ -246,9 +298,10 @@ class ShjTenService
* @param object $park 駐輪場情報 * @param object $park 駐輪場情報
* @param array $aggregationTarget 集計対象 * @param array $aggregationTarget 集計対象
* @param array $fiscalPeriod 財政期間情報 * @param array $fiscalPeriod 財政期間情報
* @param int $batchLogId バッチログID
* @return array 処理結果 ['summary_records' => int, 'data_integrity_issue' => string, 'no_data_message' => string|null] * @return array 処理結果 ['summary_records' => int, 'data_integrity_issue' => string, 'no_data_message' => string|null]
*/ */
private function processFiscalEarningsForPark($park, array $aggregationTarget, array $fiscalPeriod): array private function processFiscalEarningsForPark($park, array $aggregationTarget, array $fiscalPeriod, int $batchLogId): array
{ {
try { try {
$startDate = $aggregationTarget['start_date']; $startDate = $aggregationTarget['start_date'];
@ -259,7 +312,7 @@ class ShjTenService
// 情報不備がある場合、駐輪場単位でオペレータキュー作成(仕様 todo/SHJ-10/SHJ-10.txt:289-299 // 情報不備がある場合、駐輪場単位でオペレータキュー作成(仕様 todo/SHJ-10/SHJ-10.txt:289-299
if ($dataIntegrityIssue !== '情報不備:なし') { if ($dataIntegrityIssue !== '情報不備:なし') {
$this->createOperatorQueue($dataIntegrityIssue, $park->park_id); $this->createOperatorQueue($dataIntegrityIssue, $batchLogId, $park->park_id);
} }
// ① 定期契約データ取得(車種区分・分類名1・定期有効月数毎) // ① 定期契約データ取得(車種区分・分類名1・定期有効月数毎)
@ -758,10 +811,11 @@ class ShjTenService
* - operator_id: 9999999(バッチ処理固定値) * - operator_id: 9999999(バッチ処理固定値)
* *
* @param string $message 情報不備メッセージ * @param string $message 情報不備メッセージ
* @param int $batchLogId バッチログID
* @param int|null $parkId 駐輪場IDパラメータエラー時はnull * @param int|null $parkId 駐輪場IDパラメータエラー時はnull
* @return void * @return void
*/ */
private function createOperatorQueue(string $message, ?int $parkId = null): void private function createOperatorQueue(string $message, int $batchLogId, ?int $parkId = null): void
{ {
try { try {
DB::table('operator_que')->insert([ DB::table('operator_que')->insert([
@ -779,6 +833,7 @@ class ShjTenService
]); ]);
Log::info('オペレータキュー作成完了', [ Log::info('オペレータキュー作成完了', [
'batch_log_id' => $batchLogId,
'park_id' => $parkId, 'park_id' => $parkId,
'que_class' => 14, 'que_class' => 14,
'que_status' => 1, 'que_status' => 1,
@ -788,6 +843,7 @@ class ShjTenService
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error('オペレータキュー作成エラー', [ Log::error('オペレータキュー作成エラー', [
'batch_log_id' => $batchLogId,
'park_id' => $parkId, 'park_id' => $parkId,
'error' => $e->getMessage() 'error' => $e->getMessage()
]); ]);
@ -799,41 +855,60 @@ class ShjTenService
* *
* 共通処理「SHJ-8 バッチ処理ログ作成」を呼び出す * 共通処理「SHJ-8 バッチ処理ログ作成」を呼び出す
* *
* @param string $jobName ジョブ名 * @param array $statistics 処理統計情報
* @param string $status ステータス (success/error)
* @param string $statusComment 業務固有のステータスコメント
* @return void * @return void
*/ */
private function callShjEight(string $jobName, string $status, string $statusComment): void private function createShjBatchLog(array $statistics): void
{ {
try { try {
$device = Device::orderBy('device_id')->first(); // SHJ-8 パラメータ設定
$deviceId = $device ? $device->device_id : 1; $deviceId = 9999999; // バッチ処理用固定デバイスID
$processName = 'SHJ-10';
$jobName = $statistics['job_name'];
$status = $statistics['status'];
$statusComment = $statistics['status_comment'] ?? '';
$today = now()->format('Y/m/d'); $createdDate = now()->format('Y/m/d');
$updatedDate = now()->format('Y/m/d');
$this->shjEightService->execute( Log::info('SHJ-8 バッチ処理ログ作成', [
$deviceId, 'device_id' => $deviceId,
'SHJ-10', 'process_name' => $processName,
$jobName,
$status,
$statusComment,
$today,
$today
);
Log::info('SHJ-8 バッチ処理ログ作成完了', [
'job_name' => $jobName, 'job_name' => $jobName,
'status' => $status 'status' => $status,
'status_comment' => $statusComment
]); ]);
// 共通処理 SHJ-8 バッチ処理ログ作成を呼び出し
// BatchLog システムを使用してバッチ処理の実行ログを記録
BatchLog::createBatchLog(
$processName,
$status,
[
'device_id' => $deviceId,
'job_name' => $jobName,
'status_comment' => $statusComment,
'statistics' => $statistics,
'shj8_params' => [
'device_id' => $deviceId,
'process_name' => $processName,
'job_name' => $jobName,
'status' => $status,
'created_date' => $createdDate,
'updated_date' => $updatedDate
]
],
$statusComment
);
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error('SHJ-8 バッチ処理ログ作成エラー', [ Log::error('SHJ-8 バッチ処理ログ作成エラー', [
'error' => $e->getMessage(), 'error' => $e->getMessage(),
'job_name' => $jobName, 'statistics' => $statistics
'status_comment' => $statusComment
]); ]);
throw $e;
// SHJ-8でエラーが発生してもメイン処理は継続
// エラーログのみ出力
} }
} }

View File

@ -4,7 +4,7 @@ namespace App\Services;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use App\Models\Device; use App\Models\Batch\BatchLog;
use Carbon\Carbon; use Carbon\Carbon;
/** /**
@ -15,22 +15,6 @@ use Carbon\Carbon;
*/ */
class ShjThirteenService class ShjThirteenService
{ {
/**
* ShjEightService
*
* @var ShjEightService
*/
protected $shjEightService;
/**
* コンストラクタ
*
* @param ShjEightService $shjEightService
*/
public function __construct(ShjEightService $shjEightService)
{
$this->shjEightService = $shjEightService;
}
/** /**
* SHJ-13 契約台数追加処理実行 * SHJ-13 契約台数追加処理実行
* *
@ -162,6 +146,7 @@ class ShjThirteenService
->where('ptype_id', $contractData['ptype_id']) ->where('ptype_id', $contractData['ptype_id'])
->increment('park_number', 1, [ ->increment('park_number', 1, [
'updated_at' => now(), 'updated_at' => now(),
'operator_id' => 'SHJ-13',
]); ]);
if ($parkNumberUpdated === 0) { if ($parkNumberUpdated === 0) {
@ -173,6 +158,7 @@ class ShjThirteenService
->where('zone_id', $contractData['zone_id']) ->where('zone_id', $contractData['zone_id'])
->increment('zone_number', 1, [ ->increment('zone_number', 1, [
'updated_at' => now(), 'updated_at' => now(),
'ope_id' => 'SHJ-13',
]); ]);
if ($zoneUpdated === 0) { if ($zoneUpdated === 0) {
@ -188,19 +174,25 @@ class ShjThirteenService
$statusComment = $this->buildStatusComment($names['names'], $updatedZone->zone_number); $statusComment = $this->buildStatusComment($names['names'], $updatedZone->zone_number);
// バッチ処理ログ作成(同一トランザクション内) // バッチ処理ログ作成(同一トランザクション内)
// SHJ-8サービスを呼び出し $currentDate = now()->format('Y/m/d');
$device = Device::orderBy('device_id')->first();
$deviceId = $device ? $device->device_id : 1;
$today = now()->format('Y/m/d');
$this->shjEightService->execute( $batchLog = BatchLog::createBatchLog(
$deviceId, 'SHJ-13', // process_name
'SHJ-13', BatchLog::STATUS_SUCCESS,
'SHJ-13契約台数追加', [
'success', 'device_id' => 1,
$statusComment, 'job_name' => 'SHJ-13',
$today, 'status' => 'success',
$today '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
); );
Log::info('SHJ-13 契約台数更新・ログ作成完了', [ Log::info('SHJ-13 契約台数更新・ログ作成完了', [
@ -208,6 +200,7 @@ class ShjThirteenService
'park_number_updated' => $parkNumberUpdated, 'park_number_updated' => $parkNumberUpdated,
'zone_updated' => $zoneUpdated, 'zone_updated' => $zoneUpdated,
'updated_count' => $updatedZone->zone_number, 'updated_count' => $updatedZone->zone_number,
'batch_log_id' => $batchLog->id,
'status_comment' => $statusComment, 'status_comment' => $statusComment,
]); ]);
@ -334,7 +327,7 @@ class ShjThirteenService
/** /**
* エラー結果作成SHJ-8ログも作成) * エラー結果作成
* *
* @param int $errorCode * @param int $errorCode
* @param string $errorMessage * @param string $errorMessage
@ -343,38 +336,6 @@ class ShjThirteenService
*/ */
private function createErrorResult(int $errorCode, string $errorMessage, string $stackTrace = ''): array 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 [ return [
'result' => 1, 'result' => 1,
'error_code' => $errorCode, 'error_code' => $errorCode,

View File

@ -6,7 +6,7 @@ use App\Models\Park;
use App\Models\User; use App\Models\User;
use App\Models\RegularContract; use App\Models\RegularContract;
use App\Models\OperatorQue; use App\Models\OperatorQue;
use App\Models\Device; use App\Models\Batch\BatchLog;
use App\Services\ShjMailSendService; use App\Services\ShjMailSendService;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
@ -48,6 +48,13 @@ class ShjThreeService
*/ */
protected $operatorQueModel; protected $operatorQueModel;
/**
* BatchLog モデル
*
* @var BatchLog
*/
protected $batchLogModel;
/** /**
* ShjMailSendService * ShjMailSendService
* *
@ -55,13 +62,6 @@ class ShjThreeService
*/ */
protected $mailSendService; protected $mailSendService;
/**
* ShjEightService
*
* @var ShjEightService
*/
protected $shjEightService;
/** /**
* コンストラクタ * コンストラクタ
* *
@ -69,23 +69,23 @@ class ShjThreeService
* @param User $userModel * @param User $userModel
* @param RegularContract $contractModel * @param RegularContract $contractModel
* @param OperatorQue $operatorQueModel * @param OperatorQue $operatorQueModel
* @param BatchLog $batchLogModel
* @param ShjMailSendService $mailSendService * @param ShjMailSendService $mailSendService
* @param ShjEightService $shjEightService
*/ */
public function __construct( public function __construct(
Park $parkModel, Park $parkModel,
User $userModel, User $userModel,
RegularContract $contractModel, RegularContract $contractModel,
OperatorQue $operatorQueModel, OperatorQue $operatorQueModel,
ShjMailSendService $mailSendService, BatchLog $batchLogModel,
ShjEightService $shjEightService ShjMailSendService $mailSendService
) { ) {
$this->parkModel = $parkModel; $this->parkModel = $parkModel;
$this->userModel = $userModel; $this->userModel = $userModel;
$this->contractModel = $contractModel; $this->contractModel = $contractModel;
$this->operatorQueModel = $operatorQueModel; $this->operatorQueModel = $operatorQueModel;
$this->batchLogModel = $batchLogModel;
$this->mailSendService = $mailSendService; $this->mailSendService = $mailSendService;
$this->shjEightService = $shjEightService;
} }
/** /**
@ -120,9 +120,6 @@ class ShjThreeService
$message = '対象の駐輪場マスタが見つかりません'; $message = '対象の駐輪場マスタが見つかりません';
Log::warning($message); Log::warning($message);
// 駐輪場が見つからない場合でも実行ログを記録
$this->createOverallBatchLog(0, 0, 0, 0, 0, 0);
return [ return [
'success' => false, 'success' => false,
'message' => $message, 'message' => $message,
@ -248,16 +245,6 @@ class ShjThreeService
'queue_error_count' => $overallQueueErrorCount 'queue_error_count' => $overallQueueErrorCount
]); ]);
// 駐輪場が0件でも全体の実行ログを記録する
$this->createOverallBatchLog(
$overallProcessedParksCount,
$overallTotalTargetUsers,
$overallMailSuccessCount,
$overallMailErrorCount,
$overallQueueSuccessCount,
$overallQueueErrorCount
);
return [ return [
'success' => true, 'success' => true,
'message' => 'SHJ-3 定期更新リマインダー処理が正常に完了しました', 'message' => 'SHJ-3 定期更新リマインダー処理が正常に完了しました',
@ -276,16 +263,6 @@ class ShjThreeService
'trace' => $e->getTraceAsString() 'trace' => $e->getTraceAsString()
]); ]);
// エラー時も実行ログを記録
$this->createOverallBatchLog(
$overallProcessedParksCount,
$overallTotalTargetUsers,
$overallMailSuccessCount,
$overallMailErrorCount,
$overallQueueSuccessCount,
$overallQueueErrorCount
);
return [ return [
'success' => false, 'success' => false,
'message' => $errorMessage, 'message' => $errorMessage,
@ -322,20 +299,14 @@ class ShjThreeService
'update_grace_period_start_time', // 更新期間開始時(例:"09:00" 'update_grace_period_start_time', // 更新期間開始時(例:"09:00"
'update_grace_period_end_date', // 更新期間終了日(例:"6" 'update_grace_period_end_date', // 更新期間終了日(例:"6"
'update_grace_period_end_time', // 更新期間終了時(例:"23:59" 'update_grace_period_end_time', // 更新期間終了時(例:"23:59"
// 注意reminder_type と reminder_time フィールドはまだ存在しない 'reminder_type', // リマインダー種別0=毎日,1=1日おき,2=2日おき
// 暫定的に0毎日と開始時刻をデフォルト値として使用 'reminder_time' // リマインダー時間(例:"09:00"
]) ])
->where('park_close_flag', 0) // 閉設フラグ = 0 ->where('park_close_flag', 0) // 閉設フラグ = 0
->orderBy('park_ruby', 'asc') // 駐輪場ふりがな 昇順 ->orderBy('park_ruby', 'asc') // 駐輪場ふりがな 昇順
->get() ->get()
->toArray(); ->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('駐輪場マスタ情報取得完了', [ Log::info('駐輪場マスタ情報取得完了', [
'park_count' => count($parkInfo) 'park_count' => count($parkInfo)
]); ]);
@ -657,8 +628,7 @@ class ShjThreeService
$mailTemplateId $mailTemplateId
); );
// SHJ-7仕様準拠: result === 0 が正常、それ以外は異常 if ($mailResult['success']) {
if (($mailResult['result'] ?? 1) === 0) {
// 仕様書:処理結果 = 0正常の場合 // 仕様書:処理結果 = 0正常の場合
Log::info('メール送信成功', [ Log::info('メール送信成功', [
'user_id' => $targetUser->利用者ID, 'user_id' => $targetUser->利用者ID,
@ -674,14 +644,12 @@ class ShjThreeService
} else { } else {
// 仕様書:その他の場合(異常) // 仕様書:その他の場合(異常)
// バッチコメントに「処理2.定期契約ID」+「SHJ-7 メール送信.異常情報」を設定する(後ろに足す) // バッチコメントに「処理2.定期契約ID」+「SHJ-7 メール送信.異常情報」を設定する(後ろに足す)
// 仕様準拠: error_info を使用 $errorInfo = "定期契約ID:{$targetUser->定期契約ID} / SHJ-7 メール送信.異常情報:{$mailResult['message']}";
$shjSevenErrorInfo = $mailResult['error_info'] ?? 'メール送信失敗';
$errorInfo = "定期契約ID:{$targetUser->定期契約ID} / SHJ-7 メール送信.異常情報:{$shjSevenErrorInfo}";
Log::warning('メール送信失敗', [ Log::warning('メール送信失敗', [
'user_id' => $targetUser->利用者ID, 'user_id' => $targetUser->利用者ID,
'contract_id' => $targetUser->定期契約ID, 'contract_id' => $targetUser->定期契約ID,
'error_info' => $shjSevenErrorInfo 'error' => $mailResult['message']
]); ]);
return [ return [
@ -781,6 +749,7 @@ class ShjThreeService
* 【処理4】SHJ-8バッチ処理ログ作成 * 【処理4】SHJ-8バッチ処理ログ作成
* *
* 仕様書に基づくSHJ-8共通処理呼び出し * 仕様書に基づくSHJ-8共通処理呼び出し
* BatchLog統一システムを使用してバッチ処理の実行ログを記録
* ※各駐輪場ごとに1回実行される * ※各駐輪場ごとに1回実行される
* *
* @param object $park 駐輪場情報 * @param object $park 駐輪場情報
@ -800,8 +769,11 @@ class ShjThreeService
int $queueErrorCount int $queueErrorCount
): void { ): void {
try { try {
$device = Device::orderBy('device_id')->first(); // 仕様書SHJ-8パラメータ設定
$deviceId = $device ? $device->device_id : 1; $deviceId = 9999999; // バッチ処理用固定デバイスID他Serviceと同様
$processName = 'SHJ-3';
$jobName = 'SHJ-3定期更新リマインダー';
$status = BatchLog::STATUS_SUCCESS;
// 仕様書:ステータスコメント生成 // 仕様書:ステータスコメント生成
// 「内部変数.バッチコメント」+ "" + 「処理1.駐輪場名」 // 「内部変数.バッチコメント」+ "" + 「処理1.駐輪場名」
@ -810,29 +782,53 @@ class ShjThreeService
// + "、キュー登録正常終了件数" + 「内部変数.キュー登録正常終了件数」 // + "、キュー登録正常終了件数" + 「内部変数.キュー登録正常終了件数」
// + "、キュー登録異常終了件数" + 「内部変数.キュー登録異常終了件数」 // + "、キュー登録異常終了件数" + 「内部変数.キュー登録異常終了件数」
$statusComment = ($batchComment ? $batchComment . ' / ' : '') . $statusComment = ($batchComment ? $batchComment . ' / ' : '') .
"{$park->park_name}" . "{$park->park_name} : " .
"メール正常終了件数={$mailSuccessCount}" . "メール正常終了件数={$mailSuccessCount}" .
"メール異常終了件数={$mailErrorCount}" . "メール異常終了件数={$mailErrorCount}" .
"キュー登録正常終了件数={$queueSuccessCount}" . "キュー登録正常終了件数={$queueSuccessCount}" .
"キュー登録異常終了件数={$queueErrorCount}"; "キュー登録異常終了件数={$queueErrorCount}";
$today = now()->format('Y/m/d'); $createdDate = now()->format('Y/m/d');
$updatedDate = now()->format('Y/m/d');
Log::info('SHJ-8バッチ処理ログ作成', [ Log::info('SHJ-8バッチ処理ログ作成', [
'park_id' => $park->park_id, 'park_id' => $park->park_id,
'park_name' => $park->park_name, 'park_name' => $park->park_name,
'device_id' => $deviceId,
'process_name' => $processName,
'job_name' => $jobName,
'status' => $status,
'status_comment' => $statusComment 'status_comment' => $statusComment
]); ]);
// SHJ-8サービスを呼び出し // 仕様書共通処理「SHJ-8 バッチ処理ログ作成」を呼び出す
$this->shjEightService->execute( // BatchLog::createBatchLog を使用して統一的にログを記録
$deviceId, BatchLog::createBatchLog(
'SHJ-3', $processName,
'SHJ-3定期更新リマインダー', $status,
'success', [
$statusComment, 'device_id' => $deviceId,
$today, 'job_name' => $jobName,
$today '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
); );
} catch (\Exception $e) { } catch (\Exception $e) {
@ -846,64 +842,4 @@ 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()
]);
}
}
} }

View File

@ -4,7 +4,7 @@ namespace App\Services;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use App\Models\Device; use App\Models\Batch\BatchLog;
use App\Models\RegularContract; use App\Models\RegularContract;
use App\Models\User; use App\Models\User;
use App\Models\Park; use App\Models\Park;
@ -25,25 +25,14 @@ class ShjTwelveService
*/ */
protected $shjMailSendService; protected $shjMailSendService;
/**
* ShjEightService
*
* @var ShjEightService
*/
protected $shjEightService;
/** /**
* コンストラクタ * コンストラクタ
* *
* @param ShjMailSendService $shjMailSendService * @param ShjMailSendService $shjMailSendService
* @param ShjEightService $shjEightService
*/ */
public function __construct( public function __construct(ShjMailSendService $shjMailSendService)
ShjMailSendService $shjMailSendService, {
ShjEightService $shjEightService
) {
$this->shjMailSendService = $shjMailSendService; $this->shjMailSendService = $shjMailSendService;
$this->shjEightService = $shjEightService;
} }
/** /**
@ -61,17 +50,19 @@ class ShjTwelveService
try { try {
$query = DB::table('regular_contract as T1') $query = DB::table('regular_contract as T1')
->select([ ->select([
'T1.contract_id', // 定期契約ID 'T1.contract_id', // 定期契約ID
'T2.user_seq', // 利用者ID 'T2.user_seq', // 利用者ID
'T2.user_name', // 利用者名 'T2.user_name', // 利用者名
'T2.user_manual_regist_flag', // 手動登録フラグ 'T2.user_manual_flag', // 手動登録フラグ
'T2.user_primemail', // メールアドレス 'T2.user_mail', // メールアドレス
'T2.user_submail', // 予備メールアドレス 'T2.user_mail_sub', // 予備メールアドレス
'T1.park_id', // 駐輪場ID (regular_contractテーブルから) 'T2.park_id', // 駐輪場ID (userテーブルから)
'T3.park_name', // 駐輪場名 'T3.park_name', // 駐輪場名
'T1.billing_amount' // 請求金額 'T1.billing_amount' // 請求金額
]) ])
->join('user as T2', 'T1.user_id', '=', 'T2.user_seq') ->join('user as T2', function($join) {
$join->on('T1.user_seq', '=', 'T2.user_seq');
})
->join('park as T3', 'T1.park_id', '=', 'T3.park_id') ->join('park as T3', 'T1.park_id', '=', 'T3.park_id')
->where([ ->where([
['T1.contract_cancel_flag', '=', 0], // 解約フラグ = 0 ['T1.contract_cancel_flag', '=', 0], // 解約フラグ = 0
@ -103,89 +94,51 @@ class ShjTwelveService
/** /**
* 【処理2】未払い者への通知、またはオペレーターキュー追加処理 * 【処理2】未払い者への通知、またはオペレーターキュー追加処理
* *
* 仕様: * 各未払い者に対して以下の処理を実行:
* - 手動登録フラグ = 0 (Web申込) SHJ-7メール送信のみ * 1. メール通知の実行 (SHJ-7連携)
* - 手動登録フラグ 0 (その他) オペレーターキュー追加のみ * 2. オペレーターキューへの追加 (opeテーブル)
* *
* @param array $unpaidUsers 未払い者リスト * @param array $unpaidUsers 未払い者リスト
* @return array 処理結果 * @return array 処理結果
*/ */
public function processUnpaidUserNotifications(array $unpaidUsers): array public function processUnpaidUserNotifications(array $unpaidUsers): array
{ {
// 内部変数(カウンタ)初期化 $notificationCount = 0;
$mailSuccessCount = 0; $queueCount = 0;
$mailErrorCount = 0; $errors = [];
$queueSuccessCount = 0;
$queueErrorCount = 0;
$batchComments = []; // バッチコメント(エラー情報)累積用
$processParameters = []; $processParameters = [];
try { try {
DB::beginTransaction(); DB::beginTransaction();
// 処理1の取得レコード数分繰り返し
foreach ($unpaidUsers as $user) { foreach ($unpaidUsers as $user) {
try { try {
// 【判定】手動登録フラグによる分岐 // メール通知処理
if ($user->user_manual_regist_flag == 0) { $mailResult = $this->sendNotificationMail($user);
// Web申込 → SHJ-7メール送信 if ($mailResult['success']) {
$mailResult = $this->sendNotificationMailViaShj7($user); $notificationCount++;
// 処理結果判定: 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,
'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'
];
} }
// オペレーターキュー追加処理
$queueResult = $this->addToOperatorQueue($user);
if ($queueResult['success']) {
$queueCount++;
}
// 処理パラメータ記録
$processParameters[] = [
'contract_id' => $user->contract_id,
'user_seq' => $user->user_seq,
'billing_amount' => $user->billing_amount,
'mail_sent' => $mailResult['success'],
'queue_added' => $queueResult['success']
];
} catch (\Exception $e) { } catch (\Exception $e) {
// 個別エラーを記録して次の繰り返し処理へ $errors[] = [
$batchComments[] = sprintf( 'contract_id' => $user->contract_id,
'契約ID:%s 処理エラー: %s', 'error' => $e->getMessage()
$user->contract_id, ];
$e->getMessage()
);
Log::warning('SHJ-12 個別処理エラー', [ Log::warning('SHJ-12 個別処理エラー', [
'contract_id' => $user->contract_id, 'contract_id' => $user->contract_id,
@ -197,26 +150,12 @@ class ShjTwelveService
DB::commit(); DB::commit();
// ステータスコメント構築
$statusComment = $this->buildStatusComment(
$mailSuccessCount,
$mailErrorCount,
$queueSuccessCount,
$queueErrorCount
);
// バッチコメント整形最大100件、超過分は省略
$formattedBatchComments = $this->formatBatchComments($batchComments);
return [ return [
'success' => true, 'success' => true,
'mail_success_count' => $mailSuccessCount, 'notification_count' => $notificationCount,
'mail_error_count' => $mailErrorCount, 'queue_count' => $queueCount,
'queue_success_count' => $queueSuccessCount,
'queue_error_count' => $queueErrorCount,
'status_comment' => $statusComment,
'batch_comments' => $formattedBatchComments,
'parameters' => $processParameters, 'parameters' => $processParameters,
'errors' => $errors,
'message' => '未払い者通知処理完了' 'message' => '未払い者通知処理完了'
]; ];
@ -230,13 +169,10 @@ class ShjTwelveService
return [ return [
'success' => false, 'success' => false,
'mail_success_count' => $mailSuccessCount, 'notification_count' => $notificationCount,
'mail_error_count' => $mailErrorCount, 'queue_count' => $queueCount,
'queue_success_count' => $queueSuccessCount,
'queue_error_count' => $queueErrorCount,
'status_comment' => 'システムエラー',
'batch_comments' => $batchComments,
'parameters' => $processParameters, 'parameters' => $processParameters,
'errors' => $errors,
'message' => '通知処理エラー: ' . $e->getMessage(), 'message' => '通知処理エラー: ' . $e->getMessage(),
'details' => $e->getTraceAsString() 'details' => $e->getTraceAsString()
]; ];
@ -244,44 +180,54 @@ class ShjTwelveService
} }
/** /**
* SHJ-7 メール送信サービス経由でメール通知送信 * 未払い者へのメール通知送信
* *
* 仕様書パラメータ: * SHJ-7 メール送信サービスを使用してメール通知を実行
* - メールアドレス: 処理1.メールアドレス
* - 予備メールアドレス: 処理1.予備メールアドレス
* - 使用プログラムID: 204
* *
* @param object $user 未払い者情報 * @param object $user 未払い者情報
* @return array SHJ-7の処理結果 (result_code: 0=正常, 1=異常) * @return array 送信結果
*/ */
private function sendNotificationMailViaShj7($user): array private function sendNotificationMail($user): array
{ {
try { try {
// SHJ-7 executeMailSend 呼び出し // メールアドレスの確認
$result = $this->shjMailSendService->executeMailSend( $emailAddress = $user->user_mail ?: $user->user_mail_sub;
(string)($user->user_primemail ?? ''), // メールアドレス
(string)($user->user_submail ?? ''), // 予備メールアドレス
204 // 使用プログラムID
);
Log::info('SHJ-12 SHJ-7メール送信結果', [ if (empty($emailAddress)) {
return [
'success' => false,
'message' => 'メールアドレスが設定されていません'
];
}
// 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 メール送信結果', [
'contract_id' => $user->contract_id, 'contract_id' => $user->contract_id,
'user_seq' => $user->user_seq, 'email' => $emailAddress,
'result' => $result['result'] ?? 1, 'success' => $result['success']
'error_info' => $result['error_info'] ?? ''
]); ]);
return $result; return $result;
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error('SHJ-12 SHJ-7メール送信エラー', [ Log::error('SHJ-12 メール送信エラー', [
'contract_id' => $user->contract_id, 'contract_id' => $user->contract_id,
'error' => $e->getMessage() 'error' => $e->getMessage()
]); ]);
return [ return [
'result' => 1, // 異常終了 'success' => false,
'error_info' => 'SHJ-7メール送信エラー: ' . $e->getMessage() 'message' => 'メール送信エラー: ' . $e->getMessage()
]; ];
} }
} }
@ -289,179 +235,63 @@ class ShjTwelveService
/** /**
* オペレーターキューへの追加 * オペレーターキューへの追加
* *
* 仕様書SQL定義に基づき operator_que テーブルに登録 * opeテーブルにオペレーター処理キューとして登録
* - キュー種別ID: 8 (支払い催促)
* - キューステータスID: 1 (キュー発生)
* - que_id: MAX+1方式で生成db_now.sqlは非AUTO_INCREMENT
* - 主キー衝突時に1回リトライ
* *
* @param object $user 未払い者情報 * @param object $user 未払い者情報
* @return array 追加結果 * @return array 追加結果
*/ */
private function addToOperatorQueue($user): array private function addToOperatorQueue($user): array
{ {
$maxRetries = 2; // 最大2回試行初回 + リトライ1回 try {
$lastException = null; $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()
];
for ($attempt = 1; $attempt <= $maxRetries; $attempt++) { // opeテーブルに挿入
try { DB::table('ope')->insert($queueData);
// オペレーターキューデータ構築
// 注: 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: システム自動)
];
// operator_queテーブルに挿入que_idはDBが自動採番 Log::info('SHJ-12 オペレーターキュー追加完了', [
$newQueId = DB::table('operator_que')->insertGetId($queueData); 'contract_id' => $user->contract_id,
'user_seq' => $user->user_seq,
'billing_amount' => $user->billing_amount
]);
Log::info('SHJ-12 オペレーターキュー追加完了', [ return [
'que_id' => $newQueId, 'success' => true,
'contract_id' => $user->contract_id, 'message' => 'オペレーターキューに追加しました'
'user_seq' => $user->user_seq, ];
'park_id' => $user->park_id,
'que_class' => 8,
'que_status' => 1,
'attempt' => $attempt
]);
return [ } catch (\Exception $e) {
'success' => true, Log::error('SHJ-12 オペレーターキュー追加エラー', [
'message' => 'オペレーターキュー追加成功', 'contract_id' => $user->contract_id,
'que_id' => $newQueId 'error' => $e->getMessage()
]; ]);
} catch (\Illuminate\Database\QueryException $e) { return [
$lastException = $e; 'success' => false,
'message' => 'オペレーターキュー追加エラー: ' . $e->getMessage()
// 主キー重複エラー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】バッチ処理ログを作成する * 【処理3】バッチ処理ログを作成する
* *
* SHJ-8サービスを呼び出してbat_job_logテーブルに登録業務固有のstatus_comment記録 * 統一BatchLogシステムを使用してSHJ-12の実行ログを記録
* *
* @param string $status ステータス * @param string $status ステータス
* @param array $parameters パラメータ * @param array $parameters パラメータ
@ -480,40 +310,22 @@ class ShjTwelveService
int $errorCount = 0 int $errorCount = 0
): void { ): void {
try { try {
// デバイスIDを取得 BatchLog::createBatchLog(
$device = Device::orderBy('device_id')->first();
$deviceId = $device ? $device->device_id : 1;
// status_commentを構築業務情報を含む
$statusComment = sprintf(
'%s (実行:%d/成功:%d/エラー:%d)',
$message,
$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',
'SHJ-12未払い者通知',
$status, $status,
$statusComment, $parameters,
$today, $message,
$today [
'execution_count' => $executionCount,
'success_count' => $successCount,
'error_count' => $errorCount,
'process_type' => '未払い者通知処理',
'executed_at' => now()->toISOString()
]
); );
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error('SHJ-8 バッチログ作成エラー', [ Log::error('SHJ-12 バッチログ作成エラー', [
'error' => $e->getMessage(), 'error' => $e->getMessage(),
'status' => $status, 'status' => $status,
'message' => $message 'message' => $message

View File

@ -312,6 +312,7 @@ return null;
border-radius: 2rem !important; border-radius: 2rem !important;
padding-left: 2rem !important; padding-left: 2rem !important;
padding-right: 2rem !important; padding-right: 2rem !important;
font-weight: 500;
min-width: 140px; min-width: 140px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
} }