Skip to content

Commit

Permalink
Merge pull request #97 from HishamWattar/feature/orders-routes
Browse files Browse the repository at this point in the history
add order routes
  • Loading branch information
ahmadalashtar authored Aug 7, 2023
2 parents 6c0cad8 + 8d523bd commit 8a24124
Show file tree
Hide file tree
Showing 8 changed files with 6,078 additions and 5,645 deletions.
254 changes: 254 additions & 0 deletions src/__tests__/order.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
const supertest = require('supertest');
const app = require('../app');
const { User, Chef } = require('../models/user');
const Dish = require('../models/dish');
const Order = require('../models/order');
const cartModel = require('../models/cart');

const req = supertest(app);
const db = require('../db/connection');

let customerToken;
let customerId;
let orderId;
let chefToken;
let allDishes;
let fishId;
// let chickenId;
// let orderExp;
// let cart;

const customerUser = {
firstName: 'customerTests',
lastName: 'customerTests',
password: 'Customer%123Tests',
username: 'customerUserTests',
email: '[email protected]',
role: 'customer',
};
const chefUser = {
firstName: 'cheftest',
lastName: 'cheftest',
password: 'Chef%123test',
username: 'chefUsertest',
isApproved: true,
email: '[email protected]',
role: 'chef',
};

const fish = {
name: 'Fish and Chips',
price: 5,
ingredients: [
'Tomato sauce',
'Cod fish',
'Potatoes',
'Vegetable oil',
'Yogurt marinade',
],
reviews: [
{
rate: 4,
description: 'Perfect portion sizes and crispy batter.',
},
],
};

const chicken = {
name: 'Chicken Tikka Masala',
price: 10,
ingredients: [
'Chicken thighs',
'Yogurt marinade',
'Tomato sauce',
'Spices',
'Potatoes',
],
reviews: [
{
rate: 5,
description: 'Flavours were spot on, really tasty dish.',
},
{
rate: 3,
description: 'A bit low on spice for my liking.',
},
],
};
const cartItemData = {
quantity: 2,
};

beforeAll(async () => {
await db.connectToMongo();
let res = await req.post('/api/auth/signup').send(customerUser);
customerId = res.body.data._id;
[customerToken] = res.headers['set-cookie'][0].split(';');
const _chefUser = await Chef.create(chefUser);
res = await req.post('/api/auth/signin').send(chefUser);
[chefToken] = res.headers['set-cookie'][0].split(';');
const chefID = _chefUser._id;
fish.chefId = _chefUser._id;
chicken.chefId = _chefUser._id;
const orderExample = {
customerId,
chefID,
totalPrice: 50.0,
status: 'pending',
orderItems: [
{
fishId,
quantity: 2,
price: 25.0,
},
],
quantity: 2,
};
const cartItems = [
{
dishId: fishId,
quantity: 2,
},
];
const cartData = {
customerId,
cartItems,
};
allDishes = await Dish.insertMany([fish, chicken]);
await Order.create(orderExample);
await cartModel.create(cartData);
fishId = allDishes[0]._id;
// chickenId = allDishes[1]._id;
});

afterAll(async () => {
await User.deleteMany({});
await Dish.deleteMany({});
await cartModel.deleteMany({});
await Chef.deleteMany({});
await db.closeDatabase();
});

// Test suite for order routes
describe('Order Routes', () => {
// Test for getting all orders for customer
describe('GET /api/order/customer', () => {
// Test for success response
it('should return a success response with an array of orders', async () => {
// Create an order for the customer
const orderResponse = await req
.post('/api/orders')
.set('Cookie', customerToken)
.send({ customerId, cartItems: [cartItemData] });
orderId = orderResponse.body.orders[0]._id;

// Make a get request to the route
const response = await req
.get('/api/orders/customer')
.set('Cookie', customerToken);

// Expect a status code of 200 and an array of orders in the response body
expect(response.status).toBe(200);
expect(Array.isArray(response.body.data)).toBe(true);
});

// Test for failure response due to invalid token
it('should return a failure response with an error message', async () => {
// Make a get request to the route with an invalid token
const response = await req
.get('/api/orders/customer')
.set('Cookie', 'Bearer invalidtoken');

// Expect a status code of 401 and an error message in the response body
expect(response.status).toBe(401);
expect(response.body.message).toEqual('Unauthenticated');
});
});

// Test for getting all orders for chef
describe('GET /api/v1/order/chef', () => {
// Test for success response
it('should return a success response with an array of orders', async () => {
const response = await req
.get('/api/orders/chef')
.set('Cookie', chefToken);

// Expect a status code of 200 and an array of orders in the response body
expect(response.status).toBe(200);
expect(Array.isArray(response.body.data)).toBe(true);
expect(response.body.data[0]._id).toEqual(orderId);
});

// Test for failure response due to invalid token
it('should return a failure response with an error message', async () => {
// Make a get request to the route with an invalid token
const response = await req
.get('/api/orders/chef')
.set('Cookie', 'Bearer invalidtoken');

// Expect a status code of 401 and an error message in the response body
expect(response.status).toBe(401);
expect(response.body.message).toEqual('Unauthenticated');
});
});

describe('POST /api/orders', () => {
// Test for success response
it('should return a success response with an array of orders', async () => {
// Make a post request to the route with the customer id and cart items
const response = await req
.post('/api/orders')
.set('Cookie', customerToken)
.send({ customerId, cartItems: [cartItemData] });

// Expect a status code of 201 and an array of orders in the response body
expect(response.status).toBe(201);
expect(Array.isArray(response.body.orders)).toBe(true);
expect(response.body.orders[0].customerId).toEqual(customerId);
expect(response.body.orders[0].totalPrice).toEqual(10);
expect(response.body.orders[0].status).toEqual('pending');
expect(Array.isArray(response.body.orders[0].orderItems)).toBe(true);
expect(response.body.orders[0].orderItems[0].price).toEqual(5);
expect(response.body.orders[0].orderItems[0].quantity).toEqual(2);
});

// Test for failure response due to invalid input
it('should return a failure response with an error message', async () => {
// Make a post request to the route with an invalid customer id
const response = await req
.post('/api/orders')
.send({ customerId: 'invalidid', cartItems: [cartItemData] });

expect(response.status).toBe(401);
});
});

// Test for updating an order
describe('PUT /api/v1/order/:id', () => {
// Test for success response
it('should return a success response with the updated order', async () => {
const response = await req
.put(`/api/orders/${orderId}`)
.set('Cookie', chefToken)
.send({ status: 'in_progress' });

// Expect a status code of 200 and the updated order in the response body
expect(response.status).toBe(200);
expect(response.body.data._id).toEqual(orderId);
expect(response.body.data.status).toEqual('in_progress');
});
});

// Test for deleting an order
describe('DELETE /api/orders/:id', () => {
// Test for success response
it('should return a success response with a message', async () => {
// Make a delete request to the route with the order id
const response = await req
.delete(`/api/orders/${orderId}`)
.set('Cookie', customerToken);

expect(response.status).toBe(204);
});
});
});
123 changes: 123 additions & 0 deletions src/controllers/order.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
const orderModel = require('../models/order');
const CustomError = require('../utils/customError');
const Cart = require('../models/cart');
const Dish = require('../models/dish');

const getAllOrdersForCustomer = async (req, res, next) => {
try {
const orders = await orderModel.find({ customerId: req.user.id });
if (!orders) {
return next(new CustomError("You don't have orders", 404));
}
return res.json({ data: orders });
} catch (err) {
return next(new CustomError(err.message, 500));
}
};
const getAllOrdersForChef = async (req, res, next) => {
try {
const orders = await orderModel.find({ chefId: req.user.id });
if (!orders) {
return next(new CustomError("You don't have orders", 404));
}
return res.json({ data: orders });
} catch (err) {
return next(new CustomError(err.message, 500));
}
};

const createOrder = async (req, res, next) => {
try {
const customerId = req.user.id;

const cart = await Cart.findOne({ customerId });

if (!cart || !cart.cartItems || cart.cartItems.length === 0) {
return next(new CustomError('Cart is empty', 400));
}

const { cartItems } = cart;
let orders = [];

// eslint-disable-next-line no-restricted-syntax
for (const item of cartItems) {
const { dishId, quantity } = item;

// eslint-disable-next-line no-await-in-loop
const dish = await Dish.findOne({ id: dishId });

const { chefId, price } = dish;

let order = orders.find((o) => o.chefId.equals(chefId));

// If there is no existing order, create a new one and push it to the orders array
if (!order) {
order = {
customerId,
chefId,
totalPrice: 0,
status: 'pending',
orderItems: [],
quantity: 0,
};
orders.push(order);
}

// Add the item to the order items array
order.orderItems.push({
price,
dishId,
quantity,
});

// Update the total price and quantity of the order
order.totalPrice += price * quantity;
order.quantity += quantity;
}

// Save all the orders to the database
orders = await orderModel.insertMany(orders);
// Return a success response with the orders
return res.status(201).json({ message: 'Orders created', orders });
} catch (error) {
return next(new CustomError(error.message, 500));
}
};

const updateOrder = async (req, res, next) => {
const { id } = req.params;
const { status } = req.body;
try {
const order = await orderModel.findOneAndUpdate(
{ _id: id },
{ status },
{ returnOriginal: false }
);
if (!order) {
return next(new CustomError('Order not Found', 404));
}
return res.json({ data: order });
} catch (err) {
return next(new CustomError(err.message, 500));
}
};
const deleteOrder = async (req, res, next) => {
const { id } = req.params;
try {
const order = await orderModel.findByIdAndDelete(id);
if (!order) {
return next(new CustomError("You don't have orders", 404));
}
return res.sendStatus(204).json({ message: 'Order deleted successfully' });
} catch (err) {
return next(new CustomError(err.message, 500));
}
};

module.exports = {
getAllOrdersForCustomer,
getAllOrdersForChef,
createOrder,
updateOrder,
deleteOrder,
};
1 change: 0 additions & 1 deletion src/controllers/review.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ const addReviewToDish = async (req, res, next) => {
dish.reviews.push(reviewData);
await dish.save();
return res.status(201).json({
success: true,
data: dish,
});
} catch (err) {
Expand Down
Loading

0 comments on commit 8a24124

Please sign in to comment.