Files
PetitTeton/importSales.js

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)});
// };