| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- /* eslint-disable @typescript-eslint/no-explicit-any */
- import { PrismaClient } from '@prisma/client';
- import * as path from 'path';
- import * as fs from 'fs';
- import { ExcelReaderService } from './excel-reader';
- import { BulkInserter } from './bulk-inserter';
- import { ImportProgressServer } from './websocket-server';
- import { ImportProgress, ImportResult } from './types';
- import { FileDownloader } from './file-downloader';
- export class CintasImportProcessor {
- private prisma: PrismaClient;
- private reader: ExcelReaderService;
- private inserter: BulkInserter;
- private progressServer: ImportProgressServer;
- private fileDownloader: FileDownloader;
- constructor() {
- this.prisma = new PrismaClient();
- this.reader = new ExcelReaderService();
- this.inserter = new BulkInserter();
- this.progressServer = ImportProgressServer.getInstance();
- this.fileDownloader = new FileDownloader();
- }
- async processCintasImport(importId: number): Promise<ImportResult> {
- let filePath: string | null = null;
-
- try {
- console.log(`[${new Date().toISOString()}] [CintasImport] Starting import processing for ID: ${importId}`);
-
- // Initialize the progress server if not already done
- if (!this.progressServer.isServerInitialized()) {
- this.progressServer.initialize();
- }
- // Get import record with layout configuration
- const importRecord = await this.prisma.import.findUnique({
- where: { id: importId },
- include: {
- layout: {
- include: {
- sections: {
- include: { fields: true }
- }
- }
- }
- }
- });
- // Get the file separately
- const file = importRecord?.fileId ? await this.prisma.file.findUnique({
- where: { id: importRecord.fileId }
- }) : null;
- if (!importRecord || !file) {
- console.error(`[${new Date().toISOString()}] [CintasImport] ERROR: Import not found or no file attached`);
- throw new Error('Import not found or no file attached');
- }
- console.log(`[${new Date().toISOString()}] [CintasImport] Loaded import record: ${importRecord.id}`);
- // Initialize progress tracking
- const progress: ImportProgress = {
- importId,
- status: 'processing',
- currentSection: '',
- currentRow: 0,
- totalRows: 0,
- errors: [],
- processedSections: 0,
- totalSections: importRecord.layout?.sections?.length || 0
- };
- // Save file to temporary location
- const filename = `import_${importId}_${Date.now()}.xlsx`;
- filePath = path.join(this.fileDownloader.getTempDir(), filename);
-
- let fileBuffer: Buffer;
- if (Buffer.isBuffer(file.data)) {
- fileBuffer = file.data;
- } else if (file.data instanceof Uint8Array) {
- fileBuffer = Buffer.from(file.data);
- } else {
- fileBuffer = Buffer.from(file.data as any);
- }
-
- fs.writeFileSync(filePath, fileBuffer);
- console.log(`[${new Date().toISOString()}] [CintasImport] File saved to: ${filePath}`);
- // Read Excel file
- console.log(`[${new Date().toISOString()}] [CintasImport] Starting Excel file reading...`);
-
- const sections = await this.reader.readExcelFile(
- filePath,
- importRecord.layout,
- (sectionProgress) => {
- this.progressServer.broadcastProgress(importId, sectionProgress);
- }
- );
- console.log(`[${new Date().toISOString()}] [CintasImport] Excel file read successfully. Found ${sections.length} sections`);
- // Process each section
- const processedSections = [];
- let totalInserted = 0;
- for (let i = 0; i < sections.length; i++) {
- const section = sections[i];
-
- console.log(`[${new Date().toISOString()}] [CintasImport] Processing section ${i+1}/${sections.length}: ${section.name}`);
- progress.currentSection = section.name;
- progress.processedSections = i + 1;
- this.progressServer.broadcastProgress(importId, progress);
- try {
- // Ensure table exists for this section
- console.log(`[${new Date().toISOString()}] [CintasImport] Creating table ${section.tableName} for section ${section.name}`);
- await this.inserter.createImportTable(section.tableName, section.fields);
-
- const insertedRows = await this.inserter.insertSectionData(
- section,
- importId,
- (rows) => {
- progress.currentRow = rows;
- this.progressServer.broadcastProgress(importId, progress);
- }
- );
- processedSections.push({
- sectionData: section,
- insertedRows
- });
- totalInserted += insertedRows;
- console.log(`[${new Date().toISOString()}] [CintasImport] Completed section ${section.name}: ${insertedRows} rows inserted`);
- } catch (error) {
- const errorMessage = `Error processing section ${section.name}: ${error instanceof Error ? error.message : 'Unknown error'}`;
- progress.errors.push(errorMessage);
- console.error(`[${new Date().toISOString()}] [CintasImport] ERROR: ${errorMessage}`);
- this.progressServer.broadcastProgress(importId, progress);
- }
- }
- // Run the stored procedure to calculate summary
- console.log(`[${new Date().toISOString()}] [CintasImport] Running summary calculation procedure...`);
- try {
- await this.prisma.$executeRawUnsafe(
- `CALL cintas_calculate_summary(${importId})`
- );
- console.log(`[${new Date().toISOString()}] [CintasImport] Summary calculation completed successfully`);
- } catch (error) {
- console.error(`[${new Date().toISOString()}] [CintasImport] ERROR: Summary calculation failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
- progress.errors.push(`Stored procedure error: ${error instanceof Error ? error.message : 'Unknown error'}`);
- }
- progress.status = 'completed';
- this.progressServer.broadcastProgress(importId, progress);
- console.log(`[${new Date().toISOString()}] [CintasImport] Import processing completed successfully. Total inserted: ${totalInserted}`);
- return {
- success: true,
- totalInserted,
- sections: processedSections
- };
- } catch (error) {
- const progress: ImportProgress = {
- importId,
- status: 'failed',
- currentSection: '',
- currentRow: 0,
- totalRows: 0,
- errors: [error instanceof Error ? error.message : 'Unknown error'],
- processedSections: 0,
- totalSections: 0
- };
- this.progressServer.broadcastProgress(importId, progress);
- console.error(`[${new Date().toISOString()}] [CintasImport] ERROR: Import processing failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
- // Clean up temporary file if it exists
- if (filePath && fs.existsSync(filePath)) {
- try {
- fs.unlinkSync(filePath);
- } catch (cleanupError) {
- console.warn(`[${new Date().toISOString()}] [CintasImport] WARNING: Failed to clean up temporary file: ${cleanupError instanceof Error ? cleanupError.message : 'Unknown error'}`);
- }
- }
- return {
- success: false,
- totalInserted: 0,
- sections: [],
- errors: [error instanceof Error ? error.message : 'Unknown error']
- };
- }
- }
- }
|