From 598a40808b45413b373334092c3b60cab97d09b6 Mon Sep 17 00:00:00 2001
From: joonhoekim <26rote@gmail.com>
Date: Tue, 14 Oct 2025 15:13:25 +0900
Subject: (김준회) 벤더풀 유니크 처리 및 import 개선
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../table/vendor-pool-excel-import-button.tsx      | 39 ++++++++++++++++------
 1 file changed, 29 insertions(+), 10 deletions(-)

(limited to 'lib/vendor-pool/table/vendor-pool-excel-import-button.tsx')

diff --git a/lib/vendor-pool/table/vendor-pool-excel-import-button.tsx b/lib/vendor-pool/table/vendor-pool-excel-import-button.tsx
index 0f51170f..e07987b3 100644
--- a/lib/vendor-pool/table/vendor-pool-excel-import-button.tsx
+++ b/lib/vendor-pool/table/vendor-pool-excel-import-button.tsx
@@ -133,17 +133,18 @@ export function ImportVendorPoolButton({ onSuccess }: ImportExcelProps) {
       // Process each row
       let successCount = 0;
       let errorCount = 0;
+      let duplicateErrors: string[] = [];
 
       // Create promises for all vendor pool creation operations
       const promises = rows.map(async (row) => {
+        // Excel 컬럼 설정을 기반으로 데이터 매핑 (catch 블록에서도 사용하기 위해 밖에서 선언)
+        const vendorPoolData: any = {};
+
         try {
-          // Excel 컬럼 설정을 기반으로 데이터 매핑
-          const vendorPoolData: any = {};
-          
           vendorPoolExcelColumns.forEach(column => {
             const { accessorKey, type } = column;
             const value = row[accessorKey] || '';
-            
+
             if (type === 'boolean') {
               vendorPoolData[accessorKey] = parseBoolean(String(value));
             } else if (value === '') {
@@ -169,23 +170,23 @@ export function ImportVendorPoolButton({ onSuccess }: ImportExcelProps) {
 
           // Validate field lengths and formats
           const validationErrors: string[] = [];
-          
+
           if (vendorPoolData.designCategoryCode && vendorPoolData.designCategoryCode.length > 2) {
             validationErrors.push(`설계기능코드는 2자리 이하여야 합니다: ${vendorPoolData.designCategoryCode}`);
           }
-          
+
           if (vendorPoolData.equipBulkDivision && vendorPoolData.equipBulkDivision.length > 1) {
             validationErrors.push(`Equip/Bulk 구분은 1자리여야 합니다: ${vendorPoolData.equipBulkDivision}`);
           }
-          
+
           if (vendorPoolData.constructionSector && !['조선', '해양'].includes(vendorPoolData.constructionSector)) {
             validationErrors.push(`공사부문은 '조선' 또는 '해양'이어야 합니다: ${vendorPoolData.constructionSector}`);
           }
-          
+
           if (vendorPoolData.htDivision && !['H', 'T', '공통'].includes(vendorPoolData.htDivision)) {
             validationErrors.push(`H/T구분은 'H', 'T' 또는 '공통'이어야 합니다: ${vendorPoolData.htDivision}`);
           }
-          
+
           if (validationErrors.length > 0) {
             console.error("Validation errors:", validationErrors, vendorPoolData);
             errorCount++;
@@ -210,6 +211,16 @@ export function ImportVendorPoolButton({ onSuccess }: ImportExcelProps) {
           return result;
         } catch (error) {
           console.error("Error processing row:", error, row);
+
+          // Unique 제약 조건 위반 감지 (중복 데이터)
+          const errorMessage = error instanceof Error ? error.message : String(error);
+          if (errorMessage === 'DUPLICATE_VENDOR_POOL') {
+            duplicateErrors.push(`공사부문(${vendorPoolData.constructionSector}), H/T(${vendorPoolData.htDivision}), 자재그룹코드(${vendorPoolData.materialGroupCode}), 협력업체명(${vendorPoolData.vendorName})`);
+            // 중복인 경우 에러 카운트를 증가시키지 않고 건너뜀 (전체 import 중단하지 않음)
+            return null;
+          }
+
+          // 다른 에러의 경우 에러 카운트 증가
           errorCount++;
           return null;
         }
@@ -221,8 +232,9 @@ export function ImportVendorPoolButton({ onSuccess }: ImportExcelProps) {
       // Show results
       if (successCount > 0) {
         toast.success(`${successCount}개 항목이 성공적으로 가져와졌습니다.`);
+
         if (errorCount > 0) {
-          toast.warning(`${errorCount}개 항목 가져오기에 실패했습니다. 콘솔에서 자세한 오류를 확인하세요.`);
+          toast.warning(`${errorCount}개 항목 가져오기에 실패했습니다.`);
         }
         // Call the success callback to refresh data
         onSuccess?.();
@@ -230,6 +242,13 @@ export function ImportVendorPoolButton({ onSuccess }: ImportExcelProps) {
         toast.error(`모든 ${errorCount}개 항목 가져오기에 실패했습니다. 데이터 형식을 확인하세요.`);
       }
 
+      // 중복 데이터가 있었던 경우 개별적으로 표시 (성공/실패와 별개로 처리)
+      if (duplicateErrors.length > 0) {
+        duplicateErrors.forEach(errorMsg => {
+          toast.warning(`중복 데이터로 건너뜀: ${errorMsg}`);
+        });
+      }
+
     } catch (error) {
       console.error("Import error:", error);
       toast.error("Error importing data. Please check file format.");
-- 
cgit v1.2.3

