feat:E-Sign DOCX 업로드 시 PDF 자동 변환 (LibreOffice)

Word(.docx/.doc) 파일 업로드 시 서버에서 LibreOffice headless로 PDF 자동 변환.
계약 생성, PDF 업로드, 템플릿 PDF 교체 3개 엔드포인트에 적용.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
김보곤
2026-02-13 09:12:59 +09:00
parent 94e1e7dbb5
commit 165ccf843e
5 changed files with 115 additions and 22 deletions

View File

@@ -5,6 +5,7 @@
use App\Http\Controllers\Controller;
use App\Mail\EsignRequestMail;
use App\Models\ESign\EsignContract;
use App\Services\ESign\DocxToPdfConverter;
use App\Models\ESign\EsignFieldTemplate;
use App\Models\ESign\EsignFieldTemplateItem;
use App\Models\ESign\EsignSigner;
@@ -97,6 +98,7 @@ public function store(Request $request): JsonResponse
'signers.*.role' => 'required|in:creator,counterpart',
'metadata' => 'nullable|array',
'metadata.*' => 'nullable|string|max:500',
'file' => 'nullable|file|mimes:pdf,doc,docx|max:20480',
]);
$tenantId = session('selected_tenant_id', 1);
@@ -112,12 +114,14 @@ public function store(Request $request): JsonResponse
$fileSize = null;
if ($request->hasFile('file')) {
// 사용자가 직접 업로드한 파일 우선 사용
// 사용자가 직접 업로드한 파일 우선 사용 (Word면 PDF 자동 변환)
$file = $request->file('file');
$fileName = $file->getClientOriginalName();
$fileSize = $file->getSize();
$fileHash = hash_file('sha256', $file->getRealPath());
$filePath = $file->store("esign/{$tenantId}/contracts", 'local');
$converter = new DocxToPdfConverter();
$result = $converter->convertAndStore($file, "esign/{$tenantId}/contracts");
$filePath = $result['path'];
$fileName = $result['name'];
$fileHash = $result['hash'];
$fileSize = $result['size'];
} elseif ($request->input('template_id')) {
// 템플릿에 PDF가 있으면 복사
$template = EsignFieldTemplate::forTenant($tenantId)
@@ -535,7 +539,7 @@ public function download(int $id)
public function uploadPdf(Request $request, int $id): JsonResponse
{
$request->validate([
'file' => 'required|file|mimes:pdf|max:20480',
'file' => 'required|file|mimes:pdf,doc,docx|max:20480',
]);
$tenantId = session('selected_tenant_id', 1);
@@ -546,20 +550,21 @@ public function uploadPdf(Request $request, int $id): JsonResponse
}
$file = $request->file('file');
$filePath = $file->store("esign/{$tenantId}/contracts", 'local');
$converter = new DocxToPdfConverter();
$result = $converter->convertAndStore($file, "esign/{$tenantId}/contracts");
$contract->update([
'original_file_path' => $filePath,
'original_file_name' => $file->getClientOriginalName(),
'original_file_hash' => hash_file('sha256', $file->getRealPath()),
'original_file_size' => $file->getSize(),
'original_file_path' => $result['path'],
'original_file_name' => $result['name'],
'original_file_hash' => $result['hash'],
'original_file_size' => $result['size'],
'updated_by' => auth()->id(),
]);
return response()->json([
'success' => true,
'message' => 'PDF 파일이 업로드되었습니다.',
'data' => ['path' => $filePath, 'name' => $file->getClientOriginalName()],
'data' => ['path' => $result['path'], 'name' => $result['name']],
]);
}
@@ -764,7 +769,7 @@ public function updateTemplate(Request $request, int $id): JsonResponse
public function uploadTemplatePdf(Request $request, int $id): JsonResponse
{
$request->validate([
'file' => 'required|file|mimes:pdf|max:20480',
'file' => 'required|file|mimes:pdf,doc,docx|max:20480',
]);
$tenantId = session('selected_tenant_id', 1);
@@ -776,13 +781,14 @@ public function uploadTemplatePdf(Request $request, int $id): JsonResponse
}
$file = $request->file('file');
$filePath = $file->store("esign/{$tenantId}/templates", 'local');
$converter = new DocxToPdfConverter();
$result = $converter->convertAndStore($file, "esign/{$tenantId}/templates");
$template->update([
'file_path' => $filePath,
'file_name' => $file->getClientOriginalName(),
'file_hash' => hash_file('sha256', $file->getRealPath()),
'file_size' => $file->getSize(),
'file_path' => $result['path'],
'file_name' => $result['name'],
'file_hash' => $result['hash'],
'file_size' => $result['size'],
]);
return response()->json([