470 lines
18 KiB
PHP
470 lines
18 KiB
PHP
<?php
|
||
|
||
namespace App\Http\Controllers\Admin;
|
||
|
||
use Illuminate\Support\Facades\Schema;
|
||
use Illuminate\Http\Request;
|
||
use Illuminate\Support\Facades\DB;
|
||
use Illuminate\Support\Facades\Validator;
|
||
use App\Models\Park;
|
||
use App\Models\PriceA;
|
||
use App\Models\PriceB;
|
||
use Illuminate\Support\Facades\Auth;
|
||
|
||
class ReservesController
|
||
{
|
||
/**
|
||
* 予約一覧
|
||
* - 基本表: reserve(r)
|
||
* - 付加情報: user(u), park(p)
|
||
* - 画面変数: $list, $sort, $sort_type(利用者マスタの書式に準拠)
|
||
*
|
||
* reserve テーブルの主な列:
|
||
* reserve_id, contract_id, user_id, park_id, price_parkplaceid, psection_id,
|
||
* reserve_date, reserve_start, reserve_end, reserve_cancelday, valid_flag, ope_id など
|
||
* (DDL は dump の通り)【turn12file6†L15-L37】
|
||
*/
|
||
public function list(Request $request)
|
||
{
|
||
// ── 並び順(既定: reserve_id DESC)──────────────────────────────
|
||
$sort = $request->input('sort', 'reserve_id');
|
||
$sortType = strtolower($request->input('sort_type', 'asc')) === 'desc' ? 'desc' : 'asc';
|
||
|
||
// ── 絞り込み(必要最低限:利用者/駐輪場/期間)──────────────────
|
||
$userId = trim((string) $request->input('user_id', ''));
|
||
$parkId = trim((string) $request->input('park_id', ''));
|
||
$fromDt = $request->input('reserve_date_from', '');
|
||
$toDt = $request->input('reserve_date_to', '');
|
||
$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')
|
||
->leftJoin('user as u', 'u.user_id', '=', 'r.user_id')
|
||
->leftJoin('park as p', 'p.park_id', '=', 'r.park_id')
|
||
->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([
|
||
'r.reserve_id',
|
||
'r.contract_id',
|
||
'r.contract_created_at',
|
||
'r.user_id',
|
||
'r.park_id',
|
||
'r.price_parkplaceid',
|
||
'r.psection_id',
|
||
'r.reserve_date',
|
||
'r.reserve_start',
|
||
'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.valid_flag',
|
||
'r.reserve_manual',
|
||
'r.reserve_notice',
|
||
'r.sent_date',
|
||
'r.reserve_order',
|
||
'r.valid_flag',
|
||
'r.ope_id',
|
||
'r.user_categoryid',
|
||
DB::raw('u.user_name as user_name'),
|
||
DB::raw('u.user_phonetic as user_phonetic'),
|
||
DB::raw('u.user_mobile as user_mobile'),
|
||
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 !== '')
|
||
$q->where('r.user_id', 'like', "%{$userId}%");
|
||
if ($parkId !== '')
|
||
$q->where('r.park_id', '=', (int) $parkId);
|
||
|
||
if ($fromDt)
|
||
$q->whereDate('r.reserve_date', '>=', $fromDt);
|
||
if ($toDt)
|
||
$q->whereDate('r.reserve_date', '<=', $toDt);
|
||
|
||
if ($keyword !== '') {
|
||
$q->where(function ($w) use ($keyword) {
|
||
$w->where('u.user_name', '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 先も含む)
|
||
$sortable = [
|
||
'reserve_id',
|
||
'contract_id',
|
||
'contract_created_at',
|
||
'user_categoryid',
|
||
'user_id',
|
||
'reserve_date',
|
||
'park_price_name',
|
||
'price_parkplaceid',
|
||
'psection_subject',
|
||
'ptype_subject',
|
||
'park_name',
|
||
'reserve_reduction',
|
||
'reserve_auto_remind',
|
||
'reserve_manual_remind',
|
||
'flag_800m',
|
||
'reserve_cancelday',
|
||
'valid_flag',
|
||
'sent_date',
|
||
'reserve_manual',
|
||
'reserve_notice',
|
||
'reserve_order',
|
||
];
|
||
if (!in_array($sort, $sortable, true)) {
|
||
$sort = 'reserve_id';
|
||
}
|
||
|
||
$sortMap = [
|
||
'reserve_id' => DB::raw('r.reserve_id'),
|
||
'contract_id' => DB::raw('r.contract_id'),
|
||
'contract_created_at' => DB::raw('r.contract_created_at'),
|
||
'user_categoryid' => DB::raw('r.user_categoryid'),
|
||
'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');
|
||
$q->orderBy($sortColumn, $sortType);
|
||
|
||
$parkOptions = Park::query()
|
||
->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', [
|
||
'list' => $list,
|
||
'sort' => $sort,
|
||
'sort_type' => $sortType,
|
||
// 入力保持
|
||
'user_id' => $userId,
|
||
'park_id' => $parkId,
|
||
'reserve_date_from' => $fromDt,
|
||
'reserve_date_to' => $toDt,
|
||
'keyword' => $keyword,
|
||
'valid_flag' => $validFlag,
|
||
'mail_sent_from' => $mailSentFrom,
|
||
'mail_sent_to' => $mailSentTo,
|
||
'parkOptions' => $parkOptions,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 予約追加(GET: 画面表示 / POST: 登録)
|
||
*/
|
||
public function add(Request $request)
|
||
{
|
||
if ($request->isMethod('get')) {
|
||
$userTypes = DB::table('usertype')
|
||
->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,
|
||
]);
|
||
}
|
||
|
||
// 予約の最低限バリデーション(必要に応じて追加)
|
||
$v = Validator::make($request->all(), [
|
||
'user_id' => ['required', 'integer'],
|
||
'park_id' => ['required', 'integer'],
|
||
'reserve_date' => ['nullable', 'date'],
|
||
'reserve_start' => ['nullable', 'date'],
|
||
'reserve_end' => ['nullable', 'date'],
|
||
], [], [
|
||
'user_id' => '利用者ID',
|
||
'park_id' => '駐輪場ID',
|
||
]);
|
||
|
||
if ($v->fails()) {
|
||
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([
|
||
'reserve_id' => $nextReserveId,
|
||
'user_id' => (int) $request->input('user_id'),
|
||
'park_id' => (int) $request->input('park_id'),
|
||
'contract_id' => $request->input('contract_id'),
|
||
'price_parkplaceid' => $request->input('price_parkplaceid'),
|
||
'psection_id' => $request->input('psection_id'),
|
||
'reserve_date' => $request->input('reserve_date'),
|
||
'reserve_start' => $now,
|
||
'reserve_end' => $now,
|
||
'valid_flag' => $request->input('valid_flag'),
|
||
'ope_id' => $opeId,
|
||
'created_at' => $now,
|
||
'updated_at' => $now,
|
||
]);
|
||
|
||
return redirect()->route('reserves')->with('success', '予約を登録しました。');
|
||
}
|
||
|
||
/**
|
||
* 予約削除
|
||
*/
|
||
public function delete(Request $request)
|
||
{
|
||
|
||
$normalizeIds = function ($raw) {
|
||
|
||
if (is_string($raw)) {
|
||
$raw = explode(',', $raw);
|
||
}
|
||
if (is_array($raw) && count($raw) === 1 && is_string($raw[0]) && str_contains($raw[0], ',')) {
|
||
$raw = explode(',', $raw[0]);
|
||
}
|
||
$ids = array_map('intval', (array) $raw);
|
||
$ids = array_values(array_unique(array_filter($ids, fn($v) => $v > 0)));
|
||
return $ids;
|
||
};
|
||
|
||
if ($request->isMethod('get')) {
|
||
|
||
$ids = $normalizeIds($request->input('ids', []));
|
||
|
||
$rows = [];
|
||
if ($ids) {
|
||
$rows = DB::table('reserve as r')
|
||
->leftJoin('user as u', 'u.user_id', '=', 'r.user_id')
|
||
->leftJoin('park as p', 'p.park_id', '=', 'r.park_id')
|
||
->whereIn('r.reserve_id', $ids)
|
||
->select('r.*', 'u.user_name', 'p.park_name')
|
||
->get();
|
||
}
|
||
return view('admin.reserves.delete', compact('rows', 'ids'));
|
||
}
|
||
|
||
|
||
if ($request->post('confirmed')) {
|
||
$ids = $normalizeIds($request->input('ids', []));
|
||
if ($ids) {
|
||
$deleted = DB::table('reserve')->whereIn('reserve_id', $ids)->delete();
|
||
return redirect()->route('reserves')->with(
|
||
$deleted ? 'success' : 'warning',
|
||
$deleted ? "{$deleted} 件を削除しました。" : '対象が見つかりませんでした。'
|
||
);
|
||
}
|
||
}
|
||
|
||
return redirect()->route('reserves')->with('warning', '削除対象がありません。');
|
||
}
|
||
|
||
|
||
public function edit(Request $request, $reserve_id)
|
||
{
|
||
$id = (int) $reserve_id;
|
||
|
||
// 取得レコード(無ければ404)
|
||
$row = DB::table('reserve')->where('reserve_id', $id)->first();
|
||
if (!$row) {
|
||
abort(404);
|
||
}
|
||
|
||
// POST: 更新処理(※reserveテーブルに確実にある列だけ更新)
|
||
if ($request->isMethod('post')) {
|
||
$v = Validator::make($request->all(), [
|
||
'user_id' => ['required', 'integer'],
|
||
'park_id' => ['required', 'integer'],
|
||
'reserve_date' => ['nullable', 'date'],
|
||
'reserve_start' => ['nullable', 'date'],
|
||
'reserve_end' => ['nullable', 'date'],
|
||
], [], [
|
||
'user_id' => '利用者ID',
|
||
'park_id' => '駐輪場ID',
|
||
]);
|
||
|
||
if ($v->fails()) {
|
||
return back()->withErrors($v)->withInput();
|
||
}
|
||
|
||
$data = [
|
||
'contract_id' => $request->input('contract_id'),
|
||
'user_id' => (int) $request->input('user_id'),
|
||
'park_id' => (int) $request->input('park_id'),
|
||
'price_parkplaceid' => $request->input('price_parkplaceid'),
|
||
'psection_id' => $request->input('psection_id'),
|
||
'reserve_date' => $request->input('reserve_date'),
|
||
'reserve_start' => $request->input('reserve_start'),
|
||
'reserve_end' => $request->input('reserve_end'),
|
||
'valid_flag' => $request->input('valid_flag'),
|
||
'ope_id' => $request->input('ope_id'),
|
||
'updated_at' => now(),
|
||
];
|
||
DB::table('reserve')->where('reserve_id', $id)->update($data);
|
||
|
||
return redirect()->route('reserves')->with('success', '予約を更新しました。');
|
||
}
|
||
|
||
// GET: 編集画面表示用の各種プルダウン(存在するテーブルだけ読む)
|
||
$userOptions = DB::table('user')
|
||
->orderBy('user_id', 'asc')
|
||
->limit(5000)
|
||
->pluck(DB::raw("concat(user_id, ' ', user_name)"), 'user_id')
|
||
->toArray();
|
||
|
||
$parkOptions = DB::table('park')
|
||
->orderBy('park_id', 'asc')
|
||
->pluck('park_name', 'park_id')
|
||
->toArray();
|
||
|
||
$userTypeOptions = Schema::hasTable('usertype')
|
||
? DB::table('usertype')->orderBy('user_categoryid')
|
||
->pluck('print_name', 'user_categoryid')->toArray()
|
||
: [];
|
||
|
||
$parkplaceOptions = Schema::hasTable('price_parkplace')
|
||
? DB::table('price_parkplace')->orderBy('price_parkplaceid')
|
||
->pluck('price_parkplaceid', 'price_parkplaceid')->toArray()
|
||
: [];
|
||
|
||
$psectionOptions = Schema::hasTable('psection')
|
||
? DB::table('psection')->orderBy('psection_id')
|
||
->pluck(
|
||
Schema::hasColumn('psection', 'psection_name') ? 'psection_name' : 'psection_id',
|
||
'psection_id'
|
||
)->toArray()
|
||
: [];
|
||
|
||
$ptypeOptions = Schema::hasTable('ptype')
|
||
? DB::table('ptype')->orderBy('ptype_id')
|
||
->pluck(
|
||
Schema::hasColumn('ptype', 'ptype_name') ? 'ptype_name' : 'ptype_id',
|
||
'ptype_id'
|
||
)->toArray()
|
||
: [];
|
||
|
||
|
||
return view('admin.reserves.edit', compact(
|
||
'row',
|
||
'userOptions',
|
||
'parkOptions',
|
||
'userTypeOptions',
|
||
'parkplaceOptions',
|
||
'psectionOptions',
|
||
'ptypeOptions'
|
||
));
|
||
}
|
||
|
||
}
|