@fye/aec-parser
Version:
Parsing of AEC files
178 lines (170 loc) • 4.31 kB
JavaScript
const etl = require('etl');
const debug = require('debug')('parser:aec');
const { basename } = require('path');
const {
headerFields,
shippingFields,
billingFields,
itemFields,
trailerFields,
messageFields,
} = require('./line-maps');
/**
* assign value based on field and line element position
* @param {Array} fields
* @param {Array} lineTextList
* @return {Object}
*/
const assignValues = (fields, lineTextList) => {
const values = {};
fields.forEach((field, idx) => {
if (field) {
debug('field', field.name);
const value = lineTextList[idx] || undefined;
values[field.name] = field.type(value);
}
});
debug(values);
return values;
};
const layoutMap = {
H: headerFields,
B: billingFields,
S: shippingFields,
L: itemFields,
T: trailerFields,
M: messageFields,
};
/**
* Parses line using layout map
* @param {String} line
* @return {Object}
*/
const lineParser = line => {
const lineTextList = line.text.replace(/"/g, '').split(',');
debug(lineTextList);
if (!layoutMap[lineTextList[0]]) {
return undefined;
}
const fields = layoutMap[lineTextList[0]];
return assignValues(fields, lineTextList);
};
/**
* set order detail values by line type
* line type is designated as first element in line array
* @param {Object} opts
* @param {String} opts.line unparsed line
* @param {Object} opts.data data assigned by line mapping
* @param {Object} opts.order an existing order
* @param {String} opts.file file data origingated from
* @return {Object}
*/
const setOrderDetail = ({ line, data, order, file }) => {
const lineText = line.replace(/"/g, '').split(',');
let completedOrder = null;
/* eslint-disable no-param-reassign */
switch (lineText[0]) {
case 'F':
break;
case 'H':
// header
order = data;
order.totalShipped = 0;
order.totalBackordered = 0;
order.totalCancelled = 0;
debug('i have a header');
break;
case 'B':
// billing
order.billing = data;
break;
case 'S':
// shipping
order.shipping = data;
break;
case 'M':
// message
order.message = data;
break;
case 'L':
// line
if (order.items === undefined) {
order.items = [];
}
// eslint-disable-next-line no-case-declarations
const item = data;
order.items.push(item);
order.totalShipped += item.qtyShipped;
order.totalBackordered += item.qtyBackordered;
order.totalCancelled += item.qtyCancelled;
break;
case 'T':
// trailer
order.file = basename(file);
if (order.totalShipped) {
order.shipViaCode = data.shipViaCode;
order.trackingNumber = data.trackingNum;
order.shipDate = data.shipDate;
order.shippingCost = data.retailerOrderTotal;
}
completedOrder = order;
break;
case 'E':
break;
case '':
break;
default:
console.log(`No case for ${lineText[0]}`);
console.log(lineText);
break;
}
debug('here is the order', order);
/* eslint-enable no-param-reassign */
return { order, completedOrder };
};
/**
* parse file
* @param {String} filename
* @return {GenericTransformStream}
*/
function parseFile(filename) {
debug('parsing file', filename);
let currentOrder = null;
let currentOrderLines = [];
return etl
.file(filename)
.pipe(etl.split())
.pipe(
etl.map(line => {
const mappedLine = lineParser(line);
if (line.text.indexOf('"F"') === 0 || line.text.indexOf('"E"') === 0) {
return {
orderLines: [line.text],
};
}
const set = setOrderDetail({
line: line.text,
data: mappedLine,
order: currentOrder,
file: filename,
});
currentOrder = set.order;
currentOrderLines.push(line.text);
if (set.completedOrder) {
currentOrder = null;
const orderObject = {
order: set.completedOrder,
orderLines: currentOrderLines,
};
currentOrderLines = [];
return orderObject;
}
return undefined;
}),
);
}
module.exports = {
lineParser,
setOrderDetail,
parseFile,
};