881 lines
38 KiB
PHP
881 lines
38 KiB
PHP
<?php
|
||
|
||
namespace App\Http\Controllers\Admin;
|
||
|
||
use Illuminate\Http\Request;
|
||
use Illuminate\Support\Facades\DB;
|
||
use Illuminate\Support\Facades\Validator;
|
||
use App\Models\Park;
|
||
use Illuminate\Support\Carbon;
|
||
|
||
class RegularContractController
|
||
{
|
||
/**
|
||
* 利用者分類選択肢(user_categoryid 昇順)
|
||
*/
|
||
private function buildUsertypeOptions(): array
|
||
{
|
||
return DB::table('usertype as t')
|
||
->join('regular_contract as rc', 'rc.user_categoryid', '=', 't.user_categoryid')
|
||
->select('t.user_categoryid', 't.usertype_subject1', 't.usertype_subject2', 't.usertype_subject3')
|
||
->groupBy('t.user_categoryid', 't.usertype_subject1', 't.usertype_subject2', 't.usertype_subject3')
|
||
->orderBy('t.user_categoryid', 'asc')
|
||
->get()
|
||
->mapWithKeys(function ($row) {
|
||
$label = collect([
|
||
$row->usertype_subject1 ?? '',
|
||
$row->usertype_subject2 ?? '',
|
||
$row->usertype_subject3 ?? '',
|
||
])->filter(fn ($v) => $v !== '')->implode('/');
|
||
|
||
return [$row->user_categoryid => $label !== '' ? $label : (string) $row->user_categoryid];
|
||
})
|
||
->toArray();
|
||
}
|
||
|
||
private function buildParkOptions(): array
|
||
{
|
||
return Park::query()
|
||
->join('regular_contract as rc', 'rc.park_id', '=', 'park.park_id')
|
||
->select('park.park_id', 'park.park_name')
|
||
->groupBy('park.park_id', 'park.park_name')
|
||
->orderBy('park.park_id', 'asc')
|
||
->get()
|
||
->mapWithKeys(fn ($park) => [
|
||
$park->park_id => $park->park_name ?: (string) $park->park_id,
|
||
])
|
||
->toArray();
|
||
}
|
||
|
||
/**
|
||
* datetime-local から受け取った値を Y-m-d H:i:s へ正規化
|
||
*/
|
||
private function normalizeDateTimeInput(?string $value, bool $endOfMinute = false): ?string
|
||
{
|
||
if ($value === null) {
|
||
return null;
|
||
}
|
||
$value = trim($value);
|
||
if ($value === '') {
|
||
return null;
|
||
}
|
||
$value = str_replace('T', ' ', $value);
|
||
if (strlen($value) === 16) {
|
||
$value .= ':00';
|
||
}
|
||
try {
|
||
$dt = Carbon::parse($value);
|
||
if ($endOfMinute) {
|
||
$dt = $dt->endOfMinute();
|
||
}
|
||
return $dt->format('Y-m-d H:i:s');
|
||
} catch (\Throwable $e) {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 名寄フリガナ検索用:全角カナへ統一し空白除去
|
||
*/
|
||
private function normalizePhoneticKeyword(?string $value): ?string
|
||
{
|
||
if ($value === null) {
|
||
return null;
|
||
}
|
||
$value = trim((string) $value);
|
||
if ($value === '') {
|
||
return null;
|
||
}
|
||
$value = mb_convert_kana($value, 'KVCS');
|
||
return str_replace([' ', ' '], '', $value);
|
||
}
|
||
|
||
/**
|
||
* 定期契約一覧
|
||
* - ベース表: regular_contract(rc)
|
||
* - 付加情報: user(u), usertype(t), park(p)
|
||
* - 画面変数: $list, $sort, $sort_type(既存に合わせる)
|
||
*/
|
||
public function list(Request $request)
|
||
{
|
||
if ($request->isMethod('post')) {
|
||
$postParams = $request->except(['_token']);
|
||
$queryParams = $request->query();
|
||
|
||
return redirect()->route('regularcontracts', array_merge($queryParams, $postParams));
|
||
}
|
||
|
||
$params = $request->query();
|
||
|
||
// ===== ソート(既定: contract_id ASC)=====
|
||
$sort = $params['sort'] ?? 'contract_id';
|
||
$sortType = strtolower($params['sort_type'] ?? 'asc') === 'desc' ? 'desc' : 'asc';
|
||
|
||
// ===== 絞り込み(テキスト系)=====
|
||
$contract_qr_id = trim((string) ($params['contract_qr_id'] ?? ''));
|
||
$user_id = trim((string) ($params['user_id'] ?? ''));
|
||
$user_tag_serial = trim((string) ($params['user_tag_serial'] ?? ''));
|
||
$park_id = trim((string) ($params['park_id'] ?? ''));
|
||
$selectedParkId = trim((string) ($params['selected_park_id'] ?? ''));
|
||
$user_phonetic = trim((string) ($params['user_phonetic'] ?? ''));
|
||
$phone = trim((string) ($params['phone'] ?? ''));
|
||
$email = trim((string) ($params['email'] ?? ''));
|
||
$user_categoryid = trim((string) ($params['user_categoryid'] ?? ''));
|
||
$park_name_kw = trim((string) ($params['park_name'] ?? ''));
|
||
$zone_keyword = trim((string) ($params['zone_keyword'] ?? ''));
|
||
$zone_name = trim((string) ($params['zone_name'] ?? ''));
|
||
$merge_phonetic_input = $params['merge_phonetic'] ?? '';
|
||
$merge_phonetic = trim((string) $merge_phonetic_input);
|
||
$merge_phonetic_normalized = $this->normalizePhoneticKeyword($merge_phonetic);
|
||
$has_address = $params['has_address'] ?? '';
|
||
$workRecordFilter = (string) ($params['work_record'] ?? '0');
|
||
if (!in_array($workRecordFilter, ['0', '1', '2'], true)) {
|
||
$workRecordFilter = '0';
|
||
}
|
||
|
||
// ===== 絞り込み(日付範囲)=====
|
||
$reserve_from = $params['reserve_date_from'] ?? '';
|
||
$reserve_to = $params['reserve_date_to'] ?? '';
|
||
$created_from = $params['contract_created_from'] ?? '';
|
||
$created_to = $params['contract_created_to'] ?? '';
|
||
$updated_from = $params['contract_updated_from'] ?? '';
|
||
$updated_to = $params['contract_updated_to'] ?? '';
|
||
$canceled_from = $params['contract_canceled_from'] ?? '';
|
||
$canceled_to = $params['contract_canceled_to'] ?? '';
|
||
$receipt_delivery_from = $params['receipt_delivery_from'] ?? '';
|
||
$receipt_delivery_to = $params['receipt_delivery_to'] ?? '';
|
||
$contract_valid_months = $params['contract_valid_months'] ?? '';
|
||
|
||
// ===== 列挙(全て/0/1)=====
|
||
$contract_flag = $params['contract_flag'] ?? '';
|
||
$contract_permission = $params['contract_permission'] ?? '';
|
||
$tag_qr_flag = $params['tag_qr_flag'] ?? '';
|
||
$updateFlagFilter = (string) ($params['update_flag'] ?? '0');
|
||
if (!in_array($updateFlagFilter, ['0', '1', '2'], true)) {
|
||
$updateFlagFilter = '0';
|
||
}
|
||
$contract_cancel_flag = $params['contract_cancel_flag'] ?? '';
|
||
|
||
// ===== クエリ(結合込み)=====
|
||
$q = DB::table('regular_contract as rc')
|
||
->leftJoin('user as u', 'u.user_id', '=', 'rc.user_id')
|
||
->leftJoin('usertype as t', 't.user_categoryid', '=', 'rc.user_categoryid')
|
||
->leftJoin('park as p', 'p.park_id', '=', 'rc.park_id')
|
||
->leftJoin('zone as z', 'z.zone_id', '=', 'rc.zone_id')
|
||
->select([
|
||
'rc.*',
|
||
'u.user_seq',
|
||
'u.user_name',
|
||
'u.user_phonetic',
|
||
'u.user_mobile',
|
||
'u.user_homephone',
|
||
'u.user_primemail',
|
||
'u.user_regident_zip',
|
||
'u.user_tag_serial',
|
||
DB::raw('t.print_name as usertype_name'),
|
||
't.usertype_subject1',
|
||
't.usertype_subject2',
|
||
't.usertype_subject3',
|
||
DB::raw('p.park_name as park_name'),
|
||
DB::raw('z.zone_name as zone_name'),
|
||
]);
|
||
|
||
// ===== LIKE / キーワード =====
|
||
if ($contract_qr_id !== '') {
|
||
$q->where('rc.contract_qr_id', 'like', "%{$contract_qr_id}%");
|
||
}
|
||
if ($user_id !== '') {
|
||
$q->where('rc.user_id', 'like', "%{$user_id}%");
|
||
}
|
||
if ($user_tag_serial !== '') {
|
||
$q->where('u.user_tag_serial', 'like', "%{$user_tag_serial}%");
|
||
}
|
||
if ($park_id !== '') {
|
||
$q->where('rc.park_id', (int) $park_id);
|
||
} elseif ($selectedParkId !== '') {
|
||
$q->where('rc.park_id', (int) $selectedParkId);
|
||
}
|
||
if ($user_phonetic !== '') {
|
||
$q->where('u.user_phonetic', 'like', "%{$user_phonetic}%");
|
||
}
|
||
if ($email !== '') {
|
||
$q->where('u.user_primemail', 'like', "%{$email}%");
|
||
}
|
||
if ($user_categoryid !== '') {
|
||
$q->where('rc.user_categoryid', (int) $user_categoryid);
|
||
}
|
||
if ($park_name_kw !== '') {
|
||
$q->where('p.park_name', 'like', "%{$park_name_kw}%");
|
||
}
|
||
if ($zone_name !== '') {
|
||
$q->where('z.zone_name', 'like', "%{$zone_name}%");
|
||
}
|
||
if ($merge_phonetic_normalized !== null) {
|
||
$likeKeyword = '%' . $merge_phonetic_normalized . '%';
|
||
$q->whereRaw("REPLACE(REPLACE(IFNULL(rc.chk_user_phonetic, ''), ' ', ''), ' ', '') LIKE ?", [$likeKeyword]);
|
||
}
|
||
if ($phone !== '') {
|
||
$q->where(function ($w) use ($phone) {
|
||
$w->where('u.user_mobile', 'like', "%{$phone}%")
|
||
->orWhere('u.user_homephone', 'like', "%{$phone}%");
|
||
});
|
||
}
|
||
if ($reserve_from !== '' && ($normalized = $this->normalizeDateTimeInput($reserve_from))) {
|
||
$q->where('rc.reserve_date', '>=', $normalized);
|
||
}
|
||
if ($reserve_to !== '' && ($normalized = $this->normalizeDateTimeInput($reserve_to, true))) {
|
||
$q->where('rc.reserve_date', '<=', $normalized);
|
||
}
|
||
if ($receipt_delivery_from !== '' && ($normalized = $this->normalizeDateTimeInput($receipt_delivery_from))) {
|
||
$q->where('rc.contract_payment_day', '>=', $normalized);
|
||
}
|
||
if ($receipt_delivery_to !== '' && ($normalized = $this->normalizeDateTimeInput($receipt_delivery_to, true))) {
|
||
$q->where('rc.contract_payment_day', '<=', $normalized);
|
||
}
|
||
if ($zone_keyword !== '') {
|
||
$q->where(function ($w) use ($zone_keyword) {
|
||
$w->where('rc.zone_id', 'like', "%{$zone_keyword}%")
|
||
->orWhere('rc.pplace_no', 'like', "%{$zone_keyword}%")
|
||
->orWhere('rc.old_contract_id', 'like', "%{$zone_keyword}%");
|
||
});
|
||
}
|
||
if ($workRecordFilter === '1') {
|
||
$q->where(function ($w) {
|
||
$w->whereNull('rc.contract_flag')
|
||
->orWhere('rc.contract_flag', '=', 0);
|
||
});
|
||
} elseif ($workRecordFilter === '2') {
|
||
$q->where('rc.contract_flag', '=', 1);
|
||
}
|
||
if ($created_from !== '' && ($normalized = $this->normalizeDateTimeInput($created_from))) {
|
||
$q->where('rc.contract_created_at', '>=', $normalized);
|
||
}
|
||
if ($created_to !== '' && ($normalized = $this->normalizeDateTimeInput($created_to, true))) {
|
||
$q->where('rc.contract_created_at', '<=', $normalized);
|
||
}
|
||
if ($updated_from !== '' && ($normalized = $this->normalizeDateTimeInput($updated_from))) {
|
||
$q->where('rc.contract_updated_at', '>=', $normalized);
|
||
}
|
||
if ($updated_to !== '' && ($normalized = $this->normalizeDateTimeInput($updated_to, true))) {
|
||
$q->where('rc.contract_updated_at', '<=', $normalized);
|
||
}
|
||
if ($canceled_from !== '' && ($normalized = $this->normalizeDateTimeInput($canceled_from))) {
|
||
$q->where('rc.contract_cancelday', '>=', $normalized);
|
||
}
|
||
if ($canceled_to !== '' && ($normalized = $this->normalizeDateTimeInput($canceled_to, true))) {
|
||
$q->where('rc.contract_cancelday', '<=', $normalized);
|
||
}
|
||
if ($contract_valid_months !== '') {
|
||
$q->where('rc.enable_months', (int) $contract_valid_months);
|
||
}
|
||
if ($contract_flag !== '') {
|
||
$q->where('rc.contract_flag', (int) $contract_flag);
|
||
}
|
||
if ($contract_permission !== '') {
|
||
$q->where('rc.contract_permission', (int) $contract_permission);
|
||
}
|
||
if ($tag_qr_flag !== '') {
|
||
$q->where('rc.tag_qr_flag', (int) $tag_qr_flag);
|
||
}
|
||
if ($updateFlagFilter === '1') {
|
||
$q->where('rc.update_flag', '=', 1);
|
||
} elseif ($updateFlagFilter === '2') {
|
||
$q->where(function ($w) {
|
||
$w->whereNull('rc.update_flag')
|
||
->orWhere('rc.update_flag', '!=', 1);
|
||
});
|
||
}
|
||
if ($contract_cancel_flag !== '') {
|
||
$q->where('rc.contract_cancel_flag', (int) $contract_cancel_flag);
|
||
}
|
||
|
||
// ===== ソート(仮想列は結合側にマッピング)=====
|
||
$sortable = [
|
||
'contract_id', 'contract_qr_id', 'old_contract_id', 'zone_id', 'zone_name', 'pplace_no',
|
||
'contract_periods', 'contract_periode', 'user_id', 'user_categoryid', 'reserve_id', 'park_id',
|
||
'price_parkplaceid', 'user_securitynum', 'reserve_date', 'contract_reserve', 'contract_created_at',
|
||
'contract_updated_at', 'contract_cancelday', 'contract_reduction', 'enable_months', 'printable_date',
|
||
'billing_amount', 'contract_payment_day', 'contract_money', 'refunds', 'contract_flag',
|
||
'contract_permission', 'contract_cancel_flag', 'tag_qr_flag', 'update_flag', 'pplace_allocation_flag',
|
||
'settlement_transaction_id', 'contract_seal_issue', 'storage_company_code', 'share_storage_company_code',
|
||
'ope_id', 'park_position', 'contract_manual', 'contract_notice', 'contract_payment_number',
|
||
'user_name', 'user_phonetic', 'user_mobile', 'user_homephone', 'user_primemail', 'user_regident_zip',
|
||
'usertype_name', 'park_name',
|
||
];
|
||
if (!in_array($sort, $sortable, true)) {
|
||
$sort = 'contract_id';
|
||
}
|
||
$sortMap = [
|
||
'user_name' => 'u.user_name',
|
||
'user_phonetic' => 'u.user_phonetic',
|
||
'user_mobile' => 'u.user_mobile',
|
||
'user_homephone' => 'u.user_homephone',
|
||
'user_primemail' => 'u.user_primemail',
|
||
'user_regident_zip' => 'u.user_regident_zip',
|
||
'usertype_name' => 't.print_name',
|
||
'park_name' => 'p.park_name',
|
||
'zone_name' => 'z.zone_name',
|
||
];
|
||
$sortColumn = $sortMap[$sort] ?? ('rc.' . $sort);
|
||
|
||
$list = $q->orderBy($sortColumn, $sortType)->paginate(50)->withQueryString();
|
||
|
||
// ===== 画面へ(Blade 側が参照するすべての変数を渡す)=====
|
||
return view('admin.regularcontracts.list', [
|
||
'list' => $list,
|
||
'sort' => $sort,
|
||
'sort_type' => $sortType,
|
||
|
||
// 入力保持(テキスト)
|
||
'contract_qr_id' => $contract_qr_id,
|
||
'user_id' => $user_id,
|
||
'user_tag_serial' => $user_tag_serial,
|
||
'park_id' => $selectedParkId !== '' ? $selectedParkId : $park_id,
|
||
'user_phonetic' => $user_phonetic,
|
||
'phone' => $phone,
|
||
'email' => $email,
|
||
'user_categoryid' => $user_categoryid,
|
||
'park_name' => $park_name_kw,
|
||
'zone_keyword' => $zone_keyword,
|
||
'zone_name' => $zone_name,
|
||
'merge_phonetic' => $merge_phonetic,
|
||
'has_address' => $has_address,
|
||
'work_record' => $workRecordFilter,
|
||
|
||
// 入力保持(日付)
|
||
'reserve_date_from' => $reserve_from,
|
||
'reserve_date_to' => $reserve_to,
|
||
'contract_created_from' => $created_from,
|
||
'contract_created_to' => $created_to,
|
||
'contract_updated_from' => $updated_from,
|
||
'contract_updated_to' => $updated_to,
|
||
'contract_canceled_from' => $canceled_from,
|
||
'contract_canceled_to' => $canceled_to,
|
||
'receipt_delivery_from' => $receipt_delivery_from,
|
||
'receipt_delivery_to' => $receipt_delivery_to,
|
||
'contract_valid_months' => $contract_valid_months,
|
||
|
||
// 入力保持(列挙)
|
||
'contract_flag' => $contract_flag,
|
||
'contract_permission' => $contract_permission,
|
||
'tag_qr_flag' => $tag_qr_flag,
|
||
'update_flag' => $updateFlagFilter,
|
||
'contract_cancel_flag' => $contract_cancel_flag,
|
||
|
||
'userTypeOptions' => $this->buildUsertypeOptions(),
|
||
'parkOptions' => $this->buildParkOptions(),
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 定期契約編集(GET: 画面表示 / POST: 更新実行)
|
||
* - 主キー: contract_id
|
||
*/
|
||
public function edit(Request $request, $id)
|
||
{
|
||
$id = (int) $id;
|
||
|
||
if ($request->isMethod('get')) {
|
||
$row = DB::table('regular_contract')->where('contract_id', $id)->first();
|
||
if (!$row) {
|
||
abort(404);
|
||
}
|
||
return view('admin.regularcontracts.edit', [
|
||
'row' => $row,
|
||
'contract_id' => $id,
|
||
]);
|
||
}
|
||
|
||
$v = Validator::make($request->all(), [
|
||
'user_id' => ['required', 'integer'],
|
||
'park_id' => ['required', 'integer'],
|
||
// 任意項目
|
||
'contract_qr_id' => ['nullable', 'string', 'max:255'],
|
||
'user_categoryid' => ['nullable', 'integer'],
|
||
'reserve_id' => ['nullable', 'integer'],
|
||
'price_parkplaceid' => ['nullable', 'integer'],
|
||
'user_securitynum' => ['nullable', 'string', 'max:255'],
|
||
'reserve_date' => ['nullable', 'date'],
|
||
'contract_reserve' => ['nullable', 'string', 'max:255'],
|
||
'contract_created_at' => ['nullable', 'date'],
|
||
'contract_updated_at' => ['nullable', 'date'],
|
||
'contract_cancelday' => ['nullable', 'date'],
|
||
'contract_flag' => ['nullable', 'integer'],
|
||
'contract_permission' => ['nullable', 'integer'],
|
||
'contract_cancel_flag' => ['nullable', 'integer'],
|
||
'tag_qr_flag' => ['nullable', 'integer'],
|
||
'park_position' => ['nullable', 'string', 'max:255'],
|
||
'ope_id' => ['nullable', 'integer'],
|
||
]);
|
||
|
||
if ($v->fails()) {
|
||
return back()->withErrors($v)->withInput();
|
||
}
|
||
|
||
$data = [
|
||
'contract_qr_id' => $request->input('contract_qr_id'),
|
||
'user_id' => (int) $request->input('user_id'),
|
||
'user_categoryid' => $request->input('user_categoryid'),
|
||
'reserve_id' => $request->input('reserve_id'),
|
||
'park_id' => (int) $request->input('park_id'),
|
||
'price_parkplaceid' => $request->input('price_parkplaceid'),
|
||
'user_securitynum' => $request->input('user_securitynum'),
|
||
'reserve_date' => $request->input('reserve_date'),
|
||
'contract_reserve' => $request->input('contract_reserve'),
|
||
'contract_created_at' => $request->input('contract_created_at'),
|
||
'contract_updated_at' => $request->input('contract_updated_at'),
|
||
'contract_cancelday' => $request->input('contract_cancelday'),
|
||
'contract_flag' => $request->input('contract_flag'),
|
||
'contract_permission' => $request->input('contract_permission'),
|
||
'contract_cancel_flag' => $request->input('contract_cancel_flag'),
|
||
'tag_qr_flag' => $request->input('tag_qr_flag'),
|
||
'park_position' => $request->input('park_position'),
|
||
'ope_id' => $request->input('ope_id'),
|
||
'updated_at' => now(),
|
||
];
|
||
|
||
DB::table('regular_contract')->where('contract_id', $id)->update($data);
|
||
|
||
return redirect()->route('regularcontracts')->with('success', '定期契約を更新しました。');
|
||
}
|
||
|
||
/**
|
||
* 定期契約削除
|
||
* - 物理削除(必要なら cancel フラグ運用に切替)
|
||
*/
|
||
public function delete(Request $request)
|
||
{
|
||
$ids = $request->input('ids', []);
|
||
if (!is_array($ids)) {
|
||
$ids = [$ids];
|
||
}
|
||
$ids = array_values(array_filter(
|
||
array_map('intval', $ids),
|
||
static fn (int $v) => $v > 0
|
||
));
|
||
|
||
if (empty($ids)) {
|
||
return redirect()->route('regularcontracts')
|
||
->with('error', '削除する定期契約が選択されていません。');
|
||
}
|
||
|
||
DB::table('regular_contract')
|
||
->whereIn('contract_id', $ids)
|
||
->delete();
|
||
|
||
return redirect()->route('regularcontracts')->with('success', '定期契約を削除しました。');
|
||
}
|
||
|
||
/**
|
||
* 定期契約インポート(仮実装)
|
||
*/
|
||
public function import(Request $request)
|
||
{
|
||
if ($request->isMethod('get')) {
|
||
// GET で来たら一覧へ
|
||
return redirect()->route('regularcontracts');
|
||
}
|
||
|
||
// ファイル必須 & 形式チェック
|
||
$request->validate([
|
||
'file' => ['required', 'file', 'mimetypes:text/plain,text/csv,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
|
||
], [], [
|
||
'file' => 'インポートファイル',
|
||
]);
|
||
|
||
$file = $request->file('file');
|
||
|
||
// TODO: ここで実際のインポート処理(CSV/XLSXの解析とレコード登録)を書く
|
||
// 例:Storage::putFile('imports', $file); で一旦保存してバッチに回す etc.
|
||
|
||
return redirect()->route('regularcontracts')->with('success', 'インポートを受け付けました。');
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* 定期契約エクスポート(仮実装)
|
||
* - 現時点では何もしません。ルーティング確認用のプレーンテキストを返します。
|
||
* - 後で CSV / Excel 出力処理に置き換えてください。
|
||
*/
|
||
|
||
public function export(Request $request)
|
||
{
|
||
$params = $request->all();
|
||
$sort = $params['sort'] ?? 'contract_id';
|
||
$sortType = strtolower($params['sort_type'] ?? 'asc') === 'desc' ? 'desc' : 'asc';
|
||
$type = (string) ($request->query('type') ?? '');
|
||
|
||
$fileName = match ($type) {
|
||
'smbc' => '定期契約マスタ_SMBC.csv',
|
||
'city' => '定期契約マスタ_役所提出用.csv',
|
||
default => '定期契約マスタ.csv',
|
||
};
|
||
|
||
$query = $this->buildListQuery($params);
|
||
|
||
$columns = [
|
||
'contract_id' => '契約ID',
|
||
'contract_qr_id' => '定期契約ID',
|
||
'old_contract_id' => '旧定期契約番号',
|
||
'pplace_no' => '車室番号',
|
||
'user_id' => '利用者ID',
|
||
'user_categoryid' => '利用者分類ID',
|
||
'tag_qr_flag' => 'タグ・QR',
|
||
'park_id' => '駐輪場ID',
|
||
'reserve_date' => '予約日時',
|
||
'contract_periods' => '有効期間S',
|
||
'contract_periode' => '有効期間E',
|
||
'price_parkplaceid' => '駐輪場所ID',
|
||
'user_securitynum' => '防犯登録番号',
|
||
'contract_created_at' => '契約日時',
|
||
'contract_updated_at' => '更新可能日',
|
||
'contract_cancelday' => '解約日時',
|
||
'contract_reduction' => '減免措置',
|
||
'enable_months' => '定期有効月数',
|
||
'printable_date' => 'シール印刷可能日',
|
||
'billing_amount' => '請求金額',
|
||
'pplace_allocation_flag' => '車室割り当てフラグ',
|
||
'contract_payment_day' => '授受日時',
|
||
'contract_money' => '授受金額',
|
||
'contract_flag' => '授受フラグ',
|
||
'settlement_transaction_id' => '決済トランザクションID',
|
||
'contract_seal_issue' => 'シール発行数',
|
||
'storage_company_code' => '収納企業コード',
|
||
'share_storage_company_code' => '共有先収納企業コード',
|
||
'accept_number' => '受付番号',
|
||
'update_flag' => '(更新元)契約更新済フラグ',
|
||
'vehicle_type_id' => '車種区分ID',
|
||
'chk_user_phonetic' => 'チェック用_フリガナ',
|
||
'user_regident_zip' => 'チェック用_居住所郵便番号',
|
||
'user_mobile' => 'チェック用_携帯電話番号',
|
||
'user_homephone' => 'チェック用_自宅電話番号',
|
||
'old_member_number' => 'チェック用_旧会員番号',
|
||
'user_name' => '利用者氏名',
|
||
'user_phonetic' => '利用者フリガナ',
|
||
'park_name' => '駐輪場名',
|
||
'zone_name' => 'ゾーン名',
|
||
'usertype_name' => '利用者分類名',
|
||
];
|
||
|
||
$dateColumns = [
|
||
'contract_periods',
|
||
'contract_periode',
|
||
'contract_created_at',
|
||
'contract_updated_at',
|
||
'contract_cancelday',
|
||
'printable_date',
|
||
'contract_payment_day',
|
||
'reserve_date',
|
||
];
|
||
|
||
$rows = $query->orderBy($sort, $sortType)->get();
|
||
|
||
$headers = [
|
||
'Content-Type' => 'text/csv; charset=Shift_JIS',
|
||
'Content-Disposition' => "attachment; filename=\"{$fileName}\"",
|
||
];
|
||
|
||
return response()->streamDownload(function () use ($rows, $columns, $dateColumns) {
|
||
$handle = fopen('php://output', 'w');
|
||
|
||
$headerRow = array_map(fn ($label) => mb_convert_encoding($label, 'SJIS-win', 'UTF-8'), array_values($columns));
|
||
fputcsv($handle, $headerRow);
|
||
|
||
foreach ($rows as $row) {
|
||
$line = [];
|
||
foreach ($columns as $key => $label) {
|
||
$value = $row->{$key} ?? '';
|
||
|
||
if (in_array($key, $dateColumns, true) && $value) {
|
||
try {
|
||
$value = \Illuminate\Support\Carbon::parse($value)->format(str_contains($key, '_day') || str_contains($key, '_date') ? 'Y-m-d H:i' : 'Y-m-d');
|
||
} catch (\Throwable $e) {
|
||
$value = (string) $value;
|
||
}
|
||
} elseif ($key === 'tag_qr_flag' && $value !== '') {
|
||
$value = ((int) $value) === 1 ? 'QR' : 'タグ';
|
||
} elseif ($key === 'pplace_allocation_flag' && $value !== '') {
|
||
$value = ((int) $value) === 1 ? '割当済' : '未割当';
|
||
} elseif ($key === 'contract_flag' && $value !== '') {
|
||
$value = ((int) $value) === 1 ? '済' : '未';
|
||
} elseif ($key === 'update_flag' && $value !== '') {
|
||
$value = ((int) $value) === 1 ? '更新済' : '未更新';
|
||
}
|
||
|
||
$line[] = mb_convert_encoding((string) $value, 'SJIS-win', 'UTF-8');
|
||
}
|
||
fputcsv($handle, $line);
|
||
}
|
||
|
||
fclose($handle);
|
||
}, $fileName, $headers);
|
||
}
|
||
|
||
|
||
|
||
|
||
// 追加:新規登録(GET: 画面表示 / POST: 登録実行)
|
||
public function add(Request $request)
|
||
{
|
||
// 画面表示
|
||
if ($request->isMethod('get')) {
|
||
return view('admin.regularcontracts.add');
|
||
}
|
||
|
||
// ========= バリデーション =========
|
||
// ※ 必須最小限。その他は任意(nullable)
|
||
$v = Validator::make(
|
||
$request->all(),
|
||
[
|
||
'user_id' => ['required', 'integer'],
|
||
'park_id' => ['required', 'integer'],
|
||
'contract_qr_id' => ['nullable', 'string', 'max:255'],
|
||
'user_categoryid' => ['nullable', 'integer'],
|
||
'reserve_id' => ['nullable', 'integer'],
|
||
'price_parkplaceid' => ['nullable', 'integer'],
|
||
'reserve_date' => ['nullable', 'date'],
|
||
'contract_created_at' => ['nullable', 'date'],
|
||
'contract_cancelday' => ['nullable', 'date'],
|
||
'contract_permission' => ['nullable', 'integer'],
|
||
'contract_cancel_flag' => ['nullable', 'integer'],
|
||
'tag_qr_flag' => ['nullable', 'integer'],
|
||
'update_flag' => ['nullable', 'integer'],
|
||
'park_position' => ['nullable', 'string', 'max:255'],
|
||
'ope_id' => ['nullable', 'integer'],
|
||
// 画面の「定期有効月数」は DB の contract_valid_months に保存する
|
||
'enable_months' => ['nullable', 'integer', 'min:0'],
|
||
],
|
||
[],
|
||
[
|
||
'user_id' => '利用者ID',
|
||
'park_id' => '駐輪場ID',
|
||
'contract_qr_id' => '定期契約QRID',
|
||
'user_categoryid' => '利用者分類ID',
|
||
'reserve_id' => '定期予約ID',
|
||
'price_parkplaceid' => '駐輪場所ID',
|
||
'reserve_date' => '予約日時',
|
||
'contract_created_at' => '契約日時',
|
||
'contract_cancelday' => '解約日時',
|
||
'contract_permission' => 'シール発行許可',
|
||
'contract_cancel_flag' => '解約フラグ',
|
||
'tag_qr_flag' => 'タグ・QR',
|
||
'update_flag' => '(更新元)契約更新済フラグ',
|
||
'park_position' => '駐輪位置番号',
|
||
'ope_id' => 'オペレータID',
|
||
'enable_months' => '定期有効月数',
|
||
]
|
||
);
|
||
|
||
if ($v->fails()) {
|
||
return back()->withErrors($v)->withInput();
|
||
}
|
||
|
||
// ========= 登録データ作成 =========
|
||
// ここでは「regular_contract」テーブルに確実にある列を中心に保存します。
|
||
// 追加したい列があれば、同様にキーを増やして下さい。
|
||
$data = [
|
||
'contract_qr_id' => $request->input('contract_qr_id'),
|
||
'user_id' => (int) $request->input('user_id'),
|
||
'user_categoryid' => $request->input('user_categoryid'),
|
||
'reserve_id' => $request->input('reserve_id'),
|
||
'park_id' => (int) $request->input('park_id'),
|
||
'price_parkplaceid' => $request->input('price_parkplaceid'),
|
||
'reserve_date' => $request->input('reserve_date'),
|
||
'contract_created_at' => $request->input('contract_created_at') ?: now(), // 未指定なら現在時刻
|
||
'contract_cancelday' => $request->input('contract_cancelday'),
|
||
'contract_permission' => $request->input('contract_permission'),
|
||
'contract_cancel_flag' => $request->input('contract_cancel_flag'),
|
||
'tag_qr_flag' => $request->input('tag_qr_flag'),
|
||
'update_flag' => $request->input('update_flag'),
|
||
'park_position' => $request->input('park_position'),
|
||
'ope_id' => $request->input('ope_id'),
|
||
// 画面の enable_months → DB の contract_valid_months
|
||
'contract_valid_months' => $request->input('enable_months'),
|
||
'created_at' => now(),
|
||
'updated_at' => now(),
|
||
];
|
||
|
||
DB::table('regular_contract')->insert($data);
|
||
|
||
return redirect()
|
||
->route('regularcontracts')
|
||
->with('success', '定期契約を登録しました。');
|
||
}
|
||
|
||
private function buildListQuery(array $params)
|
||
{
|
||
$contract_qr_id = trim((string)($params['contract_qr_id'] ?? ''));
|
||
$user_id = trim((string)($params['user_id'] ?? ''));
|
||
$user_tag_serial = trim((string)($params['user_tag_serial'] ?? ''));
|
||
$park_id = trim((string)($params['park_id'] ?? ''));
|
||
$selectedParkId = trim((string)($params['selected_park_id'] ?? ''));
|
||
$user_phonetic = trim((string)($params['user_phonetic'] ?? ''));
|
||
$phone = trim((string)($params['phone'] ?? ''));
|
||
$email = trim((string)($params['email'] ?? ''));
|
||
$user_categoryid = trim((string)($params['user_categoryid'] ?? ''));
|
||
$park_name_kw = trim((string)($params['park_name'] ?? ''));
|
||
$zone_keyword = trim((string)($params['zone_keyword'] ?? ''));
|
||
$zone_name = trim((string)($params['zone_name'] ?? ''));
|
||
$merge_phonetic_input = $params['merge_phonetic'] ?? '';
|
||
$merge_phonetic = trim((string)$merge_phonetic_input);
|
||
$merge_phonetic_normalized = $this->normalizePhoneticKeyword($merge_phonetic);
|
||
$workRecordFilter = (string)($params['work_record'] ?? '0');
|
||
if (!in_array($workRecordFilter, ['0', '1', '2'], true)) {
|
||
$workRecordFilter = '0';
|
||
}
|
||
$reserve_from = $params['reserve_date_from'] ?? '';
|
||
$reserve_to = $params['reserve_date_to'] ?? '';
|
||
$created_from = $params['contract_created_from'] ?? '';
|
||
$created_to = $params['contract_created_to'] ?? '';
|
||
$updated_from = $params['contract_updated_from'] ?? '';
|
||
$updated_to = $params['contract_updated_to'] ?? '';
|
||
$canceled_from = $params['contract_canceled_from'] ?? '';
|
||
$canceled_to = $params['contract_canceled_to'] ?? '';
|
||
$receipt_delivery_from = $params['receipt_delivery_from'] ?? '';
|
||
$receipt_delivery_to = $params['receipt_delivery_to'] ?? '';
|
||
$contract_valid_months = $params['contract_valid_months'] ?? '';
|
||
$contract_flag = $params['contract_flag'] ?? '';
|
||
$contract_permission = $params['contract_permission'] ?? '';
|
||
$tag_qr_flag = $params['tag_qr_flag'] ?? '';
|
||
$updateFlagFilter = (string)($params['update_flag'] ?? '0');
|
||
if (!in_array($updateFlagFilter, ['0', '1', '2'], true)) {
|
||
$updateFlagFilter = '0';
|
||
}
|
||
$contract_cancel_flag = $params['contract_cancel_flag'] ?? '';
|
||
|
||
$q = DB::table('regular_contract as rc')
|
||
->leftJoin('user as u', 'u.user_id', '=', 'rc.user_id')
|
||
->leftJoin('usertype as t', 't.user_categoryid', '=', 'rc.user_categoryid')
|
||
->leftJoin('park as p', 'p.park_id', '=', 'rc.park_id')
|
||
->leftJoin('zone as z', 'z.zone_id', '=', 'rc.zone_id')
|
||
->select([
|
||
'rc.*',
|
||
'u.user_seq',
|
||
'u.user_name',
|
||
'u.user_phonetic',
|
||
'u.user_mobile',
|
||
'u.user_homephone',
|
||
'u.user_primemail',
|
||
'u.user_regident_zip',
|
||
'u.user_tag_serial',
|
||
DB::raw('t.print_name as usertype_name'),
|
||
't.usertype_subject1',
|
||
't.usertype_subject2',
|
||
't.usertype_subject3',
|
||
DB::raw('p.park_name as park_name'),
|
||
DB::raw('z.zone_name as zone_name'),
|
||
]);
|
||
|
||
if ($contract_qr_id !== '') {
|
||
$q->where('rc.contract_qr_id', 'like', "%{$contract_qr_id}%");
|
||
}
|
||
if ($user_id !== '') {
|
||
$q->where('rc.user_id', 'like', "%{$user_id}%");
|
||
}
|
||
if ($user_tag_serial !== '') {
|
||
$q->where('u.user_tag_serial', 'like', "%{$user_tag_serial}%");
|
||
}
|
||
if ($park_id !== '') {
|
||
$q->where('rc.park_id', (int)$park_id);
|
||
} elseif ($selectedParkId !== '') {
|
||
$q->where('rc.park_id', (int)$selectedParkId);
|
||
}
|
||
if ($user_phonetic !== '') {
|
||
$q->where('u.user_phonetic', 'like', "%{$user_phonetic}%");
|
||
}
|
||
if ($email !== '') {
|
||
$q->where('u.user_primemail', 'like', "%{$email}%");
|
||
}
|
||
if ($user_categoryid !== '') {
|
||
$q->where('rc.user_categoryid', (int)$user_categoryid);
|
||
}
|
||
if ($park_name_kw !== '') {
|
||
$q->where('p.park_name', 'like', "%{$park_name_kw}%");
|
||
}
|
||
if ($zone_name !== '') {
|
||
$q->where('z.zone_name', 'like', "%{$zone_name}%");
|
||
}
|
||
if ($merge_phonetic_normalized !== null) {
|
||
$likeKeyword = '%' . $merge_phonetic_normalized . '%';
|
||
$q->whereRaw("REPLACE(REPLACE(IFNULL(rc.chk_user_phonetic, ''), ' ', ''), ' ', '') LIKE ?", [$likeKeyword]);
|
||
}
|
||
if ($phone !== '') {
|
||
$q->where(function ($w) use ($phone) {
|
||
$w->where('u.user_mobile', 'like', "%{$phone}%")
|
||
->orWhere('u.user_homephone', 'like', "%{$phone}%");
|
||
});
|
||
}
|
||
if ($reserve_from !== '' && ($normalized = $this->normalizeDateTimeInput($reserve_from))) {
|
||
$q->where('rc.reserve_date', '>=', $normalized);
|
||
}
|
||
if ($reserve_to !== '' && ($normalized = $this->normalizeDateTimeInput($reserve_to, true))) {
|
||
$q->where('rc.reserve_date', '<=', $normalized);
|
||
}
|
||
if ($receipt_delivery_from !== '' && ($normalized = $this->normalizeDateTimeInput($receipt_delivery_from))) {
|
||
$q->where('rc.contract_payment_day', '>=', $normalized);
|
||
}
|
||
if ($receipt_delivery_to !== '' && ($normalized = $this->normalizeDateTimeInput($receipt_delivery_to, true))) {
|
||
$q->where('rc.contract_payment_day', '<=', $normalized);
|
||
}
|
||
if ($zone_keyword !== '') {
|
||
$q->where(function ($w) use ($zone_keyword) {
|
||
$w->where('rc.zone_id', 'like', "%{$zone_keyword}%")
|
||
->orWhere('rc.pplace_no', 'like', "%{$zone_keyword}%")
|
||
->orWhere('rc.old_contract_id', 'like', "%{$zone_keyword}%");
|
||
});
|
||
}
|
||
if ($workRecordFilter === '1') {
|
||
$q->where(function ($w) {
|
||
$w->whereNull('rc.contract_flag')
|
||
->orWhere('rc.contract_flag', '=', 0);
|
||
});
|
||
} elseif ($workRecordFilter === '2') {
|
||
$q->where('rc.contract_flag', '=', 1);
|
||
}
|
||
if ($created_from !== '' && ($normalized = $this->normalizeDateTimeInput($created_from))) {
|
||
$q->where('rc.contract_created_at', '>=', $normalized);
|
||
}
|
||
if ($created_to !== '' && ($normalized = $this->normalizeDateTimeInput($created_to, true))) {
|
||
$q->where('rc.contract_created_at', '<=', $normalized);
|
||
}
|
||
if ($updated_from !== '' && ($normalized = $this->normalizeDateTimeInput($updated_from))) {
|
||
$q->where('rc.contract_updated_at', '>=', $normalized);
|
||
}
|
||
if ($updated_to !== '' && ($normalized = $this->normalizeDateTimeInput($updated_to, true))) {
|
||
$q->where('rc.contract_updated_at', '<=', $normalized);
|
||
}
|
||
if ($canceled_from !== '' && ($normalized = $this->normalizeDateTimeInput($canceled_from))) {
|
||
$q->where('rc.contract_cancelday', '>=', $normalized);
|
||
}
|
||
if ($canceled_to !== '' && ($normalized = $this->normalizeDateTimeInput($canceled_to, true))) {
|
||
$q->where('rc.contract_cancelday', '<=', $normalized);
|
||
}
|
||
if ($contract_valid_months !== '') {
|
||
$q->where('rc.enable_months', (int)$contract_valid_months);
|
||
}
|
||
if ($contract_flag !== '') {
|
||
$q->where('rc.contract_flag', (int)$contract_flag);
|
||
}
|
||
if ($contract_permission !== '') {
|
||
$q->where('rc.contract_permission', (int)$contract_permission);
|
||
}
|
||
if ($tag_qr_flag !== '') {
|
||
$q->where('rc.tag_qr_flag', (int)$tag_qr_flag);
|
||
}
|
||
if ($updateFlagFilter === '1') {
|
||
$q->where('rc.update_flag', '=', 1);
|
||
} elseif ($updateFlagFilter === '2') {
|
||
$q->where(function ($w) {
|
||
$w->whereNull('rc.update_flag')
|
||
->orWhere('rc.update_flag', '!=', 1);
|
||
});
|
||
}
|
||
if ($contract_cancel_flag !== '') {
|
||
$q->where('rc.contract_cancel_flag', (int)$contract_cancel_flag);
|
||
}
|
||
|
||
return $q;
|
||
}
|
||
}
|