diff --git a/.env b/.env index def78a6..e5b250d 100644 --- a/.env +++ b/.env @@ -1,6 +1,7 @@ DB_URL="mongodb+srv://smellica:Anjefef23dnsfjne@cluster0.c5gfqzm.mongodb.net/" +# DB_URL="mongodb://localhost:27017/smellica" PORT = 5000 JWT_SECRET = jdvnvjwrniwj4562ddsjn6@1xsbfeh@wre4Njdf; @@ -13,9 +14,12 @@ WEBHOOK_SECRET_KEY="whsec_m9u7CFBCY1qWarhxq65CkII6egOBf20K" STRIPE_SECRET_KEY="sk_test_51OhPRdSG6gbAOwcEid1GavJ4FTD0ZuHVTferdvJwKal77RlMtFJGBzL5GjtL0ie8ZJztsGjUWi8DWrnw1pDdDRGS005Hk0ahql" STRIPE_WEBHOOK_SECRET="whsec_dc9b9084fc764c806c8c5c06dd91de1ee809e9c8deab6d56e8e3ef2fc9c30c67" +<<<<<<< HEAD FRONTEND_URL="http://127.0.0.1:5173" RAZERPAY_KEY_ID="rzp_test_smzQmWoS64S2W9" RAZERPAY_SECRET_KEY="cSn6MgA4xSEaZBpPp4zpDA3C" +FRONTEND_URL="https://smellika.com" + SEND_EMAIL_FROM="hello@smellika.com" #brevo send mail @@ -25,4 +29,6 @@ SMPT_MAIL="neonflake.enterprises@gmail.com" SMPT_PASSWORD="ND5sgVnWtrpUFfTb" PAYPAL_CLIENT_ID="AemCjVuWswklp1sWUo4peCFg9eS4bofMsMR0RCrVRB2DifYR1IUSrWqtHpVmQlrVMKTI2cWZXLJAdYwn" -PAYPAL_CLIENT_SECRET="EAo0Y9ff3jpHHg1QAbftdebfh7cb_-vnebhQrP9KALbCVer908yx2tO2eHO39r7EJSfqc4D69Qgx8R31" \ No newline at end of file +PAYPAL_CLIENT_SECRET="EAo0Y9ff3jpHHg1QAbftdebfh7cb_-vnebhQrP9KALbCVer908yx2tO2eHO39r7EJSfqc4D69Qgx8R31" + +STRIPE_SECRET="sk_test_51OhPRdSG6gbAOwcEid1GavJ4FTD0ZuHVTferdvJwKal77RlMtFJGBzL5GjtL0ie8ZJztsGjUWi8DWrnw1pDdDRGS005Hk0ahql" \ No newline at end of file diff --git a/app.js b/app.js index 8f66712..b93919e 100644 --- a/app.js +++ b/app.js @@ -155,10 +155,20 @@ import TaxRouter from "./resources/Tax/tax_routes.js"; //specialties import SpecialtiesRouter from "./resources/Specialties/SpecialtiesRoute.js"; import ShippingAddressRoute from "./resources/ShippingAddresses/ShippingAddressRoute.js"; +import stripeRoute from "./resources/StripePayment/stripeRoute.js"; +import SeoRoute from "./resources/SEO&Analytics/SEORouter.js"; + +//Affiliate Routes +import AffiliateRoute from "./resources/Affiliate&Coupon/Affiliate/AffiliateRoute.js"; +//Blog Routes +import BlogRoute from "./resources/Blog/BlogRoute.js"; +//Coupon Routes +import CouponRoute from "./resources/Affiliate&Coupon/Coupon/CouponRoute.js"; //short urls // import ShortUrlRouter from "./resources/Businesses/Short_Urls/ShortUrlRoute.js"; - +//support Ticket +import SupportRouter from "./resources/Supports/supportRoute.js"; app.use("/api/v1/", user); //Product @@ -200,6 +210,18 @@ app.use("/api/business", orderRoute); app.use("/api/tax", TaxRouter); //config app.use("/api/config", ConfigRouter); + +app.use("/api/stripe", stripeRoute); + +app.use("/api/seo", SeoRoute); + +//Affiliates +app.use("/api/v1/affiliate", AffiliateRoute); + +//Coupons +app.use("/api/v1/coupon", CouponRoute); +//Blog +app.use("/api/v1/blog", BlogRoute); //config specialty // app.use("/api/config/specialty", SpecialtiesRouter); //specialties @@ -208,5 +230,6 @@ app.use("/api/config", ConfigRouter); // app.use("/api/appointment", AppointmentRouter); //short urls // app.use("/api/shorturl", ShortUrlRouter); - +//Support +app.use("/api", SupportRouter); export default app; diff --git a/resources/Affiliate&Coupon/Affiliate/AffiliateController.js b/resources/Affiliate&Coupon/Affiliate/AffiliateController.js new file mode 100644 index 0000000..790f917 --- /dev/null +++ b/resources/Affiliate&Coupon/Affiliate/AffiliateController.js @@ -0,0 +1,291 @@ +import { AffiliateModel } from "./AffiliateModel.js"; + +// -----------------------------AFFILIATE & COUPONS ARE HARDLY BINDED DATA-------------------------------------------------------- +//Create Affiliate +export const createAffiliate = async (req, res) => { + try { + const result = req.body; + const affiliate = new AffiliateModel(result); + const savedData = await affiliate.save(); + if (savedData) { + return res + .status(201) + .json({ success: true, message: "Affiliate Added" }); + } + } catch (error) { + res.status(500).json({ + success: false, + message: error.message + .split(":") + .splice(1) + .join(":") + .trim() + .split(":") + .splice(1) + .join(":") + .trim(), + }); + } +}; + +//EDIT +export const editAffiliate = async (req, res) => { + const updateFields = {}; + + const { + name, + mobile, + email, + country, + state, + city, + address, + pincode, + nameAsBank, + accountNo, + ifsc, + bankName, + branchName, + } = req.body; + + // Add only the fields that are present in the request body to the updateFields object + if (name) updateFields.name = name; + if (mobile) updateFields.mobile = mobile; + if (email) updateFields.email = email; + if (country) updateFields.country = country; + if (state) { + updateFields.state = state; + } else { + updateFields.state = ""; + } + if (city) { + updateFields.city = city; + } else { + updateFields.city = ""; + } + if (address) updateFields.address = address; + if (pincode) updateFields.pincode = pincode; + if (nameAsBank) updateFields.nameAsBank = nameAsBank; + if (accountNo) updateFields.accountNo = accountNo; + if (ifsc) updateFields.ifsc = ifsc; + if (bankName) updateFields.bankName = bankName; + if (branchName) updateFields.branchName = branchName; + try { + const saveData = await AffiliateModel.findByIdAndUpdate( + { _id: req.params.id }, + { $set: updateFields }, + { new: true } + ); + res.json({ + success: true, + message: "Affiliate Updated Succesfully", + }); + } catch (error) { + res.status(400).json({ + success: false, + message: "Error in Updation", + }); + } +}; +//DELETE +export const deleteAffiliate = async (req, res) => {}; +//PAY AFFILIATE TODO +export const payAffiliate = async (req, res) => { + // console.log(req.body); + const { noOfCoupons, amountToPay, amount, transecId, date, time } = req.body; + if ( + !req.params.id || + !noOfCoupons || + !amountToPay || + !amount || + !transecId || + !date || + !time + ) { + return res.status(400).json({ + success: false, + message: "Error in Payment", + }); + } + try { + const affiliate = await AffiliateModel.findById(req.params.id); + //Checking if it's valid data from the client + if ( + amountToPay != affiliate.total_earning - affiliate.paid_amount || + noOfCoupons != affiliate.coupon_claimed - affiliate.no_of_paid_coupon + ) { + return res.status(400).json({ + success: false, + message: "Data invalid", + }); + } + + // Construct the update operation + const updateOperation = { + $push: { + affiliate_pay_history: { + amount: amountToPay, + transecId: transecId, + date: date, + time: time, + }, + }, + $inc: { + paid_amount: amountToPay, + no_of_paid_coupon: noOfCoupons, + }, + }; + + // Execute the update operation + const updatedAffiliate = await AffiliateModel.findByIdAndUpdate( + req.params.id, + updateOperation, + { new: true } + ); + + return res.json({ + success: true, + message: "Payment Done Successfully", + updatedAffiliate: { updatedAffiliate }, + }); + } catch (error) { + console.error(error); + return res.status(400).json({ + success: false, + message: "Error in Payment", + }); + } +}; + +//GET ONE AFFLILIATE +export const getOneAffiliate = async (req, res) => { + if (req.params?.id) { + try { + const saveData = await AffiliateModel.findById(req.params.id); + const resObj = { + name: saveData.name, + mobile: saveData.mobile, + email: saveData.email, + country: saveData.country, + state: saveData.state, + city: saveData.city, + address: saveData.address, + pincode: saveData.pincode, + nameAsBank: saveData.nameAsBank, + accountNo: saveData.accountNo, + ifsc: saveData.ifsc, + bankName: saveData.bankName, + branchName: saveData.branchName, + }; + res.status(200).json({ + success: true, + message: resObj, + }); + } catch (error) { + res.status(400).json({ + success: false, + message: "Error in getting Affiliates", + }); + } + } +}; +//LIST ALL AFFILIATE +export const listAllAffiliate = async (req, res) => { + try { + const affiliate = await AffiliateModel.find( + {}, + { + name: 1, + _id: 1, + coupon_claimed: 1, + coupon_code: 1, + total_earning: 1, + paid_amount: 1, + is_affiliate_active: 1, + } + ).sort({ createdAt: -1 }); + res.status(200).json({ + success: true, + message: affiliate, + }); + } catch (error) { + res.status(500).json({ + success: false, + messgae: error.message ? error.message : "Something went wrong!", + }); + } +}; + +//Activate & Deactivate Affiliates +export const suspendAffiliate = async (req, res) => { + const { id, is_affiliate_active } = req.body; + try { + const saveData = await AffiliateModel.findByIdAndUpdate(id, { + is_affiliate_active: is_affiliate_active, + }); + res.status(200).json({ + success: true, + message: "Success", + }); + } catch (error) { + res.status(400).json({ + success: false, + message: "Affiliate Doesn't Exists", + }); + } +}; + +//Get Affiliate data for payment +export const getOneAffiliateForPay = async (req, res) => { + if (req.params?.id) { + try { + const saveData = await AffiliateModel.findById(req.params.id); + const resObj = { + name: saveData.name, + coupon_claimed: saveData.coupon_claimed, + total_earning: saveData.total_earning, + paid_amount: saveData.paid_amount, + no_of_paid_coupon: saveData.no_of_paid_coupon, + affiliate_discount_amount: saveData.affiliate_discount_amount, + coupon_code: saveData.coupon_code, + nameAsBank: saveData.nameAsBank, + accountNo: saveData.accountNo, + ifsc: saveData.ifsc, + bankName: saveData.bankName, + branchName: saveData.branchName, + }; + res.status(200).json({ + success: true, + message: resObj, + }); + } catch (error) { + res.status(400).json({ + success: false, + message: "Error in getting Affiliates", + }); + } + } +}; +//Get Affiliate data for History +export const affiliatePayHistory = async (req, res) => { + if (req.params?.id) { + try { + const saveData = await AffiliateModel.findById(req.params.id).sort({ + updatedAt: -1, + }); + const resObj = { + affiliate_pay_history: saveData.affiliate_pay_history, + name: saveData.name, + }; + res.status(200).json({ + success: true, + message: resObj, + }); + } catch (error) { + res.status(400).json({ + success: false, + message: "Error in getting History", + }); + } + } +}; diff --git a/resources/Affiliate&Coupon/Affiliate/AffiliateModel.js b/resources/Affiliate&Coupon/Affiliate/AffiliateModel.js new file mode 100644 index 0000000..928243e --- /dev/null +++ b/resources/Affiliate&Coupon/Affiliate/AffiliateModel.js @@ -0,0 +1,122 @@ +import mongoose from "mongoose"; +const { Schema, model } = mongoose; + +const couponUsedSchema = new Schema({ + userId: { type: String, required: true }, + orderId: { type: String, required: true }, + couponCode: { type: String, required: true }, + date: { type: String, required: true }, +}); +const affilitePaySchema = new Schema({ + amount: { type: Number, required: true }, + transecId: { type: String, required: true }, + date: { type: String, required: true }, + time: { type: String, required: true }, +}); +const affiliateSchema = new Schema( + { + name: { + type: String, + maxLength: [25, "name cannot exceed 25 characters"], + required: [true, "Please Enter Name"], + }, + mobile: { + type: Number, + maxLength: [10, "Mobile cannot exceed 10 characters"], + minlength: [10, "Invalid Mobile Number"], + required: [true, "Please Enter Mobile Number"], + unique: true, + }, + email: { + type: String, + required: [true, "Please Enter Email"], + unique: true, + }, + country: { + type: String, + required: [true, "Please Enter Country"], + }, + state: { + type: String, + }, + city: { + type: String, + }, + address: { + type: String, + required: [true, "Please Enter Address"], + }, + pincode: { + type: Number, + required: [true, "Please Enter Pincode"], + }, + nameAsBank: { + type: String, + required: [true, "Please Enter Name as Bank"], + }, + accountNo: { + type: Number, + required: [true, "Please Enter Account Number"], + unique: true, + }, + ifsc: { + type: String, + required: [true, "Please Enter IFSC code"], + }, + bankName: { + type: String, + required: [true, "Please Enter Bank Name"], + }, + branchName: { + type: String, + required: [true, "Please Enter Branch Name"], + }, + coupon_code: { + type: String, + unique: [true, "Coupon Alerady Exists"], + sparse: true, + }, + discount_amount: { + type: Number, + }, + affiliate_discount_amount: { + type: Number, + }, + valid_till: { + type: String, + }, + createdAt: { + type: String, + }, + + coupon_claimed: { + type: Number, + default: 0, + }, + total_earning: { + type: Number, + default: 0, + }, + paid_amount: { + type: Number, + default: 0, + }, + no_of_paid_coupon: { + type: Number, + default: 0, + }, + is_affiliate_active: { + type: Boolean, + default: true, + }, + is_coupon_active: { + type: Boolean, + default: false, + }, + coupon_used_history: [couponUsedSchema], + affiliate_pay_history: [affilitePaySchema], + }, + { timestamps: true } +); + +export const AffiliateModel = model("Affiliate", affiliateSchema); diff --git a/resources/Affiliate&Coupon/Affiliate/AffiliateRoute.js b/resources/Affiliate&Coupon/Affiliate/AffiliateRoute.js new file mode 100644 index 0000000..ccf9b66 --- /dev/null +++ b/resources/Affiliate&Coupon/Affiliate/AffiliateRoute.js @@ -0,0 +1,69 @@ +import express from "express"; +import { + affiliatePayHistory, + createAffiliate, + editAffiliate, + getOneAffiliate, + getOneAffiliateForPay, + listAllAffiliate, + payAffiliate, + suspendAffiliate, +} from "./AffiliateController.js"; + +import { + isAuthenticatedUser, + authorizeRoles, +} from "../../../middlewares/auth.js"; + +const router = express.Router(); + +router.post( + "/create", + isAuthenticatedUser, + authorizeRoles("admin"), + createAffiliate +); +router.get( + "/getall", + isAuthenticatedUser, + authorizeRoles("admin"), + listAllAffiliate +); +router.get( + "/getone/:id", + isAuthenticatedUser, + authorizeRoles("admin"), + getOneAffiliate +); +router.patch( + "/edit/:id", + isAuthenticatedUser, + authorizeRoles("admin"), + editAffiliate +); +router.patch( + "/suspend", + isAuthenticatedUser, + authorizeRoles("admin"), + suspendAffiliate +); +router.post( + "/pay/:id", + isAuthenticatedUser, + authorizeRoles("admin"), + payAffiliate +); +router.get( + "/getpay/:id", + isAuthenticatedUser, + authorizeRoles("admin"), + getOneAffiliateForPay +); +router.get( + "/history/:id", + isAuthenticatedUser, + authorizeRoles("admin"), + affiliatePayHistory +); + +export default router; diff --git a/resources/Affiliate&Coupon/Coupon/CouponController.js b/resources/Affiliate&Coupon/Coupon/CouponController.js new file mode 100644 index 0000000..285d145 --- /dev/null +++ b/resources/Affiliate&Coupon/Coupon/CouponController.js @@ -0,0 +1,414 @@ +import { AffiliateModel } from "../Affiliate/AffiliateModel.js"; //Note AffiliteModel is binded with coupons + +//GET ALL Coupons +export const listAllCoupon = async (req, res) => { + try { + const coupon = await AffiliateModel.find( + {}, + { + name: 1, + _id: 1, + coupon_code: 1, + discount_amount: 1, + affiliate_discount_amount: 1, + is_coupon_active: 1, + } + ).sort({ createdAt: -1 }); + const filteredCoupons = coupon.filter( + (data) => !(data.coupon_code == null) + ); + // console.log(filteredCoupons); + // console.log(coupon); + + res.status(200).json({ + success: true, + message: filteredCoupons, + }); + } catch (error) { + res.status(500).json({ + success: false, + message: error.message ? error.message : "Something went wrong!", + }); + } +}; +//CREATE Coupon (AKA Need to update Affiliate ) +export const createCoupon = async (req, res) => { + //creation of date + const date = new Date(); + const daysOfWeek = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; + const monthsOfYear = [ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", + ]; + const dayOfWeek = daysOfWeek[date.getUTCDay()]; + const dateOfMonth = date.getUTCDate(); + const month = monthsOfYear[date.getUTCMonth()]; + const year = date.getUTCFullYear(); + const formattedDate = `${dayOfWeek} ${dateOfMonth}-${month}-${year}`; + const { + coupon_code, + discount_amount, + valid_till, + is_coupon_active, + affiliate_discount_amount, + } = req.body; + try { + const { id } = req.body; + const update = { + coupon_code, + discount_amount, + valid_till, + affiliate_discount_amount, + createdAt: formattedDate, + is_coupon_active, + }; + const options = { new: true }; + const saveData = await AffiliateModel.findByIdAndUpdate( + id, + update, + options + ); + + if (saveData) { + res.json("done"); + } else { + res.status(404).json("Affiliate not found"); + } + } catch (error) { + res.status(400).json({ + success: true, + message: "Coupon Already Exists", + }); + console.log(error); + } +}; + +//GET AFFILIATE FOR COUPON LIST +export const listAffiliateCoupon = async (req, res) => { + try { + let resArr = []; + const coupon = await AffiliateModel.find( + {}, + { + name: 1, + _id: 1, + is_coupon_active: 1, + mobile: 1, + } + ); + for (let i = 0; i < coupon.length; i++) { + if (coupon[i].is_coupon_active == false) { + resArr.push(coupon[i]); + } + } + // console.log(resArr); + res.status(200).json({ + success: true, + message: resArr, + }); + } catch (error) { + res.status(500).json({ + success: false, + message: error.message ? error.message : "Something went wrong!", + }); + } +}; +//EDIT COUPON +export const editCoupon = async (req, res) => { + const { + coupon_code, + discount_amount, + valid_till, + affiliate_discount_amount, + } = req.body; + + const updateFields = {}; + + // Add only the fields that are present in the request body to the updateFields object + if (coupon_code) updateFields.coupon_code = coupon_code; + if (discount_amount) updateFields.discount_amount = discount_amount; + if (valid_till) updateFields.valid_till = valid_till; + if (affiliate_discount_amount) + updateFields.affiliate_discount_amount = affiliate_discount_amount; + + try { + const saveData = await AffiliateModel.findByIdAndUpdate( + { _id: req.params.id }, + { $set: updateFields }, + { new: true } + ); + res.json({ + success: true, + message: "Coupon Edited Succesfully", + }); + } catch (error) { + res.status(400).json({ + success: false, + message: error.message + ? error.message + .split(":") + .splice(1) + .join(":") + .trim() + .split(":") + .splice(1) + .join(":") + .trim() + : "Error in Editing Coupon", + }); + } +}; +//SUSPEND COUPON +export const suspendCoupon = async (req, res) => { + const { id, is_coupon_active } = req.body; + try { + const saveData = await AffiliateModel.findByIdAndUpdate(id, { + is_coupon_active: is_coupon_active, + }); + res.status(200).json({ + success: true, + message: "Success", + }); + } catch (error) { + res.status(400).json({ + success: false, + message: "Coupon Doesn't Exists", + }); + } +}; + +//GET ONE COUPON +export const getOneCoupon = async (req, res) => { + if (req.params?.id) { + try { + const saveData = await AffiliateModel.findById(req.params.id); + + const resObj = { + name: saveData.name, + mobile: saveData.mobile, + coupon_code: saveData.coupon_code, + discount_amount: saveData.discount_amount, + valid_till: saveData.valid_till, + affiliate_discount_amount: saveData.affiliate_discount_amount, + }; + res.status(200).json({ + success: true, + message: resObj, + }); + } catch (error) { + res.status(400).json({ + success: false, + message: "Error in getting Coupons", + }); + } + } +}; + +//Validate Coupon----------------------- +export const validateCoupon = async (req, res) => { + const { coupon } = req.params; + + if (!coupon) { + return res.status(400).json({ + success: false, + message: "Coupon code is required", + }); + } + + try { + // Find the coupon data in the database + const couponData = await AffiliateModel.findOne({ coupon_code: coupon }); + + if (!couponData) { + return res.status(404).json({ + success: false, + message: "Coupon not found", + }); + } + + const { valid_till, discount_amount, is_coupon_active } = couponData; + //Check whether Coupon is Active or not + if (!is_coupon_active) { + return res.status(404).json({ + success: false, + message: "Coupon Code Expired", + }); + } + // Check if the coupon is expired + const currentDate = new Date(); + const expirationDate = new Date(valid_till); + + if (currentDate > expirationDate) { + return res.status(400).json({ + success: false, + message: "Coupon has expired", + }); + } + + // If coupon is valid, return success response + res.status(200).json({ + success: true, + message: "Coupon is valid", + discount_amount: discount_amount, + }); + } catch (error) { + console.error(error); + res.status(500).json({ + success: false, + message: "Internal server error", + }); + } +}; + +//PAY & HISTORY--------------------- +export const usedCoupon = async (req, res) => { + // Retrieve orderId and coupon_code from request body or query parameters + const { orderId, coupon_code, userId } = req.body; + if (!orderId || !coupon_code || !userId) { + return res.status(400).json({ + success: false, + message: "Error in getting OrderId or Coupon", + }); + } + + // Validating Coupon + try { + const couponData = await AffiliateModel.findOne({ + coupon_code: coupon_code, + }); + //order exists or not + + if (!couponData) { + // Check if the coupon exists + return res.status(404).json({ + success: false, + message: "Coupon not found", + }); + } + // Check if orderId is unique + try { + const isOrderIdUnique = await AffiliateModel.find( + {}, + { + coupon_used_history: 1, + } + ); + + let orderIdFound = false; + + isOrderIdUnique.forEach((data) => { + data.coupon_used_history.forEach((subItem) => { + if (subItem.orderId == orderId) { + orderIdFound = true; + } + }); + }); + + if (orderIdFound) { + return res.status(400).json({ + success: false, + message: "Error: OrderId already used", + }); + } + } catch (error) { + console.error(error); + return res.status(500).json({ + success: false, + message: "Internal server error", + }); + } + //If not unique then create + const { + valid_till, + is_coupon_active, + is_affiliate_active, + affiliate_discount_amount, + _id, + } = couponData; + // console.log(couponData); + if (!is_coupon_active || !is_affiliate_active) { + return res.status(404).json({ + success: false, + message: "Coupon Code Expired", + }); + } + const currentDate = new Date(); + const expirationDate = new Date(valid_till); + + if (currentDate > expirationDate) { + return res.status(400).json({ + success: false, + message: "Coupon has expired", + }); + } + + AffiliateModel.findByIdAndUpdate( + _id, + { + $inc: { total_earning: affiliate_discount_amount, coupon_claimed: 1 }, + $push: { + coupon_used_history: { + orderId: orderId, + userId: userId, + date: currentDate, + couponCode: coupon_code, + }, + }, + }, + { new: true } + ) + .then(() => { + res.status(200).json({ + success: true, + message: "Coupon add success", + }); + }) + .catch((error) => { + console.error(error); + res.status(500).json({ + success: false, + message: "Internal server error", + }); + }); + } catch (error) { + console.error(error); + res.status(500).json({ + success: false, + message: "Internal server error", + }); + } +}; +//Get Coupon data for History +export const couponPayHistory = async (req, res) => { + if (req.params?.id) { + try { + const saveData = await AffiliateModel.findById(req.params.id).sort({ + updatedAt: -1, + }); + // console.log(saveData.coupon_used_history); + const resObj = { + coupon_used_history: saveData.coupon_used_history, + coupon_code: saveData.coupon_code, + }; + res.status(200).json({ + success: true, + message: resObj, + }); + } catch (error) { + res.status(400).json({ + success: false, + message: "Error in getting History", + }); + } + } +}; diff --git a/resources/Affiliate&Coupon/Coupon/CouponRoute.js b/resources/Affiliate&Coupon/Coupon/CouponRoute.js new file mode 100644 index 0000000..bead939 --- /dev/null +++ b/resources/Affiliate&Coupon/Coupon/CouponRoute.js @@ -0,0 +1,76 @@ +import express from "express"; +import { + couponPayHistory, + createCoupon, + editCoupon, + getOneCoupon, + listAffiliateCoupon, + listAllCoupon, + suspendCoupon, + usedCoupon, + validateCoupon, +} from "./CouponController.js"; + +import { + isAuthenticatedUser, + authorizeRoles, +} from "../../../middlewares/auth.js"; + +const router = express.Router(); +router.get( + "/getall", + isAuthenticatedUser, + authorizeRoles("admin"), + listAllCoupon +); +router.patch( + "/create", + isAuthenticatedUser, + authorizeRoles("admin"), + createCoupon +); +router.get( + "/getaffiliate", + isAuthenticatedUser, + authorizeRoles("admin"), + listAffiliateCoupon +); +router.patch( + "/edit/:id", + isAuthenticatedUser, + authorizeRoles("admin"), + editCoupon +); +router.get( + "/getone/:id", + isAuthenticatedUser, + authorizeRoles("admin"), + getOneCoupon +); +router.get("/validcoupon/:coupon", validateCoupon); +router.patch( + "/suspend", + isAuthenticatedUser, + authorizeRoles("admin"), + suspendCoupon +); +router.patch( + "/paycoupon", + // isAuthenticatedUser, + usedCoupon +); +/* url:http://localhost:5000/api/v1/coupon/paycoupon + json structure to paycoupon , Need Header to be auth +{ + "userId":"random1", + "orderId":"12s213", + "coupon_code":"3000MONY" +}*/ +router.get( + "/history/:id", + isAuthenticatedUser, + authorizeRoles("admin"), + couponPayHistory +); + +export default router; diff --git a/resources/Blog/BlogController.js b/resources/Blog/BlogController.js new file mode 100644 index 0000000..79abfd3 --- /dev/null +++ b/resources/Blog/BlogController.js @@ -0,0 +1,63 @@ +import Blog from "./BlogModel.js"; + +export const createBlog = async (req, res) => { + const { title, tags, image, blog_content } = req.body; + console.log(req.body); + + // Checking Fields + if (!title || !tags || !image || !blog_content) { + return res.status(400).json({ + success: false, + message: "All fields are mandatory", + }); + } + + try { + let images = []; + let Allfiles = req.files.image; + console.log(Allfiles); + // if (!Array.isArray(Allfiles)) { + // Allfiles = [Allfiles]; // Convert to array if it's not already + // } + + // Allfiles.forEach((file) => { + // if (typeof file.tempFilePath === "string") { + // let filepath = file.tempFilePath; + // images.push(filepath); + // } + // }); + + // const newBlog = await Blog.create({ + // title, + // tags, + // image: images, // Assign the array of image file paths + // blog_content, + // }); + + res.status(201).json({ + success: true, + message: "Blog created successfully", + data: images, + }); + } catch (error) { + console.error("Error creating blog:", error); + res.status(500).json({ + success: false, + message: error.message ? error.message : "Internal server error", + }); + } +}; +export const getAllBlog = async (req, res) => { + try { + const saveData = await Blog.find(); + res.status(200).json({ + success: true, + message: saveData, + }); + } catch { + res.status(500).json({ + success: false, + message: "Internal server error", + }); + } +}; diff --git a/resources/Blog/BlogModel.js b/resources/Blog/BlogModel.js new file mode 100644 index 0000000..1b3a65b --- /dev/null +++ b/resources/Blog/BlogModel.js @@ -0,0 +1,28 @@ +import mongoose from "mongoose"; + +const { Schema, model } = mongoose; + +const blogSchema = new Schema( + { + title: { + type: String, + required: [true, "Title is required"], + }, + tags: { + type: [String], + required: [true, "Tags are required"], + }, + image: { + type: String, + }, + blog_content: { + type: Object, + required: [true, "Content is required"], + }, + }, + { timestamps: true } +); + +const Blog = model("Blog", blogSchema); + +export default Blog; diff --git a/resources/Blog/BlogRoute.js b/resources/Blog/BlogRoute.js new file mode 100644 index 0000000..772b7b6 --- /dev/null +++ b/resources/Blog/BlogRoute.js @@ -0,0 +1,11 @@ +import express from "express"; + +import { createBlog, getAllBlog } from "./BlogController.js"; +import { isAuthenticatedUser, authorizeRoles } from "../../middlewares/auth.js"; + +const router = express.Router(); + +router.post("/create", createBlog); +router.get("/getallblog", getAllBlog); + +export default router; diff --git a/resources/Blog/dummy.json b/resources/Blog/dummy.json new file mode 100644 index 0000000..90dfec3 --- /dev/null +++ b/resources/Blog/dummy.json @@ -0,0 +1,5 @@ +[ + { + "title": "String0" + } +] diff --git a/resources/ContactRequests/ContactRequestsModel.js b/resources/ContactRequests/ContactRequestsModel.js index ccad01d..6dcca01 100644 --- a/resources/ContactRequests/ContactRequestsModel.js +++ b/resources/ContactRequests/ContactRequestsModel.js @@ -1,7 +1,4 @@ - - - import mongoose from "mongoose"; const { Schema, model } = mongoose; diff --git a/resources/Content/ContentController.js b/resources/Content/ContentController.js index f7500ff..b366441 100644 --- a/resources/Content/ContentController.js +++ b/resources/Content/ContentController.js @@ -51,16 +51,24 @@ export const getTermsAndCondition = async (req, res) => { export const updateTermsAndConditions = async (req, res) => { try { if (!req?.user) return res.status(400).json({ message: "please login !" }); - // console.log(req?.user) - const { content } = req.body; - const termsAndCondition = await TermsAndCondition.findOneAndUpdate( - { - addedBy: req.user._id, - }, - { - termsAndContionContent: content, - } - ); + // new content + const { content } = req.body; + + // id of the terms and conndition document + const id = req.query.id; + + // object for updated terms and conndition data + const updatedTermsData = { + termsAndContionContent: content, + addedBy: req.user._id + } + + // update the terms and conndition in database + const termsAndCondition = await TermsAndCondition.findByIdAndUpdate( + { _id: id }, + { $set: updatedTermsData }, + { new: true } + ); res.status(200).json({ success: true, @@ -80,23 +88,10 @@ export const RefundPolicy = async (req, res) => { if (!req?.user) return res.status(400).json({ message: "please login !" }); // console.log(req?.user) const { content } = req.body; - const findv = await Refundpolicy.findOne(); - let refundPolicy; - if (findv) { - refundPolicy = await Refundpolicy.findOneAndUpdate( - { - addedBy: req.user._id, - }, - { - Refundpolicy: content, - } - ); - } else { - refundPolicy = await Refundpolicy.create({ + const refundPolicy = await Refundpolicy.create({ addedBy: req.user._id, Refundpolicy: content, }); - } res.status(200).json({ success: true, @@ -130,6 +125,42 @@ export const getRefundPolicy = async (req, res) => { } }; +// update refund policy +export const updateRefundPolicy = async (req, res) => { + try { + if (!req?.user) return res.status(400).json({ message: "please login !" }); + + const {content} = req.body; + // id of the refund policy document + const id = req.query.id; + + // object for updated refund policy data + const updatedRefundPolicyData = { + Refundpolicy: content, + addedBy: req.user._id + } + + // update the refund policy in database + const refundPolicy = await Refundpolicy.findByIdAndUpdate( + { _id: id }, + { $set: updatedRefundPolicyData }, + { new: true } + ); + + res.status(200).json({ + success: true, + refundPolicy, + message: "updated successfully ", + }); + } catch (error) { + res.status(500).json({ + success: false, + message: error.message ? error.message : "Something went Wrong", + }); + } +}; + + // Privacy policy controller functions export const AddPrivacyAndPolicy = async (req, res) => { @@ -180,15 +211,24 @@ export const getPrivacyPolicy = async (req, res) => { export const updatePrivacyPolicy = async (req, res) => { try { if (!req?.user) return res.status(400).json({ message: "please login !" }); - // console.log(req?.user) + + // new content const { content } = req.body; - const privacyAndPolicy = await PrivacyAndPolicy.findOneAndUpdate( - { - addedBy: req.user._id, - }, - { - privacyAndPolicyContent: content, - } + + // id of the privacy policy document + const id = req.query.id; + + // object for updated privacy policy data + const updatedPrivacyPolicyData = { + privacyAndPolicyContent: content, + addedBy: req.user._id + } + + // update the privacy policy in database + const privacyAndPolicy = await PrivacyAndPolicy.findByIdAndUpdate( + { _id: id }, + { $set: updatedPrivacyPolicyData }, + { new: true } ); res.status(200).json({ @@ -254,15 +294,23 @@ export const getShipping = async (req, res) => { export const updateShipping = async (req, res) => { try { if (!req?.user) return res.status(400).json({ message: "please login !" }); - // console.log(req?.user) + // new content const { content } = req.body; - const shipping = await Shipping.findOneAndUpdate( - { - addedBy: req.user._id, - }, - { - shippingContent: content, - } + + // id of the shipping policy document + const id = req.query.id; + + // object for updated shipping policy data + const updatedShippingData = { + shippingContent: content, + addedBy: req.user._id + } + + // update the shipping policy in database + const shipping = await Shipping.findByIdAndUpdate( + { _id: id }, + { $set: updatedShippingData }, + { new: true } ); res.status(200).json({ diff --git a/resources/Content/ContentRoutes.js b/resources/Content/ContentRoutes.js index 907dafe..eddc29a 100644 --- a/resources/Content/ContentRoutes.js +++ b/resources/Content/ContentRoutes.js @@ -11,6 +11,7 @@ import { updatePrivacyPolicy, updateShipping, updateTermsAndConditions, + updateRefundPolicy } from "./ContentController.js"; import { isAuthenticatedUser, authorizeRoles } from "../../middlewares/auth.js"; @@ -46,7 +47,10 @@ router router.route("/refund-policy").get(getRefundPolicy); router .route("/refund-policy") - .patch(isAuthenticatedUser, authorizeRoles("admin"), RefundPolicy); + .post(isAuthenticatedUser, authorizeRoles("admin"), RefundPolicy); +router + .route("/refund-policy-update") + .patch(isAuthenticatedUser, authorizeRoles("admin"), updateRefundPolicy); // export default router; diff --git a/resources/Orders/StripeCheckOutController.js b/resources/Orders/StripeCheckOutController.js index b92eb18..f031fe1 100644 --- a/resources/Orders/StripeCheckOutController.js +++ b/resources/Orders/StripeCheckOutController.js @@ -11,7 +11,7 @@ import { shippingAddress } from "../ShippingAddresses/ShippingAddressModel.js"; import sendEmail from "../../Utils/sendEmail.js"; // const endpointSecret = STRIPE_SECRET_KEY; //generate unique order id -const generateUniqueOrderId = async () => { +export 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 } }); @@ -36,6 +36,7 @@ export const handlePayment = async (req, res) => { 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) { @@ -48,7 +49,7 @@ export const handlePayment = async (req, res) => { } } let addss = await shippingAddress.findById(address); - console.log(addss?.postalCode); + let shipping = { first_Name: addss.first_Name, last_Name: addss.last_Name, @@ -78,7 +79,7 @@ export const handlePayment = async (req, res) => { shippingInfo: shipping, user: req.user._id, }); - console.log("fffffffff", order, "llllllllll"); + // console.log("fffffffff", order, "llllllllll"); const lineItems = await cart.map((item) => ({ price_data: { currency: "inr", @@ -102,12 +103,19 @@ 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`, + shipping_address_collection: { + allowed_countries: ["IN"], + // Allow only India for INR transactions + }, + billing_address_collection: "required", + success_url: `${process.env.FRONTEND_URL}/order-complete`, // Provide your success URL here + cancel_url: `${process.env.FRONTEND_URL}/cart`, }); // res.json({ sessionId: session.id }); - res.status(200).send({ message: "order created", url: session.url }); + res + .status(200) + .send({ message: "order created", url: session.url, id: session.id }); } } catch (err) { console.log(err); @@ -117,6 +125,7 @@ export const handlePayment = async (req, res) => { export const webhook = async (req, res) => { const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET; + const signature = req.headers["stripe-signature"]; let event; if (webhookSecret) { @@ -134,7 +143,6 @@ export const webhook = async (req, res) => { } if (event.type === "checkout.session.completed") { - // console.log("dddddddddddd", event.data); const findOrder = await Order.findById(event.data.object.metadata?.orderId); findOrder.paypal_payer_id = event.data.object.id; findOrder.paidAt = new Date(event.data.object.created * 1000); @@ -146,20 +154,52 @@ export const webhook = async (req, res) => { } findOrder.orderStatus = "new"; await findOrder.save(); + + // Construct the HTML for the email + const itemRows = findOrder?.orderItems + .map( + (item) => + `
Great news! Your order #${findOrder?.orderID} has been confirmed. Here are the details:
+Item | +Quantity | +Price | +
---|
Shipping Address: ${findOrder?.shippingInfo.first_Name} ${findOrder?.shippingInfo.last_Name},${findOrder?.shippingInfo.postalCode}, + ${findOrder?.shippingInfo.street}, + ${findOrder?.shippingInfo.city}, + ${findOrder?.shippingInfo.state}, + ${findOrder?.shippingInfo.country} Phone number:${findOrder?.shippingInfo.phone_Number}
+Total: ₹${findOrder.total_amount}
+ +Great news! Your order #${findOrder?.orderID} has been confirmed. Here are the details
-Great news! Your order has been confirmed. Here are the details
+