251 lines
11 KiB
PHP
251 lines
11 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace App\Http\Controllers;
|
||
|
||
use App\Http\Traits\AuthenticatesUser;
|
||
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
|
||
{
|
||
use AuthenticatesUser;
|
||
|
||
/**
|
||
* 領収書宛名入力画面を表示する。
|
||
* 契約IDに基づき、領収書宛名入力フォームを表示する。
|
||
*
|
||
* @param string $management_code 運営元コード
|
||
* @param string $contract_id 契約ID
|
||
* @return mixed ビュー応答またはリダイレクト
|
||
*/
|
||
public function input(string $management_code, string $contract_id): mixed
|
||
{
|
||
if ($redirect = $this->handleSessionExpired('領収書宛名入力', false)) {
|
||
return $redirect;
|
||
}
|
||
|
||
// ヘッダー表示のためユーザー名取得
|
||
$user_id = session('user_id');
|
||
$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
|
||
{
|
||
if ($redirect = $this->handleSessionExpired('領収書宛名入力', false)) {
|
||
return $redirect;
|
||
}
|
||
|
||
$user_id = session('user_id');
|
||
|
||
// 既存レコードがある場合、再発行を促す
|
||
$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 {
|
||
if ($redirect = $this->handleSessionExpired('領収書ダウンロード', false)) {
|
||
return $redirect;
|
||
}
|
||
|
||
$user_id = session('user_id');
|
||
$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();
|
||
|
||
// 社員側の社判画像を参照するため、シンボリックリンクを作成 (company_image_path が存在する場合のみ)
|
||
if (!empty($inv_setting->company_image_path)) {
|
||
$krgmStoragePath = config('app.krgm_storage_path');
|
||
$linkPath = public_path('other-storage');
|
||
if (!file_exists($krgmStoragePath)) {
|
||
\Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " 社判画像保存フォルダ発見不可: " . $krgmStoragePath . ", user_id=" . $user_id . ", contract_id=" . $contract_id);
|
||
throw new \Exception();
|
||
}
|
||
if (!file_exists($linkPath)) {
|
||
$result = symlink($krgmStoragePath, $linkPath);
|
||
\Log::info("[INFO] " . now()->format('Y-m-d H:i:s') . " 社判画像参照リンク作成。結果: " . ($result ? '成功' : '失敗') . ", user_id=" . $user_id . ", contract_id=" . $contract_id);
|
||
if (!$result) {
|
||
\Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " 社判画像参照リンク作成失敗。user_id=" . $user_id . ", contract_id=" . $contract_id);
|
||
throw new \Exception();
|
||
}
|
||
}
|
||
}
|
||
|
||
// ダウンロード回数をカウントアップ
|
||
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, '領収書ダウンロードに失敗しました。');
|
||
}
|
||
}
|
||
}
|