Skip to content

Commit

Permalink
Feat/checkout (#82)
Browse files Browse the repository at this point in the history
- add filtering orders by current and past
- fix userType, productType, orderType to match their models
  • Loading branch information
yousefyasser authored Nov 29, 2024
1 parent 3db3257 commit 82a7ea0
Show file tree
Hide file tree
Showing 11 changed files with 99 additions and 63 deletions.
51 changes: 42 additions & 9 deletions backend/src/controllers/order.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,48 @@ import { Request, Response } from 'express';
import { logger } from '../middlewares/logger.middleware';
import { ResponseStatusCodes } from '../types/ResponseStatusCodes.types';
import orderRepo from '../database/repositories/order.repo';
import userRepo from '../database/repositories/user.repo';
import cartRepo from '../database/repositories/cart.repo';
import { OrderItemType } from '../types/Order.types';
import { ProductType } from '../types/Product.types';

const getAllOrders = async (req: Request, res: Response) => {
try {
const orders = await orderRepo.getOrders();
res.status(ResponseStatusCodes.OK).json({ message: 'Orders fetched successfully', data: { orders: orders } });
} catch (error: any) {
logger.error(`Error fetching orders: ${error.message}`);
res.status(ResponseStatusCodes.BAD_REQUEST).json({ message: error.message, data: [] });
class OrderController {
async getAllOrders(req: Request, res: Response) {
try {
const orders = await orderRepo.getOrders(req.query.past as string);
res.status(ResponseStatusCodes.OK).json({ message: 'Orders fetched successfully', data: { orders: orders } });
} catch (error: any) {
logger.error(`Error fetching orders: ${error.message}`);
res.status(ResponseStatusCodes.BAD_REQUEST).json({ message: error.message, data: [] });
}
}
};

export { getAllOrders };
async checkoutOrder(req: Request, res: Response) {
const user = await cartRepo.getUserCart(req.user.userId);
try {
const cart = user?.cart || [];

if (cart.length === 0) {
throw new Error('Cart is empty');
}

let totalOrderPrice = 0;
cart.forEach((cartItem) => {
const product = cartItem.product as ProductType;

totalOrderPrice += product.price * cartItem.quantity;
});

const order = await orderRepo.checkoutOrder(req.user.userId, totalOrderPrice, cart);

res
.status(ResponseStatusCodes.CREATED)
.json({ message: 'Order checked out successfully', data: { order: order } });
} catch (error: any) {
logger.error(`Error checking out order: ${error.message}`);
res.status(ResponseStatusCodes.BAD_REQUEST).json({ message: error.message, data: [] });
}
}
}

export default new OrderController();
15 changes: 2 additions & 13 deletions backend/src/database/models/order.model.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,10 @@
import { model, Schema } from 'mongoose';
import { OrderStatusType } from '../../types/Order.types';
import { cartItemSchema } from './cart.model';

const orderSchema = new Schema(
{
products: [
{
product: {
type: Schema.Types.ObjectId,
ref: 'Product',
required: true,
},
quantity: {
type: Number,
required: true,
},
},
],
products: [cartItemSchema],
totalPrice: {
type: Number,
required: true,
Expand Down
1 change: 1 addition & 0 deletions backend/src/database/models/product.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const productSchema = new Schema(
},
price: {
type: Number,
required: true,
},
available_quantity: {
type: Number,
Expand Down
3 changes: 2 additions & 1 deletion backend/src/database/repositories/cart.repo.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { UserType } from '../../types/User.types';
import { User } from '../models/user.model';
import { ObjectId } from 'mongodb';

class CartRepo {
async getUserCart(id: string) {
async getUserCart(id: string): Promise<UserType | null> {
return await User.findById(id).populate('cart.product');
}

Expand Down
19 changes: 17 additions & 2 deletions backend/src/database/repositories/order.repo.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
import { OrderItemType, OrderStatusType } from '../../types/Order.types';
import { Order } from '../models/order.model';

class OrderRepo {
async getOrders() {
return await Order.find();
async getOrders(past: string) {
let query = {
status: { $in: [OrderStatusType.PENDING] },
};

if (past === 'true') {
query = {
status: { $in: [OrderStatusType.DELIVERED, OrderStatusType.CANCELLED] },
};
}

return await Order.find(query).populate('products.product');
}

async checkoutOrder(userId: string, totalPrice: Number, cart?: OrderItemType[]) {
return await Order.create({ products: cart, totalPrice, created_by: userId });
}
}
export default new OrderRepo();
4 changes: 2 additions & 2 deletions backend/src/database/repositories/user.repo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ class UserRepository {
return await User.deleteOne({ _id: new ObjectId(id) });
}

async ChangeUserPassword(id: string, pass: string) {
return await User.updateOne({ _id: new ObjectId(id) }, { password: pass });
async ChangeUserPassword(id: ObjectId, pass: string) {
return await User.updateOne({ _id: id }, { password: pass });
}

async acceptTerms(id: string) {
Expand Down
5 changes: 3 additions & 2 deletions backend/src/routes/order.route.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Router } from 'express';
import { getAllOrders } from '../controllers/order.controller';
import OrderController from '../controllers/order.controller';

const orderRouter = Router();

orderRouter.get('/', getAllOrders);
orderRouter.get('/', OrderController.getAllOrders);
orderRouter.post('/checkout', OrderController.checkoutOrder);

export default orderRouter;
5 changes: 3 additions & 2 deletions backend/src/types/Order.types.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { ProductType } from './Product.types';
import { UserType } from './User.types';
import { ObjectId } from 'mongodb';

export interface OrderType {
products: [OrderItemType];
totalPrice: number;
totalPrice: Number;
status: OrderStatusType;
created_by: UserType;
createdAt: Date;
updatedAt: Date;
}

export interface OrderItemType {
product: ProductType;
product: ObjectId | ProductType;
quantity: number;
}

Expand Down
2 changes: 1 addition & 1 deletion backend/src/types/Product.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ export interface ProductType {
_id?: string;
name: string;
description?: string;
price?: number;
price: number;
available_quantity?: number;
attachments?: number[];
reviews?: ReviewType[];
Expand Down
46 changes: 23 additions & 23 deletions backend/src/types/User.types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Types } from 'mongoose';
import { ObjectId } from 'mongodb';
import { OrderItemType } from './Order.types';

export enum accountType {
Expand All @@ -16,49 +17,48 @@ export interface previousWorkType {
company: string;
startDate: Date;
endDate: Date;
location?: string;
location?: string | null;
locationType: string;
description?: string;
description?: string | null;
}

export interface companyProfileType {
industry: string;
headquarters: string;
specialties?: string;
specialties?: string | null;
}

export interface UserType {
_id: string;
_id: ObjectId;
password: string;
username: string;
account_type: accountType;
email?: string;
dob?: string;
mobile_number: string;
job?: string;
picture?: string;
name?: string;
email?: string | null;
dob?: Date | null;
mobile_number?: string | null;
job?: string | null;
name?: string | null;
accepted: boolean;
nationality: string;
nationality?: string | null;
rejected: boolean;
termsAndConditions: boolean;
attachment: [Types.ObjectId];
attachments: Types.ObjectId[];
// Tour guide
years_of_experience?: number;
previous_work?: [previousWorkType];
years_of_experience?: number | null;
previous_work: previousWorkType[];
// Advertiser
website?: string;
hotline?: string;
profile_pic?: Types.ObjectId;
company_profile?: companyProfileType;
website?: string | null;
hotline?: string | null;
profile_pic?: Types.ObjectId | null;
company_profile?: companyProfileType | null;
// Seller
description?: string;
description?: string | null;
// Tourist
preferences: [string];
preferences: ObjectId[];
loyalty_points: number;
loyalty_level: number;
wallet: number;
itinerary_bookings: [Types.ObjectId];
purchased_products: [Types.ObjectId];
cart: [OrderItemType];
itinerary_bookings: Types.ObjectId[];
purchased_products: Types.ObjectId[];
cart: OrderItemType[];
}
11 changes: 3 additions & 8 deletions backend/src/utils/AgeVerification.utils.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
import userRepo from '../database/repositories/user.repo';
import { UserType } from '../types/User.types';

async function checkLegalAge(dob: string): Promise<boolean> {
async function checkLegalAge(dob: Date): Promise<boolean> {
try {
// Ensure dob is a string
dob = String(dob);

// Parse the date string to a Date object
const birthDate = new Date(dob);
if (isNaN(birthDate.getTime())) {
if (isNaN(dob.getTime())) {
throw new Error('Invalid date format');
}

const birthYear = birthDate.getFullYear();
const birthYear = dob.getFullYear();
const curYear = new Date().getFullYear();
return curYear - birthYear >= 18;
} catch (error) {
Expand Down

0 comments on commit 82a7ea0

Please sign in to comment.