✨ feat(order): add customer email and optional fields, update order creation flow
- Added `customerEmail` field to Order model. - Made `customerNote` optional in the Order model. - Updated order creation logic to send a tracking email. - Updated order validation to handle optional fields. - Refactored configurations import path from `errors/configs` to `configs`. - Minor modifications across account and order services for consistency.
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Order" ADD COLUMN "customerEmail" TEXT,
|
||||
ALTER COLUMN "customerNote" DROP NOT NULL;
|
||||
@@ -20,8 +20,9 @@ model Order {
|
||||
status STATUS
|
||||
customerName String
|
||||
customerPhone String
|
||||
customerEmail String?
|
||||
customerAddress String
|
||||
customerNote String
|
||||
customerNote String?
|
||||
paymentType PAYMENT_TYPE
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
import { configs } from "../errors/configs";
|
||||
import { configs } from "../configs";
|
||||
import { AppError } from "../utils/app_error";
|
||||
import { jwtHelpers, JwtPayloadType } from "../utils/JWT";
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ErrorRequestHandler } from "express";
|
||||
import { ZodError } from "zod";
|
||||
import { configs } from "../errors/configs";
|
||||
import { configs } from "../configs";
|
||||
import handleZodError from "../errors/zodError";
|
||||
import { TErrorSources } from "../types/error";
|
||||
import { AppError } from "../utils/app_error";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { configs } from "../../errors/configs";
|
||||
import { configs } from "../../configs";
|
||||
import catchAsync from "../../utils/catch_async";
|
||||
import manageResponse from "../../utils/manage_response";
|
||||
import { account_services } from "./account.service";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import bcrypt from "bcrypt";
|
||||
import { Request } from "express";
|
||||
import { configs } from "../../errors/configs";
|
||||
import { configs } from "../../configs";
|
||||
import { prisma } from "../../lib/prisma";
|
||||
import { emailQueue } from "../../queues/email/email.queue";
|
||||
import { AppError } from "../../utils/app_error";
|
||||
@@ -72,7 +72,7 @@ const create_account_into_db = async (req: Request) => {
|
||||
email: payload.email,
|
||||
textBody: "You can use otp or verification link for verifying your account"
|
||||
})
|
||||
return result;
|
||||
return null;
|
||||
};
|
||||
|
||||
const verify_account_using_otp_into_db = async (req: Request) => {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
|
||||
import { Request } from "express";
|
||||
import { configs } from "../../configs";
|
||||
import { prisma } from "../../lib/prisma";
|
||||
import { AppError } from "../../utils/app_error";
|
||||
import { orderEmailQueue } from "../../queues/email/order/order.email.queue";
|
||||
|
||||
const get_all_order_from_db = async (req: Request) => {
|
||||
// define your own login here
|
||||
@@ -11,68 +12,42 @@ const get_all_order_from_db = async (req: Request) => {
|
||||
|
||||
const get_single_order_from_db = async (req: Request) => {
|
||||
// define your own login here
|
||||
const { id } = req.params;
|
||||
const { id } = req.params as { id: string };
|
||||
const result = await prisma.order.findUnique({ where: { id } });
|
||||
return result;
|
||||
};
|
||||
|
||||
const create_order_into_db = async (req: Request) => {
|
||||
// define your own login here
|
||||
const payload = req?.body;
|
||||
payload.status = "INITIATED";
|
||||
payload.paymentType = "COD"
|
||||
|
||||
const user = req.user
|
||||
console.log(user)
|
||||
const {
|
||||
shopAccountId,
|
||||
productPrice,
|
||||
productQuantity,
|
||||
productName,
|
||||
customerName,
|
||||
customerPhone,
|
||||
customerAddress,
|
||||
customerNote,
|
||||
paymentType,
|
||||
status,
|
||||
} = req.body
|
||||
const isUserExists = await prisma.account.findFirst({
|
||||
where: {
|
||||
id: user?.accountId
|
||||
}
|
||||
// nwo init order
|
||||
const result = await prisma.order.create({ data: payload });
|
||||
|
||||
// if email exist sent tracking link
|
||||
if (payload.customerEmail) {
|
||||
const trackingLink = `${configs.jwt.front_end_url}/track-order/${result.id}`;
|
||||
await orderEmailQueue.add("order-email-queue", {
|
||||
email: payload.customerEmail,
|
||||
subject: "Order Tracking",
|
||||
textBody: `Your order has been created. Track your order here: ${trackingLink}`,
|
||||
htmlBody: `<p>Your order has been created. Track your order here: <a href="${trackingLink}">Track Order</a></p>`
|
||||
})
|
||||
if (!isUserExists) {
|
||||
throw new AppError("Account not found", 404);
|
||||
}
|
||||
|
||||
const result = await prisma.order.create({
|
||||
data: {
|
||||
productPrice,
|
||||
productQuantity,
|
||||
productName,
|
||||
customerName,
|
||||
customerPhone,
|
||||
customerAddress,
|
||||
customerNote,
|
||||
paymentType,
|
||||
status,
|
||||
account: {
|
||||
connect: {
|
||||
id: user?.accountId,
|
||||
},
|
||||
},
|
||||
}
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
const update_order_into_db = async (req: Request) => {
|
||||
// define your own login here
|
||||
const { id } = req.params;
|
||||
const { id } = req.params as { id: string };
|
||||
const result = await prisma.order.update({ where: { id }, data: req.body });
|
||||
return result;
|
||||
};
|
||||
|
||||
const delete_order_from_db = async (req: Request) => {
|
||||
// define your own login here
|
||||
const { id } = req.params;
|
||||
const { id } = req.params as { id: string };
|
||||
const result = await prisma.order.delete({ where: { id } });
|
||||
return result;
|
||||
};
|
||||
|
||||
@@ -10,18 +10,16 @@ export const orderSwaggerDocs = {
|
||||
content: {
|
||||
"application/json": {
|
||||
example: JSON.stringify({
|
||||
|
||||
"shopAccountId": "",
|
||||
"productPrice": 1500,
|
||||
"productQuantity": 2,
|
||||
"productName": "Wireless Mouse",
|
||||
"customerName": "Rahim Uddin",
|
||||
"customerPhone": "+8801712345678",
|
||||
"customerEmail": "softvence.abumahid@gmail.com",
|
||||
"customerAddress": "Rangpur, Bangladesh",
|
||||
"customerNote": "Please deliver between 3-5 PM",
|
||||
"paymentType": "Cash on Delivery",
|
||||
"status": "Pending"
|
||||
|
||||
}), // put your request body
|
||||
"customerNote": "Please deliver between 3-5 PM"
|
||||
})
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
import { uuid, z } from "zod";
|
||||
import { z } from "zod";
|
||||
|
||||
const create_order = z.object({
|
||||
shopAccountId: z.string(),
|
||||
@@ -8,10 +8,9 @@ const create_order = z.object({
|
||||
productName: z.string(),
|
||||
customerName: z.string(),
|
||||
customerPhone: z.string(),
|
||||
customerEmail: z.string().optional(),
|
||||
customerAddress: z.string(),
|
||||
customerNote:z.string(),
|
||||
paymentType:z.string(),
|
||||
status:z.string()
|
||||
customerNote: z.string().optional()
|
||||
});
|
||||
const update_order = z.object({
|
||||
shopAccountId: z.string().optional(),
|
||||
@@ -20,9 +19,9 @@ const update_order = z.object({
|
||||
productName: z.string().optional(),
|
||||
customerName: z.string().optional(),
|
||||
customerPhone: z.string().optional(),
|
||||
customerEmail: z.string().optional(),
|
||||
customerAddress: z.string().optional(),
|
||||
customerNote: z.string().optional(),
|
||||
paymentType:z.string().optional(),
|
||||
status: z.string().optional()
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import sendMail from "../../../utils/mail_sender";
|
||||
import { TOrderEmailQueue } from "./order.email.queue";
|
||||
|
||||
// email.processor.ts
|
||||
export const orderEmailProcessor = async (job: any) => {
|
||||
const payload: TOrderEmailQueue = job.data;
|
||||
await sendMail({
|
||||
to: payload.email as string,
|
||||
subject: payload.subject,
|
||||
htmlBody: payload.htmlBody as string,
|
||||
textBody: payload.textBody as string,
|
||||
});
|
||||
console.log("Sending email job complete:", job.id);
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Queue } from "bullmq";
|
||||
import { redisConnection } from "../../connection";
|
||||
|
||||
export type TOrderEmailQueue = {
|
||||
email: string;
|
||||
subject: string;
|
||||
textBody?: string;
|
||||
htmlBody?: string;
|
||||
|
||||
}
|
||||
|
||||
|
||||
export const orderEmailQueue = new Queue<TOrderEmailQueue>("order-email-queue", {
|
||||
connection: redisConnection,
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
// email.worker.ts
|
||||
import { Worker } from "bullmq";
|
||||
import { redisConnection } from "../../connection";
|
||||
import { orderEmailProcessor } from "./order.email.processor";
|
||||
import { TOrderEmailQueue } from "./order.email.queue";
|
||||
|
||||
|
||||
export const emailWorker = new Worker<TOrderEmailQueue>(
|
||||
"order-email-queue",
|
||||
async (job) => orderEmailProcessor(job),
|
||||
{
|
||||
connection: redisConnection,
|
||||
}
|
||||
);
|
||||
@@ -1,3 +1,4 @@
|
||||
import "./email/email.worker";
|
||||
import "./email/order/order.email.worker";
|
||||
|
||||
console.log("Workers running...");
|
||||
@@ -1,6 +1,6 @@
|
||||
import { v2 as cloudinary } from 'cloudinary';
|
||||
import fs from 'fs';
|
||||
import { configs } from '../errors/configs';
|
||||
import { configs } from '../configs';
|
||||
|
||||
type ICloudinaryResponse = {
|
||||
asset_id: string;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import nodemailer from 'nodemailer';
|
||||
import { configs } from '../errors/configs';
|
||||
import { configs } from '../configs';
|
||||
type TMailContent = {
|
||||
to: string,
|
||||
subject: string,
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import app from "./app";
|
||||
import { configs } from "./app/errors/configs/index";
|
||||
import { configs } from "./app/configs/index";
|
||||
import { prisma } from "./app/lib/prisma";
|
||||
// import "./app/queues/worker";
|
||||
import "./app/queues/worker";
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { fileURLToPath } from "node:url";
|
||||
import path from "path";
|
||||
import { configs } from "./app/errors/configs";
|
||||
import { configs } from "./app/configs";
|
||||
import { accountSwaggerDocs } from "./app/modules/account/account.swagger";
|
||||
import { orderSwaggerDocs } from "./app/modules/order/order.swagger";
|
||||
import { planSwaggerDocs } from "./app/modules/plan/plan.swagger";
|
||||
|
||||
Reference in New Issue
Block a user