krgm.so-manager-dev.com/app/Http/Controllers/Admin/SettlementTransactionController.php

284 lines
11 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\SettlementTransaction;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Symfony\Component\HttpFoundation\StreamedResponse;
class SettlementTransactionController extends Controller
{
/**
* 一覧
* ルート: settlement_transactions
*/
public function list(Request $request)
{
$q = SettlementTransaction::query();
// --- 絞り込み(必要なら増やせます)
$contractId = $request->input('contract_id');
$status = trim((string)$request->input('status', ''));
$from = $request->input('from'); // 支払日時 from
$to = $request->input('to'); // 支払日時 to
if ($contractId !== null && $contractId !== '') {
$q->where('contract_id', (int)$contractId);
}
if ($status !== '') {
$q->where('status', 'like', "%{$status}%");
}
if ($from) {
$q->whereDate('pay_date', '>=', $from);
}
if ($to) {
$q->whereDate('pay_date', '<=', $to);
}
// --- ソート既定created_at desc
$sort = $request->input('sort', 'created_at');
$type = strtolower($request->input('sort_type', 'desc'));
$allow = [
'settlement_transaction_id', 'created_at', 'updated_at',
'contract_id', 'status', 'pay_date', 'settlement_amount',
];
if (!in_array($sort, $allow, true)) $sort = 'created_at';
if (!in_array($type, ['asc', 'desc'], true)) $type = 'desc';
$q->orderBy($sort, $type);
return view('admin.settlement_transactions.list', [
'transactions' => $q->paginate(20)->appends($request->except('page')),
'contract_id' => $contractId,
'status' => $status,
'from' => $from,
'to' => $to,
'sort' => $sort,
'sort_type' => $type,
]);
}
/**
* 新規
* ルート: settlement_transactions_add
*/
public function add(Request $request)
{
if ($request->isMethod('post')) {
$data = $this->validatePayload($request);
SettlementTransaction::create($data);
return redirect()->route('settlement_transactions')->with('success', '登録しました');
}
return view('admin.settlement_transactions.add', [
'transaction' => null,
'isEdit' => false,
'isInfo' => false,
]);
}
/**
* 編集
* ルート: settlement_transactions_edit
*/
public function edit(int $settlement_transaction_id, Request $request)
{
$transaction = SettlementTransaction::findOrFail($settlement_transaction_id);
if ($request->isMethod('post')) {
$data = $this->validatePayload($request);
$transaction->update($data);
return redirect()->route('settlement_transactions')->with('success', '更新しました');
}
return view('admin.settlement_transactions.edit', [
'transaction' => $transaction,
'isEdit' => true,
'isInfo' => false,
]);
}
/**
* 詳細
* ルート: settlement_transactions_info
*/
public function info(int $settlement_transaction_id)
{
$transaction = SettlementTransaction::findOrFail($settlement_transaction_id);
return view('admin.settlement_transactions.info', [
'transaction' => $transaction,
'isEdit' => false,
'isInfo' => true,
]);
}
/**
* 一括削除(一覧のチェック name="ids[]"
* ルート: settlement_transactions_delete
*/
public function delete(Request $request)
{
$ids = (array) $request->input('ids', []);
$ids = array_values(array_filter($ids, fn($v) => preg_match('/^\d+$/', (string)$v)));
if (!$ids) {
return redirect()->route('settlement_transactions')->with('error', '削除対象が選択されていません。');
}
SettlementTransaction::whereIn('settlement_transaction_id', $ids)->delete();
return redirect()->route('settlement_transactions')->with('success', '削除しました');
}
/**
* CSVインポート簡易
* ルート: settlement_transactions_import
*
* 想定カラム順:
* contract_id,status,pay_code,contract_payment_number,corp_code,
* mms_date,cvs_code,shop_code,pay_date,settlement_amount,stamp_flag,md5_string
* 1行目ヘッダ可
*/
public function import(Request $request)
{
$request->validate([
'file' => ['required', 'file', 'mimetypes:text/plain,text/csv,text/tsv', 'max:4096'],
]);
$path = $request->file('file')->getRealPath();
$created = 0;
$updated = 0;
$skipped = 0;
DB::beginTransaction();
try {
if (($fp = fopen($path, 'r')) !== false) {
$line = 0;
while (($row = fgetcsv($fp)) !== false) {
$line++;
// ヘッダ行をスキップ
if ($line === 1) {
$joined = strtolower(implode(',', $row));
if (str_contains($joined, 'contract_id') || str_contains($joined, 'status')) {
continue;
}
}
// 入力列を安全に展開
[$contract_id,$status,$pay_code,$contract_payment_number,$corp_code,$mms_date,$cvs_code,$shop_code,$pay_date,$settlement_amount,$stamp_flag,$md5_string] = array_pad($row, 12, null);
// 正規化
$payload = [
'contract_id' => ($contract_id === '' || $contract_id === null) ? null : (int)$contract_id,
'status' => $status !== null ? trim($status) : null,
'pay_code' => $pay_code !== null ? trim($pay_code) : null,
'contract_payment_number' => $contract_payment_number !== null ? trim($contract_payment_number) : null,
'corp_code' => $corp_code !== null ? trim($corp_code) : null,
'mms_date' => $mms_date !== null ? trim($mms_date) : null,
'cvs_code' => $cvs_code !== null ? trim($cvs_code) : null,
'shop_code' => $shop_code !== null ? trim($shop_code) : null,
'pay_date' => $pay_date ? date('Y-m-d H:i:s', strtotime($pay_date)) : null,
'settlement_amount' => ($settlement_amount === '' || $settlement_amount === null) ? null : (float)preg_replace('/[^\d.]/','',$settlement_amount),
'stamp_flag' => $stamp_flag !== null ? trim($stamp_flag) : null,
'md5_string' => $md5_string !== null ? trim($md5_string) : null,
];
// upsert キー(優先: md5_string、なければ contract_id+pay_date
$ex = null;
if (!empty($payload['md5_string'])) {
$ex = SettlementTransaction::where('md5_string', $payload['md5_string'])->first();
} elseif (!empty($payload['contract_id']) && !empty($payload['pay_date'])) {
$ex = SettlementTransaction::where('contract_id', $payload['contract_id'])
->where('pay_date', $payload['pay_date'])->first();
}
if ($ex) { $ex->update($payload); $updated++; }
else { SettlementTransaction::create($payload); $created++; }
}
fclose($fp);
}
DB::commit();
return redirect()->route('settlement_transactions')
->with('success', "インポート完了:新規 {$created} 件、更新 {$updated} 件、スキップ {$skipped}");
} catch (\Throwable $e) {
DB::rollBack();
return redirect()->route('settlement_transactions')
->with('error', 'インポートに失敗しました:' . $e->getMessage());
}
}
/**
* CSVエクスポート
* ルート: settlement_transactions_export
*/
public function export(Request $request): StreamedResponse
{
$q = SettlementTransaction::query();
// 一覧と同じソートを適用(任意で絞り込みも追加可能)
$sort = $request->input('sort', 'created_at');
$type = strtolower($request->input('sort_type', 'desc'));
if (!in_array($type, ['asc','desc'], true)) $type = 'desc';
$q->orderBy($sort, $type);
$filename = 'settlement_transactions_' . now()->format('Ymd_His') . '.csv';
return response()->streamDownload(function () use ($q) {
$out = fopen('php://output', 'w');
fputcsv($out, [
'ID','契約ID','ステータス','支払コード','契約課金番号','企業コード',
'MMS日付','CVSコード','店舗コード','支払日時','金額','スタンプ','MD5',
'登録日時','更新日時'
]);
$q->chunk(500, function ($rows) use ($out) {
foreach ($rows as $r) {
fputcsv($out, [
$r->settlement_transaction_id,
$r->contract_id,
$r->status,
$r->pay_code,
$r->contract_payment_number,
$r->corp_code,
$r->mms_date,
$r->cvs_code,
$r->shop_code,
optional($r->pay_date)->format('Y-m-d H:i:s'),
$r->settlement_amount,
$r->stamp_flag,
$r->md5_string,
optional($r->created_at)->format('Y-m-d H:i:s'),
optional($r->updated_at)->format('Y-m-d H:i:s'),
]);
}
});
fclose($out);
}, $filename, ['Content-Type' => 'text/csv; charset=UTF-8']);
}
/**
* 共通バリデーション
*/
private function validatePayload(Request $request): array
{
return $request->validate([
'contract_id' => ['nullable','integer'],
'status' => ['nullable','string','max:255'],
'pay_code' => ['nullable','string','max:255'],
'contract_payment_number' => ['nullable','string','max:255'],
'corp_code' => ['nullable','string','max:255'],
'mms_date' => ['nullable','string','max:255'],
'cvs_code' => ['nullable','string','max:255'],
'shop_code' => ['nullable','string','max:255'],
'pay_date' => ['nullable','date'],
'settlement_amount' => ['nullable','numeric'], // DB は decimal(10,0)
'stamp_flag' => ['nullable','string','max:255'],
'md5_string' => ['nullable','string','max:255'],
]);
}
}