summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-11-05 02:55:31 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-11-05 02:55:31 +0000
commitad6bde0250cfe014d5f78747ec76ac59df95a25d (patch)
tree10cf65130b20a21caef0961215f8f6645a68c76d
parent70aada2ef189467d1bc62dc892c629a71196e755 (diff)
(최겸) 구매 PQ 수정, 기본계약 수정하기 내 drm 추가
-rw-r--r--app/[lng]/admin/ecc/page.tsx32
-rw-r--r--app/[lng]/partners/(partners)/pq_new/[id]/page.tsx (renamed from app/[lng]/partners/pq_new/[id]/page.tsx)0
-rw-r--r--app/[lng]/partners/(partners)/pq_new/page.tsx (renamed from app/[lng]/partners/pq_new/page.tsx)0
-rw-r--r--app/[lng]/partners/(partners)/site-visit/page.tsx (renamed from app/[lng]/partners/site-visit/page.tsx)0
-rw-r--r--components/pq-input/pq-input-tabs.tsx94
-rw-r--r--lib/basic-contract/service.ts14
-rw-r--r--lib/vendor-evaluation-submit/service.ts1
7 files changed, 67 insertions, 74 deletions
diff --git a/app/[lng]/admin/ecc/page.tsx b/app/[lng]/admin/ecc/page.tsx
index cd09e213..a3e4eba4 100644
--- a/app/[lng]/admin/ecc/page.tsx
+++ b/app/[lng]/admin/ecc/page.tsx
@@ -15,7 +15,7 @@ import { toast } from 'sonner'
// SOAP 송신 함수들 import
import { confirmTestPCR, confirmPCR } from '@/lib/soap/ecc/send/pcr-confirm'
-import { cancelTestRFQ, cancelRFQ } from '@/lib/soap/ecc/send/cancel-rfq'
+import { cancelTestRFQ, cancelRFQ } from '@/lib/soap/ecc/send/delete-rfq'
import { sendTestRFQInformation, sendRFQInformation } from '@/lib/soap/ecc/send/rfq-info'
import { createTestPurchaseOrder, createPurchaseOrder } from '@/lib/soap/ecc/send/create-po'
@@ -97,7 +97,7 @@ export default function ECCSenderTestPage() {
CONFIRM_RSN: '테스트 확인'
})
- // RFQ 취소 테스트
+ // RFQ 삭제 테스트
const [rfqCancelData, setRfqCancelData] = useState({
ANFNR: 'TEST_RFQ_001'
})
@@ -232,7 +232,7 @@ export default function ECCSenderTestPage() {
<Tabs defaultValue="pcr-confirm" className="w-full">
<TabsList className="grid w-full grid-cols-4">
<TabsTrigger value="pcr-confirm">PCR 확인</TabsTrigger>
- <TabsTrigger value="rfq-cancel">RFQ 취소</TabsTrigger>
+ <TabsTrigger value="rfq-cancel">RFQ 삭제</TabsTrigger>
<TabsTrigger value="rfq-info">RFQ 정보</TabsTrigger>
<TabsTrigger value="po-create">PO 생성</TabsTrigger>
</TabsList>
@@ -345,7 +345,7 @@ export default function ECCSenderTestPage() {
</Card>
</TabsContent>
- {/* RFQ 취소 탭 */}
+ {/* RFQ 삭제 탭 */}
<TabsContent value="rfq-cancel" className="space-y-6">
<Card>
<CardHeader>
@@ -354,7 +354,7 @@ export default function ECCSenderTestPage() {
RFQ (Request for Quotation) 취소
</CardTitle>
<CardDescription>
- RFQ 취소 요청을 ECC로 전송합니다. (IF_ECC_EVCP_CANCEL_RFQ)
+ RFQ 삭제 요청을 ECC로 전송합니다. (IF_ECC_EVCP_CANCEL_RFQ)
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
@@ -372,34 +372,34 @@ export default function ECCSenderTestPage() {
<div className="flex gap-4">
<Button
- onClick={() => runTest('RFQ 취소 (샘플)', () => cancelTestRFQ())}
- disabled={isLoading['RFQ 취소 (샘플)']}
+ onClick={() => runTest('RFQ 삭제 (샘플)', () => cancelTestRFQ())}
+ disabled={isLoading['RFQ 삭제 (샘플)']}
variant="outline"
>
- {isLoading['RFQ 취소 (샘플)'] && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
+ {isLoading['RFQ 삭제 (샘플)'] && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
<Play className="mr-2 h-4 w-4" />
샘플 데이터로 테스트
</Button>
<Button
- onClick={() => runTest('RFQ 취소 (사용자)', () => cancelRFQ(rfqCancelData.ANFNR))}
- disabled={isLoading['RFQ 취소 (사용자)']}
+ onClick={() => runTest('RFQ 삭제 (사용자)', () => cancelRFQ(rfqCancelData.ANFNR))}
+ disabled={isLoading['RFQ 삭제 (사용자)']}
variant="destructive"
>
- {isLoading['RFQ 취소 (사용자)'] && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
+ {isLoading['RFQ 삭제 (사용자)'] && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
<Send className="mr-2 h-4 w-4" />
사용자 데이터로 취소
</Button>
</div>
{/* 테스트 결과 표시 */}
- {(testResults['RFQ 취소 (샘플)'] || testResults['RFQ 취소 (사용자)']) && (
+ {(testResults['RFQ 삭제 (샘플)'] || testResults['RFQ 삭제 (사용자)']) && (
<div className="space-y-2">
<h4 className="font-semibold">테스트 결과</h4>
- {testResults['RFQ 취소 (샘플)'] && (
- <TestResultCard result={testResults['RFQ 취소 (샘플)']} title="샘플 테스트" />
+ {testResults['RFQ 삭제 (샘플)'] && (
+ <TestResultCard result={testResults['RFQ 삭제 (샘플)']} title="샘플 테스트" />
)}
- {testResults['RFQ 취소 (사용자)'] && (
- <TestResultCard result={testResults['RFQ 취소 (사용자)']} title="사용자 테스트" />
+ {testResults['RFQ 삭제 (사용자)'] && (
+ <TestResultCard result={testResults['RFQ 삭제 (사용자)']} title="사용자 테스트" />
)}
</div>
)}
diff --git a/app/[lng]/partners/pq_new/[id]/page.tsx b/app/[lng]/partners/(partners)/pq_new/[id]/page.tsx
index 5a8313cc..5a8313cc 100644
--- a/app/[lng]/partners/pq_new/[id]/page.tsx
+++ b/app/[lng]/partners/(partners)/pq_new/[id]/page.tsx
diff --git a/app/[lng]/partners/pq_new/page.tsx b/app/[lng]/partners/(partners)/pq_new/page.tsx
index eea5b21d..eea5b21d 100644
--- a/app/[lng]/partners/pq_new/page.tsx
+++ b/app/[lng]/partners/(partners)/pq_new/page.tsx
diff --git a/app/[lng]/partners/site-visit/page.tsx b/app/[lng]/partners/(partners)/site-visit/page.tsx
index 92580b35..92580b35 100644
--- a/app/[lng]/partners/site-visit/page.tsx
+++ b/app/[lng]/partners/(partners)/site-visit/page.tsx
diff --git a/components/pq-input/pq-input-tabs.tsx b/components/pq-input/pq-input-tabs.tsx
index 8d5aa2ab..f0d44d04 100644
--- a/components/pq-input/pq-input-tabs.tsx
+++ b/components/pq-input/pq-input-tabs.tsx
@@ -822,18 +822,11 @@ export function PQInputTabs({
if (!shouldShowItem(isSaved)) return null
return (
- <Collapsible key={criteriaId} defaultOpen={isReadOnly || !isSaved} className="w-full">
<Card className={`${isSaved ? "border-green-200" : ""} h-fit min-h-[400px]`}>
<CardHeader className="pb-1">
<div className="flex justify-between">
<div className="flex-1">
<div className="flex items-center gap-2">
- <CollapsibleTrigger asChild>
- <Button variant="ghost" size="sm" className="p-0 h-7 w-7">
- <ChevronsUpDown className="h-4 w-4" />
- <span className="sr-only">Toggle</span>
- </Button>
- </CollapsibleTrigger>
<CardTitle className="text-md">
{code} - {checkPoint}
</CardTitle>
@@ -882,7 +875,6 @@ export function PQInputTabs({
</div>
</CardHeader>
- <CollapsibleContent>
<CardContent className="pt-3 space-y-3 h-full flex flex-col">
{/* 프로젝트별 추가 필드 (contractInfo, additionalRequirement) */}
{projectId && contractInfo && (
@@ -1298,9 +1290,7 @@ export function PQInputTabs({
/>
</CardContent>
- </CollapsibleContent>
</Card>
- </Collapsible>
)
})}
</div>
@@ -1323,51 +1313,45 @@ export function PQInputTabs({
</DialogHeader>
<div className="space-y-4 max-h-[600px] overflow-y-auto ">
- {data.map((group) => (
- <Collapsible key={group.groupName} defaultOpen>
- <CollapsibleTrigger asChild>
- <div className="flex justify-between items-center p-2 mb-1 cursor-pointer ">
- <p className="font-semibold">{group.groupName}</p>
- <ChevronsUpDown className="h-4 w-4 ml-2" />
- </div>
- </CollapsibleTrigger>
-
- <CollapsibleContent>
- {group.items.map((item) => {
- const answerObj = form
- .getValues()
- .answers.find((a) => a.criteriaId === item.criteriaId)
-
- if (!answerObj) return null
-
- return (
- <div key={item.criteriaId} className="mb-2 p-2 ml-2 border rounded-md text-sm">
- {/* code & checkPoint */}
- <p className="font-semibold">
- {item.code} - {item.checkPoint}
- </p>
-
- {/* user's typed answer */}
- <p className="text-sm font-medium mt-2">Answer:</p>
- <p className="whitespace-pre-wrap text-sm">
- {answerObj.answer || "(no answer)"}
- </p>
- {/* attachments */}
- <p>Attachments:</p>
- {answerObj.uploadedFiles.length > 0 ? (
- <ul className="list-disc list-inside ml-4 text-xs">
- {answerObj.uploadedFiles.map((file, idx) => (
- <li key={idx}>{file.fileName}</li>
- ))}
- </ul>
- ) : (
- <p className="text-xs text-muted-foreground">(none)</p>
- )}
- </div>
- )
- })}
- </CollapsibleContent>
- </Collapsible>
+ {data.map((group, groupIndex) => (
+ <div key={groupIndex}>
+ {group.items.map((item) => {
+ const answerObj = form
+ .getValues()
+ .answers.find((a) => a.criteriaId === item.criteriaId);
+
+ if (!answerObj) return null;
+
+ return (
+ <div
+ key={item.criteriaId}
+ className="mb-2 p-2 ml-2 border rounded-md text-sm"
+ >
+ {/* code & checkPoint */}
+ <p className="font-semibold">
+ {item.code} - {item.checkPoint}
+ </p>
+
+ {/* user's typed answer */}
+ <p className="text-sm font-medium mt-2">Answer:</p>
+ <p className="whitespace-pre-wrap text-sm">
+ {answerObj.answer || "(no answer)"}
+ </p>
+ {/* attachments */}
+ <p>Attachments:</p>
+ {answerObj.uploadedFiles && answerObj.uploadedFiles.length > 0 ? (
+ <ul className="list-disc list-inside ml-4 text-xs">
+ {answerObj.uploadedFiles.map((file, idx) => (
+ <li key={idx}>{file.fileName}</li>
+ ))}
+ </ul>
+ ) : (
+ <p className="text-xs text-muted-foreground">(none)</p>
+ )}
+ </div>
+ );
+ })}
+ </div>
))}
</div>
diff --git a/lib/basic-contract/service.ts b/lib/basic-contract/service.ts
index 123d2367..8c29dbf2 100644
--- a/lib/basic-contract/service.ts
+++ b/lib/basic-contract/service.ts
@@ -65,7 +65,8 @@ import { sendEmail } from "../mail/sendEmail";
import { headers } from 'next/headers';
import { filterColumns } from "@/lib/filter-columns";
import { differenceInDays, addYears, isBefore } from "date-fns";
-import { deleteFile, saveBuffer, saveFile } from "@/lib/file-stroage";
+import { deleteFile, saveBuffer, saveFile, saveDRMFile } from "@/lib/file-stroage";
+import { decryptWithServerAction } from "@/components/drm/drmUtils";
import { getServerSession } from "next-auth/next"
import { authOptions } from "@/app/api/auth/[...nextauth]/route"
@@ -430,8 +431,15 @@ export async function updateTemplate({
let filePath: string | undefined = undefined;
if (file) {
- // 1) 새 파일 저장
- const saveResult = await saveFile({ file, directory: "basicContract/template" });
+ // 1) 새 파일 저장 (DRM 해제 로직 적용)
+
+ const saveResult = await saveDRMFile(
+ file,
+ decryptWithServerAction,
+ 'basicContract/template'
+ );
+
+
if (!saveResult.success) {
return { success: false, error: saveResult.error };
}
diff --git a/lib/vendor-evaluation-submit/service.ts b/lib/vendor-evaluation-submit/service.ts
index 3a31b380..c7fe7122 100644
--- a/lib/vendor-evaluation-submit/service.ts
+++ b/lib/vendor-evaluation-submit/service.ts
@@ -451,6 +451,7 @@ export async function updateEvaluationSubmissionStatus(
.set({
documentsSubmitted: true,
submissionDate: new Date(),
+ status: 'SUBMITTED',
updatedAt: new Date(),
})
.where(eq(periodicEvaluations.id, updatedSubmission.periodicEvaluationId));