Files
vda-to-edifact-converter/js/vda-parser.js
2026-03-13 09:53:40 +01:00

247 lines
8.0 KiB
JavaScript

/**
* 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;