846 lines
34 KiB
PHP
846 lines
34 KiB
PHP
<?php
|
||
|
||
namespace App\Services;
|
||
|
||
use App\Models\Park;
|
||
use App\Models\User;
|
||
use App\Models\RegularContract;
|
||
use App\Models\OperatorQue;
|
||
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;
|
||
|
||
/**
|
||
* OperatorQue モデル
|
||
*
|
||
* @var OperatorQue
|
||
*/
|
||
protected $operatorQueModel;
|
||
|
||
/**
|
||
* BatchLog モデル
|
||
*
|
||
* @var BatchLog
|
||
*/
|
||
protected $batchLogModel;
|
||
|
||
/**
|
||
* ShjMailSendService
|
||
*
|
||
* @var ShjMailSendService
|
||
*/
|
||
protected $mailSendService;
|
||
|
||
/**
|
||
* コンストラクタ
|
||
*
|
||
* @param Park $parkModel
|
||
* @param User $userModel
|
||
* @param RegularContract $contractModel
|
||
* @param OperatorQue $operatorQueModel
|
||
* @param BatchLog $batchLogModel
|
||
* @param ShjMailSendService $mailSendService
|
||
*/
|
||
public function __construct(
|
||
Park $parkModel,
|
||
User $userModel,
|
||
RegularContract $contractModel,
|
||
OperatorQue $operatorQueModel,
|
||
BatchLog $batchLogModel,
|
||
ShjMailSendService $mailSendService
|
||
) {
|
||
$this->parkModel = $parkModel;
|
||
$this->userModel = $userModel;
|
||
$this->contractModel = $contractModel;
|
||
$this->operatorQueModel = $operatorQueModel;
|
||
$this->batchLogModel = $batchLogModel;
|
||
$this->mailSendService = $mailSendService;
|
||
}
|
||
|
||
/**
|
||
* SHJ-3 定期更新リマインダー処理メイン実行
|
||
*
|
||
* 処理フロー(仕様書準拠):
|
||
* 【処理0】駐輪場マスタの情報を取得する
|
||
* 【判断0】当該駐輪場実行タイミングチェック
|
||
* 【処理2】定期更新対象者を取得する
|
||
* 【判断2】利用者有無をチェック
|
||
* 【処理3】対象者向けにメール送信、またはオペレーターキュー追加処理
|
||
* 【処理4】バッチ処理ログを作成する(各駐輪場ごとに実行)
|
||
*
|
||
* @return array 処理結果
|
||
*/
|
||
public function executeReminderProcess(): array
|
||
{
|
||
$overallProcessedParksCount = 0;
|
||
$overallTotalTargetUsers = 0;
|
||
$overallMailSuccessCount = 0;
|
||
$overallMailErrorCount = 0;
|
||
$overallQueueSuccessCount = 0;
|
||
$overallQueueErrorCount = 0;
|
||
|
||
try {
|
||
Log::info('SHJ-3 定期更新リマインダー処理開始');
|
||
|
||
// 【処理0】駐輪場マスタの情報を取得する
|
||
$parkList = $this->getParkMasterInfo();
|
||
|
||
if (empty($parkList)) {
|
||
$message = '対象の駐輪場マスタが見つかりません';
|
||
Log::warning($message);
|
||
|
||
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
|
||
];
|
||
}
|
||
|
||
// 取得レコード数分【判断0】を繰り返す
|
||
foreach ($parkList as $park) {
|
||
// 各駐輪場ごとの内部変数(仕様書:場景A)
|
||
$mailSuccessCount = 0;
|
||
$mailErrorCount = 0;
|
||
$queueSuccessCount = 0;
|
||
$queueErrorCount = 0;
|
||
$batchComment = '';
|
||
|
||
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;
|
||
}
|
||
|
||
$overallProcessedParksCount++;
|
||
|
||
// 【処理2】定期更新対象者を取得する
|
||
$targetUsers = $this->getRegularUpdateTargetUsers(
|
||
$park,
|
||
$timingCheckResult['update_pattern']
|
||
);
|
||
|
||
// 【判断2】利用者有無をチェック
|
||
if (empty($targetUsers)) {
|
||
// 仕様書:利用者なしの結果を設定する
|
||
$batchComment = "定期更新リマインダー:今月の定期更新対象者は無しです / {$park->park_name}";
|
||
|
||
Log::info('利用者なし', [
|
||
'park_id' => $park->park_id,
|
||
'batch_comment' => $batchComment
|
||
]);
|
||
|
||
// 【処理4】バッチ処理ログを作成する
|
||
$this->createShjBatchLog(
|
||
$park,
|
||
$batchComment,
|
||
$mailSuccessCount,
|
||
$mailErrorCount,
|
||
$queueSuccessCount,
|
||
$queueErrorCount
|
||
);
|
||
|
||
// 次の駐輪場マスタへ
|
||
continue;
|
||
}
|
||
|
||
$overallTotalTargetUsers += count($targetUsers);
|
||
|
||
// 【処理3】処理2の対象レコード数分繰り返す
|
||
foreach ($targetUsers as $targetUser) {
|
||
$processResult = $this->processTargetUser($targetUser, $park);
|
||
|
||
if ($processResult['type'] === 'mail_success') {
|
||
$mailSuccessCount++;
|
||
} elseif ($processResult['type'] === 'mail_error') {
|
||
$mailErrorCount++;
|
||
// バッチコメントに異常情報を追加
|
||
if (!empty($processResult['error_info'])) {
|
||
$batchComment .= ($batchComment ? ' / ' : '') . $processResult['error_info'];
|
||
}
|
||
} elseif ($processResult['type'] === 'queue_success') {
|
||
$queueSuccessCount++;
|
||
} elseif ($processResult['type'] === 'queue_error') {
|
||
$queueErrorCount++;
|
||
}
|
||
}
|
||
|
||
// 全体集計用に加算
|
||
$overallMailSuccessCount += $mailSuccessCount;
|
||
$overallMailErrorCount += $mailErrorCount;
|
||
$overallQueueSuccessCount += $queueSuccessCount;
|
||
$overallQueueErrorCount += $queueErrorCount;
|
||
|
||
Log::info('駐輪場処理完了', [
|
||
'park_id' => $park->park_id,
|
||
'target_users_count' => count($targetUsers),
|
||
'mail_success' => $mailSuccessCount,
|
||
'mail_error' => $mailErrorCount,
|
||
'queue_success' => $queueSuccessCount,
|
||
'queue_error' => $queueErrorCount
|
||
]);
|
||
|
||
// 【処理4】バッチ処理ログを作成する(各駐輪場ごと)
|
||
$this->createShjBatchLog(
|
||
$park,
|
||
$batchComment,
|
||
$mailSuccessCount,
|
||
$mailErrorCount,
|
||
$queueSuccessCount,
|
||
$queueErrorCount
|
||
);
|
||
}
|
||
|
||
Log::info('SHJ-3 定期更新リマインダー処理完了', [
|
||
'processed_parks_count' => $overallProcessedParksCount,
|
||
'total_target_users' => $overallTotalTargetUsers,
|
||
'mail_success_count' => $overallMailSuccessCount,
|
||
'mail_error_count' => $overallMailErrorCount,
|
||
'queue_success_count' => $overallQueueSuccessCount,
|
||
'queue_error_count' => $overallQueueErrorCount
|
||
]);
|
||
|
||
return [
|
||
'success' => true,
|
||
'message' => 'SHJ-3 定期更新リマインダー処理が正常に完了しました',
|
||
'processed_parks_count' => $overallProcessedParksCount,
|
||
'total_target_users' => $overallTotalTargetUsers,
|
||
'mail_success_count' => $overallMailSuccessCount,
|
||
'mail_error_count' => $overallMailErrorCount,
|
||
'operator_queue_count' => $overallQueueSuccessCount + $overallQueueErrorCount
|
||
];
|
||
|
||
} catch (\Exception $e) {
|
||
$errorMessage = 'SHJ-3 定期更新リマインダー処理でエラーが発生: ' . $e->getMessage();
|
||
|
||
Log::error('SHJ-3 定期更新リマインダー処理エラー', [
|
||
'exception' => $e->getMessage(),
|
||
'trace' => $e->getTraceAsString()
|
||
]);
|
||
|
||
return [
|
||
'success' => false,
|
||
'message' => $errorMessage,
|
||
'details' => $e->getMessage(),
|
||
'processed_parks_count' => $overallProcessedParksCount,
|
||
'total_target_users' => $overallTotalTargetUsers,
|
||
'mail_success_count' => $overallMailSuccessCount,
|
||
'mail_error_count' => $overallMailErrorCount,
|
||
'operator_queue_count' => $overallQueueSuccessCount + $overallQueueErrorCount
|
||
];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 【処理0】駐輪場マスタの情報を取得する
|
||
*
|
||
* 仕様書に基づくSQLクエリ:
|
||
* SELECT 駐輪場ID, 駐輪場名, 更新期間開始日, 更新期間開始時,
|
||
* 更新期間終了日, 更新期間終了時, リマインダー種別, リマインダー時間
|
||
* FROM 駐輪場マスタ
|
||
* WHERE 閉設フラグ = 0
|
||
* ORDER BY 駐輪場ふりがな asc
|
||
*
|
||
* @return array 駐輪場マスタ情報
|
||
*/
|
||
private function getParkMasterInfo(): array
|
||
{
|
||
try {
|
||
$parkInfo = DB::table('park')
|
||
->select([
|
||
'park_id', // 駐輪場ID
|
||
'park_name', // 駐輪場名
|
||
'update_grace_period_start_date', // 更新期間開始日(例:"20")
|
||
'update_grace_period_start_time', // 更新期間開始時(例:"09:00")
|
||
'update_grace_period_end_date', // 更新期間終了日(例:"6")
|
||
'update_grace_period_end_time', // 更新期間終了時(例:"23:59")
|
||
'reminder_type', // リマインダー種別(0=毎日,1=1日おき,2=2日おき)
|
||
'reminder_time' // リマインダー時間(例:"09:00")
|
||
])
|
||
->where('park_close_flag', 0) // 閉設フラグ = 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】当該駐輪場実行タイミングチェック
|
||
*
|
||
* 仕様書に基づく実行タイミング判定:
|
||
* 1. リマインダー時間 = 現在の時間 のチェック
|
||
* 2. 内部変数.更新パターン の設定(A or B)
|
||
* 3. 内部変数.更新期間開始日からの経過日数 の算出
|
||
* 4. 内部変数.実行フラグ の判定
|
||
*
|
||
* @param object $park 駐輪場情報
|
||
* @return array 実行タイミング判定結果
|
||
*/
|
||
private function checkExecutionTiming($park): array
|
||
{
|
||
try {
|
||
$now = Carbon::now();
|
||
$currentTime = $now->format('H:i');
|
||
$todayDay = (int)$now->format('d'); // 本日の日(1-31)
|
||
|
||
Log::info('実行タイミングチェック開始', [
|
||
'park_id' => $park->park_id,
|
||
'current_time' => $currentTime,
|
||
'today_day' => $todayDay,
|
||
'reminder_time' => $park->reminder_time,
|
||
'reminder_type' => $park->reminder_type
|
||
]);
|
||
|
||
// 仕様書:駐輪場マスタ.リマインダー時間 = [現在の時間] の場合
|
||
if ($park->reminder_time !== $currentTime) {
|
||
return [
|
||
'should_execute' => false,
|
||
'reason' => "リマインダー時間不一致(設定:{$park->reminder_time} vs 現在:{$currentTime})"
|
||
];
|
||
}
|
||
|
||
// 内部変数.更新パターン を設定
|
||
// DBから返る値は文字列なので、型変換して使用
|
||
$startDay = (int)$park->update_grace_period_start_date; // 例:"20" → 20
|
||
$endDay = (int)$park->update_grace_period_end_date; // 例:"6" → 6
|
||
|
||
$updatePattern = '';
|
||
if ($startDay <= $endDay) {
|
||
// パターンA: 月を跨らない場合
|
||
$updatePattern = 'A';
|
||
} else {
|
||
// パターンB: 月を跨る場合
|
||
$updatePattern = 'B';
|
||
}
|
||
|
||
// 内部変数.更新期間開始日からの経過日数 を設定
|
||
$elapsedDays = 99; // デフォルト: 対象外
|
||
|
||
if ($updatePattern === 'A') {
|
||
// パターンA の場合
|
||
if ($endDay < $todayDay) {
|
||
// 駐輪場マスタ.更新期間終了日 > [本日の日付]の日 の場合
|
||
$elapsedDays = 99; // 対象外
|
||
} elseif ($startDay <= $todayDay) {
|
||
// 駐輪場マスタ.更新期間開始日 <= [本日の日付]の日 の場合
|
||
$elapsedDays = $todayDay - $startDay;
|
||
} else {
|
||
// その他の場合
|
||
$elapsedDays = 99; // 対象外
|
||
}
|
||
} else {
|
||
// パターンB の場合
|
||
if ($startDay <= $todayDay) {
|
||
// 駐輪場マスタ.更新期間開始日 <= [本日の日付]の日 の場合
|
||
$elapsedDays = $todayDay - $startDay;
|
||
} elseif ($endDay >= $todayDay) {
|
||
// 駐輪場マスタ.更新期間終了日 >= [本日の日付]の日 の場合
|
||
// 仕様書の計算式: ([先月の月末日]の日 − 駐輪場マスタ.更新期間開始日) + [本日の日付]の日
|
||
$lastMonthEnd = $now->copy()->subMonth()->endOfMonth()->day;
|
||
$elapsedDays = ($lastMonthEnd - $startDay) + $todayDay;
|
||
} else {
|
||
// その他の場合
|
||
$elapsedDays = 99; // 対象外
|
||
}
|
||
}
|
||
|
||
Log::info('経過日数算出完了', [
|
||
'park_id' => $park->park_id,
|
||
'update_pattern' => $updatePattern,
|
||
'start_day' => $startDay,
|
||
'end_day' => $endDay,
|
||
'today_day' => $todayDay,
|
||
'elapsed_days' => $elapsedDays
|
||
]);
|
||
|
||
// 内部変数.実行フラグ を設定
|
||
$executionFlag = 0;
|
||
|
||
if ($elapsedDays !== 99) {
|
||
// DBから返る値は文字列なので、型変換して比較
|
||
$reminderType = (int)($park->reminder_type ?? 0);
|
||
|
||
if ($reminderType === 0) {
|
||
// 仕様書:毎日
|
||
$executionFlag = 1;
|
||
} elseif ($reminderType === 1) {
|
||
// 仕様書:1日おき(経過日数が偶数の場合)
|
||
$executionFlag = ($elapsedDays % 2 === 0) ? 1 : 0;
|
||
} elseif ($reminderType === 2) {
|
||
// 仕様書:2日おき(経過日数を3で割った余りが0の場合)
|
||
$executionFlag = ($elapsedDays % 3 === 0) ? 1 : 0;
|
||
} else {
|
||
// あり得ない
|
||
$executionFlag = 0;
|
||
}
|
||
}
|
||
|
||
$shouldExecute = ($executionFlag === 1);
|
||
|
||
Log::info('実行タイミングチェック完了', [
|
||
'park_id' => $park->park_id,
|
||
'update_pattern' => $updatePattern,
|
||
'elapsed_days' => $elapsedDays,
|
||
'reminder_type' => $park->reminder_type,
|
||
'execution_flag' => $executionFlag,
|
||
'should_execute' => $shouldExecute
|
||
]);
|
||
|
||
return [
|
||
'should_execute' => $shouldExecute,
|
||
'reason' => $shouldExecute ? '実行対象' : "実行フラグ=0(経過日数:{$elapsedDays}, リマインダー種別:{$park->reminder_type})",
|
||
'update_pattern' => $updatePattern,
|
||
'elapsed_days' => $elapsedDays,
|
||
'execution_flag' => $executionFlag
|
||
];
|
||
|
||
} catch (\Exception $e) {
|
||
Log::error('実行タイミングチェックエラー', [
|
||
'park_id' => $park->park_id ?? 'unknown',
|
||
'error' => $e->getMessage(),
|
||
'trace' => $e->getTraceAsString()
|
||
]);
|
||
|
||
throw $e;
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* 【処理2】定期更新対象者を取得する
|
||
*
|
||
* 仕様書に基づくSQLクエリ:
|
||
* 定期契約マスタ T1 と 利用者マスタ T2 を結合して更新対象者の情報を取得する
|
||
*
|
||
* WHERE条件:
|
||
* - T1.駐輪場ID = 処理0.駐輪場ID
|
||
* - T1.更新可能日 <= 本日の日付
|
||
* - T1.解約フラグ = 0
|
||
* - T2.退会フラグ = 0
|
||
* - T1.授受フラグ = 1
|
||
* - T1.更新済フラグ is null
|
||
* - 更新パターンによる有効期間Eの判定
|
||
*
|
||
* @param object $park 駐輪場情報
|
||
* @param string $updatePattern 更新パターン("A" or "B")
|
||
* @return array 定期更新対象者情報
|
||
*/
|
||
private function getRegularUpdateTargetUsers($park, string $updatePattern): array
|
||
{
|
||
try {
|
||
$now = Carbon::now();
|
||
$currentDate = $now->format('Y-m-d');
|
||
$todayDay = (int)$now->format('d'); // 本日の日(1-31)
|
||
// DBから返る値は文字列なので、型変換して使用
|
||
$startDay = (int)$park->update_grace_period_start_date; // 例:"20" → 20
|
||
$endDay = (int)$park->update_grace_period_end_date; // 例:"6" → 6
|
||
|
||
// 有効期間E(契約終了日)の判定
|
||
$thisMonthEnd = $now->copy()->endOfMonth()->format('Y-m-d');
|
||
$lastMonthEnd = $now->copy()->subMonth()->endOfMonth()->format('Y-m-d');
|
||
|
||
$query = DB::table('regular_contract as T1')
|
||
->select([
|
||
'T1.contract_id as 定期契約ID',
|
||
'T1.park_id as 駐輪場ID',
|
||
'T2.user_seq as 利用者ID', // user_seqが主キー
|
||
'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_seq') // user_seqに結合
|
||
->where('T1.park_id', $park->park_id) // 駐輪場ID
|
||
->where('T1.contract_updated_at', '<=', $currentDate) // 更新可能日
|
||
->where('T1.contract_cancel_flag', 0) // 解約フラグ = 0
|
||
->where('T2.user_quit_flag', 0) // 退会フラグ = 0
|
||
->where('T1.contract_flag', 1) // 授受フラグ = 1
|
||
->whereNull('T1.contract_renewal'); // 更新済フラグ is null
|
||
|
||
// 仕様書:更新パターンによる有効期間Eの判定
|
||
if ($updatePattern === 'A') {
|
||
// パターンA の場合: 有効期間E = 今月末
|
||
$query->where('T1.contract_periode', '=', $thisMonthEnd);
|
||
} else {
|
||
// パターンB の場合
|
||
if ($startDay <= $todayDay) {
|
||
// 処理0.更新期間開始日 <= [本日の日付]の日 の場合
|
||
$query->where('T1.contract_periode', '=', $thisMonthEnd);
|
||
} elseif ($endDay >= $todayDay) {
|
||
// 処理0.更新期間終了日 >= [本日の日付]の日 の場合
|
||
$query->where('T1.contract_periode', '=', $lastMonthEnd);
|
||
}
|
||
}
|
||
|
||
$targetUsers = $query->get()->toArray();
|
||
|
||
Log::info('定期更新対象者取得完了', [
|
||
'park_id' => $park->park_id,
|
||
'update_pattern' => $updatePattern,
|
||
'this_month_end' => $thisMonthEnd,
|
||
'last_month_end' => $lastMonthEnd,
|
||
'target_users_count' => count($targetUsers)
|
||
]);
|
||
|
||
return $targetUsers;
|
||
|
||
} catch (\Exception $e) {
|
||
Log::error('定期更新対象者取得エラー', [
|
||
'park_id' => $park->park_id ?? 'unknown',
|
||
'update_pattern' => $updatePattern ?? 'unknown',
|
||
'error' => $e->getMessage(),
|
||
'trace' => $e->getTraceAsString()
|
||
]);
|
||
|
||
throw $e;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 【処理3】対象者の処理実行
|
||
*
|
||
* 手動登録フラグによって処理を分岐:
|
||
* - = 0 (ウェブ申込み): SHJ-7メール送信を呼び出し
|
||
* - その他: オペレーターキュー追加処理
|
||
*
|
||
* @param object $targetUser 対象者情報
|
||
* @param object $park 駐輪場情報
|
||
* @return array 処理結果
|
||
*/
|
||
private function processTargetUser($targetUser, $park): array
|
||
{
|
||
try {
|
||
$manualRegistFlag = $targetUser->手動登録フラグ ?? 1;
|
||
|
||
if ($manualRegistFlag == 0) {
|
||
// 仕様書:手動登録フラグ = 0(ウェブ申込み)の場合
|
||
// SHJ-7メール送信処理を呼び出し
|
||
return $this->sendReminderMail($targetUser);
|
||
} else {
|
||
// 仕様書:手動登録フラグ <> 0 の場合
|
||
// オペレーターキュー追加処理
|
||
// ※文書には詳細仕様なし。他のService実装を参考に実装
|
||
return $this->addToOperatorQueue($targetUser, $park);
|
||
}
|
||
|
||
} catch (\Exception $e) {
|
||
Log::error('対象者処理エラー', [
|
||
'user_id' => $targetUser->利用者ID ?? 'unknown',
|
||
'contract_id' => $targetUser->定期契約ID ?? 'unknown',
|
||
'error' => $e->getMessage(),
|
||
'trace' => $e->getTraceAsString()
|
||
]);
|
||
|
||
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 = 200
|
||
|
||
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']) {
|
||
// 仕様書:処理結果 = 0(正常)の場合
|
||
Log::info('メール送信成功', [
|
||
'user_id' => $targetUser->利用者ID,
|
||
'contract_id' => $targetUser->定期契約ID
|
||
]);
|
||
|
||
return [
|
||
'type' => 'mail_success',
|
||
'success' => true,
|
||
'message' => 'メール送信成功',
|
||
'error_info' => null
|
||
];
|
||
} else {
|
||
// 仕様書:その他の場合(異常)
|
||
// バッチコメントに「処理2.定期契約ID」+「SHJ-7 メール送信.異常情報」を設定する(後ろに足す)
|
||
$errorInfo = "定期契約ID:{$targetUser->定期契約ID} / SHJ-7 メール送信.異常情報:{$mailResult['message']}";
|
||
|
||
Log::warning('メール送信失敗', [
|
||
'user_id' => $targetUser->利用者ID,
|
||
'contract_id' => $targetUser->定期契約ID,
|
||
'error' => $mailResult['message']
|
||
]);
|
||
|
||
return [
|
||
'type' => 'mail_error',
|
||
'success' => false,
|
||
'message' => 'メール送信失敗',
|
||
'error_info' => $errorInfo
|
||
];
|
||
}
|
||
|
||
} catch (\Exception $e) {
|
||
Log::error('リマインダーメール送信エラー', [
|
||
'user_id' => $targetUser->利用者ID ?? 'unknown',
|
||
'contract_id' => $targetUser->定期契約ID ?? 'unknown',
|
||
'error' => $e->getMessage(),
|
||
'trace' => $e->getTraceAsString()
|
||
]);
|
||
|
||
// 仕様書準拠のエラー情報フォーマット
|
||
$errorInfo = "定期契約ID:{$targetUser->定期契約ID} / SHJ-7 メール送信.異常情報:例外エラー - {$e->getMessage()}";
|
||
|
||
return [
|
||
'type' => 'mail_error',
|
||
'success' => false,
|
||
'message' => 'メール送信例外エラー',
|
||
'error_info' => $errorInfo
|
||
];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* オペレーターキュー追加処理
|
||
*
|
||
* 仕様書には詳細記載なし。
|
||
* 他のService(ShjOneService、ShjSixService)の実装を参考に実装。
|
||
*
|
||
* @param object $targetUser 対象者情報
|
||
* @param object $park 駐輪場情報
|
||
* @return array 追加結果
|
||
*/
|
||
private function addToOperatorQueue($targetUser, $park): array
|
||
{
|
||
try {
|
||
// operator_queテーブルに登録
|
||
$operatorQue = OperatorQue::create([
|
||
'que_class' => 5, // 定期更新通知(OperatorQueモデルの定数参照)
|
||
'user_id' => $targetUser->利用者ID,
|
||
'contract_id' => $targetUser->定期契約ID,
|
||
'park_id' => $targetUser->駐輪場ID,
|
||
'que_comment' => sprintf(
|
||
'定期更新通知 / 契約ID:%s / 利用者:%s / 駐輪場:%s',
|
||
$targetUser->定期契約ID,
|
||
$targetUser->氏名 ?? '',
|
||
$park->park_name ?? ''
|
||
),
|
||
'que_status' => 1, // キュー発生
|
||
'que_status_comment' => '',
|
||
'work_instructions' => '',
|
||
'operator_id' => 9999999, // 仕様書準拠:固定値(他Serviceと同様)
|
||
'created_at' => now(),
|
||
'updated_at' => now()
|
||
]);
|
||
|
||
Log::info('オペレーターキュー追加成功', [
|
||
'que_id' => $operatorQue->que_id,
|
||
'que_class' => 5,
|
||
'user_id' => $targetUser->利用者ID,
|
||
'contract_id' => $targetUser->定期契約ID,
|
||
'park_id' => $targetUser->駐輪場ID
|
||
]);
|
||
|
||
return [
|
||
'type' => 'queue_success',
|
||
'success' => true,
|
||
'message' => 'オペレーターキュー追加成功',
|
||
'que_id' => $operatorQue->que_id
|
||
];
|
||
|
||
} catch (\Exception $e) {
|
||
Log::error('オペレーターキュー追加エラー', [
|
||
'user_id' => $targetUser->利用者ID ?? 'unknown',
|
||
'contract_id' => $targetUser->定期契約ID ?? 'unknown',
|
||
'park_id' => $targetUser->駐輪場ID ?? 'unknown',
|
||
'error' => $e->getMessage(),
|
||
'trace' => $e->getTraceAsString()
|
||
]);
|
||
|
||
return [
|
||
'type' => 'queue_error',
|
||
'success' => false,
|
||
'message' => 'オペレーターキュー追加エラー: ' . $e->getMessage()
|
||
];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 【処理4】SHJ-8バッチ処理ログ作成
|
||
*
|
||
* 仕様書に基づくSHJ-8共通処理呼び出し
|
||
* BatchLog統一システムを使用してバッチ処理の実行ログを記録
|
||
* ※各駐輪場ごとに1回実行される
|
||
*
|
||
* @param object $park 駐輪場情報
|
||
* @param string $batchComment バッチコメント
|
||
* @param int $mailSuccessCount メール正常終了件数
|
||
* @param int $mailErrorCount メール異常終了件数
|
||
* @param int $queueSuccessCount キュー登録正常終了件数
|
||
* @param int $queueErrorCount キュー登録異常終了件数
|
||
* @return void
|
||
*/
|
||
private function createShjBatchLog(
|
||
$park,
|
||
string $batchComment,
|
||
int $mailSuccessCount,
|
||
int $mailErrorCount,
|
||
int $queueSuccessCount,
|
||
int $queueErrorCount
|
||
): void {
|
||
try {
|
||
// 仕様書:SHJ-8パラメータ設定
|
||
$deviceId = 9999999; // バッチ処理用固定デバイスID(他Serviceと同様)
|
||
$processName = 'SHJ-3';
|
||
$jobName = 'SHJ-3定期更新リマインダー';
|
||
$status = BatchLog::STATUS_SUCCESS;
|
||
|
||
// 仕様書:ステータスコメント生成
|
||
// 「内部変数.バッチコメント」+ "/" + 「処理1.駐輪場名」
|
||
// + ":メール正常終了件数" + 「内部変数.メール正常終了件数」
|
||
// + "、メール異常終了件数" + 「内部変数.メール異常終了件数」
|
||
// + "、キュー登録正常終了件数" + 「内部変数.キュー登録正常終了件数」
|
||
// + "、キュー登録異常終了件数" + 「内部変数.キュー登録異常終了件数」
|
||
$statusComment = ($batchComment ? $batchComment . ' / ' : '') .
|
||
"{$park->park_name} : " .
|
||
"メール正常終了件数={$mailSuccessCount}、" .
|
||
"メール異常終了件数={$mailErrorCount}、" .
|
||
"キュー登録正常終了件数={$queueSuccessCount}、" .
|
||
"キュー登録異常終了件数={$queueErrorCount}";
|
||
|
||
$createdDate = now()->format('Y/m/d');
|
||
$updatedDate = now()->format('Y/m/d');
|
||
|
||
Log::info('SHJ-8バッチ処理ログ作成', [
|
||
'park_id' => $park->park_id,
|
||
'park_name' => $park->park_name,
|
||
'device_id' => $deviceId,
|
||
'process_name' => $processName,
|
||
'job_name' => $jobName,
|
||
'status' => $status,
|
||
'status_comment' => $statusComment
|
||
]);
|
||
|
||
// 仕様書:共通処理「SHJ-8 バッチ処理ログ作成」を呼び出す
|
||
// BatchLog::createBatchLog を使用して統一的にログを記録
|
||
BatchLog::createBatchLog(
|
||
$processName,
|
||
$status,
|
||
[
|
||
'device_id' => $deviceId,
|
||
'job_name' => $jobName,
|
||
'park_id' => $park->park_id,
|
||
'park_name' => $park->park_name,
|
||
'status_comment' => $statusComment,
|
||
'statistics' => [
|
||
'mail_success_count' => $mailSuccessCount,
|
||
'mail_error_count' => $mailErrorCount,
|
||
'queue_success_count' => $queueSuccessCount,
|
||
'queue_error_count' => $queueErrorCount,
|
||
'batch_comment' => $batchComment
|
||
],
|
||
'shj8_params' => [
|
||
'device_id' => $deviceId,
|
||
'process_name' => $processName,
|
||
'job_name' => $jobName,
|
||
'status' => $status,
|
||
'created_date' => $createdDate,
|
||
'updated_date' => $updatedDate
|
||
]
|
||
],
|
||
$statusComment
|
||
);
|
||
|
||
} catch (\Exception $e) {
|
||
Log::error('SHJ-8バッチ処理ログ作成エラー', [
|
||
'park_id' => $park->park_id ?? 'unknown',
|
||
'error' => $e->getMessage(),
|
||
'trace' => $e->getTraceAsString()
|
||
]);
|
||
|
||
// 仕様書:SHJ-8でエラーが発生してもメイン処理は継続
|
||
// エラーログのみ出力
|
||
}
|
||
}
|
||
}
|