so-manager-dev.com/app/Http/Controllers/RegularContractCreateController.php

1146 lines
50 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Http\Controllers;
use App\Http\Traits\AuthenticatesUser;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\Artisan;
use Exception;
use function redirect;
use Carbon\Carbon;
class RegularContractCreateController extends Controller
{
use AuthenticatesUser;
/**
* 駐輪場選択画面を表示
*
* @param Request $request
* @return \Illuminate\View\View|\Illuminate\Http\RedirectResponse
*/
public function show(Request $request)
{
if ($redirect = $this->handleSessionExpired('駐輪場選択')) {
return $redirect;
}
$userId = session('user_id');
$user = DB::table('user')->where('user_id', $userId)->first();
// マルチテナント対応のため、運営元情報をセッションから取得
$management = session('management');
if (!$management) {
\Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " 運営元情報が見つからない user_id=" . $userId);
abort(404);
}
// 検索条件・ページング取得
$cityId = $request->input('city_id');
$stationName = $request->input('station_neighbor_station');
$parkId = $request->input('park_id');
$page = (int)$request->input('page', 1);
$perPage = 10;
// ルート名で画面種別判定(新規定期契約 or 駐輪場検索)
$isRegularContract = $request->route()->getName() === 'regular_contract.create';
$activeMenu = $isRegularContract ? 'SWC-8-1' : 'SWC-10-1';
// マスタデータ取得(運営元フィルタ適用)
$cities = $this->getCitiesList($management->management_id);
$stations = $this->getStationsList($management->management_id);
$parks = $this->getParksList($management->management_id);
// 運営元が取り扱う車種一覧を取得
$availableVehicles = $this->getAvailableVehicles($management->management_id);
// 駐輪場テーブルデータ取得(検索・ページング、運営元フィルタ適用)
$parksTableData = $this->getParksTableData($management->management_id, $cityId, $stationName, $parkId, $page, $perPage);
// zone・reserve マスタ取得(運営元フィルタ適用)
$zones = $this->getZonesByParkId($management->management_id);
$reserve = $this->getReserveByParkId($management->management_id);
// 駐輪場ごとの更新可能期間取得(運営元フィルタ適用)
$parkGracePeriods = $this->getParkGracePeriods($management->management_id);
// 駐輪場ごと・車種ごとの状態を事前計算
$parksTableData['data'] = $this->calculateVehicleStatus(
$parksTableData['data'],
$zones,
$reserve,
$parkGracePeriods,
$availableVehicles
);
// アクセスログ記録
$screenName = $isRegularContract ? '新規定期契約登録' : '駐輪場検索';
\Log::info("[INFO] " . now()->format('Y-m-d H:i:s') . " {$screenName}画面アクセス user_id=" . $userId . ", management_id=" . $management->management_id . ", city_id=" . ($cityId ?? 'null') . ", park_id=" . ($parkId ?? 'null'));
return view('regular_contract.create', [
'active_menu' => $activeMenu,
'user_name' => $user->user_name ?? '',
'cities' => $cities,
'stations' => $stations,
'parks' => $parks,
'parks_table' => $parksTableData['data'],
'parks_table_total' => $parksTableData['total'],
'parks_table_page' => $page,
'parks_table_perPage' => $perPage,
'available_vehicles' => $availableVehicles,
'reserve' => $reserve,
'isRegularContract' => $isRegularContract,
]);
}
/**
* 市町村一覧取得(運営元フィルタ適用)
* マルチテナント対応のため、運営元に紐づく駐輪場の市町村のみ表示
*
* @param int $managementId
* @return \Illuminate\Support\Collection
*/
private function getCitiesList(int $managementId)
{
try {
return DB::table('park')
->join('city', 'park.city_id', '=', 'city.city_id')
->where('park.management_id', $managementId)
->select('city.city_id', 'city.city_name')
->distinct()
->get();
} catch (\Exception $e) {
\Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " 市町村一覧取得失敗 management_id=" . $managementId . ", error=" . $e->getMessage());
return collect();
}
}
/**
* 駅名一覧取得(運営元フィルタ適用)
*
* マルチテナント対応のため、運営元に紐づく駐輪場の駅のみ表示する。
*
* @param int $managementId
* @return \Illuminate\Support\Collection
*/
private function getStationsList(int $managementId)
{
try {
return DB::table('station')
->join('park', 'station.park_id', '=', 'park.park_id')
->where('park.management_id', $managementId)
->select('station.station_neighbor_station')
->distinct()
->get();
} catch (\Exception $e) {
\Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " 駅名一覧取得失敗 management_id=" . $managementId . ", error=" . $e->getMessage());
return collect();
}
}
/**
* 駐輪場名一覧取得(運営元フィルタ適用)
*
* マルチテナント対応のため、運営元に紐づく駐輪場のみ表示する。
*
* @param int $managementId
* @return \Illuminate\Support\Collection
*/
private function getParksList(int $managementId)
{
try {
return DB::table('park')
->where('management_id', $managementId)
->select('park_id', 'park_name')
->distinct()
->get();
} catch (\Exception $e) {
\Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " 駐輪場名一覧取得失敗 management_id=" . $managementId . ", error=" . $e->getMessage());
return collect();
}
}
/**
* 駐輪場テーブルデータ取得(検索・ページング適用、運営元フィルタ適用)
*
* マルチテナント対応のため、運営元に紐づく駐輪場のみ表示する。
*
* @param int $managementId
* @param int|null $cityId
* @param string|null $stationName
* @param int|null $parkId
* @param int $page
* @param int $perPage
* @return array ['data' => Collection, 'total' => int]
*/
private function getParksTableData(int $managementId, $cityId, $stationName, $parkId, int $page, int $perPage)
{
try {
$query = DB::table('park')
->join('city', 'park.city_id', '=', 'city.city_id')
->leftJoin('station', 'park.park_id', '=', 'station.park_id')
->where('park.management_id', $managementId)
->select(
'park.park_id',
'park.park_name',
'park.park_ruby',
'city.city_name',
'city.city_id',
'station.station_neighbor_station',
'station.station_name_ruby'
);
// 検索条件適用
if ($cityId) {
$query->where('city.city_id', $cityId);
}
if ($stationName) {
$query->where('station.station_neighbor_station', $stationName);
}
if ($parkId) {
$query->where('park.park_id', $parkId);
}
$query->orderBy('park.park_id', 'asc');
$total = $query->count();
// ページング適用
$data = $query
->skip(($page - 1) * $perPage)
->take($perPage)
->get();
\Log::info("[INFO] " . now()->format('Y-m-d H:i:s') . " 駐輪場データ取得成功 management_id=" . $managementId . ", 件数=" . $total . ", page=" . $page);
return [
'data' => $data,
'total' => $total,
];
} catch (\Exception $e) {
\Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " 駐輪場テーブルデータ取得失敗 management_id=" . $managementId . ", error=" . $e->getMessage());
return [
'data' => collect(),
'total' => 0,
];
}
}
/**
* ゾーンデータを park_id でグループ化して取得(運営元フィルタ適用)
*
* マルチテナント対応のため、運営元に紐づく駐輪場のゾーンのみ取得する。
*
* @param int $managementId
* @return \Illuminate\Support\Collection
*/
private function getZonesByParkId(int $managementId)
{
try {
return DB::table('zone')
->join('park', 'zone.park_id', '=', 'park.park_id')
->leftJoin('psection', 'zone.psection_id', '=', 'psection.psection_id')
->where('park.management_id', $managementId)
->select(
'zone.zone_id',
'zone.park_id',
'zone.ptype_id',
'zone.psection_id',
'zone.zone_number',
'zone.zone_tolerance',
'psection.psection_subject'
)
->get()
->groupBy('park_id');
} catch (\Exception $e) {
\Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " zone データ取得失敗 management_id=" . $managementId . ", error=" . $e->getMessage());
return collect();
}
}
/**
* 予約データを park_id でグループ化して取得(運営元フィルタ適用)
*
* マルチテナント対応のため、運営元に紐づく駐輪場の予約のみ取得する。
*
* @param int $managementId
* @return \Illuminate\Support\Collection
*/
private function getReserveByParkId(int $managementId)
{
try {
return DB::table('reserve')
->join('park', 'reserve.park_id', '=', 'park.park_id')
->where('park.management_id', $managementId)
->where('reserve.valid_flag', 1)
->select('reserve.reserve_id', 'reserve.park_id', 'reserve.ptype_id', 'reserve.psection_id')
->get()
->groupBy('park_id');
} catch (\Exception $e) {
\Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " reserve データ取得失敗 management_id=" . $managementId . ", error=" . $e->getMessage());
return collect();
}
}
/**
* 駐輪場ごとの更新可能期間を取得(運営元フィルタ適用)
*
*
* @param int $managementId
* @return \Illuminate\Support\Collection
*/
private function getParkGracePeriods(int $managementId)
{
try {
return DB::table('park')
->where('management_id', $managementId)
->select(
'park_id',
'update_grace_period_start_date',
'update_grace_period_start_time',
'update_grace_period_end_date',
'update_grace_period_end_time'
)
->get()
->keyBy('park_id');
} catch (\Exception $e) {
\Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " 駐輪場更新可能期間取得失敗 management_id=" . $managementId . ", error=" . $e->getMessage());
return collect();
}
}
/**
* 運営元が取り扱う車種一覧を取得
*
* マルチテナント対応のため、運営元ごとに表示する車種を可変にする。
*
* @param int $managementId
* @return array
*/
private function getAvailableVehicles(int $managementId)
{
try {
return DB::table('zone')
->join('park', 'zone.park_id', '=', 'park.park_id')
->leftJoin('psection', 'zone.psection_id', '=', 'psection.psection_id')
->where('park.management_id', $managementId)
->whereNotNull('psection.psection_subject')
->select('psection.psection_subject')
->distinct()
->orderByRaw("FIELD(psection.psection_subject, '自転車', '原付', '自動二輪', '自動車')")
->pluck('psection_subject')
->toArray();
} catch (\Exception $e) {
\Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " 取り扱い車種取得失敗 management_id=" . $managementId . ", error=" . $e->getMessage());
return [];
}
}
/**
* 駐輪場ごと・車種ごとの状態を計算
*
* @param \Illuminate\Support\Collection $parks
* @param \Illuminate\Support\Collection $zones
* @param \Illuminate\Support\Collection $reserve
* @param \Illuminate\Support\Collection $parkGracePeriods
* @param array $availableVehicles
* @return \Illuminate\Support\Collection
*/
private function calculateVehicleStatus($parks, $zones, $reserve, $parkGracePeriods, $availableVehicles)
{
$now = \Carbon\Carbon::now();
foreach ($parks as $park) {
$park->vehicle_status = [];
foreach ($availableVehicles as $vehicle) {
$zonesForType = ($zones[$park->park_id] ?? collect())->where('psection_subject', $vehicle);
// 空き台数計算
$hasVacancy = false;
foreach ($zonesForType as $zone) {
$reserveCount = ($reserve[$park->park_id] ?? collect())
->where('psection_id', $zone->psection_id)
->where('ptype_id', $zone->ptype_id)
->count();
$vacancy = $zone->zone_tolerance - $zone->zone_number - $reserveCount;
if ($vacancy > 0) {
$hasVacancy = true;
break;
}
}
// 猶予期間判定
$grace = $parkGracePeriods[$park->park_id] ?? null;
$inGrace = $this->isInGracePeriod($grace, $now);
// 状態判定
if ($zonesForType->isEmpty() || !$grace) {
$park->vehicle_status[$vehicle] = 'none';
} elseif ($inGrace && $hasVacancy) {
$park->vehicle_status[$vehicle] = 'available';
} elseif (!$inGrace) {
$park->vehicle_status[$vehicle] = 'out_of_period';
} elseif (!$hasVacancy) {
$park->vehicle_status[$vehicle] = 'waiting';
} else {
$park->vehicle_status[$vehicle] = 'none';
}
}
}
return $parks;
}
/**
* 猶予期間内かどうかを判定
*
* @param object|null $grace
* @param \Carbon\Carbon $now
* @return bool
*/
private function isInGracePeriod($grace, $now)
{
if (!$grace) {
return false;
}
// バリデーション
if (
!is_numeric($grace->update_grace_period_start_date) ||
!preg_match('/^\d{1,2}:\d{2}$/', $grace->update_grace_period_start_time) ||
!is_numeric($grace->update_grace_period_end_date) ||
!preg_match('/^\d{1,2}:\d{2}$/', $grace->update_grace_period_end_time)
) {
return false;
}
$year = $now->year;
$month = $now->month;
$startDay = (int)$grace->update_grace_period_start_date;
$endDay = (int)$grace->update_grace_period_end_date;
if ($startDay > $endDay) {
// 月またぎ(例: 25日5日
$prevMonth = $now->copy()->subMonth();
$startPrev = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $prevMonth->year, $prevMonth->month, $startDay, $grace->update_grace_period_start_time));
$endCurr = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $year, $month, $endDay, $grace->update_grace_period_end_time));
$startCurr = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $year, $month, $startDay, $grace->update_grace_period_start_time));
$nextMonth = $month == 12 ? 1 : $month + 1;
$nextYear = $month == 12 ? $year + 1 : $year;
$endNext = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $nextYear, $nextMonth, $endDay, $grace->update_grace_period_end_time));
return $now->between($startPrev, $endCurr) || $now->between($startCurr, $endNext);
} else {
// 同月(例: 5日25日
$start = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $year, $month, $startDay, $grace->update_grace_period_start_time));
$end = \Carbon\Carbon::createFromFormat('Y-m-d H:i', sprintf('%04d-%02d-%02d %s', $year, $month, $endDay, $grace->update_grace_period_end_time));
return $now->between($start, $end);
}
}
public function regulationCheck(Request $request)
{
// GETパラメータを取得
$parkId = $request->query('park_id');
$psectionId = $request->query('psection_id');
$ptypeId = $request->query('ptype_id');
// 必要なDB処理やロジック
$park_regulation = DB::table('park')->where('park_id', $parkId)->value('parking_regulations_flag');
if ($park_regulation == 1) {
// 駐輪規定画面へ
return redirect()->route('regular_contract.regulation', [
'park_id' => $parkId,
'psection_id' => $psectionId,
'ptype_id' => $ptypeId,
]);
} else {
// 契約情報入力画面へ
return redirect()->route('regular_contract.input', [
'park_id' => $parkId,
'psection_id' => $psectionId,
'ptype_id' => $ptypeId,
]);
}
}
public function showRegulation(Request $request)
{
$user_id = session('user_id');
if (!$user_id) {
return redirect('/login');
}
$user_name = DB::table('user')->where('user_id', $user_id)->value('user_name');
// 必要なパラメータ取得
$parkId = $request->query('park_id');
$psectionId = $request->query('psection_id');
$ptypeId = $request->query('ptype_id');
$park_name = DB::table('park')->where('park_id', $parkId)->value('park_name');
$psection_subject = DB::table('psection')->where('psection_id', $psectionId)->value('psection_subject');
$ptype_subject = DB::table('ptype')->where('ptype_id', $ptypeId)->value('ptype_subject');
$regulations_text = DB::table('parking_regulations')
->where('park_id', $parkId)
->where('psection_id', $psectionId)
->where('ptype_id', $ptypeId)
->value('regulations_text');
\Log::info('駐輪規定確認画面にアクセス', [
'user_id' => $user_id,
]);
return view('regular_contract.regulation', [
'park_id' => $parkId,
'park_name' => $park_name,
'psection_id' => $psectionId,
'psection_subject' => $psection_subject,
'ptype_id' => $ptypeId,
'ptype_subject' => $ptype_subject,
'regulations_text' => $regulations_text,
'active_menu' => 'SWC-8-1', // この画面のID
'user_name' => $user_name, // ユーザー名(ヘッダー用)
]);
}
public function insertRegulation(Request $request)
{
$user_id = session('user_id');
if (!$user_id) {
return redirect('/login');
}
$park_id = $request->input('park_id');
$psection_id = $request->input('psection_id');
$ptype_id = $request->input('ptype_id');
DB::table('parking_regulations_read')->insert([
'park_id' => $park_id,
'psection_id' => $psection_id,
'ptype_id' => $ptype_id,
'user_id' => $user_id,
'created_at' => now(),
]);
// 契約入力画面へリダイレクト
return redirect()->route('regular_contract.input', [
'park_id' => $park_id,
'psection_id' => $psection_id,
'ptype_id' => $ptype_id,
]);
}
// 契約入力画面表示
public function showContractForm(Request $request)
{
$user_id = session('user_id');
if (!$user_id) {
return redirect('/login');
}
$user = DB::table('user')->where('user_id', $user_id)->first();
$park_id = $request->query('park_id');
$park = DB::table('park')->where('park_id', $park_id)->first();
$psection_id = $request->query('psection_id');
$ptype_id = $request->query('ptype_id');
$city_id = DB::table('park')->where('park_id', $park_id)->value('city_id');
$terms_text = DB::table('terms')->where('city_id', $city_id)->value('terms_text');
// 利用者区分をusertypeテーブルから取得
$user_category = '';
if (isset($user->user_categoryid)) {
$usertype = DB::table('usertype')
->where('user_categoryid', $user->user_categoryid)
->first();
if ($usertype && isset($usertype->usertype_subject1)) {
$user_category = $usertype->usertype_subject1;
}
}
$user->user_homephone = explode('-', $user->user_homephone ?? '');
$user->user_mobile = explode('-', $user->user_mobile ?? '');
$user->user_regident_zip_1 = substr($user->user_regident_zip ?? '', 0, 3);
$user->user_regident_zip_2 = substr($user->user_regident_zip ?? '', 3, 4);
$user->user_relate_zip_1 = substr($user->user_relate_zip ?? '', 0, 3);
$user->user_relate_zip_2 = substr($user->user_relate_zip ?? '', 3, 4);
\Log::info('新規定期契約-契約情報入力画面にアクセス', [
'user_id' => $user_id,
]);
session()->forget('show_terms_modal');
return view('regular_contract.input', [
'park' => $park,
'psection_id' => $psection_id,
'ptype_id' => $ptype_id,
'terms_text' => $terms_text,
'user' => $user,
'user_name' => $user->user_name, // ユーザー名(ヘッダー用)
'active_menu' => 'SWC-8-1', // この画面のID
'user_category' => $user_category,
'show_terms_modal' => true,
]);
}
public function inputCheck(Request $request)
{
$user_id = session('user_id');
if (!$user_id) {
return redirect('/login');
}
$user = DB::table('user')->where('user_id', $user_id)->first();
$park_id = $request->input('park_id');
$park = DB::table('park')->where('park_id', $park_id)->first();
// バリデーションルール
$rules = [
'user_phonetic' => ['required', 'regex:/^[ァ-ヶー \s]+$/u'],
'user_regident_zip_1' => 'required|digits:3',
'user_regident_zip_2' => 'required|digits:4',
'user_regident_pre' => [
'required',
Rule::in([
'北海道',
'青森県',
'岩手県',
'宮城県',
'秋田県',
'山形県',
'福島県',
'茨城県',
'栃木県',
'群馬県',
'埼玉県',
'千葉県',
'東京都',
'神奈川県',
'新潟県',
'富山県',
'石川県',
'福井県',
'山梨県',
'長野県',
'岐阜県',
'静岡県',
'愛知県',
'三重県',
'滋賀県',
'京都府',
'大阪府',
'兵庫県',
'奈良県',
'和歌山県',
'鳥取県',
'島根県',
'岡山県',
'広島県',
'山口県',
'徳島県',
'香川県',
'愛媛県',
'高知県',
'福岡県',
'佐賀県',
'長崎県',
'熊本県',
'大分県',
'宮崎県',
'鹿児島県',
'沖縄県'
]),
],
'user_regident_city' => ['required', 'string', 'max:20', 'regex:/^(?:(?![\xF0-\xF7][\x80-\xBF]{3}).)*$/'],
'user_regident_add' => ['required', 'string', 'max:50', 'regex:/^(?:(?![\xF0-\xF7][\x80-\xBF]{3}).)*$/'],
'user_homephone.*' => 'nullable|digits_between:1,5',
'user_mobile.*' => 'nullable|digits_between:1,5',
'user_submail' => 'nullable|email|different:user_primemail|max:80',
'user_category' => ['required', Rule::in(['一般', '学生'])],
'contract_reduction' => ['required', Rule::in(['はい', 'いいえ'])],
'user_relate_zip_1' => 'nullable|digits:3',
'user_relate_zip_2' => 'nullable|digits:4',
'user_relate_pre' => [
'nullable',
Rule::in([
'北海道',
'青森県',
'岩手県',
'宮城県',
'秋田県',
'山形県',
'福島県',
'茨城県',
'栃木県',
'群馬県',
'埼玉県',
'千葉県',
'東京都',
'神奈川県',
'新潟県',
'富山県',
'石川県',
'福井県',
'山梨県',
'長野県',
'岐阜県',
'静岡県',
'愛知県',
'三重県',
'滋賀県',
'京都府',
'大阪府',
'兵庫県',
'奈良県',
'和歌山県',
'鳥取県',
'島根県',
'岡山県',
'広島県',
'山口県',
'徳島県',
'香川県',
'愛媛県',
'高知県',
'福岡県',
'佐賀県',
'長崎県',
'熊本県',
'大分県',
'宮崎県',
'鹿児島県',
'沖縄県'
]),
],
'user_relate_city' => ['nullable', 'string', 'max:20', 'regex:/^(?:(?![\xF0-\xF7][\x80-\xBF]{3}).)*$/'],
'user_relate_add' => ['nullable', 'string', 'max:50', 'regex:/^(?:(?![\xF0-\xF7][\x80-\xBF]{3}).)*$/'],
];
// 性別欄が表示されている場合のみ必須
if ((int)$park->gender_display_flag === 1) {
$rules['user_gender'] = ['required', Rule::in(['男性', '女性'])];
}
// 生年月日欄が表示されている場合のみ必須
if ((int)$park->bd_display_flag === 1) {
$rules['user_birthdate'] = ['required', 'date'];
}
// 防犯登録番号欄が表示されている場合のみ必須
if ((int)$park->securityreg_display_flag === 1) {
$rules['user_securitynum'] = ['required', 'max:50', 'regex:/^[a-zA-Z0-9]+$/'];
}
// 利用者区分ごとの追加バリデーション
if ($request->input('user_category') === '学生') {
$rules['user_school'] = ['required', 'string', 'max:50', 'regex:/^(?:(?![\xF0-\xF7][\x80-\xBF]{3}).)*$/'];
$rules['user_graduate'] = ['required', 'date'];
} else {
$rules['user_workplace'] = ['nullable', 'string', 'max:50', 'regex:/^(?:(?![\xF0-\xF7][\x80-\xBF]{3}).)*$/'];
}
$messages = [
'user_phonetic.required' => 'フリガナが入力されていません。',
'user_phonetic.regex' => 'フリガナはカタカナでご入力ください。',
'user_gender.required' => '性別が入力されていません。',
'user_gender.in' => '性別は「男性」または「女性」を選択してください。',
'user_regident_zip_1.required' => '居住所の郵便番号前半3桁が入力されていません。',
'user_regident_zip_2.required' => '居住所の郵便番号後半4桁が入力されていません。',
'user_regident_zip_1.digits' => '居住所の郵便番号前半3桁は3桁の数字で入力してください。',
'user_regident_zip_2.digits' => '居住所の郵便番号後半4桁は4桁の数字で入力してください。',
'user_regident_pre.required' => '居住所の都道府県が選択されていません。',
'user_regident_pre.in' => '都道府県は選択肢から選んでください。',
'user_regident_city.required' => '居住所の市区町村が入力されていません。',
'user_regident_city.max' => '居住所の市区町村は20文字以内で入力してください。',
'user_regident_city.regex' => '居住所の市区町村に絵文字などの特殊文字は使用できません。',
'user_regident_add.required' => '居住所の住所が入力されていません。',
'user_regident_add.max' => '居住所の住所は50文字以内で入力してください。',
'user_regident_add.regex' => '居住所の住所に絵文字などの特殊文字は使用できません。',
'user_birthdate.required' => '生年月日が入力されていません。',
'user_birthdate.date' => '生年月日は正しい日付で入力してください。',
'user_homephone.*.digits_between' => '自宅電話番号はそれぞれ15桁の数字で入力してください。',
'user_mobile.*.digits_between' => '携帯電話番号はそれぞれ15桁の数字で入力してください。',
'user_submail.email' => '予備メールアドレスは正しい形式で入力してください。',
'user_submail.max' => '予備メールアドレスは80文字以内で入力してください。',
'user_submail.different' => 'メールアドレスと予備メールアドレスに同じアドレスを入力できません。',
'user_category.required' => '利用者区分は必須です。',
'user_category.in' => '利用者区分の値が不正です。',
'contract_reduction.required' => '減免が選択されていません。',
'contract_reduction.in' => '減免の値が不正です。',
'user_workplace.max' => '勤務先は50文字以内で入力してください。',
'user_workplace.regex' => '勤務先に絵文字などの特殊文字は使用できません。',
'user_school.required' => '学校名が入力されていません。',
'user_school.max' => '学校名は50文字以内で入力してください。',
'user_school.regex' => '学校名に絵文字などの特殊文字は使用できません。',
'user_graduate.required' => '卒業年月日が入力されていません。',
'user_graduate.date' => '卒業年月日は正しい日付で入力してください。',
'user_relate_zip_1.digits' => '住所の郵便番号前半3桁は3桁の数字で入力してください。',
'user_relate_zip_2.digits' => '住所の郵便番号後半4桁は4桁の数字で入力してください。',
'user_relate_pre.in' => '住所の都道府県は選択肢から選んでください。',
'user_relate_city.max' => '住所の市区町村は20文字以内で入力してください。',
'user_relate_city.regex' => '住所の市区町村に絵文字などの特殊文字は使用できません。',
'user_relate_add.max' => '住所は50文字以内で入力してください。',
'user_relate_add.regex' => '住所に絵文字などの特殊文字は使用できません。',
'user_securitynum.required' => '防犯登録番号が入力されていません。',
'user_securitynum.max' => '防犯登録番号は50文字以内で入力してください。',
'user_securitynum.regex' => '防犯登録番号は英数字のみで入力してください。',
];
try {
$validated = $request->validate($rules, $messages);
} catch (ValidationException $e) {
return Redirect()->back()
->withErrors($e->validator)
->withInput($request->except('_token') + ['show_terms_modal' => false]);
}
if (empty(implode('', $request->input('user_homephone', []))) && empty(implode('', $request->input('user_mobile', [])))) {
return redirect()->back()
->withErrors(['user_homephone' => '自宅電話番号または携帯電話番号のいずれかは必須です'])
->withInput($request->except('_token') + ['show_terms_modal' => false]);
}
$city = DB::table('city')->where('city_id', $park->city_id)->first();
$matched = (mb_strpos($request->user_regident_city, $city->city_name) !== false);
if ($matched === true) {
$ward_residents = 1;
DB::table('user')
->where('user_id', $user->user_id)
->update(['ward_residents' => $ward_residents]);
} else {
$contract_allowable_city_name = DB::table('contract_allowable_city')->where('city_id', $city->city_id)->value('contract_allowable_city_name');
$matched_allowable = (mb_strpos($request->user_regident_city, $contract_allowable_city_name) !== false);
if ($matched_allowable) {
$ward_residents = 0;
DB::table('user')
->where('user_id', $user->user_id)
->update(['ward_residents' => $ward_residents]);
} else {
return redirect()->back()->withErrors(['契約対象地域にお住まいでないためお申込みできません'])->withInput()->with(['show_terms_modal' => false]);
}
}
if ($ward_residents == 1) {
$usertype_subject2 = '区民';
} else {
$usertype_subject2 = '区民外';
}
$user_categoryid = DB::table('usertype')
->where('usertype_subject1', $request->user_category)
->where('usertype_subject2', $usertype_subject2)
->value('user_categoryid');
$updateData = [
'user_categoryid' => $user_categoryid,
'user_phonetic' => $request->user_phonetic,
'user_mobile' => implode('-', $request->input('user_mobile', [])),
'user_homephone' => implode('-', $request->input('user_homephone', [])),
'user_submail' => $request->filled('user_submail') ? $request->user_submail : null,
'user_regident_zip' => $request->user_regident_zip_1 . $request->user_regident_zip_2,
'user_regident_pre' => $request->user_regident_pre,
'user_regident_city' => $request->user_regident_city,
'user_regident_add' => $request->user_regident_add,
'user_relate_zip' => ($request->filled('user_relate_zip_1') && $request->filled('user_relate_zip_2')) ? ($request->user_relate_zip_1 . $request->user_relate_zip_2) : null,
'user_relate_pre' => $request->filled('user_relate_pre') ? $request->user_relate_pre : null,
'user_relate_city' => $request->filled('user_relate_city') ? $request->user_relate_city : null,
'user_relate_add' => $request->filled('user_relate_add') ? $request->user_relate_add : null,
'ward_residents' => $ward_residents,
'user_workplace' => $request->user_category === '一般' ? $request->user_workplace : null,
'user_school' => $request->user_category === '学生' ? $request->user_school : null,
'user_graduate' => $request->user_category === '学生' ? $request->user_graduate : null,
'updated_at' => now()
];
// 性別欄が表示されている場合のみ追加
if (!empty($park->gender_display_flag) && $park->gender_display_flag == 1) {
$updateData['user_gender'] = $request->user_gender;
}
// 生年月日欄が表示されている場合のみ追加
if (!empty($park->bd_display_flag) && $park->bd_display_flag == 1) {
$updateData['user_birthdate'] = $request->user_birthdate;
$updateData['user_age'] = $request->user_age;
}
DB::table('user')
->where('user_id', $user->user_id)
->update($updateData);
$zone_id = DB::table('zone')
->where('park_id', $request->park_id)
->where('ptype_id', $request->ptype_id)
->where('psection_id', $request->psection_id)
->orderBy('zone_sort', 'asc')
->value('zone_id');
$contract_id = DB::table('regular_contract')->insertGetId([
'created_at' => now(),
'updated_at' => now(),
'user_id' => $user->user_id,
'user_categoryid' => $user_categoryid,
'park_id' => $park->park_id,
'contract_created_at' => now(),
'contract_reduction' => $request->contract_reduction === 'はい' ? 1 : 0,
'update_flag' => 2,
'contract_cancel_flag' => 0,
'psection_id' => $request->psection_id,
'ptype_id' => $request->ptype_id,
'zone_id' => $zone_id
]);
$contractUpdateData = [
'contract_qr_id' => DB::raw("TO_BASE64(AES_ENCRYPT($contract_id, 'LJLASR4FAS34SAADFA72ASDFALLSDRGT'))")
];
// 防犯登録番号が表示されている場合のみ追加
if (!empty($park->securityreg_display_flag) && $park->securityreg_display_flag == 1) {
$contractUpdateData['user_securitynum'] = $request->user_securitynum;
}
DB::table('regular_contract')
->where('contract_id', $contract_id)
->update($contractUpdateData);
return redirect()->route('regular_contract.upload_identity_create', [
'contract_id' => $contract_id,
]);
}
public function showUploadIdentityCreate(Request $request)
{
$user_id = session('user_id');
if (!$user_id) {
return redirect('/login');
}
$user_name = DB::table('user')->where('user_id', $user_id)->value('user_name');
$contract = DB::table('regular_contract')->where('contract_id', $request->contract_id)->first();
\Log::info('新規定期契約-本人確認書類アップロード画面にアクセス', [
'user_id' => $user_id,
]);
return view('regular_contract.upload_identity_create', [
'contract_id' => $request->contract_id,
'park_id' => $contract->park_id,
'psection_id' => $contract->psection_id,
'ptype_id' => $contract->ptype_id,
'user_name' => $user_name,
'active_menu' => 'SWC-8-1'
]);
}
public function confirmUploadIdentity(Request $request, $contract_id)
{
$user_id = session('user_id');
if (!$user_id) {
return redirect('/login');
}
$validator = Validator::make($request->all(), [
'idcard_type' => 'required',
'user_idcard' => 'required|file|mimes:jpg,jpeg,png,pdf',
], [
'idcard_type.required' => '本人確認書類の種類を選択してください。',
'user_idcard.required' => '本人確認書類のおもて画像をアップロードしてください。',
'user_idcard.file' => '本人確認書類のおもて画像はファイルで指定してください。',
'user_idcard.mimes' => 'アップロードできるファイル形式はjpg、jpeg、png、pdfのみです。',
]);
if ($validator->fails()) {
return redirect()->route('regular_contract.upload_identity_create', [
'contract_id' => $contract_id,
])
->withErrors($validator)
->withInput();
}
// おもて画像保存Laravel Storageを使用
$front = $request->file('user_idcard');
$filename_front = uniqid('photo1_') . '.' . $front->getClientOriginalExtension();
$front->storeAs('photo', $filename_front, 'public');
// userテーブルに保存チェック済フラグはSHJ-1処理後に設定
$updateData = [
'photo_filename1' => $filename_front,
'user_idcard' => $request->idcard_type,
'updated_at' => now(),
];
// ウラ画像がある場合保存し更新項目に追加
if ($request->hasFile('user_idcard2')) {
$back = $request->file('user_idcard2');
$filename_back = uniqid('photo2_') . '.' . $back->getClientOriginalExtension();
$back->storeAs('photo', $filename_back, 'public');
$updateData['photo_filename2'] = $filename_back;
}
DB::table('user')->where('user_id', $user_id)->update($updateData);
// SHJ-1 本人確認自動処理を実行
$user = DB::table('user')->where('user_id', $user_id)->first();
$park = DB::table('park')->where('park_id', $request->park_id)->first();
$psection = DB::table('psection')->where('psection_id', $request->psection_id)->first();
$usertype = DB::table('usertype')->where('user_categoryid', $user->user_categoryid)->first();
// user_idからuser_seqを取得してSHJ-1に渡す
$user_seq = $user->user_seq;
$park_id = $request->park_id;
\Log::info('SHJ-1バッチ処理開始', [
'user_id' => $user_id,
'user_seq' => $user_seq,
'park_id' => $park_id,
'contract_id' => $contract_id
]);
try {
// SHJ-1 コマンドを同期実行
$exitCode = Artisan::call('shj:one', [
'user_id' => $user_seq,
'park_id' => $park_id
]);
\Log::info('SHJ-1バッチ処理完了', [
'exit_code' => $exitCode,
'user_seq' => $user_seq,
'park_id' => $park_id
]);
} catch (\Exception $e) {
\Log::error('SHJ-1バッチ処理でエラー発生', [
'error' => $e->getMessage(),
'user_seq' => $user_seq,
'park_id' => $park_id
]);
}
// 処理結果に基づいて遷移
return view('regular_contract.create_confirm', [
'contract_id' => $request->contract_id,
'user' => $user,
'park' => $park,
'psection' => $psection,
'usertype' => $usertype,
'user_name' => $user->user_name,
'active_menu' => 'SWC-8-1'
]);
}
public function createConfirmNext($contract_id)
{
$user_id = session('user_id');
if (!$user_id) {
return redirect('/login');
}
$user = DB::table('user')->where('user_id', $user_id)->first();
// 本人確認自動処理結果を取得
if ($user && $user->user_idcard_chk_flag == 2) {
// 本人確認OKの場合は利用期間選択画面へ
// 必要な各マスタ情報を取得
$contract = DB::table('regular_contract')->where('contract_id', $contract_id)->first();
$park = DB::table('park')->where('park_id', $contract->park_id)->first();
$city = DB::table('city')->where('city_id', $park->city_id)->first();
$regular_type = DB::table('regular_type')->where('city_id', $city->city_id)->first();
$usertype = DB::table('usertype')->where('user_categoryid', $contract->user_categoryid)->first();
// 2重化しているマスタのため現在のテーブル名を取得
$master_setting = DB::table('setting')->value('web_master');
$tableName = 'price' . $master_setting;
// 利用者区分に応じた逆利用フラグを取得
$inverse_use_flag_column = ($usertype->usertype_subject1 == '一般') ? 'inverse_use_flag1' : 'inverse_use_flag2';
$inverse_use_flag = $park->$inverse_use_flag_column;
if ($inverse_use_flag == 0) {
// regident_cityまたはrelate_cityが一致するか
$is_same = (
strpos($user->user_regident_city, $city->city_name) !== false ||
strpos($user->user_relate_city, $city->city_name) !== false
);
} else {
// regident_cityのみ一致するか
$is_same = (strpos($user->user_regident_city, $city->city_name) !== false);
}
$target_subject2 = $is_same ? '区民' : '区民外';
$user_categoryid = DB::table('usertype')
->where('usertype_subject1', $usertype->usertype_subject1)
->where('usertype_subject2', $target_subject2)
->where('usertype_subject3', $usertype->usertype_subject3)
->value('user_categoryid');
// 駐輪場所マスタから料金を取得
$prices = DB::table($tableName)
->where('park_id', $contract->park_id)
->where('psection_id', $contract->psection_id)
->where('ptype_id', $contract->ptype_id)
->where('user_categoryid', $user_categoryid)
->get();
\Log::info('利用期間選択画面にアクセス', [
'user_id' => $user_id,
]);
// 利用期間選択画面へ遷移
return view('regular_contract.create_select_period', [
'active_menu' => 'SWC-8-1', // マイページメニューの選択状態用
'user_name' => $user->user_name, // ユーザー名(ヘッダー用)
'contract_id' => $contract_id,
'regular_type' => $regular_type,
'prices' => $prices,
]);
} else {
// NGの場合は本人確認書類確認中画面へ
\Log::info('本人確認書類確認中画面にアクセス', [
'user_id' => $user_id,
]);
return view('regular_contract.create_idcard_checking', [
'active_menu' => 'SWC-8-1', // マイページメニューの選択状態用
'user_name' => $user->user_name, // ユーザー名(ヘッダー用)
]);
}
}
public function selectPeriod(Request $request)
{
$user_id = session('user_id');
if (!$user_id) {
return redirect('/login');
}
$contract_id = $request->input('contract_id');
$validator = Validator::make($request->all(), [
'month' => 'required',
], [
'month.required' => '契約期間が選択されていません。',
]);
if ($validator->fails()) {
return redirect()->route('regular_contract.create_confirm_error', ['contract_id' => $contract_id])
->withErrors($validator)
->withInput();
}
$month = $request->input('month');
$price = $request->input('price_' . $month);
$today = now();
$day = $today->day;
if ($day <= 19) {
// 今月の1日
$contract_periods = $today->copy()->startOfMonth()->format('Y-m-d');
} else {
// 翌月の1日
$contract_periods = $today->copy()->addMonth()->startOfMonth()->format('Y-m-d');
}
$contract_periode = Carbon::parse($contract_periods)->addMonths($month - 1)->endOfMonth()->format('Y-m-d');
// 契約更新
DB::table('regular_contract')->where('contract_id', $contract_id)->update([
'enable_months' => $month,
'billing_amount' => $price,
'contract_periods' => $contract_periods,
'contract_periode' => $contract_periode,
'updated_at' => now(),
]);
// 完了後はウェルネット決済画面(仮)へリダイレクト
return redirect()->route('wellnet.payment');
}
}