294 lines
10 KiB
PHP
294 lines
10 KiB
PHP
<?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',
|
||
// ]);
|
||
// }
|
||
}
|