format('Y-m-d H:i:s') . " 未認証ユーザーによるアクセス(セッション切れ): 領収書宛名入力画面アクセス"); return redirect()->guest('/login'); } // ヘッダー表示のためユーザー名取得 $user_name = DB::table('user')->where('user_id', $user_id)->value('user_name'); $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_name, 'contract_id' => $contract_id, 'management_code' => $management_code, ]); } /** * 領収書の宛名入力内容を確認し、保存する。 * * @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'); } // 既存レコードがある場合、再発行を促す $exists = DB::table('inv_publish')->where('contract_id', $contract_id)->exists(); if ($exists) { // エラー時はinput画面に戻し、メッセージ表示 \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')]); } $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' => str_replace('{0}', '宛名', __('messages.SYSCOMMON_E000046'))]); } // 文字数チェック if (mb_strlen($receipt_name) > 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' => str_replace('{0}', '敬称', __('messages.SYSCOMMON_E000047'))]); } // 領収書再発行を可能にするため、領収書発行履歴登録 $inv_name = $receipt_name . $keisho; $now = date('Y-m-d H:i:s'); $seq = DB::table('inv_publish')->max('seq') ?? 0; $seq = $seq + 1; DB::table('inv_publish')->insert([ 'seq' => $seq, 'user_id' => $user_id, 'contract_id' => $contract_id, 'inv_name' => $inv_name, 'published_at' => date('Y-m-d'), 'type' => 0, 'count' => 0, 'created_at' => $now, 'updated_at' => null, ]); // 領収書発行履歴の登録成功を記録 \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($management->management_code, $contract_id, $is_reissue); } /** * 領収書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 { 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; $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, 'inv_setting' => $inv_setting, 'is_reissue' => $is_reissue, ])->render(); // mPDF最新版(autoload対応) $mpdf = new \Mpdf\Mpdf([ 'mode' => 'ja', 'format' => 'A4', 'custom_font_dir' => resource_path('fonts'), 'custom_font_data' => [ 'noto_sans_jp' => [ 'R' => 'NotoSansJP-Regular.ttf', // 通常フォント 'B' => 'NotoSansJP-Bold.ttf', // 太字フォント ] ], 'default_font' => 'noto_sans_jp', ]); $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, '領収書ダウンロードに失敗しました。'); } } }