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

468 lines
15 KiB
JavaScript

/**
* ifm electronic DELFOR D04A to VDA 4905 Converter
* Converts EDIFACT DELFOR D04A (ifm electronic format) to VDA 4905
*
* Uses:
* - DelforParser: Parses EDIFACT DELFOR into structured segments
* - VDA4905Generator: Generates VDA 4905 output
*
* Based on ifm_electronic_DELFOR_D04A specification
*/
window.EDIBridge = window.EDIBridge || {};
class DelforToVDA4905Converter {
/**
* Main conversion function
* @param {string} delforContent - Raw EDIFACT DELFOR D04A content
* @returns {string} VDA 4905 formatted output
*/
static convert(delforContent) {
const DelforParser = window.EDIBridge.DelforParser;
const VDA4905Generator = window.EDIBridge.VDA4905Generator;
if (!DelforParser) {
throw new Error('DelforParser not found. Please include delfor-parser.js');
}
if (!VDA4905Generator) {
throw new Error('VDA4905Generator not found. Please include vda4905-generator.js');
}
// Step 1: Parse DELFOR
const parsed = DelforParser.parse(delforContent);
// Step 2: Transform to VDA4905-compatible structure
const transformed = this.transformDelforStructure(parsed);
// Step 3: Generate VDA 4905
return VDA4905Generator.generate(transformed);
}
/**
* Transform DELFOR D04A structure to match VDA4905Generator expectations
* Handles ifm electronic specific segment mappings
*/
static transformDelforStructure(parsed) {
const segments = parsed.segments;
const result = { segments: [] };
// Helper to get segment value
const getVal = (seg, elIdx, compIdx) => {
if (!seg || !seg.elements) return '';
const el = seg.elements[elIdx];
if (!el) return '';
if (Array.isArray(el)) return el[compIdx] || '';
if (compIdx === 0) return el;
return '';
};
// Copy all segments but enhance/transform as needed
for (const seg of segments) {
const transformed = this.transformSegment(seg, segments);
if (transformed) {
result.segments.push(transformed);
}
}
return result;
}
/**
* Transform individual segment according to ifm electronic DELFOR D04A spec
*/
static transformSegment(seg, allSegments) {
// Most segments pass through unchanged
// Add specific transformations based on ifm electronic requirements
switch (seg.tag) {
case 'UNH':
// Message Header - verify DELFOR type
return this.validateUNH(seg);
case 'BGM':
// Beginning of Message - Document code 241 expected
return this.transformBGM(seg);
case 'DTM':
// Date/Time/Period - handle various qualifiers
return this.transformDTM(seg);
case 'RFF':
// Reference - handle ON (Order Number), AAN, etc.
return this.transformRFF(seg);
case 'NAD':
// Name and Address - BY, SE, etc.
return this.transformNAD(seg);
case 'LIN':
// Line Item - Article information
return this.transformLIN(seg);
case 'QTY':
// Quantity - handle 194 (cumulative), 113 (schedule), etc.
return this.transformQTY(seg);
case 'SCC':
// Scheduling Conditions
return this.transformSCC(seg);
case 'GEI':
// Processing Information
return this.transformGEI(seg);
case 'LOC':
// Location - Plant, Unloading Point
return seg;
case 'CTA':
case 'COM':
// Contact information - pass through
return seg;
default:
return seg;
}
}
/**
* Validate UNH segment - must be DELFOR:D:04A:UN
*/
static validateUNH(seg) {
const elements = seg.elements || [];
// UNH+172354030+DELFOR:D:04A:UN
// elements[0] = message reference number
// elements[1] = [DELFOR, D, 04A, UN]
if (elements[1]) {
const msgType = Array.isArray(elements[1]) ? elements[1][0] : elements[1];
if (msgType !== 'DELFOR') {
console.warn('Warning: Expected DELFOR message type, got:', msgType);
}
}
return seg;
}
/**
* Transform BGM segment
* Expected: BGM+241+177754999+9
* - 241 = Delivery schedule message
* - Document identifier
* - 9 = Original
*/
static transformBGM(seg) {
// Pass through - VDA4905Generator handles this
return seg;
}
/**
* Transform DTM segment
* Handle ifm electronic specific date qualifiers:
* - 137: Document date
* - 4: Order date
* - 171: Reference date/time
* - 64: Earliest delivery date
*/
static transformDTM(seg) {
const elements = seg.elements || [];
const qualifier = Array.isArray(elements[0]) ? elements[0][0] : elements[0];
// Map ifm electronic qualifiers to VDA4905 expected qualifiers
const qualifierMap = {
'137': '137', // Document date -> Document date
'4': '4', // Order date
'171': '171', // Reference date
'64': '64', // Earliest delivery date
'63': '63', // Latest delivery date
'2': '2', // Delivery date
'10': '10', // Shipment date
'11': '11', // Dispatch date
'50': '50', // Goods receipt date
'131': '131', // Tax point date
'192': '192', // Previous document date
'242': '242' // Actual date
};
return seg;
}
/**
* Transform RFF segment
* Handle ifm electronic references:
* - ON: Order number (5500002000)
* - AAN: Delivery schedule number
* - AIF: Previous release number
*/
static transformRFF(seg) {
const elements = seg.elements || [];
const qualifier = Array.isArray(elements[0]) ? elements[0][0] : elements[0];
// RFF+ON:5500002000 -> Order reference
// RFF+AAN:55 -> Delivery schedule number
return seg;
}
/**
* Transform NAD segment
* ifm electronic format:
* NAD+BY+1100+ifm electronic gmbh+ifm electronic gmbh+ifm-Straße 1:Halle 16+Tettnang+88069+DE
*/
static transformNAD(seg) {
const elements = seg.elements || [];
const qualifier = Array.isArray(elements[0]) ? elements[0][0] : elements[0];
// Ensure proper structure for VDA4905Generator
// BY = Buyer, SE = Seller, ST = Ship-to
return seg;
}
/**
* Transform LIN segment
* ifm electronic format:
* LIN+00010++AK2258921:BP
* - Line item number
* - (empty)
* - Item identifier:BP (Buyer's part number)
*/
static transformLIN(seg) {
const elements = seg.elements || [];
// Ensure item identifier is properly extracted
// elements[2] should contain [ItemNumber, 'BP']
return seg;
}
/**
* Transform QTY segment
* ifm electronic qualifiers:
* - 194: Cumulative quantity received
* - 113: Quantity to be delivered (schedule)
* - 1: Discrete quantity
* - 12: Despatch quantity
* - 21: Ordered quantity
* - 48: Received quantity
* - 70: Minimum stock quantity
*/
static transformQTY(seg) {
const elements = seg.elements || [];
const qualifier = Array.isArray(elements[0]) ? elements[0][0] : elements[0];
// Map ifm electronic quantity qualifiers
const qualifierMap = {
'194': '194', // Cumulative received
'113': '113', // Schedule quantity (maps to VDA 4905 schedule)
'1': '1', // Discrete quantity
'12': '12', // Despatch quantity
'21': '21', // Ordered quantity
'48': '48', // Received quantity
'70': '70' // Minimum stock
};
return seg;
}
/**
* Transform SCC segment
* Scheduling Conditions:
* SCC+1 = Firm schedule
* SCC+4 = Planning schedule
*/
static transformSCC(seg) {
return seg;
}
/**
* Transform GEI segment
* Processing Information:
* GEI+3++35 = Process type
*/
static transformGEI(seg) {
return seg;
}
/**
* Extract schedule data from DELFOR for VDA 4905 records 513/514
* Groups QTY segments with their associated DTM dates
*/
static extractSchedules(segments) {
const schedules = [];
let currentLin = null;
const getVal = (seg, elIdx, compIdx) => {
if (!seg || !seg.elements) return '';
const el = seg.elements[elIdx];
if (!el) return '';
if (Array.isArray(el)) return el[compIdx] || '';
if (compIdx === 0) return el;
return '';
};
for (let i = 0; i < segments.length; i++) {
const seg = segments[i];
if (seg.tag === 'LIN') {
currentLin = {
itemNumber: getVal(seg, 2, 0),
schedules: []
};
}
if (seg.tag === 'QTY' && currentLin) {
const qualifier = getVal(seg, 0, 0);
const quantity = getVal(seg, 0, 1);
const unit = getVal(seg, 0, 2);
// Look for associated DTM
let deliveryDate = '';
for (let j = i + 1; j < segments.length; j++) {
const next = segments[j];
if (next.tag === 'QTY' || next.tag === 'LIN' || next.tag === 'UNT') break;
if (next.tag === 'DTM') {
const dtmQual = getVal(next, 0, 0);
if (['64', '2', '10', '11', '171'].includes(dtmQual)) {
deliveryDate = getVal(next, 0, 1);
break;
}
}
}
// Only include schedule quantities (113, 1, 12, 21)
if (['113', '1', '12', '21'].includes(qualifier)) {
currentLin.schedules.push({
qualifier,
quantity,
unit,
date: deliveryDate
});
}
}
}
return schedules;
}
/**
* Validate DELFOR content before conversion
*/
static validate(delforContent) {
const errors = [];
const warnings = [];
// Check for required segments
const requiredSegments = ['UNH', 'BGM', 'DTM', 'NAD', 'LIN', 'QTY', 'UNT'];
for (const tag of requiredSegments) {
if (!delforContent.includes(tag + '+') && !delforContent.includes(tag + "'")) {
errors.push(`Missing required segment: ${tag}`);
}
}
// Check for DELFOR message type
if (!delforContent.includes('DELFOR')) {
errors.push('Not a DELFOR message');
}
// Check for D04A version (optional warning)
if (!delforContent.includes('D:04A') && !delforContent.includes(':D:04A:')) {
warnings.push('Expected DELFOR D04A version');
}
return {
valid: errors.length === 0,
errors,
warnings
};
}
/**
* Convert with validation
*/
static convertWithValidation(delforContent) {
const validation = this.validate(delforContent);
if (!validation.valid) {
return {
success: false,
errors: validation.errors,
warnings: validation.warnings,
output: null
};
}
try {
const output = this.convert(delforContent);
return {
success: true,
errors: [],
warnings: validation.warnings,
output
};
} catch (e) {
return {
success: false,
errors: [e.message],
warnings: validation.warnings,
output: null
};
}
}
/**
* Parse DELFOR and return structured data for inspection
*/
static parseOnly(delforContent) {
const DelforParser = window.EDIBridge.DelforParser;
if (!DelforParser) {
throw new Error('DelforParser not found');
}
return DelforParser.parse(delforContent);
}
/**
* Get mapping info for debugging
*/
static getMappingInfo() {
return {
name: 'DELFOR D04A to VDA 4905',
source: 'EDIFACT DELFOR D04A (ifm electronic)',
target: 'VDA 4905',
version: '1.0.0',
segments: {
'UNH': 'Message Header -> VDA 511 (Header)',
'BGM': 'Beginning of Message -> VDA 511',
'DTM': 'Date/Time -> VDA 511, 512, 513',
'RFF': 'Reference -> VDA 511, 512',
'NAD': 'Name and Address -> VDA 511 (Customer/Supplier)',
'LIN': 'Line Item -> VDA 512 (Article)',
'QTY': 'Quantity -> VDA 513/514 (Schedules)',
'SCC': 'Scheduling Conditions -> VDA 513/514',
'UNT': 'Message Trailer -> VDA 519'
},
quantityQualifiers: {
'194': 'Cumulative received -> VDA 513 (Cumulative)',
'113': 'Schedule quantity -> VDA 513/514 (Schedule lines)',
'1': 'Discrete quantity -> VDA 513/514',
'12': 'Despatch quantity -> VDA 513',
'48': 'Received quantity -> VDA 513',
'70': 'Minimum stock -> VDA 513 (EFZ)'
},
dateQualifiers: {
'137': 'Document date -> VDA 511',
'171': 'Reference date -> VDA 513',
'64': 'Earliest delivery -> VDA 513/514',
'192': 'Previous document date -> VDA 512'
}
};
}
}
// Register in EDIBridge namespace
window.EDIBridge.DelforToVDA4905Converter = DelforToVDA4905Converter;
// Convenience alias
window.EDIBridge.convertDelforToVDA4905 = (content) => DelforToVDA4905Converter.convert(content);