diff --git a/package-lock.json b/package-lock.json index a1f5970..9bafc1a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5417,8 +5417,7 @@ "cloudinary-core": { "version": "2.12.3", "resolved": "https://registry.npmjs.org/cloudinary-core/-/cloudinary-core-2.12.3.tgz", - "integrity": "sha512-Ll4eDzcrIVn4zCttMh3Mdi+KNz07p5EEjBT2PQSRx8Eok1lKPt3uBBenOk/w88RKK3B8SFIWcEe/mN4BHQ0p8A==", - "requires": {} + "integrity": "sha512-Ll4eDzcrIVn4zCttMh3Mdi+KNz07p5EEjBT2PQSRx8Eok1lKPt3uBBenOk/w88RKK3B8SFIWcEe/mN4BHQ0p8A==" }, "color-convert": { "version": "2.0.1", @@ -6661,8 +6660,7 @@ "multer-storage-cloudinary": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/multer-storage-cloudinary/-/multer-storage-cloudinary-4.0.0.tgz", - "integrity": "sha512-25lm9R6o5dWrHLqLvygNX+kBOxprzpmZdnVKH4+r68WcfCt8XV6xfQaMuAg+kUE5Xmr8mJNA4gE0AcBj9FJyWA==", - "requires": {} + "integrity": "sha512-25lm9R6o5dWrHLqLvygNX+kBOxprzpmZdnVKH4+r68WcfCt8XV6xfQaMuAg+kUE5Xmr8mJNA4gE0AcBj9FJyWA==" }, "mute-stream": { "version": "0.0.8", @@ -7895,8 +7893,7 @@ "ws": { "version": "7.4.6", "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", - "requires": {} + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==" }, "xregexp": { "version": "2.0.0", diff --git a/resources/Orders/orderController.js b/resources/Orders/orderController.js index 8056833..a973ee1 100644 --- a/resources/Orders/orderController.js +++ b/resources/Orders/orderController.js @@ -149,11 +149,188 @@ export const updateOrderStatusById = async (req, res) => { const currentDate = new Date(); body["status_timeline." + req.body.status] = currentDate; // if (req.body?.package_weight) body.package_weight = req.body.package_weight; - const order = await Order.findById(req.params.id); - // console.log(order); + const order = await Order.findById(req.params.id).populate({ + path: "user", + select: "name email -_id", + }); + // console.log("order", order); // const parentData = { email: order?.parent?.email }; - // if (body.status === "cancelled") - // await OrderCancelledEmail(parentData.email, order.order_id); + if (req.body.status === "cancelled") { + body["order_Cancelled_Reason"] = req.body?.ReasonforCancellation; + body["iscancelled"] = true; + await Order.findByIdAndUpdate(order._id, body); + await sendEmail({ + to: `${order?.user?.email}`, // Change to your recipient + from: `${process.env.SEND_EMAIL_FROM}`, // Change to your verified sender + subject: `Order #${order?.orderID} Update: Cancellation and Refund Process`, + html: ` Hi ${ + order?.shippingInfo?.first_Name + }, +

We hope this message finds you well. We're writing to inform you that your order ${ + order?.orderID + } has been canceled. We understand that circumstances may change, and we're here to assist you throughout the process.

+ + +

Items :

+ + + + + + + + + + + + + + + + + + ${order?.orderItems + ?.map( + (product, index) => ` + + + + + + + + + + + + + ` + ) + .join("")} + + + + + +
S No.Product NameImageQuantityPriceGST AmountSubTotal
${ + index + 1 + }${ + product.name + }${
+          product.name
+        }${ + product.quantity + }₹${ + product.price + }₹${ + product?.gst_amount + }₹${ + product.product_Subtotal + }
Total Amount :₹${ + order?.total_amount + }
+

Cancellation Reason : ${ + req.body?.ReasonforCancellation + }

+

Refund Information: The amount from your canceled order will be processed for a refund. Please allow up to 7 working days for the amount to be transferred back to your original payment method.

+ +
If you have any concerns or further questions, please feel free to reply to this email. We appreciate your understanding and hope to serve you better in the future. +
+
+ Best regards,
+ + Team Smellika`, + }); + return res + .status(200) + .json({ status: "ok", message: "Order status updated successfully!" }); + } else if (req.body.status === "processing") { + await Order.findByIdAndUpdate(order._id, body); + + await sendEmail({ + to: `${order?.user?.email}`, // Change to your recipient + from: `${process.env.SEND_EMAIL_FROM}`, // Change to your verified sender + subject: `Your Order #${order?.orderID} is in Processing!`, + html: `

Exciting news! Your order #${ + order?.orderID + } has entered the processing phase. Our team is diligently preparing your items for dispatch. Rest assured, we're working hard to ensure everything is perfect for you.

+ Hi ${ + order?.shippingInfo?.first_Name + }, +

Order Status : Processing

+

Order Items :

+ + + + + + + + + + + + + + + + + + ${order?.orderItems + ?.map( + (product, index) => ` + + + + + + + + + + + + + ` + ) + .join("")} + + + + + +
S No.Product NameImageQuantityPriceGST AmountSubTotal
${ + index + 1 + }${ + product.name + }${
+          product.name
+        }${ + product.quantity + }₹${ + product.price + }₹${ + product?.gst_amount + }₹${ + product.product_Subtotal + }
Total Amount :₹${ + order?.total_amount + }
+
We'll send you another email with the tracking details as soon as your order is dispatched. If you have any questions or need assistance, feel free to reply to this email.
+
Thank you for choosing Smellika!
+
+ Best regards,
+ + Team Smellika`, + }); + return res + .status(200) + .json({ status: "ok", message: "Order status updated successfully!" }); + } // else if (body.status === "dispatched") { // const noBalanceRemaining = // order?.sales_items?.filter((e) => Number(e?.balance_quantity) > 0) @@ -176,24 +353,98 @@ export const updateOrderStatusById = async (req, res) => { // { status: body.status, "status_timeline.delivered": currentDate } // ); // } - if (req.body.status === "dispatched") { + else if (req.body.status === "dispatched") { body["courier_name"] = req.body.courierName; body["courier_tracking_id"] = req.body.TrackingID; await Order.findByIdAndUpdate(order._id, body); await sendEmail({ - to: `${req.body.sendemail}`, // Change to your recipient - + to: `${order?.user?.email}`, // Change to your recipient from: `${process.env.SEND_EMAIL_FROM}`, // Change to your verified sender + subject: `Your Order #${order?.orderID} is On Its Way!`, + html: ` Hi ${ + order?.shippingInfo?.first_Name + }, +

Exciting news! Your order #${ + order?.orderID + } has been dispatched and is en route to you. 🚚 Here are the details:

- subject: `Your Order is On Its Way!`, - html: `

Welcome to Smellika - Let the Shopping Begin!

- Hi ${req.body?.customerName}, +

Courier Name : ${ + req.body.courierName + }

+

Courier Tracking ID : ${ + req.body.TrackingID + }

-

Great news! Your order has been confirmed. Here are the details

-
- Best regards,
- - Team Smellika`, + +

Items :

+ + + + + + + + + + + + + + + + + + ${order?.orderItems + ?.map( + (product, index) => ` + + + + + + + + + + + + + ` + ) + .join("")} + + + + + +
S No.Product NameImageQuantityPriceGST AmountSubTotal
${ + index + 1 + }${ + product.name + }${
+          product.name
+        }${ + product.quantity + }₹${ + product.price + }₹${ + product?.gst_amount + }₹${ + product.product_Subtotal + }
Total Amount :₹${ + order?.total_amount + }
+

Order Status : Dispatched

+

If you have any questions or need assistance, feel free to reply to this email. +

+
Thanks for choosing Smellika! We hope you enjoy your purchase. +
+
+ Best regards,
+ + Team Smellika`, }); return res .status(200) @@ -202,11 +453,97 @@ export const updateOrderStatusById = async (req, res) => { body["isDelivered"] = true; body["DeliveredDate"] = req.body.DDate; await Order.findByIdAndUpdate(order._id, body); + await sendEmail({ + to: `${order?.user?.email}`, // Change to your recipient + from: `${process.env.SEND_EMAIL_FROM}`, // Change to your verified sender + subject: `Your Order #${order?.orderID} Has Been Delivered!`, + html: ` Hi ${ + order?.shippingInfo?.first_Name + }, +

Great news! Your order #${ + order?.orderID + } has been successfully delivered to your doorstep. We hope everything is just as you expected!

+

Items :

+ + + + + + + + + + + + + + + + + + ${order?.orderItems + ?.map( + (product, index) => ` + + + + + + + + + + + + + ` + ) + .join("")} + + + + + +
S No.Product NameImageQuantityPriceGST AmountSubTotal
${ + index + 1 + }${ + product.name + }${
+                product.name
+              }${ + product.quantity + }₹${ + product.price + }₹${ + product?.gst_amount + }₹${ + product.product_Subtotal + }
Total Amount :₹${ + order?.total_amount + }
+

Delivery Date: ${ + req.body.DDate + }

+

Your satisfaction is our priority, and we'd love to hear about your experience. Please take a moment to share your thoughts by leaving a review. Your feedback is invaluable to us! +

+
If you have any questions or concerns about your order, feel free to reply to this email. +
+
Thank you for choosing Smellika! We hope to serve you again soon. + +
+
+ Best regards,
+ + Team Smellika`, + }); + return res .status(200) .json({ status: "ok", message: "Order status updated successfully!" }); } else { - await Order.findByIdAndUpdate(order._id, body); + // await Order.findByIdAndUpdate(order._id, body); // console.log(order); res .status(200) diff --git a/resources/Orders/orderModel.js b/resources/Orders/orderModel.js index c360aba..b41e027 100644 --- a/resources/Orders/orderModel.js +++ b/resources/Orders/orderModel.js @@ -155,6 +155,13 @@ const orderSchema = new mongoose.Schema( cancelled: { type: Date }, returned: { type: Date }, }, + iscancelled: { + type: Boolean, + default: false, + }, + order_Cancelled_Reason: { + type: String, + }, courier_name: { type: String }, courier_tracking_id: { type: String }, }, diff --git a/resources/Orders/orderRoute.js b/resources/Orders/orderRoute.js index 89721b8..44cfa4b 100644 --- a/resources/Orders/orderRoute.js +++ b/resources/Orders/orderRoute.js @@ -47,11 +47,13 @@ router.route("/user/self").get(isAuthenticatedUser, getUserSelf); router .route("/getAll/:status") .get(isAuthenticatedUser, authorizeRoles("admin"), getAllOrder); - router +router .route("/getAll/") .get(isAuthenticatedUser, authorizeRoles("admin"), getOrders); router.route("/getOne/:id").get(isAuthenticatedUser, getSingleOrder); -router.route("/change/status/:id").patch(updateOrderStatusById); +router + .route("/change/status/:id") + .patch(isAuthenticatedUser, authorizeRoles("admin"), updateOrderStatusById); router .route("/delete/:id") diff --git a/resources/Products/ProductController.js b/resources/Products/ProductController.js index 9fb4748..5553fb2 100644 --- a/resources/Products/ProductController.js +++ b/resources/Products/ProductController.js @@ -79,8 +79,8 @@ export const getAllProduct = async (req, res) => { export const getAllProductsDevicesFirst = async (req, res) => { try { // we want products with category name Device to be displayed first, so i have first found the products with category name Devices then made another request to find all products and filtered products with category devices , then merged both arrays so we get devices first then all other categories - - const categoryName = 'Devices'; + + const categoryName = "Devices"; // Find the category object by name first const category = await CategoryModel.findOne({ categoryName }); @@ -88,8 +88,10 @@ export const getAllProductsDevicesFirst = async (req, res) => { throw new Error("Category not found"); } // products with device category - const deviceProducts = await Product.find({ category: category._id }).populate('category'); - + const deviceProducts = await Product.find({ + category: category._id, + }).populate("category"); + // all products const allProducts = await Product.find() .populate({ @@ -99,11 +101,13 @@ export const getAllProductsDevicesFirst = async (req, res) => { .sort({ createdAt: -1, }); - // filtering out products with device category - const filteredProducts = allProducts.filter((ele) => { return ele.category?.categoryName !== categoryName }) + // filtering out products with device category + const filteredProducts = allProducts.filter((ele) => { + return ele.category?.categoryName !== categoryName; + }); // merging both deviceProcuts and filtered products - const product = deviceProducts.concat(filteredProducts) + const product = deviceProducts.concat(filteredProducts); if (product) { return res.status(200).json({ success: true, @@ -240,10 +244,10 @@ export const updateProduct = async (req, res) => { category, image, gst_amount, + product_Status, gst, total_amount, } = req.body; - try { // Prepare an array for the images const jsonArray = JSON.parse(image); @@ -286,6 +290,7 @@ export const updateProduct = async (req, res) => { $set: { name, description, + product_Status, price, category, image: updatedImages, @@ -388,7 +393,9 @@ export const getProductsByCategory = async (req, res) => { if (!category) { throw new Error("Category not found"); } - const products = await Product.find({ category: category._id }).populate('category'); + const products = await Product.find({ category: category._id }).populate( + "category" + ); // console.log(products); if (products && products.length > 0) { diff --git a/resources/Products/ProductModel.js b/resources/Products/ProductModel.js index 4780c94..8d048b8 100644 --- a/resources/Products/ProductModel.js +++ b/resources/Products/ProductModel.js @@ -51,6 +51,11 @@ const productSchema = new Schema( }, }, ], + product_Status: { + type: String, + enum: ["Active", "Inactive"], + default: "Active", + }, addedBy: { type: Schema.Types.ObjectId, ref: "User", diff --git a/resources/ShippingAddresses/ShippingAddressController.js b/resources/ShippingAddresses/ShippingAddressController.js index f0411ed..9df4be4 100644 --- a/resources/ShippingAddresses/ShippingAddressController.js +++ b/resources/ShippingAddresses/ShippingAddressController.js @@ -53,7 +53,7 @@ export const AddshippingAddress = async (req, res) => { }); } }; - +// For website export const getSingleUserSippingAddress = async (req, res) => { try { const UserShippingAddress = await shippingAddress @@ -74,6 +74,27 @@ export const getSingleUserSippingAddress = async (req, res) => { }); } }; +// For Admin +export const getSingleUserSippingAddressForAdmin = async (req, res) => { + try { + const UserShippingAddress = await shippingAddress + .find({ user: req.params._id }) + + .sort({ createdAt: -1 }); + if (UserShippingAddress) { + res.status(201).json({ + success: true, + UserShippingAddress, + message: "All User Shipping Address Fetched", + }); + } + } catch (error) { + res.status(500).json({ + success: false, + message: error.message ? error.message : "Something went Wrong", + }); + } +}; /// export const deleteSelfShippingAddress = async (req, res) => { diff --git a/resources/ShippingAddresses/ShippingAddressRoute.js b/resources/ShippingAddresses/ShippingAddressRoute.js index d7b2b9b..470f118 100644 --- a/resources/ShippingAddresses/ShippingAddressRoute.js +++ b/resources/ShippingAddresses/ShippingAddressRoute.js @@ -3,10 +3,11 @@ import { AddshippingAddress, getSingleUserSippingAddress, deleteSelfShippingAddress, + getSingleUserSippingAddressForAdmin, updateShippingAddress, getSingleSippingAddress, } from "./ShippingAddressController.js"; -import { isAuthenticatedUser } from "../../middlewares/auth.js"; +import { authorizeRoles, isAuthenticatedUser } from "../../middlewares/auth.js"; const router = express.Router(); router.route("/new").post(isAuthenticatedUser, AddshippingAddress); @@ -14,15 +15,19 @@ router .route("/user/address/") .get(isAuthenticatedUser, getSingleUserSippingAddress); +router + .route("/user/address/:_id") + .get( + isAuthenticatedUser, + authorizeRoles("admin"), + getSingleUserSippingAddressForAdmin + ); + router .route("/delete/:id") .delete(isAuthenticatedUser, deleteSelfShippingAddress); - router - .route("/update/:id") - .patch(isAuthenticatedUser, updateShippingAddress); - router - .route("/get/:id") - .get(isAuthenticatedUser, getSingleSippingAddress); +router.route("/update/:id").patch(isAuthenticatedUser, updateShippingAddress); +router.route("/get/:id").get(isAuthenticatedUser, getSingleSippingAddress); export default router; diff --git a/resources/user/userController.js b/resources/user/userController.js index 60161d4..040eaad 100644 --- a/resources/user/userController.js +++ b/resources/user/userController.js @@ -201,24 +201,36 @@ export const getUserDetails = catchAsyncErrors(async (req, res, next) => { user, }); }); -export const getAllUsers = catchAsyncErrors(async (req, res, next) => { - const users = await User.find().populate("orders"); // Assuming orders are stored in a separate collection and populated in the User model - // Process user data to calculate last purchase date and order count - const usersWithInfo = users.map((user) => { - const lastPurchase = - user.orders.length > 0 - ? user.orders[user.orders.length - 1].createdAt - : null; - const orderCount = user.orders.length; - return { ...user.toJSON(), lastPurchase, orderCount }; - }); +// export const getUserDetailsForAdmin = catchAsyncErrors( +// async (req, res, next) => { +// const user = await User.findById(req.params._id); - res.status(200).json({ - success: true, - users: usersWithInfo, - }); -}); +// res.status(200).json({ +// success: true, +// user, +// }); +// } +// ); + +// export const getAllUsers = catchAsyncErrors(async (req, res, next) => { +// const users = await User.find().populate("orders"); // Assuming orders are stored in a separate collection and populated in the User model + +// // Process user data to calculate last purchase date and order count +// const usersWithInfo = users.map((user) => { +// const lastPurchase = +// user.orders.length > 0 +// ? user.orders[user.orders.length - 1].createdAt +// : null; +// const orderCount = user.orders.length; +// return { ...user.toJSON(), lastPurchase, orderCount }; +// }); + +// res.status(200).json({ +// success: true, +// users: usersWithInfo, +// }); +// }); // 7.Get single user (admin) export const getSingleUser = catchAsyncErrors(async (req, res, next) => { @@ -244,7 +256,7 @@ export const getUserOrderForAdmin = async (req, res) => { try { const order = await Order.find({ user: id, - payment_status: "success", + // payment_status: "success", }).sort({ createdAt: -1 }); if (order) { diff --git a/resources/user/userRoute.js b/resources/user/userRoute.js index 78c4c2b..df3bec0 100644 --- a/resources/user/userRoute.js +++ b/resources/user/userRoute.js @@ -27,6 +27,7 @@ router.route("/user/password/reset/:token").put(resetPassword); router.route("/user/logout").get(logout); router.route("/user/details").get(isAuthenticatedUser, getUserDetails); + router .route("/admin/users") .get(isAuthenticatedUser, authorizeRoles("admin"), getAllUser);