Store cart in the DB and handle the holding of stock across sessions
							parent
							
								
									b76df6c03e
								
							
						
					
					
						commit
						f1b6d1dcc8
					
				
							
								
								
									
										20
									
								
								app.js
								
								
								
								
							
							
						
						
									
										20
									
								
								app.js
								
								
								
								
							|  | @ -5,11 +5,13 @@ const cookieParser = require('cookie-parser'); | |||
| const bodyParser = require('body-parser'); | ||||
| const session = require('express-session'); | ||||
| const moment = require('moment'); | ||||
| const _ = require('lodash'); | ||||
| const MongoStore = require('connect-mongodb-session')(session); | ||||
| const MongoClient = require('mongodb').MongoClient; | ||||
| const numeral = require('numeral'); | ||||
| const helmet = require('helmet'); | ||||
| const colors = require('colors'); | ||||
| const cron = require('node-cron'); | ||||
| const common = require('./lib/common'); | ||||
| const mongodbUri = require('mongodb-uri'); | ||||
| let handlebars = require('express-handlebars'); | ||||
|  | @ -234,7 +236,7 @@ app.use(session({ | |||
|     cookie: { | ||||
|         path: '/', | ||||
|         httpOnly: true, | ||||
|         maxAge: 3600000 * 24 | ||||
|         maxAge: 900000 | ||||
|     }, | ||||
|     store: store | ||||
| })); | ||||
|  | @ -346,6 +348,8 @@ MongoClient.connect(config.databaseConnectionString, {}, (err, client) => { | |||
|     db.pages = db.collection('pages'); | ||||
|     db.menu = db.collection('menu'); | ||||
|     db.customers = db.collection('customers'); | ||||
|     db.cart = db.collection('cart'); | ||||
|     db.sessions = db.collection('sessions'); | ||||
| 
 | ||||
|     // add db to app for routes
 | ||||
|     app.dbClient = client; | ||||
|  | @ -353,6 +357,20 @@ MongoClient.connect(config.databaseConnectionString, {}, (err, client) => { | |||
|     app.config = config; | ||||
|     app.port = app.get('port'); | ||||
| 
 | ||||
|     // Fire up the cron job to clear temp held stock
 | ||||
|     cron.schedule('*/1 * * * *', async () => { | ||||
|         const validSessions = await db.sessions.find({}).toArray(); | ||||
|         const validSessionIds = []; | ||||
|         _.forEach(validSessions, (value) => { | ||||
|             validSessionIds.push(value._id); | ||||
|         }); | ||||
| 
 | ||||
|         // Remove any invalid cart holds
 | ||||
|         await db.cart.remove({ | ||||
|             sessionId: {$nin: validSessionIds} | ||||
|         }); | ||||
|     }); | ||||
| 
 | ||||
|     // run indexing
 | ||||
|     common.runIndexing(app) | ||||
|     .then(app.listen(app.get('port'))) | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ const colors = require('colors'); | |||
| const async = require('async'); | ||||
| const _ = require('lodash'); | ||||
| const common = require('../lib/common'); | ||||
| const ObjectId = require('mongodb').ObjectID; | ||||
| 
 | ||||
| // These is the customer facing routes
 | ||||
| router.get('/payment/:orderId', async (req, res, next) => { | ||||
|  | @ -207,10 +208,15 @@ router.post('/product/updatecart', (req, res, next) => { | |||
|                 } | ||||
|             }); | ||||
|         } | ||||
|     }, () => { | ||||
|     }, async () => { | ||||
|         // update total cart amount
 | ||||
|         common.updateTotalCartAmount(req, res); | ||||
| 
 | ||||
|         // Update cart to the DB
 | ||||
|         await db.cart.update({sessionId: req.session.id}, { | ||||
|             $set: {cart: req.session.cart} | ||||
|         }); | ||||
| 
 | ||||
|         // show response
 | ||||
|         if(hasError === false){ | ||||
|             res.status(200).json({message: 'Cart successfully updated', totalCartItems: Object.keys(req.session.cart).length}); | ||||
|  | @ -226,6 +232,8 @@ router.post('/product/updatecart', (req, res, next) => { | |||
| 
 | ||||
| // Remove single product from cart
 | ||||
| router.post('/product/removefromcart', (req, res, next) => { | ||||
|     const db = req.app.db; | ||||
| 
 | ||||
|     // remove item from cart
 | ||||
|     async.each(req.session.cart, (item, callback) => { | ||||
|         if(item){ | ||||
|  | @ -234,7 +242,11 @@ router.post('/product/removefromcart', (req, res, next) => { | |||
|             } | ||||
|         } | ||||
|         callback(); | ||||
|     }, () => { | ||||
|     }, async () => { | ||||
|         // Update cart in DB
 | ||||
|         await db.cart.update({sessionId: req.session.id}, { | ||||
|             $set: {cart: req.session.cart} | ||||
|         }); | ||||
|         // update total cart amount
 | ||||
|         common.updateTotalCartAmount(req, res); | ||||
|         res.status(200).json({message: 'Product successfully removed', totalCartItems: Object.keys(req.session.cart).length}); | ||||
|  | @ -242,10 +254,16 @@ router.post('/product/removefromcart', (req, res, next) => { | |||
| }); | ||||
| 
 | ||||
| // Totally empty the cart
 | ||||
| router.post('/product/emptycart', (req, res, next) => { | ||||
| router.post('/product/emptycart', async (req, res, next) => { | ||||
|     const db = req.app.db; | ||||
| 
 | ||||
|     // Remove from session
 | ||||
|     delete req.session.cart; | ||||
|     delete req.session.orderId; | ||||
| 
 | ||||
|     // Remove cart from DB
 | ||||
|     await db.cart.removeOne({sessionId: req.session.id}); | ||||
| 
 | ||||
|     // update total cart amount
 | ||||
|     common.updateTotalCartAmount(req, res); | ||||
|     res.status(200).json({message: 'Cart successfully emptied', totalCartItems: 0}); | ||||
|  | @ -269,7 +287,7 @@ router.post('/product/addtocart', (req, res, next) => { | |||
|     } | ||||
| 
 | ||||
|     // Get the item from the DB
 | ||||
|     db.products.findOne({_id: common.getId(req.body.productId)}, (err, product) => { | ||||
|     db.products.findOne({_id: common.getId(req.body.productId)}, async (err, product) => { | ||||
|         if(err){ | ||||
|             console.error(colors.red('Error adding to cart', err)); | ||||
|             return res.status(400).json({message: 'Error updating cart. Please try again.'}); | ||||
|  | @ -281,9 +299,36 @@ router.post('/product/addtocart', (req, res, next) => { | |||
|         } | ||||
| 
 | ||||
|         // If stock management on check there is sufficient stock for this product
 | ||||
|         if(config.trackStock){ | ||||
|             if(productQuantity > product.productStock){ | ||||
|                 return res.status(400).json({message: 'There is insufficient stock of this product.'}); | ||||
|         if(config.trackStock && product.productStock){ | ||||
|             const stockHeld = await db.cart.aggregate( | ||||
|                 { | ||||
|                     $match: { | ||||
|                         cart: {$elemMatch: {productId: product._id.toString()}} | ||||
|                     } | ||||
|                 }, | ||||
|                 {$unwind: '$cart'}, | ||||
|                 { | ||||
|                     $group: { | ||||
|                         _id: '$cart.productId', | ||||
|                         sumHeld: {$sum: '$cart.quantity'} | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     $project: { | ||||
|                         sumHeld: 1 | ||||
|                     } | ||||
|                 } | ||||
|             ).toArray(); | ||||
| 
 | ||||
|             // If there is stock
 | ||||
|             if(stockHeld.length > 0){ | ||||
|                 const totalHeld = _.find(stockHeld, {_id: product._id.toString()}).sumHeld; | ||||
|                 const netStock = product.productStock - totalHeld; | ||||
| 
 | ||||
|                 // Check there is sufficient stock
 | ||||
|                 if(productQuantity > netStock){ | ||||
|                     return res.status(400).json({message: 'There is insufficient stock of this product.'}); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|  | @ -301,13 +346,18 @@ router.post('/product/addtocart', (req, res, next) => { | |||
| 
 | ||||
|         // if exists we add to the existing value
 | ||||
|         let cartIndex = _.findIndex(req.session.cart, findDoc); | ||||
|         let cartQuantity = 0; | ||||
|         if(cartIndex > -1){ | ||||
|             req.session.cart[cartIndex].quantity = parseInt(req.session.cart[cartIndex].quantity) + productQuantity; | ||||
|             cartQuantity = parseInt(req.session.cart[cartIndex].quantity) + productQuantity; | ||||
|             req.session.cart[cartIndex].quantity = cartQuantity; | ||||
|             req.session.cart[cartIndex].totalItemPrice = productPrice * parseInt(req.session.cart[cartIndex].quantity); | ||||
|         }else{ | ||||
|             // Doesnt exist so we add to the cart session
 | ||||
|             req.session.cartTotalItems = req.session.cartTotalItems + productQuantity; | ||||
| 
 | ||||
|             // Set the card quantity
 | ||||
|             cartQuantity = productQuantity; | ||||
| 
 | ||||
|             // new product deets
 | ||||
|             let productObj = {}; | ||||
|             productObj.productId = req.body.productId; | ||||
|  | @ -327,6 +377,11 @@ router.post('/product/addtocart', (req, res, next) => { | |||
|             req.session.cart.push(productObj); | ||||
|         } | ||||
| 
 | ||||
|         // Update cart to the DB
 | ||||
|         await db.cart.update({sessionId: req.session.id}, { | ||||
|             $set: {cart: req.session.cart} | ||||
|         }, {upsert: true}); | ||||
| 
 | ||||
|         // update total cart amount
 | ||||
|         common.updateTotalCartAmount(req, res); | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue