Skip to content

Commit

Permalink
ft(order): A buyer and seller should be able to watch their orders
Browse files Browse the repository at this point in the history
           -  Seller should see order made on his product
	   -  Buyer should see order has been ordered

[Delivery]
  • Loading branch information
yvanddniyo committed Jul 18, 2024
1 parent 9e61a03 commit 77dd55e
Show file tree
Hide file tree
Showing 16 changed files with 449 additions and 4 deletions.
48 changes: 48 additions & 0 deletions src/controllers/getOrderController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Request, Response } from "express"
import { getOrderBuyer, updateOrderStatusService } from "../services/OrderService"
import * as mailService from "../services/mail.service";
import { SUBJECTS, UserId } from "../types";
import { orderStatusTemplate } from "../email-templates/orderStatus";
import Order from "../sequelize/models/orders";
import User from "../sequelize/models/users";


export const getOrderController = async (req: Request, res: Response) => {
try {
const response = await getOrderBuyer(req, res)
return res.status(200).json({
status: 200,
length: response?.length,
orders: response?.length === 0? "You have not order yet" : response
})
} catch (error) {
console.log(error);
res.status(500).json({
status: 500,
message: `error accured during fetching order ${error}`
})
}
}

export const updateOrderStatus = async (req: Request, res: Response) => {

try {
const { id: userId} = req.user as UserId;
const { id: orderId } = req.params;
const { status } = req.body;
const buyerId = await Order.findByPk(orderId)
const dataValues = await User.findByPk(buyerId?.buyerId)

const updatedItems = await updateOrderStatusService(userId, orderId, status);
if (updatedItems) {
// @ts-ignore
await mailService.sendNotification(dataValues?.dataValues.email, SUBJECTS.ORDER_STATUS_UPDATED, orderStatusTemplate(dataValues?.dataValues.username, buyerId?.id, buyerId?.createdAt, status))

return res.json({ message: 'Order items status updated', updatedItems });
}

} catch (error: any) {
res.status(500).json({ message: error.message });
}
};

2 changes: 1 addition & 1 deletion src/controllers/paymentController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const handleSuccess = async (req: Request, res: Response) => {
try {
const { userId, sessionId } = req.query as { userId: string, sessionId: string }
const session = await stripe.checkout.sessions.retrieve(sessionId);
const user: any = await findUserById(userId);
const user: any = await findUserById(userId);``
const cart: any = await viewCart(user);
if (session.payment_status === "paid") {
const order = await placeOrder(cart);
Expand Down
74 changes: 74 additions & 0 deletions src/docs/orders.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { required } from "joi";

export const StatusSchema = {
type: "object",
properties: {
status: {
type: "string",
},
},
};

export const buyerAndSellerOrder = {
tags: ["orders"],
security: [{ bearerAuth: [] }],
summary: "Orders for seller and buyers",
responses: {
200: {
description: "Success",
},
400: {
description: "Bad request",
},
401: {
description: "Unauthorized",
},
500: {
description: "Internal server error",
},
},
};

export const statusUpdate = {
tags: ["orders"],
security: [{ bearerAuth: [] }],
summary: "Status update for seller",
parameters: [
{
name: "id",
in: "path",
required: true,
description: "order Id",
schema: {
type: "number",
},
},
],
requestBody: {
required: true,
content: {
"application/json": {
schema: {
type: "object",
properties: {
status: {
type: "string",
},
},
required: ["status"],
},
},
},
},
responses: {
201: {
description: "Upgrade successfully",
},
404: {
description: "Review not found",
},
500: {
description: "Internal server error.",
},
},
};
20 changes: 20 additions & 0 deletions src/docs/swagger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,12 @@ import { homepage } from "./home";
import { payment } from "./payments";
import { createReviewProduct, deleteReview, getReviewProduct, reviewSchema, updateReviewProduct } from "./reviews";
import { getAdProducts } from "./products";
<<<<<<< HEAD
import { PrivateChatSchema, getAllUserPrivateChats, getUserToUserPrivateMessages, createPrivateChat } from "./privateChatDoc";
=======
import {PrivateChatSchema, getAllUserPrivateChats, getUserToUserPrivateMessages, createPrivateChat } from "./privateChatDoc"
import { StatusSchema, buyerAndSellerOrder, statusUpdate } from "./orders";
>>>>>>> f1369b1 (ft(order): A buyer and seller should be able to watch their orders)

const docRouter = express.Router();

Expand Down Expand Up @@ -77,7 +82,12 @@ const options = {
{ name: "Wishes", description: "Endpoints related to Wishes" },
{ name: "Carts", description: "Endpoints related to Cart" },
{ name: "Payments", description: "Endpoints related to payments" },
<<<<<<< HEAD
{ name: "PrivateChat", description: "Endpoints related to Private Chat" },
=======
{name: "PrivateChat", description: "Endpoints related to Private Chat"},
{name: "orders", description: "Endpoints related to orders"}
>>>>>>> f1369b1 (ft(order): A buyer and seller should be able to watch their orders)
],

paths: {
Expand Down Expand Up @@ -197,6 +207,12 @@ const options = {
post: createPrivateChat,
get: getUserToUserPrivateMessages,
},
"/api/v1/orders": {
get: buyerAndSellerOrder
},
"/api/v1/orders/{id}/status": {
patch: statusUpdate
}
},
components: {
schemas: {
Expand All @@ -210,6 +226,10 @@ const options = {
Wish: wishSchema,
Review: reviewSchema,
PrivateChat: PrivateChatSchema,
<<<<<<< HEAD
=======
status: StatusSchema
>>>>>>> f1369b1 (ft(order): A buyer and seller should be able to watch their orders)
},
securitySchemes: {
bearerAuth: {
Expand Down
63 changes: 63 additions & 0 deletions src/email-templates/orderStatus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
export const orderStatusTemplate = (username: string, orderId: number, createdAt: Date, status: string) => {
return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Order Status</title>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap" rel="stylesheet">
<style>
body {
font-family: 'Poppins', sans-serif;
background-color: #f8f9fa;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
.container {
width: 80%;
max-width: 400px;
margin: auto;
padding: 30px;
background-color: #ffffff;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
text-align: center;
}
.title {
color: #333333;
font-size: 24px;
margin-bottom: 20px;
}
.content {
color: #666666;
font-size: 16px;
line-height: 1.6;
margin-bottom: 20px;
}
.status {
color: black;
}
.footer {
font-style: italic;
color: #999999;
}
.status{
font-weigth: 800;
}
</style>
</head>
<body>
<div class="container">
<h1 class="title">Order Status Updated 😍</h1>
<p class="content">Dear ${username}, Your product status with this order id #${orderId} has been successfully to <span class="status"> ${status}</span> .</p>
<div class="status">Status updated at ${createdAt}</div> <br />
<div class="footer">I hope you liked our services.</div>
</div>
</body>
</html>
`;
};
2 changes: 2 additions & 0 deletions src/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import cartRoutes from "./cartRoutes";
import notificationRoutes from "./notificationRoutes";
import paymentRouter from "./paymentRoutes";
import PrivateChatRoutes from "./privateChatRoutes";
import orderRouter from "./orderRoute";
const appROutes = Router();

appROutes.use("/chats", PrivateChatRoutes);
Expand All @@ -19,4 +20,5 @@ appROutes.use("/messages", joinChatRoomRoutes);
appROutes.use("/carts", cartRoutes);
appROutes.use("/notifications", notificationRoutes);
appROutes.use("/payment", paymentRouter);
appROutes.use("/orders", orderRouter)
export default appROutes;
12 changes: 12 additions & 0 deletions src/routes/orderRoute.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import express from "express"
import { getOrderController, updateOrderStatus, } from "../controllers/getOrderController";
import { isLoggedIn } from "../middlewares/isLoggedIn";
import { isAseller } from "../middlewares/sellerAuth";


const orderRouter = express.Router()

orderRouter.get('/', isLoggedIn, getOrderController)
orderRouter.patch("/:id/status", isLoggedIn, updateOrderStatus)

export default orderRouter;
6 changes: 6 additions & 0 deletions src/schemas/signUpSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,9 @@ export const profileSchemas = Joi.object({
country: Joi.string()
.optional()
})

export const OrderStatus = Joi.object({
status: Joi.string()
.valid("Pending", "Delivered", "Cancelled")
.required()
})
31 changes: 31 additions & 0 deletions src/sequelize/migrations/x20240711191430-modify-order-items.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
module.exports = {
async up(queryInterface, Sequelize) {
return Promise.all([
queryInterface.addColumn(
'orderItems',
'userId',
{
type: Sequelize.INTEGER,
allowNull: true,
},
),
queryInterface.addColumn(
'orderItems',
'status',
{
type: Sequelize.ENUM,
allowNull: false,
values: ["Pending", "Delivered", "Cancelled"],
defaultValue: 'Pending'
},
),
]);
},

down(queryInterface, Sequelize) {
return Promise.all([
queryInterface.removeColumn('orderItems', 'status'),
queryInterface.removeColumn('orderItems', 'userId'),
]);
},
};
65 changes: 65 additions & 0 deletions src/sequelize/migrations/z20240529192329-add-private-Chat-Model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
'use strict';

/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up (queryInterface, Sequelize) {
await queryInterface.createTable('PrivateChats', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
userId: {
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: 'users',
key: 'id'
}
},
receiverId: {
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: 'users',
key: 'id'
}
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});

await queryInterface.addColumn('messages', 'privateChatId', {
type: Sequelize.INTEGER,
allowNull: true,
references: {
model: 'PrivateChats',
key: 'id'
},
onUpdate: 'CASCADE',
onDelete: 'SET NULL',
});
await queryInterface.addColumn('messages', 'isPrivate',{
type: Sequelize.BOOLEAN,
allowNull: false
})



},


async down (queryInterface, Sequelize) {
await queryInterface.dropTable('PrivateChats');
await queryInterface.removeColumn('messages', 'privateChatId');
await queryInterface.removeColumn('messages', 'isPrivate')

}
};
Loading

0 comments on commit 77dd55e

Please sign in to comment.