From d1481c0efc143fe83a70c610ac20ac95ca181179 Mon Sep 17 00:00:00 2001 From: pawan-dot <71133473+pawan-dot@users.noreply.github.com> Date: Thu, 18 Apr 2024 17:50:07 +0530 Subject: [PATCH 1/7] change product and razorpay --- .env | 10 +- .../Orders/RazerPayCheckoutController.js | 151 ++++++++++-------- resources/Orders/orderController.js | 28 +++- resources/Orders/orderModel.js | 10 +- 4 files changed, 119 insertions(+), 80 deletions(-) diff --git a/.env b/.env index e5b250d..c10b19c 100644 --- a/.env +++ b/.env @@ -12,12 +12,12 @@ CLOUDINARY_API_KEY = "877544192441588" CLOUDINARY_API_SECRET = "9paejuSC-fY5b0WoaUuSFURSnvM" WEBHOOK_SECRET_KEY="whsec_m9u7CFBCY1qWarhxq65CkII6egOBf20K" -STRIPE_SECRET_KEY="sk_test_51OhPRdSG6gbAOwcEid1GavJ4FTD0ZuHVTferdvJwKal77RlMtFJGBzL5GjtL0ie8ZJztsGjUWi8DWrnw1pDdDRGS005Hk0ahql" -STRIPE_WEBHOOK_SECRET="whsec_dc9b9084fc764c806c8c5c06dd91de1ee809e9c8deab6d56e8e3ef2fc9c30c67" -<<<<<<< HEAD +# STRIPE_SECRET_KEY="sk_test_51OhPRdSG6gbAOwcEid1GavJ4FTD0ZuHVTferdvJwKal77RlMtFJGBzL5GjtL0ie8ZJztsGjUWi8DWrnw1pDdDRGS005Hk0ahql" +# STRIPE_WEBHOOK_SECRET="whsec_dc9b9084fc764c806c8c5c06dd91de1ee809e9c8deab6d56e8e3ef2fc9c30c67" + FRONTEND_URL="http://127.0.0.1:5173" -RAZERPAY_KEY_ID="rzp_test_smzQmWoS64S2W9" -RAZERPAY_SECRET_KEY="cSn6MgA4xSEaZBpPp4zpDA3C" +RAZERPAY_KEY_ID="rzp_test_2rg1Bq3Ki8xw9e" +RAZERPAY_SECRET_KEY="WFhHbXL7AlLIuull9kKjYiNA" FRONTEND_URL="https://smellika.com" diff --git a/resources/Orders/RazerPayCheckoutController.js b/resources/Orders/RazerPayCheckoutController.js index fe4f436..b0b0afc 100644 --- a/resources/Orders/RazerPayCheckoutController.js +++ b/resources/Orders/RazerPayCheckoutController.js @@ -39,20 +39,7 @@ export const getRzpkey = async (req, res) => { }); }; export const checkout = async (req, res) => { - // console.log(req.body.subtotal); - const options = { - amount: Number(req.body.subtotal * 100), - currency: "INR", - }; - const order = await instance.orders.create(options); - // id: "order_Ns423uPG0r36Dk"; - - //save order in database - - if (order?.id) { - const { email } = req.user; - if (!email) - return res.status(400).send({ message: "Please enter the email" }); + try { const { address, cart, subtotal } = req.body; if (cart.length < 1) return res.status(400).json({ message: "cart is empty!" }); @@ -64,63 +51,90 @@ export const checkout = async (req, res) => { return res .status(404) .json({ message: "please provide product subtotal!" }); - // switch (true) { - // //validation - // case !address: { - // return res.status(404).json({ msg: "please select shipping address" }); - // } - // case !subtotal: { - // return res.status(404).json({ msg: "please provide product subtotal" }); - // } - // } - let addss = await shippingAddress.findById(address); - let shipping = { - first_Name: addss.first_Name, - last_Name: addss.last_Name, - phone_Number: addss.phone_Number, - street: addss.street, - city: addss.city, - state: addss.state, - postalCode: addss?.postalCode, - country: addss.country, - addressId: address, + const options = { + amount: Number(req.body.subtotal * 100), + currency: "INR", }; - // console.log("cart", cart[0]?.product?.gst); - const orderItems = await cart.map((item) => ({ - product: item.product._id, - name: item.product.name, - price: item.product.price, - total_Amount: item.product.total_amount, + const order = await instance.orders.create(options); + //save order in database + if (order?.id) { + const { email } = req.user; + if (!email) + return res.status(400).send({ message: "Please enter the email" }); + let addss = await shippingAddress.findById(address); + let shipping = { + first_Name: addss.first_Name, + last_Name: addss.last_Name, + phone_Number: addss.phone_Number, + street: addss.street, + city: addss.city, + state: addss.state, + postalCode: addss?.postalCode, + country: addss.country, + addressId: address, + }; + // console.log("cart", cart[0]?.product?.gst); + const orderItems = await cart.map((item) => ({ + product: item.product._id, + name: item.product.name, + variant_Name: item.variant.variant_Name, + price: Number(item.variant.price), + total_price: item.quantity * Number(item.variant.price), - image: item.product.image, - quantity: item.quantity, - gst_amount: item.product.gst_amount, - gst_rate: item.product.gst?.tax, - tax_Name: item.product.gst?.name, - product_Subtotal: item.subtotal, - })); + image: item.product.image, + quantity: item.quantity, + gst_amount: Number( + (Number(item.variant.price) * item.variant.gst_Id?.tax) / 100 + )?.toFixed(3), + total_gst_amount: Number( + Number(item.quantity) * + Number( + (Number(item.variant.price) * item.variant.gst_Id?.tax) / 100 + ) + )?.toFixed(3), + gst_rate: item.variant.gst_Id?.tax, + tax_Name: item.variant?.gst_Id?.name, + product_Subtotal: Number( + Number(item.quantity * Number(item.variant.price)) + + Number( + Number(item.quantity) * + Number( + (Number(item.variant.price) * item.variant.gst_Id?.tax) / 100 + ) + ) + ).toFixed(3), + })); - // console.log("line", lineItems[0]); - const Id = await generateUniqueOrderId(); - const orders = await Order.create({ - orderID: Id, - total_amount: subtotal, - orderItems, - shippingInfo: shipping, - user: req.user._id, - razorpay_order_id: order?.id, + // console.log("line", lineItems[0]); + const Id = await generateUniqueOrderId(); + const orders = await Order.create({ + orderID: Id, + total_amount: subtotal, + orderItems, + shippingInfo: shipping, + user: req.user._id, + razorpay_order_id: order?.id, + }); + } else { + return res.status(400).json({ + success: false, + message: "Failled to order Create", + }); + } + + return res.status(200).json({ + success: true, + order, }); - } else { - res.status(400).json({ + } catch (error) { + console.log("error", error); + return res.status(400).json({ success: false, - message: "Failled to order Create", + message: error?.description + ? "Razorpay" + error?.description + : "Something went wrong!", }); } - - res.status(200).json({ - success: true, - order, - }); }; export const paymentVerification = async (req, res) => { @@ -188,6 +202,8 @@ export const paymentVerification = async (req, res) => { S No. Product Name + Variant + Image Quantity @@ -210,6 +226,9 @@ export const paymentVerification = async (req, res) => { ${ product.name } + ${ + product?.variant_Name + } ${
@@ -226,7 +245,7 @@ export const paymentVerification = async (req, res) => {
            product?.gst_amount
          }</td>
                 <td style=₹${ - product.product_Subtotal + product?.product_Subtotal } @@ -234,7 +253,7 @@ export const paymentVerification = async (req, res) => { ) .join("")} - Total Amount : + Total Amount : ₹${ findSameOrder?.total_amount } diff --git a/resources/Orders/orderController.js b/resources/Orders/orderController.js index 38d618b..0e1ddd4 100644 --- a/resources/Orders/orderController.js +++ b/resources/Orders/orderController.js @@ -176,14 +176,12 @@ export const updateOrderStatusById = async (req, res) => { S No. - Product Name + Variant Image - Quantity Price GST Amount - SubTotal @@ -199,6 +197,9 @@ export const updateOrderStatusById = async (req, res) => { ${ product.name + } + ${ + product?.variant_Name } - Total Amount : + Total Amount : ₹${ order?.total_amount } @@ -267,6 +268,7 @@ export const updateOrderStatusById = async (req, res) => { S No. Product Name + Variant Image Quantity @@ -288,6 +290,9 @@ export const updateOrderStatusById = async (req, res) => { ${ product.name + } + ${ + product?.variant_Name } - Total Amount : + Total Amount : ₹${ order?.total_amount } @@ -383,6 +388,7 @@ export const updateOrderStatusById = async (req, res) => { S No. Product Name + Variant Image Quantity @@ -404,6 +410,9 @@ export const updateOrderStatusById = async (req, res) => { ${ product.name + } + ${ + product?.variant_Name } - Total Amount : + Total Amount : ₹${ order?.total_amount } @@ -470,8 +479,8 @@ export const updateOrderStatusById = async (req, res) => { S No. Product Name + Variant Image - Quantity Price GST Amount @@ -491,6 +500,9 @@ export const updateOrderStatusById = async (req, res) => { ${ product.name + } + ${ + product?.variant_Name } - Total Amount : + Total Amount : ₹${ order?.total_amount } diff --git a/resources/Orders/orderModel.js b/resources/Orders/orderModel.js index b41e027..79f12f8 100644 --- a/resources/Orders/orderModel.js +++ b/resources/Orders/orderModel.js @@ -62,11 +62,15 @@ const orderSchema = new mongoose.Schema( type: String, default: "", }, + variant_Name: { + type: String, + default: "", + }, price: { type: Number, default: "", }, - total_Amount: { + total_price: { type: Number, default: "", }, @@ -85,6 +89,10 @@ const orderSchema = new mongoose.Schema( type: Number, default: "", }, + total_gst_amount: { + type: Number, + default: "", + }, gst_rate: { type: Number, default: "", From 5378264c99593a0e220a6335a2cbcc6feeadc523 Mon Sep 17 00:00:00 2001 From: Sibunnayak Date: Fri, 19 Apr 2024 15:54:41 +0530 Subject: [PATCH 2/7] point of sale instorecashOrders --- app.js | 4 + resources/PosOrders/PosCheckoutController.js | 85 +++ .../PosRazerPayCheckoutController.js | 481 +++++++++++++++ resources/PosOrders/PosorderController.js | 552 ++++++++++++++++++ resources/PosOrders/PosorderModel.js | 165 ++++++ resources/PosOrders/PosorderRoute.js | 51 ++ 6 files changed, 1338 insertions(+) create mode 100644 resources/PosOrders/PosCheckoutController.js create mode 100644 resources/PosOrders/PosRazerPayCheckoutController.js create mode 100644 resources/PosOrders/PosorderController.js create mode 100644 resources/PosOrders/PosorderModel.js create mode 100644 resources/PosOrders/PosorderRoute.js diff --git a/app.js b/app.js index 6adea88..4781cde 100644 --- a/app.js +++ b/app.js @@ -171,6 +171,8 @@ import CouponRoute from "./resources/Affiliate&Coupon/Coupon/CouponRoute.js"; // import ShortUrlRouter from "./resources/Businesses/Short_Urls/ShortUrlRoute.js"; //support Ticket import SupportRouter from "./resources/Supports/supportRoute.js"; +// Point of Sale +import PosorderRoute from "./resources/PosOrders/PosorderRoute.js"; app.use("/api/v1/", user); //Product @@ -238,4 +240,6 @@ app.use("/api/panel", PanelRoute); // app.use("/api/shorturl", ShortUrlRouter); //Support app.use("/api", SupportRouter); +// Point of Sale +app.use("/api/posOrder", PosorderRoute); export default app; diff --git a/resources/PosOrders/PosCheckoutController.js b/resources/PosOrders/PosCheckoutController.js new file mode 100644 index 0000000..8acb18e --- /dev/null +++ b/resources/PosOrders/PosCheckoutController.js @@ -0,0 +1,85 @@ +import { POSOrder } from "./PosorderModel.js"; +import { shippingAddress } from "../ShippingAddresses/ShippingAddressModel.js"; + +//generate unique order id +const generateOrderId = async () => { + const currentYear = new Date().getFullYear(); + // Find the latest order to get the last serial number + const latestOrder = await POSOrder.findOne({}, {}, { sort: { orderID: -1 } }); + let serialNumber = 1; + + if (latestOrder) { + const lastYear = parseInt(latestOrder.orderID.substring(0, 4), 10); + if (lastYear === currentYear) { + // If the last order was in the current year, increment the serial number + serialNumber = parseInt(latestOrder.orderID.substring(4), 10) + 1; + } + } + // Pad the serial number with zeros and concatenate with the current year + const paddedSerialNumber = serialNumber.toString().padStart(7, "0"); + const orderId = `${currentYear}${paddedSerialNumber}`; + return orderId; +}; + +export const createOrderCheckout = async (req, res) => { + try { + const { address, cart, user, SalesType, paymentMode } = + req.body; +// console.log(req.body) + // Perform validation + if (!address || !cart || cart.length === 0 || !SalesType || !user || !paymentMode) { + return res.status(400).json({ message: "Invalid order data" }); + } + + // Retrieve shipping address from database + const shippingInfo = await shippingAddress.findById(address); + if (!shippingInfo) { + return res.status(404).json({ message: "Shipping address not found" }); + } + + // Ensure that addressId is included in the shippingInfo object + const { _id: addressId, ...restOfShippingInfo } = shippingInfo.toObject(); + + // Calculate total amount based on the product_Subtotal of each product + const totalAmount = cart.reduce( + (acc, item) => acc + item.product_Subtotal, + 0 + ); + + // Construct order items array + const orderItems = cart.map((item) => ({ + product: item.product, + name: item.name, + price: item.price, + quantity: item.quantity, + product_Subtotal: item.total_amount, + gst_amount: item.gst_amount, + image: item.image, + variant_Name: item.variant_Name, + })); + + // Generate a unique order ID + const orderId = await generateOrderId(); + + // Create the order document + const order = await POSOrder.create({ + orderID: orderId, + total_amount: totalAmount, + orderItems, + shippingInfo: { + addressId: addressId, // Include the addressId + ...restOfShippingInfo, // Include other shipping information + }, + user, // Assuming you have authenticated users + SalesType, + paymentMode, + }); + + return res.status(201).json({ success: true, order }); + } catch (error) { + console.error("Error creating order:", error); + return res + .status(500) + .json({ success: false, message: "Internal server error" }); + } +}; diff --git a/resources/PosOrders/PosRazerPayCheckoutController.js b/resources/PosOrders/PosRazerPayCheckoutController.js new file mode 100644 index 0000000..111fbe4 --- /dev/null +++ b/resources/PosOrders/PosRazerPayCheckoutController.js @@ -0,0 +1,481 @@ +import bodyParser from "body-parser"; +import crypto from "crypto"; +import Razorpay from "razorpay"; +import { POSOrder } from "./PosorderModel.js"; +import { shippingAddress } from "../ShippingAddresses/ShippingAddressModel.js"; +import sendEmail from "../../Utils/sendEmail.js"; +const instance = new Razorpay({ + key_id: process.env.RAZERPAY_KEY_ID, + key_secret: process.env.RAZERPAY_SECRET_KEY, +}); + +const generateUniqueOrderId = async () => { + const currentYear = new Date().getFullYear(); + // Find the latest order to get the last serial number + const latestOrder = await POSOrder.findOne({}, {}, { sort: { orderID: -1 } }); + let serialNumber = 1; + + if (latestOrder) { + const lastYear = parseInt(latestOrder.orderID.substring(0, 4), 10); + if (lastYear === currentYear) { + // If the last order was in the current year, increment the serial number + serialNumber = parseInt(latestOrder.orderID.substring(4), 10) + 1; + } + } + // Pad the serial number with zeros and concatenate with the current year + const paddedSerialNumber = serialNumber.toString().padStart(7, "0"); + const orderId = `${currentYear}${paddedSerialNumber}`; + return orderId; +}; + +export const getRzpKey = async (req, res) => { + try { + const { name, email } = req.params; + console.log("name", name, "email", email); + if (!name || !email) { + throw new Error("Name and email are required parameters"); + } + res.status(200).json({ + success: true, + key: process.env.RAZERPAY_KEY_ID, + name, + email, + }); + } catch (error) { + console.error("Error in getRzpKey:", error); + res + .status(500) + .json({ + success: false, + message: error.message || "Internal server error", + }); + } +}; + +export const checkout = async (req, res) => { + try { + console.log(req.body); + const options = { + amount: Number(req.body.subtotal * 100), + currency: "INR", + }; + + console.log("options", options); + + // Wait for the order creation to complete + const order = await instance.orders.create(options); + + console.log("order", order); + + // Check if the order was created successfully + if (!order || !order.id) { + return res.status(400).json({ + success: false, + message: "Failed to create order", + }); + } + + // Extract required data from request parameters and body + const { email } = req.params; + const { address, cart, user, SalesType, paymentMode, subtotal } = req.body; + + // Check for required parameters + if (!email) { + return res.status(400).send({ message: "Please enter the email" }); + } + + if (cart.length < 1) { + return res.status(400).json({ message: "Cart is empty!" }); + } + + if (!address) { + return res + .status(404) + .json({ message: "Please select a shipping address!" }); + } + + if (!subtotal) { + return res + .status(404) + .json({ message: "Please provide the product subtotal!" }); + } + + // Fetch shipping information from the database + const shippingInfo = await shippingAddress.findById(address); + if (!shippingInfo) { + return res.status(404).json({ message: "Shipping address not found" }); + } + + console.log("shippinginfo", shippingInfo); + + // Extract addressId and other shipping information + const { _id: addressId, ...restOfShippingInfo } = shippingInfo.toObject(); + + // Prepare order items + const orderItems = cart.map((item) => ({ + product: item.product, + name: item.name, + price: item.price, + quantity: item.quantity, + product_Subtotal: item.total_amount, + gst_amount: item.gst_amount, + image: item.image, + variant_Name: item.variant_Name, + })); + + // Generate a unique order ID + const orderId = await generateUniqueOrderId(); + + // Create the order in the database + const orders = await POSOrder.create({ + orderID: orderId, + total_amount: subtotal, + orderItems, + shippingInfo: { + addressId: addressId, + ...restOfShippingInfo, + }, + user, + SalesType, + paymentMode, + razorpay_order_id: order.id, + }); + + res.status(200).json({ + success: true, + order, + }); + } catch (error) { + console.error("Error in checkout:", error); + res + .status(500) + .json({ + success: false, + message: error.message || "Internal server error", + }); + } +}; + +export const paymentVerification = async (req, res) => { + const { razorpay_order_id, razorpay_payment_id, razorpay_signature } = + req.body; + console.log(req.body); + const body = razorpay_order_id + "|" + razorpay_payment_id; + + const expectedSignature = crypto + .createHmac("sha256", process.env.RAZERPAY_SECRET_KEY) + .update(body.toString()) + .digest("hex"); + + const isAuthentic = expectedSignature === razorpay_signature; + + if (isAuthentic) { + // Database comes here + let findSameOrder = await POSOrder.findOne({ + razorpay_order_id: razorpay_order_id, + }).populate({ + path: "user", + select: "name email -_id", + }); + // console.log("findSameOrder", findSameOrder); + if (findSameOrder) { + (findSameOrder.razorpay_payment_id = razorpay_payment_id), // await Payment.create({ + (findSameOrder.isPaid = true), + (findSameOrder.paidAt = Date.now()), + (findSameOrder.razorpay_signature = razorpay_signature); + // await Payment.create({ + findSameOrder.payment_status = "success"; + + findSameOrder.orderStatus = "new"; + await findSameOrder.save(); + } + //send email to customer + // console.log("findSameOrder", findSameOrder); + await sendEmail({ + to: `${findSameOrder?.user?.email}`, // Change to your recipient + + from: `${process.env.SEND_EMAIL_FROM}`, // Change to your verified sender + + subject: `Your POSOrder #${findSameOrder?.orderID} Confirmation`, + html: `

Welcome to Smellika - Let the Shopping Begin!

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

Great news! Your order #${ + findSameOrder?.orderID + } has been confirmed. Here are the details

+

Shipping Address : ${ + findSameOrder?.shippingInfo?.first_Name + } ${findSameOrder?.shippingInfo?.last_Name} , ${ + findSameOrder?.shippingInfo?.street + } ${findSameOrder?.shippingInfo?.city} ${ + findSameOrder?.shippingInfo?.state + } ${findSameOrder?.shippingInfo?.country}, PIN-${ + findSameOrder?.shippingInfo?.postalCode + }, Phone Number: ${findSameOrder?.shippingInfo?.phone_Number}

+

POSOrder Items :

+ + + + + + + + + + + + + + + + + + ${findSameOrder?.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 :₹${ + findSameOrder?.total_amount + }
+ +
+ Best regards,
+ + Team Smellika`, + }); + // console.log("findSameOrder", findSameOrder); + + // // findSameOrder.razorpay_payment_id=razorpay_payment_id,// await Payment.create({ + // findOrder.paidAt = new Date(event.data.object.created * 1000); + // findOrder.isPaid = true; + + // razorpay_signature: { type: String }, + // razorpay_order_id, + // razorpay_payment_id, + // razorpay_signature, + // }); + + // res.redirect(`https://admin.smellika.com/#/pos`); + res.redirect(`http://localhost:3000/#/pos`); + } else { + res.status(400).json({ + success: false, + }); + } +}; +export const handlePayment = async (req, res) => { + try { + const { email } = req.user; + if (!email) + return res.status(400).send({ message: "Please enter the email" }); + const { address, cart, subtotal } = req.body; + if (cart.length < 1) + return res.status(400).json({ message: "cart is empty!" }); + switch (true) { + //validation + case !address: { + return res.status(404).json({ msg: "please provide shipping address" }); + } + case !subtotal: { + return res.status(404).json({ msg: "please provide product subtotal" }); + } + } + let addss = await shippingAddress.findById(address); + // console.log(addss?.postalCode); + let shipping = { + first_Name: addss.first_Name, + last_Name: addss.last_Name, + phone_Number: addss.phone_Number, + street: addss.street, + city: addss.city, + state: addss.state, + postalCode: addss?.postalCode, + country: addss.country, + addressId: address, + }; + const orderItems = await cart.map((item) => ({ + product: item.product._id, + name: item.product.name, + price: item.product.total_amount, + image: item.product.image, + quantity: item.quantity, + product_Subtotal: item.subtotal, + })); + + // console.log("line", lineItems[0]); + const Id = await generateUniqueOrderId(); + const order = await POSOrder.create({ + orderID: Id, + total_amount: subtotal, + orderItems, + shippingInfo: shipping, + user: req.user._id, + }); + console.log("fffffffff", order, "llllllllll"); + const lineItems = await cart.map((item) => ({ + price_data: { + currency: "inr", + product_data: { + name: item.product.name, + + images: [item.product.image[0]?.url], + }, + unit_amount: Number(item.product.total_amount) * 100, + }, + quantity: Number(item.quantity), + })); + if (order) { + const session = await stripe.checkout.sessions.create({ + payment_method_types: ["card"], + line_items: lineItems, + mode: "payment", + customer_email: `${email}`, + metadata: { + orderId: order._id.toString(), + + // Add any other key-value pairs as needed + }, + success_url: `${process.env.FRONTEND_URL}/cart`, + cancel_url: `${process.env.FRONTEND_URL}/error`, + }); + // res.json({ sessionId: session.id }); + + res.status(200).send({ message: "order created", url: session.url }); + } + } catch (err) { + console.log(err); + res.status(500).send({ message: "Something went wrong", err }); + } +}; + +export const webhook = async (req, res) => { + const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET; + const signature = req.headers["stripe-signature"]; + let event; + if (webhookSecret) { + try { + event = stripe.webhooks.constructEvent( + req.body, + signature, + webhookSecret + ); + } catch (err) { + console.log(`❌ Error message: ${err.message}`); + res.status(400).send(`Webhook Error: ${err.message}`); + return; + } + } + + if (event.type === "checkout.session.completed") { + // console.log("dddddddddddd", event.data); + const findOrder = await POSOrder.findById( + event.data.object.metadata?.orderId + ); + findOrder.paypal_payer_id = event.data.object.id; + findOrder.paidAt = new Date(event.data.object.created * 1000); + findOrder.isPaid = true; + if (event.data.object?.payment_status === "paid") { + findOrder.payment_status = "success"; + } else { + findOrder.payment_status = "failed"; + } + findOrder.orderStatus = "new"; + await findOrder.save(); + await sendEmail({ + to: `${event.data.object.customer_email}`, // Change to your recipient + + from: `${process.env.SEND_EMAIL_FROM}`, // Change to your verified sender + + subject: `Your POSOrder #${findOrder?.orderID} Confirmation`, + html: `

Welcome to Smellika - Let the Shopping Begin!

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

Great news! Your order #${findOrder?.orderID} has been confirmed. Here are the details

+
+ Best regards,
+ + Team Smellika`, + }); + + // Items: [List of Purchased Items] + // Total Amount: [Total Amount] + // Shipping Address: [Shipping Address] + + // We'll keep you updated on the shipping progress. Thanks for choosing Smellika! + + // Best regards + // Team Smellika + console.log( + "event.data.object", + event.data.object, + "---------------------" + ); + + console.log(`💰 Payment status: ${event.data.object?.payment_status}`); + + // Saving the payment details in the database + // const payment = await Payment.create({ + // customer_email: event.data.object.customer_email, + // amount: event.data.object.amount_total / 100, + // paymentId: event.data.object.id, + // paymentStatus: event.data.object.payment_status, + // createdAt: event.data.object.created, + // }); + } + // if (event.type === "checkout.session.completed") { + // console.log("dddddddddddd", event.data); + // console.log("event.data.object", event.data.object); + // console.log(`💰 Payment status: ${event.data.object?.payment_status}`); + // payment_intent.payment_failed; + + // // Saving the payment details in the database + // // const payment = await Payment.create({ + // // customer_email: event.data.object.customer_email, + // // amount: event.data.object.amount_total / 100, + // // paymentId: event.data.object.id, + // // paymentStatus: event.data.object.payment_status, + // // createdAt: event.data.object.created, + // // }); + // } + + // Return a 200 res to acknowledge receipt of the event + res.status(200).end(); + // res.send().end(); +}; diff --git a/resources/PosOrders/PosorderController.js b/resources/PosOrders/PosorderController.js new file mode 100644 index 0000000..6a02741 --- /dev/null +++ b/resources/PosOrders/PosorderController.js @@ -0,0 +1,552 @@ +import sendEmail from "../../Utils/sendEmail.js"; +import { POSOrder } from "./PosorderModel.js"; + +export const getAllOrder = async (req, res) => { + try { + const { status } = req.params; + const order = await POSOrder.find({ + IsStoreDelivery: "Cash", + orderStatus: status, + }) + .populate({ + path: "user", + select: "name -_id", + }) + .populate({ + path: "shippingInfo.addressId", + }) + .sort({ updatedAt: -1 }); + if (order) { + res.status(201).json({ + success: true, + order, + message: "All POSOrder Fetched", + }); + } + } catch (error) { + res.status(500).json({ + success: false, + message: error.message ? error.message : "Something went Wrong", + }); + } +}; +export const getOrders = async (req, res) => { + try { + const order = await POSOrder.find({ + // payment_status: "success", + }) + .populate({ + path: "user", + select: "name -_id", + }) + .populate({ + path: "shippingInfo.addressId", + }) + .sort({ updatedAt: -1 }); + if (order) { + res.status(201).json({ + success: true, + order, + message: "All POSOrder Fetched", + }); + } + } catch (error) { + res.status(500).json({ + success: false, + message: error.message ? error.message : "Something went Wrong", + }); + } +}; +export const getSingleOrder = async (req, res) => { + try { + if (!req.params.id) + return res.status(400).json({ message: "please Provide POSOrder Id" }); + + const order = await POSOrder.findById(req.params.id) + .populate({ + path: "user", + select: "name email -_id", + }) + .populate({ + path: "shippingInfo.addressId", + }) + .sort({ createdAt: -1 }); + if (order) { + res.status(201).json({ + success: true, + order, + message: " POSOrder Fetched", + }); + } + } catch (error) { + res.status(500).json({ + success: false, + message: error.message ? error.message : "Something went Wrong", + }); + } +}; + +//get self User POSOrder +export const getUserSelf = async (req, res) => { + if (!req?.user) return res.status(400).json({ message: "please login !" }); + try { + const order = await POSOrder.find({ + user: req.user?._id, + payment_status: "success", + }).sort({ createdAt: -1 }); + + if (order) { + return res.status(200).json({ + success: true, + order, + message: "self POSOrder fetched", + }); + } + } catch (error) { + res.status(500).json({ + success: false, + message: error.message ? error.message : "Something went Wrong", + }); + } +}; + +export const deleteOneOrder = async (req, res) => { + try { + if (!req?.user) return res.status(400).json({ message: "please login !" }); + if (!req.params.id) + return res.status(400).json({ message: "please Provide POSOrder Id" }); + const getOrder = await POSOrder.findById(req.params.id); + if (!getOrder) { + return res.status(404).json({ + success: false, + message: "No POSOrder Found!", + }); + } + const order = await POSOrder.findByIdAndDelete(req.params.id); + + await order.remove(); + res.status(200).json({ + success: true, + message: "POSOrder Deleted Successfully!!", + }); + } catch (error) { + res.status(500).json({ + success: false, + message: error.message ? error.message : "Something went Wrong", + }); + } +}; +export const updateOrderStatusById = async (req, res) => { + try { + let body = { orderStatus: req.body.status }; + + 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 POSOrder.findById(req.params.id).populate({ + path: "user", + select: "name email -_id", + }); + // console.log("order", order); + // const parentData = { email: order?.parent?.email }; + if (req.body.status === "cancelled") { + body["order_Cancelled_Reason"] = req.body?.ReasonforCancellation; + body["iscancelled"] = true; + await POSOrder.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: `POSOrder #${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: "POSOrder status updated successfully!" }); + } else if (req.body.status === "processing") { + await POSOrder.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 POSOrder #${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 + }, +

POSOrder Status : Processing

+

POSOrder 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: "POSOrder status updated successfully!" }); + } + // else if (body.status === "dispatched") { + // const noBalanceRemaining = + // order?.sales_items?.filter((e) => Number(e?.balance_quantity) > 0) + // ?.length === 0 + // ? true + // : false; + // if (!noBalanceRemaining) + // return res + // .status(400) + // .json({ message: "Few items still have balance quantity!" }); + // await OrderDispatchedEmail(parentData.email, order.order_id, body); + // await Invoice.updateMany( + // { order: order._id, status: { $in: ["processing"] } }, + // { status: body.status, "status_timeline.dispatched": currentDate } + // ); + // } else if (body.status === "delivered") { + // await OrderDeliveredEmail(parentData.email, order.order_id); + // await Invoice.updateMany( + // { order: order._id, status: { $in: ["processing", "dispatched"] } }, + // { status: body.status, "status_timeline.delivered": currentDate } + // ); + // } + else if (req.body.status === "dispatched") { + body["courier_name"] = req.body.courierName; + body["courier_tracking_id"] = req.body.TrackingID; + await POSOrder.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 POSOrder #${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:

+ +

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

+

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

+ + +

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 + }
+

POSOrder 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) + .json({ status: "ok", message: "POSOrder status updated successfully!" }); + } else if (req.body.status === "delivered") { + body["isDelivered"] = true; + body["DeliveredDate"] = req.body.DDate; + await POSOrder.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 POSOrder #${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: "POSOrder status updated successfully!" }); + } else { + // await POSOrder.findByIdAndUpdate(order._id, body); + // console.log(order); + res + .status(200) + .json({ status: "ok", message: "POSOrder status updated successfully!" }); + } + } catch (error) { + console.log(error); + res + .status(500) + .json({ message: error?.message || "Something went wrong!" }); + } +}; diff --git a/resources/PosOrders/PosorderModel.js b/resources/PosOrders/PosorderModel.js new file mode 100644 index 0000000..5134084 --- /dev/null +++ b/resources/PosOrders/PosorderModel.js @@ -0,0 +1,165 @@ +import mongoose from "mongoose"; + +const POSorderSchema = new mongoose.Schema( + { + orderID: { + type: String, + required: true, + unique: true, + }, + user: { + type: mongoose.Schema.ObjectId, + ref: "User", + required: true, + }, + shippingInfo: { + first_Name: { + type: String, + required: true, + }, + last_Name: { + type: String, + required: true, + }, + phone_Number: { + type: Number, + required: true, + }, + street: { + type: String, + required: true, + }, + city: { + type: String, + required: true, + trim: true, + }, + state: { + type: String, + required: true, + }, + postalCode: { + type: String, + required: true, + trim: true, + // Add a regular expression to enforce a specific postal code format + // For example, assuming a 5-digit format for the United States + match: /^\d{6}$/, + }, + country: { + type: String, + required: true, + }, + addressId: { + type: mongoose.Schema.ObjectId, + ref: "ShippingAddress", + required: true, + }, + }, + orderItems: [ + { + name: { + type: String, + default: "", + }, + price: { + type: Number, + default: "", + }, + variant_Name: { type: String, default: "" }, + quantity: { + type: Number, + default: "", + default: 1, + }, + image: [{}], + + product_Subtotal: { + type: Number, + default: "", + }, + gst_amount: { + type: Number, + default: "", + }, + gst_rate: { + type: Number, + default: "", + }, + tax_Name: { + type: String, + default: "", + }, + product: { + type: mongoose.Schema.ObjectId, + ref: "Product", + }, + }, + ], + + shipping_charge: { type: Number, default: 0 }, + tax_amount: { type: Number, default: 0 }, + total_amount: { type: Number, default: 0 }, + weight: { type: Number, default: 0 }, + + SalesType: { + type: String, + enum: ["inStoreDelivery", "shipToCustomer"], + }, + paymentMode: { + type: String, + enum: ["QRCode", "Cash","SendPaymentLink"], + }, + payment_status: { + type: String, + enum: ["pending", "success", "failed"], + }, + isPaid: { + type: Boolean, + default: false, + }, + paidAt: { + type: Date, + }, + + orderStatus: { + type: String, + enum: [ + "new", + "processing", + "dispatched", + "delivered", + "cancelled", + "returned", + ], + default: "new", + }, + razorpay_payment_id: { type: String }, + razorpay_order_id: { type: String }, + razorpay_signature: { type: String }, + isDelivered: { type: Boolean, required: true, default: false }, + DeliveredDate: { type: String, default: "" }, + + // deliveredAt: { type: Date }, + status_timeline: { + new: { type: Date }, + processing: { type: Date }, + dispatched: { type: Date }, + delivered: { type: Date }, + 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 }, + }, + { timestamps: true } +); + +export const POSOrder = mongoose.model("POSOrder", POSorderSchema); diff --git a/resources/PosOrders/PosorderRoute.js b/resources/PosOrders/PosorderRoute.js new file mode 100644 index 0000000..65dace4 --- /dev/null +++ b/resources/PosOrders/PosorderRoute.js @@ -0,0 +1,51 @@ +import bodyParser from "body-parser"; +import { + deleteOneOrder, + getAllOrder, + getOrders, + getSingleOrder, + getUserSelf, + updateOrderStatusById, +} from "./PosorderController.js"; +import { isAuthenticatedUser, authorizeRoles } from "../../middlewares/auth.js"; +import express from "express"; +import { + createOrderCheckout, +} from "./PosCheckoutController.js"; +import { checkout, getRzpKey, paymentVerification } from "./PosRazerPayCheckoutController.js"; + +const app = express(); + +// Configure bodyParser to parse the raw request body as a buffer +app.use(bodyParser.raw({ type: "application/json" })); + + +const router = express.Router(); +//checkout Routes-------------------------// +router.route("/pos-checkout/").post(isAuthenticatedUser, createOrderCheckout); +// --------------------------------------------------- + +// -------------------------------------------------- +//get user self +router.route("/user/self").get(isAuthenticatedUser, getUserSelf); + +//admin route +router + .route("/pos-getAll/:status") + .get(isAuthenticatedUser, authorizeRoles("admin"), getAllOrder); +router + .route("/pos-getAll/") + .get(isAuthenticatedUser, authorizeRoles("admin"), getOrders); +router.route("/pos-getOne/:id").get(isAuthenticatedUser, getSingleOrder); +router + .route("/pos-change/status/:id") + .patch(isAuthenticatedUser, authorizeRoles("admin"), updateOrderStatusById); + +router + .route("/pos-delete/:id") + .delete(isAuthenticatedUser, authorizeRoles("admin"), deleteOneOrder); +//RAZERPAY checkout +router.route("/getRzpKey/:name/:email").get(isAuthenticatedUser, getRzpKey); +router.route("/Rzpcheckout/").post(isAuthenticatedUser, checkout); +router.route("/paymentverification").post(paymentVerification); +export default router; From 150a8320e7c64ee83ad4346f3822781678644901 Mon Sep 17 00:00:00 2001 From: pawan-dot <71133473+pawan-dot@users.noreply.github.com> Date: Fri, 26 Apr 2024 15:37:29 +0530 Subject: [PATCH 3/7] change product and razorpay --- .../Orders/RazerPayCheckoutController.js | 26 ++++++--- resources/Orders/orderModel.js | 6 ++ resources/Products/ProductController.js | 55 ++++++++++++++++++- resources/Products/ProductModel.js | 4 ++ resources/Products/ProductRoute.js | 5 ++ .../ShippingAddresses/ShippingAddressModel.js | 11 +++- 6 files changed, 94 insertions(+), 13 deletions(-) diff --git a/resources/Orders/RazerPayCheckoutController.js b/resources/Orders/RazerPayCheckoutController.js index b0b0afc..5211a0e 100644 --- a/resources/Orders/RazerPayCheckoutController.js +++ b/resources/Orders/RazerPayCheckoutController.js @@ -62,15 +62,18 @@ export const checkout = async (req, res) => { if (!email) return res.status(400).send({ message: "Please enter the email" }); let addss = await shippingAddress.findById(address); + let shipping = { first_Name: addss.first_Name, - last_Name: addss.last_Name, - phone_Number: addss.phone_Number, - street: addss.street, - city: addss.city, - state: addss.state, + last_Name: addss?.last_Name, + phone_Number: addss?.phone_Number, + street: addss?.street, + city: addss?.city, + state: addss?.state, postalCode: addss?.postalCode, - country: addss.country, + country: addss?.country, + company_name: addss?.company_name, + gst_number: addss?.gst_number, addressId: address, }; // console.log("cart", cart[0]?.product?.gst); @@ -194,7 +197,16 @@ export const paymentVerification = async (req, res) => { findSameOrder?.shippingInfo?.state } ${findSameOrder?.shippingInfo?.country}, PIN-${ findSameOrder?.shippingInfo?.postalCode - }, Phone Number: ${findSameOrder?.shippingInfo?.phone_Number} + }, Phone Number: ${findSameOrder?.shippingInfo?.phone_Number} + ${ + findSameOrder?.shippingInfo?.company_name + ? ",Company Name :" + findSameOrder?.shippingInfo?.company_name + "" + : "" + } ${ + findSameOrder?.shippingInfo?.gst_number + ? ", GST_NO:" + findSameOrder?.shippingInfo?.gst_number + : "" + }

Order Items :

diff --git a/resources/Orders/orderModel.js b/resources/Orders/orderModel.js index 79f12f8..1d7a78c 100644 --- a/resources/Orders/orderModel.js +++ b/resources/Orders/orderModel.js @@ -50,6 +50,12 @@ const orderSchema = new mongoose.Schema( type: String, required: true, }, + company_name: { + type: String, + }, + gst_number: { + type: String, + }, addressId: { type: mongoose.Schema.ObjectId, ref: "ShippingAddress", diff --git a/resources/Products/ProductController.js b/resources/Products/ProductController.js index 2293cbd..6af6b46 100644 --- a/resources/Products/ProductController.js +++ b/resources/Products/ProductController.js @@ -124,6 +124,8 @@ export const getAllProductAdmin = async (req, res) => { $options: "i", }; if (req.query?.category) obj.category = req.query.category; + if (req.query?.FeatureProduct) + obj.featured_Product = req.query.FeatureProduct; const total = await Product.countDocuments(obj); const product = await Product.find(obj) .populate({ @@ -134,6 +136,7 @@ export const getAllProductAdmin = async (req, res) => { .skip(PAGE_SIZE * page) // .sort("name") .sort({ + featured_Product: -1, createdAt: -1, }) .exec(); @@ -166,6 +169,8 @@ export const getAllProductUser = async (req, res) => { $options: "i", }; if (req.query?.category) obj.category = req.query.category; + if (req.query?.FeatureProduct) + obj.featured_Product = req.query.FeatureProduct; obj.product_Status = "Active"; const total = await Product.countDocuments(obj); const product = await Product.find(obj) @@ -177,6 +182,7 @@ export const getAllProductUser = async (req, res) => { .skip(PAGE_SIZE * page) // .sort("name") .sort({ + featured_Product: -1, createdAt: -1, }) .exec(); @@ -230,6 +236,49 @@ export const ChangeProductStatus = async (req, res) => { }); } }; +//Change Product status +export const ChangeFeatueProductStatus = async (req, res) => { + try { + const data = await Product.findById(req.params.id); + if (data) { + if (data?.featured_Product === false) { + const totalFeatueProduct = await Product.countDocuments({ + featured_Product: true, + }); + if (totalFeatueProduct > 2) { + return res.status(400).json({ + success: false, + msg: "Maximum 3 Featue Product can be..", + }); + } + let product = await Product.findByIdAndUpdate( + req.params.id, + { featured_Product: true }, + { new: true } // Return the updated document + ); + return res.status(200).json({ + success: true, + msg: "Changed status as Featue Product", + }); + } else { + let product = await Product.findByIdAndUpdate( + req.params.id, + { featured_Product: false }, + { new: true } // Return the updated document + ); + return res.status(200).json({ + success: true, + msg: "Changed status as not Featue Product", + }); + } + } + } catch (error) { + res.status(500).json({ + success: false, + msg: error.message ? error.message : "Something went wrong!", + }); + } +}; //get One Product export const getOneProduct = async (req, res) => { try { @@ -503,14 +552,14 @@ export const deleteProduct = async (req, res) => { if (!req.params.id) { return res.status(400).json({ success: false, - msg: "Please Provide Product ID!", + message: "Please Provide Product ID!", }); } const getProduct = await Product.findById(req.params.id); if (!getProduct) { return res.status(404).json({ success: false, - msg: "Product not Found!", + message: "Product not Found!", }); } // Deleting Images From Cloudinary @@ -528,7 +577,7 @@ export const deleteProduct = async (req, res) => { await product.remove(); res.status(200).json({ success: true, - msg: "Product Deleted Successfully!!", + message: "Product Deleted Successfully!!", }); } catch (error) { res.status(500).json({ diff --git a/resources/Products/ProductModel.js b/resources/Products/ProductModel.js index 073d5c2..f68b880 100644 --- a/resources/Products/ProductModel.js +++ b/resources/Products/ProductModel.js @@ -38,6 +38,10 @@ const productSchema = new Schema( special_instructions: { type: String, }, + featured_Product: { + type: Boolean, + default: false, // Initially, products are not featured + }, variants: [ { variant_Name: { type: String, default: "" }, diff --git a/resources/Products/ProductRoute.js b/resources/Products/ProductRoute.js index 5641538..2d61bfb 100644 --- a/resources/Products/ProductRoute.js +++ b/resources/Products/ProductRoute.js @@ -10,6 +10,7 @@ import { getAllProductUser, getAllProductsDevicesFirst, ChangeProductStatus, + ChangeFeatueProductStatus, } from "./ProductController.js"; const router = express.Router(); import { isAuthenticatedUser, authorizeRoles } from "../../middlewares/auth.js"; @@ -22,6 +23,10 @@ router //change Product status router.route("/product/admin/status/:id").patch(ChangeProductStatus); +router + .route("/product/admin/feature_product/status/:id") + .patch(ChangeFeatueProductStatus); + //get all product user router.route("/product/getAll/user/").get(getAllProductUser); router diff --git a/resources/ShippingAddresses/ShippingAddressModel.js b/resources/ShippingAddresses/ShippingAddressModel.js index 55d3c93..336e7db 100644 --- a/resources/ShippingAddresses/ShippingAddressModel.js +++ b/resources/ShippingAddresses/ShippingAddressModel.js @@ -40,11 +40,16 @@ const shippingAddressSchema = new mongoose.Schema( }, company_name: { type: String, - maxLength: [70, "name cannot exceed 70 characters"], }, gst_number: { - type: Number, - maxLength: [15, "name cannot exceed 15 characters"], + type: String, + validate: { + validator: function (v) { + // Regular expression for Indian GST number validation + return /^(\d{2}[A-Z]{5}\d{4}[A-Z]{1}\d[Z]{1}[A-Z\d]{1})$/.test(v); + }, + message: (props) => `${props.value} is not a valid Indian GST number!`, + }, }, default: { type: Boolean, From fcf344518c1ce27a3354cb99918771b7c61c8e20 Mon Sep 17 00:00:00 2001 From: Sibunnayak Date: Sun, 28 Apr 2024 11:21:28 +0530 Subject: [PATCH 4/7] point of sale order contoller --- resources/PosOrders/PosCheckoutController.js | 5 ++--- .../PosOrders/PosRazerPayCheckoutController.js | 17 +++++++++-------- resources/PosOrders/PosorderModel.js | 6 +----- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/resources/PosOrders/PosCheckoutController.js b/resources/PosOrders/PosCheckoutController.js index 8acb18e..598c743 100644 --- a/resources/PosOrders/PosCheckoutController.js +++ b/resources/PosOrders/PosCheckoutController.js @@ -23,11 +23,11 @@ const generateOrderId = async () => { export const createOrderCheckout = async (req, res) => { try { - const { address, cart, user, SalesType, paymentMode } = + const { address, cart, user, paymentMode } = req.body; // console.log(req.body) // Perform validation - if (!address || !cart || cart.length === 0 || !SalesType || !user || !paymentMode) { + if (!address || !cart || cart.length === 0 || !user || !paymentMode) { return res.status(400).json({ message: "Invalid order data" }); } @@ -71,7 +71,6 @@ export const createOrderCheckout = async (req, res) => { ...restOfShippingInfo, // Include other shipping information }, user, // Assuming you have authenticated users - SalesType, paymentMode, }); diff --git a/resources/PosOrders/PosRazerPayCheckoutController.js b/resources/PosOrders/PosRazerPayCheckoutController.js index 111fbe4..f7ae283 100644 --- a/resources/PosOrders/PosRazerPayCheckoutController.js +++ b/resources/PosOrders/PosRazerPayCheckoutController.js @@ -76,13 +76,13 @@ export const checkout = async (req, res) => { } // Extract required data from request parameters and body - const { email } = req.params; - const { address, cart, user, SalesType, paymentMode, subtotal } = req.body; + // const { email } = req.params; + const { address, cart, user, paymentMode, subtotal } = req.body; // Check for required parameters - if (!email) { - return res.status(400).send({ message: "Please enter the email" }); - } + // if (!email) { + // return res.status(400).send({ message: "Please enter the email" }); + // } if (cart.length < 1) { return res.status(400).json({ message: "Cart is empty!" }); @@ -136,7 +136,6 @@ export const checkout = async (req, res) => { ...restOfShippingInfo, }, user, - SalesType, paymentMode, razorpay_order_id: order.id, }); @@ -372,8 +371,10 @@ export const handlePayment = async (req, res) => { // Add any other key-value pairs as needed }, - success_url: `${process.env.FRONTEND_URL}/cart`, - cancel_url: `${process.env.FRONTEND_URL}/error`, + // success_url: `${process.env.FRONTEND_URL}/cart`, + sccess_url: `httphttp://localhost:5000/#/success`, + // cancel_url: `${process.env.FRONTEND_URL}/error`, + cancel_url: `http://localhost:5000/#/error`, }); // res.json({ sessionId: session.id }); diff --git a/resources/PosOrders/PosorderModel.js b/resources/PosOrders/PosorderModel.js index 5134084..2f3032d 100644 --- a/resources/PosOrders/PosorderModel.js +++ b/resources/PosOrders/PosorderModel.js @@ -102,13 +102,9 @@ const POSorderSchema = new mongoose.Schema( total_amount: { type: Number, default: 0 }, weight: { type: Number, default: 0 }, - SalesType: { - type: String, - enum: ["inStoreDelivery", "shipToCustomer"], - }, paymentMode: { type: String, - enum: ["QRCode", "Cash","SendPaymentLink"], + enum: ["QRCode", "Cash"], }, payment_status: { type: String, From 6dc55eeb2867537225ebf5ef3eb2c59ecc25bc68 Mon Sep 17 00:00:00 2001 From: Sibunnayak Date: Sun, 28 Apr 2024 17:19:13 +0530 Subject: [PATCH 5/7] point of sale order contoller with razorpay completed --- resources/Orders/PosCheckoutController.js | 186 ++++++ .../Orders/RazerPayCheckoutController.js | 209 ++++++- resources/Orders/orderModel.js | 6 +- resources/Orders/orderRoute.js | 8 +- resources/PosOrders/PosCheckoutController.js | 84 --- .../PosRazerPayCheckoutController.js | 482 --------------- resources/PosOrders/PosorderController.js | 552 ------------------ resources/PosOrders/PosorderModel.js | 161 ----- resources/PosOrders/PosorderRoute.js | 51 -- 9 files changed, 402 insertions(+), 1337 deletions(-) create mode 100644 resources/Orders/PosCheckoutController.js delete mode 100644 resources/PosOrders/PosCheckoutController.js delete mode 100644 resources/PosOrders/PosRazerPayCheckoutController.js delete mode 100644 resources/PosOrders/PosorderController.js delete mode 100644 resources/PosOrders/PosorderModel.js delete mode 100644 resources/PosOrders/PosorderRoute.js diff --git a/resources/Orders/PosCheckoutController.js b/resources/Orders/PosCheckoutController.js new file mode 100644 index 0000000..7792e1f --- /dev/null +++ b/resources/Orders/PosCheckoutController.js @@ -0,0 +1,186 @@ +import { shippingAddress } from "../ShippingAddresses/ShippingAddressModel.js"; +import { Order } from "./orderModel.js"; + +//generate unique order id +const generateUniqueOrderId = async () => { + const currentYear = new Date().getFullYear(); + // Find the latest order to get the last serial number + const latestOrder = await Order.findOne({}, {}, { sort: { orderID: -1 } }); + let serialNumber = 1; + + if (latestOrder) { + const lastYear = parseInt(latestOrder.orderID.substring(0, 4), 10); + if (lastYear === currentYear) { + // If the last order was in the current year, increment the serial number + serialNumber = parseInt(latestOrder.orderID.substring(4), 10) + 1; + } + } + // Pad the serial number with zeros and concatenate with the current year + const paddedSerialNumber = serialNumber.toString().padStart(7, "0"); + const orderId = `${currentYear}${paddedSerialNumber}`; + return orderId; +}; + +// export const poscreateOrderCheckout = async (req, res) => { +// try { +// const { userr,address, cart, subtotal,orderType } = req.body; +// // console.log(req.body) +// // Perform validation +// if (cart.length < 1) +// return res.status(400).json({ message: "cart is empty!" }); +// if (!address) +// return res +// .status(404) +// .json({ message: "please select shipping address!" }); +// if (!subtotal) +// return res +// .status(404) +// .json({ message: "please provide product subtotal!" }); +// if (!userr) +// return res.status(400).json({ message: "user is not defined" }); + +// // Retrieve shipping address from database +// let addss = await shippingAddress.findById(address); + +// let shipping = { +// first_Name: addss.first_Name, +// last_Name: addss?.last_Name, +// phone_Number: addss?.phone_Number, +// street: addss?.street, +// city: addss?.city, +// state: addss?.state, +// postalCode: addss?.postalCode, +// country: addss?.country, +// company_name: addss?.company_name, +// gst_number: addss?.gst_number, +// addressId: address, +// }; + +// // Construct order items array +// const orderItems = await cart.map((item) => ({ +// product: item.product._id, +// name: item.product.name, +// variant_Name: item.variant.variant_Name, +// price: Number(item.variant.price), +// total_price: item.quantity * Number(item.variant.price), + +// image: item.product.image, +// quantity: item.quantity, +// gst_amount: Number( +// (Number(item.variant.price) * item.variant.gst_Id?.tax) / 100 +// )?.toFixed(3), +// total_gst_amount: Number( +// Number(item.quantity) * +// Number( +// (Number(item.variant.price) * item.variant.gst_Id?.tax) / 100 +// ) +// )?.toFixed(3), +// gst_rate: item.variant.gst_Id?.tax, +// tax_Name: item.variant?.gst_Id?.name, +// product_Subtotal: Number( +// Number(item.quantity * Number(item.variant.price)) + +// Number( +// Number(item.quantity) * +// Number( +// (Number(item.variant.price) * item.variant.gst_Id?.tax) / 100 +// ) +// ) +// ).toFixed(3), +// })); + +// // Generate a unique order ID +// const Id = await generateUniqueOrderId(); + +// // Create the order document +// const order = await Order.create({ +// orderID: Id, +// total_amount: subtotal, +// orderItems, +// shippingInfo: shipping, +// user: userr, +// orderType, +// paymentMode:"cod", +// payment_status:"success", +// isPaid:true, +// paidAt:new Date().toISOString(), +// }); + +// return res.status(201).json({ success: true, order }); +// } catch (error) { +// console.error("Error creating order:", error); +// return res +// .status(500) +// .json({ success: false, message: "Internal server error" }); +// } +// }; + +export const poscreateOrderCheckout = async (req, res) => { + try { + const { userr, address, cart, subtotal, orderType } = req.body; + + // Perform validation + if (cart.length < 1) + return res.status(400).json({ message: "Cart is empty!" }); + if (!address) + return res.status(404).json({ message: "Please select a shipping address!" }); + if (!subtotal) + return res.status(404).json({ message: "Please provide the product subtotal!" }); + if (!userr) + return res.status(400).json({ message: "User is not defined" }); + + // Retrieve shipping address from database + let addss = await shippingAddress.findById(address); + + let shipping = { + first_Name: addss.first_Name, + last_Name: addss?.last_Name, + phone_Number: addss?.phone_Number, + street: addss?.street, + city: addss?.city, + state: addss?.state, + postalCode: addss?.postalCode, + country: addss?.country, + company_name: addss?.company_name, + gst_number: addss?.gst_number, + addressId: address, + }; + + // Construct order items array + const orderItems = cart.map((item) => ({ + product: item.product._id, + name: item.product.name, + variant_Name: item.variant.variant_Name, + price: Number(item.variant.price), + total_price: item.quantity * Number(item.variant.price), + image: item.product.image, + quantity: item.quantity, + gst_amount: Number((Number(item.variant.price) * item.variant.gst_Id?.tax) / 100)?.toFixed(3), + total_gst_amount: Number(Number(item.quantity) * Number((Number(item.variant.price) * item.variant.gst_Id?.tax) / 100))?.toFixed(3), + gst_rate: item.variant.gst_Id?.tax, + tax_Name: item.variant?.gst_Id?.name, + product_Subtotal: Number(Number(item.quantity * Number(item.variant.price)) + Number(Number(item.quantity) * Number((Number(item.variant.price) * item.variant.gst_Id?.tax) / 100))).toFixed(3), + })); + + // Generate a unique order ID + const Id = await generateUniqueOrderId(); + + // Create the order document + const order = await Order.create({ + orderID: Id, + total_amount: subtotal, + orderItems, + shippingInfo: shipping, + user: userr, + orderType, + paymentMode: "cod", + payment_status: "success", + isPaid: true, + paidAt: new Date().toISOString(), + }); + + return res.status(201).json({ success: true, order }); + } catch (error) { + console.error("Error creating order:", error); + return res.status(500).json({ success: false, message: "Internal server error" }); + } +}; diff --git a/resources/Orders/RazerPayCheckoutController.js b/resources/Orders/RazerPayCheckoutController.js index 5211a0e..7af902c 100644 --- a/resources/Orders/RazerPayCheckoutController.js +++ b/resources/Orders/RazerPayCheckoutController.js @@ -31,6 +31,8 @@ const generateUniqueOrderId = async () => { export const getRzpkey = async (req, res) => { const { name, email } = req.user; + // console.log(name); + // console.log(email); res.status(200).json({ success: true, key: process.env.RAZERPAY_KEY_ID, @@ -38,9 +40,35 @@ export const getRzpkey = async (req, res) => { email, }); }; +//point of sale order +export const getRazerpayKey = async (req, res) => { + try { + const { name, email } = req.params; + // console.log("name", name, "email", email); + if (!name || !email) { + throw new Error("Name and email are required parameters"); + } + res.status(200).json({ + success: true, + key: process.env.RAZERPAY_KEY_ID, + name, + email, + }); + } catch (error) { + console.error("Error in getRzpKey:", error); + res + .status(500) + .json({ + success: false, + message: error.message || "Internal server error", + }); + } +}; + export const checkout = async (req, res) => { try { - const { address, cart, subtotal } = req.body; + const { userr,address, cart, subtotal,orderType } = req.body; +// console.log(req.body); if (cart.length < 1) return res.status(400).json({ message: "cart is empty!" }); if (!address) @@ -55,12 +83,21 @@ export const checkout = async (req, res) => { amount: Number(req.body.subtotal * 100), currency: "INR", }; + // Determine the user ID + let User; + if (userr) { + User = userr; // Use provided user ID + } else { + User = req.user._id; // Use authenticated user ID + } + // console.log(User); const order = await instance.orders.create(options); + // console.log(order); //save order in database if (order?.id) { - const { email } = req.user; - if (!email) - return res.status(400).send({ message: "Please enter the email" }); + // const { email } = req.user; + // if (!email) + // return res.status(400).send({ message: "Please enter the email" }); let addss = await shippingAddress.findById(address); let shipping = { @@ -115,8 +152,9 @@ export const checkout = async (req, res) => { total_amount: subtotal, orderItems, shippingInfo: shipping, - user: req.user._id, + user: User, razorpay_order_id: order?.id, + orderType, }); } else { return res.status(400).json({ @@ -300,6 +338,167 @@ export const paymentVerification = async (req, res) => { }); } }; + +// point of sale payment varification +export const pospaymentVerification = async (req, res) => { + const { razorpay_order_id, razorpay_payment_id, razorpay_signature } = + req.body; + + const body = razorpay_order_id + "|" + razorpay_payment_id; + + const expectedSignature = crypto + .createHmac("sha256", process.env.RAZERPAY_SECRET_KEY) + .update(body.toString()) + .digest("hex"); + + const isAuthentic = expectedSignature === razorpay_signature; + + if (isAuthentic) { + // Database comes here + let findSameOrder = await Order.findOne({ + razorpay_order_id: razorpay_order_id, + }).populate({ + path: "user", + select: "name email -_id", + }); + // console.log("findSameOrder", findSameOrder); + if (findSameOrder) { + (findSameOrder.razorpay_payment_id = razorpay_payment_id), // await Payment.create({ + (findSameOrder.isPaid = true), + (findSameOrder.paidAt = Date.now()), + (findSameOrder.razorpay_signature = razorpay_signature); + // await Payment.create({ + findSameOrder.payment_status = "success"; + + findSameOrder.orderStatus = "new"; + await findSameOrder.save(); + } + //send email to customer + // console.log("findSameOrder", findSameOrder); + await sendEmail({ + to: `${findSameOrder?.user?.email}`, // Change to your recipient + + from: `${process.env.SEND_EMAIL_FROM}`, // Change to your verified sender + + subject: `Your Order #${findSameOrder?.orderID} Confirmation`, + html: `

Welcome to Smellika - Let the Shopping Begin!

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

Great news! Your order #${ + findSameOrder?.orderID + } has been confirmed. Here are the details

+

Shipping Address : ${ + findSameOrder?.shippingInfo?.first_Name + } ${findSameOrder?.shippingInfo?.last_Name} , ${ + findSameOrder?.shippingInfo?.street + } ${findSameOrder?.shippingInfo?.city} ${ + findSameOrder?.shippingInfo?.state + } ${findSameOrder?.shippingInfo?.country}, PIN-${ + findSameOrder?.shippingInfo?.postalCode + }, Phone Number: ${findSameOrder?.shippingInfo?.phone_Number} + ${ + findSameOrder?.shippingInfo?.company_name + ? ",Company Name :" + findSameOrder?.shippingInfo?.company_name + "" + : "" + } ${ + findSameOrder?.shippingInfo?.gst_number + ? ", GST_NO:" + findSameOrder?.shippingInfo?.gst_number + : "" + }

+

Order Items :

+
+ + + + + + + + + + + + + + + + + + + ${findSameOrder?.orderItems + ?.map( + (product, index) => ` + + + + + + + + + + + + + + ` + ) + .join("")} + + + + + +
S No.Product NameVariantImageQuantityPriceGST AmountSubTotal
${ + index + 1 + }${ + product.name + }${ + product?.variant_Name + }${
+          product.name
+        }${ + product.quantity + }₹${ + product.price + }₹${ + product?.gst_amount + }₹${ + product?.product_Subtotal + }
Total Amount :₹${ + findSameOrder?.total_amount + }
+ +
+ Best regards,
+ + Team Smellika`, + }); + // console.log("findSameOrder", findSameOrder); + + // // findSameOrder.razorpay_payment_id=razorpay_payment_id,// await Payment.create({ + // findOrder.paidAt = new Date(event.data.object.created * 1000); + // findOrder.isPaid = true; + + // razorpay_signature: { type: String }, + // razorpay_order_id, + // razorpay_payment_id, + // razorpay_signature, + // }); + + res.redirect(`https://admin.smellika.com/#/pos`); + // res.redirect(`http://localhost:3000/#/pos`); + } else { + res.status(400).json({ + success: false, + }); + } +}; + export const handlePayment = async (req, res) => { try { const { email } = req.user; diff --git a/resources/Orders/orderModel.js b/resources/Orders/orderModel.js index 1d7a78c..f40d843 100644 --- a/resources/Orders/orderModel.js +++ b/resources/Orders/orderModel.js @@ -124,7 +124,11 @@ const orderSchema = new mongoose.Schema( enum: ["online", "cod"], default: "online", }, - + orderType: { + type: String, + enum: ["WebSite", "PointOfSale"], + default: "WebSite", + }, payment_status: { type: String, enum: ["pending", "success", "failed"], diff --git a/resources/Orders/orderRoute.js b/resources/Orders/orderRoute.js index 44cfa4b..3ccec85 100644 --- a/resources/Orders/orderRoute.js +++ b/resources/Orders/orderRoute.js @@ -22,12 +22,17 @@ app.use(bodyParser.raw({ type: "application/json" })); import { handlePayment, webhook } from "./StripeCheckOutController.js"; import { checkout, + getRazerpayKey, getRzpkey, paymentVerification, + pospaymentVerification, } from "./RazerPayCheckoutController.js"; +import { poscreateOrderCheckout } from "./PosCheckoutController.js"; const router = express.Router(); //checkout Routes-------------------------// router.route("/checkout/").post(isAuthenticatedUser, createOrderCheckout); +//checkout Routes-------------------------// +router.route("/pos-checkout/").post(isAuthenticatedUser, poscreateOrderCheckout); router.route("/clientid/get/").get(isAuthenticatedUser, getClientId); router.route("/:orderID/capture/payment").post(captureOrderPayment); // --------------------------------------------------- @@ -60,10 +65,11 @@ router .delete(isAuthenticatedUser, authorizeRoles("admin"), deleteOneOrder); //RAZERPAY checkout +router.route("/getRzpKey/:name/:email").get(isAuthenticatedUser, getRazerpayKey); router.route("/getRzpKey/").get(isAuthenticatedUser, getRzpkey); router.route("/Rzpcheckout/").post(isAuthenticatedUser, checkout); router.route("/paymentverification").post(paymentVerification); - +router.route("/pos-paymentverification").post(pospaymentVerification); // router.route("/product/getAll/").get(getAllProduct) export default router; diff --git a/resources/PosOrders/PosCheckoutController.js b/resources/PosOrders/PosCheckoutController.js deleted file mode 100644 index 598c743..0000000 --- a/resources/PosOrders/PosCheckoutController.js +++ /dev/null @@ -1,84 +0,0 @@ -import { POSOrder } from "./PosorderModel.js"; -import { shippingAddress } from "../ShippingAddresses/ShippingAddressModel.js"; - -//generate unique order id -const generateOrderId = async () => { - const currentYear = new Date().getFullYear(); - // Find the latest order to get the last serial number - const latestOrder = await POSOrder.findOne({}, {}, { sort: { orderID: -1 } }); - let serialNumber = 1; - - if (latestOrder) { - const lastYear = parseInt(latestOrder.orderID.substring(0, 4), 10); - if (lastYear === currentYear) { - // If the last order was in the current year, increment the serial number - serialNumber = parseInt(latestOrder.orderID.substring(4), 10) + 1; - } - } - // Pad the serial number with zeros and concatenate with the current year - const paddedSerialNumber = serialNumber.toString().padStart(7, "0"); - const orderId = `${currentYear}${paddedSerialNumber}`; - return orderId; -}; - -export const createOrderCheckout = async (req, res) => { - try { - const { address, cart, user, paymentMode } = - req.body; -// console.log(req.body) - // Perform validation - if (!address || !cart || cart.length === 0 || !user || !paymentMode) { - return res.status(400).json({ message: "Invalid order data" }); - } - - // Retrieve shipping address from database - const shippingInfo = await shippingAddress.findById(address); - if (!shippingInfo) { - return res.status(404).json({ message: "Shipping address not found" }); - } - - // Ensure that addressId is included in the shippingInfo object - const { _id: addressId, ...restOfShippingInfo } = shippingInfo.toObject(); - - // Calculate total amount based on the product_Subtotal of each product - const totalAmount = cart.reduce( - (acc, item) => acc + item.product_Subtotal, - 0 - ); - - // Construct order items array - const orderItems = cart.map((item) => ({ - product: item.product, - name: item.name, - price: item.price, - quantity: item.quantity, - product_Subtotal: item.total_amount, - gst_amount: item.gst_amount, - image: item.image, - variant_Name: item.variant_Name, - })); - - // Generate a unique order ID - const orderId = await generateOrderId(); - - // Create the order document - const order = await POSOrder.create({ - orderID: orderId, - total_amount: totalAmount, - orderItems, - shippingInfo: { - addressId: addressId, // Include the addressId - ...restOfShippingInfo, // Include other shipping information - }, - user, // Assuming you have authenticated users - paymentMode, - }); - - return res.status(201).json({ success: true, order }); - } catch (error) { - console.error("Error creating order:", error); - return res - .status(500) - .json({ success: false, message: "Internal server error" }); - } -}; diff --git a/resources/PosOrders/PosRazerPayCheckoutController.js b/resources/PosOrders/PosRazerPayCheckoutController.js deleted file mode 100644 index f7ae283..0000000 --- a/resources/PosOrders/PosRazerPayCheckoutController.js +++ /dev/null @@ -1,482 +0,0 @@ -import bodyParser from "body-parser"; -import crypto from "crypto"; -import Razorpay from "razorpay"; -import { POSOrder } from "./PosorderModel.js"; -import { shippingAddress } from "../ShippingAddresses/ShippingAddressModel.js"; -import sendEmail from "../../Utils/sendEmail.js"; -const instance = new Razorpay({ - key_id: process.env.RAZERPAY_KEY_ID, - key_secret: process.env.RAZERPAY_SECRET_KEY, -}); - -const generateUniqueOrderId = async () => { - const currentYear = new Date().getFullYear(); - // Find the latest order to get the last serial number - const latestOrder = await POSOrder.findOne({}, {}, { sort: { orderID: -1 } }); - let serialNumber = 1; - - if (latestOrder) { - const lastYear = parseInt(latestOrder.orderID.substring(0, 4), 10); - if (lastYear === currentYear) { - // If the last order was in the current year, increment the serial number - serialNumber = parseInt(latestOrder.orderID.substring(4), 10) + 1; - } - } - // Pad the serial number with zeros and concatenate with the current year - const paddedSerialNumber = serialNumber.toString().padStart(7, "0"); - const orderId = `${currentYear}${paddedSerialNumber}`; - return orderId; -}; - -export const getRzpKey = async (req, res) => { - try { - const { name, email } = req.params; - console.log("name", name, "email", email); - if (!name || !email) { - throw new Error("Name and email are required parameters"); - } - res.status(200).json({ - success: true, - key: process.env.RAZERPAY_KEY_ID, - name, - email, - }); - } catch (error) { - console.error("Error in getRzpKey:", error); - res - .status(500) - .json({ - success: false, - message: error.message || "Internal server error", - }); - } -}; - -export const checkout = async (req, res) => { - try { - console.log(req.body); - const options = { - amount: Number(req.body.subtotal * 100), - currency: "INR", - }; - - console.log("options", options); - - // Wait for the order creation to complete - const order = await instance.orders.create(options); - - console.log("order", order); - - // Check if the order was created successfully - if (!order || !order.id) { - return res.status(400).json({ - success: false, - message: "Failed to create order", - }); - } - - // Extract required data from request parameters and body - // const { email } = req.params; - const { address, cart, user, paymentMode, subtotal } = req.body; - - // Check for required parameters - // if (!email) { - // return res.status(400).send({ message: "Please enter the email" }); - // } - - if (cart.length < 1) { - return res.status(400).json({ message: "Cart is empty!" }); - } - - if (!address) { - return res - .status(404) - .json({ message: "Please select a shipping address!" }); - } - - if (!subtotal) { - return res - .status(404) - .json({ message: "Please provide the product subtotal!" }); - } - - // Fetch shipping information from the database - const shippingInfo = await shippingAddress.findById(address); - if (!shippingInfo) { - return res.status(404).json({ message: "Shipping address not found" }); - } - - console.log("shippinginfo", shippingInfo); - - // Extract addressId and other shipping information - const { _id: addressId, ...restOfShippingInfo } = shippingInfo.toObject(); - - // Prepare order items - const orderItems = cart.map((item) => ({ - product: item.product, - name: item.name, - price: item.price, - quantity: item.quantity, - product_Subtotal: item.total_amount, - gst_amount: item.gst_amount, - image: item.image, - variant_Name: item.variant_Name, - })); - - // Generate a unique order ID - const orderId = await generateUniqueOrderId(); - - // Create the order in the database - const orders = await POSOrder.create({ - orderID: orderId, - total_amount: subtotal, - orderItems, - shippingInfo: { - addressId: addressId, - ...restOfShippingInfo, - }, - user, - paymentMode, - razorpay_order_id: order.id, - }); - - res.status(200).json({ - success: true, - order, - }); - } catch (error) { - console.error("Error in checkout:", error); - res - .status(500) - .json({ - success: false, - message: error.message || "Internal server error", - }); - } -}; - -export const paymentVerification = async (req, res) => { - const { razorpay_order_id, razorpay_payment_id, razorpay_signature } = - req.body; - console.log(req.body); - const body = razorpay_order_id + "|" + razorpay_payment_id; - - const expectedSignature = crypto - .createHmac("sha256", process.env.RAZERPAY_SECRET_KEY) - .update(body.toString()) - .digest("hex"); - - const isAuthentic = expectedSignature === razorpay_signature; - - if (isAuthentic) { - // Database comes here - let findSameOrder = await POSOrder.findOne({ - razorpay_order_id: razorpay_order_id, - }).populate({ - path: "user", - select: "name email -_id", - }); - // console.log("findSameOrder", findSameOrder); - if (findSameOrder) { - (findSameOrder.razorpay_payment_id = razorpay_payment_id), // await Payment.create({ - (findSameOrder.isPaid = true), - (findSameOrder.paidAt = Date.now()), - (findSameOrder.razorpay_signature = razorpay_signature); - // await Payment.create({ - findSameOrder.payment_status = "success"; - - findSameOrder.orderStatus = "new"; - await findSameOrder.save(); - } - //send email to customer - // console.log("findSameOrder", findSameOrder); - await sendEmail({ - to: `${findSameOrder?.user?.email}`, // Change to your recipient - - from: `${process.env.SEND_EMAIL_FROM}`, // Change to your verified sender - - subject: `Your POSOrder #${findSameOrder?.orderID} Confirmation`, - html: `

Welcome to Smellika - Let the Shopping Begin!

- Hi ${ - findSameOrder?.shippingInfo?.first_Name - }, - -

Great news! Your order #${ - findSameOrder?.orderID - } has been confirmed. Here are the details

-

Shipping Address : ${ - findSameOrder?.shippingInfo?.first_Name - } ${findSameOrder?.shippingInfo?.last_Name} , ${ - findSameOrder?.shippingInfo?.street - } ${findSameOrder?.shippingInfo?.city} ${ - findSameOrder?.shippingInfo?.state - } ${findSameOrder?.shippingInfo?.country}, PIN-${ - findSameOrder?.shippingInfo?.postalCode - }, Phone Number: ${findSameOrder?.shippingInfo?.phone_Number}

-

POSOrder Items :

- - - - - - - - - - - - - - - - - - ${findSameOrder?.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 :₹${ - findSameOrder?.total_amount - }
- -
- Best regards,
- - Team Smellika`, - }); - // console.log("findSameOrder", findSameOrder); - - // // findSameOrder.razorpay_payment_id=razorpay_payment_id,// await Payment.create({ - // findOrder.paidAt = new Date(event.data.object.created * 1000); - // findOrder.isPaid = true; - - // razorpay_signature: { type: String }, - // razorpay_order_id, - // razorpay_payment_id, - // razorpay_signature, - // }); - - // res.redirect(`https://admin.smellika.com/#/pos`); - res.redirect(`http://localhost:3000/#/pos`); - } else { - res.status(400).json({ - success: false, - }); - } -}; -export const handlePayment = async (req, res) => { - try { - const { email } = req.user; - if (!email) - return res.status(400).send({ message: "Please enter the email" }); - const { address, cart, subtotal } = req.body; - if (cart.length < 1) - return res.status(400).json({ message: "cart is empty!" }); - switch (true) { - //validation - case !address: { - return res.status(404).json({ msg: "please provide shipping address" }); - } - case !subtotal: { - return res.status(404).json({ msg: "please provide product subtotal" }); - } - } - let addss = await shippingAddress.findById(address); - // console.log(addss?.postalCode); - let shipping = { - first_Name: addss.first_Name, - last_Name: addss.last_Name, - phone_Number: addss.phone_Number, - street: addss.street, - city: addss.city, - state: addss.state, - postalCode: addss?.postalCode, - country: addss.country, - addressId: address, - }; - const orderItems = await cart.map((item) => ({ - product: item.product._id, - name: item.product.name, - price: item.product.total_amount, - image: item.product.image, - quantity: item.quantity, - product_Subtotal: item.subtotal, - })); - - // console.log("line", lineItems[0]); - const Id = await generateUniqueOrderId(); - const order = await POSOrder.create({ - orderID: Id, - total_amount: subtotal, - orderItems, - shippingInfo: shipping, - user: req.user._id, - }); - console.log("fffffffff", order, "llllllllll"); - const lineItems = await cart.map((item) => ({ - price_data: { - currency: "inr", - product_data: { - name: item.product.name, - - images: [item.product.image[0]?.url], - }, - unit_amount: Number(item.product.total_amount) * 100, - }, - quantity: Number(item.quantity), - })); - if (order) { - const session = await stripe.checkout.sessions.create({ - payment_method_types: ["card"], - line_items: lineItems, - mode: "payment", - customer_email: `${email}`, - metadata: { - orderId: order._id.toString(), - - // Add any other key-value pairs as needed - }, - // success_url: `${process.env.FRONTEND_URL}/cart`, - sccess_url: `httphttp://localhost:5000/#/success`, - // cancel_url: `${process.env.FRONTEND_URL}/error`, - cancel_url: `http://localhost:5000/#/error`, - }); - // res.json({ sessionId: session.id }); - - res.status(200).send({ message: "order created", url: session.url }); - } - } catch (err) { - console.log(err); - res.status(500).send({ message: "Something went wrong", err }); - } -}; - -export const webhook = async (req, res) => { - const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET; - const signature = req.headers["stripe-signature"]; - let event; - if (webhookSecret) { - try { - event = stripe.webhooks.constructEvent( - req.body, - signature, - webhookSecret - ); - } catch (err) { - console.log(`❌ Error message: ${err.message}`); - res.status(400).send(`Webhook Error: ${err.message}`); - return; - } - } - - if (event.type === "checkout.session.completed") { - // console.log("dddddddddddd", event.data); - const findOrder = await POSOrder.findById( - event.data.object.metadata?.orderId - ); - findOrder.paypal_payer_id = event.data.object.id; - findOrder.paidAt = new Date(event.data.object.created * 1000); - findOrder.isPaid = true; - if (event.data.object?.payment_status === "paid") { - findOrder.payment_status = "success"; - } else { - findOrder.payment_status = "failed"; - } - findOrder.orderStatus = "new"; - await findOrder.save(); - await sendEmail({ - to: `${event.data.object.customer_email}`, // Change to your recipient - - from: `${process.env.SEND_EMAIL_FROM}`, // Change to your verified sender - - subject: `Your POSOrder #${findOrder?.orderID} Confirmation`, - html: `

Welcome to Smellika - Let the Shopping Begin!

- Hi ${findOrder?.shippingInfo?.first_Name}, - -

Great news! Your order #${findOrder?.orderID} has been confirmed. Here are the details

-
- Best regards,
- - Team Smellika`, - }); - - // Items: [List of Purchased Items] - // Total Amount: [Total Amount] - // Shipping Address: [Shipping Address] - - // We'll keep you updated on the shipping progress. Thanks for choosing Smellika! - - // Best regards - // Team Smellika - console.log( - "event.data.object", - event.data.object, - "---------------------" - ); - - console.log(`💰 Payment status: ${event.data.object?.payment_status}`); - - // Saving the payment details in the database - // const payment = await Payment.create({ - // customer_email: event.data.object.customer_email, - // amount: event.data.object.amount_total / 100, - // paymentId: event.data.object.id, - // paymentStatus: event.data.object.payment_status, - // createdAt: event.data.object.created, - // }); - } - // if (event.type === "checkout.session.completed") { - // console.log("dddddddddddd", event.data); - // console.log("event.data.object", event.data.object); - // console.log(`💰 Payment status: ${event.data.object?.payment_status}`); - // payment_intent.payment_failed; - - // // Saving the payment details in the database - // // const payment = await Payment.create({ - // // customer_email: event.data.object.customer_email, - // // amount: event.data.object.amount_total / 100, - // // paymentId: event.data.object.id, - // // paymentStatus: event.data.object.payment_status, - // // createdAt: event.data.object.created, - // // }); - // } - - // Return a 200 res to acknowledge receipt of the event - res.status(200).end(); - // res.send().end(); -}; diff --git a/resources/PosOrders/PosorderController.js b/resources/PosOrders/PosorderController.js deleted file mode 100644 index 6a02741..0000000 --- a/resources/PosOrders/PosorderController.js +++ /dev/null @@ -1,552 +0,0 @@ -import sendEmail from "../../Utils/sendEmail.js"; -import { POSOrder } from "./PosorderModel.js"; - -export const getAllOrder = async (req, res) => { - try { - const { status } = req.params; - const order = await POSOrder.find({ - IsStoreDelivery: "Cash", - orderStatus: status, - }) - .populate({ - path: "user", - select: "name -_id", - }) - .populate({ - path: "shippingInfo.addressId", - }) - .sort({ updatedAt: -1 }); - if (order) { - res.status(201).json({ - success: true, - order, - message: "All POSOrder Fetched", - }); - } - } catch (error) { - res.status(500).json({ - success: false, - message: error.message ? error.message : "Something went Wrong", - }); - } -}; -export const getOrders = async (req, res) => { - try { - const order = await POSOrder.find({ - // payment_status: "success", - }) - .populate({ - path: "user", - select: "name -_id", - }) - .populate({ - path: "shippingInfo.addressId", - }) - .sort({ updatedAt: -1 }); - if (order) { - res.status(201).json({ - success: true, - order, - message: "All POSOrder Fetched", - }); - } - } catch (error) { - res.status(500).json({ - success: false, - message: error.message ? error.message : "Something went Wrong", - }); - } -}; -export const getSingleOrder = async (req, res) => { - try { - if (!req.params.id) - return res.status(400).json({ message: "please Provide POSOrder Id" }); - - const order = await POSOrder.findById(req.params.id) - .populate({ - path: "user", - select: "name email -_id", - }) - .populate({ - path: "shippingInfo.addressId", - }) - .sort({ createdAt: -1 }); - if (order) { - res.status(201).json({ - success: true, - order, - message: " POSOrder Fetched", - }); - } - } catch (error) { - res.status(500).json({ - success: false, - message: error.message ? error.message : "Something went Wrong", - }); - } -}; - -//get self User POSOrder -export const getUserSelf = async (req, res) => { - if (!req?.user) return res.status(400).json({ message: "please login !" }); - try { - const order = await POSOrder.find({ - user: req.user?._id, - payment_status: "success", - }).sort({ createdAt: -1 }); - - if (order) { - return res.status(200).json({ - success: true, - order, - message: "self POSOrder fetched", - }); - } - } catch (error) { - res.status(500).json({ - success: false, - message: error.message ? error.message : "Something went Wrong", - }); - } -}; - -export const deleteOneOrder = async (req, res) => { - try { - if (!req?.user) return res.status(400).json({ message: "please login !" }); - if (!req.params.id) - return res.status(400).json({ message: "please Provide POSOrder Id" }); - const getOrder = await POSOrder.findById(req.params.id); - if (!getOrder) { - return res.status(404).json({ - success: false, - message: "No POSOrder Found!", - }); - } - const order = await POSOrder.findByIdAndDelete(req.params.id); - - await order.remove(); - res.status(200).json({ - success: true, - message: "POSOrder Deleted Successfully!!", - }); - } catch (error) { - res.status(500).json({ - success: false, - message: error.message ? error.message : "Something went Wrong", - }); - } -}; -export const updateOrderStatusById = async (req, res) => { - try { - let body = { orderStatus: req.body.status }; - - 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 POSOrder.findById(req.params.id).populate({ - path: "user", - select: "name email -_id", - }); - // console.log("order", order); - // const parentData = { email: order?.parent?.email }; - if (req.body.status === "cancelled") { - body["order_Cancelled_Reason"] = req.body?.ReasonforCancellation; - body["iscancelled"] = true; - await POSOrder.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: `POSOrder #${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: "POSOrder status updated successfully!" }); - } else if (req.body.status === "processing") { - await POSOrder.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 POSOrder #${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 - }, -

POSOrder Status : Processing

-

POSOrder 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: "POSOrder status updated successfully!" }); - } - // else if (body.status === "dispatched") { - // const noBalanceRemaining = - // order?.sales_items?.filter((e) => Number(e?.balance_quantity) > 0) - // ?.length === 0 - // ? true - // : false; - // if (!noBalanceRemaining) - // return res - // .status(400) - // .json({ message: "Few items still have balance quantity!" }); - // await OrderDispatchedEmail(parentData.email, order.order_id, body); - // await Invoice.updateMany( - // { order: order._id, status: { $in: ["processing"] } }, - // { status: body.status, "status_timeline.dispatched": currentDate } - // ); - // } else if (body.status === "delivered") { - // await OrderDeliveredEmail(parentData.email, order.order_id); - // await Invoice.updateMany( - // { order: order._id, status: { $in: ["processing", "dispatched"] } }, - // { status: body.status, "status_timeline.delivered": currentDate } - // ); - // } - else if (req.body.status === "dispatched") { - body["courier_name"] = req.body.courierName; - body["courier_tracking_id"] = req.body.TrackingID; - await POSOrder.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 POSOrder #${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:

- -

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

-

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

- - -

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 - }
-

POSOrder 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) - .json({ status: "ok", message: "POSOrder status updated successfully!" }); - } else if (req.body.status === "delivered") { - body["isDelivered"] = true; - body["DeliveredDate"] = req.body.DDate; - await POSOrder.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 POSOrder #${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: "POSOrder status updated successfully!" }); - } else { - // await POSOrder.findByIdAndUpdate(order._id, body); - // console.log(order); - res - .status(200) - .json({ status: "ok", message: "POSOrder status updated successfully!" }); - } - } catch (error) { - console.log(error); - res - .status(500) - .json({ message: error?.message || "Something went wrong!" }); - } -}; diff --git a/resources/PosOrders/PosorderModel.js b/resources/PosOrders/PosorderModel.js deleted file mode 100644 index 2f3032d..0000000 --- a/resources/PosOrders/PosorderModel.js +++ /dev/null @@ -1,161 +0,0 @@ -import mongoose from "mongoose"; - -const POSorderSchema = new mongoose.Schema( - { - orderID: { - type: String, - required: true, - unique: true, - }, - user: { - type: mongoose.Schema.ObjectId, - ref: "User", - required: true, - }, - shippingInfo: { - first_Name: { - type: String, - required: true, - }, - last_Name: { - type: String, - required: true, - }, - phone_Number: { - type: Number, - required: true, - }, - street: { - type: String, - required: true, - }, - city: { - type: String, - required: true, - trim: true, - }, - state: { - type: String, - required: true, - }, - postalCode: { - type: String, - required: true, - trim: true, - // Add a regular expression to enforce a specific postal code format - // For example, assuming a 5-digit format for the United States - match: /^\d{6}$/, - }, - country: { - type: String, - required: true, - }, - addressId: { - type: mongoose.Schema.ObjectId, - ref: "ShippingAddress", - required: true, - }, - }, - orderItems: [ - { - name: { - type: String, - default: "", - }, - price: { - type: Number, - default: "", - }, - variant_Name: { type: String, default: "" }, - quantity: { - type: Number, - default: "", - default: 1, - }, - image: [{}], - - product_Subtotal: { - type: Number, - default: "", - }, - gst_amount: { - type: Number, - default: "", - }, - gst_rate: { - type: Number, - default: "", - }, - tax_Name: { - type: String, - default: "", - }, - product: { - type: mongoose.Schema.ObjectId, - ref: "Product", - }, - }, - ], - - shipping_charge: { type: Number, default: 0 }, - tax_amount: { type: Number, default: 0 }, - total_amount: { type: Number, default: 0 }, - weight: { type: Number, default: 0 }, - - paymentMode: { - type: String, - enum: ["QRCode", "Cash"], - }, - payment_status: { - type: String, - enum: ["pending", "success", "failed"], - }, - isPaid: { - type: Boolean, - default: false, - }, - paidAt: { - type: Date, - }, - - orderStatus: { - type: String, - enum: [ - "new", - "processing", - "dispatched", - "delivered", - "cancelled", - "returned", - ], - default: "new", - }, - razorpay_payment_id: { type: String }, - razorpay_order_id: { type: String }, - razorpay_signature: { type: String }, - isDelivered: { type: Boolean, required: true, default: false }, - DeliveredDate: { type: String, default: "" }, - - // deliveredAt: { type: Date }, - status_timeline: { - new: { type: Date }, - processing: { type: Date }, - dispatched: { type: Date }, - delivered: { type: Date }, - 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 }, - }, - { timestamps: true } -); - -export const POSOrder = mongoose.model("POSOrder", POSorderSchema); diff --git a/resources/PosOrders/PosorderRoute.js b/resources/PosOrders/PosorderRoute.js deleted file mode 100644 index 65dace4..0000000 --- a/resources/PosOrders/PosorderRoute.js +++ /dev/null @@ -1,51 +0,0 @@ -import bodyParser from "body-parser"; -import { - deleteOneOrder, - getAllOrder, - getOrders, - getSingleOrder, - getUserSelf, - updateOrderStatusById, -} from "./PosorderController.js"; -import { isAuthenticatedUser, authorizeRoles } from "../../middlewares/auth.js"; -import express from "express"; -import { - createOrderCheckout, -} from "./PosCheckoutController.js"; -import { checkout, getRzpKey, paymentVerification } from "./PosRazerPayCheckoutController.js"; - -const app = express(); - -// Configure bodyParser to parse the raw request body as a buffer -app.use(bodyParser.raw({ type: "application/json" })); - - -const router = express.Router(); -//checkout Routes-------------------------// -router.route("/pos-checkout/").post(isAuthenticatedUser, createOrderCheckout); -// --------------------------------------------------- - -// -------------------------------------------------- -//get user self -router.route("/user/self").get(isAuthenticatedUser, getUserSelf); - -//admin route -router - .route("/pos-getAll/:status") - .get(isAuthenticatedUser, authorizeRoles("admin"), getAllOrder); -router - .route("/pos-getAll/") - .get(isAuthenticatedUser, authorizeRoles("admin"), getOrders); -router.route("/pos-getOne/:id").get(isAuthenticatedUser, getSingleOrder); -router - .route("/pos-change/status/:id") - .patch(isAuthenticatedUser, authorizeRoles("admin"), updateOrderStatusById); - -router - .route("/pos-delete/:id") - .delete(isAuthenticatedUser, authorizeRoles("admin"), deleteOneOrder); -//RAZERPAY checkout -router.route("/getRzpKey/:name/:email").get(isAuthenticatedUser, getRzpKey); -router.route("/Rzpcheckout/").post(isAuthenticatedUser, checkout); -router.route("/paymentverification").post(paymentVerification); -export default router; From 105da2bccbd0c402af96f01cabd26dd2a2134e5a Mon Sep 17 00:00:00 2001 From: Sibunnayak Date: Mon, 29 Apr 2024 15:10:57 +0530 Subject: [PATCH 6/7] point of sale order contoller with razorpay completed and cash with mail completed --- app.js | 3 - package-lock.json | 9 +- resources/Orders/PosCheckoutController.js | 241 +++++++++++++--------- 3 files changed, 146 insertions(+), 107 deletions(-) diff --git a/app.js b/app.js index 4781cde..dec8764 100644 --- a/app.js +++ b/app.js @@ -172,7 +172,6 @@ import CouponRoute from "./resources/Affiliate&Coupon/Coupon/CouponRoute.js"; //support Ticket import SupportRouter from "./resources/Supports/supportRoute.js"; // Point of Sale -import PosorderRoute from "./resources/PosOrders/PosorderRoute.js"; app.use("/api/v1/", user); //Product @@ -240,6 +239,4 @@ app.use("/api/panel", PanelRoute); // app.use("/api/shorturl", ShortUrlRouter); //Support app.use("/api", SupportRouter); -// Point of Sale -app.use("/api/posOrder", PosorderRoute); export default app; diff --git a/package-lock.json b/package-lock.json index 9bafc1a..a1f5970 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5417,7 +5417,8 @@ "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==" + "integrity": "sha512-Ll4eDzcrIVn4zCttMh3Mdi+KNz07p5EEjBT2PQSRx8Eok1lKPt3uBBenOk/w88RKK3B8SFIWcEe/mN4BHQ0p8A==", + "requires": {} }, "color-convert": { "version": "2.0.1", @@ -6660,7 +6661,8 @@ "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==" + "integrity": "sha512-25lm9R6o5dWrHLqLvygNX+kBOxprzpmZdnVKH4+r68WcfCt8XV6xfQaMuAg+kUE5Xmr8mJNA4gE0AcBj9FJyWA==", + "requires": {} }, "mute-stream": { "version": "0.0.8", @@ -7893,7 +7895,8 @@ "ws": { "version": "7.4.6", "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==" + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "requires": {} }, "xregexp": { "version": "2.0.0", diff --git a/resources/Orders/PosCheckoutController.js b/resources/Orders/PosCheckoutController.js index 7792e1f..ee069ad 100644 --- a/resources/Orders/PosCheckoutController.js +++ b/resources/Orders/PosCheckoutController.js @@ -1,6 +1,7 @@ import { shippingAddress } from "../ShippingAddresses/ShippingAddressModel.js"; import { Order } from "./orderModel.js"; +import sendEmail from "../../Utils/sendEmail.js"; //generate unique order id const generateUniqueOrderId = async () => { const currentYear = new Date().getFullYear(); @@ -21,99 +22,6 @@ const generateUniqueOrderId = async () => { return orderId; }; -// export const poscreateOrderCheckout = async (req, res) => { -// try { -// const { userr,address, cart, subtotal,orderType } = req.body; -// // console.log(req.body) -// // Perform validation -// if (cart.length < 1) -// return res.status(400).json({ message: "cart is empty!" }); -// if (!address) -// return res -// .status(404) -// .json({ message: "please select shipping address!" }); -// if (!subtotal) -// return res -// .status(404) -// .json({ message: "please provide product subtotal!" }); -// if (!userr) -// return res.status(400).json({ message: "user is not defined" }); - -// // Retrieve shipping address from database -// let addss = await shippingAddress.findById(address); - -// let shipping = { -// first_Name: addss.first_Name, -// last_Name: addss?.last_Name, -// phone_Number: addss?.phone_Number, -// street: addss?.street, -// city: addss?.city, -// state: addss?.state, -// postalCode: addss?.postalCode, -// country: addss?.country, -// company_name: addss?.company_name, -// gst_number: addss?.gst_number, -// addressId: address, -// }; - -// // Construct order items array -// const orderItems = await cart.map((item) => ({ -// product: item.product._id, -// name: item.product.name, -// variant_Name: item.variant.variant_Name, -// price: Number(item.variant.price), -// total_price: item.quantity * Number(item.variant.price), - -// image: item.product.image, -// quantity: item.quantity, -// gst_amount: Number( -// (Number(item.variant.price) * item.variant.gst_Id?.tax) / 100 -// )?.toFixed(3), -// total_gst_amount: Number( -// Number(item.quantity) * -// Number( -// (Number(item.variant.price) * item.variant.gst_Id?.tax) / 100 -// ) -// )?.toFixed(3), -// gst_rate: item.variant.gst_Id?.tax, -// tax_Name: item.variant?.gst_Id?.name, -// product_Subtotal: Number( -// Number(item.quantity * Number(item.variant.price)) + -// Number( -// Number(item.quantity) * -// Number( -// (Number(item.variant.price) * item.variant.gst_Id?.tax) / 100 -// ) -// ) -// ).toFixed(3), -// })); - -// // Generate a unique order ID -// const Id = await generateUniqueOrderId(); - -// // Create the order document -// const order = await Order.create({ -// orderID: Id, -// total_amount: subtotal, -// orderItems, -// shippingInfo: shipping, -// user: userr, -// orderType, -// paymentMode:"cod", -// payment_status:"success", -// isPaid:true, -// paidAt:new Date().toISOString(), -// }); - -// return res.status(201).json({ success: true, order }); -// } catch (error) { -// console.error("Error creating order:", error); -// return res -// .status(500) -// .json({ success: false, message: "Internal server error" }); -// } -// }; - export const poscreateOrderCheckout = async (req, res) => { try { const { userr, address, cart, subtotal, orderType } = req.body; @@ -122,11 +30,14 @@ export const poscreateOrderCheckout = async (req, res) => { if (cart.length < 1) return res.status(400).json({ message: "Cart is empty!" }); if (!address) - return res.status(404).json({ message: "Please select a shipping address!" }); + return res + .status(404) + .json({ message: "Please select a shipping address!" }); if (!subtotal) - return res.status(404).json({ message: "Please provide the product subtotal!" }); - if (!userr) - return res.status(400).json({ message: "User is not defined" }); + return res + .status(404) + .json({ message: "Please provide the product subtotal!" }); + if (!userr) return res.status(400).json({ message: "User is not defined" }); // Retrieve shipping address from database let addss = await shippingAddress.findById(address); @@ -154,11 +65,24 @@ export const poscreateOrderCheckout = async (req, res) => { total_price: item.quantity * Number(item.variant.price), image: item.product.image, quantity: item.quantity, - gst_amount: Number((Number(item.variant.price) * item.variant.gst_Id?.tax) / 100)?.toFixed(3), - total_gst_amount: Number(Number(item.quantity) * Number((Number(item.variant.price) * item.variant.gst_Id?.tax) / 100))?.toFixed(3), + gst_amount: Number( + (Number(item.variant.price) * item.variant.gst_Id?.tax) / 100 + )?.toFixed(3), + total_gst_amount: Number( + Number(item.quantity) * + Number((Number(item.variant.price) * item.variant.gst_Id?.tax) / 100) + )?.toFixed(3), gst_rate: item.variant.gst_Id?.tax, tax_Name: item.variant?.gst_Id?.name, - product_Subtotal: Number(Number(item.quantity * Number(item.variant.price)) + Number(Number(item.quantity) * Number((Number(item.variant.price) * item.variant.gst_Id?.tax) / 100))).toFixed(3), + product_Subtotal: Number( + Number(item.quantity * Number(item.variant.price)) + + Number( + Number(item.quantity) * + Number( + (Number(item.variant.price) * item.variant.gst_Id?.tax) / 100 + ) + ) + ).toFixed(3), })); // Generate a unique order ID @@ -177,10 +101,125 @@ export const poscreateOrderCheckout = async (req, res) => { isPaid: true, paidAt: new Date().toISOString(), }); + // console.log(order); + // Find the user associated with the order + const orderWithUser = await Order.findById(order._id).populate("user"); + + if (!orderWithUser) { + return res + .status(404) + .json({ success: false, message: "Order not found" }); + } + + const user = orderWithUser.user; + const userEmail = user.email; + + // Send email after order creation + await sendEmail({ + to: userEmail, + from: `${process.env.SEND_EMAIL_FROM}`, + subject: `Your Order #${order?.orderID} Confirmation`, + html: `

Welcome to Smellika - Let the Shopping Begin!

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

Great news! Your order #${ + order?.orderID + } has been confirmed. Here are the details

+

Shipping Address : ${ + order?.shippingInfo?.first_Name + } ${order?.shippingInfo?.last_Name} , ${order?.shippingInfo?.street} ${ + order?.shippingInfo?.city + } ${order?.shippingInfo?.state} ${order?.shippingInfo?.country}, PIN-${ + order?.shippingInfo?.postalCode + }, Phone Number: ${order?.shippingInfo?.phone_Number} + ${ + order?.shippingInfo?.company_name + ? ",Company Name :" + order?.shippingInfo?.company_name + "" + : "" + } ${ + order?.shippingInfo?.gst_number + ? ", GST_NO:" + order?.shippingInfo?.gst_number + : "" + }

+

Order Items :

+ + + + + + + + + + + + + + + + + + + + ${order?.orderItems + ?.map( + (product, index) => ` + + + + + + + + + + + + + + ` + ) + .join("")} + + + + + +
S No.Product NameVariantImageQuantityPriceGST AmountSubTotal
${ + index + 1 + }${ + product.name + }${ + product?.variant_Name + }${
+         product.name
+       }${ + product.quantity + }₹${ + product.price + }₹${ + product?.gst_amount + }₹${ + product?.product_Subtotal + }
Total Amount :₹${ + order?.total_amount + }
+ +
+ Best regards,
+ + Team Smellika`, + }); return res.status(201).json({ success: true, order }); } catch (error) { console.error("Error creating order:", error); - return res.status(500).json({ success: false, message: "Internal server error" }); + return res + .status(500) + .json({ success: false, message: "Internal server error" }); } }; From 00e6d2227a8bbed8ada2616a1ecdafdaa6f35b6c Mon Sep 17 00:00:00 2001 From: Sibunnayak Date: Tue, 30 Apr 2024 17:13:33 +0530 Subject: [PATCH 7/7] point of sale order contoller with razorpay completed and cash with mail completed --- resources/Orders/RazerPayCheckoutController.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/resources/Orders/RazerPayCheckoutController.js b/resources/Orders/RazerPayCheckoutController.js index 7af902c..688e633 100644 --- a/resources/Orders/RazerPayCheckoutController.js +++ b/resources/Orders/RazerPayCheckoutController.js @@ -68,7 +68,8 @@ export const getRazerpayKey = async (req, res) => { export const checkout = async (req, res) => { try { const { userr,address, cart, subtotal,orderType } = req.body; -// console.log(req.body); +// console.log(req.body.cart[0].product); +// console.log(req.body.cart[0].variant); if (cart.length < 1) return res.status(400).json({ message: "cart is empty!" }); if (!address) @@ -145,7 +146,7 @@ export const checkout = async (req, res) => { ).toFixed(3), })); - // console.log("line", lineItems[0]); + // console.log("Order", orderItems[0]); const Id = await generateUniqueOrderId(); const orders = await Order.create({ orderID: Id,