edifact-parser
Version:
EDIFACT parser based on the edi npm package
928 lines (878 loc) • 26.1 kB
JavaScript
/**
* @author Ricardo Veronese Ricci
* @copyright 2016-2019 Jobin S.L.
* @license MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* inspired by: https://github.com/nabudaldah/EDI
*/
function getOrderType(code) {
switch (code) {
case "220":
return "Order";
case "221":
return "Blanket order";
case "224":
return "Rush order";
case "225":
return "Repair order";
case "226":
return "Call off order";
case "227":
return "Consignment order";
case "22E":
return "Manufacturer raised order (GS1 Temporary Code)";
case "23E":
return "Manufacturer raised consignment order (GS1 Temporary Code)";
case "258":
return "Standing order";
case "237":
return "Cross docking services order";
case "400":
return "Exceptional order";
case "401":
return "Transshipment order";
case "402":
return "Cross docking order";
default:
break;
}
}
function getDateType(code) {
switch (code) {
case "2":
return "Delivery date/time, requested";
case "10":
return "Shipment date/time, requested";
case "11":
return "Despatch date and/or time";
case "15":
return "Promotion start date/time";
case "37":
return "Ship not before date/time";
case "38":
return "Ship not later than date/time";
case "61":
return "Cancel if not delivered by this date";
case "63":
return "Delivery date/time, latest";
case "64":
return "Delivery date/time, earliest";
case "69":
return "Delivery date/time, promised for";
case "76":
return "Delivery date/time, scheduled for";
case "X14":
return "Requested for delivery week commencing (GS1 Temporary Code)";
case "137":
return "Document/message date/time";
case "200":
return "Pick-up/collection date/time of cargo";
case "235":
return "Collection date/time, latest";
case "263":
return "Invoicing period";
case "273":
return "Validity period";
case "282":
return "Confirmation date lead time";
case "383":
return "Cancel if not shipped by this date";
default:
break;
}
}
function getMRefType(code) {
switch (code) {
case "AAB":
return "Proforma invoice number";
case "AAJ":
return "Delivery order number";
case "AAK":
return "Despatch advice number";
case "AFO":
return "Beneficiary's reference";
case "ALL":
return "Message batch number";
case "AIZ":
return "Consolidated invoice number";
case "AMT":
return "Goods and Services Tax identification number";
case "APQ":
return "Commercial account summary reference number";
case "CD":
return "Credit note number";
case "CR":
return "Customer reference number";
case "DL":
return "Debit note number";
case "DQ":
return "Delivery note number";
case "IV":
return "Invoice number";
case "ON":
return "Order number (buyer)";
case "PL":
return "Price list number";
case "RF":
return "Export reference number";
case "VN":
return "Order number (supplier)";
default:
break;
}
}
function getRefType(code) {
switch (code) {
case "ADE":
return "Account number";
case "ALV":
return "Registered capital reference";
case "AP":
return "Accounts receivable number";
case "AMT":
return "Goods and Services Tax identification number";
case "YC1":
return "Additional party identification (GS1 Temporary Code)";
case "EX":
return "Export licence number";
case "FC":
return "Fiscal number";
case "CR":
return "Customer reference number";
case "GN":
return "Government reference number";
case "IA":
return "Internal vendor number";
case "IP":
return "Import licence number";
case "IT":
return "Internal customer number";
case "PY":
return "Payee's financial institution account number";
case "SZ":
return "Specification number";
case "TRB":
return "Tribunal place registration number (GS1 Temporary Code)";
case "VA":
return "VAT registration number";
case "XA":
return "Company/place registration number";
case "AQQ":
return "Activite Principale Exercee (APE) identifier";
case "ATB":
return "Purchase for export Customs agreement number";
default:
break;
}
}
function getNameAddressType(code) {
switch (code) {
case "BO":
return "Broker or sales office";
case "BS":
return "Bill and ship to";
case "BY":
return "Buyer";
case "CN":
return "Consignee";
case "CS":
return "Consolidator";
case "DP":
return "Delivery party";
case "II":
return "Issuer of invoice";
case "IV":
return "Invoicee";
case "LD":
return "Party recovering the Value Added Tax (VAT)";
case "PE":
return "Payee";
case "RE":
return "Party to receive commercial invoice remittance";
case "SE":
return "Seller";
case "SR":
return "Supplier's agent/representative";
case "SN":
return "Store number";
case "ST":
return "Ship to";
case "SU":
return "Supplier";
case "LC":
return "Party declaring the Value Added Tax (VAT)";
default:
break;
}
}
function getControlTotalType(code) {
switch (code) {
case "1":
return "Total value of the quantity segments at line level in a message";
case "2":
return "Number of line items in message";
case "7":
return "Total gross weight";
case "29":
return "Total net weight of consignment";
case "15":
return "Total consignment, cube";
default:
break;
}
}
function getProductType(code) {
switch (code) {
case "1":
return "Additional identification";
case "2":
return "Identification for potential substitution";
case "4":
return "Substituted for";
case "5":
return "Product identification";
case "X1":
return "No substitution accepted (GS1 Code)";
default:
break;
}
}
function getItemType(code) {
switch (code) {
case "AC":
return "HIBC (Health Industry Bar Code)";
case "DW":
return "Drawing";
case "IB":
return "ISBN (International Standard Book Number)";
case "IN":
return "Buyer's item number";
case "SA":
return "Supplier's article number";
case "SRV":
return "GS1 Global Trade Item Number";
case "EWC":
return "European Waste Catalogue (GS1 code)";
case "UA":
return "Ultimate customer's article number";
default:
break;
}
}
function getQuantityType(code) {
switch (code) {
case "1":
return "Discrete quantity";
case "12":
return "Despatch quantity";
case "21":
return "Ordered quantity";
case "46":
return "Delivered quantity";
case "59":
return "Number of consumer units in the traded unit";
case "47":
return "Invoiced quantity";
case "61":
return "Return quantity";
case "192":
return "Free goods quantity";
case "194":
return "Received and accepted";
case "39E":
return "Minimum invoicing quantity (GS1 Temporary Code)";
case "45E":
return "Number of units in higher packaging or configuration level (GS1 Temporary Code)";
default:
break;
}
}
function getPriceType(code) {
switch (code) {
case "AAA":
return "Calculation net (The price stated is the net price including all allowances and charges and excluding taxes. Allowances and charges may be stated for information purposes only.)";
case "AAB":
return "Calculation gross (AAB - The price stated is the gross price excluding all allowances, charges and taxes. Allowances and charges must be stated for net calculation purposes.)";
case "AAE":
return "Information price, excluding allowances or charges, including taxes";
case "AAF":
return "Information price, excluding allowances or charges and taxes";
case "AAH":
return "Subject to escalation and price adjustment, use this when dealing with CSA (customer specific articles).";
case "AAQ":
return "Firm price, use this when dealing with CSA (customer specific articles).";
case "ABL":
return "Base price, use this when dealing with CSA (customer specific articles).";
case "ABM":
return "Base price difference, use this when dealing with CSA (customer specific articles).";
default:
break;
}
}
function getPriceTypeCode(code) {
switch (code) {
case "CA":
return "Catalogue";
case "CT":
return "Contract";
default:
break;
}
}
function getPriceSpecificationCode(code) {
switch (code) {
case "DPR":
return "Discount price";
case "PPR":
return "Provisional price";
case "PRP":
return "Promotional price";
case "RTP":
return "Retail price";
case "SRP":
return "Suggested retail price";
default:
break;
}
}
var EDI = function(string) {
this.string = string;
};
/* type transformations */
EDI.prototype.toString = function() {
return "" + this.string;
};
EDI.prototype.toNumber = function() {
return parseFloat(this.toString());
};
EDI.prototype.toDate = function() {
return new Date(this.string);
};
EDI.prototype.valueOf = function() {
return this.string;
};
/* Generic EDIFACT functions */
// EDI parse lines, return all document lines or a specific one
EDI.prototype.lines = function(n, format = "edi") {
var lines = this.string.split(/['\n\r]+/);
lines = lines.map(function(line) {
if (format === "edi") return new EDI(line);
else return line;
});
if (n || n === 0) return lines[n];
else return lines;
};
// EDI parse lines, return documents lines starting with certain token
EDI.prototype.lineSegment = function(token, format = "edi") {
let result = [];
const lines = this.string.split(/['\n\r]+/);
lines.map(function(line) {
if (line.startsWith(token)) {
if (format === "edi") return result.push(new EDI(line));
else return result.push(line);
}
}, []);
return result;
};
// EDI parse segments
EDI.prototype.segments = function(token) {
let segments = this.string.split(token);
segments = segments.splice(1, segments.length);
segments = segments.map(function(text) {
const segment = text.split("'");
return new EDI(token + segment[0]);
});
return segments;
};
// search for segment
EDI.prototype.segment = function(token) {
var esc = token.replace("+", "\\+");
var search = new RegExp(esc + "+[^']+", "g");
var segment = search.exec(this.string);
if (!segment || !segment[0]) segment = "";
else segment = "" + segment[0];
return new EDI(segment);
};
// return n'th element (zero-index)
EDI.prototype.element = function(n) {
// var elements = this.string.split('+');
// split while handling escape characters: credits: http://stackoverflow.com/a/14334054
var elements = this.string.match(/(\?.|[^\+])+/g);
var element = "";
if (!elements || n > elements.length - 1) element = "";
else element = elements[n];
return new EDI(element);
};
// return n'th component (zero-index)
EDI.prototype.component = function(n) {
// var components = this.string.split(':');
// split while handling escape characters: credits: http://stackoverflow.com/a/14334054
var components = this.string.match(/(\?.|[^:])+/g);
var component = "";
if (!components || n > components.length - 1) component = "";
else component = components[n];
return new EDI(component);
};
// extract batches from EDI message
EDI.prototype.bsegments = function() {
var bsegments = this.string.match(/UNB\+.*?UNZ\+[^\']+?/g);
bsegments = bsegments.map(function(segment) {
return new EDI(segment);
});
return bsegments;
};
// extract messages
EDI.prototype.msegments = function() {
var msegments = this.string.match(/UNH\+.*?UNT\+[^\']+?/g);
msegments = msegments.map(function(segment) {
return new EDI(segment);
});
return msegments;
};
// formats date, adds hyphen to separate, resulting in YYYY-MM-DD
// assuming the string comes from a date source
EDI.prototype.formatDate = function() {
return new Date(this.string.replace(/(\d{4})(\d{2})(\d{2})/, "$1-$2-$3"));
};
/* Batch specific functions */
// TODO: FIX THE FUNCTION NAMES
EDI.prototype.mid = function() {
return this.segment("UNH")
.element(1)
.toString();
};
EDI.prototype.mtype = function() {
return this.segment("UNH")
.element(2)
.component(0)
.toString();
};
EDI.prototype.msubtype = function() {
return this.segment("BGM")
.element(1)
.component(0)
.toString();
};
EDI.prototype.oref = function() {
return this.segment("BGM")
.element(2)
.toString();
};
EDI.prototype.mproduct = function() {
return this.segment("MKS")
.element(1)
.toString();
};
/* message specific functions */
EDI.prototype.idFrom = function() {
return this.segment("UNB")
.element(2)
.component(0)
.toString();
};
EDI.prototype.idTo = function() {
return this.segment("UNB")
.element(3)
.component(0)
.toString();
};
EDI.prototype.orderCode = function() {
return this.segment("BGM")
.element(1)
.component(0)
.toString();
};
EDI.prototype.orderType = function() {
const code = this.segment("BGM")
.element(1)
.component(0)
.toString();
return getOrderType(code);
};
EDI.prototype.orderRef = function() {
return this.segment("BGM")
.element(2)
.toString();
};
EDI.prototype.dateCode = function() {
return this.segment("DTM")
.element(1)
.component(0)
.toString();
};
EDI.prototype.dateType = function() {
const code = this.segment("DTM")
.element(1)
.component(0)
.toString();
return getDateType(code);
};
EDI.prototype.mDate = function() {
return this.segment("DTM+137")
.element(1)
.component(1)
.formatDate();
};
EDI.prototype.deliveryTimeEarliest = function() {
return this.segment("DTM+64")
.element(1)
.component(1)
.formatDate();
};
EDI.prototype.deliveryTimeLatest = function() {
return this.segment("DTM+63")
.element(1)
.component(1)
.formatDate();
};
EDI.prototype.deliveryDaysRange = function() {
const time =
this.deliveryTimeLatest().getTime() -
this.deliveryTimeEarliest().getTime();
return time / (1000 * 3600 * 24);
};
EDI.prototype.deliveryTimeRange = function() {
return (
this.deliveryTimeLatest().getTime() -
this.deliveryTimeEarliest().getTime()
);
};
EDI.prototype.mrefCode = function() {
return this.segment("RFF")
.element(1)
.component(0)
.toString();
};
EDI.prototype.mrefType = function() {
const code = this.segment("RFF")
.element(1)
.component(0)
.toString();
return getMRefType(code);
};
EDI.prototype.mref = function() {
return this.segment("RFF")
.element(1)
.component(1)
.toString();
};
EDI.prototype.refCode = function() {
const segments = this.segments("RFF");
const length = segments.length;
return segments[length - 1]
.element(2)
.component(0)
.toString();
};
EDI.prototype.refType = function() {
const segments = this.segments("RFF");
const length = segments.length;
const code = segments[length - 1]
.element(2)
.component(0)
.toString();
return getRefType(code);
};
EDI.prototype.ref = function() {
const segments = this.segments("RFF");
const length = segments.length;
return segments[length - 1]
.element(1)
.component(1)
.toString();
};
EDI.prototype.refVAT = function() {
return this.segment("RFF+VAT")
.component(1)
.toString()
.replace("?", "")
.toString();
};
// TODO: check this
EDI.prototype.refs = function() {
return this.segments("RFF");
};
EDI.prototype.nameAddressesType = function() {
const refs = this.segments("NAD").map(seg => {
return getNameAddressType(
seg
.element(1)
.component(0)
.toString()
);
});
return refs;
};
EDI.prototype.naBuyer = function() {
return this.segment("NAD+BY")
.element(2)
.component(0)
.toString();
};
EDI.prototype.naSupplier = function() {
return this.segment("NAD+SU")
.element(2)
.component(0)
.toString();
};
EDI.prototype.naDeliveryParty = function() {
return this.segment("NAD+DP")
.element(2)
.component(0)
.toString();
};
EDI.prototype.naMessageReceiver = function() {
return this.segment("NAD+MR")
.element(2)
.component(0)
.toString();
};
EDI.prototype.naInvoicee = function() {
return this.segment("NAD+IV")
.element(2)
.component(0)
.toString();
};
EDI.prototype.naInvoiceeAddress1 = function() {
return this.segment("NAD+IV")
.element(3)
.component(0)
.toString();
};
EDI.prototype.naInvoiceeAddress2 = function() {
return this.segment("NAD+IV")
.element(4)
.component(0)
.toString();
};
EDI.prototype.naInvoiceeAddressCity = function() {
return this.segment("NAD+IV")
.element(5)
.component(0)
.toString();
};
EDI.prototype.naInvoiceeAddressPostalCode = function() {
return this.segment("NAD+IV")
.element(6)
.component(0)
.toString();
};
EDI.prototype.naInvoiceeAddressCountry = function() {
return this.segment("NAD+IV")
.element(7)
.component(0)
.toString();
};
EDI.prototype.nameAdresses = function() {
return this.segments("NAD");
};
EDI.prototype.currency = function() {
return this.segment("CUX")
.element(1)
.component(1)
.toString();
};
/* group product by lines */
EDI.prototype.productLines = function() {
return this.segments("LIN");
};
EDI.prototype.productsType = function(lineNumber) {
const codes = this.segments("PIA");
if (lineNumber)
return getProductType(codes[lineNumber].element(1).toString());
else return codes.map(code => getProductType(code.element(1).toString()));
};
EDI.prototype.productsID = function(lineNumber) {
const segents = this.segments("PIA");
if (lineNumber)
return segents[lineNumber]
.element(2)
.component(0)
.toString();
else
return segents.map(segment =>
code
.element(2)
.component(0)
.toString()
);
};
EDI.prototype.itemsType = function(lineNumber) {
const codes = this.segments("PIA");
if (lineNumber)
return getItemType(
codes[lineNumber]
.element(2)
.component(1)
.toString()
);
else
return codes.map(code =>
getItemType(
code
.element(2)
.component(1)
.toString()
)
);
};
EDI.prototype.productsQtyType = function(lineNumber) {
const codes = this.segments("QTY");
if (lineNumber)
return getQuantityType(
codes[lineNumber]
.elmement(1)
.component(0)
.toString()
);
else
return codes.map(code =>
getQuantityType(
code
.element(1)
.component(0)
.toString()
)
);
};
EDI.prototype.productsQty = function(lineNumber) {
const segments = this.segments("QTY");
if (lineNumber)
return segments[lineNumber]
.elmement(1)
.component(1)
.toString();
else
return segments.map(segment =>
segment
.element(1)
.component(1)
.toString()
);
};
EDI.prototype.productsPriceType = function(lineNumber) {
const codes = this.segments("PRI");
if (lineNumber)
return getPriceType(
codes[lineNumber]
.elmement(1)
.component(0)
.toString()
);
else
return codes.map(code =>
getPriceType(
code
.element(1)
.component(0)
.toString()
)
);
};
// not on use
EDI.prototype.productsPriceTypeCode = function(lineNumber) {
const codes = this.segments("PRI");
if (lineNumber)
return getPriceTypeCode(
codes[lineNumber]
.elmement(1)
.component(0)
.toString()
);
else
return codes.map(code =>
getPriceTypeCode(
code
.element(1)
.component(0)
.toString()
)
);
};
// not on use
EDI.prototype.productsPriceSpecificationCode = function(lineNumber) {
const codes = this.segments("PRI");
if (lineNumber)
return getPriceSpecificationCode(
codes[lineNumber]
.elmement(1)
.component(0)
.toString()
);
else
return codes.map(code =>
getPriceSpecificationCode(
code
.element(1)
.component(0)
.toString()
)
);
};
EDI.prototype.productsPrice = function(lineNumber) {
const segments = this.segments("PRI");
if (lineNumber)
return segments[lineNumber]
.elmement(1)
.component(1)
.toString();
else
return segments.map(segment =>
segment
.element(1)
.component(1)
.toString()
);
};
/* product logic ends here */
EDI.prototype.summarySeparator = function() {
return this.segment("UNS").toString();
};
EDI.prototype.controlTotalType = function() {
const code = this.segment("CNT")
.element(1)
.component(0)
.toString();
return getControlTotalType(code);
};
EDI.prototype.controlTotal = function() {
return this.segment("CNT")
.element(1)
.component(1)
.toString();
};
EDI.prototype.segmentQty = function() {
return this.segment("UNT")
.element(1)
.component(0)
.toString();
};
EDI.prototype.documentEnd = function() {
return this.segment("UNZ")
.element(1)
.component(0)
.toString();
};
// Aliases
EDI.prototype.e = EDI.prototype.elem = EDI.prototype.element;
EDI.prototype.c = EDI.prototype.comp = EDI.prototype.component;
EDI.prototype.s = EDI.prototype.str = EDI.prototype.toString;
EDI.prototype.n = EDI.prototype.num = EDI.prototype.toNumber;
EDI.prototype.d = EDI.prototype.date = EDI.prototype.toDate;
exports = module.exports = EDI;