2018-01-07 04:55:48 +10:00
|
|
|
const express = require('express');
|
|
|
|
const router = express.Router();
|
|
|
|
const colors = require('colors');
|
2018-02-04 01:23:59 +10:00
|
|
|
const async = require('async');
|
2018-01-07 04:55:48 +10:00
|
|
|
const _ = require('lodash');
|
2019-06-15 15:52:32 +10:00
|
|
|
const {
|
|
|
|
getId,
|
|
|
|
hooker,
|
|
|
|
showCartCloseBtn,
|
|
|
|
clearSessionValue,
|
|
|
|
sortMenu,
|
|
|
|
getMenu,
|
|
|
|
getPaymentConfig,
|
|
|
|
getImages,
|
|
|
|
updateTotalCartAmount,
|
2019-11-06 20:40:27 +10:00
|
|
|
updateSubscriptionCheck,
|
2019-06-15 15:52:32 +10:00
|
|
|
getData,
|
|
|
|
addSitemapProducts
|
2019-11-06 18:31:25 +10:00
|
|
|
} = require('../lib/common');
|
2018-01-07 04:55:48 +10:00
|
|
|
|
2018-02-05 23:20:44 +10:00
|
|
|
// These is the customer facing routes
|
2018-01-15 03:02:10 +10:00
|
|
|
router.get('/payment/:orderId', async (req, res, next) => {
|
2019-07-12 18:06:34 +10:00
|
|
|
const db = req.app.db;
|
|
|
|
const config = req.app.config;
|
2018-01-07 04:55:48 +10:00
|
|
|
|
2019-10-26 11:08:53 +10:00
|
|
|
// Get the order
|
|
|
|
const order = await db.orders.findOne({ _id: getId(req.params.orderId) });
|
|
|
|
if(!order){
|
|
|
|
res.render('error', { title: 'Not found', message: 'Order not found', helpers: req.handlebars.helpers, config });
|
|
|
|
return;
|
|
|
|
}
|
2019-02-09 14:07:02 +10:00
|
|
|
|
2019-10-26 11:08:53 +10:00
|
|
|
// If stock management is turned on payment approved update stock level
|
|
|
|
if(config.trackStock && req.session.paymentApproved){
|
|
|
|
order.orderProducts.forEach(async (product) => {
|
|
|
|
const dbProduct = await db.products.findOne({ _id: getId(product.productId) });
|
|
|
|
let newStockLevel = dbProduct.productStock - product.quantity;
|
|
|
|
if(newStockLevel < 1){
|
|
|
|
newStockLevel = 0;
|
|
|
|
}
|
2019-02-09 14:07:02 +10:00
|
|
|
|
2019-10-26 11:08:53 +10:00
|
|
|
// Update product stock
|
2019-10-29 18:26:30 +10:00
|
|
|
await db.products.updateOne({
|
2019-10-26 11:08:53 +10:00
|
|
|
_id: getId(product.productId)
|
|
|
|
}, {
|
|
|
|
$set: {
|
|
|
|
productStock: newStockLevel
|
|
|
|
}
|
|
|
|
}, { multi: false });
|
|
|
|
});
|
|
|
|
}
|
2019-02-09 14:07:02 +10:00
|
|
|
|
2019-10-26 11:08:53 +10:00
|
|
|
// If hooks are configured, send hook
|
|
|
|
if(config.orderHook){
|
|
|
|
await hooker(order);
|
|
|
|
};
|
2019-06-15 15:52:32 +10:00
|
|
|
|
2019-10-26 11:08:53 +10:00
|
|
|
res.render(`${config.themeViews}payment_complete`, {
|
|
|
|
title: 'Payment complete',
|
|
|
|
config: req.app.config,
|
|
|
|
session: req.session,
|
|
|
|
pageCloseBtn: showCartCloseBtn('payment'),
|
|
|
|
result: order,
|
|
|
|
message: clearSessionValue(req.session, 'message'),
|
|
|
|
messageType: clearSessionValue(req.session, 'messageType'),
|
|
|
|
helpers: req.handlebars.helpers,
|
|
|
|
showFooter: 'showFooter',
|
|
|
|
menu: sortMenu(await getMenu(db))
|
2018-01-07 04:55:48 +10:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2019-11-06 20:40:27 +10:00
|
|
|
router.get('/emptycart', async (req, res, next) => {
|
|
|
|
emptyCart(req, res, '');
|
|
|
|
});
|
|
|
|
|
2018-01-15 03:02:10 +10:00
|
|
|
router.get('/checkout', async (req, res, next) => {
|
2019-07-12 18:06:34 +10:00
|
|
|
const config = req.app.config;
|
2018-01-07 04:55:48 +10:00
|
|
|
|
|
|
|
// if there is no items in the cart then render a failure
|
|
|
|
if(!req.session.cart){
|
|
|
|
req.session.message = 'The are no items in your cart. Please add some items before checking out';
|
|
|
|
req.session.messageType = 'danger';
|
|
|
|
res.redirect('/');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// render the checkout
|
2018-01-15 07:11:22 +10:00
|
|
|
res.render(`${config.themeViews}checkout`, {
|
2018-01-07 04:55:48 +10:00
|
|
|
title: 'Checkout',
|
2018-02-23 03:41:24 +10:00
|
|
|
config: req.app.config,
|
2018-01-07 04:55:48 +10:00
|
|
|
session: req.session,
|
2019-06-15 15:52:32 +10:00
|
|
|
pageCloseBtn: showCartCloseBtn('checkout'),
|
2018-01-07 04:55:48 +10:00
|
|
|
checkout: 'hidden',
|
|
|
|
page: 'checkout',
|
2019-06-15 15:52:32 +10:00
|
|
|
message: clearSessionValue(req.session, 'message'),
|
|
|
|
messageType: clearSessionValue(req.session, 'messageType'),
|
2018-01-07 04:55:48 +10:00
|
|
|
helpers: req.handlebars.helpers,
|
2018-01-15 03:02:10 +10:00
|
|
|
showFooter: 'showFooter'
|
2018-01-07 04:55:48 +10:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2018-01-15 03:02:10 +10:00
|
|
|
router.get('/pay', async (req, res, next) => {
|
2018-02-23 03:41:24 +10:00
|
|
|
const config = req.app.config;
|
2018-01-07 04:55:48 +10:00
|
|
|
|
|
|
|
// if there is no items in the cart then render a failure
|
|
|
|
if(!req.session.cart){
|
|
|
|
req.session.message = 'The are no items in your cart. Please add some items before checking out';
|
|
|
|
req.session.messageType = 'danger';
|
|
|
|
res.redirect('/checkout');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-11-06 20:40:27 +10:00
|
|
|
let paymentType = '';
|
|
|
|
if(req.session.cartSubscription){
|
|
|
|
paymentType = '_subscription';
|
|
|
|
}
|
|
|
|
|
2018-01-07 04:55:48 +10:00
|
|
|
// render the payment page
|
2018-01-15 07:11:22 +10:00
|
|
|
res.render(`${config.themeViews}pay`, {
|
2018-01-07 04:55:48 +10:00
|
|
|
title: 'Pay',
|
2018-02-23 03:41:24 +10:00
|
|
|
config: req.app.config,
|
2019-06-15 15:52:32 +10:00
|
|
|
paymentConfig: getPaymentConfig(),
|
|
|
|
pageCloseBtn: showCartCloseBtn('pay'),
|
2018-01-07 04:55:48 +10:00
|
|
|
session: req.session,
|
|
|
|
paymentPage: true,
|
2019-11-06 20:40:27 +10:00
|
|
|
paymentType,
|
2018-01-07 04:55:48 +10:00
|
|
|
page: 'pay',
|
2019-06-15 15:52:32 +10:00
|
|
|
message: clearSessionValue(req.session, 'message'),
|
|
|
|
messageType: clearSessionValue(req.session, 'messageType'),
|
2018-01-07 04:55:48 +10:00
|
|
|
helpers: req.handlebars.helpers,
|
2018-01-15 03:02:10 +10:00
|
|
|
showFooter: 'showFooter'
|
2018-01-07 04:55:48 +10:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
router.get('/cartPartial', (req, res) => {
|
2018-02-23 03:41:24 +10:00
|
|
|
const config = req.app.config;
|
2018-02-14 06:21:22 +10:00
|
|
|
|
|
|
|
res.render(`${config.themeViews}cart`, {
|
2019-06-15 15:52:32 +10:00
|
|
|
pageCloseBtn: showCartCloseBtn(req.query.path),
|
2018-01-07 04:55:48 +10:00
|
|
|
page: req.query.path,
|
|
|
|
layout: false,
|
|
|
|
helpers: req.handlebars.helpers,
|
2018-02-23 03:41:24 +10:00
|
|
|
config: req.app.config,
|
2018-01-07 04:55:48 +10:00
|
|
|
session: req.session
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
// show an individual product
|
2019-10-26 11:08:53 +10:00
|
|
|
router.get('/product/:id', async (req, res) => {
|
2019-07-12 18:06:34 +10:00
|
|
|
const db = req.app.db;
|
|
|
|
const config = req.app.config;
|
2018-01-07 04:55:48 +10:00
|
|
|
|
2019-10-26 11:08:53 +10:00
|
|
|
const product = await db.products.findOne({ $or: [{ _id: getId(req.params.id) }, { productPermalink: req.params.id }] });
|
|
|
|
if(!product){
|
|
|
|
res.render('error', { title: 'Not found', message: 'Order not found', helpers: req.handlebars.helpers, config });
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(product.productPublished === false){
|
|
|
|
res.render('error', { title: 'Not found', message: 'Product not found', helpers: req.handlebars.helpers, config });
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const productOptions = product.productOptions;
|
2018-01-07 04:55:48 +10:00
|
|
|
|
2019-10-26 11:08:53 +10:00
|
|
|
// If JSON query param return json instead
|
|
|
|
if(req.query.json === 'true'){
|
|
|
|
res.status(200).json(product);
|
|
|
|
return;
|
|
|
|
}
|
2018-02-23 03:41:24 +10:00
|
|
|
|
2019-10-26 11:08:53 +10:00
|
|
|
// show the view
|
|
|
|
const images = await getImages(product._id, req, res);
|
|
|
|
|
|
|
|
res.render(`${config.themeViews}product`, {
|
|
|
|
title: product.productTitle,
|
|
|
|
result: product,
|
|
|
|
productOptions: productOptions,
|
|
|
|
images: images,
|
|
|
|
productDescription: product.productDescription,
|
|
|
|
metaDescription: config.cartTitle + ' - ' + product.productTitle,
|
|
|
|
pageCloseBtn: showCartCloseBtn('product'),
|
|
|
|
config: config,
|
|
|
|
session: req.session,
|
|
|
|
pageUrl: config.baseUrl + req.originalUrl,
|
|
|
|
message: clearSessionValue(req.session, 'message'),
|
|
|
|
messageType: clearSessionValue(req.session, 'messageType'),
|
|
|
|
helpers: req.handlebars.helpers,
|
|
|
|
showFooter: 'showFooter',
|
|
|
|
menu: sortMenu(await getMenu(db))
|
2018-01-07 04:55:48 +10:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2018-02-04 01:23:59 +10:00
|
|
|
// Updates a single product quantity
|
|
|
|
router.post('/product/updatecart', (req, res, next) => {
|
|
|
|
const db = req.app.db;
|
2019-02-09 20:46:41 +10:00
|
|
|
const config = req.app.config;
|
2019-07-12 18:06:34 +10:00
|
|
|
const cartItems = JSON.parse(req.body.items);
|
2018-02-04 01:23:59 +10:00
|
|
|
let hasError = false;
|
2019-02-09 20:46:41 +10:00
|
|
|
let stockError = false;
|
2018-01-07 04:55:48 +10:00
|
|
|
|
2019-10-26 11:08:53 +10:00
|
|
|
async.eachSeries(cartItems, async (cartItem, callback) => {
|
2019-07-12 18:06:34 +10:00
|
|
|
const productQuantity = cartItem.itemQuantity ? cartItem.itemQuantity : 1;
|
2018-02-04 01:23:59 +10:00
|
|
|
if(cartItem.itemQuantity === 0){
|
|
|
|
// quantity equals zero so we remove the item
|
|
|
|
req.session.cart.splice(cartItem.cartIndex, 1);
|
|
|
|
callback(null);
|
|
|
|
}else{
|
2019-10-26 11:08:53 +10:00
|
|
|
const product = await db.products.findOne({ _id: getId(cartItem.productId) });
|
|
|
|
if(product){
|
|
|
|
// If stock management on check there is sufficient stock for this product
|
|
|
|
if(config.trackStock){
|
|
|
|
if(productQuantity > product.productStock){
|
|
|
|
hasError = true;
|
|
|
|
stockError = true;
|
2018-02-04 01:23:59 +10:00
|
|
|
callback(null);
|
2019-10-26 11:08:53 +10:00
|
|
|
return;
|
2018-02-04 01:23:59 +10:00
|
|
|
}
|
2019-10-26 11:08:53 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
const productPrice = parseFloat(product.productPrice).toFixed(2);
|
|
|
|
if(req.session.cart[cartItem.cartIndex]){
|
|
|
|
req.session.cart[cartItem.cartIndex].quantity = productQuantity;
|
|
|
|
req.session.cart[cartItem.cartIndex].totalItemPrice = productPrice * productQuantity;
|
2018-02-04 01:23:59 +10:00
|
|
|
callback(null);
|
|
|
|
}
|
2019-10-26 11:08:53 +10:00
|
|
|
}else{
|
|
|
|
hasError = true;
|
|
|
|
callback(null);
|
|
|
|
}
|
2018-02-04 01:23:59 +10:00
|
|
|
}
|
2019-06-01 22:22:14 +10:00
|
|
|
}, async () => {
|
2018-02-04 01:23:59 +10:00
|
|
|
// update total cart amount
|
2019-06-15 15:52:32 +10:00
|
|
|
updateTotalCartAmount(req, res);
|
2018-02-04 01:23:59 +10:00
|
|
|
|
2019-11-06 20:40:27 +10:00
|
|
|
// Update checking cart for subscription
|
|
|
|
updateSubscriptionCheck(req, res);
|
|
|
|
|
2019-06-01 22:22:14 +10:00
|
|
|
// Update cart to the DB
|
2019-10-29 18:26:30 +10:00
|
|
|
await db.cart.updateOne({ sessionId: req.session.id }, {
|
2019-06-15 14:46:08 +10:00
|
|
|
$set: { cart: req.session.cart }
|
2019-06-01 22:22:14 +10:00
|
|
|
});
|
|
|
|
|
2018-02-04 01:23:59 +10:00
|
|
|
// show response
|
|
|
|
if(hasError === false){
|
2019-06-15 14:46:08 +10:00
|
|
|
res.status(200).json({ message: 'Cart successfully updated', totalCartItems: Object.keys(req.session.cart).length });
|
2018-01-07 04:55:48 +10:00
|
|
|
}else{
|
2019-02-09 20:46:41 +10:00
|
|
|
if(stockError){
|
2019-06-15 14:46:08 +10:00
|
|
|
res.status(400).json({ message: 'There is insufficient stock of this product.', totalCartItems: Object.keys(req.session.cart).length });
|
2019-02-09 20:46:41 +10:00
|
|
|
}else{
|
2019-06-15 14:46:08 +10:00
|
|
|
res.status(400).json({ message: 'There was an error updating the cart', totalCartItems: Object.keys(req.session.cart).length });
|
2019-02-09 20:46:41 +10:00
|
|
|
}
|
2018-01-07 04:55:48 +10:00
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2018-02-04 01:23:59 +10:00
|
|
|
// Remove single product from cart
|
2019-11-06 20:40:27 +10:00
|
|
|
router.post('/product/removefromcart', async (req, res, next) => {
|
2019-06-01 22:22:14 +10:00
|
|
|
const db = req.app.db;
|
2019-06-11 15:12:07 +10:00
|
|
|
let itemRemoved = false;
|
2019-06-01 22:22:14 +10:00
|
|
|
|
2018-02-04 01:23:59 +10:00
|
|
|
// remove item from cart
|
2019-11-06 20:40:27 +10:00
|
|
|
req.session.cart.forEach((item) => {
|
2018-02-04 01:23:59 +10:00
|
|
|
if(item){
|
2019-06-11 15:12:07 +10:00
|
|
|
if(item.productId === req.body.cartId){
|
|
|
|
itemRemoved = true;
|
2018-02-04 05:14:13 +10:00
|
|
|
req.session.cart = _.pull(req.session.cart, item);
|
2018-02-04 01:23:59 +10:00
|
|
|
}
|
2018-01-07 04:55:48 +10:00
|
|
|
}
|
2019-11-06 20:40:27 +10:00
|
|
|
});
|
2019-06-11 15:12:07 +10:00
|
|
|
|
2019-11-06 20:40:27 +10:00
|
|
|
// Update cart in DB
|
|
|
|
await db.cart.updateOne({ sessionId: req.session.id }, {
|
|
|
|
$set: { cart: req.session.cart }
|
2018-01-07 04:55:48 +10:00
|
|
|
});
|
2019-11-06 20:40:27 +10:00
|
|
|
// update total cart amount
|
|
|
|
updateTotalCartAmount(req, res);
|
|
|
|
|
|
|
|
// Update checking cart for subscription
|
|
|
|
updateSubscriptionCheck(req, res);
|
|
|
|
|
|
|
|
if(itemRemoved === false){
|
|
|
|
return res.status(400).json({ message: 'Product not found in cart' });
|
|
|
|
}
|
|
|
|
return res.status(200).json({ message: 'Product successfully removed', totalCartItems: Object.keys(req.session.cart).length });
|
2018-01-07 04:55:48 +10:00
|
|
|
});
|
|
|
|
|
2018-02-04 01:23:59 +10:00
|
|
|
// Totally empty the cart
|
2019-06-01 22:22:14 +10:00
|
|
|
router.post('/product/emptycart', async (req, res, next) => {
|
2019-11-06 20:40:27 +10:00
|
|
|
emptyCart(req, res, 'json');
|
|
|
|
});
|
|
|
|
|
|
|
|
const emptyCart = async (req, res, type) => {
|
2019-06-01 22:22:14 +10:00
|
|
|
const db = req.app.db;
|
|
|
|
|
|
|
|
// Remove from session
|
2018-02-04 01:23:59 +10:00
|
|
|
delete req.session.cart;
|
|
|
|
delete req.session.orderId;
|
2018-01-07 04:55:48 +10:00
|
|
|
|
2019-06-01 22:22:14 +10:00
|
|
|
// Remove cart from DB
|
2019-10-29 18:26:30 +10:00
|
|
|
await db.cart.deleteOne({ sessionId: req.session.id });
|
2019-06-01 22:22:14 +10:00
|
|
|
|
2018-02-04 01:23:59 +10:00
|
|
|
// update total cart amount
|
2019-06-15 15:52:32 +10:00
|
|
|
updateTotalCartAmount(req, res);
|
2019-11-06 20:40:27 +10:00
|
|
|
|
|
|
|
// Update checking cart for subscription
|
|
|
|
updateSubscriptionCheck(req, res);
|
|
|
|
|
|
|
|
// If POST, return JSON else redirect nome
|
|
|
|
if(type === 'json'){
|
|
|
|
res.status(200).json({ message: 'Cart successfully emptied', totalCartItems: 0 });
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
req.session.message = 'Cart successfully emptied.';
|
|
|
|
req.session.messageType = 'success';
|
|
|
|
res.redirect('/');
|
|
|
|
};
|
2018-02-04 01:23:59 +10:00
|
|
|
|
|
|
|
// Add item to cart
|
2019-10-26 11:08:53 +10:00
|
|
|
router.post('/product/addtocart', async (req, res, next) => {
|
2018-02-04 01:23:59 +10:00
|
|
|
const db = req.app.db;
|
2019-02-09 14:07:02 +10:00
|
|
|
const config = req.app.config;
|
2018-02-04 01:23:59 +10:00
|
|
|
let productQuantity = req.body.productQuantity ? parseInt(req.body.productQuantity) : 1;
|
2018-10-05 21:54:42 +10:00
|
|
|
const productComment = req.body.productComment ? req.body.productComment : null;
|
2018-02-04 01:23:59 +10:00
|
|
|
|
2018-05-21 23:36:12 +10:00
|
|
|
// Don't allow negative quantity
|
|
|
|
if(productQuantity < 0){
|
|
|
|
productQuantity = 1;
|
|
|
|
}
|
|
|
|
|
2018-02-04 01:23:59 +10:00
|
|
|
// setup cart object if it doesn't exist
|
|
|
|
if(!req.session.cart){
|
|
|
|
req.session.cart = [];
|
|
|
|
}
|
|
|
|
|
2019-11-06 20:40:27 +10:00
|
|
|
// Get the product from the DB
|
2019-10-26 11:08:53 +10:00
|
|
|
const product = await db.products.findOne({ _id: getId(req.body.productId) });
|
|
|
|
// No product found
|
|
|
|
if(!product){
|
|
|
|
return res.status(400).json({ message: 'Error updating cart. Please try again.' });
|
|
|
|
}
|
2018-02-04 01:23:59 +10:00
|
|
|
|
2019-11-06 20:40:27 +10:00
|
|
|
// If cart already has a subscription you cannot add anything else
|
|
|
|
if(req.session.cartSubscription){
|
|
|
|
return res.status(400).json({ message: 'Subscription already existing in cart. You cannot add more.' });
|
|
|
|
}
|
|
|
|
|
|
|
|
// If existing cart isn't empty check if product is a subscription
|
|
|
|
if(req.session.cart.length !== 0){
|
|
|
|
if(product.productSubscription){
|
|
|
|
return res.status(400).json({ message: 'You cannot combine scubscription products with existing in your cart. Empty your cart and try again.' });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-26 11:08:53 +10:00
|
|
|
// If stock management on check there is sufficient stock for 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
|
2019-06-01 22:22:14 +10:00
|
|
|
}
|
2019-10-26 11:08:53 +10:00
|
|
|
}
|
|
|
|
).toArray();
|
2019-06-01 22:22:14 +10:00
|
|
|
|
2019-10-26 11:08:53 +10:00
|
|
|
// If there is stock
|
|
|
|
if(stockHeld.length > 0){
|
|
|
|
const totalHeld = _.find(stockHeld, { _id: product._id.toString() }).sumHeld;
|
|
|
|
const netStock = product.productStock - totalHeld;
|
2019-06-01 22:22:14 +10:00
|
|
|
|
2019-10-26 11:08:53 +10:00
|
|
|
// Check there is sufficient stock
|
|
|
|
if(productQuantity > netStock){
|
|
|
|
return res.status(400).json({ message: 'There is insufficient stock of this product.' });
|
2019-02-09 14:07:02 +10:00
|
|
|
}
|
|
|
|
}
|
2019-10-26 11:08:53 +10:00
|
|
|
}
|
2019-02-09 14:07:02 +10:00
|
|
|
|
2019-10-26 11:08:53 +10:00
|
|
|
const productPrice = parseFloat(product.productPrice).toFixed(2);
|
2018-02-04 01:23:59 +10:00
|
|
|
|
2019-10-26 11:08:53 +10:00
|
|
|
// Doc used to test if existing in the cart with the options. If not found, we add new.
|
|
|
|
let options = {};
|
|
|
|
if(req.body.productOptions){
|
2019-11-06 20:40:27 +10:00
|
|
|
try{
|
|
|
|
if(typeof req.body.productOptions === 'object'){
|
|
|
|
options = req.body.productOptions;
|
|
|
|
}else{
|
|
|
|
options = JSON.parse(req.body.productOptions);
|
|
|
|
}
|
|
|
|
}catch(ex){}
|
2019-10-26 11:08:53 +10:00
|
|
|
}
|
|
|
|
const findDoc = {
|
|
|
|
productId: req.body.productId,
|
|
|
|
options: options
|
|
|
|
};
|
|
|
|
|
|
|
|
// if exists we add to the existing value
|
|
|
|
const cartIndex = _.findIndex(req.session.cart, findDoc);
|
|
|
|
let cartQuantity = 0;
|
|
|
|
if(cartIndex > -1){
|
|
|
|
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
|
|
|
|
const productObj = {};
|
|
|
|
productObj.productId = req.body.productId;
|
|
|
|
productObj.title = product.productTitle;
|
|
|
|
productObj.quantity = productQuantity;
|
|
|
|
productObj.totalItemPrice = productPrice * productQuantity;
|
|
|
|
productObj.options = options;
|
|
|
|
productObj.productImage = product.productImage;
|
|
|
|
productObj.productComment = productComment;
|
2019-11-06 20:40:27 +10:00
|
|
|
productObj.productSubscription = product.productSubscription;
|
2019-10-26 11:08:53 +10:00
|
|
|
if(product.productPermalink){
|
|
|
|
productObj.link = product.productPermalink;
|
2018-02-23 03:41:24 +10:00
|
|
|
}else{
|
2019-10-26 11:08:53 +10:00
|
|
|
productObj.link = product._id;
|
2018-01-07 04:55:48 +10:00
|
|
|
}
|
2018-02-23 03:41:24 +10:00
|
|
|
|
2019-10-26 11:08:53 +10:00
|
|
|
// merge into the current cart
|
|
|
|
req.session.cart.push(productObj);
|
|
|
|
}
|
2019-06-01 22:22:14 +10:00
|
|
|
|
2019-10-26 11:08:53 +10:00
|
|
|
// Update cart to the DB
|
2019-10-29 18:26:30 +10:00
|
|
|
await db.cart.updateOne({ sessionId: req.session.id }, {
|
2019-10-26 11:08:53 +10:00
|
|
|
$set: { cart: req.session.cart }
|
|
|
|
}, { upsert: true });
|
2018-02-23 03:41:24 +10:00
|
|
|
|
2019-10-26 11:08:53 +10:00
|
|
|
// update total cart amount
|
|
|
|
updateTotalCartAmount(req, res);
|
|
|
|
|
2019-11-06 20:40:27 +10:00
|
|
|
// Update checking cart for subscription
|
|
|
|
updateSubscriptionCheck(req, res);
|
|
|
|
|
|
|
|
if(product.productSubscription){
|
|
|
|
req.session.cartSubscription = product.productSubscription;
|
|
|
|
}
|
|
|
|
|
2019-10-26 11:08:53 +10:00
|
|
|
// update how many products in the shopping cart
|
|
|
|
req.session.cartTotalItems = req.session.cart.reduce((a, b) => +a + +b.quantity, 0);
|
|
|
|
return res.status(200).json({ message: 'Cart successfully updated', totalCartItems: req.session.cartTotalItems });
|
2018-01-07 04:55:48 +10:00
|
|
|
});
|
|
|
|
|
|
|
|
// search products
|
2018-01-07 05:35:49 +10:00
|
|
|
router.get('/search/:searchTerm/:pageNum?', (req, res) => {
|
2019-07-12 18:06:34 +10:00
|
|
|
const db = req.app.db;
|
|
|
|
const searchTerm = req.params.searchTerm;
|
|
|
|
const productsIndex = req.app.productsIndex;
|
|
|
|
const config = req.app.config;
|
|
|
|
const numberProducts = config.productsPerPage ? config.productsPerPage : 6;
|
2018-01-07 05:35:49 +10:00
|
|
|
|
2019-07-12 18:06:34 +10:00
|
|
|
const lunrIdArray = [];
|
2018-01-07 05:35:49 +10:00
|
|
|
productsIndex.search(searchTerm).forEach((id) => {
|
2019-06-15 15:52:32 +10:00
|
|
|
lunrIdArray.push(getId(id.ref));
|
2018-01-07 04:55:48 +10:00
|
|
|
});
|
|
|
|
|
2018-01-07 05:35:49 +10:00
|
|
|
let pageNum = 1;
|
2018-01-07 04:55:48 +10:00
|
|
|
if(req.params.pageNum){
|
|
|
|
pageNum = req.params.pageNum;
|
|
|
|
}
|
|
|
|
|
2018-01-15 07:11:22 +10:00
|
|
|
Promise.all([
|
2019-06-15 15:52:32 +10:00
|
|
|
getData(req, pageNum, { _id: { $in: lunrIdArray } }),
|
|
|
|
getMenu(db)
|
2018-01-15 07:11:22 +10:00
|
|
|
])
|
2019-11-06 18:31:25 +10:00
|
|
|
.then(([results, menu]) => {
|
|
|
|
// If JSON query param return json instead
|
|
|
|
if(req.query.json === 'true'){
|
|
|
|
res.status(200).json(results.data);
|
|
|
|
return;
|
|
|
|
}
|
2018-02-23 03:41:24 +10:00
|
|
|
|
2019-11-06 18:31:25 +10:00
|
|
|
res.render(`${config.themeViews}index`, {
|
|
|
|
title: 'Results',
|
|
|
|
results: results.data,
|
|
|
|
filtered: true,
|
|
|
|
session: req.session,
|
|
|
|
metaDescription: req.app.config.cartTitle + ' - Search term: ' + searchTerm,
|
|
|
|
searchTerm: searchTerm,
|
|
|
|
pageCloseBtn: showCartCloseBtn('search'),
|
|
|
|
message: clearSessionValue(req.session, 'message'),
|
|
|
|
messageType: clearSessionValue(req.session, 'messageType'),
|
|
|
|
productsPerPage: numberProducts,
|
|
|
|
totalProductCount: results.totalProducts,
|
|
|
|
pageNum: pageNum,
|
|
|
|
paginateUrl: 'search',
|
|
|
|
config: config,
|
|
|
|
menu: sortMenu(menu),
|
|
|
|
helpers: req.handlebars.helpers,
|
|
|
|
showFooter: 'showFooter'
|
|
|
|
});
|
|
|
|
})
|
|
|
|
.catch((err) => {
|
|
|
|
console.error(colors.red('Error searching for products', err));
|
2018-01-07 04:55:48 +10:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
// search products
|
2018-01-07 05:35:49 +10:00
|
|
|
router.get('/category/:cat/:pageNum?', (req, res) => {
|
2019-07-12 18:06:34 +10:00
|
|
|
const db = req.app.db;
|
|
|
|
const searchTerm = req.params.cat;
|
|
|
|
const productsIndex = req.app.productsIndex;
|
|
|
|
const config = req.app.config;
|
|
|
|
const numberProducts = config.productsPerPage ? config.productsPerPage : 6;
|
2018-01-07 05:35:49 +10:00
|
|
|
|
2019-07-12 18:06:34 +10:00
|
|
|
const lunrIdArray = [];
|
2018-01-07 05:35:49 +10:00
|
|
|
productsIndex.search(searchTerm).forEach((id) => {
|
2019-06-15 15:52:32 +10:00
|
|
|
lunrIdArray.push(getId(id.ref));
|
2018-01-07 04:55:48 +10:00
|
|
|
});
|
|
|
|
|
2018-01-07 05:35:49 +10:00
|
|
|
let pageNum = 1;
|
2018-01-07 04:55:48 +10:00
|
|
|
if(req.params.pageNum){
|
|
|
|
pageNum = req.params.pageNum;
|
|
|
|
}
|
|
|
|
|
2018-01-15 07:11:22 +10:00
|
|
|
Promise.all([
|
2019-06-15 15:52:32 +10:00
|
|
|
getData(req, pageNum, { _id: { $in: lunrIdArray } }),
|
|
|
|
getMenu(db)
|
2018-01-15 07:11:22 +10:00
|
|
|
])
|
2019-11-06 18:31:25 +10:00
|
|
|
.then(([results, menu]) => {
|
|
|
|
const sortedMenu = sortMenu(menu);
|
2018-01-07 04:55:48 +10:00
|
|
|
|
2019-11-06 18:31:25 +10:00
|
|
|
// If JSON query param return json instead
|
|
|
|
if(req.query.json === 'true'){
|
|
|
|
res.status(200).json(results.data);
|
|
|
|
return;
|
|
|
|
}
|
2018-02-23 03:41:24 +10:00
|
|
|
|
2019-11-06 18:31:25 +10:00
|
|
|
res.render(`${config.themeViews}index`, {
|
2019-12-18 19:18:31 +10:00
|
|
|
title: `Category: ${searchTerm}`,
|
2019-11-06 18:31:25 +10:00
|
|
|
results: results.data,
|
|
|
|
filtered: true,
|
|
|
|
session: req.session,
|
|
|
|
searchTerm: searchTerm,
|
2019-12-18 19:18:31 +10:00
|
|
|
metaDescription: `${req.app.config.cartTitle} - Category: ${searchTerm}`,
|
2019-11-06 18:31:25 +10:00
|
|
|
pageCloseBtn: showCartCloseBtn('category'),
|
|
|
|
message: clearSessionValue(req.session, 'message'),
|
|
|
|
messageType: clearSessionValue(req.session, 'messageType'),
|
|
|
|
productsPerPage: numberProducts,
|
|
|
|
totalProductCount: results.totalProducts,
|
|
|
|
pageNum: pageNum,
|
|
|
|
menuLink: _.find(sortedMenu.items, (obj) => { return obj.link === searchTerm; }),
|
|
|
|
paginateUrl: 'category',
|
|
|
|
config: config,
|
|
|
|
menu: sortedMenu,
|
|
|
|
helpers: req.handlebars.helpers,
|
|
|
|
showFooter: 'showFooter'
|
|
|
|
});
|
|
|
|
})
|
|
|
|
.catch((err) => {
|
|
|
|
console.error(colors.red('Error getting products for category', err));
|
2018-01-07 04:55:48 +10:00
|
|
|
});
|
2019-11-06 18:31:25 +10:00
|
|
|
});
|
|
|
|
|
|
|
|
// Language setup in cookie
|
|
|
|
router.get('/lang/:locale', (req, res) => {
|
|
|
|
res.cookie('locale', req.params.locale, { maxAge: 900000, httpOnly: true });
|
|
|
|
res.redirect('back');
|
2018-01-07 04:55:48 +10:00
|
|
|
});
|
|
|
|
|
|
|
|
// return sitemap
|
2018-01-07 05:35:49 +10:00
|
|
|
router.get('/sitemap.xml', (req, res, next) => {
|
2019-07-12 18:06:34 +10:00
|
|
|
const sm = require('sitemap');
|
|
|
|
const config = req.app.config;
|
2018-01-07 04:55:48 +10:00
|
|
|
|
2019-06-15 15:52:32 +10:00
|
|
|
addSitemapProducts(req, res, (err, products) => {
|
2018-01-07 04:55:48 +10:00
|
|
|
if(err){
|
|
|
|
console.error(colors.red('Error generating sitemap.xml', err));
|
|
|
|
}
|
2019-07-12 18:06:34 +10:00
|
|
|
const sitemap = sm.createSitemap(
|
2018-01-07 04:55:48 +10:00
|
|
|
{
|
|
|
|
hostname: config.baseUrl,
|
|
|
|
cacheTime: 600000,
|
|
|
|
urls: [
|
2019-06-15 14:46:08 +10:00
|
|
|
{ url: '/', changefreq: 'weekly', priority: 1.0 }
|
2018-01-07 04:55:48 +10:00
|
|
|
]
|
|
|
|
});
|
|
|
|
|
2019-07-12 18:06:34 +10:00
|
|
|
const currentUrls = sitemap.urls;
|
|
|
|
const mergedUrls = currentUrls.concat(products);
|
2018-01-07 04:55:48 +10:00
|
|
|
sitemap.urls = mergedUrls;
|
|
|
|
// render the sitemap
|
2018-01-07 05:35:49 +10:00
|
|
|
sitemap.toXML((err, xml) => {
|
2018-01-07 04:55:48 +10:00
|
|
|
if(err){
|
|
|
|
return res.status(500).end();
|
|
|
|
}
|
|
|
|
res.header('Content-Type', 'application/xml');
|
|
|
|
res.send(xml);
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2018-01-07 05:35:49 +10:00
|
|
|
router.get('/page/:pageNum', (req, res, next) => {
|
2019-07-12 18:06:34 +10:00
|
|
|
const db = req.app.db;
|
|
|
|
const config = req.app.config;
|
|
|
|
const numberProducts = config.productsPerPage ? config.productsPerPage : 6;
|
2018-01-07 04:55:48 +10:00
|
|
|
|
2018-01-15 07:11:22 +10:00
|
|
|
Promise.all([
|
2019-06-15 15:52:32 +10:00
|
|
|
getData(req, req.params.pageNum),
|
|
|
|
getMenu(db)
|
2018-01-15 07:11:22 +10:00
|
|
|
])
|
|
|
|
.then(([results, menu]) => {
|
2018-02-23 03:41:24 +10:00
|
|
|
// If JSON query param return json instead
|
|
|
|
if(req.query.json === 'true'){
|
|
|
|
res.status(200).json(results.data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-01-15 07:11:22 +10:00
|
|
|
res.render(`${config.themeViews}index`, {
|
2019-11-06 18:31:25 +10:00
|
|
|
title: 'Shop',
|
2018-01-07 04:55:48 +10:00
|
|
|
results: results.data,
|
|
|
|
session: req.session,
|
2019-06-15 15:52:32 +10:00
|
|
|
message: clearSessionValue(req.session, 'message'),
|
|
|
|
messageType: clearSessionValue(req.session, 'messageType'),
|
2019-11-06 18:31:25 +10:00
|
|
|
metaDescription: req.app.config.cartTitle + ' - Products page: ' + req.params.pageNum,
|
2019-06-15 15:52:32 +10:00
|
|
|
pageCloseBtn: showCartCloseBtn('page'),
|
2018-02-23 03:41:24 +10:00
|
|
|
config: req.app.config,
|
2018-01-07 04:55:48 +10:00
|
|
|
productsPerPage: numberProducts,
|
|
|
|
totalProductCount: results.totalProducts,
|
2019-11-06 18:31:25 +10:00
|
|
|
pageNum: req.params.pageNum,
|
2018-01-07 04:55:48 +10:00
|
|
|
paginateUrl: 'page',
|
|
|
|
helpers: req.handlebars.helpers,
|
|
|
|
showFooter: 'showFooter',
|
2019-06-15 15:52:32 +10:00
|
|
|
menu: sortMenu(menu)
|
2018-01-07 04:55:48 +10:00
|
|
|
});
|
2018-01-15 07:11:22 +10:00
|
|
|
})
|
|
|
|
.catch((err) => {
|
|
|
|
console.error(colors.red('Error getting products for page', err));
|
2018-01-07 04:55:48 +10:00
|
|
|
});
|
2019-11-06 18:31:25 +10:00
|
|
|
});
|
|
|
|
|
|
|
|
// The main entry point of the shop
|
|
|
|
router.get('/:page?', async (req, res, next) => {
|
|
|
|
const db = req.app.db;
|
|
|
|
const config = req.app.config;
|
|
|
|
const numberProducts = config.productsPerPage ? config.productsPerPage : 6;
|
|
|
|
|
|
|
|
// if no page is specified, just render page 1 of the cart
|
|
|
|
if(!req.params.page){
|
|
|
|
Promise.all([
|
|
|
|
getData(req, 1, {}),
|
|
|
|
getMenu(db)
|
|
|
|
])
|
|
|
|
.then(([results, menu]) => {
|
|
|
|
// If JSON query param return json instead
|
|
|
|
if(req.query.json === 'true'){
|
|
|
|
res.status(200).json(results.data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
res.render(`${config.themeViews}index`, {
|
|
|
|
title: `${config.cartTitle} - Shop`,
|
|
|
|
theme: config.theme,
|
|
|
|
results: results.data,
|
|
|
|
session: req.session,
|
|
|
|
message: clearSessionValue(req.session, 'message'),
|
|
|
|
messageType: clearSessionValue(req.session, 'messageType'),
|
|
|
|
pageCloseBtn: showCartCloseBtn('page'),
|
2019-11-06 18:43:16 +10:00
|
|
|
config,
|
2019-11-06 18:31:25 +10:00
|
|
|
productsPerPage: numberProducts,
|
|
|
|
totalProductCount: results.totalProducts,
|
|
|
|
pageNum: 1,
|
|
|
|
paginateUrl: 'page',
|
|
|
|
helpers: req.handlebars.helpers,
|
|
|
|
showFooter: 'showFooter',
|
|
|
|
menu: sortMenu(menu)
|
|
|
|
});
|
|
|
|
})
|
|
|
|
.catch((err) => {
|
|
|
|
console.error(colors.red('Error getting products for page', err));
|
|
|
|
});
|
2018-01-07 04:55:48 +10:00
|
|
|
}else{
|
|
|
|
if(req.params.page === 'admin'){
|
|
|
|
next();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// lets look for a page
|
2019-10-26 11:08:53 +10:00
|
|
|
const page = db.pages.findOne({ pageSlug: req.params.page, pageEnabled: 'true' });
|
|
|
|
// if we have a page lets render it, else throw 404
|
|
|
|
if(page){
|
|
|
|
res.render(`${config.themeViews}page`, {
|
|
|
|
title: page.pageName,
|
|
|
|
page: page,
|
|
|
|
searchTerm: req.params.page,
|
|
|
|
session: req.session,
|
|
|
|
message: clearSessionValue(req.session, 'message'),
|
|
|
|
messageType: clearSessionValue(req.session, 'messageType'),
|
|
|
|
pageCloseBtn: showCartCloseBtn('page'),
|
|
|
|
config: req.app.config,
|
|
|
|
metaDescription: req.app.config.cartTitle + ' - ' + page,
|
|
|
|
helpers: req.handlebars.helpers,
|
|
|
|
showFooter: 'showFooter',
|
|
|
|
menu: sortMenu(await getMenu(db))
|
|
|
|
});
|
|
|
|
}else{
|
|
|
|
res.status(404).render('error', {
|
|
|
|
title: '404 Error - Page not found',
|
|
|
|
config: req.app.config,
|
|
|
|
message: '404 Error - Page not found',
|
|
|
|
helpers: req.handlebars.helpers,
|
|
|
|
showFooter: 'showFooter',
|
|
|
|
menu: sortMenu(await getMenu(db))
|
|
|
|
});
|
|
|
|
}
|
2018-01-07 04:55:48 +10:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
module.exports = router;
|