416 lines
12 KiB
JavaScript
416 lines
12 KiB
JavaScript
|
|
var fs = require("fs");
|
|
var csv = require('./csv.js');
|
|
var Promise = require('bluebird');
|
|
|
|
var fileName = "./importSales.csv";
|
|
|
|
// module.exports = function(models, softErrors, handler) {
|
|
// return new Promise(function(resolve, reject) {
|
|
var models = require("./models");
|
|
var softErrors = [];
|
|
var p = new Promise(function(resolve, reject) {
|
|
//The CSV data as an array of rows (each row is an array).
|
|
var data;
|
|
//The mapping of model attributes to CSV columns. The oz sizes are arrays of columns since there are multiple.
|
|
var map = {};
|
|
|
|
//Database maps so we don't have to constantly query for the same data repeatedly.
|
|
var vendorIdMap = {};
|
|
var measureIdMap = {};
|
|
var itemIdMap = {};
|
|
|
|
//Collect the metadata from the first row of the CSV data - make a mapping.
|
|
function collectMetadata() {
|
|
var DATE = 'date';
|
|
var VENDOR = 'vendor';
|
|
var ITEM = 'item';
|
|
var OZ32 = '32 oz';
|
|
var OZ16 = '16 oz';
|
|
var OZ12 = '12 oz';
|
|
var OZ8 = '8 oz';
|
|
var OZ4 = '4 oz';
|
|
var BAGS = 'bags';
|
|
var EACH = 'each';
|
|
|
|
//Data is an array of arrays. data[0] = array of headers. data[1] = first row of data.
|
|
//Iterate over the columns to create a mapping.
|
|
for(var i = 0; i < data[0].length; i++) {
|
|
var next = data[0][i];
|
|
|
|
if(next && next != '') {
|
|
switch(next.toLowerCase()) {
|
|
case DATE:
|
|
map.date = i;
|
|
break;
|
|
case VENDOR:
|
|
map.vendor = i;
|
|
break;
|
|
case ITEM:
|
|
map.item = i;
|
|
break;
|
|
case OZ32:
|
|
map.oz32 = i;
|
|
break;
|
|
case OZ16:
|
|
map.oz16 = i;
|
|
break;
|
|
case OZ12:
|
|
map.oz12 = i;
|
|
break;
|
|
case OZ8:
|
|
map.oz8 = i;
|
|
break;
|
|
case OZ4:
|
|
map.oz4 = i;
|
|
break;
|
|
case BAGS:
|
|
map.bags = i;
|
|
break;
|
|
case EACH:
|
|
map.each = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//Reads a single row of CSV data and adds it to the database.
|
|
function readRow(rowIndex) {
|
|
if(!data) {
|
|
console.log("WTF?");
|
|
//process.exit(1);
|
|
reject(new Error("Data is null?!?"));
|
|
return;
|
|
}
|
|
else if(!data[rowIndex]) {
|
|
console.log("Empty line?");
|
|
readRow(rowIndex + 1);
|
|
return;
|
|
}
|
|
|
|
var date = data[rowIndex][map.date];
|
|
var vendor = data[rowIndex][map.vendor];
|
|
var item = data[rowIndex][map.item];
|
|
var oz32 = data[rowIndex][map.oz32];
|
|
var oz16 = data[rowIndex][map.oz16];
|
|
var oz12 = data[rowIndex][map.oz12];
|
|
var oz8 = data[rowIndex][map.oz8];
|
|
var oz4 = data[rowIndex][map.oz4];
|
|
var bags = data[rowIndex][map.bags];
|
|
var each = data[rowIndex][map.each];
|
|
|
|
var vendorId = vendorIdMap[vendor];
|
|
var itemId = itemIdMap[item];
|
|
var priceMap = {};
|
|
|
|
var saleQueries = [];
|
|
|
|
//TODO: Trim and lowercase any names.
|
|
priceMap[2016] = {
|
|
oz4: 7,
|
|
oz8: 11,
|
|
oz12: 13,
|
|
oz16: 11,
|
|
oz32: 15,
|
|
"pickled onion, spicy": {oz16: 12},
|
|
"pickled onion, sweet": {oz16: 12},
|
|
"pickled onion, fennel": {oz16: 12},
|
|
"pickled beets": {oz16: 15},
|
|
"prickly pear margarita mix": {oz16: 15},
|
|
"prickly pear syrup": {oz16: 15},
|
|
"tomato sauce": {oz16: 15}, //TODO: Replace all 'tomato sauce, xxxx' with 'tomato sauce' for price lookup only.
|
|
"bone broth": {oz16: 20}, //TODO: Replace all 'bone broth, xxxx' with 'bone broth' for price lookup only.
|
|
"fava bean soup": {oz32: 20},
|
|
"pickles, bread butter": {oz16: 11},
|
|
"kimchi": {oz16: 11},
|
|
"kraut - red & white": {oz16: 11},
|
|
|
|
"3 pack": {each: 21},
|
|
"espelette, smoked": {each: 1},
|
|
"leather": {each: 6},
|
|
"leather, apple": {each: 6},
|
|
"leather, grape": {each: 6},
|
|
"leather, peach": {each: 6},
|
|
"leather, persimmon": {each: 6},
|
|
"leather, pumpkin": {each: 6},
|
|
"leather, strawberry": {each: 6},
|
|
"leather, quince": {each: 6},
|
|
"membrillo": {each: 7},
|
|
"membrillo candy": {each: 2.5},
|
|
"spices": {each: 4},
|
|
"spices, basil/coriander": {each: 4},
|
|
"spices, fennel": {each: 4},
|
|
"spices, other": {each: 4},
|
|
"spices, pepper": {each: 4},
|
|
"spices, smoked": {each: 4},
|
|
|
|
"baba ganoush": {bag: 8, oz4: 8},
|
|
"dried, pear": {bag: 6}, //Price??
|
|
"dried, tomatillo": {bag: 6}, //Price??
|
|
"dried, strawberry": {bag: 7.5},
|
|
"dried, tomato": {bag: 7},
|
|
"pesto": {bags: 8},
|
|
"pesto, cilantro jalapeno": {bags: 8},
|
|
"pesto, eggplant": {bags: 8},
|
|
"pesto, mint": {bags: 8},
|
|
"pesto, jalapeno": {bags: 8},
|
|
"jalapeno candy": {bags: 5},
|
|
"tomato, dried": {bag: 7}, //Spelling??? Should be Dried, Tomato
|
|
|
|
|
|
//Fresh
|
|
"persimmons": {lbs: 5},
|
|
"persimmon, frozen": {lbs: 5},
|
|
"dried, persimmon": {lbs: 5},
|
|
|
|
"eggs": {each: 11}
|
|
};
|
|
|
|
priceMap[2015] = {
|
|
oz4: 6,
|
|
oz8: 10,
|
|
oz12: 13,
|
|
oz16: 10,
|
|
oz32: 15,
|
|
"blackberry jam": {oz4: 7, oz8: 12},
|
|
"raspberry jam": {oz4: 7, oz8: 12},
|
|
"blackberry vanilla": {oz4: 7, oz8: 12},
|
|
"bloody mary mix": {oz16: 13},
|
|
"pickled beets": {oz16: 15},
|
|
"tomato juice cocktail": {oz16: 8},
|
|
"fava bean soup": {oz32: 20},
|
|
"kimchi": {oz16: 10},
|
|
"kraut - red & white": {oz16: 10},
|
|
"bread & butter pickles": {oz16: 10},
|
|
"pickled eggs": {oz16: 15},
|
|
|
|
"3 pack": {each: 18},
|
|
"leather": {each: 6},
|
|
"leather, apple": {each: 6},
|
|
"leather, grape": {each: 6},
|
|
"leather, peach": {each: 6},
|
|
"leather, persimmon": {each: 6},
|
|
"leather, pumpkin": {each: 6},
|
|
"leather, strawberry": {each: 6},
|
|
"leather, quince": {each: 6},
|
|
"membrillo": {each: 6},
|
|
"membrillo candy": {each: 2.5},
|
|
"popsicles": {each: 5},
|
|
"spices": {each: 4},
|
|
"spices, basil/coriander": {each: 4},
|
|
"spices, fennel": {each: 4},
|
|
"spices, other": {each: 4},
|
|
"spices, pepper": {each: 4},
|
|
"spices, smoked": {each: 4},
|
|
|
|
"baba ganoush": {bag: 8, oz4: 8},
|
|
"dried, pear": {bag: 6}, //Price??
|
|
"dried, tomatillo": {bag: 6}, //Price??
|
|
"dried, strawberry": {bag: 7.5},
|
|
"dried, tomato": {bag: 7},
|
|
"jalapeno candy": {bag: 5},
|
|
|
|
"eggs": {each: 10},
|
|
};
|
|
|
|
//Log errors, but keep on chugging.
|
|
if(vendorId == undefined) {
|
|
softErrors.push("ERROR: Unexpected vendor: " + vendor);
|
|
}
|
|
else if(itemId == undefined) {
|
|
softErrors.push("ERROR: Unexpected item: " + item);
|
|
}
|
|
else {
|
|
//Split it into multiple sales entries, one for each measure that has a positive value.
|
|
if(oz32 > 0) {
|
|
var measureId = measureIdMap['32 oz'];
|
|
var price = priceMap[year][item];
|
|
|
|
if(price == undefined) {
|
|
price = priceMap[year]['oz32'];
|
|
}
|
|
|
|
saleQueries.push(models.Sale.create({date: date, vendorId: vendorId, itemId: itemId, measureId: measureId, amount: oz32, price: price}));
|
|
}
|
|
|
|
if(oz16 > 0) {
|
|
var measureId = measureIdMap['16 oz'];
|
|
var price = priceMap[year][item];
|
|
|
|
if(price == undefined) {
|
|
price = priceMap[year]['oz16'];
|
|
}
|
|
|
|
saleQueries.push(models.Sale.create({date: date, vendorId: vendorId, itemId: itemId, measureId: measureId, amount: oz32, price: price}));
|
|
}
|
|
|
|
if(oz12 > 0) {
|
|
var measureId = measureIdMap['12 oz'];
|
|
var price = priceMap[year][item];
|
|
|
|
if(price == undefined) {
|
|
price = priceMap[year]['oz12'];
|
|
}
|
|
|
|
saleQueries.push(models.Sale.create({date: date, vendorId: vendorId, itemId: itemId, measureId: measureId, amount: oz32, price: price}));
|
|
}
|
|
|
|
if(oz8 > 0) {
|
|
var measureId = measureIdMap['8 oz'];
|
|
var price = priceMap[year][item];
|
|
|
|
if(price == undefined) {
|
|
price = priceMap[year]['oz8'];
|
|
}
|
|
|
|
saleQueries.push(models.Sale.create({date: date, vendorId: vendorId, itemId: itemId, measureId: measureId, amount: oz32, price: price}));
|
|
}
|
|
|
|
if(oz4 > 0) {
|
|
var measureId = measureIdMap['4 oz'];
|
|
var price = priceMap[year][item];
|
|
|
|
if(price == undefined) {
|
|
price = priceMap[year]['oz4'];
|
|
}
|
|
|
|
saleQueries.push(models.Sale.create({date: date, vendorId: vendorId, itemId: itemId, measureId: measureId, amount: oz32, price: price}));
|
|
}
|
|
|
|
if(bags > 0) {
|
|
var measureId = measureIdMap['bags'];
|
|
var price = priceMap[year][item];
|
|
|
|
if(price == undefined) {
|
|
price = priceMap[year]['bags'];
|
|
}
|
|
|
|
saleQueries.push(models.Sale.create({date: date, vendorId: vendorId, itemId: itemId, measureId: measureId, amount: oz32, price: price}));
|
|
}
|
|
|
|
if(each > 0) {
|
|
var measureId = measureIdMap['each'];
|
|
var price = priceMap[year][item];
|
|
|
|
if(price == undefined) {
|
|
price = priceMap[year]['each'];
|
|
}
|
|
|
|
saleQueries.push(models.Sale.create({date: date, vendorId: vendorId, itemId: itemId, measureId: measureId, amount: oz32, price: price}));
|
|
}
|
|
|
|
Promise.each(saleQueries, function(value, index, length) {
|
|
//Ignored.
|
|
}).then(function(result) {
|
|
//Recursively read rows until there are no more rows to read.
|
|
if(rowIndex + 1 < data.length) readRow(rowIndex + 1);
|
|
else resolve();
|
|
});
|
|
}
|
|
}
|
|
|
|
if(fs.existsSync(fileName)) {
|
|
csv.read(fileName, function(error, csvData) {
|
|
if(error) console.log(error);
|
|
else {
|
|
data = csvData;
|
|
//Collect the mapping data.
|
|
collectMetadata();
|
|
|
|
//Read or create the required models to make this all work:
|
|
Promise.each([
|
|
//Measures 1-6
|
|
models.Measure.find({where: {name: 'Jar 32oz'}}),
|
|
models.Measure.find({where: {name: 'Jar 16oz'}}),
|
|
models.Measure.find({where: {name: 'Jar 12oz'}}),
|
|
models.Measure.find({where: {name: 'Jar 8oz'}}),
|
|
models.Measure.find({where: {name: 'Jar 4oz'}}),
|
|
models.Measure.find({where: {name: 'Each'}}),
|
|
models.Measure.find({where: {name: 'Bags'}}),
|
|
//Vendors 7-16
|
|
models.Venue.find({where: {name: 'Boonville'}}),
|
|
models.Venue.find({where: {name: 'Clement St'}}),
|
|
models.Venue.find({where: {name: 'Ukiah'}}),
|
|
models.Venue.find({where: {name: 'Mendocino'}}),
|
|
models.Venue.find({where: {name: 'Ft Bragg'}}),
|
|
models.Venue.find({where: {name: 'On Farm'}}),
|
|
models.Venue.find({where: {name: 'Unknown Restaurant'}}),
|
|
models.Venue.find({where: {name: 'Yorkville Market'}}),
|
|
models.Venue.find({where: {name: 'Yorkville Cellars'}}),
|
|
models.Venue.find({where: {name: 'Mail Order'}}),
|
|
//Items
|
|
models.Item.findAll()
|
|
], function(value, index, length) {
|
|
switch(index) {
|
|
case 0:
|
|
measureIdMap['32 oz'] = value.id;
|
|
break;
|
|
case 1:
|
|
measureIdMap['16 oz'] = value.id;
|
|
break;
|
|
case 2:
|
|
measureIdMap['12 oz'] = value.id;
|
|
break;
|
|
case 3:
|
|
measureIdMap['8 oz'] = value.id;
|
|
break;
|
|
case 4:
|
|
measureIdMap['4 oz'] = value.id;
|
|
break;
|
|
case 5:
|
|
measureIdMap['each'] = value.id;
|
|
break;
|
|
case 6:
|
|
measureIdMap['bags'] = value.id;
|
|
break;
|
|
case 7:
|
|
vendorIdMap['bv'] = value.id;
|
|
break;
|
|
case 8:
|
|
vendorIdMap['sf'] = value.id;
|
|
break;
|
|
case 9:
|
|
vendorIdMap['uk'] = value.id;
|
|
break;
|
|
case 10:
|
|
vendorIdMap['men'] = value.id;
|
|
break;
|
|
case 11:
|
|
vendorIdMap['fb'] = value.id;
|
|
break;
|
|
case 12:
|
|
vendorIdMap['of'] = value.id;
|
|
break;
|
|
case 13:
|
|
vendorIdMap['res'] = value.id;
|
|
break;
|
|
case 14:
|
|
vendorIdMap['ym'] = value.id;
|
|
break;
|
|
case 15:
|
|
vendorIdMap['yc'] = value.id;
|
|
break;
|
|
case 16:
|
|
vendorIdMap['mo'] = value.id;
|
|
break;
|
|
case 17:
|
|
//Iterate over all the items and setup the itemIdMap to reference the item id given the item name. Item names are unique.
|
|
for(var i = 0; i < value.length; i++) {
|
|
itemIdMap[value[i].name] = value[i].id;
|
|
}
|
|
}
|
|
}).then(function() {
|
|
//Read the first row.
|
|
readRow(1);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
else {
|
|
console.log("Cannot find " + fileName);
|
|
}
|
|
});
|
|
|
|
p.then(function() {console.log("Import Complete!")}).error(function(error) {console.log("Ran into an error: \n" + error)});
|
|
// };
|