Compare commits
99 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 781e665d7e | |||
| a266cdca57 | |||
|
|
10a917b556 | ||
| d22bafbc93 | |||
| 0c076466a9 | |||
| 2fdb3ce74a | |||
| 778b3ac9cc | |||
| ae8315ba89 | |||
| fcf07cecc4 | |||
| c602b214e4 | |||
| a085a47e04 | |||
| 195f130a46 | |||
| 3c40565377 | |||
| 0a102e2a47 | |||
| a6637c9f72 | |||
| 61b3283b58 | |||
| c1e95ce881 | |||
| 7e2a25d37b | |||
| 184860862b | |||
| 57bae5bcf4 | |||
| 63efbb9481 | |||
| 6aebe63251 | |||
| f29ba66745 | |||
| ebd3a65096 | |||
| 89465021e4 | |||
| 5dff9d627a | |||
| e13302475e | |||
| 8a9bd9d569 | |||
| ca283fc9a9 | |||
| d84b0fb9e1 | |||
| e80b0639ca | |||
| 3cad3b3d0f | |||
| a139353a2f | |||
| 29f40c37bb | |||
| 8d33e2bf78 | |||
| 57efa7f63e | |||
| 9d9717863e | |||
| f22f447a86 | |||
| 0afe05606e | |||
| dfa786ca6f | |||
| e25df2dd27 | |||
|
|
253e388058 | ||
|
|
ff21ee5796 | ||
|
|
9441a34f6f | ||
| 56c7ae8778 | |||
| b4532dd76c | |||
| 7b2d8c4416 | |||
| 1ecaf6d46a | |||
| 23327a4ca3 | |||
| a34046b72a | |||
| 467ae8d055 | |||
| d2b631bbab | |||
| 8dc41b211c | |||
| 56ea54ab15 | |||
| 609faf58a4 | |||
| b18f4762bb | |||
| f389f1482a | |||
| 4f4a914b7d | |||
| d677aa232d | |||
| 70a0919746 | |||
| ecc7095818 | |||
| d1306131cf | |||
| 5a7721b217 | |||
| facc01dca6 | |||
| 3c0406727b | |||
| 926562d135 | |||
| bf7e6c901a | |||
| b2b359028b | |||
| 86af1df345 | |||
| 831b25ae8b | |||
| b6bbb605dd | |||
| 79fd7f2ca3 | |||
| 0e67f5a11b | |||
| e70c834bb0 | |||
| eed5d85741 | |||
|
|
3960e062b9 | ||
| bbc7ae7e83 | |||
| dce7e1daad | |||
| 41cd07db41 | |||
| 01c1f74d09 | |||
| ef056d1255 | |||
| 814b85cdbb | |||
| 3337d6abac | |||
| 52f568c5f4 | |||
| 3964a85578 | |||
| a85f96cc01 | |||
| 00ae084aad | |||
| 5ba63ace77 | |||
| 641375c7b4 | |||
| 8cf1d96eeb | |||
| ded82e0b8e | |||
| 8cae7b6c47 | |||
| de257704ab | |||
| ada3971259 | |||
| 62e0fe7f5c | |||
| 5682ea1614 | |||
| ada43efd75 | |||
| c8aba53248 | |||
| d5a4d8bd9c |
25
.env
25
.env
@ -2,7 +2,7 @@ APP_NAME=so-manager
|
||||
APP_ENV=local
|
||||
APP_KEY=base64:ejLwJbt2bEXY9emPUmsurG+X1hzkjTxQQvq2/FO14RY=
|
||||
APP_DEBUG=true
|
||||
APP_URL=http://www-somanager.localhost:81/
|
||||
APP_URL=https://so-manager-dev.com/public/
|
||||
APP_LOCALE=ja
|
||||
APP_FALLBACK_LOCALE=ja
|
||||
APP_FAKER_LOCALE=ja_JP
|
||||
@ -22,9 +22,9 @@ LOG_LEVEL=debug
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=localhost
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=somanager_admin
|
||||
DB_USERNAME=root
|
||||
DB_PASSWORD=
|
||||
DB_DATABASE=krgm
|
||||
DB_USERNAME=krgm_user
|
||||
DB_PASSWORD=StrongDbP@ss2
|
||||
|
||||
SESSION_DRIVER=database
|
||||
SESSION_LIFETIME=120
|
||||
@ -46,15 +46,16 @@ REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_MAILER=log
|
||||
MAIL_SCHEME=null
|
||||
MAIL_HOST=127.0.0.1
|
||||
MAIL_PORT=2525
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_FROM_ADDRESS="hp@so-manager-dev.com"
|
||||
MAIL_MAILER=smtp
|
||||
#MAIL_SCHEME=null
|
||||
MAIL_HOST=tomatofox9.sakura.ne.jp
|
||||
MAIL_PORT=587
|
||||
MAIL_USERNAME=demo@so-rin.jp
|
||||
MAIL_PASSWORD=rokuchou4665
|
||||
MAIL_ENCRYPTION=tls
|
||||
MAIL_FROM_ADDRESS=demo@so-rin.jp
|
||||
MAIL_FROM_NAME="${APP_NAME}"
|
||||
MAIL_ADMIN=null
|
||||
MAIL_ADMIN=demo@so-rin.jp
|
||||
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
|
||||
@ -4,54 +4,70 @@ namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Models\Batch\BatchLog;
|
||||
use App\Models\Device;
|
||||
use App\Services\ShjEightService;
|
||||
|
||||
/**
|
||||
* SHJ-8 バッチ処理ログ登録コマンド
|
||||
*
|
||||
* 統一BatchLogを使用してバッチ処理の実行ログをbatch_logテーブルに登録する
|
||||
* 仕様書に基づくSHJ-8の要求パラメータを受け取り、通用のログシステムで記録
|
||||
*
|
||||
* bat_job_logテーブルにバッチ処理の実行ログを登録する
|
||||
* ShjEightServiceを使用して実装
|
||||
*/
|
||||
class ShjBatchLogCommand extends Command
|
||||
{
|
||||
/**
|
||||
* ShjEightService インスタンス
|
||||
*
|
||||
* @var ShjEightService
|
||||
*/
|
||||
protected $shjEightService;
|
||||
|
||||
/**
|
||||
* コンソールコマンドの名前とシグネチャ
|
||||
*
|
||||
* 引数:
|
||||
*
|
||||
* 修正版:7項目(status_comment追加)
|
||||
* - device_id: デバイスID (必須)
|
||||
* - process_name: プロセス名 (必須)
|
||||
* - job_name: ジョブ名 (必須)
|
||||
* - status: ステータス (必須)
|
||||
* - status_comment: ステータスコメント (必須)
|
||||
* - created_date: 登録日時 (必須、yyyy/mm/dd形式)
|
||||
* - updated_date: 更新日時 (必須、yyyy/mm/dd形式)
|
||||
* - process_name: プロセス名 (オプション)
|
||||
* - job_name: ジョブ名 (オプション)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'shj:batch-log {device_id : デバイスID} {process_name : プロセス名} {job_name : ジョブ名} {status : ステータス} {created_date : 登録日時} {updated_date : 更新日時}';
|
||||
protected $signature = 'shj:batch-log
|
||||
{device_id : デバイスID}
|
||||
{status : ステータス}
|
||||
{status_comment : ステータスコメント}
|
||||
{created_date : 登録日時}
|
||||
{updated_date : 更新日時}
|
||||
{process_name? : プロセス名}
|
||||
{job_name? : ジョブ名}';
|
||||
|
||||
/**
|
||||
* コンソールコマンドの説明
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'SHJ-8 バッチ処理ログ登録 - バッチ処理の実行ログを登録';
|
||||
protected $description = 'SHJ-8 バッチ処理ログ登録 - bat_job_logテーブルにバッチ処理の実行ログを登録';
|
||||
|
||||
/**
|
||||
* コンストラクタ
|
||||
*
|
||||
* @param ShjEightService $shjEightService
|
||||
*/
|
||||
public function __construct()
|
||||
public function __construct(ShjEightService $shjEightService)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->shjEightService = $shjEightService;
|
||||
}
|
||||
|
||||
/**
|
||||
* コンソールコマンドを実行
|
||||
*
|
||||
*
|
||||
* 処理フロー:
|
||||
* 1. 入力パラメーターをチェックする
|
||||
* 2. 統一BatchLogを使用してbatch_logテーブルに記録
|
||||
* 3. 仕様書準拠の処理結果を返却する
|
||||
* 1. ShjEightServiceを呼び出して処理を実行
|
||||
* 2. 処理結果を返却する
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
@ -61,12 +77,13 @@ class ShjBatchLogCommand extends Command
|
||||
// 開始ログ出力
|
||||
$startTime = now();
|
||||
$this->info('SHJ-8 バッチ処理ログ登録を開始します。');
|
||||
|
||||
|
||||
// 引数取得
|
||||
$deviceId = (int) $this->argument('device_id');
|
||||
$processName = $this->argument('process_name');
|
||||
$jobName = $this->argument('job_name');
|
||||
$status = $this->argument('status');
|
||||
$statusComment = $this->argument('status_comment');
|
||||
$createdDate = $this->argument('created_date');
|
||||
$updatedDate = $this->argument('updated_date');
|
||||
|
||||
@ -76,163 +93,71 @@ class ShjBatchLogCommand extends Command
|
||||
'process_name' => $processName,
|
||||
'job_name' => $jobName,
|
||||
'status' => $status,
|
||||
'status_comment' => $statusComment,
|
||||
'created_date' => $createdDate,
|
||||
'updated_date' => $updatedDate
|
||||
]);
|
||||
|
||||
// 【処理1】入力パラメーターをチェックする
|
||||
$paramCheckResult = $this->validateParameters($deviceId, $processName, $jobName, $status, $createdDate, $updatedDate);
|
||||
if (!$paramCheckResult['valid']) {
|
||||
$this->error('パラメータエラー: ' . $paramCheckResult['message']);
|
||||
|
||||
// 仕様書【判断1】パラメーターNG時の結果出力
|
||||
$this->line('処理結果: 1'); // 1 = 異常終了
|
||||
$this->line('異常情報: ' . $paramCheckResult['message']);
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
// 【処理2】統一BatchLogを使用してログ登録
|
||||
$batchLog = BatchLog::createBatchLog(
|
||||
$processName, // 実際のプロセス名を使用
|
||||
// ShjEightServiceを呼び出して処理を実行
|
||||
$result = $this->shjEightService->execute(
|
||||
$deviceId,
|
||||
$processName,
|
||||
$jobName,
|
||||
$status,
|
||||
[
|
||||
'device_id' => $deviceId,
|
||||
'job_name' => $jobName,
|
||||
'status_comment' => BatchLog::getSuccessComment(),
|
||||
'input_created_date' => $createdDate,
|
||||
'input_updated_date' => $updatedDate,
|
||||
'shj8_params' => [
|
||||
'device_id' => $deviceId,
|
||||
'process_name' => $processName,
|
||||
'job_name' => $jobName,
|
||||
'status' => $status,
|
||||
'created_date' => $createdDate,
|
||||
'updated_date' => $updatedDate
|
||||
]
|
||||
],
|
||||
$jobName . ':' . BatchLog::getSuccessComment()
|
||||
$statusComment,
|
||||
$createdDate,
|
||||
$updatedDate
|
||||
);
|
||||
|
||||
$endTime = now();
|
||||
$this->info('SHJ-8 バッチ処理ログ登録が正常に完了しました。');
|
||||
$this->info("処理時間: {$startTime->diffInSeconds($endTime)}秒");
|
||||
|
||||
Log::info('SHJ-8 バッチ処理ログ登録完了', [
|
||||
'end_time' => $endTime,
|
||||
'duration_seconds' => $startTime->diffInSeconds($endTime),
|
||||
'batch_log_id' => $batchLog->id
|
||||
]);
|
||||
|
||||
// 仕様書【処理3】正常終了時の結果出力
|
||||
$this->line('処理結果: 0'); // 0 = 正常終了
|
||||
$this->line('異常情報: '); // 正常時は空文字
|
||||
// 処理結果に応じた出力
|
||||
if ($result['result'] === 0) {
|
||||
// 正常終了
|
||||
$this->info('SHJ-8 バッチ処理ログ登録が正常に完了しました。');
|
||||
$this->info("処理時間: {$startTime->diffInSeconds($endTime)}秒");
|
||||
|
||||
return self::SUCCESS;
|
||||
// 標準出力形式 (SHJ-8仕様書準拠)
|
||||
$this->line('処理結果: 0');
|
||||
$this->line('異常情報: ');
|
||||
|
||||
Log::info('SHJ-8 バッチ処理ログ登録完了', [
|
||||
'end_time' => $endTime,
|
||||
'duration_seconds' => $startTime->diffInSeconds($endTime)
|
||||
]);
|
||||
|
||||
return self::SUCCESS;
|
||||
|
||||
} else {
|
||||
// 異常終了
|
||||
$errorMessage = $result['error_message'] ?? '不明なエラー';
|
||||
$this->error('SHJ-8 バッチ処理ログ登録エラー: ' . $errorMessage);
|
||||
|
||||
// 標準出力形式 (SHJ-8仕様書準拠)
|
||||
$this->line('処理結果: 1');
|
||||
$this->line('異常情報: ' . $errorMessage);
|
||||
|
||||
Log::error('SHJ-8 バッチ処理ログ登録エラー', [
|
||||
'error_message' => $errorMessage,
|
||||
'error_code' => $result['error_code'] ?? null
|
||||
]);
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$this->error('SHJ-8 バッチ処理ログ登録で予期しないエラーが発生しました: ' . $e->getMessage());
|
||||
|
||||
// 標準出力形式 (SHJ-8仕様書準拠 - 例外時)
|
||||
$this->line('処理結果: 1');
|
||||
$this->line('異常情報: ' . $e->getMessage());
|
||||
|
||||
Log::error('SHJ-8 バッチ処理ログ登録例外エラー', [
|
||||
'exception' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString()
|
||||
]);
|
||||
|
||||
// 仕様書【処理3】異常終了時の結果出力
|
||||
$this->line('処理結果: 1'); // 1 = 異常終了
|
||||
$this->line('異常情報: エラー: ' . $e->getMessage());
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 【処理1】パラメータの妥当性を検証
|
||||
*
|
||||
* 仕様書に基づく検証内容:
|
||||
* - デバイスID: 必須、数値、device表に存在するか
|
||||
* - プロセス名: 「プロセス名」「ジョブ名」いずれか必須
|
||||
* - ジョブ名: 「プロセス名」「ジョブ名」いずれか必須
|
||||
* - ステータス: 必須
|
||||
* - 登録日時: 必須、yyyy/mm/dd形式
|
||||
* - 更新日時: 必須、yyyy/mm/dd形式
|
||||
*
|
||||
* @param int $deviceId デバイスID
|
||||
* @param string $processName プロセス名
|
||||
* @param string $jobName ジョブ名
|
||||
* @param string $status ステータス
|
||||
* @param string $createdDate 登録日時
|
||||
* @param string $updatedDate 更新日時
|
||||
* @return array 検証結果 ['valid' => bool, 'message' => string]
|
||||
*/
|
||||
private function validateParameters(int $deviceId, string $processName, string $jobName, string $status, string $createdDate, string $updatedDate): array
|
||||
{
|
||||
// デバイスID存在チェック
|
||||
if ($deviceId <= 0) {
|
||||
return [
|
||||
'valid' => false,
|
||||
'message' => 'パラメーターNG: デバイスIDは正の整数である必要があります'
|
||||
];
|
||||
}
|
||||
|
||||
if (!Device::exists($deviceId)) {
|
||||
return [
|
||||
'valid' => false,
|
||||
'message' => "パラメーターNG: デバイスID {$deviceId} が存在しません"
|
||||
];
|
||||
}
|
||||
|
||||
// プロセス名とジョブ名のいずれか必須チェック
|
||||
if (empty($processName) && empty($jobName)) {
|
||||
return [
|
||||
'valid' => false,
|
||||
'message' => 'パラメーターNG: プロセス名またはジョブ名のいずれかは必須です'
|
||||
];
|
||||
}
|
||||
|
||||
// ステータス必須チェック
|
||||
if (empty($status)) {
|
||||
return [
|
||||
'valid' => false,
|
||||
'message' => 'パラメーターNG: ステータスは必須です'
|
||||
];
|
||||
}
|
||||
|
||||
// 日付形式チェック
|
||||
if (!$this->isValidDateFormat($createdDate)) {
|
||||
return [
|
||||
'valid' => false,
|
||||
'message' => 'パラメーターNG: 登録日時の形式が正しくありません(yyyy/mm/dd)'
|
||||
];
|
||||
}
|
||||
|
||||
if (!$this->isValidDateFormat($updatedDate)) {
|
||||
return [
|
||||
'valid' => false,
|
||||
'message' => 'パラメーターNG: 更新日時の形式が正しくありません(yyyy/mm/dd)'
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'valid' => true,
|
||||
'message' => 'パラメーターチェックOK'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 日付形式の検証
|
||||
*
|
||||
* @param string $date 日付文字列
|
||||
* @return bool 有効な日付形式かどうか
|
||||
*/
|
||||
private function isValidDateFormat(string $date): bool
|
||||
{
|
||||
// yyyy/mm/dd形式の正規表現チェック
|
||||
if (!preg_match('/^\d{4}\/\d{2}\/\d{2}$/', $date)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 実際の日付として有効かチェック
|
||||
$dateParts = explode('/', $date);
|
||||
return checkdate((int)$dateParts[1], (int)$dateParts[2], (int)$dateParts[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,15 +51,14 @@ class ShjElevenCommand extends Command
|
||||
|
||||
/**
|
||||
* コンソールコマンドを実行
|
||||
*
|
||||
* 処理フロー:
|
||||
* 1. 集計単位每个の契約台数を算出する
|
||||
* 2. 取得件数判定
|
||||
* 3. ゾーンマスタを取得する
|
||||
* 4. 取得判定とゾーンマスタ登録
|
||||
* 5. 契約台数チェック(限界台数超過判定)
|
||||
* 6. 契約台数を反映する
|
||||
* 7. バッチ処理ログを作成する
|
||||
*
|
||||
* 処理フロー(仕様書準拠):
|
||||
* 【処理1】集計単位每个の契約台数を算出する
|
||||
* 【判断1】取得件数判定
|
||||
* - 取得件数 = 0 → 【処理4】バッチログ作成(「全駐輪場契約なし」)→ 終了
|
||||
* - 取得件数 ≥ 1 → 【処理2】ゾーンマスタ処理(循環)→ 終了
|
||||
*
|
||||
* ※【処理4】は各レコードの処理ごとにService層で呼び出される
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
@ -82,29 +81,37 @@ class ShjElevenCommand extends Command
|
||||
$this->info("取得件数: {$countResults}件");
|
||||
|
||||
if ($countResults === 0) {
|
||||
// 対象なしの結果を設定する
|
||||
$this->info('契約台数算出対象なしのため処理を終了します。');
|
||||
|
||||
// バッチ処理ログを作成
|
||||
$this->shjElevenService->createBatchLog(
|
||||
'success',
|
||||
[],
|
||||
'契約台数算出対象なし',
|
||||
0,
|
||||
0,
|
||||
0
|
||||
);
|
||||
// 【判断1】取得件数 = 0 の場合
|
||||
$this->info('対象なしのため処理を終了します。');
|
||||
|
||||
// 【処理4】bat_job_logに直接書き込み(取得件数=0時)
|
||||
$batchLogResult = $this->shjElevenService->writeBatJobLogForNoContracts();
|
||||
|
||||
// bat_job_log書き込み結果をチェック
|
||||
if (!$batchLogResult['success']) {
|
||||
$this->warn('bat_job_log書き込みで異常が発生しました');
|
||||
if (isset($batchLogResult['error_message'])) {
|
||||
$this->warn('error_message: ' . $batchLogResult['error_message']);
|
||||
}
|
||||
|
||||
Log::warning('bat_job_log書き込み失敗(対象なし)', [
|
||||
'error_message' => $batchLogResult['error_message'] ?? null
|
||||
]);
|
||||
}
|
||||
|
||||
Log::info('SHJ-11 現在契約台数集計完了(対象なし)', [
|
||||
'end_time' => now(),
|
||||
'duration_seconds' => $startTime->diffInSeconds(now())
|
||||
'duration_seconds' => $startTime->diffInSeconds(now()),
|
||||
'bat_job_log_success' => $batchLogResult['success']
|
||||
]);
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
// 【処理2・3】ゾーンマスタ処理(取得・登録・更新)
|
||||
// 【判断1】取得件数 ≥ 1 の場合
|
||||
// 【処理2・3・4】ゾーンマスタ処理(各レコードごとに処理4を実行)
|
||||
$this->info('【処理2】ゾーンマスタ処理を実行しています...');
|
||||
$this->info('※各レコードごとに【処理4】バッチログを作成します');
|
||||
$processResult = $this->shjElevenService->processZoneManagement($contractCounts);
|
||||
|
||||
// 処理結果確認
|
||||
@ -116,16 +123,10 @@ class ShjElevenCommand extends Command
|
||||
$this->info("ゾーン新規作成件数: {$processResult['created_zones']}件");
|
||||
$this->info("ゾーン更新件数: {$processResult['updated_zones']}件");
|
||||
$this->info("限界台数超過件数: {$processResult['over_capacity_count']}件");
|
||||
|
||||
// 【処理4】バッチ処理ログを作成する
|
||||
$this->shjElevenService->createBatchLog(
|
||||
'success',
|
||||
$processResult['parameters'],
|
||||
'現在契約台数集計処理完了',
|
||||
$countResults,
|
||||
$processResult['created_zones'] + $processResult['updated_zones'],
|
||||
0
|
||||
);
|
||||
|
||||
if (!empty($processResult['batch_log_errors'])) {
|
||||
$this->warn("バッチログエラー件数: " . count($processResult['batch_log_errors']) . "件");
|
||||
}
|
||||
|
||||
Log::info('SHJ-11 現在契約台数集計完了', [
|
||||
'end_time' => $endTime,
|
||||
@ -133,22 +134,13 @@ class ShjElevenCommand extends Command
|
||||
'processed_count' => $countResults,
|
||||
'created_zones' => $processResult['created_zones'],
|
||||
'updated_zones' => $processResult['updated_zones'],
|
||||
'over_capacity_count' => $processResult['over_capacity_count']
|
||||
'over_capacity_count' => $processResult['over_capacity_count'],
|
||||
'batch_log_errors' => count($processResult['batch_log_errors'])
|
||||
]);
|
||||
|
||||
return self::SUCCESS;
|
||||
} else {
|
||||
$this->error('SHJ-11 現在契約台数集計でエラーが発生しました: ' . $processResult['message']);
|
||||
|
||||
// エラー時のバッチログ作成
|
||||
$this->shjElevenService->createBatchLog(
|
||||
'error',
|
||||
$processResult['parameters'] ?? [],
|
||||
$processResult['message'],
|
||||
$countResults,
|
||||
$processResult['created_zones'] ?? 0,
|
||||
1
|
||||
);
|
||||
|
||||
Log::error('SHJ-11 現在契約台数集計エラー', [
|
||||
'error' => $processResult['message'],
|
||||
@ -160,16 +152,6 @@ class ShjElevenCommand extends Command
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$this->error('SHJ-11 現在契約台数集計で予期しないエラーが発生しました: ' . $e->getMessage());
|
||||
|
||||
// 例外時のバッチログ作成
|
||||
$this->shjElevenService->createBatchLog(
|
||||
'error',
|
||||
[],
|
||||
'システムエラー: ' . $e->getMessage(),
|
||||
0,
|
||||
0,
|
||||
1
|
||||
);
|
||||
|
||||
Log::error('SHJ-11 現在契約台数集計例外エラー', [
|
||||
'exception' => $e->getMessage(),
|
||||
|
||||
148
app/Console/Commands/ShjFiveCommand.php
Normal file
148
app/Console/Commands/ShjFiveCommand.php
Normal file
@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Services\ShjFiveService;
|
||||
|
||||
/**
|
||||
* SHJ-5 空き待ち通知処理コマンド
|
||||
*
|
||||
* 駐輪場の空き状況を確認し、空き待ち予約者への通知処理を実行する
|
||||
* バックグラウンドで実行される定期バッチ処理
|
||||
*/
|
||||
class ShjFiveCommand extends Command
|
||||
{
|
||||
/**
|
||||
* コンソールコマンドの名前とシグネチャ
|
||||
*
|
||||
* 引数なし - 全ての駐輪場を対象に処理を実行
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'shj:5';
|
||||
|
||||
/**
|
||||
* コンソールコマンドの説明
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'SHJ-5 空き待ち通知処理 - 駐輪場の空き状況確認と空き待ち者への通知を実行';
|
||||
|
||||
/**
|
||||
* SHJ-5サービスクラス
|
||||
*
|
||||
* @var ShjFiveService
|
||||
*/
|
||||
protected $shjFiveService;
|
||||
|
||||
/**
|
||||
* コンストラクタ
|
||||
*
|
||||
* @param ShjFiveService $shjFiveService
|
||||
*/
|
||||
public function __construct(ShjFiveService $shjFiveService)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->shjFiveService = $shjFiveService;
|
||||
}
|
||||
|
||||
/**
|
||||
* コンソールコマンドを実行
|
||||
*
|
||||
* 処理フロー:
|
||||
* 1. バッチログ開始記録
|
||||
* 2. 駐輪場の空き状況を取得する
|
||||
* 3. 空き状況判定
|
||||
* 4. 空き待ち者の情報を取得する
|
||||
* 5. 取得件数判定
|
||||
* 6. 空き待ち者への通知、またはオペレーターキュー追加処理
|
||||
* 7. バッチ処理ログを作成する
|
||||
* 8. 処理結果返却
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
try {
|
||||
// 開始ログ出力
|
||||
$startTime = now();
|
||||
$this->info('SHJ-5 空き待ち通知処理を開始します。');
|
||||
|
||||
Log::info('SHJ-5 空き待ち通知処理開始', [
|
||||
'start_time' => $startTime
|
||||
]);
|
||||
|
||||
// SHJ-5メイン処理実行
|
||||
$result = $this->shjFiveService->executeParkVacancyNotification();
|
||||
|
||||
$endTime = now();
|
||||
$this->info('SHJ-5 空き待ち通知処理が完了しました。');
|
||||
$this->info("処理時間: {$startTime->diffInSeconds($endTime)}秒");
|
||||
|
||||
// 処理結果表示
|
||||
$this->displayProcessResult($result);
|
||||
|
||||
// バッチログはShjFiveServiceが自動的にSHJ-8経由で作成
|
||||
|
||||
Log::info('SHJ-5 空き待ち通知処理完了', [
|
||||
'end_time' => $endTime,
|
||||
'duration_seconds' => $startTime->diffInSeconds($endTime),
|
||||
'result' => $result
|
||||
]);
|
||||
|
||||
return $result['success'] ? self::SUCCESS : self::FAILURE;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$this->error('SHJ-5 空き待ち通知処理で予期しないエラーが発生しました: ' . $e->getMessage());
|
||||
|
||||
// エラー時もShjFiveServiceが自動的にバッチログを作成
|
||||
|
||||
Log::error('SHJ-5 空き待ち通知処理例外エラー', [
|
||||
'exception' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString()
|
||||
]);
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 処理結果を表示
|
||||
*
|
||||
* @param array $result 処理結果
|
||||
* @return void
|
||||
*/
|
||||
private function displayProcessResult(array $result): void
|
||||
{
|
||||
$this->line('');
|
||||
$this->info('=== 処理結果 ===');
|
||||
|
||||
if ($result['success']) {
|
||||
$this->info("✓ 処理実行成功: " . $result['message']);
|
||||
} else {
|
||||
$this->error("✗ 処理実行失敗: " . $result['message']);
|
||||
}
|
||||
|
||||
$this->line('');
|
||||
$this->info('=== 処理統計 ===');
|
||||
$this->line(" 処理対象駐輪場数: " . ($result['processed_parks_count'] ?? 0));
|
||||
$this->line(" 空きあり駐輪場数: " . ($result['vacant_parks_count'] ?? 0));
|
||||
$this->line(" 空き待ち者総数: " . ($result['total_waiting_users'] ?? 0));
|
||||
$this->line(" 通知送信成功: " . ($result['notification_success_count'] ?? 0) . "件");
|
||||
$this->line(" オペレーターキュー追加: " . ($result['operator_queue_count'] ?? 0) . "件");
|
||||
$this->line(" エラー件数: " . ($result['error_count'] ?? 0) . "件");
|
||||
$this->line(" 処理時間: " . ($result['duration_seconds'] ?? 0) . "秒");
|
||||
|
||||
// エラー詳細があれば表示
|
||||
if (!empty($result['errors'])) {
|
||||
$this->line('');
|
||||
$this->warn('=== エラー詳細 ===');
|
||||
foreach ($result['errors'] as $index => $error) {
|
||||
$this->line(" " . ($index + 1) . ". " . $error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -4,7 +4,8 @@ namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use App\Models\SettlementTransaction;
|
||||
use App\Models\Batch\BatchLog;
|
||||
use App\Models\BatJobLog;
|
||||
use App\Models\Device;
|
||||
use App\Jobs\ProcessSettlementJob;
|
||||
use App\Services\ShjFourBService;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
@ -77,22 +78,6 @@ class ShjFourBCheckCommand extends Command
|
||||
$this->info("処理制限: {$limit}件");
|
||||
$this->info("対象期間: {$hours}時間以内");
|
||||
|
||||
// バッチログ作成
|
||||
$batch = BatchLog::createBatchLog(
|
||||
'shj4b_check',
|
||||
BatchLog::STATUS_START,
|
||||
[
|
||||
'command' => 'shj4b:check',
|
||||
'options' => [
|
||||
'dry_run' => $isDryRun,
|
||||
'limit' => $limit,
|
||||
'hours' => $hours,
|
||||
],
|
||||
'start_time' => $startTime,
|
||||
],
|
||||
'SHJ-4B チェックコマンド開始'
|
||||
);
|
||||
|
||||
try {
|
||||
// 未処理の決済トランザクション取得
|
||||
$unprocessedSettlements = $this->getUnprocessedSettlements($hours, $limit);
|
||||
@ -101,13 +86,9 @@ class ShjFourBCheckCommand extends Command
|
||||
|
||||
if ($unprocessedSettlements->isEmpty()) {
|
||||
$this->info("処理対象なし");
|
||||
|
||||
$batch->update([
|
||||
'status' => BatchLog::STATUS_SUCCESS,
|
||||
'end_time' => now(),
|
||||
'message' => 'SHJ-4B チェック完了 - 処理対象なし',
|
||||
'success_count' => 0,
|
||||
]);
|
||||
|
||||
// バッチログ作成 - 処理対象なし
|
||||
$this->createBatchLog('success', 0, 0, 'SHJ-4B チェック完了 - 処理対象なし');
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -117,14 +98,9 @@ class ShjFourBCheckCommand extends Command
|
||||
|
||||
if ($isDryRun) {
|
||||
$this->info("ドライランモードのため、実際の処理はスキップします");
|
||||
|
||||
$batch->update([
|
||||
'status' => BatchLog::STATUS_SUCCESS,
|
||||
'end_time' => now(),
|
||||
'message' => 'SHJ-4B チェック完了 - ドライラン',
|
||||
'success_count' => 0,
|
||||
'parameters' => json_encode(['targets' => $unprocessedSettlements->pluck('settlement_transaction_id')->toArray()]),
|
||||
]);
|
||||
|
||||
// バッチログ作成 - ドライラン
|
||||
$this->createBatchLog('success', 0, 0, 'SHJ-4B チェック完了 - ドライラン(' . $unprocessedSettlements->count() . '件検出)');
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -134,14 +110,10 @@ class ShjFourBCheckCommand extends Command
|
||||
|
||||
$this->info("処理完了: {$processed['success']}件成功, {$processed['failed']}件失敗");
|
||||
|
||||
$batch->update([
|
||||
'status' => $processed['failed'] > 0 ? BatchLog::STATUS_ERROR : BatchLog::STATUS_SUCCESS,
|
||||
'end_time' => now(),
|
||||
'message' => "SHJ-4B チェック完了 - 成功:{$processed['success']}件, 失敗:{$processed['failed']}件",
|
||||
'success_count' => $processed['success'],
|
||||
'error_count' => $processed['failed'],
|
||||
'parameters' => json_encode($processed),
|
||||
]);
|
||||
// バッチログ作成 - 処理完了
|
||||
$status = $processed['failed'] > 0 ? 'error' : 'success';
|
||||
$message = "SHJ-4B チェック完了 - 成功:{$processed['success']}件, 失敗:{$processed['failed']}件";
|
||||
$this->createBatchLog($status, $processed['success'], $processed['failed'], $message);
|
||||
|
||||
return $processed['failed'] > 0 ? 1 : 0;
|
||||
|
||||
@ -152,13 +124,8 @@ class ShjFourBCheckCommand extends Command
|
||||
'trace' => $e->getTraceAsString(),
|
||||
]);
|
||||
|
||||
$batch->update([
|
||||
'status' => BatchLog::STATUS_ERROR,
|
||||
'end_time' => now(),
|
||||
'message' => 'SHJ-4B チェック失敗: ' . $e->getMessage(),
|
||||
'error_details' => $e->getTraceAsString(),
|
||||
'error_count' => 1,
|
||||
]);
|
||||
// バッチログ作成 - エラー
|
||||
$this->createBatchLog('error', 0, 1, 'SHJ-4B チェック失敗: ' . $e->getMessage());
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -214,10 +181,10 @@ class ShjFourBCheckCommand extends Command
|
||||
return true;
|
||||
}
|
||||
|
||||
// 2. batch_logで処理完了記録があるかチェック
|
||||
$processedInBatch = BatchLog::where('process_name', 'shj4b')
|
||||
->where('status', BatchLog::STATUS_SUCCESS)
|
||||
->where('parameters', 'like', '%"settlement_transaction_id":' . $settlement->settlement_transaction_id . '%')
|
||||
// 2. bat_job_logで処理完了記録があるかチェック
|
||||
$processedInBatch = BatJobLog::where('process_name', 'SHJ-4B')
|
||||
->where('status', 'success')
|
||||
->where('status_comment', 'like', '%settlement_transaction_id:' . $settlement->settlement_transaction_id . '%')
|
||||
->exists();
|
||||
|
||||
if ($processedInBatch) {
|
||||
@ -226,8 +193,8 @@ class ShjFourBCheckCommand extends Command
|
||||
|
||||
// 3. 現在キューに入っているかチェック(簡易版)
|
||||
// 注: より正確にはRedis/DBキューの内容を確認する必要がある
|
||||
$recentJobDispatched = BatchLog::where('process_name', 'shj4b')
|
||||
->where('parameters', 'like', '%"settlement_transaction_id":' . $settlement->settlement_transaction_id . '%')
|
||||
$recentJobDispatched = BatJobLog::where('process_name', 'SHJ-4B')
|
||||
->where('status_comment', 'like', '%settlement_transaction_id:' . $settlement->settlement_transaction_id . '%')
|
||||
->where('created_at', '>=', Carbon::now()->subHours(1))
|
||||
->exists();
|
||||
|
||||
@ -314,4 +281,37 @@ class ShjFourBCheckCommand extends Command
|
||||
'total' => $settlements->count(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* バッチログ作成 - 直接bat_job_log書き込み
|
||||
*
|
||||
* @param string $status
|
||||
* @param int $successCount
|
||||
* @param int $errorCount
|
||||
* @param string $message
|
||||
*/
|
||||
private function createBatchLog(string $status, int $successCount, int $errorCount, string $message): void
|
||||
{
|
||||
try {
|
||||
$device = Device::orderBy('device_id')->first();
|
||||
$deviceId = $device ? $device->device_id : 1;
|
||||
|
||||
BatJobLog::create([
|
||||
'device_id' => $deviceId,
|
||||
'process_name' => 'SHJ-4B-CHECK',
|
||||
'job_name' => 'SHJ-4Bチェックコマンド',
|
||||
'status' => $status,
|
||||
'status_comment' => $message . " (成功:{$successCount}/失敗:{$errorCount})",
|
||||
'created_at' => now()->startOfDay(),
|
||||
'updated_at' => now()->startOfDay()
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('SHJ-4B-CHECK バッチログ作成エラー', [
|
||||
'error' => $e->getMessage(),
|
||||
'status' => $status,
|
||||
'message' => $message
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,12 +53,14 @@ class ShjMailSendCommand extends Command
|
||||
|
||||
/**
|
||||
* コンソールコマンドを実行
|
||||
*
|
||||
* 処理フロー:
|
||||
* 1. 入力パラメーターをチェックする
|
||||
* 2. メール送信テンプレート情報を取得する
|
||||
* 3. メールを送信する
|
||||
* 4. 処理結果を返却する
|
||||
*
|
||||
* SHJ-7 メール送信処理フロー:
|
||||
* 【処理1】入力パラメーターをチェックする
|
||||
* 【判断1】チェック結果
|
||||
* 【処理2】メール送信テンプレート情報を取得する
|
||||
* 【判断2】取得結果
|
||||
* 【処理3】メールを送信する
|
||||
* 【処理4】処理結果を返却する
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
@ -67,8 +69,8 @@ class ShjMailSendCommand extends Command
|
||||
try {
|
||||
// 開始ログ出力
|
||||
$startTime = now();
|
||||
$this->info('SHJ メール送信処理を開始します。');
|
||||
Log::info('SHJ メール送信処理開始', [
|
||||
$this->info('SHJ-7 メール送信処理を開始します。');
|
||||
Log::info('SHJ-7 メール送信処理開始', [
|
||||
'start_time' => $startTime,
|
||||
'mail_address' => $this->argument('mail_address'),
|
||||
'backup_mail_address' => $this->argument('backup_mail_address'),
|
||||
@ -80,41 +82,36 @@ class ShjMailSendCommand extends Command
|
||||
$backupMailAddress = $this->argument('backup_mail_address');
|
||||
$mailTemplateId = $this->argument('mail_template_id');
|
||||
|
||||
// 【処理1】パラメータ検証
|
||||
if (!$this->validateParameters($mailAddress, $backupMailAddress, $mailTemplateId)) {
|
||||
$this->error('パラメータが不正です。');
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
// SHJメール送信処理実行
|
||||
// SHJ-7 メール送信処理実行
|
||||
$result = $this->shjMailSendService->executeMailSend($mailAddress, $backupMailAddress, $mailTemplateId);
|
||||
|
||||
// 処理結果確認
|
||||
if ($result['success']) {
|
||||
// 【処理4】処理結果を返却する
|
||||
if ($result['result'] === 0) {
|
||||
$endTime = now();
|
||||
$this->info('SHJ メール送信処理が正常に完了しました。');
|
||||
$this->info('SHJ-7 メール送信処理が正常に完了しました。');
|
||||
$this->info("処理時間: {$startTime->diffInSeconds($endTime)}秒");
|
||||
|
||||
Log::info('SHJ メール送信処理完了', [
|
||||
|
||||
Log::info('SHJ-7 メール送信処理完了', [
|
||||
'end_time' => $endTime,
|
||||
'duration_seconds' => $startTime->diffInSeconds($endTime),
|
||||
'result' => $result
|
||||
'result' => $result['result'],
|
||||
'error_info' => $result['error_info']
|
||||
]);
|
||||
|
||||
return self::SUCCESS;
|
||||
} else {
|
||||
$this->error('SHJ メール送信処理でエラーが発生しました: ' . $result['message']);
|
||||
Log::error('SHJ メール送信処理エラー', [
|
||||
'error' => $result['message'],
|
||||
'details' => $result['details'] ?? null
|
||||
$this->error('SHJ-7 メール送信処理でエラーが発生しました: ' . $result['error_info']);
|
||||
Log::error('SHJ-7 メール送信処理エラー', [
|
||||
'result' => $result['result'],
|
||||
'error_info' => $result['error_info']
|
||||
]);
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$this->error('SHJ メール送信処理で予期しないエラーが発生しました: ' . $e->getMessage());
|
||||
Log::error('SHJ メール送信処理例外エラー', [
|
||||
$this->error('SHJ-7 メール送信処理で予期しないエラーが発生しました: ' . $e->getMessage());
|
||||
Log::error('SHJ-7 メール送信処理例外エラー', [
|
||||
'exception' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString()
|
||||
]);
|
||||
@ -123,55 +120,4 @@ class ShjMailSendCommand extends Command
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 【処理1】パラメータの妥当性を検証
|
||||
*
|
||||
* 仕様書に基づく検証内容:
|
||||
* - メールアドレス: 「メールアドレス」「予備メールアドレス」いずれか必須
|
||||
* - メールテンプレートID: 必須
|
||||
*
|
||||
* @param mixed $mailAddress メールアドレス
|
||||
* @param mixed $backupMailAddress 予備メールアドレス
|
||||
* @param mixed $mailTemplateId メールテンプレートID
|
||||
* @return bool 検証結果
|
||||
*/
|
||||
private function validateParameters($mailAddress, $backupMailAddress, $mailTemplateId): bool
|
||||
{
|
||||
// メールテンプレートIDチェック
|
||||
if (empty($mailTemplateId)) {
|
||||
$this->error('メールテンプレートIDは必須です。');
|
||||
return false;
|
||||
}
|
||||
|
||||
// 数値形式チェック(メールテンプレートID)
|
||||
if (!is_numeric($mailTemplateId)) {
|
||||
$this->error('メールテンプレートIDは数値である必要があります。');
|
||||
return false;
|
||||
}
|
||||
|
||||
// 正の整数チェック(メールテンプレートID)
|
||||
if ($mailTemplateId <= 0) {
|
||||
$this->error('メールテンプレートIDは正の整数である必要があります。');
|
||||
return false;
|
||||
}
|
||||
|
||||
// メールアドレスチェック(いずれか必須)
|
||||
if (empty($mailAddress) && empty($backupMailAddress)) {
|
||||
$this->error('メールアドレスまたは予備メールアドレスのいずれかは必須です。');
|
||||
return false;
|
||||
}
|
||||
|
||||
// メールアドレス形式チェック
|
||||
if (!empty($mailAddress) && !filter_var($mailAddress, FILTER_VALIDATE_EMAIL)) {
|
||||
$this->error('メールアドレスの形式が正しくありません。');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty($backupMailAddress) && !filter_var($backupMailAddress, FILTER_VALIDATE_EMAIL)) {
|
||||
$this->error('予備メールアドレスの形式が正しくありません。');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ use App\Services\ShjNineService;
|
||||
/**
|
||||
* SHJ-9 売上集計処理コマンド
|
||||
*
|
||||
* 駐輪場の売上データを日次・月次・年次で集計する処理を実行する
|
||||
* 駐輪場の売上データを日次で集計する処理を実行する
|
||||
* バックグラウンドで実行される定期バッチ処理
|
||||
*/
|
||||
class ShjNineCommand extends Command
|
||||
@ -18,19 +18,19 @@ class ShjNineCommand extends Command
|
||||
* コンソールコマンドの名前とシグネチャ
|
||||
*
|
||||
* 引数:
|
||||
* - type: 集計種別 (daily/monthly/yearly) (必須)
|
||||
* - type: 集計種別 (daily のみ) (必須)
|
||||
* - target_date: 集計対象日 (オプション、YYYY-MM-DD形式)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'shj:9 {type : 集計種別(daily/monthly/yearly)} {target_date? : 集計対象日(YYYY-MM-DD)}';
|
||||
protected $signature = 'shj:9 {type : 集計種別(daily)} {target_date? : 集計対象日(YYYY-MM-DD)}';
|
||||
|
||||
/**
|
||||
* コンソールコマンドの説明
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'SHJ-9 売上集計処理 - 日次/月次/年次売上データ集計を実行';
|
||||
protected $description = 'SHJ-9 売上集計処理 - 日次売上データ集計を実行';
|
||||
|
||||
/**
|
||||
* SHJ-9サービスクラス
|
||||
@ -138,10 +138,9 @@ class ShjNineCommand extends Command
|
||||
*/
|
||||
private function validateParameters(string $type, ?string $targetDate): bool
|
||||
{
|
||||
// 集計種別チェック
|
||||
$allowedTypes = ['daily', 'monthly', 'yearly'];
|
||||
if (!in_array($type, $allowedTypes)) {
|
||||
$this->error('集計種別は daily, monthly, yearly のいずれかを指定してください。');
|
||||
// 集計種別チェック(SHJ-9 は日次のみ対応)
|
||||
if ($type !== 'daily') {
|
||||
$this->error('SHJ-9 は日次集計(daily)のみ対応しています。月次/年次は SHJ-10 を使用してください。');
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -157,7 +156,7 @@ class ShjNineCommand extends Command
|
||||
/**
|
||||
* 集計対象日を決定
|
||||
*
|
||||
* @param string $type 集計種別
|
||||
* @param string $type 集計種別(daily 固定)
|
||||
* @param string|null $targetDate 指定日
|
||||
* @return string 集計対象日
|
||||
*/
|
||||
@ -167,23 +166,8 @@ class ShjNineCommand extends Command
|
||||
return $targetDate;
|
||||
}
|
||||
|
||||
// パラメータ指定がない場合のデフォルト設定
|
||||
switch ($type) {
|
||||
case 'daily':
|
||||
// 日次:昨日(本日の1日前)
|
||||
return now()->subDay()->format('Y-m-d');
|
||||
|
||||
case 'monthly':
|
||||
// 月次:前月の最終日
|
||||
return now()->subMonth()->endOfMonth()->format('Y-m-d');
|
||||
|
||||
case 'yearly':
|
||||
// 年次:前年の最終日
|
||||
return now()->subYear()->endOfYear()->format('Y-m-d');
|
||||
|
||||
default:
|
||||
return now()->subDay()->format('Y-m-d');
|
||||
}
|
||||
// パラメータ指定がない場合は昨日(本日の1日前)
|
||||
return now()->subDay()->format('Y-m-d');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -3,8 +3,8 @@
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Services\ShjOneService;
|
||||
use App\Models\Batch\BatchLog;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
@ -58,51 +58,32 @@ class ShjOneCommand extends Command
|
||||
$this->info("駐輪場ID: {$parkId}");
|
||||
|
||||
try {
|
||||
// バッチログ開始 - SHJ-8共通処理
|
||||
$batchLog = BatchLog::createBatchLog(
|
||||
'SHJ-1本人確認自動処理',
|
||||
BatchLog::STATUS_START,
|
||||
$parameters,
|
||||
'SHJ-1処理開始: 利用者ID=' . $userId . ', 駐輪場ID=' . $parkId
|
||||
);
|
||||
|
||||
// SHJ-1 メイン処理を実行
|
||||
$result = $this->shjOneService->execute($userId, $parkId);
|
||||
|
||||
|
||||
// 処理結果の表示
|
||||
$this->displayResult($result);
|
||||
|
||||
// バッチログ完了 - 実際の処理結果に基づく
|
||||
$logStatus = $result['log_status'] ?? ($result['system_success'] ? BatchLog::STATUS_SUCCESS : BatchLog::STATUS_ERROR);
|
||||
$batchLog->update([
|
||||
'status' => $logStatus,
|
||||
'end_time' => now(),
|
||||
'message' => $result['message'],
|
||||
'success_count' => $result['stats']['success_count'] ?? 0,
|
||||
'error_count' => $result['stats']['error_count'] ?? 0,
|
||||
'execution_count' => $result['stats']['processed_count'] ?? 1
|
||||
]);
|
||||
|
||||
|
||||
// バッチログはShjOneServiceが自動的にSHJ-8経由で作成
|
||||
|
||||
$this->info("=== SHJ-1 本人確認自動処理 完了 ===");
|
||||
|
||||
|
||||
// システムエラーまたは身元確認失敗の場合は exit code 1
|
||||
$isSuccess = $result['system_success'] && ($result['identity_result'] ?? '') === 'OK';
|
||||
return $isSuccess ? 0 : 1;
|
||||
|
||||
|
||||
} catch (Exception $e) {
|
||||
$this->error("SHJ-1処理中にエラーが発生しました: " . $e->getMessage());
|
||||
|
||||
// エラーログ記録
|
||||
if (isset($batchLog)) {
|
||||
$batchLog->update([
|
||||
'status' => BatchLog::STATUS_ERROR,
|
||||
'end_time' => now(),
|
||||
'message' => $e->getMessage(),
|
||||
'error_details' => $e->getMessage(),
|
||||
'error_count' => 1
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
// エラー時もShjOneServiceが自動的にバッチログを作成
|
||||
|
||||
Log::error('SHJ-1処理例外エラー', [
|
||||
'user_id' => $userId,
|
||||
'park_id' => $parkId,
|
||||
'exception' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString()
|
||||
]);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -114,7 +95,7 @@ class ShjOneCommand extends Command
|
||||
{
|
||||
$this->line('');
|
||||
$this->info('=== 処理結果 ===');
|
||||
|
||||
|
||||
if ($result['system_success']) {
|
||||
$this->info("✓ 処理実行成功: " . $result['message']);
|
||||
if (isset($result['identity_result'])) {
|
||||
@ -124,13 +105,13 @@ class ShjOneCommand extends Command
|
||||
} else {
|
||||
$this->error("✗ 処理実行失敗: " . $result['message']);
|
||||
}
|
||||
|
||||
|
||||
if (isset($result['details'])) {
|
||||
foreach ($result['details'] as $key => $value) {
|
||||
$this->line(" {$key}: {$value}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (isset($result['stats'])) {
|
||||
$this->line('');
|
||||
$this->info('=== 統計情報 ===');
|
||||
@ -139,4 +120,5 @@ class ShjOneCommand extends Command
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
154
app/Console/Commands/ShjThirteenCommand.php
Normal file
154
app/Console/Commands/ShjThirteenCommand.php
Normal file
@ -0,0 +1,154 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Services\ShjThirteenService;
|
||||
|
||||
/**
|
||||
* SHJ-13 契約台数追加処理コマンド
|
||||
*
|
||||
* 指定されたパラメータで契約台数をpark_number・zoneテーブルに反映する
|
||||
* 主にSHJ-4Bから呼び出されるが、独立実行も可能
|
||||
*/
|
||||
class ShjThirteenCommand extends Command
|
||||
{
|
||||
/**
|
||||
* コンソールコマンドの名前とシグネチャ
|
||||
*
|
||||
* 引数:
|
||||
* - park_id: 駐輪場ID (必須)
|
||||
* - psection_id: 車種区分ID (必須)
|
||||
* - ptype_id: 駐輪分類ID (必須)
|
||||
* - zone_id: ゾーンID (必須)
|
||||
*
|
||||
* オプション:
|
||||
* - contract_id: 契約ID (任意、ログ用)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'shj:13
|
||||
{park_id : 駐輪場ID}
|
||||
{psection_id : 車種区分ID}
|
||||
{ptype_id : 駐輪分類ID}
|
||||
{zone_id : ゾーンID}
|
||||
{--contract_id= : 契約ID(ログ用、任意)}';
|
||||
|
||||
/**
|
||||
* コンソールコマンドの説明
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'SHJ-13 契約台数追加処理 - park_number・zoneテーブルの契約台数を+1更新しログ記録';
|
||||
|
||||
/**
|
||||
* SHJ-13サービスクラス
|
||||
*
|
||||
* @var ShjThirteenService
|
||||
*/
|
||||
protected $shjThirteenService;
|
||||
|
||||
/**
|
||||
* コンストラクタ
|
||||
*
|
||||
* @param ShjThirteenService $shjThirteenService
|
||||
*/
|
||||
public function __construct(ShjThirteenService $shjThirteenService)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->shjThirteenService = $shjThirteenService;
|
||||
}
|
||||
|
||||
/**
|
||||
* コンソールコマンドを実行
|
||||
*
|
||||
* 処理フロー:
|
||||
* 1. 引数取得・検証
|
||||
* 2. ShjThirteenService実行
|
||||
* 3. 結果表示
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
try {
|
||||
// 開始ログ出力
|
||||
$startTime = now();
|
||||
$this->info('SHJ-13 契約台数追加処理を開始します。');
|
||||
|
||||
// 引数取得
|
||||
$contractData = [
|
||||
'park_id' => (int) $this->argument('park_id'),
|
||||
'psection_id' => (int) $this->argument('psection_id'),
|
||||
'ptype_id' => (int) $this->argument('ptype_id'),
|
||||
'zone_id' => (int) $this->argument('zone_id'),
|
||||
'contract_id' => $this->option('contract_id'),
|
||||
];
|
||||
|
||||
Log::info('SHJ-13 契約台数追加処理開始', [
|
||||
'start_time' => $startTime,
|
||||
'contract_data' => $contractData,
|
||||
]);
|
||||
|
||||
$this->info("駐輪場ID: {$contractData['park_id']}");
|
||||
$this->info("車種区分ID: {$contractData['psection_id']}");
|
||||
$this->info("駐輪分類ID: {$contractData['ptype_id']}");
|
||||
$this->info("ゾーンID: {$contractData['zone_id']}");
|
||||
if ($contractData['contract_id']) {
|
||||
$this->info("契約ID: {$contractData['contract_id']}");
|
||||
}
|
||||
|
||||
// SHJ-13処理実行
|
||||
$this->info('【処理実行】契約台数追加処理を実行しています...');
|
||||
$result = $this->shjThirteenService->execute($contractData);
|
||||
|
||||
// 処理結果確認・表示
|
||||
if ($result['result'] === 0) {
|
||||
$endTime = now();
|
||||
$this->info('SHJ-13 契約台数追加処理が正常に完了しました。');
|
||||
$this->info("処理時間: {$startTime->diffInSeconds($endTime)}秒");
|
||||
|
||||
Log::info('SHJ-13 契約台数追加処理完了', [
|
||||
'end_time' => $endTime,
|
||||
'duration_seconds' => $startTime->diffInSeconds($endTime),
|
||||
'contract_data' => $contractData,
|
||||
]);
|
||||
|
||||
// 成功時の結果出力
|
||||
$this->line('処理結果: 0'); // 0 = 正常終了
|
||||
$this->line('異常情報: '); // 正常時は空文字
|
||||
|
||||
return self::SUCCESS;
|
||||
} else {
|
||||
$this->error('SHJ-13 契約台数追加処理でエラーが発生しました。');
|
||||
$this->error("エラーコード: {$result['error_code']}");
|
||||
$this->error("エラーメッセージ: {$result['error_message']}");
|
||||
|
||||
Log::error('SHJ-13 契約台数追加処理エラー', [
|
||||
'contract_data' => $contractData,
|
||||
'error_result' => $result,
|
||||
]);
|
||||
|
||||
// エラー時の結果出力
|
||||
$this->line('処理結果: 1'); // 1 = 異常終了
|
||||
$this->line('異常情報: ' . $result['error_message']);
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$this->error('SHJ-13 契約台数追加処理で予期しないエラーが発生しました: ' . $e->getMessage());
|
||||
Log::error('SHJ-13 契約台数追加処理例外エラー', [
|
||||
'exception' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString(),
|
||||
]);
|
||||
|
||||
// 例外時の結果出力
|
||||
$this->line('処理結果: 1'); // 1 = 異常終了
|
||||
$this->line('異常情報: システムエラー: ' . $e->getMessage());
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -79,14 +79,17 @@ class ShjTwelveCommand extends Command
|
||||
$this->info("取得件数: {$unpaidCount}件");
|
||||
|
||||
if ($unpaidCount === 0) {
|
||||
// 未払い者対象なしの結果を設定する
|
||||
$this->info('未払い者対象なしのため処理を終了します。');
|
||||
|
||||
// バッチ処理ログを作成
|
||||
// 未払い者なしの結果を設定する
|
||||
$this->info('未払い者なしのため処理を終了します。');
|
||||
|
||||
// バッチ処理ログを作成(SHJ-8仕様に合わせ job_name と status_comment を追加)
|
||||
$this->shjTwelveService->createBatchLog(
|
||||
'success',
|
||||
[],
|
||||
'未払い者対象なし',
|
||||
[
|
||||
'job_name' => 'SHJ-12未払い者アラート',
|
||||
'status_comment' => '未払い者なし'
|
||||
],
|
||||
'未払い者なし',
|
||||
0,
|
||||
0,
|
||||
0
|
||||
@ -110,39 +113,73 @@ class ShjTwelveCommand extends Command
|
||||
$this->info('SHJ-12 未払い者通知処理が正常に完了しました。');
|
||||
$this->info("処理時間: {$startTime->diffInSeconds($endTime)}秒");
|
||||
$this->info("処理対象件数: {$unpaidCount}件");
|
||||
$this->info("通知送信件数: {$processResult['notification_count']}件");
|
||||
$this->info("オペレーターキュー追加件数: {$processResult['queue_count']}件");
|
||||
|
||||
$this->info("メール送信成功: {$processResult['mail_success_count']}件");
|
||||
$this->info("メール送信失敗: {$processResult['mail_error_count']}件");
|
||||
$this->info("キュー登録成功: {$processResult['queue_success_count']}件");
|
||||
$this->info("キュー登録失敗: {$processResult['queue_error_count']}件");
|
||||
|
||||
// 【処理3】バッチ処理ログを作成する
|
||||
$statusComment = $processResult['status_comment'];
|
||||
$batchComments = $processResult['batch_comments'];
|
||||
$totalSuccessCount = $processResult['mail_success_count'] + $processResult['queue_success_count'];
|
||||
$totalErrorCount = $processResult['mail_error_count'] + $processResult['queue_error_count'];
|
||||
|
||||
// status_commentに詳細エラー情報を付加
|
||||
$finalMessage = $statusComment;
|
||||
if (!empty($batchComments)) {
|
||||
$finalMessage .= "\n" . $batchComments;
|
||||
}
|
||||
|
||||
// SHJ-8仕様に合わせ、job_name と status_comment を parameters に追加
|
||||
$batchLogParameters = array_merge($processResult['parameters'], [
|
||||
'job_name' => 'SHJ-12未払い者アラート',
|
||||
'status_comment' => $statusComment
|
||||
]);
|
||||
|
||||
$this->shjTwelveService->createBatchLog(
|
||||
'success',
|
||||
$processResult['parameters'],
|
||||
'未払い者通知処理完了',
|
||||
$batchLogParameters,
|
||||
$finalMessage,
|
||||
$unpaidCount,
|
||||
$processResult['notification_count'] + $processResult['queue_count'],
|
||||
0
|
||||
$totalSuccessCount,
|
||||
$totalErrorCount
|
||||
);
|
||||
|
||||
Log::info('SHJ-12 未払い者通知処理完了', [
|
||||
'end_time' => $endTime,
|
||||
'duration_seconds' => $startTime->diffInSeconds($endTime),
|
||||
'processed_count' => $unpaidCount,
|
||||
'notification_count' => $processResult['notification_count'],
|
||||
'queue_count' => $processResult['queue_count']
|
||||
'mail_success_count' => $processResult['mail_success_count'],
|
||||
'mail_error_count' => $processResult['mail_error_count'],
|
||||
'queue_success_count' => $processResult['queue_success_count'],
|
||||
'queue_error_count' => $processResult['queue_error_count']
|
||||
]);
|
||||
|
||||
return self::SUCCESS;
|
||||
} else {
|
||||
$this->error('SHJ-12 未払い者通知処理でエラーが発生しました: ' . $processResult['message']);
|
||||
|
||||
|
||||
// エラー時のバッチログ作成
|
||||
$statusComment = $processResult['status_comment'] ?? 'システムエラー';
|
||||
$batchComments = $processResult['batch_comments'] ?? '';
|
||||
$finalMessage = $statusComment;
|
||||
if (!empty($batchComments)) {
|
||||
$finalMessage .= "\n" . $batchComments;
|
||||
}
|
||||
|
||||
// SHJ-8仕様に合わせ、job_name と status_comment を parameters に追加
|
||||
$batchLogParameters = array_merge($processResult['parameters'] ?? [], [
|
||||
'job_name' => 'SHJ-12未払い者アラート',
|
||||
'status_comment' => $statusComment
|
||||
]);
|
||||
|
||||
$this->shjTwelveService->createBatchLog(
|
||||
'error',
|
||||
$processResult['parameters'] ?? [],
|
||||
$processResult['message'],
|
||||
$batchLogParameters,
|
||||
$finalMessage,
|
||||
$unpaidCount,
|
||||
$processResult['notification_count'] ?? 0,
|
||||
1
|
||||
($processResult['mail_success_count'] ?? 0) + ($processResult['queue_success_count'] ?? 0),
|
||||
($processResult['mail_error_count'] ?? 0) + ($processResult['queue_error_count'] ?? 0)
|
||||
);
|
||||
|
||||
Log::error('SHJ-12 未払い者通知処理エラー', [
|
||||
@ -156,10 +193,13 @@ class ShjTwelveCommand extends Command
|
||||
} catch (\Exception $e) {
|
||||
$this->error('SHJ-12 未払い者通知処理で予期しないエラーが発生しました: ' . $e->getMessage());
|
||||
|
||||
// 例外時のバッチログ作成
|
||||
// 例外時のバッチログ作成(SHJ-8仕様に合わせ job_name と status_comment を追加)
|
||||
$this->shjTwelveService->createBatchLog(
|
||||
'error',
|
||||
[],
|
||||
[
|
||||
'job_name' => 'SHJ-12未払い者アラート',
|
||||
'status_comment' => 'システムエラー'
|
||||
],
|
||||
'システムエラー: ' . $e->getMessage(),
|
||||
0,
|
||||
0,
|
||||
|
||||
146
app/Console/Commands/TestMailCommand.php
Normal file
146
app/Console/Commands/TestMailCommand.php
Normal file
@ -0,0 +1,146 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -11,9 +11,9 @@ class InquiryConfirmController extends Controller
|
||||
{
|
||||
// 初期表示内容
|
||||
public $form_data = [
|
||||
["name", "text", "氏名*", ""],
|
||||
["email", "email", "メールアドレス*", ""],
|
||||
["tel", "text", "電話番号*", ""],
|
||||
["name", "text", "氏名*", "山田 太郎"],
|
||||
["email", "email", "メールアドレス*", "info@so-manager.com"],
|
||||
["tel", "text", "電話番号*", "000-0000-0000"],
|
||||
["subject", "checkbox", "お問い合わせ概要*", ["定期契約について", "操作方法について", "支払方法について", "その他お問合せ"]],
|
||||
["parking", "text", "お問い合わせ駐輪場名", ""],
|
||||
["detail", "textarea", "お問い合わせ詳細*", ""],
|
||||
@ -40,11 +40,11 @@ class InquiryConfirmController extends Controller
|
||||
|
||||
// エラーメッセージ
|
||||
$message = [
|
||||
'name.required' => '名前を入力してください',
|
||||
'email.required' => 'メールアドレスを入力してください',
|
||||
'tel.required' => '電話番号を入力してください',
|
||||
'subject.required' => 'お問い合わせ概要を選択してください',
|
||||
'detail.required' => 'お問い合わせ詳細を入力してください',
|
||||
'name.required' => '氏名は必ず入力してください。',
|
||||
'email.required' => 'メールアドレスは必ず入力してください。',
|
||||
'tel.required' => '電話番号は必ず入力してください。',
|
||||
'subject.required' => 'お問い合わせ概要が選択されていません。',
|
||||
'detail.required' => 'お問い合わせの詳細が入力されていません。',
|
||||
];
|
||||
|
||||
// バリデーションチェック
|
||||
|
||||
@ -15,7 +15,7 @@ class LoginController extends Controller
|
||||
public function login(Request $request)
|
||||
{
|
||||
// ID・パスワードチェック
|
||||
$existingMember = User::where('user_primemail', $request->input('login_id'))->first();
|
||||
$existingMember = User::where('user_primemail', $request->input('login_id'))->where('user_quit_flag', 0)->first();
|
||||
if (!$existingMember || !CommonFunction::verifyPassword($existingMember->user_seq, $request->input('password'), $existingMember->user_pass)) {
|
||||
return redirect('swo8_1')
|
||||
->withErrors(['login' => 'ID/パスワードが間違っています'])
|
||||
|
||||
@ -51,7 +51,7 @@ class MemberRegistrationController extends Controller
|
||||
return view('general.swo2_2');
|
||||
}
|
||||
|
||||
// 入力画面表示
|
||||
// メールのURLからアクセス
|
||||
public function index()
|
||||
{
|
||||
// 署名付きURLの有効期限チェック
|
||||
@ -59,32 +59,39 @@ class MemberRegistrationController extends Controller
|
||||
return redirect('error')->withErrors(['error' => '署名の有効期限が切れています']);
|
||||
}
|
||||
|
||||
// 初回遷移(GETアクセス)時のリクエストパラメータチェック
|
||||
if (!session()->has('email')) {
|
||||
// パラメータ存在チェック
|
||||
$encryptedEmail = request()->query('email');
|
||||
if (!$encryptedEmail) {
|
||||
return redirect('error')->withErrors(['error' => 'メールアドレスが指定されていません']);
|
||||
}
|
||||
|
||||
// パラメータ存在チェック
|
||||
$encryptedEmail = request()->query('email');
|
||||
if (!$encryptedEmail) {
|
||||
return redirect('error')->withErrors(['error' => 'メールアドレスが指定されていません']);
|
||||
// パラメータ整合性チェック
|
||||
try {
|
||||
$email = decrypt($encryptedEmail);
|
||||
} catch (\Exception $e) {
|
||||
return redirect('error')->withErrors(['error' => 'メールアドレスの情報が不正です']);
|
||||
}
|
||||
|
||||
// 二重登録防止チェック
|
||||
$existingMember = User::where('user_primemail', $email)->get();
|
||||
foreach ($existingMember as $member) {
|
||||
if ($member->user_quit_flag != 1) {
|
||||
return redirect('error')->withErrors(['error' => '既に登録済みです']);
|
||||
}
|
||||
}
|
||||
|
||||
// パラメータ整合性チェック
|
||||
try {
|
||||
$email = decrypt($encryptedEmail);
|
||||
} catch (\Exception $e) {
|
||||
return redirect('error')->withErrors(['error' => 'メールアドレスの情報が不正です']);
|
||||
}
|
||||
// メールアドレスをセッションに保存
|
||||
session(['email' => $email]);
|
||||
|
||||
// 二重登録防止チェック
|
||||
$existingMember = User::where('user_primemail', $email)->get();
|
||||
foreach ($existingMember as $member) {
|
||||
if ($member->user_quit_flag != 1) {
|
||||
return redirect('error')->withErrors(['error' => '既に登録済みです']);
|
||||
}
|
||||
}
|
||||
// 入力画面に遷移
|
||||
return view('general.swo2_3');
|
||||
}
|
||||
|
||||
// メールアドレスをセッションに保存
|
||||
session(['email' => $email]);
|
||||
// リダイレクト用
|
||||
public function indexBack(Request $request)
|
||||
{
|
||||
if (!session('email')) {
|
||||
return redirect('error')->withErrors(['error' => '不正なアクセスです']);
|
||||
}
|
||||
|
||||
// 入力画面に遷移
|
||||
@ -119,9 +126,7 @@ class MemberRegistrationController extends Controller
|
||||
// バリデーションチェック
|
||||
$validator = Validator::make($request->all(), $rules, $message);
|
||||
if ($validator->fails()) {
|
||||
return redirect('swo2_3')
|
||||
->withErrors($validator)
|
||||
->withInput();
|
||||
return redirect('swo2_3B')->withErrors($validator)->withInput();
|
||||
}
|
||||
|
||||
// 画面返却値
|
||||
@ -142,7 +147,7 @@ class MemberRegistrationController extends Controller
|
||||
{
|
||||
// 前の画面に戻る
|
||||
if($request->input('back') == 'back'){
|
||||
return redirect('swo2_3')->withInput();
|
||||
return redirect('swo2_3B')->withInput();
|
||||
}
|
||||
|
||||
// 登録完了後のブラウザバックによる二重登録対策
|
||||
|
||||
100
app/Http/Controllers/MypageController.php
Normal file
100
app/Http/Controllers/MypageController.php
Normal file
@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Http\Request;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class MypageController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$user_id = session('user_id');
|
||||
if (!$user_id) {
|
||||
return redirect('/login');
|
||||
}
|
||||
$user = DB::table('user')->where('user_id', $user_id)->first();
|
||||
|
||||
$today = date('Y-m-d');
|
||||
// 定期契約情報を取得(park/usertype/psection/ptypeテーブルもJOIN)
|
||||
$contracts = DB::table('regular_contract')
|
||||
->join('park', 'regular_contract.park_id', '=', 'park.park_id')
|
||||
->join('usertype', 'regular_contract.user_categoryid', '=', 'usertype.user_categoryid')
|
||||
->leftJoin('city', 'park.city_id', '=', 'city.city_id')
|
||||
->leftJoin('psection', 'regular_contract.psection_id', '=', 'psection.psection_id')
|
||||
->leftJoin('ptype', 'regular_contract.ptype_id', '=', 'ptype.ptype_id')
|
||||
->where('regular_contract.user_id', $user_id)
|
||||
->where('regular_contract.contract_flag', 1)
|
||||
->where('regular_contract.contract_cancel_flag', 0)
|
||||
->where(function ($query) use ($today) {
|
||||
$query->where('regular_contract.contract_periode', '>', $today)
|
||||
->orWhere(function ($q) use ($today) {
|
||||
$q->where('regular_contract.contract_periode', '<=', $today)
|
||||
->whereRaw('DATEDIFF(?, regular_contract.contract_periode) <= 5', [$today]);
|
||||
});
|
||||
})
|
||||
->select(
|
||||
'regular_contract.contract_id',
|
||||
'park.park_name',
|
||||
'usertype.usertype_subject1',
|
||||
'regular_contract.contract_periods',
|
||||
'regular_contract.contract_periode',
|
||||
'regular_contract.enable_months',
|
||||
'regular_contract.contract_renewal',
|
||||
'regular_contract.park_id',
|
||||
'city.update_grace_period_start_date',
|
||||
'city.update_grace_period_start_time',
|
||||
'city.update_grace_period_end_date',
|
||||
'city.update_grace_period_end_time',
|
||||
'psection.psection_subject',
|
||||
'ptype.ptype_subject',
|
||||
'regular_contract.pplace_no'
|
||||
)
|
||||
->get();
|
||||
|
||||
// シール情報を取得
|
||||
$seals = DB::table('regular_contract')
|
||||
->join('usertype', 'regular_contract.user_categoryid', '=', 'usertype.user_categoryid')
|
||||
->leftJoin('psection', 'regular_contract.psection_id', '=', 'psection.psection_id')
|
||||
->leftJoin('ptype', 'regular_contract.ptype_id', '=', 'ptype.ptype_id')
|
||||
->where('regular_contract.user_id', $user_id)
|
||||
->where('regular_contract.contract_flag', 1)
|
||||
->where('regular_contract.contract_cancel_flag', 0)
|
||||
->where('regular_contract.contract_periode', '>=', $today)
|
||||
->where('regular_contract.contract_permission', 1)
|
||||
->select(
|
||||
'regular_contract.contract_id',
|
||||
'regular_contract.contract_qr_id',
|
||||
'usertype.usertype_subject1',
|
||||
'regular_contract.contract_periods',
|
||||
'regular_contract.contract_periode',
|
||||
'regular_contract.enable_months',
|
||||
'regular_contract.contract_renewal',
|
||||
'regular_contract.park_id',
|
||||
'psection.psection_subject',
|
||||
'ptype.ptype_subject',
|
||||
'regular_contract.pplace_no'
|
||||
)
|
||||
->get();
|
||||
|
||||
// お知らせ情報を取得
|
||||
$information = DB::table('user_information_history')
|
||||
->where('user_id', $user_id)
|
||||
->orderBy('user_information_history_id', 'desc')
|
||||
->select('entry_date', 'user_information_history')
|
||||
->first();
|
||||
|
||||
\Log::info('マイページにアクセス', [
|
||||
'user_id' => $user_id,
|
||||
]);
|
||||
|
||||
return view('mypage.index', [
|
||||
'active_menu' => 'SWO-4-1', // マイページメニューの選択状態用
|
||||
'user_name' => $user->user_name, // ユーザー名(ヘッダー用)
|
||||
'contracts' => $contracts,
|
||||
'seals' => $seals,
|
||||
'information' => $information
|
||||
]);
|
||||
}
|
||||
}
|
||||
@ -11,14 +11,14 @@ class ParkDetailController extends Controller
|
||||
public function show($park_id)
|
||||
{
|
||||
$park = DB::table('park')->where('park_id', $park_id)->first();
|
||||
Log::debug('park:', (array)$park);
|
||||
|
||||
$zones = DB::table('zone')
|
||||
->leftJoin('psection', 'zone.psection_id', '=', 'psection.psection_id')
|
||||
->leftJoin('ptype', 'zone.ptype_id', '=', 'ptype.ptype_id')
|
||||
->select('zone.*', 'psection.psection_subject', 'ptype.ptype_subject')
|
||||
->where('zone.park_id', $park_id)
|
||||
->get();
|
||||
Log::debug('zones:', $zones->toArray());
|
||||
|
||||
$reserves = DB::table('reserve')
|
||||
->join('zone', function ($join) {
|
||||
$join->on('reserve.psection_id', '=', 'zone.psection_id')
|
||||
@ -29,16 +29,7 @@ class ParkDetailController extends Controller
|
||||
->where('reserve.valid_flag', 1)
|
||||
->select('reserve.*', 'ptype.ptype_subject')
|
||||
->get();
|
||||
Log::debug('reserves:', $reserves->toArray());
|
||||
|
||||
$zoneStandardSum = [];
|
||||
/*foreach ($zones as $zone) {
|
||||
$psectionId = $zone->psection_id;
|
||||
if (!isset($zoneStandardSum[$psectionId])) {
|
||||
$zoneStandardSum[$psectionId] = 0;
|
||||
}
|
||||
$zoneStandardSum[$psectionId] += $zone->zone_standard;
|
||||
}*/
|
||||
$zoneStandardSum = [];
|
||||
foreach ($zones as $zone) {
|
||||
$key = $zone->psection_subject; // 「自転車」「原付」など
|
||||
@ -47,7 +38,6 @@ class ParkDetailController extends Controller
|
||||
}
|
||||
$zoneStandardSum[$key] += $zone->zone_standard;
|
||||
}
|
||||
Log::debug('zoneStandardSum:', $zoneStandardSum);
|
||||
|
||||
// 空き台数集計用配列
|
||||
$vacancyData = [];
|
||||
@ -59,7 +49,6 @@ class ParkDetailController extends Controller
|
||||
// zone_tolerance - zone_number を合計
|
||||
$vacancyData[$key] += ($zone->zone_tolerance - $zone->zone_number);
|
||||
}
|
||||
Log::debug('vacancyData:', $vacancyData);
|
||||
|
||||
// reserve件数分を減算
|
||||
foreach ($reserves as $reserve) {
|
||||
@ -77,11 +66,37 @@ class ParkDetailController extends Controller
|
||||
})
|
||||
->get()
|
||||
->keyBy('city_id');
|
||||
Log::debug('city_grace_periods:', $city_grace_periods->toArray());
|
||||
|
||||
// 必要なら他テーブルJOINや追加情報も取得
|
||||
return response()->json([
|
||||
'html' => view('regular_contract.park_detail', compact('park', 'zones', 'reserves', 'zoneStandardSum', 'vacancyData', 'city_grace_periods'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
public function showWait($reserve_id)
|
||||
{
|
||||
$reserve = DB::table('reserve')->where('reserve_id', $reserve_id)->first();
|
||||
$park = DB::table('park')->where('park_id', $reserve->park_id)->first();
|
||||
|
||||
$zones = DB::table('zone')
|
||||
->leftJoin('psection', 'zone.psection_id', '=', 'psection.psection_id')
|
||||
->leftJoin('ptype', 'zone.ptype_id', '=', 'ptype.ptype_id')
|
||||
->select('zone.*', 'psection.psection_subject', 'ptype.ptype_subject')
|
||||
->where('zone.park_id', $park->park_id)
|
||||
->get();
|
||||
|
||||
$zoneStandardSum = [];
|
||||
foreach ($zones as $zone) {
|
||||
$key = $zone->psection_subject; // 「自転車」「原付」など
|
||||
if (!isset($zoneStandardSum[$key])) {
|
||||
$zoneStandardSum[$key] = 0;
|
||||
}
|
||||
$zoneStandardSum[$key] += $zone->zone_standard;
|
||||
}
|
||||
|
||||
// 必要なら他テーブルJOINや追加情報も取得
|
||||
return response()->json([
|
||||
'html' => view('park_waitlist.park_detail', compact('park', 'zones', 'reserve', 'zoneStandardSum'))->render()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
184
app/Http/Controllers/ParkWaitlistController.php
Normal file
184
app/Http/Controllers/ParkWaitlistController.php
Normal file
@ -0,0 +1,184 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Mail\ReservationCancelledMail;
|
||||
|
||||
class ParkWaitlistController extends Controller
|
||||
{
|
||||
// 空き待ち状況一覧画面
|
||||
public function index(Request $request)
|
||||
{
|
||||
$user_id = session('user_id');
|
||||
if (!$user_id) {
|
||||
return redirect('/login');
|
||||
}
|
||||
$user = DB::table('user')->where('user_id', $user_id)->first();
|
||||
|
||||
// 空き待ち予約状況データ取得
|
||||
$waitlists = DB::table('reserve')
|
||||
->where('reserve.user_id', $user_id)
|
||||
->where('reserve.valid_flag', 1)
|
||||
->leftJoin('park', 'reserve.park_id', '=', 'park.park_id')
|
||||
->leftJoin('station', 'park.park_id', '=', 'station.park_id')
|
||||
->leftJoin('ptype', 'reserve.ptype_id', '=', 'ptype.ptype_id')
|
||||
->leftJoin('psection', 'reserve.psection_id', '=', 'psection.psection_id')
|
||||
->select(
|
||||
'reserve.reserve_id',
|
||||
'reserve.reserve_date',
|
||||
'park.park_name',
|
||||
'station.station_neighbor_station',
|
||||
'ptype.ptype_subject',
|
||||
'psection.psection_subject'
|
||||
)
|
||||
->orderBy('reserve.reserve_date', 'desc')
|
||||
->get();
|
||||
|
||||
\Log::info('空き待ち状況確認画面にアクセス', [
|
||||
'user_id' => $user_id,
|
||||
]);
|
||||
|
||||
return view('park_waitlist.index', [
|
||||
'active_menu' => 'SWC-11-1', // この画面のID
|
||||
'user_name' => $user ? $user->user_name : '', // ユーザー名(ヘッダー用)
|
||||
'waitlists' => $waitlists,
|
||||
]);
|
||||
}
|
||||
|
||||
public function check(Request $request)
|
||||
{
|
||||
$user_id = session('user_id');
|
||||
if (!$user_id) {
|
||||
return redirect('/login');
|
||||
}
|
||||
|
||||
$park_id = $request->input('park_id');
|
||||
$psection_id = $request->input('psection_id');
|
||||
$ptype_id = $request->input('ptype_id');
|
||||
|
||||
$existingReservation = DB::table('reserve')
|
||||
->where('user_id', $user_id)
|
||||
->where('park_id', $park_id)
|
||||
->where('psection_id', $psection_id)
|
||||
->where('ptype_id', $ptype_id)
|
||||
->where('valid_flag', 1)
|
||||
->first();
|
||||
|
||||
if ($existingReservation) {
|
||||
return response()->json(['status' => 'exists']);
|
||||
} else {
|
||||
return response()->json(['status' => 'ok']);
|
||||
}
|
||||
}
|
||||
|
||||
public function create(Request $request)
|
||||
{
|
||||
$user_id = session('user_id');
|
||||
if (!$user_id) {
|
||||
return redirect('/login');
|
||||
}
|
||||
$user = DB::table('user')->where('user_id', $user_id)->first();
|
||||
|
||||
$park_id = $request->input('park_id');
|
||||
$psection_id = $request->input('psection_id');
|
||||
$ptype_id = $request->input('ptype_id');
|
||||
|
||||
// 予約順を決定
|
||||
$reserve_order = DB::table('reserve')
|
||||
->where('park_id', $park_id)
|
||||
->where('psection_id', $psection_id)
|
||||
->where('ptype_id', $ptype_id)
|
||||
->where('valid_flag', 1)
|
||||
->count() + 1;
|
||||
|
||||
// 予約情報を追加
|
||||
DB::table('reserve')->insert([
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
'user_categoryid' => $user->user_categoryid,
|
||||
'user_id' => $user_id,
|
||||
'park_id' => $park_id,
|
||||
'psection_id' => $psection_id,
|
||||
'reserve_date' => now(),
|
||||
'valid_flag' => 1,
|
||||
'ptype_id' => $ptype_id,
|
||||
'reserve_order' => $reserve_order
|
||||
]);
|
||||
|
||||
return redirect()->route('park_waitlist.index');
|
||||
}
|
||||
|
||||
public function cancelConfirm($reserve_id)
|
||||
{
|
||||
$user_id = session('user_id');
|
||||
if (!$user_id) {
|
||||
return redirect('/login');
|
||||
}
|
||||
$user_name = DB::table('user')->where('user_id', $user_id)->value('user_name');
|
||||
|
||||
\Log::info('空き待ち状況確認 - キャンセル確認画面にアクセス', [
|
||||
'user_id' => $user_id,
|
||||
]);
|
||||
|
||||
return view('park_waitlist.cancel', [
|
||||
'active_menu' => 'SWC-11-1', // この画面のID
|
||||
'user_name' => $user_name, // ユーザー名(ヘッダー用)
|
||||
'reserve_id' => $reserve_id,
|
||||
]);
|
||||
}
|
||||
|
||||
public function cancel($reserve_id)
|
||||
{
|
||||
$user_id = session('user_id');
|
||||
if (!$user_id) {
|
||||
return redirect('/login');
|
||||
}
|
||||
$user = DB::table('user')->where('user_id', $user_id)->first();
|
||||
|
||||
// 定期予約をキャンセル
|
||||
DB::table('reserve')->where('reserve_id', $reserve_id)->update([
|
||||
'valid_flag' => 0,
|
||||
'updated_at' => now(),
|
||||
'reserve_cancelday' => date('Y-m-d'),
|
||||
]);
|
||||
|
||||
// メール送信用データ取得
|
||||
$reserve = DB::table('reserve')
|
||||
->leftJoin('park', 'reserve.park_id', '=', 'park.park_id')
|
||||
->leftJoin('psection', 'reserve.psection_id', '=', 'psection.psection_id')
|
||||
->leftJoin('ptype', 'reserve.ptype_id', '=', 'ptype.ptype_id')
|
||||
->select(
|
||||
'park.park_name',
|
||||
'psection.psection_subject',
|
||||
'ptype.ptype_subject'
|
||||
)
|
||||
->where('reserve.reserve_id', $reserve_id)
|
||||
->first();
|
||||
|
||||
// メール送信処理
|
||||
try {
|
||||
Mail::to($user->user_primemail)->send(
|
||||
new ReservationCancelledMail(
|
||||
$user->user_name,
|
||||
$reserve
|
||||
)
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
Log::error('予約キャンセルメール送信エラー: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
\Log::info('空き待ち状況確認 - キャンセル完了画面にアクセス', [
|
||||
'user_id' => $user_id,
|
||||
]);
|
||||
|
||||
return view('park_waitlist.cancel_complete', [
|
||||
'reserve' => $reserve,
|
||||
'active_menu' => 'SWC-11-1', // この画面のID
|
||||
'user_name' => $user ? $user->user_name : '', // ユーザー名(ヘッダー用)
|
||||
]);
|
||||
}
|
||||
}
|
||||
@ -12,86 +12,184 @@ class ParkingSearchController extends Controller
|
||||
// 初期表示
|
||||
public function index()
|
||||
{
|
||||
// 検索仕様
|
||||
// 駐輪場マスタの全件(条件を絞った場合はその条件に一致するもの)を取得。
|
||||
// 併せて各マスタから追加情報を取得するが、その際のレコードは全て1対1で結びつく想定で暫定実装する
|
||||
// ※設計書に詳細な記載なし。DBの定義上は1対多の可能性もあるが、その場合現在の画面イメージと矛盾するため、実態として無い想定で進める
|
||||
$result = $this->getParkData('', '', '');
|
||||
return view('general.swo5_1', $result);
|
||||
}
|
||||
|
||||
// プルダウン選択
|
||||
public function search(Request $request)
|
||||
{
|
||||
$result = $this->getParkData(
|
||||
$request->input('conditions_city'),
|
||||
$request->input('conditions_station'),
|
||||
$request->input('conditions_park')
|
||||
);
|
||||
|
||||
return view('general.swo5_1', $result);
|
||||
}
|
||||
|
||||
// 検索処理
|
||||
public function getParkData($city_name, $station_neighbor_station, $park_name)
|
||||
{
|
||||
// 駐輪場情報検索
|
||||
$park = \DB::table('park as p')
|
||||
->select(
|
||||
'p.park_id',
|
||||
'p.park_name',
|
||||
'p.park_adrs',
|
||||
'p.price_memo',
|
||||
'p.park_latitude',
|
||||
'p.park_longitude',
|
||||
'p.update_grace_period_start_date',
|
||||
'p.update_grace_period_start_time',
|
||||
'p.update_grace_period_end_date',
|
||||
'p.update_grace_period_end_time',
|
||||
'c.city_name',
|
||||
's.station_neighbor_station',
|
||||
'z.psection_id'
|
||||
's.station_neighbor_station'
|
||||
)
|
||||
->leftJoin('city as c', 'p.city_id', '=', 'c.city_id')
|
||||
->leftJoin(\DB::raw(
|
||||
'(SELECT park_id, station_neighbor_station FROM station WHERE station_id IN (SELECT MAX(station_id) FROM station GROUP BY park_id)) as s'
|
||||
),'p.park_id','=','s.park_id')
|
||||
->leftJoin('zone as z', 'p.park_id', '=', 'z.park_id')
|
||||
//->where('p.park_name', 'a')
|
||||
//->where('c.city_name', 'b')
|
||||
//->where('s.station_neighbor_station', 'c')
|
||||
->orderBy('p.park_ruby')
|
||||
->get();
|
||||
),'p.park_id','=','s.park_id');
|
||||
|
||||
// プルダウン指定の条件でwhere句を付与
|
||||
if (!empty($city_name)) {
|
||||
$park = $park->where('c.city_name', $city_name);
|
||||
}
|
||||
if (!empty($station_neighbor_station)) {
|
||||
$park = $park->where('s.station_neighbor_station', $station_neighbor_station);
|
||||
}
|
||||
if (!empty($park_name)) {
|
||||
$park = $park->whereRaw("LEFT(p.park_ruby, 1) REGEXP '^[".$park_name."]'");
|
||||
}
|
||||
$park = $park->orderBy('p.park_ruby')->get();
|
||||
|
||||
// 各マスタから追加情報を取得し、各ボタンの表示有無を判定する
|
||||
$result = [];
|
||||
$form_data = [];
|
||||
$now = date('Y-m-d H:i:s');
|
||||
foreach ($park as $row) {
|
||||
|
||||
// ゾーンマスタの情報から空き台数を取得する
|
||||
$vacantInfo = \DB::table('zone')
|
||||
->selectRaw('SUM(zone_tolerance) - SUM(zone_number) as vacant')
|
||||
->where('psection_id', $row->psection_id)
|
||||
->groupBy('psection_id')
|
||||
->first();
|
||||
// ゾーンマスタの情報を取得する
|
||||
$zoneInfo = \DB::table('zone as z')
|
||||
->select(
|
||||
'z.psection_id',
|
||||
'z.ptype_id',
|
||||
\DB::raw('SUM(z.zone_standard) as zone_standard'),
|
||||
\DB::raw('SUM(z.zone_number) as zone_number'),
|
||||
\DB::raw('SUM(z.zone_tolerance) as zone_tolerance'),
|
||||
'ps.psection_subject',
|
||||
'pt.ptype_subject'
|
||||
)
|
||||
->join('ptype as pt', 'z.ptype_id', '=', 'pt.ptype_id')
|
||||
->leftJoin('psection as ps', 'z.psection_id', '=', 'ps.psection_id')
|
||||
->where('z.park_id', $row->park_id)
|
||||
->groupBy('z.park_id', 'z.ptype_id', 'z.psection_id', 'ps.psection_subject', 'pt.ptype_subject')
|
||||
->get();
|
||||
|
||||
// ゾーンマスタが0件の場合、次のデータへ
|
||||
if ($zoneInfo->isEmpty()) {
|
||||
$form_data[] = [
|
||||
'park_name' => $row->park_name,
|
||||
'park_adrs' => $row->park_adrs,
|
||||
'price_memo' => $row->price_memo,
|
||||
'park_latitude' => $row->park_latitude,
|
||||
'park_longitude' => $row->park_longitude,
|
||||
'city_name' => $row->city_name,
|
||||
'station_neighbor_station' => $row->station_neighbor_station,
|
||||
'zone_data' => []
|
||||
];
|
||||
continue;
|
||||
}
|
||||
|
||||
// 定期予約マスタから予約中の台数を取得する
|
||||
$reservedCount = \DB::table('reserve')
|
||||
->where('psection_id', $row->psection_id)
|
||||
->where('valid_flag', 1)
|
||||
->count();
|
||||
|
||||
// 空き台数を計算
|
||||
$vacant = ($vacantInfo ? $vacantInfo->vacant : 0) - $reservedCount;
|
||||
|
||||
// 更新期間内判定
|
||||
$update_start = $row->update_grace_period_start_date . ' ' . $row->update_grace_period_start_time;
|
||||
$update_end = $row->update_grace_period_end_date . ' ' . $row->update_grace_period_end_time;
|
||||
$is_update_period = ($now >= $update_start && $now <= $update_end);
|
||||
|
||||
// ボタン表示有無判定
|
||||
if ($vacant > 0 && $is_update_period) { // 定期契約ボタン (空き台数が1台以上かつ更新期間内)
|
||||
$status = 1;
|
||||
} elseif ($vacant <= 0 && $is_update_period) { // 当日予約ボタン (空き台数が0台以下かつ更新期間内)
|
||||
$status = 2;
|
||||
} elseif ($vacant <= 0 && !$is_update_period) { // 販売期間外ボタン (空き台数が0台以下かつ更新期間外)
|
||||
$status = 3;
|
||||
} else {
|
||||
$status = null;
|
||||
// ゾーンマスタの件数分だけループする
|
||||
$zone_data = [];
|
||||
foreach ($zoneInfo as $zone) {
|
||||
|
||||
// 予約中件数取得
|
||||
$reservedCount = \DB::table('reserve')
|
||||
->where('park_id', $row->park_id)
|
||||
->where('psection_id', $zone->psection_id)
|
||||
->where('ptype_id', $zone->ptype_id)
|
||||
->where('valid_flag', 1)
|
||||
->count();
|
||||
|
||||
// ステータス(表示ボタン)判定
|
||||
$status = 0; // 0:非表示, 1:定期契約, 2:空き待ち予約, 3:販売期間外
|
||||
$zone_vacant = $zone->zone_tolerance - $zone->zone_number - $reservedCount;
|
||||
if ($zone_vacant > 0 && $is_update_period) { // 定期契約ボタン (空き台数が1台以上かつ更新期間内)
|
||||
$status = 1;
|
||||
} elseif ($zone_vacant <= 0 && $is_update_period) { // 空き待ち予約ボタン (空き台数が0台以下かつ更新期間内)
|
||||
$status = 2;
|
||||
} elseif ($zone_vacant <= 0 && !$is_update_period) { // 販売期間外ボタン (空き台数が0台以下かつ更新期間外)
|
||||
$status = 3;
|
||||
}
|
||||
|
||||
// 返却用データに追加
|
||||
$zone_data[] = [
|
||||
'psection_subject' => $zone->psection_subject,
|
||||
'ptype_subject' => $zone->ptype_subject,
|
||||
'zone_standard' => $zone->zone_standard,
|
||||
'zone_vacant' => $zone_vacant,
|
||||
'status' => $status
|
||||
];
|
||||
}
|
||||
|
||||
// $zone_dataを並び替え
|
||||
usort($zone_data, function($a, $b) {
|
||||
// 第一優先: ptype_subject昇順
|
||||
$ptypeCmp = strcmp($a['ptype_subject'], $b['ptype_subject']);
|
||||
if ($ptypeCmp !== 0) {
|
||||
return $ptypeCmp;
|
||||
}
|
||||
// 第二優先: psection_subject昇順
|
||||
$psectionCmp = strcmp($a['psection_subject'], $b['psection_subject']);
|
||||
if ($psectionCmp !== 0) {
|
||||
return $psectionCmp;
|
||||
}
|
||||
// 第三優先: status昇順
|
||||
return $a['status'] <=> $b['status'];
|
||||
});
|
||||
|
||||
// 画面返却用データに追加
|
||||
$result[] = [
|
||||
$form_data[] = [
|
||||
'park_name' => $row->park_name,
|
||||
'park_adrs' => $row->park_adrs,
|
||||
'price_memo' => $row->price_memo,
|
||||
'park_latitude' => $row->park_latitude,
|
||||
'park_longitude' => $row->park_longitude,
|
||||
'city_name' => $row->city_name,
|
||||
'station_neighbor_station' => $row->station_neighbor_station,
|
||||
'status' => $status
|
||||
'zone_data' => $zone_data
|
||||
];
|
||||
}
|
||||
|
||||
// 検索用プルダウン取得
|
||||
$cities = \DB::table('city')->select('city_name')->orderBy('city_ruby')->get();
|
||||
// プルダウン用データ取得
|
||||
$conditions = [$city_name, $station_neighbor_station, $park_name];
|
||||
$cities = \DB::table('city')->select('city_name')->orderBy('city_id')->get();
|
||||
$stations = \DB::table('station')->select('station_neighbor_station')->distinct()->orderBy('station_neighbor_station')->get();
|
||||
$parkings = ['全て', 'あ行', 'か行', 'さ行', 'た行', 'な行', 'は行', 'ま行', 'や行', 'ら行', 'わ行'];
|
||||
|
||||
// 検索結果返却
|
||||
return view('general.swo5_1',['form_data' => $result, 'cities' => $cities, 'stations' => $stations, 'parkings' => $parkings]);
|
||||
$parks = [
|
||||
'全て'=>'',
|
||||
'あ行'=>'あいうえおアイウエオ',
|
||||
'か行'=>'かきくけこがぎぐげごカキクケコガギグゲゴ',
|
||||
'さ行'=>'さしすせそざじずぜぞサシスセソザジズゼゾ',
|
||||
'た行'=>'たちつてとだぢづでどタチツテトダヂヅデド',
|
||||
'な行'=>'なにぬねのナニヌネノ',
|
||||
'は行'=>'はひふへほばびぶべぼぱぴぷぺぽハヒフヘホバビブベボパピプペポ',
|
||||
'ま行'=>'まみむめもマミムメモ',
|
||||
'や行'=>'やゆよヤユヨ',
|
||||
'ら行'=>'らりるれろラリルレロ',
|
||||
'わ行'=>'わをんワヲン '
|
||||
];
|
||||
|
||||
// 車種区分リスト取得
|
||||
$psections = \DB::table('psection')->select('psection_subject')->orderBy('psection_id', 'asc')->limit(4)->get();
|
||||
|
||||
// 情報返却
|
||||
return ['form_data' => $form_data, 'conditions' => $conditions, 'cities' => $cities, 'stations' => $stations, 'parks' => $parks, 'psections' => $psections];
|
||||
}
|
||||
}
|
||||
@ -90,7 +90,7 @@ class RegularContractController extends Controller
|
||||
->join('usertype', 'regular_contract.user_categoryid', '=', 'usertype.user_categoryid')
|
||||
->leftJoin('city', 'park.city_id', '=', 'city.city_id')
|
||||
->where('regular_contract.user_id', $user_id)
|
||||
->whereNotNull('regular_contract.contract_periods')
|
||||
->whereNotNull('regular_contract.contract_money')
|
||||
->select(
|
||||
'regular_contract.contract_id',
|
||||
'park.park_name',
|
||||
|
||||
@ -12,11 +12,12 @@ use Illuminate\Support\Facades\Redirect;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Exception;
|
||||
use function redirect;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class RegularContractCreateController extends Controller
|
||||
{
|
||||
// 新規作成画面表示
|
||||
public function show()
|
||||
public function show(Request $request)
|
||||
{
|
||||
$user_id = session('user_id');
|
||||
if (!$user_id) {
|
||||
@ -88,35 +89,62 @@ class RegularContractCreateController extends Controller
|
||||
'station_name_ruby' => 'station.station_name_ruby',
|
||||
'park_id' => 'park.park_id',
|
||||
];
|
||||
if (isset($sortable[$sort])) {
|
||||
$query->orderBy($sortable[$sort], $order);
|
||||
} else {
|
||||
$query->orderBy('park.park_id', 'asc');
|
||||
}
|
||||
$query->orderBy('park.park_id', 'asc');
|
||||
|
||||
$total = $query->count();
|
||||
$parks_table = $query->skip(($page - 1) * $perPage)->take($perPage)->get();
|
||||
$parks_table = $query->get();
|
||||
|
||||
if ($sort === 'park_ruby' || $sort === 'station_name_ruby') {
|
||||
$collator = new \Collator('ja');
|
||||
$parks_table = $parks_table->sort(function ($a, $b) use ($order, $sort, $collator) {
|
||||
$a_val = $a->$sort ?? '';
|
||||
$b_val = $b->$sort ?? '';
|
||||
return $order === 'asc'
|
||||
? $collator->compare($a_val, $b_val)
|
||||
: $collator->compare($b_val, $a_val);
|
||||
})->values();
|
||||
} else {
|
||||
// park_id, city_idなどはSQLのorderByで十分なので、ここでPHPソートは不要
|
||||
if (isset($sortable[$sort])) {
|
||||
$parks_table = $parks_table->sortBy($sort, SORT_REGULAR, $order === 'desc')->values();
|
||||
}
|
||||
}
|
||||
$page = request()->input('page', 1);
|
||||
$perPage = 10;
|
||||
$parks_table = $parks_table->slice(($page - 1) * $perPage, $perPage)->values();
|
||||
|
||||
// zoneテーブルデータを取得(psectionテーブルとJOINしてpsection_subjectも取得)
|
||||
$zones = DB::table('zone')
|
||||
->leftJoin('psection', 'zone.psection_id', '=', 'psection.psection_id')
|
||||
->select('zone.zone_id', 'zone.park_id', 'zone.psection_id', 'zone.zone_number', 'zone.zone_tolerance', 'psection.psection_subject')
|
||||
->select('zone.zone_id', 'zone.park_id', 'zone.ptype_id', 'zone.psection_id', 'zone.zone_number', 'zone.zone_tolerance', 'psection.psection_subject')
|
||||
->get()
|
||||
->groupBy('park_id');
|
||||
|
||||
// 空き予約マスタデータを取得
|
||||
$reserve = DB::table('reserve')
|
||||
->select('reserve_id', 'park_id', 'psection_id')
|
||||
->select('reserve_id', 'park_id', 'ptype_id', 'psection_id')
|
||||
->where('valid_flag', 1)
|
||||
->get()
|
||||
->groupBy('park_id');
|
||||
|
||||
\Log::info('新規定期契約-駐輪場選択画面にアクセス', [
|
||||
'user_id' => $user_id,
|
||||
]);
|
||||
// ルート名で画面表示を切り替え(新規定期契約 or 駐輪場検索)
|
||||
$isRegularContract = $request->route()->getName() === 'regular_contract.create';
|
||||
|
||||
// ヘッダーの選択状態を分岐
|
||||
$active_menu = $isRegularContract ? 'SWC-8-1' : 'SWC-10-1';
|
||||
|
||||
if ($isRegularContract) {
|
||||
\Log::info('新規定期契約-駐輪場選択画面にアクセス', [
|
||||
'user_id' => $user_id,
|
||||
]);
|
||||
} else {
|
||||
\Log::info('駐輪場検索-駐輪場選択画面にアクセス', [
|
||||
'user_id' => $user_id,
|
||||
]);
|
||||
}
|
||||
|
||||
return view('regular_contract.create', [
|
||||
'active_menu' => 'SWC-8-1', // この画面のID
|
||||
'active_menu' => $active_menu, // この画面のID
|
||||
'user_name' => $user ? $user->user_name : '', // ユーザー名(ヘッダー用)
|
||||
'cities' => $cities,
|
||||
'stations' => $stations,
|
||||
@ -128,6 +156,7 @@ class RegularContractCreateController extends Controller
|
||||
'zones' => $zones,
|
||||
'city_grace_periods' => $city_grace_periods,
|
||||
'reserve' => $reserve,
|
||||
'isRegularContract' => $isRegularContract
|
||||
]);
|
||||
}
|
||||
|
||||
@ -563,7 +592,7 @@ class RegularContractCreateController extends Controller
|
||||
'user_categoryid' => $user_categoryid,
|
||||
'park_id' => $park->park_id,
|
||||
'contract_created_at' => now(),
|
||||
'contract_reduction' => $ward_residents,
|
||||
'contract_reduction' => $request->contract_reduction === 'はい' ? 1 : 0,
|
||||
'update_flag' => 2,
|
||||
'contract_cancel_flag' => 0,
|
||||
'psection_id' => $request->psection_id,
|
||||
@ -636,16 +665,16 @@ class RegularContractCreateController extends Controller
|
||||
|
||||
// おもて画像保存(Laravel Storageを使用)
|
||||
$front = $request->file('user_idcard');
|
||||
$filename_front = uniqid('photo1_') . '.' . $front->getClientOriginalExtension();
|
||||
$filename_front = uniqid('photo1_') . '.' . $front->getClientOriginalExtension();
|
||||
$front->storeAs('photo', $filename_front, 'public');
|
||||
|
||||
|
||||
// userテーブルに保存(チェック済フラグはSHJ-1処理後に設定)
|
||||
$updateData = [
|
||||
'photo_filename1' => $filename_front,
|
||||
'user_idcard' => $request->idcard_type,
|
||||
'updated_at' => now(),
|
||||
];
|
||||
|
||||
|
||||
// ウラ画像がある場合保存し更新項目に追加
|
||||
if ($request->hasFile('user_idcard2')) {
|
||||
$back = $request->file('user_idcard2');
|
||||
@ -654,7 +683,7 @@ class RegularContractCreateController extends Controller
|
||||
$updateData['photo_filename2'] = $filename_back;
|
||||
}
|
||||
DB::table('user')->where('user_id', $user_id)->update($updateData);
|
||||
|
||||
|
||||
// SHJ-1 本人確認自動処理を実行
|
||||
$user = DB::table('user')->where('user_id', $user_id)->first();
|
||||
$park = DB::table('park')->where('park_id', $request->park_id)->first();
|
||||
@ -685,45 +714,24 @@ class RegularContractCreateController extends Controller
|
||||
'user_seq' => $user_seq,
|
||||
'park_id' => $park_id
|
||||
]);
|
||||
|
||||
// 処理結果に基づいて遷移先を決定
|
||||
if ($exitCode === 0) {
|
||||
// 成功の場合
|
||||
return redirect("/regular-contract/upload_identity_success?contract_id={$contract_id}");
|
||||
// return view('regular_contract.create_confirm', [
|
||||
// 'contract_id' => $request->contract_id,
|
||||
// 'user' => $user,
|
||||
// 'park' => $park,
|
||||
// 'psection' => $psection,
|
||||
// 'usertype' => $usertype,
|
||||
// 'user_name' => $user->user_name,
|
||||
// 'active_menu' => 'SWC-8-1'
|
||||
// ]);
|
||||
} else {
|
||||
// 失敗の場合 または、学生証 と その他 の場合
|
||||
return redirect("/regular-contract/upload_identity_fail?contract_id={$contract_id}");
|
||||
|
||||
// return view('regular_contract.create_confirm', [
|
||||
// 'contract_id' => $request->contract_id,
|
||||
// 'user' => $user,
|
||||
// 'park' => $park,
|
||||
// 'psection' => $psection,
|
||||
// 'usertype' => $usertype,
|
||||
// 'user_name' => $user->user_name,
|
||||
// 'active_menu' => 'SWC-8-1'
|
||||
// ]);
|
||||
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
\Log::error('SHJ-1バッチ処理でエラー発生', [
|
||||
'error' => $e->getMessage(),
|
||||
'user_seq' => $user_seq,
|
||||
'park_id' => $park_id
|
||||
]);
|
||||
|
||||
return redirect("/regular-contract/upload_identity_fail?contract_id={$contract_id}");
|
||||
}
|
||||
|
||||
// 処理結果に基づいて遷移
|
||||
return view('regular_contract.create_confirm', [
|
||||
'contract_id' => $request->contract_id,
|
||||
'user' => $user,
|
||||
'park' => $park,
|
||||
'psection' => $psection,
|
||||
'usertype' => $usertype,
|
||||
'user_name' => $user->user_name,
|
||||
'active_menu' => 'SWC-8-1'
|
||||
]);
|
||||
}
|
||||
|
||||
public function createConfirmNext($contract_id)
|
||||
@ -784,7 +792,7 @@ class RegularContractCreateController extends Controller
|
||||
|
||||
// 利用期間選択画面へ遷移
|
||||
return view('regular_contract.create_select_period', [
|
||||
'active_menu' => 'SWC-4-1', // マイページメニューの選択状態用
|
||||
'active_menu' => 'SWC-8-1', // マイページメニューの選択状態用
|
||||
'user_name' => $user->user_name, // ユーザー名(ヘッダー用)
|
||||
'contract_id' => $contract_id,
|
||||
'regular_type' => $regular_type,
|
||||
@ -809,14 +817,20 @@ class RegularContractCreateController extends Controller
|
||||
return redirect('/login');
|
||||
}
|
||||
|
||||
// 期間選択チェック
|
||||
$request->validate([
|
||||
$contract_id = $request->input('contract_id');
|
||||
|
||||
$validator = Validator::make($request->all(), [
|
||||
'month' => 'required',
|
||||
], [
|
||||
'month.required' => '契約期間が選択されていません。',
|
||||
]);
|
||||
|
||||
$contract_id = $request->input('contract_id');
|
||||
if ($validator->fails()) {
|
||||
return redirect()->route('regular_contract.create_confirm_error', ['contract_id' => $contract_id])
|
||||
->withErrors($validator)
|
||||
->withInput();
|
||||
}
|
||||
|
||||
$month = $request->input('month');
|
||||
$price = $request->input('price_' . $month);
|
||||
|
||||
@ -842,554 +856,4 @@ class RegularContractCreateController extends Controller
|
||||
// 完了後はウェルネット決済画面(仮)へリダイレクト
|
||||
return redirect()->route('wellnet.payment');
|
||||
}
|
||||
|
||||
/**
|
||||
* SHJ-1本人確認処理成功ページ表示!!!!テスト後に削除して!!!!viewも!!!!!
|
||||
*/
|
||||
public function showUploadIdentitySuccess(Request $request)
|
||||
{
|
||||
$contractId = $request->get('contract_id');
|
||||
$userId = Session::get('user_id');
|
||||
|
||||
// 詳細情報を取得
|
||||
$debugInfo = $this->getShjDebugInfo($userId, $contractId);
|
||||
|
||||
return view('regular_contract.upload_identity_success', compact('debugInfo', 'contractId'));
|
||||
}
|
||||
|
||||
/**
|
||||
* SHJ-1本人確認処理失敗ページ表示!!!!テスト後に削除して!!!!viewも!!!!!
|
||||
*/
|
||||
public function showUploadIdentityFail(Request $request)
|
||||
{
|
||||
$contractId = $request->get('contract_id');
|
||||
$userId = Session::get('user_id');
|
||||
|
||||
// 詳細情報を取得
|
||||
$debugInfo = $this->getShjDebugInfo($userId, $contractId);
|
||||
|
||||
return view('regular_contract.upload_identity_fail', compact('debugInfo', 'contractId'));
|
||||
}
|
||||
|
||||
/**
|
||||
* SHJ-1デバッグ情報取得!!!!テスト後に削除して!!!!
|
||||
*/
|
||||
private function getShjDebugInfo($userId, $contractId)
|
||||
{
|
||||
try {
|
||||
// ユーザー情報取得
|
||||
$user = DB::table('user')->where('user_id', $userId)->first();
|
||||
|
||||
// 契約情報取得
|
||||
$contract = DB::table('regular_contract')->where('user_id', $user->user_id ?? 0)->first();
|
||||
|
||||
// 駐輪場情報取得
|
||||
$park = null;
|
||||
if ($contract) {
|
||||
$park = DB::table('park')->where('park_id', $contract->park_id)->first();
|
||||
}
|
||||
|
||||
// 最新のSHJ-1バッチログ取得
|
||||
$batchLog = DB::table('batch_log')
|
||||
->where('process_name', 'SHJ-1本人確認自動処理')
|
||||
->orderBy('created_at', 'desc')
|
||||
->first();
|
||||
|
||||
// 最新のログファイルから詳細ログを取得
|
||||
$logContent = $this->getRecentShjLogs();
|
||||
|
||||
// ログからAPI結果情報を解析
|
||||
$apiResults = $this->parseApiResultsFromLogs($logContent);
|
||||
|
||||
return [
|
||||
'user' => $user,
|
||||
'contract' => $contract,
|
||||
'park' => $park,
|
||||
'batch_log' => $batchLog,
|
||||
'detailed_logs' => $logContent,
|
||||
'recent_logs' => $logContent, // 为调试页面提供日志内容访问
|
||||
'timestamp' => now()->format('Y-m-d H:i:s'),
|
||||
// API結果情報
|
||||
'ocr_text_length' => $apiResults['ocr_text_length'],
|
||||
'ocr_text_preview' => $apiResults['ocr_text_preview'],
|
||||
'ocr_full_text' => $apiResults['ocr_full_text'],
|
||||
'ocr_threshold' => $apiResults['ocr_threshold'],
|
||||
'name_similarity' => $apiResults['name_similarity'],
|
||||
'address_similarity' => $apiResults['address_similarity'],
|
||||
'name_passed' => $apiResults['name_passed'],
|
||||
'address_passed' => $apiResults['address_passed'],
|
||||
'matched_address_type' => $apiResults['matched_address_type'] ?? null, // 新增:匹配成功的地址类型
|
||||
'name_match_attempts' => $apiResults['name_match_attempts'],
|
||||
'address_match_attempts' => $apiResults['address_match_attempts'],
|
||||
'best_name_match' => $apiResults['best_name_match'],
|
||||
'best_address_match' => $apiResults['best_address_match'],
|
||||
'name_match_details' => $apiResults['name_match_details'],
|
||||
'address_match_details' => $apiResults['address_match_details'],
|
||||
'ocr_debug_info' => $apiResults['ocr_debug_info'] ?? null,
|
||||
// 移除重复分析逻辑,只显示SHJ-1的结果
|
||||
'calculated_distance' => $apiResults['calculated_distance'],
|
||||
'distance_text' => $apiResults['distance_text'] ?? null,
|
||||
'distance_limit' => $apiResults['distance_limit'] ?? null,
|
||||
'distance_start_address' => $apiResults['distance_start_address'] ?? null,
|
||||
'distance_end_address' => $apiResults['distance_end_address'] ?? null,
|
||||
'distance_passed' => $apiResults['distance_passed'],
|
||||
'maps_api_status' => $apiResults['maps_api_status'],
|
||||
'maps_api_error' => $apiResults['maps_api_error']
|
||||
];
|
||||
|
||||
} catch (Exception $e) {
|
||||
\Log::error('Debug info error: ' . $e->getMessage());
|
||||
return [
|
||||
'error' => 'デバッグ情報の取得に失敗しました: ' . $e->getMessage(),
|
||||
'timestamp' => now()->format('Y-m-d H:i:s')
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 最新のSHJ-1関連ログを取得!!!!テスト後に削除して!!!!
|
||||
*/
|
||||
private function getRecentShjLogs()
|
||||
{
|
||||
try {
|
||||
$logPath = storage_path('logs/laravel.log');
|
||||
if (!file_exists($logPath)) {
|
||||
return '日志文件未找到';
|
||||
}
|
||||
|
||||
$logs = file_get_contents($logPath);
|
||||
$lines = explode("\n", $logs);
|
||||
|
||||
// 最新の1000行からSHJ-1関連ログを抽出(さらに範囲拡大)
|
||||
$recentLines = array_slice($lines, -1000);
|
||||
$shjLogs = [];
|
||||
|
||||
foreach ($recentLines as $line) {
|
||||
if (strpos($line, 'SHJ-1') !== false ||
|
||||
strpos($line, 'GoogleVision') !== false ||
|
||||
strpos($line, 'Google Maps') !== false ||
|
||||
strpos($line, 'バッチ処理') !== false) {
|
||||
$shjLogs[] = $line;
|
||||
}
|
||||
}
|
||||
|
||||
return implode("\n", array_slice($shjLogs, -200)); // 最新200行(さらに拡大)
|
||||
|
||||
} catch (Exception $e) {
|
||||
return 'ログ取得エラー: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ログからAPI結果情報を解析!!!!テスト後に削除して!!!!
|
||||
*/
|
||||
private function parseApiResultsFromLogs($logContent)
|
||||
{
|
||||
$results = [
|
||||
'ocr_text_length' => 'N/A',
|
||||
'ocr_text_preview' => 'N/A',
|
||||
'ocr_threshold' => 'N/A',
|
||||
'name_similarity' => 'N/A',
|
||||
'address_similarity' => 'N/A',
|
||||
'name_passed' => false,
|
||||
'address_passed' => false,
|
||||
'calculated_distance' => 'N/A',
|
||||
'distance_passed' => false,
|
||||
'maps_api_status' => '成功',
|
||||
'maps_api_error' => 'なし',
|
||||
// 新增详细OCR信息
|
||||
'ocr_full_text' => 'N/A',
|
||||
'name_match_attempts' => [],
|
||||
'address_match_attempts' => [],
|
||||
'best_name_match' => 'N/A',
|
||||
'best_address_match' => 'N/A',
|
||||
'match_details' => 'N/A'
|
||||
];
|
||||
|
||||
try {
|
||||
// OCR処理完了ログから文字数とプレビューを抽取(清理格式)
|
||||
if (preg_match('/GoogleVision OCR処理完了.*"text_length":(\d+).*"text_preview":"([^"]*)"/', $logContent, $matches)) {
|
||||
$results['ocr_text_length'] = $matches[1];
|
||||
// 清理OCR文本,移除可能的日志污染
|
||||
$cleanText = $matches[2];
|
||||
// 移除可能混入的日志时间戳和标记
|
||||
$cleanText = preg_replace('/\[\d{4}-\d{2}-\d{2}.*?\].*?local\.INFO.*?$/', '', $cleanText);
|
||||
// 移除末尾的不完整JSON片段
|
||||
$cleanText = preg_replace('/\s*\{?\s*$/', '', $cleanText);
|
||||
// 清理换行和多余空格
|
||||
$cleanText = trim($cleanText);
|
||||
$results['ocr_text_preview'] = $cleanText;
|
||||
}
|
||||
|
||||
// 尝试从GoogleVision日志提取完整的OCR文本
|
||||
if (preg_match('/GoogleVision OCR処理完了.*"text_full":"([^"]*)"/', $logContent, $matches)) {
|
||||
$fullText = $matches[1];
|
||||
// 解码JSON转义字符
|
||||
$fullText = str_replace('\n', "\n", $fullText);
|
||||
$fullText = str_replace('\r', "\r", $fullText);
|
||||
$fullText = str_replace('\"', '"', $fullText);
|
||||
$fullText = str_replace('\\\\', '\\', $fullText);
|
||||
$results['ocr_full_text'] = $fullText;
|
||||
}
|
||||
|
||||
// 尝试从SHJ-1日志提取完整的OCR文本(多种模式匹配)
|
||||
$patterns = [
|
||||
'/SHJ-1 完全OCR認識結果.*"ocr_full_text":"([^"]*)"/', // 原始日文版本
|
||||
'/螳悟・OCR隱崎ュ倡オ先棡.*"ocr_full_text":"([^"]*)"/', // 日文编码版本
|
||||
'/OCR認識結果.*"ocr_full_text":"([^"]*)"/', // 简化匹配
|
||||
'/"ocr_full_text":"([^"]*)"/', // 最宽泛匹配
|
||||
];
|
||||
|
||||
foreach ($patterns as $pattern) {
|
||||
if (empty($results['ocr_full_text']) && preg_match($pattern, $logContent, $matches)) {
|
||||
$encodedText = $matches[1];
|
||||
// Base64解码
|
||||
$fullText = base64_decode($encodedText);
|
||||
if ($fullText !== false && strlen($fullText) > 10) {
|
||||
$results['ocr_full_text'] = $fullText;
|
||||
|
||||
// 简化OCR信息显示 - 只显示基本信息
|
||||
$results['ocr_debug_info'] = [
|
||||
'decoded_length' => strlen($fullText),
|
||||
'preview' => substr($fullText, 0, 200)
|
||||
];
|
||||
break; // 找到后停止尝试其他模式
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 尝试从OCR认识内容详细日志提取(备选方案,适配日文编码)
|
||||
if (empty($results['ocr_full_text']) && preg_match('/OCR隱崎ュ伜・螳ケ隧ウ邏ー.*"raw_text":"OCR_TEXT_START>([^<]*)<OCR_TEXT_END"/', $logContent, $matches)) {
|
||||
$results['ocr_full_text'] = $matches[1];
|
||||
}
|
||||
|
||||
// 提取氏名匹配详细信息(适配日文编码)
|
||||
$nameMatchDetails = [];
|
||||
if (preg_match_all('/豌丞錐繝槭ャ繝√Φ繧ー隧ウ邏ー.*"target_name":"([^"]*)".*"similarity_score":([^,}]*).*"ocr_contains_name":"([^"]*)"/', $logContent, $nameMatches, PREG_SET_ORDER)) {
|
||||
foreach ($nameMatches as $match) {
|
||||
$nameMatchDetails[] = [
|
||||
'target' => $match[1],
|
||||
'score' => round(floatval($match[2]), 2),
|
||||
'found_in_ocr' => $match[3]
|
||||
];
|
||||
}
|
||||
}
|
||||
$results['name_match_details'] = $nameMatchDetails;
|
||||
|
||||
// 提取住所匹配详细信息(适配日文编码)
|
||||
$addressMatchDetails = [];
|
||||
if (preg_match_all('/菴乗園繝槭ャ繝√Φ繧ー隧ウ邏ー.*"target_address":"([^"]*)".*"address_type":"([^"]*)".*"similarity_score":([^,}]*).*"ocr_contains_address":"([^"]*)"/', $logContent, $addressMatches, PREG_SET_ORDER)) {
|
||||
foreach ($addressMatches as $match) {
|
||||
$addressMatchDetails[] = [
|
||||
'target' => $match[1],
|
||||
'type' => $match[2],
|
||||
'score' => round(floatval($match[3]), 2),
|
||||
'found_in_ocr' => $match[4]
|
||||
];
|
||||
}
|
||||
}
|
||||
$results['address_match_details'] = $addressMatchDetails;
|
||||
|
||||
// 从新的SHJ-1日志格式中提取信息
|
||||
|
||||
// 提取OCR抽出结果
|
||||
if (preg_match('/SHJ-1 OCR抽出成功.*"extracted_name":"([^"]*)".*"extracted_address":"([^"]*)".*"ocr_value":"([^"]*)"/', $logContent, $matches)) {
|
||||
$results['extracted_name'] = $matches[1];
|
||||
$results['extracted_address'] = $matches[2];
|
||||
$results['extracted_ocr_value'] = $matches[3];
|
||||
}
|
||||
|
||||
// 提取居住住所照合结果
|
||||
if (preg_match('/SHJ-1 居住住所照合.*"resident_address":"([^"]*)".*"similarity":([^,}]*)/', $logContent, $matches)) {
|
||||
$results['resident_address'] = $matches[1];
|
||||
$results['resident_similarity'] = round(floatval($matches[2]), 2);
|
||||
}
|
||||
|
||||
// 提取関連住所照合结果
|
||||
if (preg_match('/SHJ-1 関連住所照合.*"related_address":"([^"]*)".*"similarity":([^,}]*)/', $logContent, $matches)) {
|
||||
$results['related_address'] = $matches[1];
|
||||
$results['related_similarity'] = round(floatval($matches[2]), 2);
|
||||
}
|
||||
|
||||
// 提取最終OCR結果
|
||||
if (preg_match('/SHJ-1 OCR照合(成功|失敗)/', $logContent, $matches)) {
|
||||
$results['final_ocr_result'] = $matches[1];
|
||||
$results['address_passed'] = ($matches[1] === '成功');
|
||||
$results['name_passed'] = ($matches[1] === '成功'); // 新SHJ-1逻辑中,成功表示整体成功
|
||||
}
|
||||
|
||||
// 如果OCR文本为空或太短,提供说明
|
||||
if (empty($results['ocr_text_preview']) || strlen($results['ocr_text_preview']) < 5) {
|
||||
$results['ocr_text_preview'] = '(OCR認識内容が短いか、表示できない文字が含まれています)';
|
||||
}
|
||||
|
||||
// 表面画像処理完了の詳細結果を抽取
|
||||
if (preg_match('/SHJ-1 表面画像処理完了.*"front_result":\{"name_matches":\[([^\]]*)\],"address_matches":\[([^\]]*)\]\}/', $logContent, $matches)) {
|
||||
$nameMatches = explode(',', $matches[1]);
|
||||
$addressMatches = explode(',', $matches[2]);
|
||||
|
||||
$results['name_match_attempts'] = array_map(function($val) {
|
||||
return round(floatval($val), 2);
|
||||
}, $nameMatches);
|
||||
|
||||
$results['address_match_attempts'] = array_map(function($val) {
|
||||
return round(floatval($val), 2);
|
||||
}, $addressMatches);
|
||||
}
|
||||
|
||||
// OCR類似度計算結果の詳細情報を抽取
|
||||
if (preg_match('/SHJ-1 OCR類似度計算結果.*"best_name_match":([^,}]*).*"best_address_match":([^,}]*).*"all_name_matches":\[([^\]]*)\].*"all_address_matches":\[([^\]]*)\]/', $logContent, $matches)) {
|
||||
$results['best_name_match'] = round(floatval($matches[1]), 2);
|
||||
$results['best_address_match'] = round(floatval($matches[2]), 2);
|
||||
|
||||
$allNameMatches = explode(',', $matches[3]);
|
||||
$allAddressMatches = explode(',', $matches[4]);
|
||||
|
||||
$results['name_match_attempts'] = array_map(function($val) {
|
||||
return round(floatval($val), 2);
|
||||
}, $allNameMatches);
|
||||
|
||||
$results['address_match_attempts'] = array_map(function($val) {
|
||||
return round(floatval($val), 2);
|
||||
}, $allAddressMatches);
|
||||
}
|
||||
|
||||
// OCR閾値チェックログから類似度情報を抽出(新しい順序匹配対応)
|
||||
if (preg_match('/SHJ-1 OCR閾値チェック.*"threshold":"?([^",}]*)"?.*"name_match":([^,}]*).*"address_match":([^,}]*).*"name_passed":([^,}]*).*"address_passed":([^,}]*).*"matched_address_type":"?([^",}]*)"?/', $logContent, $matches)) {
|
||||
$results['ocr_threshold'] = $matches[1];
|
||||
$results['name_similarity'] = round(floatval($matches[2]), 2);
|
||||
$results['address_similarity'] = round(floatval($matches[3]), 2);
|
||||
$results['name_passed'] = $matches[4] === 'true';
|
||||
$results['address_passed'] = $matches[5] === 'true';
|
||||
$results['matched_address_type'] = $matches[6] ?: null;
|
||||
}
|
||||
|
||||
// Google Maps API エラーチェック
|
||||
if (strpos($logContent, 'Google Maps distance calculation error') !== false) {
|
||||
$results['maps_api_status'] = 'エラー';
|
||||
if (preg_match('/Google Maps distance calculation error.*"error":"([^"]*)"/', $logContent, $matches)) {
|
||||
$results['maps_api_error'] = $matches[1];
|
||||
}
|
||||
} else if (strpos($logContent, 'Distance calculation failed') !== false) {
|
||||
$results['maps_api_status'] = 'アドレス未発見';
|
||||
$results['maps_api_error'] = 'NOT_FOUND';
|
||||
}
|
||||
|
||||
// 距離計算結果を抽取(最新の詳細ログから)
|
||||
if (preg_match_all('/SHJ-1 距離計算完了.*"calculated_distance_meters":(\d+).*"distance_text":"([^"]*)".*"limit_meters":"?([^",}]*)"?.*"within_limit":([^,}]*)/', $logContent, $allMatches, PREG_SET_ORDER)) {
|
||||
// 最後の(最新の)マッチを使用
|
||||
$matches = end($allMatches);
|
||||
$results['calculated_distance'] = $matches[1]; // 距離メートル
|
||||
$results['distance_text'] = $matches[2]; // Google Mapsテキスト
|
||||
$results['distance_limit'] = $matches[3]; // 制限値
|
||||
$results['distance_passed'] = $matches[4] === 'true';
|
||||
} else {
|
||||
// ログから具体的な結果が取得できない場合はデフォルト値を設定
|
||||
// ※重要:API成功≠距離制限内ではないため、明示的にfalseにする
|
||||
$results['distance_passed'] = false;
|
||||
if (strpos($logContent, 'Distance check error') === false &&
|
||||
strpos($logContent, 'Google Maps distance calculation error') === false) {
|
||||
$results['calculated_distance'] = '計算成功(制限値詳細はログで確認)';
|
||||
$results['maps_api_status'] = '成功(但制限確認要)';
|
||||
} else {
|
||||
$results['calculated_distance'] = '計算失敗';
|
||||
$results['maps_api_status'] = 'エラー';
|
||||
}
|
||||
}
|
||||
|
||||
// 距離計算開始ログから起点・終点住所を抽取
|
||||
if (preg_match('/SHJ-1 距離計算開始.*"user_address":"([^"]*)".*"park_address":"([^"]*)"/', $logContent, $matches)) {
|
||||
$results['distance_start_address'] = $matches[1];
|
||||
$results['distance_end_address'] = $matches[2];
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
\Log::error('API結果解析エラー: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
// 不再需要的分析方法已移除 - 只显示SHJ-1的结果
|
||||
|
||||
/**
|
||||
* 废弃的方法(已不再使用)
|
||||
*/
|
||||
private function manualOcrAnalysis($logContent, $user = null)
|
||||
{
|
||||
$analysis = [
|
||||
'found_base64' => false,
|
||||
'decoded_success' => false,
|
||||
'decoded_text' => '',
|
||||
'contains_yamada' => false,
|
||||
'contains_taro' => false,
|
||||
'contains_tokyo' => false,
|
||||
'contains_osaka' => false,
|
||||
'full_analysis' => 'Analysis failed',
|
||||
'corrected_matching' => null
|
||||
];
|
||||
|
||||
try {
|
||||
// 分割日志内容为行数组,按时间倒序搜索最新的OCR结果
|
||||
$logLines = explode("\n", $logContent);
|
||||
$logLines = array_reverse($logLines); // 从最新的开始搜索
|
||||
|
||||
// 查找最新的Base64编码OCR结果
|
||||
$patterns = [
|
||||
'/SHJ-1 完全OCR認識結果.*"ocr_full_text":"([^"]*)"/',
|
||||
'/SHJ-1.*OCR.*結果.*"ocr_full_text":"([^"]*)"/',
|
||||
'/"ocr_full_text":"([^"]*)"/'
|
||||
];
|
||||
|
||||
foreach ($logLines as $line) {
|
||||
foreach ($patterns as $pattern) {
|
||||
if (preg_match($pattern, $line, $matches)) {
|
||||
$analysis['found_base64'] = true;
|
||||
$base64Text = $matches[1];
|
||||
|
||||
// Base64解码
|
||||
$decodedText = base64_decode($base64Text);
|
||||
if ($decodedText !== false && strlen($decodedText) > 10) {
|
||||
$analysis['decoded_success'] = true;
|
||||
$analysis['decoded_text'] = $decodedText;
|
||||
|
||||
// 内容分析
|
||||
$analysis['contains_yamada'] = strpos($decodedText, '山田') !== false;
|
||||
$analysis['contains_taro'] = strpos($decodedText, '太郎') !== false;
|
||||
$analysis['contains_tokyo'] = strpos($decodedText, '東京') !== false;
|
||||
$analysis['contains_osaka'] = strpos($decodedText, '大阪') !== false;
|
||||
|
||||
// ユーザー提案:空白と改行を除去して比較
|
||||
$analysis['corrected_matching'] = $this->performCorrectedMatching($decodedText, $user);
|
||||
|
||||
// 詳細分析(実際のユーザーデータから期待値を取得)
|
||||
if ($user) {
|
||||
$expectedName = $user->user_name ?? "";
|
||||
$expectedAddress = ($user->user_regident_pre ?? '') .
|
||||
($user->user_regident_city ?? '') .
|
||||
($user->user_regident_add ?? '') ?: "";
|
||||
} else {
|
||||
$expectedName = "";
|
||||
$expectedAddress = "";
|
||||
}
|
||||
|
||||
$analysis['full_analysis'] =
|
||||
"OCR認識テキスト長: " . strlen($decodedText) . "文字\n" .
|
||||
"期待氏名: '$expectedName'\n" .
|
||||
"期待住所: '$expectedAddress'\n" .
|
||||
"山田を含む: " . ($analysis['contains_yamada'] ? 'YES' : 'NO') . "\n" .
|
||||
"太郎を含む: " . ($analysis['contains_taro'] ? 'YES' : 'NO') . "\n" .
|
||||
"東京を含む: " . ($analysis['contains_tokyo'] ? 'YES' : 'NO') . "\n" .
|
||||
"大阪を含む: " . ($analysis['contains_osaka'] ? 'YES' : 'NO') . "\n" .
|
||||
"認識完全内容: " . substr($decodedText, 0, 200) . "...";
|
||||
|
||||
// 成功解码最新OCR结果后立即返回
|
||||
return $analysis;
|
||||
}
|
||||
// 解码失败时,继续搜索其他条目
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
$analysis['full_analysis'] = 'OCR分析エラー: ' . $e->getMessage();
|
||||
}
|
||||
|
||||
return $analysis;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修正マッチングアルゴリズム実行(空白・改行除去)
|
||||
*/
|
||||
private function performCorrectedMatching($ocrText, $user = null)
|
||||
{
|
||||
// ユーザー情報から期待値を取得、デフォルトはテスト用
|
||||
if ($user) {
|
||||
$expectedName = $user->user_name ?? "";
|
||||
$expectedAddress = ($user->user_regident_pre ?? '') .
|
||||
($user->user_regident_city ?? '') .
|
||||
($user->user_regident_add ?? '') ?: "";
|
||||
} else {
|
||||
$expectedName = "";
|
||||
$expectedAddress = "";
|
||||
}
|
||||
|
||||
// 統一的テキスト正規化関数
|
||||
$normalize = function($text) {
|
||||
// 全空白文字と改行を除去(全角スペース含む)
|
||||
$text = preg_replace('/[\s\x{3000}]+/u', '', $text); // \x{3000}は全角スペース
|
||||
// 一般的な空白文字を明示的に除去
|
||||
$text = str_replace([' ', ' ', "\t", "\n", "\r"], '', $text);
|
||||
// 全角→半角変換
|
||||
$text = mb_convert_kana($text, 'rnask', 'UTF-8');
|
||||
// 住所統一
|
||||
$text = str_replace(['東京市', '東京府'], '東京都', $text);
|
||||
$text = str_replace(['の'], '', $text);
|
||||
// 数字統一
|
||||
$text = str_replace(['1','2','3','4','5','6','7','8','9','0'],
|
||||
['1','2','3','4','5','6','7','8','9','0'], $text);
|
||||
return $text;
|
||||
};
|
||||
|
||||
// 正規化処理
|
||||
$normalizedOcr = $normalize($ocrText);
|
||||
$normalizedExpectedName = $normalize($expectedName);
|
||||
$normalizedExpectedAddr = $normalize($expectedAddress);
|
||||
|
||||
// 使用"住所"分割OCR文本
|
||||
$addressKeyword = '住所';
|
||||
$ocrParts = explode($addressKeyword, $normalizedOcr, 2);
|
||||
|
||||
$personalInfoSection = $ocrParts[0] ?? ''; // "住所"前の個人情報欄
|
||||
$addressSection = isset($ocrParts[1]) ? $addressKeyword . $ocrParts[1] : ''; // "住所"後の住所欄
|
||||
|
||||
// 分区マッチング計算
|
||||
$nameMatch = $this->calculateSimpleMatch($normalizedExpectedName, $personalInfoSection);
|
||||
$addrMatch = $this->calculateSimpleMatch($normalizedExpectedAddr, $addressSection);
|
||||
|
||||
return [
|
||||
'original_ocr' => substr($ocrText, 0, 100) . '...',
|
||||
'normalized_ocr' => substr($normalizedOcr, 0, 100) . '...',
|
||||
'normalized_expected_name' => $normalizedExpectedName,
|
||||
'normalized_expected_addr' => $normalizedExpectedAddr,
|
||||
'personal_info_section' => substr($personalInfoSection, 0, 80) . '...',
|
||||
'address_section' => substr($addressSection, 0, 80) . '...',
|
||||
'name_match_score' => $nameMatch,
|
||||
'addr_match_score' => $addrMatch,
|
||||
'name_passed' => $nameMatch >= 70,
|
||||
'addr_passed' => $addrMatch >= 70,
|
||||
'overall_result' => ($nameMatch >= 70 && $addrMatch >= 70) ? 'PASS' : 'FAIL'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* シンプルマッチング計算
|
||||
*/
|
||||
private function calculateSimpleMatch($expected, $haystack)
|
||||
{
|
||||
if (empty($expected)) return 0;
|
||||
|
||||
// 1. 完全包含チェック
|
||||
if (strpos($haystack, $expected) !== false) {
|
||||
return 100;
|
||||
}
|
||||
|
||||
// 2. 文字包含率
|
||||
$expectedChars = mb_str_split($expected, 1, 'UTF-8');
|
||||
$foundChars = 0;
|
||||
|
||||
foreach ($expectedChars as $char) {
|
||||
if (mb_strpos($haystack, $char, 0, 'UTF-8') !== false) {
|
||||
$foundChars++;
|
||||
}
|
||||
}
|
||||
|
||||
$charRate = ($foundChars / count($expectedChars)) * 100;
|
||||
|
||||
// 3. 類似度計算
|
||||
similar_text($expected, $haystack, $similarRate);
|
||||
|
||||
// 最高スコアを返す
|
||||
return max($charRate, $similarRate);
|
||||
}
|
||||
}
|
||||
|
||||
96
app/Http/Controllers/SealReissueController.php
Normal file
96
app/Http/Controllers/SealReissueController.php
Normal file
@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class SealReissueController extends Controller
|
||||
{
|
||||
public function index($contract_id)
|
||||
{
|
||||
$user_id = session('user_id');
|
||||
if (!$user_id) {
|
||||
return redirect('/login');
|
||||
}
|
||||
$user_name = DB::table('user')->where('user_id', $user_id)->value('user_name');
|
||||
$contract = DB::table('regular_contract')
|
||||
->join('park', 'regular_contract.park_id', '=', 'park.park_id')
|
||||
->where('contract_id', $contract_id)
|
||||
->select('regular_contract.contract_id', 'park.park_name')
|
||||
->first();
|
||||
|
||||
\Log::info('シール再発行確認画面にアクセス', [
|
||||
'user_id' => $user_id,
|
||||
]);
|
||||
|
||||
return view('regular_contract.seal_reissue', [
|
||||
'contract' => $contract,
|
||||
'active_menu' => 'SWC-3-1', // マイページメニューの選択状態用
|
||||
'user_name' => $user_name ? $user_name : '', // ユーザー名(ヘッダー用)
|
||||
]);
|
||||
}
|
||||
|
||||
public function reason($contract_id)
|
||||
{
|
||||
$user_id = session('user_id');
|
||||
if (!$user_id) {
|
||||
return redirect('/login');
|
||||
}
|
||||
$user_name = DB::table('user')->where('user_id', $user_id)->value('user_name');
|
||||
|
||||
\Log::info('シール再発行理由入力画面にアクセス', [
|
||||
'user_id' => $user_id,
|
||||
]);
|
||||
|
||||
return view('regular_contract.seal_reissue_reason', [
|
||||
'contract_id' => $contract_id,
|
||||
'active_menu' => 'SWC-3-1', // マイページメニューの選択状態用
|
||||
'user_name' => $user_name ? $user_name : '', // ユーザー名(ヘッダー用)
|
||||
]);
|
||||
}
|
||||
|
||||
public function complete(Request $request, $contract_id)
|
||||
{
|
||||
$user_id = session('user_id');
|
||||
if (!$user_id) {
|
||||
return redirect('/login');
|
||||
}
|
||||
$user_name = DB::table('user')->where('user_id', $user_id)->value('user_name');
|
||||
|
||||
$validated = $request->validate([
|
||||
'reason' => ['required'],
|
||||
'other_reason' => [
|
||||
'nullable',
|
||||
'string',
|
||||
'max:255',
|
||||
'regex:/^[\x20-\x7Eぁ-んァ-ヶ一-龠々ーa-zA-Z0-90-9a-zA-Z、。・「」『』()【】[]{}〈〉《》!?:;…ー~\s\r\n]+$/u',
|
||||
'required_if:reason,その他'
|
||||
],
|
||||
], [
|
||||
'reason.required' => '理由を選択してください。',
|
||||
'other_reason.max' => 'その他の理由は255文字以内で入力してください。',
|
||||
'other_reason.regex' => 'その他の理由に使用できない文字が含まれています。',
|
||||
'other_reason.required_if' => 'その他を選択した場合は理由を入力してください。'
|
||||
]);
|
||||
|
||||
$contract = DB::table('regular_contract')
|
||||
->join('park', 'regular_contract.park_id', '=', 'park.park_id')
|
||||
->where('contract_id', $contract_id)
|
||||
->select('regular_contract.contract_id', 'park.park_name')
|
||||
->first();
|
||||
|
||||
$reason = $request->input('reason');
|
||||
$other_reason = $request->input('other_reason');
|
||||
|
||||
\Log::info('シール再発行申請完了画面にアクセス', [
|
||||
'user_id' => $user_id,
|
||||
]);
|
||||
|
||||
return view('regular_contract.seal_reissue_complete', [
|
||||
'active_menu' => 'SWC-3-1', // マイページメニューの選択状態用
|
||||
'user_name' => $user_name ? $user_name : '', // ユーザー名(ヘッダー用)
|
||||
'contract' => $contract
|
||||
]);
|
||||
}
|
||||
}
|
||||
60
app/Http/Controllers/UserInformationController.php
Normal file
60
app/Http/Controllers/UserInformationController.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class UserInformationController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$user_id = session('user_id');
|
||||
if (!$user_id) {
|
||||
return redirect('/login');
|
||||
}
|
||||
$user_name = DB::table('user')->where('user_id', $user_id)->value('user_name');
|
||||
|
||||
// お知らせデータ取得
|
||||
$informations = DB::table('user_information_history')
|
||||
->where('user_id', $user_id)
|
||||
->orderByDesc('user_information_history_id')
|
||||
->select('entry_date', 'user_information_history')
|
||||
->limit(10)
|
||||
->get();
|
||||
|
||||
\Log::info('お知らせ画面にアクセス', [
|
||||
'user_id' => $user_id,
|
||||
]);
|
||||
|
||||
return view('user_information.index', [
|
||||
'user_name' => $user_name, // ユーザー名(ヘッダー用)
|
||||
'informations' => $informations
|
||||
]);
|
||||
}
|
||||
|
||||
public function history()
|
||||
{
|
||||
$user_id = session('user_id');
|
||||
if (!$user_id) {
|
||||
return redirect('/login');
|
||||
}
|
||||
$user_name = DB::table('user')->where('user_id', $user_id)->value('user_name');
|
||||
|
||||
// お知らせデータ取得(全件)
|
||||
$informations = DB::table('user_information_history')
|
||||
->where('user_id', $user_id)
|
||||
->orderByDesc('user_information_history_id')
|
||||
->select('entry_date', 'user_information_history')
|
||||
->paginate(10);
|
||||
|
||||
\Log::info('過去のお知らせ画面にアクセス', [
|
||||
'user_id' => $user_id,
|
||||
]);
|
||||
|
||||
return view('user_information.history', [
|
||||
'user_name' => $user_name, // ユーザー名(ヘッダー用)
|
||||
'informations' => $informations
|
||||
]);
|
||||
}
|
||||
}
|
||||
45
app/Http/Controllers/UserTagReissueController.php
Normal file
45
app/Http/Controllers/UserTagReissueController.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class UserTagReissueController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$user_id = session('user_id');
|
||||
if (!$user_id) {
|
||||
return redirect('/login');
|
||||
}
|
||||
$user = DB::table('user')->where('user_id', $user_id)->first();
|
||||
|
||||
\Log::info('タグ再発行申請画面にアクセス', [
|
||||
'user_id' => $user_id,
|
||||
]);
|
||||
|
||||
return view('user.tag_reissue', [
|
||||
'user' => $user,
|
||||
'active_menu' => 'SWC-1-1', // マイページメニューの選択状態用
|
||||
'user_name' => $user ? $user->user_name : '', // ユーザー名(ヘッダー用)
|
||||
]);
|
||||
}
|
||||
|
||||
public function complete()
|
||||
{
|
||||
$user_id = session('user_id');
|
||||
if (!$user_id) {
|
||||
return redirect('/login');
|
||||
}
|
||||
$user = DB::table('user')->where('user_id', $user_id)->first();
|
||||
|
||||
\Log::info('タグ再発行申請完了画面にアクセス', [
|
||||
'user_id' => $user_id,
|
||||
]);
|
||||
|
||||
return view('user.tag_reissue_complete', [
|
||||
'active_menu' => 'SWC-1-1', // マイページメニューの選択状態用
|
||||
'user_name' => $user ? $user->user_name : '', // ユーザー名(ヘッダー用)
|
||||
]);
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,7 @@ use Illuminate\Support\Facades\Auth;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Mail\WithdrawCompleteMail;
|
||||
|
||||
class UserWithdrawController extends Controller
|
||||
|
||||
@ -8,8 +8,6 @@ use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Models\Batch\BatchLog;
|
||||
use App\Models\SettlementTransaction;
|
||||
use App\Services\ShjFourBService;
|
||||
|
||||
/**
|
||||
@ -78,18 +76,6 @@ class ProcessSettlementJob implements ShouldQueue
|
||||
public function handle()
|
||||
{
|
||||
$startTime = now();
|
||||
|
||||
// バッチログの開始記録
|
||||
$batch = BatchLog::createBatchLog(
|
||||
'shj4b',
|
||||
BatchLog::STATUS_START,
|
||||
[
|
||||
'settlement_transaction_id' => $this->settlementTransactionId,
|
||||
'context' => $this->context,
|
||||
'job_id' => $this->job->getJobId(),
|
||||
],
|
||||
'SHJ-4B ProcessSettlementJob start'
|
||||
);
|
||||
|
||||
try {
|
||||
Log::info('SHJ-4B ProcessSettlementJob開始', [
|
||||
@ -99,24 +85,15 @@ class ProcessSettlementJob implements ShouldQueue
|
||||
]);
|
||||
|
||||
// SHJ-4Bサービスを使用して決済トランザクション処理を実行
|
||||
// バッチログはShjFourBServiceが自動的にSHJ-8経由で作成
|
||||
$shjFourBService = app(ShjFourBService::class);
|
||||
$result = $shjFourBService->processSettlementTransaction(
|
||||
$this->settlementTransactionId,
|
||||
$this->context
|
||||
);
|
||||
|
||||
// 処理結果に基づいてバッチログを更新
|
||||
// 処理結果のログ記録
|
||||
if ($result['success']) {
|
||||
$batch->update([
|
||||
'status' => BatchLog::STATUS_SUCCESS,
|
||||
'end_time' => now(),
|
||||
'message' => 'SHJ-4B ProcessSettlementJob completed successfully',
|
||||
'success_count' => 1,
|
||||
'parameters' => json_encode([
|
||||
'result' => $result,
|
||||
]),
|
||||
]);
|
||||
|
||||
Log::info('SHJ-4B ProcessSettlementJob完了', [
|
||||
'settlement_transaction_id' => $this->settlementTransactionId,
|
||||
'execution_time' => now()->diffInSeconds($startTime),
|
||||
@ -124,17 +101,6 @@ class ProcessSettlementJob implements ShouldQueue
|
||||
]);
|
||||
} else {
|
||||
// ビジネスロジック上の問題(エラーではない)
|
||||
$batch->update([
|
||||
'status' => BatchLog::STATUS_SUCCESS,
|
||||
'end_time' => now(),
|
||||
'message' => 'SHJ-4B ProcessSettlementJob completed with issues: ' . $result['reason'],
|
||||
'success_count' => 0,
|
||||
'parameters' => json_encode([
|
||||
'result' => $result,
|
||||
'requires_manual_action' => true,
|
||||
]),
|
||||
]);
|
||||
|
||||
Log::warning('SHJ-4B ProcessSettlementJob要手動対応', [
|
||||
'settlement_transaction_id' => $this->settlementTransactionId,
|
||||
'result' => $result,
|
||||
@ -148,15 +114,7 @@ class ProcessSettlementJob implements ShouldQueue
|
||||
'trace' => $e->getTraceAsString(),
|
||||
]);
|
||||
|
||||
// バッチログのエラー記録
|
||||
$batch->update([
|
||||
'status' => BatchLog::STATUS_ERROR,
|
||||
'end_time' => now(),
|
||||
'message' => 'SHJ-4B ProcessSettlementJob failed: ' . $e->getMessage(),
|
||||
'error_details' => $e->getTraceAsString(),
|
||||
'error_count' => 1,
|
||||
]);
|
||||
|
||||
// エラー時もShjFourBServiceが自動的にバッチログを作成
|
||||
// ジョブを失敗させて再試行を促す
|
||||
throw $e;
|
||||
}
|
||||
@ -177,6 +135,7 @@ class ProcessSettlementJob implements ShouldQueue
|
||||
'attempts' => $this->attempts(),
|
||||
]);
|
||||
|
||||
// バッチログはShjFourBServiceが既に作成済み
|
||||
// 最終失敗時の追加処理があればここに記述
|
||||
// 例:管理者への通知、障害キューへの登録など
|
||||
}
|
||||
|
||||
31
app/Mail/ReservationCancelledMail.php
Normal file
31
app/Mail/ReservationCancelledMail.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class ReservationCancelledMail extends Mailable
|
||||
{
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
public $user_name;
|
||||
public $reserve;
|
||||
|
||||
public function __construct($user_name, $reserve)
|
||||
{
|
||||
$this->user_name = $user_name;
|
||||
$this->reserve = $reserve;
|
||||
}
|
||||
|
||||
public function build()
|
||||
{
|
||||
return $this->subject('So-Manager:空き待ちのキャンセルが完了しました')
|
||||
->view('emails.reservation_cancelled')
|
||||
->with([
|
||||
'user_name' => $this->user_name,
|
||||
'reserve' => $this->reserve,
|
||||
]);
|
||||
}
|
||||
}
|
||||
70
app/Models/BatJobLog.php
Normal file
70
app/Models/BatJobLog.php
Normal file
@ -0,0 +1,70 @@
|
||||
<?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');
|
||||
}
|
||||
}
|
||||
@ -1,159 +0,0 @@
|
||||
<?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'
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -48,8 +48,8 @@ class EarningsSummary extends Model
|
||||
'regular_update_amount', // 更新金額
|
||||
'regular_update_reduction_count', // 更新成免件数
|
||||
'regular_update_reduction_amount', // 更新成免金額
|
||||
'turnsum_count', // 残金件数
|
||||
'turnsum', // 残金
|
||||
'lumpsum_count', // 一時金件数
|
||||
'lumpsum', // 一時金
|
||||
'refunds', // 解時返戻金
|
||||
'other_income', // 分別収入
|
||||
'other_spending', // 分別支出
|
||||
@ -79,8 +79,8 @@ class EarningsSummary extends Model
|
||||
'regular_update_amount' => 'decimal:2',
|
||||
'regular_update_reduction_count' => 'integer',
|
||||
'regular_update_reduction_amount' => 'decimal:2',
|
||||
'turnsum_count' => 'integer',
|
||||
'turnsum' => 'decimal:2',
|
||||
'lumpsum_count' => 'integer',
|
||||
'lumpsum' => 'decimal:2',
|
||||
'refunds' => 'decimal:2',
|
||||
'other_income' => 'decimal:2',
|
||||
'other_spending' => 'decimal:2',
|
||||
@ -175,8 +175,8 @@ class EarningsSummary extends Model
|
||||
SUM(regular_new_amount) as total_new_amount,
|
||||
SUM(regular_update_count) as total_update_count,
|
||||
SUM(regular_update_amount) as total_update_amount,
|
||||
SUM(turnsum_count) as total_turnsum_count,
|
||||
SUM(turnsum) as total_turnsum,
|
||||
SUM(lumpsum_count) as total_lumpsum_count,
|
||||
SUM(lumpsum) as total_lumpsum,
|
||||
SUM(refunds) as total_refunds,
|
||||
SUM(reissue_count) as total_reissue_count,
|
||||
SUM(reissue_amount) as total_reissue_amount
|
||||
@ -249,8 +249,8 @@ class EarningsSummary extends Model
|
||||
'regular_update_amount' => 0.00,
|
||||
'regular_update_reduction_count' => 0,
|
||||
'regular_update_reduction_amount' => 0.00,
|
||||
'turnsum_count' => 0,
|
||||
'turnsum' => 0.00,
|
||||
'lumpsum_count' => 0,
|
||||
'lumpsum' => 0.00,
|
||||
'refunds' => 0.00,
|
||||
'other_income' => 0.00,
|
||||
'other_spending' => 0.00,
|
||||
@ -273,7 +273,7 @@ class EarningsSummary extends Model
|
||||
{
|
||||
return $this->regular_new_amount +
|
||||
$this->regular_update_amount +
|
||||
$this->turnsum +
|
||||
$this->lumpsum +
|
||||
$this->reissue_amount +
|
||||
$this->other_income -
|
||||
$this->other_spending -
|
||||
|
||||
@ -24,7 +24,7 @@ class HardwareCheckLog extends Model
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'log_id';
|
||||
protected $primaryKey = 'hardware_check_log_id';
|
||||
|
||||
/**
|
||||
* 一括代入可能な属性
|
||||
@ -46,7 +46,7 @@ class HardwareCheckLog extends Model
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'log_id' => 'integer',
|
||||
'hardware_check_log_id' => 'integer',
|
||||
'device_id' => 'integer',
|
||||
'status' => 'integer',
|
||||
'operator_id' => 'integer',
|
||||
@ -220,7 +220,7 @@ class HardwareCheckLog extends Model
|
||||
{
|
||||
return sprintf(
|
||||
'HardwareCheckLog[ID:%d, Device:%d, Status:%s, Time:%s]',
|
||||
$this->log_id,
|
||||
$this->hardware_check_log_id,
|
||||
$this->device_id,
|
||||
$this->getStatusNameAttribute(),
|
||||
$this->created_at ? $this->created_at->format('Y-m-d H:i:s') : 'N/A'
|
||||
|
||||
97
app/Models/JurisdictionParking.php
Normal file
97
app/Models/JurisdictionParking.php
Normal file
@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* 管轄駐輪場モデル - jurisdiction_parkingテーブル
|
||||
*
|
||||
* オペレータが管轄する駐輪場の情報を管理
|
||||
*/
|
||||
class JurisdictionParking extends Model
|
||||
{
|
||||
/**
|
||||
* テーブル名
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'jurisdiction_parking';
|
||||
|
||||
/**
|
||||
* プライマリキー
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'jurisdiction_parking_id';
|
||||
|
||||
/**
|
||||
* タイムスタンプ使用
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
const CREATED_AT = 'created_at';
|
||||
const UPDATED_AT = 'updated_at';
|
||||
|
||||
/**
|
||||
* 一括代入可能な属性
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'jurisdiction_parking_name',
|
||||
'ope_id',
|
||||
'park_id',
|
||||
'operator_id'
|
||||
];
|
||||
|
||||
/**
|
||||
* キャストする属性
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'jurisdiction_parking_id' => 'integer',
|
||||
'ope_id' => 'integer',
|
||||
'park_id' => 'integer',
|
||||
'operator_id' => 'integer',
|
||||
'created_at' => 'datetime',
|
||||
'updated_at' => 'datetime'
|
||||
];
|
||||
|
||||
/**
|
||||
* オペレータとの関連
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function ope()
|
||||
{
|
||||
return $this->belongsTo(Ope::class, 'ope_id', 'ope_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 駐輪場との関連
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function park()
|
||||
{
|
||||
return $this->belongsTo(Park::class, 'park_id', 'park_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定駐輪場を管轄するオペレータIDリストを取得
|
||||
*
|
||||
* @param int $parkId 駐輪場ID
|
||||
* @return array オペレータIDの配列
|
||||
*/
|
||||
public static function getOperatorIdsByPark(int $parkId): array
|
||||
{
|
||||
return self::where('park_id', $parkId)
|
||||
->pluck('ope_id')
|
||||
->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
228
app/Models/Manager.php
Normal file
228
app/Models/Manager.php
Normal file
@ -0,0 +1,228 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* 駐輪場管理者モデル - managerテーブル
|
||||
*
|
||||
* 駐輪場管理者マスタ情報を管理するモデル
|
||||
* 各駐輪場に紐づく管理者の情報、警報送信設定などを保持
|
||||
*/
|
||||
class Manager extends Model
|
||||
{
|
||||
/**
|
||||
* テーブル名
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'manager';
|
||||
|
||||
/**
|
||||
* プライマリキー
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'manager_id';
|
||||
|
||||
/**
|
||||
* タイムスタンプ使用
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
const CREATED_AT = 'created_at';
|
||||
const UPDATED_AT = 'updated_at';
|
||||
|
||||
/**
|
||||
* 一括代入可能な属性
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'manager_name', // 管理者名
|
||||
'manager_type', // 管理者種別
|
||||
'manager_parkid', // 所属駐輪場ID
|
||||
'manager_device1', // デバイス1
|
||||
'manager_device2', // デバイス2
|
||||
'manager_mail', // メールアドレス
|
||||
'manager_tel', // 電話番号
|
||||
'manager_alert1', // アラート送信フラグ1
|
||||
'manager_alert2', // アラート送信フラグ2
|
||||
'manager_quit_flag', // 退職フラグ
|
||||
'manager_quitday', // 退職日
|
||||
'operator_id' // 登録オペレータID
|
||||
];
|
||||
|
||||
/**
|
||||
* キャストする属性
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'manager_id' => 'integer',
|
||||
'manager_parkid' => 'integer',
|
||||
'manager_device1' => 'integer',
|
||||
'manager_device2' => 'integer',
|
||||
'manager_alert1' => 'boolean',
|
||||
'manager_alert2' => 'boolean',
|
||||
'manager_quit_flag' => 'boolean',
|
||||
'operator_id' => 'integer',
|
||||
'manager_quitday' => 'date',
|
||||
'created_at' => 'datetime',
|
||||
'updated_at' => 'datetime'
|
||||
];
|
||||
|
||||
/**
|
||||
* 所属駐輪場との関連
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function park()
|
||||
{
|
||||
return $this->belongsTo(Park::class, 'manager_parkid', 'park_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 登録オペレータとの関連
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function operator()
|
||||
{
|
||||
return $this->belongsTo(Ope::class, 'operator_id', 'ope_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* アクティブな管理者のみを取得するスコープ
|
||||
* (退職フラグ = 0)
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopeActive($query)
|
||||
{
|
||||
return $query->where('manager_quit_flag', 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* メールアドレスが設定されている管理者のみを取得するスコープ
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopeHasEmail($query)
|
||||
{
|
||||
return $query->whereNotNull('manager_mail')
|
||||
->where('manager_mail', '!=', '');
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定駐輪場の管理者を取得するスコープ
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param int $parkId 駐輪場ID
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopeByPark($query, int $parkId)
|
||||
{
|
||||
return $query->where('manager_parkid', $parkId);
|
||||
}
|
||||
|
||||
/**
|
||||
* メール送信対象の駐輪場管理者を取得
|
||||
*
|
||||
* 条件:
|
||||
* - 退職フラグ = 0(在職中)
|
||||
* - メールアドレスが設定されている
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Collection
|
||||
*/
|
||||
public static function getMailTargetManagers()
|
||||
{
|
||||
return self::active()
|
||||
->hasEmail()
|
||||
->select(['manager_id', 'manager_name', 'manager_mail', 'manager_parkid'])
|
||||
->get()
|
||||
->map(function ($manager) {
|
||||
return [
|
||||
'manager_id' => $manager->manager_id,
|
||||
'name' => $manager->manager_name,
|
||||
'email' => $manager->manager_mail,
|
||||
'park_id' => $manager->manager_parkid
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定駐輪場のメール送信対象管理者を取得
|
||||
*
|
||||
* @param int $parkId 駐輪場ID
|
||||
* @return \Illuminate\Database\Eloquent\Collection
|
||||
*/
|
||||
public static function getMailTargetManagersByPark(int $parkId)
|
||||
{
|
||||
return self::active()
|
||||
->hasEmail()
|
||||
->byPark($parkId)
|
||||
->select(['manager_id', 'manager_name', 'manager_mail', 'manager_parkid'])
|
||||
->get()
|
||||
->map(function ($manager) {
|
||||
return [
|
||||
'manager_id' => $manager->manager_id,
|
||||
'name' => $manager->manager_name,
|
||||
'email' => $manager->manager_mail,
|
||||
'park_id' => $manager->manager_parkid
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 退職しているかどうかを判定
|
||||
*
|
||||
* @return bool 退職しているかどうか
|
||||
*/
|
||||
public function isQuit(): bool
|
||||
{
|
||||
return (bool) $this->manager_quit_flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* アクティブ(在職中)かどうかを判定
|
||||
*
|
||||
* @return bool 在職中かどうか
|
||||
*/
|
||||
public function isActive(): bool
|
||||
{
|
||||
return !$this->isQuit();
|
||||
}
|
||||
|
||||
/**
|
||||
* メールアドレスが設定されているかどうかを判定
|
||||
*
|
||||
* @return bool メールアドレスが設定されているかどうか
|
||||
*/
|
||||
public function hasEmail(): bool
|
||||
{
|
||||
return !empty($this->manager_mail);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文字列表現
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
return sprintf(
|
||||
'Manager[ID:%d, Name:%s, Park:%d, Email:%s]',
|
||||
$this->manager_id,
|
||||
$this->manager_name,
|
||||
$this->manager_parkid,
|
||||
$this->manager_mail ?? 'N/A'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ class PrintJobLog extends Model
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'log_id';
|
||||
protected $primaryKey = 'job_log_id';
|
||||
|
||||
/**
|
||||
* 一括代入可能な属性
|
||||
@ -49,7 +49,7 @@ class PrintJobLog extends Model
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'log_id' => 'integer',
|
||||
'job_log_id' => 'integer',
|
||||
'park_id' => 'integer',
|
||||
'user_id' => 'integer',
|
||||
'contract_id' => 'integer',
|
||||
@ -242,7 +242,7 @@ class PrintJobLog extends Model
|
||||
{
|
||||
return sprintf(
|
||||
'PrintJobLog[ID:%d, Process:%s, ErrorCode:%d, Time:%s]',
|
||||
$this->log_id,
|
||||
$this->job_log_id,
|
||||
$this->process_name,
|
||||
$this->error_code,
|
||||
$this->created_at ? $this->created_at->format('Y-m-d H:i:s') : 'N/A'
|
||||
|
||||
85
app/Models/Setting.php
Normal file
85
app/Models/Setting.php
Normal file
@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* 設定マスタモデル - settingテーブル
|
||||
*
|
||||
* システム全体の設定情報を管理するモデル
|
||||
*/
|
||||
class Setting extends Model
|
||||
{
|
||||
/**
|
||||
* テーブル名
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'setting';
|
||||
|
||||
/**
|
||||
* プライマリキー
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'setting_id';
|
||||
|
||||
/**
|
||||
* タイムスタンプ使用
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
const CREATED_AT = 'created_at';
|
||||
const UPDATED_AT = 'updated_at';
|
||||
|
||||
/**
|
||||
* 一括代入可能な属性
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'edit_master',
|
||||
'web_master',
|
||||
'auto_change_date',
|
||||
'auto_chage_master',
|
||||
're-issue_alert_number',
|
||||
'image_base_url1',
|
||||
'image_base_url2',
|
||||
'printable_alert_flag',
|
||||
'printable_number',
|
||||
'printable_alert_number',
|
||||
'printer_keep_alive',
|
||||
'operator_id'
|
||||
];
|
||||
|
||||
/**
|
||||
* キャストする属性
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'setting_id' => 'integer',
|
||||
'printable_alert_flag' => 'boolean',
|
||||
'printable_number' => 'integer',
|
||||
'printable_alert_number' => 'integer',
|
||||
'printer_keep_alive' => 'integer',
|
||||
'operator_id' => 'integer',
|
||||
'auto_change_date' => 'datetime',
|
||||
'created_at' => 'datetime',
|
||||
'updated_at' => 'datetime'
|
||||
];
|
||||
|
||||
/**
|
||||
* 設定情報を取得(通常はID=1の単一レコード)
|
||||
*
|
||||
* @return Setting|null
|
||||
*/
|
||||
public static function getSettings(): ?Setting
|
||||
{
|
||||
return self::first();
|
||||
}
|
||||
}
|
||||
|
||||
270
app/Services/ShjEightService.php
Normal file
270
app/Services/ShjEightService.php
Normal file
@ -0,0 +1,270 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
@ -4,30 +4,112 @@ namespace App\Services;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Models\Batch\BatchLog;
|
||||
use App\Models\RegularContract;
|
||||
use App\Models\Park;
|
||||
use App\Models\Psection;
|
||||
use App\Models\Ptype;
|
||||
use App\Models\Setting;
|
||||
use App\Models\Device;
|
||||
use Carbon\Carbon;
|
||||
|
||||
/**
|
||||
* SHJ-11 現在契約台数集計サービス
|
||||
*
|
||||
*
|
||||
* 集計単位每个の契約台数を算出し、ゾーンマスタとの管理処理を実行
|
||||
* bat_job_logへの書き込みはSHJ-8を呼び出す
|
||||
*/
|
||||
class ShjElevenService
|
||||
{
|
||||
/**
|
||||
* ShjEightService
|
||||
*
|
||||
* @var ShjEightService
|
||||
*/
|
||||
protected $shjEightService;
|
||||
|
||||
/**
|
||||
* コンストラクタ
|
||||
*
|
||||
* @param ShjEightService $shjEightService
|
||||
*/
|
||||
public function __construct(ShjEightService $shjEightService)
|
||||
{
|
||||
$this->shjEightService = $shjEightService;
|
||||
}
|
||||
|
||||
/**
|
||||
* バッチ処理用の有効なデバイスIDを取得
|
||||
*
|
||||
* deviceテーブルから最初の有効なdevice_idを取得する。
|
||||
* データが存在しない場合は例外をスローする。
|
||||
*
|
||||
* @return int 有効なdevice_id
|
||||
* @throws \Exception deviceテーブルにレコードが存在しない場合
|
||||
*/
|
||||
private function getBatchDeviceId(): int
|
||||
{
|
||||
$device = Device::orderBy('device_id')->first();
|
||||
|
||||
if (!$device) {
|
||||
throw new \Exception('deviceテーブルにレコードが存在しません。SHJ-8バッチログ作成に必要なデバイスIDを取得できません。');
|
||||
}
|
||||
|
||||
Log::debug('SHJ-11 バッチ用デバイスID取得', [
|
||||
'device_id' => $device->device_id
|
||||
]);
|
||||
|
||||
return $device->device_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 現在使用中のprice主表名を取得する
|
||||
*
|
||||
* setting.web_master から価格マスタテーブル名を決定
|
||||
* web_master の値('_a' または '_b')から 'price_a' または 'price_b' を返す
|
||||
*
|
||||
* @return string price主表名('price_a' または 'price_b')
|
||||
* @throws \Exception setting取得失敗時
|
||||
*/
|
||||
private function getPriceTableName(): string
|
||||
{
|
||||
try {
|
||||
$setting = Setting::getSettings();
|
||||
|
||||
if (!$setting || empty($setting->web_master)) {
|
||||
throw new \Exception('setting.web_masterの取得に失敗しました');
|
||||
}
|
||||
|
||||
// web_master の値:'_a' または '_b'
|
||||
$webMaster = $setting->web_master;
|
||||
|
||||
// 'price_' + ('_a' → 'a' / '_b' → 'b')
|
||||
$priceTable = 'price_' . ltrim($webMaster, '_');
|
||||
|
||||
Log::info('SHJ-11 price主表名決定', [
|
||||
'web_master' => $webMaster,
|
||||
'price_table' => $priceTable
|
||||
]);
|
||||
|
||||
return $priceTable;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('SHJ-11 price主表名取得エラー', [
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 【処理1】集計単位每个の契約台数を算出する
|
||||
*
|
||||
*
|
||||
* 集計単位: 駐輪場ID + 車種区分ID + 駐輪分類ID + ゾーンID
|
||||
*
|
||||
*
|
||||
* SQL仕様に基づく複雑なJOIN処理:
|
||||
* - regular_contract (T1)
|
||||
* - regular_contract (T1)
|
||||
* - park (T2)
|
||||
* - psection (T4)
|
||||
* - price_a (T5)
|
||||
* - price_a/price_b (T5) ※web_master設定により動的に決定
|
||||
* - ptype (T3)
|
||||
*
|
||||
* @return array 契約台数集計結果
|
||||
@ -35,6 +117,9 @@ class ShjElevenService
|
||||
public function calculateContractCounts(): array
|
||||
{
|
||||
try {
|
||||
// setting.web_master から使用するprice主表を決定
|
||||
$priceTable = $this->getPriceTableName();
|
||||
|
||||
$query = DB::table('regular_contract as T1')
|
||||
->select([
|
||||
'T1.park_id', // 駐輪場ID
|
||||
@ -50,8 +135,8 @@ class ShjElevenService
|
||||
->join('park as T2', 'T1.park_id', '=', 'T2.park_id')
|
||||
// psection テーブルとの JOIN
|
||||
->join('psection as T4', 'T1.psection_id', '=', 'T4.psection_id')
|
||||
// price_a テーブルとの複合条件 JOIN
|
||||
->join('price_a as T5', function($join) {
|
||||
// price_a/price_b テーブルとの複合条件 JOIN(動的テーブル名)
|
||||
->join(DB::raw($priceTable . ' as T5'), function($join) {
|
||||
$join->on('T1.park_id', '=', 'T5.park_id')
|
||||
->on('T1.price_parkplaceid', '=', 'T5.price_parkplaceid')
|
||||
->on('T1.psection_id', '=', 'T5.psection_id');
|
||||
@ -59,11 +144,13 @@ class ShjElevenService
|
||||
// ptype テーブルとの JOIN
|
||||
->join('ptype as T3', 'T5.ptype_id', '=', 'T3.ptype_id')
|
||||
->where([
|
||||
['T1.contract_flag', '=', 1], // 有効契約
|
||||
['T2.park_close_flag', '=', 0], // 駐輪場未閉鎖
|
||||
['T1.contract_flag', '=', 1], // 授受フラグ = 1
|
||||
['T2.park_close_flag', '=', 0], // 閉設フラグ = 0
|
||||
])
|
||||
// 契約有効期間内の条件
|
||||
->whereRaw("date_format(now(), '%y %m %d') BETWEEN T1.contract_periods AND T1.contract_periode")
|
||||
// 契約有効期間内の条件(仕様書指定:'%y.%m.%d'形式)
|
||||
->whereRaw("date_format(now(), '%y.%m.%d') BETWEEN T1.contract_periods AND T1.contract_periode")
|
||||
// zone_idがNULLのレコードは除外(ゾーンマスタ更新不可のため)
|
||||
->whereNotNull('T1.zone_id')
|
||||
->groupBy([
|
||||
'T1.park_id',
|
||||
'T2.park_name',
|
||||
@ -77,9 +164,11 @@ class ShjElevenService
|
||||
|
||||
Log::info('SHJ-11 契約台数算出完了', [
|
||||
'count' => $query->count(),
|
||||
'price_table' => $priceTable,
|
||||
'sql_conditions' => [
|
||||
'contract_flag' => 1,
|
||||
'park_close_flag' => 0,
|
||||
'date_format' => '%y.%m.%d',
|
||||
'contract_period_check' => 'BETWEEN contract_periods AND contract_periode'
|
||||
]
|
||||
]);
|
||||
@ -97,12 +186,15 @@ class ShjElevenService
|
||||
|
||||
/**
|
||||
* 【処理2・3】ゾーンマスタ管理処理
|
||||
*
|
||||
* 処理フロー:
|
||||
* 1. ゾーンマスタを取得する
|
||||
* 2. 取得判定 → 存在しない場合は新規登録
|
||||
* 3. 契約台数チェック(限界台数超過判定)
|
||||
* 4. 契約台数を反映する(ゾーンマスタ更新)
|
||||
*
|
||||
* 処理フロー(仕様書準拠):
|
||||
* 処理1の取得レコード数分繰り返し:
|
||||
* 【処理2】ゾーンマスタを取得する
|
||||
* 【判断2】取得判定
|
||||
* - ゾーンマスタなし → INSERT(トランザクション内) → commit → 【処理4】SHJ-8(トランザクション外) → 次へ
|
||||
* - ゾーンマスタあり → 【判断3】契約台数チェック → 【処理3】UPDATE(トランザクション内) → commit → 【処理4】SHJ-8(トランザクション外) → 次へ
|
||||
*
|
||||
* ※SHJ-8ログは各レコード処理後に確実に記録するため、トランザクション外で実行
|
||||
*
|
||||
* @param array $contractCounts 契約台数集計結果
|
||||
* @return array 処理結果
|
||||
@ -112,27 +204,104 @@ class ShjElevenService
|
||||
$createdZones = 0;
|
||||
$updatedZones = 0;
|
||||
$overCapacityCount = 0;
|
||||
$errors = [];
|
||||
$processParameters = [];
|
||||
$batchLogErrors = [];
|
||||
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
|
||||
// 処理1の取得レコード数分繰り返し
|
||||
foreach ($contractCounts as $contractData) {
|
||||
try {
|
||||
// 【防御的チェック】必須キーがNULLの場合はスキップ
|
||||
if (empty($contractData->zone_id) || empty($contractData->psection_id) || empty($contractData->ptype_id)) {
|
||||
Log::warning('SHJ-11 必須キー欠落のためスキップ', [
|
||||
'park_id' => $contractData->park_id ?? null,
|
||||
'zone_id' => $contractData->zone_id ?? null,
|
||||
'psection_id' => $contractData->psection_id ?? null,
|
||||
'ptype_id' => $contractData->ptype_id ?? null
|
||||
]);
|
||||
|
||||
$batchLogErrors[] = [
|
||||
'park_id' => $contractData->park_id ?? null,
|
||||
'zone_id' => $contractData->zone_id ?? null,
|
||||
'error' => '必須キー欠落(zone_id/psection_id/ptype_id)'
|
||||
];
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// 各レコードごとに独立したトランザクションを開始
|
||||
DB::beginTransaction();
|
||||
|
||||
// 【処理2】ゾーンマスタを取得する
|
||||
$zoneData = $this->getZoneData($contractData);
|
||||
|
||||
// 【判断2】取得判定
|
||||
if (!$zoneData) {
|
||||
// 【判断2】ゾーンマスタが存在しない場合 → 新規登録
|
||||
// ゾーンマスタなし → INSERT
|
||||
$createResult = $this->createZoneData($contractData);
|
||||
if ($createResult['success']) {
|
||||
$createdZones++;
|
||||
|
||||
if (!$createResult['success']) {
|
||||
// INSERT失敗時のエラー処理
|
||||
DB::rollBack();
|
||||
|
||||
Log::error('SHJ-11 ゾーンマスタINSERT失敗', [
|
||||
'park_id' => $contractData->park_id,
|
||||
'zone_id' => $contractData->zone_id,
|
||||
'error' => $createResult['message']
|
||||
]);
|
||||
|
||||
$batchLogErrors[] = [
|
||||
'park_id' => $contractData->park_id,
|
||||
'zone_id' => $contractData->zone_id,
|
||||
'error' => 'INSERT失敗: ' . $createResult['message']
|
||||
];
|
||||
|
||||
// INSERT失敗時も次の繰り返しへ
|
||||
continue;
|
||||
}
|
||||
$zoneData = $createResult['zone_data'];
|
||||
|
||||
// INSERTトランザクションをcommit
|
||||
DB::commit();
|
||||
|
||||
$createdZones++;
|
||||
|
||||
// status_comment作成(INSERT分岐)
|
||||
$statusComment = $this->formatStatusComment(
|
||||
$contractData->park_name,
|
||||
$contractData->ptype_subject,
|
||||
$contractData->psection_subject,
|
||||
$contractData->zone_id,
|
||||
'' // INSERT分岐では台数アラートなし
|
||||
);
|
||||
|
||||
// 【処理4】bat_job_logに直接書き込み(トランザクション外・INSERT分岐)
|
||||
$batchLogResult = $this->writeBatJobLog(
|
||||
$contractData,
|
||||
$statusComment,
|
||||
false // 限界台数超過なし
|
||||
);
|
||||
|
||||
// bat_job_log書き込み結果チェック
|
||||
if (!$batchLogResult['success']) {
|
||||
Log::warning('bat_job_log書き込み失敗(INSERT分岐)', [
|
||||
'park_id' => $contractData->park_id,
|
||||
'zone_id' => $contractData->zone_id,
|
||||
'error_message' => $batchLogResult['error_message'] ?? null
|
||||
]);
|
||||
|
||||
// bat_job_log書き込み失敗をbatch_log_errorsに記録
|
||||
$batchLogErrors[] = [
|
||||
'park_id' => $contractData->park_id,
|
||||
'zone_id' => $contractData->zone_id,
|
||||
'error' => 'bat_job_log書き込み失敗(INSERT分岐): ' . ($batchLogResult['error_message'] ?? 'unknown error')
|
||||
];
|
||||
}
|
||||
|
||||
// INSERT分岐は【処理4】後に次の繰り返しへ
|
||||
continue;
|
||||
}
|
||||
|
||||
// 【判断3】契約台数チェック(限界台数超過判定)
|
||||
// ゾーンマスタあり → 【判断3】契約台数チェック
|
||||
$isOverCapacity = $this->checkCapacityLimit($contractData, $zoneData);
|
||||
if ($isOverCapacity) {
|
||||
$overCapacityCount++;
|
||||
@ -144,57 +313,112 @@ class ShjElevenService
|
||||
]);
|
||||
}
|
||||
|
||||
// 【処理3】契約台数を反映する(ゾーンマスタ更新)
|
||||
// 【処理3】契約台数を反映する(UPDATE)
|
||||
$updateResult = $this->updateZoneContractCount($contractData);
|
||||
if ($updateResult['success']) {
|
||||
$updatedZones++;
|
||||
|
||||
if (!$updateResult['success']) {
|
||||
// UPDATE失敗時のエラー処理
|
||||
DB::rollBack();
|
||||
|
||||
Log::error('SHJ-11 ゾーンマスタUPDATE失敗', [
|
||||
'park_id' => $contractData->park_id,
|
||||
'zone_id' => $contractData->zone_id,
|
||||
'error' => $updateResult['message']
|
||||
]);
|
||||
|
||||
$batchLogErrors[] = [
|
||||
'park_id' => $contractData->park_id,
|
||||
'zone_id' => $contractData->zone_id,
|
||||
'error' => 'UPDATE失敗: ' . $updateResult['message']
|
||||
];
|
||||
|
||||
// UPDATE失敗時も次の繰り返しへ
|
||||
continue;
|
||||
}
|
||||
|
||||
// 処理パラメータ記録
|
||||
$processParameters[] = [
|
||||
'park_id' => $contractData->park_id,
|
||||
'psection_id' => $contractData->psection_id,
|
||||
'ptype_id' => $contractData->ptype_id,
|
||||
'zone_id' => $contractData->zone_id,
|
||||
'contract_count' => $contractData->cnt,
|
||||
'is_over_capacity' => $isOverCapacity,
|
||||
'zone_created' => !$zoneData && $createResult['success'] ?? false,
|
||||
'zone_updated' => $updateResult['success'] ?? false
|
||||
];
|
||||
// UPDATEトランザクションをcommit
|
||||
DB::commit();
|
||||
|
||||
$updatedZones++;
|
||||
|
||||
// status_comment作成(UPDATE分岐)
|
||||
$capacityAlert = $isOverCapacity ? '限界収容台数を超えています。' : '';
|
||||
$statusComment = $this->formatStatusComment(
|
||||
$contractData->park_name,
|
||||
$contractData->ptype_subject,
|
||||
$contractData->psection_subject,
|
||||
$contractData->zone_id,
|
||||
$capacityAlert
|
||||
);
|
||||
|
||||
// 【処理4】bat_job_logに直接書き込み(トランザクション外・UPDATE分岐)
|
||||
$batchLogResult = $this->writeBatJobLog(
|
||||
$contractData,
|
||||
$statusComment,
|
||||
$isOverCapacity
|
||||
);
|
||||
|
||||
// bat_job_log書き込み結果チェック
|
||||
if (!$batchLogResult['success']) {
|
||||
Log::warning('bat_job_log書き込み失敗(UPDATE分岐)', [
|
||||
'park_id' => $contractData->park_id,
|
||||
'zone_id' => $contractData->zone_id,
|
||||
'error_message' => $batchLogResult['error_message'] ?? null
|
||||
]);
|
||||
|
||||
// bat_job_log書き込み失敗をbatch_log_errorsに記録
|
||||
$batchLogErrors[] = [
|
||||
'park_id' => $contractData->park_id,
|
||||
'zone_id' => $contractData->zone_id,
|
||||
'error' => 'bat_job_log書き込み失敗(UPDATE分岐): ' . ($batchLogResult['error_message'] ?? 'unknown error')
|
||||
];
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$errors[] = [
|
||||
// 例外時はロールバック(アクティブなトランザクションがある場合のみ)
|
||||
if (DB::transactionLevel() > 0) {
|
||||
DB::rollBack();
|
||||
}
|
||||
|
||||
// 個別レコードエラーもログ記録して次へ進む
|
||||
$batchLogErrors[] = [
|
||||
'park_id' => $contractData->park_id ?? null,
|
||||
'zone_id' => $contractData->zone_id ?? null,
|
||||
'error' => $e->getMessage()
|
||||
];
|
||||
|
||||
Log::warning('SHJ-11 個別処理エラー', [
|
||||
|
||||
Log::warning('SHJ-11 個別レコード処理エラー', [
|
||||
'park_id' => $contractData->park_id ?? null,
|
||||
'zone_id' => $contractData->zone_id ?? null,
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
|
||||
// エラーでも次の繰り返しへ続行
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'created_zones' => $createdZones,
|
||||
'updated_zones' => $updatedZones,
|
||||
'over_capacity_count' => $overCapacityCount,
|
||||
'parameters' => $processParameters,
|
||||
'errors' => $errors,
|
||||
'batch_log_errors' => $batchLogErrors,
|
||||
'message' => '現在契約台数集計処理完了'
|
||||
];
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
|
||||
// 外層エラー時のロールバック
|
||||
// ※各レコード処理は独立トランザクションのため、
|
||||
// ここでのrollBackは不要だが安全のため実行
|
||||
if (DB::transactionLevel() > 0) {
|
||||
DB::rollBack();
|
||||
}
|
||||
|
||||
Log::error('SHJ-11 ゾーンマスタ管理処理全体エラー', [
|
||||
'error' => $e->getMessage(),
|
||||
'processed_count' => count($processParameters)
|
||||
'created_zones' => $createdZones,
|
||||
'updated_zones' => $updatedZones
|
||||
]);
|
||||
|
||||
return [
|
||||
@ -202,8 +426,7 @@ class ShjElevenService
|
||||
'created_zones' => $createdZones,
|
||||
'updated_zones' => $updatedZones,
|
||||
'over_capacity_count' => $overCapacityCount,
|
||||
'parameters' => $processParameters,
|
||||
'errors' => $errors,
|
||||
'batch_log_errors' => $batchLogErrors,
|
||||
'message' => 'ゾーンマスタ管理処理エラー: ' . $e->getMessage(),
|
||||
'details' => $e->getTraceAsString()
|
||||
];
|
||||
@ -329,7 +552,7 @@ class ShjElevenService
|
||||
|
||||
/**
|
||||
* ゾーンマスタ契約台数更新
|
||||
*
|
||||
*
|
||||
* 【処理3】現在契約台数をゾーンマスタに反映
|
||||
*
|
||||
* @param object $contractData 契約台数集計データ
|
||||
@ -341,7 +564,7 @@ class ShjElevenService
|
||||
$updateData = [
|
||||
'zone_number' => $contractData->cnt, // 現在契約台数を更新
|
||||
'updated_at' => now(), // 更新日時
|
||||
'ope_id' => 'SHJ-11' // 更新オペレータID
|
||||
'ope_id' => 9999999 // 更新オペレータID(INSERT時と同様、DB型int unsignedに対応)
|
||||
];
|
||||
|
||||
$updated = DB::table('zone')
|
||||
@ -365,6 +588,11 @@ class ShjElevenService
|
||||
'message' => 'ゾーンマスタ契約台数を更新しました'
|
||||
];
|
||||
} else {
|
||||
Log::warning('SHJ-11 ゾーンマスタ更新対象なし', [
|
||||
'zone_id' => $contractData->zone_id,
|
||||
'park_id' => $contractData->park_id
|
||||
]);
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => 'ゾーンマスタ更新対象が見つかりません'
|
||||
@ -386,47 +614,176 @@ class ShjElevenService
|
||||
}
|
||||
|
||||
/**
|
||||
* 【処理4】バッチ処理ログを作成する
|
||||
*
|
||||
* 統一BatchLogシステムを使用してSHJ-11の実行ログを記録
|
||||
* status_commentを仕様書指定フォーマットで作成
|
||||
*
|
||||
* @param string $status ステータス
|
||||
* @param array $parameters パラメータ
|
||||
* @param string $message メッセージ
|
||||
* @param int $executionCount 実行回数
|
||||
* @param int $successCount 成功回数
|
||||
* @param int $errorCount エラー回数
|
||||
* @return void
|
||||
* フォーマット: 駐輪場名/駐輪分類名/車種区分名/ゾーンID[台数アラート]
|
||||
*
|
||||
* @param string $parkName 駐輪場名
|
||||
* @param string $ptypeSubject 駐輪分類名
|
||||
* @param string $psectionSubject 車種区分名
|
||||
* @param int $zoneId ゾーンID
|
||||
* @param string $capacityAlert 台数アラート(「限界収容台数を超えています。」または空文字)
|
||||
* @return string フォーマット済みstatus_comment
|
||||
*/
|
||||
public function createBatchLog(
|
||||
string $status,
|
||||
array $parameters,
|
||||
string $message,
|
||||
int $executionCount = 0,
|
||||
int $successCount = 0,
|
||||
int $errorCount = 0
|
||||
): void {
|
||||
private function formatStatusComment(
|
||||
string $parkName,
|
||||
string $ptypeSubject,
|
||||
string $psectionSubject,
|
||||
int $zoneId,
|
||||
string $capacityAlert
|
||||
): string {
|
||||
$baseComment = $parkName . '/' . $ptypeSubject . '/' . $psectionSubject . '/' . $zoneId;
|
||||
|
||||
if (!empty($capacityAlert)) {
|
||||
return $baseComment . ' ' . $capacityAlert;
|
||||
}
|
||||
|
||||
return $baseComment;
|
||||
}
|
||||
|
||||
/**
|
||||
* 【処理4】個別レコードのバッチ処理ログを作成する
|
||||
*
|
||||
* SHJ-11は業務固有のstatus_commentを記録するため、SHJ-8を使わずbat_job_logに直接書き込む
|
||||
*
|
||||
* bat_job_log登録内容:
|
||||
* 1. デバイスID
|
||||
* 2. プロセス名: SHJ-11
|
||||
* 3. ジョブ名: SHJ-11現在契約台数集計
|
||||
* 4. ステータス: success
|
||||
* 5. ステータスコメント: 業務固有(駐輪場名/駐輪分類名/車種区分名/ゾーンID[台数アラート])
|
||||
* 6. 登録日時: 現在の日付
|
||||
* 7. 更新日時: 現在の日付
|
||||
*
|
||||
* @param object $contractData 契約台数集計データ
|
||||
* @param string $statusComment status_comment(台数アラート含む)
|
||||
* @param bool $isOverCapacity 限界台数超過フラグ
|
||||
* @return array 処理結果 ['success' => bool, 'error_message' => string|null]
|
||||
*/
|
||||
private function writeBatJobLog(
|
||||
$contractData,
|
||||
string $statusComment,
|
||||
bool $isOverCapacity
|
||||
): array {
|
||||
try {
|
||||
BatchLog::createBatchLog(
|
||||
'SHJ-11',
|
||||
// SHJ-8バッチ処理ログ作成パラメータ設定
|
||||
$deviceId = $this->getBatchDeviceId(); // deviceテーブルから有効なIDを取得
|
||||
$processName = 'SHJ-11';
|
||||
$jobName = 'SHJ-11現在契約台数集計';
|
||||
$status = 'success';
|
||||
$today = now()->format('Y/m/d');
|
||||
|
||||
Log::info('SHJ-8バッチ処理ログ作成', [
|
||||
'device_id' => $deviceId,
|
||||
'process_name' => $processName,
|
||||
'job_name' => $jobName,
|
||||
'status' => $status,
|
||||
'status_comment' => $statusComment,
|
||||
'park_id' => $contractData->park_id,
|
||||
'zone_id' => $contractData->zone_id
|
||||
]);
|
||||
|
||||
// SHJ-8サービスを呼び出し
|
||||
$this->shjEightService->execute(
|
||||
$deviceId,
|
||||
$processName,
|
||||
$jobName,
|
||||
$status,
|
||||
$parameters,
|
||||
$message,
|
||||
[
|
||||
'execution_count' => $executionCount,
|
||||
'success_count' => $successCount,
|
||||
'error_count' => $errorCount,
|
||||
'process_type' => '現在契約台数集計',
|
||||
'executed_at' => now()->toISOString()
|
||||
]
|
||||
$statusComment,
|
||||
$today,
|
||||
$today
|
||||
);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('SHJ-11 バッチログ作成エラー', [
|
||||
'error' => $e->getMessage(),
|
||||
'status' => $status,
|
||||
'message' => $message
|
||||
Log::info('SHJ-8バッチ処理ログ作成完了', [
|
||||
'park_id' => $contractData->park_id,
|
||||
'zone_id' => $contractData->zone_id
|
||||
]);
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'error_message' => null
|
||||
];
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('bat_job_log書き込みエラー', [
|
||||
'park_id' => $contractData->park_id ?? null,
|
||||
'zone_id' => $contractData->zone_id ?? null,
|
||||
'error' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString()
|
||||
]);
|
||||
|
||||
// エラーが発生してもメイン処理は継続
|
||||
return [
|
||||
'success' => false,
|
||||
'error_message' => $e->getMessage()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 【判断1】取得件数=0時のバッチログ作成
|
||||
*
|
||||
* 取得件数が0件の場合に呼び出される特別なバッチログ作成
|
||||
* bat_job_logに直接書き込み
|
||||
*
|
||||
* bat_job_log登録内容:
|
||||
* 1. デバイスID
|
||||
* 2. プロセス名: SHJ-11
|
||||
* 3. ジョブ名: SHJ-11現在契約台数集計
|
||||
* 4. ステータス: success
|
||||
* 5. ステータスコメント: 全駐輪場契約なし
|
||||
* 6. 登録日時: 現在の日付
|
||||
* 7. 更新日時: 現在の日付
|
||||
*
|
||||
* @return array 処理結果 ['success' => bool, 'error_message' => string|null]
|
||||
*/
|
||||
public function writeBatJobLogForNoContracts(): array
|
||||
{
|
||||
try {
|
||||
// SHJ-8バッチ処理ログ作成パラメータ設定
|
||||
$deviceId = $this->getBatchDeviceId(); // deviceテーブルから有効なIDを取得
|
||||
$processName = 'SHJ-11';
|
||||
$jobName = 'SHJ-11現在契約台数集計';
|
||||
$status = 'success';
|
||||
$statusComment = '全駐輪場契約なし';
|
||||
$today = now()->format('Y/m/d');
|
||||
|
||||
Log::info('SHJ-8バッチ処理ログ作成(対象なし)', [
|
||||
'device_id' => $deviceId,
|
||||
'process_name' => $processName,
|
||||
'job_name' => $jobName,
|
||||
'status' => $status,
|
||||
'status_comment' => $statusComment
|
||||
]);
|
||||
|
||||
// SHJ-8サービスを呼び出し
|
||||
$this->shjEightService->execute(
|
||||
$deviceId,
|
||||
$processName,
|
||||
$jobName,
|
||||
$status,
|
||||
$statusComment,
|
||||
$today,
|
||||
$today
|
||||
);
|
||||
|
||||
Log::info('SHJ-8バッチ処理ログ作成完了(対象なし)');
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'error_message' => null
|
||||
];
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('bat_job_log書き込みエラー(対象なし)', [
|
||||
'error' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString()
|
||||
]);
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'error_message' => $e->getMessage()
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
699
app/Services/ShjFiveService.php
Normal file
699
app/Services/ShjFiveService.php
Normal file
@ -0,0 +1,699 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Models\OperatorQue;
|
||||
use App\Models\Device;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* SHJ-5 空き待ち通知処理サービス
|
||||
*
|
||||
* 駐輪場の空き状況を確認し、空き待ち予約者への通知処理を実行する
|
||||
* 仕様書に基づくバックグラウンド定期バッチ処理
|
||||
*/
|
||||
class ShjFiveService
|
||||
{
|
||||
/**
|
||||
* ShjEightService
|
||||
*
|
||||
* @var ShjEightService
|
||||
*/
|
||||
protected $shjEightService;
|
||||
|
||||
/**
|
||||
* コンストラクタ
|
||||
*
|
||||
* @param ShjEightService $shjEightService
|
||||
*/
|
||||
public function __construct(ShjEightService $shjEightService)
|
||||
{
|
||||
$this->shjEightService = $shjEightService;
|
||||
}
|
||||
/**
|
||||
* SHJ-5 メイン処理を実行
|
||||
*
|
||||
* 処理フロー:
|
||||
* 1. 駐輪場の空き状況を取得する
|
||||
* 2. 空き状況判定
|
||||
* 3. 空き待ち者の情報を取得する
|
||||
* 4. 取得件数判定
|
||||
* 5. 空き待ち者への通知、またはオペレーターキュー追加処理
|
||||
* 6. バッチ処理ログを作成する
|
||||
*
|
||||
* @return array 処理結果
|
||||
*/
|
||||
public function executeParkVacancyNotification(): array
|
||||
{
|
||||
try {
|
||||
$startTime = now();
|
||||
Log::info('SHJ-5 空き待ち通知処理開始');
|
||||
|
||||
// 処理統計
|
||||
$processedParksCount = 0;
|
||||
$vacantParksCount = 0;
|
||||
$totalWaitingUsers = 0;
|
||||
$notificationSuccessCount = 0;
|
||||
$operatorQueueCount = 0;
|
||||
$mailErrors = []; // メール異常終了件数専用
|
||||
$errors = []; // 全体エラー収集用
|
||||
$allQueueItems = []; // 全オペレーターキュー作成用データ
|
||||
|
||||
// 【処理1】駐輪場の空き状況を取得する
|
||||
$parkVacancyList = $this->getParkVacancyStatus();
|
||||
Log::info('駐輪場空き状況取得完了', [
|
||||
'total_parks' => count($parkVacancyList)
|
||||
]);
|
||||
|
||||
// 各駐輪場に対する処理
|
||||
foreach ($parkVacancyList as $parkVacancyData) {
|
||||
// 配列をオブジェクトに変換
|
||||
$parkVacancy = (object) $parkVacancyData;
|
||||
$processedParksCount++;
|
||||
|
||||
Log::info('駐輪場処理開始', [
|
||||
'park_id' => $parkVacancy->park_id,
|
||||
'park_name' => $parkVacancy->park_name,
|
||||
'psection_id' => $parkVacancy->psection_id,
|
||||
'ptype_id' => $parkVacancy->ptype_id,
|
||||
'vacant_count' => $parkVacancy->vacant_count
|
||||
]);
|
||||
|
||||
// 【判断1】空き状況判定
|
||||
if ($parkVacancy->vacant_count < 1) {
|
||||
Log::info('空きなし - 処理スキップ', [
|
||||
'park_id' => $parkVacancy->park_id,
|
||||
'vacant_count' => $parkVacancy->vacant_count
|
||||
]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$vacantParksCount++;
|
||||
|
||||
// 【処理2】空き待ち者の情報を取得する
|
||||
$waitingUsers = $this->getWaitingUsersInfo(
|
||||
$parkVacancy->park_id,
|
||||
$parkVacancy->psection_id,
|
||||
$parkVacancy->ptype_id
|
||||
);
|
||||
|
||||
// 【判断2】取得件数判定
|
||||
if (empty($waitingUsers)) {
|
||||
Log::info('空き待ち者なし', [
|
||||
'park_id' => $parkVacancy->park_id
|
||||
]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$totalWaitingUsers += count($waitingUsers);
|
||||
Log::info('空き待ち者情報取得完了', [
|
||||
'park_id' => $parkVacancy->park_id,
|
||||
'waiting_users_count' => count($waitingUsers)
|
||||
]);
|
||||
|
||||
// 【処理3】空き待ち者への通知、またはオペレーターキュー追加処理
|
||||
$notificationResult = $this->processWaitingUsersNotification(
|
||||
$waitingUsers,
|
||||
$parkVacancy
|
||||
);
|
||||
|
||||
$notificationSuccessCount += $notificationResult['notification_success_count'];
|
||||
$operatorQueueCount += $notificationResult['operator_queue_count'];
|
||||
|
||||
if (!empty($notificationResult['errors'])) {
|
||||
$mailErrors = array_merge($mailErrors, $notificationResult['errors']);
|
||||
$errors = array_merge($errors, $notificationResult['errors']);
|
||||
}
|
||||
|
||||
// オペレーターキュー作成用データを収集
|
||||
if (!empty($notificationResult['queue_items'])) {
|
||||
$allQueueItems = array_merge($allQueueItems ?? [], $notificationResult['queue_items']);
|
||||
}
|
||||
}
|
||||
|
||||
// 【処理4】仕様書準拠:先に呼び出し、成功時のみ内部変数を更新
|
||||
$queueErrorCount = 0; // キュー登録異常終了件数(累計)
|
||||
$queueSuccessCount = 0; // キュー登録正常終了件数(累計)
|
||||
|
||||
foreach ($allQueueItems as $queueItem) {
|
||||
// 仕様書準拠:在呼叫前先計算"如果這次成功會是第幾件",確保記錄反映最新件數
|
||||
$predictedSuccessCount = $queueSuccessCount + 1;
|
||||
$predictedErrorCount = $queueErrorCount; // 暂时保持当前错误计数
|
||||
|
||||
$queueResult = $this->addToOperatorQueue(
|
||||
$queueItem['waiting_user'],
|
||||
$queueItem['park_vacancy'],
|
||||
$queueItem['batch_comment'],
|
||||
$notificationSuccessCount, // 最終メール正常終了件数
|
||||
$predictedSuccessCount, // 預測成功時的件數(包含本次)
|
||||
count($mailErrors), // 現在のメール異常終了件数(動態計算)
|
||||
$predictedErrorCount // 現在のキュー登録異常終了件数
|
||||
);
|
||||
|
||||
// 仕様書:根据实际结果决定是否采用预测值
|
||||
if ($queueResult['success']) {
|
||||
$queueSuccessCount = $predictedSuccessCount; // 采用预测的成功计数
|
||||
} else {
|
||||
$queueErrorCount++; // 失败时递增错误计数
|
||||
|
||||
// 仕様書:包含具体错误消息,满足"エラーメッセージ/スタックトレースを保持"要求
|
||||
$errorDetail = $queueResult['error'] ?? 'Unknown error';
|
||||
$queueErrorInfo = sprintf('キュー登録失敗:予約ID:%d - %s',
|
||||
$queueItem['waiting_user']->reserve_id ?? 0,
|
||||
$errorDetail
|
||||
);
|
||||
$errors[] = $queueErrorInfo; // 加入总错误统计(包含具体原因)
|
||||
|
||||
Log::error('オペレーターキュー作成失敗', [
|
||||
'user_id' => $queueItem['waiting_user']->user_id,
|
||||
'reserve_id' => $queueItem['waiting_user']->reserve_id ?? 0,
|
||||
'error' => $errorDetail
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$endTime = now();
|
||||
$duration = $startTime->diffInSeconds($endTime);
|
||||
|
||||
Log::info('SHJ-5 空き待ち通知処理完了', [
|
||||
'duration_seconds' => $duration,
|
||||
'processed_parks_count' => $processedParksCount,
|
||||
'vacant_parks_count' => $vacantParksCount,
|
||||
'total_waiting_users' => $totalWaitingUsers,
|
||||
'notification_success_count' => $notificationSuccessCount,
|
||||
'operator_queue_success_count' => $queueSuccessCount, // 仕様書:正常完了件数
|
||||
'queue_error_count' => $queueErrorCount,
|
||||
'mail_error_count' => count($mailErrors), // メール異常終了件数(分離)
|
||||
'total_error_count' => count($errors) // 全体エラー件数
|
||||
]);
|
||||
|
||||
// 仕様書に基づく内部変数.ステータスコメント生成
|
||||
$statusComment = sprintf(
|
||||
'メール正常終了件数:%d/メール異常終了件数:%d/キュー登録正常終了件数:%d/キュー登録異常終了件数:%d',
|
||||
$notificationSuccessCount,
|
||||
count($mailErrors), // メール異常終了件数(キュー失敗を除外)
|
||||
$queueSuccessCount ?? 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 [
|
||||
'success' => true,
|
||||
'message' => 'SHJ-5 空き待ち通知処理が正常に完了しました',
|
||||
'processed_parks_count' => $processedParksCount,
|
||||
'vacant_parks_count' => $vacantParksCount,
|
||||
'total_waiting_users' => $totalWaitingUsers,
|
||||
'notification_success_count' => $notificationSuccessCount,
|
||||
'operator_queue_count' => $queueSuccessCount ?? 0, // 仕様書:正常完了件数を使用
|
||||
'error_count' => count($errors),
|
||||
'errors' => $errors,
|
||||
'duration_seconds' => $duration,
|
||||
'status_comment' => $statusComment // SHJ-8用の完全なステータスコメント
|
||||
];
|
||||
|
||||
} catch (Exception $e) {
|
||||
Log::error('SHJ-5 空き待ち通知処理でエラーが発生', [
|
||||
'error' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString()
|
||||
]);
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => 'SHJ-5 空き待ち通知処理でエラーが発生: ' . $e->getMessage(),
|
||||
'error_details' => $e->getMessage()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 【処理1】駐輪場の空き状況を取得する
|
||||
*
|
||||
* 仕様書に基づくSQL:
|
||||
* - zone表から標準台数と現在の契約台数を比較
|
||||
* - 空きがある駐輪場の情報を取得
|
||||
*
|
||||
* @return array 駐輪場空き状況リスト
|
||||
*/
|
||||
private function getParkVacancyStatus(): array
|
||||
{
|
||||
try {
|
||||
// ゾーン毎の契約台数を取得
|
||||
$contractCounts = DB::table('regular_contract as T1')
|
||||
->select([
|
||||
'T1.park_id',
|
||||
'T1.psection_id',
|
||||
'T5.ptype_id',
|
||||
DB::raw('count(T1.contract_id) as contract_count')
|
||||
])
|
||||
->join('park as T2', 'T1.park_id', '=', 'T2.park_id')
|
||||
->join('price_a as T5', function($join) {
|
||||
$join->on('T1.park_id', '=', 'T5.park_id')
|
||||
->on('T1.price_parkplaceid', '=', 'T5.price_parkplaceid')
|
||||
->on('T1.psection_id', '=', 'T5.psection_id');
|
||||
})
|
||||
->where([
|
||||
['T1.contract_flag', '=', 1], // 有効契約
|
||||
['T2.park_close_flag', '=', 0], // 駐輪場未閉鎖
|
||||
])
|
||||
// 契約有効期間内の条件
|
||||
->whereRaw("date_format(now(), '%Y%m%d') BETWEEN T1.contract_periods AND T1.contract_periode")
|
||||
->groupBy(['T1.park_id', 'T1.psection_id', 'T5.ptype_id'])
|
||||
->get()
|
||||
->keyBy(function($item) {
|
||||
return $item->park_id . '_' . $item->psection_id . '_' . $item->ptype_id;
|
||||
});
|
||||
|
||||
// ゾーン情報と照合して空き状況を算出
|
||||
$vacancyList = DB::table('zone as T1')
|
||||
->select([
|
||||
'T1.park_id',
|
||||
'T2.park_name',
|
||||
'T1.psection_id',
|
||||
'T1.ptype_id',
|
||||
'T1.zone_standard',
|
||||
'T3.psection_subject',
|
||||
'T4.ptype_subject'
|
||||
])
|
||||
->join('park as T2', 'T1.park_id', '=', 'T2.park_id')
|
||||
->join('psection as T3', 'T1.psection_id', '=', 'T3.psection_id')
|
||||
->join('ptype as T4', 'T1.ptype_id', '=', 'T4.ptype_id')
|
||||
->where([
|
||||
['T1.delete_flag', '=', 0], // ゾーン有効
|
||||
['T2.park_close_flag', '=', 0], // 駐輪場開設
|
||||
])
|
||||
->get()
|
||||
->map(function($zone) use ($contractCounts) {
|
||||
$key = $zone->park_id . '_' . $zone->psection_id . '_' . $zone->ptype_id;
|
||||
$contractCount = isset($contractCounts[$key]) ? $contractCounts[$key]->contract_count : 0;
|
||||
|
||||
$zone->contract_count = $contractCount;
|
||||
$zone->vacant_count = max(0, $zone->zone_standard - $contractCount);
|
||||
|
||||
return $zone;
|
||||
})
|
||||
->filter(function($zone) {
|
||||
return $zone->vacant_count > 0; // 空きがあるもののみ
|
||||
})
|
||||
->values();
|
||||
|
||||
Log::info('駐輪場空き状況算出完了', [
|
||||
'total_zones' => count($vacancyList),
|
||||
'vacant_zones' => $vacancyList->filter(function($v) {
|
||||
return $v->vacant_count > 0;
|
||||
})->count()
|
||||
]);
|
||||
|
||||
return $vacancyList->toArray();
|
||||
|
||||
} catch (Exception $e) {
|
||||
Log::error('駐輪場空き状況取得エラー', [
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 【処理2】空き待ち者の情報を取得する
|
||||
*
|
||||
* 仕様書に基づく取得条件:
|
||||
* - 契約未紐付(contract_id IS NULL)
|
||||
* - 退会でない(user_quit_flag <> 1)
|
||||
* - 有効な予約(valid_flag = 1)
|
||||
* - 予約日時順で取得(reserve_date昇順)
|
||||
*
|
||||
* @param int $parkId 駐輪場ID
|
||||
* @param int $psectionId 車種区分ID
|
||||
* @param int $ptypeId 駐輪分類ID
|
||||
* @return array 空き待ち者情報リスト
|
||||
*/
|
||||
private function getWaitingUsersInfo(int $parkId, int $psectionId, int $ptypeId): array
|
||||
{
|
||||
try {
|
||||
$waitingUsers = DB::table('reserve as T1')
|
||||
->select([
|
||||
'T1.reserve_id',
|
||||
'T1.user_id',
|
||||
'T1.park_id',
|
||||
'T1.psection_id',
|
||||
'T1.ptype_id',
|
||||
'T1.reserve_order',
|
||||
'T1.reserve_date',
|
||||
'T1.reserve_manual', // 手動通知フラグ
|
||||
'T1.contract_id', // 契約紐付確認用
|
||||
'T2.user_name',
|
||||
'T2.user_primemail',
|
||||
'T2.user_submail', // 副メールアドレス
|
||||
'T2.user_manual_regist_flag', // 手動登録フラグ
|
||||
'T2.user_quit_flag', // 退会フラグ
|
||||
'T3.park_name',
|
||||
'T4.psection_subject',
|
||||
'T5.ptype_subject'
|
||||
])
|
||||
->join('user as T2', 'T1.user_id', '=', 'T2.user_id')
|
||||
->join('park as T3', 'T1.park_id', '=', 'T3.park_id')
|
||||
->join('psection as T4', 'T1.psection_id', '=', 'T4.psection_id')
|
||||
->join('ptype as T5', 'T1.ptype_id', '=', 'T5.ptype_id')
|
||||
->where([
|
||||
['T1.park_id', '=', $parkId],
|
||||
['T1.psection_id', '=', $psectionId],
|
||||
['T1.ptype_id', '=', $ptypeId],
|
||||
['T1.valid_flag', '=', 1], // 有効な予約
|
||||
['T2.user_quit_flag', '<>', 1] // 退会でない
|
||||
])
|
||||
->whereNull('T1.contract_id') // 契約未紐付
|
||||
->orderBy('T1.reserve_date', 'asc') // 仕様書に基づく予約日時順
|
||||
->get()
|
||||
->toArray();
|
||||
|
||||
Log::info('空き待ち者情報取得完了', [
|
||||
'park_id' => $parkId,
|
||||
'psection_id' => $psectionId,
|
||||
'ptype_id' => $ptypeId,
|
||||
'waiting_users_count' => count($waitingUsers)
|
||||
]);
|
||||
|
||||
return $waitingUsers;
|
||||
|
||||
} catch (Exception $e) {
|
||||
Log::error('空き待ち者情報取得エラー', [
|
||||
'park_id' => $parkId,
|
||||
'psection_id' => $psectionId,
|
||||
'ptype_id' => $ptypeId,
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 【処理3】空き待ち者への通知、またはオペレーターキュー追加処理
|
||||
*
|
||||
* 仕様書に基づく分岐処理:
|
||||
* - 手動通知フラグ判定(reserve_manual)
|
||||
* - メール送信成功時のreserve.sent_date更新
|
||||
* - 失敗時のオペレーターキュー追加(最終統計で処理)
|
||||
*
|
||||
* @param array $waitingUsers 空き待ち者リスト
|
||||
* @param object $parkVacancy 駐輪場空き情報
|
||||
* @return array 通知処理結果
|
||||
*/
|
||||
private function processWaitingUsersNotification(array $waitingUsers, object $parkVacancy): array
|
||||
{
|
||||
$notificationSuccessCount = 0;
|
||||
$operatorQueueCount = 0;
|
||||
$errors = [];
|
||||
$queueItems = []; // オペレーターキュー作成用データ収集
|
||||
|
||||
try {
|
||||
// 空きがある分だけ処理(先着順)
|
||||
$availableSpots = min($parkVacancy->vacant_count, count($waitingUsers));
|
||||
|
||||
for ($i = 0; $i < $availableSpots; $i++) {
|
||||
$waitingUserData = $waitingUsers[$i];
|
||||
// 配列をオブジェクトに変換
|
||||
$waitingUser = (object) $waitingUserData;
|
||||
|
||||
try {
|
||||
// 【仕様判断】手動通知フラグチェック
|
||||
if ($waitingUser->reserve_manual == 1) {
|
||||
// 手動通知 → オペレーターキュー作成データ収集
|
||||
$batchComment = '手動通知フラグ設定のため予約ID:' . $waitingUser->reserve_id;
|
||||
$queueItems[] = [
|
||||
'waiting_user' => $waitingUser,
|
||||
'park_vacancy' => $parkVacancy,
|
||||
'batch_comment' => $batchComment
|
||||
];
|
||||
$operatorQueueCount++;
|
||||
|
||||
Log::info('手動通知フラグによりオペレーターキュー登録予定', [
|
||||
'user_id' => $waitingUser->user_id,
|
||||
'reserve_id' => $waitingUser->reserve_id
|
||||
]);
|
||||
} else {
|
||||
// 自動通知 → メール送信を試行
|
||||
$mailResult = $this->sendVacancyNotificationMail($waitingUser, $parkVacancy);
|
||||
|
||||
if ($mailResult['success']) {
|
||||
// メール送信成功 → reserve.sent_date更新
|
||||
$this->updateReserveSentDate($waitingUser->reserve_id);
|
||||
$notificationSuccessCount++;
|
||||
|
||||
Log::info('空き待ち通知メール送信成功', [
|
||||
'user_id' => $waitingUser->user_id,
|
||||
'reserve_id' => $waitingUser->reserve_id,
|
||||
'park_id' => $parkVacancy->park_id
|
||||
]);
|
||||
} else {
|
||||
// メール送信失敗 → オペレーターキュー作成データ収集
|
||||
$shjSevenError = $mailResult['error'] ?? $mailResult['message'] ?? 'SHJ-7メール送信エラー';
|
||||
$batchComment = $shjSevenError . '予約ID:' . $waitingUser->reserve_id;
|
||||
$queueItems[] = [
|
||||
'waiting_user' => $waitingUser,
|
||||
'park_vacancy' => $parkVacancy,
|
||||
'batch_comment' => $batchComment
|
||||
];
|
||||
$operatorQueueCount++;
|
||||
$errors[] = $shjSevenError;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
Log::error('空き待ち者通知処理エラー', [
|
||||
'user_id' => $waitingUser->user_id,
|
||||
'reserve_id' => $waitingUser->reserve_id,
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
|
||||
// エラー発生時もオペレーターキュー作成データ収集
|
||||
$batchComment = 'システムエラー:' . $e->getMessage() . '予約ID:' . $waitingUser->reserve_id;
|
||||
$queueItems[] = [
|
||||
'waiting_user' => $waitingUser,
|
||||
'park_vacancy' => $parkVacancy,
|
||||
'batch_comment' => $batchComment
|
||||
];
|
||||
$operatorQueueCount++;
|
||||
$errors[] = $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'notification_success_count' => $notificationSuccessCount,
|
||||
'operator_queue_count' => $operatorQueueCount,
|
||||
'errors' => $errors,
|
||||
'queue_items' => $queueItems // 後でキュー作成用
|
||||
];
|
||||
|
||||
} catch (Exception $e) {
|
||||
Log::error('空き待ち者通知処理全体エラー', [
|
||||
'park_id' => $parkVacancy->park_id,
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 空き待ち通知メールを送信
|
||||
*
|
||||
* 仕様書に基づくSHJ-7呼び出し:
|
||||
* - 主メールアドレス・副メールアドレスを正しく渡す
|
||||
* - 必要なパラメータを全て設定
|
||||
*
|
||||
* @param object $waitingUser 空き待ち者情報
|
||||
* @param object $parkVacancy 駐輪場空き情報
|
||||
* @return array 送信結果
|
||||
*/
|
||||
private function sendVacancyNotificationMail(object $waitingUser, object $parkVacancy): array
|
||||
{
|
||||
try {
|
||||
// ShjMailSendServiceを利用してメール送信
|
||||
$mailService = app(ShjMailSendService::class);
|
||||
|
||||
// 空き待ち通知用のメールテンプレートID(予約告知通知)
|
||||
// OperatorQueの定数と合わせて4番を使用
|
||||
$mailTemplateId = 4; // 予約告知通知のテンプレートID
|
||||
|
||||
// 仕様書No1/No2に基づく主メール・副メール設定
|
||||
$mainEmail = $waitingUser->user_primemail ?? '';
|
||||
$subEmail = $waitingUser->user_submail ?? '';
|
||||
|
||||
// メール送信実行(仕様書準拠)
|
||||
$mailResult = $mailService->executeMailSend(
|
||||
$mainEmail,
|
||||
$subEmail,
|
||||
$mailTemplateId
|
||||
);
|
||||
|
||||
// SHJ-7の結果を標準形式に変換(result: 0=成功, 1=失敗)
|
||||
$success = ($mailResult['result'] ?? 1) === 0;
|
||||
|
||||
Log::info('空き待ち通知メール送信試行完了', [
|
||||
'user_id' => $waitingUser->user_id,
|
||||
'main_email' => $mainEmail,
|
||||
'sub_email' => $subEmail,
|
||||
'mail_template_id' => $mailTemplateId,
|
||||
'result' => $mailResult['result'] ?? 1,
|
||||
'success' => $success
|
||||
]);
|
||||
|
||||
return [
|
||||
'success' => $success,
|
||||
'result' => $mailResult['result'] ?? 1,
|
||||
'error' => $mailResult['error_info'] ?? null,
|
||||
'message' => $success ? 'メール送信成功' : ($mailResult['error_info'] ?? 'メール送信失敗')
|
||||
];
|
||||
|
||||
} catch (Exception $e) {
|
||||
Log::error('空き待ち通知メール送信エラー', [
|
||||
'user_id' => $waitingUser->user_id,
|
||||
'main_email' => $waitingUser->user_primemail ?? '',
|
||||
'sub_email' => $waitingUser->user_submail ?? '',
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'error' => $e->getMessage()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* reserve.sent_date及びvalid_flag更新
|
||||
*
|
||||
* 仕様書準拠:メール送信成功時にreserve.sent_dateとvalid_flag=0を同時更新
|
||||
* 重複通知を防ぎ、処理済みマークを設定
|
||||
*
|
||||
* @param int $reserveId 予約ID
|
||||
* @return void
|
||||
*/
|
||||
private function updateReserveSentDate(int $reserveId): void
|
||||
{
|
||||
try {
|
||||
DB::table('reserve')
|
||||
->where('reserve_id', $reserveId)
|
||||
->update([
|
||||
'sent_date' => now()->format('Y-m-d H:i:s'),
|
||||
'valid_flag' => 0, // 仕様書:メール送信成功時に0に更新
|
||||
'updated_at' => now()
|
||||
]);
|
||||
|
||||
Log::info('reserve.sent_date及びvalid_flag更新完了', [
|
||||
'reserve_id' => $reserveId,
|
||||
'sent_date' => now()->format('Y-m-d H:i:s'),
|
||||
'valid_flag' => 0
|
||||
]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
Log::error('reserve.sent_date及びvalid_flag更新エラー', [
|
||||
'reserve_id' => $reserveId,
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* オペレーターキューに追加
|
||||
*
|
||||
* 仕様書に基づくキュー登録:
|
||||
* - que_comment: 空文字列
|
||||
* - que_status_comment: 仕様書完全準拠形式(統計情報含む)
|
||||
* - operator_id: 9999999固定
|
||||
*
|
||||
* @param object $waitingUser 空き待ち者情報
|
||||
* @param object $parkVacancy 駐輪場空き情報
|
||||
* @param string $batchComment 内部変数.バッチコメント
|
||||
* @param int $mailSuccessCount メール正常終了件数
|
||||
* @param int $queueSuccessCount キュー登録正常終了件数
|
||||
* @param int $mailErrorCount メール異常終了件数
|
||||
* @param int $queueErrorCount キュー登録異常終了件数
|
||||
* @return array 追加結果
|
||||
*/
|
||||
private function addToOperatorQueue(object $waitingUser, object $parkVacancy, string $batchComment, int $mailSuccessCount, int $queueSuccessCount, int $mailErrorCount, int $queueErrorCount): array
|
||||
{
|
||||
try {
|
||||
// 仕様書完全準拠:駐輪場名/駐輪分類名/車種区分名/空き台数…/対象予約ID…/内部変数.バッチコメント/内部変数.メール正常終了件数…メール異常終了件数…キュー登録正常終了件数…キュー登録異常終了件数…
|
||||
$statusComment = sprintf(
|
||||
'%s/%s/%s/空き台数:%d台/対象予約ID:%d/%s/メール正常終了件数:%d/メール異常終了件数:%d/キュー登録正常終了件数:%d/キュー登録異常終了件数:%d',
|
||||
$waitingUser->park_name ?? '',
|
||||
$waitingUser->ptype_subject ?? '', // 駐輪分類名
|
||||
$waitingUser->psection_subject ?? '', // 車種区分名
|
||||
$parkVacancy->vacant_count ?? 0,
|
||||
$waitingUser->reserve_id ?? 0,
|
||||
$batchComment, // 内部変数.バッチコメント
|
||||
$mailSuccessCount, // 内部変数.メール正常終了件数
|
||||
$mailErrorCount,
|
||||
$queueSuccessCount,
|
||||
$queueErrorCount
|
||||
);
|
||||
|
||||
OperatorQue::create([
|
||||
'que_class' => 4, // 予約告知通知
|
||||
'user_id' => $waitingUser->user_id,
|
||||
'contract_id' => null,
|
||||
'park_id' => $waitingUser->park_id,
|
||||
'que_comment' => '', // 仕様書:空文字列
|
||||
'que_status' => 1, // キュー発生
|
||||
'que_status_comment' => $statusComment, // 仕様書:完全準拠形式
|
||||
'work_instructions' => '空き待ち者への連絡をお願いします。',
|
||||
'operator_id' => 9999999, // 仕様書:固定値9999999
|
||||
]);
|
||||
|
||||
Log::info('オペレーターキュー追加成功', [
|
||||
'user_id' => $waitingUser->user_id,
|
||||
'park_id' => $waitingUser->park_id,
|
||||
'reserve_id' => $waitingUser->reserve_id,
|
||||
'que_class' => 4,
|
||||
'operator_id' => 9999999,
|
||||
'batch_comment' => $batchComment,
|
||||
'mail_success_count' => $mailSuccessCount,
|
||||
'mail_error_count' => $mailErrorCount,
|
||||
'queue_success_count' => $queueSuccessCount,
|
||||
'queue_error_count' => $queueErrorCount,
|
||||
'status_comment' => $statusComment
|
||||
]);
|
||||
|
||||
return ['success' => true];
|
||||
|
||||
} catch (Exception $e) {
|
||||
Log::error('オペレーターキュー追加エラー', [
|
||||
'user_id' => $waitingUser->user_id,
|
||||
'park_id' => $waitingUser->park_id,
|
||||
'reserve_id' => $waitingUser->reserve_id ?? null,
|
||||
'batch_comment' => $batchComment,
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'error' => $e->getMessage()
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6,14 +6,19 @@ use App\Models\SettlementTransaction;
|
||||
use App\Models\RegularContract;
|
||||
use App\Models\Park;
|
||||
use App\Models\PriceA;
|
||||
use App\Models\Batch\BatchLog;
|
||||
use App\Models\BatJobLog;
|
||||
use App\Models\Device;
|
||||
use App\Models\User;
|
||||
use App\Services\ShjThirteenService;
|
||||
use App\Services\ShjEightService;
|
||||
use App\Services\ShjMailSendService;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Carbon\Carbon;
|
||||
|
||||
/**
|
||||
* SHJ-4B 定期契約更新処理サービス
|
||||
*
|
||||
*
|
||||
* SHJ-4Aで登録された決済情報を基に定期契約の更新処理を実行する
|
||||
* ウェルネットのPUSH通知を契機とした決済トランザクション処理
|
||||
*/
|
||||
@ -33,6 +38,34 @@ class ShjFourBService
|
||||
const CONTRACT_FLAG_UPDATED = 1; // 更新済
|
||||
const CONTRACT_FLAG_ERROR = 2; // エラー状態
|
||||
|
||||
/**
|
||||
* SHJ-8 バッチ処理ログ作成サービス
|
||||
*
|
||||
* @var ShjEightService
|
||||
*/
|
||||
protected $shjEightService;
|
||||
|
||||
/**
|
||||
* SHJ-7 メール送信サービス
|
||||
*
|
||||
* @var ShjMailSendService
|
||||
*/
|
||||
protected $mailSendService;
|
||||
|
||||
/**
|
||||
* コンストラクタ
|
||||
*
|
||||
* @param ShjEightService $shjEightService
|
||||
* @param ShjMailSendService $mailSendService
|
||||
*/
|
||||
public function __construct(
|
||||
ShjEightService $shjEightService,
|
||||
ShjMailSendService $mailSendService
|
||||
) {
|
||||
$this->shjEightService = $shjEightService;
|
||||
$this->mailSendService = $mailSendService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 決済トランザクション処理メイン実行
|
||||
*
|
||||
@ -65,22 +98,29 @@ class ShjFourBService
|
||||
|
||||
if (!$contractResult['found']) {
|
||||
// 対象レコードなしの場合
|
||||
return $this->handleNoTargetRecord($settlement, $contractResult);
|
||||
$result = $this->handleNoTargetRecord($settlement, $contractResult);
|
||||
$this->createBatchLog($settlement, null, null, true, $result['message']);
|
||||
return $result;
|
||||
}
|
||||
|
||||
if ($contractResult['already_processed']) {
|
||||
// 登録済みの場合
|
||||
return $this->handleAlreadyProcessed($settlement, $contractResult);
|
||||
$result = $this->handleAlreadyProcessed($settlement, $contractResult);
|
||||
$contract = $contractResult['contract'];
|
||||
$this->createBatchLog($settlement, $contract, null, true, $result['message']);
|
||||
return $result;
|
||||
}
|
||||
|
||||
$contract = $contractResult['contract'];
|
||||
|
||||
|
||||
// 【判断1】授受状態チェック
|
||||
$statusResult = $this->judgeReceiptStatus($settlement, $contract);
|
||||
|
||||
|
||||
if (!$statusResult['valid']) {
|
||||
// 授受状態が異常な場合
|
||||
return $this->handleInvalidStatus($settlement, $contract, $statusResult);
|
||||
$result = $this->handleInvalidStatus($settlement, $contract, $statusResult);
|
||||
$this->createBatchLog($settlement, $contract, null, true, $result['message']);
|
||||
return $result;
|
||||
}
|
||||
|
||||
// 【判断2】金額チェック
|
||||
@ -104,7 +144,11 @@ class ShjFourBService
|
||||
];
|
||||
|
||||
Log::info('SHJ-4B 決済トランザクション処理完了', $result);
|
||||
|
||||
|
||||
// 【処理6】バッチ処理ログ作成(SHJ-8呼び出し)
|
||||
$mailCommentSuffix = $sideEffectResult['user_mail']['batch_comment_suffix'] ?? null;
|
||||
$this->createBatchLog($settlement, $contract, $amountResult, true, null, $mailCommentSuffix);
|
||||
|
||||
return $result;
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
@ -114,7 +158,17 @@ class ShjFourBService
|
||||
'error' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString(),
|
||||
]);
|
||||
|
||||
|
||||
// エラー時のバッチログ作成
|
||||
try {
|
||||
$settlement = SettlementTransaction::find($settlementTransactionId);
|
||||
if ($settlement) {
|
||||
$this->createBatchLog($settlement, null, null, false, $e->getMessage());
|
||||
}
|
||||
} catch (\Throwable $logError) {
|
||||
Log::error('SHJ-4B バッチログ作成エラー', ['error' => $logError->getMessage()]);
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
@ -170,6 +224,7 @@ class ShjFourBService
|
||||
'T1.billing_amount',
|
||||
'T4.price_ptypeid as ptype_id',
|
||||
'T1.psection_id',
|
||||
'T1.zone_id',
|
||||
'T1.update_flag',
|
||||
'T1.reserve_id',
|
||||
'T1.contract_payment_number',
|
||||
@ -282,16 +337,17 @@ class ShjFourBService
|
||||
];
|
||||
}
|
||||
|
||||
// 条件3: batch_logで同一決済の処理完了記録があるか
|
||||
$existingBatchLog = BatchLog::where('process_name', 'shj4b')
|
||||
->where('status', BatchLog::STATUS_SUCCESS)
|
||||
->where('parameters', 'like', '%"settlement_transaction_id":' . $settlement->settlement_transaction_id . '%')
|
||||
// 条件3: bat_job_logで同一決済の処理完了記録があるか
|
||||
// status_commentに決済トランザクションIDが含まれているかチェック
|
||||
$existingBatchLog = BatJobLog::where('process_name', 'SHJ-4B')
|
||||
->where('status', 'success')
|
||||
->where('status_comment', 'like', '%settlement_transaction_id:' . $settlement->settlement_transaction_id . '%')
|
||||
->exists();
|
||||
|
||||
if ($existingBatchLog) {
|
||||
return [
|
||||
'processed' => true,
|
||||
'reason' => "batch_logに処理完了記録が存在",
|
||||
'reason' => "bat_job_logに処理完了記録が存在",
|
||||
];
|
||||
}
|
||||
|
||||
@ -764,58 +820,161 @@ class ShjFourBService
|
||||
|
||||
/**
|
||||
* SHJ-13実行処理(新規のみ)
|
||||
*
|
||||
* ShjThirteenServiceを使用した契約台数追加処理
|
||||
*
|
||||
* @param object $contract
|
||||
* @return array
|
||||
*/
|
||||
private function triggerShjThirteen($contract): array
|
||||
{
|
||||
// TODO: SHJ-13の具体的な処理を実装
|
||||
// 現在はプレースホルダー
|
||||
|
||||
Log::info('SHJ-4B SHJ-13実行処理', [
|
||||
'contract_id' => $contract->contract_id,
|
||||
'user_id' => $contract->user_id,
|
||||
'park_id' => $contract->park_id,
|
||||
'psection_id' => $contract->psection_id,
|
||||
'ptype_id' => $contract->ptype_id,
|
||||
'zone_id' => $contract->zone_id,
|
||||
]);
|
||||
|
||||
return [
|
||||
'triggered' => true,
|
||||
'method' => 'placeholder',
|
||||
'message' => 'SHJ-13処理は実装予定です',
|
||||
'contract_id' => $contract->contract_id,
|
||||
];
|
||||
|
||||
try {
|
||||
// 契約データ準備
|
||||
$contractData = [
|
||||
'contract_id' => $contract->contract_id,
|
||||
'park_id' => $contract->park_id,
|
||||
'psection_id' => $contract->psection_id,
|
||||
'ptype_id' => $contract->ptype_id,
|
||||
'zone_id' => $contract->zone_id,
|
||||
];
|
||||
|
||||
// ShjThirteenService実行
|
||||
$shjThirteenService = app(ShjThirteenService::class);
|
||||
$result = $shjThirteenService->execute($contractData);
|
||||
|
||||
Log::info('SHJ-4B SHJ-13実行完了', [
|
||||
'contract_id' => $contract->contract_id,
|
||||
'result' => $result,
|
||||
]);
|
||||
|
||||
return $result;
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('SHJ-4B SHJ-13実行エラー', [
|
||||
'contract_id' => $contract->contract_id,
|
||||
'error' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString(),
|
||||
]);
|
||||
|
||||
return [
|
||||
'result' => 1,
|
||||
'error_code' => $e->getCode() ?: 1999,
|
||||
'error_message' => $e->getMessage(),
|
||||
'stack_trace' => $e->getTraceAsString(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 利用者メール送信処理
|
||||
* 【処理5】利用者メール送信処理
|
||||
*
|
||||
* SHJ-4B仕様準拠:
|
||||
* 1. 利用者マスタよりメールアドレス、予備メールアドレスを取得
|
||||
* 2. SHJ-7メール送信を呼び出し(使用プログラムID: 205)
|
||||
* 3. 処理結果判定:
|
||||
* - result = 0 (正常): バッチコメントに "/メール正常終了件数:1" を追加
|
||||
* - その他: バッチコメントに "/メール異常終了件数:1、" + error_info を追加
|
||||
*
|
||||
* @param SettlementTransaction $settlement
|
||||
* @param object $contract
|
||||
* @param array $amountResult
|
||||
* @return array
|
||||
* @return array 処理結果 ['success' => bool, 'mail_status' => string, 'batch_comment_suffix' => string]
|
||||
*/
|
||||
private function sendUserNotificationMail(SettlementTransaction $settlement, $contract, array $amountResult): array
|
||||
{
|
||||
// TODO: 実際のメール送信処理を実装
|
||||
// 現在はプレースホルダー
|
||||
|
||||
$mailType = ($amountResult['comparison'] === self::AMOUNT_MATCH) ? 'success' : 'error';
|
||||
|
||||
Log::info('SHJ-4B 利用者メール送信処理', [
|
||||
'contract_id' => $contract->contract_id,
|
||||
'user_id' => $contract->user_id,
|
||||
'settlement_transaction_id' => $settlement->settlement_transaction_id,
|
||||
'mail_type' => $mailType,
|
||||
'amount_comparison' => $amountResult['comparison'],
|
||||
]);
|
||||
|
||||
return [
|
||||
'sent' => true,
|
||||
'method' => 'placeholder',
|
||||
'mail_type' => $mailType,
|
||||
'message' => '利用者メール送信処理は実装予定です',
|
||||
];
|
||||
try {
|
||||
// 【処理5】利用者マスタよりメールアドレス、予備メールアドレスを取得する
|
||||
$user = User::select('user_name', 'user_primemail', 'user_submail')
|
||||
->where('user_seq', $contract->user_id)
|
||||
->first();
|
||||
|
||||
if (!$user) {
|
||||
Log::error('SHJ-4B 利用者メール送信処理: 利用者情報取得失敗', [
|
||||
'user_id' => $contract->user_id,
|
||||
'contract_id' => $contract->contract_id,
|
||||
]);
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'mail_status' => 'user_not_found',
|
||||
'batch_comment_suffix' => '/メール異常終了件数:1、利用者情報取得失敗'
|
||||
];
|
||||
}
|
||||
|
||||
$mailAddress = $user->user_primemail ?? '';
|
||||
$backupMailAddress = $user->user_submail ?? '';
|
||||
|
||||
Log::info('SHJ-4B 利用者メール送信処理開始', [
|
||||
'contract_id' => $contract->contract_id,
|
||||
'user_id' => $contract->user_id,
|
||||
'user_name' => $user->user_name,
|
||||
'settlement_transaction_id' => $settlement->settlement_transaction_id,
|
||||
'mail_address' => $mailAddress,
|
||||
'amount_comparison' => $amountResult['comparison'],
|
||||
]);
|
||||
|
||||
// 共通処理「SHJ-7メール送信」を呼び出し
|
||||
// 使用プログラムID: 205(仕様書準拠)
|
||||
$mailResult = $this->mailSendService->executeMailSend(
|
||||
$mailAddress,
|
||||
$backupMailAddress,
|
||||
205 // SHJ-4B仕様: 使用プログラムID = 205
|
||||
);
|
||||
|
||||
// SHJ-7仕様準拠: result === 0 が正常、それ以外は異常
|
||||
if (($mailResult['result'] ?? 1) === 0) {
|
||||
// 【正常終了】バッチコメントに "/メール正常終了件数:1" を設定
|
||||
Log::info('SHJ-4B 利用者メール送信成功', [
|
||||
'contract_id' => $contract->contract_id,
|
||||
'user_id' => $contract->user_id,
|
||||
'mail_address' => $mailAddress,
|
||||
]);
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'mail_status' => 'sent',
|
||||
'batch_comment_suffix' => '/メール正常終了件数:1'
|
||||
];
|
||||
} else {
|
||||
// 【異常終了】バッチコメントに "/メール異常終了件数:1、" + error_info を設定
|
||||
$errorInfo = $mailResult['error_info'] ?? 'メール送信失敗';
|
||||
|
||||
Log::error('SHJ-4B 利用者メール送信失敗', [
|
||||
'contract_id' => $contract->contract_id,
|
||||
'user_id' => $contract->user_id,
|
||||
'mail_address' => $mailAddress,
|
||||
'error_info' => $errorInfo,
|
||||
]);
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'mail_status' => 'failed',
|
||||
'batch_comment_suffix' => "/メール異常終了件数:1、{$errorInfo}"
|
||||
];
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('SHJ-4B 利用者メール送信処理例外エラー', [
|
||||
'contract_id' => $contract->contract_id,
|
||||
'user_id' => $contract->user_id,
|
||||
'error' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString(),
|
||||
]);
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'mail_status' => 'exception',
|
||||
'batch_comment_suffix' => '/メール異常終了件数:1、システムエラー: ' . $e->getMessage()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -832,18 +991,100 @@ class ShjFourBService
|
||||
array $amountResult
|
||||
): array {
|
||||
// TODO: OperatorQue モデルを使用したキューへの登録処理を実装
|
||||
|
||||
|
||||
Log::info('SHJ-4B オペレーターキュー登録処理実行', [
|
||||
'settlement_transaction_id' => $settlement->settlement_transaction_id,
|
||||
'contract_id' => $contract->contract_id,
|
||||
'amount_comparison' => $amountResult['comparison'],
|
||||
'difference' => $amountResult['difference'],
|
||||
]);
|
||||
|
||||
|
||||
return [
|
||||
'registered' => true,
|
||||
'method' => 'placeholder',
|
||||
'message' => 'オペレーターキュー登録処理は実装予定です',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 【処理6】バッチ処理ログ作成
|
||||
*
|
||||
* SHJ-8サービスを呼び出してbat_job_logに記録
|
||||
*
|
||||
* @param SettlementTransaction $settlement
|
||||
* @param object|null $contract
|
||||
* @param array|null $amountResult
|
||||
* @param bool $isSuccess
|
||||
* @param string|null $errorMessage
|
||||
* @param string|null $mailCommentSuffix メール送信結果コメント(例: "/メール正常終了件数:1" or "/メール異常終了件数:1、{error_info}")
|
||||
* @return void
|
||||
*/
|
||||
private function createBatchLog(
|
||||
SettlementTransaction $settlement,
|
||||
$contract = null,
|
||||
?array $amountResult = null,
|
||||
bool $isSuccess = true,
|
||||
?string $errorMessage = null,
|
||||
?string $mailCommentSuffix = null
|
||||
): void {
|
||||
try {
|
||||
$device = Device::orderBy('device_id')->first();
|
||||
$deviceId = $device ? $device->device_id : 1;
|
||||
$today = now()->format('Y/m/d');
|
||||
|
||||
// ステータスコメント生成(内部変数.バッチコメント)
|
||||
if ($errorMessage) {
|
||||
// エラー時
|
||||
$statusComment = "支払いステータスチェック:エラー(決済トランザクションID:{$settlement->settlement_transaction_id}) - {$errorMessage}";
|
||||
} elseif ($amountResult) {
|
||||
// 正常処理時
|
||||
$contractId = $contract ? $contract->contract_id : 'N/A';
|
||||
|
||||
switch ($amountResult['comparison']) {
|
||||
case self::AMOUNT_MATCH:
|
||||
$statusComment = "支払いステータスチェック:OK(決済トランザクションID:{$settlement->settlement_transaction_id}、契約ID:{$contractId}、金額一致)";
|
||||
break;
|
||||
case self::AMOUNT_SHORTAGE:
|
||||
$statusComment = "支払いステータスチェック:請求金額より授受金額が少ないです(決済トランザクションID:{$settlement->settlement_transaction_id}、契約ID:{$contractId}、差額:{$amountResult['difference']}円)";
|
||||
break;
|
||||
case self::AMOUNT_EXCESS:
|
||||
$statusComment = "支払いステータスチェック:請求金額より授受金額が多いです(決済トランザクションID:{$settlement->settlement_transaction_id}、契約ID:{$contractId}、差額:{$amountResult['difference']}円)";
|
||||
break;
|
||||
default:
|
||||
$statusComment = "支払いステータスチェック:処理完了(決済トランザクションID:{$settlement->settlement_transaction_id}、契約ID:{$contractId})";
|
||||
}
|
||||
} else {
|
||||
// その他のケース(対象なし、登録済み等)
|
||||
$contractId = $contract ? $contract->contract_id : 'N/A';
|
||||
$statusComment = "支払いステータスチェック:処理完了(決済トランザクションID:{$settlement->settlement_transaction_id}、契約ID:{$contractId})";
|
||||
}
|
||||
|
||||
// メール送信結果をバッチコメントに追加
|
||||
if ($mailCommentSuffix) {
|
||||
$statusComment .= $mailCommentSuffix;
|
||||
}
|
||||
|
||||
// SHJ-8サービス呼び出し
|
||||
$this->shjEightService->execute(
|
||||
$deviceId,
|
||||
'SHJ-4B',
|
||||
'SHJ-4支払いステータスチェック',
|
||||
'success',
|
||||
$statusComment,
|
||||
$today,
|
||||
$today
|
||||
);
|
||||
|
||||
Log::info('SHJ-4B バッチ処理ログ作成完了', [
|
||||
'settlement_transaction_id' => $settlement->settlement_transaction_id,
|
||||
'status_comment' => $statusComment,
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('SHJ-4B バッチ処理ログ作成エラー', [
|
||||
'error' => $e->getMessage(),
|
||||
'settlement_transaction_id' => $settlement->settlement_transaction_id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ namespace App\Services;
|
||||
|
||||
use App\Models\Park;
|
||||
use App\Models\RegularContract;
|
||||
use App\Models\Batch\BatchLog;
|
||||
use App\Models\Device;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Carbon\Carbon;
|
||||
@ -32,27 +32,27 @@ class ShjFourCService
|
||||
protected $contractModel;
|
||||
|
||||
/**
|
||||
* BatchLog モデル
|
||||
* ShjEightService
|
||||
*
|
||||
* @var BatchLog
|
||||
* @var ShjEightService
|
||||
*/
|
||||
protected $batchLogModel;
|
||||
protected $shjEightService;
|
||||
|
||||
/**
|
||||
* コンストラクタ
|
||||
*
|
||||
* @param Park $parkModel
|
||||
* @param RegularContract $contractModel
|
||||
* @param BatchLog $batchLogModel
|
||||
* @param ShjEightService $shjEightService
|
||||
*/
|
||||
public function __construct(
|
||||
Park $parkModel,
|
||||
RegularContract $contractModel,
|
||||
BatchLog $batchLogModel
|
||||
ShjEightService $shjEightService
|
||||
) {
|
||||
$this->parkModel = $parkModel;
|
||||
$this->contractModel = $contractModel;
|
||||
$this->batchLogModel = $batchLogModel;
|
||||
$this->shjEightService = $shjEightService;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -71,24 +71,11 @@ class ShjFourCService
|
||||
*/
|
||||
public function executeRoomAllocation(int $parkId, int $ptypeId, int $psectionId): array
|
||||
{
|
||||
$batchLogId = null;
|
||||
|
||||
try {
|
||||
// バッチ処理開始ログ作成(実際のコマンド名を記録)
|
||||
$batchLog = BatchLog::createBatchLog(
|
||||
'shj4c',
|
||||
BatchLog::STATUS_START,
|
||||
[
|
||||
'park_id' => $parkId,
|
||||
'ptype_id' => $ptypeId,
|
||||
'psection_id' => $psectionId
|
||||
],
|
||||
'SHJ-4C 室割当処理開始'
|
||||
);
|
||||
$batchLogId = $batchLog->id;
|
||||
$statusComment = '';
|
||||
$status = 'success';
|
||||
|
||||
try {
|
||||
Log::info('SHJ-4C 室割当処理開始', [
|
||||
'batch_log_id' => $batchLogId,
|
||||
'park_id' => $parkId,
|
||||
'ptype_id' => $ptypeId,
|
||||
'psection_id' => $psectionId
|
||||
@ -99,20 +86,16 @@ class ShjFourCService
|
||||
|
||||
if (empty($zoneInfo)) {
|
||||
$message = '対象のゾーン情報が見つかりません';
|
||||
|
||||
// バッチログ更新(通用方法使用)
|
||||
$batchLog->update([
|
||||
'status' => BatchLog::STATUS_ERROR,
|
||||
'end_time' => now(),
|
||||
'message' => $message,
|
||||
'error_details' => $message,
|
||||
'error_count' => 1
|
||||
]);
|
||||
|
||||
$status = 'error';
|
||||
$statusComment = sprintf('エラー: %s (park_id:%d, ptype_id:%d, psection_id:%d)',
|
||||
$message, $parkId, $ptypeId, $psectionId);
|
||||
|
||||
// バッチログ作成
|
||||
$this->createBatchLog($status, $statusComment);
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => $message,
|
||||
'batch_log_id' => $batchLogId
|
||||
'message' => $message
|
||||
];
|
||||
}
|
||||
|
||||
@ -122,36 +105,31 @@ class ShjFourCService
|
||||
if (!$allocationResult['can_allocate']) {
|
||||
// 割当NGの場合、対象事室番号を設定
|
||||
$this->setTargetRoomNumber($allocationResult['target_room_number']);
|
||||
|
||||
// バッチログ更新(警告)
|
||||
$batchLog->update([
|
||||
'status' => BatchLog::STATUS_WARNING,
|
||||
'end_time' => now(),
|
||||
'message' => '割当処理NG: ' . $allocationResult['reason'],
|
||||
'success_count' => 1 // 処理は成功したが割当NGのため
|
||||
]);
|
||||
|
||||
|
||||
$status = 'warning';
|
||||
$statusComment = sprintf('割当NG: %s (park_id:%d, ptype_id:%d, psection_id:%d)',
|
||||
$allocationResult['reason'], $parkId, $ptypeId, $psectionId);
|
||||
|
||||
// バッチログ作成
|
||||
$this->createBatchLog($status, $statusComment);
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'message' => '割当判定完了(割当NG)',
|
||||
'allocation_result' => $allocationResult,
|
||||
'batch_log_id' => $batchLogId
|
||||
'allocation_result' => $allocationResult
|
||||
];
|
||||
}
|
||||
|
||||
// 【処理2】割当実行(割当OKの場合)
|
||||
$executionResult = $this->executeAllocation($zoneInfo, $allocationResult);
|
||||
|
||||
// バッチ処理完了ログ更新
|
||||
$batchLog->update([
|
||||
'status' => BatchLog::STATUS_SUCCESS,
|
||||
'end_time' => now(),
|
||||
'message' => 'SHJ-4C 室割当処理正常完了',
|
||||
'success_count' => 1
|
||||
]);
|
||||
$statusComment = sprintf('室割当処理完了 (park_id:%d, ptype_id:%d, psection_id:%d, zone_id:%s)',
|
||||
$parkId, $ptypeId, $psectionId, $allocationResult['target_room_number'] ?? 'N/A');
|
||||
|
||||
// バッチログ作成
|
||||
$this->createBatchLog($status, $statusComment);
|
||||
|
||||
Log::info('SHJ-4C 室割当処理完了', [
|
||||
'batch_log_id' => $batchLogId,
|
||||
'execution_result' => $executionResult
|
||||
]);
|
||||
|
||||
@ -161,25 +139,19 @@ class ShjFourCService
|
||||
'message' => 'SHJ-4C 室割当処理が正常に完了しました',
|
||||
'zone_info' => $zoneInfo,
|
||||
'allocation_result' => $allocationResult,
|
||||
'execution_result' => $executionResult,
|
||||
'batch_log_id' => $batchLogId
|
||||
'execution_result' => $executionResult
|
||||
];
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$errorMessage = 'SHJ-4C 室割当処理でエラーが発生: ' . $e->getMessage();
|
||||
|
||||
if (isset($batchLog) && $batchLog) {
|
||||
$batchLog->update([
|
||||
'status' => BatchLog::STATUS_ERROR,
|
||||
'end_time' => now(),
|
||||
'message' => $errorMessage,
|
||||
'error_details' => $e->getMessage(),
|
||||
'error_count' => 1
|
||||
]);
|
||||
}
|
||||
$status = 'error';
|
||||
$statusComment = sprintf('例外エラー: %s (park_id:%d, ptype_id:%d, psection_id:%d)',
|
||||
$e->getMessage(), $parkId, $ptypeId, $psectionId);
|
||||
|
||||
// バッチログ作成
|
||||
$this->createBatchLog($status, $statusComment);
|
||||
|
||||
Log::error('SHJ-4C 室割当処理エラー', [
|
||||
'batch_log_id' => $batchLogId,
|
||||
'exception' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString()
|
||||
]);
|
||||
@ -187,12 +159,52 @@ class ShjFourCService
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => $errorMessage,
|
||||
'details' => $e->getMessage(),
|
||||
'batch_log_id' => $batchLogId
|
||||
'details' => $e->getMessage()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SHJ-8バッチ処理ログ作成
|
||||
*
|
||||
* @param string $status ステータス
|
||||
* @param string $statusComment ステータスコメント
|
||||
* @return void
|
||||
*/
|
||||
private function createBatchLog(string $status, string $statusComment): void
|
||||
{
|
||||
try {
|
||||
$device = Device::orderBy('device_id')->first();
|
||||
$deviceId = $device ? $device->device_id : 1;
|
||||
|
||||
$today = now()->format('Y/m/d');
|
||||
|
||||
Log::info('SHJ-8バッチ処理ログ作成', [
|
||||
'device_id' => $deviceId,
|
||||
'process_name' => 'SHJ-4C',
|
||||
'job_name' => 'SHJ-4C室割当',
|
||||
'status' => $status,
|
||||
'status_comment' => $statusComment
|
||||
]);
|
||||
|
||||
// SHJ-8サービスを呼び出し
|
||||
$this->shjEightService->execute(
|
||||
$deviceId,
|
||||
'SHJ-4C',
|
||||
'SHJ-4C室割当',
|
||||
$status,
|
||||
$statusComment,
|
||||
$today,
|
||||
$today
|
||||
);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('SHJ-8 バッチログ作成エラー', [
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 【処理1】ゾーン情報取得
|
||||
*
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\MailTemplate;
|
||||
use App\Models\Batch\BatchLog;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Carbon\Carbon;
|
||||
@ -23,32 +22,23 @@ class ShjMailSendService
|
||||
*/
|
||||
protected $mailTemplateModel;
|
||||
|
||||
/**
|
||||
* BatchLog モデル
|
||||
*
|
||||
* @var BatchLog
|
||||
*/
|
||||
protected $batchLogModel;
|
||||
|
||||
/**
|
||||
* コンストラクタ
|
||||
*
|
||||
* @param MailTemplate $mailTemplateModel
|
||||
* @param BatchLog $batchLogModel
|
||||
*/
|
||||
public function __construct(
|
||||
MailTemplate $mailTemplateModel,
|
||||
BatchLog $batchLogModel
|
||||
MailTemplate $mailTemplateModel
|
||||
) {
|
||||
$this->mailTemplateModel = $mailTemplateModel;
|
||||
$this->batchLogModel = $batchLogModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* SHJ メール送信処理メイン実行
|
||||
*
|
||||
* SHJ-7 メール送信処理メイン実行
|
||||
*
|
||||
* 処理フロー:
|
||||
* 【処理1】入力パラメーターをチェックする
|
||||
* 【判断1】チェック結果
|
||||
* 【処理2】メール送信テンプレート情報を取得する
|
||||
* 【判断2】取得結果判定
|
||||
* 【処理3】メールを送信する
|
||||
@ -56,29 +46,13 @@ class ShjMailSendService
|
||||
*
|
||||
* @param string $mailAddress メールアドレス
|
||||
* @param string $backupMailAddress 予備メールアドレス
|
||||
* @param int $mailTemplateId メールテンプレートID
|
||||
* @return array 処理結果
|
||||
* @param int $mailTemplateId メールテンプレートID(使用プログラムID)
|
||||
* @return array 処理結果 ['result' => 0|1, 'error_info' => string]
|
||||
*/
|
||||
public function executeMailSend(string $mailAddress, string $backupMailAddress, int $mailTemplateId): array
|
||||
{
|
||||
$batchLogId = null;
|
||||
|
||||
try {
|
||||
// バッチ処理開始ログ作成(実際のコマンド名を記録)
|
||||
$batchLog = BatchLog::createBatchLog(
|
||||
'shj-mail-send',
|
||||
BatchLog::STATUS_START,
|
||||
[
|
||||
'mail_address' => $mailAddress,
|
||||
'backup_mail_address' => $backupMailAddress,
|
||||
'mail_template_id' => $mailTemplateId
|
||||
],
|
||||
'SHJ メール送信処理開始'
|
||||
);
|
||||
$batchLogId = $batchLog->id;
|
||||
|
||||
Log::info('SHJ メール送信処理開始', [
|
||||
'batch_log_id' => $batchLogId,
|
||||
Log::info('SHJ-7 メール送信処理開始', [
|
||||
'mail_address' => $mailAddress,
|
||||
'backup_mail_address' => $backupMailAddress,
|
||||
'mail_template_id' => $mailTemplateId
|
||||
@ -86,14 +60,19 @@ class ShjMailSendService
|
||||
|
||||
// 【処理1】入力パラメーターをチェックする
|
||||
$paramCheckResult = $this->checkInputParameters($mailAddress, $backupMailAddress, $mailTemplateId);
|
||||
|
||||
// 【判断1】チェック結果
|
||||
if (!$paramCheckResult['valid']) {
|
||||
$this->updateBatchLog($batchLogId, 'error', $paramCheckResult['message']);
|
||||
|
||||
$errorInfo = $paramCheckResult['error_info'];
|
||||
|
||||
Log::warning('SHJ-7 パラメーターチェックNG', [
|
||||
'error_info' => $errorInfo
|
||||
]);
|
||||
|
||||
// 【処理4】処理結果を返却する(異常終了)
|
||||
return [
|
||||
'success' => false,
|
||||
'result_code' => 1, // 異常終了
|
||||
'message' => $paramCheckResult['message'],
|
||||
'batch_log_id' => $batchLogId
|
||||
'result' => 1,
|
||||
'error_info' => $errorInfo
|
||||
];
|
||||
}
|
||||
|
||||
@ -102,14 +81,18 @@ class ShjMailSendService
|
||||
|
||||
// 【判断2】取得結果判定
|
||||
if (empty($templateInfo)) {
|
||||
$message = "メールテンプレートが存在しません。テンプレートID: {$mailTemplateId}";
|
||||
$this->updateBatchLog($batchLogId, 'error', $message);
|
||||
|
||||
// 0件の場合:取得NGの結果を設定する
|
||||
$errorInfo = "メール送信NG:メール送信テンプレートが存在しません。/{$mailTemplateId}";
|
||||
|
||||
Log::warning('SHJ-7 メールテンプレート取得NG', [
|
||||
'mail_template_id' => $mailTemplateId,
|
||||
'error_info' => $errorInfo
|
||||
]);
|
||||
|
||||
// 【処理4】処理結果を返却する(異常終了)
|
||||
return [
|
||||
'success' => false,
|
||||
'result_code' => 1, // 異常終了
|
||||
'message' => $message,
|
||||
'batch_log_id' => $batchLogId
|
||||
'result' => 1,
|
||||
'error_info' => $errorInfo
|
||||
];
|
||||
}
|
||||
|
||||
@ -117,103 +100,109 @@ class ShjMailSendService
|
||||
$mailSendResult = $this->sendMail($mailAddress, $backupMailAddress, $templateInfo);
|
||||
|
||||
if (!$mailSendResult['success']) {
|
||||
$this->updateBatchLog($batchLogId, 'error', $mailSendResult['message']);
|
||||
|
||||
$errorInfo = $mailSendResult['error_info'];
|
||||
|
||||
Log::error('SHJ-7 メール送信失敗', [
|
||||
'error_info' => $errorInfo
|
||||
]);
|
||||
|
||||
// 【処理4】処理結果を返却する(異常終了)
|
||||
return [
|
||||
'success' => false,
|
||||
'result_code' => 1, // 異常終了
|
||||
'message' => $mailSendResult['message'],
|
||||
'batch_log_id' => $batchLogId
|
||||
'result' => 1,
|
||||
'error_info' => $errorInfo
|
||||
];
|
||||
}
|
||||
|
||||
// バッチ処理完了ログ更新
|
||||
$this->updateBatchLog($batchLogId, 'success', 'SHJ メール送信処理正常完了');
|
||||
|
||||
Log::info('SHJ メール送信処理完了', [
|
||||
'batch_log_id' => $batchLogId,
|
||||
'mail_send_result' => $mailSendResult
|
||||
Log::info('SHJ-7 メール送信処理完了', [
|
||||
'to_address' => $mailSendResult['to_address']
|
||||
]);
|
||||
|
||||
// 【処理4】処理結果を返却する
|
||||
// 【処理4】処理結果を返却する(正常終了)
|
||||
return [
|
||||
'success' => true,
|
||||
'result_code' => 0, // 正常終了
|
||||
'message' => 'SHJ メール送信処理が正常に完了しました',
|
||||
'mail_send_result' => $mailSendResult,
|
||||
'batch_log_id' => $batchLogId
|
||||
'result' => 0,
|
||||
'error_info' => ''
|
||||
];
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$errorMessage = 'SHJ メール送信処理でエラーが発生: ' . $e->getMessage();
|
||||
|
||||
if ($batchLogId) {
|
||||
$this->updateBatchLog($batchLogId, 'error', $errorMessage);
|
||||
}
|
||||
$errorInfo = 'メール送信NG:' . $e->getMessage();
|
||||
|
||||
Log::error('SHJ メール送信処理エラー', [
|
||||
'batch_log_id' => $batchLogId,
|
||||
Log::error('SHJ-7 メール送信処理例外エラー', [
|
||||
'exception' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString()
|
||||
]);
|
||||
|
||||
// 【処理4】処理結果を返却する(異常終了)
|
||||
return [
|
||||
'success' => false,
|
||||
'result_code' => 1, // 異常終了
|
||||
'message' => $errorMessage,
|
||||
'details' => $e->getMessage(),
|
||||
'batch_log_id' => $batchLogId
|
||||
'result' => 1,
|
||||
'error_info' => $errorInfo
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 【処理1】入力パラメーターをチェックする
|
||||
*
|
||||
* 仕様書に基づく詳細チェック:
|
||||
* - メールアドレス形式チェック
|
||||
* - テンプレートID存在性チェック
|
||||
*
|
||||
* SHJ-7仕様書に基づくチェック内容:
|
||||
* 1. メールアドレス: 「メールアドレス」「予備メールアドレス」いずれか必須
|
||||
* 2. 予備メールアドレス: 「メールアドレス」「予備メールアドレス」いずれか必須
|
||||
* 3. 使用プログラムID: 必須
|
||||
*
|
||||
* エラーメッセージ形式: "パラメーターNG: 項目名/入力値"
|
||||
* 複数エラーの場合は全角カンマ(、)で連結
|
||||
*
|
||||
* @param string $mailAddress メールアドレス
|
||||
* @param string $backupMailAddress 予備メールアドレス
|
||||
* @param int $mailTemplateId メールテンプレートID
|
||||
* @return array チェック結果
|
||||
* @param int $mailTemplateId メールテンプレートID(使用プログラムID)
|
||||
* @return array チェック結果 ['valid' => bool, 'error_info' => string]
|
||||
*/
|
||||
private function checkInputParameters(string $mailAddress, string $backupMailAddress, int $mailTemplateId): array
|
||||
{
|
||||
$errors = [];
|
||||
|
||||
try {
|
||||
// メールアドレス存在チェック(いずれか必須)
|
||||
// 1. メールアドレスと予備メールアドレスのいずれか必須チェック
|
||||
// 両方とも空の場合は、それぞれ別エラーとして追加
|
||||
if (empty($mailAddress) && empty($backupMailAddress)) {
|
||||
$errors[] = "パラメーターNG:メールアドレス/<空>";
|
||||
$errors[] = "パラメーターNG:予備メールアドレス/<空>";
|
||||
} else {
|
||||
// いずれかに値がある場合は、形式チェックを実施
|
||||
// 2. メールアドレス形式チェック(値がある場合のみ)
|
||||
if (!empty($mailAddress) && !filter_var($mailAddress, FILTER_VALIDATE_EMAIL)) {
|
||||
$errors[] = "パラメーターNG:メールアドレス/{$mailAddress}";
|
||||
}
|
||||
|
||||
// 3. 予備メールアドレス形式チェック(値がある場合のみ)
|
||||
if (!empty($backupMailAddress) && !filter_var($backupMailAddress, FILTER_VALIDATE_EMAIL)) {
|
||||
$errors[] = "パラメーターNG:予備メールアドレス/{$backupMailAddress}";
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 使用プログラムID(メールテンプレートID)必須チェック
|
||||
if (empty($mailTemplateId) || $mailTemplateId <= 0) {
|
||||
$errors[] = "パラメーターNG:使用プログラムID/{$mailTemplateId}";
|
||||
}
|
||||
|
||||
// エラーがある場合
|
||||
if (!empty($errors)) {
|
||||
// 複数のエラーがある場合は全角カンマ(、)で連結
|
||||
$errorInfo = implode('、', $errors);
|
||||
|
||||
Log::warning('SHJ-7 入力パラメーターチェックNG', [
|
||||
'mail_address' => $mailAddress,
|
||||
'backup_mail_address' => $backupMailAddress,
|
||||
'mail_template_id' => $mailTemplateId,
|
||||
'error_info' => $errorInfo
|
||||
]);
|
||||
|
||||
return [
|
||||
'valid' => false,
|
||||
'message' => 'パラメーターNG: メールアドレスまたは予備メールアドレスのいずれかは必須です'
|
||||
'error_info' => $errorInfo
|
||||
];
|
||||
}
|
||||
|
||||
// メールアドレス形式チェック
|
||||
if (!empty($mailAddress) && !filter_var($mailAddress, FILTER_VALIDATE_EMAIL)) {
|
||||
return [
|
||||
'valid' => false,
|
||||
'message' => 'パラメーターNG: メールアドレスの形式が正しくありません'
|
||||
];
|
||||
}
|
||||
|
||||
if (!empty($backupMailAddress) && !filter_var($backupMailAddress, FILTER_VALIDATE_EMAIL)) {
|
||||
return [
|
||||
'valid' => false,
|
||||
'message' => 'パラメーターNG: 予備メールアドレスの形式が正しくありません'
|
||||
];
|
||||
}
|
||||
|
||||
// メールテンプレートID形式チェック
|
||||
if ($mailTemplateId <= 0) {
|
||||
return [
|
||||
'valid' => false,
|
||||
'message' => 'パラメーターNG: メールテンプレートIDは正の整数である必要があります'
|
||||
];
|
||||
}
|
||||
|
||||
Log::info('入力パラメーターチェック完了', [
|
||||
// 正常終了
|
||||
Log::info('SHJ-7 入力パラメーターチェックOK', [
|
||||
'mail_address' => $mailAddress,
|
||||
'backup_mail_address' => $backupMailAddress,
|
||||
'mail_template_id' => $mailTemplateId
|
||||
@ -221,63 +210,66 @@ class ShjMailSendService
|
||||
|
||||
return [
|
||||
'valid' => true,
|
||||
'message' => 'パラメーターチェックOK'
|
||||
'error_info' => ''
|
||||
];
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('入力パラメーターチェックエラー', [
|
||||
'error' => $e->getMessage()
|
||||
$errorInfo = 'パラメーターチェック中にエラーが発生:' . $e->getMessage();
|
||||
|
||||
Log::error('SHJ-7 入力パラメーターチェック例外エラー', [
|
||||
'error' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString()
|
||||
]);
|
||||
|
||||
return [
|
||||
'valid' => false,
|
||||
'message' => 'パラメーターチェック中にエラーが発生しました: ' . $e->getMessage()
|
||||
'error_info' => $errorInfo
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 【処理2】メール送信テンプレート情報を取得する
|
||||
*
|
||||
* 仕様書に基づくSQLクエリ:
|
||||
*
|
||||
* SHJ-7仕様書に基づくSQLクエリ:
|
||||
* SELECT エリアマネージャー同報, bccアドレス, 件名, 本文
|
||||
* FROM メール送信テンプレート
|
||||
* WHERE 使用プログラムID = 入力パラメーター使用プログラムID
|
||||
* AND 使用フラグ = 1
|
||||
* WHERE 使用プログラムID = 入力パラメーター.使用プログラムID
|
||||
* AND 使用フラグ = 1
|
||||
*
|
||||
* @param int $mailTemplateId メールテンプレートID(使用プログラムIDとして扱う)
|
||||
* @param int $mailTemplateId メールテンプレートID(使用プログラムID)
|
||||
* @return MailTemplate|null メールテンプレート情報
|
||||
*/
|
||||
private function getMailTemplateInfo(int $mailTemplateId): ?MailTemplate
|
||||
{
|
||||
try {
|
||||
// 仕様書に記載されたSQLクエリに基づくメールテンプレート情報取得
|
||||
// 注意: 仕様書では「使用プログラムID」を条件にしているが、
|
||||
// 入力パラメーターは「メールテンプレートID」なので、pg_idで検索
|
||||
// SHJ-7仕様: 使用プログラムID(pg_id)で検索、使用フラグ=1
|
||||
$templateInfo = $this->mailTemplateModel::where('pg_id', $mailTemplateId)
|
||||
->where('use_flag', 1)
|
||||
->first();
|
||||
|
||||
if ($templateInfo) {
|
||||
Log::info('メールテンプレート情報取得完了', [
|
||||
Log::info('SHJ-7 メールテンプレート情報取得完了', [
|
||||
'mail_template_id' => $mailTemplateId,
|
||||
'template_found' => true,
|
||||
'subject' => $templateInfo->getSubject()
|
||||
'subject' => $templateInfo->getSubject(),
|
||||
'mgr_cc_flag' => $templateInfo->isManagerCcEnabled(),
|
||||
'has_bcc' => !empty($templateInfo->getBccAddress())
|
||||
]);
|
||||
} else {
|
||||
Log::warning('メールテンプレート情報取得結果', [
|
||||
Log::warning('SHJ-7 メールテンプレート情報取得結果0件', [
|
||||
'mail_template_id' => $mailTemplateId,
|
||||
'template_found' => false,
|
||||
'message' => 'テンプレートが見つかりません'
|
||||
'template_found' => false
|
||||
]);
|
||||
}
|
||||
|
||||
return $templateInfo;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('メールテンプレート情報取得エラー', [
|
||||
Log::error('SHJ-7 メールテンプレート情報取得エラー', [
|
||||
'mail_template_id' => $mailTemplateId,
|
||||
'error' => $e->getMessage()
|
||||
'error' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString()
|
||||
]);
|
||||
|
||||
throw $e;
|
||||
@ -286,92 +278,95 @@ class ShjMailSendService
|
||||
|
||||
/**
|
||||
* 【処理3】メールを送信する
|
||||
*
|
||||
* 仕様書に基づくmb_send_mail関数使用:
|
||||
* - 送信者: 処理2で取得したメールアドレス(処理1で予備メールアドレス)
|
||||
* - タイトル: 処理2で取得したタイトル
|
||||
* - 本文: 処理2で取得した本文(※現在の文字列は「So-Manager一般的なWebサイト内部処理」参照)
|
||||
* - 追加ヘッダ: 処理2で取得したbccアドレス(※値が設定されている場合のみ)
|
||||
*
|
||||
* SHJ-7仕様書に基づくmb_send_mail関数使用:
|
||||
* - 送信先: 入力パラメーター.メールアドレス(空なら予備メールアドレス)
|
||||
* - タイトル: 処理2.件名
|
||||
* - 本文: 処理2.本文
|
||||
* - 追加ヘッダ: 処理2.bccアドレス(※値が設定されている場合のみ)
|
||||
*
|
||||
* ※待ち時間: 仕様では「一定の待ち時間を設ける」とあるが、現時点では実装しない(0秒)
|
||||
*
|
||||
* @param string $mailAddress メールアドレス
|
||||
* @param string $backupMailAddress 予備メールアドレス
|
||||
* @param MailTemplate $templateInfo テンプレート情報
|
||||
* @return array 送信結果
|
||||
* @return array 送信結果 ['success' => bool, 'error_info' => string, 'to_address' => string]
|
||||
*/
|
||||
private function sendMail(string $mailAddress, string $backupMailAddress, MailTemplate $templateInfo): array
|
||||
{
|
||||
try {
|
||||
// 送信先アドレス決定(優先: メールアドレス、代替: 予備メールアドレス)
|
||||
$toAddress = !empty($mailAddress) ? $mailAddress : $backupMailAddress;
|
||||
|
||||
// メール内容取得
|
||||
|
||||
// 処理2で取得したメール内容を取得
|
||||
$subject = $templateInfo->getSubject() ?? '';
|
||||
$message = $templateInfo->getText() ?? '';
|
||||
|
||||
// 追加ヘッダ設定
|
||||
|
||||
// 追加ヘッダ設定(BCC、From等)
|
||||
$headers = $this->buildMailHeaders($templateInfo);
|
||||
|
||||
Log::info('メール送信準備完了', [
|
||||
|
||||
Log::info('SHJ-7 メール送信準備完了', [
|
||||
'to_address' => $toAddress,
|
||||
'subject' => $subject,
|
||||
'has_bcc' => !empty($templateInfo->getBccAddress()),
|
||||
'manager_cc_enabled' => $templateInfo->isManagerCcEnabled()
|
||||
'mgr_cc_flag' => $templateInfo->isManagerCcEnabled()
|
||||
]);
|
||||
|
||||
// mb_send_mail関数を使用してメール送信
|
||||
$sendResult = mb_send_mail(
|
||||
$toAddress, // 送信先
|
||||
$subject, // 件名
|
||||
$subject, // 件名(タイトル)
|
||||
$message, // 本文
|
||||
$headers // 追加ヘッダ
|
||||
);
|
||||
|
||||
if ($sendResult) {
|
||||
Log::info('メール送信成功', [
|
||||
Log::info('SHJ-7 メール送信成功', [
|
||||
'to_address' => $toAddress,
|
||||
'subject' => $subject
|
||||
]);
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'message' => 'メール送信が正常に完了しました',
|
||||
'to_address' => $toAddress,
|
||||
'subject' => $subject
|
||||
'error_info' => '',
|
||||
'to_address' => $toAddress
|
||||
];
|
||||
} else {
|
||||
$errorMessage = 'mb_send_mail関数でメール送信に失敗しました';
|
||||
Log::error('メール送信失敗', [
|
||||
// mb_send_mail がfalseを返した場合
|
||||
$errorInfo = 'メール送信NG:mb_send_mail関数がfalseを返しました';
|
||||
Log::error('SHJ-7 メール送信失敗', [
|
||||
'to_address' => $toAddress,
|
||||
'subject' => $subject,
|
||||
'error' => $errorMessage
|
||||
'error_info' => $errorInfo
|
||||
]);
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => $errorMessage
|
||||
'error_info' => $errorInfo
|
||||
];
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$errorMessage = 'メール送信中にエラーが発生: ' . $e->getMessage();
|
||||
Log::error('メール送信エラー', [
|
||||
$errorInfo = 'メール送信NG:' . $e->getMessage();
|
||||
Log::error('SHJ-7 メール送信例外エラー', [
|
||||
'error' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString()
|
||||
]);
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => $errorMessage
|
||||
'error_info' => $errorInfo
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* メールヘッダを構築
|
||||
*
|
||||
* 仕様書に基づく設定:
|
||||
* - BCCアドレス: 値が設定されている場合のみ追加
|
||||
* - エリアマネージャー同報: フラグが有効な場合の処理
|
||||
*
|
||||
* SHJ-7仕様書に基づく追加ヘッダ設定:
|
||||
* - 追加ヘッダ: 処理2.bccアドレス(※値が設定されている場合のみ)
|
||||
* - From: システム設定から取得
|
||||
* - エリアマネージャー同報: フラグが有効な場合はログ出力のみ(実装保留)
|
||||
*
|
||||
* @param MailTemplate $templateInfo テンプレート情報
|
||||
* @return string メールヘッダ
|
||||
@ -380,19 +375,19 @@ class ShjMailSendService
|
||||
{
|
||||
$headers = [];
|
||||
|
||||
// BCCアドレス設定(値が設定されている場合のみ)
|
||||
// BCCアドレス設定(値が設定されている場合のみ追加)
|
||||
$bccAddress = $templateInfo->getBccAddress();
|
||||
if (!empty($bccAddress)) {
|
||||
$headers[] = "Bcc: {$bccAddress}";
|
||||
}
|
||||
|
||||
// エリアマネージャー同報フラグが有効な場合
|
||||
// ※具体的な処理内容は仕様書に詳細がないため、ログ出力のみ
|
||||
// ※SHJ-7では実装しない(仕様詳細不明)。ログ出力のみ。
|
||||
if ($templateInfo->isManagerCcEnabled()) {
|
||||
Log::info('エリアマネージャー同報フラグが有効です', [
|
||||
Log::info('SHJ-7 エリアマネージャー同報フラグが有効', [
|
||||
'mail_template_id' => $templateInfo->mail_template_id
|
||||
]);
|
||||
// 実際のエリアマネージャーアドレス取得・設定処理は追加仕様が必要
|
||||
// 実際のエリアマネージャーアドレス取得・設定処理は将来実装
|
||||
}
|
||||
|
||||
// From設定(システム設定から取得)
|
||||
@ -405,41 +400,6 @@ class ShjMailSendService
|
||||
return implode("\r\n", $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* バッチログ作成
|
||||
*
|
||||
* @param string $processName プロセス名
|
||||
* @param string $status ステータス
|
||||
* @param array $params パラメータ
|
||||
* @return int バッチログID
|
||||
*/
|
||||
private function createBatchLog(string $processName, string $status, array $params = []): int
|
||||
{
|
||||
return $this->batchLogModel->create([
|
||||
'process_name' => $processName,
|
||||
'status' => $status,
|
||||
'start_time' => now(),
|
||||
'parameters' => json_encode($params),
|
||||
'message' => 'バッチ処理開始'
|
||||
])->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* バッチログ更新
|
||||
*
|
||||
* @param int $batchLogId バッチログID
|
||||
* @param string $status ステータス
|
||||
* @param string $message メッセージ
|
||||
* @return void
|
||||
*/
|
||||
private function updateBatchLog(int $batchLogId, string $status, string $message): void
|
||||
{
|
||||
$this->batchLogModel->where('id', $batchLogId)->update([
|
||||
'status' => $status,
|
||||
'end_time' => now(),
|
||||
'message' => $message
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* SHJ-12 未払い者通知メール送信
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -7,9 +7,11 @@ use App\Models\Usertype;
|
||||
use App\Models\Park;
|
||||
use App\Models\RegularContract;
|
||||
use App\Models\OperatorQue;
|
||||
use App\Models\Device;
|
||||
use App\Services\GoogleVisionService;
|
||||
use App\Services\GoogleMapsService;
|
||||
use App\Services\ShjMailSendService;
|
||||
use App\Services\ShjEightService;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
@ -22,15 +24,18 @@ class ShjOneService
|
||||
protected $googleVisionService;
|
||||
protected $googleMapsService;
|
||||
protected $mailSendService;
|
||||
protected $shjEightService;
|
||||
|
||||
public function __construct(
|
||||
GoogleVisionService $googleVisionService,
|
||||
GoogleMapsService $googleMapsService,
|
||||
ShjMailSendService $mailSendService
|
||||
ShjMailSendService $mailSendService,
|
||||
ShjEightService $shjEightService
|
||||
) {
|
||||
$this->googleVisionService = $googleVisionService;
|
||||
$this->googleMapsService = $googleMapsService;
|
||||
$this->mailSendService = $mailSendService;
|
||||
$this->shjEightService = $shjEightService;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -55,11 +60,13 @@ class ShjOneService
|
||||
'user_id' => $userId,
|
||||
'park_id' => $parkId
|
||||
]);
|
||||
return [
|
||||
$result = [
|
||||
'system_success' => false,
|
||||
'message' => '利用者が見つかりません',
|
||||
'stats' => ['error_count' => 1, 'processed_count' => 0]
|
||||
];
|
||||
$this->createBatchLog($userId, null, null, $result);
|
||||
return $result;
|
||||
}
|
||||
|
||||
Log::info('SHJ-1 【処理1】成功: 利用者データ取得', [
|
||||
@ -79,11 +86,13 @@ class ShjOneService
|
||||
'user_idcard_chk_flag' => $user->user_idcard_chk_flag,
|
||||
'reason' => '免許証以外または写真なしまたは既に処理済み'
|
||||
]);
|
||||
return [
|
||||
$result = [
|
||||
'system_success' => false,
|
||||
'message' => '処理対象外の利用者です(免許証以外または写真なし)',
|
||||
'stats' => ['error_count' => 1, 'processed_count' => 0]
|
||||
];
|
||||
$this->createBatchLog($userId, $user->user_name, null, $result);
|
||||
return $result;
|
||||
}
|
||||
|
||||
$park = $this->getParkRecord($parkId);
|
||||
@ -91,11 +100,13 @@ class ShjOneService
|
||||
Log::error('SHJ-1 駐輪場データ取得失敗', [
|
||||
'park_id' => $parkId
|
||||
]);
|
||||
return [
|
||||
$result = [
|
||||
'system_success' => false,
|
||||
'message' => '駐輪場が見つかりません',
|
||||
'stats' => ['error_count' => 1, 'processed_count' => 0]
|
||||
];
|
||||
$this->createBatchLog($userId, $user->user_name, null, $result);
|
||||
return $result;
|
||||
}
|
||||
|
||||
Log::info('SHJ-1 駐輪場データ取得成功', [
|
||||
@ -119,6 +130,7 @@ class ShjOneService
|
||||
]);
|
||||
$result = $this->processNonTargetUser($user, $categoryCheck['category_name']);
|
||||
DB::commit(); // 対象外処理後はコミット
|
||||
$this->createBatchLog($userId, $user->user_name, null, $result);
|
||||
return $result;
|
||||
}
|
||||
|
||||
@ -130,9 +142,12 @@ class ShjOneService
|
||||
// 【処理2】本人確認自動処理+800Mチェック処理
|
||||
Log::info('SHJ-1 【処理2】開始: 本人確認自動処理');
|
||||
$identityResult = $this->processIdentityVerification($user, $park);
|
||||
|
||||
|
||||
DB::commit();
|
||||
|
||||
|
||||
// バッチ処理ログ作成
|
||||
$this->createBatchLog($userId, $user->user_name, $identityResult['similarity_rate'] ?? null, $identityResult);
|
||||
|
||||
return $identityResult;
|
||||
|
||||
} catch (Exception $e) {
|
||||
@ -142,12 +157,17 @@ class ShjOneService
|
||||
'park_id' => $parkId,
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
|
||||
return [
|
||||
|
||||
$result = [
|
||||
'system_success' => false,
|
||||
'message' => 'システムエラーが発生しました: ' . $e->getMessage(),
|
||||
'stats' => ['error_count' => 1, 'processed_count' => 0]
|
||||
];
|
||||
|
||||
// エラー時もバッチログ作成
|
||||
$this->createBatchLog($userId, null, null, $result);
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
@ -803,6 +823,7 @@ class ShjOneService
|
||||
'system_success' => true,
|
||||
'identity_result' => 'OK',
|
||||
'message' => '本人確認自動処理が成功しました',
|
||||
'similarity_rate' => $ocrResult['similarity'] ?? 0,
|
||||
'details' => [
|
||||
'user_id' => $user->user_seq,
|
||||
'park_id' => $park->park_id,
|
||||
@ -856,6 +877,7 @@ class ShjOneService
|
||||
'system_success' => true,
|
||||
'identity_result' => 'NG',
|
||||
'message' => '本人確認自動処理NGのため手動処理キューを作成しました',
|
||||
'similarity_rate' => $ocrResult['similarity'] ?? 0,
|
||||
'details' => [
|
||||
'user_id' => $user->user_seq,
|
||||
'park_id' => $park->park_id,
|
||||
@ -914,13 +936,29 @@ class ShjOneService
|
||||
private function sendSuccessEmail(User $user, Park $park): void
|
||||
{
|
||||
try {
|
||||
$this->mailSendService->executeMailSend(
|
||||
// SHJ-7 メール送信処理
|
||||
$mailResult = $this->mailSendService->executeMailSend(
|
||||
$user->user_primemail,
|
||||
$user->user_submail,
|
||||
config('shj1.mail.program_id_success')
|
||||
);
|
||||
|
||||
// SHJ-7仕様準拠: result === 0 が正常、それ以外は異常
|
||||
if (($mailResult['result'] ?? 1) === 0) {
|
||||
Log::info('SHJ-1 成功メール送信成功', [
|
||||
'user_id' => $user->user_seq,
|
||||
'email' => $user->user_primemail
|
||||
]);
|
||||
} else {
|
||||
// 仕様準拠: error_info をログに記録
|
||||
Log::error('SHJ-1 成功メール送信失敗', [
|
||||
'user_id' => $user->user_seq,
|
||||
'email' => $user->user_primemail,
|
||||
'error_info' => $mailResult['error_info'] ?? 'メール送信失敗'
|
||||
]);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
Log::error('Success email sending failed', [
|
||||
Log::error('SHJ-1 成功メール送信例外エラー', [
|
||||
'user_id' => $user->user_seq,
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
@ -933,13 +971,29 @@ class ShjOneService
|
||||
private function sendFailureEmail(User $user, Park $park): void
|
||||
{
|
||||
try {
|
||||
$this->mailSendService->executeMailSend(
|
||||
// SHJ-7 メール送信処理
|
||||
$mailResult = $this->mailSendService->executeMailSend(
|
||||
$user->user_primemail,
|
||||
$user->user_submail,
|
||||
config('shj1.mail.program_id_failure')
|
||||
);
|
||||
|
||||
// SHJ-7仕様準拠: result === 0 が正常、それ以外は異常
|
||||
if (($mailResult['result'] ?? 1) === 0) {
|
||||
Log::info('SHJ-1 失敗メール送信成功', [
|
||||
'user_id' => $user->user_seq,
|
||||
'email' => $user->user_primemail
|
||||
]);
|
||||
} else {
|
||||
// 仕様準拠: error_info をログに記録
|
||||
Log::error('SHJ-1 失敗メール送信失敗', [
|
||||
'user_id' => $user->user_seq,
|
||||
'email' => $user->user_primemail,
|
||||
'error_info' => $mailResult['error_info'] ?? 'メール送信失敗'
|
||||
]);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
Log::error('Failure email sending failed', [
|
||||
Log::error('SHJ-1 失敗メール送信例外エラー', [
|
||||
'user_id' => $user->user_seq,
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
@ -971,14 +1025,14 @@ class ShjOneService
|
||||
{
|
||||
$expectedChars = mb_str_split($expected, 1, 'UTF-8');
|
||||
$normalizedOcr = $this->normalizeForAnalysis($ocrText);
|
||||
|
||||
|
||||
$analysis = [
|
||||
'total_chars' => count($expectedChars),
|
||||
'matched_chars' => 0,
|
||||
'missing_chars' => [],
|
||||
'match_rate' => 0
|
||||
];
|
||||
|
||||
|
||||
foreach ($expectedChars as $char) {
|
||||
if (mb_strpos($normalizedOcr, $char, 0, 'UTF-8') !== false) {
|
||||
$analysis['matched_chars']++;
|
||||
@ -986,10 +1040,63 @@ class ShjOneService
|
||||
$analysis['missing_chars'][] = $char;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$analysis['match_rate'] = round(($analysis['matched_chars'] / $analysis['total_chars']) * 100, 2);
|
||||
|
||||
|
||||
return $analysis;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* バッチ処理ログ作成
|
||||
*
|
||||
* SHJ-8サービスを呼び出してbat_job_logテーブルに登録
|
||||
*
|
||||
* @param int $userId 利用者連番
|
||||
* @param string|null $userName 利用者名
|
||||
* @param float|null $similarityRate 類似度
|
||||
* @param array $result 処理結果
|
||||
* @return void
|
||||
*/
|
||||
private function createBatchLog(int $userId, ?string $userName, ?float $similarityRate, array $result): void
|
||||
{
|
||||
try {
|
||||
$device = Device::orderBy('device_id')->first();
|
||||
$deviceId = $device ? $device->device_id : 1;
|
||||
$today = now()->format('Y/m/d');
|
||||
|
||||
// ステータス判定
|
||||
$status = $result['system_success'] ? 'success' : 'error';
|
||||
|
||||
// ステータスコメント生成: {user_id}/{user_name}/{similarity_rate}%
|
||||
$displayUserId = $userId;
|
||||
$displayUserName = $userName ?? '不明';
|
||||
$displaySimilarity = $similarityRate !== null ? number_format($similarityRate, 1) : '0.0';
|
||||
|
||||
$statusComment = "{$displayUserId}/{$displayUserName}/{$displaySimilarity}%";
|
||||
|
||||
// SHJ-8サービス呼び出し
|
||||
$this->shjEightService->execute(
|
||||
$deviceId,
|
||||
'SHJ-1',
|
||||
'SHJ-1本人確認自動処理',
|
||||
$status,
|
||||
$statusComment,
|
||||
$today,
|
||||
$today
|
||||
);
|
||||
|
||||
Log::info('SHJ-1 バッチ処理ログ作成完了', [
|
||||
'user_id' => $userId,
|
||||
'status' => $status,
|
||||
'status_comment' => $statusComment
|
||||
]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
Log::error('SHJ-1 バッチ処理ログ作成エラー', [
|
||||
'error' => $e->getMessage(),
|
||||
'user_id' => $userId
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
385
app/Services/ShjThirteenService.php
Normal file
385
app/Services/ShjThirteenService.php
Normal file
@ -0,0 +1,385 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Models\Device;
|
||||
use Carbon\Carbon;
|
||||
|
||||
/**
|
||||
* SHJ-13 契約台数追加処理サービス
|
||||
*
|
||||
* 新規契約時の契約台数を park_number・zone テーブルに反映する処理
|
||||
* SHJ-4B の副作用処理として実行される
|
||||
*/
|
||||
class ShjThirteenService
|
||||
{
|
||||
/**
|
||||
* ShjEightService
|
||||
*
|
||||
* @var ShjEightService
|
||||
*/
|
||||
protected $shjEightService;
|
||||
|
||||
/**
|
||||
* コンストラクタ
|
||||
*
|
||||
* @param ShjEightService $shjEightService
|
||||
*/
|
||||
public function __construct(ShjEightService $shjEightService)
|
||||
{
|
||||
$this->shjEightService = $shjEightService;
|
||||
}
|
||||
/**
|
||||
* SHJ-13 契約台数追加処理実行
|
||||
*
|
||||
* 【処理1】契約台数を反映する - park_number・zone テーブルの契約台数を+1更新
|
||||
* 【処理2】バッチ処理ログを作成する - SHJ-8共通仕様でログ登録
|
||||
*
|
||||
* @param array $contractData 契約データ
|
||||
* @return array 処理結果
|
||||
*/
|
||||
public function execute(array $contractData): array
|
||||
{
|
||||
$startTime = now();
|
||||
|
||||
Log::info('SHJ-13 契約台数追加処理開始', [
|
||||
'contract_id' => $contractData['contract_id'] ?? null,
|
||||
'park_id' => $contractData['park_id'] ?? null,
|
||||
'psection_id' => $contractData['psection_id'] ?? null,
|
||||
'ptype_id' => $contractData['ptype_id'] ?? null,
|
||||
'zone_id' => $contractData['zone_id'] ?? null,
|
||||
]);
|
||||
|
||||
try {
|
||||
// パラメータ検証
|
||||
$validationResult = $this->validateParameters($contractData);
|
||||
if (!$validationResult['valid']) {
|
||||
return $this->createErrorResult(
|
||||
1001,
|
||||
'パラメータエラー: ' . $validationResult['message']
|
||||
);
|
||||
}
|
||||
|
||||
// 【処理1・2】契約台数反映とバッチログ作成を一体で実行
|
||||
$processResult = $this->executeProcessWithLogging($contractData);
|
||||
if (!$processResult['success']) {
|
||||
return $this->createErrorResult(
|
||||
$processResult['error_code'],
|
||||
$processResult['error_message'],
|
||||
$processResult['stack_trace'] ?? ''
|
||||
);
|
||||
}
|
||||
|
||||
$statusComment = $processResult['status_comment'];
|
||||
|
||||
$endTime = now();
|
||||
Log::info('SHJ-13 契約台数追加処理完了', [
|
||||
'contract_id' => $contractData['contract_id'],
|
||||
'execution_time' => $startTime->diffInSeconds($endTime),
|
||||
'updated_count' => $processResult['updated_count'],
|
||||
'status_comment' => $statusComment,
|
||||
]);
|
||||
|
||||
return ['result' => 0];
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('SHJ-13 契約台数追加処理例外エラー', [
|
||||
'contract_data' => $contractData,
|
||||
'error' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString(),
|
||||
]);
|
||||
|
||||
return $this->createErrorResult(
|
||||
$e->getCode() ?: 1999,
|
||||
$e->getMessage(),
|
||||
$e->getTraceAsString()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* パラメータ検証
|
||||
*
|
||||
* @param array $contractData
|
||||
* @return array
|
||||
*/
|
||||
private function validateParameters(array $contractData): array
|
||||
{
|
||||
$errors = [];
|
||||
|
||||
if (empty($contractData['park_id'])) {
|
||||
$errors[] = '駐輪場IDが設定されていません';
|
||||
}
|
||||
|
||||
if (empty($contractData['psection_id'])) {
|
||||
$errors[] = '車種区分IDが設定されていません';
|
||||
}
|
||||
|
||||
if (empty($contractData['ptype_id'])) {
|
||||
$errors[] = '駐輪分類IDが設定されていません';
|
||||
}
|
||||
|
||||
if (empty($contractData['zone_id'])) {
|
||||
$errors[] = 'ゾーンIDが設定されていません';
|
||||
}
|
||||
|
||||
if (!empty($errors)) {
|
||||
return [
|
||||
'valid' => false,
|
||||
'message' => implode(', ', $errors),
|
||||
'details' => $errors,
|
||||
];
|
||||
}
|
||||
|
||||
return ['valid' => true];
|
||||
}
|
||||
|
||||
/**
|
||||
* 契約台数反映とバッチログ作成の一体処理
|
||||
*
|
||||
* park_number・zone テーブルの契約台数を+1更新し、バッチログを作成
|
||||
* 全てを1つのトランザクション内で実行
|
||||
*
|
||||
* @param array $contractData
|
||||
* @return array
|
||||
*/
|
||||
private function executeProcessWithLogging(array $contractData): array
|
||||
{
|
||||
try {
|
||||
return DB::transaction(function() use ($contractData) {
|
||||
// 各テーブルの名称取得
|
||||
$names = $this->getTableNames($contractData);
|
||||
if (!$names['success']) {
|
||||
throw new \Exception('名称取得エラー: ' . $names['message'], 1002);
|
||||
}
|
||||
|
||||
// park_number テーブル更新
|
||||
$parkNumberUpdated = DB::table('park_number')
|
||||
->where('park_id', $contractData['park_id'])
|
||||
->where('psection_id', $contractData['psection_id'])
|
||||
->where('ptype_id', $contractData['ptype_id'])
|
||||
->increment('park_number', 1, [
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
if ($parkNumberUpdated === 0) {
|
||||
throw new \Exception('park_numberテーブルの対象レコードが存在しません', 1011);
|
||||
}
|
||||
|
||||
// zone テーブル更新
|
||||
$zoneUpdated = DB::table('zone')
|
||||
->where('zone_id', $contractData['zone_id'])
|
||||
->increment('zone_number', 1, [
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
if ($zoneUpdated === 0) {
|
||||
throw new \Exception('zoneテーブルの対象レコードが存在しません', 1012);
|
||||
}
|
||||
|
||||
// 更新後の契約台数取得
|
||||
$updatedZone = DB::table('zone')
|
||||
->where('zone_id', $contractData['zone_id'])
|
||||
->first(['zone_number']);
|
||||
|
||||
// ステータスコメント構築
|
||||
$statusComment = $this->buildStatusComment($names['names'], $updatedZone->zone_number);
|
||||
|
||||
// バッチ処理ログ作成(同一トランザクション内)
|
||||
// SHJ-8サービスを呼び出し
|
||||
$device = Device::orderBy('device_id')->first();
|
||||
$deviceId = $device ? $device->device_id : 1;
|
||||
$today = now()->format('Y/m/d');
|
||||
|
||||
$this->shjEightService->execute(
|
||||
$deviceId,
|
||||
'SHJ-13',
|
||||
'SHJ-13契約台数追加',
|
||||
'success',
|
||||
$statusComment,
|
||||
$today,
|
||||
$today
|
||||
);
|
||||
|
||||
Log::info('SHJ-13 契約台数更新・ログ作成完了', [
|
||||
'contract_id' => $contractData['contract_id'],
|
||||
'park_number_updated' => $parkNumberUpdated,
|
||||
'zone_updated' => $zoneUpdated,
|
||||
'updated_count' => $updatedZone->zone_number,
|
||||
'status_comment' => $statusComment,
|
||||
]);
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'updated_count' => $updatedZone->zone_number,
|
||||
'status_comment' => $statusComment,
|
||||
];
|
||||
});
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('SHJ-13 契約台数更新・ログ作成エラー', [
|
||||
'contract_data' => $contractData,
|
||||
'error_code' => $e->getCode(),
|
||||
'error' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString(),
|
||||
]);
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'error_code' => $e->getCode() ?: 1010,
|
||||
'error_message' => $e->getMessage(),
|
||||
'stack_trace' => $e->getTraceAsString(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* テーブル名称取得
|
||||
*
|
||||
* @param array $contractData
|
||||
* @return array
|
||||
*/
|
||||
private function getTableNames(array $contractData): array
|
||||
{
|
||||
try {
|
||||
// 駐輪場名取得
|
||||
$park = DB::table('park')
|
||||
->where('park_id', $contractData['park_id'])
|
||||
->first(['park_name']);
|
||||
|
||||
if (!$park) {
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => "駐輪場が見つかりません: park_id={$contractData['park_id']}",
|
||||
];
|
||||
}
|
||||
|
||||
// 駐輪分類名取得
|
||||
$ptype = DB::table('ptype')
|
||||
->where('ptype_id', $contractData['ptype_id'])
|
||||
->first(['ptype_subject']);
|
||||
|
||||
if (!$ptype) {
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => "駐輪分類が見つかりません: ptype_id={$contractData['ptype_id']}",
|
||||
];
|
||||
}
|
||||
|
||||
// 車種区分名取得
|
||||
$psection = DB::table('psection')
|
||||
->where('psection_id', $contractData['psection_id'])
|
||||
->first(['psection_subject']);
|
||||
|
||||
if (!$psection) {
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => "車種区分が見つかりません: psection_id={$contractData['psection_id']}",
|
||||
];
|
||||
}
|
||||
|
||||
// ゾーン名取得
|
||||
$zone = DB::table('zone')
|
||||
->where('zone_id', $contractData['zone_id'])
|
||||
->first(['zone_name']);
|
||||
|
||||
if (!$zone) {
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => "ゾーンが見つかりません: zone_id={$contractData['zone_id']}",
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'names' => [
|
||||
'park_name' => $park->park_name,
|
||||
'ptype_subject' => $ptype->ptype_subject,
|
||||
'psection_subject' => $psection->psection_subject,
|
||||
'zone_name' => $zone->zone_name,
|
||||
],
|
||||
];
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => 'テーブル名称取得エラー: ' . $e->getMessage(),
|
||||
'details' => $e->getTraceAsString(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ステータスコメント構築
|
||||
*
|
||||
* 形式:駐輪場名/駐輪分類名/車種区分名/ゾーン名/現在契約台数(更新後):{数値}/
|
||||
*
|
||||
* @param array $names
|
||||
* @param int $updatedCount
|
||||
* @return string
|
||||
*/
|
||||
private function buildStatusComment(array $names, int $updatedCount): string
|
||||
{
|
||||
return sprintf(
|
||||
'%s/%s/%s/%s/現在契約台数(更新後):%d/',
|
||||
$names['park_name'],
|
||||
$names['ptype_subject'],
|
||||
$names['psection_subject'],
|
||||
$names['zone_name'],
|
||||
$updatedCount
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* エラー結果作成(SHJ-8ログも作成)
|
||||
*
|
||||
* @param int $errorCode
|
||||
* @param string $errorMessage
|
||||
* @param string $stackTrace
|
||||
* @return 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 [
|
||||
'result' => 1,
|
||||
'error_code' => $errorCode,
|
||||
'error_message' => $errorMessage,
|
||||
'stack_trace' => $stackTrace,
|
||||
];
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -4,7 +4,7 @@ namespace App\Services;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Models\Batch\BatchLog;
|
||||
use App\Models\Device;
|
||||
use App\Models\RegularContract;
|
||||
use App\Models\User;
|
||||
use App\Models\Park;
|
||||
@ -25,14 +25,25 @@ class ShjTwelveService
|
||||
*/
|
||||
protected $shjMailSendService;
|
||||
|
||||
/**
|
||||
* ShjEightService
|
||||
*
|
||||
* @var ShjEightService
|
||||
*/
|
||||
protected $shjEightService;
|
||||
|
||||
/**
|
||||
* コンストラクタ
|
||||
*
|
||||
* @param ShjMailSendService $shjMailSendService
|
||||
* @param ShjEightService $shjEightService
|
||||
*/
|
||||
public function __construct(ShjMailSendService $shjMailSendService)
|
||||
{
|
||||
public function __construct(
|
||||
ShjMailSendService $shjMailSendService,
|
||||
ShjEightService $shjEightService
|
||||
) {
|
||||
$this->shjMailSendService = $shjMailSendService;
|
||||
$this->shjEightService = $shjEightService;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -50,19 +61,17 @@ class ShjTwelveService
|
||||
try {
|
||||
$query = DB::table('regular_contract as T1')
|
||||
->select([
|
||||
'T1.contract_id', // 定期契約ID
|
||||
'T2.user_seq', // 利用者ID
|
||||
'T2.user_name', // 利用者名
|
||||
'T2.user_manual_flag', // 手動登録フラグ
|
||||
'T2.user_mail', // メールアドレス
|
||||
'T2.user_mail_sub', // 予備メールアドレス
|
||||
'T2.park_id', // 駐輪場ID (userテーブルから)
|
||||
'T3.park_name', // 駐輪場名
|
||||
'T1.billing_amount' // 請求金額
|
||||
'T1.contract_id', // 定期契約ID
|
||||
'T2.user_seq', // 利用者ID
|
||||
'T2.user_name', // 利用者名
|
||||
'T2.user_manual_regist_flag', // 手動登録フラグ
|
||||
'T2.user_primemail', // メールアドレス
|
||||
'T2.user_submail', // 予備メールアドレス
|
||||
'T1.park_id', // 駐輪場ID (regular_contractテーブルから)
|
||||
'T3.park_name', // 駐輪場名
|
||||
'T1.billing_amount' // 請求金額
|
||||
])
|
||||
->join('user as T2', function($join) {
|
||||
$join->on('T1.user_seq', '=', 'T2.user_seq');
|
||||
})
|
||||
->join('user as T2', 'T1.user_id', '=', 'T2.user_seq')
|
||||
->join('park as T3', 'T1.park_id', '=', 'T3.park_id')
|
||||
->where([
|
||||
['T1.contract_cancel_flag', '=', 0], // 解約フラグ = 0
|
||||
@ -93,53 +102,91 @@ class ShjTwelveService
|
||||
|
||||
/**
|
||||
* 【処理2】未払い者への通知、またはオペレーターキュー追加処理
|
||||
*
|
||||
* 各未払い者に対して以下の処理を実行:
|
||||
* 1. メール通知の実行 (SHJ-7連携)
|
||||
* 2. オペレーターキューへの追加 (opeテーブル)
|
||||
*
|
||||
* 仕様:
|
||||
* - 手動登録フラグ = 0 (Web申込) → SHJ-7メール送信のみ
|
||||
* - 手動登録フラグ ≠ 0 (その他) → オペレーターキュー追加のみ
|
||||
*
|
||||
* @param array $unpaidUsers 未払い者リスト
|
||||
* @return array 処理結果
|
||||
*/
|
||||
public function processUnpaidUserNotifications(array $unpaidUsers): array
|
||||
{
|
||||
$notificationCount = 0;
|
||||
$queueCount = 0;
|
||||
$errors = [];
|
||||
// 内部変数(カウンタ)初期化
|
||||
$mailSuccessCount = 0;
|
||||
$mailErrorCount = 0;
|
||||
$queueSuccessCount = 0;
|
||||
$queueErrorCount = 0;
|
||||
$batchComments = []; // バッチコメント(エラー情報)累積用
|
||||
$processParameters = [];
|
||||
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
|
||||
// 処理1の取得レコード数分繰り返し
|
||||
foreach ($unpaidUsers as $user) {
|
||||
try {
|
||||
// メール通知処理
|
||||
$mailResult = $this->sendNotificationMail($user);
|
||||
if ($mailResult['success']) {
|
||||
$notificationCount++;
|
||||
}
|
||||
// 【判定】手動登録フラグによる分岐
|
||||
if ($user->user_manual_regist_flag == 0) {
|
||||
// Web申込 → SHJ-7メール送信
|
||||
$mailResult = $this->sendNotificationMailViaShj7($user);
|
||||
|
||||
// オペレーターキュー追加処理
|
||||
$queueResult = $this->addToOperatorQueue($user);
|
||||
if ($queueResult['success']) {
|
||||
$queueCount++;
|
||||
}
|
||||
// 処理結果判定: result === 0 → 正常
|
||||
if (($mailResult['result'] ?? 1) === 0) {
|
||||
$mailSuccessCount++;
|
||||
} else {
|
||||
$mailErrorCount++;
|
||||
// バッチコメントにSHJ-7異常情報を設定(後ろに足す)
|
||||
$batchComments[] = sprintf(
|
||||
'SHJ-7メール送信: 契約ID:%s メール送信失敗: %s',
|
||||
$user->contract_id,
|
||||
$mailResult['error_info'] ?? 'Unknown error'
|
||||
);
|
||||
}
|
||||
|
||||
// 処理パラメータ記録
|
||||
$processParameters[] = [
|
||||
'contract_id' => $user->contract_id,
|
||||
'user_seq' => $user->user_seq,
|
||||
'billing_amount' => $user->billing_amount,
|
||||
'mail_sent' => $mailResult['success'],
|
||||
'queue_added' => $queueResult['success']
|
||||
];
|
||||
// 処理パラメータ記録
|
||||
$processParameters[] = [
|
||||
'contract_id' => $user->contract_id,
|
||||
'user_seq' => $user->user_seq,
|
||||
'billing_amount' => $user->billing_amount,
|
||||
'process_type' => 'mail',
|
||||
'result' => ($mailResult['result'] ?? 1) === 0 ? 'success' : 'error'
|
||||
];
|
||||
|
||||
} else {
|
||||
// その他(手動登録)→ オペレーターキュー追加
|
||||
$queueResult = $this->addToOperatorQueue($user);
|
||||
|
||||
if ($queueResult['success']) {
|
||||
$queueSuccessCount++;
|
||||
} else {
|
||||
$queueErrorCount++;
|
||||
// バッチコメントに異常情報を設定(後ろに足す)
|
||||
$batchComments[] = sprintf(
|
||||
'キュー登録: 契約ID:%s キュー登録失敗: %s',
|
||||
$user->contract_id,
|
||||
$queueResult['message'] ?? 'Unknown error'
|
||||
);
|
||||
}
|
||||
|
||||
// 処理パラメータ記録
|
||||
$processParameters[] = [
|
||||
'contract_id' => $user->contract_id,
|
||||
'user_seq' => $user->user_seq,
|
||||
'billing_amount' => $user->billing_amount,
|
||||
'process_type' => 'queue',
|
||||
'result' => $queueResult['success'] ? 'success' : 'error'
|
||||
];
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$errors[] = [
|
||||
'contract_id' => $user->contract_id,
|
||||
'error' => $e->getMessage()
|
||||
];
|
||||
|
||||
// 個別エラーを記録して次の繰り返し処理へ
|
||||
$batchComments[] = sprintf(
|
||||
'契約ID:%s 処理エラー: %s',
|
||||
$user->contract_id,
|
||||
$e->getMessage()
|
||||
);
|
||||
|
||||
Log::warning('SHJ-12 個別処理エラー', [
|
||||
'contract_id' => $user->contract_id,
|
||||
'user_seq' => $user->user_seq,
|
||||
@ -150,18 +197,32 @@ class ShjTwelveService
|
||||
|
||||
DB::commit();
|
||||
|
||||
// ステータスコメント構築
|
||||
$statusComment = $this->buildStatusComment(
|
||||
$mailSuccessCount,
|
||||
$mailErrorCount,
|
||||
$queueSuccessCount,
|
||||
$queueErrorCount
|
||||
);
|
||||
|
||||
// バッチコメント整形(最大100件、超過分は省略)
|
||||
$formattedBatchComments = $this->formatBatchComments($batchComments);
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'notification_count' => $notificationCount,
|
||||
'queue_count' => $queueCount,
|
||||
'mail_success_count' => $mailSuccessCount,
|
||||
'mail_error_count' => $mailErrorCount,
|
||||
'queue_success_count' => $queueSuccessCount,
|
||||
'queue_error_count' => $queueErrorCount,
|
||||
'status_comment' => $statusComment,
|
||||
'batch_comments' => $formattedBatchComments,
|
||||
'parameters' => $processParameters,
|
||||
'errors' => $errors,
|
||||
'message' => '未払い者通知処理完了'
|
||||
];
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
|
||||
|
||||
Log::error('SHJ-12 通知処理全体エラー', [
|
||||
'error' => $e->getMessage(),
|
||||
'processed_count' => count($processParameters)
|
||||
@ -169,10 +230,13 @@ class ShjTwelveService
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'notification_count' => $notificationCount,
|
||||
'queue_count' => $queueCount,
|
||||
'mail_success_count' => $mailSuccessCount,
|
||||
'mail_error_count' => $mailErrorCount,
|
||||
'queue_success_count' => $queueSuccessCount,
|
||||
'queue_error_count' => $queueErrorCount,
|
||||
'status_comment' => 'システムエラー',
|
||||
'batch_comments' => $batchComments,
|
||||
'parameters' => $processParameters,
|
||||
'errors' => $errors,
|
||||
'message' => '通知処理エラー: ' . $e->getMessage(),
|
||||
'details' => $e->getTraceAsString()
|
||||
];
|
||||
@ -180,118 +244,224 @@ class ShjTwelveService
|
||||
}
|
||||
|
||||
/**
|
||||
* 未払い者へのメール通知送信
|
||||
*
|
||||
* SHJ-7 メール送信サービスを使用してメール通知を実行
|
||||
* SHJ-7 メール送信サービス経由でメール通知送信
|
||||
*
|
||||
* 仕様書パラメータ:
|
||||
* - メールアドレス: 処理1.メールアドレス
|
||||
* - 予備メールアドレス: 処理1.予備メールアドレス
|
||||
* - 使用プログラムID: 204
|
||||
*
|
||||
* @param object $user 未払い者情報
|
||||
* @return array 送信結果
|
||||
* @return array SHJ-7の処理結果 (result_code: 0=正常, 1=異常)
|
||||
*/
|
||||
private function sendNotificationMail($user): array
|
||||
private function sendNotificationMailViaShj7($user): array
|
||||
{
|
||||
try {
|
||||
// メールアドレスの確認
|
||||
$emailAddress = $user->user_mail ?: $user->user_mail_sub;
|
||||
|
||||
if (empty($emailAddress)) {
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => 'メールアドレスが設定されていません'
|
||||
];
|
||||
}
|
||||
// SHJ-7 executeMailSend 呼び出し
|
||||
$result = $this->shjMailSendService->executeMailSend(
|
||||
(string)($user->user_primemail ?? ''), // メールアドレス
|
||||
(string)($user->user_submail ?? ''), // 予備メールアドレス
|
||||
204 // 使用プログラムID
|
||||
);
|
||||
|
||||
// SHJ-7 メール送信サービス呼び出し
|
||||
$mailParams = [
|
||||
'to_email' => $emailAddress,
|
||||
'user_name' => $user->user_name,
|
||||
'park_name' => $user->park_name,
|
||||
'billing_amount' => $user->billing_amount,
|
||||
'contract_id' => $user->contract_id
|
||||
];
|
||||
|
||||
$result = $this->shjMailSendService->sendUnpaidNotificationMail($mailParams);
|
||||
|
||||
Log::info('SHJ-12 メール送信結果', [
|
||||
Log::info('SHJ-12 SHJ-7メール送信結果', [
|
||||
'contract_id' => $user->contract_id,
|
||||
'email' => $emailAddress,
|
||||
'success' => $result['success']
|
||||
'user_seq' => $user->user_seq,
|
||||
'result' => $result['result'] ?? 1,
|
||||
'error_info' => $result['error_info'] ?? ''
|
||||
]);
|
||||
|
||||
return $result;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('SHJ-12 メール送信エラー', [
|
||||
Log::error('SHJ-12 SHJ-7メール送信エラー', [
|
||||
'contract_id' => $user->contract_id,
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => 'メール送信エラー: ' . $e->getMessage()
|
||||
'result' => 1, // 異常終了
|
||||
'error_info' => 'SHJ-7メール送信エラー: ' . $e->getMessage()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* オペレーターキューへの追加
|
||||
*
|
||||
* opeテーブルにオペレーター処理キューとして登録
|
||||
*
|
||||
* 仕様書SQL定義に基づき operator_que テーブルに登録
|
||||
* - キュー種別ID: 8 (支払い催促)
|
||||
* - キューステータスID: 1 (キュー発生)
|
||||
* - que_id: MAX+1方式で生成(db_now.sqlは非AUTO_INCREMENT)
|
||||
* - 主キー衝突時に1回リトライ
|
||||
*
|
||||
* @param object $user 未払い者情報
|
||||
* @return array 追加結果
|
||||
*/
|
||||
private function addToOperatorQueue($user): array
|
||||
{
|
||||
try {
|
||||
$queueData = [
|
||||
'ope_device_id' => null, // デバイスID (未設定)
|
||||
'ope_process_name' => 'SHJ-12', // プロセス名
|
||||
'ope_job_name' => '未払い者通知', // ジョブ名
|
||||
'ope_status' => 'pending', // ステータス
|
||||
'ope_comment' => sprintf(
|
||||
'契約ID:%s ユーザー:%s 金額:%s円',
|
||||
$user->contract_id,
|
||||
$user->user_name,
|
||||
number_format($user->billing_amount)
|
||||
),
|
||||
'ope_target_user_id' => $user->user_seq, // 対象ユーザーID
|
||||
'ope_target_contract_id' => $user->contract_id, // 対象契約ID
|
||||
'ope_billing_amount' => $user->billing_amount, // 請求金額
|
||||
'created_at' => now(),
|
||||
'updated_at' => now()
|
||||
];
|
||||
$maxRetries = 2; // 最大2回試行(初回 + リトライ1回)
|
||||
$lastException = null;
|
||||
|
||||
// opeテーブルに挿入
|
||||
DB::table('ope')->insert($queueData);
|
||||
for ($attempt = 1; $attempt <= $maxRetries; $attempt++) {
|
||||
try {
|
||||
// オペレーターキューデータ構築
|
||||
// 注: que_idはAUTO_INCREMENTのため、DBに委任(手動採番しない)
|
||||
$queueData = [
|
||||
// 'que_id' は削除(AUTO_INCREMENTに委任)
|
||||
'que_class' => 8, // キュー種別ID: 8=支払い催促
|
||||
'user_id' => $user->user_seq, // 利用者ID
|
||||
'contract_id' => $user->contract_id, // 定期契約ID
|
||||
'park_id' => $user->park_id, // 駐輪場ID
|
||||
'que_comment' => '', // キューコメント (空文字)
|
||||
'que_status' => 1, // キューステータスID: 1=キュー発生
|
||||
'que_status_comment' => '', // キューステータスコメント (空文字)
|
||||
'work_instructions' => '', // 業務指示コメント (空文字)
|
||||
'created_at' => now(), // 登録日時
|
||||
'updated_at' => now(), // 更新日時
|
||||
'operator_id' => null // 更新オペレータID (NULL: システム自動)
|
||||
];
|
||||
|
||||
Log::info('SHJ-12 オペレーターキュー追加完了', [
|
||||
'contract_id' => $user->contract_id,
|
||||
'user_seq' => $user->user_seq,
|
||||
'billing_amount' => $user->billing_amount
|
||||
]);
|
||||
// operator_queテーブルに挿入(que_idはDBが自動採番)
|
||||
$newQueId = DB::table('operator_que')->insertGetId($queueData);
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'message' => 'オペレーターキューに追加しました'
|
||||
];
|
||||
Log::info('SHJ-12 オペレーターキュー追加完了', [
|
||||
'que_id' => $newQueId,
|
||||
'contract_id' => $user->contract_id,
|
||||
'user_seq' => $user->user_seq,
|
||||
'park_id' => $user->park_id,
|
||||
'que_class' => 8,
|
||||
'que_status' => 1,
|
||||
'attempt' => $attempt
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('SHJ-12 オペレーターキュー追加エラー', [
|
||||
'contract_id' => $user->contract_id,
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
return [
|
||||
'success' => true,
|
||||
'message' => 'オペレーターキュー追加成功',
|
||||
'que_id' => $newQueId
|
||||
];
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => 'オペレーターキュー追加エラー: ' . $e->getMessage()
|
||||
];
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
$lastException = $e;
|
||||
|
||||
// 主キー重複エラー(Duplicate entry)の場合のみリトライ
|
||||
// SQLSTATEコード 23000 は整合性制約違反を示す
|
||||
if ($e->getCode() == 23000 && $attempt < $maxRetries) {
|
||||
Log::warning('SHJ-12 que_id重複検出、リトライします', [
|
||||
'attempt' => $attempt,
|
||||
'max_retries' => $maxRetries,
|
||||
'que_id' => $newQueId ?? null,
|
||||
'contract_id' => $user->contract_id,
|
||||
'error_code' => $e->getCode()
|
||||
]);
|
||||
|
||||
// 短時間待機後に再試行(100ms)
|
||||
usleep(100000);
|
||||
continue;
|
||||
}
|
||||
|
||||
// その他のエラー、または最終試行での失敗時は例外をスロー
|
||||
throw $e;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
// QueryException以外の例外は即座にスロー
|
||||
$lastException = $e;
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
// ループを抜けた場合(通常は到達しない)
|
||||
Log::error('SHJ-12 オペレーターキュー追加エラー(最大リトライ回数超過)', [
|
||||
'contract_id' => $user->contract_id,
|
||||
'user_seq' => $user->user_seq,
|
||||
'max_retries' => $maxRetries,
|
||||
'error' => $lastException ? $lastException->getMessage() : 'Unknown error',
|
||||
'trace' => $lastException ? $lastException->getTraceAsString() : ''
|
||||
]);
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => 'オペレーターキュー追加エラー(リトライ失敗): ' .
|
||||
($lastException ? $lastException->getMessage() : 'Unknown error')
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* ステータスコメント構築
|
||||
*
|
||||
* 仕様書に基づくステータスコメント形式:
|
||||
* - エラーなし: "メール送信成功:X件 / キュー登録成功:Y件"
|
||||
* - エラーあり: "メール送信成功:X件 / メール送信失敗:A件 / キュー登録成功:Y件 / キュー登録失敗:B件"
|
||||
*
|
||||
* @param int $mailSuccessCount メール正常終了件数
|
||||
* @param int $mailErrorCount メール異常終了件数
|
||||
* @param int $queueSuccessCount キュー登録正常終了件数
|
||||
* @param int $queueErrorCount キュー登録異常終了件数
|
||||
* @return string ステータスコメント
|
||||
*/
|
||||
private function buildStatusComment(
|
||||
int $mailSuccessCount,
|
||||
int $mailErrorCount,
|
||||
int $queueSuccessCount,
|
||||
int $queueErrorCount
|
||||
): string {
|
||||
$parts = [];
|
||||
|
||||
// メール送信結果
|
||||
if ($mailSuccessCount > 0 || $mailErrorCount > 0) {
|
||||
if ($mailErrorCount > 0) {
|
||||
$parts[] = "メール送信成功:{$mailSuccessCount}件";
|
||||
$parts[] = "メール送信失敗:{$mailErrorCount}件";
|
||||
} else {
|
||||
$parts[] = "メール送信成功:{$mailSuccessCount}件";
|
||||
}
|
||||
}
|
||||
|
||||
// キュー登録結果
|
||||
if ($queueSuccessCount > 0 || $queueErrorCount > 0) {
|
||||
if ($queueErrorCount > 0) {
|
||||
$parts[] = "キュー登録成功:{$queueSuccessCount}件";
|
||||
$parts[] = "キュー登録失敗:{$queueErrorCount}件";
|
||||
} else {
|
||||
$parts[] = "キュー登録成功:{$queueSuccessCount}件";
|
||||
}
|
||||
}
|
||||
|
||||
return implode(' / ', $parts);
|
||||
}
|
||||
|
||||
/**
|
||||
* バッチコメント整形
|
||||
*
|
||||
* エラー情報を最大100件に制限し、超過分は省略表記
|
||||
*
|
||||
* @param array $batchComments エラー情報配列
|
||||
* @return string 整形済みバッチコメント
|
||||
*/
|
||||
private function formatBatchComments(array $batchComments): string
|
||||
{
|
||||
if (empty($batchComments)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// 最大100件に制限
|
||||
$limitedComments = array_slice($batchComments, 0, 100);
|
||||
|
||||
// 超過分の件数を追加
|
||||
if (count($batchComments) > 100) {
|
||||
$limitedComments[] = sprintf(
|
||||
'...他%d件省略',
|
||||
count($batchComments) - 100
|
||||
);
|
||||
}
|
||||
|
||||
return implode("\n", $limitedComments);
|
||||
}
|
||||
|
||||
/**
|
||||
* 【処理3】バッチ処理ログを作成する
|
||||
*
|
||||
* 統一BatchLogシステムを使用してSHJ-12の実行ログを記録
|
||||
*
|
||||
* SHJ-8サービスを呼び出してbat_job_logテーブルに登録(業務固有のstatus_comment記録)
|
||||
*
|
||||
* @param string $status ステータス
|
||||
* @param array $parameters パラメータ
|
||||
@ -310,22 +480,40 @@ class ShjTwelveService
|
||||
int $errorCount = 0
|
||||
): void {
|
||||
try {
|
||||
BatchLog::createBatchLog(
|
||||
'SHJ-12',
|
||||
$status,
|
||||
$parameters,
|
||||
// デバイスIDを取得
|
||||
$device = Device::orderBy('device_id')->first();
|
||||
$deviceId = $device ? $device->device_id : 1;
|
||||
|
||||
// status_commentを構築(業務情報を含む)
|
||||
$statusComment = sprintf(
|
||||
'%s (実行:%d/成功:%d/エラー:%d)',
|
||||
$message,
|
||||
[
|
||||
'execution_count' => $executionCount,
|
||||
'success_count' => $successCount,
|
||||
'error_count' => $errorCount,
|
||||
'process_type' => '未払い者通知処理',
|
||||
'executed_at' => now()->toISOString()
|
||||
]
|
||||
$executionCount,
|
||||
$successCount,
|
||||
$errorCount
|
||||
);
|
||||
|
||||
$today = now()->format('Y/m/d');
|
||||
|
||||
Log::info('SHJ-8 バッチ処理ログ作成', [
|
||||
'device_id' => $deviceId,
|
||||
'status' => $status,
|
||||
'status_comment' => $statusComment
|
||||
]);
|
||||
|
||||
// SHJ-8サービスを呼び出し
|
||||
$this->shjEightService->execute(
|
||||
$deviceId,
|
||||
'SHJ-12',
|
||||
'SHJ-12未払い者通知',
|
||||
$status,
|
||||
$statusComment,
|
||||
$today,
|
||||
$today
|
||||
);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('SHJ-12 バッチログ作成エラー', [
|
||||
Log::error('SHJ-8 バッチログ作成エラー', [
|
||||
'error' => $e->getMessage(),
|
||||
'status' => $status,
|
||||
'message' => $message
|
||||
|
||||
@ -8,7 +8,9 @@
|
||||
"require": {
|
||||
"php": "^8.2",
|
||||
"laravel/framework": "^12.0",
|
||||
"laravel/tinker": "^2.10.1"
|
||||
"laravel/tinker": "^2.10.1",
|
||||
"mpdf/mpdf": "^8.2",
|
||||
"simplesoftwareio/simple-qrcode": "^4.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"fakerphp/faker": "^1.23",
|
||||
|
||||
589
composer.lock
generated
589
composer.lock
generated
@ -4,8 +4,62 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "d8f67b824a1bf31c8999ead558d9b485",
|
||||
"content-hash": "571741bd63db78c990a3a07320a20496",
|
||||
"packages": [
|
||||
{
|
||||
"name": "bacon/bacon-qr-code",
|
||||
"version": "2.0.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Bacon/BaconQrCode.git",
|
||||
"reference": "8674e51bb65af933a5ffaf1c308a660387c35c22"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/8674e51bb65af933a5ffaf1c308a660387c35c22",
|
||||
"reference": "8674e51bb65af933a5ffaf1c308a660387c35c22",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"dasprid/enum": "^1.0.3",
|
||||
"ext-iconv": "*",
|
||||
"php": "^7.1 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phly/keep-a-changelog": "^2.1",
|
||||
"phpunit/phpunit": "^7 | ^8 | ^9",
|
||||
"spatie/phpunit-snapshot-assertions": "^4.2.9",
|
||||
"squizlabs/php_codesniffer": "^3.4"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-imagick": "to generate QR code images"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"BaconQrCode\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-2-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Ben Scholzen 'DASPRiD'",
|
||||
"email": "mail@dasprids.de",
|
||||
"homepage": "https://dasprids.de/",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "BaconQrCode is a QR code generator for PHP.",
|
||||
"homepage": "https://github.com/Bacon/BaconQrCode",
|
||||
"support": {
|
||||
"issues": "https://github.com/Bacon/BaconQrCode/issues",
|
||||
"source": "https://github.com/Bacon/BaconQrCode/tree/2.0.8"
|
||||
},
|
||||
"time": "2022-12-07T17:46:57+00:00"
|
||||
},
|
||||
{
|
||||
"name": "brick/math",
|
||||
"version": "0.13.1",
|
||||
@ -135,6 +189,56 @@
|
||||
],
|
||||
"time": "2024-02-09T16:56:22+00:00"
|
||||
},
|
||||
{
|
||||
"name": "dasprid/enum",
|
||||
"version": "1.0.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/DASPRiD/Enum.git",
|
||||
"reference": "b5874fa9ed0043116c72162ec7f4fb50e02e7cce"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/DASPRiD/Enum/zipball/b5874fa9ed0043116c72162ec7f4fb50e02e7cce",
|
||||
"reference": "b5874fa9ed0043116c72162ec7f4fb50e02e7cce",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1 <9.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^7 || ^8 || ^9 || ^10 || ^11",
|
||||
"squizlabs/php_codesniffer": "*"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"DASPRiD\\Enum\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-2-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Ben Scholzen 'DASPRiD'",
|
||||
"email": "mail@dasprids.de",
|
||||
"homepage": "https://dasprids.de/",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "PHP 7.1 enum implementation",
|
||||
"keywords": [
|
||||
"enum",
|
||||
"map"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/DASPRiD/Enum/issues",
|
||||
"source": "https://github.com/DASPRiD/Enum/tree/1.0.7"
|
||||
},
|
||||
"time": "2025-09-16T12:23:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "dflydev/dot-access-data",
|
||||
"version": "v3.0.3",
|
||||
@ -2109,6 +2213,239 @@
|
||||
],
|
||||
"time": "2025-03-24T10:02:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mpdf/mpdf",
|
||||
"version": "v8.2.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mpdf/mpdf.git",
|
||||
"reference": "dd30e3b01061cf8dfe65e7041ab4cc46d8ebdd44"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/mpdf/mpdf/zipball/dd30e3b01061cf8dfe65e7041ab4cc46d8ebdd44",
|
||||
"reference": "dd30e3b01061cf8dfe65e7041ab4cc46d8ebdd44",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-gd": "*",
|
||||
"ext-mbstring": "*",
|
||||
"mpdf/psr-http-message-shim": "^1.0 || ^2.0",
|
||||
"mpdf/psr-log-aware-trait": "^2.0 || ^3.0",
|
||||
"myclabs/deep-copy": "^1.7",
|
||||
"paragonie/random_compat": "^1.4|^2.0|^9.99.99",
|
||||
"php": "^5.6 || ^7.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0",
|
||||
"psr/http-message": "^1.0 || ^2.0",
|
||||
"psr/log": "^1.0 || ^2.0 || ^3.0",
|
||||
"setasign/fpdi": "^2.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^1.3.0",
|
||||
"mpdf/qrcode": "^1.1.0",
|
||||
"squizlabs/php_codesniffer": "^3.5.0",
|
||||
"tracy/tracy": "~2.5",
|
||||
"yoast/phpunit-polyfills": "^1.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-bcmath": "Needed for generation of some types of barcodes",
|
||||
"ext-xml": "Needed mainly for SVG manipulation",
|
||||
"ext-zlib": "Needed for compression of embedded resources, such as fonts"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/functions.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Mpdf\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"GPL-2.0-only"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Matěj Humpál",
|
||||
"role": "Developer, maintainer"
|
||||
},
|
||||
{
|
||||
"name": "Ian Back",
|
||||
"role": "Developer (retired)"
|
||||
}
|
||||
],
|
||||
"description": "PHP library generating PDF files from UTF-8 encoded HTML",
|
||||
"homepage": "https://mpdf.github.io",
|
||||
"keywords": [
|
||||
"pdf",
|
||||
"php",
|
||||
"utf-8"
|
||||
],
|
||||
"support": {
|
||||
"docs": "https://mpdf.github.io",
|
||||
"issues": "https://github.com/mpdf/mpdf/issues",
|
||||
"source": "https://github.com/mpdf/mpdf"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://www.paypal.me/mpdf",
|
||||
"type": "custom"
|
||||
}
|
||||
],
|
||||
"time": "2025-08-18T08:51:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mpdf/psr-http-message-shim",
|
||||
"version": "v2.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mpdf/psr-http-message-shim.git",
|
||||
"reference": "f25a0153d645e234f9db42e5433b16d9b113920f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/mpdf/psr-http-message-shim/zipball/f25a0153d645e234f9db42e5433b16d9b113920f",
|
||||
"reference": "f25a0153d645e234f9db42e5433b16d9b113920f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"psr/http-message": "^2.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Mpdf\\PsrHttpMessageShim\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Mark Dorison",
|
||||
"email": "mark@chromatichq.com"
|
||||
},
|
||||
{
|
||||
"name": "Kristofer Widholm",
|
||||
"email": "kristofer@chromatichq.com"
|
||||
},
|
||||
{
|
||||
"name": "Nigel Cunningham",
|
||||
"email": "nigel.cunningham@technocrat.com.au"
|
||||
}
|
||||
],
|
||||
"description": "Shim to allow support of different psr/message versions.",
|
||||
"support": {
|
||||
"issues": "https://github.com/mpdf/psr-http-message-shim/issues",
|
||||
"source": "https://github.com/mpdf/psr-http-message-shim/tree/v2.0.1"
|
||||
},
|
||||
"time": "2023-10-02T14:34:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mpdf/psr-log-aware-trait",
|
||||
"version": "v3.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mpdf/psr-log-aware-trait.git",
|
||||
"reference": "a633da6065e946cc491e1c962850344bb0bf3e78"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/mpdf/psr-log-aware-trait/zipball/a633da6065e946cc491e1c962850344bb0bf3e78",
|
||||
"reference": "a633da6065e946cc491e1c962850344bb0bf3e78",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"psr/log": "^3.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Mpdf\\PsrLogAwareTrait\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Mark Dorison",
|
||||
"email": "mark@chromatichq.com"
|
||||
},
|
||||
{
|
||||
"name": "Kristofer Widholm",
|
||||
"email": "kristofer@chromatichq.com"
|
||||
}
|
||||
],
|
||||
"description": "Trait to allow support of different psr/log versions.",
|
||||
"support": {
|
||||
"issues": "https://github.com/mpdf/psr-log-aware-trait/issues",
|
||||
"source": "https://github.com/mpdf/psr-log-aware-trait/tree/v3.0.0"
|
||||
},
|
||||
"time": "2023-05-03T06:19:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "myclabs/deep-copy",
|
||||
"version": "1.13.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/myclabs/DeepCopy.git",
|
||||
"reference": "faed855a7b5f4d4637717c2b3863e277116beb36"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/faed855a7b5f4d4637717c2b3863e277116beb36",
|
||||
"reference": "faed855a7b5f4d4637717c2b3863e277116beb36",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1 || ^8.0"
|
||||
},
|
||||
"conflict": {
|
||||
"doctrine/collections": "<1.6.8",
|
||||
"doctrine/common": "<2.13.3 || >=3 <3.2.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/collections": "^1.6.8",
|
||||
"doctrine/common": "^2.13.3 || ^3.2.2",
|
||||
"phpspec/prophecy": "^1.10",
|
||||
"phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/DeepCopy/deep_copy.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"DeepCopy\\": "src/DeepCopy/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "Create deep copies (clones) of your objects",
|
||||
"keywords": [
|
||||
"clone",
|
||||
"copy",
|
||||
"duplicate",
|
||||
"object",
|
||||
"object graph"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/myclabs/DeepCopy/issues",
|
||||
"source": "https://github.com/myclabs/DeepCopy/tree/1.13.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-07-05T12:25:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nesbot/carbon",
|
||||
"version": "3.10.1",
|
||||
@ -2507,6 +2844,56 @@
|
||||
],
|
||||
"time": "2025-05-08T08:14:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "paragonie/random_compat",
|
||||
"version": "v9.99.100",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/paragonie/random_compat.git",
|
||||
"reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a",
|
||||
"reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">= 7"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "4.*|5.*",
|
||||
"vimeo/psalm": "^1"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
|
||||
},
|
||||
"type": "library",
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Paragon Initiative Enterprises",
|
||||
"email": "security@paragonie.com",
|
||||
"homepage": "https://paragonie.com"
|
||||
}
|
||||
],
|
||||
"description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
|
||||
"keywords": [
|
||||
"csprng",
|
||||
"polyfill",
|
||||
"pseudorandom",
|
||||
"random"
|
||||
],
|
||||
"support": {
|
||||
"email": "info@paragonie.com",
|
||||
"issues": "https://github.com/paragonie/random_compat/issues",
|
||||
"source": "https://github.com/paragonie/random_compat"
|
||||
},
|
||||
"time": "2020-10-15T08:29:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpoption/phpoption",
|
||||
"version": "1.9.3",
|
||||
@ -3271,6 +3658,146 @@
|
||||
},
|
||||
"time": "2025-06-25T14:20:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "setasign/fpdi",
|
||||
"version": "v2.6.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Setasign/FPDI.git",
|
||||
"reference": "4b53852fde2734ec6a07e458a085db627c60eada"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Setasign/FPDI/zipball/4b53852fde2734ec6a07e458a085db627c60eada",
|
||||
"reference": "4b53852fde2734ec6a07e458a085db627c60eada",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-zlib": "*",
|
||||
"php": "^7.1 || ^8.0"
|
||||
},
|
||||
"conflict": {
|
||||
"setasign/tfpdf": "<1.31"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^7",
|
||||
"setasign/fpdf": "~1.8.6",
|
||||
"setasign/tfpdf": "~1.33",
|
||||
"squizlabs/php_codesniffer": "^3.5",
|
||||
"tecnickcom/tcpdf": "^6.8"
|
||||
},
|
||||
"suggest": {
|
||||
"setasign/fpdf": "FPDI will extend this class but as it is also possible to use TCPDF or tFPDF as an alternative. There's no fixed dependency configured."
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"setasign\\Fpdi\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jan Slabon",
|
||||
"email": "jan.slabon@setasign.com",
|
||||
"homepage": "https://www.setasign.com"
|
||||
},
|
||||
{
|
||||
"name": "Maximilian Kresse",
|
||||
"email": "maximilian.kresse@setasign.com",
|
||||
"homepage": "https://www.setasign.com"
|
||||
}
|
||||
],
|
||||
"description": "FPDI is a collection of PHP classes facilitating developers to read pages from existing PDF documents and use them as templates in FPDF. Because it is also possible to use FPDI with TCPDF, there are no fixed dependencies defined. Please see suggestions for packages which evaluates the dependencies automatically.",
|
||||
"homepage": "https://www.setasign.com/fpdi",
|
||||
"keywords": [
|
||||
"fpdf",
|
||||
"fpdi",
|
||||
"pdf"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/Setasign/FPDI/issues",
|
||||
"source": "https://github.com/Setasign/FPDI/tree/v2.6.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/setasign/fpdi",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-08-05T09:57:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "simplesoftwareio/simple-qrcode",
|
||||
"version": "4.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/SimpleSoftwareIO/simple-qrcode.git",
|
||||
"reference": "916db7948ca6772d54bb617259c768c9cdc8d537"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/SimpleSoftwareIO/simple-qrcode/zipball/916db7948ca6772d54bb617259c768c9cdc8d537",
|
||||
"reference": "916db7948ca6772d54bb617259c768c9cdc8d537",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"bacon/bacon-qr-code": "^2.0",
|
||||
"ext-gd": "*",
|
||||
"php": ">=7.2|^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "~1",
|
||||
"phpunit/phpunit": "~9"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-imagick": "Allows the generation of PNG QrCodes.",
|
||||
"illuminate/support": "Allows for use within Laravel."
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"aliases": {
|
||||
"QrCode": "SimpleSoftwareIO\\QrCode\\Facades\\QrCode"
|
||||
},
|
||||
"providers": [
|
||||
"SimpleSoftwareIO\\QrCode\\QrCodeServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"SimpleSoftwareIO\\QrCode\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Simple Software LLC",
|
||||
"email": "support@simplesoftware.io"
|
||||
}
|
||||
],
|
||||
"description": "Simple QrCode is a QR code generator made for Laravel.",
|
||||
"homepage": "https://www.simplesoftware.io/#/docs/simple-qrcode",
|
||||
"keywords": [
|
||||
"Simple",
|
||||
"generator",
|
||||
"laravel",
|
||||
"qrcode",
|
||||
"wrapper"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/SimpleSoftwareIO/simple-qrcode/issues",
|
||||
"source": "https://github.com/SimpleSoftwareIO/simple-qrcode/tree/4.2.0"
|
||||
},
|
||||
"time": "2021-02-08T20:43:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/clock",
|
||||
"version": "v7.3.0",
|
||||
@ -6258,66 +6785,6 @@
|
||||
},
|
||||
"time": "2024-05-16T03:13:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "myclabs/deep-copy",
|
||||
"version": "1.13.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/myclabs/DeepCopy.git",
|
||||
"reference": "faed855a7b5f4d4637717c2b3863e277116beb36"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/faed855a7b5f4d4637717c2b3863e277116beb36",
|
||||
"reference": "faed855a7b5f4d4637717c2b3863e277116beb36",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1 || ^8.0"
|
||||
},
|
||||
"conflict": {
|
||||
"doctrine/collections": "<1.6.8",
|
||||
"doctrine/common": "<2.13.3 || >=3 <3.2.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/collections": "^1.6.8",
|
||||
"doctrine/common": "^2.13.3 || ^3.2.2",
|
||||
"phpspec/prophecy": "^1.10",
|
||||
"phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/DeepCopy/deep_copy.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"DeepCopy\\": "src/DeepCopy/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "Create deep copies (clones) of your objects",
|
||||
"keywords": [
|
||||
"clone",
|
||||
"copy",
|
||||
"duplicate",
|
||||
"object",
|
||||
"object graph"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/myclabs/DeepCopy/issues",
|
||||
"source": "https://github.com/myclabs/DeepCopy/tree/1.13.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-07-05T12:25:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nunomaduro/collision",
|
||||
"version": "v8.8.2",
|
||||
|
||||
@ -1,61 +0,0 @@
|
||||
/* iCheck plugin skins
|
||||
----------------------------------- */
|
||||
@import url("minimal/_all.css");
|
||||
/*
|
||||
@import url("minimal/minimal.css");
|
||||
@import url("minimal/red.css");
|
||||
@import url("minimal/green.css");
|
||||
@import url("minimal/blue.css");
|
||||
@import url("minimal/aero.css");
|
||||
@import url("minimal/grey.css");
|
||||
@import url("minimal/orange.css");
|
||||
@import url("minimal/yellow.css");
|
||||
@import url("minimal/pink.css");
|
||||
@import url("minimal/purple.css");
|
||||
*/
|
||||
|
||||
@import url("square/_all.css");
|
||||
/*
|
||||
@import url("square/square.css");
|
||||
@import url("square/red.css");
|
||||
@import url("square/green.css");
|
||||
@import url("square/blue.css");
|
||||
@import url("square/aero.css");
|
||||
@import url("square/grey.css");
|
||||
@import url("square/orange.css");
|
||||
@import url("square/yellow.css");
|
||||
@import url("square/pink.css");
|
||||
@import url("square/purple.css");
|
||||
*/
|
||||
|
||||
@import url("flat/_all.css");
|
||||
/*
|
||||
@import url("flat/flat.css");
|
||||
@import url("flat/red.css");
|
||||
@import url("flat/green.css");
|
||||
@import url("flat/blue.css");
|
||||
@import url("flat/aero.css");
|
||||
@import url("flat/grey.css");
|
||||
@import url("flat/orange.css");
|
||||
@import url("flat/yellow.css");
|
||||
@import url("flat/pink.css");
|
||||
@import url("flat/purple.css");
|
||||
*/
|
||||
|
||||
@import url("line/_all.css");
|
||||
/*
|
||||
@import url("line/line.css");
|
||||
@import url("line/red.css");
|
||||
@import url("line/green.css");
|
||||
@import url("line/blue.css");
|
||||
@import url("line/aero.css");
|
||||
@import url("line/grey.css");
|
||||
@import url("line/orange.css");
|
||||
@import url("line/yellow.css");
|
||||
@import url("line/pink.css");
|
||||
@import url("line/purple.css");
|
||||
*/
|
||||
|
||||
@import url("polaris/polaris.css");
|
||||
|
||||
@import url("futurico/futurico.css");
|
||||
@ -130,6 +130,21 @@ $(document).on('click', '.btn-popup', function () {
|
||||
});
|
||||
});
|
||||
|
||||
$(document).on('click', '.btn-reserve-popup', function () {
|
||||
var reserveId = $(this).data('reserve-id');
|
||||
$.ajax({
|
||||
url: '/api/park-detail-wait/' + reserveId,
|
||||
method: 'GET',
|
||||
success: function (data) {
|
||||
$('#modalArea').html(data.html); // モーダル全体を挿入
|
||||
$('#parkDetailWaitModal').modal('show'); // モーダルを表示
|
||||
},
|
||||
error: function () {
|
||||
alert('詳細情報の取得に失敗しました');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$(document).on('click', '.btn-reserve', function (e) {
|
||||
e.preventDefault();
|
||||
var parkId = $(this).data('park-id');
|
||||
@ -141,8 +156,19 @@ $(document).on('click', '.btn-reserve', function (e) {
|
||||
content: 'こちらの駐輪場を予約しますか?<br>お申込みいただく各自治体の条例等によって、駐輪場までの距離制限等によりご契約いただけない場合がございます。<br>予めご了承くださいますようお願いいたします。',
|
||||
buttons: {
|
||||
OK: function () {
|
||||
// GETパラメータでregulationメソッドに遷移
|
||||
location.href = '/park-waitlist/create?park_id=' + parkId + '&psection_id=' + psectionId + '&ptype_id=' + ptypeId;
|
||||
// Ajaxで予約済みかチェック
|
||||
$.get('/park-waitlist/check', {
|
||||
park_id: parkId,
|
||||
psection_id: psectionId,
|
||||
ptype_id: ptypeId
|
||||
}, function (response) {
|
||||
if (response.status === 'exists') {
|
||||
$.alert('こちらの駐輪場は予約済みです。');
|
||||
} else {
|
||||
// 予約画面へ遷移
|
||||
location.href = '/park-waitlist/create?park_id=' + parkId + '&psection_id=' + psectionId + '&ptype_id=' + ptypeId;
|
||||
}
|
||||
});
|
||||
},
|
||||
キャンセル: function () { }
|
||||
}
|
||||
|
||||
22
resources/views/emails/reservation_cancelled.blade.php
Normal file
22
resources/views/emails/reservation_cancelled.blade.php
Normal file
@ -0,0 +1,22 @@
|
||||
{!! nl2br(e(
|
||||
$user_name . ' 様
|
||||
|
||||
So-Manager自動応答システムです。
|
||||
|
||||
下記駐輪場の空き待ちのキャンセルを受け付けました。
|
||||
|
||||
空き駐輪場: ' . $reserve->park_name . '
|
||||
車種区分 : ' . $reserve->psection_subject . '
|
||||
駐輪分類 : ' . $reserve->ptype_subject . '
|
||||
|
||||
So-Manager.comのユーザー登録は解約されておりません。別の駐輪場でのご契約や空き待ちをご希望の際には、マイページをご活用ください。
|
||||
|
||||
|
||||
■お問合せ先■
|
||||
So-Managerコールセンター(ソーマネージャーコールセンター)
|
||||
●電話:03-5856-4720
|
||||
●メールでのお問合せ(専用フォームよりお問合わせください)
|
||||
|
||||
※本メールアドレスは送信専用です。ご返信には回答致しかねますのでご了承ください。
|
||||
※本メールにお心あたりのない場合には、コールセンターまでご連絡くださいますようお願い致します。'
|
||||
)) !!}
|
||||
@ -31,7 +31,7 @@
|
||||
<h3 class="other mt50">開示等の依頼の手続き、使用する様式</h3>
|
||||
<p class="p1">開示等の依頼は、以下の手続き及び様式に則って実施致します。</p>
|
||||
<p class="p1">利用目的の通知:本書面の“開示対象個人情報の利用目的”をご覧下さい。</p>
|
||||
<p class="p1">開示、訂正・削除、利用停止:当社の定める様式にて実施致します。該当の受付け窓口にご連絡頂き、所定の様式『<a href="{{ asset('assets/page-img/privacy_disclosure.pdf') }}" target="_blank">個人情報開示等依頼書(PDF:9KB)</a>』を入手のうえ、手続きをお願い致します。</p>
|
||||
<p class="p1">開示、訂正・削除、利用停止:当社の定める様式にて実施致します。該当の受付け窓口にご連絡頂き、所定の様式『<a href="{{ asset('assets/privacy_disclosure.pdf') }}" target="_blank">個人情報開示等依頼書(PDF:9KB)</a>』を入手のうえ、手続きをお願い致します。</p>
|
||||
<p class="p1">回答に関しては、記入済み個人情報開示等依頼書を、ご自宅への郵送のみとさせて頂きます。</p>
|
||||
<h3 class="other mt50">開示対象個人情報の取扱いに関する苦情受付け窓口</h3>
|
||||
<p class="p1">開示対象個人情報の取扱いに関する苦情、相談に関しましては、以下の窓口宛てにご連絡ください。</p>
|
||||
|
||||
@ -9,140 +9,140 @@
|
||||
<h5 class="card-title text-success">駐輪場をお選びください。</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form class="row form">
|
||||
<form class="row form" method="post" action="{{ route('swo5_2') }}">
|
||||
<div class="w-100 alert alert-success">
|
||||
<h6><a class="text-success" data-toggle="collapse" href="#search-option" role="button" aria-expanded="false" aria-controls="search-option">絞込み条件を追加する</a></h6>
|
||||
<div class="collapse row" id="search-option">
|
||||
<div class="col-3">市町村名</div>
|
||||
<div class="col-9 mb10">
|
||||
<select class="form-control form-control-lg">
|
||||
<option>市町村を選択してください</option>
|
||||
<option>〇〇市</option>
|
||||
<option>〇〇市</option>
|
||||
<option>〇〇市</option>
|
||||
<option>〇〇市</option>
|
||||
<option>〇〇市</option>
|
||||
<select class="form-control form-control-lg" name="conditions_city">
|
||||
<option value="">市町村を選択してください</option>
|
||||
@foreach($cities as $city)
|
||||
@if(isset($conditions) && $conditions[0] == $city->city_name) {
|
||||
<option value="{{ $city->city_name }}" selected>{{ $city->city_name }}</option>
|
||||
@else
|
||||
<option value="{{ $city->city_name }}">{{ $city->city_name }}</option>
|
||||
@endif
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-3">駅名</div>
|
||||
<div class="col-9 mb10">
|
||||
<select class="form-control form-control-lg">
|
||||
<option>駅名を選択してください</option>
|
||||
<option>〇〇駅</option>
|
||||
<option>〇〇駅</option>
|
||||
<option>〇〇駅</option>
|
||||
<option>〇〇駅</option>
|
||||
<option>〇〇駅</option>
|
||||
<select class="form-control form-control-lg" name="conditions_station">
|
||||
<option value="">駅名を選択してください</option>
|
||||
@foreach($stations as $station)
|
||||
@if(isset($conditions) && $conditions[1] == $station->station_neighbor_station) {
|
||||
<option value="{{ $station->station_neighbor_station }}" selected>{{ $station->station_neighbor_station }}</option>
|
||||
@else
|
||||
<option value="{{ $station->station_neighbor_station }}">{{ $station->station_neighbor_station }}</option>
|
||||
@endif
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-3">駐車場名</div>
|
||||
<div class="col-9 mb10">
|
||||
<select class="form-control form-control-lg">
|
||||
<option>全て</option>
|
||||
<option>あ行</option>
|
||||
<option>か行</option>
|
||||
<option>さ行</option>
|
||||
<option>た行</option>
|
||||
<option>な行</option>
|
||||
<option>は行</option>
|
||||
<option>ま行</option>
|
||||
<option>や行</option>
|
||||
<option>ら行</option>
|
||||
<option>わ行</option>
|
||||
<select class="form-control form-control-lg" name="conditions_park">
|
||||
@foreach($parks as $key => $value)
|
||||
@if(isset($conditions) && $conditions[2] == $value) {
|
||||
<option value="{{ $value }}" selected>{{ $key }}</option>
|
||||
@else
|
||||
<option value="{{ $value }}">{{ $key }}</option>
|
||||
@endif
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(function() {
|
||||
$('select[name="conditions_city"], select[name="conditions_station"], select[name="conditions_park"]').on('change', function() {
|
||||
$(this).closest('form').submit();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@csrf
|
||||
</form>
|
||||
<table id="searchTable" class="tablesorter table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>駐輪場名</th>
|
||||
<th>市町村名</th>
|
||||
<th>駅名</th>
|
||||
<th></th>
|
||||
<th width="20%">駐輪場名</th>
|
||||
<th width="30%">市町村名</th>
|
||||
<th width="20%">駅名</th>
|
||||
@foreach($psections as $psection)
|
||||
<th width="10%">{{ $psection->psection_subject }}</th>
|
||||
@endforeach
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@php
|
||||
$perPage = 10;
|
||||
$page = request()->get('page', 1);
|
||||
$total = count($form_data);
|
||||
$start = ($page - 1) * $perPage;
|
||||
$pagedData = array_slice($form_data, $start, $perPage);
|
||||
$lastPage = ceil($total / $perPage);
|
||||
@endphp
|
||||
@foreach($pagedData as $data)
|
||||
<tr>
|
||||
<td><a href="#placeModal01" data-toggle="modal" data-target="#placeModal01">あマルバツ駐輪場A</a></td>
|
||||
<td>〇〇市</td>
|
||||
<td>〇〇駅</td>
|
||||
<td><a href="./SWC-08-02.html" class="btn btn-block btn-sm btn-outline-success">定期契約</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#placeModal02" data-toggle="modal" data-target="#placeModal02">かマルバツ駐輪場B</a></td>
|
||||
<td>〇〇市</td>
|
||||
<td>〇〇駅</td>
|
||||
<td><a href="#" class="btn btn-block btn-sm btn-outline-danger">空き待ち申込</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#placeModal01" data-toggle="modal" data-target="#placeModal01">あマルバツ駐輪場A</a></td>
|
||||
<td>〇〇市</td>
|
||||
<td>〇〇駅</td>
|
||||
<td><a href="./SWC-08-02.html" class="btn btn-block btn-sm btn-outline-success">定期契約</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#placeModal02" data-toggle="modal" data-target="#placeModal02">かマルバツ駐輪場B</a></td>
|
||||
<td>〇〇市</td>
|
||||
<td>〇〇駅</td>
|
||||
<td><a href="#" class="btn btn-block btn-sm btn-outline-danger">空き待ち申込</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#placeModal01" data-toggle="modal" data-target="#placeModal01">あマルバツ駐輪場A</a></td>
|
||||
<td>〇〇市</td>
|
||||
<td>〇〇駅</td>
|
||||
<td><a href="./SWC-08-02.html" class="btn btn-block btn-sm btn-outline-success">定期契約</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#placeModal02" data-toggle="modal" data-target="#placeModal02">かマルバツ駐輪場B</a></td>
|
||||
<td>〇〇市</td>
|
||||
<td>〇〇駅</td>
|
||||
<td><a href="#" class="btn btn-block btn-sm btn-outline-danger">空き待ち申込</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#placeModal01" data-toggle="modal" data-target="#placeModal01">あマルバツ駐輪場A</a></td>
|
||||
<td>〇〇市</td>
|
||||
<td>〇〇駅</td>
|
||||
<td><a href="./SWC-08-02.html" class="btn btn-block btn-sm btn-outline-success">定期契約</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#placeModal02" data-toggle="modal" data-target="#placeModal02">かマルバツ駐輪場B</a></td>
|
||||
<td>〇〇市</td>
|
||||
<td>〇〇駅</td>
|
||||
<td><a href="#" class="btn btn-block btn-sm btn-outline-danger">空き待ち申込</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#placeModal01" data-toggle="modal" data-target="#placeModal01">あマルバツ駐輪場A</a></td>
|
||||
<td>〇〇市</td>
|
||||
<td>〇〇駅</td>
|
||||
<td><a href="./SWC-08-02.html" class="btn btn-block btn-sm btn-outline-success">定期契約</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#placeModal02" data-toggle="modal" data-target="#placeModal02">かマルバツ駐輪場B</a></td>
|
||||
<td>〇〇市</td>
|
||||
<td>〇〇駅</td>
|
||||
<td><a href="#" class="btn btn-block btn-sm btn-outline-danger">空き待ち申込</a></td>
|
||||
</tr>
|
||||
<td>
|
||||
<a href="#placeModal"
|
||||
data-toggle="modal"
|
||||
data-target="#placeModal"
|
||||
data-park_name="{{ $data['park_name'] }}"
|
||||
data-park_adrs="{{ $data['park_adrs'] ?? '' }}"
|
||||
data-price_memo="{{ $data['price_memo'] ?? '' }}"
|
||||
data-park_latitude="{{ $data['park_latitude'] ?? '' }}"
|
||||
data-park_longitude="{{ $data['park_longitude'] ?? '' }}"
|
||||
data-city_name="{{ $data['city_name'] }}"
|
||||
data-station="{{ $data['station_neighbor_station'] }}"
|
||||
data-zone_data='@json($data["zone_data"])'>
|
||||
{{ $data['park_name'] }}
|
||||
</a>
|
||||
</td>
|
||||
<td>{{ $data['city_name'] }}</td>
|
||||
<td>{{ $data['station_neighbor_station'] }}</td>
|
||||
@foreach($psections as $psection)
|
||||
<td>
|
||||
@foreach($data['zone_data'] as $zone)
|
||||
@if($zone['psection_subject'] == $psection->psection_subject)
|
||||
@if($zone['status'] == 1)
|
||||
<a href="{{route('user.info')}}" class="btn btn-block btn-sm btn-outline-success">定期契約</a>
|
||||
@elseif($zone['status'] == 2)
|
||||
<a href="{{route('park_waitlist.index')}}" class="btn btn-block btn-sm btn-outline-primary">空き待ち予約</a>
|
||||
@elseif($zone['status'] == 3)
|
||||
<a href="{{route('park_waitlist.index')}}" class="btn btn-block btn-sm btn-secondary">販売期間外</a>
|
||||
@endif
|
||||
@break;
|
||||
@endif
|
||||
@endforeach
|
||||
</td>
|
||||
@endforeach
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
<nav aria-label="searchTable-pager">
|
||||
<ul class="pagination justify-content-center">
|
||||
<li class="page-item">
|
||||
<a class="page-link text-success" href="#" aria-label="前">
|
||||
<span aria-hidden="true">«</span>
|
||||
<span class="sr-only">前</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="page-item"><a class="page-link text-success" href="#">1</a></li>
|
||||
<li class="page-item"><a class="page-link text-success" href="#">2</a></li>
|
||||
<li class="page-item"><a class="page-link text-success" href="#">3</a></li>
|
||||
<li class="page-item">
|
||||
<a class="page-link text-success" href="#" aria-label="次">
|
||||
<span aria-hidden="true">»</span>
|
||||
<span class="sr-only">次</span>
|
||||
</a>
|
||||
</li>
|
||||
@if($lastPage > 1)
|
||||
{{-- 前へ --}}
|
||||
<li class="page-item {{ $page == 1 ? 'disabled' : '' }}">
|
||||
<a class="page-link text-success" href="?page={{ $page - 1 }}" aria-label="前">
|
||||
<span aria-hidden="true">«</span><span class="sr-only">前</span>
|
||||
</a>
|
||||
</li>
|
||||
{{-- ページ番号 --}}
|
||||
@for($i = 1; $i <= $lastPage; $i++)
|
||||
<li class="page-item {{ $page == $i ? 'active' : '' }}">
|
||||
<a class="page-link text-success" href="?page={{ $i }}">{{ $i }}</a>
|
||||
</li>
|
||||
@endfor
|
||||
{{-- 次へ --}}
|
||||
<li class="page-item {{ $page == $lastPage ? 'disabled' : '' }}">
|
||||
<a class="page-link text-success" href="?page={{ $page + 1 }}" aria-label="次">
|
||||
<span aria-hidden="true">»</span><span class="sr-only">次</span>
|
||||
</a>
|
||||
</li>
|
||||
@endif
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
@ -151,64 +151,91 @@
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<div class="modal fade" id="placeModal01" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="placeModal" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<script>
|
||||
$('#placeModal').on('show.bs.modal', function (event) {
|
||||
var button = $(event.relatedTarget);
|
||||
var parkName = button.data('park_name') || '';
|
||||
var parkAdrs = button.data('park_adrs') || '';
|
||||
var parkMemo = button.data('price_memo') || '';
|
||||
var lat = button.data('park_latitude') || '';
|
||||
var lng = button.data('park_longitude') || '';
|
||||
$('#parkName').text(parkName).attr('data-park_name', parkName);
|
||||
$('#parkAdrs').text('住所:' + parkAdrs).attr('data-park_adrs', parkAdrs);
|
||||
$('#parkmemo').text(parkMemo).attr('data-price_memo', parkMemo);
|
||||
$('#parkMap').attr('src', 'https://www.google.com/maps?q=' + lat + ',' + lng + '&z=15&output=embed');
|
||||
|
||||
// zone_dataはJSON文字列として渡されているのでパース
|
||||
var zoneData = button.data('zone_data') || [];
|
||||
|
||||
// psection_subjectごとの標準収容台数を集計
|
||||
var standardMap = {};
|
||||
if (zoneData && Array.isArray(zoneData)) {
|
||||
zoneData.forEach(function(zone) {
|
||||
if (!standardMap[zone.psection_subject]) {
|
||||
standardMap[zone.psection_subject] = 0;
|
||||
}
|
||||
standardMap[zone.psection_subject] += parseInt(zone.zone_standard, 10) || 0;
|
||||
});
|
||||
}
|
||||
// 表示用文字列を生成
|
||||
var standardText = '';
|
||||
var keys = Object.keys(standardMap);
|
||||
if (keys.length > 0) {
|
||||
standardText = '【標準収容台数】';
|
||||
standardText += keys.map(function(key) {
|
||||
return key + ':' + standardMap[key] + '台';
|
||||
}).join(' / ');
|
||||
}
|
||||
$('#parkStandard').text(standardText);
|
||||
|
||||
// 各ゾーンの空き台数・ボタンを表示
|
||||
var html = '';
|
||||
if (zoneData && Array.isArray(zoneData)) {
|
||||
var grouped = {};
|
||||
zoneData.forEach(function(zone) {
|
||||
if (!grouped[zone.ptype_subject]) grouped[zone.ptype_subject] = [];
|
||||
grouped[zone.ptype_subject].push(zone);
|
||||
});
|
||||
Object.keys(grouped).forEach(function(ptype) {
|
||||
html += '<h4 class="mt-3">' + ptype + '</h4>';
|
||||
grouped[ptype].forEach(function(zone) {
|
||||
html += '<div class="d-flex align-items-center mb-2">';
|
||||
html += '<span>' + zone.psection_subject + ':空き' + zone.zone_vacant + '台</span>';
|
||||
if (zone.status == 1) {
|
||||
html += '<a href="{{route('regular_contract.create')}}" class="btn btn-sm btn-outline-success ml-2">定期契約</a>';
|
||||
} else if (zone.status == 2) {
|
||||
html += '<a href="{{route('park_waitlist.index')}}" class="btn btn-sm btn-outline-primary ml-2">空き待ち予約</a>';
|
||||
} else if (zone.status == 3) {
|
||||
html += '<a href="{{route('park_waitlist.index')}}" class="btn btn-sm btn-outline-secondary ml-2">販売期間外</a>';
|
||||
}
|
||||
html += '</div>';
|
||||
});
|
||||
});
|
||||
}
|
||||
$('#zoneData').html(html);
|
||||
});
|
||||
</script>
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">あマルバツ駐輪場A</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="閉じる">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<h5 class="modal-title" id="parkName" data-park_name=""></h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="閉じる"><span aria-hidden="true">×</span></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3240.722943699139!2d139.75162621525894!3d35.68382338019366!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x60188c0b185b3b75%3A0x3282e79fbc91959c!2z44CSMTAwLTAwMDEg5p2x5Lqs6YO95Y2D5Luj55Sw5Yy65Y2D5Luj55Sw77yR4oiS77yR!5e0!3m2!1sja!2sjp!4v1536695351221" width="100%" height="450" frameborder="0" style="border:0" allowfullscreen></iframe>
|
||||
<iframe id="parkMap" src="" width="100%" height="450" frameborder="0" style="border:0" allowfullscreen></iframe>
|
||||
<p class="small">
|
||||
〒000-0000 東京都千代田区1-1 <br class="sp">
|
||||
標準収容台数:XXX台
|
||||
<span id="parkAdrs"> </span>
|
||||
<span id="parkStandard"></span><br />
|
||||
<span id="parkmemo"></span>
|
||||
</p>
|
||||
<p class="text-danger">
|
||||
空き台数:XXX台
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-success" onClick="location.href='./SWC-08-02.html'">定期契約</button>
|
||||
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">閉じる</button>
|
||||
<span id="zoneData"></span>
|
||||
<div class="text-right"><button type="button" class="btn btn-outline-secondary" data-dismiss="modal">閉じる</button></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade" id="placeModal02" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">かマルバツ駐輪場B</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="閉じる">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3240.722943699139!2d139.75162621525894!3d35.68382338019366!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x60188c0b185b3b75%3A0x3282e79fbc91959c!2z44CSMTAwLTAwMDEg5p2x5Lqs6YO95Y2D5Luj55Sw5Yy65Y2D5Luj55Sw77yR4oiS77yR!5e0!3m2!1sja!2sjp!4v1536695351221" width="100%" height="450" frameborder="0" style="border:0" allowfullscreen></iframe>
|
||||
<p class="small">
|
||||
〒000-0000 東京都千代田区1-1 <br class="sp">
|
||||
標準収容台数:XXX台
|
||||
</p>
|
||||
<p class="text-danger">
|
||||
空き待ち
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-danger">空き待ち申込</button>
|
||||
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">閉じる</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
|
||||
<script>window.jQuery || document.write('<script src="./assets/js/vendor/jquery.min.js"><\/script>')</script>
|
||||
<script src="./assets/js/vendor/popper.min.js"></script>
|
||||
<script src="./bootstrap/js/bootstrap.min.js"></script>
|
||||
<script src="./assets/js/ie10-viewport-bug-workaround.js"></script>
|
||||
<script src="./assets/js/commons.js"></script>
|
||||
<script src="./assets/js/vendor/jquery.tablesorter/jquery.tablesorter.min.js" type="text/javascript"></script>
|
||||
<script type="text/javascript">$(document).ready(function() { $("#sampleTable").tablesorter();} ); </script>
|
||||
@endsection
|
||||
@ -5,13 +5,18 @@
|
||||
<div class="col-12 col-lg-10 offset-0 offset-lg-1 mt20 mb20">
|
||||
<h2 class="text-success text-center">お問い合わせ</h2>
|
||||
<p>株式会社ソーリンへのご訪問ありがとうございます。
|
||||
お問い合わせいただくお客さまは、当社のホームページにおける<a href="{{ route('swo14_1') }}">個人情報の取り扱い</a>について、あらかじめご確認いただき、ご同意いただいた上でお問い合わせください。個人情報の開示、訂正、削除、利用停止については、<a href="{{ asset('assets/privacy_disclosure.pdf') }}">こちら</a>をご覧下さい。<br>
|
||||
お問い合わせいただくお客さまは、当社のホームページにおける<a href="{{ route('swo14_1') }}">個人情報の取り扱い</a>について、あらかじめご確認いただき、ご同意いただいた上でお問い合わせください。個人情報の開示、訂正、削除、利用停止については、<a href="{{ route('swo15_1') }}">こちら</a>をご覧下さい。<br>
|
||||
また、メールから送信ができないお客様はお手数ですが、下記電話までご連絡をお願い致します。
|
||||
※ 携帯・スマートフォンからメールでのお問い合わせの際に、確実にご返信をさせていただくために、ドメイン (so-manager.com) の受信許可設定をお願い致します。</p>
|
||||
<form class="form-contact form mt50" method="post" action="{{ route('swo7_2') }}">
|
||||
@if($errors->any())
|
||||
<div class="alert alert-danger error-message" role="alert">
|
||||
@foreach ($errors->all() as $error){{ $error }}<br /> @endforeach
|
||||
</div>
|
||||
@endif
|
||||
<div class="row">
|
||||
@foreach($form_data as $value)
|
||||
<div class="col-lg-3">{{ $value[2] }}</div>
|
||||
<div class="col-lg-3">{!! preg_replace('/\*$/', '<span style="color:red;">*</span>', e($value[2])) !!}</div>
|
||||
@if($value[1] == 'textarea')
|
||||
<div class="col-lg-9"><textarea name="{{ $value[0] }}" cols="6" class="form-control">{{ old($value[0]) }}</textarea></div>
|
||||
@elseif($value[1] == 'checkbox')
|
||||
@ -25,18 +30,10 @@
|
||||
@endforeach
|
||||
</div>
|
||||
@else
|
||||
<div class="col-lg-9"><input name="{{ $value[0] }}" type="{{ $value[1] }}" value="{{ old($value[0]) }}" class="form-control mb10"></div>
|
||||
<div class="col-lg-9"><input name="{{ $value[0] }}" type="{{ $value[1] }}" value="{{ old($value[0]) }}" class="form-control mb10" placeholder="{{ $value[3] }}"></div>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
<p style="color: red;">
|
||||
@foreach($form_data as $value)
|
||||
@if($errors->has($value[0]))
|
||||
{{ $errors->first($value[0]) }}
|
||||
@break;
|
||||
@endif
|
||||
@endforeach
|
||||
</p>
|
||||
<div class="col-lg-12 mt50 mb50 text-center"><button type="submit" class="btn btn-lg btn-success mb10">入力内容を確認する</button></div>
|
||||
@csrf
|
||||
</form>
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
</div>
|
||||
<div class="col-12 col-lg-3 text-lg-center offset-0 offset-lg-1"><label>パスワード</label></div>
|
||||
<div class="col-12 col-lg-7 mb10">
|
||||
<input type="text" name="password" class="form-control form-control-lg" value="" />
|
||||
<input type="password" name="password" class="form-control form-control-lg" value="" />
|
||||
</div>
|
||||
<div class="col-12 col-lg-6 text-lg-center offset-0 offset-lg-3 mt30 mb50">
|
||||
<div class="text-danger">@if ($errors->any()) @foreach ($errors->all() as $error) {{ $error }} @endforeach @endif</div><br />
|
||||
|
||||
@ -5,14 +5,14 @@
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<title>@yield('title', 'So-Manager')</title>
|
||||
<link rel="icon" href="{{ asset('assets/img/favicon.ico') }}">
|
||||
<link href="{{ asset('assets/css/mypage/app.css') }}" rel="stylesheet">
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/typicons/2.0.9/typicons.css" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/earlyaccess/roundedmplus1c.css" rel="stylesheet">
|
||||
<link href="{{ asset('assets/css/mypage/slick.css') }}" rel="stylesheet">
|
||||
<link href="{{ asset('assets/css/mypage/slick-theme.css') }}" rel="stylesheet">
|
||||
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/slick-carousel@1.8.1/slick/slick-theme.css"/>
|
||||
<link rel="stylesheet" href="{{ asset('assets/css/mypage/font-awesome.min.css') }}">
|
||||
<link href="{{ asset('assets/css/mypage/bootstrap.min.css') }}" rel="stylesheet">
|
||||
<link rel="stylesheet" href="{{ asset('assets/css/mypage/all.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('assets/css/mypage/picker.min.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('assets/css/mypage/tablesorter-blue.css') }}" type="text/css" media="print, projection, screen">
|
||||
<link href="{{ asset('assets/css/mypage/style.css') }}" rel="stylesheet">
|
||||
|
||||
260
resources/views/mypage/index.blade.php
Normal file
260
resources/views/mypage/index.blade.php
Normal file
@ -0,0 +1,260 @@
|
||||
@extends('layouts.app')
|
||||
@section('content')
|
||||
<main>
|
||||
<section id="" class="container mt20 mb20">
|
||||
<div class="row">
|
||||
<div class="col-12 col-lg-6 mb20">
|
||||
<div class="card border-success">
|
||||
<div class="card-header border-success">
|
||||
<h5 class="card-title text-success">定期契約情報</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="slider_2-1">
|
||||
@forelse($contracts as $contract)
|
||||
@php
|
||||
$now = \Carbon\Carbon::now();
|
||||
$update_flag = $contract->contract_renewal;
|
||||
$start_dd = $contract->update_grace_period_start_date;
|
||||
$start_hm = $contract->update_grace_period_start_time;
|
||||
$end_dd = $contract->update_grace_period_end_date;
|
||||
$end_hm = $contract->update_grace_period_end_time;
|
||||
$contract_end_dt = $contract->contract_periode ? \Carbon\Carbon::parse($contract->contract_periode) : null;
|
||||
$periode_month = $contract_end_dt ? $contract_end_dt->month : null;
|
||||
$periode_year = $contract_end_dt ? $contract_end_dt->year : null;
|
||||
$bg = 'alert-warning';
|
||||
$btn_text = '更新する';
|
||||
$btn_active = true;
|
||||
|
||||
// 契約終了月より前は「ご契約中」
|
||||
if ($now->lt($contract_end_dt)) {
|
||||
$bg = 'bg-white';
|
||||
$btn_text = 'ご契約中';
|
||||
$btn_active = false;
|
||||
} else {
|
||||
// 契約終了月より後は猶予期間判定
|
||||
if (is_numeric($start_dd) && is_numeric($end_dd)) {
|
||||
// 開始日
|
||||
$start_date = $contract_end_dt->format('Y-m-') . str_pad($start_dd, 2, '0', STR_PAD_LEFT);
|
||||
$start_time = ($start_hm && preg_match('/^\d{2}:\d{2}$/', $start_hm)) ? $start_hm : '00:00';
|
||||
$start_dt = \Carbon\Carbon::createFromFormat('Y-m-d H:i:s', $start_date . ' ' . $start_time . ':00');
|
||||
// 終了日
|
||||
if ($start_dd < $end_dd) {
|
||||
$end_date=$contract_end_dt->format('Y-m-') . str_pad($end_dd, 2, '0', STR_PAD_LEFT);
|
||||
$end_time = ($end_hm && preg_match('/^\d{2}:\d{2}$/', $end_hm)) ? $end_hm : '23:59';
|
||||
$end_dt = \Carbon\Carbon::createFromFormat('Y-m-d H:i:s', $end_date . ' ' . $end_time . ':00');
|
||||
} else {
|
||||
$next_month_dt = $contract_end_dt->copy()->addMonth();
|
||||
$end_date = $next_month_dt->format('Y-m-') . str_pad($end_dd, 2, '0', STR_PAD_LEFT);
|
||||
$end_time = ($end_hm && preg_match('/^\d{2}:\d{2}$/', $end_hm)) ? $end_hm : '23:59';
|
||||
$end_dt = \Carbon\Carbon::createFromFormat('Y-m-d H:i:s', $end_date . ' ' . $end_time . ':00');
|
||||
}
|
||||
} else {
|
||||
$start_dt = null;
|
||||
$end_dt = null;
|
||||
}
|
||||
// 猶予期間判定
|
||||
if ($update_flag === 0) {
|
||||
$bg = 'bg-white';
|
||||
$btn_text = '手続き中';
|
||||
$btn_active = false;
|
||||
} elseif ($update_flag === 1) {
|
||||
$bg = 'bg-white';
|
||||
$btn_text = '更新済';
|
||||
$btn_active = false;
|
||||
} elseif ($start_dt && $end_dt && $now->between($start_dt, $end_dt)) {
|
||||
// 猶予期間内
|
||||
if ($contract_end_dt && $now->gt($contract_end_dt)) {
|
||||
$bg = 'alert-danger';
|
||||
$btn_text = '更新する';
|
||||
$btn_active = true;
|
||||
} else {
|
||||
$bg = 'alert-warning';
|
||||
$btn_text = '更新する';
|
||||
$btn_active = true;
|
||||
}
|
||||
} else {
|
||||
$bg = 'bg-white';
|
||||
$btn_text = 'ご契約中';
|
||||
$btn_active = false;
|
||||
}
|
||||
}
|
||||
// 契約終了月の場合(既存ロジック)
|
||||
if (is_numeric($start_dd) && is_numeric($end_dd)) {
|
||||
// 開始日
|
||||
$start_date = $contract_end_dt->format('Y-m-') . str_pad($start_dd, 2, '0', STR_PAD_LEFT);
|
||||
$start_time = ($start_hm && preg_match('/^\d{2}:\d{2}$/', $start_hm)) ? $start_hm : '00:00';
|
||||
$start_dt = \Carbon\Carbon::createFromFormat('Y-m-d H:i:s', $start_date . ' ' . $start_time . ':00');
|
||||
// 終了日
|
||||
if ($start_dd < $end_dd) {
|
||||
$end_date=$contract_end_dt->format('Y-m-') . str_pad($end_dd, 2, '0', STR_PAD_LEFT);
|
||||
$end_time = ($end_hm && preg_match('/^\d{2}:\d{2}$/', $end_hm)) ? $end_hm : '23:59';
|
||||
$end_dt = \Carbon\Carbon::createFromFormat('Y-m-d H:i:s', $end_date . ' ' . $end_time . ':00');
|
||||
} else {
|
||||
$next_month_dt = $contract_end_dt->copy()->addMonth();
|
||||
$end_date = $next_month_dt->format('Y-m-') . str_pad($end_dd, 2, '0', STR_PAD_LEFT);
|
||||
$end_time = ($end_hm && preg_match('/^\d{2}:\d{2}$/', $end_hm)) ? $end_hm : '23:59';
|
||||
$end_dt = \Carbon\Carbon::createFromFormat('Y-m-d H:i:s', $end_date . ' ' . $end_time . ':00');
|
||||
}
|
||||
} else {
|
||||
$start_dt = null;
|
||||
$end_dt = null;
|
||||
}
|
||||
// 以降は既存のボタン・背景色判定ロジック
|
||||
if ($update_flag===0) {
|
||||
$bg='bg-white';
|
||||
$btn_text='手続き中';
|
||||
$btn_active=false;
|
||||
}
|
||||
elseif ($update_flag===1) {
|
||||
$bg='bg-white';
|
||||
$btn_text='更新済';
|
||||
$btn_active=false;
|
||||
}
|
||||
elseif (!is_null($end_dt) && $end_dt->gt($start_dt)) {
|
||||
if ($start_dt && $now->lt($start_dt)) {
|
||||
$bg = 'bg-white';
|
||||
$btn_text = 'ご契約中';
|
||||
$btn_active = false;
|
||||
} else {
|
||||
// 契約終了日を過ぎていて、更新可能期間内は赤背景
|
||||
if ($contract_end_dt && $now->gt($contract_end_dt) && $start_dt && $end_dt && $now->between($start_dt, $end_dt)) {
|
||||
$bg = 'alert-danger';
|
||||
$btn_text = '更新する';
|
||||
$btn_active = true;
|
||||
} else {
|
||||
$bg = 'alert-warning';
|
||||
$btn_text = '更新する';
|
||||
$btn_active = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif ($start_dt && $start_dt->gt($end_dt)) {
|
||||
if ($now->lt($start_dt)) {
|
||||
$bg = 'bg-white';
|
||||
$btn_text = 'ご契約中';
|
||||
$btn_active = false;
|
||||
} elseif ($now->gte($start_dt) && $now->lte($contract_end_dt->copy()->endOfMonth())) {
|
||||
$bg = 'alert-warning';
|
||||
$btn_text = '更新する';
|
||||
$btn_active = true;
|
||||
} else {
|
||||
$bg = 'alert-danger';
|
||||
$btn_text = '更新する';
|
||||
$btn_active = true;
|
||||
}
|
||||
}
|
||||
@endphp
|
||||
<div>
|
||||
<div class="card {{ $bg }}">
|
||||
<h6 class="mt10 ml10 font-weight-bold">{{ $contract->park_name }}</h6>
|
||||
<table class="table table-sm">
|
||||
<tr>
|
||||
<th>{{ $contract->psection_subject ?? '' }}</th>
|
||||
<td>{{ $contract->usertype_subject1 ?? '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{ $contract->ptype_subject ?? '' }}</th>
|
||||
<td>{{ $contract->pplace_no ?? '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>定期契約ID</th>
|
||||
<td>{{ $contract->contract_id }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>期間</th>
|
||||
<td>{{ \Carbon\Carbon::parse($contract->contract_periods)->format('Y-m-d') }}から</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="text-center" colspan="2"><span class="h2">{{ $contract->enable_months }}</span>ヶ月</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-center" colspan="2">
|
||||
@if($btn_active)
|
||||
<a href="{{ url('regular_contract/update/' . $contract->contract_id) }}"
|
||||
class="btn {{ $bg == 'alert-warning' ? 'btn-warning' : ($bg == 'alert-danger' ? 'btn-danger' : 'btn-outline-secondary disabled') }} badge-pill">
|
||||
{{ $btn_text }}
|
||||
</a>
|
||||
@else
|
||||
<button class="btn btn-outline-secondary badge-pill disabled">{{ $btn_text }}</button>
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<p class="text-center">定期契約情報はありません<br>
|
||||
<a href="{{ url('regular_contract/create') }}" class="btn btn-block btn-lg btn-success">新規定期契約</a>
|
||||
</p>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-lg-6 mb20">
|
||||
<div class="card border-success mb20">
|
||||
<div class="card-header border-success text-success">
|
||||
<h5 class="card-title">シール発行</h5>
|
||||
</div>
|
||||
<div class="container slider_1-1">
|
||||
@forelse($seals as $seal)
|
||||
<article class="row">
|
||||
<figure class="col-12 col-md-4 float-right mt50">
|
||||
<div class="ml30 mt10 text-danger text-center">
|
||||
@if(!empty($seal->contract_qr_id))
|
||||
{!! QrCode::size(120)->generate($seal->contract_qr_id) !!}
|
||||
@else
|
||||
<div class="text-danger">QRコード<br>未発行</div>
|
||||
@endif
|
||||
</div>
|
||||
</figure>
|
||||
<div class="col-12 col-md-8">
|
||||
<h6 class="mt30 ml20 font-weight-bold"></h6>
|
||||
<table class="table table-sm ml20">
|
||||
<tr>
|
||||
<th style="padding-right:8px;padding-left:8px;">{{ $seal->psection_subject ?? '' }}</th>
|
||||
<td style="padding-left:8px;">{{ $seal->usertype_subject1 ?? '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th style="padding-right:8px;padding-left:8px;">{{ $seal->ptype_subject ?? '' }}</th>
|
||||
<td style="padding-left:8px;">{{ $seal->pplace_no ?? '' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th style="padding-right:8px;padding-left:8px;">定期契約ID</th>
|
||||
<td style="padding-left:8px;">{{ $seal->contract_id }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="text-center" colspan="2">
|
||||
<span class="h2">{{ $seal->enable_months }}</span>ヶ月
|
||||
</th>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</article>
|
||||
@empty
|
||||
<div class="text-center p-4">シール発行対象の契約はありません。</div>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
<div id="my-information" class="card border-success">
|
||||
<div class="card-header border-success text-success">
|
||||
<h5 class="card-title">{{ $user_name }}さんへのお知らせ
|
||||
<a href="{{ url('/user_information') }}" class="badge badge-secondary badge-pill float-right">お知らせ一覧を見る</a>
|
||||
</h5>
|
||||
</div>
|
||||
<ul class="info-slider_1-1">
|
||||
@if($information)
|
||||
<li>
|
||||
<span class="small" style="margin-right: 1em;">{{ $information->entry_date }}</span>
|
||||
{{ $information->user_information_history }}
|
||||
</li>
|
||||
@else
|
||||
<li class="text-center">お知らせはありません。</li>
|
||||
@endif
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
@endsection
|
||||
29
resources/views/park_waitlist/cancel.blade.php
Normal file
29
resources/views/park_waitlist/cancel.blade.php
Normal file
@ -0,0 +1,29 @@
|
||||
@extends('layouts.app')
|
||||
@section('content')
|
||||
<main>
|
||||
<header class="alert alert-success">
|
||||
<h4 class="container">空き待ち状況確認 > キャンセル</h4>
|
||||
</header>
|
||||
<section id="" class="container mt30 mb50">
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-8 offset-0 offset-md-2 mb30">
|
||||
<h3 class="text-center alert-success">キャンセルしますか?</h3>
|
||||
<ul>
|
||||
<li>キャンセル確定を押されますと確認ページは表示されません。即キャンセルになりますのでご注意ください。</li>
|
||||
<li>一度キャンセルされると再度予約しても順番は最後になります。予めご了承ください。</li>
|
||||
<li>再度予約を希望の場合は、空き待ち申込からお手続きください。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-12 col-md-4 offset-md-2 mt10">
|
||||
<a href="{{ route('park_waitlist.index') }}" class="btn btn-lg btn-block btn-outline-success">戻る</a>
|
||||
</div>
|
||||
<div class="col-12 col-md-4 offset-0 mt10">
|
||||
<form action="{{ route('park_waitlist.cancel.post', ['reserve_id' => $reserve_id]) }}" method="POST">
|
||||
@csrf
|
||||
<button type="submit" class="btn btn-lg btn-block btn-success">キャンセル確定</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
@endsection
|
||||
19
resources/views/park_waitlist/cancel_complete.blade.php
Normal file
19
resources/views/park_waitlist/cancel_complete.blade.php
Normal file
@ -0,0 +1,19 @@
|
||||
@extends('layouts.app')
|
||||
@section('content')
|
||||
<main>
|
||||
<header class="alert alert-success">
|
||||
<h4 class="container">空き待ち状況確認 > キャンセル完了</h4>
|
||||
</header>
|
||||
<section id="" class="container mt30 mb50">
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-8 offset-0 offset-md-2 mb30">
|
||||
<h3 class="text-center alert-success">駐輪場名:{{ $reserve->park_name }}</h3>
|
||||
<p class="mt30 mb30">上記の空き待ちキャンセルが完了しました。確認のメールを会員情報のメールアドレスに送信しました。</p>
|
||||
</div>
|
||||
<div class="col-12 col-md-8 offset-0 offset-md-2 mt30">
|
||||
<a href="{{ route('park_waitlist.index') }}" class="btn btn-lg btn-block btn-outline-success">予約状況一覧へ戻る</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
@endsection
|
||||
55
resources/views/park_waitlist/index.blade.php
Normal file
55
resources/views/park_waitlist/index.blade.php
Normal file
@ -0,0 +1,55 @@
|
||||
@extends('layouts.app')
|
||||
@section('content')
|
||||
<main>
|
||||
<style>
|
||||
/* テーブルヘッダーの色を #d4edda に固定し、クリックやフォーカス時も変化しない */
|
||||
#searchTable th,
|
||||
#searchTable th:active,
|
||||
#searchTable th:focus {
|
||||
background-color: #d4edda !important;
|
||||
color: #212529 !important;
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
#searchTable th {
|
||||
cursor: default !important;
|
||||
}
|
||||
</style>
|
||||
<header class="alert alert-success">
|
||||
<h4 class="container">空き待ち状況確認 > 予約状況</h4>
|
||||
</header>
|
||||
<section id="" class="container mt30 mb50">
|
||||
@if($waitlists->count())
|
||||
<div class="table-responsive">
|
||||
<table id="searchTable" class="tablesorter table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>予約日</th>
|
||||
<th>駐輪場名</th>
|
||||
<th>駅名</th>
|
||||
<th>駐輪分類</th>
|
||||
<th>車種区分</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($waitlists as $row)
|
||||
<tr>
|
||||
<td>{{ \Carbon\Carbon::parse($row->reserve_date)->format('Y/m/d') }}</td>
|
||||
<td><a href="javascript:void(0);" class="btn-reserve-popup text-primary" data-reserve-id="{{ $row->reserve_id }}">
|
||||
{{ $row->park_name }}
|
||||
</a></td>
|
||||
<td>{{ $row->station_neighbor_station }}</td>
|
||||
<td>{{ $row->ptype_subject }}</td>
|
||||
<td>{{ $row->psection_subject }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@else
|
||||
<div class="text-center mt-5">予約している駐輪場はありません。</div>
|
||||
@endif
|
||||
</section>
|
||||
</main>
|
||||
<div id="modalArea"></div>
|
||||
@endsection
|
||||
47
resources/views/park_waitlist/park_detail.blade.php
Normal file
47
resources/views/park_waitlist/park_detail.blade.php
Normal file
@ -0,0 +1,47 @@
|
||||
<!-- Bootstrapモーダル -->
|
||||
<div class="modal fade" id="parkDetailWaitModal" tabindex="-1" aria-labelledby="parkDetailWaitLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="parkDetailWaitLabel">{{ $park->park_name }}</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="閉じる">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- Googleマップ埋め込み -->
|
||||
<div style="width:100%; height:350px;">
|
||||
<iframe
|
||||
width="100%"
|
||||
height="350"
|
||||
frameborder="0"
|
||||
style="border:0"
|
||||
src="https://www.google.com/maps?q={{ $park->park_latitude }},{{ $park->park_longitude }}&hl=ja&z=16&output=embed"
|
||||
allowfullscreen>
|
||||
</iframe>
|
||||
</div>
|
||||
<!-- 駐輪場情報 -->
|
||||
<div class="mt-3 small">
|
||||
{{ $park->park_adrs }}
|
||||
<span class="d-inline-block" style="margin-top:0.5em;"></span>
|
||||
<span>
|
||||
【標準収容台数】
|
||||
@foreach($zoneStandardSum as $type => $count)
|
||||
{{ $type }}:{{ $count }}台
|
||||
@endforeach
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="{{ route('park_waitlist.cancel', ['reserve_id' => $reserve->reserve_id]) }}"
|
||||
class="btn btn-outline-success btn_103">
|
||||
キャンセルする
|
||||
</a>
|
||||
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">閉じる</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- jQuery Confirm用CSS/JS(jQuery本体は既に読み込まれていれば不要) -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-confirm/3.3.4/jquery-confirm.min.css">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-confirm/3.3.4/jquery-confirm.min.js"></script>
|
||||
@ -1,12 +1,11 @@
|
||||
@php
|
||||
// コントローラーから $user_name を渡してください
|
||||
if (!isset($user_name)) $user_name = '';
|
||||
@endphp
|
||||
<header id="top" class="bg-light">
|
||||
<div class="container pt10">
|
||||
<div class="row mt10 mb10">
|
||||
<div class="col-5 col-lg-4">
|
||||
<a id="site-logo" class="navbar-brand" href="{{ url('../index.html') }}">
|
||||
<a id="site-logo" class="navbar-brand" href="{{ url('/mypage') }}">
|
||||
<img src="{{ asset('assets/img/so-rin_logo.png') }}" alt="logo" />
|
||||
<h1>
|
||||
<span class="small pc">駐車場・駐輪場総合サポートの株式会社ソーリン<br></span>
|
||||
@ -15,12 +14,11 @@ if (!isset($user_name)) $user_name = '';
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-6 col-lg-4 ml-auto tl-btn-area">
|
||||
<a href="{{ url('SWO-4-1.html') }}" class="" id="login-btn">
|
||||
<a href="{{ url('/mypage') }}" class="" id="login-btn">
|
||||
<span class="small d-none d-xl-inline">ようこそ</span>{{ $user_name }}さん
|
||||
</a>
|
||||
<a href="{{ url('../index.html') }}" class="btn btn-outline-secondary badge-pill pc" id="sub-btn">ログアウト</a>
|
||||
<a href="{{ url('/logout') }}" class="btn btn-outline-secondary badge-pill pc" id="sub-btn">ログアウト</a>
|
||||
<a class="d-lg-none h2" data-toggle="collapse" data-target="#collapseExample" aria-expanded="false" aria-controls="collapseExample" href="#collapseExample" id="nav-menu-btn">
|
||||
<span class="typcn typcn-th-menu"></span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -15,15 +15,15 @@ if (!isset($active_menu)) $active_menu = '';
|
||||
<a id="my-menu-btn" class="navbar-toggler text-center" href="#navbarSupportedContent" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> マイメニューを開く </a>
|
||||
<div class="collapse navbar-collapse justify-content-around" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item {{ $active_menu == 'SWO-4-1' ? 'active' : '' }}"><a class="nav-link" href="{{ url('SWO-4-1.html') }}">マイページトップ<span class="sr-only">(current)</span></a></li>
|
||||
<li class="nav-item {{ $active_menu == 'SWO-4-1' ? 'active' : '' }}"><a class="nav-link" href="{{ url('/mypage') }}">マイページトップ<span class="sr-only">(current)</span></a></li>
|
||||
<li class="nav-item {{ $active_menu == 'SWC-1-1' ? 'active' : '' }}"><a class="nav-link" href="{{ url('/user/info') }}">ユーザー情報確認</a></li>
|
||||
<li class="nav-item {{ $active_menu == 'SWC-3-1' ? 'active' : '' }}"><a class="nav-link" href="{{ url('/regular_contract/info') }}">定期契約情報</a></li>
|
||||
<li class="nav-item {{ $active_menu == 'SWC-4-1' ? 'active' : '' }}"><a class="nav-link" href="{{ url('/regular_contract/update') }}">契約更新</a></li>
|
||||
<li class="nav-item {{ $active_menu == 'SWC-6-1' ? 'active' : '' }}"><a class="nav-link" href="{{ url('/regular_contract/history') }}">契約履歴</a></li>
|
||||
<li class="nav-item {{ $active_menu == 'SWC-8-1' ? 'active' : '' }}"><a class="nav-link" href="{{ url('/regular_contract/create') }}">新規定期契約</a></li>
|
||||
<li class="nav-item {{ $active_menu == 'SWC-11-1' ? 'active' : '' }}"><a class="nav-link" href="{{ url('/park_waitlist') }}">空き待ち状況確認</a></li>
|
||||
<li class="nav-item {{ $active_menu == 'SWC-10-1' ? 'active' : '' }}"><a class="nav-link" href="{{ url('SWC-10-1.html') }}">駐輪場検索</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="{{ url('../howto.html') }}" target="_blank">このページの使い方</a></li>
|
||||
<li class="nav-item {{ $active_menu == 'SWC-10-1' ? 'active' : '' }}"><a class="nav-link" href="{{ url('/park_search') }}">駐輪場検索</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="{{ route('swo16_1') }}" target="_blank">このページの使い方</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
</div>
|
||||
<div class="col-6 col-md-2 mb20">
|
||||
<div class="card text-center border-success">
|
||||
<a href="{{ url('SWC-10-1.html') }}" target="_top">
|
||||
<a href="{{ url('/park_search') }}" target="_top">
|
||||
<figure><img src="{{ asset('assets/img/menu-aki.png') }}" alt="" class="w-75 mt10"></figure>
|
||||
<p class="text-success">駐輪場検索</p><br>
|
||||
</a>
|
||||
@ -50,7 +50,7 @@
|
||||
</div>
|
||||
<div class="col-6 col-md-2 mb20">
|
||||
<div class="card text-center border-success">
|
||||
<a href="{{ url('SWC-15-1.html') }}" target="_top">
|
||||
<a href="{{ url('/user_information') }}" target="_top">
|
||||
<figure><img src="{{ asset('assets/img/menu-tuuchi.png') }}" alt="" class="w-75 mt10"></figure>
|
||||
<p class="text-success">お知らせ一覧</p>
|
||||
</a>
|
||||
@ -66,7 +66,7 @@
|
||||
</div>
|
||||
<div class="col-6 col-md-2 mb20">
|
||||
<div class="card text-center border-success">
|
||||
<a href="{{ url('../index.html') }}" target="_top">
|
||||
<a href="{{ route('logout') }}" target="_top">
|
||||
<figure><img src="{{ asset('assets/img/menu-logout.png') }}" alt="" class="w-75 mt10"></figure>
|
||||
<p class="text-success">ログアウト</p>
|
||||
</a>
|
||||
@ -74,7 +74,7 @@
|
||||
</div>
|
||||
<div class="col-6 col-md-2 mb20">
|
||||
<div class="card text-center border-success">
|
||||
<a href="{{ url('../howto.html') }}" target="_blank">
|
||||
<a href="{{ route('swo16_1') }}" target="_blank">
|
||||
<figure><img src="{{ asset('assets/img/menu-help.png') }}" alt="" class="w-75 mt10"></figure>
|
||||
<p class="text-success">このページの使い方</p>
|
||||
</a>
|
||||
|
||||
@ -2,7 +2,11 @@
|
||||
@section('content')
|
||||
<main>
|
||||
<header class="alert alert-success">
|
||||
@if($isRegularContract)
|
||||
<h4 class="container">新規定期契約 > 空き駐輪場を確認する</h4>
|
||||
@else
|
||||
<h4 class="container">駐輪場検索 > 駐輪場選択</h4>
|
||||
@endif
|
||||
</header>
|
||||
<section id="" class="container mt20 mb20">
|
||||
<div class="row">
|
||||
@ -47,100 +51,103 @@
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<table id="searchTable" class="tablesorter table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="header">
|
||||
駐輪場名
|
||||
<a href="{{ request()->fullUrlWithQuery(['sort' => 'park_ruby', 'order' => 'asc', 'page' => 1]) }}" class="text-success"><i class="bi bi-caret-up-fill"></i></a>
|
||||
<a href="{{ request()->fullUrlWithQuery(['sort' => 'park_ruby', 'order' => 'desc', 'page' => 1]) }}" class="text-success"><i class="bi bi-caret-down-fill"></i></a>
|
||||
</th>
|
||||
<th class="header">
|
||||
市町村名
|
||||
<a href="{{ request()->fullUrlWithQuery(['sort' => 'city_id', 'order' => 'asc', 'page' => 1]) }}" class="text-success"><i class="bi bi-caret-up-fill"></i></a>
|
||||
<a href="{{ request()->fullUrlWithQuery(['sort' => 'city_id', 'order' => 'desc', 'page' => 1]) }}" class="text-success"><i class="bi bi-caret-down-fill"></i></a>
|
||||
</th>
|
||||
<th class="header">
|
||||
駅名
|
||||
<a href="{{ request()->fullUrlWithQuery(['sort' => 'station_name_ruby', 'order' => 'asc', 'page' => 1]) }}" class="text-success"><i class="bi bi-caret-up-fill"></i></a>
|
||||
<a href="{{ request()->fullUrlWithQuery(['sort' => 'station_name_ruby', 'order' => 'desc', 'page' => 1]) }}" class="text-success"><i class="bi bi-caret-down-fill"></i></a>
|
||||
</th>
|
||||
<th class="header">自転車</th>
|
||||
<th class="header">原付</th>
|
||||
<th class="header">自動二輪</th>
|
||||
<th class="header">自動車</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($parks_table as $row)
|
||||
<tr>
|
||||
<td><a href="javascript:void(0);" class="btn-popup text-primary" data-park-id="{{ $row->park_id }}">
|
||||
{{ $row->park_name }}
|
||||
</a></td>
|
||||
<td>{{ $row->city_name }}</td>
|
||||
<td>{{ $row->station_neighbor_station }}</td>
|
||||
{{-- 自転車・原付・自動二輪・自動車列 --}}
|
||||
@foreach(['自転車', '原付', '自動二輪', '自動車'] as $vehicle)
|
||||
<td>
|
||||
@php
|
||||
$zonesForType = ($zones[$row->park_id] ?? collect())->where('psection_subject', $vehicle);
|
||||
@endphp
|
||||
@forelse ($zonesForType as $zone)
|
||||
@php
|
||||
$reserveCount = ($reserve[$row->park_id] ?? collect())
|
||||
->where('psection_id', $zone->psection_id)
|
||||
->count();
|
||||
$vacancy = $zone->zone_tolerance - $zone->zone_number - $reserveCount;
|
||||
// 猶予期間判定
|
||||
$grace = $city_grace_periods[$row->city_id] ?? null;
|
||||
$now = \Carbon\Carbon::now();
|
||||
$inGrace = false;
|
||||
if ($grace && $grace->update_grace_period_start_date && $grace->update_grace_period_start_time && $grace->update_grace_period_end_date && $grace->update_grace_period_end_time) {
|
||||
$year = $now->year;
|
||||
$month = $now->month;
|
||||
$startDay = (int)$grace->update_grace_period_start_date;
|
||||
$endDay = (int)$grace->update_grace_period_end_date;
|
||||
if ($startDay > $endDay) {
|
||||
// 月またぎ
|
||||
// 前月の開始日~今月の終了日
|
||||
$prevMonth = $now->copy()->subMonth();
|
||||
$startPrev = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $prevMonth->year, $prevMonth->month, $startDay, $grace->update_grace_period_start_time));
|
||||
$endCurr = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $year, $month, $endDay, $grace->update_grace_period_end_time));
|
||||
// 今月の開始日~翌月の終了日
|
||||
$startCurr = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $year, $month, $startDay, $grace->update_grace_period_start_time));
|
||||
$nextMonth = $month == 12 ? 1 : $month + 1;
|
||||
$nextYear = $month == 12 ? $year + 1 : $year;
|
||||
$endNext = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $nextYear, $nextMonth, $endDay, $grace->update_grace_period_end_time));
|
||||
$inGrace = $now->between($startPrev, $endCurr) || $now->between($startCurr, $endNext);
|
||||
} else {
|
||||
// 同月
|
||||
$start = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $year, $month, $startDay, $grace->update_grace_period_start_time));
|
||||
$end = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $year, $month, $endDay, $grace->update_grace_period_end_time));
|
||||
$inGrace = $now->between($start, $end);
|
||||
}
|
||||
}
|
||||
@endphp
|
||||
@if ($vacancy > 0 && $inGrace)
|
||||
<button class="btn btn-block btn-sm btn-outline-success btn_82-table btn-popup" data-park-id="{{ $row->park_id }}">定期契約</button>
|
||||
@elseif ($vacancy > 0 && !$inGrace)
|
||||
<button class="btn btn-block btn-sm btn-outline-danger btn_103-table btn-popup" data-park-id="{{ $row->park_id }}">販売期間外</button>
|
||||
@else
|
||||
<button class="btn btn-block btn-sm btn-outline-danger btn_103-table btn-popup" data-park-id="{{ $row->park_id }}">空き待ち申込</button>
|
||||
@endif
|
||||
@empty
|
||||
<span class="text-muted"></span>
|
||||
@endforelse
|
||||
</td>
|
||||
@endforeach
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="7" class="text-center">該当する駐輪場はありません。</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
<div style="overflow-x: auto; width: 100%;">
|
||||
<table id="searchTable" class="tablesorter table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="header" style="cursor:default; pointer-events: none; background-color: #d4edda !important;">駐輪場名</th>
|
||||
<th class="header" style="cursor:default; pointer-events: none;">市町村名</th>
|
||||
<th class="header" style="cursor:default; pointer-events: none;">駅名</th>
|
||||
<th class="header" style="cursor:default; pointer-events: none;">自転車</th>
|
||||
<th class="header" style="cursor:default; pointer-events: none;">原付</th>
|
||||
<th class="header" style="cursor:default; pointer-events: none;">自動二輪</th>
|
||||
<th class="header" style="cursor:default; pointer-events: none;">自動車</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($parks_table as $row)
|
||||
<tr>
|
||||
<td><a href="javascript:void(0);" class="btn-popup text-primary" data-park-id="{{ $row->park_id }}">
|
||||
{{ $row->park_name }}
|
||||
</a></td>
|
||||
<td>{{ $row->city_name }}</td>
|
||||
<td>{{ $row->station_neighbor_station }}</td>
|
||||
{{-- 自転車・原付・自動二輪・自動車列 --}}
|
||||
@foreach(['自転車', '原付', '自動二輪', '自動車'] as $vehicle)
|
||||
<td>
|
||||
@php
|
||||
$zonesForType = ($zones[$row->park_id] ?? collect())->where('psection_subject', $vehicle);
|
||||
// 空き台数計算
|
||||
$hasVacancy = false;
|
||||
foreach ($zonesForType as $zone) {
|
||||
$reserveCount = ($reserve[$row->park_id] ?? collect())
|
||||
->where('psection_id', $zone->psection_id)
|
||||
->where('ptype_id', $zone->ptype_id)
|
||||
->count();
|
||||
$vacancy = $zone->zone_tolerance - $zone->zone_number - $reserveCount;
|
||||
if ($vacancy > 0) {
|
||||
$hasVacancy = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 猶予期間判定
|
||||
$grace = $city_grace_periods[$row->city_id] ?? null;
|
||||
$gracePeriodValid =
|
||||
$grace &&
|
||||
is_numeric($grace->update_grace_period_start_date) &&
|
||||
preg_match('/^\d{1,2}:\d{2}$/', $grace->update_grace_period_start_time) &&
|
||||
is_numeric($grace->update_grace_period_end_date) &&
|
||||
preg_match('/^\d{1,2}:\d{2}$/', $grace->update_grace_period_end_time);
|
||||
|
||||
$inGrace = false;
|
||||
if ($gracePeriodValid) {
|
||||
$now = \Carbon\Carbon::now();
|
||||
$year = $now->year;
|
||||
$month = $now->month;
|
||||
$startDay = (int)$grace->update_grace_period_start_date;
|
||||
$endDay = (int)$grace->update_grace_period_end_date;
|
||||
if ($startDay > $endDay) {
|
||||
// 月またぎ
|
||||
// 前月の開始日~今月の終了日
|
||||
$prevMonth = $now->copy()->subMonth();
|
||||
$startPrev = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $prevMonth->year, $prevMonth->month, $startDay, $grace->update_grace_period_start_time));
|
||||
$endCurr = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $year, $month, $endDay, $grace->update_grace_period_end_time));
|
||||
// 今月の開始日~翌月の終了日
|
||||
$startCurr = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $year, $month, $startDay, $grace->update_grace_period_start_time));
|
||||
$nextMonth = $month == 12 ? 1 : $month + 1;
|
||||
$nextYear = $month == 12 ? $year + 1 : $year;
|
||||
$endNext = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $nextYear, $nextMonth, $endDay, $grace->update_grace_period_end_time));
|
||||
$inGrace = $now->between($startPrev, $endCurr) || $now->between($startCurr, $endNext);
|
||||
} else {
|
||||
// 同月
|
||||
$start = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $year, $month, $startDay, $grace->update_grace_period_start_time));
|
||||
$end = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $year, $month, $endDay, $grace->update_grace_period_end_time));
|
||||
$inGrace = $now->between($start, $end);
|
||||
}
|
||||
}
|
||||
@endphp
|
||||
@if ($zonesForType->isNotEmpty() && $gracePeriodValid)
|
||||
@if ($hasVacancy && $inGrace)
|
||||
<button class="btn btn-block btn-sm btn-outline-success btn_82-table btn-popup" data-park-id="{{ $row->park_id }}">定期契約</button>
|
||||
@elseif (!$inGrace)
|
||||
<button class="btn btn-block btn-sm btn-outline-danger btn_103-table btn-popup" data-park-id="{{ $row->park_id }}">販売期間外</button>
|
||||
@elseif (!$hasVacancy && $inGrace)
|
||||
<button class="btn btn-block btn-sm btn-outline-danger btn_103-table btn-popup" data-park-id="{{ $row->park_id }}">空き待ち申込</button>
|
||||
@endif
|
||||
@else
|
||||
<span class="text-muted"></span>
|
||||
@endif
|
||||
</td>
|
||||
@endforeach
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="7" class="text-center">該当する駐輪場はありません。</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@php
|
||||
$totalPages = ceil($parks_table_total / $parks_table_perPage);
|
||||
$currentPage = $parks_table_page;
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
{{ $errors->first('month') }}
|
||||
</div>
|
||||
@endif
|
||||
<form class="row form" action="{{ url('regular_contract/update_period') }}" method="post">
|
||||
<form class="row form" action="{{ route('regular_contract.create_select_period') }}" method="post">
|
||||
@csrf
|
||||
<input type="hidden" name="contract_id" value="{{ $contract_id }}">
|
||||
<div class="col-12 col-md-8 offset-0 offset-md-2 mb30">
|
||||
|
||||
@ -262,26 +262,35 @@ return null;
|
||||
<button type="button" id="cancelModalBtn" class="btn btn-outline-secondary badge-pill custom-rounded-btn" style="background: transparent;" data-bs-toggle="modal" data-bs-target="#cancelModal">解約について</button>
|
||||
@endif
|
||||
</div>
|
||||
@php
|
||||
$has_receipt = DB::table('inv_publish')->where('contract_id', $contract->contract_id)->exists();
|
||||
@endphp
|
||||
@if($has_receipt)
|
||||
@if($bg == 'alert-warning')
|
||||
<a href="{{ url('receipt/download/' . $contract->contract_id) }}" class="btn btn-outline-warning badge-pill custom-rounded-btn" style="background: transparent;">領収書再発行</a>
|
||||
@elseif($bg == 'alert-danger')
|
||||
<a href="{{ url('receipt/download/' . $contract->contract_id) }}" class="btn btn-outline-danger badge-pill custom-rounded-btn" style="background: transparent;">領収書再発行</a>
|
||||
@else
|
||||
<a href="{{ url('receipt/download/' . $contract->contract_id) }}" class="btn btn-outline-secondary badge-pill custom-rounded-btn" style="background: transparent;">領収書再発行</a>
|
||||
@endif
|
||||
@else
|
||||
@if($bg == 'alert-warning')
|
||||
<a href="{{ url('receipt/input/' . $contract->contract_id) }}" class="btn btn-outline-warning badge-pill custom-rounded-btn" style="background: transparent;">領収書発行</a>
|
||||
@elseif($bg == 'alert-danger')
|
||||
<a href="{{ url('receipt/input/' . $contract->contract_id) }}" class="btn btn-outline-danger badge-pill custom-rounded-btn" style="background: transparent;">領収書発行</a>
|
||||
@else
|
||||
<a href="{{ url('receipt/input/' . $contract->contract_id) }}" class="btn btn-outline-secondary badge-pill custom-rounded-btn" style="background: transparent;">領収書発行</a>
|
||||
@endif
|
||||
@endif
|
||||
<div style="display: flex; gap: 6px;">
|
||||
@php
|
||||
$has_receipt = DB::table('inv_publish')->where('contract_id', $contract->contract_id)->exists();
|
||||
@endphp
|
||||
@if($has_receipt)
|
||||
@if($bg == 'alert-warning')
|
||||
<a href="{{ url('receipt/download/' . $contract->contract_id) }}" class="btn btn-outline-warning badge-pill custom-rounded-btn" style="background: transparent;">領収書再発行</a>
|
||||
@elseif($bg == 'alert-danger')
|
||||
<a href="{{ url('receipt/download/' . $contract->contract_id) }}" class="btn btn-outline-danger badge-pill custom-rounded-btn" style="background: transparent;">領収書再発行</a>
|
||||
@else
|
||||
<a href="{{ url('receipt/download/' . $contract->contract_id) }}" class="btn btn-outline-secondary badge-pill custom-rounded-btn" style="background: transparent;">領収書再発行</a>
|
||||
@endif
|
||||
@else
|
||||
@if($bg == 'alert-warning')
|
||||
<a href="{{ url('receipt/input/' . $contract->contract_id) }}" class="btn btn-outline-warning badge-pill custom-rounded-btn" style="background: transparent;">領収書発行</a>
|
||||
@elseif($bg == 'alert-danger')
|
||||
<a href="{{ url('receipt/input/' . $contract->contract_id) }}" class="btn btn-outline-danger badge-pill custom-rounded-btn" style="background: transparent;">領収書発行</a>
|
||||
@else
|
||||
<a href="{{ url('receipt/input/' . $contract->contract_id) }}" class="btn btn-outline-secondary badge-pill custom-rounded-btn" style="background: transparent;">領収書発行</a>
|
||||
@endif
|
||||
@endif
|
||||
@if($bg == 'alert-warning')
|
||||
<a href="{{ url('seal/reissue/' . $contract->contract_id) }}" class="btn btn-outline-warning badge-pill custom-rounded-btn" style="background: transparent;">シール再発行</a>
|
||||
@elseif($bg == 'alert-danger')
|
||||
<a href="{{ url('seal/reissue/' . $contract->contract_id) }}" class="btn btn-outline-danger badge-pill custom-rounded-btn" style="background: transparent;">シール再発行</a>
|
||||
@else
|
||||
<a href="{{ url('seal/reissue/' . $contract->contract_id) }}" class="btn btn-outline-secondary badge-pill custom-rounded-btn" style="background: transparent;">シール再発行</a>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@ -36,64 +36,79 @@
|
||||
</div>
|
||||
<!-- 空き台数・契約情報 -->
|
||||
<div class="mt-3">
|
||||
@foreach($zones as $zone)
|
||||
@php
|
||||
$vacant = $vacancyData[$zone->psection_id . '_' . $zone->ptype_subject] ?? 0;
|
||||
$grace = $city_grace_periods[$park->city_id] ?? null;
|
||||
$now = \Carbon\Carbon::now();
|
||||
|
||||
// 猶予期間判定
|
||||
$isGracePeriod = false;
|
||||
if ($grace && $grace->update_grace_period_start_date && $grace->update_grace_period_start_time && $grace->update_grace_period_end_date && $grace->update_grace_period_end_time) {
|
||||
$now = \Carbon\Carbon::now();
|
||||
$year = $now->year;
|
||||
$month = $now->month;
|
||||
$startDay = (int)$grace->update_grace_period_start_date;
|
||||
$endDay = (int)$grace->update_grace_period_end_date;
|
||||
$startTime = $grace->update_grace_period_start_time;
|
||||
$endTime = $grace->update_grace_period_end_time;
|
||||
|
||||
if ($startDay > $endDay) {
|
||||
// 月またぎ
|
||||
$start = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $year, $month, $startDay, $startTime));
|
||||
$nextMonth = $month == 12 ? 1 : $month + 1;
|
||||
$nextYear = $month == 12 ? $year + 1 : $year;
|
||||
$end = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $nextYear, $nextMonth, $endDay, $endTime));
|
||||
} else {
|
||||
// 同月
|
||||
$start = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $year, $month, $startDay, $startTime));
|
||||
$end = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $year, $month, $endDay, $endTime));
|
||||
}
|
||||
$isGracePeriod = $now->between($start, $end);
|
||||
}
|
||||
$zonesByPtype = $zones->groupBy('ptype_id');
|
||||
@endphp
|
||||
<div class="mb-2">
|
||||
<strong>{{ $zone->ptype_subject }}</strong><br>
|
||||
{{ $zone->psection_subject }}:空き {{ $vacant }}台
|
||||
@if($isGracePeriod)
|
||||
@if($vacant > 0)
|
||||
<button type="button" class="btn btn-success btn-sm btn-contract"
|
||||
data-park-id="{{ $park->park_id }}"
|
||||
data-psection-id="{{ $zone->psection_id }}"
|
||||
data-ptype-id="{{ $zone->ptype_id }}">
|
||||
定期契約
|
||||
</button>
|
||||
@else
|
||||
<button type="button" class="btn btn-danger btn_103 btn-reserve"
|
||||
data-park-id="{{ $park->park_id }}"
|
||||
data-psection-id="{{ $zone->psection_id }}"
|
||||
data-ptype-id="{{ $zone->ptype_id }}">
|
||||
空き待ち申込
|
||||
</button>
|
||||
@endif
|
||||
@else
|
||||
<button type="button" class="btn btn-danger btn_103 btn-reserve"
|
||||
data-park-id="{{ $park->park_id }}"
|
||||
data-psection-id="{{ $zone->psection_id }}"
|
||||
data-ptype-id="{{ $zone->ptype_id }}">
|
||||
販売期間外
|
||||
</button>
|
||||
@endif
|
||||
@foreach($zonesByPtype as $ptypeId => $zonesGroup)
|
||||
<div class="mb-3">
|
||||
<strong>{{ $zonesGroup->first()->ptype_subject }}</strong>
|
||||
<div style="display: flex; gap: 1em;">
|
||||
@foreach($zonesGroup as $zone)
|
||||
@php
|
||||
$vacant = $vacancyData[$zone->psection_id . '_' . $zone->ptype_subject] ?? 0;
|
||||
$grace = $city_grace_periods[$park->city_id] ?? null;
|
||||
$now = \Carbon\Carbon::now();
|
||||
|
||||
// 猶予期間判定
|
||||
$isGracePeriod = false;
|
||||
if ($grace && $grace->update_grace_period_start_date && $grace->update_grace_period_start_time && $grace->update_grace_period_end_date && $grace->update_grace_period_end_time) {
|
||||
$now = \Carbon\Carbon::now();
|
||||
$year = $now->year;
|
||||
$month = $now->month;
|
||||
$startDay = (int)$grace->update_grace_period_start_date;
|
||||
$endDay = (int)$grace->update_grace_period_end_date;
|
||||
$startTime = $grace->update_grace_period_start_time;
|
||||
$endTime = $grace->update_grace_period_end_time;
|
||||
|
||||
if ($startDay > $endDay) {
|
||||
// 月またぎ
|
||||
// 前月の開始日~今月の終了日
|
||||
$prevMonth = $now->copy()->subMonth();
|
||||
$startPrev = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $prevMonth->year, $prevMonth->month, $startDay, $grace->update_grace_period_start_time));
|
||||
$endCurr = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $year, $month, $endDay, $grace->update_grace_period_end_time));
|
||||
// 今月の開始日~翌月の終了日
|
||||
$startCurr = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $year, $month, $startDay, $grace->update_grace_period_start_time));
|
||||
$nextMonth = $month == 12 ? 1 : $month + 1;
|
||||
$nextYear = $month == 12 ? $year + 1 : $year;
|
||||
$endNext = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $nextYear, $nextMonth, $endDay, $grace->update_grace_period_end_time));
|
||||
$isGracePeriod = $now->between($startPrev, $endCurr) || $now->between($startCurr, $endNext);
|
||||
} else {
|
||||
// 同月
|
||||
$start = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $year, $month, $startDay, $grace->update_grace_period_start_time));
|
||||
$end = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $year, $month, $endDay, $grace->update_grace_period_end_time));
|
||||
$isGracePeriod = $now->between($start, $end);
|
||||
}
|
||||
}
|
||||
@endphp
|
||||
<div class="mb-2">
|
||||
{{ $zone->psection_subject }}:空き {{ max(0, $vacant) }}台
|
||||
@if($isGracePeriod)
|
||||
@if($vacant > 0)
|
||||
<button type="button" class="btn btn-success btn-sm btn-contract"
|
||||
data-park-id="{{ $park->park_id }}"
|
||||
data-psection-id="{{ $zone->psection_id }}"
|
||||
data-ptype-id="{{ $zone->ptype_id }}">
|
||||
定期契約
|
||||
</button>
|
||||
@else
|
||||
<button type="button" class="btn btn-danger btn-sm btn_103 btn-reserve"
|
||||
data-park-id="{{ $park->park_id }}"
|
||||
data-psection-id="{{ $zone->psection_id }}"
|
||||
data-ptype-id="{{ $zone->ptype_id }}">
|
||||
空き待ち申込
|
||||
</button>
|
||||
@endif
|
||||
@else
|
||||
<button type="button" class="btn btn-danger btn-sm btn_103 btn-reserve"
|
||||
data-park-id="{{ $park->park_id }}"
|
||||
data-psection-id="{{ $zone->psection_id }}"
|
||||
data-ptype-id="{{ $zone->ptype_id }}">
|
||||
販売期間外
|
||||
</button>
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
27
resources/views/regular_contract/seal_reissue.blade.php
Normal file
27
resources/views/regular_contract/seal_reissue.blade.php
Normal file
@ -0,0 +1,27 @@
|
||||
@extends('layouts.app')
|
||||
@section('content')
|
||||
<main>
|
||||
<header class="alert alert-success">
|
||||
<h4 class="container">定期契約情報確認 > シール再発行</h4>
|
||||
</header>
|
||||
<section id="" class="container mt30 mb50">
|
||||
<div class="col-12 col-md-8 offset-0 offset-md-2 mb30">
|
||||
<h3 class="text-center alert-success">選択した駐輪場</h3>
|
||||
</div>
|
||||
<div class="col-12 col-md-8 offset-0 offset-md-2 mb30">
|
||||
<h3 class="text-center alert-warning">
|
||||
<span class="small">定期契約ID: {{ $contract->contract_id }}<br>{{ $contract->park_name }}</span>
|
||||
</h3>
|
||||
<p class="text-center"><br>こちらのシールを再発行します。<br>よろしいですか?</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-5 offset-md-1 mt10">
|
||||
<a href="{{ url('regular_contract/info') }}" class="btn btn-lg btn-block btn-outline-success">戻る</a>
|
||||
</div>
|
||||
<div class="col-12 col-md-5 mt10">
|
||||
<a href="{{ url('seal/reissue/reason/' . $contract->contract_id) }}" class="btn btn-lg btn-block btn-success">進む</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
@endsection
|
||||
@ -0,0 +1,20 @@
|
||||
@extends('layouts.app')
|
||||
@section('content')
|
||||
<main>
|
||||
<header class="alert alert-success">
|
||||
<h4 class="container">定期契約情報確認 > シール再発行</h4>
|
||||
</header>
|
||||
<section id="" class="container mt30 mb50">
|
||||
<div class="col-12 col-md-8 offset-0 offset-md-2 mb30">
|
||||
<h3 class="text-center alert-warning">
|
||||
<span class="small">定期契約ID: {{ $contract->contract_id }}<br></span>
|
||||
<span>{{ $contract->park_name }}</span>
|
||||
</h3>
|
||||
<p class="text-center"><br>こちらのシールの再発行準備が整いました。<br>上記駐輪場にてシールをお受け取りください。</p>
|
||||
</div>
|
||||
<div class="col-12 col-md-8 offset-0 offset-md-2 mb30">
|
||||
<a href="{{ url('mypage') }}" class="btn btn-lg btn-block btn-outline-success">マイページへ戻る</a>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
@endsection
|
||||
@ -0,0 +1,86 @@
|
||||
@extends('layouts.app')
|
||||
@section('content')
|
||||
<main>
|
||||
<header class="alert alert-success">
|
||||
<h4 class="container">ユーザー情報確認 > シール再発行理由</h4>
|
||||
</header>
|
||||
@if ($errors->any())
|
||||
<div class="alert alert-danger text-center">
|
||||
@foreach ($errors->all() as $error)
|
||||
<div>{{ $error }}</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
<section class="container mt30 mb50">
|
||||
<div class="col-12 col-md-8 offset-0 offset-md-2 mb30">
|
||||
<h2 class="text-center alert-success">再発行手続き</h2>
|
||||
</div>
|
||||
<form method="POST" action="{{ url('seal/reissue/complete/' . $contract_id) }}">
|
||||
@csrf
|
||||
<div class="col-12 col-md-8 offset-0 offset-md-2 mb30">
|
||||
<div class="mb-4">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="reason" id="reason1" value="自動車の買い換え">
|
||||
<label class="form-check-label" for="reason1">自動車の買い換え</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="reason" id="reason2" value="汚損">
|
||||
<label class="form-check-label" for="reason2">汚損</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="reason" id="reason3" value="盗難">
|
||||
<label class="form-check-label" for="reason3">盗難</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="reason" id="reason4" value="その他">
|
||||
<label class="form-check-label" for="reason4">その他</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-4" id="other-reason-area" style="display: none;">
|
||||
<textarea class="form-control" name="other_reason" rows="4" maxlength="255"
|
||||
placeholder="その他の場合、こちらへ理由をご入力ください" style="resize: none;"></textarea>
|
||||
<div class="text-right small"><span id="char-count">0</span>/255</div>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
【再発行に関する注意事項】<br>
|
||||
2回以上の再発行には別途手続きが必要です。<br>
|
||||
紛失にはご注意ください。
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-5 offset-md-1 mt10">
|
||||
<a href="{{ url('seal/reissue/' . $contract_id) }}" class="btn btn-lg btn-block btn-outline-success">戻る</a>
|
||||
</div>
|
||||
<div class="col-12 col-md-5 mt10">
|
||||
<button type="submit" class="btn btn-lg btn-block btn-success">進む</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
</main>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// ラジオボタンの選択でテキストエリア表示切替
|
||||
const radios = document.querySelectorAll('input[name="reason"]');
|
||||
const otherArea = document.getElementById('other-reason-area');
|
||||
radios.forEach(radio => {
|
||||
radio.addEventListener('change', function() {
|
||||
if (this.value === 'その他') {
|
||||
otherArea.style.display = '';
|
||||
} else {
|
||||
otherArea.style.display = 'none';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 文字数カウント
|
||||
const textarea = document.querySelector('textarea[name="other_reason"]');
|
||||
const charCount = document.getElementById('char-count');
|
||||
if (textarea) {
|
||||
textarea.addEventListener('input', function() {
|
||||
charCount.textContent = this.value.length;
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
@ -16,7 +16,7 @@ return null;
|
||||
@endphp
|
||||
<main>
|
||||
<header class="alert alert-success">
|
||||
<h4 class="container">定期契約情報 > 定期契約情報を確認する</h4>
|
||||
<h4 class="container">契約更新 > 定期契約を更新する</h4>
|
||||
</header>
|
||||
<section class="container mt30 mb50">
|
||||
@if(count($contracts) > 0)
|
||||
@ -294,7 +294,6 @@ return null;
|
||||
</section>
|
||||
</main>
|
||||
|
||||
@endsection
|
||||
<!-- 解約についてモーダル -->
|
||||
<div class="modal fade" id="cancelModal" tabindex="-1" aria-labelledby="cancelModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
@ -313,9 +312,9 @@ return null;
|
||||
border-radius: 2rem !important;
|
||||
padding-left: 2rem !important;
|
||||
padding-right: 2rem !important;
|
||||
font-weight: 500;
|
||||
min-width: 140px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
</style>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
@endsection
|
||||
@ -3,9 +3,9 @@
|
||||
@section('content')
|
||||
<main>
|
||||
@if (session('success'))
|
||||
<div class="alert alert-success">
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
<div class="alert alert-success">
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
<header class="alert alert-success">
|
||||
<h4 class="container">ユーザー情報確認 > ユーザー情報</h4>
|
||||
@ -60,7 +60,7 @@
|
||||
<div class="col-12 col-lg-6 mb10">
|
||||
<h3>{{ $user_category }}</h3>
|
||||
</div>
|
||||
@if ($user->ward_residents == 0 || $user->ward_residents == 2)
|
||||
@if ($user_category === '一般')
|
||||
<div class="col-12 col-md-3 offset-0 offset-md-2">
|
||||
<label for="user_workplace">勤務先名</label>
|
||||
</div>
|
||||
@ -68,7 +68,7 @@
|
||||
<h3>{{ $user->user_workplace }}</h3>
|
||||
</div>
|
||||
@endif
|
||||
@if ($user->ward_residents == 1)
|
||||
@if ($user_category === '学生')
|
||||
<div class="col-12 col-md-3 offset-0 offset-md-2">
|
||||
<label for="user_school">学校名</label>
|
||||
</div>
|
||||
@ -87,9 +87,9 @@
|
||||
</div>
|
||||
<div class="col-12 col-lg-6 mb10">
|
||||
@if(!empty($user->photo_filename1))
|
||||
<h3><img src="{{ asset('storage/photo/' . $user->photo_filename1) }}"></h3>
|
||||
<h3><img src="{{ asset('storage/photo/' . $user->photo_filename1) }}"></h3>
|
||||
@else
|
||||
<h3></h3>
|
||||
<h3></h3>
|
||||
@endif
|
||||
</div>
|
||||
<div class="col-12 col-md-3 offset-0 offset-md-2">
|
||||
@ -97,9 +97,9 @@
|
||||
</div>
|
||||
<div class="col-12 col-lg-6 mb10">
|
||||
@if(!empty($user->photo_filename2))
|
||||
<h3><img src="{{ asset('storage/photo/' . $user->photo_filename2) }}"></h3>
|
||||
<h3><img src="{{ asset('storage/photo/' . $user->photo_filename2) }}"></h3>
|
||||
@else
|
||||
<h3></h3>
|
||||
<h3></h3>
|
||||
@endif
|
||||
</div>
|
||||
<div class="col-12 col-md-3 offset-0 offset-md-2">
|
||||
@ -114,6 +114,9 @@
|
||||
<div class="col-12 col-md-5 mt10">
|
||||
<a class="btn btn-lg btn-block btn-outline-success" href="{{ url('/user/withdraw') }}">退会する</a>
|
||||
</div>
|
||||
<div class="col-12 col-md-4 offset-0 offset-md-4 mt50 mb50">
|
||||
<a class="btn btn-lg btn-block btn-success" href="{{ url('/user/tag_reissue') }}">タグの再発行を行う</a>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
83
resources/views/user/tag_reissue.blade.php
Normal file
83
resources/views/user/tag_reissue.blade.php
Normal file
@ -0,0 +1,83 @@
|
||||
@extends('layouts.app')
|
||||
@section('content')
|
||||
<main>
|
||||
<header class="alert alert-success">
|
||||
<h4 class="container">ユーザー情報確認 > タグ再発行申請</h4>
|
||||
</header>
|
||||
<section id="" class="container mt30 mb50">
|
||||
<div class="alert alert-success text-center pt20 pb10 mb30">
|
||||
<h5>タグ再発行を行うお客様の情報をご確認ください。</h5>
|
||||
<p>住所、電話番号、メールアドレス等に変更がある場合、再発行を申請する前にユーザー情報確認から<br class="pc">お客様の情報を最新状態へ更新をお願いいたします。</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-3 offset-0 offset-md-1">
|
||||
<label for="user_name">お名前</label>
|
||||
</div>
|
||||
<div class="col-12 col-lg-6 mb10">
|
||||
<h3>{{ $user->user_name }}</h3>
|
||||
</div>
|
||||
<div class="col-12 col-md-3 offset-0 offset-md-1">
|
||||
<label for="user_phonetic">フリガナ</label>
|
||||
</div>
|
||||
<div class="col-12 col-lg-6 mb10">
|
||||
<h3>{{ $user->user_phonetic }}</h3>
|
||||
</div>
|
||||
<div class="col-12 col-md-3 offset-0 offset-md-1">
|
||||
<label for="user_gender">性別</label>
|
||||
</div>
|
||||
<div class="col-12 col-lg-6 mb10">
|
||||
<h3>{{ $user->user_gender ?? '未入力' }}</h3>
|
||||
</div>
|
||||
<div class="col-12 col-md-3 offset-0 offset-md-1">
|
||||
<label for="user_regident">居住所</label>
|
||||
</div>
|
||||
<div class="col-12 col-lg-6 mb10">
|
||||
<h3>{{ $user->user_regident_zip }}{{ $user->user_regident_pre }}{{ $user->user_regident_city }}{{ $user->user_regident_add }}</h3>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-3 offset-0 offset-md-1">
|
||||
<label for="user_homephone">自宅電話番号</label>
|
||||
</div>
|
||||
<div class="col-12 col-lg-6 mb10">
|
||||
<h3>{{ $user->user_homephone ?? '未入力' }}</h3>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-3 offset-0 offset-md-1">
|
||||
<label for="user_mobile">携帯電話番号</label>
|
||||
</div>
|
||||
<div class="col-12 col-lg-6 mb10">
|
||||
<h3>{{ $user->user_mobile ?? '未入力' }}</h3>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-3 offset-0 offset-md-1">
|
||||
<label for="user_primemail">メールアドレス</label>
|
||||
</div>
|
||||
<div class="col-12 col-lg-6 mb10">
|
||||
<h3>{{ $user->user_primemail }}</h3>
|
||||
</div>
|
||||
<div class="col-12 col-md-3 offset-0 offset-md-1">
|
||||
<label for="user_submail">予備メールアドレス</label>
|
||||
</div>
|
||||
<div class="col-12 col-lg-6 mb10">
|
||||
<h3>{{ $user->user_submail ?? '未入力' }}</h3>
|
||||
</div>
|
||||
<div class="col-12 col-md-3 offset-0 offset-md-1">
|
||||
<label for="user_pass">パスワード</label>
|
||||
</div>
|
||||
<div class="col-12 col-lg-6 mb10">
|
||||
<h3>********</h3>
|
||||
</div>
|
||||
<div class="col-12 col-md-5 offset-0 offset-md-1 mt10">
|
||||
<a href="{{ url('/user/edit') }}" class="btn btn-lg btn-block btn-success">ユーザー情報を変更する</a>
|
||||
</div>
|
||||
<div class="col-12 col-md-5 mt10">
|
||||
<a href="{{ url('/user/tag_reissue/complete') }}" class="btn btn-lg btn-block btn-outline-success">再発行申請する</a>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-6 offset-0 offset-md-3 mt50 mb50">
|
||||
<a href="{{ url('/mypage') }}" class="btn btn-lg btn-block btn-outline-success">マイページへ戻る</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
@endsection
|
||||
17
resources/views/user/tag_reissue_complete.blade.php
Normal file
17
resources/views/user/tag_reissue_complete.blade.php
Normal file
@ -0,0 +1,17 @@
|
||||
@extends('layouts.app')
|
||||
@section('content')
|
||||
<main>
|
||||
<header class="alert alert-success">
|
||||
<h4 class="container">ユーザー情報確認 > タグ再発行申請完了</h4>
|
||||
</header>
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-8 offset-0 offset-md-2 mt-4 mb30">
|
||||
<h3 class="text-center">タグの再発行申請が完了しました。</h3>
|
||||
<p class="mt30 text-center">現在オペレーターが確認中です。<br>タグの再発行までいましばらくお待ちください。</p>
|
||||
<div class="col-12 col-md-6 offset-0 offset-md-3 mt50 mb50">
|
||||
<a href="{{ url('/mypage') }}" class="btn btn-lg btn-block btn-outline-success">マイページへ戻る</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
@endsection
|
||||
37
resources/views/user_information/history.blade.php
Normal file
37
resources/views/user_information/history.blade.php
Normal file
@ -0,0 +1,37 @@
|
||||
@extends('layouts.app')
|
||||
@section('content')
|
||||
<main>
|
||||
<header class="alert alert-success">
|
||||
<h4 class="container">お知らせ > 過去のお知らせ</h4>
|
||||
</header>
|
||||
<section id="" class="container mt30 mb50">
|
||||
<div class="col-12 col-md-8 offset-0 offset-md-2 mb30">
|
||||
<h3 class="text-center alert-success">過去のお知らせ</h3>
|
||||
</div>
|
||||
<div class="row">
|
||||
@forelse($informations as $information)
|
||||
<div class="col-12 col-md-3 offset-0 offset-md-2">
|
||||
<h5 class="text-success">
|
||||
{{ \Carbon\Carbon::parse($information->entry_date)->format('Y年n月j日') }}
|
||||
</h5>
|
||||
</div>
|
||||
<div class="col-12 col-lg-7 mb10">
|
||||
<p class="h5 font-weight-normal">
|
||||
{{ $information->user_information_history }}
|
||||
</p>
|
||||
</div>
|
||||
@empty
|
||||
<div class="col-12 text-center py-5">
|
||||
<p>過去のお知らせはありません。</p>
|
||||
</div>
|
||||
@endforelse
|
||||
</div>
|
||||
<div class="d-flex justify-content-center mt-4">
|
||||
{{ $informations->links('partials.paging') }}
|
||||
</div>
|
||||
<div class="col-12 col-md-6 offset-0 offset-md-3 mt-4 mb50">
|
||||
<a href="{{ url('mypage') }}" class="btn btn-lg btn-block btn-outline-success">マイページへ戻る</a>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
@endsection
|
||||
38
resources/views/user_information/index.blade.php
Normal file
38
resources/views/user_information/index.blade.php
Normal file
@ -0,0 +1,38 @@
|
||||
@extends('layouts.app')
|
||||
@section('content')
|
||||
<main>
|
||||
<header class="alert alert-success">
|
||||
<h4 class="container">お知らせ > お知らせ一覧</h4>
|
||||
</header>
|
||||
<section id="" class="container mt30 mb50">
|
||||
<div class="col-12 col-md-8 offset-0 offset-md-2 mb30">
|
||||
<h3 class="text-center alert-success">お知らせ一覧</h3>
|
||||
</div>
|
||||
<div class="row">
|
||||
@forelse($informations as $information)
|
||||
<div class="col-12 col-md-3 offset-0 offset-md-2">
|
||||
<h5 class="text-success">
|
||||
{{ \Carbon\Carbon::parse($information->entry_date)->format('Y年n月j日') }}
|
||||
</h5>
|
||||
</div>
|
||||
<div class="col-12 col-lg-7 mb10">
|
||||
<p class="h5 font-weight-normal">
|
||||
{{ $information->user_information_history }}
|
||||
</p>
|
||||
</div>
|
||||
@empty
|
||||
<div class="col-12 text-center py-5">
|
||||
<p>お知らせはありません。</p>
|
||||
</div>
|
||||
@endforelse
|
||||
|
||||
<div class="col-12 col-md-5 offset-md-1 mt10">
|
||||
<a href="{{ url('mypage') }}" class="btn btn-lg btn-block btn-outline-success">マイページへ戻る</a>
|
||||
</div>
|
||||
<div class="col-12 col-md-5 mt10">
|
||||
<a href="{{ url('user_information/history') }}" class="btn btn-lg btn-block btn-outline-success">過去のお知らせ</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
@endsection
|
||||
148
routes/web.php
148
routes/web.php
@ -1,4 +1,3 @@
|
||||
|
||||
<?php
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
@ -12,16 +11,20 @@ use App\Http\Controllers\InquiryConfirmController;
|
||||
use App\Http\Controllers\LoginController;
|
||||
use App\Http\Controllers\MemberRegistrationController;
|
||||
use App\Http\Controllers\PasswordReminderController;
|
||||
use App\Http\Controllers\MypageController;
|
||||
use App\Http\Controllers\UserInfoController;
|
||||
use App\Http\Controllers\UserEditController;
|
||||
use App\Http\Controllers\UserEditConfirmController;
|
||||
use App\Http\Controllers\UserWithdrawController;
|
||||
use App\Http\Controllers\UserTagReissueController;
|
||||
use App\Http\Controllers\RegularContractController;
|
||||
use App\Http\Controllers\RegularContractCreateController;
|
||||
use App\Http\Controllers\ParkingSearchController;
|
||||
use App\Http\Controllers\ParkWaitlistController;
|
||||
use App\Http\Controllers\ReceiptController;
|
||||
use App\Http\Controllers\SealReissueController;
|
||||
use App\Http\Controllers\ParkDetailController;
|
||||
use App\Http\Controllers\UserInformationController;
|
||||
|
||||
// 画面遷移のみ
|
||||
Route::get('/', function () { return view('general.swo1_1'); })->name('swo1_1');
|
||||
@ -51,84 +54,70 @@ Route::get('/error', function () { return view('general.error'); })->name('error
|
||||
// コントローラー経由
|
||||
Route::post('/swo2_2', [MemberRegistrationController::class, 'sendMail'])->name('swo2_2');
|
||||
Route::get('/swo2_3', [MemberRegistrationController::class, 'index'])->name('swo2_3')->middleware('signed');
|
||||
Route::get('/swo2_3B', [MemberRegistrationController::class, 'indexBack'])->name('swo2_3B');
|
||||
Route::post('/swo2_4', [MemberRegistrationController::class, 'confirm'])->name('swo2_4');
|
||||
Route::post('/swo2_5', [MemberRegistrationController::class, 'complete'])->name('swo2_5');
|
||||
Route::get('/swo4_1', [LoginController::class, 'login'])->name('swo4_1');
|
||||
Route::get('/swo5_1', [ParkingSearchController::class, 'index'])->name('swo5_1');
|
||||
Route::post('/swo5_2', [ParkingSearchController::class, 'search'])->name('swo5_2');
|
||||
Route::get('/swo7_1', [InquiryConfirmController::class, 'index'])->name('swo7_1');
|
||||
Route::post('/swo7_2',[InquiryConfirmController::class, 'confirm'])->name('swo7_2');
|
||||
Route::post('/swo7_3',[InquiryConfirmController::class, 'complete'])->name('swo7_3');
|
||||
Route::post('/swo8_3', [PasswordReminderController::class, 'sendMail'])->name('swo8_3');
|
||||
|
||||
// ログアウト処理
|
||||
Route::get('/logout', function () {
|
||||
// セッション全削除
|
||||
session()->flush();
|
||||
return redirect()->route('swo1_1');
|
||||
})->name('logout');
|
||||
|
||||
// ログイン画面へのリダイレクト
|
||||
Route::get('/login', function () {
|
||||
return redirect()->route('swo8_1');
|
||||
})->name('login');
|
||||
|
||||
// マイページ画面へのリダイレクト
|
||||
Route::get('/mypage', function () {
|
||||
return '
|
||||
<div style="padding:2em;">
|
||||
<h2>マイページ(仮)</h2>
|
||||
<a href="' . route('user.info') . '" class="btn btn-primary">ユーザー情報を確認する</a>
|
||||
</div>
|
||||
';
|
||||
})->name('mypage');
|
||||
// マイページ
|
||||
Route::get('/mypage', [MypageController::class, 'index'])->name('mypage');
|
||||
|
||||
// ユーザー情報確認画面
|
||||
Route::get('/user/info', [UserInfoController::class, 'show'])
|
||||
->name('user.info');
|
||||
// ユーザー情報確認・編集
|
||||
Route::get('/user/info', [UserInfoController::class, 'show'])->name('user.info');
|
||||
Route::get('/user/edit', [UserEditController::class, 'show'])->name('user.edit');
|
||||
Route::post('/user/edit', [UserEditController::class, 'update'])->name('user.edit.post');
|
||||
Route::get('/user/edit/confirm', [UserEditConfirmController::class, 'show'])->name('user.confirm');
|
||||
Route::post('/user/edit/submit', [UserEditConfirmController::class, 'submit'])->name('user.edit.submit');
|
||||
Route::get('/user/edit/verify', [UserEditConfirmController::class, 'verify'])->name('user.edit.verify');
|
||||
|
||||
// ユーザー情報編集画面(GET: 編集フォーム表示)
|
||||
Route::get('/user/edit', [UserEditController::class, 'show'])
|
||||
->name('user.edit');
|
||||
// 退会
|
||||
Route::get('/user/withdraw', [UserWithdrawController::class, 'showConfirm'])->name('user.withdraw');
|
||||
Route::post('/user/withdraw/confirm', [UserWithdrawController::class, 'withdraw'])->name('user.withdraw.confirm');
|
||||
|
||||
// ユーザー情報編集(POST: 編集内容保存)
|
||||
Route::post('/user/edit', [UserEditController::class, 'update'])
|
||||
->name('user.edit.post');
|
||||
|
||||
// ユーザー情報編集確認
|
||||
Route::get('/user/edit/confirm', [UserEditConfirmController::class, 'show'])
|
||||
->name('user.confirm');
|
||||
|
||||
// 入力内容確認画面から「変更を確定する」ボタン押下時(認証メール送信)
|
||||
Route::post('/user/edit/submit', [UserEditConfirmController::class, 'submit'])
|
||||
->name('user.edit.submit');
|
||||
|
||||
// 認証メール内URLクリック時(変更確定処理)
|
||||
Route::get('/user/edit/verify', [UserEditConfirmController::class, 'verify'])
|
||||
->name('user.edit.verify');
|
||||
|
||||
// 退会画面(GET: 退会確認)
|
||||
Route::get('/user/withdraw', [UserWithdrawController::class, 'showConfirm'])
|
||||
->name('user.withdraw');
|
||||
// 退会処理(POST: 退会確定)
|
||||
Route::post('/user/withdraw/confirm', [UserWithdrawController::class, 'withdraw'])
|
||||
->name('user.withdraw.confirm');
|
||||
// タグ再発行
|
||||
Route::get('/user/tag_reissue', [UserTagReissueController::class, 'index'])->name('user.tag_reissue');
|
||||
Route::get('/user/tag_reissue/complete', [UserTagReissueController::class, 'complete'])->name('user.tag_reissue.complete');
|
||||
|
||||
// 定期契約情報確認
|
||||
Route::get('regular_contract/info', [RegularContractController::class, 'showInfo'])
|
||||
->name('regular_contract.info');
|
||||
Route::get('regular_contract/info', [RegularContractController::class, 'showInfo'])->name('regular_contract.info');
|
||||
|
||||
// 領収書宛名入力画面
|
||||
Route::get('receipt/input/{contract_id}', [ReceiptController::class, 'input'])
|
||||
->name('receipt.input');
|
||||
Route::get('receipt/download/{contract_id}', [ReceiptController::class, 'download'])
|
||||
->name('receipt.download');
|
||||
// 領収書発行
|
||||
Route::get('receipt/input/{contract_id}', [ReceiptController::class, 'input'])->name('receipt.input');
|
||||
Route::get('receipt/download/{contract_id}', [ReceiptController::class, 'download'])->name('receipt.download');
|
||||
Route::post('receipt/issue/{contract_id}', [ReceiptController::class, 'issue']);
|
||||
|
||||
// 新規定期契約画面
|
||||
Route::get('regular_contract/create', [RegularContractCreateController::class, 'show'])
|
||||
->name('regular_contract.create');
|
||||
// シール再発行
|
||||
Route::get('/seal/reissue/{contract_id}', [SealReissueController::class, 'index'])->name('seal.reissue');
|
||||
Route::get('/seal/reissue/reason/{contract_id}', [SealReissueController::class, 'reason'])->name('seal.reissue.reason');
|
||||
Route::post('/seal/reissue/complete/{contract_id}', [SealReissueController::class, 'complete'])->name('seal.reissue.complete');
|
||||
|
||||
// 新規定期契約
|
||||
Route::get('regular_contract/create', [RegularContractCreateController::class, 'show'])->name('regular_contract.create');
|
||||
Route::get('/api/park-detail/{park_id}', [ParkDetailController::class, 'show']);
|
||||
Route::get('/regular-contract/regulationCheck', [RegularContractCreateController::class, 'regulationCheck']);
|
||||
Route::get('/regular-contract/regulation', [RegularContractCreateController::class, 'showRegulation'])
|
||||
->name('regular_contract.regulation');
|
||||
Route::get('/regular-contract/regulation', [RegularContractCreateController::class, 'showRegulation'])->name('regular_contract.regulation');
|
||||
Route::post('/regular-contract/insertRegulation', [RegularContractCreateController::class, 'insertRegulation']);
|
||||
Route::get('/regular-contract/input', [RegularContractCreateController::class, 'showContractForm'])->name('regular_contract.input');
|
||||
Route::post('/regular_contract/input/check', [RegularContractCreateController::class, 'inputCheck'])->name('regular_contract.input.check');
|
||||
Route::get('/regular-contract/upload_identity_create', [RegularContractCreateController::class, 'showUploadIdentityCreate'])->name('regular_contract.upload_identity_create');
|
||||
|
||||
Route::post('regular_contract/confirm_upload_identity/{contract_id}', [RegularContractCreateController::class, 'confirmUploadIdentity'])->name('regular_contract.confirm_upload_identity');
|
||||
|
||||
// SHJ-1バッチ処理結果表示ページ
|
||||
@ -136,42 +125,39 @@ Route::get('/regular-contract/upload_identity_success', [RegularContractCreateCo
|
||||
Route::get('/regular-contract/upload_identity_fail', [RegularContractCreateController::class, 'showUploadIdentityFail'])->name('regular_contract.upload_identity_fail');
|
||||
Route::get('regular_contract/create_confirm', [RegularContractCreateController::class, 'createConfirm'])->name('regular_contract.create_confirm');
|
||||
Route::post('/regular_contract/create_confirm_next/{contract_id}', [RegularContractCreateController::class, 'createConfirmNext'])->name('regular_contract.create_confirm_next');
|
||||
Route::post('regular_contract/create_select_period', [RegularContractCreateController::class, 'selectPeriod'])
|
||||
->name('regular_contract.create_select_period');
|
||||
Route::get('/regular_contract/create_confirm_error/{contract_id}', [RegularContractCreateController::class, 'createConfirmNext'])->name('regular_contract.create_confirm_error');
|
||||
Route::post('/regular_contract/create_select_period', [RegularContractCreateController::class, 'selectPeriod'])->name('regular_contract.create_select_period');
|
||||
|
||||
// 定期契約更新
|
||||
Route::get('regular_contract/update', [RegularContractController::class, 'showInfo'])
|
||||
->name('regular_contract.update');
|
||||
Route::get('regular_contract/update', [RegularContractController::class, 'showInfo'])->name('regular_contract.update');
|
||||
Route::get('regular_contract/update/{contract_id}', [RegularContractController::class, 'update']);
|
||||
// 契約区分確認
|
||||
Route::get('regular_contract/confirm_category/{contract_id}', [RegularContractController::class, 'confirmCategory'])
|
||||
->name('regular_contract.confirm_category');
|
||||
Route::get('regular_contract/confirm_category_next/{contract_id}', [RegularContractController::class, 'confirmCategoryNext'])
|
||||
->name('regular_contract.confirm_category_next');
|
||||
// 本人確認書類アップロード
|
||||
Route::get('regular_contract/upload_identity/{contract_id}', [RegularContractController::class, 'uploadIdentity'])
|
||||
->name('regular_contract.upload_identity');
|
||||
// 本人確認書類確認中
|
||||
Route::post('regular_contract/upload_identity/{contract_id}', [RegularContractController::class, 'uploadIdentitySubmit'])
|
||||
->name('regular_contract.upload_identity_submit');
|
||||
// 利用期間選択
|
||||
Route::get('regular_contract/select_period/{contract_id}', [RegularContractController::class, 'selectPeriod'])
|
||||
->name('regular_contract.select_period');
|
||||
Route::post('regular_contract/update_period', [RegularContractController::class, 'updatePeriod'])
|
||||
->name('regular_contract.update_period');
|
||||
Route::get('regular_contract/confirm_category/{contract_id}', [RegularContractController::class, 'confirmCategory'])->name('regular_contract.confirm_category');
|
||||
Route::get('regular_contract/confirm_category_next/{contract_id}', [RegularContractController::class, 'confirmCategoryNext'])->name('regular_contract.confirm_category_next');
|
||||
Route::get('regular_contract/upload_identity/{contract_id}', [RegularContractController::class, 'uploadIdentity'])->name('regular_contract.upload_identity');
|
||||
Route::post('regular_contract/upload_identity/{contract_id}', [RegularContractController::class, 'uploadIdentitySubmit'])->name('regular_contract.upload_identity_submit');
|
||||
Route::get('regular_contract/select_period/{contract_id}', [RegularContractController::class, 'selectPeriod'])->name('regular_contract.select_period');
|
||||
Route::post('regular_contract/update_period', [RegularContractController::class, 'updatePeriod'])->name('regular_contract.update_period');
|
||||
|
||||
// 定期契約履歴
|
||||
Route::get('regular_contract/history', [RegularContractController::class, 'showHistory'])
|
||||
->name('regular_contract.history');
|
||||
Route::get('regular_contract/history', [RegularContractController::class, 'showHistory'])->name('regular_contract.history');
|
||||
|
||||
// 空き待ち状況確認画面
|
||||
Route::get('park_waitlist', [ParkWaitlistController::class, 'index'])
|
||||
->name('park_waitlist.index');
|
||||
// 駐輪場検索
|
||||
Route::get('park_search', [RegularContractCreateController::class, 'show'])->name('park_search');
|
||||
|
||||
Route::post('/login', function (Request $request) {
|
||||
$user_id = $request->input('user_id');
|
||||
Session::put('user_id', $user_id); // 入力されたIDをそのまま保存
|
||||
return redirect('/user/info'); // 認証なしでリダイレクト
|
||||
});
|
||||
// 空き待ち状況確認
|
||||
Route::get('park_waitlist', [ParkWaitlistController::class, 'index'])->name('park_waitlist.index');
|
||||
Route::get('/park-waitlist/check', [ParkWaitlistController::class, 'check'])->name('park_waitlist.check');
|
||||
Route::get('/park-waitlist/create', [ParkWaitlistController::class, 'create'])->name('park_waitlist.create');
|
||||
Route::get('/api/park-detail-wait/{reserve_id}', [ParkDetailController::class, 'showWait']);
|
||||
Route::get('/park_waitlist/cancel/{reserve_id}', [ParkWaitlistController::class, 'cancelConfirm'])->name('park_waitlist.cancel');
|
||||
Route::post('/park_waitlist/cancel/{reserve_id}', [ParkWaitlistController::class, 'cancel'])->name('park_waitlist.cancel.post');
|
||||
Route::get('/park_waitlist/cancel/complete', function () {
|
||||
return view('park_waitlist.cancel_complete');
|
||||
})->name('park_waitlist.cancel.complete');
|
||||
|
||||
// 会員へのお知らせ
|
||||
Route::get('/user_information', [UserInformationController::class, 'index'])->name('user_information.index');
|
||||
Route::get('/user_information/history', [UserInformationController::class, 'history'])->name('user_information.history');
|
||||
|
||||
// ウェルネット決済画面(仮)
|
||||
Route::get('/wellnet/payment', function (): mixed {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user