2019-10-07 15:51:50 -07:00
import { Mongo } from "meteor/mongo" ;
import { Meteor } from 'meteor/meteor' ;
import { check } from 'meteor/check' ;
2025-07-02 11:18:09 -07:00
import 'meteor/aldeed:collection2/static'
import SimpleSchema from 'meteor/aldeed:simple-schema' ;
import Products from "./Product" ;
import Measures from "./Measure" ;
2019-10-07 15:51:50 -07:00
2025-07-02 11:18:09 -07:00
let Barcodes = new Mongo . Collection ( 'Barcodes' ) ;
if ( Meteor . isServer ) {
//Set MongoDB indexes (or remove them) here.
try {
Barcodes . rawCollection ( ) . createIndex ( { barcodeId : - 1 } , { unique : true } )
Barcodes . rawCollection ( ) . createIndex ( { productAndMeasureId : - 1 } , { unique : true } )
} catch ( e ) { console . log ( "Caught exception while setting indexes in MongoDB" ) ; console . error ( e ) }
}
2019-10-07 15:51:50 -07:00
// 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 ,
2025-07-02 11:18:09 -07:00
//index: 1,
//unique: true
2019-10-07 15:51:50 -07:00
} ,
productAndMeasureId : { //Just the two ids jammed together with a single space between them.
type : String ,
label : "Product And Measure ID" ,
optional : false ,
2025-07-02 11:18:09 -07:00
//index: 1,
//unique: true
2019-10-07 15:51:50 -07:00
}
} ) ;
if ( Meteor . isServer ) {
//Meteor.publish('barcodes', function() {
// return Barcodes.find({});
//});
Meteor . methods ( {
2025-07-02 11:18:09 -07:00
getBarcodeId : async function ( productId , measureId ) {
2019-10-07 15:51:50 -07:00
check ( productId , String ) ;
check ( measureId , String ) ;
2025-07-02 11:18:09 -07:00
let hasProduct = await Meteor . collections . Products . findOneAsync ( { _id : productId } , { fields : { } } ) ;
let hasMeasure = await Meteor . collections . Measures . findOneAsync ( { _id : measureId } , { fields : { } } ) ;
2019-10-07 15:51:50 -07:00
if ( hasProduct && hasMeasure ) {
2025-07-02 11:18:09 -07:00
let existing = await Barcodes . findOneAsync ( { productAndMeasureId : productId + ' ' + measureId } ) ;
2019-10-07 15:51:50 -07:00
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.
2025-07-02 11:18:09 -07:00
//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;
let product = await Products . findOneAsync ( { barcodeId : { $exists : true } } , { sort : { barcodeId : - 1 } } )
let barcodeId = product ? product . barcodeId : 1 ;
2019-10-07 15:51:50 -07:00
2025-07-02 11:18:09 -07:00
await Barcodes . insertAsync ( { productAndMeasureId : productId + ' ' + measureId , barcodeId } , function ( err , id ) {
2019-10-07 15:51:50 -07:00
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 ;