311 lines
11 KiB
PHP
311 lines
11 KiB
PHP
<?php
|
||
|
||
namespace App\Http\Controllers\Admin;
|
||
|
||
use App\Http\Requests\PriceRequest;
|
||
use App\Models\Park;
|
||
use App\Models\Price;
|
||
use App\Models\Pplace;
|
||
use App\Models\Psection;
|
||
use App\Models\Ptype;
|
||
use App\Models\Usertype;
|
||
use App\Models\Utils;
|
||
use Illuminate\Support\Facades\DB;
|
||
use Illuminate\Http\Request;
|
||
use App\Http\Controllers\Controller;
|
||
use Illuminate\Support\Facades\Validator;
|
||
use Illuminate\Support\Facades\Response;
|
||
|
||
class PriceController extends Controller
|
||
{
|
||
public function list(Request $request)
|
||
{
|
||
$inputs = [
|
||
'isExport' => 0,
|
||
'sort' => $request->input('sort', ''), // ソート対象カラム
|
||
'sort_type' => $request->input('sort_type', ''), // 昇順/降順
|
||
'page' => $request->get('page', 1),
|
||
];
|
||
|
||
// Price::search 内で orderBy を反映させる
|
||
$inputs['list'] = Price::search($inputs);
|
||
|
||
if ($inputs['list']->total() > 0 && $inputs['page'] > $inputs['list']->lastPage()) {
|
||
return redirect()->route('prices');
|
||
}
|
||
$dataList = $this->getDataDropList();
|
||
$inputs = array_merge($inputs, $dataList);
|
||
|
||
return view('admin.prices.list', $inputs);
|
||
}
|
||
|
||
|
||
public function add(Request $request)
|
||
{
|
||
if ($request->isMethod('get')) {
|
||
return view('admin.prices.add', array_merge(
|
||
$this->getDataDropList(),
|
||
[
|
||
'record' => new Price(),
|
||
'isEdit' => false,
|
||
]
|
||
));
|
||
}
|
||
|
||
$request->merge([
|
||
'pplace_id' => mb_convert_kana($request->input('pplace_id'), 'n'),
|
||
]);
|
||
|
||
$validated = $this->validateRequest($request);
|
||
|
||
$created = false;
|
||
\DB::transaction(function () use ($validated, &$created) {
|
||
$price = new Price();
|
||
$price->fill($validated);
|
||
$created = $price->save();
|
||
});
|
||
|
||
return redirect()->route('prices')
|
||
->with($created ? 'success' : 'error', $created ? '登録しました。' : '登録に失敗しました。');
|
||
}
|
||
|
||
|
||
public function edit(Request $request, $id)
|
||
{
|
||
$price = Price::getByPk($id);
|
||
if (!$price) {
|
||
abort(404);
|
||
}
|
||
|
||
if ($request->isMethod('get')) {
|
||
return view('admin.prices.edit', array_merge(
|
||
$this->getDataDropList(),
|
||
[
|
||
'record' => $price,
|
||
'isEdit' => true,
|
||
]
|
||
));
|
||
}
|
||
|
||
$request->merge([
|
||
'pplace_id' => mb_convert_kana($request->input('pplace_id'), 'n'),
|
||
]);
|
||
|
||
$validated = $this->validateRequest($request, $id);
|
||
|
||
$updated = false;
|
||
\DB::transaction(function () use ($validated, &$updated, $price) {
|
||
$price->fill($validated);
|
||
$updated = $price->save();
|
||
});
|
||
|
||
return redirect()->route('prices')
|
||
->with($updated ? 'success' : 'error', $updated ? '更新しました。' : '更新に失敗しました。');
|
||
}
|
||
|
||
|
||
|
||
public function delete(Request $request, $id = null)
|
||
{
|
||
// 一覧画面(checkbox で複数削除)
|
||
$ids = $request->input('pk');
|
||
|
||
// 編集画面(単体削除)
|
||
if ($id) {
|
||
$ids = [$id];
|
||
}
|
||
|
||
// 削除対象が空
|
||
if (empty($ids)) {
|
||
return redirect()->route('prices')->with('error', '削除対象が選択されていません。');
|
||
}
|
||
|
||
// 削除処理
|
||
Price::destroy($ids);
|
||
|
||
return redirect()->route('prices')->with('success', '削除しました。');
|
||
}
|
||
|
||
|
||
|
||
public static function deleteByPk($ids)
|
||
{
|
||
if (!is_array($ids)) {
|
||
$ids = [$ids];
|
||
}
|
||
return self::whereIn('price_parkplaceid', $ids)->delete();
|
||
}
|
||
|
||
public function export()
|
||
{
|
||
$filename = '駐輪場所、料金マスタ' . now()->format('YmdHis') . '.csv';
|
||
|
||
$file = fopen($filename, 'w+');
|
||
fwrite($file, "\xEF\xBB\xBF"); // BOM追加(UTF-8)
|
||
|
||
$columns = [
|
||
'駐輪場所ID',
|
||
'駐輪場ID',
|
||
'商品名',
|
||
'期間',
|
||
'利用者分類ID',
|
||
'駐輪料金(税込)',
|
||
'車種区分ID',
|
||
'駐輪分類ID',
|
||
'駐車車室ID',
|
||
];
|
||
|
||
fputcsv($file, $columns);
|
||
|
||
$data = Price::all();
|
||
foreach ($data as $item) {
|
||
fputcsv($file, [
|
||
$item->price_parkplaceid, // 駐輪場所ID
|
||
$item->park_id, // 駐輪場ID
|
||
optional($item->getUserType())->print_name, // 利用者分類名
|
||
$item->price_month, // 期間
|
||
optional($item->getUserType())->print_name, // 利用者分類ID
|
||
$item->price, // 駐輪料金(税込)
|
||
optional($item->getPSection())->psection_subject, // 車種区分名
|
||
optional($item->getPType())->ptype_subject, // 駐輪分類名
|
||
$item->pplace_id, // 駐車車室ID
|
||
]);
|
||
}
|
||
|
||
|
||
fclose($file);
|
||
|
||
$headers = [
|
||
"Content-Type" => "text/csv; charset=UTF-8",
|
||
"Content-Disposition" => "attachment; filename={$filename}",
|
||
];
|
||
|
||
return response()->download($filename, $filename, $headers)->deleteFileAfterSend(true);
|
||
}
|
||
|
||
public function import(Request $request)
|
||
{
|
||
$file = $request->file('file');
|
||
if (empty($file)) {
|
||
return redirect()->route('prices')->with('error', __('CSVファイルを選択してください。'));
|
||
}
|
||
|
||
$data = Utils::csvToArray($file);
|
||
$type = true;
|
||
$msg = '';
|
||
$record = 0;
|
||
|
||
DB::beginTransaction();
|
||
try {
|
||
// 先清空数据(全置換仕様なら残す)
|
||
Price::query()->delete();
|
||
|
||
$col = 13; // CSV 項目数
|
||
foreach ($data as $key => $items) {
|
||
$record = $key + 2; // エラー行番号(ヘッダ行を考慮)
|
||
|
||
// 項目数チェック
|
||
if (count($items) != $col) {
|
||
$type = false;
|
||
$msg = "行:{$record} 列数が一致しません。";
|
||
break;
|
||
}
|
||
|
||
// 必須チェック
|
||
if (empty($items[0])) { $type = false; $msg = "行:{$record} 駐車場所IDが未設定です。"; break; }
|
||
if (empty($items[1])) { $type = false; $msg = "行:{$record} 商品名が未設定です。"; break; }
|
||
if (empty($items[2])) { $type = false; $msg = "行:{$record} 期間が未設定です。"; break; }
|
||
if (empty($items[3])) { $type = false; $msg = "行:{$record} 駐輪場IDが未設定です。"; break; }
|
||
if (empty($items[5])) { $type = false; $msg = "行:{$record} 車種区分IDが未設定です。"; break; }
|
||
if (empty($items[7])) { $type = false; $msg = "行:{$record} 駐輪分類IDが未設定です。"; break; }
|
||
if (empty($items[9])) { $type = false; $msg = "行:{$record} 利用者分類IDが未設定です。"; break; }
|
||
if (empty($items[11])) { $type = false; $msg = "行:{$record} 駐車車室IDが未設定です。"; break; }
|
||
if (empty($items[12])) { $type = false; $msg = "行:{$record} 駐輪料金が未設定です。"; break; }
|
||
|
||
// マスタ存在チェック
|
||
if (!Park::where('park_id', $items[3])->exists()) {
|
||
$type = false; $msg = "行:{$record} 駐輪場IDが存在しません。"; break;
|
||
}
|
||
if (!Psection::where('psection_id', $items[5])->exists()) {
|
||
$type = false; $msg = "行:{$record} 車種区分IDが存在しません。"; break;
|
||
}
|
||
if (!Ptype::where('ptype_id', $items[7])->exists()) {
|
||
$type = false; $msg = "行:{$record} 駐輪分類IDが存在しません。"; break;
|
||
}
|
||
if (!Usertype::where('user_categoryid', $items[9])->exists()) {
|
||
$type = false; $msg = "行:{$record} 利用者分類IDが存在しません。"; break;
|
||
}
|
||
// TODO: 駐車車室ID チェック(pplace_id)
|
||
|
||
// 保存
|
||
$row = new Price();
|
||
$row->price_parkplaceid = $items[0];
|
||
$row->prine_name = $items[1];
|
||
$row->price_month = $items[2];
|
||
$row->park_id = $items[3];
|
||
$row->psection_id = $items[5];
|
||
$row->price_ptypeid = $items[7];
|
||
$row->user_categoryid = $items[9];
|
||
$row->pplace_id = $items[11];
|
||
$row->price = $items[12];
|
||
|
||
if (!$row->save()) {
|
||
$type = false; $msg = "行:{$record} データ保存に失敗しました。"; break;
|
||
}
|
||
}
|
||
} catch (\Exception $e) {
|
||
$type = false;
|
||
$msg = "行:{$record} 予期せぬエラー: ".$e->getMessage();
|
||
}
|
||
|
||
if ($type) {
|
||
DB::commit();
|
||
return redirect()->route('prices')->with('success', __('インポートが正常に完了しました。'));
|
||
} else {
|
||
DB::rollBack();
|
||
return redirect()->route('prices')->with('error', $msg);
|
||
}
|
||
}
|
||
|
||
|
||
public function info(Request $request, $id)
|
||
{
|
||
return $this->edit($request, $id, 'admin.prices.info');
|
||
}
|
||
|
||
public function getDataDropList()
|
||
{
|
||
$data['parks'] = Park::getList() ;
|
||
$data['psections'] = Psection::getList() ;
|
||
$data['ptypes'] = Ptype::getList() ;
|
||
$data['userTypes'] = Usertype::getList() ;
|
||
$data['pplaces'] = Pplace::getList() ;
|
||
|
||
return $data;
|
||
}
|
||
|
||
/**
|
||
* Price バリデーション共通
|
||
*/
|
||
private function validateRequest(Request $request): array
|
||
{
|
||
return $request->validate([
|
||
'prine_name' => 'required|string|max:255',
|
||
'price_month' => 'required|int',
|
||
'park_id' => 'required|int',
|
||
'psection_id' => 'required|int',
|
||
'price_ptypeid' => 'required|int',
|
||
'user_categoryid' => 'required|int',
|
||
'pplace_id' => 'nullable|int',
|
||
'park_number' => 'nullable|int',
|
||
'park_standard' => 'nullable|int',
|
||
'park_limit' => 'nullable|int',
|
||
'price' => 'required|numeric',
|
||
'operator_id' => 'nullable|int',
|
||
]);
|
||
}
|
||
|
||
|
||
|
||
|
||
} |