app/Services/ShjThreeService.php を削除
Some checks failed
Deploy main / deploy (push) Has been cancelled

This commit is contained in:
go.unhi 2025-10-23 20:38:05 +09:00
parent dbc059ef2c
commit 5ca8e82ac9

View File

@ -1,796 +0,0 @@
<?php
namespace App\Services;
use App\Models\Park;
use App\Models\User;
use App\Models\RegularContract;
use App\Models\Batch\BatchLog;
use App\Services\ShjMailSendService;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
/**
* SHJ-3 定期更新リマインダー処理サービス
*
* 駐輪場の定期契約更新対象者に対するリマインダー処理を実行するビジネスロジック
* バッチ処理「SHJ-3定期更新リマインダー」の核となる処理を担当
*/
class ShjThreeService
{
/**
* Park モデル
*
* @var Park
*/
protected $parkModel;
/**
* User モデル
*
* @var User
*/
protected $userModel;
/**
* RegularContract モデル
*
* @var RegularContract
*/
protected $contractModel;
/**
* BatchLog モデル
*
* @var BatchLog
*/
protected $batchLogModel;
/**
* ShjMailSendService
*
* @var ShjMailSendService
*/
protected $mailSendService;
/**
* コンストラクタ
*
* @param Park $parkModel
* @param User $userModel
* @param RegularContract $contractModel
* @param BatchLog $batchLogModel
* @param ShjMailSendService $mailSendService
*/
public function __construct(
Park $parkModel,
User $userModel,
RegularContract $contractModel,
BatchLog $batchLogModel,
ShjMailSendService $mailSendService
) {
$this->parkModel = $parkModel;
$this->userModel = $userModel;
$this->contractModel = $contractModel;
$this->batchLogModel = $batchLogModel;
$this->mailSendService = $mailSendService;
}
/**
* SHJ-3 定期更新リマインダー処理メイン実行
*
* 処理フロー:
* 【処理0】駐輪場マスタの情報を取得する
* 【判断0】当該駐輪場実行タイミングチェック
* 【処理2】定期更新対象者を取得する
* 【判断2】利用者有無をチェック
* 【処理3】対象者向けにメール送信、またはオペレーターキュー追加処理
* 【処理4】バッチ処理ログを作成する
*
* @return array 処理結果
*/
public function executeReminderProcess(): array
{
$batchLogId = null;
$processedParksCount = 0;
$totalTargetUsers = 0;
$mailSuccessCount = 0;
$mailErrorCount = 0;
$operatorQueueCount = 0;
try {
// バッチ処理開始ログ作成
$batchLog = BatchLog::createBatchLog(
'shj3',
BatchLog::STATUS_START,
[],
'SHJ-3 定期更新リマインダー処理開始'
);
$batchLogId = $batchLog->id;
Log::info('SHJ-3 定期更新リマインダー処理開始', [
'batch_log_id' => $batchLogId
]);
// 【処理0】駐輪場マスタの情報を取得する
$parkList = $this->getParkMasterInfo();
if (empty($parkList)) {
$message = '対象の駐輪場マスタが見つかりません';
$batchLog->update([
'status' => BatchLog::STATUS_ERROR,
'end_time' => now(),
'message' => $message,
'error_details' => $message,
'error_count' => 1
]);
return [
'success' => false,
'message' => $message,
'processed_parks_count' => 0,
'total_target_users' => 0,
'mail_success_count' => 0,
'mail_error_count' => 0,
'operator_queue_count' => 0,
'batch_log_id' => $batchLogId
];
}
// 各駐輪場に対する処理ループ
foreach ($parkList as $park) {
Log::info('駐輪場処理開始', [
'park_id' => $park->park_id,
'park_name' => $park->park_name
]);
// 【判断0】当該駐輪場実行タイミングチェック
$timingCheckResult = $this->checkExecutionTiming($park);
if (!$timingCheckResult['should_execute']) {
Log::info('実行タイミング対象外', [
'park_id' => $park->park_id,
'reason' => $timingCheckResult['reason']
]);
continue;
}
$processedParksCount++;
// 【処理2】定期更新対象者を取得する
$targetUsers = $this->getRegularUpdateTargetUsers($park->park_id);
// 【判断2】利用者有無をチェック
if (empty($targetUsers)) {
Log::info('利用者なし', [
'park_id' => $park->park_id
]);
continue;
}
$totalTargetUsers += count($targetUsers);
// 【処理3】対象者向けにメール送信、またはオペレーターキュー追加処理
foreach ($targetUsers as $targetUser) {
$processResult = $this->processTargetUser($targetUser);
if ($processResult['type'] === 'mail_success') {
$mailSuccessCount++;
} elseif ($processResult['type'] === 'mail_error') {
$mailErrorCount++;
} elseif ($processResult['type'] === 'operator_queue') {
$operatorQueueCount++;
}
}
Log::info('駐輪場処理完了', [
'park_id' => $park->park_id,
'target_users_count' => count($targetUsers)
]);
}
// 【処理4】バッチ処理ログを作成するSHJ-8呼び出し
$this->createShjBatchLog([
'processed_parks_count' => $processedParksCount,
'total_target_users' => $totalTargetUsers,
'mail_success_count' => $mailSuccessCount,
'mail_error_count' => $mailErrorCount,
'operator_queue_count' => $operatorQueueCount
]);
// バッチ処理完了ログ更新
$batchLog->update([
'status' => BatchLog::STATUS_SUCCESS,
'end_time' => now(),
'message' => 'SHJ-3 定期更新リマインダー処理正常完了',
'success_count' => 1,
'parameters' => [
'processed_parks_count' => $processedParksCount,
'total_target_users' => $totalTargetUsers,
'mail_success_count' => $mailSuccessCount,
'mail_error_count' => $mailErrorCount,
'operator_queue_count' => $operatorQueueCount,
'executed_at' => now()->toISOString()
]
]);
Log::info('SHJ-3 定期更新リマインダー処理完了', [
'batch_log_id' => $batchLogId,
'processed_parks_count' => $processedParksCount,
'total_target_users' => $totalTargetUsers
]);
return [
'success' => true,
'message' => 'SHJ-3 定期更新リマインダー処理が正常に完了しました',
'processed_parks_count' => $processedParksCount,
'total_target_users' => $totalTargetUsers,
'mail_success_count' => $mailSuccessCount,
'mail_error_count' => $mailErrorCount,
'operator_queue_count' => $operatorQueueCount,
'batch_log_id' => $batchLogId
];
} catch (\Exception $e) {
$errorMessage = 'SHJ-3 定期更新リマインダー処理でエラーが発生: ' . $e->getMessage();
if (isset($batchLog) && $batchLog) {
$batchLog->update([
'status' => BatchLog::STATUS_ERROR,
'end_time' => now(),
'message' => $errorMessage,
'error_details' => $e->getMessage(),
'error_count' => 1
]);
}
Log::error('SHJ-3 定期更新リマインダー処理エラー', [
'batch_log_id' => $batchLogId,
'exception' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
return [
'success' => false,
'message' => $errorMessage,
'details' => $e->getMessage(),
'processed_parks_count' => $processedParksCount,
'total_target_users' => $totalTargetUsers,
'mail_success_count' => $mailSuccessCount,
'mail_error_count' => $mailErrorCount,
'operator_queue_count' => $operatorQueueCount,
'batch_log_id' => $batchLogId
];
}
}
/**
* 【処理0】駐輪場マスタの情報を取得する
*
* 仕様書に基づくSQLクエリ:
* SELECT 駐輪場ID, 駐輪場名, 更新期間開始日, 更新期間開始時,
* 更新期間終了日, 更新期間終了時, リマインダー種別, リマインダー時間
* FROM 駐輪場マスタ
* WHERE 閉設フラグ = 0
* ORDER BY 駐輪場ふりがな asc
*
* @return array 駐輪場マスタ情報
*/
private function getParkMasterInfo(): array
{
try {
$parkInfo = DB::table('park')
->select([
'park_id',
'park_name',
'renew_start_date',
'renew_start_time',
'renew_end_date',
'renew_end_time',
'reminder_type',
'reminder_time'
])
->where('park_close_flag', 0)
->orderBy('park_ruby', 'asc')
->get()
->toArray();
Log::info('駐輪場マスタ情報取得完了', [
'park_count' => count($parkInfo)
]);
return $parkInfo;
} catch (\Exception $e) {
Log::error('駐輪場マスタ情報取得エラー', [
'error' => $e->getMessage()
]);
throw $e;
}
}
/**
* 【判断0】当該駐輪場実行タイミングチェック
*
* 仕様書に基づく複雑なリマインダー時期判定:
* - パターンA: 月を跨らない場合(更新期間開始日 <= 更新期間終了日)
* - パターンB: 月を跨る場合(更新期間開始日 > 更新期間終了日)
* - リマインダー種別による実行判定
*
* @param object $park 駐輪場情報
* @return array 実行タイミング判定結果
*/
private function checkExecutionTiming($park): array
{
try {
$today = Carbon::now();
$currentDate = $today->format('Y-m-d');
// 更新期間の日付を取得
$startDate = Carbon::parse($park->renew_start_date);
$endDate = Carbon::parse($park->renew_end_date);
Log::info('実行タイミングチェック開始', [
'park_id' => $park->park_id,
'current_date' => $currentDate,
'start_date' => $startDate->format('Y-m-d'),
'end_date' => $endDate->format('Y-m-d'),
'reminder_type' => $park->reminder_type
]);
// パターン判定: 月を跨るかどうか
$isPatternA = $startDate->lte($endDate); // パターンA: 月を跨らない
$isPatternB = !$isPatternA; // パターンB: 月を跨る
// 現在日付が更新期間内かチェック
$isWithinUpdatePeriod = false;
if ($isPatternA) {
// パターンA: 更新期間開始日 <= 現在日 <= 更新期間終了日
$isWithinUpdatePeriod = $today->between($startDate, $endDate);
} else {
// パターンB: 月を跨る場合の判定
// 現在日 >= 更新期間開始日 OR 現在日 <= 更新期間終了日
$isWithinUpdatePeriod = $today->gte($startDate) || $today->lte($endDate);
}
if (!$isWithinUpdatePeriod) {
return [
'should_execute' => false,
'reason' => '更新期間外のため実行対象外',
'pattern' => $isPatternA ? 'A' : 'B'
];
}
// リマインダー種別による実行判定
$reminderExecutionResult = $this->checkReminderTiming($park, $today, $startDate, $endDate, $isPatternA);
Log::info('実行タイミングチェック完了', [
'park_id' => $park->park_id,
'should_execute' => $reminderExecutionResult['should_execute'],
'pattern' => $isPatternA ? 'A' : 'B',
'reminder_result' => $reminderExecutionResult
]);
return $reminderExecutionResult;
} catch (\Exception $e) {
Log::error('実行タイミングチェックエラー', [
'park_id' => $park->park_id,
'error' => $e->getMessage()
]);
throw $e;
}
}
/**
* リマインダー時期の詳細判定
*
* 仕様書の複雑なリマインダー種別判定を実装
* パターンA/Bに基づく詳細な日付計算ロジック
*
* @param object $park 駐輪場情報
* @param Carbon $today 現在日
* @param Carbon $startDate 更新期間開始日
* @param Carbon $endDate 更新期間終了日
* @param bool $isPatternA パターンAかどうか
* @return array リマインダー実行判定結果
*/
private function checkReminderTiming($park, Carbon $today, Carbon $startDate, Carbon $endDate, bool $isPatternA): array
{
$reminderType = $park->reminder_type ?? 0;
// リマインダー種別 = 0 の場合は実行しない
if ($reminderType == 0) {
return [
'should_execute' => false,
'reason' => 'リマインダー種別=0のため実行対象外'
];
}
// 仕様書に基づく詳細なリマインダー時期判定
$executionCheck = $this->performDetailedReminderCheck($park, $today, $startDate, $endDate, $isPatternA);
return [
'should_execute' => $executionCheck['should_execute'],
'reason' => $executionCheck['reason'],
'reminder_type' => $reminderType,
'pattern' => $isPatternA ? 'A' : 'B',
'execution_details' => $executionCheck
];
}
/**
* 仕様書に基づく詳細なリマインダー実行判定
*
* 複雑な条件分岐を含む実行フラグ判定処理
* - パターンA/Bによる分岐
* - リマインダー種別による日数計算
* - 月跨ぎ処理の考慮
*
* @param object $park 駐輪場情報
* @param Carbon $today 現在日
* @param Carbon $startDate 更新期間開始日
* @param Carbon $endDate 更新期間終了日
* @param bool $isPatternA パターンAかどうか
* @return array 実行判定詳細結果
*/
private function performDetailedReminderCheck($park, Carbon $today, Carbon $startDate, Carbon $endDate, bool $isPatternA): array
{
$reminderType = $park->reminder_type ?? 0;
// 内部変数 更新パターン判定
$updatePattern = '';
if ($isPatternA) {
// パターンA: 月を跨らない場合
if ($startDate->lte($endDate)) {
$updatePattern = 'A';
} else {
$updatePattern = 'B'; // 実際はパターンBになる
}
} else {
// パターンB: 月を跨る場合
$updatePattern = 'B';
}
// 実行フラグ判定処理
$executionFlag = $this->calculateExecutionFlag($today, $startDate, $endDate, $reminderType, $updatePattern);
Log::info('詳細リマインダー判定完了', [
'park_id' => $park->park_id,
'reminder_type' => $reminderType,
'update_pattern' => $updatePattern,
'execution_flag' => $executionFlag,
'today' => $today->format('Y-m-d'),
'start_date' => $startDate->format('Y-m-d'),
'end_date' => $endDate->format('Y-m-d')
]);
return [
'should_execute' => $executionFlag['should_execute'],
'reason' => $executionFlag['reason'],
'update_pattern' => $updatePattern,
'execution_details' => $executionFlag
];
}
/**
* 実行フラグ計算処理
*
* 仕様書の複雑な分岐条件に基づく実行判定
*
* @param Carbon $today 現在日
* @param Carbon $startDate 更新期間開始日
* @param Carbon $endDate 更新期間終了日
* @param int $reminderType リマインダー種別
* @param string $updatePattern 更新パターンA/B
* @return array 実行フラグ判定結果
*/
private function calculateExecutionFlag(Carbon $today, Carbon $startDate, Carbon $endDate, int $reminderType, string $updatePattern): array
{
// リマインダー種別による実行判定
switch ($reminderType) {
case 1: // -1日前
return $this->checkReminderType1($today, $startDate, $endDate, $updatePattern);
case 2: // -2日前
return $this->checkReminderType2($today, $startDate, $endDate, $updatePattern);
default:
return [
'should_execute' => false,
'reason' => "未対応のリマインダー種別: {$reminderType}"
];
}
}
/**
* リマインダー種別=1-1日前)の判定
*
* @param Carbon $today 現在日
* @param Carbon $startDate 更新期間開始日
* @param Carbon $endDate 更新期間終了日
* @param string $updatePattern 更新パターン
* @return array 判定結果
*/
private function checkReminderType1(Carbon $today, Carbon $startDate, Carbon $endDate, string $updatePattern): array
{
// 更新期間終了日の1日前が実行日
$executionDate = $endDate->copy()->subDay();
if ($today->isSameDay($executionDate)) {
return [
'should_execute' => true,
'reason' => '-1日前のリマインダー実行日',
'execution_date' => $executionDate->format('Y-m-d')
];
}
return [
'should_execute' => false,
'reason' => "リマインダー実行日({$executionDate->format('Y-m-d')})ではない(現在: {$today->format('Y-m-d')}",
'execution_date' => $executionDate->format('Y-m-d')
];
}
/**
* リマインダー種別=2-2日前)の判定
*
* @param Carbon $today 現在日
* @param Carbon $startDate 更新期間開始日
* @param Carbon $endDate 更新期間終了日
* @param string $updatePattern 更新パターン
* @return array 判定結果
*/
private function checkReminderType2(Carbon $today, Carbon $startDate, Carbon $endDate, string $updatePattern): array
{
// 更新期間終了日の2日前が実行日
$executionDate = $endDate->copy()->subDays(2);
if ($today->isSameDay($executionDate)) {
return [
'should_execute' => true,
'reason' => '-2日前のリマインダー実行日',
'execution_date' => $executionDate->format('Y-m-d')
];
}
return [
'should_execute' => false,
'reason' => "リマインダー実行日({$executionDate->format('Y-m-d')})ではない(現在: {$today->format('Y-m-d')}",
'execution_date' => $executionDate->format('Y-m-d')
];
}
/**
* 【処理2】定期更新対象者を取得する
*
* 仕様書に基づく複雑なSQLクエリ:
* 定期契約マスタ T1 利用者マスタ T2 を結合して
* 更新対象者の情報を取得する
*
* @param int $parkId 駐輪場ID
* @return array 定期更新対象者情報
*/
private function getRegularUpdateTargetUsers(int $parkId): array
{
try {
$currentDate = Carbon::now()->format('Y-m-d');
// 仕様書に記載されたSQLクエリに基づく対象者取得
$targetUsers = DB::table('regular_contract as T1')
->select([
'T1.contract_id as 定期契約内ID',
'T1.park_id as 駐輪場ID',
'T2.user_id as 利用者ID',
'T2.user_manual_regist_flag as 手動登録フラグ',
'T2.user_primemail as メールアドレス',
'T2.user_submail as 予備メールアドレス',
'T2.user_name as 氏名',
'T1.contract_periode as 有効期間E'
])
->join('user as T2', 'T1.user_id', '=', 'T2.user_id')
->where('T1.park_id', $parkId)
->where('T1.contract_periode', '<=', $currentDate) // 更新可能日チェック
->where('T1.contract_cancel_flag', 0) // 解約フラグ = 0
->where('T2.user_quit_flag', 0) // 退会フラグ = 0
->where('T1.contract_flag', 1) // 承認フラグ = 1
->whereNull('T1.contract_permission') // 更新済フラグ is null
->get()
->toArray();
Log::info('定期更新対象者取得完了', [
'park_id' => $parkId,
'target_users_count' => count($targetUsers)
]);
return $targetUsers;
} catch (\Exception $e) {
Log::error('定期更新対象者取得エラー', [
'park_id' => $parkId,
'error' => $e->getMessage()
]);
throw $e;
}
}
/**
* 【処理3】対象者の処理実行
*
* 手動登録フラグによって処理を分岐:
* - = 0 (ウェブ申込み): SHJ-7メール送信を呼び出し
* - その他: 内部変数のカウントアップ(オペレーターキュー処理)
*
* @param object $targetUser 対象者情報
* @return array 処理結果
*/
private function processTargetUser($targetUser): array
{
try {
$manualRegistFlag = $targetUser->手動登録フラグ ?? 1;
if ($manualRegistFlag == 0) {
// ウェブ申込み: SHJ-7メール送信処理
return $this->sendReminderMail($targetUser);
} else {
// その他: オペレーターキュー追加処理(内部変数カウントアップ)
Log::info('オペレーターキュー対象者', [
'user_id' => $targetUser->利用者ID,
'contract_id' => $targetUser->定期契約内ID,
'manual_regist_flag' => $manualRegistFlag
]);
return [
'type' => 'operator_queue',
'success' => true,
'message' => 'オペレーターキュー対象として処理'
];
}
} catch (\Exception $e) {
Log::error('対象者処理エラー', [
'user_id' => $targetUser->利用者ID ?? 'unknown',
'error' => $e->getMessage()
]);
return [
'type' => 'error',
'success' => false,
'message' => $e->getMessage()
];
}
}
/**
* リマインダーメール送信処理
*
* SHJ-7メール送信処理を呼び出し、使用プログラムID=200を使用
*
* @param object $targetUser 対象者情報
* @return array 送信結果
*/
private function sendReminderMail($targetUser): array
{
try {
$mailAddress = $targetUser->メールアドレス ?? '';
$backupMailAddress = $targetUser->予備メールアドレス ?? '';
$mailTemplateId = 200; // 使用プログラムID
Log::info('SHJ-7メール送信処理呼び出し', [
'user_id' => $targetUser->利用者ID,
'contract_id' => $targetUser->定期契約内ID,
'mail_address' => $mailAddress,
'backup_mail_address' => $backupMailAddress,
'mail_template_id' => $mailTemplateId
]);
// SHJ-7メール送信処理実行
$mailResult = $this->mailSendService->executeMailSend(
$mailAddress,
$backupMailAddress,
$mailTemplateId
);
if ($mailResult['success']) {
return [
'type' => 'mail_success',
'success' => true,
'message' => 'メール送信成功',
'mail_result' => $mailResult
];
} else {
return [
'type' => 'mail_error',
'success' => false,
'message' => 'メール送信失敗: ' . $mailResult['message'],
'mail_result' => $mailResult
];
}
} catch (\Exception $e) {
Log::error('リマインダーメール送信エラー', [
'user_id' => $targetUser->利用者ID ?? 'unknown',
'error' => $e->getMessage()
]);
return [
'type' => 'mail_error',
'success' => false,
'message' => 'メール送信エラー: ' . $e->getMessage()
];
}
}
/**
* 【処理4】SHJ-8バッチ処理ログ作成
*
* 仕様書に基づくSHJ-8共通処理呼び出し
*
* @param array $statistics 処理統計情報
* @return void
*/
private function createShjBatchLog(array $statistics): void
{
try {
// 仕様書に基づくSHJ-8パラメータ設定
$deviceId = 9999; // テスト用デバイスID規格書では"-"だが、既存実装に合わせて9999使用
$processName = 'SHJ-3定期更新リマインダー';
$jobName = 'success';
$status = 'success';
// ステータスコメント生成
$statusComment = "メール正常終了件数: {$statistics['mail_success_count']}" .
" + メール異常終了件数: {$statistics['mail_error_count']}" .
" + キュー登録正常終了件数: {$statistics['operator_queue_count']}";
$createdDate = now()->format('Y/m/d');
$updatedDate = now()->format('Y/m/d');
Log::info('SHJ-8バッチ処理ログ作成', [
'device_id' => $deviceId,
'process_name' => $processName,
'job_name' => $jobName,
'status' => $status,
'status_comment' => $statusComment,
'created_date' => $createdDate,
'updated_date' => $updatedDate
]);
// 共通処理SHJ-8バッチ処理ログ作成を呼び出し
// 注意: 実際の運用では外部コマンド呼び出しまたは専用サービス経由で実行
BatchLog::createBatchLog(
$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) {
Log::error('SHJ-8バッチ処理ログ作成エラー', [
'error' => $e->getMessage(),
'statistics' => $statistics
]);
// SHJ-8でエラーが発生してもメイン処理は継続
// エラーログのみ出力
}
}
}