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); $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', 'unique:tax,tax_day'], ]); $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', 'unique:tax,tax_day,' . $tax->tax_id . ',tax_id'], ]); $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', // ]); // } }