From 50adedf48ee4674ebe00f1ee72d93485183cdc51 Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Fri, 5 Sep 2025 11:44:32 +0000
Subject: (대표님, 최겸, 임수민) EDP 입력 진행률, 견적목록관리, EDP excel
 import 오류수정, GTC-Contract
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 components/form-data/import-excel-form.tsx | 216 +++++++++++++++--------------
 1 file changed, 115 insertions(+), 101 deletions(-)

(limited to 'components/form-data/import-excel-form.tsx')

diff --git a/components/form-data/import-excel-form.tsx b/components/form-data/import-excel-form.tsx
index 637b0ccf..df6ab6c1 100644
--- a/components/form-data/import-excel-form.tsx
+++ b/components/form-data/import-excel-form.tsx
@@ -2,7 +2,7 @@ import ExcelJS from "exceljs";
 import { saveAs } from "file-saver";
 import { toast } from "sonner";
 import { DataTableColumnJSON } from "./form-data-table-columns";
-import { updateFormDataInDB } from "@/lib/forms/services";
+import { updateFormDataBatchInDB } from "@/lib/forms/services";
 import { decryptWithServerAction } from "../drm/drmUtils";
 
 // Define error structure for import
@@ -37,6 +37,7 @@ export interface ImportExcelResult {
   skippedFields?: { tagNo: string, fields: string[] }[]; // 건너뛴 필드 정보
   errorCount?: number;
   hasErrors?: boolean;
+  notFoundTags?: string[];
 }
 
 export interface ExportExcelOptions {
@@ -529,119 +530,132 @@ export async function importExcelData({
     });
 
     // If formCode and contractItemId are provided, save directly to DB
-    if (formCode && contractItemId) {
-      try {
-        // Process each imported row individually
-        let successCount = 0;
-        let errorCount = 0;
-        const errors = [];
-
-        // Since updateFormDataInDB expects a single row at a time,
-        // we need to process each imported row individually
-        for (const importedRow of importedData) {
-          try {
-            const result = await updateFormDataInDB(
-              formCode,
-              contractItemId,
-              importedRow
-            );
-            
-            if (result.success) {
-              successCount++;
-            } else {
-              errorCount++;
-              errors.push(`Error updating tag ${importedRow.TAG_NO}: ${result.message}`);
-            }
-          } catch (rowError) {
-            errorCount++;
-            errors.push(`Exception updating tag ${importedRow.TAG_NO}: ${rowError instanceof Error ? rowError.message : 'Unknown error'}`);
-          }
-        }
-
-        // If any errors occurred
-        if (errorCount > 0) {
-          console.error("Errors during import:", errors);
-          
-          if (successCount > 0) {
-            toast.warning(`Partially successful: ${successCount} rows updated, ${errorCount} errors`);
-          } else {
-            toast.error(`Failed to update all ${errorCount} rows`);
-          }
-          
-          // If some rows were updated successfully, update the local state
-          if (successCount > 0) {
-            if (onDataUpdate) {
-              onDataUpdate(() => mergedData);
-            }
-            return { 
-              success: true, 
-              importedCount: successCount,
-              message: `Partially successful: ${successCount} rows updated, ${errorCount} errors`,
-              errorCount: errorCount,
-              hasErrors: errorCount > 0,
-              skippedFields: skippedFieldsLog
-            };
-          } else {
-            return { 
-              success: false, 
-              error: "All updates failed", 
-              message: errors.join("\n"),
-              errorCount: errorCount,
-              hasErrors: true,
-              skippedFields: skippedFieldsLog
-            };
-          }
-        }
-        
-        // All rows were updated successfully
+  // importExcelData 함수에서 DB 저장 부분
+if (formCode && contractItemId) {
+  try {
+    // 배치 업데이트 함수 호출
+    const result = await updateFormDataBatchInDB(
+      formCode,
+      contractItemId,
+      importedData // 모든 imported rows를 한번에 전달
+    );
+    
+    if (result.success) {
+      // 로컬 상태 업데이트
+      if (onDataUpdate) {
+        onDataUpdate(() => mergedData);
+      }
+      
+      // 성공 메시지 구성
+      const { updatedCount, notFoundTags } = result.data || {};
+      
+      let message = `Successfully updated ${updatedCount || importedData.length} rows`;
+      
+      // 건너뛴 필드가 있는 경우
+      if (skippedFieldsLog.length > 0) {
+        const totalSkippedFields = skippedFieldsLog.reduce((sum, log) => sum + log.fields.length, 0);
+        message += ` (${totalSkippedFields} read-only fields preserved)`;
+      }
+      
+      // 찾을 수 없는 TAG가 있는 경우
+      if (notFoundTags && notFoundTags.length > 0) {
+        console.warn("Tags not found in database:", notFoundTags);
+        message += `. Warning: ${notFoundTags.length} tags not found in database`;
+      }
+      
+      toast.success(message);
+      
+      return { 
+        success: true, 
+        importedCount: updatedCount || importedData.length,
+        message: message,
+        errorCount: 0,
+        hasErrors: false,
+        skippedFields: skippedFieldsLog,
+        notFoundTags: notFoundTags
+      };
+      
+    } else {
+      // 배치 업데이트 실패
+      console.error("Batch update failed:", result.message);
+      
+      // 부분 성공인 경우
+      if (result.data?.updatedCount > 0) {
+        // 부분적으로라도 업데이트된 경우 로컬 상태 업데이트
         if (onDataUpdate) {
           onDataUpdate(() => mergedData);
         }
         
-        const successMessage = skippedFieldsLog.length > 0 
-          ? `Successfully updated ${successCount} rows (read-only fields were preserved)`
-          : `Successfully updated ${successCount} rows`;
+        toast.warning(
+          `Partially updated: ${result.data.updatedCount} of ${importedData.length} rows updated. ` +
+          `${result.data.failedCount || 0} failed.`
+        );
         
-        toast.success(successMessage);
-        return { 
-          success: true, 
-          importedCount: successCount, 
-          message: "All data imported and saved to database",
-          errorCount: 0,
-          hasErrors: false,
+        return {
+          success: true, // 부분 성공도 success로 처리
+          importedCount: result.data.updatedCount,
+          message: result.message,
+          errorCount: result.data.failedCount || 0,
+          hasErrors: true,
           skippedFields: skippedFieldsLog
         };
-      } catch (saveError) {
-        console.error("Failed to save imported data:", saveError);
-        toast.error("Failed to save imported data to database");
-        return { 
-          success: false, 
-          error: saveError,
-          errorCount: 1,
+        
+      } else {
+        // 완전 실패
+        toast.error(result.message || "Failed to update data to database");
+        
+        return {
+          success: false,
+          error: result.message,
+          errorCount: importedData.length,
           hasErrors: true,
           skippedFields: skippedFieldsLog
         };
       }
-    } else {
-      // Fall back to just updating local state if DB parameters aren't provided
-      if (onDataUpdate) {
-        onDataUpdate(() => mergedData);
-      }
-      
-      const successMessage = skippedFieldsLog.length > 0 
-        ? `Imported ${importedData.length} rows successfully (read-only fields preserved)`
-        : `Imported ${importedData.length} rows successfully`;
-      
-      toast.success(`${successMessage} (local only)`);
-      return { 
-        success: true, 
-        importedCount: importedData.length,
-        errorCount: 0,
-        hasErrors: false,
-        skippedFields: skippedFieldsLog
-      };
     }
     
+  } catch (saveError) {
+    // 예외 발생 처리
+    console.error("Failed to save imported data:", saveError);
+    
+    const errorMessage = saveError instanceof Error 
+      ? saveError.message 
+      : "Unknown error occurred";
+    
+    toast.error(`Database update failed: ${errorMessage}`);
+    
+    return { 
+      success: false, 
+      error: saveError,
+      message: errorMessage,
+      errorCount: importedData.length,
+      hasErrors: true,
+      skippedFields: skippedFieldsLog
+    };
+  }
+  
+} else {
+  // formCode나 contractItemId가 없는 경우 - 로컬 업데이트만
+  if (onDataUpdate) {
+    onDataUpdate(() => mergedData);
+  }
+  
+  const successMessage = skippedFieldsLog.length > 0 
+    ? `Imported ${importedData.length} rows successfully (read-only fields preserved)`
+    : `Imported ${importedData.length} rows successfully`;
+  
+  toast.success(`${successMessage} (local only - no database connection)`);
+  
+  return { 
+    success: true, 
+    importedCount: importedData.length,
+    message: "Data imported locally only",
+    errorCount: 0,
+    hasErrors: false,
+    skippedFields: skippedFieldsLog
+  };
+}
+    
   } catch (err) {
     console.error("Excel import error:", err);
     toast.error("Excel import failed.");
-- 
cgit v1.2.3

