Skip to content

Commit

Permalink
Adding discount code support (mrvautin#109)
Browse files Browse the repository at this point in the history
Added a discount code module. Lots of work went into this. 

Please report any problems as issues to be fixed
  • Loading branch information
mrvautin authored Jan 21, 2020
1 parent 83dc6f7 commit 799ed30
Show file tree
Hide file tree
Showing 45 changed files with 1,236 additions and 285 deletions.
7 changes: 5 additions & 2 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const crypto = require('crypto');
const common = require('./lib/common');
const { runIndexing } = require('./lib/indexing');
const { addSchemas } = require('./lib/schema');
const { initDb } = require('./lib/db');
const { initDb, getDbUri } = require('./lib/db');
let handlebars = require('express-handlebars');
const i18n = require('i18n');

Expand Down Expand Up @@ -237,6 +237,9 @@ handlebars = handlebars.create({
formatDate: (date, format) => {
return moment(date).format(format);
},
discountExpiry: (start, end) => {
return moment().isBetween(moment(start), moment(end));
},
ifCond: (v1, operator, v2, options) => {
switch(operator){
case'==':
Expand Down Expand Up @@ -317,7 +320,7 @@ handlebars = handlebars.create({

// session store
const store = new MongoStore({
uri: config.databaseConnectionString,
uri: getDbUri(config.databaseConnectionString),
collection: 'sessions'
});

Expand Down
30 changes: 30 additions & 0 deletions bin/testdata.json
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,36 @@
"orderProducts": []
}
],
"discounts": [
{
"code": "valid_10_amount_code",
"type": "amount",
"value": 10,
"start": "",
"end": ""
},
{
"code": "valid_10_percent_code",
"type": "percent",
"value": 10,
"start": "",
"end": ""
},
{
"code": "expired_10_percent_code",
"type": "percent",
"value": 10,
"start": "",
"end": ""
},
{
"code": "future_10_percent_code",
"type": "percent",
"value": 10,
"start": "",
"end": ""
}
],
"menu": {
"items": [
{
Expand Down
3 changes: 2 additions & 1 deletion config/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
"maxQuantity": 25,
"modules": {
"enabled": {
"shipping": "shipping-basic"
"shipping": "shipping-basic",
"discount": "discount-voucher"
}
}
}
4 changes: 2 additions & 2 deletions lib/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const restrictedRoutes = [
{ route: '/admin/product/edit/:id', response: 'redirect' },
{ route: '/admin/product/update', response: 'redirect' },
{ route: '/admin/product/delete/:id', response: 'redirect' },
{ route: '/admin/product/published_state', response: 'json' },
{ route: '/admin/product/publishedState', response: 'json' },
{ route: '/admin/product/setasmainimage', response: 'json' },
{ route: '/admin/product/deleteimage', response: 'json' },
{ route: '/admin/product/removeoption', response: 'json' },
Expand All @@ -20,7 +20,7 @@ const restrictedRoutes = [
{ route: '/admin/settings/menu/new', response: 'json' },
{ route: '/admin/settings/menu/update', response: 'json' },
{ route: '/admin/settings/menu/delete', response: 'json' },
{ route: '/admin/settings/menu/save_order', response: 'json' },
{ route: '/admin/settings/menu/saveOrder', response: 'json' },
{ route: '/admin/file/upload', response: 'json' }
];

Expand Down
31 changes: 26 additions & 5 deletions lib/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,9 @@ const clearSessionValue = (session, sessionVar) => {
return temp;
};

const updateTotalCart = (req, res) => {
const updateTotalCart = async (req, res) => {
const config = getConfig();
const db = req.app.db;

req.session.totalCartAmount = 0;
req.session.totalCartItems = 0;
Expand All @@ -131,15 +132,34 @@ const updateTotalCart = (req, res) => {
// Update the total items in cart for the badge
req.session.totalCartItems = Object.keys(req.session.cart).length;

// Net cart amount
const netCartAmount = req.session.totalCartAmount - req.session.totalCartShipping || 0;
// Update the total amount not including shipping/discounts
req.session.totalCartNetAmount = req.session.totalCartAmount;

// Calculate shipping using the loaded module
config.modules.loaded.shipping.calculateShipping(
netCartAmount,
req.session.totalCartNetAmount,
config,
req
);

// If discount module enabled
if(config.modules.loaded.discount){
// Recalculate discounts
const discount = await db.discounts.findOne({ code: req.session.discountCode });
if(discount){
config.modules.loaded.discount.calculateDiscount(
discount,
req
);
}else{
// If discount code is not found, remove it
delete req.session.discountCode;
req.session.totalCartDiscount = 0;
}
}

// Calculate our total amount removing discount and adding shipping
req.session.totalCartAmount = (req.session.totalCartNetAmount - req.session.totalCartDiscount) + req.session.totalCartShipping;
};

const emptyCart = async (req, res, type, customMessage) => {
Expand All @@ -150,12 +170,13 @@ const emptyCart = async (req, res, type, customMessage) => {
delete req.session.shippingAmount;
delete req.session.orderId;
delete req.session.cartSubscription;
delete req.session.discountCode;

// Remove cart from DB
await db.cart.deleteOne({ sessionId: req.session.id });

// update total cart
updateTotalCart(req, res);
await updateTotalCart(req, res);

// Update checking cart for subscription
updateSubscriptionCheck(req, res);
Expand Down
26 changes: 18 additions & 8 deletions lib/db.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,14 @@ function initDb(dbUrl, callback){ // eslint-disable-line
return callback(err);
}

// Set the DB url
dbUrl = getDbUri(dbUrl);

// select DB
const dbUriObj = mongodbUri.parse(dbUrl);
let db;
// if in testing, set the testing DB
if(process.env.NODE_ENV === 'test'){
db = client.db('testingdb');
}else{
db = client.db(dbUriObj.database);
}

// Set the DB depending on ENV
const db = client.db(dbUriObj.database);

// setup the collections
db.users = db.collection('users');
Expand All @@ -33,17 +32,28 @@ function initDb(dbUrl, callback){ // eslint-disable-line
db.customers = db.collection('customers');
db.cart = db.collection('cart');
db.sessions = db.collection('sessions');
db.discounts = db.collection('discounts');

_db = db;
return callback(null, _db);
}
};

function getDbUri(dbUrl){
const dbUriObj = mongodbUri.parse(dbUrl);
// if in testing, set the testing DB
if(process.env.NODE_ENV === 'test'){
dbUriObj.database = 'expresscart-test';
}
return mongodbUri.format(dbUriObj);
}

function getDb(){
return _db;
}

module.exports = {
getDb,
initDb
initDb,
getDbUri
};
18 changes: 18 additions & 0 deletions lib/modules/discount-voucher.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const calculateDiscount = (discount, req) => {
let discountAmount = 0;
if(req.session.discountCode){
if(discount.type === 'amount'){
discountAmount = discount.value;
}
if(discount.type === 'percent'){
// Apply the discount on the net cart amount (eg: minus shipping)
discountAmount = (discount.value / 100) * req.session.totalCartNetAmount;
}
}

req.session.totalCartDiscount = discountAmount;
};

module.exports = {
calculateDiscount
};
6 changes: 3 additions & 3 deletions lib/modules/shipping-basic.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,22 @@ const calculateShipping = (amount, config, req) => {
if(!req.session.customerCountry){
req.session.shippingMessage = 'Estimated shipping';
req.session.totalCartShipping = domesticShippingAmount;
req.session.totalCartAmount = req.session.totalCartAmount + domesticShippingAmount;
req.session.totalCartAmount = amount + domesticShippingAmount;
return;
}

// Check for international
if(req.session.customerCountry.toLowerCase() !== shippingFromCountry.toLowerCase()){
req.session.shippingMessage = 'International shipping';
req.session.totalCartShipping = internationalShippingAmount;
req.session.totalCartAmount = req.session.totalCartAmount + internationalShippingAmount;
req.session.totalCartAmount = amount + internationalShippingAmount;
return;
}

// Domestic shipping
req.session.shippingMessage = 'Domestic shipping';
req.session.totalCartShipping = domesticShippingAmount;
req.session.totalCartAmount = req.session.totalCartAmount + domesticShippingAmount;
req.session.totalCartAmount = amount + domesticShippingAmount;
};

module.exports = {
Expand Down
8 changes: 8 additions & 0 deletions lib/schema.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const path = require('path');
const fs = require('fs');
const moment = require('moment');
const glob = require('glob');
const Ajv = require('ajv');
const ajv = new Ajv();
Expand All @@ -19,6 +20,13 @@ const addSchemas = () => {
const amountRegex = /^\d+\.\d\d$/;
ajv.addFormat('amount', amountRegex);

// Datetime format
ajv.addFormat('datetime', {
validate: (dateTimeString) => {
return moment(dateTimeString, 'DD/MM/YYYY HH:mm').isValid();
}
});

ajv.addKeyword('isNotEmpty', {
type: 'string',
validate: (schema, data) => {
Expand Down
30 changes: 30 additions & 0 deletions lib/schemas/editDiscount.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"$id": "editDiscount",
"type": "object",
"properties": {
"code": {
"type": "string"
},
"type": {
"type": "string",
"enum": [
"amount",
"percent"
]
},
"value": {
"type": "number"
},
"start": {
"type": "object",
"format" : "datetime"
},
"end": {
"type": "object",
"format" : "datetime"
}
},
"required": [
"discountId"
]
}
34 changes: 34 additions & 0 deletions lib/schemas/newDiscount.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"$id": "newDiscount",
"type": "object",
"properties": {
"code": {
"type": "string"
},
"type": {
"type": "string",
"enum": [
"amount",
"percent"
]
},
"value": {
"type": "number"
},
"start": {
"type": "object",
"format" : "datetime"
},
"end": {
"type": "object",
"format" : "datetime"
}
},
"required": [
"code",
"type",
"value",
"start",
"end"
]
}
4 changes: 3 additions & 1 deletion lib/testdata.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const { getConfig } = require('./common');
const { initDb } = require('./db');
const { fixProductDates } = require('../test/helper');
const { fixProductDates, fixDiscountDates } = require('../test/helper');
const fs = require('fs');
const path = require('path');

Expand All @@ -15,13 +15,15 @@ initDb(config.databaseConnectionString, (err, db) => {
db.users.deleteMany({}, {}),
db.customers.deleteMany({}, {}),
db.products.deleteMany({}, {}),
db.discounts.deleteMany({}, {}),
db.menu.deleteMany({}, {})
])
.then(() => {
Promise.all([
db.users.insertMany(jsonData.users),
db.customers.insertMany(jsonData.customers),
db.products.insertMany(fixProductDates(jsonData.products)),
db.discounts.insertMany(fixDiscountDates(jsonData.discounts)),
db.menu.insertOne(jsonData.menu)
])
.then(() => {
Expand Down
21 changes: 20 additions & 1 deletion locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -172,5 +172,24 @@
"Dashboard": "Dashboard",
"Create order": "Create order",
"Order shipping amount": "Order shipping amount",
"Order net amount": "Order net amount"
"Order net amount": "Order net amount",
"Discount code": "Discount code",
"Apply": "Apply",
"Discount codes": "Discount codes",
"Code": "Code",
"Expiry": "Expiry",
"There are currently no discount codes setup.": "There are currently no discount codes setup.",
"New discount": "New discount",
"Amount": "Amount",
"Percent": "Percent",
"Discount type": "Discount type",
"Discount value": "Discount value",
"Discount": "Discount",
"Edit discount": "Edit discount",
"New Discount": "New Discount",
"Discount start": "Discount start",
"Discount end": "Discount end",
"Start": "Start",
"Running": "Running",
"Not running": "Not running"
}
Loading

0 comments on commit 799ed30

Please sign in to comment.