UNPKG

shift-admin-ui-kit

Version:
133 lines (111 loc) 4.51 kB
import Lazy from "lazy.js" export default class CsvValidator { constructor(csvString) { this.csvString = csvString } validate() { let lazyCsv = Lazy(this.csvString).split("\n") if (lazyCsv.drop(1).isEmpty()) { return "missing header or data" } let header = lazyCsv.take(1).toArray()[0].split(/\s*,\s*/) let validationErrors = this.validateHeader(header) if (validationErrors.length > 0) { return validationErrors } let headerData = this.createHeaderData(header) let error = lazyCsv .drop(1) // skip header .map((line, idx) => { return this.validateData(headerData, line, idx + 2) }) // map line to validation error if any .dropWhile((err) => { return err.length === 0 }) // drop valid lines .take(1) // stop on first invalid line .toArray()[0] return error || "" } validateHeader(header) { const standardHeader = ["sku", "stock_location_reference", "stock_allocated", "stock_on_hand"] let standardHeaderSet = new Set(standardHeader) let headerSet = new Set(header) let missing = standardHeader.filter(function(x) { return !headerSet.has(x) }) let unexpected = header.filter(function(x) { return !standardHeaderSet.has(x) }) let error_messages = [] if (missing.length > 0) { error_messages.push("missing header(s): " + missing.join()) } if (unexpected.length > 0) { error_messages.push("unexpected header(s): " + unexpected.join()) } return(error_messages.join()) } createHeaderData(header) { let data = { columnsCount: header.length } for (var i = 0; i < header.length; i++) { switch ( header[i] ) { case "sku": data.skuIndex = i break case "stock_location_reference": data.stockLocationReferenceIndex = i break case "stock_allocated": data.stockAllocatedIndex = i break case "stock_on_hand": data.stockOnHandIndex = i break } } return data } validateData(headerData, line, line_num) { let error_messages = [] let fields = line.split(",").map((field)=>{ return field.trim() }) // skip empty line if (fields.length === 1 && fields[0].length === 0) { return "" } if (fields.length !== headerData.columnsCount) { return "line " + line_num + ": columns count doesn't match header" } error_messages = this.validateLine(headerData, fields, line_num) return (error_messages.join()) } validateLine(headerData, fields, line_num) { let error_messages = [] // validate fields according to header data this.validateSku(fields[headerData.skuIndex], error_messages, line_num) this.validateStockLocationReference(fields[headerData.stockLocationReferenceIndex], error_messages, line_num) this.validateStockAllocated(fields[headerData.stockAllocatedIndex], error_messages, line_num) this.validateStockOnHand(fields[headerData.stockOnHandIndex], error_messages, line_num) this.validateStockOnHandAndStockAllocatedPresence(fields[headerData.stockAllocatedIndex], fields[headerData.stockOnHandIndex], error_messages, line_num) return(error_messages) } validateSku(sku_field, error_messages, line_num) { if (sku_field.length === 0) { error_messages.push("line " + line_num + ": missed sku") } } validateStockLocationReference(stock_location_reference, error_messages, line_num) { if (stock_location_reference.length === 0) { error_messages.push("line " + line_num + ": missed stock_location_reference") } } validateStockAllocated(stock_allocated_field, error_messages, line_num) { if (Number(stock_allocated_field) < 0) { error_messages.push("line " + line_num + ": negative stock_allocated") } } validateStockOnHand(stock_on_hand_field, error_messages, line_num) { if (Number(stock_on_hand_field) < 0) { error_messages.push("line " + line_num + ": negative stock_on_hand_field") } } validateStockOnHandAndStockAllocatedPresence(stock_allocated_field, stock_on_hand_field, error_messages, line_num) { if (stock_allocated_field.length === 0 && stock_on_hand_field.length === 0) { error_messages.push("line " + line_num + ": missed both stock_allocated and stock_on_hand") } } }