fix: [approval] 재직증명서 DOCX 생성을 PhpWord 직접 생성으로 변경
- 외부 템플릿 파일(employment_cert.docx) 의존성 제거 - PhpWord로 테이블/텍스트 직접 생성하여 서버 배포 시 템플릿 누락 문제 해결
This commit is contained in:
@@ -6,7 +6,9 @@
|
|||||||
use App\Models\HR\Employee;
|
use App\Models\HR\Employee;
|
||||||
use App\Models\Tenants\Tenant;
|
use App\Models\Tenants\Tenant;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use PhpOffice\PhpWord\TemplateProcessor;
|
use PhpOffice\PhpWord\PhpWord;
|
||||||
|
use PhpOffice\PhpWord\SimpleType\Jc;
|
||||||
|
use PhpOffice\PhpWord\SimpleType\TblWidth;
|
||||||
|
|
||||||
class EmploymentCertService
|
class EmploymentCertService
|
||||||
{
|
{
|
||||||
@@ -45,17 +47,20 @@ public function getCertInfo(int $userId, int $tenantId): array
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DOCX 생성
|
* DOCX 생성 (PhpWord 직접 생성 - 외부 템플릿 불필요)
|
||||||
*/
|
*/
|
||||||
public function generateDocx(array $data, int $tenantId): string
|
public function generateDocx(array $data, int $tenantId): string
|
||||||
{
|
{
|
||||||
$templatePath = storage_path('app/templates/employment_cert.docx');
|
$phpWord = new PhpWord;
|
||||||
|
$phpWord->setDefaultFontName('맑은 고딕');
|
||||||
|
$phpWord->setDefaultFontSize(11);
|
||||||
|
|
||||||
if (! file_exists($templatePath)) {
|
$section = $phpWord->addSection([
|
||||||
throw new \RuntimeException('재직증명서 템플릿 파일이 없습니다.');
|
'marginTop' => 1440, // 1 inch
|
||||||
}
|
'marginBottom' => 1440,
|
||||||
|
'marginLeft' => 1440,
|
||||||
$template = new TemplateProcessor($templatePath);
|
'marginRight' => 1440,
|
||||||
|
]);
|
||||||
|
|
||||||
$hireDateFormatted = '';
|
$hireDateFormatted = '';
|
||||||
if (! empty($data['hire_date'])) {
|
if (! empty($data['hire_date'])) {
|
||||||
@@ -65,34 +70,122 @@ public function generateDocx(array $data, int $tenantId): string
|
|||||||
$hireDateFormatted = $data['hire_date'];
|
$hireDateFormatted = $data['hire_date'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$issueDateFormatted = date('Y년 m월 d일');
|
$issueDateFormatted = date('Y년 m월 d일');
|
||||||
|
|
||||||
$template->setValue('name', $data['name'] ?? '');
|
// 제목
|
||||||
$template->setValue('resident_number', $data['resident_number_full'] ?? '');
|
$section->addText('재 직 증 명 서', [
|
||||||
$template->setValue('address', $data['address'] ?? '');
|
'size' => 22,
|
||||||
$template->setValue('company_name', $data['company_name'] ?? '');
|
'bold' => true,
|
||||||
$template->setValue('business_num', $data['business_num'] ?? '');
|
], ['alignment' => Jc::CENTER, 'spaceAfter' => 400]);
|
||||||
$template->setValue('ceo_name', $data['ceo_name'] ?? '');
|
|
||||||
$template->setValue('phone', $data['phone'] ?? '');
|
|
||||||
$template->setValue('company_address', $data['company_address'] ?? '');
|
|
||||||
$template->setValue('department', $data['department'] ?? '');
|
|
||||||
$template->setValue('position', $data['position'] ?? '');
|
|
||||||
$template->setValue('hire_date', $hireDateFormatted);
|
|
||||||
$template->setValue('purpose', $data['purpose'] ?? '');
|
|
||||||
$template->setValue('issue_date', $issueDateFormatted);
|
|
||||||
|
|
||||||
|
$section->addTextBreak();
|
||||||
|
|
||||||
|
// === 1. 인적사항 ===
|
||||||
|
$section->addText('1. 인적사항', ['size' => 12, 'bold' => true], ['spaceAfter' => 120]);
|
||||||
|
|
||||||
|
$tableStyle = [
|
||||||
|
'borderSize' => 6,
|
||||||
|
'borderColor' => '333333',
|
||||||
|
'cellMargin' => 80,
|
||||||
|
'width' => 100 * 50,
|
||||||
|
'unit' => TblWidth::PERCENT,
|
||||||
|
];
|
||||||
|
$thStyle = ['bgColor' => 'F8F9FA', 'valign' => 'center'];
|
||||||
|
$thFont = ['size' => 10, 'bold' => true];
|
||||||
|
$tdFont = ['size' => 10];
|
||||||
|
|
||||||
|
$table = $section->addTable($tableStyle);
|
||||||
|
|
||||||
|
$table->addRow(400);
|
||||||
|
$table->addCell(1800, $thStyle)->addText('성 명', $thFont);
|
||||||
|
$table->addCell(3200)->addText($data['name'] ?? '', $tdFont);
|
||||||
|
$table->addCell(1800, $thStyle)->addText('주민등록번호', $thFont);
|
||||||
|
$table->addCell(3200)->addText($data['resident_number_full'] ?? '', $tdFont);
|
||||||
|
|
||||||
|
$table->addRow(400);
|
||||||
|
$table->addCell(1800, $thStyle)->addText('주 소', $thFont);
|
||||||
|
$table->addCell(8200, ['gridSpan' => 3])->addText($data['address'] ?? '', $tdFont);
|
||||||
|
|
||||||
|
$section->addTextBreak();
|
||||||
|
|
||||||
|
// === 2. 재직사항 ===
|
||||||
|
$section->addText('2. 재직사항', ['size' => 12, 'bold' => true], ['spaceAfter' => 120]);
|
||||||
|
|
||||||
|
$table2 = $section->addTable($tableStyle);
|
||||||
|
|
||||||
|
$table2->addRow(400);
|
||||||
|
$table2->addCell(1800, $thStyle)->addText('회 사 명', $thFont);
|
||||||
|
$table2->addCell(8200, ['gridSpan' => 3])->addText($data['company_name'] ?? '', $tdFont);
|
||||||
|
|
||||||
|
$table2->addRow(400);
|
||||||
|
$table2->addCell(1800, $thStyle)->addText('사업자번호', $thFont);
|
||||||
|
$table2->addCell(8200, ['gridSpan' => 3])->addText($data['business_num'] ?? '', $tdFont);
|
||||||
|
|
||||||
|
$table2->addRow(400);
|
||||||
|
$table2->addCell(1800, $thStyle)->addText('근무부서', $thFont);
|
||||||
|
$table2->addCell(3200)->addText($data['department'] ?? '', $tdFont);
|
||||||
|
$table2->addCell(1800, $thStyle)->addText('직 급', $thFont);
|
||||||
|
$table2->addCell(3200)->addText($data['position'] ?? '', $tdFont);
|
||||||
|
|
||||||
|
$table2->addRow(400);
|
||||||
|
$table2->addCell(1800, $thStyle)->addText('재직기간', $thFont);
|
||||||
|
$table2->addCell(8200, ['gridSpan' => 3])->addText($hireDateFormatted.' ~ 현재', $tdFont);
|
||||||
|
|
||||||
|
$section->addTextBreak();
|
||||||
|
|
||||||
|
// === 3. 발급정보 ===
|
||||||
|
$section->addText('3. 발급정보', ['size' => 12, 'bold' => true], ['spaceAfter' => 120]);
|
||||||
|
|
||||||
|
$table3 = $section->addTable($tableStyle);
|
||||||
|
|
||||||
|
$table3->addRow(400);
|
||||||
|
$table3->addCell(1800, $thStyle)->addText('사용용도', $thFont);
|
||||||
|
$table3->addCell(8200, ['gridSpan' => 3])->addText($data['purpose'] ?? '', $tdFont);
|
||||||
|
|
||||||
|
$section->addTextBreak(2);
|
||||||
|
|
||||||
|
// 증명 문구
|
||||||
|
$section->addText(
|
||||||
|
'위 사항을 증명합니다.',
|
||||||
|
['size' => 12],
|
||||||
|
['alignment' => Jc::CENTER, 'spaceBefore' => 400, 'spaceAfter' => 400]
|
||||||
|
);
|
||||||
|
|
||||||
|
$section->addTextBreak();
|
||||||
|
|
||||||
|
// 발급일
|
||||||
|
$section->addText(
|
||||||
|
$issueDateFormatted,
|
||||||
|
['size' => 12, 'bold' => true],
|
||||||
|
['alignment' => Jc::CENTER, 'spaceAfter' => 600]
|
||||||
|
);
|
||||||
|
|
||||||
|
$section->addTextBreak();
|
||||||
|
|
||||||
|
// 회사명 + 대표이사
|
||||||
|
$section->addText(
|
||||||
|
($data['company_name'] ?? ''),
|
||||||
|
['size' => 14, 'bold' => true],
|
||||||
|
['alignment' => Jc::CENTER]
|
||||||
|
);
|
||||||
|
$section->addText(
|
||||||
|
'대표이사 '.($data['ceo_name'] ?? '').' (인)',
|
||||||
|
['size' => 12],
|
||||||
|
['alignment' => Jc::CENTER]
|
||||||
|
);
|
||||||
|
|
||||||
|
// 파일 저장
|
||||||
$outputDir = storage_path("app/approvals/{$tenantId}");
|
$outputDir = storage_path("app/approvals/{$tenantId}");
|
||||||
if (! is_dir($outputDir)) {
|
if (! is_dir($outputDir)) {
|
||||||
mkdir($outputDir, 0755, true);
|
mkdir($outputDir, 0755, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$fileName = '재직증명서_'.($data['name'] ?? 'unknown').'_'.date('Ymd').'.docx';
|
|
||||||
$storedName = Str::random(40).'.docx';
|
$storedName = Str::random(40).'.docx';
|
||||||
$storagePath = "approvals/{$tenantId}/{$storedName}";
|
$storagePath = "approvals/{$tenantId}/{$storedName}";
|
||||||
$fullPath = storage_path("app/{$storagePath}");
|
$fullPath = storage_path("app/{$storagePath}");
|
||||||
|
|
||||||
$template->saveAs($fullPath);
|
$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007');
|
||||||
|
$objWriter->save($fullPath);
|
||||||
|
|
||||||
return $storagePath;
|
return $storagePath;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user