feat:E-Sign 템플릿에 PDF 파일 포함 기능 추가
- 모델: EsignFieldTemplate fillable에 file 컬럼 추가 - storeTemplate: include_pdf + contract_id로 계약 PDF를 템플릿으로 복사 - store(계약 생성): template_id로 템플릿 PDF 자동 복사 (사용자 업로드 우선) - duplicateTemplate: 복제 시 PDF 파일도 복사 - 템플릿 PDF 다운로드 엔드포인트 추가 - SaveTemplateModal: "현재 PDF 파일 포함" 체크박스 추가 - create: 템플릿 카드에 PDF 뱃지, PDF 자동 사용 안내 - templates: 템플릿 카드에 PDF 파일명 표시 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class EsignApiController extends Controller
|
||||
@@ -88,6 +89,7 @@ public function store(Request $request): JsonResponse
|
||||
'sign_order_type' => 'required|in:counterpart_first,creator_first',
|
||||
'expires_at' => 'nullable|date',
|
||||
'expires_days' => 'nullable|integer|min:1|max:365',
|
||||
'template_id' => 'nullable|integer',
|
||||
'signers' => 'required|array|size:2',
|
||||
'signers.*.name' => 'required|string|max:100',
|
||||
'signers.*.email' => 'required|email|max:200',
|
||||
@@ -108,11 +110,28 @@ public function store(Request $request): JsonResponse
|
||||
$fileSize = null;
|
||||
|
||||
if ($request->hasFile('file')) {
|
||||
// 사용자가 직접 업로드한 파일 우선 사용
|
||||
$file = $request->file('file');
|
||||
$fileName = $file->getClientOriginalName();
|
||||
$fileSize = $file->getSize();
|
||||
$fileHash = hash_file('sha256', $file->getRealPath());
|
||||
$filePath = $file->store("esign/{$tenantId}/contracts", 'local');
|
||||
} elseif ($request->input('template_id')) {
|
||||
// 템플릿에 PDF가 있으면 복사
|
||||
$template = EsignFieldTemplate::forTenant($tenantId)
|
||||
->where('is_active', true)
|
||||
->find($request->input('template_id'));
|
||||
|
||||
if ($template && $template->file_path && Storage::disk('local')->exists($template->file_path)) {
|
||||
$ext = pathinfo($template->file_path, PATHINFO_EXTENSION) ?: 'pdf';
|
||||
$newPath = "esign/{$tenantId}/contracts/" . Str::random(40) . ".{$ext}";
|
||||
Storage::disk('local')->copy($template->file_path, $newPath);
|
||||
|
||||
$filePath = $newPath;
|
||||
$fileName = $template->file_name;
|
||||
$fileHash = $template->file_hash;
|
||||
$fileSize = $template->file_size;
|
||||
}
|
||||
}
|
||||
|
||||
$contract = EsignContract::create([
|
||||
@@ -388,6 +407,25 @@ public function uploadPdf(Request $request, int $id): JsonResponse
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 템플릿 PDF 다운로드
|
||||
*/
|
||||
public function downloadTemplatePdf(int $id)
|
||||
{
|
||||
$tenantId = session('selected_tenant_id', 1);
|
||||
$template = EsignFieldTemplate::forTenant($tenantId)->findOrFail($id);
|
||||
|
||||
if (!$template->file_path || !Storage::disk('local')->exists($template->file_path)) {
|
||||
abort(404, 'PDF 파일을 찾을 수 없습니다.');
|
||||
}
|
||||
|
||||
$fileName = $template->file_name ?: 'template.pdf';
|
||||
|
||||
return Storage::disk('local')->download($template->file_path, $fileName, [
|
||||
'Content-Type' => 'application/pdf',
|
||||
]);
|
||||
}
|
||||
|
||||
// ─── 필드 템플릿 관련 메서드 ───
|
||||
|
||||
/**
|
||||
@@ -423,6 +461,8 @@ public function storeTemplate(Request $request): JsonResponse
|
||||
'name' => 'required|string|max:100',
|
||||
'description' => 'nullable|string',
|
||||
'category' => 'nullable|string|max:50',
|
||||
'include_pdf' => 'nullable|boolean',
|
||||
'contract_id' => 'nullable|integer',
|
||||
'items' => 'required|array|min:1',
|
||||
'items.*.signer_order' => 'required|integer|min:1',
|
||||
'items.*.page_number' => 'required|integer|min:1',
|
||||
@@ -441,8 +481,36 @@ public function storeTemplate(Request $request): JsonResponse
|
||||
$items = $request->input('items');
|
||||
$signerCount = max(array_column($items, 'signer_order'));
|
||||
|
||||
$template = DB::transaction(function () use ($tenantId, $request, $items, $signerCount) {
|
||||
$template = EsignFieldTemplate::create([
|
||||
// PDF 포함 여부 확인
|
||||
$includePdf = $request->boolean('include_pdf');
|
||||
$contractId = $request->input('contract_id');
|
||||
$sourceContract = null;
|
||||
|
||||
if ($includePdf && $contractId) {
|
||||
$sourceContract = EsignContract::forTenant($tenantId)->find($contractId);
|
||||
if (!$sourceContract || !$sourceContract->original_file_path || !Storage::disk('local')->exists($sourceContract->original_file_path)) {
|
||||
$sourceContract = null;
|
||||
}
|
||||
}
|
||||
|
||||
$template = DB::transaction(function () use ($tenantId, $request, $items, $signerCount, $sourceContract) {
|
||||
$fileData = [];
|
||||
|
||||
if ($sourceContract) {
|
||||
$timestamp = now()->format('YmdHis');
|
||||
$ext = pathinfo($sourceContract->original_file_path, PATHINFO_EXTENSION) ?: 'pdf';
|
||||
$newPath = "esign/{$tenantId}/templates/{$timestamp}.{$ext}";
|
||||
Storage::disk('local')->copy($sourceContract->original_file_path, $newPath);
|
||||
|
||||
$fileData = [
|
||||
'file_path' => $newPath,
|
||||
'file_name' => $sourceContract->original_file_name,
|
||||
'file_hash' => $sourceContract->original_file_hash,
|
||||
'file_size' => $sourceContract->original_file_size,
|
||||
];
|
||||
}
|
||||
|
||||
$template = EsignFieldTemplate::create(array_merge([
|
||||
'tenant_id' => $tenantId,
|
||||
'name' => $request->input('name'),
|
||||
'description' => $request->input('description'),
|
||||
@@ -450,7 +518,7 @@ public function storeTemplate(Request $request): JsonResponse
|
||||
'signer_count' => $signerCount,
|
||||
'is_active' => true,
|
||||
'created_by' => auth()->id(),
|
||||
]);
|
||||
], $fileData));
|
||||
|
||||
foreach ($items as $i => $item) {
|
||||
EsignFieldTemplateItem::create([
|
||||
@@ -531,7 +599,22 @@ public function duplicateTemplate(int $id): JsonResponse
|
||||
->findOrFail($id);
|
||||
|
||||
$newTemplate = DB::transaction(function () use ($template, $tenantId) {
|
||||
$newTemplate = EsignFieldTemplate::create([
|
||||
$fileData = [];
|
||||
if ($template->file_path && Storage::disk('local')->exists($template->file_path)) {
|
||||
$timestamp = now()->format('YmdHis');
|
||||
$ext = pathinfo($template->file_path, PATHINFO_EXTENSION) ?: 'pdf';
|
||||
$newPath = "esign/{$tenantId}/templates/{$timestamp}_copy.{$ext}";
|
||||
Storage::disk('local')->copy($template->file_path, $newPath);
|
||||
|
||||
$fileData = [
|
||||
'file_path' => $newPath,
|
||||
'file_name' => $template->file_name,
|
||||
'file_hash' => $template->file_hash,
|
||||
'file_size' => $template->file_size,
|
||||
];
|
||||
}
|
||||
|
||||
$newTemplate = EsignFieldTemplate::create(array_merge([
|
||||
'tenant_id' => $tenantId,
|
||||
'name' => $template->name . ' (복사)',
|
||||
'description' => $template->description,
|
||||
@@ -539,7 +622,7 @@ public function duplicateTemplate(int $id): JsonResponse
|
||||
'signer_count' => $template->signer_count,
|
||||
'is_active' => true,
|
||||
'created_by' => auth()->id(),
|
||||
]);
|
||||
], $fileData));
|
||||
|
||||
foreach ($template->items as $item) {
|
||||
EsignFieldTemplateItem::create([
|
||||
|
||||
Reference in New Issue
Block a user