diff --git a/app/Http/Controllers/Admin/InvSettingController.php b/app/Http/Controllers/Admin/InvSettingController.php new file mode 100644 index 0000000..4956823 --- /dev/null +++ b/app/Http/Controllers/Admin/InvSettingController.php @@ -0,0 +1,151 @@ +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' => 'nullable|image|mimes:png,jpg,jpeg|max:2048', + ]; + + // カスタム日本語メッセージ + $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文字以内で入力してください。', + + 'bldg.max' => '建物名は80文字以内で入力してください。', + + '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桁で入力してください。', + + 'company_image.image' => '社判画像は画像ファイルを選択してください。', + 'company_image.mimes' => '社判画像はpng, jpg, jpeg形式でアップロードしてください。', + 'company_image.max' => '社判画像は2MB以下にしてください。', + ]; + + // バリデーション実行(カスタムメッセージ適用) + $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 = $row?->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, + ]); + } 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', 'インボイス設定を登録しました。'); + } + +} diff --git a/app/Http/Controllers/Admin/JurisdictionParkingController.php b/app/Http/Controllers/Admin/JurisdictionParkingController.php index 0b42a5e..a2f24d9 100644 --- a/app/Http/Controllers/Admin/JurisdictionParkingController.php +++ b/app/Http/Controllers/Admin/JurisdictionParkingController.php @@ -12,10 +12,15 @@ use Illuminate\Support\Facades\DB; class JurisdictionParkingController extends Controller { public function list(Request $request) - { - $list = JurisdictionParking::query()->paginate(20); - return view('admin.jurisdiction_parkings.list', compact('list')); - } +{ + + $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) { @@ -37,9 +42,9 @@ class JurisdictionParkingController extends Controller } - public function edit(Request $request, $jurisdiction_parking_id) + public function edit(Request $request, $id) { - $record = JurisdictionParking::findOrFail($jurisdiction_parking_id); + $record = JurisdictionParking::findOrFail($id); if ($request->isMethod('post')) { $validated = $request->validate([ @@ -59,6 +64,7 @@ class JurisdictionParkingController extends Controller return view('admin.jurisdiction_parkings.edit', compact('record', 'parks', 'opes')); } + public function delete(Request $request) { if ($request->has('pk')) { diff --git a/app/Http/Controllers/Admin/MailTemplateController.php b/app/Http/Controllers/Admin/MailTemplateController.php new file mode 100644 index 0000000..6323dff --- /dev/null +++ b/app/Http/Controllers/Admin/MailTemplateController.php @@ -0,0 +1,124 @@ +input('action') === 'reset') { + return redirect()->route('mail_templates'); + } + + $sort = $request->input('sort', 'mail_template_id'); + $sort_type = $request->input('sort_type', 'desc'); + + $query = MailTemplate::query(); + + // 絞り込み + if ($request->filled('mail_template_id')) { + $query->where('mail_template_id', $request->mail_template_id); + } + if ($request->filled('pg_id')) { + $query->where('pg_id', $request->pg_id); + } + if ($request->has('mgr_cc_flag') && $request->mgr_cc_flag !== '') { + $query->where('mgr_cc_flag', $request->mgr_cc_flag); + } + if ($request->has('use_flag') && $request->use_flag !== '') { + $query->where('use_flag', $request->use_flag); + } + if ($request->filled('subject')) { + $query->where('subject', 'LIKE', "%{$request->subject}%"); + } + + $templates = $query->orderBy($sort, $sort_type)->paginate(20); + + return view('admin.mail_templates.list', compact( + 'templates', 'sort', 'sort_type' + )); + } + + /** + * 新規登録 + */ + public function add(Request $request) + { + if ($request->isMethod('post')) { + $data = $this->validateTemplate($request); + MailTemplate::create($data); + + return redirect()->route('mail_templates') + ->with('success', 'テンプレートを登録しました'); + } + + $mailTemplate = new MailTemplate(); + return view('admin.mail_templates.add', compact('mailTemplate')); + } + + /** + * 編集 + */ + public function edit($id, Request $request) + { + $mailTemplate = MailTemplate::findOrFail($id); + + if ($request->isMethod('post')) { + $data = $this->validateTemplate($request); + $mailTemplate->update($data); + + return redirect()->route('mail_templates') + ->with('success', 'テンプレートを更新しました'); + } + + return view('admin.mail_templates.edit', compact('mailTemplate')); + } + + /** + * 詳細表示 + */ + public function info($id) + { + $mailTemplate = MailTemplate::findOrFail($id); + + return view('admin.mail_templates.info', compact('mailTemplate')); + } + + /** + * 削除 + */ + public function delete(Request $request) + { + $id = $request->input('id'); + if ($id) { + MailTemplate::destroy($id); + return redirect()->route('mail_templates')->with('success', 'テンプレートを削除しました'); + } + return redirect()->route('mail_templates')->with('error', '削除対象が指定されていません'); + } + + /** + * バリデーション共通化 + */ + private function validateTemplate(Request $request) + { + return $request->validate([ + 'pg_id' => 'nullable|integer', + 'internal_id' => 'nullable|integer', + 'mgr_cc_flag' => 'nullable|boolean', + 'bcc_adrs' => 'nullable|string|max:255', + 'use_flag' => 'nullable|boolean', + 'memo' => 'nullable|string|max:255', + 'subject' => 'required|string|max:255', + 'text' => 'required|string', + 'operator_id' => 'nullable|integer', + ]); + } +} diff --git a/app/Http/Controllers/Admin/NeighborStationController.php b/app/Http/Controllers/Admin/NeighborStationController.php deleted file mode 100644 index b40b104..0000000 --- a/app/Http/Controllers/Admin/NeighborStationController.php +++ /dev/null @@ -1,119 +0,0 @@ -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'; - } - - $stations = NeighborStation::select([ - 'station_id', - 'station_neighbor_station', - 'station_name_ruby', - 'station_route_name', - // 'station_latitude', - // 'station_longitude', - 'park_id' - ])->orderBy($sort, $sort_type)->paginate(20); - - return view('admin.neighbor_stations.list', compact('stations', 'sort', 'sort_type')); -} - - - // 新規登録画面と登録処理 - public function add(Request $request) - { - if ($request->isMethod('post')) { - $validated = $request->validate([ - 'station_neighbor_station' => 'required|string|max:255', - 'station_name_ruby' => 'nullable|string|max:255', - 'station_route_name' => 'nullable|string|max:255', - 'park_id' => 'nullable|integer', - 'operator_id' => 'nullable|integer', - ]); - - NeighborStation::create($validated); - return redirect()->route('neighbor_stations')->with('success', '近傍駅が登録されました'); - } - - return view('admin.neighbor_stations.add'); - } - - // 編集画面・更新処理 - public function edit(Request $request, $id) - { - $station = NeighborStation::findOrFail($id); - - if ($request->isMethod('post')) { - $validated = $request->validate([ - 'station_neighbor_station' => 'required|string|max:255', - 'station_name_ruby' => 'nullable|string|max:255', - 'station_route_name' => 'nullable|string|max:255', - 'park_id' => 'nullable|integer', - 'operator_id' => 'nullable|integer', - ]); - - $station->update($validated); - return redirect()->route('neighbor_stations')->with('success', '更新しました'); - } - - return view('admin.neighbor_stations.edit', compact('station')); - } - - // 詳細表示 - public function info($id) - { - $station = NeighborStation::findOrFail($id); - return view('admin.neighbor_stations.info', compact('station')); - } - - // 削除処理 - public function delete(Request $request) - { - $ids = $request->input('pk'); // ← 接收复数 checkbox 名称 pk[] - - if (!empty($ids)) { - NeighborStation::destroy($ids); // 一次性删除多个 - return redirect()->route('neighbor_stations')->with('success', '削除しました'); - } - - return redirect()->route('neighbor_stations')->with('error', '削除対象が見つかりません'); - } - - - // CSVインポート(仮) - public function import(Request $request) - { - // TODO: 実装 - return redirect()->route('neighbor_stations')->with('info', 'CSVインポートは未実装です'); - } - - // CSVエクスポート(仮) - public function export() - { - // TODO: 実装 - return response()->streamDownload(function () { - echo "id,station_neighbor_station,station_name_ruby,station_route_name,park_id,operator_id\n"; - foreach (NeighborStation::all() as $station) { - echo "{$station->id},{$station->station_neighbor_station},{$station->station_name_ruby},{$station->station_route_name},{$station->park_id},{$station->operator_id}\n"; - } - }, 'neighbor_stations.csv'); - } -} diff --git a/app/Http/Controllers/Admin/StationController.php b/app/Http/Controllers/Admin/StationController.php new file mode 100644 index 0000000..beeb510 --- /dev/null +++ b/app/Http/Controllers/Admin/StationController.php @@ -0,0 +1,140 @@ +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'; + } + + // 必要カラムのみ取得 + $stations = Station::select([ + 'station_id', + 'station_neighbor_station', + 'station_name_ruby', + 'station_route_name', + 'park_id', + 'operator_id' + ])->orderBy($sort, $sort_type)->paginate(20); + + return view('admin.stations.list', compact('stations', 'sort', 'sort_type')); + } + + /** + * 新規登録 + */ + public function add(Request $request) + { + if ($request->isMethod('post')) { + $validated = $request->validate([ + 'station_neighbor_station' => 'required|string|max:255', + 'station_name_ruby' => 'nullable|string|max:255', + 'station_route_name' => 'nullable|string|max:255', + 'park_id' => 'nullable|integer', + 'operator_id' => 'nullable|integer', + ]); + + Station::create($validated); + return redirect()->route('stations')->with('success', '近傍駅が登録されました'); + } + + return view('admin.stations.add'); + } + + /** + * 編集 + */ + public function edit(Request $request, $id) + { + $station = Station::findOrFail($id); + + if ($request->isMethod('post')) { + $validated = $request->validate([ + 'station_neighbor_station' => 'required|string|max:255', + 'station_name_ruby' => 'nullable|string|max:255', + 'station_route_name' => 'nullable|string|max:255', + 'park_id' => 'nullable|integer', + 'operator_id' => 'nullable|integer', + ]); + + $station->update($validated); + return redirect()->route('stations')->with('success', '更新しました'); + } + + return view('admin.stations.edit', compact('station')); + } + + /** + * 詳細 + */ + public function info($id) + { + $station = Station::findOrFail($id); + return view('admin.stations.info', compact('station')); + } + + /** + * 削除 + */ + public function delete(Request $request) + { + $ids = $request->input('pk'); // 複数ID対応 + + if (!empty($ids)) { + Station::destroy($ids); + return redirect()->route('stations')->with('success', '削除しました'); + } + + return redirect()->route('stations')->with('error', '削除対象が見つかりません'); + } + + /** + * CSVインポート(仮) + */ + public function import(Request $request) + { + // TODO: 実装予定 + return redirect()->route('stations')->with('info', 'CSVインポートは未実装です'); + } + + /** + * CSVエクスポート + */ + public function export() + { + return response()->streamDownload(function () { + // Excel用のUTF-8 BOM + echo "\xEF\xBB\xBF"; + echo "station_id,station_neighbor_station,station_name_ruby,station_route_name,park_id,operator_id\n"; + + foreach (Station::all() as $station) { + echo "{$station->station_id},{$station->station_neighbor_station},{$station->station_name_ruby},{$station->station_route_name},{$station->park_id},{$station->operator_id}\n"; + } + }, 'stations.csv'); + } +} diff --git a/app/Http/Controllers/Admin/ZoneController.php b/app/Http/Controllers/Admin/ZoneController.php new file mode 100644 index 0000000..1834da8 --- /dev/null +++ b/app/Http/Controllers/Admin/ZoneController.php @@ -0,0 +1,130 @@ +input('action') === 'reset') { + return redirect()->route('zones'); + } + + // ソート設定 + $sort = $request->input('sort', 'zone_id'); + $sort_type = $request->input('sort_type', 'desc'); + + // ベースクエリ + $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); + + return view('admin.zones.list', compact( + 'zones', 'sort', 'sort_type' + )); + } + + /** + * 新規登録 + */ + public function add(Request $request) + { + if ($request->isMethod('post')) { + $data = $this->validateZone($request); + Zone::create($data); + + return redirect()->route('zones') + ->with('success', 'ゾーンを登録しました'); + } + + $zone = new Zone(); + return view('admin.zones.add', compact('zone')); + } + + /** + * 編集 + */ + public function edit($id, Request $request) + { + $zone = Zone::findOrFail($id); + + if ($request->isMethod('post')) { + $data = $this->validateZone($request); + $zone->update($data); + + return redirect()->route('zones') + ->with('success', 'ゾーンを更新しました'); + } + + return view('admin.zones.edit', compact('zone')); + } + + /** + * 詳細表示 + */ + public function info($id) + { + $zone = Zone::findOrFail($id); + + return view('admin.zones.info', compact('zone')); + } + + /** + * 削除 + */ + public function delete(Request $request) + { + $id = $request->input('id'); + if ($id) { + Zone::destroy($id); + return redirect()->route('zones')->with('success', 'ゾーンを削除しました'); + } + return redirect()->route('zones')->with('error', '削除対象が指定されていません'); + } + + /** + * バリデーション共通化 + */ + 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', + ]); + } +} diff --git a/app/Models/InvSetting.php b/app/Models/InvSetting.php new file mode 100644 index 0000000..2c9be1b --- /dev/null +++ b/app/Models/InvSetting.php @@ -0,0 +1,16 @@ +