/** * Watcher Bridge – Renderer-side logic for folder watcher * Communicates with Electron main process via window.electronAPI * * Flow: * 1. Main process detects new file via chokidar * 2. Main sends file content to renderer via 'watcher-file-detected' * 3. This bridge converts using the EDIBridge converters * 4. Calls back to main to write output file * 5. Calls back to main to move source file to archiv/ */ window.EDIBridge = window.EDIBridge || {}; class OutboundWatcherBridge { constructor() { this.status = 'stopped'; // 'stopped', 'running', 'paused' this.log = []; this.maxLogEntries = 200; this.onStatusChange = null; this.onLogEntry = null; this.config = null; this._setupListeners(); } _setupListeners() { if (!window.electronAPI) return; window.electronAPI.onOutboundFileDetected((data) => { this._processDetectedFile(data); }); window.electronAPI.onOutboundWatcherError((data) => { this._addLog('error', data.filePath || '', data.error || 'Unbekannter Fehler'); }); window.electronAPI.onOutboundWatcherReady((data) => { this._addLog('info', '', `Watcher bereit. Überwache: ${data.inputDir}`); }); } async _processDetectedFile(data) { const { filePath, fileName, content, outputDir } = data; this._addLog('info', fileName, 'Datei erkannt, starte Konvertierung...'); let konvertierungsmodus = 'Unbekannt'; let quellformat = null; let zielformat = null; let convertedContent = null; let pError = null; let outFileName = null; try { // Try to use a global config if this.config is not set (e.g. from app.js) if (!this.config && window.app) { this.config = window.app.config; } const result = this._convertContent(content, fileName); if (result.error) { this._addLog('error', fileName, result.error); pError = result.error; } else { konvertierungsmodus = result.type; quellformat = result.format === 'vda' ? 'EDIFACT DELFOR' : 'VDA 4913'; zielformat = result.targetFormat || (result.format === 'vda' ? 'VDA 4905' : (result.format === 'xml' ? 'IFM DELVRY03' : 'Bosch DESADV')); convertedContent = result.output; // Build output filename const baseName = fileName.replace(/\.[^.]+$/, ''); const outExt = result.format === 'vda' ? '.vda' : (result.format === 'xml' ? '.xml' : '.edi'); outFileName = baseName + '_converted' + outExt; const outPath = outputDir + '\\' + outFileName; // Write converted file const writeResult = await window.electronAPI.writeFile(outPath, result.output); if (writeResult.error) { this._addLog('error', fileName, `Schreibfehler: ${writeResult.error}`); pError = writeResult.error; } else { this._addLog('success', fileName, `Konvertiert → ${outFileName} (${result.type})`); // Move source file to archiv const archiveResult = await window.electronAPI.moveToArchive(filePath); if (archiveResult.error) { this._addLog('error', fileName, `Archiv-Fehler: ${archiveResult.error}`); } else { this._addLog('info', fileName, 'Quelldatei nach archiv/ verschoben.'); } } } } catch (e) { this._addLog('error', fileName, `Fehler: ${e.message}`); pError = e.message; } // Log to database if (window.app && typeof window.app._logConversion === 'function') { await window.app._logConversion({ dateiname: fileName, ausgangsdateiname: outFileName, quellformat: quellformat, zielformat: zielformat, konvertierungsmodus: konvertierungsmodus, eingang_daten: content, ausgang_daten: convertedContent, status: pError ? 'FEHLERHAFT' : 'ERFOLGREICH', fehlermeldung: pError, quelle: 'WATCHER' // Auto tag }); } } _convertContent(content, fileName) { const trimmed = content.trim(); const upper = trimmed.toUpperCase(); // Detect file type and choose converter if (upper.startsWith('UNA') || upper.startsWith('UNB')) { // EDIFACT inbound → VDA 4905 return this._convertInbound(content, upper); } else if (/^[0-9]{3}/.test(trimmed) || /^[57][0-9]{2}/.test(trimmed)) { // VDA record (starts with 3-digit record type, e.g. 511, 711) → EDIFACT outbound return this._convertOutbound(content); } else { return { error: `Dateiformat nicht erkannt (weder EDIFACT noch VDA). Erste Zeichen: "${trimmed.substring(0, 20)}..."` }; } } _convertInbound(content, upper) { try { const ConfigParser = window.EDIBridge.ConfigParser; const DelforParser = window.EDIBridge.DelforParser; let preferredMode = null; if (ConfigParser && DelforParser) { const customerId = DelforParser.getCustomerId(content); console.log("Watcher detected Inbound Customer ID:", customerId); if (customerId) { preferredMode = ConfigParser.lookupCustomerMode(this.config, customerId); console.log("Watcher mapped Inbound mode for ID", customerId, ":", preferredMode); } } // 1. Prioritize mapped mode if (preferredMode === 'inbound-ifm') { const converter = window.EDIBridge.DelforToVDA4905Converter; if (converter) { const result = converter.convert(content); return { output: result, type: 'IFM DELFOR → VDA 4905', format: 'vda' }; } } else if (preferredMode === 'inbound-bosch') { const parser = window.EDIBridge.DelforParser; const generator = window.EDIBridge.VDA4905Generator; if (parser && generator) { const parsed = parser.parse(content); const vda4905 = generator.generate(parsed); return { output: vda4905, type: 'DELFOR → VDA 4905', format: 'vda' }; } } else if (preferredMode === 'inbound-invrpt') { const converter = window.EDIBridge.InvrptToVDA4913; if (converter) { const vda4913 = converter.convert(content); return { output: vda4913, type: 'INVRPT → VDA 4913', format: 'vda' }; } } // 2. Fallback to hardcoded logic if no mapping if (upper.includes('INVRPT')) { const converter = window.EDIBridge.InvrptToVDA4913; if (converter) { const vda4913 = converter.convert(content); return { output: vda4913, type: 'INVRPT → VDA 4913', format: 'vda' }; } } if (upper.includes('DELFOR') && upper.includes('D:04A')) { const converter = window.EDIBridge.DelforToVDA4905Converter; if (converter) { const result = converter.convert(content); return { output: result, type: 'IFM DELFOR D:04A → VDA 4905', format: 'vda' }; } } const parser = window.EDIBridge.DelforParser; const generator = window.EDIBridge.VDA4905Generator; if (parser && generator) { const parsed = parser.parse(content); const vda4905 = generator.generate(parsed); return { output: vda4905, type: 'DELFOR → VDA 4905', format: 'vda' }; } return { error: 'Passendes Inbound-Modul nicht geladen oder Typ unbekannt.' }; } catch (e) { return { error: `Inbound-Konvertierung fehlgeschlagen: ${e.message}` }; } } _convertOutbound(content) { try { const VDAParser = window.EDIBridge.VDAParser; if (!VDAParser) return { error: 'VDA Parser nicht geladen.' }; const vda = VDAParser.parse(content); if (!vda.interchanges || vda.interchanges.length === 0) { return { error: 'Keine gültigen VDA 4913 Daten gefunden.' }; } // Check for customer mapping in config const ConfigParser = window.EDIBridge.ConfigParser; const customerId = VDAParser.getCustomerId(content); console.log("Watcher detected Customer ID:", customerId); let preferredMode = null; if (ConfigParser && customerId) { preferredMode = ConfigParser.lookupCustomerMode(this.config, customerId); console.log("Watcher mapped mode for ID", customerId, ":", preferredMode); } if (preferredMode === 'outbound-ifm') { const delvry = window.EDIBridge.VDA4913ToDELVRY03; if (delvry) { const idocs = delvry.convert(vda, this.config || {}); const output = delvry.toXML(idocs); return { output, type: 'VDA 4913 → IFM DELVRY03', format: 'xml' }; } } else if (preferredMode === 'outbound-zf') { const desadvZf = window.EDIBridge.VDA4913ToDESADVZF; if (desadvZf) { const output = desadvZf.convert(content, {}, { linWeights: {}, pacWeights: {}, pacDims: {} }, this.config); return { output, type: 'VDA 4913 → ZF DESADV', format: 'zf-edi', targetFormat: 'ZF DESADV' }; } } else if (preferredMode === 'outbound-bosch') { const desadv = window.EDIBridge.VDA4913ToDESADV; if (desadv) { const output = desadv.convert(content, {}, { linWeights: {}, pacWeights: {}, pacDims: {} }, this.config); return { output, type: 'VDA 4913 → Bosch DESADV', format: 'edi' }; } } // Fallback to original logic if no mapping or mapped converter missing // Try IFM DELVRY03 first const delvry = window.EDIBridge.VDA4913ToDELVRY03; if (delvry) { const idocs = delvry.convert(vda, this.config || {}); const output = delvry.toXML(idocs); return { output, type: 'VDA 4913 → IFM DELVRY03', format: 'xml' }; } // Fallback to Bosch DESADV const desadv = window.EDIBridge.VDA4913ToDESADV; if (desadv) { const output = desadv.convert(content, {}, { linWeights: {}, pacWeights: {}, pacDims: {} }, this.config); return { output, type: 'VDA 4913 → Bosch DESADV', format: 'edi' }; } return { error: 'Kein Outbound-Converter geladen.' }; } catch (e) { return { error: `Outbound-Konvertierung fehlgeschlagen: ${e.message}` }; } } _addLog(level, fileName, message) { const entry = { time: new Date().toLocaleTimeString('de-DE'), level, fileName, message }; this.log.unshift(entry); if (this.log.length > this.maxLogEntries) this.log.pop(); if (this.onLogEntry) this.onLogEntry(entry); } async start(inputDir, outputDir) { if (!window.electronAPI) { return { error: 'Electron API nicht verfügbar. App läuft im Browser-Modus.' }; } const result = await window.electronAPI.startOutboundWatcher({ inputDir, outputDir }); if (result.success) { this.status = 'running'; this._addLog('info', '', `Watcher gestartet. Überwache: ${inputDir}`); if (this.onStatusChange) this.onStatusChange(this.status); } else if (result.error) { this._addLog('error', '', result.error); } return result; } async stop() { if (!window.electronAPI) return; const result = await window.electronAPI.stopOutboundWatcher(); if (result.success) { this.status = 'stopped'; this._addLog('info', '', 'Watcher gestoppt.'); if (this.onStatusChange) this.onStatusChange(this.status); } return result; } async pause() { if (!window.electronAPI) return; const result = await window.electronAPI.pauseOutboundWatcher(); if (result.success) { this.status = 'paused'; this._addLog('info', '', 'Watcher pausiert.'); if (this.onStatusChange) this.onStatusChange(this.status); } return result; } async resume() { if (!window.electronAPI) return; const result = await window.electronAPI.resumeOutboundWatcher(); if (result.success) { this.status = 'running'; this._addLog('info', '', 'Watcher fortgesetzt.'); if (this.onStatusChange) this.onStatusChange(this.status); } else if (result.error) { this._addLog('error', '', result.error); } return result; } async loadSettings() { if (!window.electronAPI) return { inputDir: '', outputDir: '', mode: 'auto' }; return await window.electronAPI.loadSettings(); } async saveSettings(settings) { if (!window.electronAPI) return; return await window.electronAPI.saveSettings(settings); } async selectFolder() { if (!window.electronAPI) return null; return await window.electronAPI.selectFolder(); } isElectron() { return !!window.electronAPI; } } window.EDIBridge.OutboundWatcherBridge = OutboundWatcherBridge;