Redesigned the querying for the sale duplicates screen to use aggregation; Finished the styling of the sale duplicate screen; Tested the functionality of sale duplicates; Added a way to show hidden (ignored) duplicates.
This commit is contained in:
212
imports/ui/SaleDuplicates.js
Normal file
212
imports/ui/SaleDuplicates.js
Normal file
@@ -0,0 +1,212 @@
|
||||
|
||||
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)
|
||||
});
|
||||
Reference in New Issue
Block a user