Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5aef2b7fc9 | ||
|
|
86e738a8fb |
19
.env
19
.env
@ -2,7 +2,8 @@ APP_NAME=so-manager
|
|||||||
APP_ENV=local
|
APP_ENV=local
|
||||||
APP_KEY=base64:ejLwJbt2bEXY9emPUmsurG+X1hzkjTxQQvq2/FO14RY=
|
APP_KEY=base64:ejLwJbt2bEXY9emPUmsurG+X1hzkjTxQQvq2/FO14RY=
|
||||||
APP_DEBUG=true
|
APP_DEBUG=true
|
||||||
APP_URL=https://krgm.so-manager-dev.com/
|
APP_URL=https://main-ou.so-manager-dev.com/
|
||||||
|
|
||||||
APP_LOCALE=ja
|
APP_LOCALE=ja
|
||||||
APP_FALLBACK_LOCALE=ja
|
APP_FALLBACK_LOCALE=ja
|
||||||
APP_FAKER_LOCALE=ja_JP
|
APP_FAKER_LOCALE=ja_JP
|
||||||
@ -46,16 +47,14 @@ REDIS_HOST=127.0.0.1
|
|||||||
REDIS_PASSWORD=null
|
REDIS_PASSWORD=null
|
||||||
REDIS_PORT=6379
|
REDIS_PORT=6379
|
||||||
|
|
||||||
MAIL_MAILER=smtp
|
MAIL_MAILER=log
|
||||||
#MAIL_SCHEME=null
|
MAIL_SCHEME=null
|
||||||
MAIL_HOST=tomatofox9.sakura.ne.jp
|
MAIL_HOST=127.0.0.1
|
||||||
MAIL_PORT=587
|
MAIL_PORT=2525
|
||||||
MAIL_USERNAME=demo@so-rin.jp
|
MAIL_USERNAME=null
|
||||||
MAIL_PASSWORD=rokuchou4665
|
MAIL_PASSWORD=null
|
||||||
MAIL_ENCRYPTION=tls
|
MAIL_FROM_ADDRESS="hello@so-manager-dev.com"
|
||||||
MAIL_FROM_ADDRESS=demo@so-rin.jp
|
|
||||||
MAIL_FROM_NAME="${APP_NAME}"
|
MAIL_FROM_NAME="${APP_NAME}"
|
||||||
MAIL_ADMIN=demo@so-rin.jp
|
|
||||||
|
|
||||||
AWS_ACCESS_KEY_ID=
|
AWS_ACCESS_KEY_ID=
|
||||||
AWS_SECRET_ACCESS_KEY=
|
AWS_SECRET_ACCESS_KEY=
|
||||||
|
|||||||
@ -1,18 +0,0 @@
|
|||||||
name: Deploy main
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: ["main"]
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: deploy-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
deploy:
|
|
||||||
runs-on: ["native"]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Deploy main to server
|
|
||||||
run: /usr/local/bin/deploy_krgm.sh
|
|
||||||
@ -1,28 +1,20 @@
|
|||||||
name: Deploy preview (main_xxx)
|
name: Deploy preview (main_ou)
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches: ["main_ou"]
|
||||||
- 'main_*' # 通配所有 main_xxx 分支
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: deploy-${{ github.ref_name }} # 同一分支串行
|
group: deploy-main_ou
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
deploy:
|
deploy:
|
||||||
name: Deploy ${{ github.ref_name }}
|
|
||||||
runs-on: ["native"]
|
runs-on: ["native"]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
- name: Deploy to preview (main_ou)
|
||||||
- name: Set BRANCH env
|
env:
|
||||||
shell: bash
|
BRANCH: main_ou
|
||||||
run: |
|
|
||||||
BR="${GITHUB_REF_NAME:-${GITHUB_REF##*/}}"
|
|
||||||
echo "BRANCH=$BR" >> "$GITHUB_ENV"
|
|
||||||
echo "Branch: $BR"
|
|
||||||
|
|
||||||
- name: Deploy to preview
|
|
||||||
run: /usr/local/bin/deploy_branch_simple.sh
|
run: /usr/local/bin/deploy_branch_simple.sh
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
@ -21,7 +21,3 @@ yarn-error.log
|
|||||||
/.nova
|
/.nova
|
||||||
/.vscode
|
/.vscode
|
||||||
/.zed
|
/.zed
|
||||||
/docs
|
|
||||||
# Backup files
|
|
||||||
*.bak
|
|
||||||
/.gitea/workflows/deploy-main.yml
|
|
||||||
238
app/Console/Commands/ShjBatchLogCommand.php
Normal file
238
app/Console/Commands/ShjBatchLogCommand.php
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use App\Models\Batch\BatchLog;
|
||||||
|
use App\Models\Device;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHJ-8 バッチ処理ログ登録コマンド
|
||||||
|
*
|
||||||
|
* 統一BatchLogを使用してバッチ処理の実行ログをbatch_logテーブルに登録する
|
||||||
|
* 仕様書に基づくSHJ-8の要求パラメータを受け取り、通用のログシステムで記録
|
||||||
|
*/
|
||||||
|
class ShjBatchLogCommand extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* コンソールコマンドの名前とシグネチャ
|
||||||
|
*
|
||||||
|
* 引数:
|
||||||
|
* - device_id: デバイスID (必須)
|
||||||
|
* - process_name: プロセス名 (必須)
|
||||||
|
* - job_name: ジョブ名 (必須)
|
||||||
|
* - status: ステータス (必須)
|
||||||
|
* - created_date: 登録日時 (必須、yyyy/mm/dd形式)
|
||||||
|
* - updated_date: 更新日時 (必須、yyyy/mm/dd形式)
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'shj:batch-log {device_id : デバイスID} {process_name : プロセス名} {job_name : ジョブ名} {status : ステータス} {created_date : 登録日時} {updated_date : 更新日時}';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* コンソールコマンドの説明
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'SHJ-8 バッチ処理ログ登録 - バッチ処理の実行ログを登録';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* コンストラクタ
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* コンソールコマンドを実行
|
||||||
|
*
|
||||||
|
* 処理フロー:
|
||||||
|
* 1. 入力パラメーターをチェックする
|
||||||
|
* 2. 統一BatchLogを使用してbatch_logテーブルに記録
|
||||||
|
* 3. 仕様書準拠の処理結果を返却する
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// 開始ログ出力
|
||||||
|
$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');
|
||||||
|
$createdDate = $this->argument('created_date');
|
||||||
|
$updatedDate = $this->argument('updated_date');
|
||||||
|
|
||||||
|
Log::info('SHJ-8 バッチ処理ログ登録開始', [
|
||||||
|
'start_time' => $startTime,
|
||||||
|
'device_id' => $deviceId,
|
||||||
|
'process_name' => $processName,
|
||||||
|
'job_name' => $jobName,
|
||||||
|
'status' => $status,
|
||||||
|
'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, // 実際のプロセス名を使用
|
||||||
|
$status,
|
||||||
|
[
|
||||||
|
'device_id' => $deviceId,
|
||||||
|
'job_name' => $jobName,
|
||||||
|
'status_comment' => BatchLog::getSuccessComment(),
|
||||||
|
'input_created_date' => $createdDate,
|
||||||
|
'input_updated_date' => $updatedDate,
|
||||||
|
'shj8_params' => [
|
||||||
|
'device_id' => $deviceId,
|
||||||
|
'process_name' => $processName,
|
||||||
|
'job_name' => $jobName,
|
||||||
|
'status' => $status,
|
||||||
|
'created_date' => $createdDate,
|
||||||
|
'updated_date' => $updatedDate
|
||||||
|
]
|
||||||
|
],
|
||||||
|
$jobName . ':' . BatchLog::getSuccessComment()
|
||||||
|
);
|
||||||
|
|
||||||
|
$endTime = now();
|
||||||
|
$this->info('SHJ-8 バッチ処理ログ登録が正常に完了しました。');
|
||||||
|
$this->info("処理時間: {$startTime->diffInSeconds($endTime)}秒");
|
||||||
|
|
||||||
|
Log::info('SHJ-8 バッチ処理ログ登録完了', [
|
||||||
|
'end_time' => $endTime,
|
||||||
|
'duration_seconds' => $startTime->diffInSeconds($endTime),
|
||||||
|
'batch_log_id' => $batchLog->id
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 仕様書【処理3】正常終了時の結果出力
|
||||||
|
$this->line('処理結果: 0'); // 0 = 正常終了
|
||||||
|
$this->line('異常情報: '); // 正常時は空文字
|
||||||
|
|
||||||
|
return self::SUCCESS;
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->error('SHJ-8 バッチ処理ログ登録で予期しないエラーが発生しました: ' . $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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
157
app/Console/Commands/ShjFourCCommand.php
Normal file
157
app/Console/Commands/ShjFourCCommand.php
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use App\Services\ShjFourCService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHJ-4C 室割当処理コマンド
|
||||||
|
*
|
||||||
|
* 駐輪場の区画別利用率状況に基づく室割当処理を実行する
|
||||||
|
* バックグラウンドで実行される定期バッチ処理
|
||||||
|
*/
|
||||||
|
class ShjFourCCommand extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* コンソールコマンドの名前とシグネチャ
|
||||||
|
*
|
||||||
|
* 引数:
|
||||||
|
* - park_id: 駐輪場ID (必須)
|
||||||
|
* - ptype_id: 駐輪分類ID (必須)
|
||||||
|
* - psection_id: 車種区分ID (必須)
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'shj:4c {park_id : 駐輪場ID} {ptype_id : 駐輪分類ID} {psection_id : 車種区分ID}';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* コンソールコマンドの説明
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'SHJ-4C 室割当処理 - ゾーン情報取得及び割当処理を実行';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHJ-4Cサービスクラス
|
||||||
|
*
|
||||||
|
* @var ShjFourCService
|
||||||
|
*/
|
||||||
|
protected $shjFourCService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* コンストラクタ
|
||||||
|
*
|
||||||
|
* @param ShjFourCService $shjFourCService
|
||||||
|
*/
|
||||||
|
public function __construct(ShjFourCService $shjFourCService)
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
$this->shjFourCService = $shjFourCService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* コンソールコマンドを実行
|
||||||
|
*
|
||||||
|
* 処理フロー:
|
||||||
|
* 1. パラメータ取得と検証
|
||||||
|
* 2. ゾーン情報取得処理
|
||||||
|
* 3. 割当判定処理
|
||||||
|
* 4. バッチログ作成
|
||||||
|
* 5. 処理結果返却
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// 開始ログ出力
|
||||||
|
$startTime = now();
|
||||||
|
$this->info('SHJ-4C 室割当処理を開始します。');
|
||||||
|
Log::info('SHJ-4C 室割当処理開始', [
|
||||||
|
'start_time' => $startTime,
|
||||||
|
'park_id' => $this->argument('park_id'),
|
||||||
|
'ptype_id' => $this->argument('ptype_id'),
|
||||||
|
'psection_id' => $this->argument('psection_id')
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 引数取得
|
||||||
|
$parkId = $this->argument('park_id');
|
||||||
|
$ptypeId = $this->argument('ptype_id');
|
||||||
|
$psectionId = $this->argument('psection_id');
|
||||||
|
|
||||||
|
// パラメータ検証
|
||||||
|
if (!$this->validateParameters($parkId, $ptypeId, $psectionId)) {
|
||||||
|
$this->error('パラメータが不正です。');
|
||||||
|
return self::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SHJ-4C処理実行
|
||||||
|
$result = $this->shjFourCService->executeRoomAllocation($parkId, $ptypeId, $psectionId);
|
||||||
|
|
||||||
|
// 処理結果確認
|
||||||
|
if ($result['success']) {
|
||||||
|
$endTime = now();
|
||||||
|
$this->info('SHJ-4C 室割当処理が正常に完了しました。');
|
||||||
|
$this->info("処理時間: {$startTime->diffInSeconds($endTime)}秒");
|
||||||
|
|
||||||
|
Log::info('SHJ-4C 室割当処理完了', [
|
||||||
|
'end_time' => $endTime,
|
||||||
|
'duration_seconds' => $startTime->diffInSeconds($endTime),
|
||||||
|
'result' => $result
|
||||||
|
]);
|
||||||
|
|
||||||
|
return self::SUCCESS;
|
||||||
|
} else {
|
||||||
|
$this->error('SHJ-4C 室割当処理でエラーが発生しました: ' . $result['message']);
|
||||||
|
Log::error('SHJ-4C 室割当処理エラー', [
|
||||||
|
'error' => $result['message'],
|
||||||
|
'details' => $result['details'] ?? null
|
||||||
|
]);
|
||||||
|
|
||||||
|
return self::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->error('SHJ-4C 室割当処理で予期しないエラーが発生しました: ' . $e->getMessage());
|
||||||
|
Log::error('SHJ-4C 室割当処理例外エラー', [
|
||||||
|
'exception' => $e->getMessage(),
|
||||||
|
'trace' => $e->getTraceAsString()
|
||||||
|
]);
|
||||||
|
|
||||||
|
return self::FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* パラメータの妥当性を検証
|
||||||
|
*
|
||||||
|
* @param mixed $parkId 駐輪場ID
|
||||||
|
* @param mixed $ptypeId 駐輪分類ID
|
||||||
|
* @param mixed $psectionId 車種区分ID
|
||||||
|
* @return bool 検証結果
|
||||||
|
*/
|
||||||
|
private function validateParameters($parkId, $ptypeId, $psectionId): bool
|
||||||
|
{
|
||||||
|
// 必須パラメータチェック
|
||||||
|
if (empty($parkId) || empty($ptypeId) || empty($psectionId)) {
|
||||||
|
$this->error('全てのパラメータは必須です。');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 数値形式チェック
|
||||||
|
if (!is_numeric($parkId) || !is_numeric($ptypeId) || !is_numeric($psectionId)) {
|
||||||
|
$this->error('全てのパラメータは数値である必要があります。');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 正の整数チェック
|
||||||
|
if ($parkId <= 0 || $ptypeId <= 0 || $psectionId <= 0) {
|
||||||
|
$this->error('全てのパラメータは正の整数である必要があります。');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
177
app/Console/Commands/ShjMailSendCommand.php
Normal file
177
app/Console/Commands/ShjMailSendCommand.php
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use App\Services\ShjMailSendService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHJ メール送信処理コマンド
|
||||||
|
*
|
||||||
|
* メールテンプレートを使用したメール送信処理を実行する
|
||||||
|
* バックグラウンドで実行される定期バッチ処理
|
||||||
|
*/
|
||||||
|
class ShjMailSendCommand extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* コンソールコマンドの名前とシグネチャ
|
||||||
|
*
|
||||||
|
* 引数:
|
||||||
|
* - mail_address: メールアドレス (必須)
|
||||||
|
* - backup_mail_address: 予備メールアドレス (必須)
|
||||||
|
* - mail_template_id: メールテンプレートID (必須)
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'shj:mail-send {mail_address : メールアドレス} {backup_mail_address : 予備メールアドレス} {mail_template_id : メールテンプレートID}';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* コンソールコマンドの説明
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'SHJ メール送信処理 - テンプレートに基づくメール送信を実行';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHJメール送信サービスクラス
|
||||||
|
*
|
||||||
|
* @var ShjMailSendService
|
||||||
|
*/
|
||||||
|
protected $shjMailSendService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* コンストラクタ
|
||||||
|
*
|
||||||
|
* @param ShjMailSendService $shjMailSendService
|
||||||
|
*/
|
||||||
|
public function __construct(ShjMailSendService $shjMailSendService)
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
$this->shjMailSendService = $shjMailSendService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* コンソールコマンドを実行
|
||||||
|
*
|
||||||
|
* 処理フロー:
|
||||||
|
* 1. 入力パラメーターをチェックする
|
||||||
|
* 2. メール送信テンプレート情報を取得する
|
||||||
|
* 3. メールを送信する
|
||||||
|
* 4. 処理結果を返却する
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// 開始ログ出力
|
||||||
|
$startTime = now();
|
||||||
|
$this->info('SHJ メール送信処理を開始します。');
|
||||||
|
Log::info('SHJ メール送信処理開始', [
|
||||||
|
'start_time' => $startTime,
|
||||||
|
'mail_address' => $this->argument('mail_address'),
|
||||||
|
'backup_mail_address' => $this->argument('backup_mail_address'),
|
||||||
|
'mail_template_id' => $this->argument('mail_template_id')
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 引数取得
|
||||||
|
$mailAddress = $this->argument('mail_address');
|
||||||
|
$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メール送信処理実行
|
||||||
|
$result = $this->shjMailSendService->executeMailSend($mailAddress, $backupMailAddress, $mailTemplateId);
|
||||||
|
|
||||||
|
// 処理結果確認
|
||||||
|
if ($result['success']) {
|
||||||
|
$endTime = now();
|
||||||
|
$this->info('SHJ メール送信処理が正常に完了しました。');
|
||||||
|
$this->info("処理時間: {$startTime->diffInSeconds($endTime)}秒");
|
||||||
|
|
||||||
|
Log::info('SHJ メール送信処理完了', [
|
||||||
|
'end_time' => $endTime,
|
||||||
|
'duration_seconds' => $startTime->diffInSeconds($endTime),
|
||||||
|
'result' => $result
|
||||||
|
]);
|
||||||
|
|
||||||
|
return self::SUCCESS;
|
||||||
|
} else {
|
||||||
|
$this->error('SHJ メール送信処理でエラーが発生しました: ' . $result['message']);
|
||||||
|
Log::error('SHJ メール送信処理エラー', [
|
||||||
|
'error' => $result['message'],
|
||||||
|
'details' => $result['details'] ?? null
|
||||||
|
]);
|
||||||
|
|
||||||
|
return self::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->error('SHJ メール送信処理で予期しないエラーが発生しました: ' . $e->getMessage());
|
||||||
|
Log::error('SHJ メール送信処理例外エラー', [
|
||||||
|
'exception' => $e->getMessage(),
|
||||||
|
'trace' => $e->getTraceAsString()
|
||||||
|
]);
|
||||||
|
|
||||||
|
return self::FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【処理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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -24,5 +24,3 @@ enum QueueClass: string
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -15,5 +15,3 @@ enum QueueStatus: string
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -12,9 +12,12 @@ class CityController extends Controller
|
|||||||
{
|
{
|
||||||
public function list(Request $request)
|
public function list(Request $request)
|
||||||
{
|
{
|
||||||
$sort = $request->input('sort', 'city_id');
|
$inputs = [
|
||||||
$sortType = $request->input('sort_type', 'asc');
|
'isMethodPost' => $request->isMethod('post'),
|
||||||
$page = $request->get('page', 1);
|
'sort' => $request->input('sort', ''),
|
||||||
|
'sort_type' => $request->input('sort_type', ''),
|
||||||
|
'page' => $request->get('page', 1),
|
||||||
|
];
|
||||||
|
|
||||||
$query = City::query();
|
$query = City::query();
|
||||||
|
|
||||||
@ -22,28 +25,17 @@ class CityController extends Controller
|
|||||||
$query->where('city_name', 'like', '%' . $request->input('city_name') . '%');
|
$query->where('city_name', 'like', '%' . $request->input('city_name') . '%');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 排序处理
|
if (!empty($inputs['sort'])) {
|
||||||
if (!empty($sort)) {
|
$query->orderBy($inputs['sort'], $inputs['sort_type'] ?? 'asc');
|
||||||
$query->orderBy($sort, $sortType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$list = $query->paginate(20);
|
$inputs['list'] = $query->paginate(20);
|
||||||
|
|
||||||
// 页码越界处理
|
if ($inputs['list']->total() > 0 && $inputs['page'] > $inputs['list']->lastPage()) {
|
||||||
if ($list->total() > 0 && $page > $list->lastPage()) {
|
return redirect()->route('city');
|
||||||
return redirect()->route('city', [
|
|
||||||
'sort' => $sort,
|
|
||||||
'sort_type' => $sortType,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return view('admin.CityMaster.list', [
|
return view('admin.CityMaster.list', $inputs);
|
||||||
'isMethodPost' => $request->isMethod('post'),
|
|
||||||
'sort' => $sort,
|
|
||||||
'sort_type' => $sortType,
|
|
||||||
'list' => $list,
|
|
||||||
'page' => $page,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function add(Request $request)
|
public function add(Request $request)
|
||||||
@ -57,21 +49,9 @@ class CityController extends Controller
|
|||||||
|
|
||||||
if ($request->isMethod('POST')) {
|
if ($request->isMethod('POST')) {
|
||||||
$rules = [
|
$rules = [
|
||||||
'city_name' => ['required', 'string', 'max:10', 'regex:/^[^ -~。-゚]+$/u'],
|
'city_name' => 'required|string|max:255',
|
||||||
'print_layout' => ['required', 'string', 'max:10', 'regex:/^[^ -~。-゚]+$/u'],
|
|
||||||
'city_user' => ['required', 'string', 'max:10', 'regex:/^[^ -~。-゚]+$/u'],
|
|
||||||
'city_remarks' => ['nullable', 'string', 'max:20'],
|
|
||||||
];
|
];
|
||||||
$messages = [
|
$validator = Validator::make($request->all(), $rules);
|
||||||
'city_name.required' => '市区名は必須です。',
|
|
||||||
'city_name.regex' => '市区名は全角で入力してください。',
|
|
||||||
'print_layout.required' => '印字レイアウトファイルは必須です。',
|
|
||||||
'print_layout.regex' => '印字レイアウトファイルは全角で入力してください。',
|
|
||||||
'city_user.required' => '顧客M入力不要フィールドIDは必須です。',
|
|
||||||
'city_user.regex' => '顧客M入力不要フィールドIDは全角で入力してください。',
|
|
||||||
'city_remarks.max' => '備考は20文字以内で入力してください。',
|
|
||||||
];
|
|
||||||
$validator = Validator::make($request->all(), $rules, $messages);
|
|
||||||
|
|
||||||
$inputs = array_merge($inputs, $request->all());
|
$inputs = array_merge($inputs, $request->all());
|
||||||
|
|
||||||
@ -111,21 +91,9 @@ class CityController extends Controller
|
|||||||
|
|
||||||
if ($request->isMethod('POST')) {
|
if ($request->isMethod('POST')) {
|
||||||
$rules = [
|
$rules = [
|
||||||
'city_name' => ['required', 'string', 'max:10', 'regex:/^[^ -~。-゚]+$/u'],
|
'city_name' => 'required|string|max:255',
|
||||||
'print_layout' => ['required', 'string', 'max:10', 'regex:/^[^ -~。-゚]+$/u'],
|
|
||||||
'city_user' => ['required', 'string', 'max:10', 'regex:/^[^ -~。-゚]+$/u'],
|
|
||||||
'city_remarks' => ['nullable', 'string', 'max:20'],
|
|
||||||
];
|
];
|
||||||
$messages = [
|
$validator = Validator::make($request->all(), $rules);
|
||||||
'city_name.required' => '市区名は必須です。',
|
|
||||||
'city_name.regex' => '市区名は全角で入力してください。',
|
|
||||||
'print_layout.required' => '印字レイアウトファイルは必須です。',
|
|
||||||
'print_layout.regex' => '印字レイアウトファイルは全角で入力してください。',
|
|
||||||
'city_user.required' => '顧客M入力不要フィールドIDは必須です。',
|
|
||||||
'city_user.regex' => '顧客M入力不要フィールドIDは全角で入力してください。',
|
|
||||||
'city_remarks.max' => '備考は20文字以内で入力してください。',
|
|
||||||
];
|
|
||||||
$validator = Validator::make($request->all(), $rules, $messages);
|
|
||||||
|
|
||||||
if (!$validator->fails()) {
|
if (!$validator->fails()) {
|
||||||
$city->fill($request->only([
|
$city->fill($request->only([
|
||||||
@ -162,10 +130,7 @@ class CityController extends Controller
|
|||||||
public function delete(Request $request)
|
public function delete(Request $request)
|
||||||
{
|
{
|
||||||
$arr_pk = $request->get('pk');
|
$arr_pk = $request->get('pk');
|
||||||
if (!$arr_pk) {
|
if ($arr_pk && City::destroy($arr_pk)) {
|
||||||
return redirect()->route('city')->with('error', __('削除する市区を選択してください。'));
|
|
||||||
}
|
|
||||||
if (City::destroy($arr_pk)) {
|
|
||||||
return redirect()->route('city')->with('success', __("削除が完了しました。"));
|
return redirect()->route('city')->with('success', __("削除が完了しました。"));
|
||||||
} else {
|
} else {
|
||||||
return redirect()->route('city')->with('error', __('削除に失敗しました。'));
|
return redirect()->route('city')->with('error', __('削除に失敗しました。'));
|
||||||
|
|||||||
@ -1,204 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use App\Models\ContractAllowableCity;
|
|
||||||
use App\Models\City;
|
|
||||||
use App\Models\Park;
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
|
||||||
|
|
||||||
class ContractAllowableCityController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 一覧表示
|
|
||||||
*/
|
|
||||||
public function list(Request $request)
|
|
||||||
{
|
|
||||||
$inputs = $request->all();
|
|
||||||
$inputs['isMethodPost'] = $request->isMethod('post');
|
|
||||||
|
|
||||||
// 解除処理
|
|
||||||
if ($request->isMethod('post') && $request->input('action') === 'unlink') {
|
|
||||||
// バリデーション:解除条件が1つも入力されていない場合はエラー
|
|
||||||
if (
|
|
||||||
!$request->filled('contract_allowable_city_id')
|
|
||||||
&& !$request->filled('city_id')
|
|
||||||
&& !$request->filled('contract_allowable_city_name')
|
|
||||||
&& !$request->filled('park_id')
|
|
||||||
) {
|
|
||||||
return back()->withErrors(['解除条件を1つ以上入力してください。']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$query = ContractAllowableCity::query();
|
|
||||||
|
|
||||||
if ($request->filled('contract_allowable_city_id')) {
|
|
||||||
$query->where('contract_allowable_city_id', $request->contract_allowable_city_id);
|
|
||||||
}
|
|
||||||
if ($request->filled('city_id')) {
|
|
||||||
$query->where('city_id', $request->city_id);
|
|
||||||
}
|
|
||||||
if ($request->filled('contract_allowable_city_name')) {
|
|
||||||
$query->where('contract_allowable_city_name', 'like', '%' . $request->contract_allowable_city_name . '%');
|
|
||||||
}
|
|
||||||
if ($request->filled('park_id')) {
|
|
||||||
$query->where('park_id', $request->park_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
$count = $query->delete();
|
|
||||||
return redirect()->route('contract_allowable_cities')->with('success', '解除しました');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 通常の絞り込み処理
|
|
||||||
$list = ContractAllowableCity::search($inputs);
|
|
||||||
|
|
||||||
return view('admin.contract_allowable_cities.list', [
|
|
||||||
'list' => $list,
|
|
||||||
'inputs' => $inputs,
|
|
||||||
'sort' => $inputs['sort'] ?? '',
|
|
||||||
'sort_type' => $inputs['sort_type'] ?? '',
|
|
||||||
'cityList' => City::getList(),
|
|
||||||
'parkList' => Park::getList(),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 新規登録
|
|
||||||
*/
|
|
||||||
public function add(Request $request)
|
|
||||||
{
|
|
||||||
if ($request->isMethod('post')) {
|
|
||||||
$validated = $request->validate([
|
|
||||||
'city_id' => 'required|integer',
|
|
||||||
'contract_allowable_city_name' => 'required|string|max:20',
|
|
||||||
'park_id' => 'required|integer',
|
|
||||||
'same_district_flag' => 'required|integer',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$validated['operator_id'] = Auth::user()->ope_id;
|
|
||||||
|
|
||||||
ContractAllowableCity::create($validated);
|
|
||||||
|
|
||||||
return redirect()->route('contract_allowable_cities')
|
|
||||||
->with('success', '登録しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
return view('admin.contract_allowable_cities.add', [
|
|
||||||
'record' => null,
|
|
||||||
'cityList' => City::getList(),
|
|
||||||
'parkList' => Park::getList(),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 編集
|
|
||||||
*/
|
|
||||||
public function edit(Request $request, $id)
|
|
||||||
{
|
|
||||||
$record = ContractAllowableCity::getByPk($id);
|
|
||||||
if (!$record) {
|
|
||||||
return redirect()->route('contract_allowable_cities')
|
|
||||||
->with('error', 'データが存在しません');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($request->isMethod('post')) {
|
|
||||||
$validated = $request->validate([
|
|
||||||
'city_id' => 'required|integer',
|
|
||||||
'contract_allowable_city_name' => 'required|string|max:20',
|
|
||||||
'park_id' => 'required|integer',
|
|
||||||
'same_district_flag' => 'required|integer',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$record->fill($validated);
|
|
||||||
$record->operator_id = Auth::user()->ope_id;
|
|
||||||
$record->save();
|
|
||||||
|
|
||||||
return redirect()->route('contract_allowable_cities')
|
|
||||||
->with('success', '更新しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
return view('admin.contract_allowable_cities.edit', [
|
|
||||||
'record' => $record,
|
|
||||||
'cityList' => City::getList(),
|
|
||||||
'parkList' => Park::getList(),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 一括削除(単一・複数対応)
|
|
||||||
*/
|
|
||||||
public function delete(Request $request)
|
|
||||||
{
|
|
||||||
// バリデーション:'id'は必須、配列の場合は各要素が整数
|
|
||||||
$request->validate([
|
|
||||||
'id' => 'required',
|
|
||||||
'id.*' => 'integer',
|
|
||||||
]);
|
|
||||||
|
|
||||||
// idを配列化(単一でも複数でも対応)
|
|
||||||
$ids = (array)$request->input('id');
|
|
||||||
|
|
||||||
// 削除処理
|
|
||||||
// ContractAllowableCity::destroy($ids) が使える場合
|
|
||||||
$deleted = ContractAllowableCity::destroy($ids);
|
|
||||||
|
|
||||||
// 削除件数でメッセージ分岐
|
|
||||||
if ($deleted > 0) {
|
|
||||||
return redirect()->route('contract_allowable_cities')->with('success', '削除しました。');
|
|
||||||
} else {
|
|
||||||
return redirect()->route('contract_allowable_cities')->with('error', '削除に失敗しました。');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 契約許容市区マスタ CSVエクスポート
|
|
||||||
*/
|
|
||||||
public function export(Request $request)
|
|
||||||
{
|
|
||||||
$filename = '契約許容市区マスタ_' . now()->format('YmdHis') . '.csv';
|
|
||||||
|
|
||||||
// 検索条件でデータ取得
|
|
||||||
$list = ContractAllowableCity::search($request->all());
|
|
||||||
|
|
||||||
// CSVファイル作成
|
|
||||||
$file = fopen($filename, 'w+');
|
|
||||||
fwrite($file, "\xEF\xBB\xBF"); // UTF-8 BOM追加
|
|
||||||
|
|
||||||
// ヘッダー行
|
|
||||||
$columns = [
|
|
||||||
'契約許容市区ID',
|
|
||||||
'市区ID',
|
|
||||||
'許容市区名',
|
|
||||||
'駐輪場ID',
|
|
||||||
'隣接区フラグ'
|
|
||||||
];
|
|
||||||
fputcsv($file, $columns);
|
|
||||||
|
|
||||||
// データ行
|
|
||||||
foreach ($list as $item) {
|
|
||||||
fputcsv($file, [
|
|
||||||
$item->contract_allowable_city_id,
|
|
||||||
$item->city_id,
|
|
||||||
$item->contract_allowable_city_name,
|
|
||||||
$item->park_id,
|
|
||||||
$item->same_district_flag == 0 ? '隣接市' : 'その他',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose($file);
|
|
||||||
|
|
||||||
// ヘッダー設定
|
|
||||||
$headers = [
|
|
||||||
"Content-Type" => "text/csv; charset=UTF-8",
|
|
||||||
"Content-Disposition" => "attachment; filename={$filename}",
|
|
||||||
];
|
|
||||||
|
|
||||||
// ダウンロード後に一時ファイル削除
|
|
||||||
return response()->download($filename, $filename, $headers)->deleteFileAfterSend(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -13,9 +13,7 @@ class ContractorController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function list(Request $request)
|
public function list(Request $request)
|
||||||
{
|
{
|
||||||
// ベースクエリを構築
|
|
||||||
$q = DB::table('regular_contract as rc')
|
$q = DB::table('regular_contract as rc')
|
||||||
->leftJoin('user as u','rc.user_id','=','u.user_id')
|
|
||||||
->select([
|
->select([
|
||||||
'rc.contract_id',
|
'rc.contract_id',
|
||||||
'rc.contract_qr_id',
|
'rc.contract_qr_id',
|
||||||
@ -34,12 +32,10 @@ class ContractorController extends Controller
|
|||||||
'rc.contract_permission',
|
'rc.contract_permission',
|
||||||
'rc.contract_manual',
|
'rc.contract_manual',
|
||||||
'rc.contract_notice',
|
'rc.contract_notice',
|
||||||
'rc.update_flag',
|
|
||||||
'p.park_name',
|
'p.park_name',
|
||||||
'u.user_name',
|
'u.user_name',
|
||||||
'u.user_phonetic',
|
'u.user_phonetic',
|
||||||
'u.user_mobile',
|
'u.user_mobile',
|
||||||
'u.user_seq',
|
|
||||||
'u.user_homephone',
|
'u.user_homephone',
|
||||||
'u.user_primemail',
|
'u.user_primemail',
|
||||||
'u.user_gender',
|
'u.user_gender',
|
||||||
@ -56,125 +52,37 @@ class ContractorController extends Controller
|
|||||||
'u.user_workplace',
|
'u.user_workplace',
|
||||||
'u.user_school',
|
'u.user_school',
|
||||||
'u.user_remarks',
|
'u.user_remarks',
|
||||||
'u.user_tag_serial_64',
|
// 他に必要なカラムもここに追加
|
||||||
'u.user_reduction',
|
|
||||||
DB::raw('rc.user_securitynum as crime_prevention'),
|
|
||||||
DB::raw('rc.contract_seal_issue as seal_issue_count'),
|
|
||||||
DB::raw("CASE rc.enable_months
|
|
||||||
WHEN 1 THEN '月極(1ヶ月)'
|
|
||||||
WHEN 3 THEN '3ヶ月'
|
|
||||||
WHEN 6 THEN '6ヶ月'
|
|
||||||
WHEN 12 THEN '年'
|
|
||||||
ELSE CONCAT(rc.enable_months, 'ヶ月') END as ticket_type"),
|
|
||||||
DB::raw('ps.psection_subject as vehicle_type'),
|
|
||||||
// 利用者分類のラベル(usertype テーブルの subject を取得)
|
|
||||||
DB::raw('ut.usertype_subject1 as user_category1'),
|
|
||||||
DB::raw('ut.usertype_subject2 as user_category2'),
|
|
||||||
DB::raw('ut.usertype_subject3 as user_category3'),
|
|
||||||
])
|
])
|
||||||
->leftJoin('park as p', 'rc.park_id', '=', 'p.park_id')
|
->leftJoin('park as p', 'rc.park_id', '=', 'p.park_id')
|
||||||
->leftJoin('psection as ps', 'rc.psection_id', '=', 'ps.psection_id')
|
->leftJoin('user as u', 'rc.user_id', '=', 'u.user_id');
|
||||||
->leftJoin('usertype as ut', 'u.user_categoryid', '=', 'ut.user_categoryid');
|
|
||||||
|
|
||||||
// ===== 絞り込み条件 =====
|
// 検索条件例
|
||||||
|
if ($request->filled('contract_id')) {
|
||||||
// 駐輪場で絞る(完全一致)
|
$q->where('rc.contract_id', $request->input('contract_id'));
|
||||||
if ($request->filled('park_id')) {
|
}
|
||||||
$q->where('rc.park_id', $request->park_id);
|
if ($request->filled('name')) {
|
||||||
|
$q->where('u.user_name', 'like', '%' . $request->input('name') . '%');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 利用者IDで絞る(完全一致)
|
// タグ・QR(完全一致、空白なら絞り込まない)
|
||||||
if ($request->filled('user_id')) {
|
if ($request->filled('tag_qr_flag') && $request->input('tag_qr_flag') !== '') {
|
||||||
$q->where('rc.user_id', $request->user_id);
|
$q->where('rc.tag_qr_flag', $request->input('tag_qr_flag'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 利用者分類で絞る(※ select の value を user_categoryid にしているため、user テーブルのカラムで比較)
|
// ソート処理
|
||||||
if ($request->filled('user_category1')) {
|
$sort = $request->input('sort', 'rc.contract_id');
|
||||||
$q->where('u.user_categoryid', $request->user_category1);
|
$sortType = $request->input('sort_type', 'desc');
|
||||||
|
// カラム名のバリデーション(必要に応じて拡張)
|
||||||
|
$allowSorts = ['rc.contract_id'];
|
||||||
|
if (!in_array($sort, $allowSorts)) {
|
||||||
|
$sort = 'rc.contract_id';
|
||||||
}
|
}
|
||||||
|
$sortType = ($sortType === 'asc') ? 'asc' : 'desc';
|
||||||
|
|
||||||
// タグシリアル64進で部分一致検索
|
$rows = $q->orderBy($sort, $sortType)->paginate(20)->withQueryString();
|
||||||
if ($request->filled('user_tag_serial_64')) {
|
|
||||||
$val = $request->user_tag_serial_64;
|
|
||||||
$q->where('u.user_tag_serial_64','like','%'.$val.'%');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 有効期限で絞る(指定日以前を抽出する= <= を使用)
|
return view('admin.contractor.list', compact('rows', 'sort', 'sortType'));
|
||||||
if ($request->filled('contract_periode')) {
|
|
||||||
$raw = trim($request->contract_periode);
|
|
||||||
$norm = str_replace('/', '-', $raw); // スラッシュ入力を許容
|
|
||||||
try {
|
|
||||||
$target = \Carbon\Carbon::parse($norm)->format('Y-m-d');
|
|
||||||
// 指定日「以前」を含める
|
|
||||||
$q->whereDate('rc.contract_periode', '<=', $target);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
// 無効な日付は無視する
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// フリガナで部分一致
|
|
||||||
if ($request->filled('user_phonetic')) {
|
|
||||||
$q->where('u.user_phonetic', 'like', '%' . $request->user_phonetic . '%');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 携帯電話で部分一致
|
|
||||||
if ($request->filled('user_mobile')) {
|
|
||||||
$q->where('u.user_mobile', 'like', '%' . $request->user_mobile . '%');
|
|
||||||
}
|
|
||||||
|
|
||||||
// メールアドレスで部分一致
|
|
||||||
if ($request->filled('user_primemail')) {
|
|
||||||
$q->where('u.user_primemail', 'like', '%' . $request->user_primemail . '%');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 勤務先で部分一致
|
|
||||||
if ($request->filled('user_workplace')) {
|
|
||||||
$q->where('u.user_workplace', 'like', '%' . $request->user_workplace . '%');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 学校で部分一致
|
|
||||||
if ($request->filled('user_school')) {
|
|
||||||
$q->where('u.user_school', 'like', '%' . $request->user_school . '%');
|
|
||||||
}
|
|
||||||
|
|
||||||
// タグ・QR フラグで絞る(空文字は無視)
|
|
||||||
if ($request->filled('tag_qr_flag') && $request->tag_qr_flag !== '') {
|
|
||||||
$q->where('rc.tag_qr_flag', $request->tag_qr_flag);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== ソート処理 =====
|
|
||||||
// 指定があればその列でソート、なければデフォルトで契約IDの昇順
|
|
||||||
$sort = $request->input('sort'); // null 許容
|
|
||||||
$sortType = $request->input('sort_type','asc');
|
|
||||||
|
|
||||||
$allowSorts = [
|
|
||||||
'rc.contract_id',
|
|
||||||
'rc.user_id',
|
|
||||||
'u.user_name',
|
|
||||||
'rc.tag_qr_flag',
|
|
||||||
'p.park_name',
|
|
||||||
];
|
|
||||||
if ($sort && in_array($sort, $allowSorts)) {
|
|
||||||
$sortType = $sortType === 'desc' ? 'desc' : 'asc';
|
|
||||||
$q->orderBy($sort, $sortType);
|
|
||||||
} else {
|
|
||||||
// デフォルトソート
|
|
||||||
$sort = null;
|
|
||||||
$sortType = null;
|
|
||||||
$q->orderBy('rc.contract_id','asc');
|
|
||||||
}
|
|
||||||
|
|
||||||
// ページネーション(クエリ文字列を引き継ぐ)
|
|
||||||
$rows = $q->paginate(20)->appends($request->query());
|
|
||||||
|
|
||||||
// 駐輪場セレクト用データ取得
|
|
||||||
$parks = DB::table('park')->select('park_id', 'park_name')->orderBy('park_name')->get();
|
|
||||||
|
|
||||||
// 利用者分類セレクト用:実際に使用されている分類のみを取得する
|
|
||||||
$categories = $this->buildCategoryOptions(true);
|
|
||||||
|
|
||||||
// ビューに渡す
|
|
||||||
return view('admin.contractor.list', compact('rows', 'sort', 'sortType', 'parks', 'categories'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -182,7 +90,6 @@ class ContractorController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function info($id)
|
public function info($id)
|
||||||
{
|
{
|
||||||
// 指定契約IDの詳細を取得
|
|
||||||
$contract = DB::table('regular_contract as rc')
|
$contract = DB::table('regular_contract as rc')
|
||||||
->select([
|
->select([
|
||||||
'rc.*',
|
'rc.*',
|
||||||
@ -205,55 +112,4 @@ class ContractorController extends Controller
|
|||||||
|
|
||||||
return view('admin.contractor.info', compact('contract'));
|
return view('admin.contractor.info', compact('contract'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 利用者分類選択肢を取得
|
|
||||||
*
|
|
||||||
* @param bool $onlyUsed true の場合は regular_contract に出現する分類のみ返す
|
|
||||||
* @return array [user_categoryid => label, ...]
|
|
||||||
*/
|
|
||||||
private function buildCategoryOptions(bool $onlyUsed = false): array
|
|
||||||
{
|
|
||||||
if (! $onlyUsed) {
|
|
||||||
// 全件取得(既存の挙動)
|
|
||||||
return DB::table('usertype')
|
|
||||||
->orderBy('user_categoryid', 'asc')
|
|
||||||
->get()
|
|
||||||
->mapWithKeys(function ($row) {
|
|
||||||
$label = collect([
|
|
||||||
$row->usertype_subject1 ?? '',
|
|
||||||
$row->usertype_subject2 ?? '',
|
|
||||||
$row->usertype_subject3 ?? '',
|
|
||||||
])->filter(fn ($v) => $v !== '')->implode('/');
|
|
||||||
|
|
||||||
return [$row->user_categoryid => $label !== '' ? $label : (string) $row->user_categoryid];
|
|
||||||
})
|
|
||||||
->toArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 実際に使用されている分類のみ取得する(内部結合で user と regular_contract と紐付くもの)
|
|
||||||
$rows = DB::table('usertype as ut')
|
|
||||||
->join('user as u', 'u.user_categoryid', '=', 'ut.user_categoryid')
|
|
||||||
->join('regular_contract as rc', 'rc.user_id', '=', 'u.user_id')
|
|
||||||
->select(
|
|
||||||
'ut.user_categoryid',
|
|
||||||
'ut.usertype_subject1',
|
|
||||||
'ut.usertype_subject2',
|
|
||||||
'ut.usertype_subject3'
|
|
||||||
)
|
|
||||||
->groupBy('ut.user_categoryid', 'ut.usertype_subject1', 'ut.usertype_subject2', 'ut.usertype_subject3')
|
|
||||||
->orderBy('ut.user_categoryid', 'asc')
|
|
||||||
->get();
|
|
||||||
|
|
||||||
// ラベルを組み立てて配列で返す
|
|
||||||
return $rows->mapWithKeys(function ($row) {
|
|
||||||
$label = collect([
|
|
||||||
$row->usertype_subject1 ?? '',
|
|
||||||
$row->usertype_subject2 ?? '',
|
|
||||||
$row->usertype_subject3 ?? '',
|
|
||||||
])->filter(fn ($v) => $v !== '')->implode('/');
|
|
||||||
|
|
||||||
return [$row->user_categoryid => $label !== '' ? $label : (string) $row->user_categoryid];
|
|
||||||
})->toArray();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,9 +13,7 @@ class ContractorListController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function list(Request $request)
|
public function list(Request $request)
|
||||||
{
|
{
|
||||||
// ベースクエリを構築
|
|
||||||
$q = DB::table('regular_contract as rc')
|
$q = DB::table('regular_contract as rc')
|
||||||
->leftJoin('user as u','rc.user_id','=','u.user_id')
|
|
||||||
->select([
|
->select([
|
||||||
'rc.contract_id',
|
'rc.contract_id',
|
||||||
'rc.contract_qr_id',
|
'rc.contract_qr_id',
|
||||||
@ -34,14 +32,11 @@ class ContractorListController extends Controller
|
|||||||
'rc.contract_permission',
|
'rc.contract_permission',
|
||||||
'rc.contract_manual',
|
'rc.contract_manual',
|
||||||
'rc.contract_notice',
|
'rc.contract_notice',
|
||||||
'rc.update_flag',
|
|
||||||
'rc.user_securitynum',
|
|
||||||
'rc.contract_seal_issue',
|
|
||||||
'p.park_name',
|
'p.park_name',
|
||||||
|
// userテーブルの正しいカラム名
|
||||||
'u.user_name',
|
'u.user_name',
|
||||||
'u.user_phonetic',
|
'u.user_phonetic',
|
||||||
'u.user_mobile',
|
'u.user_mobile',
|
||||||
'u.user_seq',
|
|
||||||
'u.user_homephone',
|
'u.user_homephone',
|
||||||
'u.user_primemail',
|
'u.user_primemail',
|
||||||
'u.user_gender',
|
'u.user_gender',
|
||||||
@ -58,127 +53,37 @@ class ContractorListController extends Controller
|
|||||||
'u.user_workplace',
|
'u.user_workplace',
|
||||||
'u.user_school',
|
'u.user_school',
|
||||||
'u.user_remarks',
|
'u.user_remarks',
|
||||||
'u.user_tag_serial_64',
|
// 他に必要なカラムもここに追加
|
||||||
'u.user_reduction',
|
|
||||||
DB::raw('rc.user_securitynum as crime_prevention'),
|
|
||||||
DB::raw('rc.contract_seal_issue as seal_issue_count'),
|
|
||||||
DB::raw("CASE rc.enable_months
|
|
||||||
WHEN 1 THEN '月極(1ヶ月)'
|
|
||||||
WHEN 3 THEN '3ヶ月'
|
|
||||||
WHEN 6 THEN '6ヶ月'
|
|
||||||
WHEN 12 THEN '年'
|
|
||||||
ELSE CONCAT(rc.enable_months, 'ヶ月') END as ticket_type"),
|
|
||||||
DB::raw('ps.psection_subject as vehicle_type'),
|
|
||||||
// 利用者分類のラベル(usertype テーブルの subject を取得)
|
|
||||||
DB::raw('ut.usertype_subject1 as user_category1'),
|
|
||||||
DB::raw('ut.usertype_subject2 as user_category2'),
|
|
||||||
DB::raw('ut.usertype_subject3 as user_category3'),
|
|
||||||
])
|
])
|
||||||
->leftJoin('park as p', 'rc.park_id', '=', 'p.park_id')
|
->leftJoin('park as p', 'rc.park_id', '=', 'p.park_id')
|
||||||
->leftJoin('psection as ps', 'rc.psection_id', '=', 'ps.psection_id')
|
->leftJoin('user as u', 'rc.user_id', '=', 'u.user_id');
|
||||||
->leftJoin('usertype as ut', 'u.user_categoryid', '=', 'ut.user_categoryid');
|
|
||||||
|
|
||||||
// ===== 絞り込み条件 =====
|
// 検索条件例
|
||||||
|
if ($request->filled('contract_id')) {
|
||||||
// 駐輪場で絞る(完全一致)
|
$q->where('rc.contract_id', $request->input('contract_id'));
|
||||||
if ($request->filled('park_id')) {
|
}
|
||||||
$q->where('rc.park_id', $request->park_id);
|
if ($request->filled('name')) {
|
||||||
|
$q->where('u.user_name', 'like', '%' . $request->input('name') . '%');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 利用者IDで絞る(完全一致)
|
// タグ・QR(完全一致、空白なら絞り込まない)
|
||||||
if ($request->filled('user_id')) {
|
if ($request->filled('tag_qr_flag') && $request->input('tag_qr_flag') !== '') {
|
||||||
$q->where('rc.user_id', $request->user_id);
|
$q->where('rc.tag_qr_flag', $request->input('tag_qr_flag'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 利用者分類で絞る(※ select の value を user_categoryid にしているため、user テーブルのカラムで比較)
|
// ソート処理
|
||||||
if ($request->filled('user_category1')) {
|
$sort = $request->input('sort', 'rc.contract_id');
|
||||||
$q->where('u.user_categoryid', $request->user_category1);
|
$sortType = $request->input('sort_type', 'desc');
|
||||||
|
// カラム名のバリデーション(必要に応じて拡張)
|
||||||
|
$allowSorts = ['rc.contract_id'];
|
||||||
|
if (!in_array($sort, $allowSorts)) {
|
||||||
|
$sort = 'rc.contract_id';
|
||||||
}
|
}
|
||||||
|
$sortType = ($sortType === 'asc') ? 'asc' : 'desc';
|
||||||
|
|
||||||
// タグシリアル64進で部分一致検索
|
$rows = $q->orderBy($sort, $sortType)->paginate(20)->withQueryString();
|
||||||
if ($request->filled('user_tag_serial_64')) {
|
|
||||||
$val = $request->user_tag_serial_64;
|
|
||||||
$q->where('u.user_tag_serial_64','like','%'.$val.'%');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 対象月
|
return view('admin.contractor_list.list', compact('rows', 'sort', 'sortType'));
|
||||||
$target = $request->input('target_month');
|
|
||||||
if (in_array($target,['last','this','next','after2'],true)) {
|
|
||||||
$base = now()->startOfMonth();
|
|
||||||
$offset = ['last'=>-1,'this'=>0,'next'=>1,'after2'=>2][$target];
|
|
||||||
$m = $base->copy()->addMonths($offset);
|
|
||||||
if ($target === 'after2') {
|
|
||||||
// 2か月後「以降」を抽出(該当月の月初以降)
|
|
||||||
$q->whereDate('rc.contract_periode', '>=', $m->toDateString());
|
|
||||||
} else {
|
|
||||||
$q->whereYear('rc.contract_periode',$m->year)
|
|
||||||
->whereMonth('rc.contract_periode',$m->month);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// フリガナで部分一致
|
|
||||||
if ($request->filled('user_phonetic')) {
|
|
||||||
$q->where('u.user_phonetic', 'like', '%' . $request->user_phonetic . '%');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 携帯電話で部分一致
|
|
||||||
if ($request->filled('user_mobile')) {
|
|
||||||
$q->where('u.user_mobile', 'like', '%' . $request->user_mobile . '%');
|
|
||||||
}
|
|
||||||
|
|
||||||
// メールアドレスで部分一致
|
|
||||||
if ($request->filled('user_primemail')) {
|
|
||||||
$q->where('u.user_primemail', 'like', '%' . $request->user_primemail . '%');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 勤務先で部分一致
|
|
||||||
if ($request->filled('user_workplace')) {
|
|
||||||
$q->where('u.user_workplace', 'like', '%' . $request->user_workplace . '%');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 学校で部分一致
|
|
||||||
if ($request->filled('user_school')) {
|
|
||||||
$q->where('u.user_school', 'like', '%' . $request->user_school . '%');
|
|
||||||
}
|
|
||||||
|
|
||||||
// タグ・QR フラグで絞る(空文字は無視)
|
|
||||||
if ($request->filled('tag_qr_flag') && $request->tag_qr_flag !== '') {
|
|
||||||
$q->where('rc.tag_qr_flag', $request->tag_qr_flag);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== ソート処理 =====
|
|
||||||
// 指定があればその列でソート、なければデフォルトで契約IDの昇順
|
|
||||||
$sort = $request->input('sort'); // null 許容
|
|
||||||
$sortType = $request->input('sort_type','asc');
|
|
||||||
|
|
||||||
$allowSorts = [
|
|
||||||
'rc.contract_id',
|
|
||||||
'rc.user_id',
|
|
||||||
'u.user_name',
|
|
||||||
'rc.tag_qr_flag',
|
|
||||||
'p.park_name',
|
|
||||||
];
|
|
||||||
if ($sort && in_array($sort, $allowSorts)) {
|
|
||||||
$sortType = $sortType === 'desc' ? 'desc' : 'asc';
|
|
||||||
$q->orderBy($sort, $sortType);
|
|
||||||
} else {
|
|
||||||
// デフォルトソート
|
|
||||||
$sort = null;
|
|
||||||
$sortType = null;
|
|
||||||
$q->orderBy('rc.contract_id','asc');
|
|
||||||
}
|
|
||||||
|
|
||||||
// ページネーション(クエリ文字列を引き継ぐ)
|
|
||||||
$rows = $q->paginate(20)->appends($request->query());
|
|
||||||
|
|
||||||
// 駐輪場セレクト用データ取得
|
|
||||||
$parks = DB::table('park')->select('park_id', 'park_name')->orderBy('park_name')->get();
|
|
||||||
|
|
||||||
// 利用者分類セレクト用:実際に使用されている分類のみを取得する
|
|
||||||
$categories = $this->buildCategoryOptions(true);
|
|
||||||
|
|
||||||
// ビューに渡す
|
|
||||||
return view('admin.contractor_list.list', compact('rows', 'sort', 'sortType', 'parks', 'categories'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -186,7 +91,6 @@ class ContractorListController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function info($id)
|
public function info($id)
|
||||||
{
|
{
|
||||||
// 指定契約IDの詳細を取得
|
|
||||||
$contract = DB::table('regular_contract as rc')
|
$contract = DB::table('regular_contract as rc')
|
||||||
->select([
|
->select([
|
||||||
'rc.*',
|
'rc.*',
|
||||||
@ -207,57 +111,6 @@ class ContractorListController extends Controller
|
|||||||
|
|
||||||
if (!$contract) { abort(404); }
|
if (!$contract) { abort(404); }
|
||||||
|
|
||||||
return view('admin.contractor_List.info', compact('contract'));
|
return view('admin.contractor.info', compact('contract'));
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 利用者分類選択肢を取得
|
|
||||||
*
|
|
||||||
* @param bool $onlyUsed true の場合は regular_contract に出現する分類のみ返す
|
|
||||||
* @return array [user_categoryid => label, ...]
|
|
||||||
*/
|
|
||||||
private function buildCategoryOptions(bool $onlyUsed = false): array
|
|
||||||
{
|
|
||||||
if (! $onlyUsed) {
|
|
||||||
// 全件取得(既存の挙動)
|
|
||||||
return DB::table('usertype')
|
|
||||||
->orderBy('user_categoryid', 'asc')
|
|
||||||
->get()
|
|
||||||
->mapWithKeys(function ($row) {
|
|
||||||
$label = collect([
|
|
||||||
$row->usertype_subject1 ?? '',
|
|
||||||
$row->usertype_subject2 ?? '',
|
|
||||||
$row->usertype_subject3 ?? '',
|
|
||||||
])->filter(fn ($v) => $v !== '')->implode('/');
|
|
||||||
|
|
||||||
return [$row->user_categoryid => $label !== '' ? $label : (string) $row->user_categoryid];
|
|
||||||
})
|
|
||||||
->toArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 実際に使用されている分類のみ取得する(内部結合で user と regular_contract と紐付くもの)
|
|
||||||
$rows = DB::table('usertype as ut')
|
|
||||||
->join('user as u', 'u.user_categoryid', '=', 'ut.user_categoryid')
|
|
||||||
->join('regular_contract as rc', 'rc.user_id', '=', 'u.user_id')
|
|
||||||
->select(
|
|
||||||
'ut.user_categoryid',
|
|
||||||
'ut.usertype_subject1',
|
|
||||||
'ut.usertype_subject2',
|
|
||||||
'ut.usertype_subject3'
|
|
||||||
)
|
|
||||||
->groupBy('ut.user_categoryid', 'ut.usertype_subject1', 'ut.usertype_subject2', 'ut.usertype_subject3')
|
|
||||||
->orderBy('ut.user_categoryid', 'asc')
|
|
||||||
->get();
|
|
||||||
|
|
||||||
// ラベルを組み立てて配列で返す
|
|
||||||
return $rows->mapWithKeys(function ($row) {
|
|
||||||
$label = collect([
|
|
||||||
$row->usertype_subject1 ?? '',
|
|
||||||
$row->usertype_subject2 ?? '',
|
|
||||||
$row->usertype_subject3 ?? '',
|
|
||||||
])->filter(fn ($v) => $v !== '')->implode('/');
|
|
||||||
|
|
||||||
return [$row->user_categoryid => $label !== '' ? $label : (string) $row->user_categoryid];
|
|
||||||
})->toArray();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,224 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use App\Models\Device;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Facades\Validator;
|
|
||||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
|
||||||
use App\Models\Park;
|
|
||||||
|
|
||||||
class DeviceController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 一覧: /device
|
|
||||||
*/
|
|
||||||
|
|
||||||
public function list(Request $request)
|
|
||||||
{
|
|
||||||
$perPage = \App\Utils::item_per_page ?? 20;
|
|
||||||
|
|
||||||
// リクエストからソート対象と方向を取得(デフォルト: device_id asc)
|
|
||||||
$sort = $request->input('sort', 'device_id');
|
|
||||||
$sort_type = $request->input('sort_type', 'asc');
|
|
||||||
|
|
||||||
// 許可カラム(SQLインジェクション対策)
|
|
||||||
$sortable = [
|
|
||||||
'device_id',
|
|
||||||
'park_id',
|
|
||||||
'device_type',
|
|
||||||
'device_subject',
|
|
||||||
'device_identifier',
|
|
||||||
'device_work',
|
|
||||||
'device_workstart',
|
|
||||||
'device_replace',
|
|
||||||
'device_remarks',
|
|
||||||
'operator_id',
|
|
||||||
'ope_auth1',
|
|
||||||
];
|
|
||||||
|
|
||||||
if (!in_array($sort, $sortable)) {
|
|
||||||
$sort = 'device_id';
|
|
||||||
}
|
|
||||||
if (!in_array(strtolower($sort_type), ['asc','desc'])) {
|
|
||||||
$sort_type = 'desc';
|
|
||||||
}
|
|
||||||
|
|
||||||
$list = Device::with('park')
|
|
||||||
->orderBy($sort, $sort_type)
|
|
||||||
->paginate($perPage)
|
|
||||||
->appends([
|
|
||||||
'sort' => $sort,
|
|
||||||
'sort_type' => $sort_type,
|
|
||||||
]);
|
|
||||||
|
|
||||||
return view('admin.devices.list', [
|
|
||||||
'list' => $list,
|
|
||||||
'sort' => $sort,
|
|
||||||
'sort_type' => $sort_type,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 新規登録(GET 画面 / POST 保存)
|
|
||||||
*/
|
|
||||||
public function add(Request $request)
|
|
||||||
{
|
|
||||||
if ($request->isMethod('get')) {
|
|
||||||
return view('admin.devices.add', [
|
|
||||||
'isEdit' => false,
|
|
||||||
'device' => new Device(),
|
|
||||||
'parks' => Park::all(),
|
|
||||||
|
|
||||||
// 初期値(Bladeで old() 使うなら省略可)
|
|
||||||
'device_id' => null,
|
|
||||||
'park_id' => '',
|
|
||||||
'device_type' => '',
|
|
||||||
'device_subject' => '',
|
|
||||||
'device_identifier'=> '',
|
|
||||||
'device_work' => '',
|
|
||||||
'device_workstart' => '',
|
|
||||||
'device_replace' => '',
|
|
||||||
'device_remarks' => '',
|
|
||||||
'operator_id' => '',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 入力値を一旦取得
|
|
||||||
$data = $request->all();
|
|
||||||
|
|
||||||
// --- バリデーション ---
|
|
||||||
$rules = [
|
|
||||||
'park_id' => ['required','integer'],
|
|
||||||
'device_type' => ['required','in:1,2,3'], // 1=サーバー, 2=プリンタ, 3=その他
|
|
||||||
'device_subject' => ['required','string','max:255'],
|
|
||||||
'device_identifier' => ['required','string','max:255'],
|
|
||||||
'device_work' => ['required','in:0,1'], // 1=稼働, 0=停止
|
|
||||||
'device_workstart' => ['required','date'],
|
|
||||||
'device_replace' => ['nullable','date'],
|
|
||||||
'device_remarks' => ['nullable','string','max:255'],
|
|
||||||
'operator_id' => ['nullable','integer'],
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
$request->validate($rules);
|
|
||||||
|
|
||||||
// 保存処理
|
|
||||||
$device = new Device();
|
|
||||||
$device->fill($data);
|
|
||||||
$device->save();
|
|
||||||
|
|
||||||
return redirect()->route('devices')->with('success', '登録しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 編集(GET 画面 / POST 更新)
|
|
||||||
*/
|
|
||||||
public function edit($id, Request $request)
|
|
||||||
{
|
|
||||||
$device = Device::find($id);
|
|
||||||
if (!$device) abort(404);
|
|
||||||
|
|
||||||
if ($request->isMethod('get')) {
|
|
||||||
return view('admin.devices.edit', [
|
|
||||||
'isEdit' => true,
|
|
||||||
'device' => $device,
|
|
||||||
'parks' => Park::all(),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 入力値を一旦取得
|
|
||||||
$data = $request->all();
|
|
||||||
|
|
||||||
// --- バリデーション ---
|
|
||||||
$rules = [
|
|
||||||
'park_id' => ['required','integer'],
|
|
||||||
'device_type' => ['required','in:1,2,3'], // 1=サーバー, 2=プリンタ, 3=その他
|
|
||||||
'device_subject' => ['required','string','max:255'],
|
|
||||||
'device_identifier' => ['required','string','max:255'],
|
|
||||||
'device_work' => ['required','in:0,1'], // 1=稼働, 0=停止
|
|
||||||
'device_workstart' => ['required','date'],
|
|
||||||
'device_replace' => ['nullable','date'],
|
|
||||||
'device_remarks' => ['nullable','string','max:255'],
|
|
||||||
'operator_id' => ['nullable','integer'],
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
$request->validate($rules);
|
|
||||||
|
|
||||||
// 保存処理
|
|
||||||
$device->fill($data);
|
|
||||||
$device->save();
|
|
||||||
|
|
||||||
return redirect()->route('devices')->with('success', '更新しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 詳細: /device/info/{id}
|
|
||||||
*/
|
|
||||||
// public function info(int $id)
|
|
||||||
// {
|
|
||||||
// $device = Device::with('park')->findOrFail($id);
|
|
||||||
|
|
||||||
// return view('admin.devices.info', [
|
|
||||||
// 'device' => $device,
|
|
||||||
// 'isInfo' => true,
|
|
||||||
// 'isEdit' => false,
|
|
||||||
// ]);
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 削除(単体 or 複数)
|
|
||||||
*/
|
|
||||||
public function delete(Request $request)
|
|
||||||
{
|
|
||||||
$ids = [];
|
|
||||||
|
|
||||||
// 単体削除
|
|
||||||
if ($request->filled('id')) {
|
|
||||||
$ids[] = (int) $request->input('id');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 複数削除
|
|
||||||
if ($request->filled('ids')) {
|
|
||||||
$ids = array_merge($ids, array_map('intval', (array)$request->input('ids')));
|
|
||||||
}
|
|
||||||
|
|
||||||
$ids = array_unique($ids);
|
|
||||||
|
|
||||||
if (!$ids) {
|
|
||||||
return back()->with('error', '削除対象が選択されていません。');
|
|
||||||
}
|
|
||||||
|
|
||||||
Device::deleteByPk($ids);
|
|
||||||
|
|
||||||
return redirect()->route('devices')->with('success', '削除しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** バリデーションルール */
|
|
||||||
private function rules(?int $id = null): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'park_id' => ['required','integer'], // 駐輪場ID 必須
|
|
||||||
'device_type' => ['required','in:1,2,3'], // 1=サーバー, 2=プリンタ, 3=その他
|
|
||||||
'device_subject' => ['required','string','max:255'], // デバイス名 必須
|
|
||||||
'device_identifier' => ['required','string','max:255'], // 識別子 必須
|
|
||||||
'device_work' => ['required','in:0,1'], // 1=稼働, 0=停止
|
|
||||||
'device_workstart' => ['required','date'], // 稼働開始日 必須
|
|
||||||
'device_replace' => ['nullable','date'], // リプレース予約日 任意
|
|
||||||
'device_remarks' => ['nullable','string','max:255'], // 備考 任意
|
|
||||||
'operator_id' => ['nullable','integer'], // 任意
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -10,69 +10,35 @@ class InformationController extends Controller
|
|||||||
{
|
{
|
||||||
public function list(Request $request)
|
public function list(Request $request)
|
||||||
{
|
{
|
||||||
// パラメータ
|
// フィルター取得
|
||||||
$period = $request->input('period', 'month'); // month | all
|
$period = $request->input('period', 'month'); // デフォルト: 最新1ヵ月
|
||||||
$type = $request->input('type', 'all'); // task(<99) | hard(>99) | all
|
|
||||||
$status = $request->input('status', 'untreated'); // untreated(=1) | inprogress(=2) | done(=3) | all
|
|
||||||
|
|
||||||
$q = DB::table('operator_que as oq')
|
$query = DB::table('bat_job_log')
|
||||||
->leftJoin('user as u', 'oq.user_id', '=', 'u.user_id')
|
->leftJoin('device', 'bat_job_log.device_id', '=', 'device.device_id')
|
||||||
->leftJoin('park as p', 'oq.park_id', '=', 'p.park_id')
|
|
||||||
// オペレータマスタ(テーブル・カラム名は環境に合わせて調整)
|
|
||||||
->leftJoin('ope as o', 'oq.operator_id', '=', 'o.ope_id')
|
|
||||||
->select(
|
->select(
|
||||||
'oq.que_id','oq.que_class','oq.user_id',
|
'bat_job_log.job_log_id',
|
||||||
DB::raw('u.user_name as user_name'),
|
'bat_job_log.process_name',
|
||||||
'oq.contract_id','oq.park_id',
|
'bat_job_log.job_name',
|
||||||
DB::raw('p.park_name as park_name'),
|
'bat_job_log.device_id',
|
||||||
'oq.que_comment','oq.que_status','oq.que_status_comment',
|
'device.park_id',
|
||||||
'oq.work_instructions','oq.created_at','oq.updated_at','oq.operator_id',
|
'bat_job_log.status_comment',
|
||||||
DB::raw('o.ope_name as operator_name')
|
'bat_job_log.status',
|
||||||
|
'bat_job_log.status_comment as comment',
|
||||||
|
'bat_job_log.created_at',
|
||||||
|
'bat_job_log.updated_at'
|
||||||
);
|
);
|
||||||
|
|
||||||
// 期間: 登録日ベース(最新1ヵ月 or 全期間)
|
// 期間フィルター
|
||||||
if ($period === 'month') {
|
if ($period === 'month') {
|
||||||
$q->where('oq.created_at', '>=', now()->subMonth());
|
$query->where('bat_job_log.updated_at', '>=', now()->subMonth());
|
||||||
}
|
}
|
||||||
|
// 'all'の場合はフィルターなし
|
||||||
|
|
||||||
// 種別: que_class
|
$jobs = $query->orderByDesc('bat_job_log.job_log_id')->limit(50)->get();
|
||||||
if ($type === 'task') {
|
|
||||||
$q->where('oq.que_class', '<', 99);
|
|
||||||
} elseif ($type === 'hard') {
|
|
||||||
$q->where('oq.que_class', '>', 99);
|
|
||||||
} // all は絞り込みなし
|
|
||||||
|
|
||||||
// ステータス: que_status
|
return view('admin.information.list', [
|
||||||
if ($status === 'untreated') {
|
'jobs' => $jobs,
|
||||||
$q->where('oq.que_status', 1);
|
'period' => $period,
|
||||||
} elseif ($status === 'inprogress') {
|
|
||||||
$q->where('oq.que_status', 2);
|
|
||||||
} elseif ($status === 'done') {
|
|
||||||
$q->where('oq.que_status', 3);
|
|
||||||
} // all は絞り込みなし
|
|
||||||
|
|
||||||
$jobs = $q->orderBy('oq.que_id')->paginate(20)->appends($request->query());
|
|
||||||
|
|
||||||
return view('admin.information.list', compact('jobs','period','type','status'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// ステータス一括更新(着手=2 / 対応完了=3)
|
|
||||||
public function updateStatus(Request $request)
|
|
||||||
{
|
|
||||||
$request->validate([
|
|
||||||
'ids' => 'required|array',
|
|
||||||
'action' => 'required|in:inprogress,done',
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$new = $request->action === 'inprogress' ? 2 : 3;
|
|
||||||
|
|
||||||
DB::table('operator_que')
|
|
||||||
->whereIn('que_id', $request->ids)
|
|
||||||
->update([
|
|
||||||
'que_status' => $new,
|
|
||||||
'updated_at' => now(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
return back()->with('success', '選択したキューのステータスを更新しました。');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,226 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Models\InvSetting;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\Storage;
|
|
||||||
|
|
||||||
class InvSettingController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 登録フォーム表示
|
|
||||||
*/
|
|
||||||
public function form(Request $request)
|
|
||||||
{
|
|
||||||
$row = InvSetting::first();
|
|
||||||
|
|
||||||
$zip1 = $zip2 = $tel1 = $tel2 = $tel3 = $fax1 = $fax2 = $fax3 = '';
|
|
||||||
|
|
||||||
if ($row) {
|
|
||||||
// 郵便番号(そのままハイフン分割)
|
|
||||||
if (!empty($row->zipcode) && str_contains($row->zipcode, '-')) {
|
|
||||||
[$zip1, $zip2] = explode('-', $row->zipcode);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 電話番号:数字以外を除去 → 2桁+4桁+4桁 に分割
|
|
||||||
if (!empty($row->tel_num)) {
|
|
||||||
$tel = preg_replace('/\D/', '', $row->tel_num); // 数字以外を除去
|
|
||||||
$tel1 = substr($tel, 0, 2);
|
|
||||||
$tel2 = substr($tel, 2, 4);
|
|
||||||
$tel3 = substr($tel, 6, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FAX番号:同じく 2桁+4桁+4桁
|
|
||||||
if (!empty($row->fax_num)) {
|
|
||||||
$fax = preg_replace('/\D/', '', $row->fax_num);
|
|
||||||
$fax1 = substr($fax, 0, 2);
|
|
||||||
$fax2 = substr($fax, 2, 4);
|
|
||||||
$fax3 = substr($fax, 6, 4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return view('admin.invsettings._form', compact(
|
|
||||||
'row', 'zip1', 'zip2', 'tel1', 'tel2', 'tel3', 'fax1', 'fax2', 'fax3'
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登録・更新処理
|
|
||||||
*/
|
|
||||||
public function save(Request $request)
|
|
||||||
{
|
|
||||||
// ▼ バリデーションルール
|
|
||||||
$rules = [
|
|
||||||
't_number' => 'required|string|max:20',
|
|
||||||
't_name' => 'required|string|max:50',
|
|
||||||
'zip1' => 'required|digits:3',
|
|
||||||
'zip2' => 'required|digits:4',
|
|
||||||
'adrs' => 'required|string|max:100',
|
|
||||||
'bldg' => 'nullable|string|max:80',
|
|
||||||
'tel1' => 'nullable|digits_between:2,4',
|
|
||||||
'tel2' => 'nullable|digits_between:2,4',
|
|
||||||
'tel3' => 'nullable|digits_between:3,4',
|
|
||||||
'fax1' => 'nullable|digits_between:2,4',
|
|
||||||
'fax2' => 'nullable|digits_between:2,4',
|
|
||||||
'fax3' => 'nullable|digits_between:3,4',
|
|
||||||
'company_image_path' => 'nullable|string|max:255',
|
|
||||||
];
|
|
||||||
|
|
||||||
// ▼ カスタム日本語メッセージ
|
|
||||||
$messages = [
|
|
||||||
't_number.required' => '適格請求書発行事業者番号を入力してください。',
|
|
||||||
't_number.max' => '適格請求書発行事業者番号は20文字以内で入力してください。',
|
|
||||||
|
|
||||||
't_name.required' => '適格事業者名を入力してください。',
|
|
||||||
't_name.max' => '適格事業者名は50文字以内で入力してください。',
|
|
||||||
|
|
||||||
'zip1.required' => '郵便番号(前半)を入力してください。',
|
|
||||||
'zip1.digits' => '郵便番号(前半)は3桁で入力してください。',
|
|
||||||
'zip2.required' => '郵便番号(後半)を入力してください。',
|
|
||||||
'zip2.digits' => '郵便番号(後半)は4桁で入力してください。',
|
|
||||||
|
|
||||||
'adrs.required' => '表示住所を入力してください。',
|
|
||||||
'adrs.max' => '表示住所は100文字以内で入力してください。',
|
|
||||||
|
|
||||||
'tel1.digits_between' => '電話番号1は2桁から4桁で入力してください。',
|
|
||||||
'tel2.digits_between' => '電話番号2は2桁から4桁で入力してください。',
|
|
||||||
'tel3.digits_between' => '電話番号3は3桁から4桁で入力してください。',
|
|
||||||
|
|
||||||
'fax1.digits_between' => 'FAX番号1は2桁から4桁で入力してください。',
|
|
||||||
'fax2.digits_between' => 'FAX番号2は2桁から4桁で入力してください。',
|
|
||||||
'fax3.digits_between' => 'FAX番号3は3桁から4桁で入力してください。',
|
|
||||||
];
|
|
||||||
|
|
||||||
// ▼ バリデーション実行
|
|
||||||
$request->validate($rules, $messages);
|
|
||||||
|
|
||||||
// ▼ データ整形
|
|
||||||
$zipcode = $request->zip1 . '-' . $request->zip2;
|
|
||||||
$tel = implode('-', array_filter([$request->tel1, $request->tel2, $request->tel3]));
|
|
||||||
$fax = implode('-', array_filter([$request->fax1, $request->fax2, $request->fax3]));
|
|
||||||
|
|
||||||
// ▼ 既存レコードを取得(1レコード運用)
|
|
||||||
$row = InvSetting::first();
|
|
||||||
|
|
||||||
// ▼ 画像パスを設定
|
|
||||||
$imagePath = $request->company_image_path;
|
|
||||||
|
|
||||||
// ▼ フォームで新たにファイルを送信した場合のみ再保存(保険的処理)
|
|
||||||
if ($request->hasFile('company_image')) {
|
|
||||||
if ($imagePath && Storage::disk('public')->exists($imagePath)) {
|
|
||||||
Storage::disk('public')->delete($imagePath);
|
|
||||||
}
|
|
||||||
$imagePath = $request->file('company_image')->store('inv', 'public');
|
|
||||||
}
|
|
||||||
|
|
||||||
// ▼ レコードを新規作成 or 更新
|
|
||||||
if ($row) {
|
|
||||||
$row->update([
|
|
||||||
't_number' => $request->t_number,
|
|
||||||
't_name' => $request->t_name,
|
|
||||||
'zipcode' => $zipcode,
|
|
||||||
'adrs' => $request->adrs,
|
|
||||||
'bldg' => $request->bldg,
|
|
||||||
'tel_num' => $tel,
|
|
||||||
'fax_num' => $fax,
|
|
||||||
'company_image_path' => $imagePath, // ← hiddenの値 or 新規アップロード結果を保存
|
|
||||||
]);
|
|
||||||
} else {
|
|
||||||
InvSetting::create([
|
|
||||||
't_number' => $request->t_number,
|
|
||||||
't_name' => $request->t_name,
|
|
||||||
'zipcode' => $zipcode,
|
|
||||||
'adrs' => $request->adrs,
|
|
||||||
'bldg' => $request->bldg,
|
|
||||||
'tel_num' => $tel,
|
|
||||||
'fax_num' => $fax,
|
|
||||||
'company_image_path' => $imagePath,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return back()->with('success', 'インボイス設定を登録しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 社判画像アップロード(AJAX用)
|
|
||||||
*/
|
|
||||||
// public function upload(Request $request)
|
|
||||||
// {
|
|
||||||
// // ファイルがアップロードされているか確認
|
|
||||||
// if ($request->hasFile('company_image_file')) {
|
|
||||||
|
|
||||||
// // 拡張子チェック & バリデーション
|
|
||||||
// $request->validate([
|
|
||||||
// 'company_image_file' => 'required|image|mimes:png,jpg,jpeg|max:2048',
|
|
||||||
// ], [
|
|
||||||
// 'company_image_file.image' => '画像ファイルを選択してください。',
|
|
||||||
// 'company_image_file.mimes' => 'アップロード可能な形式は png, jpg, jpeg のみです。',
|
|
||||||
// 'company_image_file.max' => 'ファイルサイズは2MB以下にしてください。',
|
|
||||||
// ]);
|
|
||||||
|
|
||||||
// // ファイル保存(public/storage/inv に格納)
|
|
||||||
// $path = $request->file('company_image_file')->store('inv', 'public');
|
|
||||||
|
|
||||||
// // ファイル名を抽出
|
|
||||||
// $fileName = basename($path);
|
|
||||||
|
|
||||||
// // JSONで返却(JSが受け取る)
|
|
||||||
// return response()->json([
|
|
||||||
// 'file_name' => $fileName,
|
|
||||||
// 'path' => $path,
|
|
||||||
// ]);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // ファイル未選択時
|
|
||||||
// return response()->json([
|
|
||||||
// 'error' => 'ファイルが選択されていません。'
|
|
||||||
// ], 400);
|
|
||||||
// }
|
|
||||||
|
|
||||||
public function upload(Request $request)
|
|
||||||
{
|
|
||||||
// ファイルがアップロードされているか確認
|
|
||||||
if ($request->hasFile('company_image_file')) {
|
|
||||||
|
|
||||||
// 拡張子チェック & バリデーション
|
|
||||||
$request->validate([
|
|
||||||
'company_image_file' => 'required|image|mimes:png,jpg,jpeg|max:2048',
|
|
||||||
], [
|
|
||||||
'company_image_file.image' => '画像ファイルを選択してください。',
|
|
||||||
'company_image_file.mimes' => 'アップロード可能な形式は png, jpg, jpeg のみです。',
|
|
||||||
'company_image_file.max' => 'ファイルサイズは2MB以下にしてください。',
|
|
||||||
]);
|
|
||||||
|
|
||||||
// ファイルオブジェクト取得
|
|
||||||
$file = $request->file('company_image_file');
|
|
||||||
|
|
||||||
// 元のファイル名(例:company_logo.png)
|
|
||||||
$originalName = $file->getClientOriginalName();
|
|
||||||
|
|
||||||
// 保存用に、ファイル名の重複を避けるためにユニーク名を生成(推奨)
|
|
||||||
$fileName = $originalName;
|
|
||||||
|
|
||||||
// public/storage/inv に保存
|
|
||||||
$path = $file->storeAs('inv', $fileName, 'public');
|
|
||||||
|
|
||||||
// JSONで返却(JS側で表示用ファイル名を使う)
|
|
||||||
return response()->json([
|
|
||||||
'file_name' => $originalName, // ユーザーが見えるファイル名
|
|
||||||
'stored_as' => $fileName, // 実際に保存されたファイル名
|
|
||||||
'path' => $path,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ファイル未選択時
|
|
||||||
return response()->json([
|
|
||||||
'error' => 'ファイルが選択されていません。'
|
|
||||||
], 400);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,134 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use App\Models\JurisdictionParking;
|
|
||||||
use App\Models\Park;
|
|
||||||
use App\Models\Ope;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
|
|
||||||
class JurisdictionParkingController extends Controller
|
|
||||||
{
|
|
||||||
public function list(Request $request)
|
|
||||||
{
|
|
||||||
|
|
||||||
$sort = $request->input('sort', 'jurisdiction_parking_id');
|
|
||||||
$sort_type = $request->input('sort_type', 'asc');
|
|
||||||
|
|
||||||
$list = JurisdictionParking::orderBy($sort, $sort_type)->paginate(20);
|
|
||||||
|
|
||||||
return view('admin.jurisdiction_parkings.list', compact('list', 'sort', 'sort_type'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function add(Request $request)
|
|
||||||
{
|
|
||||||
if ($request->isMethod('post')) {
|
|
||||||
$validated = $request->validate([
|
|
||||||
'jurisdiction_parking_name' => [
|
|
||||||
'required',
|
|
||||||
'string',
|
|
||||||
'max:20',
|
|
||||||
],
|
|
||||||
'ope_id' => [
|
|
||||||
'required',
|
|
||||||
],
|
|
||||||
'park_id' => [
|
|
||||||
'required',
|
|
||||||
],
|
|
||||||
'operator_id' => [
|
|
||||||
'nullable',
|
|
||||||
'integer',
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
|
|
||||||
JurisdictionParking::create($validated);
|
|
||||||
|
|
||||||
return redirect()->route('jurisdiction_parkings')
|
|
||||||
->with('success', '登録しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
$parks = Park::pluck('park_name', 'park_id');
|
|
||||||
$opes = Ope::pluck('ope_name', 'ope_id');
|
|
||||||
|
|
||||||
return view('admin.jurisdiction_parkings.add', compact('parks', 'opes'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function edit(Request $request, $id)
|
|
||||||
{
|
|
||||||
$record = JurisdictionParking::findOrFail($id);
|
|
||||||
|
|
||||||
if ($request->isMethod('post')) {
|
|
||||||
$validated = $request->validate([
|
|
||||||
'jurisdiction_parking_name' => [
|
|
||||||
'required',
|
|
||||||
'string',
|
|
||||||
'max:20',
|
|
||||||
],
|
|
||||||
'ope_id' => [
|
|
||||||
'required',
|
|
||||||
],
|
|
||||||
'park_id' => [
|
|
||||||
'required',
|
|
||||||
],
|
|
||||||
'operator_id' => [
|
|
||||||
'nullable',
|
|
||||||
'integer',
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
|
|
||||||
$record->update($validated);
|
|
||||||
|
|
||||||
return redirect()->route('jurisdiction_parkings')
|
|
||||||
->with('success', '更新しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
$parks = Park::pluck('park_name', 'park_id');
|
|
||||||
$opes = Ope::pluck('ope_name', 'ope_id');
|
|
||||||
|
|
||||||
return view('admin.jurisdiction_parkings.edit', compact('record', 'parks', 'opes'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function delete(Request $request)
|
|
||||||
{
|
|
||||||
$request->validate([
|
|
||||||
'pk' => 'required',
|
|
||||||
'pk.*' => 'integer', // 各要素が整数であることを確認
|
|
||||||
]);
|
|
||||||
|
|
||||||
$ids = (array) $request->input('pk'); // 配列として取得
|
|
||||||
|
|
||||||
$deleted = JurisdictionParking::destroy($ids);
|
|
||||||
|
|
||||||
if ($deleted > 0) {
|
|
||||||
return redirect()->route('jurisdiction_parkings')
|
|
||||||
->with('success', '削除しました。');
|
|
||||||
} else {
|
|
||||||
return redirect()->route('jurisdiction_parkings')
|
|
||||||
->with('error', '削除に失敗しました。');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function info(Request $request, $jurisdiction_parking_id)
|
|
||||||
{
|
|
||||||
$record = JurisdictionParking::findOrFail($jurisdiction_parking_id);
|
|
||||||
return view('admin.jurisdiction_parkings.info', compact('record'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function import(Request $request)
|
|
||||||
{
|
|
||||||
// CSVインポート処理仮
|
|
||||||
return redirect()->route('jurisdiction_parkings')->with('success', 'CSVインポート処理(未実装)');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function export(Request $request)
|
|
||||||
{
|
|
||||||
// CSVエクスポート処理仮
|
|
||||||
return response()->streamDownload(function () {
|
|
||||||
echo 'CSVエクスポートデータ(未実装)';
|
|
||||||
}, 'jurisdiction_parkings.csv');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,146 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use App\Models\MailTemplate;
|
|
||||||
|
|
||||||
class MailTemplateController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 一覧表示
|
|
||||||
*/
|
|
||||||
public function list(Request $request)
|
|
||||||
{
|
|
||||||
if ($request->input('action') === 'reset') {
|
|
||||||
return redirect()->route('mail_templates');
|
|
||||||
}
|
|
||||||
|
|
||||||
$allowedSorts = [
|
|
||||||
'mail_template_id', 'pg_id', 'internal_id', 'mgr_cc_flag',
|
|
||||||
'bcc_adrs', 'use_flag', 'memo', 'subject', 'text',
|
|
||||||
'created_at', 'updated_at', 'operator_id'
|
|
||||||
];
|
|
||||||
|
|
||||||
$sort = $request->input('sort', 'mail_template_id');
|
|
||||||
$sort_type = $request->input('sort_type', 'asc');
|
|
||||||
|
|
||||||
if (!in_array($sort, $allowedSorts)) {
|
|
||||||
$sort = 'mail_template_id';
|
|
||||||
}
|
|
||||||
if (!in_array($sort_type, ['asc', 'desc'])) {
|
|
||||||
$sort_type = 'desc';
|
|
||||||
}
|
|
||||||
|
|
||||||
$query = MailTemplate::query();
|
|
||||||
|
|
||||||
// === 絞り込み ===
|
|
||||||
$mail_template_id = $request->input('mail_template_id');
|
|
||||||
$pg_id = $request->input('pg_id');
|
|
||||||
$mgr_cc_flag = $request->input('mgr_cc_flag');
|
|
||||||
$use_flag = $request->input('use_flag');
|
|
||||||
$subject = $request->input('subject');
|
|
||||||
|
|
||||||
if ($mail_template_id) {
|
|
||||||
$query->where('mail_template_id', $mail_template_id);
|
|
||||||
}
|
|
||||||
if ($pg_id) {
|
|
||||||
$query->where('pg_id', $pg_id);
|
|
||||||
}
|
|
||||||
if ($mgr_cc_flag !== null && $mgr_cc_flag !== '') {
|
|
||||||
$query->where('mgr_cc_flag', $mgr_cc_flag);
|
|
||||||
}
|
|
||||||
if ($use_flag !== null && $use_flag !== '') {
|
|
||||||
$query->where('use_flag', $use_flag);
|
|
||||||
}
|
|
||||||
if ($subject) {
|
|
||||||
$query->where('subject', 'LIKE', "%{$subject}%");
|
|
||||||
}
|
|
||||||
|
|
||||||
$templates = $query->orderBy($sort, $sort_type)->paginate(20);
|
|
||||||
|
|
||||||
return view('admin.mail_templates.list', compact(
|
|
||||||
'templates', 'sort', 'sort_type',
|
|
||||||
'mail_template_id', 'pg_id', 'mgr_cc_flag', 'use_flag', 'subject'
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function add(Request $request)
|
|
||||||
{
|
|
||||||
if ($request->isMethod('post')) {
|
|
||||||
$data = $this->validateTemplate($request);
|
|
||||||
$data['operator_id'] = optional(\Auth::user())->ope_id ?? null;
|
|
||||||
|
|
||||||
MailTemplate::create($data);
|
|
||||||
|
|
||||||
return redirect()->route('mail_templates')
|
|
||||||
->with('success', '登録しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
return view('admin.mail_templates.add', [
|
|
||||||
'mailTemplate' => new MailTemplate(),
|
|
||||||
'isEdit' => false,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 編集
|
|
||||||
*/
|
|
||||||
public function edit(int $id, Request $request)
|
|
||||||
{
|
|
||||||
$mailTemplate = MailTemplate::findOrFail($id);
|
|
||||||
|
|
||||||
if ($request->isMethod('post')) {
|
|
||||||
$data = $this->validateTemplate($request);
|
|
||||||
$data['operator_id'] = optional(\Auth::user())->ope_id ?? null;
|
|
||||||
|
|
||||||
$mailTemplate->update($data);
|
|
||||||
|
|
||||||
return redirect()->route('mail_templates')
|
|
||||||
->with('success', '更新しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
return view('admin.mail_templates.edit', [
|
|
||||||
'mailTemplate' => $mailTemplate,
|
|
||||||
'isEdit' => true,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 削除
|
|
||||||
*/
|
|
||||||
public function delete(Request $request)
|
|
||||||
{
|
|
||||||
$pk = $request->input('pk', []);
|
|
||||||
|
|
||||||
// 配列に統一
|
|
||||||
$ids = is_array($pk) ? $pk : [$pk];
|
|
||||||
$ids = array_values(array_filter($ids, fn($v) => preg_match('/^\d+$/', (string) $v)));
|
|
||||||
|
|
||||||
if (empty($ids)) {
|
|
||||||
return redirect()->route('mail_templates')->with('error', '削除対象が選択されていません。');
|
|
||||||
}
|
|
||||||
|
|
||||||
MailTemplate::whereIn('mail_template_id', $ids)->delete();
|
|
||||||
|
|
||||||
return redirect()->route('mail_templates')->with('success', '削除しました。');
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* バリデーション共通化
|
|
||||||
*/
|
|
||||||
private function validateTemplate(Request $request)
|
|
||||||
{
|
|
||||||
return $request->validate([
|
|
||||||
'pg_id' => 'required|integer',
|
|
||||||
'internal_id' => 'required|integer',
|
|
||||||
'mgr_cc_flag' => 'required|boolean',
|
|
||||||
'bcc_adrs' => 'nullable|string|max:255',
|
|
||||||
'use_flag' => 'required|boolean',
|
|
||||||
'memo' => 'nullable|string|max:255',
|
|
||||||
'subject' => 'required|string|max:255',
|
|
||||||
'text' => 'required|string',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,249 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Models\Manager;
|
|
||||||
use App\Models\Park;
|
|
||||||
use App\Models\Device;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
|
||||||
|
|
||||||
class ManagerController extends Controller
|
|
||||||
{
|
|
||||||
/** 一覧 */
|
|
||||||
public function list(Request $request)
|
|
||||||
{
|
|
||||||
$sortable = [
|
|
||||||
'manager_id','manager_name','manager_parkid','manager_tel',
|
|
||||||
'manager_alert1','manager_alert2','manager_quit_flag'
|
|
||||||
];
|
|
||||||
$sort = $request->input('sort', 'manager_id');
|
|
||||||
$sort_type = $request->input('sort_type', 'asc');
|
|
||||||
if (!in_array($sort, $sortable)) $sort = 'manager_id';
|
|
||||||
if (!in_array(strtolower($sort_type), ['asc','desc'])) $sort_type = 'asc';
|
|
||||||
|
|
||||||
$list = Manager::with(['park','device1','device2'])
|
|
||||||
->orderBy($sort, $sort_type)
|
|
||||||
->paginate(20);
|
|
||||||
|
|
||||||
return view('admin.managers.list', compact('list','sort','sort_type'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 新規登録画面・登録処理 */
|
|
||||||
public function add(Request $request)
|
|
||||||
{
|
|
||||||
if ($request->isMethod('post')) {
|
|
||||||
$validated = $this->validated($request);
|
|
||||||
|
|
||||||
Manager::create($validated);
|
|
||||||
|
|
||||||
return redirect()
|
|
||||||
->route('managers')
|
|
||||||
->with('success', '登録しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
return view('admin.managers.add', $this->viewVars());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 編集(GET:画面表示 / POST:更新) */
|
|
||||||
public function edit(Request $request, $id)
|
|
||||||
{
|
|
||||||
$manager = Manager::findOrFail($id);
|
|
||||||
|
|
||||||
if ($request->isMethod('post')) {
|
|
||||||
$validated = $this->validated($request);
|
|
||||||
|
|
||||||
$manager->update($validated);
|
|
||||||
|
|
||||||
return redirect()
|
|
||||||
->route('managers')
|
|
||||||
->with('success', '更新されました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
return view('admin.managers.edit', $this->viewVars($manager));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 詳細(閲覧) */
|
|
||||||
public function info($manager_id)
|
|
||||||
{
|
|
||||||
$manager = Manager::with(['park','device1','device2'])->findOrFail($manager_id);
|
|
||||||
$view = $this->viewVars($manager);
|
|
||||||
return view('admin.managers.info', $view);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 一括削除(一覧・詳細・編集共通で pk[] を受ける) */
|
|
||||||
public function delete(Request $request)
|
|
||||||
{
|
|
||||||
$ids = (array) $request->input('pk', []);
|
|
||||||
if (!$ids) {
|
|
||||||
return back()->with('error', '削除対象が選択されていません。');
|
|
||||||
}
|
|
||||||
|
|
||||||
DB::transaction(fn() => Manager::whereIn('manager_id', $ids)->delete());
|
|
||||||
|
|
||||||
// 一覧画面へリダイレクト + 成功メッセージ
|
|
||||||
return redirect()
|
|
||||||
->route('managers')
|
|
||||||
->with('success', '削除しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** CSV出力 */
|
|
||||||
public function export(): StreamedResponse
|
|
||||||
{
|
|
||||||
$headers = [
|
|
||||||
'Content-Type' => 'text/csv; charset=UTF-8',
|
|
||||||
'Content-Disposition' => 'attachment; filename=managers.csv',
|
|
||||||
];
|
|
||||||
|
|
||||||
$columns = [
|
|
||||||
'manager_id','manager_name','manager_type','manager_parkid',
|
|
||||||
'manager_device1','manager_device2','manager_mail','manager_tel',
|
|
||||||
'manager_alert1','manager_alert2','manager_quit_flag','manager_quitday'
|
|
||||||
];
|
|
||||||
|
|
||||||
return response()->stream(function () use ($columns) {
|
|
||||||
$out = fopen('php://output', 'w');
|
|
||||||
fwrite($out, "\xEF\xBB\xBF"); // BOM
|
|
||||||
fputcsv($out, $columns);
|
|
||||||
|
|
||||||
Manager::chunk(500, function ($rows) use ($out, $columns) {
|
|
||||||
foreach ($rows as $r) {
|
|
||||||
fputcsv($out, array_map(fn($c) => data_get($r, $c), $columns));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
fclose($out);
|
|
||||||
}, 200, $headers);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** CSVインポート(input name="file") */
|
|
||||||
public function import(Request $request)
|
|
||||||
{
|
|
||||||
if (!$request->hasFile('file')) {
|
|
||||||
return back()->with('error', 'CSVファイルを選択してください。');
|
|
||||||
}
|
|
||||||
$fp = fopen($request->file('file')->getRealPath(), 'r');
|
|
||||||
if (!$fp) return back()->with('error', 'CSVを読み込めませんでした。');
|
|
||||||
|
|
||||||
$header = fgetcsv($fp);
|
|
||||||
if (!$header) { fclose($fp); return back()->with('error', 'ヘッダ行が読み取れません。'); }
|
|
||||||
|
|
||||||
$required = [
|
|
||||||
'manager_id','manager_name','manager_type','manager_parkid',
|
|
||||||
'manager_device1','manager_device2','manager_mail','manager_tel',
|
|
||||||
'manager_alert1','manager_alert2','manager_quit_flag','manager_quitday'
|
|
||||||
];
|
|
||||||
foreach ($required as $c) {
|
|
||||||
if (!in_array($c, $header)) { fclose($fp); return back()->with('error', "CSVに {$c} がありません。"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
DB::beginTransaction();
|
|
||||||
try {
|
|
||||||
while (($row = fgetcsv($fp)) !== false) {
|
|
||||||
$data = array_combine($header, $row); if (!$data) continue;
|
|
||||||
|
|
||||||
Manager::updateOrCreate(
|
|
||||||
['manager_id' => $data['manager_id']],
|
|
||||||
[
|
|
||||||
'manager_name' => $data['manager_name'] ?? null,
|
|
||||||
'manager_type' => $data['manager_type'] ?? null,
|
|
||||||
'manager_parkid' => $data['manager_parkid'] ?: null,
|
|
||||||
'manager_device1' => $data['manager_device1'] ?: null,
|
|
||||||
'manager_device2' => $data['manager_device2'] ?: null,
|
|
||||||
'manager_mail' => $data['manager_mail'] ?? null,
|
|
||||||
'manager_tel' => $data['manager_tel'] ?? null,
|
|
||||||
'manager_alert1' => (int)($data['manager_alert1'] ?? 0),
|
|
||||||
'manager_alert2' => (int)($data['manager_alert2'] ?? 0),
|
|
||||||
'manager_quit_flag' => (int)($data['manager_quit_flag'] ?? 0),
|
|
||||||
'manager_quitday' => $data['manager_quitday'] ?: null,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
fclose($fp);
|
|
||||||
DB::commit();
|
|
||||||
return back()->with('success', 'インポートが完了しました。');
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
if (is_resource($fp)) fclose($fp);
|
|
||||||
DB::rollBack();
|
|
||||||
return back()->with('error', 'インポートに失敗しました:'.$e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** バリデーション + 前処理 */
|
|
||||||
private function validated(Request $request): array
|
|
||||||
{
|
|
||||||
// 電話番号を全角に変換(半角入力があっても自動で全角に揃える)
|
|
||||||
$request->merge([
|
|
||||||
'manager_tel' => mb_convert_kana($request->input('manager_tel'), 'N') // 半角数字→全角数字
|
|
||||||
]);
|
|
||||||
|
|
||||||
// select の未選択 "" を null に補正
|
|
||||||
foreach (['manager_device2'] as $f) {
|
|
||||||
if ($request->input($f) === "") {
|
|
||||||
$request->merge([$f => null]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $request->validate([
|
|
||||||
'manager_name' => ['required','string','max:32'],
|
|
||||||
'manager_type' => ['required','string','max:10'],
|
|
||||||
'manager_parkid' => ['required','integer','exists:park,park_id'],
|
|
||||||
'manager_device1' => ['required','integer','exists:device,device_id'],
|
|
||||||
'manager_device2' => ['nullable','integer','exists:device,device_id'],
|
|
||||||
'manager_mail' => ['nullable','email','max:128'],
|
|
||||||
'manager_tel' => ['required','regex:/^[0-9]+$/u','max:13'], // 全角数字のみ
|
|
||||||
'manager_alert1' => ['nullable','boolean'],
|
|
||||||
'manager_alert2' => ['nullable','boolean'],
|
|
||||||
'manager_quit_flag' => ['required','in:0,1'],
|
|
||||||
'manager_quitday' => ['nullable','date'],
|
|
||||||
], [], [
|
|
||||||
'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' => '退職日',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** 画面に渡す変数を作る(_form.blade.php が個別変数を参照するため) */
|
|
||||||
private function viewVars(?Manager $m = null): array
|
|
||||||
{
|
|
||||||
$parks = Park::orderBy('park_name')->pluck('park_name','park_id')->toArray();
|
|
||||||
$devices = Device::orderBy('device_subject')->pluck('device_subject','device_id')->toArray();
|
|
||||||
|
|
||||||
return [
|
|
||||||
// _form が参照する個別変数
|
|
||||||
'manager_id' => $m->manager_id ?? null,
|
|
||||||
'manager_name' => $m->manager_name ?? null,
|
|
||||||
'manager_type' => $m->manager_type ?? null,
|
|
||||||
'manager_parkid' => $m->manager_parkid ?? null,
|
|
||||||
'manager_device1' => $m->manager_device1 ?? null,
|
|
||||||
'manager_device2' => $m->manager_device2 ?? null,
|
|
||||||
'manager_mail' => $m->manager_mail ?? null,
|
|
||||||
'manager_tel' => $m->manager_tel ?? null,
|
|
||||||
'manager_alert1' => (int)($m->manager_alert1 ?? 0),
|
|
||||||
'manager_alert2' => (int)($m->manager_alert2 ?? 0),
|
|
||||||
'manager_quit_flag' => isset($m) ? (int)$m->manager_quit_flag : 0,
|
|
||||||
'manager_quitday' => isset($m) && $m->manager_quitday ? $m->manager_quitday->format('Y-m-d') : null,
|
|
||||||
|
|
||||||
// セレクトの候補
|
|
||||||
'parks' => $parks,
|
|
||||||
'devices' => $devices,
|
|
||||||
|
|
||||||
// _form で必要なフラグ(各ビューで上書きしてもOK)
|
|
||||||
'isEdit' => isset($m),
|
|
||||||
'isInfo' => false,
|
|
||||||
'record' => $m, // 互換用(あなた的 edit.blade.php で参照しているなら)
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -61,29 +61,11 @@ class NewsController extends Controller
|
|||||||
if ($request->filled('from')) { $q->where('open_datetime','>=',$request->input('from')); }
|
if ($request->filled('from')) { $q->where('open_datetime','>=',$request->input('from')); }
|
||||||
if ($request->filled('to')) { $q->where('open_datetime','<=',$request->input('to')); }
|
if ($request->filled('to')) { $q->where('open_datetime','<=',$request->input('to')); }
|
||||||
|
|
||||||
// {追加} 並び替え(ホワイトリスト)
|
// 並び順:公開日時の降順 → 主キー降順
|
||||||
$sort = (string)$request->query('sort', '');
|
$rows = $q->orderByDesc('open_datetime')
|
||||||
$dir = strtolower((string)$request->query('dir', 'desc'));
|
->orderByDesc($this->pk)
|
||||||
$dir = in_array($dir, ['asc','desc'], true) ? $dir : 'desc';
|
->paginate(20)
|
||||||
|
->withQueryString();
|
||||||
// 画面キー → 実カラム
|
|
||||||
$sortable = [
|
|
||||||
'id' => $this->pk, // ニュースID
|
|
||||||
'news' => 'news', // ニュース内容
|
|
||||||
'open_datetime' => 'open_datetime', // 公開日時
|
|
||||||
'mode' => 'mode', // 表示モード
|
|
||||||
];
|
|
||||||
|
|
||||||
if (isset($sortable[$sort])) {
|
|
||||||
$q->orderBy($sortable[$sort], $dir);
|
|
||||||
} else {
|
|
||||||
// 既定:公開日時降順 → 主キー降順
|
|
||||||
$q->orderByDesc('open_datetime')
|
|
||||||
->orderByDesc($this->pk);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ページング(現在のクエリを維持)
|
|
||||||
$rows = $q->paginate(20)->appends($request->except('page'));
|
|
||||||
|
|
||||||
return view('admin.news.list', compact('rows'));
|
return view('admin.news.list', compact('rows'));
|
||||||
}
|
}
|
||||||
@ -94,29 +76,21 @@ class NewsController extends Controller
|
|||||||
public function add(Request $request)
|
public function add(Request $request)
|
||||||
{
|
{
|
||||||
if ($request->isMethod('post')) {
|
if ($request->isMethod('post')) {
|
||||||
$messages = [
|
// 入力チェック
|
||||||
'required' => ':attribute は、必ず入力してください。',
|
|
||||||
'open_datetime.date_format' => '公開日時は :format 形式(YYYY-MM-DD HH:MM:SS)で入力してください。',
|
|
||||||
];
|
|
||||||
$attributes = [
|
|
||||||
'news' => 'ニュース内容',
|
|
||||||
'open_datetime' => '公開日時',
|
|
||||||
'mode' => '表示モード',
|
|
||||||
];
|
|
||||||
$v = $request->validate([
|
$v = $request->validate([
|
||||||
'news' => 'required|string',
|
'news' => 'required|string',
|
||||||
'open_datetime' => 'required|date_format:Y-m-d H:i:s',
|
'open_datetime' => 'nullable|date_format:Y-m-d H:i:s',
|
||||||
'link_url' => 'nullable|string|max:255',
|
'link_url' => 'nullable|string|max:255',
|
||||||
'image1_filename' => 'nullable|string|max:255',
|
'image1_filename' => 'nullable|string|max:255',
|
||||||
'image2_filename' => 'nullable|string|max:255',
|
'image2_filename' => 'nullable|string|max:255',
|
||||||
'mode' => 'required|integer|min:0|max:9',
|
'mode' => 'required|integer|min:0|max:9',
|
||||||
], $messages, $attributes);
|
]);
|
||||||
|
|
||||||
// 登録
|
// 登録
|
||||||
$now = now();
|
$now = now();
|
||||||
DB::table($this->table)->insert([
|
DB::table($this->table)->insert([
|
||||||
'news' => $v['news'],
|
'news' => $v['news'],
|
||||||
'open_datetime' => $v['open_datetime'],
|
'open_datetime' => $v['open_datetime'] ?? null,
|
||||||
'link_url' => $v['link_url'] ?? null,
|
'link_url' => $v['link_url'] ?? null,
|
||||||
'image1_filename' => $v['image1_filename'] ?? null,
|
'image1_filename' => $v['image1_filename'] ?? null,
|
||||||
'image2_filename' => $v['image2_filename'] ?? null,
|
'image2_filename' => $v['image2_filename'] ?? null,
|
||||||
@ -144,28 +118,20 @@ class NewsController extends Controller
|
|||||||
if (!$news) { abort(404); }
|
if (!$news) { abort(404); }
|
||||||
|
|
||||||
if ($request->isMethod('post')) {
|
if ($request->isMethod('post')) {
|
||||||
$messages = [
|
// 入力チェック
|
||||||
'required' => ':attribute は、必ず入力してください。',
|
|
||||||
'open_datetime.date_format' => '公開日時は :format 形式(YYYY-MM-DD HH:MM:SS)で入力してください。',
|
|
||||||
];
|
|
||||||
$attributes = [
|
|
||||||
'news' => 'ニュース内容',
|
|
||||||
'open_datetime' => '公開日時',
|
|
||||||
'mode' => '表示モード',
|
|
||||||
];
|
|
||||||
$v = $request->validate([
|
$v = $request->validate([
|
||||||
'news' => 'required|string',
|
'news' => 'required|string',
|
||||||
'open_datetime' => 'required|date_format:Y-m-d H:i:s',
|
'open_datetime' => 'nullable|date_format:Y-m-d H:i:s',
|
||||||
'link_url' => 'nullable|string|max:255',
|
'link_url' => 'nullable|string|max:255',
|
||||||
'image1_filename' => 'nullable|string|max:255',
|
'image1_filename' => 'nullable|string|max:255',
|
||||||
'image2_filename' => 'nullable|string|max:255',
|
'image2_filename' => 'nullable|string|max:255',
|
||||||
'mode' => 'required|integer|min:0|max:9',
|
'mode' => 'required|integer|min:0|max:9',
|
||||||
], $messages, $attributes);
|
]);
|
||||||
|
|
||||||
// 更新
|
// 更新
|
||||||
DB::table($this->table)->where($this->pk, $id)->update([
|
DB::table($this->table)->where($this->pk, $id)->update([
|
||||||
'news' => $v['news'],
|
'news' => $v['news'],
|
||||||
'open_datetime' => $v['open_datetime'],
|
'open_datetime' => $v['open_datetime'] ?? null,
|
||||||
'link_url' => $v['link_url'] ?? null,
|
'link_url' => $v['link_url'] ?? null,
|
||||||
'image1_filename' => $v['image1_filename'] ?? null,
|
'image1_filename' => $v['image1_filename'] ?? null,
|
||||||
'image2_filename' => $v['image2_filename'] ?? null,
|
'image2_filename' => $v['image2_filename'] ?? null,
|
||||||
|
|||||||
@ -1,262 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace App\Http\Controllers\Admin;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use App\Models\Ope;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Facades\Validator;
|
|
||||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
|
||||||
|
|
||||||
class OpeController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 一覧
|
|
||||||
*/
|
|
||||||
public function list(Request $request)
|
|
||||||
{
|
|
||||||
$inputs = [
|
|
||||||
'isMethodPost' => $request->isMethod('post'),
|
|
||||||
'sort' => $request->input('sort', 'ope_id'),
|
|
||||||
'sort_type' => $request->input('sort_type', 'asc'),
|
|
||||||
'isExport' => false,
|
|
||||||
];
|
|
||||||
|
|
||||||
// Blade 側は $list / $sort / $sort_type を参照
|
|
||||||
$list = Ope::search($inputs);
|
|
||||||
$sort = $inputs['sort'];
|
|
||||||
$sort_type = $inputs['sort_type'];
|
|
||||||
|
|
||||||
|
|
||||||
return view('admin.opes.list', compact('list', 'sort', 'sort_type'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 新規登録(GET 画面 / POST 保存)
|
|
||||||
*/
|
|
||||||
public function add(Request $request)
|
|
||||||
{
|
|
||||||
if ($request->isMethod('get')) {
|
|
||||||
|
|
||||||
return view('admin.opes.add', [
|
|
||||||
|
|
||||||
'isEdit' => false,
|
|
||||||
'record' => new Ope(),
|
|
||||||
'ope_id' => null,
|
|
||||||
'ope_name' => '',
|
|
||||||
'ope_type' => '',
|
|
||||||
'ope_mail' => '',
|
|
||||||
'ope_phone'=> '',
|
|
||||||
|
|
||||||
'ope_sendalart_que1' => 0, 'ope_sendalart_que2' => 0, 'ope_sendalart_que3' => 0,
|
|
||||||
'ope_sendalart_que4' => 0, 'ope_sendalart_que5' => 0, 'ope_sendalart_que6' => 0,
|
|
||||||
'ope_sendalart_que7' => 0, 'ope_sendalart_que8' => 0, 'ope_sendalart_que9' => 0,
|
|
||||||
'ope_sendalart_que10'=> 0, 'ope_sendalart_que11'=> 0, 'ope_sendalart_que12'=> 0,
|
|
||||||
'ope_sendalart_que13'=> 0,
|
|
||||||
'ope_auth1' => '', 'ope_auth2' => '', 'ope_auth3' => '', 'ope_auth4' => '',
|
|
||||||
'ope_quit_flag' => 0, 'ope_quitday' => '',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 入力値を一旦取得
|
|
||||||
$data = $request->all();
|
|
||||||
|
|
||||||
// --- バリデーション ---
|
|
||||||
$rules = [
|
|
||||||
'login_id' => 'required|string|max:255|unique:ope,login_id',
|
|
||||||
'ope_name' => 'required|string|max:255',
|
|
||||||
'ope_type' => 'required|string|max:50',
|
|
||||||
'ope_mail' => [
|
|
||||||
'required',
|
|
||||||
function ($attribute, $value, $fail) {
|
|
||||||
// ; でも , でもOK、保存時は ; に統一
|
|
||||||
$emails = array_map('trim', explode(';', str_replace(',', ';', $value)));
|
|
||||||
foreach ($emails as $email) {
|
|
||||||
if ($email !== '' && !filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
|
||||||
$fail("無効なメールアドレス形式です: {$email}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'ope_phone' => 'nullable|string|max:50',
|
|
||||||
'password' => 'required|string|min:8|confirmed',
|
|
||||||
];
|
|
||||||
|
|
||||||
$request->validate($rules);
|
|
||||||
|
|
||||||
// --- 保存用にメールを ; 区切りに統一 ---
|
|
||||||
$emails = array_filter(array_map('trim', explode(';', str_replace(',', ';', $data['ope_mail']))));
|
|
||||||
$data['ope_mail'] = implode(';', $emails);
|
|
||||||
|
|
||||||
// 保存処理
|
|
||||||
$ope = new Ope();
|
|
||||||
$ope->fill($data);
|
|
||||||
$ope->save();
|
|
||||||
|
|
||||||
return redirect()->route('opes')->with('success', '登録しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 編集(GET 画面 / POST 更新)
|
|
||||||
*/
|
|
||||||
public function edit($id, Request $request)
|
|
||||||
{
|
|
||||||
$ope = Ope::getByPk($id);
|
|
||||||
if (!$ope) abort(404);
|
|
||||||
|
|
||||||
if ($request->isMethod('get')) {
|
|
||||||
return view('admin.opes.edit', [
|
|
||||||
'isEdit' => true,
|
|
||||||
'record' => $ope,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 入力値を一旦取得
|
|
||||||
$data = $request->all();
|
|
||||||
|
|
||||||
// --- バリデーション ---
|
|
||||||
$rules = [
|
|
||||||
'login_id' => "required|string|max:255|unique:ope,login_id,{$id},ope_id", // 編集時は自分を除外
|
|
||||||
'ope_name' => 'required|string|max:255',
|
|
||||||
'ope_type' => 'required|string|max:50',
|
|
||||||
'ope_phone' => 'nullable|string|max:50',
|
|
||||||
'ope_mail' => [
|
|
||||||
'required',
|
|
||||||
function ($attribute, $value, $fail) {
|
|
||||||
// , でも ; でもOKにする
|
|
||||||
$emails = array_map('trim', explode(';', str_replace(',', ';', $value)));
|
|
||||||
foreach ($emails as $email) {
|
|
||||||
if ($email !== '' && !filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
|
||||||
$fail("無効なメールアドレス形式です: {$email}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'password' => 'nullable|string|min:8|confirmed', // 編集時は任意
|
|
||||||
];
|
|
||||||
|
|
||||||
$request->validate($rules);
|
|
||||||
|
|
||||||
// --- 保存用にメールを ; 区切りに統一 ---
|
|
||||||
if (!empty($data['ope_mail'])) {
|
|
||||||
$emails = array_filter(array_map('trim', explode(';', str_replace(',', ';', $data['ope_mail']))));
|
|
||||||
$data['ope_mail'] = implode(';', $emails);
|
|
||||||
}
|
|
||||||
|
|
||||||
// パスワード空なら更新しない
|
|
||||||
if (empty($data['password'])) {
|
|
||||||
unset($data['password']);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 保存処理
|
|
||||||
$ope->fill($data);
|
|
||||||
$ope->save();
|
|
||||||
|
|
||||||
return redirect()->route('opes')->with('success', '更新しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 削除(単体 or 複数)
|
|
||||||
*/
|
|
||||||
|
|
||||||
public function delete(Request $request)
|
|
||||||
{
|
|
||||||
$ids = [];
|
|
||||||
|
|
||||||
// 単体削除
|
|
||||||
if ($request->filled('id')) {
|
|
||||||
$ids[] = (int) $request->input('id');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 複数削除
|
|
||||||
if ($request->filled('ids')) {
|
|
||||||
$ids = array_merge($ids, array_map('intval', (array)$request->input('ids')));
|
|
||||||
}
|
|
||||||
|
|
||||||
$ids = array_unique($ids);
|
|
||||||
|
|
||||||
if (!$ids) {
|
|
||||||
return back()->with('error', '削除対象が選択されていません。');
|
|
||||||
}
|
|
||||||
|
|
||||||
Ope::deleteByPk($ids);
|
|
||||||
|
|
||||||
return redirect()->route('opes')->with('success', '削除しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CSVインポート
|
|
||||||
*/
|
|
||||||
public function import(Request $request)
|
|
||||||
{
|
|
||||||
$validator = Validator::make($request->all(), [
|
|
||||||
'file' => 'required|file|mimes:csv,txt|max:20480',
|
|
||||||
]);
|
|
||||||
if ($validator->fails()) {
|
|
||||||
return back()->withErrors($validator)->withInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
$file = $request->file('file')->getRealPath();
|
|
||||||
$handle = fopen($file, 'r');
|
|
||||||
if (!$handle) return back()->with('error', 'CSVを読み取れません。');
|
|
||||||
|
|
||||||
$header = fgetcsv($handle);
|
|
||||||
$header = array_map(fn($h) => trim(ltrim($h ?? '', "\xEF\xBB\xBF")), $header);
|
|
||||||
|
|
||||||
$fillable = (new Ope())->getFillable();
|
|
||||||
$rows = [];
|
|
||||||
|
|
||||||
while (($row = fgetcsv($handle)) !== false) {
|
|
||||||
$assoc = [];
|
|
||||||
foreach ($header as $i => $key) {
|
|
||||||
if (in_array($key, $fillable, true)) {
|
|
||||||
$assoc[$key] = $row[$i] ?? null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($assoc) $rows[] = $assoc;
|
|
||||||
}
|
|
||||||
fclose($handle);
|
|
||||||
|
|
||||||
DB::transaction(function () use ($rows) {
|
|
||||||
foreach ($rows as $data) {
|
|
||||||
Ope::create($data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return redirect()->route('opes')->with('success', count($rows) . '件をインポートしました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CSVエクスポート
|
|
||||||
*/
|
|
||||||
public function export(): StreamedResponse
|
|
||||||
{
|
|
||||||
$filename = 'ope_' . now()->format('Ymd_His') . '.csv';
|
|
||||||
$fillable = (new Ope())->getFillable();
|
|
||||||
|
|
||||||
$response = new StreamedResponse(function () use ($fillable) {
|
|
||||||
$out = fopen('php://output', 'w');
|
|
||||||
fprintf($out, chr(0xEF) . chr(0xBB) . chr(0xBF)); // BOM
|
|
||||||
fputcsv($out, $fillable);
|
|
||||||
|
|
||||||
Ope::orderBy('ope_id')->chunk(500, function ($chunk) use ($out, $fillable) {
|
|
||||||
foreach ($chunk as $row) {
|
|
||||||
$line = [];
|
|
||||||
foreach ($fillable as $f) {
|
|
||||||
$line[] = $row->$f ?? '';
|
|
||||||
}
|
|
||||||
fputcsv($out, $line);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
fclose($out);
|
|
||||||
});
|
|
||||||
|
|
||||||
$response->headers->set('Content-Type', 'text/csv; charset=UTF-8');
|
|
||||||
$response->headers->set('Content-Disposition', "attachment; filename={$filename}");
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,296 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Facades\Validator;
|
|
||||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
|
||||||
|
|
||||||
// モデル
|
|
||||||
use App\Models\OperatorQue; // operator_que テーブル
|
|
||||||
use App\Models\User; // 利用者候補(user_seq / user_name / user_mobile / user_homephone)
|
|
||||||
use App\Models\Park; // 駐輪場候補(park_id / park_name)
|
|
||||||
|
|
||||||
class OperatorQueController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 一覧
|
|
||||||
* ルート: operator_ques
|
|
||||||
*/
|
|
||||||
public function list(Request $request)
|
|
||||||
{
|
|
||||||
$sort = $request->input('sort', 'que_id');
|
|
||||||
$sort_type = $request->input('sort_type', 'asc');
|
|
||||||
$que_status = $request->input('que_status');
|
|
||||||
|
|
||||||
// 許可されたカラム名のリスト(DB定義に合わせて)
|
|
||||||
$allowedSorts = ['que_id', 'ope_id', 'que_status', 'created_at', 'updated_at', 'user_id', 'park_id', 'que_class'];
|
|
||||||
|
|
||||||
if (!in_array($sort, $allowedSorts)) {
|
|
||||||
$sort = 'que_id';
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!in_array($sort_type, ['asc', 'desc'])) {
|
|
||||||
$sort_type = 'desc';
|
|
||||||
}
|
|
||||||
|
|
||||||
$query = OperatorQue::query();
|
|
||||||
|
|
||||||
// フィルタリング(絞り込み)
|
|
||||||
if (!empty($que_status)) {
|
|
||||||
$query->where('que_status', $que_status);
|
|
||||||
}
|
|
||||||
|
|
||||||
$list = $query->orderBy($sort, $sort_type)
|
|
||||||
->paginate(\App\Utils::item_per_page ?? 20);
|
|
||||||
|
|
||||||
// view に $que_status を渡す
|
|
||||||
return view('admin.operator_ques.list', compact('list', 'sort', 'sort_type', 'que_status'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 新規登録(画面/処理)
|
|
||||||
*/
|
|
||||||
public function add(Request $request)
|
|
||||||
{
|
|
||||||
if ($request->isMethod('get')) {
|
|
||||||
// 新規時は空のレコードを用意してフォーム描画
|
|
||||||
return view('admin.operator_ques.add', array_merge(
|
|
||||||
$this->formPayload(),
|
|
||||||
[
|
|
||||||
'isEdit' => false,
|
|
||||||
'record' => new OperatorQue(), // ← ★ _form.blade.php で使う用
|
|
||||||
'que_id' => null,
|
|
||||||
]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
// POST時:バリデーション
|
|
||||||
$data = $this->validateRequest($request);
|
|
||||||
|
|
||||||
// 登録処理
|
|
||||||
OperatorQue::create($data);
|
|
||||||
|
|
||||||
return redirect()->route('operator_ques')->with('success', '登録しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 編集(画面/処理)
|
|
||||||
*/
|
|
||||||
public function edit($id, Request $request)
|
|
||||||
{
|
|
||||||
$que = OperatorQue::findOrFail($id);
|
|
||||||
|
|
||||||
if ($request->isMethod('get')) {
|
|
||||||
return view('admin.operator_ques.edit', array_merge(
|
|
||||||
$this->formPayload($que),
|
|
||||||
[
|
|
||||||
'que_id' => $que->que_id,
|
|
||||||
'record' => $que,
|
|
||||||
]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = $this->validateRequest($request, $que->que_id);
|
|
||||||
|
|
||||||
$que->fill($data)->save();
|
|
||||||
|
|
||||||
return redirect()->route('operator_ques')->with('success', '更新しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 詳細(参照)
|
|
||||||
*/
|
|
||||||
public function info($id)
|
|
||||||
{
|
|
||||||
$que = OperatorQue::findOrFail($id);
|
|
||||||
|
|
||||||
return view('admin.operator_ques.info', array_merge(
|
|
||||||
$this->formPayload($que),
|
|
||||||
['que_id' => $que->que_id]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 削除(複数可)
|
|
||||||
*/
|
|
||||||
public function delete(Request $request)
|
|
||||||
{
|
|
||||||
$ids = [];
|
|
||||||
if ($request->filled('id')) {
|
|
||||||
$ids[] = (int) $request->input('id');
|
|
||||||
}
|
|
||||||
if (is_array($request->input('pk'))) {
|
|
||||||
$ids = array_merge($ids, $request->input('pk'));
|
|
||||||
}
|
|
||||||
$ids = array_values(array_unique(array_map('intval', $ids)));
|
|
||||||
|
|
||||||
if (!$ids) {
|
|
||||||
return back()->with('error', '削除対象が選択されていません。');
|
|
||||||
}
|
|
||||||
|
|
||||||
OperatorQue::whereIn('que_id', $ids)->delete();
|
|
||||||
|
|
||||||
return redirect()->route('operator_ques')->with('success', '削除しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CSV インポート
|
|
||||||
*/
|
|
||||||
public function import(Request $request)
|
|
||||||
{
|
|
||||||
$validator = Validator::make($request->all(), [
|
|
||||||
'file' => 'required|file|mimes:csv,txt|max:20480',
|
|
||||||
]);
|
|
||||||
if ($validator->fails()) {
|
|
||||||
return back()->withErrors($validator)->withInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
$file = $request->file('file')->getRealPath();
|
|
||||||
if (!$handle = fopen($file, 'r')) {
|
|
||||||
return back()->with('error', 'CSVを読み取れません。');
|
|
||||||
}
|
|
||||||
|
|
||||||
$header = fgetcsv($handle) ?: [];
|
|
||||||
$header = array_map(fn($h) => trim(ltrim($h ?? '', "\xEF\xBB\xBF")), $header);
|
|
||||||
|
|
||||||
$fillable = (new OperatorQue())->getFillable();
|
|
||||||
$rows = [];
|
|
||||||
|
|
||||||
while (($row = fgetcsv($handle)) !== false) {
|
|
||||||
$assoc = [];
|
|
||||||
foreach ($header as $i => $key) {
|
|
||||||
if (in_array($key, $fillable, true)) {
|
|
||||||
$assoc[$key] = $row[$i] ?? null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($assoc) {
|
|
||||||
$rows[] = $assoc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fclose($handle);
|
|
||||||
|
|
||||||
DB::transaction(function () use ($rows) {
|
|
||||||
foreach ($rows as $data) {
|
|
||||||
OperatorQue::create($data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return redirect()->route('operator_ques')->with('success', count($rows) . '件をインポートしました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CSV エクスポート
|
|
||||||
*/
|
|
||||||
public function export(): StreamedResponse
|
|
||||||
{
|
|
||||||
$filename = 'operator_que_' . now()->format('Ymd_His') . '.csv';
|
|
||||||
$fillable = (new OperatorQue())->getFillable(); // 見出しは fillable を流用
|
|
||||||
|
|
||||||
$response = new StreamedResponse(function () use ($fillable) {
|
|
||||||
$out = fopen('php://output', 'w');
|
|
||||||
// UTF-8 BOM
|
|
||||||
fprintf($out, chr(0xEF) . chr(0xBB) . chr(0xBF));
|
|
||||||
|
|
||||||
fputcsv($out, $fillable);
|
|
||||||
|
|
||||||
OperatorQue::orderBy('que_id')->chunk(500, function ($chunk) use ($out, $fillable) {
|
|
||||||
foreach ($chunk as $row) {
|
|
||||||
$line = [];
|
|
||||||
foreach ($fillable as $f) {
|
|
||||||
$line[] = $row->$f ?? '';
|
|
||||||
}
|
|
||||||
fputcsv($out, $line);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
fclose($out);
|
|
||||||
});
|
|
||||||
|
|
||||||
$response->headers->set('Content-Type', 'text/csv; charset=UTF-8');
|
|
||||||
$response->headers->set('Content-Disposition', "attachment; filename={$filename}");
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* フォームに渡す値/候補
|
|
||||||
*/
|
|
||||||
private function formPayload(?OperatorQue $que = null): array
|
|
||||||
{
|
|
||||||
// 値
|
|
||||||
$payload = [
|
|
||||||
'que_id' => $que->que_id ?? '',
|
|
||||||
'user_id' => $que->user_id ?? '',
|
|
||||||
'contract_id' => $que->contract_id ?? '',
|
|
||||||
'park_id' => $que->park_id ?? '',
|
|
||||||
'que_class' => $que->que_class ?? '',
|
|
||||||
'que_comment' => $que->que_comment ?? '',
|
|
||||||
'que_status' => $que->que_status ?? '',
|
|
||||||
'que_status_comment' => $que->que_status_comment?? '',
|
|
||||||
'work_instructions' => $que->work_instructions ?? '',
|
|
||||||
];
|
|
||||||
|
|
||||||
// 候補
|
|
||||||
$payload['users'] = $this->fetchUsers();
|
|
||||||
$payload['parks'] = $this->fetchParks();
|
|
||||||
|
|
||||||
return $payload;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* バリデーション
|
|
||||||
* ※ 実テーブルの型に合わせて必要に応じて調整
|
|
||||||
*/
|
|
||||||
private function validateRequest(Request $request, $queId = null): array
|
|
||||||
{
|
|
||||||
$rules = [
|
|
||||||
'user_id' => 'nullable|integer',
|
|
||||||
'contract_id' => 'nullable|integer',
|
|
||||||
'park_id' => 'nullable|integer',
|
|
||||||
'que_class' => 'required|integer',
|
|
||||||
'que_comment' => 'nullable|string|max:2000',
|
|
||||||
'que_status' => 'required|integer',
|
|
||||||
'que_status_comment' => 'nullable|string|max:2000',
|
|
||||||
'work_instructions' => 'nullable|string|max:2000',
|
|
||||||
// 'operator_id' => 'nullable|integer', // ログインユーザIDを使うなら不要
|
|
||||||
];
|
|
||||||
|
|
||||||
return $request->validate($rules);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 利用者候補(user_seq, user_name, user_mobile, user_homephone)
|
|
||||||
* Blade 側では $users をそのまま @foreach
|
|
||||||
*/
|
|
||||||
private function fetchUsers()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
return User::select('user_seq', 'user_name', 'user_mobile', 'user_homephone')
|
|
||||||
->orderBy('user_name')
|
|
||||||
->get();
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
return DB::table('users')
|
|
||||||
->select(['user_seq', 'user_name', 'user_mobile', 'user_homephone'])
|
|
||||||
->orderBy('user_name')
|
|
||||||
->get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 駐輪場候補(park_id => park_name)
|
|
||||||
*/
|
|
||||||
private function fetchParks()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
return Park::orderBy('park_name')->pluck('park_name', 'park_id');
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
return DB::table('parks')->orderBy('park_name')->pluck('park_name', 'park_id');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -11,17 +11,25 @@ use Illuminate\Http\Request;
|
|||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use Response;
|
use Response;
|
||||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
|
||||||
|
|
||||||
class ParkController extends Controller
|
class ParkController extends Controller
|
||||||
{
|
{
|
||||||
public function list(Request $request)
|
public function list(Request $request)
|
||||||
{
|
{
|
||||||
$query = \DB::table('park as p')
|
$query = \DB::table('park as p')
|
||||||
->leftJoin('city as c', 'p.city_id', '=', 'c.city_id')
|
->leftJoin('city as c', 'p.city_id', '=', 'c.city_id')
|
||||||
->select([
|
->select([
|
||||||
'p.*',
|
'p.park_id',
|
||||||
'c.city_name',
|
'c.city_name',
|
||||||
|
'p.park_name',
|
||||||
|
'p.park_ruby',
|
||||||
|
'p.park_syllabary',
|
||||||
|
'p.park_adrs',
|
||||||
|
'p.park_close_flag',
|
||||||
|
'p.park_day',
|
||||||
|
'p.alert_flag',
|
||||||
|
'p.print_number',
|
||||||
|
'p.keep_alive',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($request->filled('park_name')) {
|
if ($request->filled('park_name')) {
|
||||||
@ -42,7 +50,7 @@ public function list(Request $request)
|
|||||||
$sort = $request->input('sort', 'p.park_id');
|
$sort = $request->input('sort', 'p.park_id');
|
||||||
$sort_type = $request->input('sort_type', 'asc');
|
$sort_type = $request->input('sort_type', 'asc');
|
||||||
return view('admin.parks.list', compact('parks', 'cities', 'sort', 'sort_type'));
|
return view('admin.parks.list', compact('parks', 'cities', 'sort', 'sort_type'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function add(Request $request)
|
public function add(Request $request)
|
||||||
{
|
{
|
||||||
@ -59,10 +67,9 @@ public function list(Request $request)
|
|||||||
// 保存処理
|
// 保存処理
|
||||||
$park = new \App\Models\Park();
|
$park = new \App\Models\Park();
|
||||||
$park->fill($validated);
|
$park->fill($validated);
|
||||||
$park->operator_id = auth()->user()->ope_id ?? 1;
|
|
||||||
$park->save();
|
$park->save();
|
||||||
|
|
||||||
return redirect()->route('parks')->with('success', '新規登録に完了しました。');
|
return redirect()->route('parks')->with('success', '登録しました');
|
||||||
}
|
}
|
||||||
|
|
||||||
return view('admin.parks.add', [
|
return view('admin.parks.add', [
|
||||||
@ -129,81 +136,83 @@ public function list(Request $request)
|
|||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function export(Request $request)
|
||||||
|
{
|
||||||
|
|
||||||
|
$headers = array(
|
||||||
|
"Content-type" => "text/csv;charset=UTF-8",
|
||||||
|
'Content-Encoding: UTF-8',
|
||||||
|
"Content-Disposition" => "attachment; filename=file.csv",
|
||||||
|
"Pragma" => "no-cache",
|
||||||
|
"Cache-Control" => "must-revalidate, post-check=0, pre-check=0",
|
||||||
|
"Expires" => "0"
|
||||||
|
);
|
||||||
|
$inputs = [
|
||||||
|
'isMethodPost' => 0,
|
||||||
|
'isExport' => 1,
|
||||||
|
'sort' => $request->input('sort', ''),
|
||||||
|
'sort_type' => $request->input('sort_type', ''),
|
||||||
|
|
||||||
public function export(Request $request)
|
|
||||||
{
|
|
||||||
$columns = [
|
|
||||||
'駐輪場ID', '市区', '駐輪場名', '駐輪場ふりがな', '駐輪場五十音', '住所',
|
|
||||||
'閉設フラグ', '閉設日', '残警告チェックフラグ', '印字数', '最新キープアライブ',
|
|
||||||
'更新オペレータID', '更新期間開始日', '更新期間開始時', '更新期間終了日', '更新期間終了時',
|
|
||||||
'駐輪開始期間', 'リマインダー種別', 'リマインダー時間', '契約後即利用許可',
|
|
||||||
'項目表示設定:性別', '項目表示設定:生年月日', '項目表示設定:防犯登録番号',
|
|
||||||
'二点間距離', '駐車場座標(緯度)', '駐車場座標(経度)', '電話番号',
|
|
||||||
'駐輪場契約形態(定期)', '駐輪場契約形態(一時利用)', '車種制限', '手続方法', '支払方法',
|
|
||||||
'利用可能時間制限フラグ', '利用可能時間(開始)', '利用可能時間(終了)',
|
|
||||||
'常駐管理人フラグ', '常駐時間(開始)', '常駐時間(終了)',
|
|
||||||
'屋根フラグ', 'シール発行機フラグ', '駐輪場利用方法', '定期更新期間',
|
|
||||||
'空き待ち予約', '特記事項', '学生証確認種別',
|
|
||||||
'減免案内表示フラグ', '減免対象年齢', '減免案内表示開始月数', '年跨ぎ'
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$dataExport = DB::table('park as p')
|
$dataExport = \DB::table('park as p')
|
||||||
|
->leftJoin('city as c', 'p.city_id', '=', 'c.city_id')
|
||||||
->select([
|
->select([
|
||||||
'p.park_id', 'p.city_id', 'p.park_name', 'p.park_ruby', 'p.park_syllabary', 'p.park_adrs',
|
'p.park_id',
|
||||||
'p.park_close_flag', 'p.park_day', 'p.alert_flag', 'p.print_number', 'p.keep_alive',
|
'c.city_name',
|
||||||
'p.operator_id', 'p.update_grace_period_start_date', 'p.update_grace_period_start_time',
|
'p.park_name',
|
||||||
'p.update_grace_period_end_date', 'p.update_grace_period_end_time',
|
'p.park_ruby',
|
||||||
'p.parking_start_grace_period', 'p.reminder_type', 'p.reminder_time', 'p.immediate_use_permit',
|
'p.park_syllabary',
|
||||||
'p.gender_display_flag', 'p.bd_display_flag', 'p.securityreg_display_flag',
|
'p.park_adrs',
|
||||||
'p.distance_twopoints', 'p.park_latitude', 'p.park_longitude', 'p.park_tel',
|
'p.park_close_flag',
|
||||||
'p.park_fixed_contract', 'p.park_temporary_contract', 'p.park_restriction',
|
'p.park_day',
|
||||||
'p.park_procedure', 'p.park_payment',
|
'p.alert_flag',
|
||||||
'p.park_available_time_flag', 'p.park_available_time_from', 'p.park_available_time_to',
|
'p.print_number',
|
||||||
'p.park_manager_flag', 'p.park_manager_resident_from', 'p.park_manager_resident_to',
|
'p.keep_alive',
|
||||||
'p.park_roof_flag', 'p.park_issuing_machine_flag', 'p.park_using_method',
|
|
||||||
'p.park_contract_renewal_term', 'p.park_reservation', 'p.park_reference',
|
|
||||||
'p.student_id_confirm_type', 'p.reduction_guide_display_flag', 'p.reduction_age',
|
|
||||||
'p.reduction_guide_display_start_month', 'p.overyear_flag'
|
|
||||||
])
|
])
|
||||||
->orderBy('p.park_id', 'asc')
|
->orderBy('p.park_id', 'asc')
|
||||||
->get();
|
->get();
|
||||||
|
$columns = array(
|
||||||
$response = new StreamedResponse(function () use ($dataExport, $columns) {
|
__('駐輪場ID '),// 0
|
||||||
$stream = fopen('php://output', 'w');
|
__('市区ID'),// 1
|
||||||
// Excel兼容 BOM
|
__('市区'),// 2
|
||||||
fwrite($stream, chr(0xEF) . chr(0xBB) . chr(0xBF));
|
__('駐輪場名'),// 3
|
||||||
fputcsv($stream, $columns);
|
__('駐輪場ふりがな'),// 4
|
||||||
|
__('駐輪場五十音'),// 5
|
||||||
foreach ($dataExport as $item) {
|
__('住所'),// 6
|
||||||
fputcsv($stream, [
|
__('閉設フラグ'),// 7
|
||||||
$item->park_id, $item->city_id, $item->park_name, $item->park_ruby, $item->park_syllabary, $item->park_adrs,
|
__('閉設フラグ'),// 8
|
||||||
$item->park_close_flag, $item->park_day, $item->alert_flag, $item->print_number, $item->keep_alive,
|
__('閉設日'),// 9
|
||||||
$item->operator_id, $item->update_grace_period_start_date, $item->update_grace_period_start_time,
|
__('残警告チェックフラグ'),// 10
|
||||||
$item->update_grace_period_end_date, $item->update_grace_period_end_time,
|
__('印字数'),// 11
|
||||||
$item->parking_start_grace_period, $item->reminder_type, $item->reminder_time, $item->immediate_use_permit,
|
__('最新キープアライブ')// 12
|
||||||
$item->gender_display_flag, $item->bd_display_flag, $item->securityreg_display_flag,
|
);
|
||||||
$item->distance_twopoints, $item->park_latitude, $item->park_longitude, $item->park_tel,
|
$filename = "駐輪場マスタ.csv";
|
||||||
$item->park_fixed_contract, $item->park_temporary_contract, $item->park_restriction,
|
$file = fopen($filename, 'w+');
|
||||||
$item->park_procedure, $item->park_payment,
|
fputcsv($file, $columns);
|
||||||
$item->park_available_time_flag, $item->park_available_time_from, $item->park_available_time_to,
|
foreach ($dataExport as $items) {
|
||||||
$item->park_manager_flag, $item->park_manager_resident_from, $item->park_manager_resident_to,
|
fputcsv(
|
||||||
$item->park_roof_flag, $item->park_issuing_machine_flag, $item->park_using_method,
|
$file,
|
||||||
$item->park_contract_renewal_term, $item->park_reservation, $item->park_reference,
|
array(
|
||||||
$item->student_id_confirm_type, $item->reduction_guide_display_flag, $item->reduction_age,
|
$items->park_id,// 0
|
||||||
$item->reduction_guide_display_start_month, $item->overyear_flag
|
null, // city_id(selectで取得していないので空欄)
|
||||||
]);
|
$items->city_name ?? '',// 2
|
||||||
|
$items->park_name, // 3
|
||||||
|
$items->park_ruby, // 4
|
||||||
|
$items->park_syllabary, // 5
|
||||||
|
$items->park_adrs, // 6
|
||||||
|
$items->park_close_flag,// 7
|
||||||
|
($items->park_close_flag == 1 ? '閉設' : '開設'),// 8
|
||||||
|
$items->park_day,// 9
|
||||||
|
$items->alert_flag,// 10
|
||||||
|
$items->print_number,// 11
|
||||||
|
$items->keep_alive// 12
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
fclose($file);
|
||||||
|
return Response::download($filename, $filename, $headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose($stream);
|
|
||||||
});
|
|
||||||
|
|
||||||
$response->headers->set('Content-Type', 'text/csv; charset=UTF-8');
|
|
||||||
$response->headers->set('Content-Disposition', 'attachment; filename="駐輪場マスタ.csv"');
|
|
||||||
$response->headers->set('Cache-Control', 'no-store, no-cache');
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function import(Request $request)
|
public function import(Request $request)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,147 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use App\Models\Payment;
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
|
|
||||||
class PaymentController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 決済情報マスタ一覧表示
|
|
||||||
*/
|
|
||||||
public function list(Request $request)
|
|
||||||
{
|
|
||||||
$sort = $request->input('sort', 'payment_id');
|
|
||||||
$sort_type = $request->input('sort_type', 'asc');
|
|
||||||
|
|
||||||
$query = Payment::query();
|
|
||||||
|
|
||||||
$query->orderBy($sort, $sort_type);
|
|
||||||
|
|
||||||
$payments = $query->paginate(20);
|
|
||||||
|
|
||||||
return view('admin.payments.list', compact('payments', 'sort', 'sort_type'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 新規登録画面表示&登録処理
|
|
||||||
*/
|
|
||||||
public function add(Request $request)
|
|
||||||
{
|
|
||||||
if ($request->isMethod('post')) {
|
|
||||||
// バリデーション
|
|
||||||
$request->validate([
|
|
||||||
'payment_companyname' => 'required|string|max:255',
|
|
||||||
'payment_add' => 'nullable|string|max:255',
|
|
||||||
'payment_detail' => 'nullable|string|max:255',
|
|
||||||
'payment_space1' => 'nullable|string|max:255',
|
|
||||||
'payment_space2' => 'nullable|string|max:255',
|
|
||||||
'payment_title' => 'nullable|string|max:255',
|
|
||||||
'payment_guide' => 'nullable|string|max:255',
|
|
||||||
'payment_inquiryname' => 'nullable|string|max:255',
|
|
||||||
'payment_inquirytel' => 'nullable|string|max:255',
|
|
||||||
'payment_time' => 'nullable|string|max:255',
|
|
||||||
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 登録データ作成
|
|
||||||
$data = $request->all();
|
|
||||||
$data['operator_id'] = Auth::user()->ope_id;
|
|
||||||
|
|
||||||
Payment::create($data);
|
|
||||||
|
|
||||||
return redirect()->route('payments')->with('success', '登録しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
return view('admin.payments.add', [
|
|
||||||
'record' => null,
|
|
||||||
'mode' => 'add'
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 編集画面表示&更新処理
|
|
||||||
*/
|
|
||||||
public function edit(Request $request, $payment_id)
|
|
||||||
{
|
|
||||||
$payment = Payment::findOrFail($payment_id);
|
|
||||||
|
|
||||||
if ($request->isMethod('post')) {
|
|
||||||
// バリデーション
|
|
||||||
$request->validate([
|
|
||||||
'payment_companyname' => 'required|string|max:255',
|
|
||||||
// 其他字段...
|
|
||||||
]);
|
|
||||||
|
|
||||||
$data = $request->all();
|
|
||||||
$data['operator_id'] = Auth::user()->ope_id;
|
|
||||||
|
|
||||||
$payment->update($data);
|
|
||||||
|
|
||||||
return redirect()->route('payments')->with('success', '更新しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
return view('admin.payments.edit', [
|
|
||||||
'payment' => $payment,
|
|
||||||
'isEdit' => true,
|
|
||||||
'isInfo' => false
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 詳細画面表示
|
|
||||||
*/
|
|
||||||
public function info($payment_id)
|
|
||||||
{
|
|
||||||
$payment = Payment::findOrFail($payment_id);
|
|
||||||
|
|
||||||
return view('admin.payments.info', [
|
|
||||||
'record' => $payment,
|
|
||||||
'mode' => 'info'
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 削除処理
|
|
||||||
*/
|
|
||||||
public function delete(Request $request)
|
|
||||||
{
|
|
||||||
$pk = $request->input('pk', []);
|
|
||||||
|
|
||||||
// 配列に統一
|
|
||||||
$ids = is_array($pk) ? $pk : [$pk];
|
|
||||||
|
|
||||||
// 数字チェック
|
|
||||||
$ids = array_values(array_filter($ids, fn($v) => preg_match('/^\d+$/', (string) $v)));
|
|
||||||
|
|
||||||
if (empty($ids)) {
|
|
||||||
return redirect()->route('payments')->with('error', '削除対象が選択されていません。');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 削除
|
|
||||||
Payment::whereIn('payment_id', $ids)->delete();
|
|
||||||
|
|
||||||
return redirect()->route('payments')->with('success', '削除しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* インポート処理
|
|
||||||
*/
|
|
||||||
public function import(Request $request)
|
|
||||||
{
|
|
||||||
// TODO: CSVなどのインポート処理を実装
|
|
||||||
return redirect()->route('payments')->with('success', 'インポート処理は未実装です');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* エクスポート処理
|
|
||||||
*/
|
|
||||||
public function export()
|
|
||||||
{
|
|
||||||
// TODO: エクスポート処理を実装
|
|
||||||
return redirect()->route('payments')->with('success', 'エクスポート処理は未実装です');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -10,13 +10,13 @@ class PeriodicalController extends Controller
|
|||||||
// 画面
|
// 画面
|
||||||
public function list(Request $request)
|
public function list(Request $request)
|
||||||
{
|
{
|
||||||
$parks = DB::table('regular_contract')
|
// Bladeで使うカラム名(id, name)で取得
|
||||||
->join('park', 'regular_contract.park_id', '=', 'park.park_id')
|
$parks = DB::table('park')
|
||||||
->select('park.park_id', 'park.park_name')
|
->select('park_id', 'park_name')
|
||||||
->distinct()
|
->orderBy('park_name')
|
||||||
->orderBy('park.park_name')
|
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
|
// 必要なら選択中のpark_idも渡す
|
||||||
$selectedParkId = $request->input('park_id', '');
|
$selectedParkId = $request->input('park_id', '');
|
||||||
|
|
||||||
return view('admin.periodical.list', compact('parks', 'selectedParkId'));
|
return view('admin.periodical.list', compact('parks', 'selectedParkId'));
|
||||||
@ -27,365 +27,73 @@ class PeriodicalController extends Controller
|
|||||||
{
|
{
|
||||||
$parkId = $request->input('park_id');
|
$parkId = $request->input('park_id');
|
||||||
|
|
||||||
if (empty($parkId)) {
|
// 契約状況
|
||||||
return response()->json([
|
$bicycleGeneral = DB::table('regular_contract')
|
||||||
'contract_summary' => [],
|
->where('park_id', $parkId)
|
||||||
'waiting_summary' => [],
|
->where('user_categoryid', 1)
|
||||||
'renewal_summary' => [],
|
->where('ptype_id', 1) // 1:自転車
|
||||||
'debug_info' => ['message' => 'No park_id provided']
|
->where('contract_cancel_flag', 0)
|
||||||
]);
|
->count();
|
||||||
}
|
$bicycleStudent = DB::table('regular_contract')
|
||||||
|
->where('park_id', $parkId)
|
||||||
|
->where('user_categoryid', 2)
|
||||||
|
->where('ptype_id', 1)
|
||||||
|
->where('contract_cancel_flag', 0)
|
||||||
|
->count();
|
||||||
|
// 原付・その他も同様に集計
|
||||||
|
|
||||||
// デバッグ情報を収集
|
$contractSummary = [
|
||||||
$debugInfo = [
|
[
|
||||||
'park_id' => $parkId,
|
'type' => '自転車',
|
||||||
'has_regular_type_id' => false,
|
'general_count' => $bicycleGeneral,
|
||||||
'contract_count' => 0,
|
|
||||||
'waiting_count' => 0,
|
|
||||||
'renewal_count' => 0
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 契約状況を車種別に集計
|
|
||||||
$contractData = [
|
|
||||||
['psection_id' => 1, 'type' => '自転車'],
|
|
||||||
['psection_id' => 2, 'type' => '原付'],
|
|
||||||
['psection_id' => 0, 'type' => 'その他'] // その他は psection_id が1,2以外
|
|
||||||
];
|
|
||||||
|
|
||||||
$contractSummary = [];
|
|
||||||
$totalGeneral = 0;
|
|
||||||
$totalStudent = 0;
|
|
||||||
$totalUseTotal = 0;
|
|
||||||
$totalVacancy = 0;
|
|
||||||
$totalAll = 0;
|
|
||||||
|
|
||||||
foreach ($contractData as $vehicleType) {
|
|
||||||
$query = DB::table('regular_contract as rc')
|
|
||||||
->leftJoin('psection as ps', 'rc.psection_id', '=', 'ps.psection_id')
|
|
||||||
->selectRaw('SUM(CASE WHEN rc.user_categoryid = 1 THEN 1 ELSE 0 END) AS general_count')
|
|
||||||
->selectRaw('SUM(CASE WHEN rc.user_categoryid = 2 THEN 1 ELSE 0 END) AS student_count')
|
|
||||||
->selectRaw('SUM(CASE WHEN rc.contract_cancel_flag = 0 THEN 1 ELSE 0 END) AS use_total')
|
|
||||||
->selectRaw('SUM(CASE WHEN rc.contract_cancel_flag = 1 THEN 1 ELSE 0 END) AS vacancy')
|
|
||||||
->selectRaw('COUNT(*) AS total')
|
|
||||||
->where('rc.park_id', $parkId);
|
|
||||||
|
|
||||||
if ($vehicleType['psection_id'] === 0) {
|
|
||||||
// その他:psection_id が 1,2 以外
|
|
||||||
$query->whereNotIn('rc.psection_id', [1, 2]);
|
|
||||||
} else {
|
|
||||||
// 自転車または原付
|
|
||||||
$query->where('rc.psection_id', $vehicleType['psection_id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$result = $query->first();
|
|
||||||
|
|
||||||
$generalCount = (int) ($result->general_count ?? 0);
|
|
||||||
$studentCount = (int) ($result->student_count ?? 0);
|
|
||||||
$useTotal = (int) ($result->use_total ?? 0);
|
|
||||||
$vacancy = (int) ($result->vacancy ?? 0);
|
|
||||||
$total = (int) ($result->total ?? 0);
|
|
||||||
|
|
||||||
// 最古の予約日と契約日を取得
|
|
||||||
$minReserveQuery = DB::table('regular_contract as rc2')
|
|
||||||
->join('reserve as r2', 'rc2.contract_id', '=', 'r2.contract_id')
|
|
||||||
->where('rc2.park_id', $parkId)
|
|
||||||
->where('r2.valid_flag', 1)
|
|
||||||
->where(function ($q) {
|
|
||||||
$q->whereNull('r2.reserve_cancel_flag')->orWhere('r2.reserve_cancel_flag', 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
if ($vehicleType['psection_id'] === 0) {
|
|
||||||
$minReserveQuery->whereNotIn('rc2.psection_id', [1, 2]);
|
|
||||||
} else {
|
|
||||||
$minReserveQuery->where('rc2.psection_id', $vehicleType['psection_id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$minReserveDate = null;
|
|
||||||
$minContractDate = null;
|
|
||||||
|
|
||||||
$reserveResult = $minReserveQuery->orderBy('r2.reserve_date', 'asc')->first(['r2.reserve_date']);
|
|
||||||
if ($reserveResult) {
|
|
||||||
$minReserveDate = date('Y/m/d', strtotime($reserveResult->reserve_date));
|
|
||||||
}
|
|
||||||
|
|
||||||
$contractResult = $minReserveQuery->orderBy('r2.reserve_end', 'asc')->first(['r2.reserve_end']);
|
|
||||||
if ($contractResult) {
|
|
||||||
$minContractDate = date('Y/m/d', strtotime($contractResult->reserve_end));
|
|
||||||
}
|
|
||||||
|
|
||||||
$contractSummary[] = [
|
|
||||||
'type' => $vehicleType['type'],
|
|
||||||
'general_count' => $generalCount,
|
|
||||||
'general_extra' => '',
|
'general_extra' => '',
|
||||||
'student_count' => $studentCount,
|
'student_count' => $bicycleStudent,
|
||||||
'student_extra' => '',
|
'student_extra' => '',
|
||||||
'use_total' => $useTotal,
|
'use_total' => $bicycleGeneral + $bicycleStudent,
|
||||||
'vacancy' => $vacancy,
|
'vacancy' => 8, // 例: 空き数
|
||||||
'total' => $total,
|
'total' => $bicycleGeneral + $bicycleStudent + 8,
|
||||||
'last' => ['reserve_date' => $minReserveDate, 'contract_date' => $minContractDate],
|
'last' => [
|
||||||
|
'reserve_date' => '2025/07/27',
|
||||||
|
'contract_date' => '',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
// 原付・その他も同様に
|
||||||
];
|
];
|
||||||
|
|
||||||
$totalGeneral += $generalCount;
|
// 空き待ち状況
|
||||||
$totalStudent += $studentCount;
|
$waitingSummary = [
|
||||||
$totalUseTotal += $useTotal;
|
[
|
||||||
$totalVacancy += $vacancy;
|
'type' => '自転車',
|
||||||
$totalAll += $total;
|
'general_count' => 28,
|
||||||
}
|
'general_head' => '2023/03/08',
|
||||||
|
'student_count' => 6,
|
||||||
// 合計行を追加
|
'student_head' => '2023/11/04',
|
||||||
$contractSummary[] = [
|
'total' => 34,
|
||||||
'type' => '計',
|
],
|
||||||
'general_count' => $totalGeneral,
|
// 原付・その他も同様に
|
||||||
'general_extra' => '',
|
|
||||||
'student_count' => $totalStudent,
|
|
||||||
'student_extra' => '',
|
|
||||||
'use_total' => $totalUseTotal,
|
|
||||||
'vacancy' => $totalVacancy,
|
|
||||||
'total' => $totalAll,
|
|
||||||
'last' => ['reserve_date' => null, 'contract_date' => null],
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$debugInfo['contract_count'] = count($contractSummary);
|
// 更新状況
|
||||||
|
$renewalSummary = [];
|
||||||
// 空き待ち状況を車種別に集計
|
for ($m = 1; $m <= 12; $m++) {
|
||||||
$waitingData = [
|
$renewalSummary[] = [
|
||||||
['psection_id' => 1, 'type' => '自転車'],
|
'month' => sprintf('%02d月', $m),
|
||||||
['psection_id' => 2, 'type' => '原付'],
|
|
||||||
['psection_id' => 0, 'type' => 'その他'] // その他は psection_id が1,2以外
|
|
||||||
];
|
|
||||||
|
|
||||||
$waitingSummary = [];
|
|
||||||
$totalGeneral = 0;
|
|
||||||
$totalStudent = 0;
|
|
||||||
$totalAll = 0;
|
|
||||||
|
|
||||||
foreach ($waitingData as $vehicleType) {
|
|
||||||
$query = DB::table('regular_contract as rc')
|
|
||||||
->join('reserve as r', 'rc.contract_id', '=', 'r.contract_id')
|
|
||||||
->selectRaw('SUM(CASE WHEN rc.user_categoryid = 1 THEN 1 ELSE 0 END) AS general_count')
|
|
||||||
->selectRaw('DATE_FORMAT(MIN(CASE WHEN rc.user_categoryid = 1 THEN r.reserve_date END), "%Y/%m/%d") AS general_first')
|
|
||||||
->selectRaw('SUM(CASE WHEN rc.user_categoryid = 2 THEN 1 ELSE 0 END) AS student_count')
|
|
||||||
->selectRaw('DATE_FORMAT(MIN(CASE WHEN rc.user_categoryid = 2 THEN r.reserve_date END), "%Y/%m/%d") AS student_first')
|
|
||||||
->selectRaw('COUNT(*) AS total')
|
|
||||||
->where('rc.park_id', $parkId)
|
|
||||||
->where('r.valid_flag', 1)
|
|
||||||
->where(function ($q) {
|
|
||||||
$q->whereNull('r.reserve_cancel_flag')->orWhere('r.reserve_cancel_flag', 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
if ($vehicleType['psection_id'] === 0) {
|
|
||||||
// その他:psection_id が 1,2 以外
|
|
||||||
$query->whereNotIn('rc.psection_id', [1, 2]);
|
|
||||||
} else {
|
|
||||||
// 自転車または原付
|
|
||||||
$query->where('rc.psection_id', $vehicleType['psection_id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$result = $query->first();
|
|
||||||
|
|
||||||
$generalCount = (int) ($result->general_count ?? 0);
|
|
||||||
$studentCount = (int) ($result->student_count ?? 0);
|
|
||||||
$typeTotal = $generalCount + $studentCount;
|
|
||||||
|
|
||||||
$waitingSummary[] = [
|
|
||||||
'type' => $vehicleType['type'],
|
|
||||||
'general_count' => $generalCount,
|
|
||||||
'general_first' => $result->general_first ?? null,
|
|
||||||
'student_count' => $studentCount,
|
|
||||||
'student_first' => $result->student_first ?? null,
|
|
||||||
'total' => $typeTotal,
|
|
||||||
];
|
|
||||||
|
|
||||||
$totalGeneral += $generalCount;
|
|
||||||
$totalStudent += $studentCount;
|
|
||||||
$totalAll += $typeTotal;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 合計行を追加
|
|
||||||
$waitingSummary[] = [
|
|
||||||
'type' => '計',
|
|
||||||
'general_count' => $totalGeneral,
|
|
||||||
'general_first' => null,
|
|
||||||
'student_count' => $totalStudent,
|
|
||||||
'student_first' => null,
|
|
||||||
'total' => $totalAll,
|
|
||||||
];
|
|
||||||
|
|
||||||
$debugInfo['waiting_count'] = count($waitingSummary);
|
|
||||||
|
|
||||||
// まず期間タイプフィールドが存在するかチェック
|
|
||||||
$hasRegularTypeId = false;
|
|
||||||
try {
|
|
||||||
$columns = DB::select('DESCRIBE regular_contract');
|
|
||||||
foreach ($columns as $column) {
|
|
||||||
if ($column->Field === 'regular_type_id') {
|
|
||||||
$hasRegularTypeId = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
// エラーの場合はデフォルトで false
|
|
||||||
}
|
|
||||||
|
|
||||||
$debugInfo['has_regular_type_id'] = $hasRegularTypeId;
|
|
||||||
|
|
||||||
$renewalQuery = DB::table('regular_contract as rc')
|
|
||||||
->join('reserve as r', 'rc.contract_id', '=', 'r.contract_id')
|
|
||||||
->where('rc.park_id', $parkId)
|
|
||||||
->whereNotNull('r.reserve_start')
|
|
||||||
->where('r.valid_flag', 1)
|
|
||||||
->selectRaw("DATE_FORMAT(r.reserve_start, '%Y-%m') AS month");
|
|
||||||
|
|
||||||
if ($hasRegularTypeId) {
|
|
||||||
$renewalQuery->selectRaw('COALESCE(rc.regular_type_id, 1) AS period_type');
|
|
||||||
} else {
|
|
||||||
$renewalQuery->selectRaw('1 AS period_type'); // デフォルト値
|
|
||||||
}
|
|
||||||
|
|
||||||
$renewalSummary = $renewalQuery
|
|
||||||
->selectRaw('SUM(CASE WHEN rc.psection_id = 1 AND rc.user_categoryid = 1 THEN 1 ELSE 0 END) AS bicycle_general')
|
|
||||||
->selectRaw('SUM(CASE WHEN rc.psection_id = 1 AND rc.user_categoryid = 2 THEN 1 ELSE 0 END) AS bicycle_student')
|
|
||||||
->selectRaw('SUM(CASE WHEN rc.psection_id = 2 AND rc.user_categoryid = 1 THEN 1 ELSE 0 END) AS moped_general')
|
|
||||||
->selectRaw('SUM(CASE WHEN rc.psection_id = 2 AND rc.user_categoryid = 2 THEN 1 ELSE 0 END) AS moped_student')
|
|
||||||
->selectRaw('SUM(CASE WHEN rc.psection_id NOT IN (1,2) AND rc.user_categoryid = 1 THEN 1 ELSE 0 END) AS other_general')
|
|
||||||
->selectRaw('SUM(CASE WHEN rc.psection_id NOT IN (1,2) AND rc.user_categoryid = 2 THEN 1 ELSE 0 END) AS other_student')
|
|
||||||
->groupBy(['month', 'period_type'])
|
|
||||||
->orderBy('month')
|
|
||||||
->orderBy('period_type')
|
|
||||||
->limit(50)
|
|
||||||
->get();
|
|
||||||
|
|
||||||
// 月別期間別データを構造化
|
|
||||||
$structuredData = [];
|
|
||||||
$periodLabels = [
|
|
||||||
1 => '1ヶ月',
|
|
||||||
2 => '2ヶ月',
|
|
||||||
3 => '3ヶ月',
|
|
||||||
6 => '6ヶ月',
|
|
||||||
12 => '12ヶ月'
|
|
||||||
];
|
|
||||||
|
|
||||||
// regular_type_id がない場合のデフォルト処理
|
|
||||||
if (!$hasRegularTypeId) {
|
|
||||||
// フィールドがない場合は、月ごとに「計」行のみ表示
|
|
||||||
$monthlyTotals = [];
|
|
||||||
foreach ($renewalSummary as $row) {
|
|
||||||
$monthKey = $row->month;
|
|
||||||
if (!isset($monthlyTotals[$monthKey])) {
|
|
||||||
$monthlyTotals[$monthKey] = [
|
|
||||||
'bicycle_general' => 0,
|
'bicycle_general' => 0,
|
||||||
'bicycle_student' => 0,
|
'bicycle_student' => 0,
|
||||||
|
'bicycle_total' => 0,
|
||||||
'moped_general' => 0,
|
'moped_general' => 0,
|
||||||
'moped_student' => 0,
|
'moped_student' => 0,
|
||||||
'other_general' => 0,
|
'moped_total' => 0,
|
||||||
'other_student' => 0,
|
'others_general' => 0,
|
||||||
|
'others_student' => 0,
|
||||||
|
'others_total' => 0,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
$monthlyTotals[$monthKey]['bicycle_general'] += (int) $row->bicycle_general;
|
|
||||||
$monthlyTotals[$monthKey]['bicycle_student'] += (int) $row->bicycle_student;
|
|
||||||
$monthlyTotals[$monthKey]['moped_general'] += (int) $row->moped_general;
|
|
||||||
$monthlyTotals[$monthKey]['moped_student'] += (int) $row->moped_student;
|
|
||||||
$monthlyTotals[$monthKey]['other_general'] += (int) $row->other_general;
|
|
||||||
$monthlyTotals[$monthKey]['other_student'] += (int) $row->other_student;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($monthlyTotals as $monthKey => $totals) {
|
|
||||||
$structuredData[$monthKey] = [
|
|
||||||
'month' => $monthKey,
|
|
||||||
'rows' => [[
|
|
||||||
'label' => '計',
|
|
||||||
'bicycle_general' => $totals['bicycle_general'],
|
|
||||||
'bicycle_student' => $totals['bicycle_student'],
|
|
||||||
'bicycle_total' => $totals['bicycle_general'] + $totals['bicycle_student'],
|
|
||||||
'moped_general' => $totals['moped_general'],
|
|
||||||
'moped_student' => $totals['moped_student'],
|
|
||||||
'moped_total' => $totals['moped_general'] + $totals['moped_student'],
|
|
||||||
'other_general' => $totals['other_general'],
|
|
||||||
'other_student' => $totals['other_student'],
|
|
||||||
'other_total' => $totals['other_general'] + $totals['other_student'],
|
|
||||||
]]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// regular_type_id がある場合の通常処理
|
|
||||||
foreach ($renewalSummary as $row) {
|
|
||||||
$monthKey = $row->month;
|
|
||||||
$periodType = (int)$row->period_type;
|
|
||||||
$periodLabel = $periodLabels[$periodType] ?? "{$periodType}ヶ月";
|
|
||||||
|
|
||||||
if (!isset($structuredData[$monthKey])) {
|
|
||||||
$structuredData[$monthKey] = [
|
|
||||||
'month' => $monthKey,
|
|
||||||
'rows' => [],
|
|
||||||
'totals' => [
|
|
||||||
'bicycle_general' => 0,
|
|
||||||
'bicycle_student' => 0,
|
|
||||||
'moped_general' => 0,
|
|
||||||
'moped_student' => 0,
|
|
||||||
'other_general' => 0,
|
|
||||||
'other_student' => 0,
|
|
||||||
]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
$bicycle_total = (int) $row->bicycle_general + (int) $row->bicycle_student;
|
|
||||||
$moped_total = (int) $row->moped_general + (int) $row->moped_student;
|
|
||||||
$other_total = (int) $row->other_general + (int) $row->other_student;
|
|
||||||
|
|
||||||
// 期間別データを追加
|
|
||||||
$structuredData[$monthKey]['rows'][] = [
|
|
||||||
'label' => $periodLabel,
|
|
||||||
'bicycle_general' => (int) $row->bicycle_general,
|
|
||||||
'bicycle_student' => (int) $row->bicycle_student,
|
|
||||||
'bicycle_total' => $bicycle_total,
|
|
||||||
'moped_general' => (int) $row->moped_general,
|
|
||||||
'moped_student' => (int) $row->moped_student,
|
|
||||||
'moped_total' => $moped_total,
|
|
||||||
'other_general' => (int) $row->other_general,
|
|
||||||
'other_student' => (int) $row->other_student,
|
|
||||||
'other_total' => $other_total,
|
|
||||||
];
|
|
||||||
|
|
||||||
// 月別合計を計算
|
|
||||||
$structuredData[$monthKey]['totals']['bicycle_general'] += (int) $row->bicycle_general;
|
|
||||||
$structuredData[$monthKey]['totals']['bicycle_student'] += (int) $row->bicycle_student;
|
|
||||||
$structuredData[$monthKey]['totals']['moped_general'] += (int) $row->moped_general;
|
|
||||||
$structuredData[$monthKey]['totals']['moped_student'] += (int) $row->moped_student;
|
|
||||||
$structuredData[$monthKey]['totals']['other_general'] += (int) $row->other_general;
|
|
||||||
$structuredData[$monthKey]['totals']['other_student'] += (int) $row->other_student;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 各月に計行を追加
|
|
||||||
foreach ($structuredData as &$monthData) {
|
|
||||||
$totals = $monthData['totals'];
|
|
||||||
$monthData['rows'][] = [
|
|
||||||
'label' => '計',
|
|
||||||
'bicycle_general' => $totals['bicycle_general'],
|
|
||||||
'bicycle_student' => $totals['bicycle_student'],
|
|
||||||
'bicycle_total' => $totals['bicycle_general'] + $totals['bicycle_student'],
|
|
||||||
'moped_general' => $totals['moped_general'],
|
|
||||||
'moped_student' => $totals['moped_student'],
|
|
||||||
'moped_total' => $totals['moped_general'] + $totals['moped_student'],
|
|
||||||
'other_general' => $totals['other_general'],
|
|
||||||
'other_student' => $totals['other_student'],
|
|
||||||
'other_total' => $totals['other_general'] + $totals['other_student'],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$renewalSummary = array_values($structuredData);
|
|
||||||
|
|
||||||
$debugInfo['renewal_count'] = count($renewalSummary);
|
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'contract_summary' => $contractSummary,
|
'contract_summary' => $contractSummary,
|
||||||
'waiting_summary' => $waitingSummary,
|
'waiting_summary' => $waitingSummary,
|
||||||
'renewal_summary' => $renewalSummary,
|
'renewal_summary' => $renewalSummary,
|
||||||
'debug_info' => $debugInfo
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
|
||||||
@ -14,27 +14,14 @@ class PersonalController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function list(Request $request)
|
public function list(Request $request)
|
||||||
{
|
{
|
||||||
$query = User::query()
|
$query = User::query();
|
||||||
// 本人確認手動処理:未チェック(1) または 手動NG(4) または 自動チェックNG(5)
|
|
||||||
->whereIn('user_idcard_chk_flag', [1, 4, 5])
|
|
||||||
// 本人確認書類アップロード済み
|
|
||||||
->where(function($q) {
|
|
||||||
$q->whereNotNull('photo_filename1')
|
|
||||||
->orWhereNotNull('photo_filename2');
|
|
||||||
})
|
|
||||||
// usertypeテーブルとLEFT JOINで分類情報を取得
|
|
||||||
->leftJoin('usertype', 'user.user_categoryid', '=', 'usertype.user_categoryid')
|
|
||||||
->select('user.*',
|
|
||||||
'usertype.usertype_subject1',
|
|
||||||
'usertype.usertype_subject2',
|
|
||||||
'usertype.usertype_subject3');
|
|
||||||
|
|
||||||
if ($request->filled('user_id')) {
|
if ($request->filled('user_id')) {
|
||||||
$query->where('user.user_id', $request->input('user_id'));
|
$query->where('user_id', $request->input('user_id'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// データベースの物理順序(主キー昇順)で表示
|
|
||||||
$users = $query->paginate(20);
|
$users = $query->paginate(20);
|
||||||
|
|
||||||
return view('admin.personal.list', [
|
return view('admin.personal.list', [
|
||||||
'users' => $users,
|
'users' => $users,
|
||||||
'request' => $request,
|
'request' => $request,
|
||||||
@ -44,121 +31,33 @@ class PersonalController extends Controller
|
|||||||
/**
|
/**
|
||||||
* 本人確認手動処理 編集画面
|
* 本人確認手動処理 編集画面
|
||||||
*/
|
*/
|
||||||
public function edit(Request $request, $seq)
|
public function edit(Request $request, $id)
|
||||||
{
|
{
|
||||||
\Log::info('=== Personal Edit Method START ===', ['seq' => $seq, 'method' => $request->method()]);
|
// 利用者情報取得
|
||||||
|
$user = User::where('user_id', $id)->firstOrFail();
|
||||||
// 利用者情報取得(user_seqで検索)
|
|
||||||
$user = User::where('user_seq', $seq)->firstOrFail();
|
|
||||||
|
|
||||||
\Log::info('User found:', [
|
|
||||||
'user_seq' => $user->user_seq,
|
|
||||||
'user_id' => $user->user_id,
|
|
||||||
'current_flag' => $user->user_idcard_chk_flag
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 利用者分類マスタ取得(ラジオボタン用)
|
// 利用者分類マスタ取得(ラジオボタン用)
|
||||||
$usertypes = Usertype::orderBy('sort_order')->get();
|
$usertypes = Usertype::orderBy('sort_order')->get();
|
||||||
|
|
||||||
// POST時の処理
|
// POST時の処理
|
||||||
if ($request->isMethod('post')) {
|
if ($request->isMethod('post')) {
|
||||||
\Log::info('=== FULL REQUEST DEBUG ===');
|
// 利用者分類IDの更新
|
||||||
\Log::info('All request data:', $request->all());
|
|
||||||
|
|
||||||
\Log::info('=== Personal Edit POST Processing ===');
|
|
||||||
|
|
||||||
// 各フィールドの更新
|
|
||||||
$user->user_categoryid = $request->input('user_categoryid', $user->user_categoryid);
|
$user->user_categoryid = $request->input('user_categoryid', $user->user_categoryid);
|
||||||
$user->user_regident_zip = $request->input('user_regident_zip', $user->user_regident_zip);
|
|
||||||
$user->user_regident_pre = $request->input('user_regident_pre', $user->user_regident_pre);
|
// 本人確認チェックOK/NG
|
||||||
$user->user_regident_city = $request->input('user_regident_city', $user->user_regident_city);
|
if ($request->input('check') === 'ok') {
|
||||||
$user->user_regident_add = $request->input('user_regident_add', $user->user_regident_add);
|
$user->user_idcard_chk_flag = 1;
|
||||||
$user->user_relate_zip = $request->input('user_relate_zip', $user->user_relate_zip);
|
} elseif ($request->input('check') === 'ng') {
|
||||||
$user->user_relate_pre = $request->input('user_relate_pre', $user->user_relate_pre);
|
$user->user_idcard_chk_flag = 0;
|
||||||
$user->user_relate_city = $request->input('user_relate_city', $user->user_relate_city);
|
// 備考欄も更新(NG理由)
|
||||||
$user->user_relate_add = $request->input('user_relate_add', $user->user_relate_add);
|
|
||||||
$user->user_remarks = $request->input('user_remarks', $user->user_remarks);
|
$user->user_remarks = $request->input('user_remarks', $user->user_remarks);
|
||||||
$user->user_idcard = $request->input('user_idcard', $user->user_idcard);
|
|
||||||
|
|
||||||
// 本人確認チェック処理(バックアップ値を優先使用)
|
|
||||||
$checkValue = $request->input('check') ?? $request->input('check_backup');
|
|
||||||
|
|
||||||
\Log::info('Check value received:', [
|
|
||||||
'check' => $request->input('check'),
|
|
||||||
'check_backup' => $request->input('check_backup'),
|
|
||||||
'final_value' => $checkValue,
|
|
||||||
'type' => gettype($checkValue)
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($checkValue === 'ok') {
|
|
||||||
$user->user_idcard_chk_flag = 3; // 手動チェックOK
|
|
||||||
$user->ope_id = auth()->user()->ope_id ?? auth()->id(); // 現在ログイン中の操作者ID
|
|
||||||
\Log::info('Setting user_idcard_chk_flag to 3 (手動チェックOK)');
|
|
||||||
\Log::info('Setting ope_id to current user:', ['ope_id' => $user->ope_id]);
|
|
||||||
} elseif ($checkValue === 'ng') {
|
|
||||||
$user->user_idcard_chk_flag = 4; // 手動チェックNG
|
|
||||||
$user->ope_id = auth()->user()->ope_id ?? auth()->id(); // 現在ログイン中の操作者ID
|
|
||||||
\Log::info('Setting user_idcard_chk_flag to 4 (手動チェックNG)');
|
|
||||||
\Log::info('Setting ope_id to current user:', ['ope_id' => $user->ope_id]);
|
|
||||||
} else {
|
|
||||||
\Log::warning('No valid check value received', [
|
|
||||||
'checkValue' => $checkValue,
|
|
||||||
'all_input' => $request->all()
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
\Log::info('Before save:', [
|
$user->save();
|
||||||
'user_idcard_chk_flag' => $user->user_idcard_chk_flag,
|
|
||||||
'ope_id' => $user->ope_id,
|
|
||||||
'isDirty' => $user->isDirty(),
|
|
||||||
'getDirty' => $user->getDirty()
|
|
||||||
]);
|
|
||||||
|
|
||||||
try {
|
return redirect()->route('personal')->with('success', '更新しました');
|
||||||
$result = $user->save();
|
|
||||||
\Log::info('User saved successfully', [
|
|
||||||
'result' => $result,
|
|
||||||
'user_idcard_chk_flag' => $user->user_idcard_chk_flag
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 保存結果の検証
|
|
||||||
$user->refresh(); // モデルデータをリフレッシュ
|
|
||||||
$savedUser = User::where('user_seq', $seq)->first();
|
|
||||||
\Log::info('Verification after save', [
|
|
||||||
'model_refresh' => $user->user_idcard_chk_flag,
|
|
||||||
'user_idcard_chk_flag' => $savedUser->user_idcard_chk_flag
|
|
||||||
]);
|
|
||||||
|
|
||||||
// データベース直接確認
|
|
||||||
$dbUser = \DB::table('user')->where('user_seq', $seq)->first();
|
|
||||||
\Log::info('DB direct check:', [
|
|
||||||
'user_idcard_chk_flag' => $dbUser->user_idcard_chk_flag ?? 'NOT_FOUND'
|
|
||||||
]);
|
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
\Log::error('Save failed', [
|
|
||||||
'error' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine()
|
|
||||||
]);
|
|
||||||
return back()->withErrors('保存に失敗しました: ' . $e->getMessage());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
\Log::info('=== POST Processing END ===');
|
|
||||||
|
|
||||||
// 成功メッセージ
|
|
||||||
$message = 'データを更新しました。';
|
|
||||||
if ($checkValue === 'ok') {
|
|
||||||
$message = '本人確認チェックOKで更新しました。';
|
|
||||||
} elseif ($checkValue === 'ng') {
|
|
||||||
$message = '本人確認チェックNGで更新しました。';
|
|
||||||
}
|
|
||||||
|
|
||||||
return redirect()->route('personal')->with('success', $message);
|
|
||||||
}
|
|
||||||
|
|
||||||
\Log::info('=== Personal Edit Method END (GET) ===');
|
|
||||||
|
|
||||||
return view('admin.personal.edit', [
|
return view('admin.personal.edit', [
|
||||||
'user' => $user,
|
'user' => $user,
|
||||||
'usertypes' => $usertypes,
|
'usertypes' => $usertypes,
|
||||||
|
|||||||
@ -24,152 +24,107 @@ class PplaceController extends Controller
|
|||||||
$inputs['list'] = Pplace::search($inputs);
|
$inputs['list'] = Pplace::search($inputs);
|
||||||
|
|
||||||
if ($inputs['list']->total() > 0 && $inputs['page'] > $inputs['list']->lastPage()) {
|
if ($inputs['list']->total() > 0 && $inputs['page'] > $inputs['list']->lastPage()) {
|
||||||
return redirect()->route('pplaces');
|
return redirect()->route('pplace');
|
||||||
}
|
}
|
||||||
|
|
||||||
return view('admin.pplace.list', $inputs);
|
return view('admin.Pplace.list', $inputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 新規登録(画面/処理)
|
|
||||||
*/
|
|
||||||
public function add(Request $request)
|
public function add(Request $request)
|
||||||
{
|
{
|
||||||
if ($request->isMethod('get')) {
|
$inputs = [
|
||||||
// 新規時:空のレコードとオペレーターリストを渡す
|
'pplace_number' => $request->input('pplace_number'),
|
||||||
return view('admin.pplace.add', [
|
'pplace_remarks' => $request->input('pplace_remarks'),
|
||||||
'isEdit' => false,
|
'operator_id' => $request->input('operator_id'),
|
||||||
'record' => new Pplace(),
|
];
|
||||||
'operators' => Ope::getList(),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// POST時:バリデーション
|
$inputs['operators'] = Ope::getList(); //
|
||||||
$rules = [
|
|
||||||
|
if ($request->isMethod('POST')) {
|
||||||
|
$validator = Validator::make($inputs, [
|
||||||
'pplace_number' => 'required|string|max:255',
|
'pplace_number' => 'required|string|max:255',
|
||||||
'pplace_remarks' => 'nullable|string|max:255',
|
'pplace_remarks' => 'nullable|string|max:255',
|
||||||
'operator_id' => 'nullable|integer',
|
'operator_id' => 'nullable|integer',
|
||||||
];
|
]);
|
||||||
$messages = [
|
|
||||||
'pplace_number.required' => '駐輪場所番号は必須です。',
|
|
||||||
];
|
|
||||||
|
|
||||||
$validator = Validator::make($request->all(), $rules, $messages);
|
if (!$validator->fails()) {
|
||||||
|
DB::transaction(function () use ($inputs) {
|
||||||
if ($validator->fails()) {
|
$pplace = new Pplace();
|
||||||
return redirect()->back()
|
$pplace->fill($inputs);
|
||||||
->withErrors($validator)
|
$pplace->save();
|
||||||
->withInput()
|
|
||||||
->with(['operators' => Ope::getList()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// トランザクションで登録処理
|
|
||||||
DB::transaction(function () use ($request) {
|
|
||||||
$new = new Pplace();
|
|
||||||
$new->fill($request->only(['pplace_number', 'pplace_remarks', 'operator_id']));
|
|
||||||
$new->save();
|
|
||||||
});
|
});
|
||||||
|
return redirect()->route('pplace')->with('success', '登録成功');
|
||||||
return redirect()->route('pplaces')->with('success', '登録しました。');
|
} else {
|
||||||
|
$inputs['errorMsg'] = $this->__buildErrorMessasges($validator);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return view('admin.Pplace.add', $inputs);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
public function edit(Request $request, $id, $view = '')
|
||||||
* 編集(画面/処理)
|
|
||||||
*/
|
|
||||||
public function edit(Request $request, $id)
|
|
||||||
{
|
{
|
||||||
// 該当データ取得
|
|
||||||
$record = Pplace::find($id);
|
$record = Pplace::find($id);
|
||||||
if (!$record) {
|
|
||||||
abort(404);
|
|
||||||
}
|
|
||||||
|
|
||||||
// オペレーターリスト取得(常に渡す)
|
if (!$record) abort(404);
|
||||||
$operators = Ope::getList();
|
|
||||||
|
|
||||||
if ($request->isMethod('get')) {
|
$data = $record->toArray();
|
||||||
// 編集画面表示
|
$data['operators'] = Ope::getList();
|
||||||
return view('admin.pplace.edit', [
|
|
||||||
'isEdit' => true,
|
|
||||||
'record' => $record,
|
|
||||||
'operators' => $operators,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// POST時:バリデーション
|
|
||||||
$rules = [
|
if ($request->isMethod('POST')) {
|
||||||
|
$inputs = $request->all();
|
||||||
|
$validator = Validator::make($inputs, [
|
||||||
'pplace_number' => 'required|string|max:255',
|
'pplace_number' => 'required|string|max:255',
|
||||||
'pplace_remarks' => 'nullable|string|max:255',
|
'pplace_remarks' => 'nullable|string|max:255',
|
||||||
'operator_id' => 'nullable|integer',
|
'operator_id' => 'nullable|integer',
|
||||||
];
|
]);
|
||||||
$messages = [
|
|
||||||
'pplace_number.required' => '駐輪場所番号は必須です。',
|
|
||||||
];
|
|
||||||
|
|
||||||
$validator = Validator::make($request->all(), $rules, $messages);
|
$data = array_merge($data, $inputs);
|
||||||
|
|
||||||
if ($validator->fails()) {
|
if (!$validator->fails()) {
|
||||||
return redirect()->back()
|
DB::transaction(function () use ($record, $inputs) {
|
||||||
->withErrors($validator)
|
$record->fill($inputs);
|
||||||
->withInput()
|
|
||||||
->with(['operators' => $operators]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新処理
|
|
||||||
DB::transaction(function () use ($request, $record) {
|
|
||||||
$record->fill($request->only(['pplace_number', 'pplace_remarks', 'operator_id']));
|
|
||||||
$record->save();
|
$record->save();
|
||||||
});
|
});
|
||||||
|
return redirect()->route('pplace')->with('success', '更新成功');
|
||||||
return redirect()->route('pplaces')->with('success', '更新しました。');
|
} else {
|
||||||
|
$data['errorMsg'] = $this->__buildErrorMessasges($validator);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return view($view ?: 'admin.Pplace.edit', $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function info(Request $request, $id)
|
||||||
|
{
|
||||||
|
return $this->edit($request, $id, 'admin.Pplace.info');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 削除(単一/複数対応)
|
|
||||||
*/
|
|
||||||
public function delete(Request $request)
|
public function delete(Request $request)
|
||||||
{
|
{
|
||||||
$ids = [];
|
$pk = $request->get('pk');
|
||||||
|
if ($pk && Pplace::destroy($pk)) {
|
||||||
// 単一削除(id)
|
return redirect()->route('pplace')->with('success', '削除成功');
|
||||||
if ($request->filled('id')) {
|
|
||||||
$ids[] = (int) $request->input('id');
|
|
||||||
}
|
}
|
||||||
|
return redirect()->route('pplace')->with('error', '削除失敗');
|
||||||
// 複数削除(チェックボックス pk[])
|
|
||||||
if (is_array($request->input('pk'))) {
|
|
||||||
$ids = array_merge($ids, $request->input('pk'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重複除去 & 数値変換
|
|
||||||
$ids = array_values(array_unique(array_map('intval', $ids)));
|
|
||||||
|
|
||||||
// 対象未選択
|
|
||||||
if (empty($ids)) {
|
|
||||||
return back()->with('error', '削除対象が選択されていません。');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 削除実行
|
|
||||||
Pplace::whereIn('pplace_id', $ids)->delete();
|
|
||||||
|
|
||||||
return redirect()->route('pplaces')->with('success', '削除しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public function export()
|
public function export()
|
||||||
{
|
{
|
||||||
$filename = '駐輪車室マスタ' . now()->format('YmdHis') . '.csv';
|
$headers = [
|
||||||
|
"Content-type" => "text/csv;charset=UTF-8",
|
||||||
$file = fopen($filename, 'w+');
|
"Content-Disposition" => "attachment; filename=Pplace.csv",
|
||||||
fwrite($file, "\xEF\xBB\xBF"); // BOM追加(UTF-8)
|
];
|
||||||
|
|
||||||
$columns = ['駐輪車室ID', '番号', '備考', 'オペレータID'];
|
|
||||||
fputcsv($file, $columns);
|
|
||||||
|
|
||||||
$data = Pplace::all();
|
$data = Pplace::all();
|
||||||
|
$columns = ['ID', '番号', '備考', 'オペレータID'];
|
||||||
|
|
||||||
|
$filename = "Pplace.csv";
|
||||||
|
$file = fopen($filename, 'w+');
|
||||||
|
fputcsv($file, $columns);
|
||||||
|
|
||||||
foreach ($data as $item) {
|
foreach ($data as $item) {
|
||||||
fputcsv($file, [
|
fputcsv($file, [
|
||||||
$item->pplace_id,
|
$item->pplace_id,
|
||||||
@ -180,21 +135,14 @@ class PplaceController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
fclose($file);
|
fclose($file);
|
||||||
|
return Response::download($filename, $filename, $headers);
|
||||||
$headers = [
|
|
||||||
"Content-Type" => "text/csv; charset=UTF-8",
|
|
||||||
"Content-Disposition" => "attachment; filename={$filename}",
|
|
||||||
];
|
|
||||||
|
|
||||||
return response()->download($filename, $filename, $headers)->deleteFileAfterSend(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function import(Request $request)
|
public function import(Request $request)
|
||||||
{
|
{
|
||||||
$file = $request->file('file');
|
$file = $request->file('file');
|
||||||
if (!$file) {
|
if (!$file) {
|
||||||
return redirect()->route('pplaces')->with('error', 'CSVファイルを選択してください');
|
return redirect()->route('pplace')->with('error', 'CSVファイルを選択してください');
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = \App\Utils::csvToArray($file);
|
$data = \App\Utils::csvToArray($file);
|
||||||
@ -213,10 +161,10 @@ class PplaceController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
DB::commit();
|
DB::commit();
|
||||||
return redirect()->route('pplaces')->with('success', 'インポート成功');
|
return redirect()->route('pplace')->with('success', 'インポート成功');
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
DB::rollBack();
|
DB::rollBack();
|
||||||
return redirect()->route('pplaces')->with('error', "行 {$record} : " . $e->getMessage());
|
return redirect()->route('pplace')->with('error', "行 {$record} : " . $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,17 +5,15 @@ namespace App\Http\Controllers\Admin;
|
|||||||
use App\Http\Requests\PriceRequest;
|
use App\Http\Requests\PriceRequest;
|
||||||
use App\Models\Park;
|
use App\Models\Park;
|
||||||
use App\Models\Price;
|
use App\Models\Price;
|
||||||
use App\Models\Pplace;
|
|
||||||
use App\Models\Psection;
|
use App\Models\Psection;
|
||||||
use App\Models\Ptype;
|
use App\Models\Ptype;
|
||||||
use App\Models\Usertype;
|
use App\Models\Usertype;
|
||||||
use App\Models\Station;
|
|
||||||
use App\Models\Utils;
|
use App\Models\Utils;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use Illuminate\Support\Facades\Response;
|
use Response;
|
||||||
|
|
||||||
class PriceController extends Controller
|
class PriceController extends Controller
|
||||||
{
|
{
|
||||||
@ -23,317 +21,218 @@ class PriceController extends Controller
|
|||||||
{
|
{
|
||||||
$inputs = [
|
$inputs = [
|
||||||
'isExport' => 0,
|
'isExport' => 0,
|
||||||
'sort' => $request->input('sort', ''), // ソート対象カラム
|
'sort' => $request->input('sort', ''),
|
||||||
'sort_type' => $request->input('sort_type', ''), // 昇順/降順
|
'sort_type' => $request->input('sort_type', ''),
|
||||||
'page' => $request->get('page', 1),
|
'page' => $request->get('page', 1),
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
// Price::search 内で orderBy を反映させる
|
|
||||||
$inputs['list'] = Price::search($inputs);
|
$inputs['list'] = Price::search($inputs);
|
||||||
|
|
||||||
if ($inputs['list']->total() > 0 && $inputs['page'] > $inputs['list']->lastPage()) {
|
if ($inputs['list']->total() > 0 && $inputs['page'] > $inputs['list']->lastPage()) {
|
||||||
return redirect()->route('prices');
|
return redirect()->route('prices');
|
||||||
}
|
}
|
||||||
$dataList = $this->getDataDropList();
|
|
||||||
$inputs = array_merge($inputs, $dataList);
|
|
||||||
|
|
||||||
return view('admin.prices.list', $inputs);
|
return view('admin.prices.list', $inputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function add(Request $request)
|
public function add(Request $request)
|
||||||
{
|
{
|
||||||
if ($request->isMethod('get')) {
|
$inputs = [
|
||||||
return view('admin.prices.add', array_merge(
|
'price_parkplaceid' => $request->input('price_parkplaceid'), // 駐車場所ID
|
||||||
$this->getDataDropList(),
|
'park_id' => $request->input('park_id'), // 駐輪場ID
|
||||||
[
|
'prine_name' => $request->input('prine_name'), // 商品名
|
||||||
'record' => new Price(),
|
'price_month' => $request->input('price_month',''), // 期間
|
||||||
'isEdit' => false,
|
'user_categoryid' => $request->input('user_categoryid'), // 利用者分類ID
|
||||||
]
|
'price' => $request->input('price'), // 駐輪料金(税込)
|
||||||
|
'psection_id' => $request->input('psection_id'), // 車種区分ID
|
||||||
|
'price_ptypeid' => $request->input('price_ptypeid'), // 駐輪分類ID
|
||||||
|
'pplace_id' => $request->input('pplace_id'), // 駐車車室ID
|
||||||
|
];
|
||||||
|
|
||||||
|
$dataList = $this->getDataDropList();
|
||||||
|
$inputs = array_merge($inputs, $dataList);
|
||||||
|
if ($request->isMethod('POST')) {
|
||||||
|
$type = false;
|
||||||
|
\DB::transaction(function () use ($inputs, &$type) {
|
||||||
|
$new = new Price();
|
||||||
|
$new->fill($inputs);
|
||||||
|
if( $new->save()){
|
||||||
|
$type = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if ($type) {
|
||||||
|
$request->session()->flash('success', __('新しい成功を創造する。'));
|
||||||
|
return redirect()->route('prices');
|
||||||
|
} else {
|
||||||
|
$request->session()->flash('error', __('新しい作成に失敗しました'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('admin.prices.add', $inputs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function edit(Request $request, $pk ,$view=''){
|
||||||
|
$price = Price::getByPk($pk);
|
||||||
|
if (empty($pk) || empty($price)) {
|
||||||
|
abort('404');
|
||||||
|
}
|
||||||
|
$data = $price->getAttributes();
|
||||||
|
$dataList = $this->getDataDropList();
|
||||||
|
$data = array_merge($data, $dataList);
|
||||||
|
if ($request->isMethod('POST')) {
|
||||||
|
$type = false;
|
||||||
|
$requestAll = [
|
||||||
|
'price_parkplaceid' => $request->input('price_parkplaceid'),
|
||||||
|
'park_id' => $request->input('park_id'),
|
||||||
|
'prine_name' => $request->input('prine_name'),
|
||||||
|
'price_month' => $request->input('price_month',''),
|
||||||
|
'user_categoryid' => $request->input('user_categoryid'),
|
||||||
|
'price' => $request->input('price'),
|
||||||
|
'psection_id' => $request->input('psection_id'),
|
||||||
|
'price_ptypeid' => $request->input('price_ptypeid'),
|
||||||
|
'pplace_id' => $request->input('pplace_id'),
|
||||||
|
];
|
||||||
|
$data = array_merge($data, $requestAll);
|
||||||
|
\DB::transaction(function () use ($data, &$type,$price) {
|
||||||
|
$price->fill($data);
|
||||||
|
$price->save();
|
||||||
|
$type = true;
|
||||||
|
});
|
||||||
|
if ($type) {
|
||||||
|
$request->session()->flash('success', __('更新に成功しました'));
|
||||||
|
return redirect()->route('prices');
|
||||||
|
} else {
|
||||||
|
$request->session()->flash('error', __('更新に失敗しました'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($view != '') {
|
||||||
|
return view($view, $data);
|
||||||
|
}
|
||||||
|
return view('admin.prices.edit', $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(Request $request)
|
||||||
|
{
|
||||||
|
$arr_pk = $request->get('pk');
|
||||||
|
if ($arr_pk) {
|
||||||
|
if (Price::deleteByPk($arr_pk)) {
|
||||||
|
return redirect()->route('prices')->with('success', __("削除成功。"));
|
||||||
|
} else {
|
||||||
|
return redirect()->route('prices')->with('error', __('削除に失敗しました。'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return redirect()->route('prices')->with('error', __('削除するユーザーを選択してください。'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function export(Request $request)
|
||||||
|
{
|
||||||
|
|
||||||
|
$headers = array(
|
||||||
|
"Content-type" => "text/csv;charset=UTF-8",
|
||||||
|
'Content-Encoding: UTF-8',
|
||||||
|
"Content-Disposition" => "attachment; filename=file.csv",
|
||||||
|
"Pragma" => "no-cache",
|
||||||
|
"Cache-Control" => "must-revalidate, post-check=0, pre-check=0",
|
||||||
|
"Expires" => "0"
|
||||||
|
);
|
||||||
|
$inputs = [
|
||||||
|
'isMethodPost' => 0,
|
||||||
|
'isExport' => 1,
|
||||||
|
'sort' => $request->input('sort', ''),
|
||||||
|
'sort_type' => $request->input('sort_type', ''),
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
$dataExport = Price::search($inputs);
|
||||||
|
$columns = array(
|
||||||
|
__('駐車場所ID'),// 0
|
||||||
|
__('商品名'),// 1
|
||||||
|
__('期間'),// 2
|
||||||
|
__('駐輪場ID'),// 3
|
||||||
|
__('駐輪場名'),// 3
|
||||||
|
__('車種区分ID'),// 5
|
||||||
|
__('車種区分'),// 6
|
||||||
|
__('駐輪分類ID'),// 7
|
||||||
|
__('駐輪分類'),// 8
|
||||||
|
__('利用者分類ID'),// 9
|
||||||
|
__('利用者分類'),// 10
|
||||||
|
__('駐車車室ID'),//11
|
||||||
|
__('駐輪料金(税込)'),// 12
|
||||||
|
);
|
||||||
|
$filename = "駐輪場所、料金マスタ.csv";
|
||||||
|
$file = fopen($filename, 'w+');
|
||||||
|
fputcsv($file, $columns);
|
||||||
|
foreach ($dataExport as $items) {
|
||||||
|
fputcsv($file, array(
|
||||||
|
$items->price_parkplaceid,// 0
|
||||||
|
$items->prine_name, // 1
|
||||||
|
$items->price_month, // 2
|
||||||
|
$items->park_id, // 3
|
||||||
|
!empty($items->getPark())? $items->getPark()->park_name:'' ,// 4
|
||||||
|
$items->psection_id, // 5
|
||||||
|
!empty($items->getPSection())? $items->getPSection()->psection_subject:'',// 6
|
||||||
|
$items->price_ptypeid, // 7
|
||||||
|
!empty($items->getPType())? $items->getPType()->ptype_subject:'' ,// 8
|
||||||
|
$items->user_categoryid, //9
|
||||||
|
!empty($items->getUserType())? $items->getUserType()->print_name:'' ,//10
|
||||||
|
$items->pplace_id,// 11
|
||||||
|
$items->price, // 12
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
$request->merge([
|
|
||||||
'pplace_id' => mb_convert_kana($request->input('pplace_id'), 'n'),
|
|
||||||
]);
|
|
||||||
|
|
||||||
$validated = $this->validateRequest($request);
|
|
||||||
|
|
||||||
$created = false;
|
|
||||||
\DB::transaction(function () use ($validated, &$created) {
|
|
||||||
$price = new Price();
|
|
||||||
$price->fill($validated);
|
|
||||||
$created = $price->save();
|
|
||||||
});
|
|
||||||
|
|
||||||
return redirect()->route('prices')
|
|
||||||
->with($created ? 'success' : 'error', $created ? '登録しました。' : '登録に失敗しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function edit(Request $request, $id)
|
|
||||||
{
|
|
||||||
$price = Price::getByPk($id);
|
|
||||||
if (!$price) {
|
|
||||||
abort(404);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($request->isMethod('get')) {
|
|
||||||
return view('admin.prices.edit', array_merge(
|
|
||||||
$this->getDataDropList(),
|
|
||||||
[
|
|
||||||
'record' => $price,
|
|
||||||
'isEdit' => true,
|
|
||||||
]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
$request->merge([
|
|
||||||
'pplace_id' => mb_convert_kana($request->input('pplace_id'), 'n'),
|
|
||||||
]);
|
|
||||||
|
|
||||||
$validated = $this->validateRequest($request, $id);
|
|
||||||
|
|
||||||
$updated = false;
|
|
||||||
\DB::transaction(function () use ($validated, &$updated, $price) {
|
|
||||||
$price->fill($validated);
|
|
||||||
$updated = $price->save();
|
|
||||||
});
|
|
||||||
|
|
||||||
return redirect()->route('prices')
|
|
||||||
->with($updated ? 'success' : 'error', $updated ? '更新しました。' : '更新に失敗しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public function delete(Request $request, $id = null)
|
|
||||||
{
|
|
||||||
// 一覧画面(checkbox で複数削除)
|
|
||||||
$ids = $request->input('pk');
|
|
||||||
|
|
||||||
// 編集画面(単体削除)
|
|
||||||
if ($id) {
|
|
||||||
$ids = [$id];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 削除対象が空
|
|
||||||
if (empty($ids)) {
|
|
||||||
return redirect()->route('prices')->with('error', '削除対象が選択されていません。');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 削除処理
|
|
||||||
Price::destroy($ids);
|
|
||||||
|
|
||||||
return redirect()->route('prices')->with('success', '削除しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static function deleteByPk($ids)
|
|
||||||
{
|
|
||||||
if (!is_array($ids)) {
|
|
||||||
$ids = [$ids];
|
|
||||||
}
|
|
||||||
return self::whereIn('price_parkplaceid', $ids)->delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function export()
|
|
||||||
{
|
|
||||||
$filename = '駐輪場所、料金マスタ' . now()->format('YmdHis') . '.csv';
|
|
||||||
|
|
||||||
$file = fopen($filename, 'w+');
|
|
||||||
fwrite($file, "\xEF\xBB\xBF"); // BOM追加(UTF-8)
|
|
||||||
|
|
||||||
$columns = [
|
|
||||||
'駐輪場所ID',
|
|
||||||
'駐輪場ID',
|
|
||||||
'商品名',
|
|
||||||
'期間',
|
|
||||||
'利用者分類ID',
|
|
||||||
'駐輪料金(税込)',
|
|
||||||
'車種区分ID',
|
|
||||||
'駐輪分類ID',
|
|
||||||
'駐車車室ID',
|
|
||||||
];
|
|
||||||
|
|
||||||
fputcsv($file, $columns);
|
|
||||||
|
|
||||||
$data = Price::all();
|
|
||||||
foreach ($data as $item) {
|
|
||||||
fputcsv($file, [
|
|
||||||
$item->price_parkplaceid, // 駐輪場所ID
|
|
||||||
$item->park_id, // 駐輪場ID
|
|
||||||
optional($item->getUserType())->print_name, // 利用者分類名
|
|
||||||
$item->price_month, // 期間
|
|
||||||
optional($item->getUserType())->print_name, // 利用者分類ID
|
|
||||||
$item->price, // 駐輪料金(税込)
|
|
||||||
optional($item->getPSection())->psection_subject, // 車種区分名
|
|
||||||
optional($item->getPType())->ptype_subject, // 駐輪分類名
|
|
||||||
$item->pplace_id, // 駐車車室ID
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fclose($file);
|
fclose($file);
|
||||||
|
return Response::download($filename, $filename, $headers);
|
||||||
$headers = [
|
|
||||||
"Content-Type" => "text/csv; charset=UTF-8",
|
|
||||||
"Content-Disposition" => "attachment; filename={$filename}",
|
|
||||||
];
|
|
||||||
|
|
||||||
return response()->download($filename, $filename, $headers)->deleteFileAfterSend(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function exportFiltered(Request $request)
|
|
||||||
{
|
|
||||||
$parkId = $request->input('park_id');
|
|
||||||
$filename = 'price_' . $parkId . '_' . now()->format('YmdHis') . '.csv';
|
|
||||||
|
|
||||||
// 一時ファイル作成
|
|
||||||
$file = fopen($filename, 'w+');
|
|
||||||
fwrite($file, "\xEF\xBB\xBF"); // UTF-8 BOM追加
|
|
||||||
|
|
||||||
// CSVヘッダ
|
|
||||||
$columns = [
|
|
||||||
'駐輪場所ID',
|
|
||||||
'商品名',
|
|
||||||
'期間',
|
|
||||||
'駐輪場ID',
|
|
||||||
'駐輪場名',
|
|
||||||
'車種区分ID',
|
|
||||||
'車種区分',
|
|
||||||
'駐輪分類ID',
|
|
||||||
'駐輪分類',
|
|
||||||
'利用者分類ID',
|
|
||||||
'利用者分類',
|
|
||||||
'駐輪車室ID',
|
|
||||||
'駐輪料金(税込)',
|
|
||||||
];
|
|
||||||
fputcsv($file, $columns);
|
|
||||||
|
|
||||||
// データ取得(選択した駐輪場IDに限定)
|
|
||||||
$data = \App\Models\Price::where('price_parkplaceid', $parkId)->get();
|
|
||||||
|
|
||||||
foreach ($data as $item) {
|
|
||||||
fputcsv($file, [
|
|
||||||
$item->price_parkplaceid, // 駐輪場所ID
|
|
||||||
$item->prine_name, // 商品名
|
|
||||||
$item->price_term ?? $item->price_month, // 期間
|
|
||||||
$item->park_id, // 駐輪場ID
|
|
||||||
optional($item->getPark())->park_name, // 駐輪場名
|
|
||||||
$item->psection_id, // 車種区分ID
|
|
||||||
optional($item->getPSection())->psection_subject, // 車種区分
|
|
||||||
$item->price_ptypeid, // 駐輪分類ID
|
|
||||||
optional($item->getPType())->ptype_subject, // 駐輪分類
|
|
||||||
$item->user_categoryid, // 利用者分類ID
|
|
||||||
optional($item->getUserType())->print_name, // 利用者分類
|
|
||||||
$item->pplace_id, // 駐輪車室ID
|
|
||||||
$item->price_taxin ?? $item->price, // 駐輪料金(税込)
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose($file);
|
|
||||||
|
|
||||||
// ヘッダ設定
|
|
||||||
$headers = [
|
|
||||||
"Content-Type" => "text/csv; charset=UTF-8",
|
|
||||||
"Content-Disposition" => "attachment; filename=\"{$filename}\"",
|
|
||||||
];
|
|
||||||
|
|
||||||
// ダウンロード後にファイル削除
|
|
||||||
return response()->download($filename, $filename, $headers)->deleteFileAfterSend(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function import(Request $request)
|
public function import(Request $request)
|
||||||
{
|
{
|
||||||
$file = $request->file('file');
|
$file = $request->file('file');
|
||||||
if (empty($file)) {
|
if(!empty($file)){
|
||||||
return redirect()->route('prices')->with('error', __('CSVファイルを選択してください。'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = Utils::csvToArray($file);
|
$data = Utils::csvToArray($file);
|
||||||
$type = true;
|
$type = 1;
|
||||||
$msg = '';
|
$msg = '';
|
||||||
$record = 0;
|
$record = 0;
|
||||||
|
|
||||||
DB::beginTransaction();
|
DB::beginTransaction();
|
||||||
try {
|
try {
|
||||||
|
Price::query()->delete();
|
||||||
$col = 13; // CSV 項目数
|
$col = 13;
|
||||||
foreach ($data as $key => $items) {
|
foreach ($data as $key => $items) {
|
||||||
$record = $key + 2; // エラー行番号(ヘッダ行を考慮)
|
$record = $key + 2;
|
||||||
|
if (count($items) == $col) {
|
||||||
// 項目数チェック
|
$row = new Price();
|
||||||
if (count($items) != $col) {
|
$row->price_parkplaceid = $items[0];
|
||||||
$type = false;
|
$row->prine_name = $items[1];
|
||||||
$msg = "行:{$record} 列数が一致しません。";
|
$row->price_month = $items[2];
|
||||||
|
$row->park_id = $items[3];
|
||||||
|
$row->psection_id = $items[5];
|
||||||
|
$row->price_ptypeid = $items[7];
|
||||||
|
$row->user_categoryid = $items[9];
|
||||||
|
$row->pplace_id = $items[11];
|
||||||
|
$row->price = $items[12];
|
||||||
|
if (!$row->save()) {
|
||||||
|
$type = 0;
|
||||||
|
$msg = '行:record型が一致しません。';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
// 必須チェック
|
$type = 0;
|
||||||
if (empty($items[0])) { $type = false; $msg = "行:{$record} 駐車場所IDが未設定です。"; break; }
|
$msg = '行:record列数が一致しません。';
|
||||||
if (empty($items[1])) { $type = false; $msg = "行:{$record} 商品名が未設定です。"; break; }
|
break;
|
||||||
if (empty($items[2])) { $type = false; $msg = "行:{$record} 期間が未設定です。"; break; }
|
|
||||||
if (empty($items[3])) { $type = false; $msg = "行:{$record} 駐輪場IDが未設定です。"; break; }
|
|
||||||
if (empty($items[5])) { $type = false; $msg = "行:{$record} 車種区分IDが未設定です。"; break; }
|
|
||||||
if (empty($items[7])) { $type = false; $msg = "行:{$record} 駐輪分類IDが未設定です。"; break; }
|
|
||||||
if (empty($items[9])) { $type = false; $msg = "行:{$record} 利用者分類IDが未設定です。"; break; }
|
|
||||||
if (empty($items[11])) { $type = false; $msg = "行:{$record} 駐車車室IDが未設定です。"; break; }
|
|
||||||
if (empty($items[12])) { $type = false; $msg = "行:{$record} 駐輪料金が未設定です。"; break; }
|
|
||||||
|
|
||||||
// マスタ存在チェック
|
|
||||||
if (!Park::where('park_id', $items[3])->exists()) {
|
|
||||||
$type = false; $msg = "行:{$record} 駐輪場IDが存在しません。"; break;
|
|
||||||
}
|
}
|
||||||
if (!Psection::where('psection_id', $items[5])->exists()) {
|
|
||||||
$type = false; $msg = "行:{$record} 車種区分IDが存在しません。"; break;
|
|
||||||
}
|
|
||||||
if (!Ptype::where('ptype_id', $items[7])->exists()) {
|
|
||||||
$type = false; $msg = "行:{$record} 駐輪分類IDが存在しません。"; break;
|
|
||||||
}
|
|
||||||
if (!Usertype::where('user_categoryid', $items[9])->exists()) {
|
|
||||||
$type = false; $msg = "行:{$record} 利用者分類IDが存在しません。"; break;
|
|
||||||
}
|
|
||||||
// TODO: 駐車車室ID チェック(pplace_id)
|
|
||||||
if (!Pplace::where('pplace_id', $items[11])->exists()) {
|
|
||||||
$type = false; $msg = "行:{$record} 駐車車室IDが存在しません。"; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 保存(存在すれば更新、なければ新規作成)
|
|
||||||
Price::updateOrCreate(
|
|
||||||
['price_parkplaceid' => $items[0]], // 主キー条件(存在チェック)
|
|
||||||
|
|
||||||
[
|
|
||||||
'prine_name' => $items[1],
|
|
||||||
'price_month' => $items[2],
|
|
||||||
'park_id' => $items[3],
|
|
||||||
'psection_id' => $items[5],
|
|
||||||
'price_ptypeid' => $items[7],
|
|
||||||
'user_categoryid' => $items[9],
|
|
||||||
'pplace_id' => $items[11],
|
|
||||||
'price' => $items[12],
|
|
||||||
'operator_id' => auth()->user()->operator_id ?? null, // オプション
|
|
||||||
'updated_at' => now(),
|
|
||||||
'created_at' => now(),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$type = false;
|
$msg = '行:record型が一致しません。';
|
||||||
$msg = "行:{$record} 予期せぬエラー: ".$e->getMessage();
|
$type = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($type) {
|
if ($type) {
|
||||||
DB::commit();
|
DB::commit();
|
||||||
return redirect()->route('prices')->with('success', __('インポートが正常に完了しました。'));
|
return redirect()->route('prices')->with('success', __('輸入成功'));
|
||||||
} else {
|
} else {
|
||||||
DB::rollBack();
|
DB::rollBack();
|
||||||
return redirect()->route('prices')->with('error', $msg);
|
return redirect()->route('prices')->with('error', __($msg, ['record' => $record]));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return redirect()->route('prices')->with('error', __('あなたはcsvファイルを選択していません。'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function info(Request $request, $id)
|
public function info(Request $request, $id)
|
||||||
{
|
{
|
||||||
return $this->edit($request, $id, 'admin.prices.info');
|
return $this->edit($request, $id, 'admin.prices.info');
|
||||||
@ -345,33 +244,8 @@ class PriceController extends Controller
|
|||||||
$data['psections'] = Psection::getList() ;
|
$data['psections'] = Psection::getList() ;
|
||||||
$data['ptypes'] = Ptype::getList() ;
|
$data['ptypes'] = Ptype::getList() ;
|
||||||
$data['userTypes'] = Usertype::getList() ;
|
$data['userTypes'] = Usertype::getList() ;
|
||||||
$data['pplaces'] = Pplace::getList() ;
|
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Price バリデーション共通
|
|
||||||
*/
|
|
||||||
private function validateRequest(Request $request): array
|
|
||||||
{
|
|
||||||
return $request->validate([
|
|
||||||
'prine_name' => 'required|string|max:255',
|
|
||||||
'price_month' => 'required|int',
|
|
||||||
'park_id' => 'required|int',
|
|
||||||
'psection_id' => 'required|int',
|
|
||||||
'price_ptypeid' => 'required|int',
|
|
||||||
'user_categoryid' => 'required|int',
|
|
||||||
'pplace_id' => 'nullable|int',
|
|
||||||
'park_number' => 'nullable|int',
|
|
||||||
'park_standard' => 'nullable|int',
|
|
||||||
'park_limit' => 'nullable|int',
|
|
||||||
'price' => 'required|numeric',
|
|
||||||
'operator_id' => 'nullable|int',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -32,26 +32,16 @@ class PriceListController extends Controller
|
|||||||
];
|
];
|
||||||
|
|
||||||
if ($parkId) {
|
if ($parkId) {
|
||||||
// price_a に必要なマスタを JOIN
|
// parkとprice_aをJOIN
|
||||||
$aRows = \DB::table('price_a')
|
$aRows = \DB::table('price_a')
|
||||||
->join('park', 'park.park_id', '=', 'price_a.park_id')
|
->join('park', 'park.park_id', '=', 'price_a.park_id')
|
||||||
->leftJoin('ptype', 'price_a.ptype_id', '=', 'ptype.ptype_id')
|
|
||||||
->leftJoin('usertype', 'price_a.user_categoryid', '=', 'usertype.user_categoryid')
|
|
||||||
->leftJoin('pplace', 'price_a.pplace_id', '=', 'pplace.pplace_id')
|
|
||||||
->where('price_a.park_id', $parkId)
|
->where('price_a.park_id', $parkId)
|
||||||
->select([
|
->select('price_a.*') // 必要ならpark.*も
|
||||||
'price_a.*',
|
|
||||||
'ptype.ptype_subject',
|
|
||||||
'usertype.usertype_subject1',
|
|
||||||
'usertype.usertype_subject2',
|
|
||||||
'usertype.usertype_subject3',
|
|
||||||
'pplace.pplace_number'
|
|
||||||
])
|
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
$aGrouped = $this->groupPriceRows($aRows);
|
$aGrouped = $this->groupPriceRows($aRows);
|
||||||
$masterList[0]['groups'] = $aGrouped;
|
|
||||||
|
|
||||||
|
$masterList[0]['groups'] = $aGrouped;
|
||||||
// マスターBも同様に取得・整形する場合はここに追加
|
// マスターBも同様に取得・整形する場合はここに追加
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,103 +60,85 @@ class PriceListController extends Controller
|
|||||||
$result = [];
|
$result = [];
|
||||||
foreach ($rows as $row) {
|
foreach ($rows as $row) {
|
||||||
// グループキーは分類ID+ユーザ分類ID+駐輪場ID
|
// グループキーは分類ID+ユーザ分類ID+駐輪場ID
|
||||||
$key = $row->ptype_id . '-' . $row->user_categoryid . '-' . $row->park_id;
|
$key = $row->price_ptypeid . '-' . $row->user_categoryid . '-' . $row->park_id;
|
||||||
|
|
||||||
if (!isset($result[$key])) {
|
if (!isset($result[$key])) {
|
||||||
$result[$key] = [
|
$result[$key] = [
|
||||||
'id' => $row->price_parkplaceid,
|
'id' => $row->price_parkplaceid,
|
||||||
'classification' => $row->ptype_subject ?? '',
|
'classification' => $row->price_ptypeid,
|
||||||
'room_number' => $row->pplace_number ?? '',
|
'room_number' => '', // 必要ならpplace_id等をセット
|
||||||
'category1' => $row->usertype_subject1 ?? '',
|
'category1' => $row->prine_name ?? '',
|
||||||
'category2' => $row->usertype_subject2 ?? '',
|
'category2' => '',
|
||||||
'category3' => $row->usertype_subject3 ?? '',
|
'category3' => '',
|
||||||
'bike_1m' => '', 'bike_2m' => '', 'bike_3m' => '', 'bike_6m' => '', 'bike_12m' => '',
|
'bike_1m' => '',
|
||||||
'moped_1m' => '', 'moped_2m' => '', 'moped_3m' => '', 'moped_6m' => '', 'moped_12m' => '',
|
'bike_2m' => '',
|
||||||
'motorcycle_1m' => '', 'motorcycle_2m' => '', 'motorcycle_3m' => '', 'motorcycle_6m' => '', 'motorcycle_12m' => '',
|
'bike_3m' => '',
|
||||||
'car_1m' => '', 'car_2m' => '', 'car_3m' => '', 'car_6m' => '', 'car_12m' => '',
|
'bike_6m' => '',
|
||||||
|
'bike_12m' => '',
|
||||||
|
// 必要なら原付・自動二輪も同様に追加
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
$month = $row->price_month;
|
// 月数ごとに金額をセット
|
||||||
$price = $row->price;
|
if ($row->price_month == 1) {
|
||||||
switch ($row->psection_id) {
|
$result[$key]['bike_1m'] = $row->price;
|
||||||
case 1:
|
} elseif ($row->price_month == 2) {
|
||||||
$result[$key]["bike_{$month}m"] = $price;
|
$result[$key]['bike_2m'] = $row->price;
|
||||||
break;
|
} elseif ($row->price_month == 3) {
|
||||||
case 2:
|
$result[$key]['bike_3m'] = $row->price;
|
||||||
$result[$key]["moped_{$month}m"] = $price;
|
} elseif ($row->price_month == 6) {
|
||||||
break;
|
$result[$key]['bike_6m'] = $row->price;
|
||||||
case 3:
|
} elseif ($row->price_month == 12) {
|
||||||
$result[$key]["motorcycle_{$month}m"] = $price;
|
$result[$key]['bike_12m'] = $row->price;
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
$result[$key]["car_{$month}m"] = $price;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return array_values($result);
|
return array_values($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update(Request $request)
|
public function update(Request $request)
|
||||||
{
|
{
|
||||||
foreach ($request->input('rows', []) as $row) {
|
foreach ($request->input('rows', []) as $row) {
|
||||||
$id = $row['id'] ?? null;
|
$id = $row['id'] ?? null;
|
||||||
if (!$id) continue;
|
if (!$id) continue;
|
||||||
|
|
||||||
$vehicleTypes = [
|
// 更新対象の月リスト
|
||||||
'bike' => 1,
|
$months = [
|
||||||
'moped' => 2,
|
'bike_1m' => 1,
|
||||||
'motorcycle' => 3,
|
'bike_2m' => 2,
|
||||||
'car' => 4,
|
'bike_3m' => 3,
|
||||||
|
'bike_6m' => 6,
|
||||||
|
'bike_12m' => 12,
|
||||||
];
|
];
|
||||||
|
|
||||||
$months = [1, 2, 3, 6, 12];
|
foreach ($months as $field => $month) {
|
||||||
|
|
||||||
foreach ($vehicleTypes as $prefix => $psectionId) {
|
|
||||||
foreach ($months as $month) {
|
|
||||||
$field = "{$prefix}_{$month}m";
|
|
||||||
if (isset($row[$field])) {
|
if (isset($row[$field])) {
|
||||||
$value = $row[$field];
|
// price_aから該当レコードを取得
|
||||||
|
$item = \App\Models\PriceA::where('price_parkplaceid', $id)
|
||||||
// バリデーション:空欄はスキップ
|
|
||||||
if (!ctype_digit((string)$value)) {
|
|
||||||
return back()->withErrors([
|
|
||||||
"{$field}" => "金額は整数で入力してください。"
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// バリデーション:最大値を超えないこと
|
|
||||||
if ((int)$value > 9999999999) {
|
|
||||||
return back()->withErrors([
|
|
||||||
"{$field}" => "金額は最大 9,999,999,999 までです。"
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$item = PriceA::where('price_parkplaceid', $id)
|
|
||||||
->where('price_month', $month)
|
->where('price_month', $month)
|
||||||
->where('psection_id', $psectionId)
|
|
||||||
->first();
|
->first();
|
||||||
if ($item) {
|
if ($item) {
|
||||||
$item->price = $value;
|
$item->price = $row[$field];
|
||||||
$item->save();
|
$item->save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
// 原付・自動二輪も同様に必要なら追加
|
||||||
}
|
}
|
||||||
return back()->with('success', '金額を更新しました');
|
return back()->with('success', '金額を更新しました');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function insert(Request $request)
|
public function insert(Request $request)
|
||||||
{
|
{
|
||||||
|
// 例:bike_2m(2ヶ月)だけ新規追加する場合
|
||||||
if ($request->filled('bike_2m')) {
|
if ($request->filled('bike_2m')) {
|
||||||
$row = new PriceA();
|
$row = new \App\Models\PriceA();
|
||||||
$row->park_id = $request->input('park_id');
|
$row->park_id = $request->input('park_id'); // 必要に応じて
|
||||||
$row->price = $request->input('bike_2m');
|
$row->price = $request->input('bike_2m');
|
||||||
$row->price_month = 2;
|
$row->price_month = 2;
|
||||||
$row->psection_id = 1; // 自転車
|
// 他の必要なカラムもセット
|
||||||
$row->save();
|
$row->save();
|
||||||
}
|
}
|
||||||
|
// 他の月も同様に必要なら追加
|
||||||
return back()->with('success', '金額を追加しました');
|
return back()->with('success', '金額を追加しました');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,158 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use App\Models\PrintArea;
|
|
||||||
use App\Models\Park;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
|
|
||||||
class PrintAreaController extends Controller
|
|
||||||
{
|
|
||||||
// 一覧
|
|
||||||
public function list(Request $request)
|
|
||||||
{
|
|
||||||
$sort = $request->input('sort', 'print_area_id');
|
|
||||||
$sort_type = $request->input('sort_type', 'asc');
|
|
||||||
|
|
||||||
$list = PrintArea::orderBy($sort, $sort_type)->paginate(20);
|
|
||||||
|
|
||||||
return view('admin.print_areas.list', [
|
|
||||||
'list' => $list,
|
|
||||||
'sort' => $sort,
|
|
||||||
'sort_type' => $sort_type,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 新規
|
|
||||||
public function add(Request $request)
|
|
||||||
{
|
|
||||||
if ($request->isMethod('post')) {
|
|
||||||
$validated = $request->validate([
|
|
||||||
'print_area_name' => 'required|string|max:32',
|
|
||||||
'park_id' => 'required|integer',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$validated['operator_id'] = auth()->id(); // 現在のログインユーザーを記録
|
|
||||||
PrintArea::create($validated);
|
|
||||||
|
|
||||||
return redirect()->route('print_areas')->with('success', '登録しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
$parks = Park::pluck('park_name', 'park_id');
|
|
||||||
return view('admin.print_areas.add', compact('parks'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 編集
|
|
||||||
public function edit(Request $request, $print_area_id)
|
|
||||||
{
|
|
||||||
$record = PrintArea::findOrFail($print_area_id);
|
|
||||||
|
|
||||||
if ($request->isMethod('post')) {
|
|
||||||
$validated = $request->validate([
|
|
||||||
'print_area_name' => 'required|string|max:32',
|
|
||||||
'park_id' => 'required|integer',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$validated['operator_id'] = auth()->id(); // 更新者を記録
|
|
||||||
$record->update($validated);
|
|
||||||
|
|
||||||
return redirect()->route('print_areas')->with('success', '更新しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
$parks = Park::pluck('park_name', 'park_id');
|
|
||||||
return view('admin.print_areas.edit', compact('record', 'parks'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 詳細
|
|
||||||
public function info(Request $request, $print_area_id)
|
|
||||||
{
|
|
||||||
$record = PrintArea::with('park')->findOrFail($print_area_id);
|
|
||||||
return view('admin.print_areas.info', compact('record'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 印刷範囲マスタ削除処理
|
|
||||||
*/
|
|
||||||
public function delete(Request $request, $id = null)
|
|
||||||
{
|
|
||||||
// 一覧画面(checkboxで複数削除)
|
|
||||||
$ids = $request->input('pk');
|
|
||||||
|
|
||||||
// 編集画面(単体削除)
|
|
||||||
if ($id) {
|
|
||||||
$ids = [$id];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 削除対象が空
|
|
||||||
if (empty($ids)) {
|
|
||||||
return redirect()
|
|
||||||
->route('print_areas')
|
|
||||||
->with('error', '削除対象が選択されていません。');
|
|
||||||
}
|
|
||||||
|
|
||||||
// バリデーション:配列 or 単一でも整数確認
|
|
||||||
$request->validate([
|
|
||||||
'pk' => 'nullable',
|
|
||||||
'pk.*' => 'integer',
|
|
||||||
]);
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 削除処理
|
|
||||||
$deleted = PrintArea::destroy($ids);
|
|
||||||
|
|
||||||
if ($deleted > 0) {
|
|
||||||
return redirect()
|
|
||||||
->route('print_areas')
|
|
||||||
->with('success', '削除しました。');
|
|
||||||
} else {
|
|
||||||
return redirect()
|
|
||||||
->route('print_areas')
|
|
||||||
->with('error', '削除に失敗しました。');
|
|
||||||
}
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
\Log::error('印刷範囲削除エラー: ' . $e->getMessage());
|
|
||||||
|
|
||||||
return redirect()
|
|
||||||
->route('print_areas')
|
|
||||||
->with('error', '削除中にエラーが発生しました。');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function export(Request $request)
|
|
||||||
{
|
|
||||||
// ファイル名を日本語付きで指定(Excelで問題なく開けるようにUTF-8にBOMも付加)
|
|
||||||
$filename = 'シール印刷範囲マスタ' . now()->format('YmdHis') . '.csv';
|
|
||||||
|
|
||||||
$data = PrintArea::with('park')->get();
|
|
||||||
|
|
||||||
// UTF-8 BOM (Excel用)
|
|
||||||
$bom = "\xEF\xBB\xBF";
|
|
||||||
|
|
||||||
// CSVヘッダー
|
|
||||||
$csv = implode(",", ['印刷範囲ID', '印刷範囲名', '駐輪場ID', '駐輪場名']) . "\n";
|
|
||||||
|
|
||||||
foreach ($data as $item) {
|
|
||||||
$csv .= implode(",", [
|
|
||||||
$item->print_area_id,
|
|
||||||
$item->print_area_name,
|
|
||||||
$item->park_id,
|
|
||||||
optional($item->park)->park_name,
|
|
||||||
]) . "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
return response($bom . $csv)
|
|
||||||
->header('Content-Type', 'text/csv; charset=UTF-8')
|
|
||||||
// filename* にすれば日本語名も安全に動作
|
|
||||||
->header('Content-Disposition', "attachment; filename*=UTF-8''" . rawurlencode($filename));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// CSVインポート(仮)
|
|
||||||
public function import(Request $request)
|
|
||||||
{
|
|
||||||
// 実装未
|
|
||||||
return redirect()->route('print_areas')->with('success', 'CSVインポート処理(未実装)');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -11,118 +11,63 @@ class PsectionController extends Controller
|
|||||||
// 一覧画面
|
// 一覧画面
|
||||||
public function list(Request $request)
|
public function list(Request $request)
|
||||||
{
|
{
|
||||||
$inputs = $request->all();
|
// ソート順
|
||||||
// ソート可能なカラム
|
$sort = $request->input('sort', 'psection_id');
|
||||||
$allowedSortColumns = ['psection_id', 'psection_subject'];
|
$sort_type = $request->input('sort_type', 'asc');
|
||||||
|
|
||||||
// ソート情報の取得
|
$query = Psection::query();
|
||||||
$sortColumn = $inputs['sort'] ?? 'psection_id';
|
if (in_array($sort, ['psection_id', 'psection_subject'])) {
|
||||||
$sortType = strtolower($inputs['sort_type'] ?? 'asc');
|
$query->orderBy($sort, $sort_type);
|
||||||
|
|
||||||
$query = \App\Models\Psection::query();
|
|
||||||
|
|
||||||
if (in_array($sortColumn, $allowedSortColumns, true)) {
|
|
||||||
if (!in_array($sortType, ['asc', 'desc'], true)) {
|
|
||||||
$sortType = 'asc';
|
|
||||||
}
|
|
||||||
$query->orderBy($sortColumn, $sortType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ページネーション(20件)
|
$list = $query->get();
|
||||||
$list = $query->paginate(20);
|
|
||||||
|
|
||||||
return view('admin.psection.list', [
|
return view('admin.psection.list', compact('list', 'sort', 'sort_type'));
|
||||||
'list' => $list,
|
|
||||||
'sort' => $sortColumn,
|
|
||||||
'sort_type' => $sortType,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// 新規追加
|
||||||
* 車種区分マスタ:新規登録(画面/処理)
|
|
||||||
*/
|
|
||||||
public function add(Request $request)
|
public function add(Request $request)
|
||||||
{
|
{
|
||||||
if ($request->isMethod('get')) {
|
if ($request->isMethod('post')) {
|
||||||
// GET:新規画面を表示
|
|
||||||
return view('admin.psection.add', [
|
|
||||||
'isEdit' => false,
|
|
||||||
'record' => new Psection(),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// POST:バリデーション
|
|
||||||
$validated = $request->validate([
|
$validated = $request->validate([
|
||||||
// 'psection_id' は自動採番
|
'psection_id' => 'required|integer|unique:psection,psection_id',
|
||||||
'psection_subject' => 'required|string|max:255',
|
'psection_subject' => 'required|string|max:255',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// 登録処理
|
|
||||||
Psection::create($validated);
|
Psection::create($validated);
|
||||||
|
return redirect()->route('psection')->with('success', '車種区分を追加しました');
|
||||||
// 完了メッセージ+一覧へ戻る
|
}
|
||||||
return redirect()->route('psections')->with('success', '登録しました。');
|
return view('admin.psection.add');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 編集
|
||||||
/**
|
|
||||||
* 車種区分マスタ:編集(画面/処理)
|
|
||||||
*/
|
|
||||||
public function edit(Request $request, $id)
|
public function edit(Request $request, $id)
|
||||||
{
|
{
|
||||||
// 主キーで検索(見つからない場合は404)
|
$psection = Psection::findOrFail($id);
|
||||||
$record = Psection::findOrFail($id);
|
if ($request->isMethod('post')) {
|
||||||
|
|
||||||
if ($request->isMethod('get')) {
|
|
||||||
// 編集画面表示
|
|
||||||
return view('admin.psection.edit', [
|
|
||||||
'isEdit' => true, // ← ★ Blade 側のフォームで新規/編集を判定するため
|
|
||||||
'record' => $record, // ← ★ _form.blade.php で使用する
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// POST時:バリデーション
|
|
||||||
$validated = $request->validate([
|
$validated = $request->validate([
|
||||||
'psection_subject' => 'required|string|max:255',
|
'psection_subject' => 'required|string|max:255',
|
||||||
]);
|
]);
|
||||||
|
$psection->update($validated);
|
||||||
// データ更新
|
return redirect()->route('psection')->with('success', '車種区分を更新しました');
|
||||||
$record->update($validated);
|
}
|
||||||
|
return view('admin.psection.edit', compact('psection'));
|
||||||
// 成功メッセージ & リダイレクト
|
|
||||||
return redirect()->route('psections')->with('success', '更新しました。');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// 詳細(info)
|
||||||
* 削除(単一/複数対応)
|
public function info(Request $request, $id)
|
||||||
*/
|
{
|
||||||
|
$psection = Psection::findOrFail($id);
|
||||||
|
return view('admin.psection.info', compact('psection'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 削除
|
||||||
public function delete(Request $request)
|
public function delete(Request $request)
|
||||||
{
|
{
|
||||||
$ids = [];
|
$ids = $request->input('pk', []);
|
||||||
|
if (!empty($ids)) {
|
||||||
// 単一削除(編集画面などからの削除ボタン)
|
|
||||||
if ($request->filled('id')) {
|
|
||||||
$ids[] = (int) $request->input('id');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 一覧画面からの複数削除チェックボックス対応
|
|
||||||
if (is_array($request->input('pk'))) {
|
|
||||||
$ids = array_merge($ids, $request->input('pk'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重複削除・無効値除去
|
|
||||||
$ids = array_values(array_unique(array_map('intval', $ids)));
|
|
||||||
|
|
||||||
// 削除対象がない場合
|
|
||||||
if (empty($ids)) {
|
|
||||||
return back()->with('error', '削除対象が選択されていません。');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 削除実行
|
|
||||||
Psection::whereIn('psection_id', $ids)->delete();
|
Psection::whereIn('psection_id', $ids)->delete();
|
||||||
|
return redirect()->route('psection')->with('success', '削除しました');
|
||||||
// 完了メッセージ+リダイレクト
|
}
|
||||||
return redirect()->route('psections')->with('success', '削除しました。');
|
return redirect()->route('psection')->with('error', '削除対象を選択してください');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,156 +14,125 @@ class PtypeController extends Controller
|
|||||||
{
|
{
|
||||||
public function list(Request $request)
|
public function list(Request $request)
|
||||||
{
|
{
|
||||||
// 受け取る入力値
|
|
||||||
$inputs = [
|
$inputs = [
|
||||||
'isMethodPost' => $request->isMethod('post') ? 1 : 0,
|
'isMethodPost' => 0,
|
||||||
'isExport' => 0,
|
'isExport' => 0,
|
||||||
'sort' => $request->input('sort', 'ptype_id'), // デフォルト: ID
|
'sort' => $request->input('sort', ''),
|
||||||
'sort_type' => strtolower($request->input('sort_type', 'asc')),
|
'sort_type' => $request->input('sort_type', ''),
|
||||||
'page' => $request->get('page', 1),
|
'page' => $request->get('page', 1),
|
||||||
|
|
||||||
];
|
];
|
||||||
|
$inputs['isMethodPost'] = $request->isMethod('post');
|
||||||
// 許可するソート可能カラム
|
$inputs['list'] = Ptype::search($inputs);
|
||||||
$allowedSortColumns = [
|
|
||||||
'ptype_id',
|
|
||||||
'ptype_subject',
|
|
||||||
'floor_sort',
|
|
||||||
'created_at',
|
|
||||||
];
|
|
||||||
|
|
||||||
// 検索クエリ作成
|
|
||||||
$query = \App\Models\Ptype::query();
|
|
||||||
|
|
||||||
// ソート処理
|
|
||||||
if (in_array($inputs['sort'], $allowedSortColumns, true)) {
|
|
||||||
$sortType = in_array($inputs['sort_type'], ['asc', 'desc'], true)
|
|
||||||
? $inputs['sort_type']
|
|
||||||
: 'asc';
|
|
||||||
|
|
||||||
$query->orderBy($inputs['sort'], $sortType);
|
|
||||||
} else {
|
|
||||||
|
|
||||||
$query->orderBy('ptype_id', 'asc');
|
|
||||||
}
|
|
||||||
|
|
||||||
// ページネーション
|
|
||||||
$inputs['list'] = $query->paginate(20);
|
|
||||||
|
|
||||||
// ページが超過している場合リダイレクト
|
|
||||||
if ($inputs['list']->total() > 0 && $inputs['page'] > $inputs['list']->lastPage()) {
|
if ($inputs['list']->total() > 0 && $inputs['page'] > $inputs['list']->lastPage()) {
|
||||||
return redirect()->route('ptypes');
|
return redirect()->route('ptypes');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 画面へ
|
|
||||||
return view('admin.ptypes.list', $inputs);
|
return view('admin.ptypes.list', $inputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 新規登録(画面/処理)
|
|
||||||
*/
|
|
||||||
public function add(Request $request)
|
public function add(Request $request)
|
||||||
{
|
{
|
||||||
if ($request->isMethod('get')) {
|
$inputs = [
|
||||||
// 新規時は空のレコードを用意してフォーム描画
|
//TODO 駐輪分類ID not found in database specs
|
||||||
return view('admin.ptypes.add', [
|
'ptype_subject' => $request->input('ptype_subject'), // 駐輪分類名
|
||||||
'isEdit' => false,
|
'ptype_remarks' => $request->input('ptype_remarks'), // 備考
|
||||||
'record' => new Ptype(), // ← ★ Blade側で record->〇〇 が使える
|
];
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// POST時:バリデーション
|
if ($request->isMethod('POST')) {
|
||||||
$rules = [
|
$rules = [
|
||||||
'ptype_subject' => 'required|string|max:255',
|
'ptype_subject' => 'required|string|max:255',
|
||||||
|
'ptype_sort' => 'nullable|integer',
|
||||||
'ptype_remarks' => 'nullable|string|max:255',
|
'ptype_remarks' => 'nullable|string|max:255',
|
||||||
];
|
];
|
||||||
$messages = [
|
$messages = [
|
||||||
'ptype_subject.required' => '駐輪分類名は必須です。',
|
'ptype_subject.required' => '駐輪分類名は必須です。',
|
||||||
];
|
];
|
||||||
|
|
||||||
$validator = Validator::make($request->all(), $rules, $messages);
|
$validator = Validator::make($request->all(), $rules, $messages);
|
||||||
|
if (!$validator->fails()) {
|
||||||
if ($validator->fails()) {
|
\DB::transaction(function () use ($inputs, &$type) {
|
||||||
return redirect()->back()->withErrors($validator)->withInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
DB::transaction(function () use ($request) {
|
|
||||||
$new = new Ptype();
|
$new = new Ptype();
|
||||||
$new->fill($request->only(['ptype_subject', 'ptype_remarks']));
|
$new->fill($inputs);
|
||||||
$new->save();
|
if ($new->save()) {
|
||||||
|
$type = true;
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
if ($type) {
|
||||||
return redirect()->route('ptypes')->with('success', '登録しました。');
|
$request->session()->flash('success', __('データ新規作成しました。'));
|
||||||
|
return redirect()->route('ptypes');
|
||||||
|
} else {
|
||||||
|
$request->session()->flash('error', __('新規作成に失敗しました'));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$inputs['errorMsg'] = $this->__buildErrorMessasges($validator);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
return view('admin.ptypes.add', $inputs);
|
||||||
* 編集(画面/処理)
|
}
|
||||||
*/
|
|
||||||
public function edit(Request $request, $id)
|
public function edit(Request $request, $pk, $view = '')
|
||||||
{
|
{
|
||||||
// 該当データ取得
|
$ptype = Ptype::getByPk($pk);
|
||||||
$record = Ptype::find($id);
|
if (empty($pk) || empty($ptype)) {
|
||||||
if (!$record) {
|
abort('404');
|
||||||
abort(404);
|
|
||||||
}
|
}
|
||||||
|
$data = $ptype->getAttributes();
|
||||||
if ($request->isMethod('get')) {
|
$dataList = $this->getDataDropList();
|
||||||
// 編集画面表示
|
$data = array_merge($data, $dataList);
|
||||||
return view('admin.ptypes.edit', [
|
if ($request->isMethod('POST')) {
|
||||||
'isEdit' => true,
|
$type = false;
|
||||||
'record' => $record,
|
// ここを修正
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// POST時:バリデーション
|
|
||||||
$rules = [
|
$rules = [
|
||||||
'ptype_subject' => 'required|string|max:255',
|
'ptype_subject' => 'required|string|max:255',
|
||||||
'floor_sort' => 'nullable|string|max:50',
|
'ptype_sort' => 'nullable|integer',
|
||||||
|
|
||||||
'ptype_remarks' => 'nullable|string|max:255',
|
'ptype_remarks' => 'nullable|string|max:255',
|
||||||
];
|
];
|
||||||
$messages = [
|
$messages = [
|
||||||
'ptype_subject.required' => '駐輪分類名は必須です。',
|
'ptype_subject.required' => '駐輪分類名は必須です。',
|
||||||
];
|
];
|
||||||
|
|
||||||
$validator = Validator::make($request->all(), $rules, $messages);
|
$validator = Validator::make($request->all(), $rules, $messages);
|
||||||
|
$requestAll = $request->all();
|
||||||
if ($validator->fails()) {
|
$data = array_merge($data, $requestAll);
|
||||||
return redirect()->back()->withErrors($validator)->withInput();
|
if (!$validator->fails()) {
|
||||||
}
|
\DB::transaction(function () use ($data, &$type, $ptype) {
|
||||||
|
$ptype->fill($data);
|
||||||
DB::transaction(function () use ($request, $record) {
|
$ptype->save();
|
||||||
$record->fill($request->only(['ptype_subject','floor_sort', 'ptype_remarks']));
|
$type = true;
|
||||||
$record->save();
|
|
||||||
});
|
});
|
||||||
|
if ($type) {
|
||||||
return redirect()->route('ptypes')->with('success', '更新しました。');
|
$request->session()->flash('success', __('更新に成功しました'));
|
||||||
|
return redirect()->route('ptypes');
|
||||||
|
} else {
|
||||||
|
$request->session()->flash('error', __('更新に失敗しました'));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$data['errorMsg'] = $this->__buildErrorMessasges($validator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($view != '') {
|
||||||
|
return view($view, $data);
|
||||||
|
}
|
||||||
|
return view('admin.ptypes.edit', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 削除(単一/複数対応)
|
|
||||||
*/
|
|
||||||
public function delete(Request $request)
|
public function delete(Request $request)
|
||||||
{
|
{
|
||||||
$ids = [];
|
$arr_pk = $request->get('pk');
|
||||||
|
if ($arr_pk) {
|
||||||
if ($request->filled('id')) {
|
if (Ptype::deleteByPk($arr_pk)) {
|
||||||
$ids[] = (int) $request->input('id');
|
return redirect()->route('ptypes')->with('success', __("削除が完了しました。"));
|
||||||
|
} else {
|
||||||
|
return redirect()->route('ptypes')->with('error', __('削除に失敗しました。'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return redirect()->route('ptypes')->with('error', __('削除するデータを選択してください。'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_array($request->input('pk'))) {
|
|
||||||
$ids = array_merge($ids, $request->input('pk'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$ids = array_values(array_unique(array_map('intval', $ids)));
|
public function info(Request $request, $id)
|
||||||
|
{
|
||||||
if (empty($ids)) {
|
return $this->edit($request, $id, 'admin.ptypes.info');
|
||||||
return back()->with('error', '削除対象が選択されていません。');
|
|
||||||
}
|
|
||||||
|
|
||||||
Ptype::whereIn('ptype_id', $ids)->delete();
|
|
||||||
|
|
||||||
return redirect()->route('ptypes')->with('success', '削除しました。');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDataDropList()
|
public function getDataDropList()
|
||||||
|
|||||||
@ -5,91 +5,9 @@ namespace App\Http\Controllers\Admin;
|
|||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use App\Models\Park;
|
|
||||||
use Illuminate\Support\Carbon;
|
|
||||||
|
|
||||||
class RegularContractController
|
class RegularContractController
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* 利用者分類選択肢(user_categoryid 昇順)
|
|
||||||
*/
|
|
||||||
private function buildUsertypeOptions(): array
|
|
||||||
{
|
|
||||||
return DB::table('usertype as t')
|
|
||||||
->join('regular_contract as rc', 'rc.user_categoryid', '=', 't.user_categoryid')
|
|
||||||
->select('t.user_categoryid', 't.usertype_subject1', 't.usertype_subject2', 't.usertype_subject3')
|
|
||||||
->groupBy('t.user_categoryid', 't.usertype_subject1', 't.usertype_subject2', 't.usertype_subject3')
|
|
||||||
->orderBy('t.user_categoryid', 'asc')
|
|
||||||
->get()
|
|
||||||
->mapWithKeys(function ($row) {
|
|
||||||
$label = collect([
|
|
||||||
$row->usertype_subject1 ?? '',
|
|
||||||
$row->usertype_subject2 ?? '',
|
|
||||||
$row->usertype_subject3 ?? '',
|
|
||||||
])->filter(fn ($v) => $v !== '')->implode('/');
|
|
||||||
|
|
||||||
return [$row->user_categoryid => $label !== '' ? $label : (string) $row->user_categoryid];
|
|
||||||
})
|
|
||||||
->toArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
private function buildParkOptions(): array
|
|
||||||
{
|
|
||||||
return Park::query()
|
|
||||||
->join('regular_contract as rc', 'rc.park_id', '=', 'park.park_id')
|
|
||||||
->select('park.park_id', 'park.park_name')
|
|
||||||
->groupBy('park.park_id', 'park.park_name')
|
|
||||||
->orderBy('park.park_id', 'asc')
|
|
||||||
->get()
|
|
||||||
->mapWithKeys(fn ($park) => [
|
|
||||||
$park->park_id => $park->park_name ?: (string) $park->park_id,
|
|
||||||
])
|
|
||||||
->toArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* datetime-local から受け取った値を Y-m-d H:i:s へ正規化
|
|
||||||
*/
|
|
||||||
private function normalizeDateTimeInput(?string $value, bool $endOfMinute = false): ?string
|
|
||||||
{
|
|
||||||
if ($value === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
$value = trim($value);
|
|
||||||
if ($value === '') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
$value = str_replace('T', ' ', $value);
|
|
||||||
if (strlen($value) === 16) {
|
|
||||||
$value .= ':00';
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
$dt = Carbon::parse($value);
|
|
||||||
if ($endOfMinute) {
|
|
||||||
$dt = $dt->endOfMinute();
|
|
||||||
}
|
|
||||||
return $dt->format('Y-m-d H:i:s');
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 名寄フリガナ検索用:全角カナへ統一し空白除去
|
|
||||||
*/
|
|
||||||
private function normalizePhoneticKeyword(?string $value): ?string
|
|
||||||
{
|
|
||||||
if ($value === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
$value = trim((string) $value);
|
|
||||||
if ($value === '') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
$value = mb_convert_kana($value, 'KVCS');
|
|
||||||
return str_replace([' ', ' '], '', $value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 定期契約一覧
|
* 定期契約一覧
|
||||||
* - ベース表: regular_contract(rc)
|
* - ベース表: regular_contract(rc)
|
||||||
@ -98,86 +16,74 @@ class RegularContractController
|
|||||||
*/
|
*/
|
||||||
public function list(Request $request)
|
public function list(Request $request)
|
||||||
{
|
{
|
||||||
if ($request->isMethod('post')) {
|
// ===== ソート(既定: contract_id DESC)=====
|
||||||
$postParams = $request->except(['_token']);
|
$sort = $request->input('sort', 'contract_id');
|
||||||
$queryParams = $request->query();
|
$sortType = strtolower($request->input('sort_type', 'desc')) === 'asc' ? 'asc' : 'desc';
|
||||||
|
|
||||||
return redirect()->route('regularcontracts', array_merge($queryParams, $postParams));
|
|
||||||
}
|
|
||||||
|
|
||||||
$params = $request->query();
|
|
||||||
|
|
||||||
// ===== ソート(既定: contract_id ASC)=====
|
|
||||||
$sort = $params['sort'] ?? 'contract_id';
|
|
||||||
$sortType = strtolower($params['sort_type'] ?? 'asc') === 'desc' ? 'desc' : 'asc';
|
|
||||||
|
|
||||||
// ===== 絞り込み(テキスト系)=====
|
// ===== 絞り込み(テキスト系)=====
|
||||||
$contract_qr_id = trim((string) ($params['contract_qr_id'] ?? ''));
|
// フォームの name 属性と完全一致させる&既定値は空文字にして Blade が未定義にならないようにする
|
||||||
$user_id = trim((string) ($params['user_id'] ?? ''));
|
$contract_qr_id = trim((string) $request->input('contract_qr_id', ''));
|
||||||
$user_tag_serial = trim((string) ($params['user_tag_serial'] ?? ''));
|
$user_id = trim((string) $request->input('user_id', ''));
|
||||||
$park_id = trim((string) ($params['park_id'] ?? ''));
|
$park_id = trim((string) $request->input('park_id', ''));
|
||||||
$selectedParkId = trim((string) ($params['selected_park_id'] ?? ''));
|
$user_phonetic = trim((string) $request->input('user_phonetic', '')); // フリガナ
|
||||||
$user_phonetic = trim((string) ($params['user_phonetic'] ?? ''));
|
$phone = trim((string) $request->input('phone', '')); // 電話(携帯/自宅)
|
||||||
$phone = trim((string) ($params['phone'] ?? ''));
|
$email = trim((string) $request->input('email', '')); // メール
|
||||||
$email = trim((string) ($params['email'] ?? ''));
|
$usertype_name_kw = trim((string) $request->input('usertype_name', '')); // 利用者分類名
|
||||||
$user_categoryid = trim((string) ($params['user_categoryid'] ?? ''));
|
$park_name_kw = trim((string) $request->input('park_name', '')); // 駐輪場名
|
||||||
$park_name_kw = trim((string) ($params['park_name'] ?? ''));
|
|
||||||
$zone_keyword = trim((string) ($params['zone_keyword'] ?? ''));
|
|
||||||
$zone_name = trim((string) ($params['zone_name'] ?? ''));
|
|
||||||
$merge_phonetic_input = $params['merge_phonetic'] ?? '';
|
|
||||||
$merge_phonetic = trim((string) $merge_phonetic_input);
|
|
||||||
$merge_phonetic_normalized = $this->normalizePhoneticKeyword($merge_phonetic);
|
|
||||||
$has_address = $params['has_address'] ?? '';
|
|
||||||
$workRecordFilter = (string) ($params['work_record'] ?? '0');
|
|
||||||
if (!in_array($workRecordFilter, ['0', '1', '2'], true)) {
|
|
||||||
$workRecordFilter = '0';
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== 絞り込み(日付範囲)=====
|
// ===== 絞り込み(日付範囲)=====
|
||||||
$reserve_from = $params['reserve_date_from'] ?? '';
|
$reserve_from = $request->input('reserve_date_from', '');
|
||||||
$reserve_to = $params['reserve_date_to'] ?? '';
|
$reserve_to = $request->input('reserve_date_to', '');
|
||||||
$created_from = $params['contract_created_from'] ?? '';
|
$created_from = $request->input('contract_created_from', '');
|
||||||
$created_to = $params['contract_created_to'] ?? '';
|
$created_to = $request->input('contract_created_to', '');
|
||||||
$updated_from = $params['contract_updated_from'] ?? '';
|
$updated_from = $request->input('contract_updated_from', '');
|
||||||
$updated_to = $params['contract_updated_to'] ?? '';
|
$updated_to = $request->input('contract_updated_to', '');
|
||||||
$canceled_from = $params['contract_canceled_from'] ?? '';
|
$canceled_from = $request->input('contract_canceled_from', '');
|
||||||
$canceled_to = $params['contract_canceled_to'] ?? '';
|
$canceled_to = $request->input('contract_canceled_to', '');
|
||||||
$receipt_delivery_from = $params['receipt_delivery_from'] ?? '';
|
|
||||||
$receipt_delivery_to = $params['receipt_delivery_to'] ?? '';
|
|
||||||
$contract_valid_months = $params['contract_valid_months'] ?? '';
|
|
||||||
|
|
||||||
// ===== 列挙(全て/0/1)=====
|
// ===== 列挙(全て/0/1)=====
|
||||||
$contract_flag = $params['contract_flag'] ?? '';
|
$contract_flag = $request->input('contract_flag', '');
|
||||||
$contract_permission = $params['contract_permission'] ?? '';
|
$contract_permission = $request->input('contract_permission', '');
|
||||||
$tag_qr_flag = $params['tag_qr_flag'] ?? '';
|
$tag_qr_flag = $request->input('tag_qr_flag', '');
|
||||||
$updateFlagFilter = (string) ($params['update_flag'] ?? '0');
|
$update_flag = $request->input('update_flag', '');
|
||||||
if (!in_array($updateFlagFilter, ['0', '1', '2'], true)) {
|
$contract_cancel_flag = $request->input('contract_cancel_flag', '');
|
||||||
$updateFlagFilter = '0';
|
|
||||||
}
|
|
||||||
$contract_cancel_flag = $params['contract_cancel_flag'] ?? '';
|
|
||||||
|
|
||||||
// ===== クエリ(結合込み)=====
|
// ===== クエリ(結合込み)=====
|
||||||
$q = DB::table('regular_contract as rc')
|
$q = DB::table('regular_contract as rc')
|
||||||
->leftJoin('user as u', 'u.user_id', '=', 'rc.user_id')
|
->leftJoin('user as u', 'u.user_id', '=', 'rc.user_id')
|
||||||
->leftJoin('usertype as t', 't.user_categoryid', '=', 'rc.user_categoryid')
|
->leftJoin('usertype as t', 't.user_categoryid', '=', 'rc.user_categoryid')
|
||||||
->leftJoin('park as p', 'p.park_id', '=', 'rc.park_id')
|
->leftJoin('park as p', 'p.park_id', '=', 'rc.park_id')
|
||||||
->leftJoin('zone as z', 'z.zone_id', '=', 'rc.zone_id')
|
|
||||||
->select([
|
->select([
|
||||||
'rc.*',
|
// rc
|
||||||
'u.user_seq',
|
'rc.contract_id',
|
||||||
|
'rc.contract_qr_id',
|
||||||
|
'rc.user_id',
|
||||||
|
'rc.user_categoryid',
|
||||||
|
'rc.reserve_id',
|
||||||
|
'rc.park_id',
|
||||||
|
'rc.price_parkplaceid',
|
||||||
|
'rc.user_securitynum',
|
||||||
|
'rc.reserve_date',
|
||||||
|
'rc.contract_reserve',
|
||||||
|
'rc.contract_created_at',
|
||||||
|
'rc.contract_updated_at',
|
||||||
|
'rc.contract_cancelday',
|
||||||
|
'rc.contract_flag',
|
||||||
|
'rc.contract_permission',
|
||||||
|
'rc.contract_cancel_flag',
|
||||||
|
'rc.tag_qr_flag',
|
||||||
|
'rc.update_flag',
|
||||||
|
'rc.park_position',
|
||||||
|
'rc.ope_id',
|
||||||
|
// user
|
||||||
'u.user_name',
|
'u.user_name',
|
||||||
'u.user_phonetic',
|
'u.user_phonetic',
|
||||||
'u.user_mobile',
|
'u.user_mobile',
|
||||||
'u.user_homephone',
|
'u.user_homephone',
|
||||||
'u.user_primemail',
|
'u.user_primemail',
|
||||||
'u.user_regident_zip',
|
// usertype & park
|
||||||
'u.user_tag_serial',
|
|
||||||
DB::raw('t.print_name as usertype_name'),
|
DB::raw('t.print_name as usertype_name'),
|
||||||
't.usertype_subject1',
|
|
||||||
't.usertype_subject2',
|
|
||||||
't.usertype_subject3',
|
|
||||||
DB::raw('p.park_name as park_name'),
|
DB::raw('p.park_name as park_name'),
|
||||||
DB::raw('z.zone_name as zone_name'),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// ===== LIKE / キーワード =====
|
// ===== LIKE / キーワード =====
|
||||||
@ -187,13 +93,8 @@ class RegularContractController
|
|||||||
if ($user_id !== '') {
|
if ($user_id !== '') {
|
||||||
$q->where('rc.user_id', 'like', "%{$user_id}%");
|
$q->where('rc.user_id', 'like', "%{$user_id}%");
|
||||||
}
|
}
|
||||||
if ($user_tag_serial !== '') {
|
|
||||||
$q->where('u.user_tag_serial', 'like', "%{$user_tag_serial}%");
|
|
||||||
}
|
|
||||||
if ($park_id !== '') {
|
if ($park_id !== '') {
|
||||||
$q->where('rc.park_id', (int) $park_id);
|
$q->where('rc.park_id', 'like', "%{$park_id}%");
|
||||||
} elseif ($selectedParkId !== '') {
|
|
||||||
$q->where('rc.park_id', (int) $selectedParkId);
|
|
||||||
}
|
}
|
||||||
if ($user_phonetic !== '') {
|
if ($user_phonetic !== '') {
|
||||||
$q->where('u.user_phonetic', 'like', "%{$user_phonetic}%");
|
$q->where('u.user_phonetic', 'like', "%{$user_phonetic}%");
|
||||||
@ -201,73 +102,46 @@ class RegularContractController
|
|||||||
if ($email !== '') {
|
if ($email !== '') {
|
||||||
$q->where('u.user_primemail', 'like', "%{$email}%");
|
$q->where('u.user_primemail', 'like', "%{$email}%");
|
||||||
}
|
}
|
||||||
if ($user_categoryid !== '') {
|
if ($usertype_name_kw !== '') {
|
||||||
$q->where('rc.user_categoryid', (int) $user_categoryid);
|
$q->where('t.print_name', 'like', "%{$usertype_name_kw}%");
|
||||||
}
|
}
|
||||||
if ($park_name_kw !== '') {
|
if ($park_name_kw !== '') {
|
||||||
$q->where('p.park_name', 'like', "%{$park_name_kw}%");
|
$q->where('p.park_name', 'like', "%{$park_name_kw}%");
|
||||||
}
|
}
|
||||||
if ($zone_name !== '') {
|
|
||||||
$q->where('z.zone_name', 'like', "%{$zone_name}%");
|
|
||||||
}
|
|
||||||
if ($merge_phonetic_normalized !== null) {
|
|
||||||
$likeKeyword = '%' . $merge_phonetic_normalized . '%';
|
|
||||||
$q->whereRaw("REPLACE(REPLACE(IFNULL(rc.chk_user_phonetic, ''), ' ', ''), ' ', '') LIKE ?", [$likeKeyword]);
|
|
||||||
}
|
|
||||||
if ($phone !== '') {
|
if ($phone !== '') {
|
||||||
$q->where(function ($w) use ($phone) {
|
$q->where(function ($w) use ($phone) {
|
||||||
$w->where('u.user_mobile', 'like', "%{$phone}%")
|
$w->where('u.user_mobile', 'like', "%{$phone}%")
|
||||||
->orWhere('u.user_homephone', 'like', "%{$phone}%");
|
->orWhere('u.user_homephone', 'like', "%{$phone}%");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if ($reserve_from !== '' && ($normalized = $this->normalizeDateTimeInput($reserve_from))) {
|
|
||||||
$q->where('rc.reserve_date', '>=', $normalized);
|
// ===== 日付範囲 =====
|
||||||
|
if ($reserve_from) {
|
||||||
|
$q->whereDate('rc.reserve_date', '>=', $reserve_from);
|
||||||
}
|
}
|
||||||
if ($reserve_to !== '' && ($normalized = $this->normalizeDateTimeInput($reserve_to, true))) {
|
if ($reserve_to) {
|
||||||
$q->where('rc.reserve_date', '<=', $normalized);
|
$q->whereDate('rc.reserve_date', '<=', $reserve_to);
|
||||||
}
|
}
|
||||||
if ($receipt_delivery_from !== '' && ($normalized = $this->normalizeDateTimeInput($receipt_delivery_from))) {
|
if ($created_from) {
|
||||||
$q->where('rc.contract_payment_day', '>=', $normalized);
|
$q->whereDate('rc.contract_created_at', '>=', $created_from);
|
||||||
}
|
}
|
||||||
if ($receipt_delivery_to !== '' && ($normalized = $this->normalizeDateTimeInput($receipt_delivery_to, true))) {
|
if ($created_to) {
|
||||||
$q->where('rc.contract_payment_day', '<=', $normalized);
|
$q->whereDate('rc.contract_created_at', '<=', $created_to);
|
||||||
}
|
}
|
||||||
if ($zone_keyword !== '') {
|
if ($updated_from) {
|
||||||
$q->where(function ($w) use ($zone_keyword) {
|
$q->whereDate('rc.contract_updated_at', '>=', $updated_from);
|
||||||
$w->where('rc.zone_id', 'like', "%{$zone_keyword}%")
|
|
||||||
->orWhere('rc.pplace_no', 'like', "%{$zone_keyword}%")
|
|
||||||
->orWhere('rc.old_contract_id', 'like', "%{$zone_keyword}%");
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if ($workRecordFilter === '1') {
|
if ($updated_to) {
|
||||||
$q->where(function ($w) {
|
$q->whereDate('rc.contract_updated_at', '<=', $updated_to);
|
||||||
$w->whereNull('rc.contract_flag')
|
|
||||||
->orWhere('rc.contract_flag', '=', 0);
|
|
||||||
});
|
|
||||||
} elseif ($workRecordFilter === '2') {
|
|
||||||
$q->where('rc.contract_flag', '=', 1);
|
|
||||||
}
|
}
|
||||||
if ($created_from !== '' && ($normalized = $this->normalizeDateTimeInput($created_from))) {
|
if ($canceled_from) {
|
||||||
$q->where('rc.contract_created_at', '>=', $normalized);
|
$q->whereDate('rc.contract_cancelday', '>=', $canceled_from);
|
||||||
}
|
}
|
||||||
if ($created_to !== '' && ($normalized = $this->normalizeDateTimeInput($created_to, true))) {
|
if ($canceled_to) {
|
||||||
$q->where('rc.contract_created_at', '<=', $normalized);
|
$q->whereDate('rc.contract_cancelday', '<=', $canceled_to);
|
||||||
}
|
|
||||||
if ($updated_from !== '' && ($normalized = $this->normalizeDateTimeInput($updated_from))) {
|
|
||||||
$q->where('rc.contract_updated_at', '>=', $normalized);
|
|
||||||
}
|
|
||||||
if ($updated_to !== '' && ($normalized = $this->normalizeDateTimeInput($updated_to, true))) {
|
|
||||||
$q->where('rc.contract_updated_at', '<=', $normalized);
|
|
||||||
}
|
|
||||||
if ($canceled_from !== '' && ($normalized = $this->normalizeDateTimeInput($canceled_from))) {
|
|
||||||
$q->where('rc.contract_cancelday', '>=', $normalized);
|
|
||||||
}
|
|
||||||
if ($canceled_to !== '' && ($normalized = $this->normalizeDateTimeInput($canceled_to, true))) {
|
|
||||||
$q->where('rc.contract_cancelday', '<=', $normalized);
|
|
||||||
}
|
|
||||||
if ($contract_valid_months !== '') {
|
|
||||||
$q->where('rc.enable_months', (int) $contract_valid_months);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===== 列挙フィルタ =====
|
||||||
if ($contract_flag !== '') {
|
if ($contract_flag !== '') {
|
||||||
$q->where('rc.contract_flag', (int) $contract_flag);
|
$q->where('rc.contract_flag', (int) $contract_flag);
|
||||||
}
|
}
|
||||||
@ -277,13 +151,8 @@ class RegularContractController
|
|||||||
if ($tag_qr_flag !== '') {
|
if ($tag_qr_flag !== '') {
|
||||||
$q->where('rc.tag_qr_flag', (int) $tag_qr_flag);
|
$q->where('rc.tag_qr_flag', (int) $tag_qr_flag);
|
||||||
}
|
}
|
||||||
if ($updateFlagFilter === '1') {
|
if ($update_flag !== '') {
|
||||||
$q->where('rc.update_flag', '=', 1);
|
$q->where('rc.update_flag', (int) $update_flag);
|
||||||
} elseif ($updateFlagFilter === '2') {
|
|
||||||
$q->where(function ($w) {
|
|
||||||
$w->whereNull('rc.update_flag')
|
|
||||||
->orWhere('rc.update_flag', '!=', 1);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if ($contract_cancel_flag !== '') {
|
if ($contract_cancel_flag !== '') {
|
||||||
$q->where('rc.contract_cancel_flag', (int) $contract_cancel_flag);
|
$q->where('rc.contract_cancel_flag', (int) $contract_cancel_flag);
|
||||||
@ -291,16 +160,34 @@ class RegularContractController
|
|||||||
|
|
||||||
// ===== ソート(仮想列は結合側にマッピング)=====
|
// ===== ソート(仮想列は結合側にマッピング)=====
|
||||||
$sortable = [
|
$sortable = [
|
||||||
'contract_id', 'contract_qr_id', 'old_contract_id', 'zone_id', 'zone_name', 'pplace_no',
|
'contract_id',
|
||||||
'contract_periods', 'contract_periode', 'user_id', 'user_categoryid', 'reserve_id', 'park_id',
|
'contract_qr_id',
|
||||||
'price_parkplaceid', 'user_securitynum', 'reserve_date', 'contract_reserve', 'contract_created_at',
|
'user_id',
|
||||||
'contract_updated_at', 'contract_cancelday', 'contract_reduction', 'enable_months', 'printable_date',
|
'user_categoryid',
|
||||||
'billing_amount', 'contract_payment_day', 'contract_money', 'refunds', 'contract_flag',
|
'reserve_id',
|
||||||
'contract_permission', 'contract_cancel_flag', 'tag_qr_flag', 'update_flag', 'pplace_allocation_flag',
|
'park_id',
|
||||||
'settlement_transaction_id', 'contract_seal_issue', 'storage_company_code', 'share_storage_company_code',
|
'price_parkplaceid',
|
||||||
'ope_id', 'park_position', 'contract_manual', 'contract_notice', 'contract_payment_number',
|
'user_securitynum',
|
||||||
'user_name', 'user_phonetic', 'user_mobile', 'user_homephone', 'user_primemail', 'user_regident_zip',
|
'reserve_date',
|
||||||
'usertype_name', 'park_name',
|
'contract_reserve',
|
||||||
|
'contract_created_at',
|
||||||
|
'contract_updated_at',
|
||||||
|
'contract_cancelday',
|
||||||
|
'contract_flag',
|
||||||
|
'contract_permission',
|
||||||
|
'contract_cancel_flag',
|
||||||
|
'tag_qr_flag',
|
||||||
|
'update_flag',
|
||||||
|
'park_position',
|
||||||
|
'ope_id',
|
||||||
|
// 結合先の見出し列
|
||||||
|
'user_name',
|
||||||
|
'user_phonetic',
|
||||||
|
'user_mobile',
|
||||||
|
'user_homephone',
|
||||||
|
'user_primemail',
|
||||||
|
'usertype_name',
|
||||||
|
'park_name',
|
||||||
];
|
];
|
||||||
if (!in_array($sort, $sortable, true)) {
|
if (!in_array($sort, $sortable, true)) {
|
||||||
$sort = 'contract_id';
|
$sort = 'contract_id';
|
||||||
@ -311,14 +198,12 @@ class RegularContractController
|
|||||||
'user_mobile' => 'u.user_mobile',
|
'user_mobile' => 'u.user_mobile',
|
||||||
'user_homephone' => 'u.user_homephone',
|
'user_homephone' => 'u.user_homephone',
|
||||||
'user_primemail' => 'u.user_primemail',
|
'user_primemail' => 'u.user_primemail',
|
||||||
'user_regident_zip' => 'u.user_regident_zip',
|
|
||||||
'usertype_name' => 't.print_name',
|
'usertype_name' => 't.print_name',
|
||||||
'park_name' => 'p.park_name',
|
'park_name' => 'p.park_name',
|
||||||
'zone_name' => 'z.zone_name',
|
|
||||||
];
|
];
|
||||||
$sortColumn = $sortMap[$sort] ?? ('rc.' . $sort);
|
$sortColumn = $sortMap[$sort] ?? ('rc.' . $sort);
|
||||||
|
|
||||||
$list = $q->orderBy($sortColumn, $sortType)->paginate(50)->withQueryString();
|
$list = $q->orderBy($sortColumn, $sortType)->paginate(50);
|
||||||
|
|
||||||
// ===== 画面へ(Blade 側が参照するすべての変数を渡す)=====
|
// ===== 画面へ(Blade 側が参照するすべての変数を渡す)=====
|
||||||
return view('admin.regularcontracts.list', [
|
return view('admin.regularcontracts.list', [
|
||||||
@ -329,18 +214,12 @@ class RegularContractController
|
|||||||
// 入力保持(テキスト)
|
// 入力保持(テキスト)
|
||||||
'contract_qr_id' => $contract_qr_id,
|
'contract_qr_id' => $contract_qr_id,
|
||||||
'user_id' => $user_id,
|
'user_id' => $user_id,
|
||||||
'user_tag_serial' => $user_tag_serial,
|
'park_id' => $park_id,
|
||||||
'park_id' => $selectedParkId !== '' ? $selectedParkId : $park_id,
|
|
||||||
'user_phonetic' => $user_phonetic,
|
'user_phonetic' => $user_phonetic,
|
||||||
'phone' => $phone,
|
'phone' => $phone,
|
||||||
'email' => $email,
|
'email' => $email,
|
||||||
'user_categoryid' => $user_categoryid,
|
'usertype_name' => $usertype_name_kw,
|
||||||
'park_name' => $park_name_kw,
|
'park_name' => $park_name_kw,
|
||||||
'zone_keyword' => $zone_keyword,
|
|
||||||
'zone_name' => $zone_name,
|
|
||||||
'merge_phonetic' => $merge_phonetic,
|
|
||||||
'has_address' => $has_address,
|
|
||||||
'work_record' => $workRecordFilter,
|
|
||||||
|
|
||||||
// 入力保持(日付)
|
// 入力保持(日付)
|
||||||
'reserve_date_from' => $reserve_from,
|
'reserve_date_from' => $reserve_from,
|
||||||
@ -351,19 +230,13 @@ class RegularContractController
|
|||||||
'contract_updated_to' => $updated_to,
|
'contract_updated_to' => $updated_to,
|
||||||
'contract_canceled_from' => $canceled_from,
|
'contract_canceled_from' => $canceled_from,
|
||||||
'contract_canceled_to' => $canceled_to,
|
'contract_canceled_to' => $canceled_to,
|
||||||
'receipt_delivery_from' => $receipt_delivery_from,
|
|
||||||
'receipt_delivery_to' => $receipt_delivery_to,
|
|
||||||
'contract_valid_months' => $contract_valid_months,
|
|
||||||
|
|
||||||
// 入力保持(列挙)
|
// 入力保持(列挙)
|
||||||
'contract_flag' => $contract_flag,
|
'contract_flag' => $contract_flag,
|
||||||
'contract_permission' => $contract_permission,
|
'contract_permission' => $contract_permission,
|
||||||
'tag_qr_flag' => $tag_qr_flag,
|
'tag_qr_flag' => $tag_qr_flag,
|
||||||
'update_flag' => $updateFlagFilter,
|
'update_flag' => $update_flag,
|
||||||
'contract_cancel_flag' => $contract_cancel_flag,
|
'contract_cancel_flag' => $contract_cancel_flag,
|
||||||
|
|
||||||
'userTypeOptions' => $this->buildUsertypeOptions(),
|
|
||||||
'parkOptions' => $this->buildParkOptions(),
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,23 +318,15 @@ class RegularContractController
|
|||||||
*/
|
*/
|
||||||
public function delete(Request $request)
|
public function delete(Request $request)
|
||||||
{
|
{
|
||||||
$ids = $request->input('ids', []);
|
$id = (int) $request->input('id');
|
||||||
if (!is_array($ids)) {
|
DB::table('regular_contract')->where('contract_id', $id)->delete();
|
||||||
$ids = [$ids];
|
|
||||||
}
|
|
||||||
$ids = array_values(array_filter(
|
|
||||||
array_map('intval', $ids),
|
|
||||||
static fn (int $v) => $v > 0
|
|
||||||
));
|
|
||||||
|
|
||||||
if (empty($ids)) {
|
// 例:論理削除運用にする場合(必要なら運用側で切替)
|
||||||
return redirect()->route('regularcontracts')
|
// DB::table('regular_contract')->where('contract_id', $id)->update([
|
||||||
->with('error', '削除する定期契約が選択されていません。');
|
// 'contract_cancel_flag' => 1,
|
||||||
}
|
// 'contract_cancelday' => now(),
|
||||||
|
// 'updated_at' => now(),
|
||||||
DB::table('regular_contract')
|
// ]);
|
||||||
->whereIn('contract_id', $ids)
|
|
||||||
->delete();
|
|
||||||
|
|
||||||
return redirect()->route('regularcontracts')->with('success', '定期契約を削除しました。');
|
return redirect()->route('regularcontracts')->with('success', '定期契約を削除しました。');
|
||||||
}
|
}
|
||||||
@ -501,115 +366,70 @@ class RegularContractController
|
|||||||
|
|
||||||
public function export(Request $request)
|
public function export(Request $request)
|
||||||
{
|
{
|
||||||
$params = $request->all();
|
// ── 出力タイプ(通常 / SMBC / 役所) ──────────────────────────────
|
||||||
$sort = $params['sort'] ?? 'contract_id';
|
$type = $request->query('type'); // null | smbc | city
|
||||||
$sortType = strtolower($params['sort_type'] ?? 'asc') === 'desc' ? 'desc' : 'asc';
|
|
||||||
$type = (string) ($request->query('type') ?? '');
|
|
||||||
|
|
||||||
$fileName = match ($type) {
|
// ── 出力ファイル名 ───────────────────────────────────────────────
|
||||||
'smbc' => '定期契約マスタ_SMBC.csv',
|
$downloadName = '定期契約マスタ.csv';
|
||||||
'city' => '定期契約マスタ_役所提出用.csv',
|
if ($type === 'smbc')
|
||||||
default => '定期契約マスタ.csv',
|
$downloadName = '定期契約マスタ_SMBC.csv';
|
||||||
};
|
if ($type === 'city')
|
||||||
|
$downloadName = '定期契約マスタ_役所提出用.csv';
|
||||||
|
|
||||||
$query = $this->buildListQuery($params);
|
// ── 生成先(storage/app/tmp 配下の一時ファイル) ─────────────────
|
||||||
|
$tmpDir = storage_path('app/tmp');
|
||||||
$columns = [
|
if (!is_dir($tmpDir)) {
|
||||||
'contract_id' => '契約ID',
|
@mkdir($tmpDir, 0755, true);
|
||||||
'contract_qr_id' => '定期契約ID',
|
|
||||||
'old_contract_id' => '旧定期契約番号',
|
|
||||||
'pplace_no' => '車室番号',
|
|
||||||
'user_id' => '利用者ID',
|
|
||||||
'user_categoryid' => '利用者分類ID',
|
|
||||||
'tag_qr_flag' => 'タグ・QR',
|
|
||||||
'park_id' => '駐輪場ID',
|
|
||||||
'reserve_date' => '予約日時',
|
|
||||||
'contract_periods' => '有効期間S',
|
|
||||||
'contract_periode' => '有効期間E',
|
|
||||||
'price_parkplaceid' => '駐輪場所ID',
|
|
||||||
'user_securitynum' => '防犯登録番号',
|
|
||||||
'contract_created_at' => '契約日時',
|
|
||||||
'contract_updated_at' => '更新可能日',
|
|
||||||
'contract_cancelday' => '解約日時',
|
|
||||||
'contract_reduction' => '減免措置',
|
|
||||||
'enable_months' => '定期有効月数',
|
|
||||||
'printable_date' => 'シール印刷可能日',
|
|
||||||
'billing_amount' => '請求金額',
|
|
||||||
'pplace_allocation_flag' => '車室割り当てフラグ',
|
|
||||||
'contract_payment_day' => '授受日時',
|
|
||||||
'contract_money' => '授受金額',
|
|
||||||
'contract_flag' => '授受フラグ',
|
|
||||||
'settlement_transaction_id' => '決済トランザクションID',
|
|
||||||
'contract_seal_issue' => 'シール発行数',
|
|
||||||
'storage_company_code' => '収納企業コード',
|
|
||||||
'share_storage_company_code' => '共有先収納企業コード',
|
|
||||||
'accept_number' => '受付番号',
|
|
||||||
'update_flag' => '(更新元)契約更新済フラグ',
|
|
||||||
'vehicle_type_id' => '車種区分ID',
|
|
||||||
'chk_user_phonetic' => 'チェック用_フリガナ',
|
|
||||||
'user_regident_zip' => 'チェック用_居住所郵便番号',
|
|
||||||
'user_mobile' => 'チェック用_携帯電話番号',
|
|
||||||
'user_homephone' => 'チェック用_自宅電話番号',
|
|
||||||
'old_member_number' => 'チェック用_旧会員番号',
|
|
||||||
'user_name' => '利用者氏名',
|
|
||||||
'user_phonetic' => '利用者フリガナ',
|
|
||||||
'park_name' => '駐輪場名',
|
|
||||||
'zone_name' => 'ゾーン名',
|
|
||||||
'usertype_name' => '利用者分類名',
|
|
||||||
];
|
|
||||||
|
|
||||||
$dateColumns = [
|
|
||||||
'contract_periods',
|
|
||||||
'contract_periode',
|
|
||||||
'contract_created_at',
|
|
||||||
'contract_updated_at',
|
|
||||||
'contract_cancelday',
|
|
||||||
'printable_date',
|
|
||||||
'contract_payment_day',
|
|
||||||
'reserve_date',
|
|
||||||
];
|
|
||||||
|
|
||||||
$rows = $query->orderBy($sort, $sortType)->get();
|
|
||||||
|
|
||||||
$headers = [
|
|
||||||
'Content-Type' => 'text/csv; charset=Shift_JIS',
|
|
||||||
'Content-Disposition' => "attachment; filename=\"{$fileName}\"",
|
|
||||||
];
|
|
||||||
|
|
||||||
return response()->streamDownload(function () use ($rows, $columns, $dateColumns) {
|
|
||||||
$handle = fopen('php://output', 'w');
|
|
||||||
|
|
||||||
$headerRow = array_map(fn ($label) => mb_convert_encoding($label, 'SJIS-win', 'UTF-8'), array_values($columns));
|
|
||||||
fputcsv($handle, $headerRow);
|
|
||||||
|
|
||||||
foreach ($rows as $row) {
|
|
||||||
$line = [];
|
|
||||||
foreach ($columns as $key => $label) {
|
|
||||||
$value = $row->{$key} ?? '';
|
|
||||||
|
|
||||||
if (in_array($key, $dateColumns, true) && $value) {
|
|
||||||
try {
|
|
||||||
$value = \Illuminate\Support\Carbon::parse($value)->format(str_contains($key, '_day') || str_contains($key, '_date') ? 'Y-m-d H:i' : 'Y-m-d');
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
$value = (string) $value;
|
|
||||||
}
|
|
||||||
} elseif ($key === 'tag_qr_flag' && $value !== '') {
|
|
||||||
$value = ((int) $value) === 1 ? 'QR' : 'タグ';
|
|
||||||
} elseif ($key === 'pplace_allocation_flag' && $value !== '') {
|
|
||||||
$value = ((int) $value) === 1 ? '割当済' : '未割当';
|
|
||||||
} elseif ($key === 'contract_flag' && $value !== '') {
|
|
||||||
$value = ((int) $value) === 1 ? '済' : '未';
|
|
||||||
} elseif ($key === 'update_flag' && $value !== '') {
|
|
||||||
$value = ((int) $value) === 1 ? '更新済' : '未更新';
|
|
||||||
}
|
}
|
||||||
|
$tmpPath = $tmpDir . '/' . uniqid('regularcontracts_', true) . '.csv';
|
||||||
|
|
||||||
$line[] = mb_convert_encoding((string) $value, 'SJIS-win', 'UTF-8');
|
// ── CSV を作成(Excel を考慮し UTF-8 BOM を付与) ───────────────
|
||||||
}
|
$fp = fopen($tmpPath, 'w+');
|
||||||
fputcsv($handle, $line);
|
if ($fp === false) {
|
||||||
|
abort(500, 'CSV一時ファイルを作成できませんでした。');
|
||||||
}
|
}
|
||||||
|
// Excel 対策:BOM
|
||||||
|
fwrite($fp, "\xEF\xBB\xBF");
|
||||||
|
|
||||||
fclose($handle);
|
// ヘッダー行(必要に応じて列を増減)
|
||||||
}, $fileName, $headers);
|
fputcsv($fp, ['定期契約ID', '利用者ID', '駐輪場ID', '契約日時']);
|
||||||
|
|
||||||
|
// ── データ取得(大量件数に備え chunk で分割取得) ────────────────
|
||||||
|
// ※ list() と同等の JOIN/SELECT を最低限に簡略化
|
||||||
|
DB::table('regular_contract as rc')
|
||||||
|
->leftJoin('user as u', 'u.user_id', '=', 'rc.user_id')
|
||||||
|
->orderBy('rc.contract_id', 'asc')
|
||||||
|
->select([
|
||||||
|
'rc.contract_qr_id',
|
||||||
|
'rc.user_id',
|
||||||
|
'rc.park_id',
|
||||||
|
'rc.contract_created_at',
|
||||||
|
])
|
||||||
|
->chunk(1000, function ($rows) use ($fp) {
|
||||||
|
foreach ($rows as $r) {
|
||||||
|
fputcsv($fp, [
|
||||||
|
$r->contract_qr_id,
|
||||||
|
$r->user_id,
|
||||||
|
$r->park_id,
|
||||||
|
$r->contract_created_at,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
fclose($fp);
|
||||||
|
|
||||||
|
// ── ダウンロードレスポンス(送信後に一時ファイル削除) ────────────
|
||||||
|
return response()->download(
|
||||||
|
$tmpPath,
|
||||||
|
$downloadName,
|
||||||
|
[
|
||||||
|
'Content-Type' => 'text/csv; charset=UTF-8',
|
||||||
|
'Content-Disposition' => 'attachment; filename="' . $downloadName . '"',
|
||||||
|
'Pragma' => 'no-cache',
|
||||||
|
'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0',
|
||||||
|
'Expires' => '0',
|
||||||
|
]
|
||||||
|
)->deleteFileAfterSend(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -703,178 +523,6 @@ class RegularContractController
|
|||||||
->with('success', '定期契約を登録しました。');
|
->with('success', '定期契約を登録しました。');
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buildListQuery(array $params)
|
|
||||||
{
|
|
||||||
$contract_qr_id = trim((string)($params['contract_qr_id'] ?? ''));
|
|
||||||
$user_id = trim((string)($params['user_id'] ?? ''));
|
|
||||||
$user_tag_serial = trim((string)($params['user_tag_serial'] ?? ''));
|
|
||||||
$park_id = trim((string)($params['park_id'] ?? ''));
|
|
||||||
$selectedParkId = trim((string)($params['selected_park_id'] ?? ''));
|
|
||||||
$user_phonetic = trim((string)($params['user_phonetic'] ?? ''));
|
|
||||||
$phone = trim((string)($params['phone'] ?? ''));
|
|
||||||
$email = trim((string)($params['email'] ?? ''));
|
|
||||||
$user_categoryid = trim((string)($params['user_categoryid'] ?? ''));
|
|
||||||
$park_name_kw = trim((string)($params['park_name'] ?? ''));
|
|
||||||
$zone_keyword = trim((string)($params['zone_keyword'] ?? ''));
|
|
||||||
$zone_name = trim((string)($params['zone_name'] ?? ''));
|
|
||||||
$merge_phonetic_input = $params['merge_phonetic'] ?? '';
|
|
||||||
$merge_phonetic = trim((string)$merge_phonetic_input);
|
|
||||||
$merge_phonetic_normalized = $this->normalizePhoneticKeyword($merge_phonetic);
|
|
||||||
$workRecordFilter = (string)($params['work_record'] ?? '0');
|
|
||||||
if (!in_array($workRecordFilter, ['0', '1', '2'], true)) {
|
|
||||||
$workRecordFilter = '0';
|
|
||||||
}
|
|
||||||
$reserve_from = $params['reserve_date_from'] ?? '';
|
|
||||||
$reserve_to = $params['reserve_date_to'] ?? '';
|
|
||||||
$created_from = $params['contract_created_from'] ?? '';
|
|
||||||
$created_to = $params['contract_created_to'] ?? '';
|
|
||||||
$updated_from = $params['contract_updated_from'] ?? '';
|
|
||||||
$updated_to = $params['contract_updated_to'] ?? '';
|
|
||||||
$canceled_from = $params['contract_canceled_from'] ?? '';
|
|
||||||
$canceled_to = $params['contract_canceled_to'] ?? '';
|
|
||||||
$receipt_delivery_from = $params['receipt_delivery_from'] ?? '';
|
|
||||||
$receipt_delivery_to = $params['receipt_delivery_to'] ?? '';
|
|
||||||
$contract_valid_months = $params['contract_valid_months'] ?? '';
|
|
||||||
$contract_flag = $params['contract_flag'] ?? '';
|
|
||||||
$contract_permission = $params['contract_permission'] ?? '';
|
|
||||||
$tag_qr_flag = $params['tag_qr_flag'] ?? '';
|
|
||||||
$updateFlagFilter = (string)($params['update_flag'] ?? '0');
|
|
||||||
if (!in_array($updateFlagFilter, ['0', '1', '2'], true)) {
|
|
||||||
$updateFlagFilter = '0';
|
|
||||||
}
|
|
||||||
$contract_cancel_flag = $params['contract_cancel_flag'] ?? '';
|
|
||||||
|
|
||||||
$q = DB::table('regular_contract as rc')
|
|
||||||
->leftJoin('user as u', 'u.user_id', '=', 'rc.user_id')
|
|
||||||
->leftJoin('usertype as t', 't.user_categoryid', '=', 'rc.user_categoryid')
|
|
||||||
->leftJoin('park as p', 'p.park_id', '=', 'rc.park_id')
|
|
||||||
->leftJoin('zone as z', 'z.zone_id', '=', 'rc.zone_id')
|
|
||||||
->select([
|
|
||||||
'rc.*',
|
|
||||||
'u.user_seq',
|
|
||||||
'u.user_name',
|
|
||||||
'u.user_phonetic',
|
|
||||||
'u.user_mobile',
|
|
||||||
'u.user_homephone',
|
|
||||||
'u.user_primemail',
|
|
||||||
'u.user_regident_zip',
|
|
||||||
'u.user_tag_serial',
|
|
||||||
DB::raw('t.print_name as usertype_name'),
|
|
||||||
't.usertype_subject1',
|
|
||||||
't.usertype_subject2',
|
|
||||||
't.usertype_subject3',
|
|
||||||
DB::raw('p.park_name as park_name'),
|
|
||||||
DB::raw('z.zone_name as zone_name'),
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($contract_qr_id !== '') {
|
|
||||||
$q->where('rc.contract_qr_id', 'like', "%{$contract_qr_id}%");
|
|
||||||
}
|
|
||||||
if ($user_id !== '') {
|
|
||||||
$q->where('rc.user_id', 'like', "%{$user_id}%");
|
|
||||||
}
|
|
||||||
if ($user_tag_serial !== '') {
|
|
||||||
$q->where('u.user_tag_serial', 'like', "%{$user_tag_serial}%");
|
|
||||||
}
|
|
||||||
if ($park_id !== '') {
|
|
||||||
$q->where('rc.park_id', (int)$park_id);
|
|
||||||
} elseif ($selectedParkId !== '') {
|
|
||||||
$q->where('rc.park_id', (int)$selectedParkId);
|
|
||||||
}
|
|
||||||
if ($user_phonetic !== '') {
|
|
||||||
$q->where('u.user_phonetic', 'like', "%{$user_phonetic}%");
|
|
||||||
}
|
|
||||||
if ($email !== '') {
|
|
||||||
$q->where('u.user_primemail', 'like', "%{$email}%");
|
|
||||||
}
|
|
||||||
if ($user_categoryid !== '') {
|
|
||||||
$q->where('rc.user_categoryid', (int)$user_categoryid);
|
|
||||||
}
|
|
||||||
if ($park_name_kw !== '') {
|
|
||||||
$q->where('p.park_name', 'like', "%{$park_name_kw}%");
|
|
||||||
}
|
|
||||||
if ($zone_name !== '') {
|
|
||||||
$q->where('z.zone_name', 'like', "%{$zone_name}%");
|
|
||||||
}
|
|
||||||
if ($merge_phonetic_normalized !== null) {
|
|
||||||
$likeKeyword = '%' . $merge_phonetic_normalized . '%';
|
|
||||||
$q->whereRaw("REPLACE(REPLACE(IFNULL(rc.chk_user_phonetic, ''), ' ', ''), ' ', '') LIKE ?", [$likeKeyword]);
|
|
||||||
}
|
|
||||||
if ($phone !== '') {
|
|
||||||
$q->where(function ($w) use ($phone) {
|
|
||||||
$w->where('u.user_mobile', 'like', "%{$phone}%")
|
|
||||||
->orWhere('u.user_homephone', 'like', "%{$phone}%");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if ($reserve_from !== '' && ($normalized = $this->normalizeDateTimeInput($reserve_from))) {
|
|
||||||
$q->where('rc.reserve_date', '>=', $normalized);
|
|
||||||
}
|
|
||||||
if ($reserve_to !== '' && ($normalized = $this->normalizeDateTimeInput($reserve_to, true))) {
|
|
||||||
$q->where('rc.reserve_date', '<=', $normalized);
|
|
||||||
}
|
|
||||||
if ($receipt_delivery_from !== '' && ($normalized = $this->normalizeDateTimeInput($receipt_delivery_from))) {
|
|
||||||
$q->where('rc.contract_payment_day', '>=', $normalized);
|
|
||||||
}
|
|
||||||
if ($receipt_delivery_to !== '' && ($normalized = $this->normalizeDateTimeInput($receipt_delivery_to, true))) {
|
|
||||||
$q->where('rc.contract_payment_day', '<=', $normalized);
|
|
||||||
}
|
|
||||||
if ($zone_keyword !== '') {
|
|
||||||
$q->where(function ($w) use ($zone_keyword) {
|
|
||||||
$w->where('rc.zone_id', 'like', "%{$zone_keyword}%")
|
|
||||||
->orWhere('rc.pplace_no', 'like', "%{$zone_keyword}%")
|
|
||||||
->orWhere('rc.old_contract_id', 'like', "%{$zone_keyword}%");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if ($workRecordFilter === '1') {
|
|
||||||
$q->where(function ($w) {
|
|
||||||
$w->whereNull('rc.contract_flag')
|
|
||||||
->orWhere('rc.contract_flag', '=', 0);
|
|
||||||
});
|
|
||||||
} elseif ($workRecordFilter === '2') {
|
|
||||||
$q->where('rc.contract_flag', '=', 1);
|
|
||||||
}
|
|
||||||
if ($created_from !== '' && ($normalized = $this->normalizeDateTimeInput($created_from))) {
|
|
||||||
$q->where('rc.contract_created_at', '>=', $normalized);
|
|
||||||
}
|
|
||||||
if ($created_to !== '' && ($normalized = $this->normalizeDateTimeInput($created_to, true))) {
|
|
||||||
$q->where('rc.contract_created_at', '<=', $normalized);
|
|
||||||
}
|
|
||||||
if ($updated_from !== '' && ($normalized = $this->normalizeDateTimeInput($updated_from))) {
|
|
||||||
$q->where('rc.contract_updated_at', '>=', $normalized);
|
|
||||||
}
|
|
||||||
if ($updated_to !== '' && ($normalized = $this->normalizeDateTimeInput($updated_to, true))) {
|
|
||||||
$q->where('rc.contract_updated_at', '<=', $normalized);
|
|
||||||
}
|
|
||||||
if ($canceled_from !== '' && ($normalized = $this->normalizeDateTimeInput($canceled_from))) {
|
|
||||||
$q->where('rc.contract_cancelday', '>=', $normalized);
|
|
||||||
}
|
|
||||||
if ($canceled_to !== '' && ($normalized = $this->normalizeDateTimeInput($canceled_to, true))) {
|
|
||||||
$q->where('rc.contract_cancelday', '<=', $normalized);
|
|
||||||
}
|
|
||||||
if ($contract_valid_months !== '') {
|
|
||||||
$q->where('rc.enable_months', (int)$contract_valid_months);
|
|
||||||
}
|
|
||||||
if ($contract_flag !== '') {
|
|
||||||
$q->where('rc.contract_flag', (int)$contract_flag);
|
|
||||||
}
|
|
||||||
if ($contract_permission !== '') {
|
|
||||||
$q->where('rc.contract_permission', (int)$contract_permission);
|
|
||||||
}
|
|
||||||
if ($tag_qr_flag !== '') {
|
|
||||||
$q->where('rc.tag_qr_flag', (int)$tag_qr_flag);
|
|
||||||
}
|
|
||||||
if ($updateFlagFilter === '1') {
|
|
||||||
$q->where('rc.update_flag', '=', 1);
|
|
||||||
} elseif ($updateFlagFilter === '2') {
|
|
||||||
$q->where(function ($w) {
|
|
||||||
$w->whereNull('rc.update_flag')
|
|
||||||
->orWhere('rc.update_flag', '!=', 1);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if ($contract_cancel_flag !== '') {
|
|
||||||
$q->where('rc.contract_cancel_flag', (int)$contract_cancel_flag);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $q;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,234 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
|
||||||
|
|
||||||
use App\Models\City;
|
|
||||||
use App\Http\Requests\RegularTypeRequest;
|
|
||||||
use App\Models\RegularType;
|
|
||||||
use App\Utils;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Support\Facades\Validator;
|
|
||||||
use Response;
|
|
||||||
|
|
||||||
|
|
||||||
class RegularTypeController extends Controller
|
|
||||||
{
|
|
||||||
|
|
||||||
public function add(Request $request)
|
|
||||||
{
|
|
||||||
// 画面用データ
|
|
||||||
$dataList = $this->getDataDropList();
|
|
||||||
|
|
||||||
// フォーム入力(画面初期表示用)
|
|
||||||
$inputs = [
|
|
||||||
'city_id' => $request->input('city_id'),
|
|
||||||
'regular_class_1' => $request->input('regular_class_1'),
|
|
||||||
'regular_class_2' => $request->input('regular_class_2'),
|
|
||||||
'regular_class_3' => $request->input('regular_class_3'),
|
|
||||||
'regular_class_6' => $request->input('regular_class_6'),
|
|
||||||
'regular_class_12' => $request->input('regular_class_12'),
|
|
||||||
'memo' => $request->input('memo'),
|
|
||||||
];
|
|
||||||
$viewData = array_merge($inputs, $dataList);
|
|
||||||
|
|
||||||
$record = new RegularType();
|
|
||||||
|
|
||||||
if ($request->isMethod('POST')) {
|
|
||||||
$validation = new RegularTypeRequest();
|
|
||||||
$rules = $validation->rules();
|
|
||||||
$validator = Validator::make($request->all(), $rules, $validation->messages());
|
|
||||||
|
|
||||||
if ($validator->fails()) {
|
|
||||||
return redirect()
|
|
||||||
->back()
|
|
||||||
->withErrors($validator)
|
|
||||||
->withInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
// バリデーション成功
|
|
||||||
$payload = array_intersect_key($request->all(), array_flip([
|
|
||||||
'city_id',
|
|
||||||
'regular_class_1',
|
|
||||||
'regular_class_2',
|
|
||||||
'regular_class_3',
|
|
||||||
'regular_class_6',
|
|
||||||
'regular_class_12',
|
|
||||||
'memo',
|
|
||||||
]));
|
|
||||||
|
|
||||||
DB::transaction(function () use ($payload) {
|
|
||||||
$new = new RegularType();
|
|
||||||
$new->fill($payload);
|
|
||||||
$new->operator_id = \Auth::user()->ope_id;
|
|
||||||
$new->save();
|
|
||||||
});
|
|
||||||
|
|
||||||
$request->session()->flash('success', __('登録しました。'));
|
|
||||||
return redirect()->route('regular_types');
|
|
||||||
}
|
|
||||||
|
|
||||||
return view('admin.regular_types.add', array_merge($viewData, [
|
|
||||||
'record' => $record,
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function edit(Request $request, $id, $view = '')
|
|
||||||
{
|
|
||||||
// --- データ取得 ---
|
|
||||||
$record = RegularType::getById($id);
|
|
||||||
if (empty($id) || empty($record)) {
|
|
||||||
abort(404);
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- 初期表示用データ ---
|
|
||||||
$data = array_merge(
|
|
||||||
$record->getAttributes(),
|
|
||||||
$this->getDataDropList(),
|
|
||||||
[
|
|
||||||
'record' => $record,
|
|
||||||
'isEdit' => true,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
// --- 更新処理 ---
|
|
||||||
if ($request->isMethod('POST')) {
|
|
||||||
|
|
||||||
$validation = new RegularTypeRequest();
|
|
||||||
$rules = $validation->rules();
|
|
||||||
$validator = Validator::make($request->all(), $rules, $validation->messages());
|
|
||||||
|
|
||||||
// city_name → city_id の補正
|
|
||||||
$requestAll = $request->all();
|
|
||||||
if (isset($requestAll['city_name']) && !isset($requestAll['city_id'])) {
|
|
||||||
$requestAll['city_id'] = $requestAll['city_name'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 書き込み対象のカラムのみ許可
|
|
||||||
$payload = array_intersect_key($requestAll, array_flip([
|
|
||||||
'city_id',
|
|
||||||
'regular_class_1',
|
|
||||||
'regular_class_2',
|
|
||||||
'regular_class_3',
|
|
||||||
'regular_class_6',
|
|
||||||
'regular_class_12',
|
|
||||||
'memo',
|
|
||||||
]));
|
|
||||||
|
|
||||||
// バリデーションエラー
|
|
||||||
if ($validator->fails()) {
|
|
||||||
$data['errorMsg'] = $this->buildErrorMessages($validator);
|
|
||||||
$data = array_merge($data, $payload);
|
|
||||||
|
|
||||||
if ($view !== '') return view($view, $data);
|
|
||||||
return view('admin.regular_types.edit', $data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新
|
|
||||||
DB::transaction(function () use (&$record, $payload) {
|
|
||||||
$record->fill($payload);
|
|
||||||
$record->save();
|
|
||||||
});
|
|
||||||
|
|
||||||
$request->session()->flash('success', __('更新しました。'));
|
|
||||||
return redirect()->route('regular_types');
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- 画面表示 ---
|
|
||||||
if ($view !== '') {
|
|
||||||
return view($view, $data);
|
|
||||||
}
|
|
||||||
return view('admin.regular_types.edit', $data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** バリデーションエラーをまとめる */
|
|
||||||
protected function buildErrorMessages(\Illuminate\Contracts\Validation\Validator $validator): string
|
|
||||||
{
|
|
||||||
return implode("\n", $validator->errors()->all());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function delete(Request $request, $id = null)
|
|
||||||
{
|
|
||||||
// 一覧画面(checkbox で複数削除)
|
|
||||||
$ids = $request->input('pk');
|
|
||||||
|
|
||||||
// 編集画面(単体削除)
|
|
||||||
if ($id) {
|
|
||||||
$ids = [$id];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 削除対象が空の場合
|
|
||||||
if (empty($ids)) {
|
|
||||||
return redirect()
|
|
||||||
->route('regular_types')
|
|
||||||
->with('error', '削除対象が選択されていません。');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 削除処理
|
|
||||||
RegularType::destroy($ids);
|
|
||||||
|
|
||||||
return redirect()
|
|
||||||
->route('regular_types')
|
|
||||||
->with('success', '削除しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public function export(Request $request)
|
|
||||||
{
|
|
||||||
|
|
||||||
$headers = array(
|
|
||||||
"Content-type" => "text/csv;charset=UTF-8",
|
|
||||||
'Content-Encoding: UTF-8',
|
|
||||||
"Content-Disposition" => "attachment; filename=file.csv",
|
|
||||||
"Pragma" => "no-cache",
|
|
||||||
"Cache-Control" => "must-revalidate, post-check=0, pre-check=0",
|
|
||||||
"Expires" => "0"
|
|
||||||
);
|
|
||||||
$inputs = [
|
|
||||||
'isMethodPost' => 0,
|
|
||||||
'isExport' => 1,
|
|
||||||
'sort' => $request->input('sort', ''),
|
|
||||||
'sort_type' => $request->input('sort_type', ''),
|
|
||||||
|
|
||||||
];
|
|
||||||
$dataExport = RegularType::search($inputs);
|
|
||||||
$columns = array('user_seq', 'user_id');
|
|
||||||
$filename = "UserMaster.csv";
|
|
||||||
$file = fopen($filename, 'w+');
|
|
||||||
fputcsv($file, $columns);
|
|
||||||
foreach ($dataExport as $item) {
|
|
||||||
fputcsv($file, array($item->user_seq, $item->user_id));
|
|
||||||
}
|
|
||||||
fclose($file);
|
|
||||||
return Response::download($filename, $filename, $headers);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function info(Request $request, $id)
|
|
||||||
{
|
|
||||||
return $this->edit($request, $id, 'admin.regular_types.info');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDataDropList()
|
|
||||||
{
|
|
||||||
$data['cities'] = City::getList();
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
public function list(Request $request)
|
|
||||||
{
|
|
||||||
$sort = $request->input('sort', 'regular_type_id');
|
|
||||||
$sort_type = $request->input('sort_type', 'asc');
|
|
||||||
|
|
||||||
$list = \App\Models\RegularType::orderBy($sort, $sort_type)->paginate(20);
|
|
||||||
|
|
||||||
return view('admin.regular_types.list', [
|
|
||||||
'list' => $list,
|
|
||||||
'sort' => $sort,
|
|
||||||
'sort_type' => $sort_type,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -9,45 +9,15 @@ use Illuminate\Support\Facades\DB;
|
|||||||
class ReservationController extends Controller
|
class ReservationController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* 一覧表示(GET/POST)
|
* 予約者一覧表示
|
||||||
*/
|
*/
|
||||||
public function list(Request $request)
|
public function list(Request $request)
|
||||||
{
|
{
|
||||||
// ベースクエリを構築
|
$q = DB::table('reserve as r')
|
||||||
$q = DB::table('regular_contract as rc')
|
|
||||||
->leftJoin('user as u','rc.user_id','=','u.user_id')
|
|
||||||
->select([
|
->select([
|
||||||
'rc.contract_id',
|
'r.user_id',
|
||||||
'rc.contract_qr_id',
|
|
||||||
'rc.user_id',
|
|
||||||
'rc.user_categoryid',
|
|
||||||
'rc.park_id',
|
|
||||||
'rc.contract_created_at',
|
|
||||||
'rc.contract_periods',
|
|
||||||
'rc.contract_periode',
|
|
||||||
'rc.tag_qr_flag',
|
|
||||||
'rc.contract_flag',
|
|
||||||
'rc.contract_cancel_flag',
|
|
||||||
'rc.contract_payment_day',
|
|
||||||
'rc.contract_money',
|
|
||||||
'rc.billing_amount',
|
|
||||||
'rc.contract_permission',
|
|
||||||
'rc.contract_manual',
|
|
||||||
'rc.contract_notice',
|
|
||||||
'rc.update_flag',
|
|
||||||
'rc.800m_flag',
|
|
||||||
'rc.price_parkplaceid',
|
|
||||||
'rc.psection_id',
|
|
||||||
'rc.reserve_date',
|
|
||||||
'p.park_name',
|
|
||||||
'u.user_name',
|
'u.user_name',
|
||||||
'u.user_phonetic',
|
'u.user_phonetic',
|
||||||
'u.user_mobile',
|
|
||||||
'u.user_seq',
|
|
||||||
'u.user_homephone',
|
|
||||||
'u.user_primemail',
|
|
||||||
'u.user_gender',
|
|
||||||
'u.user_birthdate',
|
|
||||||
'u.user_regident_zip',
|
'u.user_regident_zip',
|
||||||
'u.user_regident_pre',
|
'u.user_regident_pre',
|
||||||
'u.user_regident_city',
|
'u.user_regident_city',
|
||||||
@ -56,195 +26,74 @@ class ReservationController extends Controller
|
|||||||
'u.user_relate_pre',
|
'u.user_relate_pre',
|
||||||
'u.user_relate_city',
|
'u.user_relate_city',
|
||||||
'u.user_relate_add',
|
'u.user_relate_add',
|
||||||
'u.user_graduate',
|
'u.user_birthdate',
|
||||||
'u.user_workplace',
|
'u.user_gender',
|
||||||
|
'u.user_mobile',
|
||||||
|
'u.user_homephone',
|
||||||
'u.user_school',
|
'u.user_school',
|
||||||
|
'u.user_graduate',
|
||||||
'u.user_remarks',
|
'u.user_remarks',
|
||||||
'u.user_tag_serial_64',
|
'r.reserve_id',
|
||||||
'u.user_reduction',
|
'r.park_id',
|
||||||
DB::raw('rc.user_securitynum as crime_prevention'),
|
'p.park_name',
|
||||||
DB::raw('rc.contract_seal_issue as seal_issue_count'),
|
'r.price_parkplaceid',
|
||||||
DB::raw("CASE rc.enable_months
|
'r.psection_id',
|
||||||
WHEN 1 THEN '月極(1ヶ月)'
|
'r.reserve_date',
|
||||||
WHEN 3 THEN '3ヶ月'
|
'r.reserve_reduction as reduction',
|
||||||
WHEN 6 THEN '6ヶ月'
|
'r.800m_flag as within_800m_flag',
|
||||||
WHEN 12 THEN '年'
|
|
||||||
ELSE CONCAT(rc.enable_months, 'ヶ月') END as ticket_type"),
|
|
||||||
DB::raw('ps.psection_subject as vehicle_type'),
|
|
||||||
// 利用者分類のラベル(usertype テーブルの subject を取得)
|
|
||||||
DB::raw('ut.usertype_subject1 as user_category1'),
|
|
||||||
DB::raw('ut.usertype_subject2 as user_category2'),
|
|
||||||
DB::raw('ut.usertype_subject3 as user_category3'),
|
|
||||||
])
|
])
|
||||||
->leftJoin('park as p', 'rc.park_id', '=', 'p.park_id')
|
->leftJoin('user as u', 'r.user_id', '=', 'u.user_id')
|
||||||
->leftJoin('psection as ps', 'rc.psection_id', '=', 'ps.psection_id')
|
->leftJoin('park as p', 'r.park_id', '=', 'p.park_id'); // 追加
|
||||||
->leftJoin('usertype as ut', 'u.user_categoryid', '=', 'ut.user_categoryid');
|
|
||||||
|
|
||||||
// ===== 絞り込み条件 =====
|
// フィルター条件
|
||||||
|
|
||||||
// 駐輪場で絞る(完全一致)
|
|
||||||
if ($request->filled('park_id')) {
|
if ($request->filled('park_id')) {
|
||||||
$q->where('rc.park_id', $request->park_id);
|
$q->where('r.park_id', $request->input('park_id'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 利用者IDで絞る(完全一致)
|
|
||||||
if ($request->filled('user_id')) {
|
if ($request->filled('user_id')) {
|
||||||
$q->where('rc.user_id', $request->user_id);
|
$q->where('r.user_id', $request->input('user_id'));
|
||||||
}
|
}
|
||||||
|
if ($request->filled('user_categoryid')) {
|
||||||
// 利用者分類で絞る(※ select の value を user_categoryid にしているため、user テーブルのカラムで比較)
|
$q->where('r.user_categoryid', $request->input('user_categoryid'));
|
||||||
if ($request->filled('user_category1')) {
|
|
||||||
$q->where('u.user_categoryid', $request->user_category1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// タグシリアルで部分一致検索
|
|
||||||
if ($request->filled('user_tag_serial')) {
|
if ($request->filled('user_tag_serial')) {
|
||||||
$q->where('u.user_tag_serial', 'like', '%' . $request->input('user_tag_serial') . '%');
|
$q->where('u.user_tag_serial', 'like', '%' . $request->input('user_tag_serial') . '%');
|
||||||
}
|
}
|
||||||
|
|
||||||
// タグシリアル64進で部分一致検索
|
|
||||||
if ($request->filled('user_tag_serial_64')) {
|
if ($request->filled('user_tag_serial_64')) {
|
||||||
$val = $request->user_tag_serial_64;
|
$q->where('u.user_tag_serial_64', 'like', '%' . $request->input('user_tag_serial_64') . '%');
|
||||||
$q->where('u.user_tag_serial_64','like','%'.$val.'%');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// フリガナで部分一致
|
|
||||||
if ($request->filled('user_phonetic')) {
|
if ($request->filled('user_phonetic')) {
|
||||||
$q->where('u.user_phonetic', 'like', '%' . $request->user_phonetic . '%');
|
$q->where('u.user_phonetic', 'like', '%' . $request->input('user_phonetic') . '%');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 携帯電話で部分一致
|
|
||||||
if ($request->filled('user_mobile')) {
|
if ($request->filled('user_mobile')) {
|
||||||
$q->where('u.user_mobile', 'like', '%' . $request->user_mobile . '%');
|
$q->where(function($sub) use ($request) {
|
||||||
|
$sub->where('u.user_mobile', 'like', '%' . $request->input('user_mobile') . '%')
|
||||||
|
->orWhere('u.user_homephone', 'like', '%' . $request->input('user_mobile') . '%');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// メールアドレスで部分一致
|
|
||||||
if ($request->filled('user_primemail')) {
|
if ($request->filled('user_primemail')) {
|
||||||
$q->where('u.user_primemail', 'like', '%' . $request->user_primemail . '%');
|
$q->where('u.user_primemail', 'like', '%' . $request->input('user_primemail') . '%');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 勤務先で部分一致
|
|
||||||
if ($request->filled('user_workplace')) {
|
if ($request->filled('user_workplace')) {
|
||||||
$q->where('u.user_workplace', 'like', '%' . $request->user_workplace . '%');
|
$q->where('u.user_workplace', 'like', '%' . $request->input('user_workplace') . '%');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 学校で部分一致
|
|
||||||
if ($request->filled('user_school')) {
|
if ($request->filled('user_school')) {
|
||||||
$q->where('u.user_school', 'like', '%' . $request->user_school . '%');
|
$q->where('u.user_school', 'like', '%' . $request->input('user_school') . '%');
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== ソート処理 =====
|
// ソート
|
||||||
// 指定があればその列でソート、なければデフォルトで契約IDの昇順
|
$sort = $request->input('sort', 'r.reserve_id');
|
||||||
$sort = $request->input('sort'); // null 許容
|
$sortType = $request->input('sort_type', 'desc');
|
||||||
$sortType = $request->input('sort_type','asc');
|
$allowSorts = ['r.reserve_id', 'r.reserve_date', 'r.reserve_start', 'r.reserve_end'];
|
||||||
|
if (!in_array($sort, $allowSorts)) {
|
||||||
$allowSorts = [
|
$sort = 'r.reserve_id';
|
||||||
'rc.contract_id',
|
|
||||||
'rc.user_id',
|
|
||||||
'u.user_name',
|
|
||||||
'rc.tag_qr_flag',
|
|
||||||
'p.park_name',
|
|
||||||
];
|
|
||||||
if ($sort && in_array($sort, $allowSorts)) {
|
|
||||||
$sortType = $sortType === 'desc' ? 'desc' : 'asc';
|
|
||||||
$q->orderBy($sort, $sortType);
|
|
||||||
} else {
|
|
||||||
// デフォルトソート
|
|
||||||
$sort = null;
|
|
||||||
$sortType = null;
|
|
||||||
$q->orderBy('rc.contract_id','asc');
|
|
||||||
}
|
}
|
||||||
|
$sortType = ($sortType === 'asc') ? 'asc' : 'desc';
|
||||||
|
|
||||||
// ページネーション(クエリ文字列を引き継ぐ)
|
$rows = $q->orderBy($sort, $sortType)->paginate(20)->withQueryString();
|
||||||
$rows = $q->paginate(20)->appends($request->query());
|
|
||||||
|
|
||||||
// 駐輪場セレクト用データ取得
|
// 駐輪場リスト取得(必要なら)
|
||||||
$parks = DB::table('park')->select('park_id', 'park_name')->orderBy('park_name')->get();
|
$parks = DB::table('park')->select('park_id', 'park_name')->get();
|
||||||
|
|
||||||
// 利用者分類セレクト用:実際に使用されている分類のみを取得する
|
return view('admin.reservation.list', compact('rows', 'sort', 'sortType', 'parks'));
|
||||||
$categories = $this->buildCategoryOptions(true);
|
|
||||||
|
|
||||||
// ビューに渡す
|
|
||||||
return view('admin.reservation.list', compact('rows', 'sort', 'sortType', 'parks', 'categories'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 詳細表示
|
|
||||||
*/
|
|
||||||
public function info($id)
|
|
||||||
{
|
|
||||||
// 指定契約IDの詳細を取得
|
|
||||||
$contract = DB::table('regular_contract as rc')
|
|
||||||
->select([
|
|
||||||
'rc.*',
|
|
||||||
'p.park_name',
|
|
||||||
'u.user_name',
|
|
||||||
'u.user_phonetic',
|
|
||||||
'u.user_mobile',
|
|
||||||
'u.user_homephone',
|
|
||||||
'u.user_primemail',
|
|
||||||
'u.user_gender',
|
|
||||||
'u.user_birthdate',
|
|
||||||
'u.user_regident_city',
|
|
||||||
])
|
|
||||||
->leftJoin('park as p', 'rc.park_id', '=', 'p.park_id')
|
|
||||||
->leftJoin('user as u', 'rc.user_id', '=', 'u.user_id')
|
|
||||||
->where('rc.contract_id', $id)
|
|
||||||
->first();
|
|
||||||
|
|
||||||
if (!$contract) { abort(404); }
|
|
||||||
|
|
||||||
return view('admin.reservation.info', compact('contract'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 利用者分類選択肢を取得
|
|
||||||
*
|
|
||||||
* @param bool $onlyUsed true の場合は regular_contract に出現する分類のみ返す
|
|
||||||
* @return array [user_categoryid => label, ...]
|
|
||||||
*/
|
|
||||||
private function buildCategoryOptions(bool $onlyUsed = false): array
|
|
||||||
{
|
|
||||||
if (! $onlyUsed) {
|
|
||||||
// 全件取得(既存の挙動)
|
|
||||||
return DB::table('usertype')
|
|
||||||
->orderBy('user_categoryid', 'asc')
|
|
||||||
->get()
|
|
||||||
->mapWithKeys(function ($row) {
|
|
||||||
$label = collect([
|
|
||||||
$row->usertype_subject1 ?? '',
|
|
||||||
$row->usertype_subject2 ?? '',
|
|
||||||
$row->usertype_subject3 ?? '',
|
|
||||||
])->filter(fn ($v) => $v !== '')->implode('/');
|
|
||||||
|
|
||||||
return [$row->user_categoryid => $label !== '' ? $label : (string) $row->user_categoryid];
|
|
||||||
})
|
|
||||||
->toArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 実際に使用されている分類のみ取得する(内部結合で user と regular_contract と紐付くもの)
|
|
||||||
$rows = DB::table('usertype as ut')
|
|
||||||
->join('user as u', 'u.user_categoryid', '=', 'ut.user_categoryid')
|
|
||||||
->join('regular_contract as rc', 'rc.user_id', '=', 'u.user_id')
|
|
||||||
->select(
|
|
||||||
'ut.user_categoryid',
|
|
||||||
'ut.usertype_subject1',
|
|
||||||
'ut.usertype_subject2',
|
|
||||||
'ut.usertype_subject3'
|
|
||||||
)
|
|
||||||
->groupBy('ut.user_categoryid', 'ut.usertype_subject1', 'ut.usertype_subject2', 'ut.usertype_subject3')
|
|
||||||
->orderBy('ut.user_categoryid', 'asc')
|
|
||||||
->get();
|
|
||||||
|
|
||||||
// ラベルを組み立てて配列で返す
|
|
||||||
return $rows->mapWithKeys(function ($row) {
|
|
||||||
$label = collect([
|
|
||||||
$row->usertype_subject1 ?? '',
|
|
||||||
$row->usertype_subject2 ?? '',
|
|
||||||
$row->usertype_subject3 ?? '',
|
|
||||||
])->filter(fn ($v) => $v !== '')->implode('/');
|
|
||||||
|
|
||||||
return [$row->user_categoryid => $label !== '' ? $label : (string) $row->user_categoryid];
|
|
||||||
})->toArray();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,10 +6,6 @@ use Illuminate\Support\Facades\Schema;
|
|||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use App\Models\Park;
|
|
||||||
use App\Models\PriceA;
|
|
||||||
use App\Models\PriceB;
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
|
|
||||||
class ReservesController
|
class ReservesController
|
||||||
{
|
{
|
||||||
@ -28,7 +24,7 @@ class ReservesController
|
|||||||
{
|
{
|
||||||
// ── 並び順(既定: reserve_id DESC)──────────────────────────────
|
// ── 並び順(既定: reserve_id DESC)──────────────────────────────
|
||||||
$sort = $request->input('sort', 'reserve_id');
|
$sort = $request->input('sort', 'reserve_id');
|
||||||
$sortType = strtolower($request->input('sort_type', 'asc')) === 'desc' ? 'desc' : 'asc';
|
$sortType = strtolower($request->input('sort_type', 'desc')) === 'asc' ? 'asc' : 'desc';
|
||||||
|
|
||||||
// ── 絞り込み(必要最低限:利用者/駐輪場/期間)──────────────────
|
// ── 絞り込み(必要最低限:利用者/駐輪場/期間)──────────────────
|
||||||
$userId = trim((string) $request->input('user_id', ''));
|
$userId = trim((string) $request->input('user_id', ''));
|
||||||
@ -36,32 +32,14 @@ class ReservesController
|
|||||||
$fromDt = $request->input('reserve_date_from', '');
|
$fromDt = $request->input('reserve_date_from', '');
|
||||||
$toDt = $request->input('reserve_date_to', '');
|
$toDt = $request->input('reserve_date_to', '');
|
||||||
$keyword = trim((string) $request->input('keyword', '')); // 利用者名かな など
|
$keyword = trim((string) $request->input('keyword', '')); // 利用者名かな など
|
||||||
$validFlag = trim((string) $request->input('valid_flag', ''));
|
|
||||||
$mailSentFrom = $request->input('mail_sent_from', '');
|
|
||||||
$mailSentTo = $request->input('mail_sent_to', '');
|
|
||||||
|
|
||||||
$priceUnion = DB::query()->fromSub(function ($sub) {
|
|
||||||
$sub->from('price_a')
|
|
||||||
->select('price_parkplaceid', 'prine_name')
|
|
||||||
->unionAll(
|
|
||||||
DB::table('price_b')->select('price_parkplaceid', 'prine_name')
|
|
||||||
);
|
|
||||||
}, 'price_union');
|
|
||||||
|
|
||||||
// ── クエリ構築 ────────────────────────────────────────────────
|
// ── クエリ構築 ────────────────────────────────────────────────
|
||||||
$q = DB::table('reserve as r')
|
$q = DB::table('reserve as r')
|
||||||
->leftJoin('user as u', 'u.user_id', '=', 'r.user_id')
|
->leftJoin('user as u', 'u.user_id', '=', 'r.user_id') // user: user_name, user_phonetic 等【turn12file9†L26-L34】
|
||||||
->leftJoin('park as p', 'p.park_id', '=', 'r.park_id')
|
->leftJoin('park as p', 'p.park_id', '=', 'r.park_id') // park: park_name 等【turn12file4†L17-L25】
|
||||||
->leftJoin('psection as ps', 'ps.psection_id', '=', 'r.psection_id')
|
|
||||||
->leftJoin('ptype as pt', 'pt.ptype_id', '=', 'r.ptype_id')
|
|
||||||
->leftJoin('usertype as t', 't.user_categoryid', '=', 'r.user_categoryid')
|
|
||||||
->leftJoinSub($priceUnion, 'price_union', function ($join) {
|
|
||||||
$join->on('price_union.price_parkplaceid', '=', 'r.price_parkplaceid');
|
|
||||||
})
|
|
||||||
->select([
|
->select([
|
||||||
'r.reserve_id',
|
'r.reserve_id',
|
||||||
'r.contract_id',
|
'r.contract_id',
|
||||||
'r.contract_created_at',
|
|
||||||
'r.user_id',
|
'r.user_id',
|
||||||
'r.park_id',
|
'r.park_id',
|
||||||
'r.price_parkplaceid',
|
'r.price_parkplaceid',
|
||||||
@ -69,36 +47,19 @@ class ReservesController
|
|||||||
'r.reserve_date',
|
'r.reserve_date',
|
||||||
'r.reserve_start',
|
'r.reserve_start',
|
||||||
'r.reserve_end',
|
'r.reserve_end',
|
||||||
'r.reserve_reduction',
|
|
||||||
'r.reserve_auto_remind',
|
|
||||||
'r.reserve_manual_remind',
|
|
||||||
DB::raw('r.`800m_flag` as flag_800m'),
|
|
||||||
'r.reserve_cancelday',
|
'r.reserve_cancelday',
|
||||||
'r.valid_flag',
|
'r.valid_flag',
|
||||||
'r.reserve_manual',
|
|
||||||
'r.reserve_notice',
|
|
||||||
'r.sent_date',
|
|
||||||
'r.reserve_order',
|
|
||||||
'r.valid_flag',
|
|
||||||
'r.ope_id',
|
'r.ope_id',
|
||||||
'r.user_categoryid',
|
|
||||||
DB::raw('u.user_name as user_name'),
|
DB::raw('u.user_name as user_name'),
|
||||||
DB::raw('u.user_phonetic as user_phonetic'),
|
DB::raw('u.user_phonetic as user_phonetic'),
|
||||||
DB::raw('u.user_mobile as user_mobile'),
|
DB::raw('u.user_mobile as user_mobile'),
|
||||||
DB::raw('p.park_name as park_name'),
|
DB::raw('p.park_name as park_name'),
|
||||||
DB::raw('pt.ptype_subject as ptype_subject'),
|
|
||||||
DB::raw('ps.psection_subject as psection_subject'),
|
|
||||||
DB::raw('price_union.price_parkplaceid as display_price_parkplaceid'),
|
|
||||||
DB::raw('price_union.prine_name as display_prine_name'),
|
|
||||||
DB::raw('t.usertype_subject1 as usertype_subject1'),
|
|
||||||
DB::raw('t.usertype_subject2 as usertype_subject2'),
|
|
||||||
DB::raw('t.usertype_subject3 as usertype_subject3'),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($userId !== '')
|
if ($userId !== '')
|
||||||
$q->where('r.user_id', 'like', "%{$userId}%");
|
$q->where('r.user_id', 'like', "%{$userId}%");
|
||||||
if ($parkId !== '')
|
if ($parkId !== '')
|
||||||
$q->where('r.park_id', '=', (int) $parkId);
|
$q->where('r.park_id', 'like', "%{$parkId}%");
|
||||||
|
|
||||||
if ($fromDt)
|
if ($fromDt)
|
||||||
$q->whereDate('r.reserve_date', '>=', $fromDt);
|
$q->whereDate('r.reserve_date', '>=', $fromDt);
|
||||||
@ -111,108 +72,36 @@ class ReservesController
|
|||||||
->orWhere('u.user_phonetic', 'like', "%{$keyword}%");
|
->orWhere('u.user_phonetic', 'like', "%{$keyword}%");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (in_array($validFlag, ['0', '1'], true)) {
|
|
||||||
$q->where('r.valid_flag', '=', (int) $validFlag);
|
|
||||||
}
|
|
||||||
if ($mailSentFrom !== null && $mailSentFrom !== '') {
|
|
||||||
$q->where('r.sent_date', '>=', $mailSentFrom);
|
|
||||||
}
|
|
||||||
if ($mailSentTo !== null && $mailSentTo !== '') {
|
|
||||||
$q->where('r.sent_date', '<=', $mailSentTo);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ソート許可カラム(JOIN 先も含む)
|
// ソート許可カラム(JOIN 先も含む)
|
||||||
$sortable = [
|
$sortable = [
|
||||||
'reserve_id',
|
'reserve_id',
|
||||||
'contract_id',
|
'contract_id',
|
||||||
'contract_created_at',
|
|
||||||
'user_categoryid',
|
|
||||||
'user_id',
|
'user_id',
|
||||||
|
'park_id',
|
||||||
'reserve_date',
|
'reserve_date',
|
||||||
'park_price_name',
|
'reserve_start',
|
||||||
'price_parkplaceid',
|
'reserve_end',
|
||||||
'psection_subject',
|
|
||||||
'ptype_subject',
|
|
||||||
'park_name',
|
|
||||||
'reserve_reduction',
|
|
||||||
'reserve_auto_remind',
|
|
||||||
'reserve_manual_remind',
|
|
||||||
'flag_800m',
|
|
||||||
'reserve_cancelday',
|
'reserve_cancelday',
|
||||||
'valid_flag',
|
'valid_flag',
|
||||||
'sent_date',
|
'ope_id',
|
||||||
'reserve_manual',
|
'user_name',
|
||||||
'reserve_notice',
|
'user_phonetic',
|
||||||
'reserve_order',
|
'user_mobile',
|
||||||
|
'park_name',
|
||||||
];
|
];
|
||||||
if (!in_array($sort, $sortable, true)) {
|
if (!in_array($sort, $sortable, true))
|
||||||
$sort = 'reserve_id';
|
$sort = 'reserve_id';
|
||||||
}
|
|
||||||
|
|
||||||
$sortMap = [
|
$sortMap = [
|
||||||
'reserve_id' => DB::raw('r.reserve_id'),
|
'user_name' => 'u.user_name',
|
||||||
'contract_id' => DB::raw('r.contract_id'),
|
'user_phonetic' => 'u.user_phonetic',
|
||||||
'contract_created_at' => DB::raw('r.contract_created_at'),
|
'user_mobile' => 'u.user_mobile',
|
||||||
'user_categoryid' => DB::raw('r.user_categoryid'),
|
'park_name' => 'p.park_name',
|
||||||
'user_id' => DB::raw('r.user_id'),
|
|
||||||
'reserve_date' => DB::raw('r.reserve_date'),
|
|
||||||
'park_price_name' => DB::raw('price_union.prine_name'),
|
|
||||||
'price_parkplaceid' => DB::raw('r.price_parkplaceid'),
|
|
||||||
'psection_subject' => DB::raw('ps.psection_subject'),
|
|
||||||
'ptype_subject' => DB::raw('pt.ptype_subject'),
|
|
||||||
'park_name' => DB::raw('p.park_name'),
|
|
||||||
'reserve_reduction' => DB::raw('r.reserve_reduction'),
|
|
||||||
'reserve_auto_remind' => DB::raw('r.reserve_auto_remind'),
|
|
||||||
'reserve_manual_remind' => DB::raw('r.reserve_manual_remind'),
|
|
||||||
'flag_800m' => DB::raw('r.`800m_flag`'),
|
|
||||||
'reserve_cancelday' => DB::raw('r.reserve_cancelday'),
|
|
||||||
'valid_flag' => DB::raw('r.valid_flag'),
|
|
||||||
'sent_date' => DB::raw('r.sent_date'),
|
|
||||||
'reserve_manual' => DB::raw('r.reserve_manual'),
|
|
||||||
'reserve_notice' => DB::raw('r.reserve_notice'),
|
|
||||||
'reserve_order' => DB::raw('r.reserve_order'),
|
|
||||||
];
|
];
|
||||||
$sortColumn = $sortMap[$sort] ?? DB::raw('r.reserve_id');
|
$sortCol = $sortMap[$sort] ?? ('r.' . $sort);
|
||||||
$q->orderBy($sortColumn, $sortType);
|
|
||||||
|
|
||||||
$parkOptions = Park::query()
|
$list = $q->orderBy($sortCol, $sortType)->paginate(50);
|
||||||
->orderBy('park_id', 'asc')
|
|
||||||
->pluck('park_name', 'park_id')
|
|
||||||
->toArray();
|
|
||||||
|
|
||||||
$list = $q->paginate(50);
|
|
||||||
|
|
||||||
$placeIds = $list->getCollection()
|
|
||||||
->pluck('price_parkplaceid')
|
|
||||||
->filter()
|
|
||||||
->unique()
|
|
||||||
->values()
|
|
||||||
->all();
|
|
||||||
|
|
||||||
if (!empty($placeIds)) {
|
|
||||||
$priceNamesA = PriceA::query()
|
|
||||||
->whereIn('price_parkplaceid', $placeIds)
|
|
||||||
->pluck('prine_name', 'price_parkplaceid')
|
|
||||||
->toArray();
|
|
||||||
|
|
||||||
$priceNamesB = PriceB::query()
|
|
||||||
->whereIn('price_parkplaceid', $placeIds)
|
|
||||||
->pluck('prine_name', 'price_parkplaceid')
|
|
||||||
->toArray();
|
|
||||||
|
|
||||||
// 駐輪場所名のマッピング(price_b で上書き)
|
|
||||||
$priceNames = array_replace($priceNamesA, $priceNamesB);
|
|
||||||
|
|
||||||
$list->setCollection(
|
|
||||||
$list->getCollection()->map(function ($row) use ($priceNames) {
|
|
||||||
$id = $row->price_parkplaceid ?? null;
|
|
||||||
$row->display_prine_name = ($id !== null && array_key_exists($id, $priceNames))
|
|
||||||
? $priceNames[$id]
|
|
||||||
: null;
|
|
||||||
return $row;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return view('admin.reserves.list', [
|
return view('admin.reserves.list', [
|
||||||
'list' => $list,
|
'list' => $list,
|
||||||
@ -224,10 +113,6 @@ class ReservesController
|
|||||||
'reserve_date_from' => $fromDt,
|
'reserve_date_from' => $fromDt,
|
||||||
'reserve_date_to' => $toDt,
|
'reserve_date_to' => $toDt,
|
||||||
'keyword' => $keyword,
|
'keyword' => $keyword,
|
||||||
'valid_flag' => $validFlag,
|
|
||||||
'mail_sent_from' => $mailSentFrom,
|
|
||||||
'mail_sent_to' => $mailSentTo,
|
|
||||||
'parkOptions' => $parkOptions,
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,44 +122,7 @@ class ReservesController
|
|||||||
public function add(Request $request)
|
public function add(Request $request)
|
||||||
{
|
{
|
||||||
if ($request->isMethod('get')) {
|
if ($request->isMethod('get')) {
|
||||||
$userTypes = DB::table('usertype')
|
return view('admin.reserves.add');
|
||||||
->orderBy('user_categoryid', 'asc')
|
|
||||||
->get([
|
|
||||||
'user_categoryid',
|
|
||||||
'usertype_subject1',
|
|
||||||
'usertype_subject2',
|
|
||||||
'usertype_subject3',
|
|
||||||
])
|
|
||||||
->map(function ($row) {
|
|
||||||
$labels = array_filter([
|
|
||||||
$row->usertype_subject1,
|
|
||||||
$row->usertype_subject2,
|
|
||||||
$row->usertype_subject3,
|
|
||||||
], fn ($v) => $v !== null && $v !== '');
|
|
||||||
$row->display_name = $labels ? implode('/', $labels) : '';
|
|
||||||
return $row;
|
|
||||||
});
|
|
||||||
|
|
||||||
$parks = Park::query()
|
|
||||||
->orderBy('park_id', 'asc')
|
|
||||||
->get(['park_id', 'park_name']);
|
|
||||||
|
|
||||||
$priceA = PriceA::query()
|
|
||||||
->select('price_parkplaceid', 'prine_name')
|
|
||||||
->get();
|
|
||||||
$priceB = PriceB::query()
|
|
||||||
->select('price_parkplaceid', 'prine_name')
|
|
||||||
->get();
|
|
||||||
$priceOptions = $priceA->merge($priceB)
|
|
||||||
->sortBy('price_parkplaceid', SORT_NATURAL)
|
|
||||||
->unique('price_parkplaceid')
|
|
||||||
->values();
|
|
||||||
|
|
||||||
return view('admin.reserves.add', [
|
|
||||||
'userTypes' => $userTypes,
|
|
||||||
'parks' => $parks,
|
|
||||||
'priceOptions' => $priceOptions,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 予約の最低限バリデーション(必要に応じて追加)
|
// 予約の最低限バリデーション(必要に応じて追加)
|
||||||
@ -293,28 +141,19 @@ class ReservesController
|
|||||||
return back()->withErrors($v)->withInput();
|
return back()->withErrors($v)->withInput();
|
||||||
}
|
}
|
||||||
|
|
||||||
$now = now();
|
|
||||||
$opeId = optional(Auth::user())->ope_id;
|
|
||||||
|
|
||||||
$nextReserveId = DB::transaction(function () {
|
|
||||||
$currentMax = DB::table('reserve')->max('reserve_id');
|
|
||||||
return $currentMax ? $currentMax + 1 : 1;
|
|
||||||
});
|
|
||||||
|
|
||||||
DB::table('reserve')->insert([
|
DB::table('reserve')->insert([
|
||||||
'reserve_id' => $nextReserveId,
|
|
||||||
'user_id' => (int) $request->input('user_id'),
|
'user_id' => (int) $request->input('user_id'),
|
||||||
'park_id' => (int) $request->input('park_id'),
|
'park_id' => (int) $request->input('park_id'),
|
||||||
'contract_id' => $request->input('contract_id'),
|
'contract_id' => $request->input('contract_id'), // 任意:regular_contract と紐づける場合【turn12file7†L20-L28】
|
||||||
'price_parkplaceid' => $request->input('price_parkplaceid'),
|
'price_parkplaceid' => $request->input('price_parkplaceid'),
|
||||||
'psection_id' => $request->input('psection_id'),
|
'psection_id' => $request->input('psection_id'),
|
||||||
'reserve_date' => $request->input('reserve_date'),
|
'reserve_date' => $request->input('reserve_date'),
|
||||||
'reserve_start' => $now,
|
'reserve_start' => $request->input('reserve_start'),
|
||||||
'reserve_end' => $now,
|
'reserve_end' => $request->input('reserve_end'),
|
||||||
'valid_flag' => $request->input('valid_flag'),
|
'valid_flag' => $request->input('valid_flag'),
|
||||||
'ope_id' => $opeId,
|
'ope_id' => $request->input('ope_id'),
|
||||||
'created_at' => $now,
|
'created_at' => now(),
|
||||||
'updated_at' => $now,
|
'updated_at' => now(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return redirect()->route('reserves')->with('success', '予約を登録しました。');
|
return redirect()->route('reserves')->with('success', '予約を登録しました。');
|
||||||
@ -425,7 +264,8 @@ class ReservesController
|
|||||||
|
|
||||||
$parkOptions = DB::table('park')
|
$parkOptions = DB::table('park')
|
||||||
->orderBy('park_id', 'asc')
|
->orderBy('park_id', 'asc')
|
||||||
->pluck('park_name', 'park_id')
|
->limit(5000)
|
||||||
|
->pluck(DB::raw("concat(park_id, ' ', park_name)"), 'park_id')
|
||||||
->toArray();
|
->toArray();
|
||||||
|
|
||||||
$userTypeOptions = Schema::hasTable('usertype')
|
$userTypeOptions = Schema::hasTable('usertype')
|
||||||
|
|||||||
@ -10,69 +10,19 @@ class SealsController extends Controller
|
|||||||
{
|
{
|
||||||
public function list(Request $request)
|
public function list(Request $request)
|
||||||
{
|
{
|
||||||
$q = \DB::table('seal as s')
|
// ソート用パラメータを取得(デフォルト値を設定)
|
||||||
->leftJoin('park as p','s.park_id','=','p.park_id')
|
$sort = $request->input('sort', 'seal_issueid');
|
||||||
->leftJoin('regular_contract as rc','s.contract_id','=','rc.contract_id')
|
$sort_type = $request->input('sort_type', 'desc');
|
||||||
->leftJoin('psection as ps','rc.psection_id','=','ps.psection_id')
|
|
||||||
->select([
|
// sealテーブルを参照し、ソート
|
||||||
's.seal_issueid',
|
$list = DB::table('seal')
|
||||||
's.park_id',
|
->orderBy($sort, $sort_type)
|
||||||
'p.park_name',
|
->paginate(20);
|
||||||
's.contract_id',
|
|
||||||
'rc.psection_id',
|
return view('admin.seals.list', [
|
||||||
\DB::raw('ps.psection_subject AS psection_subject'),
|
'list' => $list,
|
||||||
'rc.contract_seal_issue',
|
'sort' => $sort,
|
||||||
's.seal_day',
|
'sort_type' => $sort_type,
|
||||||
's.seal_reason',
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// 駐輪場フィルタ
|
|
||||||
if($request->filled('park_id')){
|
|
||||||
$q->where('s.park_id',$request->park_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 期間フィルタ
|
|
||||||
$periodType = $request->input('period_type','range');
|
|
||||||
if($periodType === 'range'){
|
|
||||||
if($request->filled('seal_day_from')){
|
|
||||||
$q->whereDate('s.seal_day','>=',$request->seal_day_from);
|
|
||||||
}
|
|
||||||
if($request->filled('seal_day_to')){
|
|
||||||
$q->whereDate('s.seal_day','<=',$request->seal_day_to);
|
|
||||||
}
|
|
||||||
} elseif($periodType === 'recent' && $request->filled('recent_period')){
|
|
||||||
$map = ['12m'=>12,'6m'=>6,'3m'=>3,'2m'=>2,'1m'=>1,'1w'=>'1w'];
|
|
||||||
$key = $request->recent_period;
|
|
||||||
if(isset($map[$key])){
|
|
||||||
$from = $key==='1w' ? now()->subWeek() : now()->subMonths($map[$key]);
|
|
||||||
$q->where('s.seal_day','>=',$from->toDateString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- 並び替え: パラメータがある場合のみ適用 ---
|
|
||||||
$sort = $request->query('sort'); // デフォルト null
|
|
||||||
$sortType = $request->query('sort_type','asc'); // 指定なければ asc
|
|
||||||
$allow = [
|
|
||||||
'seal_issueid' => 's.seal_issueid',
|
|
||||||
'park_id' => 'p.park_name',
|
|
||||||
'contract_id' => 's.contract_id',
|
|
||||||
'seal_day' => 's.seal_day',
|
|
||||||
'contract_seal_issue' => 'rc.contract_seal_issue',
|
|
||||||
'psection_subject' => 'ps.psection_subject',
|
|
||||||
];
|
|
||||||
if(isset($allow[$sort])){
|
|
||||||
$sortType = $sortType === 'desc' ? 'desc' : 'asc';
|
|
||||||
$q->orderBy($allow[$sort], $sortType);
|
|
||||||
}
|
|
||||||
// 並び替え指定が無い時は orderBy 不要 → DB の物理(主キー)順
|
|
||||||
|
|
||||||
$list = $q->paginate(20)->appends($request->query());
|
|
||||||
|
|
||||||
$parks = \DB::table('park')
|
|
||||||
->select('park_id','park_name')
|
|
||||||
->orderBy('park_name')
|
|
||||||
->get();
|
|
||||||
|
|
||||||
return view('admin.seals.list', compact('list','parks','sort','sortType'));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,187 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Models\Setting;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Facades\Validator;
|
|
||||||
|
|
||||||
class SettingController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 一覧(絞り込みなし・ページングのみ): /settings
|
|
||||||
*/
|
|
||||||
public function list(Request $request)
|
|
||||||
{
|
|
||||||
$perPage = \App\Utils::item_per_page ?? 20;
|
|
||||||
|
|
||||||
// リクエストから取得
|
|
||||||
$sort = $request->input('sort', 'setting_id');
|
|
||||||
$sort_type = $request->input('sort_type', 'asc');
|
|
||||||
|
|
||||||
// 許可されたカラムのみソート(安全対策)
|
|
||||||
$allowedSorts = ['setting_id', 'setting_key', 'setting_value']; // ← 必要に応じて増やす
|
|
||||||
|
|
||||||
if (!in_array($sort, $allowedSorts)) {
|
|
||||||
$sort = 'setting_id';
|
|
||||||
}
|
|
||||||
if (!in_array($sort_type, ['asc', 'desc'])) {
|
|
||||||
$sort_type = 'desc';
|
|
||||||
}
|
|
||||||
|
|
||||||
$list = Setting::orderBy($sort, $sort_type)->paginate($perPage);
|
|
||||||
|
|
||||||
return view('admin.settings.list', [
|
|
||||||
'list' => $list,
|
|
||||||
'sort' => $sort,
|
|
||||||
'sort_type' => $sort_type,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 新規追加(GET/POST): /settings/add
|
|
||||||
*/
|
|
||||||
public function add(Request $request)
|
|
||||||
{
|
|
||||||
if ($request->isMethod('post')) {
|
|
||||||
$v = Validator::make($request->all(), $this->rules());
|
|
||||||
if ($v->fails()) {
|
|
||||||
return back()->withErrors($v)->withInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
// チェックボックス(未送信時は false)
|
|
||||||
$data = $this->onlyFillable($request);
|
|
||||||
$data['printable_alert_flag'] = $request->boolean('printable_alert_flag');
|
|
||||||
|
|
||||||
DB::transaction(function () use ($data) {
|
|
||||||
Setting::create($data);
|
|
||||||
});
|
|
||||||
|
|
||||||
return redirect()->route('settings')->with('success', '設定を登録しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
// GET時:空フォーム表示
|
|
||||||
return view('admin.settings.add', [
|
|
||||||
'setting' => new Setting(), // フォーム初期化用
|
|
||||||
'isEdit' => false,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 編集(GET/POST): /settings/edit/{id}
|
|
||||||
*/
|
|
||||||
public function edit(Request $request, int $id)
|
|
||||||
{
|
|
||||||
$setting = Setting::findOrFail($id);
|
|
||||||
|
|
||||||
if ($request->isMethod('post')) {
|
|
||||||
$v = Validator::make($request->all(), $this->rules($id));
|
|
||||||
if ($v->fails()) {
|
|
||||||
return back()->withErrors($v)->withInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = $this->onlyFillable($request);
|
|
||||||
$data['printable_alert_flag'] = $request->boolean('printable_alert_flag');
|
|
||||||
|
|
||||||
DB::transaction(function () use ($setting, $data) {
|
|
||||||
$setting->update($data);
|
|
||||||
});
|
|
||||||
|
|
||||||
return redirect()->route('settings')->with('success', '設定を更新しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
// GET時:編集フォーム表示
|
|
||||||
return view('admin.settings.edit', [
|
|
||||||
'setting' => $setting,
|
|
||||||
'isEdit' => true,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 詳細表示: /settings/info/{id}
|
|
||||||
*/
|
|
||||||
public function info(int $id)
|
|
||||||
{
|
|
||||||
$setting = Setting::findOrFail($id);
|
|
||||||
|
|
||||||
return view('admin.settings.info', [
|
|
||||||
'setting' => $setting,
|
|
||||||
'isInfo' => true,
|
|
||||||
'isEdit' => false,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 削除(一覧/編集 共通対応): /settings/delete または /settings/delete/{id}
|
|
||||||
*/
|
|
||||||
public function delete(Request $request, $id = null)
|
|
||||||
{
|
|
||||||
// 一覧画面(checkbox で複数削除)
|
|
||||||
$ids = $request->input('ids');
|
|
||||||
|
|
||||||
// 編集画面(単体削除)
|
|
||||||
if ($id) {
|
|
||||||
$ids = [$id];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 削除対象が空
|
|
||||||
if (empty($ids)) {
|
|
||||||
return redirect()->route('settings')->with('error', '削除対象が選択されていません。');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 削除処理
|
|
||||||
Setting::destroy($ids);
|
|
||||||
|
|
||||||
return redirect()->route('settings')->with('success', '設定を削除しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ===== バリデーション・ユーティリティ =====
|
|
||||||
|
|
||||||
/**
|
|
||||||
* バリデーションルール
|
|
||||||
*/
|
|
||||||
private function rules(?int $id = null): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'edit_master' => ['nullable','string','max:255'],
|
|
||||||
'web_master' => ['nullable','string','max:255'],
|
|
||||||
'auto_change_date' => ['nullable','date'],
|
|
||||||
'auto_chage_master' => ['nullable','string','max:255'], // ※カラム名は仕様通り
|
|
||||||
're-issue_alert_number' => ['nullable','integer','min:0'],
|
|
||||||
'image_base_url1' => ['nullable','string','max:255'],
|
|
||||||
'image_base_url2' => ['nullable','string','max:255'],
|
|
||||||
'printable_alert_flag' => ['nullable','boolean'],
|
|
||||||
'printable_number' => ['nullable','integer','min:0'],
|
|
||||||
'printable_alert_number' => ['nullable','integer','min:0'],
|
|
||||||
'printer_keep_alive' => ['nullable','integer','min:0'],
|
|
||||||
'operator_id' => ['nullable','integer','min:0'],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* フォームから fillable のみ抽出
|
|
||||||
*/
|
|
||||||
private function onlyFillable(Request $request): array
|
|
||||||
{
|
|
||||||
return $request->only([
|
|
||||||
'edit_master',
|
|
||||||
'web_master',
|
|
||||||
'auto_change_date',
|
|
||||||
'auto_chage_master',
|
|
||||||
're-issue_alert_number',
|
|
||||||
'image_base_url1',
|
|
||||||
'image_base_url2',
|
|
||||||
'printable_number',
|
|
||||||
'printable_alert_number',
|
|
||||||
'printer_keep_alive',
|
|
||||||
'operator_id',
|
|
||||||
'printable_alert_flag',
|
|
||||||
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,289 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Models\SettlementTransaction;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
|
||||||
|
|
||||||
class SettlementTransactionController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 一覧
|
|
||||||
* ルート: settlement_transactions
|
|
||||||
*/
|
|
||||||
public function list(Request $request)
|
|
||||||
{
|
|
||||||
// 解除ボタンが押された場合 → 一覧にリダイレクトして検索条件リセット
|
|
||||||
if ($request->input('action') === 'unlink') {
|
|
||||||
return redirect()->route('settlement_transactions');
|
|
||||||
}
|
|
||||||
|
|
||||||
$q = SettlementTransaction::query();
|
|
||||||
|
|
||||||
// --- 絞り込み
|
|
||||||
$contractId = $request->input('contract_id');
|
|
||||||
$status = trim((string)$request->input('status', ''));
|
|
||||||
$from = $request->input('from'); // 支払日時 from
|
|
||||||
$to = $request->input('to'); // 支払日時 to
|
|
||||||
|
|
||||||
if ($contractId !== null && $contractId !== '') {
|
|
||||||
$q->where('contract_id', (int)$contractId);
|
|
||||||
}
|
|
||||||
if ($status !== '') {
|
|
||||||
$q->where('status', 'like', "%{$status}%");
|
|
||||||
}
|
|
||||||
if ($from) {
|
|
||||||
$q->whereDate('pay_date', '>=', $from);
|
|
||||||
}
|
|
||||||
if ($to) {
|
|
||||||
$q->whereDate('pay_date', '<=', $to);
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- ソート(既定:created_at desc)
|
|
||||||
$sort = $request->input('sort', 'created_at');
|
|
||||||
$type = strtolower($request->input('sort_type', 'desc'));
|
|
||||||
$allow = [
|
|
||||||
'settlement_transaction_id', 'created_at', 'updated_at',
|
|
||||||
'contract_id', 'status', 'pay_date', 'settlement_amount',
|
|
||||||
];
|
|
||||||
if (!in_array($sort, $allow, true)) $sort = 'created_at';
|
|
||||||
if (!in_array($type, ['asc', 'desc'], true)) $type = 'desc';
|
|
||||||
$q->orderBy($sort, $type);
|
|
||||||
|
|
||||||
return view('admin.settlement_transactions.list', [
|
|
||||||
'transactions' => $q->paginate(20)->appends($request->except('page')),
|
|
||||||
'contract_id' => $contractId,
|
|
||||||
'status' => $status,
|
|
||||||
'from' => $from,
|
|
||||||
'to' => $to,
|
|
||||||
'sort' => $sort,
|
|
||||||
'sort_type' => $type,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 新規
|
|
||||||
* ルート: settlement_transactions_add
|
|
||||||
*/
|
|
||||||
public function add(Request $request)
|
|
||||||
{
|
|
||||||
if ($request->isMethod('post')) {
|
|
||||||
$data = $this->validatePayload($request);
|
|
||||||
SettlementTransaction::create($data);
|
|
||||||
return redirect()->route('settlement_transactions')->with('success', '登録しました');
|
|
||||||
}
|
|
||||||
|
|
||||||
return view('admin.settlement_transactions.add', [
|
|
||||||
'transaction' => null,
|
|
||||||
'isEdit' => false,
|
|
||||||
'isInfo' => false,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 編集
|
|
||||||
* ルート: settlement_transactions_edit
|
|
||||||
*/
|
|
||||||
public function edit(int $settlement_transaction_id, Request $request)
|
|
||||||
{
|
|
||||||
$transaction = SettlementTransaction::findOrFail($settlement_transaction_id);
|
|
||||||
|
|
||||||
if ($request->isMethod('post')) {
|
|
||||||
$data = $this->validatePayload($request);
|
|
||||||
$transaction->update($data);
|
|
||||||
return redirect()->route('settlement_transactions')->with('success', '更新しました');
|
|
||||||
}
|
|
||||||
|
|
||||||
return view('admin.settlement_transactions.edit', [
|
|
||||||
'transaction' => $transaction,
|
|
||||||
'isEdit' => true,
|
|
||||||
'isInfo' => false,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 詳細
|
|
||||||
* ルート: settlement_transactions_info
|
|
||||||
*/
|
|
||||||
public function info(int $settlement_transaction_id)
|
|
||||||
{
|
|
||||||
$transaction = SettlementTransaction::findOrFail($settlement_transaction_id);
|
|
||||||
|
|
||||||
return view('admin.settlement_transactions.info', [
|
|
||||||
'transaction' => $transaction,
|
|
||||||
'isEdit' => false,
|
|
||||||
'isInfo' => true,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 一括削除(一覧のチェック name="ids[]")
|
|
||||||
* ルート: settlement_transactions_delete
|
|
||||||
*/
|
|
||||||
public function delete(Request $request)
|
|
||||||
{
|
|
||||||
$ids = (array) $request->input('ids', []);
|
|
||||||
$ids = array_values(array_filter($ids, fn($v) => preg_match('/^\d+$/', (string)$v)));
|
|
||||||
|
|
||||||
if (!$ids) {
|
|
||||||
return redirect()->route('settlement_transactions')->with('error', '削除対象が選択されていません。');
|
|
||||||
}
|
|
||||||
|
|
||||||
SettlementTransaction::whereIn('settlement_transaction_id', $ids)->delete();
|
|
||||||
|
|
||||||
return redirect()->route('settlement_transactions')->with('success', '削除しました');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CSVインポート(簡易)
|
|
||||||
* ルート: settlement_transactions_import
|
|
||||||
*
|
|
||||||
* 想定カラム順:
|
|
||||||
* contract_id,status,pay_code,contract_payment_number,corp_code,
|
|
||||||
* mms_date,cvs_code,shop_code,pay_date,settlement_amount,stamp_flag,md5_string
|
|
||||||
* 1行目ヘッダ可
|
|
||||||
*/
|
|
||||||
public function import(Request $request)
|
|
||||||
{
|
|
||||||
$request->validate([
|
|
||||||
'file' => ['required', 'file', 'mimetypes:text/plain,text/csv,text/tsv', 'max:4096'],
|
|
||||||
]);
|
|
||||||
|
|
||||||
$path = $request->file('file')->getRealPath();
|
|
||||||
|
|
||||||
$created = 0;
|
|
||||||
$updated = 0;
|
|
||||||
$skipped = 0;
|
|
||||||
|
|
||||||
DB::beginTransaction();
|
|
||||||
try {
|
|
||||||
if (($fp = fopen($path, 'r')) !== false) {
|
|
||||||
$line = 0;
|
|
||||||
while (($row = fgetcsv($fp)) !== false) {
|
|
||||||
$line++;
|
|
||||||
|
|
||||||
// ヘッダ行をスキップ
|
|
||||||
if ($line === 1) {
|
|
||||||
$joined = strtolower(implode(',', $row));
|
|
||||||
if (str_contains($joined, 'contract_id') || str_contains($joined, 'status')) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 入力列を安全に展開
|
|
||||||
[$contract_id,$status,$pay_code,$contract_payment_number,$corp_code,$mms_date,$cvs_code,$shop_code,$pay_date,$settlement_amount,$stamp_flag,$md5_string] = array_pad($row, 12, null);
|
|
||||||
|
|
||||||
// 正規化
|
|
||||||
$payload = [
|
|
||||||
'contract_id' => ($contract_id === '' || $contract_id === null) ? null : (int)$contract_id,
|
|
||||||
'status' => $status !== null ? trim($status) : null,
|
|
||||||
'pay_code' => $pay_code !== null ? trim($pay_code) : null,
|
|
||||||
'contract_payment_number' => $contract_payment_number !== null ? trim($contract_payment_number) : null,
|
|
||||||
'corp_code' => $corp_code !== null ? trim($corp_code) : null,
|
|
||||||
'mms_date' => $mms_date !== null ? trim($mms_date) : null,
|
|
||||||
'cvs_code' => $cvs_code !== null ? trim($cvs_code) : null,
|
|
||||||
'shop_code' => $shop_code !== null ? trim($shop_code) : null,
|
|
||||||
'pay_date' => $pay_date ? date('Y-m-d H:i:s', strtotime($pay_date)) : null,
|
|
||||||
'settlement_amount' => ($settlement_amount === '' || $settlement_amount === null) ? null : (float)preg_replace('/[^\d.]/','',$settlement_amount),
|
|
||||||
'stamp_flag' => $stamp_flag !== null ? trim($stamp_flag) : null,
|
|
||||||
'md5_string' => $md5_string !== null ? trim($md5_string) : null,
|
|
||||||
];
|
|
||||||
|
|
||||||
// upsert キー(優先: md5_string、なければ contract_id+pay_date)
|
|
||||||
$ex = null;
|
|
||||||
if (!empty($payload['md5_string'])) {
|
|
||||||
$ex = SettlementTransaction::where('md5_string', $payload['md5_string'])->first();
|
|
||||||
} elseif (!empty($payload['contract_id']) && !empty($payload['pay_date'])) {
|
|
||||||
$ex = SettlementTransaction::where('contract_id', $payload['contract_id'])
|
|
||||||
->where('pay_date', $payload['pay_date'])->first();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($ex) { $ex->update($payload); $updated++; }
|
|
||||||
else { SettlementTransaction::create($payload); $created++; }
|
|
||||||
}
|
|
||||||
fclose($fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
DB::commit();
|
|
||||||
return redirect()->route('settlement_transactions')
|
|
||||||
->with('success', "インポート完了:新規 {$created} 件、更新 {$updated} 件、スキップ {$skipped} 件");
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
DB::rollBack();
|
|
||||||
return redirect()->route('settlement_transactions')
|
|
||||||
->with('error', 'インポートに失敗しました:' . $e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CSVエクスポート
|
|
||||||
* ルート: settlement_transactions_export
|
|
||||||
*/
|
|
||||||
public function export(Request $request): StreamedResponse
|
|
||||||
{
|
|
||||||
$q = SettlementTransaction::query();
|
|
||||||
|
|
||||||
// 一覧と同じソートを適用(任意で絞り込みも追加可能)
|
|
||||||
$sort = $request->input('sort', 'created_at');
|
|
||||||
$type = strtolower($request->input('sort_type', 'desc'));
|
|
||||||
if (!in_array($type, ['asc','desc'], true)) $type = 'desc';
|
|
||||||
$q->orderBy($sort, $type);
|
|
||||||
|
|
||||||
$filename = 'settlement_transactions_' . now()->format('Ymd_His') . '.csv';
|
|
||||||
|
|
||||||
return response()->streamDownload(function () use ($q) {
|
|
||||||
$out = fopen('php://output', 'w');
|
|
||||||
fputcsv($out, [
|
|
||||||
'ID','契約ID','ステータス','支払コード','契約課金番号','企業コード',
|
|
||||||
'MMS日付','CVSコード','店舗コード','支払日時','金額','スタンプ','MD5',
|
|
||||||
'登録日時','更新日時'
|
|
||||||
]);
|
|
||||||
$q->chunk(500, function ($rows) use ($out) {
|
|
||||||
foreach ($rows as $r) {
|
|
||||||
fputcsv($out, [
|
|
||||||
$r->settlement_transaction_id,
|
|
||||||
$r->contract_id,
|
|
||||||
$r->status,
|
|
||||||
$r->pay_code,
|
|
||||||
$r->contract_payment_number,
|
|
||||||
$r->corp_code,
|
|
||||||
$r->mms_date,
|
|
||||||
$r->cvs_code,
|
|
||||||
$r->shop_code,
|
|
||||||
optional($r->pay_date)->format('Y-m-d H:i:s'),
|
|
||||||
$r->settlement_amount,
|
|
||||||
$r->stamp_flag,
|
|
||||||
$r->md5_string,
|
|
||||||
optional($r->created_at)->format('Y-m-d H:i:s'),
|
|
||||||
optional($r->updated_at)->format('Y-m-d H:i:s'),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
fclose($out);
|
|
||||||
}, $filename, ['Content-Type' => 'text/csv; charset=UTF-8']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 共通バリデーション
|
|
||||||
*/
|
|
||||||
private function validatePayload(Request $request): array
|
|
||||||
{
|
|
||||||
return $request->validate([
|
|
||||||
'contract_id' => ['nullable','integer'],
|
|
||||||
'status' => ['nullable','string','max:255'],
|
|
||||||
'pay_code' => ['nullable','string','max:255'],
|
|
||||||
'contract_payment_number' => ['nullable','string','max:255'],
|
|
||||||
'corp_code' => ['nullable','string','max:255'],
|
|
||||||
'mms_date' => ['nullable','string','max:255'],
|
|
||||||
'cvs_code' => ['nullable','string','max:255'],
|
|
||||||
'shop_code' => ['nullable','string','max:255'],
|
|
||||||
'pay_date' => ['nullable','date'],
|
|
||||||
'settlement_amount' => ['nullable','numeric'], // DB は decimal(10,0)
|
|
||||||
'stamp_flag' => ['nullable','string','max:255'],
|
|
||||||
'md5_string' => ['nullable','string','max:255'],
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,229 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use App\Models\Station;
|
|
||||||
use Illuminate\Support\Facades\Validator;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use App\Models\Park;
|
|
||||||
|
|
||||||
|
|
||||||
class StationController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 一覧表示
|
|
||||||
*/
|
|
||||||
public function list(Request $request)
|
|
||||||
{
|
|
||||||
$sort = $request->input('sort', 'station_id');
|
|
||||||
$sort_type = $request->input('sort_type', 'asc');
|
|
||||||
|
|
||||||
$allowedSorts = [
|
|
||||||
'station_id',
|
|
||||||
'park_id',
|
|
||||||
'station_neighbor_station',
|
|
||||||
'station_name_ruby',
|
|
||||||
'station_route_name'
|
|
||||||
];
|
|
||||||
if (!in_array($sort, $allowedSorts)) {
|
|
||||||
$sort = 'station_id';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!in_array($sort_type, ['asc', 'desc'])) {
|
|
||||||
$sort_type = 'asc';
|
|
||||||
}
|
|
||||||
|
|
||||||
$list = Station::select([
|
|
||||||
'station_id',
|
|
||||||
'station_neighbor_station',
|
|
||||||
'station_name_ruby',
|
|
||||||
'station_route_name',
|
|
||||||
'park_id',
|
|
||||||
'operator_id',
|
|
||||||
'station_latitude',
|
|
||||||
'station_longitude',
|
|
||||||
])
|
|
||||||
->orderBy($sort, $sort_type)
|
|
||||||
->paginate(20);
|
|
||||||
|
|
||||||
return view('admin.stations.list', compact('list', 'sort', 'sort_type'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function add(Request $request)
|
|
||||||
{
|
|
||||||
if ($request->isMethod('get')) {
|
|
||||||
// 駐車場リストを取得(プルダウン用)
|
|
||||||
$parks = Park::orderBy('park_name')->pluck('park_name', 'park_id');
|
|
||||||
|
|
||||||
// 新規時:空レコードを渡す
|
|
||||||
return view('admin.stations.add', [
|
|
||||||
'isEdit' => false,
|
|
||||||
'record' => new Station(),
|
|
||||||
'parks' => $parks, // ← これを追加
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// POST時:バリデーション
|
|
||||||
$rules = [
|
|
||||||
'station_neighbor_station' => 'required|string|max:255',
|
|
||||||
'station_name_ruby' => 'required|string|max:255',
|
|
||||||
'station_route_name' => 'required|string|max:255',
|
|
||||||
'station_latitude' => 'required|numeric',
|
|
||||||
'station_longitude' => 'required|numeric',
|
|
||||||
'operator_id' => 'nullable|integer',
|
|
||||||
'park_id' => 'required|integer',
|
|
||||||
];
|
|
||||||
|
|
||||||
$messages = [
|
|
||||||
'station_latitude.required' => '緯度は必須項目です。',
|
|
||||||
'station_longitude.required' => '経度は必須項目です。',
|
|
||||||
];
|
|
||||||
|
|
||||||
$validator = Validator::make($request->all(), $rules, $messages);
|
|
||||||
|
|
||||||
if ($validator->fails()) {
|
|
||||||
return redirect()->back()->withErrors($validator)->withInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
DB::transaction(function () use ($request) {
|
|
||||||
Station::create($request->only([
|
|
||||||
'station_neighbor_station',
|
|
||||||
'station_name_ruby',
|
|
||||||
'station_route_name',
|
|
||||||
'station_latitude',
|
|
||||||
'station_longitude',
|
|
||||||
'park_id',
|
|
||||||
'operator_id',
|
|
||||||
]));
|
|
||||||
});
|
|
||||||
|
|
||||||
return redirect()->route('stations')->with('success', '登録しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 編集(画面/処理)
|
|
||||||
*/
|
|
||||||
public function edit(Request $request, $id)
|
|
||||||
{
|
|
||||||
$record = Station::findOrFail($id);
|
|
||||||
|
|
||||||
if ($request->isMethod('get')) {
|
|
||||||
// 駐車場リストを取得(プルダウン用)
|
|
||||||
$parks = Park::orderBy('park_name')->pluck('park_name', 'park_id');
|
|
||||||
|
|
||||||
return view('admin.stations.edit', [
|
|
||||||
'isEdit' => true,
|
|
||||||
'record' => $record,
|
|
||||||
'parks' => $parks, // ← ここを追加
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ▼ POST時:バリデーション
|
|
||||||
$rules = [
|
|
||||||
'station_neighbor_station' => 'required|string|max:255',
|
|
||||||
'station_name_ruby' => 'required|string|max:255',
|
|
||||||
'station_route_name' => 'required|string|max:255',
|
|
||||||
'station_latitude' => 'required|numeric',
|
|
||||||
'station_longitude' => 'required|numeric',
|
|
||||||
'operator_id' => 'nullable|integer',
|
|
||||||
'park_id' => 'required|integer',
|
|
||||||
];
|
|
||||||
|
|
||||||
$messages = [
|
|
||||||
'station_latitude.required' => '緯度は必須項目です。',
|
|
||||||
'station_longitude.required' => '経度は必須項目です。',
|
|
||||||
];
|
|
||||||
|
|
||||||
$validator = Validator::make($request->all(), $rules, $messages);
|
|
||||||
|
|
||||||
if ($validator->fails()) {
|
|
||||||
return redirect()->back()->withErrors($validator)->withInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
DB::transaction(function () use ($request, $record) {
|
|
||||||
$record->update($request->only([
|
|
||||||
'station_neighbor_station',
|
|
||||||
'station_name_ruby',
|
|
||||||
'station_route_name',
|
|
||||||
'park_id',
|
|
||||||
'operator_id',
|
|
||||||
'station_latitude',
|
|
||||||
'station_longitude',
|
|
||||||
]));
|
|
||||||
});
|
|
||||||
|
|
||||||
return redirect()->route('stations')->with('success', '更新しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 削除(単一/複数対応)
|
|
||||||
*/
|
|
||||||
public function delete(Request $request)
|
|
||||||
{
|
|
||||||
$ids = [];
|
|
||||||
|
|
||||||
if ($request->filled('id')) {
|
|
||||||
$ids[] = (int) $request->input('id');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_array($request->input('pk'))) {
|
|
||||||
$ids = array_merge($ids, $request->input('pk'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$ids = array_values(array_unique(array_map('intval', $ids)));
|
|
||||||
|
|
||||||
if (empty($ids)) {
|
|
||||||
return back()->with('error', '削除対象が選択されていません。');
|
|
||||||
}
|
|
||||||
|
|
||||||
Station::whereIn('station_id', $ids)->delete();
|
|
||||||
|
|
||||||
return redirect()->route('stations')->with('success', '削除しました');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CSVインポート(仮)
|
|
||||||
*/
|
|
||||||
public function import(Request $request)
|
|
||||||
{
|
|
||||||
// TODO: 実装予定
|
|
||||||
return redirect()->route('stations')->with('info', 'CSVインポートは未実装です');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CSVエクスポート(日本語ヘッダー付き)
|
|
||||||
*/
|
|
||||||
public function export()
|
|
||||||
{
|
|
||||||
// ファイル名
|
|
||||||
$filename = '近傍駅マスタ_' . now()->format('YmdHis') . '.csv';
|
|
||||||
|
|
||||||
return response()->streamDownload(function () {
|
|
||||||
// Excel用 UTF-8 BOM
|
|
||||||
echo "\xEF\xBB\xBF";
|
|
||||||
|
|
||||||
// 日本語ヘッダー行
|
|
||||||
echo "近傍駅ID,駐車場ID,近傍駅,近傍駅ふりがな,路線名,近傍駅座標(緯度),近傍駅座標(経度)\n";
|
|
||||||
|
|
||||||
// データ行
|
|
||||||
foreach (\App\Models\Station::all() as $station) {
|
|
||||||
echo implode(',', [
|
|
||||||
$station->station_id,
|
|
||||||
$station->park_id,
|
|
||||||
$station->station_neighbor_station,
|
|
||||||
$station->station_name_ruby,
|
|
||||||
$station->station_route_name,
|
|
||||||
$station->station_latitude,
|
|
||||||
$station->station_longitude,
|
|
||||||
// $station->operator_id,
|
|
||||||
]) . "\n";
|
|
||||||
}
|
|
||||||
}, $filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -5,183 +5,37 @@ namespace App\Http\Controllers\Admin;
|
|||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Barryvdh\DomPDF\Facade\Pdf;
|
|
||||||
|
|
||||||
class TagissueController extends Controller
|
class TagissueController extends Controller
|
||||||
{
|
{
|
||||||
// タグ発送宛名PDF生成
|
|
||||||
public function printUnissuedLabels(Request $request)
|
|
||||||
{
|
|
||||||
$ids = $request->input('ids', []);
|
|
||||||
if (empty($ids) || !is_array($ids)) {
|
|
||||||
return back()->with('error', '1件以上選択してください。');
|
|
||||||
}
|
|
||||||
// 利用者情報取得
|
|
||||||
$users = DB::table('user')
|
|
||||||
->whereIn('user_id', $ids)
|
|
||||||
->select('user_name', 'user_regident_zip', 'user_regident_pre')
|
|
||||||
->get();
|
|
||||||
|
|
||||||
// PDF生成(Laravel-dompdf使用例)
|
|
||||||
$pdfHtml = view('admin.tag_issue.pdf_labels', ['users' => $users])->render();
|
|
||||||
$pdf = Pdf::setOptions(['isRemoteEnabled' => true])->loadHTML($pdfHtml);
|
|
||||||
return $pdf->download('tag_labels.pdf');
|
|
||||||
}
|
|
||||||
public function list(Request $request)
|
public function list(Request $request)
|
||||||
{
|
{
|
||||||
// 絞り込み条件
|
// userテーブルから必要なカラムを取得
|
||||||
$filterType = $request->input('filter_type'); // 'unissued', 'issued', 'all', 'unissued_toggle'
|
|
||||||
$tagSerial = $request->input('tag_serial');
|
|
||||||
$tagSerial64 = $request->input('tag_serial_64');
|
|
||||||
|
|
||||||
// ソートパラメータ取得
|
|
||||||
$sort = $request->input('sort');
|
|
||||||
$sortType = $request->input('sort_type', 'asc');
|
|
||||||
|
|
||||||
// userテーブルとoperator_queテーブルをJOIN
|
|
||||||
$query = DB::table('user')
|
$query = DB::table('user')
|
||||||
->leftJoin('operator_que', 'user.user_id', '=', 'operator_que.user_id')
|
|
||||||
->select(
|
->select(
|
||||||
'user.user_seq',
|
'user_seq',
|
||||||
'user.user_id',
|
'user_tag_serial',
|
||||||
'user.user_tag_serial',
|
'user_tag_serial_64',
|
||||||
'user.user_tag_serial_64',
|
'user_tag_issue',
|
||||||
'user.user_tag_issue',
|
'user_name',
|
||||||
'user.user_name',
|
'user_mobile',
|
||||||
'user.user_mobile',
|
'user_homephone',
|
||||||
'user.user_homephone',
|
'user_regident_zip',
|
||||||
'user.user_regident_zip',
|
'user_regident_pre',
|
||||||
'user.user_regident_pre',
|
'user_regident_city',
|
||||||
'user.user_regident_city',
|
'user_regident_add'
|
||||||
'user.user_regident_add',
|
)
|
||||||
'user.user_relate_zip',
|
->orderByDesc('user_seq');
|
||||||
'user.user_relate_pre',
|
|
||||||
'user.user_relate_city',
|
|
||||||
'user.user_relate_add',
|
|
||||||
'operator_que.que_id',
|
|
||||||
'operator_que.que_class',
|
|
||||||
'operator_que.que_status'
|
|
||||||
);
|
|
||||||
|
|
||||||
// ソート項目に応じたorderBy
|
// 必要に応じてフィルタ追加
|
||||||
switch ($sort) {
|
// if ($request->filled('user_tag_issue')) {
|
||||||
case 'que_id':
|
// $query->where('user_tag_issue', $request->input('user_tag_issue'));
|
||||||
$query->orderBy('operator_que.que_id', $sortType);
|
// }
|
||||||
break;
|
|
||||||
case 'user_tag_serial':
|
|
||||||
$query->orderBy('user.user_tag_serial', $sortType);
|
|
||||||
break;
|
|
||||||
case 'user_tag_serial_64':
|
|
||||||
$query->orderBy('user.user_tag_serial_64', $sortType);
|
|
||||||
break;
|
|
||||||
case 'user_tag_issue':
|
|
||||||
$query->orderBy('user.user_tag_issue', $sortType);
|
|
||||||
break;
|
|
||||||
case 'user_name':
|
|
||||||
$query->orderBy('user.user_name', $sortType);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
$query->orderByDesc('user.user_seq');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 【種別フィルター】タグ未発送(通常)
|
|
||||||
if ($filterType === 'unissued') {
|
|
||||||
$query->where('operator_que.que_class', 3)
|
|
||||||
->where('operator_que.que_status', 1);
|
|
||||||
}
|
|
||||||
// 【種別フィルター】タグ未発送トグル(que_class=3かつque_status≠3)
|
|
||||||
if ($filterType === 'unissued_toggle') {
|
|
||||||
$query->where('operator_que.que_class', 3)
|
|
||||||
->where('operator_que.que_status', '<>', 3);
|
|
||||||
}
|
|
||||||
// 【種別フィルター】タグ発送済み(通常)
|
|
||||||
if ($filterType === 'issued') {
|
|
||||||
$query->where('operator_que.que_class', 3)
|
|
||||||
->where('operator_que.que_status', 3);
|
|
||||||
}
|
|
||||||
// 【種別フィルター】タグ発送済みトグル(que_class=3 and que_status=3)
|
|
||||||
if ($filterType === 'issued_toggle') {
|
|
||||||
$query->where('operator_que.que_class', 3)
|
|
||||||
->where('operator_que.que_status', 3);
|
|
||||||
}
|
|
||||||
// 【タグシリアル・タグシリアル64進フィルター】
|
|
||||||
if (!empty($tagSerial)) {
|
|
||||||
$query->where('user.user_tag_serial', 'like', "%$tagSerial%");
|
|
||||||
}
|
|
||||||
if (!empty($tagSerial64)) {
|
|
||||||
$query->where('user.user_tag_serial_64', 'like', "%$tagSerial64%");
|
|
||||||
}
|
|
||||||
|
|
||||||
$users = $query->paginate(20);
|
$users = $query->paginate(20);
|
||||||
|
|
||||||
return view('admin.tag_issue.list', [
|
return view('admin.tag_issue.list', [
|
||||||
'users' => $users,
|
'users' => $users,
|
||||||
'filterType' => $filterType,
|
|
||||||
'tagSerial' => $tagSerial,
|
|
||||||
'tagSerial64' => $tagSerial64,
|
|
||||||
'sort' => $sort,
|
|
||||||
'sortType' => $sortType,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ステータス変更(タグ発送済み/未発送)
|
|
||||||
public function updateStatus(Request $request)
|
|
||||||
{
|
|
||||||
$ids = $request->input('ids', []); // チェックされたuser_id配列
|
|
||||||
$action = $request->input('action'); // 'to_issued' or 'to_unissued'
|
|
||||||
|
|
||||||
$operatorId = auth()->id();
|
|
||||||
$now = now();
|
|
||||||
// 対象ユーザーのoperator_queを取得
|
|
||||||
$ques = DB::table('operator_que')->whereIn('user_id', $ids)->get();
|
|
||||||
if ($action === 'to_issued') {
|
|
||||||
$alreadyIssued = $ques->where('que_status', 3)->pluck('user_id')->toArray();
|
|
||||||
if (count($alreadyIssued) > 0) {
|
|
||||||
return back()->with('error', 'すでにタグ発送済みのユーザーが含まれています。');
|
|
||||||
}
|
|
||||||
// 確認ダイアログはJS側で
|
|
||||||
DB::table('operator_que')->whereIn('user_id', $ids)
|
|
||||||
->update(['que_status' => 3, 'updated_at' => $now, 'operator_id' => $operatorId]);
|
|
||||||
return back()->with('success', 'ステータスをタグ発送済に変更しました。');
|
|
||||||
}
|
|
||||||
if ($action === 'to_unissued') {
|
|
||||||
$alreadyUnissued = $ques->where('que_status', 1)->pluck('user_id')->toArray();
|
|
||||||
if (count($alreadyUnissued) > 0) {
|
|
||||||
// 既にタグ未発送のユーザー名を取得
|
|
||||||
$names = DB::table('user')->whereIn('user_id', $alreadyUnissued)->pluck('user_name')->toArray();
|
|
||||||
return back()->with('error', 'すでにタグ未発送のユーザーが含まれています: ' . implode(', ', $names));
|
|
||||||
}
|
|
||||||
// すべてque_status=1以外なので更新
|
|
||||||
DB::table('operator_que')->whereIn('user_id', $ids)
|
|
||||||
->update(['que_status' => 1, 'updated_at' => $now, 'operator_id' => $operatorId]);
|
|
||||||
return back()->with('success', 'ステータスをタグ未発送に変更しました。');
|
|
||||||
}
|
|
||||||
return back()->with('error', '不正な操作です。');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ajax: 選択user_idのque_statusを返す(タグ発送済み/未発送判定)
|
|
||||||
public function checkStatus(Request $request)
|
|
||||||
{
|
|
||||||
$ids = $request->input('ids', []);
|
|
||||||
$type = $request->input('type'); // 'issued' or 'unissued'
|
|
||||||
$users = DB::table('user')
|
|
||||||
->leftJoin('operator_que', 'user.user_id', '=', 'operator_que.user_id')
|
|
||||||
->whereIn('user.user_id', $ids)
|
|
||||||
->select('user.user_name', 'operator_que.que_status')
|
|
||||||
->get();
|
|
||||||
$alreadyIssued = [];
|
|
||||||
$alreadyUnissued = [];
|
|
||||||
foreach ($users as $u) {
|
|
||||||
if ($type === 'issued' && $u->que_status == 3) {
|
|
||||||
$alreadyIssued[] = $u->user_name;
|
|
||||||
}
|
|
||||||
if ($type === 'unissued' && $u->que_status == 1) {
|
|
||||||
$alreadyUnissued[] = $u->user_name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return response()->json([
|
|
||||||
'alreadyIssued' => $alreadyIssued,
|
|
||||||
'alreadyUnissued' => $alreadyUnissued
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,293 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Models\Tax;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
|
||||||
|
|
||||||
class TaxController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 一覧:キーワード/適用日範囲で絞り込み + ソート + ページング
|
|
||||||
*/
|
|
||||||
public function list(Request $request)
|
|
||||||
{
|
|
||||||
$query = Tax::query();
|
|
||||||
|
|
||||||
// 絞り込み
|
|
||||||
$keyword = trim((string) $request->input('kw'));
|
|
||||||
if ($keyword !== '') {
|
|
||||||
$query->where('tax_percent', 'like', "%{$keyword}%");
|
|
||||||
}
|
|
||||||
$from = $request->input('from');
|
|
||||||
$to = $request->input('to');
|
|
||||||
if ($from) {
|
|
||||||
$query->whereDate('tax_day', '>=', $from);
|
|
||||||
}
|
|
||||||
if ($to) {
|
|
||||||
$query->whereDate('tax_day', '<=', $to);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ソート(既定:ID 昇順)
|
|
||||||
$sort = $request->input('sort', 'tax_id');
|
|
||||||
$type = strtolower($request->input('sort_type', 'asc'));
|
|
||||||
$allow = ['tax_day', 'tax_percent', 'updated_at', 'created_at', 'tax_id'];
|
|
||||||
if (!in_array($sort, $allow, true)) {
|
|
||||||
$sort = 'tax_id';
|
|
||||||
}
|
|
||||||
if (!in_array($type, ['asc', 'desc'], true)) {
|
|
||||||
$type = 'asc';
|
|
||||||
}
|
|
||||||
$query->orderBy($sort, $type);
|
|
||||||
|
|
||||||
$list = $query->paginate(20)->appends($request->except('page'));
|
|
||||||
|
|
||||||
return view('admin.tax.list', [
|
|
||||||
'taxes' => $list,
|
|
||||||
'kw' => $keyword,
|
|
||||||
'from' => $from,
|
|
||||||
'to' => $to,
|
|
||||||
'sort' => $sort,
|
|
||||||
'sort_type' => $type,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function add(Request $request)
|
|
||||||
{
|
|
||||||
if ($request->isMethod('post')) {
|
|
||||||
$data = $request->validate([
|
|
||||||
'tax_percent' => ['required', 'numeric', 'min:0', 'max:1000'],
|
|
||||||
'tax_day' => ['required', 'date'],
|
|
||||||
]);
|
|
||||||
$data['operator_id'] = optional(\Auth::user())->ope_id ?? null;
|
|
||||||
$data['tax_percent'] = number_format((float)$data['tax_percent'], 2, '.', '');
|
|
||||||
\App\Models\Tax::create($data);
|
|
||||||
|
|
||||||
return redirect()->route('tax')->with('success', '登録しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
return view('admin.tax.add', [
|
|
||||||
'tax' => null,
|
|
||||||
'isEdit' => false,
|
|
||||||
'isInfo' => false,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function edit(int $tax_id, Request $request)
|
|
||||||
{
|
|
||||||
$tax = \App\Models\Tax::findOrFail($tax_id);
|
|
||||||
|
|
||||||
if ($request->isMethod('post')) {
|
|
||||||
$data = $request->validate([
|
|
||||||
'tax_percent' => ['required', 'numeric', 'min:0', 'max:1000'],
|
|
||||||
'tax_day' => ['required', 'date'],
|
|
||||||
]);
|
|
||||||
$data['operator_id'] = optional(\Auth::user())->ope_id ?? null;
|
|
||||||
$data['tax_percent'] = number_format((float)$data['tax_percent'], 2, '.', '');
|
|
||||||
$tax->update($data);
|
|
||||||
|
|
||||||
return redirect()->route('tax')->with('success', '更新しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
return view('admin.tax.edit', [
|
|
||||||
'tax' => $tax,
|
|
||||||
'isEdit' => true,
|
|
||||||
'isInfo' => false,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function info(int $tax_id)
|
|
||||||
{
|
|
||||||
$tax = \App\Models\Tax::findOrFail($tax_id);
|
|
||||||
|
|
||||||
return view('admin.tax.info', [
|
|
||||||
'tax' => $tax,
|
|
||||||
'isEdit' => false,
|
|
||||||
'isInfo' => true,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 一括削除(一覧のチェックボックスで送られてくる想定)
|
|
||||||
* フォーム側 name="ids[]" の配列を POST
|
|
||||||
*/
|
|
||||||
public function delete(Request $request)
|
|
||||||
{
|
|
||||||
|
|
||||||
$pk = $request->input('pk', []);
|
|
||||||
|
|
||||||
// 配列に統一
|
|
||||||
$ids = is_array($pk) ? $pk : [$pk];
|
|
||||||
|
|
||||||
// 数字チェック
|
|
||||||
$ids = array_values(array_filter($ids, fn($v) => preg_match('/^\d+$/', (string) $v)));
|
|
||||||
|
|
||||||
if (empty($ids)) {
|
|
||||||
return redirect()->route('tax')->with('error', '削除対象が選択されていません。');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 削除
|
|
||||||
Tax::whereIn('tax_id', $ids)->delete();
|
|
||||||
|
|
||||||
return redirect()->route('tax')->with('success', '削除しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * CSVインポート
|
|
||||||
// * カラム想定: tax_percent, tax_day
|
|
||||||
// * - 1行目はヘッダ可
|
|
||||||
// * - tax_day をキーとして「存在すれば更新 / 無ければ作成」
|
|
||||||
// */
|
|
||||||
// public function import(Request $request)
|
|
||||||
// {
|
|
||||||
// $request->validate([
|
|
||||||
// 'file' => ['required', 'file', 'mimetypes:text/plain,text/csv,text/tsv', 'max:2048'],
|
|
||||||
// ]);
|
|
||||||
|
|
||||||
// $path = $request->file('file')->getRealPath();
|
|
||||||
// if (!$path || !is_readable($path)) {
|
|
||||||
// return redirect()->route('tax')->with('error', 'ファイルを読み込めません。');
|
|
||||||
// }
|
|
||||||
|
|
||||||
// $created = 0;
|
|
||||||
// $updated = 0;
|
|
||||||
// $skipped = 0;
|
|
||||||
|
|
||||||
// DB::beginTransaction();
|
|
||||||
// try {
|
|
||||||
// if (($fp = fopen($path, 'r')) !== false) {
|
|
||||||
// $line = 0;
|
|
||||||
// while (($row = fgetcsv($fp)) !== false) {
|
|
||||||
// $line++;
|
|
||||||
|
|
||||||
// // 空行スキップ
|
|
||||||
// if (count($row) === 1 && trim((string) $row[0]) === '') {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // ヘッダ行っぽい場合(1行目に 'tax_percent' を含む)
|
|
||||||
// if ($line === 1) {
|
|
||||||
// $joined = strtolower(implode(',', $row));
|
|
||||||
// if (str_contains($joined, 'tax_percent') && str_contains($joined, 'tax_day')) {
|
|
||||||
// continue; // ヘッダスキップ
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // 取り出し(列数が足りない場合スキップ)
|
|
||||||
// $percent = $row[0] ?? null;
|
|
||||||
// $day = $row[1] ?? null;
|
|
||||||
// if ($percent === null || $day === null) {
|
|
||||||
// $skipped++;
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // 正規化 & 検証
|
|
||||||
// $percent = trim((string) $percent);
|
|
||||||
// $percent = rtrim($percent, '%');
|
|
||||||
// $percent = preg_replace('/[^\d.]/', '', $percent) ?? '0';
|
|
||||||
// $percentF = (float) $percent;
|
|
||||||
// if ($percentF < 0) {
|
|
||||||
// $skipped++;
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
// $percentF = (float) number_format($percentF, 2, '.', '');
|
|
||||||
|
|
||||||
// $day = date('Y-m-d', strtotime((string) $day));
|
|
||||||
// if (!$day) {
|
|
||||||
// $skipped++;
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // upsert: 適用日ユニーク運用
|
|
||||||
// $existing = Tax::whereDate('tax_day', $day)->first();
|
|
||||||
// $payload = [
|
|
||||||
// 'tax_percent' => $percentF,
|
|
||||||
// 'tax_day' => $day,
|
|
||||||
// 'operator_id' => optional(Auth::user())->ope_id ?? null,
|
|
||||||
// ];
|
|
||||||
|
|
||||||
// if ($existing) {
|
|
||||||
// $existing->update($payload);
|
|
||||||
// $updated++;
|
|
||||||
// } else {
|
|
||||||
// Tax::create($payload);
|
|
||||||
// $created++;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// fclose($fp);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// DB::commit();
|
|
||||||
// return redirect()->route('tax')->with('success', "インポート完了:新規 {$created} 件、更新 {$updated} 件、スキップ {$skipped} 件");
|
|
||||||
// } catch (\Throwable $e) {
|
|
||||||
// DB::rollBack();
|
|
||||||
// return redirect()->route('tax')->with('error', 'インポートに失敗しました:' . $e->getMessage());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * CSVエクスポート:現在の絞り込み/ソート条件を反映
|
|
||||||
// */
|
|
||||||
// public function export(Request $request): StreamedResponse
|
|
||||||
// {
|
|
||||||
// $query = Tax::query();
|
|
||||||
|
|
||||||
// $keyword = trim((string) $request->input('kw'));
|
|
||||||
// if ($keyword !== '') {
|
|
||||||
// $query->where('tax_percent', 'like', "%{$keyword}%");
|
|
||||||
// }
|
|
||||||
// $from = $request->input('from');
|
|
||||||
// $to = $request->input('to');
|
|
||||||
// if ($from) {
|
|
||||||
// $query->whereDate('tax_day', '>=', $from);
|
|
||||||
// }
|
|
||||||
// if ($to) {
|
|
||||||
// $query->whereDate('tax_day', '<=', $to);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// $sort = $request->input('sort', 'tax_day');
|
|
||||||
// $type = strtolower($request->input('sort_type', 'desc'));
|
|
||||||
// $allow = ['tax_day', 'tax_percent', 'updated_at', 'created_at', 'tax_id'];
|
|
||||||
// if (!in_array($sort, $allow, true)) {
|
|
||||||
// $sort = 'tax_day';
|
|
||||||
// }
|
|
||||||
// if (!in_array($type, ['asc', 'desc'], true)) {
|
|
||||||
// $type = 'desc';
|
|
||||||
// }
|
|
||||||
// $query->orderBy($sort, $type);
|
|
||||||
|
|
||||||
// $filename = 'tax_' . now()->format('Ymd_His') . '.csv';
|
|
||||||
|
|
||||||
// return response()->streamDownload(function () use ($query) {
|
|
||||||
// $out = fopen('php://output', 'w');
|
|
||||||
// // Header(設計書の主要カラム)
|
|
||||||
// fputcsv($out, ['消費税ID', '消費税率', '適用日', '登録日時', '更新日時', '更新オペレータID']);
|
|
||||||
// $query->chunk(500, function ($rows) use ($out) {
|
|
||||||
// foreach ($rows as $r) {
|
|
||||||
// fputcsv($out, [
|
|
||||||
// $r->tax_id,
|
|
||||||
// // 画面仕様に合わせたい場合は getDisplayTaxPercentAttribute() に置換可
|
|
||||||
// is_numeric($r->tax_percent)
|
|
||||||
// ? number_format((float) $r->tax_percent, 2, '.', '')
|
|
||||||
// : (string) $r->tax_percent,
|
|
||||||
// optional($r->tax_day)->format('Y-m-d'),
|
|
||||||
// optional($r->created_at)->format('Y-m-d H:i:s'),
|
|
||||||
// optional($r->updated_at)->format('Y-m-d H:i:s'),
|
|
||||||
// $r->operator_id,
|
|
||||||
// ]);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// fclose($out);
|
|
||||||
// }, $filename, [
|
|
||||||
// 'Content-Type' => 'text/csv; charset=UTF-8',
|
|
||||||
// ]);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
@ -1,148 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use App\Models\Term;
|
|
||||||
use App\Models\City;
|
|
||||||
|
|
||||||
class TermsController extends Controller
|
|
||||||
{
|
|
||||||
// 一覧表示
|
|
||||||
public function list(Request $request)
|
|
||||||
{
|
|
||||||
$sort = $request->input('sort', 'terms_id');
|
|
||||||
$sort_type = $request->input('sort_type', 'asc');
|
|
||||||
|
|
||||||
$allowedSorts = ['terms_id', 'terms_revision', 'start_date', 'use_flag'];
|
|
||||||
if (!in_array($sort, $allowedSorts)) {
|
|
||||||
$sort = 'terms_id';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!in_array($sort_type, ['asc', 'desc'])) {
|
|
||||||
$sort_type = 'asc';
|
|
||||||
}
|
|
||||||
|
|
||||||
$terms = Term::select([
|
|
||||||
'terms_id',
|
|
||||||
'terms_revision',
|
|
||||||
'terms_text',
|
|
||||||
'start_date',
|
|
||||||
'use_flag',
|
|
||||||
'memo',
|
|
||||||
'city_id',
|
|
||||||
'operator_id'
|
|
||||||
])->orderBy($sort, $sort_type)->paginate(20);
|
|
||||||
|
|
||||||
return view('admin.terms.list', compact('terms', 'sort', 'sort_type'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 新規登録画面・登録処理
|
|
||||||
public function add(Request $request)
|
|
||||||
{
|
|
||||||
if ($request->isMethod('post')) {
|
|
||||||
$validated = $request->validate([
|
|
||||||
'city_id' => 'required|integer',
|
|
||||||
'terms_revision' => 'required|string|max:255',
|
|
||||||
'terms_text' => 'required|string',
|
|
||||||
'start_date' => 'nullable|date',
|
|
||||||
'use_flag' => 'required|in:0,1',
|
|
||||||
'memo' => 'nullable|string|max:255',
|
|
||||||
'terms_created_at' => 'nullable|date',
|
|
||||||
|
|
||||||
'operator_id' => 'nullable|integer',
|
|
||||||
]);
|
|
||||||
|
|
||||||
Term::create($validated);
|
|
||||||
return redirect()->route('terms')->with('success', '登録しました。');
|
|
||||||
}
|
|
||||||
// 都市の選択肢を取得
|
|
||||||
$cities = City::pluck('city_name', 'city_id');
|
|
||||||
|
|
||||||
return view('admin.terms.add', compact('cities'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function edit(Request $request, $id)
|
|
||||||
{
|
|
||||||
$term = Term::findOrFail($id);
|
|
||||||
$cities = City::pluck('city_name', 'city_id');
|
|
||||||
|
|
||||||
if ($request->isMethod('post')) {
|
|
||||||
$validated = $request->validate([
|
|
||||||
'city_id' => 'required|integer',
|
|
||||||
'terms_revision' => 'required|string|max:255',
|
|
||||||
'terms_text' => 'required|string',
|
|
||||||
'start_date' => 'nullable|date',
|
|
||||||
'use_flag' => 'required|in:0,1',
|
|
||||||
'memo' => 'nullable|string|max:255',
|
|
||||||
'terms_created_at'=> 'nullable|date',
|
|
||||||
'operator_id' => 'nullable|integer',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$term->update($validated);
|
|
||||||
return redirect()->route('terms')->with('success', '更新しました。');
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return view('admin.terms.edit', compact('term', 'cities'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 詳細表示
|
|
||||||
public function info($id)
|
|
||||||
{
|
|
||||||
$term = Term::findOrFail($id);
|
|
||||||
return view('admin.terms.info', compact('term'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 削除処理(単一・複数対応)
|
|
||||||
public function delete(Request $request)
|
|
||||||
{
|
|
||||||
$request->validate([
|
|
||||||
'pk' => 'required',
|
|
||||||
'pk.*' => 'integer', // 配列なら中身は整数
|
|
||||||
]);
|
|
||||||
|
|
||||||
$arr_pk = $request->input('pk');
|
|
||||||
$ids = is_array($arr_pk) ? $arr_pk : [$arr_pk];
|
|
||||||
|
|
||||||
$deleted = Term::destroy($ids);
|
|
||||||
|
|
||||||
if ($deleted > 0) {
|
|
||||||
return redirect()->route('terms')->with('success', __('削除しました。'));
|
|
||||||
} else {
|
|
||||||
return redirect()->route('terms')->with('error', __('削除に失敗しました。'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CSVインポート(仮)
|
|
||||||
public function import(Request $request)
|
|
||||||
{
|
|
||||||
return redirect()->route('terms')->with('info', 'CSVインポートは未実装です');
|
|
||||||
}
|
|
||||||
|
|
||||||
// CSVエクスポート(fputcsv使用)
|
|
||||||
public function export()
|
|
||||||
{
|
|
||||||
return response()->streamDownload(function () {
|
|
||||||
$handle = fopen('php://output', 'w');
|
|
||||||
fputcsv($handle, ['terms_id', 'terms_revision', 'terms_text', 'start_date', 'use_flag']);
|
|
||||||
|
|
||||||
foreach (Term::all() as $term) {
|
|
||||||
fputcsv($handle, [
|
|
||||||
$term->terms_id,
|
|
||||||
$term->terms_revision,
|
|
||||||
$term->terms_text,
|
|
||||||
$term->start_date,
|
|
||||||
$term->use_flag,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose($handle);
|
|
||||||
}, 'terms.csv');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -14,26 +14,32 @@ class UpdateCandidateController extends Controller
|
|||||||
public function list(Request $request)
|
public function list(Request $request)
|
||||||
{
|
{
|
||||||
$q = DB::table('regular_contract as rc')
|
$q = DB::table('regular_contract as rc')
|
||||||
->leftJoin('user as u','rc.user_id','=','u.user_id')
|
|
||||||
->leftJoin('park as p','rc.park_id','=','p.park_id')
|
|
||||||
->leftJoin('psection as ps','rc.psection_id','=','ps.psection_id')
|
|
||||||
->leftJoin('usertype as ut','u.user_categoryid','=','ut.user_categoryid')
|
|
||||||
->select([
|
->select([
|
||||||
'rc.contract_id',
|
'rc.contract_id',
|
||||||
|
'rc.contract_qr_id',
|
||||||
'rc.user_id',
|
'rc.user_id',
|
||||||
|
'rc.user_categoryid',
|
||||||
'rc.park_id',
|
'rc.park_id',
|
||||||
'rc.contract_created_at',
|
'rc.contract_created_at',
|
||||||
'rc.contract_periods',
|
'rc.contract_periods',
|
||||||
'rc.contract_periode',
|
'rc.contract_periode',
|
||||||
'rc.tag_qr_flag',
|
'rc.tag_qr_flag',
|
||||||
|
'rc.contract_flag',
|
||||||
'rc.contract_cancel_flag',
|
'rc.contract_cancel_flag',
|
||||||
|
'rc.contract_payment_day',
|
||||||
|
'rc.contract_money',
|
||||||
|
'rc.billing_amount',
|
||||||
'rc.contract_permission',
|
'rc.contract_permission',
|
||||||
|
'rc.contract_manual',
|
||||||
|
'rc.contract_notice',
|
||||||
|
'p.park_name',
|
||||||
'u.user_name',
|
'u.user_name',
|
||||||
'u.user_phonetic',
|
'u.user_phonetic',
|
||||||
'u.user_mobile',
|
'u.user_mobile',
|
||||||
'u.user_homephone',
|
'u.user_homephone',
|
||||||
'u.user_birthdate',
|
'u.user_primemail',
|
||||||
'u.user_gender',
|
'u.user_gender',
|
||||||
|
'u.user_birthdate',
|
||||||
'u.user_regident_zip',
|
'u.user_regident_zip',
|
||||||
'u.user_regident_pre',
|
'u.user_regident_pre',
|
||||||
'u.user_regident_city',
|
'u.user_regident_city',
|
||||||
@ -42,116 +48,57 @@ class UpdateCandidateController extends Controller
|
|||||||
'u.user_relate_pre',
|
'u.user_relate_pre',
|
||||||
'u.user_relate_city',
|
'u.user_relate_city',
|
||||||
'u.user_relate_add',
|
'u.user_relate_add',
|
||||||
|
'u.user_graduate',
|
||||||
'u.user_workplace',
|
'u.user_workplace',
|
||||||
'u.user_school',
|
'u.user_school',
|
||||||
'u.user_graduate',
|
|
||||||
'u.user_reduction',
|
|
||||||
'u.user_remarks',
|
'u.user_remarks',
|
||||||
'p.park_name',
|
|
||||||
DB::raw('ps.psection_subject as vehicle_type'),
|
|
||||||
DB::raw('ut.usertype_subject1 as user_category1'),
|
|
||||||
DB::raw('ut.usertype_subject2 as user_category2'),
|
|
||||||
DB::raw('ut.usertype_subject3 as user_category3'),
|
|
||||||
DB::raw('rc.contract_seal_issue as seal_issue_count'),
|
|
||||||
DB::raw('rc.user_securitynum as crime_prevention'),
|
|
||||||
DB::raw("CASE rc.enable_months
|
|
||||||
WHEN 1 THEN '月極(1ヶ月)'
|
|
||||||
WHEN 3 THEN '3ヶ月'
|
|
||||||
WHEN 6 THEN '6ヶ月'
|
|
||||||
WHEN 12 THEN '年'
|
|
||||||
ELSE CONCAT(rc.enable_months,'ヶ月') END as ticket_type"),
|
|
||||||
])
|
])
|
||||||
->where('rc.contract_cancel_flag',0)
|
->leftJoin('park as p', 'rc.park_id', '=', 'p.park_id')
|
||||||
->where('rc.contract_permission',1)
|
->leftJoin('user as u', 'rc.user_id', '=', 'u.user_id')
|
||||||
// 追加: 本日以降が有効期限のレコードのみ
|
->whereNull('rc.update_flag'); // 未更新のみ
|
||||||
->whereDate('rc.contract_periode','>=', now()->toDateString());
|
|
||||||
|
|
||||||
// 絞り込み
|
// 対象月による有効期限の絞り込み
|
||||||
if ($request->filled('park_id')) {
|
if ($request->filled('target_month')) {
|
||||||
$q->where('rc.park_id', $request->park_id);
|
$now = now();
|
||||||
|
switch ($request->input('target_month')) {
|
||||||
|
case 'last':
|
||||||
|
$start = $now->copy()->subMonth()->startOfMonth();
|
||||||
|
$end = $now->copy()->subMonth()->endOfMonth();
|
||||||
|
break;
|
||||||
|
case 'this':
|
||||||
|
$start = $now->copy()->startOfMonth();
|
||||||
|
$end = $now->copy()->endOfMonth();
|
||||||
|
break;
|
||||||
|
case 'next':
|
||||||
|
$start = $now->copy()->addMonth()->startOfMonth();
|
||||||
|
$end = $now->copy()->addMonth()->endOfMonth();
|
||||||
|
break;
|
||||||
|
case 'after2':
|
||||||
|
$start = $now->copy()->addMonths(2)->startOfMonth();
|
||||||
|
$end = $now->copy()->addMonths(2)->endOfMonth();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$start = null;
|
||||||
|
$end = null;
|
||||||
}
|
}
|
||||||
if ($request->filled('user_id')) {
|
if ($start && $end) {
|
||||||
$q->where('rc.user_id', trim($request->user_id));
|
$q->whereBetween('rc.contract_periode', [$start->toDateString(), $end->toDateString()]);
|
||||||
}
|
|
||||||
// 分類名1 完全一致
|
|
||||||
if ($request->filled('user_category1')) {
|
|
||||||
$val = trim(mb_convert_kana($request->user_category1,'asKV'));
|
|
||||||
$q->where('ut.usertype_subject1', $val);
|
|
||||||
}
|
|
||||||
// タグシリアル64進 部分一致 (SELECT 不要)
|
|
||||||
if ($request->filled('user_tag_serial_64')) {
|
|
||||||
$q->where('u.user_tag_serial_64','like','%'.$request->user_tag_serial_64.'%');
|
|
||||||
}
|
|
||||||
// 有効期限:指定日以前
|
|
||||||
if ($request->filled('contract_periode')) {
|
|
||||||
$raw = str_replace('/','-',$request->contract_periode);
|
|
||||||
try {
|
|
||||||
$target = \Carbon\Carbon::parse($raw)->format('Y-m-d');
|
|
||||||
$q->whereDate('rc.contract_periode','<=',$target);
|
|
||||||
} catch (\Exception $e) {}
|
|
||||||
}
|
|
||||||
if ($request->filled('user_phonetic')) {
|
|
||||||
$q->where('u.user_phonetic','like','%'.$request->user_phonetic.'%');
|
|
||||||
}
|
|
||||||
if ($request->filled('user_mobile')) {
|
|
||||||
$like = '%'.$request->user_mobile.'%';
|
|
||||||
$q->where(function($w) use ($like){
|
|
||||||
$w->where('u.user_mobile','like',$like)
|
|
||||||
->orWhere('u.user_homephone','like',$like);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if ($request->filled('user_primemail')) {
|
|
||||||
$like = '%'.$request->user_primemail.'%';
|
|
||||||
$q->where(function($w) use ($like){
|
|
||||||
$w->where('u.user_primemail','like',$like)
|
|
||||||
->orWhere('u.user_submail','like',$like);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if ($request->filled('user_workplace')) {
|
|
||||||
$q->where('u.user_workplace','like','%'.$request->user_workplace.'%');
|
|
||||||
}
|
|
||||||
if ($request->filled('user_school')) {
|
|
||||||
$q->where('u.user_school','like','%'.$request->user_school.'%');
|
|
||||||
}
|
|
||||||
if ($request->filled('tag_qr_flag') && $request->tag_qr_flag!=='') {
|
|
||||||
$q->where('rc.tag_qr_flag',$request->tag_qr_flag);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 対象月
|
|
||||||
$target = $request->input('target_month');
|
|
||||||
if (in_array($target,['last','this','next','after2'],true)) {
|
|
||||||
$base = now()->startOfMonth();
|
|
||||||
$offset = ['last'=>-1,'this'=>0,'next'=>1,'after2'=>2][$target];
|
|
||||||
$m = $base->copy()->addMonths($offset);
|
|
||||||
if ($target === 'after2') {
|
|
||||||
// 2か月後「以降」を抽出(該当月の月初以降)
|
|
||||||
$q->whereDate('rc.contract_periode', '>=', $m->toDateString());
|
|
||||||
} else {
|
|
||||||
$q->whereYear('rc.contract_periode',$m->year)
|
|
||||||
->whereMonth('rc.contract_periode',$m->month);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ソート(regular_contract の表示順に合わせて contract_id の降順を既定に)
|
$sort = $request->input('sort', 'rc.contract_id');
|
||||||
$sort = $request->input('sort','contract_id');
|
$sortType = $request->input('sort_type', 'desc');
|
||||||
$sortType = $request->input('sort_type','dac');
|
$allowSorts = ['rc.contract_id'];
|
||||||
$allow = [
|
if (!in_array($sort, $allowSorts)) {
|
||||||
'contract_id' => 'rc.contract_id',
|
$sort = 'rc.contract_id';
|
||||||
'user_id' => 'rc.user_id',
|
}
|
||||||
'contract_periode' => 'rc.contract_periode',
|
$sortType = ($sortType === 'asc') ? 'asc' : 'desc';
|
||||||
];
|
|
||||||
if (!isset($allow[$sort])) $sort = 'contract_id';
|
|
||||||
$sortType = $sortType==='desc' ? 'desc' : 'asc';
|
|
||||||
$q->orderBy($allow[$sort], $sortType);
|
|
||||||
|
|
||||||
$rows = $q->paginate(20)->appends($request->query());
|
$rows = $q->orderBy($sort, $sortType)->paginate(20)->withQueryString();
|
||||||
|
|
||||||
$parks = DB::table('park')
|
// 駐輪場リスト(プルダウン用)
|
||||||
->select('park_id','park_name')
|
$parks = DB::table('park')->select('park_id', 'park_name')->orderBy('park_name')->get();
|
||||||
->orderBy('park_name')
|
|
||||||
->get();
|
|
||||||
|
|
||||||
return view('admin.update_candidate.list',
|
return view('admin.update_candidate.list', compact('rows', 'sort', 'sortType', 'parks'));
|
||||||
compact('rows','parks'));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,496 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
|
||||||
|
|
||||||
use App\Models\City;
|
|
||||||
use App\Http\Requests\UserRequest;
|
|
||||||
use App\Models\Ope;
|
|
||||||
use App\Models\User;
|
|
||||||
use App\Models\Usertype;
|
|
||||||
use App\Utils;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Facades\Validator;
|
|
||||||
use Response;
|
|
||||||
|
|
||||||
class UserController extends Controller
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the application dashboard.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
|
||||||
public function list(Request $request)
|
|
||||||
{
|
|
||||||
$inputs = [
|
|
||||||
'isMethodPost' => 0,
|
|
||||||
'isExport' => $request->input('isExport', 0) * 1,
|
|
||||||
'sort' => $request->input('sort', ''),
|
|
||||||
'sort_type' => $request->input('sort_type', ''),
|
|
||||||
'page' => $request->get('page', 1),
|
|
||||||
'user_id' => $request->input('user_id', ''),
|
|
||||||
'member_id' => $request->input('member_id', ''),
|
|
||||||
'user_tag_serial' => $request->input('user_tag_serial', ''),
|
|
||||||
'user_phonetic' => $request->input('user_phonetic', ''),
|
|
||||||
'phone' => $request->input('phone', ''),
|
|
||||||
'crime' => $request->input('crime', ''),
|
|
||||||
'black_list' => $request->input('black_list', ''),
|
|
||||||
'ward_residents' => $request->input('ward_residents', ''),
|
|
||||||
'user_tag_serial_64' => $request->input('user_tag_serial_64', ''),
|
|
||||||
'photo_filename1' => $request->file('photo_filename1'),
|
|
||||||
'photo_filename2' => $request->file('photo_filename2'),
|
|
||||||
];
|
|
||||||
$inputs['isMethodPost'] = $request->isMethod('post');
|
|
||||||
$inputs['list'] = User::search($inputs);
|
|
||||||
if ($inputs['list']->total() > 0 && $inputs['page'] > $inputs['list']->lastPage()) {
|
|
||||||
return redirect()->route('users');
|
|
||||||
}
|
|
||||||
return view('admin.users.list', $inputs);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function add(Request $request)
|
|
||||||
{
|
|
||||||
$inputs = [
|
|
||||||
'user_id' => $request->input('user_id', ''),
|
|
||||||
'member_id' => $request->input('member_id', ''),
|
|
||||||
'user_pass' => $request->input('password', ''),
|
|
||||||
'user_manual_regist_flag' => $request->input('user_manual_regist_flag', 0),
|
|
||||||
'user_mailing_flag' => $request->input('user_mailing_flag', 0),
|
|
||||||
'contract_number' => $request->input('contract_number', ''),
|
|
||||||
'user_tag_serial' => $request->input('user_tag_serial', ''),
|
|
||||||
'user_tag_serial_64' => $request->input('user_tag_serial_64', ''),
|
|
||||||
'qr_code' => $request->input('qr_code', ''),
|
|
||||||
'tag_qr_flag' => $request->input('tag_qr_flag', ''),
|
|
||||||
'user_aid' => $request->input('user_aid', ''),
|
|
||||||
'user_park_number' => $request->input('user_park_number', ''),
|
|
||||||
'user_place_qrid' => $request->input('user_place_qrid', ''),
|
|
||||||
'user_categoryid' => $request->input('user_categoryid', ''),
|
|
||||||
'user_name' => $request->input('user_name', ''),
|
|
||||||
'user_phonetic' => $request->input('user_phonetic', ''),
|
|
||||||
'user_gender' => $request->input('user_gender', ''),
|
|
||||||
'user_birthdate' => $request->input('user_birthdate', ''),
|
|
||||||
'user_age' => $request->input('user_age', ''),
|
|
||||||
'ward_residents' => $request->input('ward_residents', ''),
|
|
||||||
'user_mobile' => $request->input('user_mobile', ''),
|
|
||||||
'user_homephone' => $request->input('user_homephone', ''),
|
|
||||||
'user_primemail' => $request->input('user_primemail', ''),
|
|
||||||
'user_submail' => $request->input('user_submail', ''),
|
|
||||||
'user_regident_zip' => $request->input('user_regident_zip', ''),
|
|
||||||
'user_regident_pre' => $request->input('user_regident_pre', ''),
|
|
||||||
'user_regident_city' => $request->input('user_regident_city', ''),
|
|
||||||
'user_regident_add' => $request->input('user_regident_add', ''),
|
|
||||||
'user_relate_zip' => $request->input('user_relate_zip', ''),
|
|
||||||
'user_relate_pre' => $request->input('user_relate_pre', ''),
|
|
||||||
'user_relate_city' => $request->input('user_relate_city', ''),
|
|
||||||
'user_relate_add' => $request->input('user_relate_add', ''),
|
|
||||||
'user_workplace' => $request->input('user_workplace', ''),
|
|
||||||
'user_school' => $request->input('user_school', ''),
|
|
||||||
'user_graduate' => $request->input('user_graduate', ''),
|
|
||||||
'user_reduction' => $request->input('user_reduction', ''),
|
|
||||||
'user_idcard' => $request->input('user_idcard', ''),
|
|
||||||
'user_idcard_chk_flag' => $request->input('user_idcard_chk_flag', 0),
|
|
||||||
'user_chk_day' => $request->input('user_chk_day', ''),
|
|
||||||
'user_chk_opeid' => $request->input('user_chk_opeid', ''),
|
|
||||||
'user_tag_issue' => $request->input('user_tag_issue', ''),
|
|
||||||
'issue_permission' => $request->input('issue_permission', 0),
|
|
||||||
'user_quit_flag' => $request->input('user_quit_flag', 0),
|
|
||||||
'user_quitday' => $request->input('user_quitday', ''),
|
|
||||||
'user_remarks' => $request->input('user_remarks', ''),
|
|
||||||
'photo_filename1' => $request->file('photo_filename1'),
|
|
||||||
'photo_filename2' => $request->file('photo_filename2'),
|
|
||||||
];
|
|
||||||
$dataList = $this->getDataDropList();
|
|
||||||
$inputs = array_merge($inputs, $dataList);
|
|
||||||
|
|
||||||
if ($request->isMethod('POST')) {
|
|
||||||
$type = false;
|
|
||||||
$validation = new UserRequest();
|
|
||||||
$rules = $validation->rules();
|
|
||||||
$rules['user_id'] = $rules['user_id'] . '|unique:user';
|
|
||||||
$rules['password'] = 'required|min:6|confirmed';
|
|
||||||
if(!empty($inputs['user_age']) ){
|
|
||||||
$rules['user_age'] = 'integer';
|
|
||||||
}
|
|
||||||
if(!empty($inputs['user_aid']) ){
|
|
||||||
$rules['user_aid'] = 'integer';
|
|
||||||
}
|
|
||||||
$validator = Validator::make($request->all(), $rules, $validation->messages());
|
|
||||||
if (!$validator->fails()) {
|
|
||||||
if ($request->hasFile('photo_filename1') && $inputs['photo_filename1']->isValid()) {
|
|
||||||
$inputs['image1'] = Utils::uploadFile($inputs['photo_filename1']);
|
|
||||||
} else {
|
|
||||||
$inputs['image1'] = '';
|
|
||||||
}
|
|
||||||
if ($request->hasFile('photo_filename2') && $inputs['photo_filename2']->isValid()) {
|
|
||||||
$inputs['image2'] = Utils::uploadFile($inputs['photo_filename2']);
|
|
||||||
} else {
|
|
||||||
$inputs['image2'] = '';
|
|
||||||
}
|
|
||||||
\DB::transaction(function () use ($inputs, &$type) {
|
|
||||||
$new = new User();
|
|
||||||
$new->fill($inputs);
|
|
||||||
if ($inputs['image1'] && $inputs['image1'] != '') {
|
|
||||||
$new->photo_filename2 = $inputs['image1'];
|
|
||||||
}
|
|
||||||
if ($inputs['image2'] && $inputs['image2'] != '') {
|
|
||||||
$new->photo_filename2 = $inputs['image2'];
|
|
||||||
}
|
|
||||||
if ($new->save()) {
|
|
||||||
$new->user_pass = Utils::getHashPassword($inputs['user_pass'], $new->user_seq);
|
|
||||||
$new->save();
|
|
||||||
}
|
|
||||||
|
|
||||||
$type = true;
|
|
||||||
});
|
|
||||||
if ($type) {
|
|
||||||
$request->session()->flash('success', __('新しい成功を創造する。'));
|
|
||||||
return redirect()->route('users');
|
|
||||||
} else {
|
|
||||||
$request->session()->flash('error', __('新しい作成に失敗しました'));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$inputs['errorMsg'] = $this->__buildErrorMessasges($validator);
|
|
||||||
$data['photo_filename1'] = '';
|
|
||||||
$data['photo_filename2'] = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return view('admin.users.add', $inputs);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function edit(Request $request, $seq, $view = '')
|
|
||||||
{
|
|
||||||
$user = User::getUserBySeq($seq);
|
|
||||||
if (empty($seq) || empty($user)) {
|
|
||||||
abort('404');
|
|
||||||
}
|
|
||||||
$data = $user->getAttributes();
|
|
||||||
$filename1 = $data['photo_filename1'];
|
|
||||||
$filename2 = $data['photo_filename2'];
|
|
||||||
$dataList = $this->getDataDropList();
|
|
||||||
$data = array_merge($data, $dataList);
|
|
||||||
|
|
||||||
if ($request->isMethod('POST')) {
|
|
||||||
$type = false;
|
|
||||||
$validation = new UserRequest();
|
|
||||||
$inputs = $request->all();
|
|
||||||
$rules = $validation->rules();
|
|
||||||
if (!empty($inputs['password'])) {
|
|
||||||
$rules['password'] = 'required|min:6|confirmed';
|
|
||||||
}
|
|
||||||
if(!empty($inputs['user_age']) ){
|
|
||||||
$rules['user_age'] = 'integer';
|
|
||||||
}
|
|
||||||
if(!empty($inputs['user_aid']) ){
|
|
||||||
$rules['user_aid'] = 'integer';
|
|
||||||
}
|
|
||||||
$validator = Validator::make($inputs, $rules, $validation->messages());
|
|
||||||
$data = array_merge($data, $inputs);
|
|
||||||
|
|
||||||
if (!$validator->fails()) {
|
|
||||||
|
|
||||||
if ($request->hasFile('photo_filename1') && $data['photo_filename1']->isValid()) {
|
|
||||||
$data['image1'] = Utils::uploadFile($data['photo_filename1']);
|
|
||||||
} else {
|
|
||||||
$data['image1'] = '';
|
|
||||||
}
|
|
||||||
if ($request->hasFile('photo_filename2') && $data['photo_filename2']->isValid()) {
|
|
||||||
$data['image2'] = Utils::uploadFile($data['photo_filename2']);
|
|
||||||
} else {
|
|
||||||
$data['image2'] = '';
|
|
||||||
}
|
|
||||||
\DB::transaction(function () use ($data, &$type, $user, $inputs) {
|
|
||||||
$user->fill($data);
|
|
||||||
if (!empty($inputs['password'])) {
|
|
||||||
$user->user_pass = Utils::getHashPassword($data['password'], $user->user_seq);
|
|
||||||
}
|
|
||||||
if ($data['image1'] && $data['image1'] != '') {
|
|
||||||
$user->photo_filename1 = $data['image1'];
|
|
||||||
}
|
|
||||||
if ($data['image2'] && $data['image2'] != '') {
|
|
||||||
$user->photo_filename2 = $data['image2'];
|
|
||||||
}
|
|
||||||
$user->save();
|
|
||||||
$type = true;
|
|
||||||
});
|
|
||||||
if ($type) {
|
|
||||||
$request->session()->flash('success', __('更新に成功しました'));
|
|
||||||
return redirect()->route('users');
|
|
||||||
} else {
|
|
||||||
$request->session()->flash('error', __('更新に失敗しました'));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$data['errorMsg'] = $this->__buildErrorMessasges($validator);
|
|
||||||
$data['photo_filename1'] = $filename1;
|
|
||||||
$data['photo_filename2'] = $filename2;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($view != '') {
|
|
||||||
return view($view, $data);
|
|
||||||
}
|
|
||||||
return view('admin.users.edit', $data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function delete(Request $request)
|
|
||||||
{
|
|
||||||
$arr_seq = $request->get('seq');
|
|
||||||
if ($arr_seq) {
|
|
||||||
if (User::deleteUsersBySeq($arr_seq)) {
|
|
||||||
return redirect()->route('users')->with('success', __("削除が完了しました。"));
|
|
||||||
} else {
|
|
||||||
return redirect()->route('users')->with('error', __('削除に失敗しました。'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return redirect()->route('users')->with('error', __('削除するユーザーを選択してください。'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function export(Request $request)
|
|
||||||
{
|
|
||||||
|
|
||||||
$headers = array(
|
|
||||||
"Content-type" => "text/csv;charset=UTF-8",
|
|
||||||
'Content-Encoding: UTF-8',
|
|
||||||
"Content-Disposition" => "attachment; filename=file.csv",
|
|
||||||
"Pragma" => "no-cache",
|
|
||||||
"Cache-Control" => "must-revalidate, post-check=0, pre-check=0",
|
|
||||||
"Expires" => "0"
|
|
||||||
);
|
|
||||||
$inputs = [
|
|
||||||
'isMethodPost' => 0,
|
|
||||||
'isExport' => 1,
|
|
||||||
'sort' => $request->input('sort', ''),
|
|
||||||
'sort_type' => $request->input('sort_type', ''),
|
|
||||||
|
|
||||||
];
|
|
||||||
|
|
||||||
$dataExport = User::search($inputs);
|
|
||||||
$columns = array(
|
|
||||||
__('利用者連番'),// 0
|
|
||||||
__('利用者ID'),// 1
|
|
||||||
__('会員ID'),// 2
|
|
||||||
__('パスワード'),// 3
|
|
||||||
__('手動登録フラグ'),// 4
|
|
||||||
__('手動登録フラグ'),
|
|
||||||
__('郵送必要フラグ'),// 5
|
|
||||||
__('郵送必要フラグ'),
|
|
||||||
__('旧定期契約番号'),// 6
|
|
||||||
__('タグシリアル'),// 7
|
|
||||||
__('タグシリアル64進'),// 8
|
|
||||||
__('QRコード'),// 9
|
|
||||||
__('タグ/QRフラグ'),// 10
|
|
||||||
__('タグ/QRフラグ'),
|
|
||||||
__('AID'),// 11
|
|
||||||
__('居場所通知用QRID'),// 12
|
|
||||||
__('利用者分類ID'),// 13
|
|
||||||
__('利用者分類'),
|
|
||||||
__('利用者名'),// 14
|
|
||||||
__('フリガナ'),// 15
|
|
||||||
__('性別'),// 16
|
|
||||||
__('生年月日'),// 17
|
|
||||||
__('年齢'),// 18
|
|
||||||
__('携帯電話番号'),// 19
|
|
||||||
__('自宅電話番号'),// 20
|
|
||||||
__('メールアドレス'),// 21
|
|
||||||
__('予備メールアドレス'),// 22
|
|
||||||
__('居住所:郵便番号'),// 23
|
|
||||||
__('居住所:都道府県'),// 24
|
|
||||||
__('居住所:市区群'),// 25
|
|
||||||
__('居住所:住所'),// 26
|
|
||||||
__('関連住所:郵便番号'),// 27
|
|
||||||
__('関連住所:都道府県'),// 28
|
|
||||||
__('関連住所:市区群'),// 29
|
|
||||||
__('関連住所:住所'),// 30
|
|
||||||
__('区民'),// 31
|
|
||||||
__('勤務先名'),// 32
|
|
||||||
__('学校'),// 33
|
|
||||||
__('卒業予定'),// 34
|
|
||||||
__('本人確認書類'),// 35
|
|
||||||
__('本人確認チェック済'),// 36
|
|
||||||
__('本人確認チェック済'),
|
|
||||||
__('本人確認日時'),// 37
|
|
||||||
__('本人確認オペレータID'),// 38
|
|
||||||
__('タグ発行数'),// 39
|
|
||||||
__('タグ発行許可'),// 40
|
|
||||||
__('退会フラグ'),// 41
|
|
||||||
__('退会フラグ'),
|
|
||||||
__('退会日'),// 42
|
|
||||||
__('備考'),// 43
|
|
||||||
);
|
|
||||||
$filename = "利用者マスタ.csv";
|
|
||||||
$file = fopen($filename, 'w+');
|
|
||||||
fputcsv($file, $columns);
|
|
||||||
foreach ($dataExport as $items) {
|
|
||||||
fputcsv($file, array(
|
|
||||||
$items->user_seq, // 0
|
|
||||||
$items->user_id, // 1
|
|
||||||
$items->member_id, // 2
|
|
||||||
'',//TODO パスワード not found in database specs
|
|
||||||
$items->user_manual_regist_flag, // 4
|
|
||||||
$items->user_manual_regist_flag ? __("はい") : __("いいえ"),
|
|
||||||
$items->user_mailing_flag, // 6
|
|
||||||
$items->user_mailing_flag ? __("はい") : __("いいえ"),
|
|
||||||
$items->contract_number, // 8
|
|
||||||
$items->user_tag_serial, // 9
|
|
||||||
$items->user_tag_serial_64, // 10
|
|
||||||
$items->qr_code, // 11
|
|
||||||
$items->tag_qr_flag, // 12
|
|
||||||
$items->tag_qr_flag ? __('QRコード') : __('タグ'),
|
|
||||||
$items->user_aid, // 14
|
|
||||||
$items->user_place_qrid, // 15
|
|
||||||
$items->user_categoryid, // 16
|
|
||||||
$items->getUserType()->print_name,
|
|
||||||
$items->user_name, // 18
|
|
||||||
$items->user_phonetic, // 19
|
|
||||||
$items->user_gender, // 20
|
|
||||||
$items->user_birthdate, // 21
|
|
||||||
$items->user_age, // 22
|
|
||||||
$items->user_mobile, // 23
|
|
||||||
$items->user_homephone, // 24
|
|
||||||
$items->user_primemail, // 25
|
|
||||||
$items->user_submail, // 26
|
|
||||||
$items->user_regident_zip, // 27
|
|
||||||
$items->user_regident_pre, // 28
|
|
||||||
$items->user_regident_city, // 29
|
|
||||||
$items->user_regident_add, // 30
|
|
||||||
$items->user_relate_zip, // 31
|
|
||||||
$items->user_relate_pre, // 32
|
|
||||||
$items->user_relate_city, // 33
|
|
||||||
$items->user_relate_add, // 34
|
|
||||||
$items->ward_residents, // 35
|
|
||||||
$items->user_workplace, // 36
|
|
||||||
$items->user_school, // 37
|
|
||||||
$items->user_graduate, // 38
|
|
||||||
$items->user_idcard, // 39
|
|
||||||
$items->user_idcard_chk_flag, // 40
|
|
||||||
\App\Models\User::USER_ID_CARD_CHK_FLG[$items->user_idcard_chk_flag],
|
|
||||||
$items->user_chk_day, // 42
|
|
||||||
$items->user_chk_opeid, // 43
|
|
||||||
$items->user_tag_issue, // 44
|
|
||||||
$items->issue_permission, // 45
|
|
||||||
$items->user_quit_flag, // 46
|
|
||||||
$items->user_quit_flag ? __("はい") : __("いいえ"),
|
|
||||||
$items->user_quitday, // 48
|
|
||||||
$items->user_remarks, // 49
|
|
||||||
));
|
|
||||||
}
|
|
||||||
fclose($file);
|
|
||||||
return Response::download($filename, $filename, $headers);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function import(Request $request)
|
|
||||||
{
|
|
||||||
$file = $request->file('file');
|
|
||||||
if (!empty($file)) {
|
|
||||||
$data = Utils::csvToArray($file);
|
|
||||||
$type = 1;
|
|
||||||
$msg = '';
|
|
||||||
$record = 0;
|
|
||||||
DB::beginTransaction();
|
|
||||||
try {
|
|
||||||
User::query()->delete();
|
|
||||||
$col = 50;
|
|
||||||
foreach ($data as $key => $items) {
|
|
||||||
$record = $key + 2;
|
|
||||||
if (count($items) == $col) {
|
|
||||||
$row = new User();
|
|
||||||
$row->user_seq = $items[0];
|
|
||||||
$row->user_id = $items[1];
|
|
||||||
$row->member_id = $items[2];
|
|
||||||
//TODO パスワード not found in database specs_$items[3]
|
|
||||||
$row->user_manual_regist_flag = $items[4];
|
|
||||||
$row->user_mailing_flag = $items[6];
|
|
||||||
$row->contract_number = $items[8];
|
|
||||||
$row->user_tag_serial = $items[9];
|
|
||||||
$row->user_tag_serial_64 = $items[10];
|
|
||||||
$row->qr_code = $items[11];
|
|
||||||
$row->tag_qr_flag = $items[12];
|
|
||||||
$row->user_aid = $items[14];
|
|
||||||
$row->user_place_qrid = $items[15];
|
|
||||||
$row->user_categoryid = $items[16];
|
|
||||||
$row->user_name = $items[18];
|
|
||||||
$row->user_phonetic = $items[19];
|
|
||||||
$row->user_gender = $items[20];
|
|
||||||
$row->user_birthdate = $items[21];
|
|
||||||
$row->user_age = !empty($items[22]) ? $items[22] : null;
|
|
||||||
$row->user_mobile = $items[23];
|
|
||||||
$row->user_homephone = $items[24];
|
|
||||||
$row->user_primemail = $items[25];
|
|
||||||
$row->user_submail = $items[26];
|
|
||||||
$row->user_regident_zip = $items[27];
|
|
||||||
$row->user_regident_pre = $items[28];
|
|
||||||
$row->user_regident_city = $items[29];
|
|
||||||
$row->user_regident_add = $items[30];
|
|
||||||
$row->user_relate_zip = $items[31];
|
|
||||||
$row->user_relate_pre = $items[32];
|
|
||||||
$row->user_relate_city = $items[33];
|
|
||||||
$row->user_relate_add = $items[34];
|
|
||||||
$row->ward_residents = $items[35];
|
|
||||||
$row->user_workplace = $items[36];
|
|
||||||
$row->user_school = $items[37];
|
|
||||||
$row->user_graduate = $items[38];
|
|
||||||
$row->user_idcard = $items[39];
|
|
||||||
$row->user_idcard_chk_flag = $items[40];
|
|
||||||
$row->user_chk_day = $items[42];
|
|
||||||
$row->user_chk_opeid = $items[43];
|
|
||||||
$row->user_tag_issue = $items[44];
|
|
||||||
$row->issue_permission = $items[45];
|
|
||||||
$row->user_quit_flag = $items[46];
|
|
||||||
$row->user_quitday = $items[48];
|
|
||||||
$row->user_remarks = $items[49];
|
|
||||||
if (!$row->save()) {
|
|
||||||
$type = 0;
|
|
||||||
$msg = '行:record型が一致しません。';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$type = 0;
|
|
||||||
$msg = '行:record列数が一致しません。';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
$msg = '行:record型が一致しません。';
|
|
||||||
$type = 0;
|
|
||||||
}
|
|
||||||
if ($type) {
|
|
||||||
DB::commit();
|
|
||||||
return redirect()->route('users')->with('success', __('輸入成功'));
|
|
||||||
} else {
|
|
||||||
DB::rollBack();
|
|
||||||
return redirect()->route('users')->with('error', __($msg, ['record' => $record]));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return redirect()->route('users')->with('error', __('あなたはcsvファイルを選択していません。'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function info(Request $request, $seq)
|
|
||||||
{
|
|
||||||
return $this->edit($request, $seq, 'admin.users.info');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDataDropList()
|
|
||||||
{
|
|
||||||
$data['cities'] = City::getList();
|
|
||||||
$data['listUserType'] = Usertype::getList();
|
|
||||||
$data['listOpe'] = Ope::getList();
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* バリデーションエラーメッセージを構築
|
|
||||||
*/
|
|
||||||
private function __buildErrorMessasges($validator)
|
|
||||||
{
|
|
||||||
$messages = [];
|
|
||||||
foreach ($validator->errors()->all() as $message) {
|
|
||||||
$messages[] = $message;
|
|
||||||
}
|
|
||||||
return implode('<br>', $messages);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -6,30 +6,8 @@ use Illuminate\Http\Request;
|
|||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||||
use Illuminate\Support\Facades\Hash;
|
|
||||||
|
|
||||||
class UsersController
|
class UsersController
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* 利用者分類選択肢を取得
|
|
||||||
*/
|
|
||||||
private function buildCategoryOptions(): array
|
|
||||||
{
|
|
||||||
return DB::table('usertype')
|
|
||||||
->orderBy('user_categoryid', 'asc')
|
|
||||||
->get()
|
|
||||||
->mapWithKeys(function ($row) {
|
|
||||||
$label = collect([
|
|
||||||
$row->usertype_subject1 ?? '',
|
|
||||||
$row->usertype_subject2 ?? '',
|
|
||||||
$row->usertype_subject3 ?? '',
|
|
||||||
])->filter(fn ($v) => $v !== '')->implode('/');
|
|
||||||
|
|
||||||
return [$row->user_categoryid => $label !== '' ? $label : (string) $row->user_categoryid];
|
|
||||||
})
|
|
||||||
->toArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 利用者一覧
|
* 利用者一覧
|
||||||
* - テーブル名: user
|
* - テーブル名: user
|
||||||
@ -60,15 +38,13 @@ class UsersController
|
|||||||
'user_name',
|
'user_name',
|
||||||
'user_birthdate',
|
'user_birthdate',
|
||||||
'user_age',
|
'user_age',
|
||||||
'user_mobile',
|
|
||||||
'user_homephone',
|
'user_homephone',
|
||||||
'user_primemail',
|
'user_primemail',
|
||||||
'user_submail',
|
'user_submail',
|
||||||
'user_school',
|
'user_school',
|
||||||
];
|
];
|
||||||
$sort = $request->input('sort', 'user_seq');
|
$sort = $request->input('sort', 'user_seq');
|
||||||
$dirParam = strtolower((string) $request->input('dir', $request->input('sort_type', 'asc')));
|
$sortType = strtolower($request->input('sort_type', 'desc')) === 'asc' ? 'asc' : 'desc';
|
||||||
$sortType = $dirParam === 'asc' ? 'asc' : 'desc';
|
|
||||||
if (!in_array($sort, $sortable, true)) {
|
if (!in_array($sort, $sortable, true)) {
|
||||||
$sort = 'user_seq';
|
$sort = 'user_seq';
|
||||||
}
|
}
|
||||||
@ -80,7 +56,6 @@ class UsersController
|
|||||||
$user_phonetic = trim((string) $request->input('user_phonetic', ''));
|
$user_phonetic = trim((string) $request->input('user_phonetic', ''));
|
||||||
$phone = trim((string) $request->input('phone', '')); // 携帯/自宅の両方対象
|
$phone = trim((string) $request->input('phone', '')); // 携帯/自宅の両方対象
|
||||||
$crime = trim((string) $request->input('crime', '')); // 防犯登録番号(暫定: qr_code)
|
$crime = trim((string) $request->input('crime', '')); // 防犯登録番号(暫定: qr_code)
|
||||||
$email = trim((string) $request->input('email', ''));
|
|
||||||
$user_categoryid = (string) $request->input('user_categoryid', '');
|
$user_categoryid = (string) $request->input('user_categoryid', '');
|
||||||
$tag_qr_flag = (string) $request->input('tag_qr_flag', ''); // 0=タグ / 1=QR
|
$tag_qr_flag = (string) $request->input('tag_qr_flag', ''); // 0=タグ / 1=QR
|
||||||
$quit_flag = (string) $request->input('quit_flag', ''); // 0=いいえ / 1=はい
|
$quit_flag = (string) $request->input('quit_flag', ''); // 0=いいえ / 1=はい
|
||||||
@ -88,14 +63,7 @@ class UsersController
|
|||||||
$quit_to = (string) $request->input('quit_to', ''); // YYYY-MM-DD
|
$quit_to = (string) $request->input('quit_to', ''); // YYYY-MM-DD
|
||||||
|
|
||||||
// ▼ ベースクエリ(一覧で使う列が多いので一旦 * を許容)
|
// ▼ ベースクエリ(一覧で使う列が多いので一旦 * を許容)
|
||||||
$query = DB::table('user')
|
$query = DB::table('user')->select('user.*');
|
||||||
->leftJoin('usertype', 'user.user_categoryid', '=', 'usertype.user_categoryid')
|
|
||||||
->select(
|
|
||||||
'user.*',
|
|
||||||
'usertype.usertype_subject1',
|
|
||||||
'usertype.usertype_subject2',
|
|
||||||
'usertype.usertype_subject3'
|
|
||||||
);
|
|
||||||
|
|
||||||
// ▼ テキスト系
|
// ▼ テキスト系
|
||||||
if ($user_id !== '')
|
if ($user_id !== '')
|
||||||
@ -116,8 +84,6 @@ class UsersController
|
|||||||
// ※ dump に防犯登録番号の明確なカラムが無いため暫定的に qr_code を対象
|
// ※ dump に防犯登録番号の明確なカラムが無いため暫定的に qr_code を対象
|
||||||
$query->where('user.qr_code', 'like', "%{$crime}%");
|
$query->where('user.qr_code', 'like', "%{$crime}%");
|
||||||
}
|
}
|
||||||
if ($email !== '')
|
|
||||||
$query->where('user.user_primemail', 'like', "%{$email}%");
|
|
||||||
|
|
||||||
// ▼ セレクト/ラジオ('' 以外なら適用。'0' も通す)
|
// ▼ セレクト/ラジオ('' 以外なら適用。'0' も通す)
|
||||||
if ($user_categoryid !== '')
|
if ($user_categoryid !== '')
|
||||||
@ -141,20 +107,17 @@ class UsersController
|
|||||||
'list' => $list,
|
'list' => $list,
|
||||||
'sort' => $sort,
|
'sort' => $sort,
|
||||||
'sort_type' => $sortType,
|
'sort_type' => $sortType,
|
||||||
'dir' => $sortType,
|
|
||||||
'user_id' => $user_id,
|
'user_id' => $user_id,
|
||||||
'member_id' => $member_id,
|
'member_id' => $member_id,
|
||||||
'user_tag_serial' => $user_tag_serial,
|
'user_tag_serial' => $user_tag_serial,
|
||||||
'user_phonetic' => $user_phonetic,
|
'user_phonetic' => $user_phonetic,
|
||||||
'phone' => $phone,
|
'phone' => $phone,
|
||||||
'crime' => $crime,
|
'crime' => $crime,
|
||||||
'email' => $email,
|
|
||||||
'user_categoryid' => $user_categoryid,
|
'user_categoryid' => $user_categoryid,
|
||||||
'tag_qr_flag' => $tag_qr_flag,
|
'tag_qr_flag' => $tag_qr_flag,
|
||||||
'quit_flag' => $quit_flag,
|
'quit_flag' => $quit_flag,
|
||||||
'quit_from' => $quit_from,
|
'quit_from' => $quit_from,
|
||||||
'quit_to' => $quit_to,
|
'quit_to' => $quit_to,
|
||||||
'categoryOptions' => $this->buildCategoryOptions(),
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,11 +260,11 @@ class UsersController
|
|||||||
return view('admin.users.add');
|
return view('admin.users.add');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ▼ バリデーション(user_id は半角数字のみ)
|
// ▼ バリデーション(user_id は半角数字のみ)
|
||||||
$rules = [
|
$rules = [
|
||||||
'user_id' => ['required', 'regex:/^\d+$/', 'digits_between:1,10'], // 半角数字(最大10桁)
|
'user_id' => ['required', 'regex:/^\d+$/'], // 半角数字のみ許可
|
||||||
'user_name' => ['required', 'string', 'max:255'],
|
'user_name' => ['required', 'string', 'max:255'],
|
||||||
'user_pass' => ['required', 'string', 'min:8', 'confirmed'],
|
|
||||||
// 任意
|
// 任意
|
||||||
'user_primemail' => ['nullable', 'email', 'max:255'],
|
'user_primemail' => ['nullable', 'email', 'max:255'],
|
||||||
'user_gender' => ['nullable', 'in:男性,女性'],
|
'user_gender' => ['nullable', 'in:男性,女性'],
|
||||||
@ -316,11 +279,6 @@ class UsersController
|
|||||||
$messages = [
|
$messages = [
|
||||||
'user_id.required' => '利用者IDは必須です。',
|
'user_id.required' => '利用者IDは必須です。',
|
||||||
'user_id.regex' => '利用者IDは半角数字のみで入力してください。',
|
'user_id.regex' => '利用者IDは半角数字のみで入力してください。',
|
||||||
'user_id.digits_between' => '利用者IDは最大10桁以内で入力してください。',
|
|
||||||
'user_name.required' => '氏名は必須です。',
|
|
||||||
'user_pass.required' => 'パスワードは必須です。',
|
|
||||||
'user_pass.min' => 'パスワードは8文字以上で入力してください。',
|
|
||||||
'user_pass.confirmed' => 'パスワードと確認用パスワードが一致しません。',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
// ▼ 属性名(日本語ラベル)
|
// ▼ 属性名(日本語ラベル)
|
||||||
@ -357,158 +315,4 @@ class UsersController
|
|||||||
return redirect()->route('users')->with('success', '利用者を登録しました。');
|
return redirect()->route('users')->with('success', '利用者を登録しました。');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 利用者編集(GET: 表示 / POST: 更新)
|
|
||||||
*/
|
|
||||||
public function edit(Request $request, int $seq)
|
|
||||||
{
|
|
||||||
|
|
||||||
$user = DB::table('user')->where('user_seq', $seq)->first();
|
|
||||||
if (!$user) {
|
|
||||||
abort(404, '利用者情報が見つかりません。');
|
|
||||||
}
|
|
||||||
|
|
||||||
$operators = DB::table('ope')
|
|
||||||
->select('ope_id', 'ope_name')
|
|
||||||
->orderBy('ope_name')
|
|
||||||
->get();
|
|
||||||
|
|
||||||
$categoryOptions = $this->buildCategoryOptions();
|
|
||||||
|
|
||||||
// ▼ 退会処理専用(hiddenフィールド quit_action があれば退会処理)
|
|
||||||
if ($request->has('quit_action')) {
|
|
||||||
DB::table('user')->where('user_seq', $seq)->update([
|
|
||||||
'user_quit_flag' => 1,
|
|
||||||
'user_quitday' => now()->format('Y-m-d'),
|
|
||||||
'ope_id' => $request->input('ope_id') ?? auth()->user()->ope_id ?? null,
|
|
||||||
'updated_at' => now(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
return redirect()
|
|
||||||
->route('users_edit', ['seq' => $seq])
|
|
||||||
->with('status', '退会処理が完了しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if ($request->isMethod('get')) {
|
|
||||||
return view('admin.users.edit', [
|
|
||||||
'user' => $user,
|
|
||||||
'operators' => $operators,
|
|
||||||
'categoryOptions' => $categoryOptions,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$rules = [
|
|
||||||
'user_id' => ['required', 'regex:/^\d+$/', 'digits_between:1,10'],
|
|
||||||
'user_name' => ['required', 'string', 'max:255'],
|
|
||||||
'user_pass' => ['nullable', 'string', 'min:8', 'confirmed'],
|
|
||||||
'user_primemail' => ['nullable', 'email', 'max:255'],
|
|
||||||
'user_gender' => ['nullable', 'in:男性,女性,未入力'],
|
|
||||||
'member_id' => ['nullable', 'string', 'max:255'],
|
|
||||||
'user_mobile' => ['nullable', 'string', 'max:255'],
|
|
||||||
'user_homephone' => ['nullable', 'string', 'max:255'],
|
|
||||||
'user_birthdate' => ['nullable', 'date'],
|
|
||||||
'user_categoryid' => ['nullable', 'integer', 'exists:usertype,user_categoryid'],
|
|
||||||
'user_age' => ['nullable', 'integer', 'min:0'],
|
|
||||||
'user_chk_day' => ['nullable', 'date'],
|
|
||||||
'user_quitday' => ['nullable', 'date'],
|
|
||||||
'ope_id' => ['nullable', 'integer', 'exists:ope,ope_id'],
|
|
||||||
];
|
|
||||||
|
|
||||||
$messages = [
|
|
||||||
'user_id.required' => '利用者IDは必須です。',
|
|
||||||
'user_id.regex' => '利用者IDは半角数字のみで入力してください。',
|
|
||||||
'user_id.digits_between' => '利用者IDは最大10桁以内で入力してください。',
|
|
||||||
'user_name.required' => '氏名は必須です。',
|
|
||||||
];
|
|
||||||
|
|
||||||
$validator = Validator::make($request->all(), $rules, $messages);
|
|
||||||
if ($validator->fails()) {
|
|
||||||
return back()->withErrors($validator)->withInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = [
|
|
||||||
'user_id' => $request->input('user_id'),
|
|
||||||
'member_id' => $request->input('member_id'),
|
|
||||||
'user_name' => $request->input('user_name'),
|
|
||||||
'user_gender' => $request->input('user_gender'),
|
|
||||||
'user_mobile' => $request->input('user_mobile'),
|
|
||||||
'user_homephone' => $request->input('user_homephone'),
|
|
||||||
'user_birthdate' => $request->input('user_birthdate'),
|
|
||||||
'user_age' => $request->input('user_age'),
|
|
||||||
'user_categoryid' => $request->input('user_categoryid'),
|
|
||||||
'user_phonetic' => $request->input('user_phonetic'),
|
|
||||||
'user_tag_serial' => $request->input('user_tag_serial'),
|
|
||||||
'user_tag_serial_64' => $request->input('user_tag_serial_64'),
|
|
||||||
'qr_code' => $request->input('qr_code'),
|
|
||||||
'tag_qr_flag' => $request->input('tag_qr_flag', '0'),
|
|
||||||
'user_aid' => $request->input('user_aid'),
|
|
||||||
'user_place_qrid' => $request->input('user_place_qrid'),
|
|
||||||
'user_primemail' => $request->input('user_primemail'),
|
|
||||||
'user_submail' => $request->input('user_submail'),
|
|
||||||
'ward_residents' => $request->input('ward_residents'),
|
|
||||||
'user_workplace' => $request->input('user_workplace'),
|
|
||||||
'user_school' => $request->input('user_school'),
|
|
||||||
'user_graduate' => $request->input('user_graduate'),
|
|
||||||
'user_idcard' => $request->input('user_idcard'),
|
|
||||||
'user_idcard_chk_flag' => $request->input('user_idcard_chk_flag', '0'),
|
|
||||||
'user_chk_day' => $request->input('user_chk_day'),
|
|
||||||
'user_chk_opeid' => $request->input('ope_id'),
|
|
||||||
'ope_id' => $request->input('ope_id'),
|
|
||||||
'user_regident_zip' => $request->input('user_regident_zip'),
|
|
||||||
'user_regident_pre' => $request->input('user_regident_pre'),
|
|
||||||
'user_regident_city' => $request->input('user_regident_city'),
|
|
||||||
'user_regident_add' => $request->input('user_regident_add'),
|
|
||||||
'user_relate_zip' => $request->input('user_relate_zip'),
|
|
||||||
'user_relate_pre' => $request->input('user_relate_pre'),
|
|
||||||
'user_relate_city' => $request->input('user_relate_city'),
|
|
||||||
'user_relate_add' => $request->input('user_relate_add'),
|
|
||||||
'user_tag_issue' => $request->input('user_tag_issue'),
|
|
||||||
'issue_permission' => $request->input('issue_permission', '1'),
|
|
||||||
'user_quit_flag' => $request->input('user_quit_flag', '0'),
|
|
||||||
'user_quitday' => $request->input('user_quitday'),
|
|
||||||
'user_remarks' => $request->input('user_remarks'),
|
|
||||||
'updated_at' => now(),
|
|
||||||
];
|
|
||||||
|
|
||||||
if ($request->filled('user_pass')) {
|
|
||||||
$data['user_pass'] = Hash::make($request->input('user_pass'));
|
|
||||||
}
|
|
||||||
|
|
||||||
DB::table('user')->where('user_seq', $seq)->update($data);
|
|
||||||
|
|
||||||
return redirect()
|
|
||||||
->route('users_edit', ['seq' => $seq])
|
|
||||||
->with('status', '利用者情報を更新しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 利用者削除(POST: 削除実行)
|
|
||||||
* - user_seq をキーに削除処理を行う
|
|
||||||
* - 削除前に存在確認を行い、存在しない場合はエラーを返す
|
|
||||||
* - 削除完了後、一覧画面へリダイレクト
|
|
||||||
*/
|
|
||||||
public function delete(Request $request)
|
|
||||||
{
|
|
||||||
// ▼ パラメータ取得
|
|
||||||
$userSeq = (int) $request->input('user_seq');
|
|
||||||
|
|
||||||
// ▼ 対象レコード存在確認
|
|
||||||
$user = DB::table('user')->where('user_seq', $userSeq)->first();
|
|
||||||
if (!$user) {
|
|
||||||
// 該当データなし
|
|
||||||
return redirect()
|
|
||||||
->route('users')
|
|
||||||
->with('error', '利用者情報が見つかりません。');
|
|
||||||
}
|
|
||||||
|
|
||||||
// ▼ 削除処理実行
|
|
||||||
DB::table('user')->where('user_seq', $userSeq)->delete();
|
|
||||||
|
|
||||||
// ▼ 正常終了メッセージを一覧画面に表示
|
|
||||||
return redirect()
|
|
||||||
->route('users')
|
|
||||||
->with('success', '利用者を削除しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,42 +15,20 @@ class UsertypeController extends Controller
|
|||||||
{
|
{
|
||||||
public function list(Request $request)
|
public function list(Request $request)
|
||||||
{
|
{
|
||||||
$sort = $request->input('sort', 'user_categoryid');
|
|
||||||
$allowSort = [
|
|
||||||
'user_categoryid',
|
|
||||||
'sort_order',
|
|
||||||
'usertype_subject1',
|
|
||||||
'usertype_subject2',
|
|
||||||
'usertype_subject3',
|
|
||||||
'print_name',
|
|
||||||
];
|
|
||||||
if (!in_array($sort, $allowSort, true)) {
|
|
||||||
$sort = 'user_categoryid';
|
|
||||||
}
|
|
||||||
$sortType = strtolower($request->input('sort_type', 'asc'));
|
|
||||||
if (!in_array($sortType, ['asc', 'desc'], true)) {
|
|
||||||
$sortType = 'asc';
|
|
||||||
}
|
|
||||||
$inputs = [
|
$inputs = [
|
||||||
'isMethodPost' => $request->isMethod('post') ? 1 : 0,
|
'isMethodPost' => 0,
|
||||||
'isExport' => 0,
|
'isExport' => 0,
|
||||||
'sort' => $sort,
|
'sort' => $request->input('sort', ''),
|
||||||
'sort_type' => $sortType,
|
'sort_type' => $request->input('sort_type', ''),
|
||||||
'page' => (int) $request->get('page', 1),
|
'page' => $request->get('page', 1),
|
||||||
|
|
||||||
];
|
];
|
||||||
$filters = [
|
$inputs['isMethodPost'] = $request->isMethod('post');
|
||||||
'filter_sort_order' => $request->input('filter_sort_order', ''),
|
$inputs['list'] = Usertype::search($inputs);
|
||||||
'filter_usertype_subject1' => $request->input('filter_usertype_subject1', ''),
|
if ($inputs['list']->total() > 0 && $inputs['page'] > $inputs['list']->lastPage()) {
|
||||||
'filter_usertype_subject2' => $request->input('filter_usertype_subject2', ''),
|
|
||||||
'filter_usertype_subject3' => $request->input('filter_usertype_subject3', ''),
|
|
||||||
];
|
|
||||||
$searchParams = array_merge($inputs, $filters);
|
|
||||||
$viewData = $searchParams;
|
|
||||||
$viewData['list'] = Usertype::search($searchParams);
|
|
||||||
if ($viewData['list']->total() > 0 && $viewData['page'] > $viewData['list']->lastPage()) {
|
|
||||||
return redirect()->route('usertypes');
|
return redirect()->route('usertypes');
|
||||||
}
|
}
|
||||||
return view('admin.usertypes.list', $viewData);
|
return view('admin.usertypes.list', $inputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function add(Request $request)
|
public function add(Request $request)
|
||||||
@ -58,9 +36,9 @@ class UsertypeController extends Controller
|
|||||||
// 画面に戻すための初期値
|
// 画面に戻すための初期値
|
||||||
$viewData = [
|
$viewData = [
|
||||||
'sort_order' => old('sort_order', ''),
|
'sort_order' => old('sort_order', ''),
|
||||||
'usertype_subject1' => old('usertype_subject1', ''),
|
'category_name1' => old('category_name1', ''),
|
||||||
'usertype_subject2' => old('usertype_subject2', ''),
|
'category_name2' => old('category_name2', ''),
|
||||||
'usertype_subject3' => old('usertype_subject3', ''),
|
'category_name3' => old('category_name3', ''),
|
||||||
'print_name' => old('print_name', ''),
|
'print_name' => old('print_name', ''),
|
||||||
'usertype_money' => old('usertype_money', ''),
|
'usertype_money' => old('usertype_money', ''),
|
||||||
'usertype_remarks' => old('usertype_remarks', ''),
|
'usertype_remarks' => old('usertype_remarks', ''),
|
||||||
@ -72,9 +50,9 @@ class UsertypeController extends Controller
|
|||||||
// 入力値をまとめる
|
// 入力値をまとめる
|
||||||
$inputs = [
|
$inputs = [
|
||||||
'sort_order' => $request->input('sort_order'),
|
'sort_order' => $request->input('sort_order'),
|
||||||
'usertype_subject1' => $request->input('usertype_subject1'),
|
'category_name1' => $request->input('category_name1'),
|
||||||
'usertype_subject2' => $request->input('usertype_subject2'),
|
'category_name2' => $request->input('category_name2'),
|
||||||
'usertype_subject3' => $request->input('usertype_subject3'),
|
'category_name3' => $request->input('category_name3'),
|
||||||
'print_name' => $request->input('print_name'),
|
'print_name' => $request->input('print_name'),
|
||||||
'usertype_money' => $request->input('usertype_money'),
|
'usertype_money' => $request->input('usertype_money'),
|
||||||
'usertype_remarks' => $request->input('usertype_remarks'),
|
'usertype_remarks' => $request->input('usertype_remarks'),
|
||||||
@ -83,9 +61,9 @@ class UsertypeController extends Controller
|
|||||||
// バリデーションルール(最小限)
|
// バリデーションルール(最小限)
|
||||||
$rules = [
|
$rules = [
|
||||||
'sort_order' => 'nullable|integer',
|
'sort_order' => 'nullable|integer',
|
||||||
'usertype_subject1' => 'nullable|string|max:255',
|
'category_name1' => 'nullable|string|max:255',
|
||||||
'usertype_subject2' => 'nullable|string|max:255',
|
'category_name2' => 'nullable|string|max:255',
|
||||||
'usertype_subject3' => 'nullable|string|max:255',
|
'category_name3' => 'nullable|string|max:255',
|
||||||
'print_name' => 'required|string|max:255',
|
'print_name' => 'required|string|max:255',
|
||||||
'usertype_money' => 'nullable|string|max:255',
|
'usertype_money' => 'nullable|string|max:255',
|
||||||
'usertype_remarks' => 'nullable|string|max:255',
|
'usertype_remarks' => 'nullable|string|max:255',
|
||||||
@ -137,9 +115,9 @@ class UsertypeController extends Controller
|
|||||||
// ▼ 内蔵バリデーション(FormRequest を使わない)
|
// ▼ 内蔵バリデーション(FormRequest を使わない)
|
||||||
$rules = [
|
$rules = [
|
||||||
'sort_order' => 'nullable|integer',
|
'sort_order' => 'nullable|integer',
|
||||||
'usertype_subject1' => 'nullable|string|max:255',
|
'category_name1' => 'nullable|string|max:255',
|
||||||
'usertype_subject2' => 'nullable|string|max:255',
|
'category_name2' => 'nullable|string|max:255',
|
||||||
'usertype_subject3' => 'nullable|string|max:255',
|
'category_name3' => 'nullable|string|max:255',
|
||||||
'print_name' => 'required|string|max:255',
|
'print_name' => 'required|string|max:255',
|
||||||
'usertype_money' => 'nullable|string|max:255',
|
'usertype_money' => 'nullable|string|max:255',
|
||||||
'usertype_remarks' => 'nullable|string|max:255',
|
'usertype_remarks' => 'nullable|string|max:255',
|
||||||
@ -163,9 +141,9 @@ class UsertypeController extends Controller
|
|||||||
// fill するフィールドだけを明示したい場合は only(...) で絞ってもOK
|
// fill するフィールドだけを明示したい場合は only(...) で絞ってもOK
|
||||||
$usertype->fill([
|
$usertype->fill([
|
||||||
'sort_order' => $data['sort_order'] ?? null,
|
'sort_order' => $data['sort_order'] ?? null,
|
||||||
'usertype_subject1' => $data['usertype_subject1'] ?? null,
|
'category_name1' => $data['category_name1'] ?? null,
|
||||||
'usertype_subject2' => $data['usertype_subject2'] ?? null,
|
'category_name2' => $data['category_name2'] ?? null,
|
||||||
'usertype_subject3' => $data['usertype_subject3'] ?? null,
|
'category_name3' => $data['category_name3'] ?? null,
|
||||||
'print_name' => $data['print_name'] ?? null,
|
'print_name' => $data['print_name'] ?? null,
|
||||||
'usertype_money' => $data['usertype_money'] ?? null,
|
'usertype_money' => $data['usertype_money'] ?? null,
|
||||||
'usertype_remarks' => $data['usertype_remarks'] ?? null,
|
'usertype_remarks' => $data['usertype_remarks'] ?? null,
|
||||||
@ -219,25 +197,21 @@ class UsertypeController extends Controller
|
|||||||
|
|
||||||
public function export(Request $request)
|
public function export(Request $request)
|
||||||
{
|
{
|
||||||
$timestamp = now()->format('YmdHis');
|
|
||||||
$filename = "利用者分類マスタ{$timestamp}.csv";
|
$headers = array(
|
||||||
$filePath = storage_path("app/{$filename}");
|
"Content-type" => "text/csv;charset=UTF-8",
|
||||||
$headers = [
|
'Content-Encoding: UTF-8',
|
||||||
'Content-Type' => 'text/csv; charset=UTF-8',
|
"Content-Disposition" => "attachment; filename=file.csv",
|
||||||
'Content-Encoding' => 'UTF-8',
|
"Pragma" => "no-cache",
|
||||||
'Pragma' => 'no-cache',
|
"Cache-Control" => "must-revalidate, post-check=0, pre-check=0",
|
||||||
'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0',
|
"Expires" => "0"
|
||||||
'Expires' => '0',
|
);
|
||||||
];
|
|
||||||
$inputs = [
|
$inputs = [
|
||||||
'isMethodPost' => 0,
|
'isMethodPost' => 0,
|
||||||
'isExport' => 1,
|
'isExport' => 1,
|
||||||
'sort' => $request->input('sort', ''),
|
'sort' => $request->input('sort', ''),
|
||||||
'sort_type' => $request->input('sort_type', ''),
|
'sort_type' => $request->input('sort_type', ''),
|
||||||
'filter_sort_order' => $request->input('filter_sort_order', ''),
|
|
||||||
'filter_usertype_subject1' => $request->input('filter_usertype_subject1', ''),
|
|
||||||
'filter_usertype_subject2' => $request->input('filter_usertype_subject2', ''),
|
|
||||||
'filter_usertype_subject3' => $request->input('filter_usertype_subject3', ''),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$dataExport = Usertype::search($inputs);
|
$dataExport = Usertype::search($inputs);
|
||||||
@ -247,7 +221,8 @@ class UsertypeController extends Controller
|
|||||||
__('適用料率'),// 2
|
__('適用料率'),// 2
|
||||||
__('備考'),// 3
|
__('備考'),// 3
|
||||||
);
|
);
|
||||||
$file = fopen($filePath, 'w+');
|
$filename = "利用者分類マスタ.csv";
|
||||||
|
$file = fopen($filename, 'w+');
|
||||||
fputcsv($file, $columns);
|
fputcsv($file, $columns);
|
||||||
foreach ($dataExport as $items) {
|
foreach ($dataExport as $items) {
|
||||||
fputcsv(
|
fputcsv(
|
||||||
@ -261,7 +236,7 @@ class UsertypeController extends Controller
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
fclose($file);
|
fclose($file);
|
||||||
return Response::download($filePath, $filename, $headers)->deleteFileAfterSend(true);
|
return Response::download($filename, $filename, $headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function import(Request $request)
|
public function import(Request $request)
|
||||||
|
|||||||
@ -38,36 +38,76 @@ class UsingStatusController extends Controller
|
|||||||
public function index(Request $request, UsingStatusService $service)
|
public function index(Request $request, UsingStatusService $service)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$parkId = $request->input('park_id'); // GET/POST どちらでも取得
|
// CSRF トークンの自動検証(Laravel 12標準機能)
|
||||||
|
|
||||||
|
// リクエストパラメータの取得
|
||||||
|
// Laravel 12変更点:$request->input()の使用を推奨
|
||||||
|
$parkId = $request->input('park_id', null);
|
||||||
|
$isSearchRequest = $request->has('search') || $request->isMethod('post');
|
||||||
|
|
||||||
|
// ログ出力(デバッグ用)
|
||||||
|
Log::info('区画別利用率状況ページアクセス', [
|
||||||
|
'park_id' => $parkId,
|
||||||
|
'is_search' => $isSearchRequest,
|
||||||
|
'method' => $request->method()
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 駐輪場一覧の取得(選択用ドロップダウン)
|
||||||
$parkList = $service->getParkList();
|
$parkList = $service->getParkList();
|
||||||
|
|
||||||
// 駐輪場が選択されている場合のみ取得。「全て/空」の場合は空コレクションを返す
|
// 利用率統計データの取得
|
||||||
$utilizationStats = collect();
|
// Laravel 12変更点:デフォルトで全データを表示(ユーザー選択不要)
|
||||||
if ($parkId !== null && $parkId !== '') {
|
|
||||||
$utilizationStats = $service->getUtilizationStats($parkId);
|
$utilizationStats = $service->getUtilizationStats($parkId);
|
||||||
|
|
||||||
|
// データが空の場合の処理
|
||||||
|
if ($utilizationStats->isEmpty() && $parkId) {
|
||||||
|
// 指定された駐輪場のデータが見つからない場合
|
||||||
|
return redirect()->route('using_status')
|
||||||
|
->with('warning', '選択された駐輪場のデータが見つかりませんでした。');
|
||||||
}
|
}
|
||||||
|
|
||||||
$totals = $service->calculateTotals($utilizationStats);
|
// 検索要求でない場合は全データを表示
|
||||||
$hasData = $utilizationStats->isNotEmpty();
|
if (!$isSearchRequest && !$parkId) {
|
||||||
$isSearchRequest = ($request->isMethod('post') || $request->has('park_id'));
|
$utilizationStats = $service->getUtilizationStats(null);
|
||||||
$selectedPark = $parkList->firstWhere('park_id', $parkId);
|
}
|
||||||
|
|
||||||
|
// 合計値の計算
|
||||||
|
$totals = $service->calculateTotals($utilizationStats);
|
||||||
|
|
||||||
|
// 選択された駐輪場の情報
|
||||||
|
$selectedPark = null;
|
||||||
|
if ($parkId && $parkList->isNotEmpty()) {
|
||||||
|
$selectedPark = $parkList->firstWhere('park_id', $parkId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ビューに渡すデータの準備
|
||||||
|
$viewData = [
|
||||||
|
'parkList' => $parkList, // 駐輪場選択用リスト
|
||||||
|
'utilizationStats' => $utilizationStats, // 利用率統計データ
|
||||||
|
'totals' => $totals, // 合計値
|
||||||
|
'selectedParkId' => $parkId, // 選択された駐輪場ID
|
||||||
|
'selectedPark' => $selectedPark, // 選択された駐輪場情報
|
||||||
|
'isSearchRequest' => $isSearchRequest, // 検索リクエストかどうか
|
||||||
|
'hasData' => $utilizationStats->isNotEmpty() // データが存在するかどうか
|
||||||
|
];
|
||||||
|
|
||||||
|
// 成功メッセージの設定(検索時)
|
||||||
|
if ($isSearchRequest && $utilizationStats->isNotEmpty()) {
|
||||||
|
session()->flash('success', '利用率データを正常に取得しました。');
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('admin.using_status.index', $viewData);
|
||||||
|
|
||||||
return view('admin.using_status.index', [
|
|
||||||
'parkList' => $parkList,
|
|
||||||
'utilizationStats' => $utilizationStats,
|
|
||||||
'totals' => $totals,
|
|
||||||
'selectedParkId' => $parkId,
|
|
||||||
'selectedPark' => $selectedPark,
|
|
||||||
'isSearchRequest' => $isSearchRequest,
|
|
||||||
'hasData' => $hasData,
|
|
||||||
]);
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
|
// エラーログの出力
|
||||||
Log::error('区画別利用率状況ページエラー', [
|
Log::error('区画別利用率状況ページエラー', [
|
||||||
'error' => $e->getMessage(),
|
'error' => $e->getMessage(),
|
||||||
'file' => $e->getFile(),
|
'file' => $e->getFile(),
|
||||||
'line' => $e->getLine(),
|
'line' => $e->getLine(),
|
||||||
'park_id' => $parkId ?? null,
|
'park_id' => $parkId ?? null
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// エラー発生時のリダイレクト
|
||||||
return redirect()->route('using_status')
|
return redirect()->route('using_status')
|
||||||
->with('error', 'データの取得中にエラーが発生しました。管理者にお問い合わせください。');
|
->with('error', 'データの取得中にエラーが発生しました。管理者にお問い合わせください。');
|
||||||
}
|
}
|
||||||
@ -160,7 +200,7 @@ class UsingStatusController extends Controller
|
|||||||
foreach ($stats as $stat) {
|
foreach ($stats as $stat) {
|
||||||
$rows[] = [
|
$rows[] = [
|
||||||
(string) $stat->park_name,
|
(string) $stat->park_name,
|
||||||
(string) $stat->psection_subject,
|
(string) $stat->ptype_subject,
|
||||||
(string) $stat->park_limit,
|
(string) $stat->park_limit,
|
||||||
(string) $stat->current_count,
|
(string) $stat->current_count,
|
||||||
(string) $stat->available,
|
(string) $stat->available,
|
||||||
|
|||||||
@ -1,250 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use App\Models\Zone;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Facades\Validator;
|
|
||||||
use App\Models\Park;
|
|
||||||
use App\Models\Ptype;
|
|
||||||
use App\Models\Psection;
|
|
||||||
|
|
||||||
|
|
||||||
class ZoneController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 一覧表示(絞り込み対応)
|
|
||||||
*/
|
|
||||||
public function list(Request $request)
|
|
||||||
{
|
|
||||||
if ($request->input('action') === 'reset') {
|
|
||||||
return redirect()->route('zones');
|
|
||||||
}
|
|
||||||
|
|
||||||
// ソート設定
|
|
||||||
$sort = $request->input('sort', 'zone_id');
|
|
||||||
$sort_type = $request->input('sort_type', 'asc');
|
|
||||||
|
|
||||||
// ベースクエリ
|
|
||||||
$query = Zone::query();
|
|
||||||
|
|
||||||
// === 絞り込み条件 ===
|
|
||||||
if ($request->filled('zone_id')) {
|
|
||||||
$query->where('zone_id', $request->zone_id);
|
|
||||||
}
|
|
||||||
if ($request->filled('zone_name')) {
|
|
||||||
$query->where('zone_name', 'LIKE', "%{$request->zone_name}%");
|
|
||||||
}
|
|
||||||
if ($request->filled('park_id')) {
|
|
||||||
$query->where('park_id', $request->park_id);
|
|
||||||
}
|
|
||||||
if ($request->filled('ptype_id')) {
|
|
||||||
$query->where('ptype_id', $request->ptype_id);
|
|
||||||
}
|
|
||||||
if ($request->filled('psection_id')) {
|
|
||||||
$query->where('psection_id', $request->psection_id);
|
|
||||||
}
|
|
||||||
if ($request->has('use_flag') && $request->use_flag !== '') {
|
|
||||||
$query->where('use_flag', $request->use_flag);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ページネーション
|
|
||||||
$zones = $query->orderBy($sort, $sort_type)->paginate(20);
|
|
||||||
|
|
||||||
// === 下拉选单用の一覧データ ===
|
|
||||||
$parkList = DB::table('park')->pluck('park_name', 'park_id');
|
|
||||||
$ptypeList = DB::table('ptype')->pluck('ptype_subject', 'ptype_id');
|
|
||||||
$psectionList = DB::table('psection')->pluck('psection_subject', 'psection_id');
|
|
||||||
|
|
||||||
return view('admin.zones.list', compact(
|
|
||||||
'zones', 'sort', 'sort_type',
|
|
||||||
'parkList', 'ptypeList', 'psectionList'
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 新規登録(画面/処理)
|
|
||||||
*/
|
|
||||||
public function add(Request $request)
|
|
||||||
{
|
|
||||||
if ($request->isMethod('get')) {
|
|
||||||
$parkList = DB::table('park')->pluck('park_name', 'park_id');
|
|
||||||
$ptypeList = DB::table('ptype')->pluck('ptype_subject', 'ptype_id');
|
|
||||||
$psectionList = DB::table('psection')->pluck('psection_subject', 'psection_id');
|
|
||||||
|
|
||||||
|
|
||||||
return view('admin.zones.add', [
|
|
||||||
'isEdit' => false,
|
|
||||||
'record' => new Zone(),
|
|
||||||
'parkList' => $parkList,
|
|
||||||
'ptypeList' => $ptypeList,
|
|
||||||
'psectionList' => $psectionList,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ▼ POST時:バリデーション
|
|
||||||
$rules = [
|
|
||||||
'park_id' => 'required|integer',
|
|
||||||
'ptype_id' => 'required|integer',
|
|
||||||
'psection_id' => 'required|integer',
|
|
||||||
'zone_name' => 'required|string|max:255',
|
|
||||||
'zone_number' => 'nullable|integer|min:0',
|
|
||||||
'zone_standard' => 'nullable|integer|min:0',
|
|
||||||
'zone_tolerance' => 'nullable|integer|min:0',
|
|
||||||
'zone_sort' => 'nullable|integer|min:0',
|
|
||||||
];
|
|
||||||
|
|
||||||
$messages = [
|
|
||||||
'park_id.required' => '駐輪場は必須です。',
|
|
||||||
'ptype_id.required' => '駐輪分類は必須です。',
|
|
||||||
'psection_id.required' => '車種区分は必須です。',
|
|
||||||
'zone_name.required' => 'ゾーン名は必須です。',
|
|
||||||
];
|
|
||||||
|
|
||||||
$validator = Validator::make($request->all(), $rules, $messages);
|
|
||||||
|
|
||||||
if ($validator->fails()) {
|
|
||||||
return redirect()->back()->withErrors($validator)->withInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ▼ 登録処理
|
|
||||||
DB::transaction(function () use ($request) {
|
|
||||||
$new = new Zone();
|
|
||||||
$new->fill($request->only([
|
|
||||||
'park_id',
|
|
||||||
'ptype_id',
|
|
||||||
'psection_id',
|
|
||||||
'zone_name',
|
|
||||||
'zone_number',
|
|
||||||
'zone_standard',
|
|
||||||
'zone_tolerance',
|
|
||||||
'zone_sort',
|
|
||||||
]));
|
|
||||||
$new->save();
|
|
||||||
});
|
|
||||||
|
|
||||||
return redirect()->route('zones')->with('success', '登録しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 編集(画面/処理)
|
|
||||||
*/
|
|
||||||
public function edit(Request $request, $id)
|
|
||||||
{
|
|
||||||
// 該当データ取得
|
|
||||||
$record = Zone::find($id);
|
|
||||||
if (!$record) {
|
|
||||||
abort(404);
|
|
||||||
}
|
|
||||||
|
|
||||||
$parkList = DB::table('park')->pluck('park_name', 'park_id');
|
|
||||||
$ptypeList = DB::table('ptype')->pluck('ptype_subject', 'ptype_id');
|
|
||||||
$psectionList = DB::table('psection')->pluck('psection_subject', 'psection_id');
|
|
||||||
|
|
||||||
|
|
||||||
if ($request->isMethod('get')) {
|
|
||||||
// 編集画面表示
|
|
||||||
return view('admin.zones.edit', [
|
|
||||||
'isEdit' => true,
|
|
||||||
'record' => $record,
|
|
||||||
'parkList' => $parkList,
|
|
||||||
'ptypeList' => $ptypeList,
|
|
||||||
'psectionList' => $psectionList,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ▼ POST時:バリデーション
|
|
||||||
$rules = [
|
|
||||||
'park_id' => 'required|integer',
|
|
||||||
'ptype_id' => 'required|integer',
|
|
||||||
'psection_id' => 'required|integer',
|
|
||||||
'zone_name' => 'required|string|max:255',
|
|
||||||
'zone_number' => 'nullable|integer|min:0',
|
|
||||||
'zone_standard' => 'nullable|integer|min:0',
|
|
||||||
'zone_tolerance' => 'nullable|integer|min:0',
|
|
||||||
'zone_sort' => 'nullable|integer|min:0',
|
|
||||||
];
|
|
||||||
|
|
||||||
$messages = [
|
|
||||||
'park_id.required' => '駐輪場は必須です。',
|
|
||||||
'ptype_id.required' => '駐輪分類は必須です。',
|
|
||||||
'psection_id.required' => '車種区分は必須です。',
|
|
||||||
'zone_name.required' => 'ゾーン名は必須です。',
|
|
||||||
];
|
|
||||||
|
|
||||||
$validator = Validator::make($request->all(), $rules, $messages);
|
|
||||||
|
|
||||||
if ($validator->fails()) {
|
|
||||||
return redirect()->back()->withErrors($validator)->withInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ▼ 更新処理
|
|
||||||
DB::transaction(function () use ($request, $record) {
|
|
||||||
$record->fill($request->only([
|
|
||||||
'park_id',
|
|
||||||
'ptype_id',
|
|
||||||
'psection_id',
|
|
||||||
'zone_name',
|
|
||||||
'zone_number',
|
|
||||||
'zone_standard',
|
|
||||||
'zone_tolerance',
|
|
||||||
'zone_sort',
|
|
||||||
]));
|
|
||||||
$record->save();
|
|
||||||
});
|
|
||||||
|
|
||||||
return redirect()->route('zones')->with('success', '更新しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 削除(単一/複数対応)
|
|
||||||
*/
|
|
||||||
public function delete(Request $request)
|
|
||||||
{
|
|
||||||
$ids = [];
|
|
||||||
|
|
||||||
// 単一削除(id 指定)
|
|
||||||
if ($request->filled('id')) {
|
|
||||||
$ids[] = (int) $request->input('id');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 複数削除(チェックボックス pk[])
|
|
||||||
if (is_array($request->input('pk'))) {
|
|
||||||
$ids = array_merge($ids, $request->input('pk'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重複除去 & 数値変換
|
|
||||||
$ids = array_values(array_unique(array_map('intval', $ids)));
|
|
||||||
|
|
||||||
// 削除対象がない場合
|
|
||||||
if (empty($ids)) {
|
|
||||||
return back()->with('error', '削除対象が選択されていません。');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 削除実行
|
|
||||||
Zone::whereIn('zone_id', $ids)->delete();
|
|
||||||
|
|
||||||
return redirect()->route('zones')->with('success', '削除しました。');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* バリデーション共通化
|
|
||||||
*/
|
|
||||||
private function validateZone(Request $request)
|
|
||||||
{
|
|
||||||
return $request->validate([
|
|
||||||
'zone_name' => 'required|string|max:50',
|
|
||||||
'park_id' => 'required|integer',
|
|
||||||
'ptype_id' => 'nullable|integer',
|
|
||||||
'psection_id' => 'nullable|integer',
|
|
||||||
'zone_number' => 'nullable|integer|min:0',
|
|
||||||
'zone_standard' => 'nullable|integer|min:0',
|
|
||||||
'zone_tolerance' => 'nullable|integer|min:0',
|
|
||||||
'use_flag' => 'nullable|boolean',
|
|
||||||
'memo' => 'nullable|string|max:255',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -77,13 +77,9 @@ class LoginController extends Controller
|
|||||||
*/
|
*/
|
||||||
protected function validateLogin(Request $request)
|
protected function validateLogin(Request $request)
|
||||||
{
|
{
|
||||||
// 個別未入力メッセージ(仕様1,2)
|
|
||||||
$request->validate([
|
$request->validate([
|
||||||
'ope_id' => 'required|string',
|
'ope_id' => 'required|string', // オペレータID(旧システムと同じ)
|
||||||
'ope_pass' => 'required|string',
|
'ope_pass' => 'required|string', // オペレータパスワード(旧システムと同じ)
|
||||||
], [
|
|
||||||
'ope_id.required' => 'ログインIDが未入力です。',
|
|
||||||
'ope_pass.required' => 'パスワードが未入力です。',
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,13 +91,6 @@ class LoginController extends Controller
|
|||||||
*/
|
*/
|
||||||
protected function attemptLogin(Request $request)
|
protected function attemptLogin(Request $request)
|
||||||
{
|
{
|
||||||
// 先にIDのみでオペレータ取得して退職フラグを確認(仕様5-1)
|
|
||||||
$opeId = $request->input('ope_id');
|
|
||||||
$operator = \App\Models\Ope::where('ope_id', $opeId)->first();
|
|
||||||
if ($operator && (int)($operator->ope_quit_flag) === 1) {
|
|
||||||
// 退職扱いは認証失敗と同じメッセージ(仕様5-1 と 3/4 統一表示)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return Auth::attempt($this->credentials($request), false);
|
return Auth::attempt($this->credentials($request), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,9 +118,9 @@ class LoginController extends Controller
|
|||||||
protected function sendLoginResponse(Request $request)
|
protected function sendLoginResponse(Request $request)
|
||||||
{
|
{
|
||||||
$request->session()->regenerate();
|
$request->session()->regenerate();
|
||||||
|
|
||||||
$this->clearLoginAttempts($request);
|
$this->clearLoginAttempts($request);
|
||||||
// 仕様5: ログインIDをセッション保持
|
|
||||||
$request->session()->put('login_ope_id', $request->input('ope_id'));
|
|
||||||
return redirect()->intended($this->redirectTo);
|
return redirect()->intended($this->redirectTo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,427 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Webhook;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Facades\Queue;
|
|
||||||
use App\Models\Batch\BatchLog;
|
|
||||||
use App\Models\SettlementTransaction;
|
|
||||||
use App\Models\RegularContract;
|
|
||||||
use App\Jobs\ProcessSettlementJob;
|
|
||||||
use Carbon\Carbon;
|
|
||||||
|
|
||||||
class WellnetController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Wellnet PUSH 受信 (SHJ-4A)
|
|
||||||
* 受け取った SOAP/XML を解析し、settlement_transaction に登録。
|
|
||||||
* 幂等性チェック、データ検証、キュー投入を含む完全な処理を実行。
|
|
||||||
*/
|
|
||||||
public function receive(Request $request)
|
|
||||||
{
|
|
||||||
$startedAt = now();
|
|
||||||
$raw = $request->getContent();
|
|
||||||
$md5Hash = md5($raw);
|
|
||||||
|
|
||||||
// IP白名单检查(如果配置了)
|
|
||||||
if (!$this->validateClientIp($request->ip())) {
|
|
||||||
Log::warning('SHJ-4A IP白名单验证失败', [
|
|
||||||
'ip' => $request->ip(),
|
|
||||||
'content_length' => strlen($raw),
|
|
||||||
]);
|
|
||||||
return $this->errorResponse('Unauthorized IP', 403);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 事前にログ記録(サイズ上限に注意)
|
|
||||||
Log::info('SHJ-4A Wellnet PUSH received', [
|
|
||||||
'length' => strlen($raw),
|
|
||||||
'content_type' => $request->header('Content-Type'),
|
|
||||||
'ip' => $request->ip(),
|
|
||||||
'md5_hash' => $md5Hash,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 共通バッチログ: start
|
|
||||||
$batch = BatchLog::createBatchLog(
|
|
||||||
'shj4a',
|
|
||||||
BatchLog::STATUS_START,
|
|
||||||
[
|
|
||||||
'ip' => $request->ip(),
|
|
||||||
'content_type' => $request->header('Content-Type'),
|
|
||||||
'content_length' => strlen($raw),
|
|
||||||
'md5_hash' => $md5Hash,
|
|
||||||
],
|
|
||||||
'SHJ-4A Wellnet PUSH start'
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 【処理1】幂等性检查 - MD5重复检查
|
|
||||||
$existingByMd5 = SettlementTransaction::where('md5_string', $md5Hash)->first();
|
|
||||||
if ($existingByMd5) {
|
|
||||||
Log::info('SHJ-4A 幂等性: MD5重复检测', [
|
|
||||||
'md5_hash' => $md5Hash,
|
|
||||||
'existing_id' => $existingByMd5->settlement_transaction_id,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$batch->update([
|
|
||||||
'status' => BatchLog::STATUS_SUCCESS,
|
|
||||||
'end_time' => now(),
|
|
||||||
'message' => 'SHJ-4A 幂等性: MD5重复,直接返回成功',
|
|
||||||
'success_count' => 0, // 幂等返回不计入成功数
|
|
||||||
]);
|
|
||||||
|
|
||||||
return $this->successResponse('処理済み(幂等性)');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 【処理2】SOAP/XML解析
|
|
||||||
$xml = @simplexml_load_string($raw);
|
|
||||||
if (!$xml) {
|
|
||||||
throw new \RuntimeException('Invalid XML/SOAP payload');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Body 以下の最初の要素を取得
|
|
||||||
$nsBody = $xml->children('http://schemas.xmlsoap.org/soap/envelope/')->Body ?? null;
|
|
||||||
$payloadNode = $nsBody ? current($nsBody->children()) : $xml; // SOAPでなければ素のXML想定
|
|
||||||
|
|
||||||
// XML -> 配列化
|
|
||||||
$payloadArray = json_decode(json_encode($payloadNode), true) ?? [];
|
|
||||||
|
|
||||||
// 【処理3】データ抽出と正規化
|
|
||||||
$data = $this->extractSettlementData($payloadArray, $md5Hash);
|
|
||||||
|
|
||||||
// 【処理4】必須フィールド検証
|
|
||||||
$this->validateRequiredFields($data);
|
|
||||||
|
|
||||||
// 【処理5】複合キー重复检查(contract_payment_number + pay_date + settlement_amount)
|
|
||||||
$existingByComposite = $this->findExistingByCompositeKey($data);
|
|
||||||
if ($existingByComposite) {
|
|
||||||
Log::info('SHJ-4A 幂等性: 複合キー重复検出', [
|
|
||||||
'contract_payment_number' => $data['contract_payment_number'],
|
|
||||||
'pay_date' => $data['pay_date'],
|
|
||||||
'settlement_amount' => $data['settlement_amount'],
|
|
||||||
'existing_id' => $existingByComposite->settlement_transaction_id,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$batch->update([
|
|
||||||
'status' => BatchLog::STATUS_SUCCESS,
|
|
||||||
'end_time' => now(),
|
|
||||||
'message' => 'SHJ-4A 幂等性: 複合キー重复,直接返回成功',
|
|
||||||
'success_count' => 0,
|
|
||||||
]);
|
|
||||||
|
|
||||||
return $this->successResponse('処理済み(幂等性)');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 【処理6】データベース取込と関連処理
|
|
||||||
$settlementId = null;
|
|
||||||
DB::transaction(function() use ($data, $batch, &$settlementId) {
|
|
||||||
// 決済トランザクション登録
|
|
||||||
$settlement = SettlementTransaction::create($data);
|
|
||||||
$settlementId = $settlement->settlement_transaction_id;
|
|
||||||
|
|
||||||
// 契約テーブルの軽微な更新(SHJ-4Bで正式更新)
|
|
||||||
RegularContract::where('contract_payment_number', $data['contract_payment_number'])
|
|
||||||
->update(['contract_updated_at' => now()]);
|
|
||||||
|
|
||||||
// バッチログ成功更新
|
|
||||||
$batch->update([
|
|
||||||
'status' => BatchLog::STATUS_SUCCESS,
|
|
||||||
'end_time' => now(),
|
|
||||||
'message' => 'SHJ-4A Wellnet PUSH stored successfully',
|
|
||||||
'success_count' => 1,
|
|
||||||
'parameters' => json_encode([
|
|
||||||
'settlement_transaction_id' => $settlementId,
|
|
||||||
'contract_payment_number' => $data['contract_payment_number'],
|
|
||||||
'settlement_amount' => $data['settlement_amount'],
|
|
||||||
]),
|
|
||||||
]);
|
|
||||||
|
|
||||||
Log::info('SHJ-4A 決済トランザクション登録成功', [
|
|
||||||
'settlement_transaction_id' => $settlementId,
|
|
||||||
'contract_payment_number' => $data['contract_payment_number'],
|
|
||||||
'settlement_amount' => $data['settlement_amount'],
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 【処理7】SHJ-4B用キュージョブ投入
|
|
||||||
try {
|
|
||||||
$jobContext = [
|
|
||||||
'contract_payment_number' => $data['contract_payment_number'],
|
|
||||||
'settlement_amount' => $data['settlement_amount'],
|
|
||||||
'pay_date' => $data['pay_date'],
|
|
||||||
'pay_code' => $data['pay_code'],
|
|
||||||
'triggered_by' => 'shj4a_webhook',
|
|
||||||
'triggered_at' => $startedAt->toISOString(),
|
|
||||||
];
|
|
||||||
|
|
||||||
ProcessSettlementJob::dispatch($settlementId, $jobContext);
|
|
||||||
|
|
||||||
Log::info('SHJ-4A ProcessSettlementJob投入成功', [
|
|
||||||
'settlement_transaction_id' => $settlementId,
|
|
||||||
'job_context' => $jobContext,
|
|
||||||
]);
|
|
||||||
|
|
||||||
} catch (\Throwable $jobError) {
|
|
||||||
// キュー投入失敗は警告レベル(メイン処理は成功済み)
|
|
||||||
Log::warning('SHJ-4A ProcessSettlementJob投入失敗', [
|
|
||||||
'settlement_transaction_id' => $settlementId,
|
|
||||||
'error' => $jobError->getMessage(),
|
|
||||||
'note' => '兜底巡検で処理される予定',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->successResponse();
|
|
||||||
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
Log::error('SHJ-4A error', [
|
|
||||||
'error' => $e->getMessage(),
|
|
||||||
'trace' => $e->getTraceAsString(),
|
|
||||||
'md5_hash' => $md5Hash,
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (isset($batch)) {
|
|
||||||
$batch->update([
|
|
||||||
'status' => BatchLog::STATUS_ERROR,
|
|
||||||
'end_time' => now(),
|
|
||||||
'message' => 'SHJ-4A failed: ' . $e->getMessage(),
|
|
||||||
'error_details' => $e->getTraceAsString(),
|
|
||||||
'error_count' => 1,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->errorResponse($e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* IP白名单验证
|
|
||||||
*
|
|
||||||
* @param string $clientIp
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
private function validateClientIp(string $clientIp): bool
|
|
||||||
{
|
|
||||||
$whitelist = config('services.wellnet.ip_whitelist', '');
|
|
||||||
|
|
||||||
if (empty($whitelist)) {
|
|
||||||
return true; // 白名单为空时不验证
|
|
||||||
}
|
|
||||||
|
|
||||||
$allowedIps = array_map('trim', explode(',', $whitelist));
|
|
||||||
|
|
||||||
foreach ($allowedIps as $allowedIp) {
|
|
||||||
if (strpos($allowedIp, '/') !== false) {
|
|
||||||
// CIDR記法対応
|
|
||||||
if ($this->ipInRange($clientIp, $allowedIp)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 直接IP比較
|
|
||||||
if ($clientIp === $allowedIp) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CIDR範囲でのIP检查
|
|
||||||
*
|
|
||||||
* @param string $ip
|
|
||||||
* @param string $range
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
private function ipInRange(string $ip, string $range): bool
|
|
||||||
{
|
|
||||||
list($subnet, $bits) = explode('/', $range);
|
|
||||||
$ip = ip2long($ip);
|
|
||||||
$subnet = ip2long($subnet);
|
|
||||||
$mask = -1 << (32 - $bits);
|
|
||||||
$subnet &= $mask; # nb: in case the supplied subnet wasn't correctly aligned
|
|
||||||
return ($ip & $mask) == $subnet;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 決済データの抽出と正規化
|
|
||||||
*
|
|
||||||
* @param array $payloadArray
|
|
||||||
* @param string $md5Hash
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
private function extractSettlementData(array $payloadArray, string $md5Hash): array
|
|
||||||
{
|
|
||||||
// inData/Result系の取り出し(キー名差異に寛容)
|
|
||||||
$first = function(array $arr, array $keys, $default = null) {
|
|
||||||
foreach ($keys as $k) {
|
|
||||||
if (isset($arr[$k])) return is_array($arr[$k]) ? $arr[$k] : (string)$arr[$k];
|
|
||||||
}
|
|
||||||
return $default;
|
|
||||||
};
|
|
||||||
|
|
||||||
$flat = $payloadArray;
|
|
||||||
// よくある入れ子: { YoyakuNyukin: { inData: {...} } } / { YoyakuNyukinResponse: { YoyakuNyukinResult: {...} } }
|
|
||||||
foreach (['inData','YoyakuSyunoBarCodeResult','YoyakuNyukinResult','YoyakuSyunoETicketResult'] as $k) {
|
|
||||||
if (isset($flat[$k]) && is_array($flat[$k])) { $flat = $flat[$k]; }
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = [
|
|
||||||
'pay_code' => $first($flat, ['NyukinPayCode','SyunoPayCode','BcPayCode']),
|
|
||||||
'contract_payment_number' => $first($flat, ['NyukinRecvNum','SyunoRecvNum','RecvNum','contract_payment_number']),
|
|
||||||
'corp_code' => $first($flat, ['NyukinCorpCode','SyunoCorpCode','BcCorpCode','CorpCode']),
|
|
||||||
'mms_date' => $first($flat, ['NyukinReferDate','SyunoMMSNo','MmsDate']),
|
|
||||||
'cvs_code' => $first($flat, ['NyukinCvsCode','CvsCode']),
|
|
||||||
'shop_code' => $first($flat, ['NyukinShopCode','ShopCode']),
|
|
||||||
'pay_date' => $first($flat, ['NyukinPaidDate','PaidDate']),
|
|
||||||
'settlement_amount' => $first($flat, ['NyukinPaidAmount','SyunoPayAmount','PaidAmount']),
|
|
||||||
'stamp_flag' => $first($flat, ['NyukinInshiFlag','InshiFlag']),
|
|
||||||
'status' => 'received',
|
|
||||||
'md5_string' => $md5Hash,
|
|
||||||
];
|
|
||||||
|
|
||||||
// データ正規化処理
|
|
||||||
$data = $this->normalizeSettlementData($data);
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 決済データの正規化
|
|
||||||
*
|
|
||||||
* @param array $data
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
private function normalizeSettlementData(array $data): array
|
|
||||||
{
|
|
||||||
// 金額を数値化(非負数)
|
|
||||||
if (!empty($data['settlement_amount'])) {
|
|
||||||
$amount = preg_replace('/[^\d.]/', '', $data['settlement_amount']);
|
|
||||||
$data['settlement_amount'] = max(0, (float)$amount);
|
|
||||||
} else {
|
|
||||||
$data['settlement_amount'] = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 支払日時の正規化
|
|
||||||
if (!empty($data['pay_date'])) {
|
|
||||||
try {
|
|
||||||
$data['pay_date'] = Carbon::parse($data['pay_date'])->format('Y-m-d H:i:s');
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
Log::warning('SHJ-4A 支払日時解析失敗', [
|
|
||||||
'original_pay_date' => $data['pay_date'],
|
|
||||||
'error' => $e->getMessage(),
|
|
||||||
]);
|
|
||||||
$data['pay_date'] = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 文字列フィールドのトリム
|
|
||||||
$stringFields = ['pay_code', 'contract_payment_number', 'corp_code', 'mms_date', 'cvs_code', 'shop_code', 'stamp_flag'];
|
|
||||||
foreach ($stringFields as $field) {
|
|
||||||
if (isset($data[$field])) {
|
|
||||||
$data[$field] = trim($data[$field]) ?: null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 必須フィールドの検証
|
|
||||||
*
|
|
||||||
* @param array $data
|
|
||||||
* @throws \RuntimeException
|
|
||||||
*/
|
|
||||||
private function validateRequiredFields(array $data): void
|
|
||||||
{
|
|
||||||
// 必須フィールドのチェック
|
|
||||||
if (empty($data['contract_payment_number'])) {
|
|
||||||
throw new \RuntimeException('必須フィールドが不足: contract_payment_number (RecvNum)');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isset($data['settlement_amount']) || $data['settlement_amount'] === null) {
|
|
||||||
throw new \RuntimeException('必須フィールドが不足: settlement_amount');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($data['pay_date'])) {
|
|
||||||
throw new \RuntimeException('必須フィールドが不足: pay_date');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 複合キーによる既存レコード検索
|
|
||||||
*
|
|
||||||
* @param array $data
|
|
||||||
* @return SettlementTransaction|null
|
|
||||||
*/
|
|
||||||
private function findExistingByCompositeKey(array $data): ?SettlementTransaction
|
|
||||||
{
|
|
||||||
return SettlementTransaction::where('contract_payment_number', $data['contract_payment_number'])
|
|
||||||
->where('pay_date', $data['pay_date'])
|
|
||||||
->where('settlement_amount', $data['settlement_amount'])
|
|
||||||
->first();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 成功レスポンスの生成
|
|
||||||
*
|
|
||||||
* @param string $message
|
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
|
||||||
private function successResponse(string $message = '正常処理'): \Illuminate\Http\Response
|
|
||||||
{
|
|
||||||
$responseFormat = config('services.wellnet.response_format', 'json');
|
|
||||||
|
|
||||||
if ($responseFormat === 'soap') {
|
|
||||||
return $this->soapResponse(0, $message);
|
|
||||||
} else {
|
|
||||||
return response()->json(['result' => 0, 'message' => $message]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* エラーレスポンスの生成
|
|
||||||
*
|
|
||||||
* @param string $message
|
|
||||||
* @param int $httpCode
|
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
|
||||||
private function errorResponse(string $message, int $httpCode = 500): \Illuminate\Http\Response
|
|
||||||
{
|
|
||||||
$responseFormat = config('services.wellnet.response_format', 'json');
|
|
||||||
|
|
||||||
if ($responseFormat === 'soap') {
|
|
||||||
return $this->soapResponse(1, $message, $httpCode);
|
|
||||||
} else {
|
|
||||||
$resultCode = ($httpCode >= 500) ? 1 : 2; // サーバーエラー:1, クライアントエラー:2
|
|
||||||
return response()->json(['result' => $resultCode, 'error' => $message], $httpCode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SOAP形式のレスポンス生成
|
|
||||||
*
|
|
||||||
* @param int $resultCode
|
|
||||||
* @param string $message
|
|
||||||
* @param int $httpCode
|
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
|
||||||
private function soapResponse(int $resultCode, string $message, int $httpCode = 200): \Illuminate\Http\Response
|
|
||||||
{
|
|
||||||
$soapEnvelope = '<?xml version="1.0" encoding="utf-8"?>'
|
|
||||||
. '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">'
|
|
||||||
. '<soap:Body>'
|
|
||||||
. '<WellnetPushResponse>'
|
|
||||||
. '<Result>' . htmlspecialchars($resultCode) . '</Result>'
|
|
||||||
. '<Message>' . htmlspecialchars($message) . '</Message>'
|
|
||||||
. '</WellnetPushResponse>'
|
|
||||||
. '</soap:Body>'
|
|
||||||
. '</soap:Envelope>';
|
|
||||||
|
|
||||||
return response($soapEnvelope, $httpCode)
|
|
||||||
->header('Content-Type', 'text/xml; charset=utf-8');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Requests;
|
|
||||||
|
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
|
||||||
|
|
||||||
class RegularContractRequest extends FormRequest
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Determine if the user is authorized to make this request.
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function authorize()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the validation rules that apply to the request.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function rules()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'contract_cvs_class'=>'max:2',
|
|
||||||
'contract_qr_id'=>'required',
|
|
||||||
'user_id'=>'required|integer',
|
|
||||||
'user_categoryid'=>'required|integer',
|
|
||||||
'reserve_id'=>'required|integer',
|
|
||||||
'park_id'=>'required|integer',
|
|
||||||
'price_parkplaceid'=>'required|integer',
|
|
||||||
|
|
||||||
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Requests;
|
|
||||||
|
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
|
||||||
|
|
||||||
class RegularTypeRequest extends FormRequest
|
|
||||||
{
|
|
||||||
public function authorize()
|
|
||||||
{
|
|
||||||
return true; // 認証はコントローラーで行うため、ここでは常にtrueを返す
|
|
||||||
}
|
|
||||||
|
|
||||||
public function rules()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'city_id' => 'required|string|max:255',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function messages()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'city_id.required' => '市区名は必須です。',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,70 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Requests;
|
|
||||||
|
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
|
||||||
|
|
||||||
class UserRequest extends FormRequest
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* ユーザーがこのリクエストを実行する権限があるかどうかを判断
|
|
||||||
*/
|
|
||||||
public function authorize(): bool
|
|
||||||
{
|
|
||||||
return true; // 認証済みユーザーのみアクセス可能
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* リクエストに適用されるバリデーションルール
|
|
||||||
*/
|
|
||||||
public function rules(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'user_id' => 'required|string|max:255',
|
|
||||||
'user_name' => 'required|string|max:255',
|
|
||||||
'user_phonetic' => 'nullable|string|max:255',
|
|
||||||
'user_gender' => 'nullable|string',
|
|
||||||
'user_birthdate' => 'nullable|date',
|
|
||||||
'user_mobile' => 'nullable|string|max:20',
|
|
||||||
'user_homephone' => 'nullable|string|max:20',
|
|
||||||
'user_primemail' => 'nullable|email|max:255',
|
|
||||||
'user_submail' => 'nullable|email|max:255',
|
|
||||||
'user_regident_zip' => 'nullable|string|max:10',
|
|
||||||
'user_regident_pre' => 'nullable|string|max:50',
|
|
||||||
'user_regident_city' => 'nullable|string|max:100',
|
|
||||||
'user_regident_add' => 'nullable|string|max:255',
|
|
||||||
'user_relate_zip' => 'nullable|string|max:10',
|
|
||||||
'user_relate_pre' => 'nullable|string|max:50',
|
|
||||||
'user_relate_city' => 'nullable|string|max:100',
|
|
||||||
'user_relate_add' => 'nullable|string|max:255',
|
|
||||||
'user_workplace' => 'nullable|string|max:255',
|
|
||||||
'user_school' => 'nullable|string|max:255',
|
|
||||||
'user_graduate' => 'nullable|string|max:255',
|
|
||||||
'user_idcard' => 'nullable|string|max:255',
|
|
||||||
'user_remarks' => 'nullable|string',
|
|
||||||
'photo_filename1' => 'nullable|image|mimes:jpeg,png,jpg,gif|max:2048',
|
|
||||||
'photo_filename2' => 'nullable|image|mimes:jpeg,png,jpg,gif|max:2048',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* カスタムバリデーションメッセージ
|
|
||||||
*/
|
|
||||||
public function messages(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'user_id.required' => '利用者IDは必須です。',
|
|
||||||
'user_id.unique' => 'この利用者IDは既に使用されています。',
|
|
||||||
'user_name.required' => '利用者名は必須です。',
|
|
||||||
'user_primemail.email' => '有効なメールアドレスを入力してください。',
|
|
||||||
'user_submail.email' => '有効なメールアドレスを入力してください。',
|
|
||||||
'photo_filename1.image' => '写真ファイル1は画像である必要があります。',
|
|
||||||
'photo_filename1.max' => '写真ファイル1のサイズは2MB以下である必要があります。',
|
|
||||||
'photo_filename2.image' => '写真ファイル2は画像である必要があります。',
|
|
||||||
'photo_filename2.max' => '写真ファイル2のサイズは2MB以下である必要があります。',
|
|
||||||
'password.required' => 'パスワードは必須です。',
|
|
||||||
'password.min' => 'パスワードは6文字以上である必要があります。',
|
|
||||||
'password.confirmed' => 'パスワード確認が一致しません。',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,183 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Jobs;
|
|
||||||
|
|
||||||
use Illuminate\Bus\Queueable;
|
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
||||||
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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SHJ-4B 決済トランザクション処理ジョブ
|
|
||||||
*
|
|
||||||
* SHJ-4Aで登録された決済情報を基に定期契約の更新処理を行う
|
|
||||||
*/
|
|
||||||
class ProcessSettlementJob implements ShouldQueue
|
|
||||||
{
|
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ジョブの実行可能回数
|
|
||||||
*
|
|
||||||
* @var int
|
|
||||||
*/
|
|
||||||
public $tries = 3;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ジョブの実行間隔(秒)
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
public $backoff = [60, 300, 900];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 使用するキュー名
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
public $queue = 'settlement';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 決済トランザクションID
|
|
||||||
*
|
|
||||||
* @var int
|
|
||||||
*/
|
|
||||||
protected $settlementTransactionId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 追加のコンテキスト情報
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
protected $context;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* コンストラクタ
|
|
||||||
*
|
|
||||||
* @param int $settlementTransactionId 決済トランザクションID
|
|
||||||
* @param array $context 追加のコンテキスト情報
|
|
||||||
*/
|
|
||||||
public function __construct(int $settlementTransactionId, array $context = [])
|
|
||||||
{
|
|
||||||
$this->settlementTransactionId = $settlementTransactionId;
|
|
||||||
$this->context = $context;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ジョブを実行
|
|
||||||
*
|
|
||||||
* SHJ-4Bサービスを使用して決済トランザクション処理を実行
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
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開始', [
|
|
||||||
'settlement_transaction_id' => $this->settlementTransactionId,
|
|
||||||
'context' => $this->context,
|
|
||||||
'start_time' => $startTime,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// SHJ-4Bサービスを使用して決済トランザクション処理を実行
|
|
||||||
$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),
|
|
||||||
'result' => $result,
|
|
||||||
]);
|
|
||||||
} 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,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
Log::error('SHJ-4B ProcessSettlementJob失敗', [
|
|
||||||
'settlement_transaction_id' => $this->settlementTransactionId,
|
|
||||||
'error' => $e->getMessage(),
|
|
||||||
'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,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// ジョブを失敗させて再試行を促す
|
|
||||||
throw $e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ジョブが失敗した場合の処理
|
|
||||||
*
|
|
||||||
* @param \Throwable $exception
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function failed(\Throwable $exception)
|
|
||||||
{
|
|
||||||
Log::error('SHJ-4B ProcessSettlementJob最終失敗', [
|
|
||||||
'settlement_transaction_id' => $this->settlementTransactionId,
|
|
||||||
'context' => $this->context,
|
|
||||||
'error' => $exception->getMessage(),
|
|
||||||
'attempts' => $this->attempts(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 最終失敗時の追加処理があればここに記述
|
|
||||||
// 例:管理者への通知、障害キューへの登録など
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -85,5 +85,3 @@ class OperatorQue extends Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -56,5 +56,3 @@ class Park extends Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -111,5 +111,3 @@ class User extends Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -19,4 +19,3 @@ abstract class BaseModel extends Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -7,10 +7,10 @@ use Illuminate\Database\Eloquent\Model;
|
|||||||
class City extends Model
|
class City extends Model
|
||||||
{
|
{
|
||||||
protected $table = 'city';
|
protected $table = 'city';
|
||||||
|
|
||||||
protected $primaryKey = 'city_id';
|
protected $primaryKey = 'city_id';
|
||||||
protected $keyType = 'int';
|
|
||||||
public $incrementing = true;
|
protected $fillable = [
|
||||||
protected $fillable = [
|
|
||||||
'city_id',
|
'city_id',
|
||||||
'city_name',
|
'city_name',
|
||||||
'print_layout',
|
'print_layout',
|
||||||
@ -18,19 +18,7 @@ class City extends Model
|
|||||||
'city_remarks',
|
'city_remarks',
|
||||||
'created_at',
|
'created_at',
|
||||||
'updated_at',
|
'updated_at',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
|
||||||
* 都市のリストを取得
|
|
||||||
*/
|
|
||||||
public static function getList(?int $operatorId = null): array
|
|
||||||
{
|
|
||||||
return static::query()
|
|
||||||
->when($operatorId, fn ($q) => $q->where('operator_id', $operatorId))
|
|
||||||
->orderBy('city_name')
|
|
||||||
->pluck('city_name', 'city_id')
|
|
||||||
->toArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,5 +38,3 @@ trait HasSortable
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,91 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
use App\Utils;
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
class ContractAllowableCity extends Model
|
|
||||||
{
|
|
||||||
const CREATED_AT = 'created_at';
|
|
||||||
const UPDATED_AT = 'updated_at';
|
|
||||||
const PERPAGE = 50;
|
|
||||||
|
|
||||||
protected $table = 'contract_allowable_city';
|
|
||||||
protected $primaryKey = 'contract_allowable_city_id';
|
|
||||||
|
|
||||||
protected $fillable = [
|
|
||||||
'city_id',
|
|
||||||
'contract_allowable_city_name',
|
|
||||||
'park_id',
|
|
||||||
'same_district_flag',
|
|
||||||
'operator_id'
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 一覧検索・ソート処理
|
|
||||||
*/
|
|
||||||
public static function search($inputs)
|
|
||||||
{
|
|
||||||
$list = self::query()
|
|
||||||
->leftJoin('park', 'contract_allowable_city.park_id', '=', 'park.park_id')
|
|
||||||
->leftJoin('city', 'contract_allowable_city.city_id', '=', 'city.city_id')
|
|
||||||
->select(
|
|
||||||
'contract_allowable_city.*',
|
|
||||||
'park.park_name',
|
|
||||||
'city.city_name'
|
|
||||||
);
|
|
||||||
|
|
||||||
if ($inputs['isMethodPost'] ?? false) {
|
|
||||||
if (!empty($inputs['contract_allowable_city_id'])) {
|
|
||||||
$list->where('contract_allowable_city.contract_allowable_city_id', $inputs['contract_allowable_city_id']);
|
|
||||||
}
|
|
||||||
if (!empty($inputs['city_id'])) {
|
|
||||||
$list->where('contract_allowable_city.city_id', $inputs['city_id']);
|
|
||||||
}
|
|
||||||
if (!empty($inputs['contract_allowable_city_name'])) {
|
|
||||||
$list->where('contract_allowable_city.contract_allowable_city_name', 'like', '%' . $inputs['contract_allowable_city_name'] . '%');
|
|
||||||
}
|
|
||||||
if (!empty($inputs['park_id'])) {
|
|
||||||
$list->where('contract_allowable_city.park_id', $inputs['park_id']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 並び順
|
|
||||||
if (!empty($inputs['sort'])) {
|
|
||||||
$list->orderBy($inputs['sort'], $inputs['sort_type'] ?? 'asc');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($inputs['isExport'] ?? false) {
|
|
||||||
return $list->get();
|
|
||||||
} else {
|
|
||||||
return $list->paginate(Utils::item_per_page);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 主キーで取得
|
|
||||||
*/
|
|
||||||
public static function getByPk($pk)
|
|
||||||
{
|
|
||||||
return self::find($pk);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 主キー配列で一括削除
|
|
||||||
*/
|
|
||||||
public static function deleteByPk($arr)
|
|
||||||
{
|
|
||||||
return self::whereIn('contract_allowable_city_id', $arr)->delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 選択リスト取得用(フォーム等)
|
|
||||||
*/
|
|
||||||
public static function getList()
|
|
||||||
{
|
|
||||||
return self::pluck('contract_allowable_city_name', 'contract_allowable_city_id');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -4,46 +4,80 @@ namespace App\Models;
|
|||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* デバイスモデル - deviceテーブル
|
||||||
|
*
|
||||||
|
* ハードウェアデバイス(印刷機等)の情報を管理するモデル
|
||||||
|
* batch_logテーブルとの関連でバッチ処理ログに使用される
|
||||||
|
*/
|
||||||
class Device extends Model
|
class Device extends Model
|
||||||
{
|
{
|
||||||
protected $table = 'device';
|
protected $table = 'device';
|
||||||
protected $primaryKey = 'device_id';
|
protected $primaryKey = 'device_id';
|
||||||
public $incrementing = true;
|
public $timestamps = true;
|
||||||
protected $keyType = 'int';
|
|
||||||
|
|
||||||
|
const CREATED_AT = 'created_at';
|
||||||
|
const UPDATED_AT = 'updated_at';
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'park_id',
|
'park_id', // 駐輪場ID
|
||||||
'device_type',
|
'device_type', // デバイスタイプ
|
||||||
'device_subject',
|
'device_subject', // デバイス件名
|
||||||
'device_identifier',
|
'device_identifier', // デバイス識別子
|
||||||
'device_work',
|
'device_work', // デバイス作業
|
||||||
'device_workstart',
|
'device_workstart', // 作業開始日
|
||||||
'device_replace',
|
'device_replace', // 交換日
|
||||||
'device_remarks',
|
'device_remarks', // 備考
|
||||||
'operator_id',
|
'operator_id' // オペレータID
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'park_id' => 'integer',
|
|
||||||
'device_workstart' => 'date',
|
'device_workstart' => 'date',
|
||||||
'device_replace' => 'date',
|
'device_replace' => 'date',
|
||||||
'operator_id' => 'integer',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 駐輪場との関連付け
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
public function park()
|
public function park()
|
||||||
{
|
{
|
||||||
|
// UsingStatus系は廃止。正式モデル Park を使用。
|
||||||
return $this->belongsTo(Park::class, 'park_id', 'park_id');
|
return $this->belongsTo(Park::class, 'park_id', 'park_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
public static function getList(): array
|
* バッチログとの関連付け(batch_logテーブル)
|
||||||
|
* 統一BatchLogで管理される
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Query\Builder
|
||||||
|
*/
|
||||||
|
public function batchLogs()
|
||||||
{
|
{
|
||||||
return static::orderBy('device_subject')->pluck('device_subject', 'device_id')->toArray();
|
return \DB::table('batch_log')
|
||||||
|
->where('parameters->device_id', $this->device_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function deleteByPk(array $ids): int
|
/**
|
||||||
|
* デバイスIDの存在確認
|
||||||
|
*
|
||||||
|
* @param int $deviceId デバイスID
|
||||||
|
* @return bool 存在するかどうか
|
||||||
|
*/
|
||||||
|
public static function exists(int $deviceId): bool
|
||||||
{
|
{
|
||||||
return static::whereIn('device_id', $ids)->delete();
|
return self::where('device_id', $deviceId)->exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* デバイス情報を取得
|
||||||
|
*
|
||||||
|
* @param int $deviceId デバイスID
|
||||||
|
* @return Device|null デバイス情報
|
||||||
|
*/
|
||||||
|
public static function findByDeviceId(int $deviceId): ?Device
|
||||||
|
{
|
||||||
|
return self::where('device_id', $deviceId)->first();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,298 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
use Carbon\Carbon;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 売上集計結果モデル - earnings_summaryテーブル
|
|
||||||
*
|
|
||||||
* SHJ-9で作成される日次・月次・年次の売上集計データを管理
|
|
||||||
*/
|
|
||||||
class EarningsSummary extends Model
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* テーブル名
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $table = 'earnings_summary';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* プライマリキー
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $primaryKey = 'earnings_summary_id';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 一括代入可能な属性
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
protected $fillable = [
|
|
||||||
'park_id', // 駐輪場ID
|
|
||||||
'summary_type', // 集計区分
|
|
||||||
'summary_start_date', // 集計開始日
|
|
||||||
'summary_end_date', // 集計終了日
|
|
||||||
'earnings_date', // 売上日
|
|
||||||
'psection_id', // 車種区分ID
|
|
||||||
'usertype_subject1', // 規格
|
|
||||||
'enable_months', // 期間(月数)
|
|
||||||
'regular_new_count', // 期間件数
|
|
||||||
'regular_new_amount', // 期間金額
|
|
||||||
'regular_new_reduction_count', // 期間成免件数
|
|
||||||
'regular_new_reduction_amount', // 期間成免金額
|
|
||||||
'regular_update_count', // 更新件数
|
|
||||||
'regular_update_amount', // 更新金額
|
|
||||||
'regular_update_reduction_count', // 更新成免件数
|
|
||||||
'regular_update_reduction_amount', // 更新成免金額
|
|
||||||
'turnsum_count', // 残金件数
|
|
||||||
'turnsum', // 残金
|
|
||||||
'refunds', // 解時返戻金
|
|
||||||
'other_income', // 分別収入
|
|
||||||
'other_spending', // 分別支出
|
|
||||||
'reissue_count', // 発行件数
|
|
||||||
'reissue_amount', // 発行金額
|
|
||||||
'summary_note', // 計備考
|
|
||||||
'created_at', // 登録日時
|
|
||||||
'updated_at', // 更新日時
|
|
||||||
'operator_id' // 新法・ページID
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* キャストする属性
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
protected $casts = [
|
|
||||||
'earnings_summary_id' => 'integer',
|
|
||||||
'park_id' => 'integer',
|
|
||||||
'psection_id' => 'integer',
|
|
||||||
'enable_months' => 'integer',
|
|
||||||
'regular_new_count' => 'integer',
|
|
||||||
'regular_new_amount' => 'decimal:2',
|
|
||||||
'regular_new_reduction_count' => 'integer',
|
|
||||||
'regular_new_reduction_amount' => 'decimal:2',
|
|
||||||
'regular_update_count' => 'integer',
|
|
||||||
'regular_update_amount' => 'decimal:2',
|
|
||||||
'regular_update_reduction_count' => 'integer',
|
|
||||||
'regular_update_reduction_amount' => 'decimal:2',
|
|
||||||
'turnsum_count' => 'integer',
|
|
||||||
'turnsum' => 'decimal:2',
|
|
||||||
'refunds' => 'decimal:2',
|
|
||||||
'other_income' => 'decimal:2',
|
|
||||||
'other_spending' => 'decimal:2',
|
|
||||||
'reissue_count' => 'integer',
|
|
||||||
'reissue_amount' => 'decimal:2',
|
|
||||||
'operator_id' => 'integer',
|
|
||||||
'summary_start_date' => 'date',
|
|
||||||
'summary_end_date' => 'date',
|
|
||||||
'earnings_date' => 'date',
|
|
||||||
'created_at' => 'datetime',
|
|
||||||
'updated_at' => 'datetime'
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 日付属性
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
protected $dates = [
|
|
||||||
'summary_start_date',
|
|
||||||
'summary_end_date',
|
|
||||||
'earnings_date',
|
|
||||||
'created_at',
|
|
||||||
'updated_at'
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 集計タイプの定数
|
|
||||||
*/
|
|
||||||
const TYPE_DAILY = '日次';
|
|
||||||
const TYPE_MONTHLY = '月次';
|
|
||||||
const TYPE_YEARLY = '年次';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 駐輪場との関連
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
|
||||||
*/
|
|
||||||
public function park()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(Park::class, 'park_id', 'park_id');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 車種区分との関連
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
|
||||||
*/
|
|
||||||
public function psection()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(Psection::class, 'psection_id', 'psection_id');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 指定期間の売上集計データを取得
|
|
||||||
*
|
|
||||||
* @param int $parkId 駐輪場ID
|
|
||||||
* @param string $startDate 開始日
|
|
||||||
* @param string $endDate 終了日
|
|
||||||
* @param string|null $summaryType 集計タイプ
|
|
||||||
* @return \Illuminate\Database\Eloquent\Collection
|
|
||||||
*/
|
|
||||||
public static function getEarningsByPeriod(int $parkId, string $startDate, string $endDate, ?string $summaryType = null)
|
|
||||||
{
|
|
||||||
$query = self::where('park_id', $parkId)
|
|
||||||
->whereBetween('earnings_date', [$startDate, $endDate]);
|
|
||||||
|
|
||||||
if ($summaryType) {
|
|
||||||
$query->where('summary_type', $summaryType);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $query->with(['park', 'psection'])
|
|
||||||
->orderBy('earnings_date')
|
|
||||||
->orderBy('psection_id')
|
|
||||||
->get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 駐輪場別の売上合計を取得
|
|
||||||
*
|
|
||||||
* @param int $parkId 駐輪場ID
|
|
||||||
* @param string $startDate 開始日
|
|
||||||
* @param string $endDate 終了日
|
|
||||||
* @return array 売上合計データ
|
|
||||||
*/
|
|
||||||
public static function getEarningsTotalByPark(int $parkId, string $startDate, string $endDate): array
|
|
||||||
{
|
|
||||||
$result = self::where('park_id', $parkId)
|
|
||||||
->whereBetween('earnings_date', [$startDate, $endDate])
|
|
||||||
->selectRaw('
|
|
||||||
SUM(regular_new_count) as total_new_count,
|
|
||||||
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(refunds) as total_refunds,
|
|
||||||
SUM(reissue_count) as total_reissue_count,
|
|
||||||
SUM(reissue_amount) as total_reissue_amount
|
|
||||||
')
|
|
||||||
->first();
|
|
||||||
|
|
||||||
return $result ? $result->toArray() : [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 最新の集計日を取得
|
|
||||||
*
|
|
||||||
* @param int|null $parkId 駐輪場ID(省略時は全体)
|
|
||||||
* @param string|null $summaryType 集計タイプ
|
|
||||||
* @return string|null 最新集計日
|
|
||||||
*/
|
|
||||||
public static function getLatestEarningsDate(?int $parkId = null, ?string $summaryType = null): ?string
|
|
||||||
{
|
|
||||||
$query = self::query();
|
|
||||||
|
|
||||||
if ($parkId) {
|
|
||||||
$query->where('park_id', $parkId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($summaryType) {
|
|
||||||
$query->where('summary_type', $summaryType);
|
|
||||||
}
|
|
||||||
|
|
||||||
$latest = $query->max('earnings_date');
|
|
||||||
|
|
||||||
return $latest ? Carbon::parse($latest)->format('Y-m-d') : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 期間の売上データを削除
|
|
||||||
*
|
|
||||||
* @param int $parkId 駐輪場ID
|
|
||||||
* @param string $startDate 開始日
|
|
||||||
* @param string $endDate 終了日
|
|
||||||
* @param string|null $summaryType 集計タイプ
|
|
||||||
* @return int 削除件数
|
|
||||||
*/
|
|
||||||
public static function deleteEarningsByPeriod(int $parkId, string $startDate, string $endDate, ?string $summaryType = null): int
|
|
||||||
{
|
|
||||||
$query = self::where('park_id', $parkId)
|
|
||||||
->where('summary_start_date', $startDate)
|
|
||||||
->where('summary_end_date', $endDate);
|
|
||||||
|
|
||||||
if ($summaryType) {
|
|
||||||
$query->where('summary_type', $summaryType);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $query->delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 売上集計データの作成
|
|
||||||
*
|
|
||||||
* @param array $data 売上データ
|
|
||||||
* @return EarningsSummary 作成されたモデル
|
|
||||||
*/
|
|
||||||
public static function createEarningsSummary(array $data): EarningsSummary
|
|
||||||
{
|
|
||||||
$defaultData = [
|
|
||||||
'regular_new_count' => 0,
|
|
||||||
'regular_new_amount' => 0.00,
|
|
||||||
'regular_new_reduction_count' => 0,
|
|
||||||
'regular_new_reduction_amount' => 0.00,
|
|
||||||
'regular_update_count' => 0,
|
|
||||||
'regular_update_amount' => 0.00,
|
|
||||||
'regular_update_reduction_count' => 0,
|
|
||||||
'regular_update_reduction_amount' => 0.00,
|
|
||||||
'turnsum_count' => 0,
|
|
||||||
'turnsum' => 0.00,
|
|
||||||
'refunds' => 0.00,
|
|
||||||
'other_income' => 0.00,
|
|
||||||
'other_spending' => 0.00,
|
|
||||||
'reissue_count' => 0,
|
|
||||||
'reissue_amount' => 0.00,
|
|
||||||
'operator_id' => 0
|
|
||||||
];
|
|
||||||
|
|
||||||
$mergedData = array_merge($defaultData, $data);
|
|
||||||
|
|
||||||
return self::create($mergedData);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 売上合計の計算
|
|
||||||
*
|
|
||||||
* @return float 売上合計
|
|
||||||
*/
|
|
||||||
public function getTotalEarningsAttribute(): float
|
|
||||||
{
|
|
||||||
return $this->regular_new_amount +
|
|
||||||
$this->regular_update_amount +
|
|
||||||
$this->turnsum +
|
|
||||||
$this->reissue_amount +
|
|
||||||
$this->other_income -
|
|
||||||
$this->other_spending -
|
|
||||||
$this->refunds;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文字列表現
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function __toString(): string
|
|
||||||
{
|
|
||||||
return sprintf(
|
|
||||||
'EarningsSummary[ID:%d, Park:%d, Type:%s, Date:%s]',
|
|
||||||
$this->earnings_summary_id,
|
|
||||||
$this->park_id,
|
|
||||||
$this->summary_type,
|
|
||||||
$this->earnings_date ? $this->earnings_date->format('Y-m-d') : 'N/A'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,229 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
use Carbon\Carbon;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ハードウェアチェックログモデル - hardware_check_logテーブル
|
|
||||||
*
|
|
||||||
* デバイスのハードウェア状態監視ログを管理
|
|
||||||
*/
|
|
||||||
class HardwareCheckLog extends Model
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* テーブル名
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $table = 'hardware_check_log';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* プライマリキー
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $primaryKey = 'log_id';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 一括代入可能な属性
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
protected $fillable = [
|
|
||||||
'device_id', // デバイスID
|
|
||||||
'status', // ステータス
|
|
||||||
'status_comment', // ステータスコメント
|
|
||||||
'created_at', // 作成日時
|
|
||||||
'updated_at', // 更新日時
|
|
||||||
'operator_id' // オペレータID
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* キャストする属性
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
protected $casts = [
|
|
||||||
'log_id' => 'integer',
|
|
||||||
'device_id' => 'integer',
|
|
||||||
'status' => 'integer',
|
|
||||||
'operator_id' => 'integer',
|
|
||||||
'created_at' => 'datetime',
|
|
||||||
'updated_at' => 'datetime'
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ステータスの定数
|
|
||||||
*/
|
|
||||||
const STATUS_NORMAL = 1; // 正常
|
|
||||||
const STATUS_WARNING = 2; // 警告
|
|
||||||
const STATUS_ERROR = 3; // エラー
|
|
||||||
const STATUS_UNKNOWN = 0; // 不明
|
|
||||||
|
|
||||||
/**
|
|
||||||
* デバイスとの関連
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
|
||||||
*/
|
|
||||||
public function device()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(Device::class, 'device_id', 'device_id');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 指定デバイスの最新ハードウェア状態を取得
|
|
||||||
*
|
|
||||||
* @param int $deviceId デバイスID
|
|
||||||
* @return HardwareCheckLog|null 最新ログ
|
|
||||||
*/
|
|
||||||
public static function getLatestStatusByDevice(int $deviceId): ?HardwareCheckLog
|
|
||||||
{
|
|
||||||
return self::where('device_id', $deviceId)
|
|
||||||
->orderBy('created_at', 'desc')
|
|
||||||
->first();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 全デバイスの最新ハードウェア状態を取得
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Database\Eloquent\Collection
|
|
||||||
*/
|
|
||||||
public static function getLatestStatusForAllDevices()
|
|
||||||
{
|
|
||||||
return self::select('device_id')
|
|
||||||
->selectRaw('MAX(created_at) as latest_created_at')
|
|
||||||
->groupBy('device_id')
|
|
||||||
->with(['device'])
|
|
||||||
->get()
|
|
||||||
->map(function ($log) {
|
|
||||||
return self::where('device_id', $log->device_id)
|
|
||||||
->where('created_at', $log->latest_created_at)
|
|
||||||
->with(['device'])
|
|
||||||
->first();
|
|
||||||
})
|
|
||||||
->filter();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 異常状態のデバイスを取得
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Database\Eloquent\Collection
|
|
||||||
*/
|
|
||||||
public static function getAbnormalDevices()
|
|
||||||
{
|
|
||||||
$latestLogs = self::getLatestStatusForAllDevices();
|
|
||||||
|
|
||||||
return $latestLogs->filter(function ($log) {
|
|
||||||
return $log->status !== self::STATUS_NORMAL;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 指定期間内のログを取得
|
|
||||||
*
|
|
||||||
* @param int $deviceId デバイスID
|
|
||||||
* @param string $startTime 開始時刻
|
|
||||||
* @param string $endTime 終了時刻
|
|
||||||
* @return \Illuminate\Database\Eloquent\Collection
|
|
||||||
*/
|
|
||||||
public static function getLogsByPeriod(int $deviceId, string $startTime, string $endTime)
|
|
||||||
{
|
|
||||||
return self::where('device_id', $deviceId)
|
|
||||||
->whereBetween('created_at', [$startTime, $endTime])
|
|
||||||
->orderBy('created_at', 'desc')
|
|
||||||
->get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ハードウェア状態ログを作成
|
|
||||||
*
|
|
||||||
* @param int $deviceId デバイスID
|
|
||||||
* @param int $status ステータス
|
|
||||||
* @param string $statusComment ステータスコメント
|
|
||||||
* @param int|null $operatorId オペレータID
|
|
||||||
* @return HardwareCheckLog 作成されたログ
|
|
||||||
*/
|
|
||||||
public static function createLog(
|
|
||||||
int $deviceId,
|
|
||||||
int $status,
|
|
||||||
string $statusComment = '',
|
|
||||||
?int $operatorId = null
|
|
||||||
): HardwareCheckLog {
|
|
||||||
return self::create([
|
|
||||||
'device_id' => $deviceId,
|
|
||||||
'status' => $status,
|
|
||||||
'status_comment' => $statusComment,
|
|
||||||
'operator_id' => $operatorId ?? 0
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ステータス名を取得
|
|
||||||
*
|
|
||||||
* @param int $status ステータス
|
|
||||||
* @return string ステータス名
|
|
||||||
*/
|
|
||||||
public static function getStatusName(int $status): string
|
|
||||||
{
|
|
||||||
switch ($status) {
|
|
||||||
case self::STATUS_NORMAL:
|
|
||||||
return '正常';
|
|
||||||
case self::STATUS_WARNING:
|
|
||||||
return '警告';
|
|
||||||
case self::STATUS_ERROR:
|
|
||||||
return 'エラー';
|
|
||||||
case self::STATUS_UNKNOWN:
|
|
||||||
return '不明';
|
|
||||||
default:
|
|
||||||
return "ステータス{$status}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 現在のステータス名を取得
|
|
||||||
*
|
|
||||||
* @return string ステータス名
|
|
||||||
*/
|
|
||||||
public function getStatusNameAttribute(): string
|
|
||||||
{
|
|
||||||
return self::getStatusName($this->status);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 正常状態かどうかを判定
|
|
||||||
*
|
|
||||||
* @return bool 正常状態かどうか
|
|
||||||
*/
|
|
||||||
public function isNormal(): bool
|
|
||||||
{
|
|
||||||
return $this->status === self::STATUS_NORMAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 異常状態かどうかを判定
|
|
||||||
*
|
|
||||||
* @return bool 異常状態かどうか
|
|
||||||
*/
|
|
||||||
public function isAbnormal(): bool
|
|
||||||
{
|
|
||||||
return $this->status !== self::STATUS_NORMAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文字列表現
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function __toString(): string
|
|
||||||
{
|
|
||||||
return sprintf(
|
|
||||||
'HardwareCheckLog[ID:%d, Device:%d, Status:%s, Time:%s]',
|
|
||||||
$this->log_id,
|
|
||||||
$this->device_id,
|
|
||||||
$this->getStatusNameAttribute(),
|
|
||||||
$this->created_at ? $this->created_at->format('Y-m-d H:i:s') : 'N/A'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
class InvSetting extends Model
|
|
||||||
{
|
|
||||||
protected $table = 'inv_setting';
|
|
||||||
protected $primaryKey = 'seq';
|
|
||||||
public $timestamps = true;
|
|
||||||
|
|
||||||
protected $fillable = [
|
|
||||||
|
|
||||||
't_number', // 適格事業者番号
|
|
||||||
't_name', // 事業者名
|
|
||||||
'zipcode', // 郵便番号
|
|
||||||
'adrs', // 住所
|
|
||||||
'bldg', // 建物名
|
|
||||||
'tel_num', // 電話番号
|
|
||||||
'fax_num', // FAX番号
|
|
||||||
'company_image_path', // 会社ロゴ画像パス(任意)
|
|
||||||
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@ -1,40 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
class JurisdictionParking extends Model
|
|
||||||
{
|
|
||||||
// テーブル名を複数形に統一
|
|
||||||
protected $table = 'jurisdiction_parking';
|
|
||||||
|
|
||||||
// 主キー
|
|
||||||
protected $primaryKey = 'jurisdiction_parking_id';
|
|
||||||
|
|
||||||
// 可変項目
|
|
||||||
protected $fillable = [
|
|
||||||
'jurisdiction_parking_name',
|
|
||||||
'ope_id',
|
|
||||||
'park_id',
|
|
||||||
'operator_id',
|
|
||||||
];
|
|
||||||
|
|
||||||
public $timestamps = true;
|
|
||||||
|
|
||||||
// リレーション
|
|
||||||
public function operator()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(User::class, 'operator_id');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function park()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(Park::class, 'park_id');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function ope()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(Ope::class, 'ope_id');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,60 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
class Manager extends Model
|
|
||||||
{
|
|
||||||
protected $table = 'manager';
|
|
||||||
protected $primaryKey = 'manager_id';
|
|
||||||
public $incrementing = true;
|
|
||||||
protected $keyType = 'int';
|
|
||||||
|
|
||||||
// timestamps は created_at / updated_at があるのでデフォルト true のまま
|
|
||||||
|
|
||||||
protected $fillable = [
|
|
||||||
'manager_name',
|
|
||||||
'manager_type',
|
|
||||||
'manager_parkid',
|
|
||||||
'manager_device1',
|
|
||||||
'manager_device2',
|
|
||||||
'manager_mail',
|
|
||||||
'manager_tel',
|
|
||||||
'manager_alert1',
|
|
||||||
'manager_alert2',
|
|
||||||
'manager_quit_flag',
|
|
||||||
'manager_quitday',
|
|
||||||
'operator_id',
|
|
||||||
];
|
|
||||||
|
|
||||||
protected $casts = [
|
|
||||||
'manager_parkid' => 'integer',
|
|
||||||
'manager_device1' => 'integer',
|
|
||||||
'manager_device2' => 'integer',
|
|
||||||
'manager_alert1' => 'boolean',
|
|
||||||
'manager_alert2' => 'boolean',
|
|
||||||
'manager_quit_flag' => 'boolean',
|
|
||||||
'manager_quitday' => 'date',
|
|
||||||
'operator_id' => 'integer',
|
|
||||||
];
|
|
||||||
|
|
||||||
// --- リレーション(テーブル名は既存に合わせて調整してください)
|
|
||||||
public function park() { return $this->belongsTo(Park::class, 'manager_parkid', 'park_id'); }
|
|
||||||
public function device1() { return $this->belongsTo(Device::class, 'manager_device1', 'device_id'); }
|
|
||||||
public function device2() { return $this->belongsTo(Device::class, 'manager_device2', 'device_id'); }
|
|
||||||
|
|
||||||
// Blade 互換のヘルパ(list.blade.php で getXxx() を呼んでいるため)
|
|
||||||
public function getPark() { return $this->park; }
|
|
||||||
public function getDevice1() { return $this->device1; }
|
|
||||||
public function getDevice2() { return $this->device2; }
|
|
||||||
|
|
||||||
public function getManagerQuitFlagDisplay()
|
|
||||||
{
|
|
||||||
return $this->manager_quit_flag ? '退職' : '在職';
|
|
||||||
}
|
|
||||||
public function getManagerQuitFlagDisplayAttribute()
|
|
||||||
{
|
|
||||||
return $this->getManagerQuitFlagDisplay();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -33,31 +33,29 @@ class Ope extends Authenticatable
|
|||||||
*/
|
*/
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'//TODO オペレータID not found in database specs',
|
'//TODO オペレータID not found in database specs',
|
||||||
'login_id', // ログインID
|
|
||||||
'password', // パスワード
|
|
||||||
'ope_name', // オペレータ名
|
'ope_name', // オペレータ名
|
||||||
'ope_type', // オペレータ種別
|
'ope_type', // オペレータ種別
|
||||||
'ope_mail', // メールアドレス(複数可)
|
'ope_mail', // メールアドレス
|
||||||
'ope_phone', // 電話番号
|
'ope_phone', // 電話番号
|
||||||
'ope_sendalart_que1',
|
'ope_sendalart_que1', // キュー1アラート送信
|
||||||
'ope_sendalart_que2',
|
'ope_sendalart_que2', // キュー2アラート送信
|
||||||
'ope_sendalart_que3',
|
'ope_sendalart_que3', // キュー3アラート送信
|
||||||
'ope_sendalart_que4',
|
'ope_sendalart_que4', // キュー4アラート送信
|
||||||
'ope_sendalart_que5',
|
'ope_sendalart_que5', // キュー5アラート送信
|
||||||
'ope_sendalart_que6',
|
'ope_sendalart_que6', // キュー6アラート送信
|
||||||
'ope_sendalart_que7',
|
'ope_sendalart_que7', // キュー7アラート送信
|
||||||
'ope_sendalart_que8',
|
'ope_sendalart_que8', // キュー8アラート送信
|
||||||
'ope_sendalart_que9',
|
'ope_sendalart_que9', // キュー9アラート送信
|
||||||
'ope_sendalart_que10',
|
'ope_sendalart_que10', // キュー10アラート送信
|
||||||
'ope_sendalart_que11',
|
'ope_sendalart_que11', // キュー11アラート送信
|
||||||
'ope_sendalart_que12',
|
'ope_sendalart_que12', // キュー12アラート送信
|
||||||
'ope_sendalart_que13',
|
'ope_sendalart_que13', // キュー13アラート送信
|
||||||
'ope_auth1',
|
'ope_auth1', // 権限1
|
||||||
'ope_auth2',
|
'ope_auth2', // 権限2
|
||||||
'ope_auth3',
|
'ope_auth3', // 権限3
|
||||||
'ope_auth4',
|
'ope_auth4', // 権限4
|
||||||
'ope_quit_flag',
|
'ope_quit_flag', // 退職フラグ
|
||||||
'ope_quitday',
|
'ope_quitday' // 退職日
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -126,7 +124,7 @@ class Ope extends Authenticatable
|
|||||||
|
|
||||||
// POST検索条件の処理
|
// POST検索条件の処理
|
||||||
if ($inputs['isMethodPost']) {
|
if ($inputs['isMethodPost']) {
|
||||||
|
// 検索条件があればここに追加
|
||||||
}
|
}
|
||||||
|
|
||||||
// ソート処理
|
// ソート処理
|
||||||
@ -138,14 +136,12 @@ class Ope extends Authenticatable
|
|||||||
if ($inputs['isExport']) {
|
if ($inputs['isExport']) {
|
||||||
$list = $list->get();
|
$list = $list->get();
|
||||||
} else {
|
} else {
|
||||||
// ページネーション件数を20に固定
|
$list = $list->paginate(Utils::item_per_page);
|
||||||
$list = $list->paginate(20);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $list;
|
return $list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* プライマリキーでオペレータを取得
|
* プライマリキーでオペレータを取得
|
||||||
*
|
*
|
||||||
|
|||||||
@ -1,25 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
class OperatorLog extends Model
|
|
||||||
{
|
|
||||||
protected $table = 'operator_log';
|
|
||||||
protected $primaryKey = 'operator_log_id';
|
|
||||||
public $timestamps = false;
|
|
||||||
protected $fillable = [
|
|
||||||
'operator_id',
|
|
||||||
'remote_ip',
|
|
||||||
'browser_user_agent',
|
|
||||||
'user_id',
|
|
||||||
'contract_id',
|
|
||||||
'operation_code',
|
|
||||||
'operation_comment',
|
|
||||||
'operation_form_name',
|
|
||||||
'operation_table_name',
|
|
||||||
'created_at',
|
|
||||||
'updated_at',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@ -1,87 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
class OperatorQue extends Model
|
|
||||||
{
|
|
||||||
protected $table = 'operator_que';
|
|
||||||
protected $primaryKey = 'que_id';
|
|
||||||
public $timestamps = true;
|
|
||||||
|
|
||||||
protected $fillable = [
|
|
||||||
'que_class',
|
|
||||||
'user_id',
|
|
||||||
'contract_id',
|
|
||||||
'park_id',
|
|
||||||
'que_comment',
|
|
||||||
'que_status',
|
|
||||||
'que_status_comment',
|
|
||||||
'work_instructions',
|
|
||||||
'operator_id',
|
|
||||||
];
|
|
||||||
|
|
||||||
// 定数
|
|
||||||
/** キュー種別 */
|
|
||||||
public const QueClass = [
|
|
||||||
1 => '本人確認(社会人)',
|
|
||||||
2 => '本人確認(学生)',
|
|
||||||
3 => 'タグ発送',
|
|
||||||
4 => '予約告知通知',
|
|
||||||
5 => '定期更新通知',
|
|
||||||
6 => '返金処理',
|
|
||||||
7 => '再発行リミット超過',
|
|
||||||
8 => '支払い催促',
|
|
||||||
9 => 'シール発行催促',
|
|
||||||
10 => 'シール再発行',
|
|
||||||
11 => '名寄せフリガナ照合エラー',
|
|
||||||
12 => '本人確認(減免更新)',
|
|
||||||
13 => '本人確認(学生更新)',
|
|
||||||
101 => 'サーバーエラー',
|
|
||||||
102 => 'プリンタエラー',
|
|
||||||
103 => 'スキャナーエラー',
|
|
||||||
104 => 'プリンタ用紙残少警告',
|
|
||||||
];
|
|
||||||
|
|
||||||
/** キューステータス */
|
|
||||||
public const QueStatus = [
|
|
||||||
1 => 'キュー発生',
|
|
||||||
2 => 'キュー作業中',
|
|
||||||
3 => 'キュー作業済',
|
|
||||||
4 => '返金済',
|
|
||||||
];
|
|
||||||
|
|
||||||
public function getQueClassLabel(): string
|
|
||||||
{
|
|
||||||
return self::QueClass[$this->que_class] ?? 'キュー種別未設定';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getQueStatusLabel(): string
|
|
||||||
{
|
|
||||||
return self::QueStatus[$this->que_status] ?? (string)$this->que_status;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function user()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(User::class, 'user_id');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function park()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(Park::class, 'park_id');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function contract()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(Contract::class, 'contract_id');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function operator()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(User::class, 'operator_id');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getUser() { return $this->user; }
|
|
||||||
public function getPark() { return $this->park; }
|
|
||||||
}
|
|
||||||
@ -64,15 +64,15 @@ class Park extends Model
|
|||||||
'reduction_guide_display_flag', // 減免案内表示フラグ
|
'reduction_guide_display_flag', // 減免案内表示フラグ
|
||||||
'reduction_target_age', // 減免対象年齢
|
'reduction_target_age', // 減免対象年齢
|
||||||
'reduction_guide_display_start_month', // 減免案内表示開始月数
|
'reduction_guide_display_start_month', // 減免案内表示開始月数
|
||||||
'cross_year', // 年跨ぎ
|
'cross_year' // 年跨ぎ
|
||||||
'reverse_use_general', // 逆利用一般
|
// 如有 created_at/updated_at 可省略不填
|
||||||
'reverse_use_student' // 逆利用学生
|
|
||||||
];
|
];
|
||||||
|
|
||||||
public static function search($inputs)
|
public static function search($inputs)
|
||||||
{
|
{
|
||||||
$list = self::query();
|
$list = self::query();
|
||||||
if ($inputs['isMethodPost']) {
|
if ($inputs['isMethodPost']) {
|
||||||
|
// 搜索条件可追加
|
||||||
}
|
}
|
||||||
// Sort
|
// Sort
|
||||||
if ($inputs['sort']) {
|
if ($inputs['sort']) {
|
||||||
|
|||||||
@ -1,40 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
class Payment extends Model
|
|
||||||
{
|
|
||||||
|
|
||||||
protected $table = 'payment';
|
|
||||||
|
|
||||||
|
|
||||||
protected $primaryKey = 'payment_id';
|
|
||||||
public $incrementing = true;
|
|
||||||
protected $keyType = 'int';
|
|
||||||
|
|
||||||
public $timestamps = true;
|
|
||||||
|
|
||||||
|
|
||||||
protected $fillable = [
|
|
||||||
'payment_companyname',
|
|
||||||
'payment_add',
|
|
||||||
'payment_detail',
|
|
||||||
'payment_space1',
|
|
||||||
'payment_space2',
|
|
||||||
'payment_title',
|
|
||||||
'payment_guide',
|
|
||||||
'payment_inquiryname',
|
|
||||||
'payment_inquirytel',
|
|
||||||
'payment_time',
|
|
||||||
'operator_id',
|
|
||||||
];
|
|
||||||
|
|
||||||
protected $casts = [
|
|
||||||
'payment_id' => 'integer',
|
|
||||||
'operator_id' => 'integer',
|
|
||||||
'created_at' => 'datetime',
|
|
||||||
'updated_at' => 'datetime',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@ -1,84 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
use App\Utils;
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
class Pplace extends Model
|
|
||||||
{
|
|
||||||
const CREATED_AT = 'created_at';
|
|
||||||
const UPDATED_AT = 'updated_at';
|
|
||||||
const PERPAGE = 50;
|
|
||||||
|
|
||||||
protected $table = 'pplace';
|
|
||||||
protected $primaryKey = 'pplace_id';
|
|
||||||
|
|
||||||
protected $fillable = [
|
|
||||||
'pplace_number',
|
|
||||||
'pplace_remarks',
|
|
||||||
'operator_id'
|
|
||||||
];
|
|
||||||
/*
|
|
||||||
public static function boot()
|
|
||||||
{
|
|
||||||
parent::boot();
|
|
||||||
self::creating(function (Pplace $model) {
|
|
||||||
if (Auth::check()) {
|
|
||||||
$model->operator_id = Auth::user()->ope_id;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
*
|
|
||||||
/**
|
|
||||||
* 一覧検索・ソート処理
|
|
||||||
*/
|
|
||||||
public static function search($inputs)
|
|
||||||
{
|
|
||||||
$list = self::query();
|
|
||||||
|
|
||||||
if ($inputs['isMethodPost'] ?? false) {
|
|
||||||
// ここで条件検索処理を追加可能(例: $list->where(...);)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 並び順
|
|
||||||
if (!empty($inputs['sort'])) {
|
|
||||||
$list->orderBy($inputs['sort'], $inputs['sort_type'] ?? 'asc');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($inputs['isExport'] ?? false) {
|
|
||||||
return $list->get();
|
|
||||||
} else {
|
|
||||||
return $list->paginate(Utils::item_per_page);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 主キーで取得
|
|
||||||
*/
|
|
||||||
public static function getByPk($pk)
|
|
||||||
{
|
|
||||||
return self::find($pk);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 主キー配列で一括削除
|
|
||||||
*/
|
|
||||||
public static function deleteByPk($ids)
|
|
||||||
{
|
|
||||||
if (!is_array($ids)) {
|
|
||||||
$ids = [$ids];
|
|
||||||
}
|
|
||||||
return self::whereIn('pplace_id', $ids)->delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 選択リスト取得用(フォーム等)
|
|
||||||
*/
|
|
||||||
public static function getList()
|
|
||||||
{
|
|
||||||
return self::pluck('pplace_number', 'pplace_id');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -17,11 +17,10 @@ class Price extends Model
|
|||||||
5 => '12ヶ月',
|
5 => '12ヶ月',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $table = 'price';
|
protected $table = 'price_a';
|
||||||
protected $primaryKey = 'price_parkplaceid';
|
protected $primaryKey = 'price_parkplaceid';
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'price_parkplaceid',
|
|
||||||
'prine_name',
|
'prine_name',
|
||||||
'price_month',
|
'price_month',
|
||||||
'park_id',
|
'park_id',
|
||||||
@ -42,46 +41,34 @@ class Price extends Model
|
|||||||
|
|
||||||
public static function search($inputs)
|
public static function search($inputs)
|
||||||
{
|
{
|
||||||
$query = self::query()
|
$list = self::query();
|
||||||
->select(
|
// 只有在sort是有效字段时才排序
|
||||||
'price.*',
|
|
||||||
\DB::raw("CONCAT_WS('/', usertype.usertype_subject1, usertype.usertype_subject2, usertype.usertype_subject3) as user_category_name"),
|
|
||||||
'psection.psection_subject',
|
|
||||||
'ptype.ptype_subject'
|
|
||||||
)
|
|
||||||
->leftJoin('usertype', 'price.user_categoryid', '=', 'usertype.user_categoryid')
|
|
||||||
->leftJoin('psection', 'price.psection_id', '=', 'psection.psection_id')
|
|
||||||
->leftJoin('ptype', 'price.price_ptypeid', '=', 'ptype.ptype_id');
|
|
||||||
|
|
||||||
// ソート対象カラム
|
|
||||||
$allowedSortColumns = [
|
$allowedSortColumns = [
|
||||||
'price_parkplaceid', // 駐車場所ID
|
'price_parkplaceid',
|
||||||
'park_id', // 駐輪場ID
|
'prine_name',
|
||||||
'prine_name', // 商品名
|
'price_month',
|
||||||
'price_month', // 期間
|
'park_id',
|
||||||
'user_categoryid', // 利用者分類ID
|
'psection_id',
|
||||||
'price', // 駐輪料金(税込)
|
'price_ptypeid',
|
||||||
'psection_id', // 車種区分ID
|
'user_categoryid',
|
||||||
'price_ptypeid', // 駐輪分類ID
|
'pplace_id',
|
||||||
'pplace_id', // 駐車車室ID
|
'price'
|
||||||
];
|
];
|
||||||
|
$sort_column = $inputs['sort'] ?? '';
|
||||||
$sortColumn = $inputs['sort'] ?? '';
|
$sort_type = strtolower($inputs['sort_type'] ?? 'asc');
|
||||||
$sortType = strtolower($inputs['sort_type'] ?? 'asc');
|
if (in_array($sort_column, $allowedSortColumns)) {
|
||||||
|
if (!in_array($sort_type, ['asc', 'desc'])) {
|
||||||
if (in_array($sortColumn, $allowedSortColumns, true)) {
|
$sort_type = 'asc';
|
||||||
if (!in_array($sortType, ['asc', 'desc'], true)) {
|
|
||||||
$sortType = 'asc';
|
|
||||||
}
|
}
|
||||||
$query->orderBy($sortColumn, $sortType);
|
$list->orderBy($sort_column, $sort_type);
|
||||||
}
|
}
|
||||||
|
if ($inputs['isExport']) {
|
||||||
return $inputs['isExport']
|
$list = $list->get();
|
||||||
? $query->get()
|
} else {
|
||||||
: $query->paginate(\App\Utils::item_per_page ?? 20);
|
$list = $list->paginate(Utils::item_per_page);
|
||||||
|
}
|
||||||
|
return $list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static function getByPk($pk)
|
public static function getByPk($pk)
|
||||||
@ -115,26 +102,4 @@ class Price extends Model
|
|||||||
return $this->belongsTo(Usertype::class, 'user_categoryid', 'user_categoryid')->first();
|
return $this->belongsTo(Usertype::class, 'user_categoryid', 'user_categoryid')->first();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function psection()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(Psection::class, 'psection_id'); // 外部キーが psection_id
|
|
||||||
|
|
||||||
}
|
|
||||||
public function ptype()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(Ptype::class, 'price_ptypeid'); // 外部キーが price_ptypeid
|
|
||||||
|
|
||||||
}
|
|
||||||
public function pplace()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(Pplace::class, 'pplace_id'); // 外部キーが pplace_id
|
|
||||||
|
|
||||||
}
|
|
||||||
// public function getStation()
|
|
||||||
// {
|
|
||||||
// return $this->belongsTo(Station::class, 'price_parkplaceid', 'park_id');
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -58,5 +58,3 @@ class PriceA extends Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,30 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
class PrintArea extends Model
|
|
||||||
{
|
|
||||||
// テーブル名を指定(必要に応じて)
|
|
||||||
protected $table = 'print_area';
|
|
||||||
|
|
||||||
// 主キー
|
|
||||||
protected $primaryKey = 'print_area_id';
|
|
||||||
|
|
||||||
// タイムスタンプ自動更新
|
|
||||||
public $timestamps = true;
|
|
||||||
|
|
||||||
// 複数代入可能なフィールド
|
|
||||||
protected $fillable = [
|
|
||||||
'print_area_name',
|
|
||||||
'park_id',
|
|
||||||
'operator_id',
|
|
||||||
];
|
|
||||||
|
|
||||||
// 駐輪場マスタとのリレーション
|
|
||||||
public function park()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(Park::class, 'park_id');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,251 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
use Carbon\Carbon;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* プリンタジョブログモデル - print_job_logテーブル
|
|
||||||
*
|
|
||||||
* プリンタ制御プログラムの実行ログを管理
|
|
||||||
*/
|
|
||||||
class PrintJobLog extends Model
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* テーブル名
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $table = 'print_job_log';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* プライマリキー
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $primaryKey = 'log_id';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 一括代入可能な属性
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
protected $fillable = [
|
|
||||||
'park_id', // 駐輪場ID
|
|
||||||
'user_id', // ユーザーID
|
|
||||||
'contract_id', // 契約ID
|
|
||||||
'process_name', // プロセス名
|
|
||||||
'job_name', // ジョブ名
|
|
||||||
'status', // ステータス
|
|
||||||
'error_code', // エラーコード
|
|
||||||
'status_comment', // ステータスコメント
|
|
||||||
'created_at' // 作成日時
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* キャストする属性
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
protected $casts = [
|
|
||||||
'log_id' => 'integer',
|
|
||||||
'park_id' => 'integer',
|
|
||||||
'user_id' => 'integer',
|
|
||||||
'contract_id' => 'integer',
|
|
||||||
'error_code' => 'integer',
|
|
||||||
'created_at' => 'datetime'
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* エラーコードの定数
|
|
||||||
*/
|
|
||||||
const ERROR_CODE_THRESHOLD = 100; // エラー判定閾値(>=100がエラー)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* updateされない設定(created_atのみ)
|
|
||||||
*
|
|
||||||
* @var bool
|
|
||||||
*/
|
|
||||||
public $timestamps = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 駐輪場との関連
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
|
||||||
*/
|
|
||||||
public function park()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(Park::class, 'park_id', 'park_id');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ユーザーとの関連
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
|
||||||
*/
|
|
||||||
public function user()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(User::class, 'user_id', 'user_id');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 契約との関連
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
|
||||||
*/
|
|
||||||
public function contract()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(RegularContract::class, 'contract_id', 'contract_id');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 過去15分間のエラーログを取得
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Database\Eloquent\Collection
|
|
||||||
*/
|
|
||||||
public static function getRecentErrorLogs()
|
|
||||||
{
|
|
||||||
$fifteenMinutesAgo = Carbon::now()->subMinutes(15);
|
|
||||||
|
|
||||||
return self::where('created_at', '>=', $fifteenMinutesAgo)
|
|
||||||
->where('error_code', '>=', self::ERROR_CODE_THRESHOLD)
|
|
||||||
->orderBy('created_at', 'desc')
|
|
||||||
->get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 指定期間内のエラーログを取得
|
|
||||||
*
|
|
||||||
* @param string $startTime 開始時刻
|
|
||||||
* @param string $endTime 終了時刻
|
|
||||||
* @return \Illuminate\Database\Eloquent\Collection
|
|
||||||
*/
|
|
||||||
public static function getErrorLogsByPeriod(string $startTime, string $endTime)
|
|
||||||
{
|
|
||||||
return self::whereBetween('created_at', [$startTime, $endTime])
|
|
||||||
->where('error_code', '>=', self::ERROR_CODE_THRESHOLD)
|
|
||||||
->orderBy('created_at', 'desc')
|
|
||||||
->get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 指定期間内の全ログを取得
|
|
||||||
*
|
|
||||||
* @param string $startTime 開始時刻
|
|
||||||
* @param string $endTime 終了時刻
|
|
||||||
* @return \Illuminate\Database\Eloquent\Collection
|
|
||||||
*/
|
|
||||||
public static function getLogsByPeriod(string $startTime, string $endTime)
|
|
||||||
{
|
|
||||||
return self::whereBetween('created_at', [$startTime, $endTime])
|
|
||||||
->orderBy('created_at', 'desc')
|
|
||||||
->get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* プリンタジョブログを作成
|
|
||||||
*
|
|
||||||
* @param array $data ログデータ
|
|
||||||
* @return PrintJobLog 作成されたログ
|
|
||||||
*/
|
|
||||||
public static function createLog(array $data): PrintJobLog
|
|
||||||
{
|
|
||||||
$defaultData = [
|
|
||||||
'park_id' => null,
|
|
||||||
'user_id' => null,
|
|
||||||
'contract_id' => null,
|
|
||||||
'process_name' => '',
|
|
||||||
'job_name' => '',
|
|
||||||
'status' => '',
|
|
||||||
'error_code' => 0,
|
|
||||||
'status_comment' => '',
|
|
||||||
'created_at' => now()
|
|
||||||
];
|
|
||||||
|
|
||||||
$mergedData = array_merge($defaultData, $data);
|
|
||||||
|
|
||||||
return self::create($mergedData);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* エラーログかどうかを判定
|
|
||||||
*
|
|
||||||
* @return bool エラーログかどうか
|
|
||||||
*/
|
|
||||||
public function isError(): bool
|
|
||||||
{
|
|
||||||
return $this->error_code >= self::ERROR_CODE_THRESHOLD;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 正常ログかどうかを判定
|
|
||||||
*
|
|
||||||
* @return bool 正常ログかどうか
|
|
||||||
*/
|
|
||||||
public function isNormal(): bool
|
|
||||||
{
|
|
||||||
return $this->error_code < self::ERROR_CODE_THRESHOLD;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* エラーレベルを取得
|
|
||||||
*
|
|
||||||
* @return string エラーレベル
|
|
||||||
*/
|
|
||||||
public function getErrorLevel(): string
|
|
||||||
{
|
|
||||||
if ($this->error_code >= 200) {
|
|
||||||
return '重大エラー';
|
|
||||||
} elseif ($this->error_code >= self::ERROR_CODE_THRESHOLD) {
|
|
||||||
return 'エラー';
|
|
||||||
} else {
|
|
||||||
return '正常';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* エラーログの統計情報を取得
|
|
||||||
*
|
|
||||||
* @param string $startTime 開始時刻
|
|
||||||
* @param string $endTime 終了時刻
|
|
||||||
* @return array 統計情報
|
|
||||||
*/
|
|
||||||
public static function getErrorStatistics(string $startTime, string $endTime): array
|
|
||||||
{
|
|
||||||
$errorLogs = self::getErrorLogsByPeriod($startTime, $endTime);
|
|
||||||
$totalLogs = self::getLogsByPeriod($startTime, $endTime);
|
|
||||||
|
|
||||||
$errorByCode = $errorLogs->groupBy('error_code')->map->count();
|
|
||||||
$errorByProcess = $errorLogs->groupBy('process_name')->map->count();
|
|
||||||
|
|
||||||
return [
|
|
||||||
'total_logs' => $totalLogs->count(),
|
|
||||||
'error_logs' => $errorLogs->count(),
|
|
||||||
'error_rate' => $totalLogs->count() > 0 ?
|
|
||||||
round(($errorLogs->count() / $totalLogs->count()) * 100, 2) : 0,
|
|
||||||
'error_by_code' => $errorByCode->toArray(),
|
|
||||||
'error_by_process' => $errorByProcess->toArray(),
|
|
||||||
'period' => [
|
|
||||||
'start' => $startTime,
|
|
||||||
'end' => $endTime
|
|
||||||
]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文字列表現
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function __toString(): string
|
|
||||||
{
|
|
||||||
return sprintf(
|
|
||||||
'PrintJobLog[ID:%d, Process:%s, ErrorCode:%d, Time:%s]',
|
|
||||||
$this->log_id,
|
|
||||||
$this->process_name,
|
|
||||||
$this->error_code,
|
|
||||||
$this->created_at ? $this->created_at->format('Y-m-d H:i:s') : 'N/A'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -5,124 +5,22 @@ namespace App\Models;
|
|||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
/**
|
|
||||||
* 車種区分モデル - psectionテーブル
|
|
||||||
*
|
|
||||||
* 駐輪場の車種区分マスタデータを管理
|
|
||||||
*/
|
|
||||||
class Psection extends Model
|
class Psection extends Model
|
||||||
{
|
{
|
||||||
/**
|
// テーブル名
|
||||||
* テーブル名
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $table = 'psection';
|
protected $table = 'psection';
|
||||||
|
// 主キー
|
||||||
/**
|
|
||||||
* プライマリキー
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $primaryKey = 'psection_id';
|
protected $primaryKey = 'psection_id';
|
||||||
|
|
||||||
/**
|
|
||||||
* 一括代入可能な属性
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
protected $fillable = [
|
|
||||||
'psection_subject', // 車種区分名
|
|
||||||
'operator_id', // オペレータID
|
|
||||||
'created_at', // 作成日時
|
|
||||||
'updated_at', // 更新日時
|
|
||||||
'psection_id' // 車種区分ID
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* キャストする属性
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
protected $casts = [
|
|
||||||
'psection_id' => 'integer',
|
|
||||||
'operator_id' => 'integer',
|
|
||||||
'created_at' => 'datetime',
|
|
||||||
'updated_at' => 'datetime'
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
// 主キーが自動増分でない場合はfalseに設定
|
// 主キーが自動増分でない場合はfalseに設定
|
||||||
public $incrementing = false;
|
public $incrementing = false;
|
||||||
// タイムスタンプ管理しない場合はfalseに設定
|
// タイムスタンプ管理しない場合はfalseに設定
|
||||||
public $timestamps = false;
|
public $timestamps = false;
|
||||||
|
|
||||||
|
// 一括代入可能なカラム
|
||||||
|
protected $fillable = [
|
||||||
/**
|
'psection_id', // 車種区分ID
|
||||||
* 売上集計との関連
|
'psection_subject', // 車種区分名
|
||||||
*
|
];
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
|
||||||
*/
|
|
||||||
public function earningsSummaries()
|
|
||||||
{
|
|
||||||
return $this->hasMany(EarningsSummary::class, 'psection_id', 'psection_id');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 定期契約との関連
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
|
||||||
*/
|
|
||||||
public function regularContracts()
|
|
||||||
{
|
|
||||||
return $this->hasMany(RegularContract::class, 'psection_id', 'psection_id');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* アクティブな車種区分一覧を取得
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Database\Eloquent\Collection
|
|
||||||
*/
|
|
||||||
public static function getActivePsections()
|
|
||||||
{
|
|
||||||
return self::orderBy('psection_id')->get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 車種区分名で検索
|
|
||||||
*
|
|
||||||
* @param string $subject 車種区分名
|
|
||||||
* @return Psection|null
|
|
||||||
*/
|
|
||||||
public static function findBySubject(string $subject): ?Psection
|
|
||||||
{
|
|
||||||
return self::where('psection_subject', $subject)->first();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文字列表現
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function __toString(): string
|
|
||||||
{
|
|
||||||
return sprintf(
|
|
||||||
'Psection[ID:%d, Subject:%s]',
|
|
||||||
$this->psection_id,
|
|
||||||
$this->psection_subject
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 新規作成時にoperator_idを自動設定(operator_idカラムがある場合のみ)
|
// 新規作成時にoperator_idを自動設定(operator_idカラムがある場合のみ)
|
||||||
public static function boot()
|
public static function boot()
|
||||||
|
|||||||
@ -33,7 +33,6 @@ class Ptype extends Model
|
|||||||
'ptype_subject',
|
'ptype_subject',
|
||||||
'ptype_remarks',
|
'ptype_remarks',
|
||||||
'operator_id',
|
'operator_id',
|
||||||
'floor_sort',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
public static function search($inputs)
|
public static function search($inputs)
|
||||||
@ -48,7 +47,7 @@ class Ptype extends Model
|
|||||||
if (!empty($inputs['isExport'])) {
|
if (!empty($inputs['isExport'])) {
|
||||||
return $list->get();
|
return $list->get();
|
||||||
} else {
|
} else {
|
||||||
return $list->paginate(20);
|
return $list->paginate(\App\Models\Utils::item_per_page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,10 +4,18 @@ namespace App\Models;
|
|||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定期契約モデル - regular_contractテーブル(正式モデル)
|
||||||
|
* 旧UsingStatusContractの責務を置き換え
|
||||||
|
*/
|
||||||
class RegularContract extends Model
|
class RegularContract extends Model
|
||||||
{
|
{
|
||||||
protected $table = 'regular_contract';
|
protected $table = 'regular_contract';
|
||||||
protected $primaryKey = 'contract_id';
|
protected $primaryKey = 'contract_id';
|
||||||
|
public $timestamps = true;
|
||||||
|
|
||||||
|
public const CREATED_AT = 'created_at';
|
||||||
|
public const UPDATED_AT = 'updated_at';
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'contract_qr_id',
|
'contract_qr_id',
|
||||||
@ -25,6 +33,8 @@ class RegularContract extends Model
|
|||||||
'contract_reduction',
|
'contract_reduction',
|
||||||
'contract_periods',
|
'contract_periods',
|
||||||
'contract_periode',
|
'contract_periode',
|
||||||
|
'enable_months',
|
||||||
|
'printable_date',
|
||||||
'contract_taxid',
|
'contract_taxid',
|
||||||
'billing_amount',
|
'billing_amount',
|
||||||
'contract_payment_day',
|
'contract_payment_day',
|
||||||
@ -39,8 +49,10 @@ class RegularContract extends Model
|
|||||||
'settlement_transaction_id',
|
'settlement_transaction_id',
|
||||||
'contract_seal_issue',
|
'contract_seal_issue',
|
||||||
'seal_reissue_request',
|
'seal_reissue_request',
|
||||||
|
'update_flag',
|
||||||
'contract_permission',
|
'contract_permission',
|
||||||
'contract_cancel_flag',
|
'contract_cancel_flag',
|
||||||
|
'800m_flag',
|
||||||
'tag_qr_flag',
|
'tag_qr_flag',
|
||||||
'tag_change_flag',
|
'tag_change_flag',
|
||||||
'park_position',
|
'park_position',
|
||||||
@ -48,61 +60,15 @@ class RegularContract extends Model
|
|||||||
'contract_manual',
|
'contract_manual',
|
||||||
'contract_notice',
|
'contract_notice',
|
||||||
'contract_payment_number',
|
'contract_payment_number',
|
||||||
'created_at',
|
|
||||||
'updated_at'
|
|
||||||
];
|
];
|
||||||
|
|
||||||
public static function search($inputs)
|
/**
|
||||||
|
* 料金設定
|
||||||
|
*/
|
||||||
|
public function price()
|
||||||
{
|
{
|
||||||
$list = self::query();
|
return $this->belongsTo(PriceA::class, 'price_parkplaceid', 'price_parkplaceid');
|
||||||
// Sort
|
|
||||||
if ($inputs['sort']) {
|
|
||||||
$list->orderBy($inputs['sort'], $inputs['sort_type']);
|
|
||||||
}
|
|
||||||
if ($inputs['isExport']){
|
|
||||||
$list = $list->get();
|
|
||||||
}else{
|
|
||||||
$list = $list->paginate(\App\Utils::item_per_page); // Utilsクラスの定数を使用
|
|
||||||
}
|
|
||||||
return $list;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getByPk($pk)
|
|
||||||
{
|
|
||||||
return self::find($pk);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function deleteByPk($arr)
|
|
||||||
{
|
|
||||||
return self::whereIn('contract_id', $arr)->delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO 定期契約ID not found in database specs
|
|
||||||
|
|
||||||
//TODO 解約/契約不可フラグ not found in database specs
|
|
||||||
public function userName()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(\App\Models\User::class,'user_id','user_seq')->first();
|
|
||||||
}
|
|
||||||
public function getUserType()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(\App\Models\Usertype::class,'user_categoryid','user_categoryid')->first();
|
|
||||||
}
|
|
||||||
public function getPark()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(\App\Models\Park::class,'park_id','park_id')->first();
|
|
||||||
}
|
|
||||||
public function getPrice()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(\App\Models\Price::class,'price_parkplaceid','price_parkplaceid')->first();
|
|
||||||
}
|
|
||||||
// public function getSettlement()
|
|
||||||
// {
|
|
||||||
// return $this->belongsTo(SettlementTransaction::class,'settlement_transaction_id','settlement_transaction_id')->first();
|
|
||||||
// }
|
|
||||||
|
|
||||||
public function getOpe()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(\App\Models\Ope::class,'ope_id','ope_id')->first();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,78 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
use App\Models\City;
|
|
||||||
use App\Utils;
|
|
||||||
|
|
||||||
class RegularType extends Model
|
|
||||||
{
|
|
||||||
const CREATED_AT = 'created_at';
|
|
||||||
const UPDATED_AT = 'updated_at';
|
|
||||||
|
|
||||||
const RegularClass = [
|
|
||||||
'有効',
|
|
||||||
'無効',
|
|
||||||
];
|
|
||||||
|
|
||||||
protected $table = 'regular_type';
|
|
||||||
protected $primaryKey = 'regular_type_id';
|
|
||||||
|
|
||||||
protected $fillable = [
|
|
||||||
'regular_type_id',
|
|
||||||
'city_id',
|
|
||||||
'regular_class_1',
|
|
||||||
'regular_class_2',
|
|
||||||
'regular_class_3',
|
|
||||||
'regular_class_6',
|
|
||||||
'regular_class_12',
|
|
||||||
'memo',
|
|
||||||
'operator_id',
|
|
||||||
];
|
|
||||||
|
|
||||||
public static function boot()
|
|
||||||
{
|
|
||||||
parent::boot();
|
|
||||||
self::creating(function (RegularType $model) {
|
|
||||||
$model->operator_id = Auth::user()->ope_id;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function search($inputs)
|
|
||||||
{
|
|
||||||
$list = self::query();
|
|
||||||
|
|
||||||
if ($inputs['isMethodPost']) {
|
|
||||||
// 検索条件
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($inputs['sort']) {
|
|
||||||
$list->orderBy($inputs['sort'], $inputs['sort_type']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($inputs['isExport']) {
|
|
||||||
$list = $list->get();
|
|
||||||
} else {
|
|
||||||
$list = $list->paginate(Utils::item_per_page);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $list;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getById($id)
|
|
||||||
{
|
|
||||||
return self::find($id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function deleteById($id)
|
|
||||||
{
|
|
||||||
return self::where('regular_type_id', $id)->delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCity()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(City::class, 'city_id', 'city_id')->first();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,62 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
class Setting extends Model
|
|
||||||
{
|
|
||||||
// 対応するテーブル名
|
|
||||||
protected $table = 'setting';
|
|
||||||
|
|
||||||
// 主キー
|
|
||||||
protected $primaryKey = 'setting_id';
|
|
||||||
|
|
||||||
// 主キーは自動増分
|
|
||||||
public $incrementing = true;
|
|
||||||
|
|
||||||
// 主キーの型
|
|
||||||
protected $keyType = 'int';
|
|
||||||
|
|
||||||
// 一括代入可能なカラム
|
|
||||||
protected $fillable = [
|
|
||||||
'edit_master', // 編集マスタ
|
|
||||||
'web_master', // ウェブ参照マスタ
|
|
||||||
'auto_change_date', // ウェブ参照マスタ自動切り替え日時
|
|
||||||
'auto_chage_master', // 自動切換えウェブ参照マスタ(※DB定義のままchage)
|
|
||||||
're-issue_alert_number', // 再発行アラート回数
|
|
||||||
'image_base_url1', // ニュースイメージURLベース名
|
|
||||||
'image_base_url2', // 本人確認写真URLベース名
|
|
||||||
'printable_alert_flag', // プリンタ印字残警告フラグ
|
|
||||||
'printable_number', // プリンタロール紙印字可能数
|
|
||||||
'printable_alert_number', // プリンタロール紙印字残警告数
|
|
||||||
'printer_keep_alive', // プリンタ制御プログラムキープアライブ間隔(分)
|
|
||||||
'operator_id', // 更新オペレータID
|
|
||||||
];
|
|
||||||
|
|
||||||
// キャスト(型変換)
|
|
||||||
protected $casts = [
|
|
||||||
'auto_change_date' => 'datetime', // 日時
|
|
||||||
're-issue_alert_number' => 'integer', // 整数
|
|
||||||
'printable_alert_flag' => 'boolean', // 真偽値
|
|
||||||
'printable_number' => 'integer', // 整数
|
|
||||||
'printable_alert_number' => 'integer', // 整数
|
|
||||||
'printer_keep_alive' => 'integer', // 整数
|
|
||||||
'operator_id' => 'integer', // 整数
|
|
||||||
'created_at' => 'datetime', // 作成日時
|
|
||||||
'updated_at' => 'datetime', // 更新日時
|
|
||||||
];
|
|
||||||
|
|
||||||
// アクセサ(getter)
|
|
||||||
public function getReissueAlertNumberAttribute()
|
|
||||||
{
|
|
||||||
return $this->attributes['re-issue_alert_number'] ?? null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ミューテタ(setter)
|
|
||||||
public function setReissueAlertNumberAttribute($value)
|
|
||||||
{
|
|
||||||
$this->attributes['re-issue_alert_number'] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
class SettlementTransaction extends Model
|
|
||||||
{
|
|
||||||
protected $table = 'settlement_transaction';
|
|
||||||
protected $primaryKey = 'settlement_transaction_id';
|
|
||||||
public $timestamps = true;
|
|
||||||
|
|
||||||
protected $fillable = [
|
|
||||||
'contract_id',
|
|
||||||
'status',
|
|
||||||
'pay_code',
|
|
||||||
'contract_payment_number',
|
|
||||||
'corp_code',
|
|
||||||
'mms_date',
|
|
||||||
'cvs_code',
|
|
||||||
'shop_code',
|
|
||||||
'pay_date',
|
|
||||||
'settlement_amount',
|
|
||||||
'stamp_flag',
|
|
||||||
'md5_string',
|
|
||||||
];
|
|
||||||
|
|
||||||
// 日付型キャスト
|
|
||||||
protected $casts = [
|
|
||||||
'created_at' => 'datetime',
|
|
||||||
'updated_at' => 'datetime',
|
|
||||||
'pay_date' => 'datetime',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
class Station extends Model
|
|
||||||
{
|
|
||||||
protected $table = 'station';
|
|
||||||
protected $primaryKey = 'station_id';
|
|
||||||
|
|
||||||
protected $fillable = [
|
|
||||||
'park_id',
|
|
||||||
'station_neighbor_station',
|
|
||||||
'station_name_ruby',
|
|
||||||
'station_route_name',
|
|
||||||
'operator_id',
|
|
||||||
'station_latitude', // ← 緯度
|
|
||||||
'station_longitude', // ← 経度
|
|
||||||
];
|
|
||||||
public function park()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(Park::class, 'park_id', 'park_id');
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
class Tax extends Model
|
|
||||||
{
|
|
||||||
use HasFactory;
|
|
||||||
|
|
||||||
// テーブル名
|
|
||||||
protected $table = 'tax';
|
|
||||||
|
|
||||||
// 主キー
|
|
||||||
protected $primaryKey = 'tax_id';
|
|
||||||
|
|
||||||
// 主キーが自動増分
|
|
||||||
public $incrementing = true;
|
|
||||||
|
|
||||||
// 主キーの型
|
|
||||||
protected $keyType = 'int';
|
|
||||||
|
|
||||||
// Laravel の自動タイムスタンプ
|
|
||||||
public $timestamps = true;
|
|
||||||
|
|
||||||
// 更新可能なカラム
|
|
||||||
protected $fillable = [
|
|
||||||
'tax_percent', // 消費税率
|
|
||||||
'tax_day', // 適用日
|
|
||||||
'operator_id', // オペレーターID
|
|
||||||
];
|
|
||||||
|
|
||||||
// キャスト(型変換)
|
|
||||||
protected $casts = [
|
|
||||||
'tax_day' => 'date',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
class Term extends Model
|
|
||||||
{
|
|
||||||
protected $table = 'terms'; // テーブル名
|
|
||||||
|
|
||||||
protected $primaryKey = 'terms_id'; // 主キー
|
|
||||||
|
|
||||||
public $timestamps = true; // created_at / updated_at
|
|
||||||
|
|
||||||
protected $fillable = [
|
|
||||||
'city_id',
|
|
||||||
'use_flag',
|
|
||||||
'terms_revision',
|
|
||||||
'terms_text',
|
|
||||||
'memo',
|
|
||||||
'start_date',
|
|
||||||
'operator_id',
|
|
||||||
];
|
|
||||||
|
|
||||||
protected $casts = [
|
|
||||||
'start_date' => 'date',
|
|
||||||
'use_flag' => 'boolean',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 利用規約のリストを取得
|
|
||||||
*/
|
|
||||||
public static function getList()
|
|
||||||
{
|
|
||||||
return self::all();
|
|
||||||
}
|
|
||||||
public static function deleteByPk($ids)
|
|
||||||
{
|
|
||||||
if (!is_array($ids)) {
|
|
||||||
$ids = [$ids];
|
|
||||||
}
|
|
||||||
return self::whereIn('terms_id', $ids)->delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -2,90 +2,25 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
use Illuminate\Notifications\Notifiable;
|
use Illuminate\Notifications\Notifiable;
|
||||||
use Illuminate\Pagination\LengthAwarePaginator;
|
|
||||||
|
|
||||||
class User extends Model
|
class User extends Authenticatable
|
||||||
{
|
{
|
||||||
/** @use HasFactory<\Database\Factories\UserFactory> */
|
/** @use HasFactory<\Database\Factories\UserFactory> */
|
||||||
use HasFactory, Notifiable;
|
use HasFactory, Notifiable;
|
||||||
|
|
||||||
protected $table = 'user';
|
|
||||||
protected $primaryKey = 'user_seq';
|
|
||||||
public $timestamps = true;
|
|
||||||
|
|
||||||
// 本人確認チェックフラグの定数
|
|
||||||
const USER_ID_CARD_CHK_FLG = [
|
|
||||||
0 => '未確認',
|
|
||||||
1 => '確認済み'
|
|
||||||
];
|
|
||||||
|
|
||||||
// 身分証明書種別の定数
|
|
||||||
const USER_IDCARD = [
|
|
||||||
'運転免許証' => '運転免許証',
|
|
||||||
'健康保険証' => '健康保険証',
|
|
||||||
'パスポート' => 'パスポート',
|
|
||||||
'学生証' => '学生証',
|
|
||||||
'その他' => 'その他'
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The attributes that are mass assignable.
|
* The attributes that are mass assignable.
|
||||||
*
|
*
|
||||||
* @var list<string>
|
* @var list<string>
|
||||||
*/
|
*/
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'user_id',
|
'name',
|
||||||
'member_id',
|
'email',
|
||||||
'user_pass',
|
'password',
|
||||||
'user_manual_regist_flag',
|
|
||||||
'user_mailing_flag',
|
|
||||||
'contract_number',
|
|
||||||
'user_tag_serial',
|
|
||||||
'user_tag_serial_64',
|
|
||||||
'qr_code',
|
|
||||||
'tag_qr_flag',
|
|
||||||
'user_aid',
|
|
||||||
'user_park_number',
|
|
||||||
'user_place_qrid',
|
|
||||||
'user_categoryid',
|
|
||||||
'user_name',
|
|
||||||
'user_phonetic',
|
|
||||||
'user_gender',
|
|
||||||
'user_birthdate',
|
|
||||||
'user_age',
|
|
||||||
'ward_residents',
|
|
||||||
'user_mobile',
|
|
||||||
'user_homephone',
|
|
||||||
'user_primemail',
|
|
||||||
'user_submail',
|
|
||||||
'user_regident_zip',
|
|
||||||
'user_regident_pre',
|
|
||||||
'user_regident_city',
|
|
||||||
'user_regident_add',
|
|
||||||
'user_relate_zip',
|
|
||||||
'user_relate_pre',
|
|
||||||
'user_relate_city',
|
|
||||||
'user_relate_add',
|
|
||||||
'user_workplace',
|
|
||||||
'user_school',
|
|
||||||
'user_graduate',
|
|
||||||
'user_reduction',
|
|
||||||
'user_idcard',
|
|
||||||
'user_idcard_chk_flag',
|
|
||||||
'user_chk_day',
|
|
||||||
'user_chk_opeid',
|
|
||||||
'user_tag_issue',
|
|
||||||
'issue_permission',
|
|
||||||
'user_quit_flag',
|
|
||||||
'user_quitday',
|
|
||||||
'user_remarks',
|
|
||||||
'photo_filename1',
|
|
||||||
'photo_filename2',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -94,7 +29,7 @@ class User extends Model
|
|||||||
* @var list<string>
|
* @var list<string>
|
||||||
*/
|
*/
|
||||||
protected $hidden = [
|
protected $hidden = [
|
||||||
'user_pass',
|
'password',
|
||||||
'remember_token',
|
'remember_token',
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -107,106 +42,7 @@ class User extends Model
|
|||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'email_verified_at' => 'datetime',
|
'email_verified_at' => 'datetime',
|
||||||
'user_birthdate' => 'date',
|
'password' => 'hashed',
|
||||||
'user_chk_day' => 'datetime',
|
|
||||||
'user_quitday' => 'date',
|
|
||||||
'user_manual_regist_flag' => 'boolean',
|
|
||||||
'user_mailing_flag' => 'boolean',
|
|
||||||
'tag_qr_flag' => 'boolean',
|
|
||||||
'user_idcard_chk_flag' => 'boolean',
|
|
||||||
'issue_permission' => 'boolean',
|
|
||||||
'user_quit_flag' => 'boolean',
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* ユーザー検索
|
|
||||||
*/
|
|
||||||
public static function search($inputs)
|
|
||||||
{
|
|
||||||
$query = self::query();
|
|
||||||
|
|
||||||
// 検索条件の適用
|
|
||||||
if (!empty($inputs['user_id'])) {
|
|
||||||
$query->where('user_id', 'like', '%' . $inputs['user_id'] . '%');
|
|
||||||
}
|
|
||||||
if (!empty($inputs['member_id'])) {
|
|
||||||
$query->where('member_id', 'like', '%' . $inputs['member_id'] . '%');
|
|
||||||
}
|
|
||||||
if (!empty($inputs['user_tag_serial'])) {
|
|
||||||
$query->where('user_tag_serial', 'like', '%' . $inputs['user_tag_serial'] . '%');
|
|
||||||
}
|
|
||||||
if (!empty($inputs['user_phonetic'])) {
|
|
||||||
$query->where('user_phonetic', 'like', '%' . $inputs['user_phonetic'] . '%');
|
|
||||||
}
|
|
||||||
if (!empty($inputs['phone'])) {
|
|
||||||
$query->where(function($q) use ($inputs) {
|
|
||||||
$q->where('user_mobile', 'like', '%' . $inputs['phone'] . '%')
|
|
||||||
->orWhere('user_homephone', 'like', '%' . $inputs['phone'] . '%');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (isset($inputs['black_list']) && $inputs['black_list'] !== '') {
|
|
||||||
$query->where('user_quit_flag', $inputs['black_list']);
|
|
||||||
}
|
|
||||||
if (isset($inputs['ward_residents']) && $inputs['ward_residents'] !== '') {
|
|
||||||
$query->where('ward_residents', $inputs['ward_residents']);
|
|
||||||
}
|
|
||||||
if (!empty($inputs['user_tag_serial_64'])) {
|
|
||||||
$query->where('user_tag_serial_64', 'like', '%' . $inputs['user_tag_serial_64'] . '%');
|
|
||||||
}
|
|
||||||
|
|
||||||
// ソート
|
|
||||||
if (!empty($inputs['sort'])) {
|
|
||||||
$sortType = !empty($inputs['sort_type']) ? $inputs['sort_type'] : 'asc';
|
|
||||||
$query->orderBy($inputs['sort'], $sortType);
|
|
||||||
} else {
|
|
||||||
$query->orderBy('user_seq', 'desc');
|
|
||||||
}
|
|
||||||
|
|
||||||
// エクスポート用の場合はページネーションしない
|
|
||||||
if (!empty($inputs['isExport'])) {
|
|
||||||
return $query->get();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ページネーション(Utilsクラスの定数を使用)
|
|
||||||
return $query->paginate(\App\Utils::item_per_page);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* シーケンスでユーザーを取得
|
|
||||||
*/
|
|
||||||
public static function getUserBySeq($seq)
|
|
||||||
{
|
|
||||||
return self::where('user_seq', $seq)->first();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* シーケンス配列でユーザーを削除
|
|
||||||
*/
|
|
||||||
public static function deleteUsersBySeq($seqArray)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
return self::whereIn('user_seq', $seqArray)->delete();
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ユーザータイプとのリレーション
|
|
||||||
*/
|
|
||||||
public function getUserType()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(Usertype::class, 'user_categoryid', 'id');
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getList()
|
|
||||||
{
|
|
||||||
return self::pluck('user_name', 'user_seq');
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getUserPhone()
|
|
||||||
{
|
|
||||||
return self::select('user_seq', 'user_name', 'user_mobile', 'user_homephone')->get();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Utils;
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
@ -16,14 +15,9 @@ class Usertype extends Model
|
|||||||
protected $primaryKey = 'user_categoryid';
|
protected $primaryKey = 'user_categoryid';
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'sort_order',
|
|
||||||
'usertype_subject1',
|
|
||||||
'usertype_subject2',
|
|
||||||
'usertype_subject3',
|
|
||||||
'print_name',
|
'print_name',
|
||||||
'usertype_money',
|
'usertype_money',
|
||||||
'usertype_remarks',
|
'usertype_remarks'
|
||||||
'operator_id',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
public static function boot()
|
public static function boot()
|
||||||
@ -34,47 +28,22 @@ class Usertype extends Model
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function search(array $inputs)
|
public static function search($inputs)
|
||||||
{
|
{
|
||||||
$query = self::query();
|
$list = self::query();
|
||||||
$table = (new self())->getTable();
|
if ($inputs['isMethodPost']) {
|
||||||
|
|
||||||
if (!empty($inputs['filter_sort_order'])) {
|
|
||||||
$query->where('sort_order', $inputs['filter_sort_order']);
|
|
||||||
}
|
}
|
||||||
if (!empty($inputs['filter_usertype_subject1'])) {
|
// Sort
|
||||||
$query->where('usertype_subject1', 'like', '%' . $inputs['filter_usertype_subject1'] . '%');
|
if ($inputs['sort']) {
|
||||||
|
$list->orderBy($inputs['sort'], $inputs['sort_type']);
|
||||||
}
|
}
|
||||||
if (!empty($inputs['filter_usertype_subject2'])) {
|
if ($inputs['isExport']){
|
||||||
$query->where('usertype_subject2', 'like', '%' . $inputs['filter_usertype_subject2'] . '%');
|
$list = $list->get();
|
||||||
|
}else{
|
||||||
|
$list = $list->paginate(Utils::item_per_page);
|
||||||
}
|
}
|
||||||
if (!empty($inputs['filter_usertype_subject3'])) {
|
return $list;
|
||||||
$query->where('usertype_subject3', 'like', '%' . $inputs['filter_usertype_subject3'] . '%');
|
|
||||||
}
|
|
||||||
|
|
||||||
$sortable = [
|
|
||||||
'user_categoryid' => "{$table}.user_categoryid",
|
|
||||||
'sort_order' => "{$table}.sort_order",
|
|
||||||
'usertype_subject1' => "{$table}.usertype_subject1",
|
|
||||||
'usertype_subject2' => "{$table}.usertype_subject2",
|
|
||||||
'usertype_subject3' => "{$table}.usertype_subject3",
|
|
||||||
'print_name' => "{$table}.print_name",
|
|
||||||
'usertype_remarks' => "{$table}.usertype_remarks",
|
|
||||||
];
|
|
||||||
|
|
||||||
$sortKey = $inputs['sort'] ?? 'user_categoryid';
|
|
||||||
$sortColumn = $sortable[$sortKey] ?? "{$table}.user_categoryid";
|
|
||||||
|
|
||||||
$direction = strtolower($inputs['sort_type'] ?? 'asc');
|
|
||||||
if (!in_array($direction, ['asc', 'desc'], true)) {
|
|
||||||
$direction = 'asc';
|
|
||||||
}
|
|
||||||
|
|
||||||
$query->orderBy($sortColumn, $direction);
|
|
||||||
|
|
||||||
return !empty($inputs['isExport'])
|
|
||||||
? $query->get()
|
|
||||||
: $query->paginate(Utils::item_per_page);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getByPk($pk)
|
public static function getByPk($pk)
|
||||||
|
|||||||
@ -1,60 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
class Zone extends Model
|
|
||||||
{
|
|
||||||
use HasFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* テーブル名
|
|
||||||
*/
|
|
||||||
protected $table = 'zone';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 主キー
|
|
||||||
*/
|
|
||||||
protected $primaryKey = 'zone_id';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* タイムスタンプを有効化
|
|
||||||
*/
|
|
||||||
public $timestamps = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 一括代入可能なカラム
|
|
||||||
*/
|
|
||||||
protected $fillable = [
|
|
||||||
'park_id',
|
|
||||||
'park_name',
|
|
||||||
'ptype_id',
|
|
||||||
'psection_id',
|
|
||||||
'zone_name',
|
|
||||||
'zone_number',
|
|
||||||
'zone_standard',
|
|
||||||
'zone_tolerance',
|
|
||||||
'zone_sort',
|
|
||||||
'delete_flag',
|
|
||||||
'ope_id',
|
|
||||||
'created_at',
|
|
||||||
'updated_at',
|
|
||||||
];
|
|
||||||
public function park()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(Park::class, 'park_id', 'park_id');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function ptype()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(Ptype::class, 'ptype_id', 'ptype_id');
|
|
||||||
}
|
|
||||||
public function psection()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(Psection::class, 'psection_id', 'psection_id');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -5,10 +5,6 @@ namespace App\Providers;
|
|||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
use App\Services\ShjFourCService;
|
use App\Services\ShjFourCService;
|
||||||
use App\Services\ShjMailSendService;
|
use App\Services\ShjMailSendService;
|
||||||
use App\Services\ShjNineService;
|
|
||||||
use App\Services\ShjTenService;
|
|
||||||
use App\Services\ShjSixService;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
|
|
||||||
class AppServiceProvider extends ServiceProvider
|
class AppServiceProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
@ -34,41 +30,7 @@ class AppServiceProvider extends ServiceProvider
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// SHJ-9売上集計処理サービスを登録
|
|
||||||
$this->app->singleton(ShjNineService::class, function ($app) {
|
|
||||||
return new ShjNineService(
|
|
||||||
$app->make(\App\Models\Park::class),
|
|
||||||
$app->make(\App\Models\RegularContract::class),
|
|
||||||
$app->make(\App\Models\EarningsSummary::class),
|
|
||||||
$app->make(\App\Models\Psection::class),
|
|
||||||
$app->make(\App\Models\Batch\BatchLog::class),
|
|
||||||
$app->make(\App\Models\OperatorQue::class)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// SHJ-10財政年度売上集計処理サービスを登録
|
|
||||||
$this->app->singleton(ShjTenService::class, function ($app) {
|
|
||||||
return new ShjTenService(
|
|
||||||
$app->make(\App\Models\Park::class),
|
|
||||||
$app->make(\App\Models\RegularContract::class),
|
|
||||||
$app->make(\App\Models\EarningsSummary::class),
|
|
||||||
$app->make(\App\Models\Psection::class),
|
|
||||||
$app->make(\App\Models\Batch\BatchLog::class),
|
|
||||||
$app->make(\App\Models\OperatorQue::class)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// SHJ-6サーバ死活監視処理サービスを登録
|
|
||||||
$this->app->singleton(ShjSixService::class, function ($app) {
|
|
||||||
return new ShjSixService(
|
|
||||||
$app->make(\App\Models\Device::class),
|
|
||||||
$app->make(\App\Models\HardwareCheckLog::class),
|
|
||||||
$app->make(\App\Models\PrintJobLog::class),
|
|
||||||
$app->make(\App\Models\Batch\BatchLog::class),
|
|
||||||
$app->make(\App\Models\OperatorQue::class),
|
|
||||||
$app->make(\App\Services\ShjMailSendService::class)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -76,44 +38,6 @@ class AppServiceProvider extends ServiceProvider
|
|||||||
*/
|
*/
|
||||||
public function boot(): void
|
public function boot(): void
|
||||||
{
|
{
|
||||||
view()->composer('layouts.app', function($view){
|
//
|
||||||
|
|
||||||
// 未対応のみ集計
|
|
||||||
$stats = DB::table('operator_que')
|
|
||||||
->selectRaw("
|
|
||||||
SUM(CASE WHEN que_status = 1 AND que_class < 100 THEN 1 ELSE 0 END) AS task_untreated,
|
|
||||||
MAX(CASE WHEN que_status = 1 AND que_class < 100 THEN created_at END) AS task_latest,
|
|
||||||
SUM(CASE WHEN que_status = 1 AND que_class > 99 THEN 1 ELSE 0 END) AS hard_untreated,
|
|
||||||
MAX(CASE WHEN que_status = 1 AND que_class > 99 THEN created_at END) AS hard_latest
|
|
||||||
")
|
|
||||||
->first();
|
|
||||||
|
|
||||||
// 変数名は互換維持(内容は未対応件数)
|
|
||||||
$taskCount = (int)($stats->task_untreated ?? 0);
|
|
||||||
$hardCount = (int)($stats->hard_untreated ?? 0);
|
|
||||||
$taskLatest = $stats->task_latest ?? null;
|
|
||||||
$hardLatest = $stats->hard_latest ?? null;
|
|
||||||
|
|
||||||
// ドロップダウン最新5件 も未対応のみ
|
|
||||||
$latestTasks = DB::table('operator_que')
|
|
||||||
->where('que_status',1)
|
|
||||||
->where('que_class','<',100)
|
|
||||||
->orderByDesc('created_at')
|
|
||||||
->limit(5)
|
|
||||||
->get();
|
|
||||||
|
|
||||||
$latestHards = DB::table('operator_que')
|
|
||||||
->where('que_status',1)
|
|
||||||
->where('que_class','>',99)
|
|
||||||
->orderByDesc('created_at')
|
|
||||||
->limit(5)
|
|
||||||
->get();
|
|
||||||
|
|
||||||
$view->with(compact(
|
|
||||||
'taskCount','taskLatest',
|
|
||||||
'hardCount','hardLatest',
|
|
||||||
'latestTasks','latestHards'
|
|
||||||
));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,4 +42,3 @@ class LegacyServiceProvider extends ServiceProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -32,5 +32,3 @@ class FileService
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -25,5 +25,3 @@ class OperatorQueService
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
406
app/Services/ShjFourCService.php
Normal file
406
app/Services/ShjFourCService.php
Normal file
@ -0,0 +1,406 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Models\Park;
|
||||||
|
use App\Models\RegularContract;
|
||||||
|
use App\Models\Batch\BatchLog;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHJ-4C 室割当処理サービス
|
||||||
|
*
|
||||||
|
* ゾーン情報取得及び割当処理を実行するビジネスロジック
|
||||||
|
* バッチ処理「SHJ-4C室割当」の核となる処理を担当
|
||||||
|
*/
|
||||||
|
class ShjFourCService
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Park モデル
|
||||||
|
*
|
||||||
|
* @var Park
|
||||||
|
*/
|
||||||
|
protected $parkModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RegularContract モデル
|
||||||
|
*
|
||||||
|
* @var RegularContract
|
||||||
|
*/
|
||||||
|
protected $contractModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BatchLog モデル
|
||||||
|
*
|
||||||
|
* @var BatchLog
|
||||||
|
*/
|
||||||
|
protected $batchLogModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* コンストラクタ
|
||||||
|
*
|
||||||
|
* @param Park $parkModel
|
||||||
|
* @param RegularContract $contractModel
|
||||||
|
* @param BatchLog $batchLogModel
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
Park $parkModel,
|
||||||
|
RegularContract $contractModel,
|
||||||
|
BatchLog $batchLogModel
|
||||||
|
) {
|
||||||
|
$this->parkModel = $parkModel;
|
||||||
|
$this->contractModel = $contractModel;
|
||||||
|
$this->batchLogModel = $batchLogModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHJ-4C 室割当処理メイン実行
|
||||||
|
*
|
||||||
|
* 処理フロー:
|
||||||
|
* 【処理1】ゾーン情報取得
|
||||||
|
* 【判断1】割当判定
|
||||||
|
* 【処理2】バッチログ作成
|
||||||
|
* 【処理3】処理結果返却
|
||||||
|
*
|
||||||
|
* @param int $parkId 駐輪場ID
|
||||||
|
* @param int $ptypeId 駐輪分類ID
|
||||||
|
* @param int $psectionId 車種区分ID
|
||||||
|
* @return array 処理結果
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
|
||||||
|
Log::info('SHJ-4C 室割当処理開始', [
|
||||||
|
'batch_log_id' => $batchLogId,
|
||||||
|
'park_id' => $parkId,
|
||||||
|
'ptype_id' => $ptypeId,
|
||||||
|
'psection_id' => $psectionId
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 【処理1】ゾーン情報取得
|
||||||
|
$zoneInfo = $this->getZoneInformation($parkId, $ptypeId, $psectionId);
|
||||||
|
|
||||||
|
if (empty($zoneInfo)) {
|
||||||
|
$message = '対象のゾーン情報が見つかりません';
|
||||||
|
|
||||||
|
// バッチログ更新(通用方法使用)
|
||||||
|
$batchLog->update([
|
||||||
|
'status' => BatchLog::STATUS_ERROR,
|
||||||
|
'end_time' => now(),
|
||||||
|
'message' => $message,
|
||||||
|
'error_details' => $message,
|
||||||
|
'error_count' => 1
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => $message,
|
||||||
|
'batch_log_id' => $batchLogId
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 【判断1】割当判定処理
|
||||||
|
$allocationResult = $this->performAllocationJudgment($zoneInfo, $parkId, $ptypeId, $psectionId);
|
||||||
|
|
||||||
|
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のため
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => true,
|
||||||
|
'message' => '割当判定完了(割当NG)',
|
||||||
|
'allocation_result' => $allocationResult,
|
||||||
|
'batch_log_id' => $batchLogId
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 【処理2】割当実行(割当OKの場合)
|
||||||
|
$executionResult = $this->executeAllocation($zoneInfo, $allocationResult);
|
||||||
|
|
||||||
|
// バッチ処理完了ログ更新
|
||||||
|
$batchLog->update([
|
||||||
|
'status' => BatchLog::STATUS_SUCCESS,
|
||||||
|
'end_time' => now(),
|
||||||
|
'message' => 'SHJ-4C 室割当処理正常完了',
|
||||||
|
'success_count' => 1
|
||||||
|
]);
|
||||||
|
|
||||||
|
Log::info('SHJ-4C 室割当処理完了', [
|
||||||
|
'batch_log_id' => $batchLogId,
|
||||||
|
'execution_result' => $executionResult
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 【処理3】処理結果返却
|
||||||
|
return [
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'SHJ-4C 室割当処理が正常に完了しました',
|
||||||
|
'zone_info' => $zoneInfo,
|
||||||
|
'allocation_result' => $allocationResult,
|
||||||
|
'execution_result' => $executionResult,
|
||||||
|
'batch_log_id' => $batchLogId
|
||||||
|
];
|
||||||
|
|
||||||
|
} 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
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::error('SHJ-4C 室割当処理エラー', [
|
||||||
|
'batch_log_id' => $batchLogId,
|
||||||
|
'exception' => $e->getMessage(),
|
||||||
|
'trace' => $e->getTraceAsString()
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => $errorMessage,
|
||||||
|
'details' => $e->getMessage(),
|
||||||
|
'batch_log_id' => $batchLogId
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【処理1】ゾーン情報取得
|
||||||
|
*
|
||||||
|
* 駐輪場ID、駐輪分類ID、車種区分IDに紐づくゾーン情報を取得する
|
||||||
|
* SQLクエリは設計書の仕様に基づく
|
||||||
|
*
|
||||||
|
* @param int $parkId 駐輪場ID
|
||||||
|
* @param int $ptypeId 駐輪分類ID
|
||||||
|
* @param int $psectionId 車種区分ID
|
||||||
|
* @return array ゾーン情報
|
||||||
|
*/
|
||||||
|
private function getZoneInformation(int $parkId, int $ptypeId, int $psectionId): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// 設計書に記載されたSQLクエリに基づくゾーン情報取得
|
||||||
|
$zoneInfo = DB::table('zone as T1')
|
||||||
|
->select([
|
||||||
|
'T1.zone_id',
|
||||||
|
'T1.zone_name',
|
||||||
|
'T1.zone_contracted_count as zone_contracted_count',
|
||||||
|
'T1.zone_capacity as zone_capacity',
|
||||||
|
'T1.zone_permitted_count as zone_permitted_count',
|
||||||
|
'T1.zone_sort',
|
||||||
|
'T2.update_grace_period_start_date',
|
||||||
|
'T2.update_grace_period_end_date'
|
||||||
|
])
|
||||||
|
->join('park as T2', 'T1.park_id', '=', 'T2.park_id')
|
||||||
|
->where('T1.park_id', $parkId)
|
||||||
|
->where('T1.ptype_id', $ptypeId)
|
||||||
|
->where('T1.psection_id', $psectionId)
|
||||||
|
->where('T1.delete_flag', 0)
|
||||||
|
->orderBy('T1.zone_sort')
|
||||||
|
->get()
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
Log::info('ゾーン情報取得完了', [
|
||||||
|
'park_id' => $parkId,
|
||||||
|
'ptype_id' => $ptypeId,
|
||||||
|
'psection_id' => $psectionId,
|
||||||
|
'zone_count' => count($zoneInfo)
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $zoneInfo;
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('ゾーン情報取得エラー', [
|
||||||
|
'park_id' => $parkId,
|
||||||
|
'ptype_id' => $ptypeId,
|
||||||
|
'psection_id' => $psectionId,
|
||||||
|
'error' => $e->getMessage()
|
||||||
|
]);
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【判断1】割当判定処理
|
||||||
|
*
|
||||||
|
* ゾーン内の定期契約マスタから該当レコード数を取得し、
|
||||||
|
* 定期契約マスタから最適な車室番号を選定する割当判定を実行
|
||||||
|
*
|
||||||
|
* @param array $zoneInfo ゾーン情報
|
||||||
|
* @param int $parkId 駐輪場ID
|
||||||
|
* @param int $ptypeId 駐輪分類ID
|
||||||
|
* @param int $psectionId 車種区分ID
|
||||||
|
* @return array 割当判定結果
|
||||||
|
*/
|
||||||
|
private function performAllocationJudgment(array $zoneInfo, int $parkId, int $ptypeId, int $psectionId): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
foreach ($zoneInfo as $zone) {
|
||||||
|
// 各ゾーンに対する定期契約情報取得
|
||||||
|
$contractInfo = $this->getRegularContractInfo($parkId, $zone->zone_id, $ptypeId, $psectionId);
|
||||||
|
|
||||||
|
// 割当可能性判定
|
||||||
|
if ($this->canAllocateToZone($zone, $contractInfo)) {
|
||||||
|
return [
|
||||||
|
'can_allocate' => true,
|
||||||
|
'zone_id' => $zone->zone_id,
|
||||||
|
'zone_name' => $zone->zone_name,
|
||||||
|
'contract_info' => $contractInfo,
|
||||||
|
'reason' => '割当OK: ゾーンID ' . $zone->zone_id
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 全ゾーンで割当NGの場合
|
||||||
|
$targetRoomNumber = $this->generateTargetRoomNumber($parkId, $ptypeId, $psectionId);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'can_allocate' => false,
|
||||||
|
'target_room_number' => $targetRoomNumber,
|
||||||
|
'reason' => '全ゾーンで割当できませんでした'
|
||||||
|
];
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('割当判定処理エラー', [
|
||||||
|
'error' => $e->getMessage()
|
||||||
|
]);
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定期契約情報取得
|
||||||
|
*
|
||||||
|
* 設計書のSQLクエリに基づく定期契約マスタ検索
|
||||||
|
*
|
||||||
|
* @param int $parkId 駐輪場ID
|
||||||
|
* @param int $zoneId ゾーンID
|
||||||
|
* @param int $ptypeId 駐輪分類ID
|
||||||
|
* @param int $psectionId 車種区分ID
|
||||||
|
* @return array 定期契約情報
|
||||||
|
*/
|
||||||
|
private function getRegularContractInfo(int $parkId, int $zoneId, int $ptypeId, int $psectionId): array
|
||||||
|
{
|
||||||
|
$currentDate = Carbon::now()->format('Y-m-d');
|
||||||
|
|
||||||
|
$contractInfo = DB::table('regular_contract as T1')
|
||||||
|
->select(['T1.contract_id'])
|
||||||
|
->where('T1.park_id', $parkId)
|
||||||
|
->where('T1.zone_id', $zoneId)
|
||||||
|
->where('T1.ptype_id', $ptypeId)
|
||||||
|
->where('T1.psection_id', $psectionId)
|
||||||
|
->where('T1.place_no', '!=', '')
|
||||||
|
->where(function ($query) use ($currentDate) {
|
||||||
|
$query->where(function ($subQuery) use ($currentDate) {
|
||||||
|
// パターンA: 処理1.更新期間開始日 <= 処理1.更新期間終了日 の場合
|
||||||
|
$subQuery->whereRaw("date_format(now(), '%y-%m-%d') >= date_format(now(), '%y-%m-%d')")
|
||||||
|
->whereRaw("date_format(now(), '%y-%m-%d') <= date_format(now(), '%y-%m-%d')");
|
||||||
|
})
|
||||||
|
->orWhere(function ($subQuery) use ($currentDate) {
|
||||||
|
// パターンB: その他の場合
|
||||||
|
$subQuery->whereRaw("date_format(now(), '%y-%m-%d') >= date_format(now(), '%y-%m-%d')");
|
||||||
|
});
|
||||||
|
})
|
||||||
|
->where('T1.contract_flag', 1)
|
||||||
|
->get()
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
return $contractInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ゾーン割当可能性判定
|
||||||
|
*
|
||||||
|
* @param object $zone ゾーン情報
|
||||||
|
* @param array $contractInfo 契約情報
|
||||||
|
* @return bool 割当可能かどうか
|
||||||
|
*/
|
||||||
|
private function canAllocateToZone($zone, array $contractInfo): bool
|
||||||
|
{
|
||||||
|
$contractedCount = count($contractInfo);
|
||||||
|
$capacity = $zone->zone_capacity;
|
||||||
|
|
||||||
|
// 空きがある場合は割当可能
|
||||||
|
return $contractedCount < $capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 対象事室番号生成
|
||||||
|
*
|
||||||
|
* @param int $parkId 駐輪場ID
|
||||||
|
* @param int $ptypeId 駐輪分類ID
|
||||||
|
* @param int $psectionId 車種区分ID
|
||||||
|
* @return string 対象事室番号
|
||||||
|
*/
|
||||||
|
private function generateTargetRoomNumber(int $parkId, int $ptypeId, int $psectionId): string
|
||||||
|
{
|
||||||
|
return sprintf('%d_%d_%d', $parkId, $ptypeId, $psectionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 対象事室番号設定
|
||||||
|
*
|
||||||
|
* @param string $targetRoomNumber 対象事室番号
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function setTargetRoomNumber(string $targetRoomNumber): void
|
||||||
|
{
|
||||||
|
Log::info('対象事室番号設定', [
|
||||||
|
'target_room_number' => $targetRoomNumber
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 実際の事室番号設定ロジックをここに実装
|
||||||
|
// 具体的な仕様が必要な場合は後で追加実装
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 割当実行
|
||||||
|
*
|
||||||
|
* @param array $zoneInfo ゾーン情報
|
||||||
|
* @param array $allocationResult 割当判定結果
|
||||||
|
* @return array 実行結果
|
||||||
|
*/
|
||||||
|
private function executeAllocation(array $zoneInfo, array $allocationResult): array
|
||||||
|
{
|
||||||
|
// 割当実行の具体的なロジックを実装
|
||||||
|
// 設計書に詳細仕様があれば追加実装
|
||||||
|
|
||||||
|
return [
|
||||||
|
'executed' => true,
|
||||||
|
'zone_id' => $allocationResult['zone_id'],
|
||||||
|
'message' => '割当実行完了'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
443
app/Services/ShjMailSendService.php
Normal file
443
app/Services/ShjMailSendService.php
Normal file
@ -0,0 +1,443 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHJ メール送信処理サービス
|
||||||
|
*
|
||||||
|
* メールテンプレートを使用したメール送信処理を実行するビジネスロジック
|
||||||
|
* バッチ処理「SHJメール送信」の核となる処理を担当
|
||||||
|
*/
|
||||||
|
class ShjMailSendService
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* MailTemplate モデル
|
||||||
|
*
|
||||||
|
* @var MailTemplate
|
||||||
|
*/
|
||||||
|
protected $mailTemplateModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BatchLog モデル
|
||||||
|
*
|
||||||
|
* @var BatchLog
|
||||||
|
*/
|
||||||
|
protected $batchLogModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* コンストラクタ
|
||||||
|
*
|
||||||
|
* @param MailTemplate $mailTemplateModel
|
||||||
|
* @param BatchLog $batchLogModel
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
MailTemplate $mailTemplateModel,
|
||||||
|
BatchLog $batchLogModel
|
||||||
|
) {
|
||||||
|
$this->mailTemplateModel = $mailTemplateModel;
|
||||||
|
$this->batchLogModel = $batchLogModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHJ メール送信処理メイン実行
|
||||||
|
*
|
||||||
|
* 処理フロー:
|
||||||
|
* 【処理1】入力パラメーターをチェックする
|
||||||
|
* 【処理2】メール送信テンプレート情報を取得する
|
||||||
|
* 【判断2】取得結果判定
|
||||||
|
* 【処理3】メールを送信する
|
||||||
|
* 【処理4】処理結果を返却する
|
||||||
|
*
|
||||||
|
* @param string $mailAddress メールアドレス
|
||||||
|
* @param string $backupMailAddress 予備メールアドレス
|
||||||
|
* @param int $mailTemplateId メールテンプレートID
|
||||||
|
* @return array 処理結果
|
||||||
|
*/
|
||||||
|
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,
|
||||||
|
'mail_address' => $mailAddress,
|
||||||
|
'backup_mail_address' => $backupMailAddress,
|
||||||
|
'mail_template_id' => $mailTemplateId
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 【処理1】入力パラメーターをチェックする
|
||||||
|
$paramCheckResult = $this->checkInputParameters($mailAddress, $backupMailAddress, $mailTemplateId);
|
||||||
|
if (!$paramCheckResult['valid']) {
|
||||||
|
$this->updateBatchLog($batchLogId, 'error', $paramCheckResult['message']);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'result_code' => 1, // 異常終了
|
||||||
|
'message' => $paramCheckResult['message'],
|
||||||
|
'batch_log_id' => $batchLogId
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 【処理2】メール送信テンプレート情報を取得する
|
||||||
|
$templateInfo = $this->getMailTemplateInfo($mailTemplateId);
|
||||||
|
|
||||||
|
// 【判断2】取得結果判定
|
||||||
|
if (empty($templateInfo)) {
|
||||||
|
$message = "メールテンプレートが存在しません。テンプレートID: {$mailTemplateId}";
|
||||||
|
$this->updateBatchLog($batchLogId, 'error', $message);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'result_code' => 1, // 異常終了
|
||||||
|
'message' => $message,
|
||||||
|
'batch_log_id' => $batchLogId
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 【処理3】メールを送信する
|
||||||
|
$mailSendResult = $this->sendMail($mailAddress, $backupMailAddress, $templateInfo);
|
||||||
|
|
||||||
|
if (!$mailSendResult['success']) {
|
||||||
|
$this->updateBatchLog($batchLogId, 'error', $mailSendResult['message']);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'result_code' => 1, // 異常終了
|
||||||
|
'message' => $mailSendResult['message'],
|
||||||
|
'batch_log_id' => $batchLogId
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// バッチ処理完了ログ更新
|
||||||
|
$this->updateBatchLog($batchLogId, 'success', 'SHJ メール送信処理正常完了');
|
||||||
|
|
||||||
|
Log::info('SHJ メール送信処理完了', [
|
||||||
|
'batch_log_id' => $batchLogId,
|
||||||
|
'mail_send_result' => $mailSendResult
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 【処理4】処理結果を返却する
|
||||||
|
return [
|
||||||
|
'success' => true,
|
||||||
|
'result_code' => 0, // 正常終了
|
||||||
|
'message' => 'SHJ メール送信処理が正常に完了しました',
|
||||||
|
'mail_send_result' => $mailSendResult,
|
||||||
|
'batch_log_id' => $batchLogId
|
||||||
|
];
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$errorMessage = 'SHJ メール送信処理でエラーが発生: ' . $e->getMessage();
|
||||||
|
|
||||||
|
if ($batchLogId) {
|
||||||
|
$this->updateBatchLog($batchLogId, 'error', $errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::error('SHJ メール送信処理エラー', [
|
||||||
|
'batch_log_id' => $batchLogId,
|
||||||
|
'exception' => $e->getMessage(),
|
||||||
|
'trace' => $e->getTraceAsString()
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'result_code' => 1, // 異常終了
|
||||||
|
'message' => $errorMessage,
|
||||||
|
'details' => $e->getMessage(),
|
||||||
|
'batch_log_id' => $batchLogId
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【処理1】入力パラメーターをチェックする
|
||||||
|
*
|
||||||
|
* 仕様書に基づく詳細チェック:
|
||||||
|
* - メールアドレス形式チェック
|
||||||
|
* - テンプレートID存在性チェック
|
||||||
|
*
|
||||||
|
* @param string $mailAddress メールアドレス
|
||||||
|
* @param string $backupMailAddress 予備メールアドレス
|
||||||
|
* @param int $mailTemplateId メールテンプレートID
|
||||||
|
* @return array チェック結果
|
||||||
|
*/
|
||||||
|
private function checkInputParameters(string $mailAddress, string $backupMailAddress, int $mailTemplateId): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// メールアドレス存在チェック(いずれか必須)
|
||||||
|
if (empty($mailAddress) && empty($backupMailAddress)) {
|
||||||
|
return [
|
||||||
|
'valid' => false,
|
||||||
|
'message' => 'パラメーターNG: メールアドレスまたは予備メールアドレスのいずれかは必須です'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// メールアドレス形式チェック
|
||||||
|
if (!empty($mailAddress) && !filter_var($mailAddress, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
return [
|
||||||
|
'valid' => false,
|
||||||
|
'message' => 'パラメーターNG: メールアドレスの形式が正しくありません'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($backupMailAddress) && !filter_var($backupMailAddress, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
return [
|
||||||
|
'valid' => false,
|
||||||
|
'message' => 'パラメーターNG: 予備メールアドレスの形式が正しくありません'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// メールテンプレートID形式チェック
|
||||||
|
if ($mailTemplateId <= 0) {
|
||||||
|
return [
|
||||||
|
'valid' => false,
|
||||||
|
'message' => 'パラメーターNG: メールテンプレートIDは正の整数である必要があります'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::info('入力パラメーターチェック完了', [
|
||||||
|
'mail_address' => $mailAddress,
|
||||||
|
'backup_mail_address' => $backupMailAddress,
|
||||||
|
'mail_template_id' => $mailTemplateId
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'valid' => true,
|
||||||
|
'message' => 'パラメーターチェックOK'
|
||||||
|
];
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('入力パラメーターチェックエラー', [
|
||||||
|
'error' => $e->getMessage()
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'valid' => false,
|
||||||
|
'message' => 'パラメーターチェック中にエラーが発生しました: ' . $e->getMessage()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【処理2】メール送信テンプレート情報を取得する
|
||||||
|
*
|
||||||
|
* 仕様書に基づくSQLクエリ:
|
||||||
|
* SELECT エリアマネージャー同報, bccアドレス, 件名, 本文
|
||||||
|
* FROM メール送信テンプレート
|
||||||
|
* WHERE 使用プログラムID = 入力パラメーター使用プログラムID
|
||||||
|
* AND 使用フラグ = 1
|
||||||
|
*
|
||||||
|
* @param int $mailTemplateId メールテンプレートID(使用プログラムIDとして扱う)
|
||||||
|
* @return MailTemplate|null メールテンプレート情報
|
||||||
|
*/
|
||||||
|
private function getMailTemplateInfo(int $mailTemplateId): ?MailTemplate
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// 仕様書に記載されたSQLクエリに基づくメールテンプレート情報取得
|
||||||
|
// 注意: 仕様書では「使用プログラムID」を条件にしているが、
|
||||||
|
// 入力パラメーターは「メールテンプレートID」なので、pg_idで検索
|
||||||
|
$templateInfo = $this->mailTemplateModel::where('pg_id', $mailTemplateId)
|
||||||
|
->where('use_flag', 1)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if ($templateInfo) {
|
||||||
|
Log::info('メールテンプレート情報取得完了', [
|
||||||
|
'mail_template_id' => $mailTemplateId,
|
||||||
|
'template_found' => true,
|
||||||
|
'subject' => $templateInfo->getSubject()
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
Log::warning('メールテンプレート情報取得結果', [
|
||||||
|
'mail_template_id' => $mailTemplateId,
|
||||||
|
'template_found' => false,
|
||||||
|
'message' => 'テンプレートが見つかりません'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $templateInfo;
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('メールテンプレート情報取得エラー', [
|
||||||
|
'mail_template_id' => $mailTemplateId,
|
||||||
|
'error' => $e->getMessage()
|
||||||
|
]);
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【処理3】メールを送信する
|
||||||
|
*
|
||||||
|
* 仕様書に基づくmb_send_mail関数使用:
|
||||||
|
* - 送信者: 処理2で取得したメールアドレス(処理1で予備メールアドレス)
|
||||||
|
* - タイトル: 処理2で取得したタイトル
|
||||||
|
* - 本文: 処理2で取得した本文(※現在の文字列は「So-Manager一般的なWebサイト内部処理」参照)
|
||||||
|
* - 追加ヘッダ: 処理2で取得したbccアドレス(※値が設定されている場合のみ)
|
||||||
|
*
|
||||||
|
* @param string $mailAddress メールアドレス
|
||||||
|
* @param string $backupMailAddress 予備メールアドレス
|
||||||
|
* @param MailTemplate $templateInfo テンプレート情報
|
||||||
|
* @return array 送信結果
|
||||||
|
*/
|
||||||
|
private function sendMail(string $mailAddress, string $backupMailAddress, MailTemplate $templateInfo): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// 送信先アドレス決定(優先: メールアドレス、代替: 予備メールアドレス)
|
||||||
|
$toAddress = !empty($mailAddress) ? $mailAddress : $backupMailAddress;
|
||||||
|
|
||||||
|
// メール内容取得
|
||||||
|
$subject = $templateInfo->getSubject() ?? '';
|
||||||
|
$message = $templateInfo->getText() ?? '';
|
||||||
|
|
||||||
|
// 追加ヘッダ設定
|
||||||
|
$headers = $this->buildMailHeaders($templateInfo);
|
||||||
|
|
||||||
|
Log::info('メール送信準備完了', [
|
||||||
|
'to_address' => $toAddress,
|
||||||
|
'subject' => $subject,
|
||||||
|
'has_bcc' => !empty($templateInfo->getBccAddress()),
|
||||||
|
'manager_cc_enabled' => $templateInfo->isManagerCcEnabled()
|
||||||
|
]);
|
||||||
|
|
||||||
|
// mb_send_mail関数を使用してメール送信
|
||||||
|
$sendResult = mb_send_mail(
|
||||||
|
$toAddress, // 送信先
|
||||||
|
$subject, // 件名
|
||||||
|
$message, // 本文
|
||||||
|
$headers // 追加ヘッダ
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($sendResult) {
|
||||||
|
Log::info('メール送信成功', [
|
||||||
|
'to_address' => $toAddress,
|
||||||
|
'subject' => $subject
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'メール送信が正常に完了しました',
|
||||||
|
'to_address' => $toAddress,
|
||||||
|
'subject' => $subject
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$errorMessage = 'mb_send_mail関数でメール送信に失敗しました';
|
||||||
|
Log::error('メール送信失敗', [
|
||||||
|
'to_address' => $toAddress,
|
||||||
|
'subject' => $subject,
|
||||||
|
'error' => $errorMessage
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => $errorMessage
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$errorMessage = 'メール送信中にエラーが発生: ' . $e->getMessage();
|
||||||
|
Log::error('メール送信エラー', [
|
||||||
|
'error' => $e->getMessage(),
|
||||||
|
'trace' => $e->getTraceAsString()
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => $errorMessage
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* メールヘッダを構築
|
||||||
|
*
|
||||||
|
* 仕様書に基づく設定:
|
||||||
|
* - BCCアドレス: 値が設定されている場合のみ追加
|
||||||
|
* - エリアマネージャー同報: フラグが有効な場合の処理
|
||||||
|
*
|
||||||
|
* @param MailTemplate $templateInfo テンプレート情報
|
||||||
|
* @return string メールヘッダ
|
||||||
|
*/
|
||||||
|
private function buildMailHeaders(MailTemplate $templateInfo): string
|
||||||
|
{
|
||||||
|
$headers = [];
|
||||||
|
|
||||||
|
// BCCアドレス設定(値が設定されている場合のみ)
|
||||||
|
$bccAddress = $templateInfo->getBccAddress();
|
||||||
|
if (!empty($bccAddress)) {
|
||||||
|
$headers[] = "Bcc: {$bccAddress}";
|
||||||
|
}
|
||||||
|
|
||||||
|
// エリアマネージャー同報フラグが有効な場合
|
||||||
|
// ※具体的な処理内容は仕様書に詳細がないため、ログ出力のみ
|
||||||
|
if ($templateInfo->isManagerCcEnabled()) {
|
||||||
|
Log::info('エリアマネージャー同報フラグが有効です', [
|
||||||
|
'mail_template_id' => $templateInfo->mail_template_id
|
||||||
|
]);
|
||||||
|
// 実際のエリアマネージャーアドレス取得・設定処理は追加仕様が必要
|
||||||
|
}
|
||||||
|
|
||||||
|
// From設定(システム設定から取得)
|
||||||
|
$fromAddress = config('mail.from.address', 'noreply@so-manager.com');
|
||||||
|
$headers[] = "From: {$fromAddress}";
|
||||||
|
|
||||||
|
// Content-Type設定(日本語対応)
|
||||||
|
$headers[] = "Content-Type: text/plain; charset=UTF-8";
|
||||||
|
|
||||||
|
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
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -53,5 +53,3 @@ class UserService
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -16,58 +16,56 @@ class UsingStatusService
|
|||||||
/**
|
/**
|
||||||
* 駐輪場別利用率統計を取得
|
* 駐輪場別利用率統計を取得
|
||||||
*
|
*
|
||||||
* 取得元:
|
|
||||||
* - 限界収容台数: park_number.park_limit
|
|
||||||
* - 現在収容台数: park_number.park_number
|
|
||||||
* - 空き : park_number.park_limit - park_number.park_number
|
|
||||||
* - 利用率 : (現在収容台数 / 限界収容台数) * 100
|
|
||||||
*
|
|
||||||
* @param int|null $parkId 駐輪場ID(null の場合は全て)
|
* @param int|null $parkId 駐輪場ID(null の場合は全て)
|
||||||
* @return Collection
|
* @return Collection 統計データのコレクション
|
||||||
*/
|
*/
|
||||||
public function getUtilizationStats(?int $parkId = null): \Illuminate\Support\Collection
|
public function getUtilizationStats(?int $parkId = null): Collection
|
||||||
{
|
{
|
||||||
// park_number に車種IDが ptype_id で入っている前提
|
// 暫定的な収容台数(実DBに無いカラムのため)
|
||||||
// 異なる場合は 'pn.ptype_id' 部分を実テーブル定義に合わせて変更してください
|
$defaultCapacity = [
|
||||||
|
1 => 100, // 自転車
|
||||||
|
2 => 50, // 原付
|
||||||
|
3 => 30, // その他
|
||||||
|
];
|
||||||
|
|
||||||
// ✅ Laravel 12対応:psectionテーブルから車種を取得するように変更
|
$query = DB::table('park as p')
|
||||||
$query = \DB::table('park as p')
|
->leftJoin('price_a as pr', 'p.park_id', '=', 'pr.park_id')
|
||||||
->join('park_number as pn', 'p.park_id', '=', 'pn.park_id')
|
->leftJoin('ptype as pt', 'pr.price_ptypeid', '=', 'pt.ptype_id')
|
||||||
// 旧: join('ptype as pt', 'pn.ptype_id', '=', 'pt.ptype_id')
|
->leftJoin('regular_contract as rc', function ($join) {
|
||||||
->leftJoin('psection as ps', 'pn.psection_id', '=', 'ps.psection_id') // ✅ 新しい車種取得方法
|
$join->on('pr.price_parkplaceid', '=', 'rc.price_parkplaceid')
|
||||||
|
->where('rc.contract_cancel_flag', '=', 0);
|
||||||
|
})
|
||||||
->select([
|
->select([
|
||||||
'p.park_id',
|
'p.park_id',
|
||||||
'p.park_name',
|
'p.park_name',
|
||||||
// 'pt.ptype_id',
|
'pt.ptype_id',
|
||||||
// 'pt.ptype_subject',
|
'pt.ptype_subject',
|
||||||
'ps.psection_subject', // 車種(psection_subject)に変更
|
DB::raw('COUNT(rc.contract_id) as current_count'),
|
||||||
// 限界収容台数
|
|
||||||
'pn.park_limit',
|
|
||||||
// 現在収容台数
|
|
||||||
\DB::raw('COALESCE(pn.park_number, 0) as current_count'),
|
|
||||||
// 空き = 収容上限 - 現在
|
|
||||||
\DB::raw('GREATEST(0, COALESCE(pn.park_limit, 0) - COALESCE(pn.park_number, 0)) as available'),
|
|
||||||
// 利用率 = 現在 / 上限 * 100
|
|
||||||
\DB::raw("CASE
|
|
||||||
WHEN COALESCE(pn.park_limit, 0) > 0
|
|
||||||
THEN ROUND((COALESCE(pn.park_number, 0) / pn.park_limit) * 100, 1)
|
|
||||||
ELSE 0
|
|
||||||
END as usage_rate"),
|
|
||||||
])
|
])
|
||||||
|
->whereNotNull('pr.price_parkplaceid')
|
||||||
|
->whereNotNull('pt.ptype_id')
|
||||||
->where('p.park_close_flag', '!=', 1);
|
->where('p.park_close_flag', '!=', 1);
|
||||||
|
|
||||||
if (!empty($parkId)) {
|
if ($parkId) {
|
||||||
$query->where('p.park_id', $parkId);
|
$query->where('p.park_id', $parkId);
|
||||||
}
|
}
|
||||||
|
|
||||||
$results = $query
|
$results = $query
|
||||||
// 表示順:自転車 → 原付 → その他
|
->groupBy(['p.park_id', 'p.park_name', 'pt.ptype_id', 'pt.ptype_subject'])
|
||||||
->orderByRaw("CASE ps.psection_subject WHEN '自転車' THEN 1 WHEN '原付' THEN 2 ELSE 3 END")
|
|
||||||
->orderBy('p.park_name')
|
->orderBy('p.park_name')
|
||||||
|
->orderBy('pt.ptype_subject')
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
|
// 後計算で容量・空き・利用率を付与
|
||||||
|
foreach ($results as $result) {
|
||||||
|
$capacity = $defaultCapacity[$result->ptype_id] ?? 50;
|
||||||
|
$result->park_limit = $capacity;
|
||||||
|
$result->available = $capacity - $result->current_count;
|
||||||
|
$result->usage_rate = $capacity > 0 ? round(($result->current_count / $capacity * 100), 1) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
return $results;
|
return $results;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 駐輪場一覧を取得(選択用)
|
* 駐輪場一覧を取得(選択用)
|
||||||
|
|||||||
@ -26,5 +26,3 @@ class Csv
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -28,5 +28,3 @@ class Files
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user