diff --git a/.meteor/packages b/.meteor/packages index 425d535..da820fd 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -6,19 +6,19 @@ meteor-base@1.4.0 # Packages every Meteor app needs to have mobile-experience@1.0.5 # Packages for a great mobile UX -mongo@1.6.0 # The database Meteor supports right now +mongo@1.6.2 # The database Meteor supports right now blaze-html-templates@1.0.4 # Compile .html files into Meteor Blaze views reactive-var@1.0.11 # Reactive variable for tracker -reactive-dict@1.2.1 # ??? +reactive-dict@1.3.0 # ??? tracker@1.2.0 # Meteor's client-side reactive programming library tomwasd:history-polyfill # Adds IE 8/9 support for HTML5 history. email@1.2.3 # Adds the Meteor/Email package for sending lost password emails -standard-minifier-css@1.5.2 # CSS minifier run for production mode -standard-minifier-js@2.4.0 # JS minifier run for production mode +standard-minifier-css@1.5.3 # CSS minifier run for production mode +standard-minifier-js@2.4.1 # JS minifier run for production mode es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers. poorvavyas:es6-shim -ecmascript@0.12.3 # Enable ECMAScript2015+ syntax in app code +ecmascript@0.12.4 # Enable ECMAScript2015+ syntax in app code #accounts-ui #accounts-base @@ -61,8 +61,8 @@ juliancwirko:s-alert # Client error/alert handling jcbernack:reactive-aggregate # Allows us to create a new client collection (from the server) with the contents being an aggregate of server data. Note that aggregation can only be done on the server currently as mini-mongo does not support it. ostrio:logger ostrio:loggermongo -dynamic-import@0.5.0 +dynamic-import@0.5.1 markdown@1.0.12 wcrisman:jquery-custom-scrollbar -underscore +underscore@1.0.10 meteorhacks:aggregate # Allows databaseName.aggragate(pipeline) calls the exact same way you would on the command line in the mongo tool. diff --git a/.meteor/release b/.meteor/release index 2299ae7..97064e1 100644 --- a/.meteor/release +++ b/.meteor/release @@ -1 +1 @@ -METEOR@1.8.0.1 +METEOR@1.8.1 diff --git a/.meteor/versions b/.meteor/versions index 7a0cb6a..424b559 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -1,4 +1,4 @@ -accounts-base@1.4.3 +accounts-base@1.4.4 accounts-password@1.5.1 alanning:roles@1.2.16 aldeed:collection2@2.10.0 @@ -9,10 +9,10 @@ aldeed:simple-schema@1.5.4 aldeed:template-extension@4.1.0 allow-deny@1.1.0 arillo:flow-router-helpers@0.5.2 -autoupdate@1.5.0 -babel-compiler@7.2.4 +autoupdate@1.6.0 +babel-compiler@7.3.4 babel-runtime@1.3.0 -base64@1.0.11 +base64@1.0.12 binary-heap@1.0.11 blaze@2.3.3 blaze-html-templates@1.1.2 @@ -27,18 +27,18 @@ ddp@1.4.0 ddp-client@2.3.3 ddp-common@1.4.0 ddp-rate-limiter@1.0.7 -ddp-server@2.2.0 +ddp-server@2.3.0 deps@1.0.12 diff-sequence@1.1.1 dynamic-import@0.5.1 -ecmascript@0.12.4 +ecmascript@0.12.7 ecmascript-runtime@0.7.0 ecmascript-runtime-client@0.8.0 ecmascript-runtime-server@0.7.1 ejson@1.1.0 email@1.2.3 es5-shim@4.8.0 -fetch@0.1.0 +fetch@0.1.1 fortawesome:fontawesome@4.7.0 geojson-utils@1.0.10 hot-code-push@1.0.4 @@ -58,7 +58,7 @@ localstorage@1.2.0 logging@1.1.20 markdown@1.0.12 mdg:validation-error@0.2.0 -meteor@1.9.2 +meteor@1.9.3 meteor-base@1.4.0 meteorhacks:aggregate@1.3.0 meteorhacks:collection-utils@1.2.0 @@ -79,37 +79,37 @@ meteortoys:sub@4.0.0 meteortoys:throttle@4.0.0 meteortoys:toggle@4.0.0 meteortoys:toykit@4.0.2 -minifier-css@1.4.1 -minifier-js@2.4.0 +minifier-css@1.4.2 +minifier-js@2.4.1 minimongo@1.4.5 mizzao:bootboxjs@4.4.0 mobile-experience@1.0.5 mobile-status-bar@1.0.14 -modern-browsers@0.1.3 +modern-browsers@0.1.4 modules@0.13.0 modules-runtime@0.10.3 -momentjs:moment@2.23.0 -mongo@1.6.0 -mongo-decimal@0.1.0 +momentjs:moment@2.24.0 +mongo@1.6.3 +mongo-decimal@0.1.1 mongo-dev-server@1.1.0 mongo-id@1.0.7 mongo-livedata@1.0.12 msavin:jetsetter@4.0.0 msavin:mongol@4.0.1 npm-bcrypt@0.9.3 -npm-mongo@3.1.1 +npm-mongo@3.1.2 observe-sequence@1.0.16 ordered-dict@1.1.0 -ostrio:logger@2.0.7 -ostrio:loggermongo@2.0.4 +ostrio:logger@2.0.8 +ostrio:loggermongo@2.0.5 poorvavyas:es6-shim@0.21.1 promise@0.11.2 raix:eventemitter@0.1.3 random@1.1.0 rate-limit@1.0.9 -reactive-dict@1.2.1 +reactive-dict@1.3.0 reactive-var@1.0.11 -reload@1.2.0 +reload@1.3.0 retry@1.1.0 routepolicy@1.1.0 service-configuration@1.0.11 @@ -121,8 +121,8 @@ softwarerero:accounts-t9n@1.3.11 spacebars@1.0.15 spacebars-compiler@1.1.3 srp@1.0.12 -standard-minifier-css@1.5.2 -standard-minifier-js@2.4.0 +standard-minifier-css@1.5.3 +standard-minifier-js@2.4.1 stylus@2.513.14 templating@1.3.2 templating-compiler@1.3.3 @@ -137,6 +137,6 @@ useraccounts:core@1.14.2 useraccounts:flow-routing@1.14.2 useraccounts:unstyled@1.14.2 wcrisman:jquery-custom-scrollbar@3.0.0 -webapp@1.7.2 +webapp@1.7.4 webapp-hashing@1.0.9 zimme:active-route@2.3.2 diff --git a/client/main.styl b/client/main.styl index e027125..375ca43 100644 --- a/client/main.styl +++ b/client/main.styl @@ -187,4 +187,5 @@ body @import "../imports/ui/Workers.import.styl" @import "../imports/ui/Graphs.import.styl" @import "../imports/ui/Reports.import.styl" +@import "../imports/ui/Label.import.styl" @import "../imports/ui/TestList.import.styl" \ No newline at end of file diff --git a/imports/api/Measure.js b/imports/api/Measure.js index 847f104..c4c57de 100644 --- a/imports/api/Measure.js +++ b/imports/api/Measure.js @@ -3,7 +3,7 @@ import { Mongo } from 'meteor/mongo'; import { check } from 'meteor/check'; import {SimpleSchema} from 'meteor/aldeed:simple-schema'; -Measures = new Mongo.Collection('Measures'); +let Measures = new Mongo.Collection('Measures'); Measures.attachSchema(new SimpleSchema({ name: { type: String, diff --git a/imports/api/Reports.js b/imports/api/Reports.js index 93f222b..3ff9c25 100644 --- a/imports/api/Reports.js +++ b/imports/api/Reports.js @@ -2,17 +2,18 @@ import { Meteor } from 'meteor/meteor'; if(Meteor.isServer) { WebApp.connectHandlers.use("/reports/AnnualTotals", (req, res, next) => { + const separator = ";"; try { let result = Meteor.collections.Sales.aggregate([{$group: {_id: {$substr: ['$date', 0, 4]}, total: {$sum: {$multiply: ["$price", "$amount"]}}}}]); result.toArray().then(function(result) { res.writeHead(200, {'Content-Type': 'text/csv'}); - res.write("Year,Sales Total\n"); + res.write("Year" + separator + "Sales Total ($)\n"); for(let i = 0; i < result.length; i++) { res.write(result[i]._id); - res.write(","); + res.write(separator); res.write("" + result[i].total); res.write("\n"); } @@ -25,13 +26,14 @@ if(Meteor.isServer) { } }); WebApp.connectHandlers.use("/reports/MonthlyTotals", (req, res, next) => { + const separator = ";"; try { let result = Meteor.collections.Sales.aggregate([{$group: {_id: {$substr: ['$date', 0, 6]}, total: {$sum: {$multiply: ["$price", "$amount"]}}}}]); result.toArray().then(function(result) { res.writeHead(200, {'Content-Type': 'text/csv'}); - res.write("Date,Sales Total\n"); + res.write("Date" + separator + "Sales Total ($)\n"); result.sort(function(a, b) { return parseInt(a._id) - parseInt(b._id); @@ -39,7 +41,7 @@ if(Meteor.isServer) { for(let i = 0; i < result.length; i++) { res.write(result[i]._id.substr(4, 2) + "/" + result[i]._id.substr(0, 4)); - res.write(","); + res.write(separator); res.write("" + result[i].total); res.write("\n"); } @@ -51,7 +53,72 @@ if(Meteor.isServer) { res.end(); } }); + WebApp.connectHandlers.use("/reports/AnnualSaleCountsByMeasure", (req, res, next) => { + const separator = ";"; + try { + let result = Meteor.collections.Sales.aggregate([{ + $group: { + _id: {$concat: [{$substr: ['$date', 0, 4]}, "-", "$measureId"]}, + measureId: {$first: "$measureId"}, + year: {$first: {$substr: ['$date', 0, 4]}}, + count: {$sum: "$amount"}, + total: {$sum: {$multiply: ["$price", "$amount"]}} + } + }]); + + result.toArray().then(function(result) { + let totalByYear = {}; + + //Create a map of maps: year -> measure id -> sales count. + for(let next of result) { + //Get the map of totals by product for the year. + let totalByMeasure = totalByYear[next.year]; + //Create the map if necessary. + if(totalByMeasure === undefined) totalByMeasure = totalByYear[next.year] = {}; + + totalByMeasure[next.measureId] = {count: next.count, total: next.total}; + } + + //Create a list of ordered measures. We could use a map, but then getting the ordering correct would be difficult. + let measures = Meteor.collections.Measures.find({}, {fields: {_id: 1, name: 1}, sort: {order: 1}}).fetch(); + + //Collect the years in ascending oder. + let years = Object.keys(totalByYear).sort(function(a, b) {return parseInt(a) - parseInt(b);}); + + res.writeHead(200, {'Content-Type': 'text/csv'}); + + res.write("Year" + separator + "Measure" + separator + "Sales Count" + separator + "Sales Total ($)\n"); + + result.sort(function(a, b) { + return parseInt(a._id) - parseInt(b._id); + }); + + for(let year of years) { + for(let measure of measures) { + let totals = totalByYear[year][measure._id]; + + if(totals) { + res.write(year); + res.write(separator); + res.write(measure.name); + res.write(separator); + res.write("" + totals.count); + res.write(separator); + res.write("" + totals.total); + res.write("\n"); + } + } + } + + res.end(); + }); + } catch(err) { + console.log(err); + res.end(); + } + }); WebApp.connectHandlers.use("/reports/TagTotals", (req, res, next) => { + const separator = ";"; try { //Aggregate all the sales by product id & year, then later create a map between products and tags to create tag totals. let result = Meteor.collections.Sales.aggregate([{ @@ -111,7 +178,7 @@ if(Meteor.isServer) { //Iterate over the years and add them to the headers. for(let year of years) { - res.write("," + year); + res.write(separator + year); } res.write('\n'); @@ -135,7 +202,7 @@ if(Meteor.isServer) { if(productAnnualTotal) annualTotal += productAnnualTotal; } - res.write("," + annualTotal); + res.write(separator + annualTotal); } res.write('\n'); @@ -201,7 +268,7 @@ if(Meteor.isServer) { //Iterate over the years and add them to the headers. for(let year of years) { - res.write(separator + year + " Count" + separator + year + " Total"); + res.write(separator + year + " Count" + separator + year + " Total ($)"); } res.write('\n'); diff --git a/imports/startup/client/routes.js b/imports/startup/client/routes.js index f566fca..f187434 100644 --- a/imports/startup/client/routes.js +++ b/imports/startup/client/routes.js @@ -116,6 +116,13 @@ pri.route('/graphTest', { BlazeLayout.render('Body', {content: 'GraphTest'}); } }); +pri.route('/labels', { + name: 'Labels', + action: function(params, queryParams) { + require("/imports/ui/Label.js"); + BlazeLayout.render('Body', {content: 'LabelMaker'}); + } +}); pri.route('/testList', { name: 'TestList', action: function(params, queryParams) { diff --git a/imports/ui/Label.html b/imports/ui/Label.html new file mode 100644 index 0000000..e056112 --- /dev/null +++ b/imports/ui/Label.html @@ -0,0 +1,31 @@ + + + diff --git a/imports/ui/Label.import.styl b/imports/ui/Label.import.styl new file mode 100644 index 0000000..df74bac --- /dev/null +++ b/imports/ui/Label.import.styl @@ -0,0 +1,93 @@ +#labelMaker + margin: 10px 20px + height: 100% + width: 100% + + .labelContents + label + font-family: TimesNewRoman, Times New Roman, Times + font-weight: 200 + font-size: 14px + .title1 + width: 500px + font-family: TimesNewRoman, Times New Roman, Times + font-size: .142in + font-weight: 800 + line-height: .142in + .title2 + width: 500px + font-family: TimesNewRoman, Times New Roman, Times + font-size: 14px + font-weight: 800 + line-height: 16px + .ingredients + width: 500px + height: 100px + font-family: TimesNewRoman, Times New Roman, Times + font-size: 12px + font-weight: 100 + line-height: 14px + .date + width: 500px + font-family: TimesNewRoman, Times New Roman, Times + font-size: 12px + font-weight: 100 + line-height: 14px + .labelContainer + text-align: center + width: 100% + width-min: 3in + height-min: 2in + background-color: grey + padding: 20px + .labelSample + display: inline-block + width: 3in + height: 2in + background-color: white + color: black + text-align: center + .labelLogo + width: .8in + .labelTagline + font-family: TimesNewRoman, Times New Roman, Times + font-size: .1in + font-weight: 100 + line-height: .2in + .title1 + width: 100% + font-family: TimesNewRoman, Times New Roman, Times + font-size: .2in + font-weight: 800 + text-transform: uppercase + .title2 + width: 100% + font-family: TimesNewRoman, Times New Roman, Times + font-size: .15in + font-weight: 800 + .ingredients + width: 100% + font-family: TimesNewRoman, Times New Roman, Times + font-size: .1in + font-weight: 100 + .ingredientsEnding + width: 100% + font-family: TimesNewRoman, Times New Roman, Times + font-size: .1in + font-weight: 100 + .instructions + width: 100% + font-family: TimesNewRoman, Times New Roman, Times + font-size: .1in + font-weight: 800 + .address + width: 100% + font-family: TimesNewRoman, Times New Roman, Times + font-size: .1in + font-weight: 100 + .website + width: 100% + font-family: TimesNewRoman, Times New Roman, Times + font-size: .1in + font-weight: 100 + diff --git a/imports/ui/Label.js b/imports/ui/Label.js new file mode 100644 index 0000000..bf023c8 --- /dev/null +++ b/imports/ui/Label.js @@ -0,0 +1,75 @@ + +import './Label.html'; +import swal from 'sweetalert2'; +import dragula from 'dragula'; + +//****************************************************************** +//** Creates printable labels for a roll style printer. +//****************************************************************** + +let PREFIX = "LabelMaker_"; + +Template.LabelMaker.onCreated(function() { +}); +Template.LabelMaker.onRendered(function() { + let template = this; +}); +Template.LabelMaker.onDestroyed(function() { +}); +Template.LabelMaker.events({ + 'change .title1': function(event, template) { + Session.set(PREFIX + "title1", $(event.target).val()); + }, + 'change .title2': function(event, template) { + Session.set(PREFIX + "title2", $(event.target).val()); + }, + 'change .ingredients': function(event, template) { + Session.set(PREFIX + "ingredients", $(event.target).val()); + }, + 'change .date': function(event, template) { + Session.set(PREFIX + "date", parseInt($(event.target).val())); + }, + 'click .generate': function(event, template) { + + } +}); +Template.LabelMaker.helpers({ + title1: function() {return Session.get(PREFIX + "title1")}, + title2: function() {return Session.get(PREFIX + "title2")}, + ingredients: function() {return Session.get(PREFIX + "ingredients")}, + date: function() {return Session.get(PREFIX + "date")}, + labelText: function() { + return "
" + Session.get(PREFIX + "title1") + "
" + + "
" + Session.get(PREFIX + "title2") + "
" + + "
Ingredients:" + Session.get(PREFIX + "ingredients") + "
" + + "
*grown by us 8oz FD1951 (" + Session.get(PREFIX + "date") + ")
" + + "
Refrigerate after opening; return jar when done
" + + "
18601 Hwy 128, Yorkville, CA 95494
" + + "
www.PetitTeton.com
"; + } +}); + +Template.Labels.onCreated(function() { +}); +Template.Labels.onRendered(function() { + let template = this; +}); +Template.Labels.onDestroyed(function() { +}); +Template.Labels.events({ +}); +Template.Labels.helpers({ + labels: function() {return Session.get(PREFIX + "labels")}, + title2: function() {return Session.get(PREFIX + "title2")}, + ingredients: function() {return Session.get(PREFIX + "ingredients")}, + date: function() {return Session.get(PREFIX + "date")}, + labelText: function() { + return "
" + Session.get(PREFIX + "title1") + "
" + + "
" + Session.get(PREFIX + "title2") + "
" + + "
Ingredients:" + Session.get(PREFIX + "ingredients") + "
" + + "
*grown by us 8oz FD1951 (" + Session.get(PREFIX + "date") + ")
" + + "
Refrigerate after opening; return jar when done
" + + "
18601 Hwy 128, Yorkville, CA 95494
" + + "
www.PetitTeton.com
"; + } +}); diff --git a/imports/ui/Reports.html b/imports/ui/Reports.html index 8fe4853..2d16add 100644 --- a/imports/ui/Reports.html +++ b/imports/ui/Reports.html @@ -5,5 +5,6 @@ Tag Totals (csv) The total sales ($) are shown by year for each tag. Since multiple tags can be associated with multiple products (N to N relationship), there will likely be overlap in the numbers.
Tag Sales By Measure (csv) This is a table of tags & measures by year. The tags and the measures associated with them are along the vertical column, and the years are horizontal. Both item counts and sales totals ($) are shown for each year.
Product Sales By Measure (csv) This is a table of products & product measures by year, showing the sales in terms of unit counts and dollar values for each year, each product, and each product's measure.
+ Annual Sale Counts By Measure (csv)
\ No newline at end of file diff --git a/imports/ui/UserManagement.js b/imports/ui/UserManagement.js index f0b53e9..b2db86c 100644 --- a/imports/ui/UserManagement.js +++ b/imports/ui/UserManagement.js @@ -144,7 +144,7 @@ Template.UserEditor.events({ let roles = []; user.username = template.$('input[name="username"]').val(); - user.email = template.$('input[name="email"]').val(); + user.emails = [{address: template.$('input[name="email"]').val(), verified: true}]; //Assume it is verified since an administrator is adding it. let roleSpans = template.$('.role.selected'); for(let i = 0; i < roleSpans.length; i++) { diff --git a/public/images/PetitTetonLabelLogo_2in Width_v1.png b/public/images/PetitTetonLabelLogo_2in Width_v1.png new file mode 100644 index 0000000..55c1564 Binary files /dev/null and b/public/images/PetitTetonLabelLogo_2in Width_v1.png differ