81 lines
3.3 KiB
JavaScript
81 lines
3.3 KiB
JavaScript
import {Mongo} from "meteor/mongo";
|
|
import { Meteor } from 'meteor/meteor';
|
|
import { check } from 'meteor/check';
|
|
import {SimpleSchema} from 'meteor/aldeed:simple-schema';
|
|
|
|
Barcodes = new Mongo.Collection('Barcodes');
|
|
|
|
// A simple mapping between a concatenation of the product & measure ID and a unique sequential number for the barcode. This allows us to have a small number to keep our barcodes simple, while maintaining the more traditional MongoDB ID's for the Product and Measure.
|
|
const BarcodesSchema = new SimpleSchema({
|
|
barcodeId: {
|
|
type: Number,
|
|
label: "Barcode ID",
|
|
optional: false,
|
|
index: 1,
|
|
unique: true
|
|
},
|
|
productAndMeasureId: { //Just the two ids jammed together with a single space between them.
|
|
type: String,
|
|
label: "Product And Measure ID",
|
|
optional: false,
|
|
index: 1,
|
|
unique: true
|
|
}
|
|
});
|
|
|
|
if(Meteor.isServer) {
|
|
//Meteor.publish('barcodes', function() {
|
|
// return Barcodes.find({});
|
|
//});
|
|
|
|
Meteor.methods({
|
|
getBarcodeId: function(productId, measureId) {
|
|
check(productId, String);
|
|
check(measureId, String);
|
|
|
|
let hasProduct = Meteor.collections.Products.findOne({_id: productId}, {fields: {}});
|
|
let hasMeasure = Meteor.collections.Measures.findOne({_id: measureId}, {fields: {}});
|
|
|
|
if(hasProduct && hasMeasure) {
|
|
let existing = Barcodes.findOne({productAndMeasureId: productId + ' ' + measureId});
|
|
|
|
if(existing) {
|
|
return existing.barcodeId;
|
|
}
|
|
else {
|
|
let c = 0;
|
|
|
|
//Try a thousand times before failing. Should never fail, should also not ever need to try a thousand times (unless we somehow automate label generation to the point where a 1000 processes at once are requesting labels that have never been generated before - highly unlikely).
|
|
while(c++ < 1000) {
|
|
//Lookup the most likely next barcode id from the db, then attempt to insert with it. If it fails due to duplication, then increment and repeat.
|
|
let cursor = Products.find({}, {barcodeId: 1}).sort({barcodeId: -1}).limit(1); //Since currently products are never removed, we shouldn't need to detect sequence gaps and fill them in (odds are we will never use more than 10k numbers anyway).
|
|
let barcodeId = cursor.hasNext() ? cursor.next().barcodeId + 1 : 1;
|
|
|
|
Barcodes.insert({productAndMeasureId: productId + ' ' + measureId, barcodeId}, function(err, id) {
|
|
if(err) console.log(err);
|
|
else return barcodeId;
|
|
});
|
|
}
|
|
|
|
//If we are still here, then there was a massive failure (c exceeded 1000).
|
|
console.log("We failed to generate a new barcode ID 1000 times, so we are giving up. This should never happen.");
|
|
throw new Meteor.Error(403, "Unable to generate a barcode ID.");
|
|
}
|
|
}
|
|
else {
|
|
//Cannot find either the product or the measure in the db. Cannot give an id.
|
|
console.log("Unable to generate a barcode ID because we could not find the product " + productId + " OR we could not find the measure " + measureId);
|
|
throw new Meteor.Error(403, "Unable to find the product or the measure. Both must exist in order to generate a barcode ID.");
|
|
}
|
|
},
|
|
});
|
|
}
|
|
|
|
//Allows the client to do DB interaction without calling server side methods, while still retaining control over whether the user can make changes.
|
|
Barcodes.allow({
|
|
insert: function() {return false;},
|
|
update: function() {return false;},
|
|
remove: function() {return false;}
|
|
});
|
|
|
|
export default Barcodes; |