import './SaleDuplicates.html'; import '/imports/util/selectize/selectize.js'; import swal from 'sweetalert2'; /** * Notes: * The Sale object has a date field which stores the date as a number in the format YYYYMMDD. Converting this number into a local date is done with moment(sale.date.toString(), "YYYYMMDD").toDate(), and converting it to a number from a date can be accomplished with ~~(moment(date).format("YYYYMMDD")), where the ~~ is a bitwise not and converts a string to a number quickly and reliably. */ let PREFIX = "SaleDuplicates."; let DuplicateSales = new Meteor.Collection("duplicateSales"); let duplicateSalesSubscription; Template.SaleDuplicates.onCreated(function() { let template = Template.instance(); //Tracker.autorun(function() { // let query = _.clone(Session.get(PREFIX + 'searchQuery')); // // duplicateSalesSubscription = template.subscribe("duplicateSales", query, Session.get(PREFIX + "showHidden")); //}); Tracker.autorun(function() { duplicateSalesSubscription = template.subscribe("duplicateSales", null, Session.get(PREFIX + "showHidden")); }); }); Template.SaleDuplicates.onDestroyed(function() { if(duplicateSalesSubscription) { duplicateSalesSubscription.stop(); } }); Template.SaleDuplicates.helpers({ sales: function() { let dbQuery = []; let query = _.clone(Session.get(PREFIX + 'searchQuery')); if(query) { // Add each query requirement sent by the client. _.each(_.keys(query), function(key) { //if(_.isObject(query[key])) dbQuery.push({[key]: query[key]}); if(_.isObject(query[key])) { if(query[key].type === 'dateRange') { if(query[key].start && query[key].end) dbQuery.push({[key]: {$gte: query[key].start, $lte: query[key].end}}); else if(query[key].start) dbQuery.push({[key]: {$gte: query[key].start}}); else if(query[key].end) dbQuery.push({[key]: {$lte: query[key].end}}); // Do nothing if a start and/or end are not provided. } else { dbQuery.push({[key]: query[key]}); } } else if(_.isNumber(query[key])) dbQuery.push({[key]: query[key]}); else { let searchValue = query[key]; let searches = searchValue && searchValue.length > 0 ? searchValue.split(/\s+/) : undefined; for(let search of searches) { dbQuery.push({[key]: {$regex: '\\b' + search, $options: 'i'}}); } } }); } if(dbQuery.length > 1) dbQuery = {$and: dbQuery}; else if(dbQuery.length == 1) dbQuery = dbQuery[0]; else dbQuery = {}; return DuplicateSales.find(dbQuery, {sort: {date: -1, productName: 1}}); }, showHidden: function() { return Session.get(PREFIX + "showHidden") ? "checked": ""; } }); Template.SaleDuplicates.events({ 'click .duplicateScan': function(event, template) { Meteor.call("markDuplicateSales", function(err, result) { Meteor.log.error(err); }); }, 'change input[name="showHidden"]': function(event, template) { //console.log("changed " + $(event.target).prop('checked')); Session.set(PREFIX + "showHidden", $(event.target).prop('checked')); } }); Template.SaleDuplicate.helpers({ //measureName: function(id) { // return Meteor.collections.Measures.findOne({_id: id}, {fields: {name: 1}}).name; //}, //venueName: function(id) { // return Meteor.collections.Venues.findOne({_id: id}, {fields: {name: 1}}).name; //}, //productName: function(id) { // return Meteor.collections.Products.findOne({_id: id}, {fields: {name: 1}}).name; //}, formatDateAndWeek: function(date) { return moment.utc(date.toString(), "YYYYMMDD").utc().format("MM/DD/YYYY (w)"); }, formatDateTime: function(date) { return moment.utc(date).format("MM/DD/YYYY"); }, formatPrice: function(price) { return price.toLocaleString("en-US", {style: 'currency', currency: 'USD', minimumFractionDigits: 2}); }, formatTotalPrice: function(price, amount) { return (price * amount).toLocaleString("en-US", {style: 'currency', currency: 'USD', minimumFractionDigits: 2}); }, showTotalPrice: function(amount) { return amount > 1; }, duplicateClasses: function() { return this.ignoreDuplicates ? "hidden" : ""; } }); Template.SaleDuplicate.events({ "click .ignoreDuplicatesButton": function(event, template) { Meteor.call('ignoreDuplicateSales', this._id, function(err, result) { if(err) sAlert.error(err); //else sAlert.success("Duplicates Ignored"); }); }, "click .removeAllDuplicatesButton": function(event, template) { let _this = this; swal({ title: "Are you sure?", text: "This will permanently remove ALL duplicate sales.", type: "question", showCancelButton: true, confirmButtonColor: "#DD6B55", confirmButtonText: "Yes" }).then( function(isConfirm) { if(isConfirm) { Meteor.call('removeDuplicateSales', _this._id, function(err, result) { if(err) sAlert.error(err); //else sAlert.success("Duplicates Removed"); }); } }, function(dismiss) { } ); }, "click .removeOneDuplicateButton": function(event, template) { let _this = this; swal({ title: "Are you sure?", text: "This will permanently remove ONE duplicate sale.", type: "question", showCancelButton: true, confirmButtonColor: "#DD6B55", confirmButtonText: "Yes" }).then( function(isConfirm) { if(isConfirm) { Meteor.call('removeDuplicateSales', _this._id, true, function(err, result) { if(err) sAlert.error(err); //else sAlert.success("Duplicates Removed"); }); } }, function(dismiss) { } ); } }); Template.SaleDuplicateSearch.helpers({ searchValue: function() { let searchFields = Session.get(PREFIX + 'searchFields'); return (searchFields && searchFields[this.columnName]) ? searchFields[this.columnName] : ''; } }); Template.SaleDuplicateSearch.events({ "keyup .searchInput": _.throttle(function(event, template) { let searchQuery = Session.get(PREFIX + 'searchQuery') || {}; let searchFields = Session.get(PREFIX + 'searchFields') || {}; let searchValue = template.$(event.target).val(); if(searchValue) { if(this.number) searchValue = parseFloat(searchValue); // A collection name will be provided if there is a related table of data that will contain the text provided and will map to an ID that is then searched for in the current table of data. // For example we are displaying a table of Sales which has the ID of a Product. The Product table has a Name field and the search box searches for Product Names. The ID's of the Products found should be used to filter the Sales by Product ID. if(this.collection) { let ids = Meteor.collections[this.collection].find({[this.collectionQueryColumnName]: {$regex: searchValue, $options: 'i'}}, {fields: {[this.collectionResultColumnName]: 1}}).fetch(); //Convert the ids to an array of ids instead of an array of objects containing an id. for(let i = 0; i < ids.length; i++) {ids[i] = ids[i]._id;} searchQuery[this.columnName] = {$in: ids}; searchFields[this.columnName] = searchValue; } else { searchFields[this.columnName] = searchQuery[this.columnName] = searchValue; } } else { //Remove columns from the search query whose values are empty so we don't bother the database with them. delete searchQuery[this.columnName]; delete searchFields[this.columnName]; } Session.set(PREFIX + 'searchQuery', searchQuery); Session.set(PREFIX + 'searchFields', searchFields); Session.set(PREFIX + 'skipCount', 0); //Reset the paging of the results. }, 500) });