Initial commit. Modified the Meteor todos app to create the Petit Teton data tracking app. Has working data for sales. Requires a Mongo database.
This commit is contained in:
829
server/import.js
Normal file
829
server/import.js
Normal file
@@ -0,0 +1,829 @@
|
||||
import readCSV from '/imports/util/csv.js';
|
||||
|
||||
//Returns the ID of the created or found object.
|
||||
//This is needed because for some crazy reason upsert only returns the affected document if a document is inserted, otherwise it does not return the ID of the affected document.
|
||||
function insertOrCreate(collection, selector, object) {
|
||||
let id;
|
||||
|
||||
let findResult = collection.findOne(selector, {fields: {_id: 1}});
|
||||
|
||||
if(findResult && findResult._id) id = findResult._id;
|
||||
else id = collection.insert(object);
|
||||
|
||||
//
|
||||
// let result = collection.upsert(selector, {$setOnInsert: object}, {multi: false});
|
||||
//
|
||||
// console.log("Upsert result: " + JSON.stringify(result));
|
||||
//
|
||||
// if(result && result.insertedId) id = result.insertedId;
|
||||
// else id = collection.findOne(selector, {fields: {_id: 1}});
|
||||
|
||||
if(!id) {
|
||||
console.log("ERROR: Cannot get the ID for " + JSON.stringify(selector));
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
Meteor.methods({
|
||||
"importBasics": function() {
|
||||
const measures = [
|
||||
{name: "Jar 4oz", postfix: "4oz", order: 0, createdAt: new Date()},
|
||||
{name: "Jar 8oz", postfix: "8oz", order: 1, createdAt: new Date()},
|
||||
{name: "Jar 12oz", postfix: "12oz", order: 2, createdAt: new Date()},
|
||||
{name: "Jar 16oz", postfix: "16oz", order: 3, createdAt: new Date()},
|
||||
{name: "Jar 32oz", postfix: "32oz", order: 4, createdAt: new Date()},
|
||||
{name: "Pounds", postfix: "lbs", order: 5, createdAt: new Date()},
|
||||
{name: "Each", postfix: "", order: 6, createdAt: new Date()},
|
||||
{name: "Bags", postfix: "bags", order: 7, createdAt: new Date()},
|
||||
{name: "Dozen Large", postfix: "12/lg", order: 8, createdAt: new Date()},
|
||||
{name: "Dozen Small", postfix: "12/sm", order: 9, createdAt: new Date()},
|
||||
{name: "Half Dozen Large", postfix: "6/lg", order: 10, createdAt: new Date()},
|
||||
{name: "Half Dozen Small", postfix: "6/sm", order: 11, createdAt: new Date()}
|
||||
];
|
||||
const venues = [
|
||||
{name: "Boonville", type: "Farmer's Market", createdAt: new Date()},
|
||||
{name: "Clement St", type: "Farmer's Market", createdAt: new Date()},
|
||||
{name: "Ukiah", type: "Farmer's Market", createdAt: new Date()},
|
||||
{name: "Mendocino", type: "Farmer's Market", createdAt: new Date()},
|
||||
{name: "Ft Bragg", type: "Farmer's Market", createdAt: new Date()},
|
||||
{name: "On Farm", type: "Retail", createdAt: new Date()},
|
||||
{name: "Yorkville Market", type: "Retail", createdAt: new Date()},
|
||||
{name: "Yorkville Cellars", type: "Retail", createdAt: new Date()},
|
||||
{name: "Unknown Restaurant", type: "Restaurant", createdAt: new Date()},
|
||||
{name: "Mail Order", type: "Mail", createdAt: new Date()},
|
||||
{name: "Website Order", type: "Mail", createdAt: new Date()}
|
||||
];
|
||||
|
||||
Measures.remove({});
|
||||
Venues.remove({});
|
||||
|
||||
for(let next of measures) {
|
||||
Measures.insert(next, function(error, _id) {
|
||||
if(error) console.log("Failed to insert measure: " + JSON.stringify(next) + " ERROR: " + error);
|
||||
});
|
||||
}
|
||||
|
||||
for(let next of venues) {
|
||||
Venues.insert(next, function(error, _id) {
|
||||
if(error) console.log("Failed to insert venue: " + JSON.stringify(next) + " ERROR: " + error);
|
||||
});
|
||||
}
|
||||
},
|
||||
"importItems": function() {
|
||||
let fileName = "importItems.csv";
|
||||
//The mapping of model attributes to CSV columns. The oz sizes are arrays of columns since there are multiple.
|
||||
let map = {};
|
||||
//The id's in the db for the letious jar sizes.
|
||||
let measureIdMap = {};
|
||||
let hasError = false;
|
||||
|
||||
{
|
||||
let result;
|
||||
|
||||
result = Measures.findOne({name: 'Jar 4oz'}, {fields: {_id: 1}});
|
||||
if(result) measureIdMap['4oz'] = result._id;
|
||||
else {console.log("Error: Couldn't find the _id for Jar 4oz"); hasError = true;}
|
||||
|
||||
result = Measures.findOne({name: 'Jar 8oz'}, {fields: {_id: 1}});
|
||||
if(result) measureIdMap['8oz'] = result._id;
|
||||
else {console.log("Error: Couldn't find the _id for Jar 8oz"); hasError = true;}
|
||||
|
||||
result = Measures.findOne({name: 'Jar 12oz'}, {fields: {_id: 1}});
|
||||
if(result) measureIdMap['12oz'] = result._id
|
||||
else {console.log("Error: Couldn't find the _id for Jar 12oz"); hasError = true;}
|
||||
|
||||
result = Measures.findOne({name: 'Jar 16oz'}, {fields: {_id: 1}});
|
||||
if(result) measureIdMap['16oz'] = result._id;
|
||||
else {console.log("Error: Couldn't find the _id for Jar 16oz"); hasError = true;}
|
||||
|
||||
result = Measures.findOne({name: 'Jar 32oz'}, {fields: {_id: 1}});
|
||||
if(result) measureIdMap['32oz'] = result._id;
|
||||
else {console.log("Error: Couldn't find the _id for Jar 32oz"); hasError = true;}
|
||||
|
||||
result = Measures.findOne({name: 'Each'}, {fields: {_id: 1}});
|
||||
if(result) measureIdMap['Each'] = result._id;
|
||||
else {console.log("Error: Couldn't find the _id for Each"); hasError = true;}
|
||||
|
||||
result = Measures.findOne({name: 'Bags'}, {fields: {_id: 1}});
|
||||
if(result) measureIdMap['Bags'] = result._id;
|
||||
else {console.log("Error: Couldn't find the _id for Bags"); hasError = true;}
|
||||
}
|
||||
|
||||
// console.log("MeasureIdMap: " + JSON.stringify(measureIdMap));
|
||||
|
||||
//Don't proceed if the necessary measures don't exist.
|
||||
if(!hasError) {
|
||||
//Collect the metadata from the first row of the CSV data - make a mapping.
|
||||
function collectMetadata(firstRow) {
|
||||
const CATEGORY = 'category';
|
||||
const SUBCATEGORY = 'subcategory';
|
||||
const ITEM = 'item';
|
||||
const OZ32 = '32 oz';
|
||||
const OZ16 = '16 oz';
|
||||
const OZ12 = '12 oz';
|
||||
const OZ8 = '8 oz';
|
||||
const OZ4 = '4 oz';
|
||||
const BAGS = 'bags';
|
||||
const EACH = 'each';
|
||||
|
||||
map.oz32 = [];
|
||||
map.oz16 = [];
|
||||
map.oz12 = [];
|
||||
map.oz8 = [];
|
||||
map.oz4 = [];
|
||||
map.bags = [];
|
||||
map.each = [];
|
||||
|
||||
//Data is an array of arrays. firstRow = array of headers. data[1] = first row of data.
|
||||
//Iterate over the columns to create a mapping.
|
||||
for(let i = 0; i < firstRow.length; i++) {
|
||||
let next = firstRow[i];
|
||||
|
||||
if(next && next != '') {
|
||||
switch(next.toLowerCase()) {
|
||||
case CATEGORY:
|
||||
map.category = i;
|
||||
break;
|
||||
case SUBCATEGORY:
|
||||
map.subcategory = i;
|
||||
break;
|
||||
case ITEM:
|
||||
map.item = i;
|
||||
break;
|
||||
case OZ32:
|
||||
map.oz32.push(i);
|
||||
break;
|
||||
case OZ16:
|
||||
map.oz16.push(i);
|
||||
break;
|
||||
case OZ12:
|
||||
map.oz12.push(i);
|
||||
break;
|
||||
case OZ8:
|
||||
map.oz8.push(i);
|
||||
break;
|
||||
case OZ4:
|
||||
map.oz4.push(i);
|
||||
break;
|
||||
case BAGS:
|
||||
map.bags.push(i);
|
||||
break;
|
||||
case EACH:
|
||||
map.each.push(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Reads a single row of CSV data and adds it to the database.
|
||||
function readRow(row) {
|
||||
let category = row[map.category].trim();
|
||||
let subcategory = row[map.subcategory].trim();
|
||||
let item = row[map.item];
|
||||
let oz32 = 0;
|
||||
let oz16 = 0;
|
||||
let oz12 = 0;
|
||||
let oz8 = 0;
|
||||
let oz4 = 0;
|
||||
let bags = 0;
|
||||
let each = 0;
|
||||
|
||||
for(let o = 0; o < map.oz32.length; o++) {
|
||||
oz32 += Math.max(row[map.oz32[o]], 0);
|
||||
}
|
||||
|
||||
for(let o = 0; o < map.oz16.length; o++) {
|
||||
oz16 += Math.max(row[map.oz16[o]], 0);
|
||||
}
|
||||
|
||||
for(let o = 0; o < map.oz12.length; o++) {
|
||||
oz12 += Math.max(row[map.oz12[o]], 0);
|
||||
}
|
||||
|
||||
for(let o = 0; o < map.oz8.length; o++) {
|
||||
oz8 += Math.max(row[map.oz8[o]], 0);
|
||||
}
|
||||
|
||||
for(let o = 0; o < map.oz4.length; o++) {
|
||||
oz4 += Math.max(row[map.oz4[o]], 0);
|
||||
}
|
||||
|
||||
for(let o = 0; o < map.bags.length; o++) {
|
||||
bags += Math.max(row[map.bags[o]], 0);
|
||||
}
|
||||
|
||||
for(let o = 0; o < map.each.length; o++) {
|
||||
each += Math.max(row[map.each[o]], 0);
|
||||
}
|
||||
|
||||
// categoryId = insertOrCreate(Categories, {name: category}, {name: category, createdAt: new Date()});
|
||||
categoryId = insertOrCreate(ProductTags, {name: category}, {name: category, createdAt: new Date()});
|
||||
|
||||
if(categoryId) {
|
||||
// subcategoryId = insertOrCreate(Subcategories, {name: subcategory}, {
|
||||
// name: subcategory,
|
||||
// categoryId: categoryId,
|
||||
// createdAt: new Date()
|
||||
// });
|
||||
subcategoryId = insertOrCreate(ProductTags, {name: subcategory}, {name: subcategory, createdAt: new Date()});
|
||||
|
||||
if(subcategoryId) {
|
||||
let weightedMeasures = [];
|
||||
let measures = [];
|
||||
|
||||
if(oz32 > 0) weightedMeasures.push({name: '32oz', count: oz32});
|
||||
if(oz16 > 0) weightedMeasures.push({name: '16oz', count: oz16});
|
||||
if(oz12 > 0) weightedMeasures.push({name: '12oz', count: oz12});
|
||||
if(oz8 > 0) weightedMeasures.push({name: '8oz', count: oz8});
|
||||
if(oz4 > 0) weightedMeasures.push({name: '4oz', count: oz4});
|
||||
if(bags > 0) weightedMeasures.push({name: 'bags', count: bags});
|
||||
if(each > 0) weightedMeasures.push({name: 'each', count: each});
|
||||
|
||||
if(weightedMeasures.length == 0) {
|
||||
measures.push(measureIdMap['Each']);
|
||||
}
|
||||
else {
|
||||
//Place the measure that had the most jars at the front of the list.
|
||||
weightedMeasures.sort(function(a, b) {
|
||||
return a.count >= b.count ? 1 : -1;
|
||||
});
|
||||
|
||||
//Build the array of measure id's.
|
||||
for(let i = 0; i < weightedMeasures.length; i++) {
|
||||
measures.push(measureIdMap[weightedMeasures[i].name]);
|
||||
}
|
||||
}
|
||||
|
||||
//Here we can just insert since we don't care about the resulting ID.
|
||||
let obj = {name: item, tags: [categoryId, subcategoryId], measures: measures, createdAt: new Date()};
|
||||
Products.insert(obj, function(error) {
|
||||
if(error) console.log("Could not insert the Product: " + JSON.stringify(obj) + "\n ERROR: " + error);
|
||||
});
|
||||
}
|
||||
else {
|
||||
console.log("SubcategoryID: " + subcategoryId);
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.log("CategoryID: " + categoryId);
|
||||
}
|
||||
}
|
||||
|
||||
readCSV(fileName, Meteor.bindEnvironment(function(error, data) {
|
||||
//csv.read(fileName, function(error, csvData) {
|
||||
if(error) console.log("Unable to read the importItems.csv file:" + error);
|
||||
else {
|
||||
//Collect the mapping data.
|
||||
collectMetadata(data[0]);
|
||||
|
||||
//Remove everything first.
|
||||
// Items.remove({});
|
||||
// Subcategories.remove({});
|
||||
// Categories.remove({});
|
||||
Products.remove({});
|
||||
|
||||
// console.log("CSV Column Mapping: " + JSON.stringify(map));
|
||||
// readRow(data[1]);
|
||||
|
||||
for(let i = 1; i < data.length; i++) {
|
||||
readRow(data[i]);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
},
|
||||
"importSales": function() {
|
||||
let fileName = "importSales.csv";
|
||||
//The mapping of model attributes to CSV columns. The oz sizes are arrays of columns since there are multiple.
|
||||
let map = {};
|
||||
//The id's in the db for the letious jar sizes.
|
||||
let measureIdMap = {};
|
||||
let venueIdMap = {};
|
||||
let itemIdMap = {};
|
||||
let hasError = false;
|
||||
let priceMap = {};
|
||||
let itemAliases = {};
|
||||
|
||||
//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},
|
||||
|
||||
"3packs": {each: 21},
|
||||
"espelette, smoked": {each: 1},
|
||||
"leather": {each: 6},
|
||||
"leather, unspecified": {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, unspecified": {each: 4},
|
||||
"spices, basil/corriander": {each: 4},
|
||||
"spices, fennel": {each: 4},
|
||||
"spices, other": {each: 4},
|
||||
"spices, pepper": {each: 4},
|
||||
"spices, smoked": {each: 4},
|
||||
|
||||
"baba ganoush": {bags: 8, oz4: 8},
|
||||
"dried, pear": {bags: 6}, //Price??
|
||||
"dried, tomatillo": {bags: 6}, //Price??
|
||||
"dried, strawberry": {bags: 7.5},
|
||||
"pesto": {bags: 8, each: 8},
|
||||
"pesto, cilantro jalapeno": {bags: 8, each: 8},
|
||||
"pesto, eggplant": {bags: 8, each: 8},
|
||||
"pesto, mint": {bags: 8, each: 8},
|
||||
"pesto, jalapeno": {bags: 8, each: 8},
|
||||
"jalapeno candy": {bags: 5},
|
||||
"dried, tomato": {bags: 7},
|
||||
"tomato, dried": {bags: 7},
|
||||
"dried tomato": {bags: 7},
|
||||
|
||||
"chipotle peppers": {each: 5, bags: 5},
|
||||
|
||||
//Fresh
|
||||
"persimmons": {lbs: 5, bags: 5},
|
||||
"persimmon, frozen": {lbs: 5, bags: 5},
|
||||
"dried, persimmon": {lbs: 5, bags: 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},
|
||||
|
||||
"3packs": {each: 18},
|
||||
"leather": {each: 6},
|
||||
"leather, unspecified": {each: 6},
|
||||
"leather, apple": {each: 6},
|
||||
"leather, grape": {each: 6},
|
||||
"leather, peach": {each: 6},
|
||||
"leather, persimmon": {each: 6},
|
||||
"leather, pumpkin": {each: 6, bags: 6},
|
||||
"leather, strawberry": {each: 6, bags: 6},
|
||||
"leather, quince": {each: 6},
|
||||
"membrillo": {each: 6},
|
||||
"membrillo candy": {each: 2.5, bags: 2.5},
|
||||
"popsicles": {each: 5, bags: 5},
|
||||
"spices": {each: 4},
|
||||
"spices, unspecified": {each: 4},
|
||||
"spices, basil/corriander": {each: 4},
|
||||
"spices, fennel": {each: 4},
|
||||
"spices, other": {each: 4},
|
||||
"spices, pepper": {each: 4},
|
||||
"spices, smoked": {each: 4},
|
||||
"spices, smoked pepper": {each: 4},
|
||||
|
||||
"pesto, mint": {each: 7, bags: 7},
|
||||
"pesto, garlic scape": {each: 7, bags: 7},
|
||||
"pesto, eggplant": {each: 7, bags: 7},
|
||||
|
||||
"jalapenos": {each: 5, bags: 5}, //? Price guess - only one entry
|
||||
"membrillo truffles": {each: 5, bags: 5}, //? Price guess - only two entries
|
||||
|
||||
"baba ganoush": {bags: 8, oz4: 8},
|
||||
"dried, pear": {bags: 6}, //Price??
|
||||
"dried, tomatillo": {bags: 6}, //Price??
|
||||
"dried, strawberry": {bags: 7.5, each: 7.5},
|
||||
"dried, tomato": {bags: 7},
|
||||
"dried tomato": {bags: 7},
|
||||
"jalapeno candy": {bags: 5, each: 5},
|
||||
|
||||
"eggs": {each: 10},
|
||||
};
|
||||
|
||||
priceMap[2014] = {
|
||||
oz4: 6,
|
||||
oz8: 9,
|
||||
oz12: 13,
|
||||
oz16: 13,
|
||||
oz32: 20,
|
||||
"3packs": {bags: 18, each: 18}, //????
|
||||
"kimchi": {oz16: 10},
|
||||
"krauts" : {oz16: 10},
|
||||
"pickled eggs": {oz16: 13},
|
||||
|
||||
"jalapeno candy": {bags: 5}, //? Price guess
|
||||
|
||||
"eggs": {each: 7}
|
||||
};
|
||||
|
||||
itemAliases["3 packs"] = "3packs";
|
||||
itemAliases["3 pack"] = "3packs";
|
||||
itemAliases["3pack"] = "3packs";
|
||||
itemAliases["Salsa Hot"] = "Salsa, Hot";
|
||||
itemAliases["Sweet Spicy Dipping"] = "Sweet Spicy Dipping Sauce";
|
||||
itemAliases["Spiced Seckel Jam"] = "Pear Jam, Seckel";
|
||||
itemAliases["Spiced Seckle Pear Jam"] = "Pear Jam, Seckel";
|
||||
itemAliases["Spices, Smoked"] = "Spices, Smoked Pepper";
|
||||
itemAliases["Sweet Sour Cabbage"] = "Sweet Sour Red Cabbage";
|
||||
itemAliases["Pickled Onion, Pepper"] = "Pickled Onions (sweet)";
|
||||
itemAliases["Pickled Onion, Spicy"] = "Pickled Onion Dill w/Espelette";
|
||||
itemAliases["Pickled Onion, hot pep"] = "Pickled Onion Dill w/Espelette";
|
||||
itemAliases["Shrub Samplers"] = "Shrubs";
|
||||
itemAliases["Shrub, Anise Hyssop"] = "Shrubs";
|
||||
itemAliases["Shrub, Basil"] = "Shrubs";
|
||||
itemAliases["Shrub, Strawberry Bals"] = "Shrubs";
|
||||
itemAliases["Shrub, Tayberry"] = "Shrubs";
|
||||
itemAliases["Tomato Sauce"] = "Tomato Sauce, Basil";
|
||||
itemAliases["Pickled Onion Hot Pepper"] = "Pickled Onion Dill w/Espelette";
|
||||
itemAliases["Applesauce Honey"] = "Applesauce, Honey";
|
||||
itemAliases["Applesauce Cinnamon"] = "Applesauce, Cinnamon";
|
||||
itemAliases["Applesauce Unsweet"] = "Applesauce, Unsweetened";
|
||||
itemAliases["Applesauce, Unsweet"] = "Applesauce, Unsweetened";
|
||||
itemAliases["Babcock Ginger Jam"] = "Peach Jam, Babcock w/ Ginger";
|
||||
itemAliases["Babcock Lavendar Jam"] = "Peach Jam, Babcock w/ Lavender";
|
||||
itemAliases["Babcock Peach Jam"] = "Peach Jam, Babcock";
|
||||
itemAliases["Bartlett Pear Jam, Vanilla"] = "Bartlett Vanilla Jam";
|
||||
itemAliases["Bartlett Pear Vanilla Jam"] = "Bartlett Vanilla Jam";
|
||||
itemAliases["Blackberry Jam, Mint"] = "Blackberry Mint Jam";
|
||||
itemAliases["Bloody Mary"] = "Bloody Mary Mix";
|
||||
itemAliases["Bread Butter Pickles"] = "Pickles, Bread Butter";
|
||||
itemAliases["Chow Chow Hot"] = "Chow Chow Spicy";
|
||||
itemAliases["Chow Chow, Mild"] = "Chow Chow Mild";
|
||||
itemAliases["Chow Chow, Spicy"] = "Chow Chow Spicy";
|
||||
itemAliases["Chow chow Hot"] = "Chow Chow Spicy";
|
||||
itemAliases["Comice Sherry Jam"] = "Comice Pear Jam w/ Sherry";
|
||||
itemAliases["Dill Pickles"] = "Pickles, Dill";
|
||||
itemAliases["Dried Pear"] = "Dried, Pear";
|
||||
itemAliases["Dried Tomatillo"] = "Dried, Tomatillo";
|
||||
itemAliases["Dried, Tomato"] = "Dried Tomato";
|
||||
itemAliases["Eggplant Pesto"] = "Pesto, Eggplant";
|
||||
itemAliases["Fennel Pickles"] = "Pickles, Fennel";
|
||||
itemAliases["Fig Port Jam"] = "Fig Jam, Port";
|
||||
itemAliases["French Apple Jam"] = "Apple Jam, French";
|
||||
itemAliases["Garlic Scape Pesto"] = "Pesto, Garlic Scape";
|
||||
itemAliases["Ginger Garlic Pickles"] = "Pickles, Ginger Garlic";
|
||||
itemAliases["Green Gage Ginger Jam"] = "Green Gage Jam w/ Ginger";
|
||||
itemAliases["Jujube Ginger Butter"] = "Jujube & Ginger Butter";
|
||||
itemAliases["Leather"] = "Leather, Unspecified";
|
||||
itemAliases["Leek Potato Soup"] = "Leek & Potato Soup";
|
||||
itemAliases["Mint Pesto"] = "Pesto, Mint";
|
||||
itemAliases["Napa Kraut Onion"] = "Napa Kraut, Onion";
|
||||
itemAliases["Peach Jam, Babcock Ginger"] = "Peach Jam, Babcock w/ Ginger";
|
||||
itemAliases["Peach Jam, Babcock Lavender"] = "Peach Jam, Babcock w/ Lavender";
|
||||
itemAliases["Pear Dessert Sauce"] = "Pear Dessert Topping";
|
||||
itemAliases["Pear Ginger Preserve"] = "Pear Ginger Preserves";
|
||||
itemAliases["Pear Jam, Bosc"] = "Bosc Pear Jam";
|
||||
itemAliases["Pear Jam, Comice"] = "Comice Pear Jam";
|
||||
itemAliases["Pear Jam, Sherry"] = "Comice Pear Jam w/ Sherry";
|
||||
itemAliases["Pepper Relish, Spicy"] = "Spicy Pepper Relish";
|
||||
itemAliases["Pepper Relish, Sweet"] = "Sweet Pepper Relish";
|
||||
itemAliases["Pickled Onion Fennel"] = "Pickled Onions Fennel";
|
||||
itemAliases["Pickled Onion, Fennel"] = "Pickled Onions Fennel";
|
||||
itemAliases["Pickled Onion, Sweet"] = "Pickled Onions (sweet)";
|
||||
itemAliases["Pickled Onion, Sweet Pep"] = "Pickled Onions (sweet)";
|
||||
itemAliases["Pickled Onion, Sweet Pepper"] = "Pickled Onions (sweet)";
|
||||
itemAliases["Pickles w/ Fennel"] = "Pickles, Fennel";
|
||||
itemAliases["Plum Jam, Wild"] = "Wild Plum Jam";
|
||||
itemAliases["Plum Syrup, Wild"] = "Wild Plum Syrup";
|
||||
itemAliases["Pumpkin Rollup"] = "Leather, Pumpkin";
|
||||
itemAliases["Rubarb Jam"] = "Rhubarb Jam";
|
||||
itemAliases["Santa Rosa Plum Jam"] = "Plum Jam, Santa Rosa";
|
||||
itemAliases["Saturn Peach Jam"] = "Peach Jam, Saturn";
|
||||
itemAliases["Sauerkraut Red"] = "Sauerkraut, Red";
|
||||
itemAliases["Seckel Pear Jam"] = "Pear Jam, Seckel";
|
||||
itemAliases["Spiced Plum Jam"] = "Plum Jam, Spiced";
|
||||
itemAliases["Spices"] = "Spices, Unspecified";
|
||||
itemAliases["Spices, Basil/Coriander"] = "Spices, Basil/Corriander";
|
||||
itemAliases["Spices, Other"] = "Spices, Unspecified";
|
||||
itemAliases["Strawberry Lavendar Jam"] = "Strawberry Lavender Jam";
|
||||
itemAliases["Sz Broccoli"] = "Szechuan Broccoli";
|
||||
itemAliases["Tomato Sauce Basil"] = "Tomato Sauce, Basil";
|
||||
itemAliases["Tomato Sauce Fennel"] = "Tomato Sauce, Fennel";
|
||||
itemAliases["Tomato Sauce Oregano"] = "Tomato Sauce, Oregano";
|
||||
itemAliases["Tomato, Dried"] = "Dried Tomato";
|
||||
itemAliases["Tomato, dried"] = "Dried Tomato";
|
||||
itemAliases["White Grape Jam"] = "Grape Jam, White";
|
||||
itemAliases["Pepper Syrup"] = "Spicy Pepper Syrup";
|
||||
itemAliases["Apple Prickly Pear"] = "Applesauce, Prickly Pear";
|
||||
itemAliases["Babcock Peach Chutney"] = "Peach Chutney, Babcock";
|
||||
itemAliases["Blackberry Conserve"] = "Blackberry Hazelnut Conserve";
|
||||
itemAliases["Bread Butter Armenian"] = "Pickles, Bread Butter Armenian";
|
||||
itemAliases["Currant Jam"] = "White Currant Jam";
|
||||
|
||||
{ //Load the object ids for the measures and venues we will encounter.
|
||||
let result;
|
||||
|
||||
result = Measures.findOne({name: 'Jar 4oz'}, {fields: {_id: 1}});
|
||||
if(result) measureIdMap['4oz'] = result._id;
|
||||
else {console.log("Error: Couldn't find the _id for Jar 4oz"); hasError = true;}
|
||||
|
||||
result = Measures.findOne({name: 'Jar 8oz'}, {fields: {_id: 1}});
|
||||
if(result) measureIdMap['8oz'] = result._id;
|
||||
else {console.log("Error: Couldn't find the _id for Jar 8oz"); hasError = true;}
|
||||
|
||||
result = Measures.findOne({name: 'Jar 12oz'}, {fields: {_id: 1}});
|
||||
if(result) measureIdMap['12oz'] = result._id
|
||||
else {console.log("Error: Couldn't find the _id for Jar 12oz"); hasError = true;}
|
||||
|
||||
result = Measures.findOne({name: 'Jar 16oz'}, {fields: {_id: 1}});
|
||||
if(result) measureIdMap['16oz'] = result._id;
|
||||
else {console.log("Error: Couldn't find the _id for Jar 16oz"); hasError = true;}
|
||||
|
||||
result = Measures.findOne({name: 'Jar 32oz'}, {fields: {_id: 1}});
|
||||
if(result) measureIdMap['32oz'] = result._id;
|
||||
else {console.log("Error: Couldn't find the _id for Jar 32oz"); hasError = true;}
|
||||
|
||||
result = Measures.findOne({name: 'Each'}, {fields: {_id: 1}});
|
||||
if(result) measureIdMap['Each'] = result._id;
|
||||
else {console.log("Error: Couldn't find the _id for Each"); hasError = true;}
|
||||
|
||||
result = Measures.findOne({name: 'Bags'}, {fields: {_id: 1}});
|
||||
if(result) measureIdMap['Bags'] = result._id;
|
||||
else {console.log("Error: Couldn't find the _id for Bags"); hasError = true;}
|
||||
|
||||
result = Venues.findOne({name: 'Boonville'}, {fields: {_id: 1}});
|
||||
if(result) venueIdMap['bv'] = result._id;
|
||||
else {console.log("Error: Couldn't find the _id for Boonville"); hasError = true;}
|
||||
|
||||
result = Venues.findOne({name: 'Clement St'}, {fields: {_id: 1}});
|
||||
if(result) venueIdMap['sf'] = result._id;
|
||||
else {console.log("Error: Couldn't find the _id for Clement St"); hasError = true;}
|
||||
|
||||
result = Venues.findOne({name: 'Ukiah'}, {fields: {_id: 1}});
|
||||
if(result) venueIdMap['uk'] = result._id;
|
||||
else {console.log("Error: Couldn't find the _id for Ukiah"); hasError = true;}
|
||||
|
||||
result = Venues.findOne({name: 'Mendocino'}, {fields: {_id: 1}});
|
||||
if(result) venueIdMap['men'] = result._id;
|
||||
else {console.log("Error: Couldn't find the _id for Mendocino"); hasError = true;}
|
||||
|
||||
result = Venues.findOne({name: 'Ft Bragg'}, {fields: {_id: 1}});
|
||||
if(result) venueIdMap['fb'] = result._id;
|
||||
else {console.log("Error: Couldn't find the _id for Ft Bragg"); hasError = true;}
|
||||
|
||||
result = Venues.findOne({name: 'On Farm'}, {fields: {_id: 1}});
|
||||
if(result) venueIdMap['of'] = result._id;
|
||||
else {console.log("Error: Couldn't find the _id for On Farm"); hasError = true;}
|
||||
|
||||
result = Venues.findOne({name: 'Unknown Restaurant'}, {fields: {_id: 1}});
|
||||
if(result) {venueIdMap['res'] = result._id; venueIdMap['w'] = result._id;}
|
||||
else {console.log("Error: Couldn't find the _id for Unknown Restaurant"); hasError = true;}
|
||||
|
||||
result = Venues.findOne({name: 'Yorkville Market'}, {fields: {_id: 1}});
|
||||
if(result) venueIdMap['ym'] = result._id;
|
||||
else {console.log("Error: Couldn't find the _id for Yorkville Market"); hasError = true;}
|
||||
|
||||
result = Venues.findOne({name: 'Yorkville Cellars'}, {fields: {_id: 1}});
|
||||
if(result) venueIdMap['yc'] = result._id;
|
||||
else {console.log("Error: Couldn't find the _id for Yorkville Cellars"); hasError = true;}
|
||||
|
||||
result = Venues.findOne({name: 'Mail Order'}, {fields: {_id: 1}});
|
||||
if(result) venueIdMap['mo'] = result._id;
|
||||
else {console.log("Error: Couldn't find the _id for Mail Order"); hasError = true;}
|
||||
|
||||
// result = Items.find({}, {fields: {_id: 1, name: 1}, sort: {name: 1}}).fetch();
|
||||
result = Products.find({}, {fields: {_id: 1, name: 1}, sort: {name: 1}}).fetch();
|
||||
for(let i = 0; i < result.length; i++) itemIdMap[result[i].name.toLowerCase()] = result[i]._id;
|
||||
|
||||
//console.log(JSON.stringify(itemIdMap));
|
||||
}
|
||||
|
||||
readCSV(fileName, Meteor.bindEnvironment(function(error, data) {
|
||||
//csv.read(fileName, function(error, csvData) {
|
||||
|
||||
//Data is an array of arrays. data[0] = array of headers. data[1] = first row of data.
|
||||
if(error) console.log("Unable to read the importSales.csv file:" + error);
|
||||
else {
|
||||
//Collect the mapping data.
|
||||
collectMetadata(data[0]);
|
||||
|
||||
//Remove everything first.
|
||||
Sales.remove({});
|
||||
|
||||
// console.log("CSV Column Mapping: " + JSON.stringify(map));
|
||||
// readRow(data[1]);
|
||||
|
||||
let undefinedItems = {};
|
||||
for(let i = 1; i < data.length; i++) {
|
||||
readRow(data[i], undefinedItems);
|
||||
}
|
||||
// let output = "";
|
||||
// output += "----------------\n";
|
||||
// output +="Undefined Items:\n";
|
||||
// output +="Name;32 oz;16 oz;12 oz;8 oz;4 oz;bags;each\n"
|
||||
//
|
||||
// let items = [];
|
||||
// for(let property in undefinedItems) {
|
||||
// items.push(property);
|
||||
// }
|
||||
// items.sort();
|
||||
// for(let i = 0; i < items.length; i++) {
|
||||
// let next = items[i];
|
||||
// let sizes = undefinedItems[next];
|
||||
//
|
||||
// // console.log(JSON.stringify(sizes));
|
||||
// output += next+";"+sizes['32 oz']+";"+sizes['16 oz']+";"+sizes['12 oz']+";"+sizes['8 oz']+";"+sizes['4 oz']+";"+sizes['bags']+";"+sizes['each'] + "\n";
|
||||
// }
|
||||
// output += "----------------";
|
||||
// console.log(output);`
|
||||
}
|
||||
}));
|
||||
|
||||
//Collect the metadata from the first row of the CSV data - make a mapping.
|
||||
function collectMetadata(row) {
|
||||
let DATE = 'date';
|
||||
let VENUE = 'vendor';
|
||||
let ITEM = 'item';
|
||||
let OZ32 = '32oz';
|
||||
let OZ16 = '16oz';
|
||||
let OZ12 = '12oz';
|
||||
let OZ8 = '8oz';
|
||||
let OZ4 = '4oz';
|
||||
let BAGS = 'bags';
|
||||
let EACH = 'each';
|
||||
|
||||
//Iterate over the columns to create a mapping.
|
||||
for(let i = 0; i < row.length; i++) {
|
||||
let next = row[i];
|
||||
|
||||
if(next && next != '') {
|
||||
switch(next.toLowerCase()) {
|
||||
case DATE:
|
||||
map.date = i;
|
||||
break;
|
||||
case VENUE:
|
||||
map.venue = 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(row, undefinedItems) {
|
||||
let date = moment(row[map.date], "M/D/YYYY").toDate();
|
||||
let venue = row[map.venue].toLowerCase();
|
||||
let item = row[map.item].trim();
|
||||
item = itemAliases[item] ? itemAliases[item] : item;
|
||||
item = item.toLowerCase();
|
||||
let oz32 = row[map.oz32] == undefined ? 0 : Number(row[map.oz32]);
|
||||
let oz16 = row[map.oz16] == undefined ? 0 : Number(row[map.oz16]);
|
||||
let oz12 = row[map.oz12] == undefined ? 0 : Number(row[map.oz12]);
|
||||
let oz8 = row[map.oz8] == undefined ? 0 : Number(row[map.oz8]);
|
||||
let oz4 = row[map.oz4] == undefined ? 0 : Number(row[map.oz4]);
|
||||
let bags = row[map.bags] == undefined ? 0 : Number(row[map.bags]);
|
||||
let each = row[map.each] == undefined ? 0 : Number(row[map.each]);
|
||||
let venueId = venueIdMap[venue];
|
||||
let itemId = itemIdMap[item];
|
||||
let year = date.getFullYear();
|
||||
|
||||
if(venueId == undefined) {
|
||||
console.log("Found an undefined venue: " + venue);
|
||||
}
|
||||
else if(itemId == undefined) {
|
||||
let sizes = undefinedItems[row[map.item]] || {'32 oz' : 0, '16 oz' : 0, '12 oz' : 0, '8 oz' : 0, '4 oz' : 0, 'bags' : 0, 'each' : 0};
|
||||
|
||||
sizes['32 oz'] += oz32;
|
||||
sizes['16 oz'] += oz16;
|
||||
sizes['12 oz'] += oz12;
|
||||
sizes['8 oz'] += oz8;
|
||||
sizes['4 oz'] += oz4;
|
||||
sizes['bags'] += bags;
|
||||
sizes['each'] += each;
|
||||
|
||||
undefinedItems[row[map.item]] = sizes; //Use the capitalized name - will use the mapping back in the calling code to generate a sorted list for sharing with the admin.
|
||||
}
|
||||
else if(priceMap[year] == undefined) {
|
||||
console.log("Unexpected year: " + year);
|
||||
}
|
||||
else {
|
||||
//Split it into multiple sales entries, one for each measure that has a positive value.
|
||||
if(oz32 > 0) {
|
||||
let price = priceMap[year][item];
|
||||
|
||||
if(price != undefined) price = price['oz32'];
|
||||
if(price == undefined) price = priceMap[year]['oz32'];
|
||||
if(price) insertSale({date: date, amount: oz32, price: price, venueId: venueId, productId: itemId, measureId: measureIdMap['32oz']});
|
||||
else console.log("Could not find a price in the year " + year + " for " + item + " in the size oz32");
|
||||
}
|
||||
|
||||
if(oz16 > 0) {
|
||||
let price = priceMap[year][item];
|
||||
|
||||
if(price != undefined) price = price['oz16'];
|
||||
if(price == undefined) price = priceMap[year]['oz16'];
|
||||
if(price) insertSale({date: date, amount: oz16, price: price, venueId: venueId, productId: itemId, measureId: measureIdMap['16oz']});
|
||||
else console.log("Could not find a price in the year " + year + " for " + item + " in the size oz16");
|
||||
}
|
||||
|
||||
if(oz12 > 0) {
|
||||
let price = priceMap[year][item];
|
||||
|
||||
if(price != undefined) price = price['oz12'];
|
||||
if(price == undefined) price = priceMap[year]['oz12'];
|
||||
if(price) insertSale({date: date, amount: oz12, price: price, venueId: venueId, productId: itemId, measureId: measureIdMap['12oz']});
|
||||
else console.log("Could not find a price in the year " + year + " for " + item + " in the size oz12");
|
||||
}
|
||||
|
||||
if(oz8 > 0) {
|
||||
let price = priceMap[year][item];
|
||||
|
||||
if(price != undefined) price = price['oz8'];
|
||||
if(price == undefined) price = priceMap[year]['oz8'];
|
||||
if(price) insertSale({date: date, amount: oz8, price: price, venueId: venueId, productId: itemId, measureId: measureIdMap['8oz']});
|
||||
else console.log("Could not find a price in the year " + year + " for " + item + " in the size oz8");
|
||||
}
|
||||
|
||||
if(oz4 > 0) {
|
||||
let price = priceMap[year][item];
|
||||
|
||||
if(price != undefined) price = price['oz4'];
|
||||
if(price == undefined) price = priceMap[year]['oz4'];
|
||||
if(price) insertSale({date: date, amount: oz4, price: price, venueId: venueId, productId: itemId, measureId: measureIdMap['4oz']});
|
||||
else console.log("Could not find a price in the year " + year + " for " + item + " in the size oz4");
|
||||
}
|
||||
|
||||
if(bags > 0) {
|
||||
let price = priceMap[year][item];
|
||||
|
||||
if(price != undefined) price = price['bags'];
|
||||
if(price == undefined) price = priceMap[year]['bags'];
|
||||
if(price) insertSale({date: date, amount: bags, price: price, venueId: venueId, productId: itemId, measureId: measureIdMap['Bags']});
|
||||
else {
|
||||
console.log("Could not find a price in the year " + year + " for " + item + " in the size bags");
|
||||
}
|
||||
}
|
||||
|
||||
if(each > 0) {
|
||||
let price = priceMap[year][item];
|
||||
|
||||
if(price != undefined) price = price['each'];
|
||||
if(price == undefined) price = priceMap[year]['each'];
|
||||
if(price) insertSale({date: date, amount: each, price: price, venueId: venueId, productId: itemId, measureId: measureIdMap['Each']});
|
||||
else console.log("Could not find a price in the year " + year + " for " + item + " in the size each");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function insertSale(sale) {
|
||||
sale.createdAt = new Date();
|
||||
Sales.insert(sale, function(error) {
|
||||
if(error) console.log("Failed to insert the sale: " + JSON.stringify(sale) + "\n ERROR: " + error);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
19
server/server.js
Normal file
19
server/server.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import '/imports/util/regex.js';
|
||||
import '/imports/startup/server';
|
||||
import '/imports/startup/both';
|
||||
import '/imports/api';
|
||||
import '/imports/startup/server/postStartup/version.js'; //Run this right after the api - relies on the API to upgrade the app database & data to the current version.
|
||||
|
||||
let PropertiesReader = require('properties-reader');
|
||||
let props = PropertiesReader('./assets/app/release.properties');
|
||||
|
||||
if(props.get('email-settings')) {
|
||||
process.env.MAIL_URL = props.get('email-settings');
|
||||
// console.log("Loaded email settings from properties file.");
|
||||
}
|
||||
|
||||
if (!process.env.MAIL_URL) {
|
||||
process.env.MAIL_URL = Meteor.settings.MAIL_URL;
|
||||
}
|
||||
|
||||
// console.log("Mail settings: " + process.env.MAIL_URL);
|
||||
Reference in New Issue
Block a user