Compare commits

..

2 Commits

Author SHA1 Message Date
00fe485cbe Merge pull request '定期契約履歴確認、領収書宛名入力画面対応' (#54) from main_higashide into main
All checks were successful
Deploy so-manager (auto) / deploy (push) Successful in 25s
Reviewed-on: #54
2026-01-20 18:01:14 +09:00
628317d04f 定期契約履歴確認、領収書宛名入力画面対応 2026-01-20 17:59:48 +09:00
10 changed files with 872 additions and 174 deletions

View File

@ -1,68 +1,114 @@
<?php
declare(strict_types=1);
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
use Mpdf\Mpdf;
use Illuminate\Contracts\View\View;
use function base_path;
class ReceiptController extends Controller
{
// 宛名入力画面表示
public function input($contract_id)
/**
* 領収書宛名入力画面を表示する。
* 契約IDに基づき、領収書宛名入力フォームを表示する。
*
* @param string $management_code 運営元コード
* @param string $contract_id 契約ID
* @return mixed ビュー応答またはリダイレクト
*/
public function input(string $management_code, string $contract_id): mixed
{
$user_id = session('user_id');
if (!$user_id) {
return redirect('/login');
// 未認証アクセスセッション切れを追跡するため、INFOログで記録
\Log::info("[INFO] " . now()->format('Y-m-d H:i:s') . " 未認証ユーザーによるアクセス(セッション切れ): 領収書宛名入力画面アクセス");
return redirect()->guest('/login');
}
$user = DB::table('user')->where('user_id', $user_id)->first();
// ヘッダー表示のためユーザー名取得
$user_name = DB::table('user')->where('user_id', $user_id)->value('user_name');
\Log::info('領収書宛名入力画面にアクセス', [
'user_id' => $user_id,
]);
$management = session('management');
$management_id = $management->management_id;
// セキュリティのため、そのユーザーの契約のみアクセス可能
$contract = DB::table('regular_contract')
->join('park', 'regular_contract.park_id', '=', 'park.park_id')
->where('contract_id', $contract_id)
->where('user_id', $user_id)
->where('park.management_id', $management_id)
->first();
if (!$contract) {
// アクセス権限がない場合、エラーログで記録
\Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " アクセス権限なし: user_id=" . $user_id . ", contract_id=" . $contract_id);
abort(403, 'アクセス権限がありません。');
}
// システム操作の追跡のため、アクセスを記録
\Log::info("[INFO] " . now()->format('Y-m-d H:i:s') . " 領収書宛名入力画面にアクセス: user_id=" . $user_id . ", contract_id=" . $contract_id);
return view('receipt.input', [
'user_name' => $user ? $user->user_name : '', // ユーザー名(ヘッダー用)
'contract_id' => $contract_id
'user_name' => $user_name,
'contract_id' => $contract_id,
'management_code' => $management_code,
]);
}
// 領収書発行(入力内容の保存)
public function issue(Request $request, $contract_id)
/**
* 領収書の宛名入力内容を確認し、保存する。
*
* @param Request $request リクエストオブジェクト
* @param string $management_code 運営元コード
* @param string $contract_id 契約ID
* @return mixed PDFダウンロードまたはリダイレクト
*/
public function issue(Request $request, string $management_code, string $contract_id): mixed
{
$user_id = session('user_id');
if (!$user_id) {
// 未認証アクセスセッション切れを追跡するため、INFOログで記録
\Log::info("[INFO] " . now()->format('Y-m-d H:i:s') . " 未認証ユーザーによるアクセス(セッション切れ): 領収書発行");
return redirect('/login');
}
$receipt_name = $request->input('receipt_name');
$keisho = $request->input('keisho');
// 既存レコードチェック
// 既存レコードがある場合、再発行を促す
$exists = DB::table('inv_publish')->where('contract_id', $contract_id)->exists();
if ($exists) {
// エラー時はinput画面に戻し、メッセージ表示
return redirect()->back()->withInput()->withErrors(['contract_id' => 'この契約の領収書は既に発行されています。契約履歴から再発行を行ってください。']);
\Log::info("[INFO] " . now()->format('Y-m-d H:i:s') . " 領収書発行済み: user_id=" . $user_id . ", contract_id=" . $contract_id);
return redirect()->back()->withInput()->withErrors(['contract_id' => __('messages.RECEIPT_E000001')]);
}
// 4バイト文字絵文字等チェック
$receipt_name = trim($request->input('receipt_name') ?? '');
$keisho = $request->input('keisho');
// 宛名必須チェック
if (empty($receipt_name)) {
return redirect()->back()->withInput()->withErrors(['contract_id' => str_replace('{0}', '宛名', __('messages.SYSCOMMON_E000001'))]);
}
// 4バイト文字絵文字等を防ぐ
if (preg_match('/[\xF0-\xF7][\x80-\xBF]{3}/', $receipt_name)) {
return redirect()->back()->withInput()->withErrors(['contract_id' => '宛名に絵文字などの特殊文字は使用できません。']);
return redirect()->back()->withInput()->withErrors(['contract_id' => str_replace('{0}', '宛名', __('messages.SYSCOMMON_E000046'))]);
}
// 文字数チェック
if (mb_strlen($receipt_name) > 30) {
return redirect()->back()->withInput()->withErrors(['contract_id' => '宛名は30文字以内で入力してください。']);
return redirect()->back()->withInput()->withErrors(['contract_id' => str_replace(['{0}', '{1}'], ['宛名', '30'], __('messages.SYSCOMMON_E000011'))]);
}
// 敬称選択チェック
if (empty($keisho)) {
return redirect()->back()->withInput()->withErrors(['contract_id' => '敬称を選択してください。']);
return redirect()->back()->withInput()->withErrors(['contract_id' => str_replace('{0}', '敬称', __('messages.SYSCOMMON_E000047'))]);
}
// inv_publishテーブルに新規登録insert
// 領収書再発行を可能にするため、領収書発行履歴登録
$inv_name = $receipt_name . $keisho;
$now = date('Y-m-d H:i:s');
$seq = DB::table('inv_publish')->max('seq') ?? 0;
@ -74,38 +120,79 @@ class ReceiptController extends Controller
'inv_name' => $inv_name,
'published_at' => date('Y-m-d'),
'type' => 0,
'count' => 1,
'count' => 0,
'created_at' => $now,
'updated_at' => null,
]);
// 完了後はdownloadメソッドを直接呼び出し再発行フラグfalseで渡す
// 領収書発行履歴の登録成功を記録
\Log::info("[INFO] " . now()->format('Y-m-d H:i:s') . " 領収書発行履歴登録成功: user_id=" . $user_id . ", contract_id=" . $contract_id . ", seq=" . $seq);
$management = session('management');
// 完了後はdownloadメソッドを直接呼び出し初回発行のため再発行フラグはfalseで渡す
$is_reissue = false;
return $this->download($contract_id, $is_reissue);
return $this->download($management->management_code, $contract_id, $is_reissue);
}
public function download($contract_id, $is_reissue = true)
/**
* 領収書PDFをダウンロードする。
* 契約IDに基づきデータを取得し、PDFを生成してレスポンスとして返す。
*
* @param string $management_code 運営元コード
* @param string $contract_id 契約ID
* @param bool $is_reissue 再発行フラグデフォルトtrue
* @return mixed PDFダウンロードまたはリダイレクト
* @throws \Symfony\Component\HttpKernel\Exception\HttpException アクセス権限エラーまたはシステムエラー時
*/
public function download(string $management_code, string $contract_id, bool $is_reissue = true): mixed
{
// 必要なデータを取得
$contract = DB::table('regular_contract')->where('contract_id', $contract_id)->first();
$inv = DB::table('inv_publish')->where('contract_id', $contract_id)->first();
$t_number = DB::table('inv_setting')->value('t_number');
try {
$user_id = session('user_id');
if (!$user_id) {
// 未認証アクセスセッション切れを追跡するため、INFOログで記録
\Log::info("[INFO] " . now()->format('Y-m-d H:i:s') . " 未認証ユーザーによるアクセス(セッション切れ): 領収書ダウンロード");
return redirect('/login');
}
$management = session('management');
$management_id = $management->management_id;
// park_name取得regular_contract.park_id=park.park_id
$park_name = '';
if ($contract && $contract->park_id) {
$park = DB::table('park')->where('park_id', $contract->park_id)->first();
if ($park && $park->park_name) {
$park_name = $park->park_name;
}
}
$contract_id = (int) $contract_id;
// PDFに表示する契約情報を取得
$contract = DB::table('regular_contract')
->join('park', 'regular_contract.park_id', '=', 'park.park_id')
->where('contract_id', $contract_id)
->where('user_id', $user_id)
->where('park.management_id', $management_id)
->select('regular_contract.*', 'park.park_name')
->first();
// PDFに表示する領収書名前を取得
$inv = DB::table('inv_publish')
->where('contract_id', $contract_id)
->where('user_id', $user_id)
->first();
// PDFに表示する事業者情報を取得
$inv_setting = DB::table('inv_setting')
->where('management_id', $management_id)
->first();
// ダウンロード回数をカウントアップ
DB::table('inv_publish')
->where('contract_id', $contract_id)
->where('user_id', $user_id)
->update([
'count' => DB::raw('count + 1'),
'updated_at' => now(),
]);
// BladeテンプレートをHTMLにレンダリング
$html = view('receipt.pdf', [
'contract' => $contract,
'inv' => $inv,
't_number' => $t_number,
'park_name' => $park_name,
'inv_setting' => $inv_setting,
'is_reissue' => $is_reissue,
])->render();
@ -125,9 +212,21 @@ class ReceiptController extends Controller
$mpdf->WriteHTML($html);
// システム操作の追跡のため、アクセスを記録
if ($is_reissue) {
\Log::info("[INFO] " . now()->format('Y-m-d H:i:s') . " 領収書再発行ダウンロード実行: user_id=" . $user_id . ", contract_id=" . $contract_id);
} else {
\Log::info("[INFO] " . now()->format('Y-m-d H:i:s') . " 領収書新規発行ダウンロード実行: user_id=" . $user_id . ", contract_id=" . $contract_id);
}
// PDFダウンロード
return response($mpdf->Output('receipt_' . $contract_id . '.pdf', 'S'))
->header('Content-Type', 'application/pdf')
->header('Content-Disposition', 'attachment; filename="receipt_' . $contract_id . '.pdf"');
} catch (\Exception $e) {
// PDF生成エラーを記録
\Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " PDFダウンロードエラー: user_id=" . $user_id . ", contract_id=" . $contract_id . ", error=" . $e->getMessage());
abort(500, '領収書ダウンロードに失敗しました。');
}
}
}

View File

@ -1,9 +1,13 @@
<?php
declare(strict_types=1);
namespace App\Http\Controllers;
use Illuminate\Support\Facades\DB;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\View\View;
use Carbon\Carbon;
class RegularContractController extends Controller
@ -76,54 +80,73 @@ class RegularContractController extends Controller
]);
}
public function showHistory(Request $request)
public function showHistory(Request $request): mixed
{
/**
* 定期契約履歴を表示する。
* ユーザーの契約履歴を取得し、ページネーション付きでビューに渡す。
*
* @param Request $request 受信したHTTPリクエスト
* @return mixed ビュー応答またはリダイレクト
*/
$user_id = session('user_id');
if (!$user_id) {
return redirect('/login');
// 未認証アクセスセッション切れを追跡するため、INFOログで記録
\Log::info("[INFO] " . now()->format('Y-m-d H:i:s') . " 未認証ユーザーによるアクセス(セッション切れ): 定期契約履歴確認画面アクセス");
return redirect()->guest('/login');
}
// ヘッダー表示のためユーザー名取得
$user_name = DB::table('user')->where('user_id', $user_id)->value('user_name');
// マルチテナント対応のため、運営元コード、IDを取得
$management = session('management');
$management_code = $management->management_code;
$management_id = $management->management_id;
// 定期契約情報を取得(ページネーション付き)
$contracts_query = DB::table('regular_contract')
->join('park', 'regular_contract.park_id', '=', 'park.park_id')
->join('usertype', 'regular_contract.user_categoryid', '=', 'usertype.user_categoryid')
->leftJoin('city', 'park.city_id', '=', 'city.city_id')
->where('regular_contract.user_id', $user_id)
->where('park.management_id', $management_id)
->whereNotNull('regular_contract.contract_money')
->select(
'regular_contract.contract_id',
'park.park_name',
'usertype.usertype_subject1',
'usertype.usertype_subject3',
'regular_contract.contract_periods',
'regular_contract.contract_periode',
'regular_contract.enable_months',
'regular_contract.park_id',
'city.update_grace_period_start_date',
'park.update_grace_period_start_date',
'park.update_grace_period_end_date',
)
->orderBy('regular_contract.contract_id', 'desc');
// ページネーション4件ずつ
$contracts = $contracts_query->paginate(4);
// grace日付加工
// 日付をyyyy/MM/dd形式で画面表示するため加工
$contracts->getCollection()->transform(function ($contract) {
$periode = $contract->contract_periode;
$grace_day = $contract->update_grace_period_start_date;
$ym = date('Y/m', strtotime($periode));
$day = str_pad($grace_day, 2, '0', STR_PAD_LEFT);
$contract->periode_with_grace = $ym . '/' . $day;
$contract->formatted_periods = \Carbon\Carbon::parse($contract->contract_periods)->format('Y/m/d');
$contract->has_receipt = DB::table('inv_publish')->where('contract_id', $contract->contract_id)->exists();
return $contract;
});
\Log::info('契約履歴表示画面にアクセス', [
'user_id' => $user_id,
]);
// システム操作の追跡のため、アクセスを記録
\Log::info("[INFO] " . now()->format('Y-m-d H:i:s') . " 契約履歴表示画面にアクセス: user_id=" . $user_id . ", management_code=" . $management_code);
return view('regular_contract.history', [
'active_menu' => 'SWC-6-1', // マイページメニューの選択状態用
'user_name' => $user_name, // ユーザー名(ヘッダー用)
'contracts' => $contracts,
'management_code' => $management_code,
]);
}

View File

@ -7,6 +7,7 @@ use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Http\Response;
use Illuminate\Http\RedirectResponse;
class ManagementMiddleware
{
@ -19,7 +20,7 @@ class ManagementMiddleware
* @return Response 次の処理のレスポンス
* @throws \Symfony\Component\HttpKernel\Exception\HttpException 運営元コードが見つからない場合
*/
public function handle(Request $request, Closure $next): Response
public function handle(Request $request, Closure $next): Response|RedirectResponse
{
// マルチテナント対応のため、URLの最初のセグメントを運営元コードとして扱う
$path = $request->getPathInfo(); // パス全体を取得

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,69 @@
<?php
return [
// 汎用エラーメッセージ
'SYSCOMMON_E000001' => '必須項目:{0}を入力してください。',
'SYSCOMMON_E000002' => '{0}はyyyy/MM/ddで入力してください。',
'SYSCOMMON_E000003' => '{0}は半角文字で入力してください。',
'SYSCOMMON_E000004' => '{0}は半角数字で入力してください。',
'SYSCOMMON_E000005' => '{0}は半角英字で入力してください。',
'SYSCOMMON_E000006' => '{0}は半角英数で入力してください。',
'SYSCOMMON_E000007' => '{0}は半角カナで入力してください。',
'SYSCOMMON_E000008' => '{0}は全角文字で入力してください。',
'SYSCOMMON_E000009' => '{0}は{1}桁で入力してください。',
'SYSCOMMON_E000010' => '{0}は{1}桁以内で入力してください。',
'SYSCOMMON_E000011' => '{0}は{1}文字以内で入力してください。',
'SYSCOMMON_E000012' => '{0}は0または0.0以外の文字を入力してください。',
'SYSCOMMON_E000013' => '{0}にはアルファベットと数字だけが入力可能です。',
'SYSCOMMON_E000014' => '{0}は整数部の最大桁数が{1}桁を超えています。',
'SYSCOMMON_E000015' => '{0}は小数部の最大桁数が{1}桁を超えています。',
'SYSCOMMON_E000016' => '{0}は整数部の最小桁数が{1}桁未満です。',
'SYSCOMMON_E000017' => '{0}は小数部の最小桁数が{1}桁未満です。',
'SYSCOMMON_E000018' => '{0}には正の値を入力してください。',
'SYSCOMMON_E000019' => '{0}には負の値を入力してください。',
'SYSCOMMON_E000020' => '{0}は整数{2}桁以内、小数{1}桁以内で入力してください。',
'SYSCOMMON_E000021' => '{0}はマスタに存在しません。',
'SYSCOMMON_E000022' => '{0}はマスタに既に存在しています。',
'SYSCOMMON_E000023' => '{0}は既に削除されています。',
'SYSCOMMON_E000024' => '一つ以上選択してください。',
'SYSCOMMON_E000025' => '正しい区分を選択してください。',
'SYSCOMMON_E000026' => '明細行を選択してください。',
'SYSCOMMON_E000027' => '複数行の選択はできません。',
'SYSCOMMON_E000028' => '{0}行以上の追加は行うことができません。',
'SYSCOMMON_E000029' => '{0}行以上の挿入は行うことができません。',
'SYSCOMMON_E000030' => '読取専用の為、行を削除することはできません。({0}行目)',
'SYSCOMMON_E000031' => '{0}は編集できません。',
'SYSCOMMON_E000032' => '明細行は{0}件以上入力してください。',
'SYSCOMMON_E000033' => '検索条件を入力してください。',
'SYSCOMMON_E000034' => '入力したIDまたはパスワードは正しくありません。',
'SYSCOMMON_E000035' => '対象のデータは編集作業中に変更されました。再度編集画面を開き直してください。',
'SYSCOMMON_E000036' => '対象のデータは既に削除されています。',
'SYSCOMMON_E000037' => '関連データが存在するため修正、削除できません。',
'SYSCOMMON_E000038' => '指定されたURLは存在しません。',
'SYSCOMMON_E000039' => 'リクエストした画面は現在使用できません。',
'SYSCOMMON_E000040' => '不正な画面遷移が行われました。メニュー選択から操作をやり直してください。',
'SYSCOMMON_E000041' => 'システムエラーが発生しました。システム管理者に連絡してください。',
'SYSCOMMON_E000042' => 'ファイルダウンロードに失敗しました。',
'SYSCOMMON_E000043' => 'ファイルアップロードに失敗しました。',
'SYSCOMMON_E000044' => 'バッチ処理が異常終了しました。',
'SYSCOMMON_E000045' => '{0}は{1}のため、入力することができません。',
'SYSCOMMON_E000046' => '{0}に特殊文字は使用できません。',
'SYSCOMMON_E000047' => '{0}を選択してください。',
// 汎用情報メッセージ
'SYSCOMMON_I000001' => '登録します。よろしいですか?',
'SYSCOMMON_I000002' => '更新します。よろしいですか?',
'SYSCOMMON_I000003' => '削除します。よろしいですか?',
'SYSCOMMON_I000004' => '一時保存します。よろしいですか?',
'SYSCOMMON_I000005' => 'ログアウトしてよろしいですか?',
'SYSCOMMON_I000006' => '入力内容が破棄されます。よろしいですか?',
'SYSCOMMON_I000007' => 'ダウンロードします。よろしいですか?',
'SYSCOMMON_I000008' => 'アップロードします。よろしいですか?',
'SYSCOMMON_I000009' => '登録されました。{0}',
'SYSCOMMON_I000010' => '更新されました。{0}',
'SYSCOMMON_I000011' => '削除されました。{0}',
'SYSCOMMON_I000012' => 'ダウンロードが終了しました。',
'SYSCOMMON_I000013' => 'アップロードが終了しました。',
// 領収書関連メッセージ
'RECEIPT_E000001' => 'この契約の領収書は既に発行されています。契約履歴から再発行を行ってください。',
];

View File

@ -39,10 +39,6 @@
<main>
@yield('content')
</main>
{{-- フッターメニュー --}}
@include('partials.mypagefootermenu')
{{-- ニュース --}}
@include('partials.news')
{{-- フッター --}}
@include('partials.footer')
</div>

View File

@ -1,35 +1,42 @@
@extends('layouts.app')
@section('title', '領収書の発行 | So-Manager')
@section('content')
<main>
<header class="alert alert-success">
<h4 class="container">領収書の発行</h4>
</header>
<header class="title-header">領収書の発行</header>
@if($errors->has('contract_id'))
<div class="alert alert-danger text-center">
{{ $errors->first('contract_id') }}
</div>
@endif
<form method="POST" action="{{ url('receipt/issue/' . $contract_id) }}">
<form method="POST" action="{{ route('receipt.issue', ['management_code' => $management_code, 'contract_id' => $contract_id]) }}" id="issueForm">
@csrf
<div class="col-12 col-md-5 offset-0 offset-md-1 mt10 mb50">
<p class="text-left font-weight-bold">領収書内容の入力</p>
<p class="text-left">領収書の宛名を入力してください。</p>
<input type="text" class="form-control" id="receipt_name" name="receipt_name" required>
<input type="text" class="form-control" id="receipt_name" name="receipt_name" value="{{ old('receipt_name') }}" required style="color: black;">
<div class="mt-2">
<div class="form-check">
<input class="form-check-input" type="radio" name="keisho" id="keisho_sama" value="" checked>
<input class="form-check-input" type="radio" name="keisho" id="keisho_sama" value="" {{ old('keisho') == '様' ? 'checked' : '' }}>
<label class="form-check-label" for="keisho_sama"></label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="keisho" id="keisho_onchu" value="御中">
<input class="form-check-input" type="radio" name="keisho" id="keisho_onchu" value="御中" {{ old('keisho') == '御中' ? 'checked' : '' }}>
<label class="form-check-label" for="keisho_onchu">御中</label>
</div>
</div>
<div class="col-6 offset-3 text-left">
<button type="submit" class="btn btn-success">発行する</button>
<button type="submit" class="green-btn long-btn" id="submitBtn">発行する</button>
</div>
</div>
</form>
</main>
<script>
window.onload = function() {
document.getElementById('submitBtn').disabled = false;
};
document.getElementById('issueForm').addEventListener('submit', function() {
document.getElementById('submitBtn').disabled = true;
});
</script>
@endsection

View File

@ -58,12 +58,18 @@
font-size: 12px;
}
.reissue {
position: absolute;
top: 16px;
left: 16px;
width: 100px;
height: 40px;
.reissue-label {
display: inline-block;
border: 2px solid #222;
border-radius: 36px;
padding: 14px 48px;
font-weight: bold;
font-size: 1.6em;
color: #222;
background: #fff;
letter-spacing: 0.05em;
box-sizing: border-box;
margin: 12px 0 0 0;
}
</style>
</head>
@ -71,19 +77,19 @@
<body>
<div class="border">
@if($is_reissue)
<img src="{{ str_replace('\\', '/', public_path('images/reissue.png')) }}" class="reissue" alt="再発行">
<span class="reissue-label">再発行</span>
@endif
<div class="right">
No. {{ $inv->seq ?? '' }}<br>
発行日: {{ !empty($inv->published_at) ? \Carbon\Carbon::parse($inv->published_at)->format('Y年m月d日') : '' }}
</div>
<div class="title" style="font-size:20px; font-weight:bold;">領収</div>
<div class="title" style="font-size:20px; font-weight:bold;">領収</div>
<div>ID: {{ $contract->contract_id ?? '' }}</div>
<div><span style="border-bottom:1px solid #222;">{{ $inv->inv_name ?? '' }}</span></div>
<table class="table">
<tr>
<td class="left">契約駐輪場名</td>
<td class="right">{{ $park_name ?? '' }}</td>
<td class="right">{{ $contract->park_name ?? '' }}</td>
</tr>
<tr>
<td class="left">小計10対象</td>
@ -108,22 +114,39 @@
{{ !empty($contract->contract_periode) ? \Carbon\Carbon::parse($contract->contract_periode)->format('Y年m月d日') : '' }}
</span>として<br>
上記金額を正に領収いたしました。
{{ !empty($contract->contract_payment_day) ? \Carbon\Carbon::parse($contract->contract_payment_day)->format('Y年m月d日') : '' }}上記金額を正に領収いたしました。
</div>
<table style="width:100%; margin-top:40px;">
<tr>
<td style="width:55%"></td>
<td>
<div class="company">
<span style="font-size:20px; font-weight:bold;">株式会社ソーリン</span><br>
〒121-0073<br>
東京都足立区六町四丁目12-25<br>
適格事業者番号:{{ $t_number }}<br>
TEL:03-5856-4647<br>
FAX:03-5856-4648<br>
<span style="font-size:20px; font-weight:bold;">{{ $inv_setting->t_name ?? '' }}</span><br>
{{ $inv_setting->zipcode ?? '' }}<br>
{{ $inv_setting->adrs ?? '' }}<br>
適格事業者番号:{{ $inv_setting->t_number ?? '' }}<br>
@if(!empty($inv_setting->tel_num))
TEL:{{ $inv_setting->tel_num}}<br>
@endif
@if(!empty($inv_setting->fax_num))
FAX:{{ $inv_setting->fax_num}}<br>
@endif
</div>
</td>
<td><img src="{{ str_replace('\\', '/', public_path('images/hanko.png')) }}" class="stamp"></td>
@php
$stamp_file = null;
$extensions = ['png', 'jpeg', 'jpg'];
foreach ($extensions as $ext) {
$file_path = public_path('images/' . $inv_setting->t_name . '_stamp.' . $ext);
if (file_exists($file_path)) {
$stamp_file = $inv_setting->t_name . '_stamp.' . $ext;
break;
}
}
@endphp
@if($stamp_file)
<td><img src="{{ str_replace('\\', '/', public_path('images/' . $stamp_file)) }}" class="stamp"></td>
@endif
</tr>
</table>
</div>

View File

@ -1,9 +1,8 @@
@extends('layouts.app')
@section('title', '定期契約履歴を見る-契約履歴 | So-Manager')
@section('content')
<main>
<header class="alert alert-success">
<h4 class="container">契約履歴 > 定期契約履歴を見る</h4>
</header>
<header class="title-header">契約履歴 &gt; 定期契約履歴を見る</header>
<section class="container mt30 mb50">
@if(count($contracts) > 0)
@foreach($contracts as $i => $contract)
@ -23,11 +22,15 @@
</tr>
<tr>
<th>利用者区分</th>
<td>{{ $contract->usertype_subject1 }}</td>
<td>{{ $contract->usertype_subject1 }}
@if($contract->usertype_subject3 !== '該当なし')
{{ $contract->usertype_subject3 }}
@endif
</td>
</tr>
<tr>
<th>開始日</th>
<td>{{ \Carbon\Carbon::parse($contract->contract_periods)->format('Y/m/d') }}</td>
<td>{{ $contract->formatted_periods }}</td>
</tr>
<tr>
<th>月数</th>
@ -39,13 +42,10 @@
</tr>
<tr>
<td colspan="2" class="text-center">
@php
$has_receipt = DB::table('inv_publish')->where('contract_id', $contract->contract_id)->exists();
@endphp
@if($has_receipt)
<a href="{{ url('receipt/download/' . $contract->contract_id) }}" class="btn btn-outline-secondary badge-pill custom-rounded-btn" style="background: transparent;">領収書再発行</a>
@if($contract->has_receipt)
<a href="{{ route('receipt.download', ['management_code' => $management_code, 'contract_id' => $contract->contract_id]) }}" class="btn btn-outline-secondary badge-pill custom-rounded-btn" style="background: transparent;">領収書再発行</a>
@else
<a href="{{ url('receipt/input/' . $contract->contract_id) }}" class="btn btn-outline-secondary badge-pill custom-rounded-btn" style="background: transparent;">領収書発行</a>
<a href="{{ route('receipt.input', ['management_code' => $management_code, 'contract_id' => $contract->contract_id]) }}" class="btn btn-outline-secondary badge-pill custom-rounded-btn" style="background: transparent;">領収書発行</a>
@endif
</td>
</tr>
@ -64,11 +64,9 @@
<p>定期契約情報はありません。</p>
</div>
@endif
<form class="row form">
<div class="col-12 col-md-4 offset-0 offset-md-4 mt50 mb50">
<a href="{{ url('mypage') }}" class="btn btn-lg btn-block btn-outline-success">マイページへ戻る</a>
<div class="mb-2 mt30" style="text-align:center;">
<a href="{{ route('mypage', ['management_code' => $management_code]) }}" class="white-btn long-btn" style="max-width:500px; display:inline-block;">マイページへ戻る</a>
</div>
</form>
</section>
</main>
@ -83,10 +81,20 @@
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
}
.btn-outline-secondary.badge-pill.custom-rounded-btn:not([disabled]):hover,
.btn-outline-secondary.badge-pill.custom-rounded-btn:not(.disabled):hover {
color: #212529 !important;
}
.table.text-center {
border-radius: 0.25rem !important;
border-radius: 1.25rem !important;
border-collapse: separate !important;
overflow: hidden;
}
.card {
border-radius: 1.25rem !important;
overflow: hidden;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>

View File

@ -103,7 +103,7 @@ Route::middleware([\App\Http\Middleware\ManagementMiddleware::class])->group(fun
// 領収書発行
Route::get('/{management_code}/receipt/input/{contract_id}', [ReceiptController::class, 'input'])->name('receipt.input');
Route::get('/{management_code}/receipt/download/{contract_id}', [ReceiptController::class, 'download'])->name('receipt.download');
Route::post('/{management_code}/receipt/issue/{contract_id}', [ReceiptController::class, 'issue']);
Route::post('/{management_code}/receipt/issue/{contract_id}', [ReceiptController::class, 'issue'])->name('receipt.issue');
// シール再発行
Route::get('/{management_code}/seal/reissue/{contract_id}', [SealReissueController::class, 'index'])->name('seal.reissue');