summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/pdftron/serverSDK/createBasicContractPdf.ts133
-rw-r--r--lib/vendors/table/request-pq-dialog.tsx267
-rw-r--r--pages/api/pdftron/createBasicContractPdf.ts16
3 files changed, 199 insertions, 217 deletions
diff --git a/lib/pdftron/serverSDK/createBasicContractPdf.ts b/lib/pdftron/serverSDK/createBasicContractPdf.ts
index a2e0b350..706508e6 100644
--- a/lib/pdftron/serverSDK/createBasicContractPdf.ts
+++ b/lib/pdftron/serverSDK/createBasicContractPdf.ts
@@ -1,4 +1,7 @@
const { PDFNet } = require("@pdftron/pdfnet-node");
+const fs = require('fs').promises;
+const path = require('path');
+import { file as tmpFile } from "tmp-promise";
type CreateBasicContractPdf = (
templateBuffer: Buffer,
@@ -15,99 +18,43 @@ export const createBasicContractPdf: CreateBasicContractPdf = async (
templateBuffer,
templateData
) => {
- const main = async () => {
- await PDFNet.initialize(process.env.NEXT_PUBLIC_PDFTRON_SERVER_KEY);
+ const result = await PDFNet.runWithCleanup(async () => {
console.log("πŸ”„ PDFTron κΈ°λ³Έκ³„μ•½μ„œ PDF λ³€ν™˜ μ‹œμž‘");
console.log("πŸ“ ν…œν”Œλ¦Ώ 데이터:", JSON.stringify(templateData, null, 2));
- // ν…œν”Œλ¦Ώ 데이터가 μžˆλŠ” 경우 λ³€μˆ˜ μΉ˜ν™˜ ν›„ PDF λ³€ν™˜
- if (Object.keys(templateData).length > 0) {
- console.log("πŸ”„ ν…œν”Œλ¦Ώ λ³€μˆ˜ μΉ˜ν™˜ μ‹œμž‘");
-
- try {
- // createReport.ts λ°©μ‹μ²˜λŸΌ ν…œν”Œλ¦Ώ λ³€μˆ˜ μΉ˜ν™˜ (UTF-8 인코딩 지원)
- const options = new PDFNet.Convert.OfficeToPDFOptions();
-
- // UTF-8 인코딩 λͺ…μ‹œ μ„€μ • μ‹œλ„
- try {
- options.setCharset("UTF-8");
- console.log("βœ… UTF-8 인코딩 μ„€μ • μ™„λ£Œ");
- } catch (charsetError) {
- console.warn("⚠️ UTF-8 인코딩 μ„€μ • μ‹€νŒ¨, κΈ°λ³Έ μ„€μ • μ‚¬μš©:", charsetError);
- }
-
- // ν…œν”Œλ¦Ώ 데이터λ₯Ό UTF-8둜 λͺ…μ‹œμ μœΌλ‘œ 인코딩
- const templateDataJson = JSON.stringify(templateData, null, 2);
- const utf8TemplateData = Buffer.from(templateDataJson, 'utf8').toString('utf8');
- console.log("πŸ“ UTF-8 μΈμ½”λ”©λœ ν…œν”Œλ¦Ώ 데이터:", utf8TemplateData);
-
- const tempPath = `/tmp/temp_template_${Date.now()}.docx`;
-
- // νŒŒμΌλ„ UTF-8둜 μ €μž₯ (λ°”μ΄λ„ˆλ¦¬ λ°μ΄ν„°λŠ” κ·ΈλŒ€λ‘œ μœ μ§€)
- require('fs').writeFileSync(tempPath, templateBuffer, { encoding: null }); // λ°”μ΄λ„ˆλ¦¬λ‘œ μ €μž₯
+ // μž„μ‹œ 파일 생성
+ const { path: tempDocxPath, cleanup } = await tmpFile({
+ postfix: ".docx",
+ });
+
+ try {
+ // ν…œν”Œλ¦Ώ 버퍼λ₯Ό μž„μ‹œ 파일둜 μ €μž₯
+ await fs.writeFile(tempDocxPath, templateBuffer);
+
+ let resultDoc;
+
+ // ν…œν”Œλ¦Ώ 데이터가 μžˆλŠ” 경우 λ³€μˆ˜ μΉ˜ν™˜, μ—†μœΌλ©΄ λ‹¨μˆœ λ³€ν™˜
+ if (templateData && Object.keys(templateData).length > 0) {
+ console.log("πŸ”„ ν…œν”Œλ¦Ώ λ³€μˆ˜ μΉ˜ν™˜ μ‹œμž‘");
- // Office ν…œν”Œλ¦Ώ 생성 및 λ³€μˆ˜ μΉ˜ν™˜
- const templateDoc = await PDFNet.Convert.createOfficeTemplateWithPath(
- tempPath,
- options
+ const template = await PDFNet.Convert.createOfficeTemplateWithPath(
+ tempDocxPath
);
-
- const filledDoc = await templateDoc.fillTemplateJson(utf8TemplateData);
-
- // μž„μ‹œ 파일 μ‚­μ œ
- require('fs').unlinkSync(tempPath);
-
- console.log("βœ… ν…œν”Œλ¦Ώ λ³€μˆ˜ μΉ˜ν™˜ 및 PDF λ³€ν™˜ μ™„λ£Œ");
-
- const buffer = await filledDoc.saveMemoryBuffer(
- PDFNet.SDFDoc.SaveOptions.e_linearized
+ resultDoc = await template.fillTemplateJson(
+ JSON.stringify(templateData)
);
-
- return {
- result: true,
- buffer,
- };
- } catch (templateError) {
- console.warn("⚠️ ν…œν”Œλ¦Ώ λ³€μˆ˜ μΉ˜ν™˜ μ‹€νŒ¨, κΈ°λ³Έ λ³€ν™˜ μˆ˜ν–‰:", templateError);
-
- // ν…œν”Œλ¦Ώ 처리 μ‹€νŒ¨ μ‹œ κΈ°λ³Έ PDF λ³€ν™˜λ§Œ μˆ˜ν–‰ (UTF-8 인코딩 적용)
- const fallbackOptions = new PDFNet.Convert.OfficeToPDFOptions();
- try {
- fallbackOptions.setCharset("UTF-8");
- } catch (charsetError) {
- console.warn("⚠️ 폴백 UTF-8 인코딩 μ„€μ • μ‹€νŒ¨:", charsetError);
- }
+ console.log("βœ… ν…œν”Œλ¦Ώ λ³€μˆ˜ μΉ˜ν™˜ 및 PDF λ³€ν™˜ μ™„λ£Œ");
+ } else {
+ console.log("πŸ“„ λ‹¨μˆœ PDF λ³€ν™˜ μˆ˜ν–‰");
- const buf = await PDFNet.Convert.office2PDFBuffer(templateBuffer, fallbackOptions);
- const templateDoc = await PDFNet.PDFDoc.createFromBuffer(buf);
+ resultDoc = await PDFNet.Convert.office2PDF(tempDocxPath);
- const buffer = await templateDoc.saveMemoryBuffer(
- PDFNet.SDFDoc.SaveOptions.e_linearized
- );
-
- return {
- result: true,
- buffer,
- };
+ console.log("βœ… λ‹¨μˆœ PDF λ³€ν™˜ μ™„λ£Œ");
}
- } else {
- // ν…œν”Œλ¦Ώ 데이터가 μ—†λŠ” 경우 λ‹¨μˆœ λ³€ν™˜ (UTF-8 인코딩 적용)
- console.log("πŸ“„ λ‹¨μˆœ PDF λ³€ν™˜ μˆ˜ν–‰ (UTF-8 인코딩)");
-
- const simpleOptions = new PDFNet.Convert.OfficeToPDFOptions();
- try {
- simpleOptions.setCharset("UTF-8");
- console.log("βœ… λ‹¨μˆœ λ³€ν™˜ UTF-8 인코딩 μ„€μ • μ™„λ£Œ");
- } catch (charsetError) {
- console.warn("⚠️ λ‹¨μˆœ λ³€ν™˜ UTF-8 인코딩 μ„€μ • μ‹€νŒ¨:", charsetError);
- }
-
- const buf = await PDFNet.Convert.office2PDFBuffer(templateBuffer, simpleOptions);
- const templateDoc = await PDFNet.PDFDoc.createFromBuffer(buf);
-
- const buffer = await templateDoc.saveMemoryBuffer(
+
+ const buffer = await resultDoc.saveMemoryBuffer(
PDFNet.SDFDoc.SaveOptions.e_linearized
);
@@ -115,23 +62,13 @@ export const createBasicContractPdf: CreateBasicContractPdf = async (
result: true,
buffer,
};
+
+ } finally {
+ // μž„μ‹œ 파일 정리
+ await cleanup();
}
- };
-
- const result = await PDFNet.runWithCleanup(
- main,
+ },
process.env.NEXT_PUBLIC_PDFTRON_SERVER_KEY
- )
- .catch((err: any) => {
- console.error("❌ PDFTron κΈ°λ³Έκ³„μ•½μ„œ PDF λ³€ν™˜ 였λ₯˜:", err);
- return {
- result: false,
- error: err,
- };
- })
- .then(async (data: any) => {
- return data;
- });
-
+ );
return result;
};
diff --git a/lib/vendors/table/request-pq-dialog.tsx b/lib/vendors/table/request-pq-dialog.tsx
index 1df2d72c..226a053f 100644
--- a/lib/vendors/table/request-pq-dialog.tsx
+++ b/lib/vendors/table/request-pq-dialog.tsx
@@ -43,6 +43,7 @@ import { useSession } from "next-auth/react"
import { DatePicker } from "@/components/ui/date-picker"
import { getALLBasicContractTemplates } from "@/lib/basic-contract/service"
import type { BasicContractTemplate } from "@/db/schema"
+// import { PQContractViewer } from "../pq-contract-viewer" // 더 이상 μ‚¬μš©ν•˜μ§€ μ•ŠμŒ
interface RequestPQDialogProps extends React.ComponentPropsWithoutRef<typeof Dialog> {
vendors: Row<Vendor>["original"][]
@@ -78,6 +79,7 @@ export function RequestPQDialog({ vendors, showTrigger = true, onSuccess, ...pro
const [selectedTemplateIds, setSelectedTemplateIds] = React.useState<number[]>([])
const [isLoadingTemplates, setIsLoadingTemplates] = React.useState(false)
+
React.useEffect(() => {
if (type === "PROJECT") {
setIsLoadingProjects(true)
@@ -104,6 +106,7 @@ export function RequestPQDialog({ vendors, showTrigger = true, onSuccess, ...pro
setPqItems("")
setExtraNote("")
setSelectedTemplateIds([])
+
}
}, [props.open])
@@ -116,7 +119,7 @@ export function RequestPQDialog({ vendors, showTrigger = true, onSuccess, ...pro
startApproveTransition(async () => {
try {
// 1단계: PQ 생성
- console.log("πŸš€ 1단계: PQ 생성 μ‹œμž‘")
+ console.log("πŸš€ PQ 생성 μ‹œμž‘")
const { error: pqError } = await requestPQVendors({
ids: vendors.map((v) => v.id),
userId: Number(session.user.id),
@@ -133,128 +136,156 @@ export function RequestPQDialog({ vendors, showTrigger = true, onSuccess, ...pro
toast.error(`PQ 생성 μ‹€νŒ¨: ${pqError}`)
return
}
- console.log("βœ… 1단계: PQ 생성 μ™„λ£Œ")
+ console.log("βœ… PQ 생성 μ™„λ£Œ")
+ toast.success("PQκ°€ μ„±κ³΅μ μœΌλ‘œ μš”μ²­λ˜μ—ˆμŠ΅λ‹ˆλ‹€")
- // 2단계 & 3단계: κΈ°λ³Έκ³„μ•½μ„œ ν…œν”Œλ¦Ώμ΄ μ„ νƒλœ κ²½μš°μ—λ§Œ μ‹€ν–‰ (μ—¬λŸ¬ ν…œν”Œλ¦Ώ 처리)
+ // 2단계: κΈ°λ³Έκ³„μ•½μ„œ ν…œν”Œλ¦Ώμ΄ μ„ νƒλœ 경우 λ°±κ·ΈλΌμš΄λ“œμ—μ„œ 처리
if (selectedTemplateIds.length > 0) {
- console.log(`πŸš€ 2단계 & 3단계: ${selectedTemplateIds.length}개 ν…œν”Œλ¦Ώ 처리 μ‹œμž‘`)
+ const templates = basicContractTemplates.filter(t =>
+ selectedTemplateIds.includes(t.id)
+ )
- let successCount = 0
- let errorCount = 0
- const errors: string[] = []
-
- // ν…œν”Œλ¦Ώλ³„λ‘œ 반볡 처리
- for (let i = 0; i < selectedTemplateIds.length; i++) {
- const templateId = selectedTemplateIds[i]
- const selectedTemplate = basicContractTemplates.find(t => t.id === templateId)
-
- if (!selectedTemplate) {
- console.error(`ν…œν”Œλ¦Ώ ID ${templateId}λ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€`)
- errorCount++
- errors.push(`ν…œν”Œλ¦Ώ ID ${templateId}λ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€`)
- continue
- }
-
- try {
- console.log(`πŸ“„ [${i+1}/${selectedTemplateIds.length}] ${selectedTemplate.templateName} - 2단계: DOCX to PDF λ³€ν™˜ μ‹œμž‘`)
-
- // ν…œν”Œλ¦Ώ νŒŒμΌμ„ κ°€μ Έμ™€μ„œ PDF둜 λ³€ν™˜
- const formData = new FormData()
-
- // ν…œν”Œλ¦Ώ 파일 κ°€μ Έμ˜€κΈ° (μ„œλ²„μ—μ„œ 파일 읽기)
- const templateResponse = await fetch('/api/basic-contract/get-template', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ templateId })
- })
-
- if (!templateResponse.ok) {
- throw new Error(`ν…œν”Œλ¦Ώ νŒŒμΌμ„ κ°€μ Έμ˜¬ 수 μ—†μŠ΅λ‹ˆλ‹€: ${selectedTemplate.templateName}`)
- }
- console.log(`βœ… [${i+1}/${selectedTemplateIds.length}] ${selectedTemplate.templateName} - ν…œν”Œλ¦Ώ 파일 κ°€μ Έμ˜€κΈ° μ™„λ£Œ`)
-
- const templateBlob = await templateResponse.blob()
- const templateFile = new File([templateBlob], selectedTemplate.fileName || 'template.docx')
-
- // ν…œν”Œλ¦Ώ 데이터 생성 (첫 번째 ν˜‘λ ₯업체 정보 기반)
- const firstVendor = vendors[0]
- const templateData = {
- // 영문 λ³€μˆ˜λͺ…μœΌλ‘œ λ³€κ²½ (PDFTron이 ν•œκΈ€ λ³€μˆ˜λͺ…을 μ§€μ›ν•˜μ§€ μ•ŠμŒ)
- vendor_name: firstVendor?.vendorName || 'ν˜‘λ ₯업체λͺ…',
- address: firstVendor?.address || 'μ£Όμ†Œ',
- representative_name: firstVendor?.representativeName || 'λŒ€ν‘œμžλͺ…',
- today_date: new Date().toLocaleDateString('ko-KR'),
- }
-
- console.log(`πŸ“ [${i+1}/${selectedTemplateIds.length}] ${selectedTemplate.templateName} - μƒμ„±λœ ν…œν”Œλ¦Ώ 데이터:`, templateData)
-
- formData.append('templateFile', templateFile)
- formData.append('outputFileName', `${selectedTemplate.templateName}_converted.pdf`)
- formData.append('templateData', JSON.stringify(templateData))
-
- // PDF λ³€ν™˜ 호좜
- const pdfResponse = await fetch('/api/pdftron/createBasicContractPdf', {
- method: 'POST',
- body: formData,
- })
- console.log(`βœ… [${i+1}/${selectedTemplateIds.length}] ${selectedTemplate.templateName} - PDF λ³€ν™˜ 호좜 μ™„λ£Œ`)
-
- if (!pdfResponse.ok) {
- const errorText = await pdfResponse.text()
- throw new Error(`PDF λ³€ν™˜ μ‹€νŒ¨ (${selectedTemplate.templateName}): ${errorText}`)
- }
-
- const pdfBuffer = await pdfResponse.arrayBuffer()
- console.log(`βœ… [${i+1}/${selectedTemplateIds.length}] ${selectedTemplate.templateName} - PDF λ³€ν™˜ μ™„λ£Œ`)
-
- // 3단계: λ³€ν™˜λœ PDF둜 기본계약 생성
- console.log(`πŸ“‹ [${i+1}/${selectedTemplateIds.length}] ${selectedTemplate.templateName} - 3단계: 기본계약 생성 μ‹œμž‘`)
- const { error: contractError } = await requestBasicContractInfo({
- vendorIds: vendors.map((v) => v.id),
- requestedBy: Number(session.user.id),
- templateId,
- pdfBuffer: new Uint8Array(pdfBuffer), // ArrayBufferλ₯Ό Uint8Array둜 λ³€ν™˜ν•˜μ—¬ 전달
- })
-
- if (contractError) {
- console.error(`기본계약 생성 였λ₯˜ (${selectedTemplate.templateName}):`, contractError)
- errorCount++
- errors.push(`${selectedTemplate.templateName}: ${contractError}`)
- } else {
- console.log(`βœ… [${i+1}/${selectedTemplateIds.length}] ${selectedTemplate.templateName} - 3단계: 기본계약 생성 μ™„λ£Œ`)
- successCount++
- }
- } catch (templateError) {
- console.error(`ν…œν”Œλ¦Ώ 처리 였λ₯˜ (${selectedTemplate.templateName}):`, templateError)
- errorCount++
- errors.push(`${selectedTemplate.templateName}: ${templateError instanceof Error ? templateError.message : 'μ•Œ 수 μ—†λŠ” 였λ₯˜'}`)
- }
- }
-
- // κ²°κ³Ό ν† μŠ€νŠΈ λ©”μ‹œμ§€
- if (successCount > 0 && errorCount === 0) {
- toast.success(`PQ μš”μ²­ 및 ${successCount}개 κΈ°λ³Έκ³„μ•½μ„œ 생성이 λͺ¨λ‘ μ™„λ£Œλ˜μ—ˆμŠ΅λ‹ˆλ‹€!`)
- } else if (successCount > 0 && errorCount > 0) {
- toast.success(`PQλŠ” μ„±κ³΅μ μœΌλ‘œ μš”μ²­λ˜μ—ˆμŠ΅λ‹ˆλ‹€. ${successCount}개 κΈ°λ³Έκ³„μ•½μ„œ 성곡, ${errorCount}개 μ‹€νŒ¨`)
- console.error('κΈ°λ³Έκ³„μ•½μ„œ 생성 였λ₯˜λ“€:', errors)
- } else if (errorCount > 0) {
- toast.error(`PQλŠ” μ„±κ³΅μ μœΌλ‘œ μš”μ²­λ˜μ—ˆμ§€λ§Œ, λͺ¨λ“  κΈ°λ³Έκ³„μ•½μ„œ 생성이 μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€`)
- console.error('κΈ°λ³Έκ³„μ•½μ„œ 생성 였λ₯˜λ“€:', errors)
- }
- } else {
- // κΈ°λ³Έκ³„μ•½μ„œ ν…œν”Œλ¦Ώμ΄ μ„ νƒλ˜μ§€ μ•Šμ€ 경우
- toast.success("PQκ°€ μ„±κ³΅μ μœΌλ‘œ μš”μ²­λ˜μ—ˆμŠ΅λ‹ˆλ‹€")
+ console.log("πŸ“‹ κΈ°λ³Έκ³„μ•½μ„œ λ°±κ·ΈλΌμš΄λ“œ 처리 μ‹œμž‘", templates.length, "개 ν…œν”Œλ¦Ώ")
+ await processBasicContractsInBackground(templates, vendors)
}
-
+
+ // μ™„λ£Œ ν›„ λ‹€μ΄μ–Όλ‘œκ·Έ λ‹«κΈ°
props.onOpenChange?.(false)
onSuccess?.()
+
} catch (error) {
- console.error('전체 ν”„λ‘œμ„ΈμŠ€ 였λ₯˜:', error)
+ console.error('PQ 생성 였λ₯˜:', error)
toast.error(`처리 쀑 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€: ${error instanceof Error ? error.message : 'μ•Œ 수 μ—†λŠ” 였λ₯˜'}`)
}
})
}
+ // λ°±κ·ΈλΌμš΄λ“œμ—μ„œ κΈ°λ³Έκ³„μ•½μ„œ 처리
+ const processBasicContractsInBackground = async (templates: BasicContractTemplate[], vendors: any[]) => {
+ if (!session?.user?.id) {
+ toast.error("인증 정보가 μ—†μŠ΅λ‹ˆλ‹€")
+ return
+ }
+
+ try {
+ const totalContracts = templates.length * vendors.length
+ let processedCount = 0
+
+ // 각 λ²€λ”λ³„λ‘œ, 각 ν…œν”Œλ¦Ώμ„ 처리
+ for (let vendorIndex = 0; vendorIndex < vendors.length; vendorIndex++) {
+ const vendor = vendors[vendorIndex]
+
+ // 벀더별 ν…œν”Œλ¦Ώ 데이터 생성
+ const templateData = {
+ vendor_name: vendor.vendorName || 'ν˜‘λ ₯업체λͺ…',
+ address: vendor.address || 'μ£Όμ†Œ',
+ representative_name: vendor.representativeName || 'λŒ€ν‘œμžλͺ…',
+ today_date: new Date().toLocaleDateString('ko-KR'),
+ }
+
+ console.log(`πŸ”„ 벀더 ${vendorIndex + 1}/${vendors.length} ν…œν”Œλ¦Ώ 데이터:`, templateData)
+
+ // ν•΄λ‹Ή 벀더에 λŒ€ν•΄ 각 ν…œν”Œλ¦Ώμ„ 순차적으둜 처리
+ for (let templateIndex = 0; templateIndex < templates.length; templateIndex++) {
+ const template = templates[templateIndex]
+ processedCount++
+
+ console.log(`πŸ“„ 처리 쀑: ${vendor.vendorName} - ${template.templateName} (${processedCount}/${totalContracts})`)
+
+ // κ°œλ³„ 벀더에 λŒ€ν•œ 기본계약 생성
+ await processTemplate(template, templateData, [vendor])
+
+ console.log(`βœ… μ™„λ£Œ: ${vendor.vendorName} - ${template.templateName}`)
+ }
+ }
+
+ toast.success(`총 ${totalContracts}개 기본계약이 λͺ¨λ‘ μƒμ„±λ˜μ—ˆμŠ΅λ‹ˆλ‹€`)
+
+ } catch (error) {
+ console.error('기본계약 처리 쀑 였λ₯˜:', error)
+ toast.error(`기본계약 처리 쀑 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€: ${error instanceof Error ? error.message : 'μ•Œ 수 μ—†λŠ” 였λ₯˜'}`)
+ }
+ }
+
+ const processTemplate = async (template: BasicContractTemplate, templateData: any, vendors: any[]) => {
+ try {
+ // 1. ν…œν”Œλ¦Ώ 파일 κ°€μ Έμ˜€κΈ°
+ const templateResponse = await fetch('/api/basic-contract/get-template', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ templateId: template.id })
+ })
+
+ if (!templateResponse.ok) {
+ throw new Error(`ν…œν”Œλ¦Ώ νŒŒμΌμ„ κ°€μ Έμ˜¬ 수 μ—†μŠ΅λ‹ˆλ‹€: ${template.templateName}`)
+ }
+
+ const templateBlob = await templateResponse.blob()
+
+ // 2. PDFTron을 μ‚¬μš©ν•΄μ„œ λ³€μˆ˜ μΉ˜ν™˜ 및 PDF λ³€ν™˜
+ // @ts-ignore
+ const WebViewer = await import("@pdftron/webviewer").then(({ default: WebViewer }) => WebViewer)
+
+ // μž„μ‹œ WebViewer μΈμŠ€ν„΄μŠ€ 생성 (DOM에 μΆ”κ°€ν•˜μ§€ μ•ŠμŒ)
+ const tempDiv = document.createElement('div')
+ tempDiv.style.display = 'none'
+ document.body.appendChild(tempDiv)
+
+ const instance = await WebViewer(
+ {
+ path: "/pdftronWeb",
+ licenseKey: process.env.NEXT_PUBLIC_PDFTRON_WEBVIEW_KEY,
+ fullAPI: true,
+ },
+ tempDiv
+ )
+
+ try {
+ const { Core } = instance
+ const { createDocument } = Core
+
+ // 3. ν…œν”Œλ¦Ώ λ¬Έμ„œ 생성 및 λ³€μˆ˜ μΉ˜ν™˜
+ const templateDoc = await createDocument(templateBlob, {
+ filename: template.fileName || 'template.docx',
+ extension: 'docx',
+ })
+
+ console.log("πŸ”„ λ³€μˆ˜ μΉ˜ν™˜ μ‹œμž‘:", templateData)
+ await templateDoc.applyTemplateValues(templateData)
+ console.log("βœ… λ³€μˆ˜ μΉ˜ν™˜ μ™„λ£Œ")
+
+ // 4. PDF λ³€ν™˜
+ const fileData = await templateDoc.getFileData()
+ const pdfBuffer = await Core.officeToPDFBuffer(fileData, { extension: 'docx' })
+
+ console.log(`βœ… PDF λ³€ν™˜ μ™„λ£Œ: ${template.templateName}`, `크기: ${pdfBuffer.byteLength} bytes`)
+
+ // 5. 기본계약 생성 μš”μ²­
+ const { error: contractError } = await requestBasicContractInfo({
+ vendorIds: vendors.map((v) => v.id),
+ requestedBy: Number(session!.user.id),
+ templateId: template.id,
+ pdfBuffer: new Uint8Array(pdfBuffer),
+ })
+
+ if (contractError) {
+ throw new Error(contractError)
+ }
+
+ console.log(`βœ… 기본계약 생성 μ™„λ£Œ: ${template.templateName}`)
+
+ } finally {
+ // μž„μ‹œ WebViewer 정리
+ instance.UI.dispose()
+ document.body.removeChild(tempDiv)
+ }
+
+ } catch (error) {
+ console.error(`❌ ν…œν”Œλ¦Ώ 처리 μ‹€νŒ¨: ${template.templateName}`, error)
+ throw error
+ }
+ }
+
const dialogContent = (
<div className="space-y-4 py-2">
{/* μ„ νƒλœ ν˜‘λ ₯업체 정보 */}
@@ -309,7 +340,15 @@ export function RequestPQDialog({ vendors, showTrigger = true, onSuccess, ...pro
<Label htmlFor="dueDate">PQ 제좜 마감일</Label>
<DatePicker
date={dueDate ? new Date(dueDate) : undefined}
- onSelect={(date?: Date) => setDueDate(date ? date.toISOString().slice(0, 10) : "")}
+ onSelect={(date?: Date) => {
+ if (date) {
+ // ν•œκ΅­ μ‹œκ°„λŒ€λ‘œ λ‚ μ§œ λ³€ν™˜ (UTC λ³€ν™˜μœΌλ‘œ μΈν•œ λ‚ μ§œ λ³€κ²½ λ°©μ§€)
+ const kstDate = new Date(date.getTime() - date.getTimezoneOffset() * 60000)
+ setDueDate(kstDate.toISOString().slice(0, 10))
+ } else {
+ setDueDate("")
+ }
+ }}
placeholder="마감일 선택"
/>
</div>
@@ -421,6 +460,8 @@ export function RequestPQDialog({ vendors, showTrigger = true, onSuccess, ...pro
</Button>
</DialogFooter>
</DialogContent>
+
+
</Dialog>
)
}
@@ -452,6 +493,8 @@ export function RequestPQDialog({ vendors, showTrigger = true, onSuccess, ...pro
</Button>
</DrawerFooter>
</DrawerContent>
+
+
</Drawer>
)
}
diff --git a/pages/api/pdftron/createBasicContractPdf.ts b/pages/api/pdftron/createBasicContractPdf.ts
index 1122c022..376d8540 100644
--- a/pages/api/pdftron/createBasicContractPdf.ts
+++ b/pages/api/pdftron/createBasicContractPdf.ts
@@ -294,13 +294,15 @@ export default async function handler(
// 4. 원본 파일 읽기
const originalBuffer = await fs.readFile(templateFile.filepath);
-
+ // const publicDir = path.join(process.cwd(), "public", "basicContract");
+ // const testBuffer = await fs.readFile(path.join(publicDir, "test123.docx"));
+ // console.log(testBuffer);
// 5. DRM λ³΅ν˜Έν™” 처리 (λ³΄μ•ˆ 검증 포함)
- console.log(`πŸ” [${requestId}] DRM λ³΅ν˜Έν™” μ‹œμž‘: ${templateFile.originalFilename || 'unknown'}`);
- const decryptedBuffer = await decryptBufferWithDRM(
- originalBuffer,
- templateFile.originalFilename || 'template.docx'
- );
+ // console.log(`πŸ” [${requestId}] DRM λ³΅ν˜Έν™” μ‹œμž‘: ${templateFile.originalFilename || 'unknown'}`);
+ // const decryptedBuffer = await decryptBufferWithDRM(
+ // originalBuffer,
+ // templateFile.originalFilename || 'template.docx'
+ // );
// 6. λ³΅ν˜Έν™”λœ λ²„νΌλ‘œ κΈ°λ³Έκ³„μ•½μ„œ PDF 생성
console.log(`πŸ“„ [${requestId}] κΈ°λ³Έκ³„μ•½μ„œ PDF 생성 μ‹œμž‘`);
@@ -308,7 +310,7 @@ export default async function handler(
result,
buffer: pdfBuffer,
error,
- } = await createBasicContractPdf(decryptedBuffer, templateData);
+ } = await createBasicContractPdf(originalBuffer, templateData);
if (result && pdfBuffer) {
console.log(`βœ… [${requestId}] κΈ°λ³Έκ³„μ•½μ„œ PDF 생성 성곡: ${outputFileName}`);