diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-12-09 09:46:22 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-12-09 09:46:22 +0000 |
| commit | 09858255bcea648c01939447233fea9e955a36ee (patch) | |
| tree | 57e22338c523a64fcb9bdcd5e2d9c75236569765 | |
| parent | bf4b3bd7ac7a8ab6fbf6672c639e9fc86c090f65 (diff) | |
(최겸) 일반계약 템플릿 매핑 수정, 템플릿 파일 변경완료(품질 업로드 완료)
4 files changed, 75 insertions, 6 deletions
diff --git a/app/[lng]/partners/(partners)/pq_new/[id]/page.tsx b/app/[lng]/partners/(partners)/pq_new/[id]/page.tsx index e43d600f..448267d0 100644 --- a/app/[lng]/partners/(partners)/pq_new/[id]/page.tsx +++ b/app/[lng]/partners/(partners)/pq_new/[id]/page.tsx @@ -134,9 +134,10 @@ export default async function PQEditPage(props: PQEditPageProps) { ); // 상태에 따른 읽기 전용 모드 결정 - const isReadOnly = [ "APPROVED"].includes(pqSubmission.status); + const isReadOnly = [ "QM_APPROVED"].includes(pqSubmission.status); const statusText = pqSubmission.status === "SUBMITTED" ? "제출됨" : pqSubmission.status === "APPROVED" ? "승인됨" : + pqSubmission.status === "QM_APPROVED" ? "최종 승인됨" : pqSubmission.status === "REJECTED" ? "거부됨" : "작성 중"; const pageTitle = pqSubmission.type === "PROJECT" diff --git a/app/[lng]/partners/(partners)/pq_new/page.tsx b/app/[lng]/partners/(partners)/pq_new/page.tsx index e72144c0..89a646a8 100644 --- a/app/[lng]/partners/(partners)/pq_new/page.tsx +++ b/app/[lng]/partners/(partners)/pq_new/page.tsx @@ -51,6 +51,12 @@ function getStatusBadge(status: string) { return <Badge variant="default">승인됨</Badge>; case "REJECTED": return <Badge variant="destructive">거부됨</Badge>; + case "QM_REVIEWING": + return <Badge variant="secondary">QM 검토 중</Badge>; + case "QM_APPROVED": + return <Badge variant="default">최종 승인됨</Badge>; + case "QM_REJECTED": + return <Badge variant="destructive">최종 거부됨</Badge>; default: return <Badge variant="outline">{status}</Badge>; } @@ -262,8 +268,8 @@ export default async function PQListPage({ params }: IndexPageProps) { </TableRow> ) : ( pqList.map((pq) => { - const canEdit = ["REQUESTED", "IN_PROGRESS", "REJECTED"].includes(pq.status); - const canView = ["SUBMITTED", "APPROVED"].includes(pq.status); + const canEdit = ["REQUESTED", "IN_PROGRESS", "REJECTED", "SAFETY_APPROVED", "QM_REVIEWING"].includes(pq.status); + const canView = ["SUBMITTED", "APPROVED", "QM_APPROVED", "SAFETY_REJECTED", "QM_REJECTED"].includes(pq.status); return ( <TableRow key={pq.id}> diff --git a/lib/general-contracts/detail/general-contract-approval-request-dialog.tsx b/lib/general-contracts/detail/general-contract-approval-request-dialog.tsx index db0901cb..04054369 100644 --- a/lib/general-contracts/detail/general-contract-approval-request-dialog.tsx +++ b/lib/general-contracts/detail/general-contract-approval-request-dialog.tsx @@ -245,7 +245,10 @@ export function ContractApprovalRequestDialog({ if (contractData) { summary.basicInfo = { ...summary.basicInfo, - externalYardEntry: contractData.externalYardEntry || 'N' + externalYardEntry: contractData.externalYardEntry || 'N', + vendorCountry: (contractData as any)?.vendorCountry || summary.basicInfo.vendorCountry, + vendorName: (contractData as any)?.vendorName || summary.basicInfo.vendorName, + vendorCode: (contractData as any)?.vendorCode || summary.basicInfo.vendorCode, } } } catch { diff --git a/lib/general-contracts/utils.ts b/lib/general-contracts/utils.ts index 5bbb5980..1262dc4d 100644 --- a/lib/general-contracts/utils.ts +++ b/lib/general-contracts/utils.ts @@ -170,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') + : '' + // ═══════════════════════════════════════════════════════════════ // 변수 매핑 시작 @@ -296,7 +341,13 @@ export function mapContractDataToTemplateVariables(contractSummary: ContractSumm // ---------------------------------- storageTableText: storageTableText, // {{storageTableText}} (fallback) // PDFTron에서 배열을 받아 테이블 루프를 돌릴 수 있다면 아래 키를 사용 - storageList: storageItems, + storageList, + + // ---------------------------------- + // 일반 견적 품목 루프 (템플릿 표에 {{#itemsList}} 사용) + // ---------------------------------- + itemsList, + itemsTableText, } // 3. 모든 키를 순회하며 undefined나 null을 빈 문자열로 변환 (안전장치) @@ -306,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 } |
