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,11 +299,38 @@ 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){
|
||||
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.'});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let productPrice = parseFloat(product.productPrice).toFixed(2);
|
||||
|
||||
|
@ -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