From 4bd8784518e15265df4b572fbb82e9c6ed5dbb60 Mon Sep 17 00:00:00 2001 From: Ndahimana Bonheur Date: Mon, 5 Aug 2024 08:39:03 +0200 Subject: [PATCH 1/3] Fixing the payment logic and the cart displaying (#112) * Fixing the payment logic and the cart displaying * Ammend * --ammend * --ammend * --ammend * --amment * --ammend * --ammend * --ammnend --- src/middlewares/validation.ts | 274 +++++++++++------- .../cart/controller/cartControllers.ts | 93 +++++- .../cart/repositories/cartRepositories.ts | 78 ++++- .../cart/validation/cartValidations.ts | 23 +- src/routes/cartRouter.ts | 18 +- src/services/stripe.ts | 108 ++++--- 6 files changed, 410 insertions(+), 184 deletions(-) diff --git a/src/middlewares/validation.ts b/src/middlewares/validation.ts index 0b2450c1..22346aa7 100644 --- a/src/middlewares/validation.ts +++ b/src/middlewares/validation.ts @@ -29,24 +29,24 @@ import userRepositories from "../modules/user/repository/userRepositories"; const validation = (schema: Joi.ObjectSchema | Joi.ArraySchema) => - async (req: Request, res: Response, next: NextFunction) => { - try { - const { error } = schema.validate(req.body, { abortEarly: false }); - - if (error) { - throw new Error( - error.details - .map((detail) => detail.message.replace(/"/g, "")) - .join(", ") - ); + async (req: Request, res: Response, next: NextFunction) => { + try { + const { error } = schema.validate(req.body, { abortEarly: false }); + + if (error) { + throw new Error( + error.details + .map((detail) => detail.message.replace(/"/g, "")) + .join(", ") + ); + } + return next(); + } catch (error) { + res + .status(httpStatus.BAD_REQUEST) + .json({ status: httpStatus.BAD_REQUEST, message: error.message }); } - return next(); - } catch (error) { - res - .status(httpStatus.BAD_REQUEST) - .json({ status: httpStatus.BAD_REQUEST, message: error.message }); - } - }; + }; const isUserExist = async (req: Request, res: Response, next: NextFunction) => { try { @@ -103,13 +103,13 @@ const isUsersExist = async ( if (userCount === 0) { return res .status(httpStatus.NOT_FOUND) - .json({ status:httpStatus.NOT_FOUND, message: "No users found in the database." }); + .json({ status: httpStatus.NOT_FOUND, message: "No users found in the database." }); } next(); } catch (err) { res .status(httpStatus.INTERNAL_SERVER_ERROR) - .json({status: httpStatus.INTERNAL_SERVER_ERROR, message: "Internet Server error." }); + .json({ status: httpStatus.INTERNAL_SERVER_ERROR, message: "Internet Server error." }); } }; @@ -134,7 +134,7 @@ const isAccountVerified = async ( if (!user) { return res .status(httpStatus.NOT_FOUND) - .json({ status:httpStatus.NOT_FOUND, message: "Account not found." }); + .json({ status: httpStatus.NOT_FOUND, message: "Account not found." }); } if (user.isVerified) { @@ -150,7 +150,7 @@ const isAccountVerified = async ( if (!session) { return res .status(httpStatus.BAD_REQUEST) - .json({status:httpStatus.BAD_REQUEST, message: "Invalid token." }); + .json({ status: httpStatus.BAD_REQUEST, message: "Invalid token." }); } req.session = session; @@ -177,7 +177,7 @@ const verifyUserCredentials = async ( if (!user) { return res .status(httpStatus.BAD_REQUEST) - .json({status:httpStatus.BAD_REQUEST, message: "Invalid Email or Password" }); + .json({ status: httpStatus.BAD_REQUEST, message: "Invalid Email or Password" }); } if (user.is2FAEnabled) { const { otp, expirationTime } = generateOTP(); @@ -194,8 +194,7 @@ const verifyUserCredentials = async ( await sendEmail( user.email, "E-Commerce Ninja Login", - `Dear ${ - user.lastName || user.email + `Dear ${user.lastName || user.email }\n\nUse This Code To Confirm Your Account: ${otp}` ); @@ -206,14 +205,15 @@ const verifyUserCredentials = async ( if (isTokenExist) { return res.status(httpStatus.OK).json({ message: "Check your Email for OTP Confirmation", - data: { - UserId: user.id, - token: isTokenExist } + data: { + UserId: user.id, + token: isTokenExist + } }); } return res.status(httpStatus.OK).json({ - status:httpStatus.OK, + status: httpStatus.OK, message: "Check your Email for OTP Confirmation", data: { userId: user.id }, }); @@ -225,7 +225,7 @@ const verifyUserCredentials = async ( if (!passwordMatches) { return res .status(httpStatus.BAD_REQUEST) - .json({status:httpStatus.BAD_REQUEST, message: "Invalid Email or Password" }); + .json({ status: httpStatus.BAD_REQUEST, message: "Invalid Email or Password" }); } req.user = user; @@ -233,7 +233,7 @@ const verifyUserCredentials = async ( } catch (error) { return res .status(httpStatus.INTERNAL_SERVER_ERROR) - .json({status:httpStatus.INTERNAL_SERVER_ERROR, message: error.message }); + .json({ status: httpStatus.INTERNAL_SERVER_ERROR, message: error.message }); } }; @@ -519,13 +519,29 @@ const isGoogleEnabled = async (req: any, res: Response, next: NextFunction) => { const isCartExist = async (req: ExtendRequest, res: Response, next: NextFunction) => { try { - const cart = await cartRepositories.getCartsByUserId (req.user.id); + const cart = await cartRepositories.getCartsByUserId(req.user.id); if (!cart) { - return res.status(httpStatus.NOT_FOUND).json({ status: httpStatus.NOT_FOUND, message: "No cart found. Please create a cart first." }); + return res.status(httpStatus.NOT_FOUND).json({ status: httpStatus.NOT_FOUND, message: "No cart found. Please create a cart first." }); + } + req.carts = cart; + return next(); + + } catch (error) { + return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ + status: httpStatus.INTERNAL_SERVER_ERROR, + message: error.message, + }); } - req.carts = cart; - return next(); - +}; +const isCartExist1 = async (req: ExtendRequest, res: Response, next: NextFunction) => { + try { + const cart = await cartRepositories.getCartsByUserId1(req.user.id); + if (!cart) { + return res.status(httpStatus.NOT_FOUND).json({ status: httpStatus.NOT_FOUND, message: "No cart found. Please create a cart first." }); + } + req.carts = cart; + return next(); + } catch (error) { return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ status: httpStatus.INTERNAL_SERVER_ERROR, @@ -704,38 +720,38 @@ const isWishListExist = async ( ) => { try { const wishList = await productRepositories.getWishListByUserId(req.user.id); - if (!wishList) { - const newWishList = await productRepositories.createWishList({userId: req.user.id}); - req.wishList = newWishList.id; + if (!wishList) { + const newWishList = await productRepositories.createWishList({ userId: req.user.id }); + req.wishList = newWishList.id; } - else{ - req.wishList = wishList.id + else { + req.wishList = wishList.id } - next(); + next(); } catch (error) { return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ - status: httpStatus.INTERNAL_SERVER_ERROR, - message: error.message, - }); - } + status: httpStatus.INTERNAL_SERVER_ERROR, + message: error.message, + }); + } }; -const isWishListProductExist = async (req:ExtendRequest , res:Response, next:NextFunction) => { - try{ - const wishListProduct = await productRepositories.findProductfromWishList(req.params.id,req.wishList); - if(wishListProduct) { - return res.status(httpStatus.OK).json({ - message: "Product is added to wishlist successfully.", - data: { wishListProduct }, - }); - } - next() - }catch (error) { +const isWishListProductExist = async (req: ExtendRequest, res: Response, next: NextFunction) => { + try { + const wishListProduct = await productRepositories.findProductfromWishList(req.params.id, req.wishList); + if (wishListProduct) { + return res.status(httpStatus.OK).json({ + message: "Product is added to wishlist successfully.", + data: { wishListProduct }, + }); + } + next() + } catch (error) { return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ status: httpStatus.INTERNAL_SERVER_ERROR, message: error.message, }); -} + } } @@ -748,14 +764,14 @@ const isUserWishlistExist = async ( const wishList = await productRepositories.findWishListByUserId( req.user.id ); - if (!wishList ) { + if (!wishList) { return res.status(httpStatus.NOT_FOUND).json({ status: httpStatus.NOT_FOUND, message: "No wishlist Found", }); } - req.wishList = wishList; - next(); + req.wishList = wishList; + next(); } catch (error) { return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ status: httpStatus.INTERNAL_SERVER_ERROR, @@ -763,7 +779,7 @@ const isUserWishlistExist = async ( }); } }; -const isProductExistIntoWishList= async ( +const isProductExistIntoWishList = async ( req: ExtendRequest, res: Response, next: NextFunction @@ -808,20 +824,20 @@ const isNotificationsExist = async (req: Request, res: Response, next: NextFunct } }; -const isProductOrdered = async (req: ExtendRequest,res: Response,next: NextFunction) => { +const isProductOrdered = async (req: ExtendRequest, res: Response, next: NextFunction) => { try { const cart = await cartRepositories.getCartsByProductId(req.params.id, req.user.id); if (!cart) { return res - .status(httpStatus.NOT_FOUND) - .json({ + .status(httpStatus.NOT_FOUND) + .json({ status: httpStatus.NOT_FOUND, message: "Product is not ordered", }); } - if(cart.status !== "completed") { - return res.status(httpStatus.BAD_REQUEST).json({ + if (cart.status !== "completed") { + return res.status(httpStatus.BAD_REQUEST).json({ status: httpStatus.BAD_REQUEST, message: "Order is not Completed" }) @@ -837,7 +853,7 @@ const isProductOrdered = async (req: ExtendRequest,res: Response,next: NextFunct const isUserProfileComplete = async (req: Request, res: Response, next: NextFunction) => { try { - const userId = req.user.id; + const userId = req.user.id; const user = await userRepositories.findUserById(userId); const requiredFields = ["firstName", "lastName", "email", "phone", "gender", "birthDate", "language", "currency"]; @@ -878,85 +894,131 @@ const isSellerRequestExist = async (req: Request, res: Response, next: NextFunct } }; -const isOrderExist = async (req: Request, res:Response, next:NextFunction)=>{ - try{ +const isOrderExist = async (req: Request, res: Response, next: NextFunction) => { + try { let order: any; if (req.user.role === "buyer") { - if(req.params.id){ - order = await cartRepositories.getOrderByOrderIdAndUserId(req.params.id, req.user.id) - if(!order){ - return res.status(httpStatus.NOT_FOUND).json({ - status: httpStatus.NOT_FOUND, - error: "order not found" - }) - } - }else{ - order = await cartRepositories.getOrdersByUserId(req.user.id) - if(!order.orders || order.orders.length === 0){ + if (req.params.id) { + order = await cartRepositories.getOrderByOrderIdAndUserId(req.params.id, req.user.id) + if (!order) { return res.status(httpStatus.NOT_FOUND).json({ status: httpStatus.NOT_FOUND, - error: "orders not found" + error: "order not found" }) } - } - - } - if(req.user.role === "admin"){ - order = await cartRepositories.getOrderById(req.params.id) - if (!order) { + } else { + order = await cartRepositories.getOrdersByUserId(req.user.id) + if (!order.orders || order.orders.length === 0) { return res.status(httpStatus.NOT_FOUND).json({ status: httpStatus.NOT_FOUND, - error: "order Not Found", - }); + error: "orders not found" + }) } } - (req as any).order = order - return next(); + } - catch(error){ - return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ - status: httpStatus.INTERNAL_SERVER_ERROR, - error: error.message - }) + if (req.user.role === "admin") { + order = await cartRepositories.getOrderById(req.params.id) + if (!order) { + return res.status(httpStatus.NOT_FOUND).json({ + status: httpStatus.NOT_FOUND, + error: "order Not Found", + }); + } } + (req as any).order = order + return next(); + } + catch (error) { + return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ + status: httpStatus.INTERNAL_SERVER_ERROR, + error: error.message + }) + } } +const isOrdersExist = async (req: any, res: Response, next: NextFunction) => { + try { + const order = await cartRepositories.getOrdersByCartId(req.user.id); + if (!order) { + return res.status(httpStatus.NOT_FOUND).json({ + status: httpStatus.NOT_FOUND, + message: "No orders found", + }); + } + req.orders = order; + next() + } catch (error) { + return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ status: httpStatus.INTERNAL_SERVER_ERROR, message: error.message }) + } +} +const isOrderExists = async (req: any, res: Response, next: NextFunction) => { + try { + const order = await cartRepositories.getOrderByCartId(req.user.id); + if (!order) { + return res.status(httpStatus.NOT_FOUND).json({ + status: httpStatus.NOT_FOUND, + message: "No orders found", + }); + } + req.order = order; + next() + } catch (error) { + return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ status: httpStatus.INTERNAL_SERVER_ERROR, message: error.message }) + } +} +const isOrderExists2 = async (req: any, res: Response, next: NextFunction) => { + try { + const order = await cartRepositories.getOrderByCartId2(req.user.id, req.params.id); + if (!order) { + return res.status(httpStatus.NOT_FOUND).json({ + status: httpStatus.NOT_FOUND, + message: "No orders found", + }); + } + req.order = order; + next() + } catch (error) { + return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ status: httpStatus.INTERNAL_SERVER_ERROR, message: error.message }) + } +} const isOrderEmpty = async (req: Request, res: Response, next: NextFunction) => { const orders = await cartRepositories.getOrdersHistory(); - if(!orders){ + if (!orders) { return res.status(httpStatus.NOT_FOUND).json({ status: httpStatus.NOT_FOUND, error: "order Not Found" }) } (req as any).orders = orders; - next(); + next(); } + const isShopEmpty = async (req: Request, res: Response, next: NextFunction) => { const shops = await userRepositories.getAllShops(); - if(!shops){ + if (!shops) { return res.status(httpStatus.NOT_FOUND).json({ status: httpStatus.NOT_FOUND, error: "Shops Not Found" }) } (req as any).shops = shops; - next(); + next(); } const isOroderExistByShopId = async (req: Request, res: Response, next: NextFunction) => { const shop = await productRepositories.findShopByUserId(req.user.id); const orders = await productRepositories.sellerGetOrdersHistory(shop.id); - - if(!orders){ + + if (!orders) { return res.status(httpStatus.NOT_FOUND).json({ status: httpStatus.NOT_FOUND, error: "Order Not Found" }) } (req as any).ordersHistory = orders; - next(); + next(); } export { @@ -981,6 +1043,7 @@ export { isCartIdExist, isProductIdExist, isCartExist, + isCartExist1, isCartProductExist, isProductExistById, isWishListExist, @@ -994,5 +1057,8 @@ export { isOrderExist, isOrderEmpty, isShopEmpty, - isOroderExistByShopId + isOroderExistByShopId, + isOrdersExist, + isOrderExists, + isOrderExists2 }; \ No newline at end of file diff --git a/src/modules/cart/controller/cartControllers.ts b/src/modules/cart/controller/cartControllers.ts index 18624fb3..d9b23f30 100644 --- a/src/modules/cart/controller/cartControllers.ts +++ b/src/modules/cart/controller/cartControllers.ts @@ -27,6 +27,8 @@ const getProductDetails = ( image: product.images[0], quantity: cartProduct.quantity, totalPrice: totalPrice, + shopId: product.shopId, + description: product.description }; }); @@ -63,7 +65,7 @@ const buyerGetCart = async (req: ExtendRequest, res: Response) => { const buyerGetCarts = async (req: ExtendRequest, res: Response) => { try { - const carts = await cartRepositories.getCartsByUserId(req.user.id); + const carts = await cartRepositories.getCartsByUserId1(req.user.id); const allCartsDetails = await Promise.all( carts.map(async (cart) => { @@ -74,12 +76,12 @@ const buyerGetCarts = async (req: ExtendRequest, res: Response) => { return { cartId: cart.id, + status: cart.status, products: productsDetails, total: cartTotal, }; }) ); - return res.status(httpStatus.OK).json({ status: httpStatus.OK, message: "Buyer's all carts", @@ -150,7 +152,7 @@ const buyerCreateUpdateCart = async (req: ExtendRequest, res: Response) => { try { const { productId, quantity } = req.body; const userId = req.user.id; - const carts = await cartRepositories.getCartsByUserId(userId); + const carts = await cartRepositories.getCartsByUserId1(userId); for (const cart of carts) { const cartProducts = await cartRepositories.getCartProductsByCartId( @@ -275,7 +277,6 @@ const buyerCheckout = async (req: ExtendRequest, res: Response) => { cart.cartProducts.forEach(product => { totalAmount += product.totalPrice; }); - return res.status(httpStatus.OK).json({ status: httpStatus.OK, data: { totalAmount, cart } @@ -302,7 +303,20 @@ const buyerGetOrderStatus = async (req: ExtendRequest, res: Response) => { }) } } +const buyerGetOrderStatus2 = async (req, res) => { + try { + const order = await req.order + return res.status(httpStatus.OK).json({ + status: httpStatus.OK, message: "Order retrieved successfully", + data: { + order + } + }) + } catch (error) { + return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ status: httpStatus.INTERNAL_SERVER_ERROR, message: error.message }) + } +} const buyerGetOrders = async (req: ExtendRequest, res: Response) => { try { const orders = req.order @@ -318,6 +332,21 @@ const buyerGetOrders = async (req: ExtendRequest, res: Response) => { }) } } +const buyerGetOrders2 = (req, res) => { + try { + const orders = req.orders + return res.status(httpStatus.OK).json({ + message: "Orders found successfully", + data: { orders } + }) + } + catch (error) { + return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ + status: httpStatus.INTERNAL_SERVER_ERROR, + error: error.message + }) + } +} const adminUpdateOrderStatus = async (req: ExtendRequest, res: Response) => { try { @@ -337,6 +366,15 @@ const adminUpdateOrderStatus = async (req: ExtendRequest, res: Response) => { } +const stripeCreateProduct = async (req, res) => { + try { + let product = await cartRepositories.getStripeProductByAttribute('name', req.body.planInfo.name); + if (!product) product = await cartRepositories.createStripeProduct(req.body.planInfo); + return res.status(httpStatus.OK).json({ message: "Success.", data: { product } }); + } catch (error) { + return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ status: httpStatus.INTERNAL_SERVER_ERROR, error: error.message }) + } +}; const stripeCheckoutSession = async (req, res) => { try { @@ -344,19 +382,43 @@ const stripeCheckoutSession = async (req, res) => { if (!customer) customer = await cartRepositories.createStripeCustomer({ email: req.body.sessionInfo.customer_email }); delete req.body.sessionInfo.customer_email; req.body.sessionInfo.customer = customer.id; - let session = await cartRepositories.getStripeSessionByAttribute('customer', customer.id); - if (!session) session = await cartRepositories.createStripeSession(req.body.sessionInfo); + const session = await cartRepositories.createStripeSession(req.body.sessionInfo); return res.status(httpStatus.OK).json({ message: "Success.", data: { session } }); } catch (error) { return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ status: httpStatus.INTERNAL_SERVER_ERROR, error: error.message }) } }; -const adminGetOrdersHistory = async(req: ExtendRequest, res:Response)=>{ - const OrderHistory = (req as any).orders - return res.status(httpStatus.OK).json({ - message: "Order History", - data: { OrderHistory } - }) + +const buyerUpdateCartStatus = async (req, res) => { + try { + const { cartId, status } = req.body + await cartRepositories.updateCartStatus(cartId, status); + const updatedCart = await cartRepositories.getCartByUserIdAndCartId(req.user.id, cartId) + return res.status(httpStatus.OK).json({ status: httpStatus.OK, message: "Cart status updated successfully", data: { updatedCart } }) + } catch (error) { + return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ status: httpStatus.INTERNAL_SERVER_ERROR, message: error.message }) + } +} +const userCreateOrder = (req, res) => { + try { + const userId = req.user.id; + const body = { + userId: userId, + products: req.body.products, + cartId: req.body.cartId, + paymentMethodId: req.body.paymentMethodId, + orderDate: new Date(), + status: req.body.status, + shippingProcess: "Order placed successfully!", + shopId: req.body.shopId, + expectedDeliveryDate: new Date(new Date().setDate(new Date().getDate() + 7)) + } + + const order = cartRepositories.userSaveOrder(body) + return res.status(httpStatus.CREATED).json({ status: httpStatus.CREATED, message: "Order created succesfully", data: { order } }) + } catch (error) { + return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ status: httpStatus.INTERNAL_SERVER_ERROR, message: error.message }) + } } export { @@ -374,6 +436,11 @@ export { buyerGetOrders, buyerCheckout, adminUpdateOrderStatus, + stripeCreateProduct, stripeCheckoutSession, - adminGetOrdersHistory + buyerUpdateCartStatus, + userCreateOrder, + buyerGetOrders2, + buyerGetOrderStatus2 + }; \ No newline at end of file diff --git a/src/modules/cart/repositories/cartRepositories.ts b/src/modules/cart/repositories/cartRepositories.ts index 716266ee..6e719d9e 100644 --- a/src/modules/cart/repositories/cartRepositories.ts +++ b/src/modules/cart/repositories/cartRepositories.ts @@ -7,6 +7,23 @@ import CartProduct from "../../../databases/models/cartProducts"; import Products from "../../../databases/models/products"; import { stripe } from "../../../services/stripe.service"; const getCartsByUserId = async (userId: string) => { + return await db.Carts.findOne({ + where: { userId, status: "pending" }, + include: [ + { + model: db.CartProducts, + as: "cartProducts", + include: [ + { + model: db.Products, + as: "products" + }, + ], + } + ] + }); +}; +const getCartsByUserId1 = async (userId: string) => { return await db.Carts.findAll({ where: { userId, status: "pending" } }); }; @@ -32,7 +49,7 @@ const getCartProductsByCartId = async (cartId: string) => { { model: db.Products, as: "products", - attributes: ["id", "name", "price", "discount", "images", "shopId"], + attributes: ["id", "name", "price", "discount", "images", "shopId", "description"], }, ], }); @@ -98,9 +115,9 @@ const findCartProductsByCartId = async (value: any) => { return result; }; -const getCartByUserIdAndCartId = async (userId: string, cartId: string, status: string = "pending") => { +const getCartByUserIdAndCartId = async (userId: string, cartId: string) => { return await db.Carts.findOne({ - where: { id: cartId, userId, status }, + where: { id: cartId, userId, status: "pending" }, include: [ { model: db.CartProducts, @@ -155,6 +172,44 @@ const getOrderByOrderIdAndUserId = async (orderId: string, userId: string) => { }) } +const getOrdersByCartId = async (userId) => { + return await db.Orders.findAll({ + include: [ + { + model: db.Carts, + as: "carts", + where: { userId: userId } + } + ], + order: [ + ["createdAt", "DESC"] + ] + }); +}; +const getOrderByCartId = async (userId) => { + return await db.Orders.findOne({ + include: [ + { + model: db.Carts, + as: "carts", + where: { userId: userId } + } + ] + }); +}; +const getOrderByCartId2 = async (userId,orderId) => { + return await db.Orders.findOne({ + where: {id: orderId }, + include: [ + { + model: db.Carts, + as: "carts", + where: { userId: userId } + } + ] + }); +}; + const getOrderById = async (orderId: string) => { return await db.Orders.findOne({ where: { id: orderId } }) } @@ -209,8 +264,17 @@ const getStripeSessionByAttribute = async (primaryKey: string, primaryValue: num const createStripeSession = async (body: Stripe.Checkout.SessionCreateParams): Promise => { return await stripe.checkout.sessions.create(body); }; +const updateCartStatus = async (cartId: string, status: string) => { + + return await db.Carts.update({ status: status }, + { where: { id: cartId } }) +} + +const userSaveOrder = async (body) => { + return await db.Orders.create(body); +} export default { getCartsByUserId, getCartProductsByCartId, @@ -225,6 +289,7 @@ export default { deleteAllCartProducts, findCartByAttributes, getCartsByProductId, + getCartsByUserId1, findCartProductsByCartId, getCartByUserIdAndCartId, findCartProductByCartId, @@ -238,5 +303,10 @@ export default { createStripeProduct, getStripeProductByAttribute, createStripeCustomer, getStripeCustomerByAttribute, createStripeSession, getStripeSessionByAttribute, - getOrdersHistory + getOrdersHistory, + updateCartStatus, + userSaveOrder, + getOrdersByCartId, + getOrderByCartId, + getOrderByCartId2 }; \ No newline at end of file diff --git a/src/modules/cart/validation/cartValidations.ts b/src/modules/cart/validation/cartValidations.ts index 9cd24050..bd6a0db8 100644 --- a/src/modules/cart/validation/cartValidations.ts +++ b/src/modules/cart/validation/cartValidations.ts @@ -115,9 +115,30 @@ const checkoutSessionSchema = Joi.object({ }) }); +const updateCartStatusSchema = Joi.object({ + cartId: Joi.string().required().messages({ + 'any.required': 'cartId is required', + 'string.base': 'cartId must be a string', + 'string.empty': 'cartId is not allowed to be empty', + }), + status: Joi.string().required().messages({ + 'any.required': 'status is required', + 'string.base': 'status must be a string', + 'string.empty': 'status is not allowed to be empty', + }) +}) + +const orderSchema = Joi.object({ + cartId: Joi.string().guid({ version: 'uuidv4' }).required(), + paymentMethodId: Joi.string().required(), + products: Joi.array().required(), + status: Joi.string().valid('pending', 'completed', 'shipped', 'cancelled').required(), +}); export { cartSchema, paymentCheckoutSchema, updateOrderStatusSchema, - productDetailsSchema, checkoutSessionSchema + productDetailsSchema, checkoutSessionSchema, + updateCartStatusSchema, + orderSchema } \ No newline at end of file diff --git a/src/routes/cartRouter.ts b/src/routes/cartRouter.ts index 32324857..5d07a292 100644 --- a/src/routes/cartRouter.ts +++ b/src/routes/cartRouter.ts @@ -8,11 +8,15 @@ import { isProductIdExist, validation, isOrderExist, - isOrderEmpty + isOrderEmpty, + isCartExist1, + isOrdersExist, + isOrderExists, + isOrderExists2 } from "../middlewares/validation"; import * as cartControllers from "../modules/cart/controller/cartControllers"; -import { cartSchema, checkoutSessionSchema, productDetailsSchema, updateOrderStatusSchema } from "../modules/cart/validation/cartValidations"; -import {stripeCreateProduct,stripeCheckoutSession } from "../services/stripe"; +import { cartSchema, checkoutSessionSchema, productDetailsSchema, updateCartStatusSchema, updateOrderStatusSchema } from "../modules/cart/validation/cartValidations"; +import { stripeCreateProduct, stripeCheckoutSession } from "../services/stripe"; const router: Router = Router(); @@ -31,6 +35,7 @@ router.get( cartControllers.buyerGetCarts ); + router.get( "/buyer-get-cart/:cartId", userAuthorization(["buyer"]), @@ -56,7 +61,7 @@ router.delete( router.delete( "/buyer-clear-carts", userAuthorization(["buyer"]), - isCartExist, + isCartExist1, cartControllers.buyerClearCarts ); router.get( @@ -67,13 +72,12 @@ router.get( ); -router.get("/user-get-order-status/:id", userAuthorization(["buyer"]), isOrderExist, cartControllers.buyerGetOrderStatus) +router.get("/user-get-order-status/:id", userAuthorization(["buyer"]), isOrderExists2, cartControllers.buyerGetOrderStatus2) router.put("/admin-update-order-status/:id", userAuthorization(["admin"]), validation(updateOrderStatusSchema), isOrderExist, cartControllers.adminUpdateOrderStatus) router.get("/buyer-get-order-history", userAuthorization(["buyer"]), isOrderExist, cartControllers.buyerGetOrders) +router.get("/buyer-get-orders-history", userAuthorization(["buyer"]), isOrdersExist, cartControllers.buyerGetOrders2) router.post("/create-stripe-product", userAuthorization(["buyer"]), validation(productDetailsSchema), stripeCreateProduct); router.post("/checkout-stripe-session", userAuthorization(["buyer"]), validation(checkoutSessionSchema), stripeCheckoutSession); -router.get("/admin-get-order-history",userAuthorization(["admin"]),isOrderEmpty,cartControllers.adminGetOrdersHistory) -router.get("/seller-get-order-history",userAuthorization(["seller"]),isOrderEmpty,cartControllers.adminGetOrdersHistory) export default router; \ No newline at end of file diff --git a/src/services/stripe.ts b/src/services/stripe.ts index 4ea51807..1d54a7e5 100644 --- a/src/services/stripe.ts +++ b/src/services/stripe.ts @@ -2,7 +2,7 @@ import { Stripe } from "stripe"; import cartRepositories from "../modules/cart/repositories/cartRepositories"; import httpStatus from "http-status"; -import { Response,Request } from "express"; +import { Response, Request } from "express"; @@ -67,65 +67,63 @@ import { Response,Request } from "express"; const stripe = new Stripe(process.env.STRIPE_SECRET); export const webhook = async (req: Request, res: Response) => { - const sign = req.headers["stripe-signature"] as string; - const webhookSecret: string = process.env.WEBHOOK_SECRET; - let event; + const sign = req.headers["stripe-signature"] as string; + const webhookSecret: string = process.env.WEBHOOK_SECRET; + let event; + try { try { + event = stripe.webhooks.constructEvent(req.body, sign, webhookSecret); + } catch (err) { + console.error("Webhook signature verification failed.", err.message); + } + const session = event.data.object; + switch (event.type) { + case "checkout.session.completed": try { - event = stripe.webhooks.constructEvent(req.body, sign, webhookSecret); - } catch (err) { - console.error("Webhook signature verification failed.", err.message); - } - const session = event.data.object; - switch (event.type) { - case "checkout.session.completed": - try { - const lineItems = await stripe.checkout.sessions.listLineItems(session.id); - const shopIds = JSON.parse(session.metadata.shopIds); - const productIds = JSON.parse(session.metadata.productIds); - const cartId = session.metadata.cartId; - const paymentMethodId = session.payment_intent; - const order = await cartRepositories.saveOrder(lineItems.data, shopIds, productIds, session, cartId,paymentMethodId); - return res.status(httpStatus.CREATED).json({ status: httpStatus.CREATED,message:"Order created successfully,", data: {order}}) - } catch (err) { - return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ status: httpStatus.INTERNAL_SERVER_ERROR, message: err.message }) - } - break; - case "payment_intent.succeeded": - return res.status(httpStatus.OK).json({ status: httpStatus.CREATED,message:"Order saved successfully", data:session}) - break; - case "payment_method.attached": - break; - default: - return res.status(httpStatus.BAD_REQUEST).json({ status: httpStatus.BAD_REQUEST, message:"Error: Unknow error occured"}) + const lineItems = await stripe.checkout.sessions.listLineItems(session.id); + const shopIds = JSON.parse(session.metadata.shopIds); + const productIds = JSON.parse(session.metadata.productIds); + const cartId = session.metadata.cartId; + const paymentMethodId = session.payment_intent; + const order = await cartRepositories.saveOrder(lineItems.data, shopIds, productIds, session, cartId, paymentMethodId); + return res.status(httpStatus.CREATED).json({ status: httpStatus.CREATED, message: "Order created successfully,", data: { order } }) + } catch (err) { + return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ status: httpStatus.INTERNAL_SERVER_ERROR, message: err.message }) } - res.json({ received: true }); - } catch (error) { - return res.status(httpStatus.BAD_REQUEST).send(`Webhook Error: ${error.message}`); + break; + case "payment_intent.succeeded": + return res.status(httpStatus.OK).json({ status: httpStatus.CREATED, message: "Order saved successfully", data: session }) + break; + case "payment_method.attached": + break; + default: + return res.status(httpStatus.BAD_REQUEST).json({ status: httpStatus.BAD_REQUEST, message: "Error: Unknow error occured" }) } + res.json({ received: true }); + } catch (error) { + return res.status(httpStatus.BAD_REQUEST).send(`Webhook Error: ${error.message}`); + } }; export const stripeCreateProduct = async (req, res) => { - try { - let product = await cartRepositories.getStripeProductByAttribute("name", req.body.planInfo.name); - if (!product) product = await cartRepositories.createStripeProduct(req.body.planInfo); - return res.status(httpStatus.OK).json({ message: "Success.", data: { product } }); - } catch (error) { - return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ status: httpStatus.INTERNAL_SERVER_ERROR, error: error.message }) - } - }; - - export const stripeCheckoutSession = async (req, res) => { - try { - let customer = await cartRepositories.getStripeCustomerByAttribute("email", req.body.sessionInfo.customer_email); - if (!customer) customer = await cartRepositories.createStripeCustomer({ email: req.body.sessionInfo.customer_email }); - delete req.body.sessionInfo.customer_email; - req.body.sessionInfo.customer = customer.id; - let session = await cartRepositories.getStripeSessionByAttribute("customer", customer.id); - if (!session) session = await cartRepositories.createStripeSession(req.body.sessionInfo); - return res.status(httpStatus.OK).json({ message: "Success.", data: { session } }); - } catch (error) { - return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ status: httpStatus.INTERNAL_SERVER_ERROR, error: error.message }) - } - }; + try { + const product = await cartRepositories.createStripeProduct(req.body.planInfo); + return res.status(httpStatus.OK).json({ message: "Success.", data: { product } }); + } catch (error) { + return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ status: httpStatus.INTERNAL_SERVER_ERROR, error: error.message }) + } +}; + +export const stripeCheckoutSession = async (req, res) => { + try { + let customer = await cartRepositories.getStripeCustomerByAttribute("email", req.body.sessionInfo.customer_email); + if (!customer) customer = await cartRepositories.createStripeCustomer({ email: req.body.sessionInfo.customer_email }); + delete req.body.sessionInfo.customer_email; + req.body.sessionInfo.customer = customer.id; + const session = await cartRepositories.createStripeSession(req.body.sessionInfo); + return res.status(httpStatus.OK).json({ message: "Success.", data: { session } }); + } catch (error) { + return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ status: httpStatus.INTERNAL_SERVER_ERROR, error: error.message }) + } +}; From 5b352438bfc4595a98762675025c666e09d9d3e7 Mon Sep 17 00:00:00 2001 From: "Mr. David" <128073754+ProgrammerDATCH@users.noreply.github.com> Date: Mon, 5 Aug 2024 13:40:00 +0300 Subject: [PATCH 2/3] Allow disable 2FA (#115) --- src/modules/auth/controller/authControllers.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/modules/auth/controller/authControllers.ts b/src/modules/auth/controller/authControllers.ts index 855372e7..0c3bf770 100644 --- a/src/modules/auth/controller/authControllers.ts +++ b/src/modules/auth/controller/authControllers.ts @@ -141,16 +141,17 @@ const resetPassword = async (req: any, res: Response): Promise => { }; const updateUser2FA = async (req: any, res: Response) => { + const { is2FAEnabled } = req.body; try { const user = await authRepositories.updateUserByAttributes( "is2FAEnabled", - true, + !!is2FAEnabled, "id", req.user.id ); res.status(httpStatus.OK).json({ status: httpStatus.OK, - message: "2FA enabled successfully.", + message: `2FA ${is2FAEnabled ? "Enabled" : "Disabled"} successfully.`, data: { user: user } }); } catch (error) { From f2292aadd5428dfa9cecaae47b8f65dd94bea9c5 Mon Sep 17 00:00:00 2001 From: Ndahimana Bonheur Date: Mon, 5 Aug 2024 15:26:02 +0200 Subject: [PATCH 3/3] Finishes fixes (#116) * Finishes fixes * --ammend --- src/modules/cart/controller/cartControllers.ts | 4 ++++ src/routes/cartRouter.ts | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/modules/cart/controller/cartControllers.ts b/src/modules/cart/controller/cartControllers.ts index d9b23f30..ae68bde0 100644 --- a/src/modules/cart/controller/cartControllers.ts +++ b/src/modules/cart/controller/cartControllers.ts @@ -396,6 +396,7 @@ const buyerUpdateCartStatus = async (req, res) => { const updatedCart = await cartRepositories.getCartByUserIdAndCartId(req.user.id, cartId) return res.status(httpStatus.OK).json({ status: httpStatus.OK, message: "Cart status updated successfully", data: { updatedCart } }) } catch (error) { + console.log(error.message) return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ status: httpStatus.INTERNAL_SERVER_ERROR, message: error.message }) } } @@ -417,10 +418,13 @@ const userCreateOrder = (req, res) => { const order = cartRepositories.userSaveOrder(body) return res.status(httpStatus.CREATED).json({ status: httpStatus.CREATED, message: "Order created succesfully", data: { order } }) } catch (error) { + console.log(error.message) return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ status: httpStatus.INTERNAL_SERVER_ERROR, message: error.message }) } } + + export { buyerGetCart, buyerGetCarts, diff --git a/src/routes/cartRouter.ts b/src/routes/cartRouter.ts index 5d07a292..8b8f5fca 100644 --- a/src/routes/cartRouter.ts +++ b/src/routes/cartRouter.ts @@ -31,7 +31,6 @@ router.post( router.get( "/buyer-get-carts", userAuthorization(["buyer"]), - isCartExist, cartControllers.buyerGetCarts ); @@ -79,5 +78,7 @@ router.get("/buyer-get-orders-history", userAuthorization(["buyer"]), isOrdersEx router.post("/create-stripe-product", userAuthorization(["buyer"]), validation(productDetailsSchema), stripeCreateProduct); router.post("/checkout-stripe-session", userAuthorization(["buyer"]), validation(checkoutSessionSchema), stripeCheckoutSession); +router.post("/user-create-order",userAuthorization(["buyer"]), cartControllers.userCreateOrder) +router.put("/update-cart-status",userAuthorization(["buyer"]), cartControllers.buyerUpdateCartStatus) export default router; \ No newline at end of file