/** * VDA 4913 Parser - Field positions verified against real data */ window.EDIBridge = window.EDIBridge || {}; class VDAParser { static parse(content) { const lines = content.split(/\r?\n/).filter(l => l.length >= 3); const result = { interchanges: [] }; let curI = null, curT = null, curDN = null; for (const line of lines) { const rt = line.substring(0, 3); switch (rt) { // VDA 4905 (DELFOR) case '511': curI = { header: this.parse511(line), articles: [], transports: [] }; result.interchanges.push(curI); break; case '512': if (!curI) break; // In 4905, articles are children of the interchange curT = { article: this.parse512(line), schedules: [], deliveries: [] }; curI.articles.push(curT); break; case '513': if (!curT || !curT.article) break; // Ensure we are in an article context const s513 = this.parse513(line); curT.schedules.push(...s513.schedules); if (s513.lastDn && s513.lastDn !== '00000000' && s513.lastDn.trim() !== '') { curT.deliveries.push({ docNo: s513.lastDn, date: s513.lastDate, qty: s513.lastQty, unit: curT.article.unit || 'ST' }); } curT.efz = s513.efz; curT.nullStellung = s513.nullStellung || ''; break; case '514': if (!curT || !curT.article) break; curT.schedules.push(...this.parse514(line)); break; case '519': if (curI) curI.trailer = this.parse519(line); break; // VDA 4913 (DESADV) case '711': curI = { header: this.parse711(line), transports: [], articles: [] }; result.interchanges.push(curI); break; case '712': if (!curI) break; curT = { data: this.parse712(line), deliveryNotes: [] }; curI.transports.push(curT); break; case '713': if (!curT) break; curDN = { header: this.parse713(line), positions: [], texts: [] }; curT.deliveryNotes.push(curDN); break; case '714': if (!curDN) break; curDN.positions.push({ data: this.parse714(line), packaging: [] }); break; case '715': if (!curDN) break; const lastP = curDN.positions[curDN.positions.length - 1]; if (lastP) lastP.packaging.push(this.parse715(line)); break; case '716': if (curDN) { curDN.texts.push(line.substring(5).trim()); const revLvl = line.substring(5, 7).trim(); if (revLvl && curDN.positions.length > 0) { const lastPos = curDN.positions[curDN.positions.length - 1]; if (!lastPos.data.revisionLevel) lastPos.data.revisionLevel = revLvl; } } break; case '719': if (curI) curI.trailer = this.parse719(line); break; } } return result; } static getCustomerId(content) { if (!content) return null; const lines = content.split(/\r?\n/).filter(l => l.length >= 3); for (const line of lines) { const rt = line.substring(0, 3); if (rt === '711' || rt === '511') { return line.substring(5, 14).trim(); } } return null; } // --- VDA 4905 Parsers --- static parse511(l) { return { version: l.substring(3, 5).trim(), customerId: l.substring(5, 14).trim(), supplierId: l.substring(14, 23).trim(), oldTransNo: l.substring(23, 28).trim(), newTransNo: l.substring(28, 33).trim(), date: l.substring(33, 39).trim() }; } static parse512(l) { return { plant: l.substring(5, 8).trim(), docNum: l.substring(8, 17).trim(), docDate: l.substring(17, 23).trim(), custMat: l.substring(38, 60).trim(), suppMat: l.substring(60, 82).trim(), orderNo: l.substring(82, 94).trim(), unloadingPoint: l.substring(94, 99).trim(), unit: l.substring(103, 105).trim() || 'ST' }; } static parse513(l) { const weDate = l.substring(5, 11).trim(); const lastDn = l.substring(11, 19).trim(); const lastDate = l.substring(19, 25).trim(); // VDA 4905: Letzte Liefermenge hat 3 implizite Dezimalstellen → /1000 const lastQty = (parseInt(l.substring(25, 37), 10) || 0) / 1000; // VDA 4905: EFZ hat ebenfalls 3 implizite Dezimalstellen → /1000 const efz = (parseInt(l.substring(37, 47), 10) || 0) / 1000; const schedules = []; let offset = 47; for (let i = 0; i < 5; i++) { const dateRaw = l.substring(offset, offset + 6); const qtyStr = l.substring(offset + 6, offset + 15).trim(); if (dateRaw.trim() && dateRaw.trim() !== '000000') { // VDA 4905: Abrufmengen haben 3 implizite Dezimalstellen → /1000 schedules.push({ date: dateRaw, qty: (parseInt(qtyStr, 10) || 0) / 1000 }); } offset += 15; } // Null-Stellung (6 Zeichen JJMMTT) steht nach den 5 Abrufzeilen const nullStellungRaw = l.substring(offset, offset + 6).trim(); const nullStellung = (nullStellungRaw && nullStellungRaw !== '000000') ? nullStellungRaw : ''; return { weDate, lastDn, lastDate, lastQty, efz, nullStellung, schedules }; } static parse514(l) { const schedules = []; let offset = 5; for (let i = 0; i < 8; i++) { const dateRaw = l.substring(offset, offset + 6); const qtyStr = l.substring(offset + 6, offset + 15).trim(); if (dateRaw.trim() && dateRaw.trim() !== '000000') { // VDA 4905: Abrufmengen haben 3 implizite Dezimalstellen → /1000 schedules.push({ date: dateRaw, qty: (parseInt(qtyStr, 10) || 0) / 1000 }); } offset += 15; } return schedules; } static parse519(l) { return { count511: parseInt(l.substring(5, 12), 10) || 0, count512: parseInt(l.substring(12, 19), 10) || 0, count513: parseInt(l.substring(19, 26), 10) || 0, count514: parseInt(l.substring(26, 33), 10) || 0 }; } // --- VDA 4913 Parsers --- static parse711(l) { return { version: l.substring(3, 5).trim(), targetId: l.substring(5, 14).trim(), sourceId: l.substring(14, 23).trim(), transNo1: l.substring(23, 28).trim(), transNo2: l.substring(28, 33).trim(), date: l.substring(33, 39).trim(), altId: l.substring(39, 48).trim() }; } static parse712(l) { return { refNo: l.substring(5, 13).trim(), carrierName: l.substring(16, 30).trim(), date: l.substring(30, 36).trim(), time: l.substring(36, 40).trim(), grossWeight: parseInt(l.substring(40, 47)) || 0, netWeight: parseInt(l.substring(47, 54)) || 0, }; } static parse713(l) { return { dnNo: l.substring(5, 13).trim(), date: l.substring(13, 19).trim(), unloadingPoint: l.substring(19, 24).trim(), qualifier: l.substring(24, 30).trim(), orderNo: l.substring(30, 38).trim(), }; } static parse714(l) { // Qty: [53-65] with 3 implied decimals (VDA Standard) → /1000 const qtyRaw = parseInt(l.substring(52, 65)) || 0; const qty = qtyRaw / 1000; return { custMat: l.substring(5, 27).trim(), suppMat: l.substring(27, 49).trim(), qty: qty, unit: l.substring(65, 67).trim(), refNo: l.substring(77, 90).trim(), // VDA 4913 standard uses different fields for batch/refs, keeping compatibility batchNo: l.substring(90, 105).trim() || l.substring(113, 127).trim(), }; } static parse715(l) { const count = parseInt(l.substring(59, 62)) || 1; const labelFrom = l.substring(78, 87).trim(); const labelTo = l.substring(87, 96).trim(); return { packMatCust: l.substring(5, 27).trim(), packMatSupp: l.substring(27, 49).trim(), qty: count, labelFrom: labelFrom, labelTo: labelTo, }; } static parse719(l) { return { lineCount: parseInt(l.substring(5, 12)) || 0 }; } } window.EDIBridge.VDAParser = VDAParser;