Prechádzať zdrojové kódy

Added debug messages for importing.

vtugulan 2 dní pred
rodič
commit
afaa7a6dca

+ 20 - 3
app/actions/imports.ts

@@ -415,7 +415,6 @@ export async function getImportProgress(importId: number) {
     const totalRecords = cintasCount + gowDataCount + gowFacCount + gowCorpCount;
     // Since we don't have status fields, we'll use record count as proxy
     const hasRecords = totalRecords > 0;
-
     return {
       success: true,
       data: {
@@ -440,19 +439,26 @@ export async function getImportProgress(importId: number) {
 export async function triggerImportProcess(importId: number) {
   try {
     if (!importId || isNaN(importId)) {
+      console.error('[TRIGGER_IMPORT] ❌ Invalid import ID:', importId);
       return { success: false, error: 'Invalid import ID' };
     }
 
+    console.log('[TRIGGER_IMPORT] 📥 Starting triggerImportProcess for ID:', importId);
+
     // Validate import exists
     const importRecord = await prisma.import.findUnique({
       where: { id: importId }
     });
 
+    console.log('[TRIGGER_IMPORT] 📄 Import record found:', { id: importRecord?.id, hasFileId: !!importRecord?.fileId, layoutId: importRecord?.layoutId });
+
     if (!importRecord) {
+      console.error('[TRIGGER_IMPORT] ❌ Import not found for ID:', importId);
       return { success: false, error: 'Import not found' };
     }
 
     if (!importRecord.fileId) {
+      console.error('[TRIGGER_IMPORT] ❌ No file attached to import:', importId);
       return { success: false, error: 'No file attached to import' };
     }
 
@@ -461,7 +467,10 @@ export async function triggerImportProcess(importId: number) {
       where: { id: importRecord.layoutId }
     });
 
+    console.log('[TRIGGER_IMPORT] 📋 Layout found:', { id: layout?.id, name: layout?.name });
+
     if (!layout) {
+      console.error('[TRIGGER_IMPORT] ❌ No layout configuration found for ID:', importRecord.layoutId);
       return { success: false, error: 'No layout configuration found' };
     }
 
@@ -470,7 +479,10 @@ export async function triggerImportProcess(importId: number) {
       where: { importId }
     });
 
+    console.log('[TRIGGER_IMPORT] 📊 Existing records count:', existingRecords);
+
     if (existingRecords > 0) {
+      console.log('[TRIGGER_IMPORT] ✅ Import already processed, returning early');
       return {
         success: true,
         message: 'Import already processed',
@@ -480,10 +492,14 @@ export async function triggerImportProcess(importId: number) {
     }
 
     // Use the ImportProcessor to actually process the import
+    console.log('[TRIGGER_IMPORT] 🔄 Starting ImportProcessor for import ID:', importId);
     const processor = new ImportProcessor();
     const result = await processor.processImport(importId);
 
+    console.log('[TRIGGER_IMPORT] 📈 ImportProcessor result:', { success: result.success, totalInserted: result.totalInserted, sectionsCount: result.sections?.length, errors: result.errors });
+
     if (result.success) {
+      console.log('[TRIGGER_IMPORT] ✅ Import completed successfully');
       revalidatePath('/imports');
       return {
         success: true,
@@ -492,6 +508,7 @@ export async function triggerImportProcess(importId: number) {
         totalInserted: result.totalInserted
       };
     } else {
+      console.error('[TRIGGER_IMPORT] ❌ Import processing failed:', result.errors);
       return {
         success: false,
         error: 'Import processing failed',
@@ -500,7 +517,7 @@ export async function triggerImportProcess(importId: number) {
     }
 
   } catch (error) {
-    console.error('Error triggering import:', error);
+    console.error('[TRIGGER_IMPORT] ❌ Error triggering import:', error);
     return { success: false, error: 'Failed to trigger import' };
   }
 }
@@ -707,4 +724,4 @@ export async function getTerraTechFacilitySummary(importId: number) {
     console.error('Error fetching TerraTech facility summary:', error);
     return { success: false, error: 'Failed to fetch facility summary' };
   }
-}
+}

+ 33 - 11
app/components/imports/ImportDetailDialog.tsx

@@ -104,51 +104,66 @@ export function ImportDetailDialog({ open, onOpenChange, importId }: ImportDetai
 
     setProcessing(true);
     setImportStatus('processing');
+    setProgress(0);
+    setProcessedRecords(0);
+    setTotalRecords(0);
 
     try {
+      console.log('[IMPORT_DIALOG] 🚀 Starting import for ID:', importId);
       const result = await triggerImportProcess(importId);
 
+      console.log('[IMPORT_DIALOG] 📊 triggerImportProcess result:', result);
+
       if (result.success) {
         toast({
           title: 'Success',
           description: result.message || 'Import process started successfully',
         });
 
+        console.log('[IMPORT_DIALOG] 🔄 Starting poll for import progress...');
+
         // Poll for import progress until completion
         const pollInterval = setInterval(async () => {
           try {
             const progressResult = await getImportProgress(importId);
 
+            console.log('[IMPORT_DIALOG] 📈 Progress result:', progressResult);
+
             if (progressResult.success && progressResult.data) {
-              const { status, progress, processedRecords, totalRecords } = progressResult.data;
+              const { status, progress: prog, processedRecords: procRecs, totalRecords: totRecs, errorMessage } = progressResult.data;
 
               // Update progress display
-              setProgress(progress);
-              setProcessedRecords(processedRecords);
-              setTotalRecords(totalRecords);
+              setProgress(prog);
+              setProcessedRecords(procRecs);
+              setTotalRecords(totRecs);
+              setImportStatus(status as 'idle' | 'processing' | 'completed' | 'failed');
 
               if (status === 'completed') {
+                console.log('[IMPORT_DIALOG] ✅ Import completed!');
                 clearInterval(pollInterval);
                 setProcessing(false);
                 setImportStatus('completed');
                 toast({
                   title: 'Import Complete',
-                  description: `Successfully imported ${totalRecords} records`,
+                  description: `Successfully imported ${totRecs} records`,
                 });
                 loadImportDetail();
               } else if (status === 'failed') {
+                console.error('[IMPORT_DIALOG] ❌ Import failed:', errorMessage);
                 clearInterval(pollInterval);
                 setProcessing(false);
                 setImportStatus('failed');
                 toast({
                   title: 'Import Failed',
-                  description: progressResult.data.errorMessage || 'Import processing failed',
+                  description: errorMessage || 'Import processing failed',
                   variant: 'destructive',
                 });
+              } else {
+                console.log('[IMPORT_DIALOG] ⏳ Import status:', status, { procRecs, totRecs });
               }
             }
           } catch (error) {
-            console.error('Error polling import progress:', error);
+            console.error('[IMPORT_DIALOG] ❌ Error polling import progress:', error);
             clearInterval(pollInterval);
             setProcessing(false);
             setImportStatus('failed');
@@ -156,6 +171,7 @@ export function ImportDetailDialog({ open, onOpenChange, importId }: ImportDetai
         }, 1000); // Poll every second
 
       } else {
+        console.error('[IMPORT_DIALOG] ❌ triggerImportProcess failed:', result.error);
         toast({
           title: 'Error',
           description: result.error || 'Failed to start import process',
@@ -165,6 +181,7 @@ export function ImportDetailDialog({ open, onOpenChange, importId }: ImportDetai
         setImportStatus('failed');
       }
     } catch {
+      console.error('[IMPORT_DIALOG] ❌ Exception in handleTriggerImport');
       toast({
         title: 'Error',
         description: 'Failed to trigger import process',
@@ -276,9 +293,14 @@ export function ImportDetailDialog({ open, onOpenChange, importId }: ImportDetai
             </CardHeader>
             <CardContent>
               {importStatus === 'processing' && (
-                <div className="flex items-center gap-2 text-sm text-blue-600">
-                  <div className="animate-spin rounded-full h-4 w-4 border-b-2 border-blue-600"></div>
-                  Import is currently processing...
+                <div className="space-y-2">
+                  <div className="flex items-center gap-2 text-sm text-blue-600">
+                    <div className="animate-spin rounded-full h-4 w-4 border-b-2 border-blue-600"></div>
+                    Import is currently processing...
+                  </div>
+                  <div className="text-xs text-muted-foreground">
+                    Progress: {processedRecords} / {totalRecords} records ({progress}%)
+                  </div>
                 </div>
               )}
               {importStatus === 'completed' && (
@@ -307,4 +329,4 @@ export function ImportDetailDialog({ open, onOpenChange, importId }: ImportDetai
       </DialogContent>
     </Dialog>
   );
-}
+}

+ 22 - 2
app/lib/excel-import/bulk-inserter.ts

@@ -13,6 +13,9 @@ export class BulkInserter {
     importId: number,
     onProgress: (rows: number) => void
   ): Promise<number> {
+    console.log('[BULK_INSERTER] 🔷 Starting insertSectionData');
+    console.log('[BULK_INSERTER] 📊 Section:', { name: sectionData.name, tableName: sectionData.tableName, importId, dataRows: sectionData.data?.length });
+
     const batchSize = 5000;
     const totalRows = sectionData.data.length;
     let insertedRows = 0;
@@ -21,6 +24,8 @@ export class BulkInserter {
       // Handle specific table names with Prisma models
       const tableName = sectionData.tableName;
 
+      console.log('[BULK_INSERTER] 📋 Table mapping:', tableName);
+
       for (let i = 0; i < totalRows; i += batchSize) {
         const batch = sectionData.data.slice(i, i + batchSize);
 
@@ -42,47 +47,62 @@ export class BulkInserter {
           return mappedRow;
         });
 
+        console.log('[BULK_INSERTER] 📤 Batch prepared:', { batchSize: values.length, sampleKeys: Object.keys(values[0] || {}) });
+
         // Use appropriate Prisma model based on table name
         if (tableName === 'cintas_install_calendar') {
+          console.log('[BULK_INSERTER] 📥 Inserting into cintasInstallCalendar...');
           await this.prisma.cintasInstallCalendar.createMany({
             data: values,
             skipDuplicates: false
           });
+          console.log('[BULK_INSERTER] ✅ Inserted into cintasInstallCalendar');
         } else if (tableName === 'cintas_install_calendar_summary') {
+          console.log('[BULK_INSERTER] 📥 Inserting into cintasSummary...');
           await this.prisma.cintasSummary.createMany({
             data: values,
             skipDuplicates: false
           });
+          console.log('[BULK_INSERTER] ✅ Inserted into cintasSummary');
         } else if (tableName === 'gow_data') {
+          console.log('[BULK_INSERTER] 📥 Inserting into gowData...');
           await this.prisma.gowData.createMany({
             data: values,
             skipDuplicates: false
           });
+          console.log('[BULK_INSERTER] ✅ Inserted into gowData');
         } else if (tableName === 'gow_fac_id') {
+          console.log('[BULK_INSERTER] 📥 Inserting into gowFacId...');
           await this.prisma.gowFacId.createMany({
             data: values,
             skipDuplicates: false
           });
+          console.log('[BULK_INSERTER] ✅ Inserted into gowFacId');
         } else if (tableName === 'gow_corp_ref') {
+          console.log('[BULK_INSERTER] 📥 Inserting into gowCorpRef...');
           await this.prisma.gowCorpRef.createMany({
             data: values,
             skipDuplicates: false
           });
+          console.log('[BULK_INSERTER] ✅ Inserted into gowCorpRef');
         } else {
+          console.log('[BULK_INSERTER] 📥 Using raw SQL insert for table:', tableName);
           // Fallback to raw SQL for other tables
           await this.prisma.$executeRawUnsafe(
             this.buildInsertQuery(tableName, values)
           );
+          console.log('[BULK_INSERTER] ✅ Raw SQL insert complete');
         }
 
         insertedRows += batch.length;
         onProgress(insertedRows);
       }
 
+      console.log('[BULK_INSERTER] ✅ Section insert complete:', { totalInserted: insertedRows });
       return insertedRows;
 
     } catch (error) {
-      console.error('Error inserting section data:', error);
+      console.error('[BULK_INSERTER] ❌ Error inserting section data:', error);
       throw error;
     }
   }
@@ -109,4 +129,4 @@ export class BulkInserter {
 
     return `INSERT INTO "${tableName}" (${columns}) VALUES ${placeholders}`;
   }
-}
+}

+ 30 - 2
app/lib/excel-import/excel-reader.ts

@@ -7,10 +7,16 @@ export class ExcelReaderService {
     layoutConfig: any,
     onProgress: (progress: ImportProgress) => void
   ): Promise<ReadSectionData[]> {
+    console.log('[EXCEL_READER] 📖 Starting readExcelFile');
+    console.log('[EXCEL_READER] 📊 File data type:', typeof fileData, fileData instanceof Buffer, fileData instanceof Uint8Array);
+    console.log('[EXCEL_READER] 📊 Layout config sections:', layoutConfig?.sections?.length);
 
     try {
+      console.log('[EXCEL_READER] 🔄 Parsing workbook...');
       const workbook = XLSX.read(fileData, { type: 'buffer' });
 
+      console.log('[EXCEL_READER] 📋 Workbook sheet names:', workbook.SheetNames);
+
       const results: ReadSectionData[] = [];
       const totalSections = layoutConfig.sections?.length || 0;
 
@@ -29,9 +35,17 @@ export class ExcelReaderService {
       for (let sectionIndex = 0; sectionIndex < totalSections; sectionIndex++) {
         const section = layoutConfig.sections[sectionIndex];
 
+        console.log(`[EXCEL_READER] 📄 Processing section ${sectionIndex + 1}/${totalSections}:`, {
+          name: section.name,
+          sheetName: section.sheetName,
+          tableName: section.tableName,
+          fieldsCount: section.fields?.length
+        });
+
         const worksheet = workbook.Sheets[section.sheetName];
 
         if (!worksheet) {
+          console.error(`[EXCEL_READER] ❌ Worksheet '${section.sheetName}' not found! Available sheets:`, workbook.SheetNames);
           const error = `Worksheet '${section.sheetName}' not found`;
 
           onProgress({
@@ -47,12 +61,16 @@ export class ExcelReaderService {
           continue;
         }
 
+        console.log(`[EXCEL_READER] ✅ Found worksheet '${section.sheetName}'`);
         const sectionData = await this.processSection(worksheet, section, sectionIndex, totalSections, onProgress);
+        console.log(`[EXCEL_READER] ✅ Section '${section.name}' processed:`, { dataRows: sectionData.data?.length });
         results.push(sectionData);
       }
 
+      console.log('[EXCEL_READER] ✅ All sections processed. Total rows across all sections:', results.reduce((sum, s) => sum + (s.data?.length || 0), 0));
       return results;
     } catch (error) {
+      console.error('[EXCEL_READER] ❌ Error reading Excel file:', error);
       throw error;
     }
   }
@@ -70,10 +88,14 @@ export class ExcelReaderService {
     // Convert worksheet to JSON array
     const worksheetData = XLSX.utils.sheet_to_json(worksheet, { header: 1 }) as any[][];
 
+    console.log(`[EXCEL_READER]   Worksheet data shape:`, { rows: worksheetData.length, cols: worksheetData[0]?.length });
+
     // Process data rows
     const data: Record<string, any>[] = [];
     const totalRows = Math.min(endingRow, worksheetData.length) - startingRow + 1;
 
+    console.log(`[EXCEL_READER]   Processing rows ${startingRow} to ${Math.min(endingRow, worksheetData.length)} (${totalRows} total rows)`);
+
     for (let rowNum = startingRow; rowNum <= Math.min(endingRow, worksheetData.length); rowNum++) {
       const row = worksheetData[rowNum - 1]; // Convert to 0-based index
 
@@ -102,7 +124,7 @@ export class ExcelReaderService {
             rowData[columnName] = value;
           }
         } catch (error) {
-          console.log(`Error processing field ${field.name} at row ${rowNum}`, {
+          console.log(`[EXCEL_READER]   Error processing field ${field.name} at row ${rowNum}`, {
             error: error instanceof Error ? error.message : String(error),
             field,
             rowNum
@@ -130,6 +152,12 @@ export class ExcelReaderService {
       }
     }
 
+    console.log(`[EXCEL_READER]   Final section data:`, {
+      name: section.name,
+      totalRows: data.length,
+      fieldsMapped: Object.keys(data[0] || {}).length
+    });
+
     const result = {
       id: section.id || 0,
       name: section.name || '',
@@ -266,4 +294,4 @@ export class ExcelReaderService {
 
     return convertedValue;
   }
-}
+}

+ 51 - 1
app/lib/excel-import/import-processor.ts

@@ -18,6 +18,8 @@ export class ImportProcessor {
   }
 
   async processImport(importId: number): Promise<ImportResult> {
+    console.log('[IMPORT_PROCESSOR] 🔷 Starting processImport for importId:', importId);
+
     try {
       // Get import record with layout configuration
       const importRecord = await this.prisma.import.findUnique({
@@ -33,11 +35,21 @@ export class ImportProcessor {
         }
       });
 
+      console.log('[IMPORT_PROCESSOR] 📄 Import record:', {
+        id: importRecord?.id,
+        name: importRecord?.name,
+        hasFileId: !!importRecord?.fileId,
+        layoutName: importRecord?.layout?.name,
+        sectionsCount: importRecord?.layout?.sections?.length
+      });
+
       if (!importRecord) {
+        console.error('[IMPORT_PROCESSOR] ❌ Import not found');
         throw new Error('Import not found');
       }
 
       if (!importRecord.fileId) {
+        console.error('[IMPORT_PROCESSOR] ❌ No file attached to import');
         throw new Error('No file attached to import');
       }
 
@@ -46,7 +58,15 @@ export class ImportProcessor {
         where: { id: importRecord.fileId }
       });
 
+      console.log('[IMPORT_PROCESSOR] 📁 File record:', {
+        id: fileRecord?.id,
+        filename: fileRecord?.filename,
+        size: fileRecord?.size,
+        mimetype: fileRecord?.mimetype
+      });
+
       if (!fileRecord) {
+        console.error('[IMPORT_PROCESSOR] ❌ File not found');
         throw new Error('File not found');
       }
 
@@ -62,7 +82,10 @@ export class ImportProcessor {
         totalSections: importRecord.layout?.sections?.length ?? 0
       };
 
+      console.log('[IMPORT_PROCESSOR] 📊 Initial progress:', { totalSections: progress.totalSections });
+
       // Read Excel file
+      console.log('[IMPORT_PROCESSOR] 📖 Starting to read Excel file...');
       const sections = await this.reader.readExcelFile(
         fileRecord.data,
         importRecord.layout,
@@ -71,10 +94,21 @@ export class ImportProcessor {
         }
       );
 
+      console.log('[IMPORT_PROCESSOR] 📖 Excel read complete. Sections parsed:', sections.length);
+      sections.forEach((section, idx) => {
+        console.log(`[IMPORT_PROCESSOR]   Section ${idx + 1}:`, {
+          name: section.name,
+          tableName: section.tableName,
+          dataRows: section.data?.length
+        });
+      });
+
       // Process each section
       const processedSections: ProcessedSection[] = [];
       let totalInserted = 0;
 
+      console.log('[IMPORT_PROCESSOR] 🔄 Starting to process', sections.length, 'sections...');
+
       for (let i = 0; i < sections.length; i++) {
         const section = sections[i];
 
@@ -83,6 +117,12 @@ export class ImportProcessor {
           progress.processedSections = i + 1;
           this.progressServer.broadcastProgress(importId, progress);
 
+          console.log(`[IMPORT_PROCESSOR] 📥 Processing section ${i + 1}/${sections.length}:`, {
+            name: section.name,
+            tableName: section.tableName,
+            dataRows: section.data?.length
+          });
+
           try {
             const insertedRows = await this.inserter.insertSectionData(
               section,
@@ -93,6 +133,8 @@ export class ImportProcessor {
               }
             );
 
+            console.log(`[IMPORT_PROCESSOR] ✅ Section ${section.name} inserted ${insertedRows} rows`);
+
             processedSections.push({
               sectionData: section,
               insertedRows
@@ -102,6 +144,7 @@ export class ImportProcessor {
 
           } catch (error: unknown) {
             const errorMessage = `Error processing section ${section.name ?? 'unknown'}: ${error instanceof Error ? error.message : 'Unknown error'}`;
+            console.error('[IMPORT_PROCESSOR] ❌', errorMessage);
             progress.errors.push(errorMessage);
             this.progressServer.broadcastProgress(importId, progress);
           }
@@ -112,6 +155,12 @@ export class ImportProcessor {
       progress.status = 'completed';
       this.progressServer.broadcastProgress(importId, progress);
 
+      console.log('[IMPORT_PROCESSOR] ✅ Import processing completed:', {
+        totalInserted,
+        sectionsProcessed: processedSections.length,
+        errors: progress.errors.length
+      });
+
       return {
         success: true,
         totalInserted,
@@ -130,6 +179,7 @@ export class ImportProcessor {
         totalSections: 0
       };
 
+      console.error('[IMPORT_PROCESSOR] ❌ Import processing failed:', error);
       this.progressServer.broadcastProgress(importId, progress);
 
       return {
@@ -171,4 +221,4 @@ export class ImportProcessor {
       return { valid: false, errors };
     }
   }
-}
+}