summaryrefslogtreecommitdiff
path: root/lib/general-contracts/utils.ts
diff options
context:
space:
mode:
Diffstat (limited to 'lib/general-contracts/utils.ts')
-rw-r--r--lib/general-contracts/utils.ts73
1 files changed, 69 insertions, 4 deletions
diff --git a/lib/general-contracts/utils.ts b/lib/general-contracts/utils.ts
index ec15a3a1..1262dc4d 100644
--- a/lib/general-contracts/utils.ts
+++ b/lib/general-contracts/utils.ts
@@ -1,5 +1,8 @@
import { format } from "date-fns"
+const DEFAULT_SHI_ADDRESS = "경기도 성남시 분당구 판교로 227번길 23"
+const DEFAULT_SHI_CEO_NAME = "최성안"
+
/**
* ContractSummary 인터페이스 (UI 컴포넌트와 맞춤)
*/
@@ -20,6 +23,9 @@ export function mapContractDataToTemplateVariables(contractSummary: ContractSumm
const { basicInfo, items, storageInfo } = contractSummary
const firstItem = items && items.length > 0 ? items[0] : {}
+ const shiAddress = basicInfo.shiAddress || DEFAULT_SHI_ADDRESS
+ const shiCeoName = basicInfo.shiCeoName || DEFAULT_SHI_CEO_NAME
+
// 날짜 포맷팅 헬퍼 (YYYY-MM-DD)
const formatDate = (date: any) => {
if (!date) return ''
@@ -164,6 +170,51 @@ export function mapContractDataToTemplateVariables(contractSummary: ContractSumm
).join('\n')
: ''
+ // PDFTron 템플릿 루프용 데이터 ({{#storageList}} ... {{/storageList}} 사용)
+ const storageList = storageItems.map(item => ({
+ project: (item.projectName || item.projectCode || '').toString().trim(),
+ poNumber: (item.poNumber || '').toString().trim(),
+ hullNumber: (item.hullNumber || '').toString().trim(),
+ remainingAmount: formatCurrency(item.remainingAmount),
+ }))
+
+ // 일반 견적 품목 루프용 데이터 ({{#itemsList}} ... {{/itemsList}} 사용)
+ const itemsList = (items || []).map((item, idx) => {
+ const quantityRaw = item.quantity ?? item.qty ?? ''
+ const unitPriceRaw = item.contractUnitPrice ?? item.unitPrice ?? ''
+ const amountRaw =
+ item.contractAmount ??
+ (Number(quantityRaw) * Number(unitPriceRaw))
+
+ const quantityNum = Number(quantityRaw)
+ const hasQuantity = !isNaN(quantityNum)
+ const unitPriceNum = Number(unitPriceRaw)
+ const hasUnitPrice = !isNaN(unitPriceNum)
+ const hasAmountCalc = !isNaN(amountRaw as number)
+
+ const amount = hasAmountCalc ? formatCurrency(amountRaw) : ''
+
+ return {
+ no: idx + 1, // NO
+ hullNumber: (item.projectCode || basicInfo.projectCode || '').toString().trim(), // 호선번호
+ shipType: (item.projectName || basicInfo.projectName || '').toString().trim(), // 선종/선형
+ exportCountry: (basicInfo.vendorCountry || basicInfo.country || '').toString().trim(), // 수출국
+ itemName: (item.itemInfo || item.description || item.itemCode || '').toString().trim(), // 품목
+ unit: (item.quantityUnit || '').toString().trim(), // 단위
+ unitPrice: hasUnitPrice ? formatCurrency(unitPriceNum) : formatCurrency(unitPriceRaw), // 단가
+ amount, // 금액
+ remark: (item.remark || item.remarks || item.note || '').toString().trim(), // 비고
+ // 보존용 기존 필드
+ itemCode: (item.itemCode || item.itemInfo || '').toString().trim(),
+ quantity: hasQuantity ? quantityNum : (quantityRaw ?? ''),
+ }
+ })
+
+ // 루프 미지원 템플릿을 위한 품목 텍스트 fallback
+ const itemsTableText = itemsList.length > 0
+ ? itemsList.map(i => `${i.no}. ${i.hullNumber || '-'} / ${i.shipType || '-'} / ${i.exportCountry || '-'} / ${i.itemName || '-'} / 단위:${i.unit || '-'} / 단가:${i.unitPrice || '-'} / 금액:${i.amount || '-'} / 비고:${i.remark || '-'}`).join('\n')
+ : ''
+
// ═══════════════════════════════════════════════════════════════
// 변수 매핑 시작
@@ -206,8 +257,8 @@ export function mapContractDataToTemplateVariables(contractSummary: ContractSumm
// ----------------------------------
// 당사(SHI) 정보 (고정값/설정값)
// ----------------------------------
- shiAddress: "경기도 성남시 분당구 판교로 227번길 23", // {{SHI_Address}}, {{위탁자 주소}}
- shiCeoName: "최성안", // {{SHI_CEO_Name}}, {{대표이사}}
+ shiAddress: shiAddress, // {{SHI_Address}}, {{위탁자 주소}}
+ shiCeoName: shiCeoName, // {{SHI_CEO_Name}}, {{대표이사}}
// ----------------------------------
// 품목 정보
@@ -290,7 +341,13 @@ export function mapContractDataToTemplateVariables(contractSummary: ContractSumm
// ----------------------------------
storageTableText: storageTableText, // {{storageTableText}} (fallback)
// PDFTron에서 배열을 받아 테이블 루프를 돌릴 수 있다면 아래 키를 사용
- storageList: storageItems,
+ storageList,
+
+ // ----------------------------------
+ // 일반 견적 품목 루프 (템플릿 표에 {{#itemsList}} 사용)
+ // ----------------------------------
+ itemsList,
+ itemsTableText,
}
// 3. 모든 키를 순회하며 undefined나 null을 빈 문자열로 변환 (안전장치)
@@ -300,5 +357,13 @@ export function mapContractDataToTemplateVariables(contractSummary: ContractSumm
}
})
- return variables
+ // 4. PDF 템플릿에서 추출한 {{ }} 변수명이 공백을 포함할 수 있어 trim 처리 후 매핑
+ const normalizedVariables: Record<string, any> = {}
+ Object.entries(variables).forEach(([key, value]) => {
+ const trimmedKey = key.trim()
+ const trimmedValue = typeof value === 'string' ? value.trim() : value
+ normalizedVariables[trimmedKey] = trimmedValue
+ })
+
+ return normalizedVariables
}