razerpay integration

This commit is contained in:
pawan-dot 2024-04-01 11:43:45 +05:30
commit 6e627056be
32 changed files with 2141 additions and 129 deletions

6
.env
View File

@ -1,6 +1,7 @@
DB_URL="mongodb+srv://smellica:Anjefef23dnsfjne@cluster0.c5gfqzm.mongodb.net/" DB_URL="mongodb+srv://smellica:Anjefef23dnsfjne@cluster0.c5gfqzm.mongodb.net/"
# DB_URL="mongodb://localhost:27017/smellica"
PORT = 5000 PORT = 5000
JWT_SECRET = jdvnvjwrniwj4562ddsjn6@1xsbfeh@wre4Njdf; JWT_SECRET = jdvnvjwrniwj4562ddsjn6@1xsbfeh@wre4Njdf;
@ -13,9 +14,12 @@ WEBHOOK_SECRET_KEY="whsec_m9u7CFBCY1qWarhxq65CkII6egOBf20K"
STRIPE_SECRET_KEY="sk_test_51OhPRdSG6gbAOwcEid1GavJ4FTD0ZuHVTferdvJwKal77RlMtFJGBzL5GjtL0ie8ZJztsGjUWi8DWrnw1pDdDRGS005Hk0ahql" STRIPE_SECRET_KEY="sk_test_51OhPRdSG6gbAOwcEid1GavJ4FTD0ZuHVTferdvJwKal77RlMtFJGBzL5GjtL0ie8ZJztsGjUWi8DWrnw1pDdDRGS005Hk0ahql"
STRIPE_WEBHOOK_SECRET="whsec_dc9b9084fc764c806c8c5c06dd91de1ee809e9c8deab6d56e8e3ef2fc9c30c67" STRIPE_WEBHOOK_SECRET="whsec_dc9b9084fc764c806c8c5c06dd91de1ee809e9c8deab6d56e8e3ef2fc9c30c67"
<<<<<<< HEAD
FRONTEND_URL="http://127.0.0.1:5173" FRONTEND_URL="http://127.0.0.1:5173"
RAZERPAY_KEY_ID="rzp_test_smzQmWoS64S2W9" RAZERPAY_KEY_ID="rzp_test_smzQmWoS64S2W9"
RAZERPAY_SECRET_KEY="cSn6MgA4xSEaZBpPp4zpDA3C" RAZERPAY_SECRET_KEY="cSn6MgA4xSEaZBpPp4zpDA3C"
FRONTEND_URL="https://smellika.com"
SEND_EMAIL_FROM="hello@smellika.com" SEND_EMAIL_FROM="hello@smellika.com"
#brevo send mail #brevo send mail
@ -26,3 +30,5 @@ SMPT_PASSWORD="ND5sgVnWtrpUFfTb"
PAYPAL_CLIENT_ID="AemCjVuWswklp1sWUo4peCFg9eS4bofMsMR0RCrVRB2DifYR1IUSrWqtHpVmQlrVMKTI2cWZXLJAdYwn" PAYPAL_CLIENT_ID="AemCjVuWswklp1sWUo4peCFg9eS4bofMsMR0RCrVRB2DifYR1IUSrWqtHpVmQlrVMKTI2cWZXLJAdYwn"
PAYPAL_CLIENT_SECRET="EAo0Y9ff3jpHHg1QAbftdebfh7cb_-vnebhQrP9KALbCVer908yx2tO2eHO39r7EJSfqc4D69Qgx8R31" PAYPAL_CLIENT_SECRET="EAo0Y9ff3jpHHg1QAbftdebfh7cb_-vnebhQrP9KALbCVer908yx2tO2eHO39r7EJSfqc4D69Qgx8R31"
STRIPE_SECRET="sk_test_51OhPRdSG6gbAOwcEid1GavJ4FTD0ZuHVTferdvJwKal77RlMtFJGBzL5GjtL0ie8ZJztsGjUWi8DWrnw1pDdDRGS005Hk0ahql"

27
app.js
View File

@ -155,10 +155,20 @@ import TaxRouter from "./resources/Tax/tax_routes.js";
//specialties //specialties
import SpecialtiesRouter from "./resources/Specialties/SpecialtiesRoute.js"; import SpecialtiesRouter from "./resources/Specialties/SpecialtiesRoute.js";
import ShippingAddressRoute from "./resources/ShippingAddresses/ShippingAddressRoute.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 //short urls
// import ShortUrlRouter from "./resources/Businesses/Short_Urls/ShortUrlRoute.js"; // import ShortUrlRouter from "./resources/Businesses/Short_Urls/ShortUrlRoute.js";
//support Ticket
import SupportRouter from "./resources/Supports/supportRoute.js";
app.use("/api/v1/", user); app.use("/api/v1/", user);
//Product //Product
@ -200,6 +210,18 @@ app.use("/api/business", orderRoute);
app.use("/api/tax", TaxRouter); app.use("/api/tax", TaxRouter);
//config //config
app.use("/api/config", ConfigRouter); 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 //config specialty
// app.use("/api/config/specialty", SpecialtiesRouter); // app.use("/api/config/specialty", SpecialtiesRouter);
//specialties //specialties
@ -208,5 +230,6 @@ app.use("/api/config", ConfigRouter);
// app.use("/api/appointment", AppointmentRouter); // app.use("/api/appointment", AppointmentRouter);
//short urls //short urls
// app.use("/api/shorturl", ShortUrlRouter); // app.use("/api/shorturl", ShortUrlRouter);
//Support
app.use("/api", SupportRouter);
export default app; export default app;

View File

@ -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",
});
}
}
};

View File

@ -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);

View File

@ -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;

View File

@ -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",
});
}
}
};

View File

@ -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;

View File

@ -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",
});
}
};

View File

@ -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;

View File

@ -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;

View File

@ -0,0 +1,5 @@
[
{
"title": "String0"
}
]

View File

@ -1,7 +1,4 @@
import mongoose from "mongoose"; import mongoose from "mongoose";
const { Schema, model } = mongoose; const { Schema, model } = mongoose;

View File

@ -51,15 +51,23 @@ export const getTermsAndCondition = async (req, res) => {
export const updateTermsAndConditions = async (req, res) => { export const updateTermsAndConditions = async (req, res) => {
try { try {
if (!req?.user) return res.status(400).json({ message: "please login !" }); if (!req?.user) return res.status(400).json({ message: "please login !" });
// console.log(req?.user) // new content
const { content } = req.body; const { content } = req.body;
const termsAndCondition = await TermsAndCondition.findOneAndUpdate(
{ // id of the terms and conndition document
addedBy: req.user._id, const id = req.query.id;
},
{ // object for updated terms and conndition data
const updatedTermsData = {
termsAndContionContent: content, 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({ res.status(200).json({
@ -80,23 +88,10 @@ export const RefundPolicy = async (req, res) => {
if (!req?.user) return res.status(400).json({ message: "please login !" }); if (!req?.user) return res.status(400).json({ message: "please login !" });
// console.log(req?.user) // console.log(req?.user)
const { content } = req.body; const { content } = req.body;
const findv = await Refundpolicy.findOne(); const refundPolicy = await Refundpolicy.create({
let refundPolicy;
if (findv) {
refundPolicy = await Refundpolicy.findOneAndUpdate(
{
addedBy: req.user._id,
},
{
Refundpolicy: content,
}
);
} else {
refundPolicy = await Refundpolicy.create({
addedBy: req.user._id, addedBy: req.user._id,
Refundpolicy: content, Refundpolicy: content,
}); });
}
res.status(200).json({ res.status(200).json({
success: true, 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 // Privacy policy controller functions
export const AddPrivacyAndPolicy = async (req, res) => { export const AddPrivacyAndPolicy = async (req, res) => {
@ -180,15 +211,24 @@ export const getPrivacyPolicy = async (req, res) => {
export const updatePrivacyPolicy = async (req, res) => { export const updatePrivacyPolicy = async (req, res) => {
try { try {
if (!req?.user) return res.status(400).json({ message: "please login !" }); if (!req?.user) return res.status(400).json({ message: "please login !" });
// console.log(req?.user)
// new content
const { content } = req.body; const { content } = req.body;
const privacyAndPolicy = await PrivacyAndPolicy.findOneAndUpdate(
{ // id of the privacy policy document
addedBy: req.user._id, const id = req.query.id;
},
{ // object for updated privacy policy data
const updatedPrivacyPolicyData = {
privacyAndPolicyContent: content, 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({ res.status(200).json({
@ -254,15 +294,23 @@ export const getShipping = async (req, res) => {
export const updateShipping = async (req, res) => { export const updateShipping = async (req, res) => {
try { try {
if (!req?.user) return res.status(400).json({ message: "please login !" }); if (!req?.user) return res.status(400).json({ message: "please login !" });
// console.log(req?.user) // new content
const { content } = req.body; const { content } = req.body;
const shipping = await Shipping.findOneAndUpdate(
{ // id of the shipping policy document
addedBy: req.user._id, const id = req.query.id;
},
{ // object for updated shipping policy data
const updatedShippingData = {
shippingContent: content, 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({ res.status(200).json({

View File

@ -11,6 +11,7 @@ import {
updatePrivacyPolicy, updatePrivacyPolicy,
updateShipping, updateShipping,
updateTermsAndConditions, updateTermsAndConditions,
updateRefundPolicy
} from "./ContentController.js"; } from "./ContentController.js";
import { isAuthenticatedUser, authorizeRoles } from "../../middlewares/auth.js"; import { isAuthenticatedUser, authorizeRoles } from "../../middlewares/auth.js";
@ -46,7 +47,10 @@ router
router.route("/refund-policy").get(getRefundPolicy); router.route("/refund-policy").get(getRefundPolicy);
router router
.route("/refund-policy") .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; export default router;

View File

@ -11,7 +11,7 @@ import { shippingAddress } from "../ShippingAddresses/ShippingAddressModel.js";
import sendEmail from "../../Utils/sendEmail.js"; import sendEmail from "../../Utils/sendEmail.js";
// const endpointSecret = STRIPE_SECRET_KEY; // const endpointSecret = STRIPE_SECRET_KEY;
//generate unique order id //generate unique order id
const generateUniqueOrderId = async () => { export const generateUniqueOrderId = async () => {
const currentYear = new Date().getFullYear(); const currentYear = new Date().getFullYear();
// Find the latest order to get the last serial number // Find the latest order to get the last serial number
const latestOrder = await Order.findOne({}, {}, { sort: { orderID: -1 } }); const latestOrder = await Order.findOne({}, {}, { sort: { orderID: -1 } });
@ -36,6 +36,7 @@ export const handlePayment = async (req, res) => {
if (!email) if (!email)
return res.status(400).send({ message: "Please enter the email" }); return res.status(400).send({ message: "Please enter the email" });
const { address, cart, subtotal } = req.body; const { address, cart, subtotal } = req.body;
if (cart.length < 1) if (cart.length < 1)
return res.status(400).json({ message: "cart is empty!" }); return res.status(400).json({ message: "cart is empty!" });
switch (true) { switch (true) {
@ -48,7 +49,7 @@ export const handlePayment = async (req, res) => {
} }
} }
let addss = await shippingAddress.findById(address); let addss = await shippingAddress.findById(address);
console.log(addss?.postalCode);
let shipping = { let shipping = {
first_Name: addss.first_Name, first_Name: addss.first_Name,
last_Name: addss.last_Name, last_Name: addss.last_Name,
@ -78,7 +79,7 @@ export const handlePayment = async (req, res) => {
shippingInfo: shipping, shippingInfo: shipping,
user: req.user._id, user: req.user._id,
}); });
console.log("fffffffff", order, "llllllllll"); // console.log("fffffffff", order, "llllllllll");
const lineItems = await cart.map((item) => ({ const lineItems = await cart.map((item) => ({
price_data: { price_data: {
currency: "inr", currency: "inr",
@ -102,12 +103,19 @@ export const handlePayment = async (req, res) => {
// Add any other key-value pairs as needed // Add any other key-value pairs as needed
}, },
success_url: `${process.env.FRONTEND_URL}/cart`, shipping_address_collection: {
cancel_url: `${process.env.FRONTEND_URL}/error`, 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.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) { } catch (err) {
console.log(err); console.log(err);
@ -117,6 +125,7 @@ export const handlePayment = async (req, res) => {
export const webhook = async (req, res) => { export const webhook = async (req, res) => {
const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET; const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET;
const signature = req.headers["stripe-signature"]; const signature = req.headers["stripe-signature"];
let event; let event;
if (webhookSecret) { if (webhookSecret) {
@ -134,7 +143,6 @@ export const webhook = async (req, res) => {
} }
if (event.type === "checkout.session.completed") { if (event.type === "checkout.session.completed") {
// console.log("dddddddddddd", event.data);
const findOrder = await Order.findById(event.data.object.metadata?.orderId); const findOrder = await Order.findById(event.data.object.metadata?.orderId);
findOrder.paypal_payer_id = event.data.object.id; findOrder.paypal_payer_id = event.data.object.id;
findOrder.paidAt = new Date(event.data.object.created * 1000); findOrder.paidAt = new Date(event.data.object.created * 1000);
@ -146,20 +154,52 @@ export const webhook = async (req, res) => {
} }
findOrder.orderStatus = "new"; findOrder.orderStatus = "new";
await findOrder.save(); 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 // Construct the HTML for the email
const itemRows = findOrder?.orderItems
.map(
(item) =>
`<tr><td>${item?.name}</td><td>${item?.quantity}</td><td>₹${item?.price}</td></tr>`
)
.join("");
const htmlContent = `
subject: `Your Order #${findOrder?.orderID} Confirmation`,
html: ` <h1 style="color: #333; text-align: center; font-family: Arial, sans-serif;">Welcome to Smellika - Let the Shopping Begin!</h1>
<strong style="color: #1b03a3; font-size: 16px"> Hi ${findOrder?.shippingInfo?.first_Name},</strong> <strong style="color: #1b03a3; font-size: 16px"> Hi ${findOrder?.shippingInfo?.first_Name},</strong>
<p style="color: #555; font-size: 15px;">Great news! Your order #${findOrder?.orderID} has been confirmed. Here are the details</p> <p style="color: #555; font-size: 15px;">Great news! Your order #${findOrder?.orderID} has been confirmed. Here are the details:</p>
<br/>
<table border="1" cellpadding="5" style="border-collapse: collapse; width: 100%;">
<thead>
<tr>
<th>Item</th>
<th>Quantity</th>
<th>Price</th>
</tr>
</thead>
<tbody>
${itemRows}
</tbody>
</table>
<p style="color: #555; font-size: 15px;">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} </br> Phone number:${findOrder?.shippingInfo.phone_Number}</p>
<p style="color: #555; font-size: 15px;">Total: ${findOrder.total_amount}</p>
<br/> <br/>
<span style="color: #555; font-size: 13px;">Best regards,</span><br/> <span style="color: #555; font-size: 13px;">Best regards,</span><br/>
<span style="color: #555; font-size: 13px;">Team Smellika</span>`;
<span style="color: #555; font-size: 13px;">Team Smellika</span>`, // Send the email
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 Order #${findOrder?.orderID} Confirmation`,
html: htmlContent,
}); });
// Items: [List of Purchased Items] // Items: [List of Purchased Items]
@ -176,7 +216,7 @@ export const webhook = async (req, res) => {
"---------------------" "---------------------"
); );
console.log(`💰 Payment status: ${event.data.object?.payment_status}`); // console.log(`💰 Payment status: ${event.data.object?.payment_status}`);
// Saving the payment details in the database // Saving the payment details in the database
// const payment = await Payment.create({ // const payment = await Payment.create({

View File

@ -1,3 +1,4 @@
import sendEmail from "../../Utils/sendEmail.js";
import { Order } from "./orderModel.js"; import { Order } from "./orderModel.js";
export const getAllOrder = async (req, res) => { export const getAllOrder = async (req, res) => {
@ -44,7 +45,7 @@ export const getSingleOrder = async (req, res) => {
const order = await Order.findById(req.params.id) const order = await Order.findById(req.params.id)
.populate({ .populate({
path: "user", path: "user",
select: "name -_id", select: "name email -_id",
}) })
.populate({ .populate({
path: "shippingInfo.addressId", path: "shippingInfo.addressId",
@ -67,13 +68,13 @@ export const getSingleOrder = async (req, res) => {
//get self User Order //get self User Order
export const getUserSelf = async (req, res) => { export const getUserSelf = async (req, res) => {
if (!req?.user) return res.status(400).json({ message: "please login !" });
try { try {
const order = await Order.find({ const order = await Order.find({
user: req.user._id, user: req.user?._id,
payment_status: "success", payment_status: "success",
}) }).sort({ createdAt: -1 });
.populate("shippingInfo.addressId")
.sort({ createdAt: -1 });
if (order) { if (order) {
return res.status(200).json({ return res.status(200).json({
success: true, success: true,
@ -117,6 +118,7 @@ export const deleteOneOrder = async (req, res) => {
export const updateOrderStatusById = async (req, res) => { export const updateOrderStatusById = async (req, res) => {
try { try {
let body = { orderStatus: req.body.status }; let body = { orderStatus: req.body.status };
const currentDate = new Date(); const currentDate = new Date();
body["status_timeline." + req.body.status] = currentDate; body["status_timeline." + req.body.status] = currentDate;
// if (req.body?.package_weight) body.package_weight = req.body.package_weight; // if (req.body?.package_weight) body.package_weight = req.body.package_weight;
@ -151,6 +153,21 @@ export const updateOrderStatusById = async (req, res) => {
body["courier_name"] = req.body.courierName; body["courier_name"] = req.body.courierName;
body["courier_tracking_id"] = req.body.TrackingID; body["courier_tracking_id"] = req.body.TrackingID;
await Order.findByIdAndUpdate(order._id, body); await Order.findByIdAndUpdate(order._id, body);
await sendEmail({
to: `${req.body.sendemail}`, // Change to your recipient
from: `${process.env.SEND_EMAIL_FROM}`, // Change to your verified sender
subject: `Your Order is On Its Way!`,
html: ` <h1 style="color: #333; text-align: center; font-family: Arial, sans-serif;">Welcome to Smellika - Let the Shopping Begin!</h1>
<strong style="color: #1b03a3; font-size: 16px"> Hi ${req.body?.customerName},</strong>
<p style="color: #555; font-size: 15px;">Great news! Your order has been confirmed. Here are the details</p>
<br/>
<span style="color: #555; font-size: 13px;">Best regards,</span><br/>
<span style="color: #555; font-size: 13px;">Team Smellika</span>`,
});
return res return res
.status(200) .status(200)
.json({ status: "ok", message: "Order status updated successfully!" }); .json({ status: "ok", message: "Order status updated successfully!" });

View File

@ -117,7 +117,7 @@ const orderSchema = new mongoose.Schema(
"cancelled", "cancelled",
"returned", "returned",
], ],
// default: "new", default: "new",
}, },
// paypal_payer_id: { type: String }, // paypal_payer_id: { type: String },

View File

@ -33,9 +33,7 @@ router.route("/:orderID/capture/payment").post(captureOrderPayment);
// ----------------------stripe checkOut-----------------// // ----------------------stripe checkOut-----------------//
// app.post("/webhook", express.raw({ type: "application/json" }), webhook); // app.post("/webhook", express.raw({ type: "application/json" }), webhook);
router router.route("/stripe-checkout").post(isAuthenticatedUser, handlePayment);
.route("/stripe-checkout-session")
.post(isAuthenticatedUser, handlePayment);
router router
.route("/webhook") .route("/webhook")
.post(express.raw({ type: "application/json" }), webhook); .post(express.raw({ type: "application/json" }), webhook);

View File

@ -1,7 +1,7 @@
import { Product } from "./ProductModel.js"; import { Product } from "./ProductModel.js";
import cloudinary from "../../Utils/cloudinary.js"; import cloudinary from "../../Utils/cloudinary.js";
import { v4 as uuidv4 } from "uuid"; import { v4 as uuidv4 } from "uuid";
import { CategoryModel } from "../Category/CategoryModel.js";
export const createProduct = async (req, res) => { export const createProduct = async (req, res) => {
try { try {
if (!req.files) { if (!req.files) {
@ -75,6 +75,48 @@ export const getAllProduct = async (req, res) => {
}); });
} }
}; };
// get all product with device products first
export const getAllProductsDevicesFirst = async (req, res) => {
try {
// we want products with category name Device to be displayed first, so i have first found the products with category name Devices then made another request to find all products and filtered products with category devices , then merged both arrays so we get devices first then all other categories
const categoryName = 'Devices';
// Find the category object by name first
const category = await CategoryModel.findOne({ categoryName });
if (!category) {
throw new Error("Category not found");
}
// products with device category
const deviceProducts = await Product.find({ category: category._id }).populate('category');
// all products
const allProducts = await Product.find()
.populate({
path: "category gst addedBy",
select: "name categoryName tax",
})
.sort({
createdAt: -1,
});
// filtering out products with device category
const filteredProducts = allProducts.filter((ele) => { return ele.category?.categoryName !== categoryName })
// merging both deviceProcuts and filtered products
const product = deviceProducts.concat(filteredProducts)
if (product) {
return res.status(200).json({
success: true,
product,
});
}
} catch (error) {
res.status(500).json({
success: false,
msg: error.message ? error.message : "Something went wrong!",
});
}
};
//get One Product //get One Product
export const getOneProduct = async (req, res) => { export const getOneProduct = async (req, res) => {
try { try {
@ -98,8 +140,109 @@ export const getOneProduct = async (req, res) => {
}; };
// 3.update Product // 3.update Product
// export const updateProduct = async (req, res) => {
// const {
// name,
// description,
// price,
// category,
// image,
// gst_amount,
// gst,
// total_amount,
// } = req.body;
// console.log(gst_amount, gst, total_amount);
// try {
// // Prepare an array for the images
// const jsonArray = JSON.parse(image);
// const AllImages = jsonArray.map(({ public_id, url }) => ({
// public_id,
// url,
// }));
// if (req.files && req.files.newImages) {
// const newuploadImages = Array.isArray(req.files.newImages)
// ? req.files.newImages
// : [req.files.newImages];
// const imagesLinks = [];
// for (let i = 0; i < newuploadImages.length; i++) {
// const result = await cloudinary.v2.uploader.upload(
// newuploadImages[i].tempFilePath,
// {
// folder: "smellica/product",
// }
// );
// imagesLinks.push({
// public_id: result.public_id,
// url: result.secure_url,
// });
// }
// // Combine the existing images and the newly uploaded images
// const updatedImages = [...AllImages, ...imagesLinks];
// // Perform the product update
// const ModifyProduct = await Product.findOneAndUpdate(
// { _id: req.params.id },
// {
// $set: {
// name,
// description,
// price,
// category,
// image: updatedImages,
// gst,
// gst_amount,
// total_amount,
// },
// },
// { new: true }
// );
// return res.status(200).json({
// success: true,
// ModifyProduct,
// });
// } else {
// const ModifyProduct = await Product.findOneAndUpdate(
// { _id: req.params.id },
// {
// $set: {
// name,
// description,
// price,
// category,
// image: AllImages,
// },
// },
// { new: true }
// );
// return res.status(200).json({
// success: true,
// ModifyProduct,
// });
// }
// } catch (error) {
// res.status(500).json({
// success: false,
// msg: error.message ? error.message : "Something went wrong!",
// });
// }
// };
export const updateProduct = async (req, res) => { export const updateProduct = async (req, res) => {
const { name, description, price, category, image } = req.body; const {
name,
description,
price,
category,
image,
gst_amount,
gst,
total_amount,
} = req.body;
try { try {
// Prepare an array for the images // Prepare an array for the images
@ -109,16 +252,18 @@ export const updateProduct = async (req, res) => {
url, url,
})); }));
let updatedImages = AllImages;
if (req.files && req.files.newImages) { if (req.files && req.files.newImages) {
const newuploadImages = Array.isArray(req.files.newImages) const newUploadImages = Array.isArray(req.files.newImages)
? req.files.newImages ? req.files.newImages
: [req.files.newImages]; : [req.files.newImages];
const imagesLinks = []; const imagesLinks = [];
for (let i = 0; i < newuploadImages.length; i++) { for (let i = 0; i < newUploadImages.length; i++) {
const result = await cloudinary.v2.uploader.upload( const result = await cloudinary.v2.uploader.upload(
newuploadImages[i].tempFilePath, newUploadImages[i].tempFilePath,
{ {
folder: "smellica/product", folder: "smellica/product",
} }
@ -131,10 +276,11 @@ export const updateProduct = async (req, res) => {
} }
// Combine the existing images and the newly uploaded images // Combine the existing images and the newly uploaded images
const updatedImages = [...AllImages, ...imagesLinks]; updatedImages = [...AllImages, ...imagesLinks];
}
// Perform the product update // Perform the product update
const ModifyProduct = await Product.findOneAndUpdate( const updatedProduct = await Product.findOneAndUpdate(
{ _id: req.params.id }, { _id: req.params.id },
{ {
$set: { $set: {
@ -143,34 +289,24 @@ export const updateProduct = async (req, res) => {
price, price,
category, category,
image: updatedImages, image: updatedImages,
gst,
gst_amount,
total_amount,
}, },
}, },
{ new: true } { new: true }
); );
return res.status(200).json({
success: true, if (!updatedProduct) {
ModifyProduct, return res.status(404).json({ success: false, msg: "Product not found" });
});
} else {
const ModifyProduct = await Product.findOneAndUpdate(
{ _id: req.params.id },
{
$set: {
name,
description,
price,
category,
image: AllImages,
},
},
{ new: true }
);
return res.status(200).json({
success: true,
ModifyProduct,
});
} }
return res.status(200).json({
success: true,
updatedProduct,
});
} catch (error) { } catch (error) {
console.error("Error updating product:", error);
res.status(500).json({ res.status(500).json({
success: false, success: false,
msg: error.message ? error.message : "Something went wrong!", msg: error.message ? error.message : "Something went wrong!",
@ -240,13 +376,20 @@ export const deleteProduct = async (req, res) => {
}); });
} }
}; };
export const getProductsByCategory = async (req, res) => { export const getProductsByCategory = async (req, res) => {
const { categoryName } = req.params; // Assuming category name is in the route const { categoryName } = req.params; // Assuming category name is in the route
// console.log(categoryName);
try { try {
const products = await Product.find({ // Find the category object by name first
category: categoryName, const category = await CategoryModel.findOne({ categoryName });
}).sort({ createdAt: -1 });
if (!category) {
throw new Error("Category not found");
}
const products = await Product.find({ category: category._id }).populate('category');
// console.log(products);
if (products && products.length > 0) { if (products && products.length > 0) {
return res.status(200).json({ return res.status(200).json({

View File

@ -5,7 +5,7 @@ const productSchema = new Schema(
{ {
name: { name: {
type: String, type: String,
maxLength: [25, "name cannot exceed 25 characters"], maxLength: [35, "name cannot exceed 25 characters"],
required: [true, "Please Enter product Name"], required: [true, "Please Enter product Name"],
trim: true, trim: true,
}, },
@ -15,7 +15,7 @@ const productSchema = new Schema(
}, },
description: { description: {
type: String, type: String,
maxLength: [100, "description cannot exceed 100 characters"], maxLength: [400, "description cannot exceed 100 characters"],
required: [true, "Please Enter product Description"], required: [true, "Please Enter product Description"],
}, },
price: { price: {

View File

@ -7,6 +7,7 @@ import {
getOneProduct, getOneProduct,
deleteImageFromCloudinary, deleteImageFromCloudinary,
getProductsByCategory, getProductsByCategory,
getAllProductsDevicesFirst,
} from "./ProductController.js"; } from "./ProductController.js";
const router = express.Router(); const router = express.Router();
import { isAuthenticatedUser, authorizeRoles } from "../../middlewares/auth.js"; import { isAuthenticatedUser, authorizeRoles } from "../../middlewares/auth.js";
@ -14,6 +15,7 @@ router
.route("/product/create/") .route("/product/create/")
.post(isAuthenticatedUser, authorizeRoles("admin"), createProduct); .post(isAuthenticatedUser, authorizeRoles("admin"), createProduct);
router.route("/product/getAll/").get(getAllProduct); router.route("/product/getAll/").get(getAllProduct);
router.route("/product/getAllProductsDevicesFrist/").get(getAllProductsDevicesFirst);
router.route("/product/getOne/:id").get(getOneProduct); router.route("/product/getOne/:id").get(getOneProduct);
router router
.route("/product/update/:id") .route("/product/update/:id")

View File

@ -0,0 +1,39 @@
import {SeoRequest} from "./SEOModel.js";
export const AddNewSeoRequest = async (req, res) => {
try {
let existingSeoRequest = await SeoRequest.findOne();
if (existingSeoRequest) {
existingSeoRequest.GoogleTag = req.body.GoogleTag;
existingSeoRequest.FacebookPixel = req.body.FacebookPixel;
existingSeoRequest.GoogleAnalytics = req.body.GoogleAnalytics;
existingSeoRequest.MicrosoftClarity=req.body.MicrosoftClarity;
existingSeoRequest = await existingSeoRequest.save();
res.status(200).json({
success: true,
seorequest: existingSeoRequest,
message: "Seo Request Updated",
});
} else {
const newSeoRequest = await SeoRequest.create(req.body);
res.status(201).json({
success: true,
seorequest: newSeoRequest,
message: "Seo Request Added",
});
}
} catch (error) {
res.status(500).json({
success: false,
message: error.message ? error.message : "Something went Wrong",
});
}
};

View File

@ -0,0 +1,33 @@
import mongoose from "mongoose";
const { Schema, model } = mongoose;
const SeoRequestSchema = new mongoose.Schema(
{
GoogleTag: {
type: String,
maxLength: [25, "tag cannot exceed 25 characters"],
required: [true, "Please Enter google tag "],
},
FacebookPixel: {
type: String,
maxLength: [25, "tag cannot exceed 25 characters"],
required: [true, "Please Enter Facebook Pixel "],
},
GoogleAnalytics: {
type: String,
maxLength: [500, "google analytics cannot exceed 500 characters"],
required: [true, "Please Enter google analytics"],
},
MicrosoftClarity: {
type: String,
maxLength: [500, "Microsoft clarity cannot exceed 500 characters"],
required: [true, "Please Enter microsoft clarity"],
},
},
{ timestamps: true, versionKey: false }
);
export const SeoRequest = mongoose.model("SeoRequest", SeoRequestSchema);

View File

@ -0,0 +1,12 @@
import express from "express";
import { isAuthenticatedUser, authorizeRoles } from "../../middlewares/auth.js";
import { AddNewSeoRequest } from "./SEOController.js";
const router = express.Router();
router
.route("/new")
.post(isAuthenticatedUser, authorizeRoles("admin"), AddNewSeoRequest);
export default router;

View File

@ -0,0 +1,11 @@
import { createCheckoutSession } from "./stripeModel.js";
export async function createCheckoutSessionController(req, res) {
try {
const sessionId = await createCheckoutSession(req.body);
res.json({ id: sessionId });
} catch (error) {
console.error("Error creating checkout session:", error);
res.status(500).json({ error: "Failed to create checkout session" });
}
}

View File

@ -0,0 +1,27 @@
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET);
export async function createCheckoutSession(body) {
const lineItems = body.products.map(({ product, quantity }) => ({
price_data: {
currency: "usd",
product_data: {
name: product.name,
images: [product.image[0].url], // assuming you want to use the first image URL
},
unit_amount: Math.round(product.price * 100), // Ensure proper conversion to cents
},
quantity: quantity,
}));
const session = await stripe.checkout.sessions.create({
payment_method_types: ["card"],
line_items: lineItems,
mode: "payment",
success_url: "http://localhost:5173/order-complete", // Provide your success URL here
cancel_url: "http://localhost:5173/cart", // Provide your cancel URL here
});
return session.id;
}

View File

@ -0,0 +1,8 @@
import express from "express";
import { createCheckoutSessionController } from "./stripeController.js";
const router = express.Router();
router.post("/create-checkout-session", createCheckoutSessionController);
export default router;

View File

@ -0,0 +1,292 @@
import { Support } from "./supportModel.js";
import cloudinary from "../../Utils/cloudinary.js";
export const createSupport = async (req, res) => {
// console.log(req.body);
// console.log(req.files.image);
try {
// const { ticketId, createdOn, subject, description } = req.body;
if(req.files && req.files.image){
let images = [];
let Allfiles = req.files.image;
if (typeof Allfiles.tempFilePath === "string") {
let filepath = Allfiles.tempFilePath;
images.push(filepath);
} else {
Allfiles.map((item) => {
images.push(item.tempFilePath);
});
}
const imagesLinks = [];
for (let i = 0; i < images.length; i++) {
const result = await cloudinary.v2.uploader.upload(images[i], {
folder: "smellica/CustomerSupport",
});
imagesLinks.push({
public_id: result.public_id,
url: result.secure_url,
});
}
req.body.image = imagesLinks;
}
req.body.addedBy = req.user._id;
// Check if any required field is missing
// if (!ticketId || !createdOn || !subject || !description) {
// return res.status(400).json({
// success: false,
// msg: "All fields are required.",
// });
// }
// Create the support ticket
// const support = await Support.create({
// ticketId,
// createdOn,
// subject,
// description,
// addedBy: req.user._id,
// image: imagesLinks,
// });
const support = await Support.create({ ...req.body });
// Return the created support ticket
res.status(201).json({
success: true,
data: support,
msg: "Support ticket created successfully.",
});
} catch (error) {
console.error(error);
// Handle errors
res.status(500).json({
success: false,
msg: error.message,
});
}
};
// ****************************
export const getAllSupportTicket = async (req, res) => {
try {
// Use the find method to retrieve all support tickets
const support = await Support.find().sort({ createdAt: -1 });
// Check if support tickets were found
if (support) {
return res.status(200).json({
success: true,
support,
});
}
} catch (error) {
// Handle errors
// console.error(error);
res.status(500).json({
success: false,
msg: error.message ? error.message : "Something went wrong!",
});
}
};
export const getOneSupportTicket = async (req, res) => {
try {
// console.log(req.params.id);
const support = await Support.findOne({ ticketId: req.params.id });
if (support) {
return res.status(200).json({
success: true,
support,
});
} else {
return res.status(404).json({
success: false,
msg: "Support ticket not found",
});
}
} catch (error) {
res.status(500).json({
success: false,
msg: error.message ? error.message : "Something went wrong!",
});
}
};
// ************************8
export const getAllSupportTicketofuser = async (req, res) => {
try {
// Retrieve the user ID from the request
const userId = req.user._id;
// Use the find method to retrieve all support tickets created by the user
const support = await Support.find({ addedBy: userId }).sort({
createdAt: -1,
});
// Check if support tickets were found
if (support) {
return res.status(200).json({
success: true,
support,
});
} else {
return res.status(404).json({
success: false,
msg: "No support tickets found for the user.",
});
}
} catch (error) {
// Handle errors
// console.error(error);
res.status(500).json({
success: false,
msg: error.message ? error.message : "Something went wrong!",
});
}
};
// ************************8
export const deleteSupport = async (req, res) => {
try {
if (!req.params.id) {
return res.status(400).json({
success: false,
msg: "Please Provide Support ID!",
});
}
// console.log(req.params.id);
const getSupport = await Support.findById(req.params.id);
if (!getSupport) {
return res.status(404).json({
success: false,
msg: "Support not Found!",
});
}
// Deleting Images From Cloudinary
for (let i = 0; i < getSupport.image.length; i++) {
await cloudinary.v2.uploader.destroy(getSupport.image[i].public_id);
}
//-------------------------//
const supportticket = await Support.findByIdAndDelete(req.params.id);
if (!supportticket) {
return res.status(404).json({ message: "Support Not Found" });
}
await supportticket.remove();
res.status(200).json({
success: true,
msg: "Support Deleted Successfully!!",
});
} catch (error) {
res.status(500).json({
success: false,
msg: error.message ? error.message : "Something went wrong!",
});
}
};
export const updateSupport = async (req, res) => {
try {
const { status, message } = req.body;
// console.log(req.params.id);
// Prepare an array for the images
// const jsonArray = JSON.parse(image);
// const AllImages = jsonArray.map(({ public_id, url }) => ({
// public_id,
// url,
// }));
// if (req.files && req.files.newImages) {
// const newuploadImages = Array.isArray(req.files.newImages)
// ? req.files.newImages
// : [req.files.newImages];
// const imagesLinks = [];
// for (let i = 0; i < newuploadImages.length; i++) {
// const result = await cloudinary.v2.uploader.upload(
// newuploadImages[i].tempFilePath,
// {
// folder: "smellica/product",
// }
// );
// imagesLinks.push({
// public_id: result.public_id,
// url: result.secure_url,
// });
// }
// Combine the existing images and the newly uploaded images
// const updatedImages = [...AllImages, ...imagesLinks];
// Perform the product update
// Find the support ticket by ID
const supportTicket = await Support.findOne({ ticketId: req.params.id });
// Check if the support ticket exists
if (!supportTicket) {
return res.status(404).json({
success: false,
msg: "Support ticket not found",
});
}
// Update the support ticket fields
if (status) {
supportTicket.status = status;
}
if (message) {
const newMessage = {
message: message.message,
user: message.user,
replyDate: message.replyDate, // Add a timestamp to the message object
};
supportTicket.message.push(newMessage);
// Update the last reply to the timestamp of the new message if the user is admin
if (message.user === "admin") {
supportTicket.lastreply = newMessage.replyDate;
}
}
// Save the updated support ticket
const updatedSupportTicket = await supportTicket.save();
return res.status(200).json({
success: true,
updatedSupportTicket,
});
} catch (error) {
// Handle errors
// console.error(error);
res.status(500).json({
success: false,
msg: error.message ? error.message : "Something went wrong!",
});
}
};
export const deleteImageFromCloudinary = async (req, res) => {
const { public_id } = req.params;
try {
if (!public_id) {
return res.status(400).json({
success: false,
msg: "Please Provide Product ID!",
});
}
const response = await cloudinary.v2.uploader.destroy(public_id);
if (response) {
res.status(200).json({
success: true,
msg: "CustomerSupport Deleted Successfully!!",
});
}
} catch (error) {
res.status(500).json({
success: false,
msg: error.message ? error.message : "Something went wrong!",
});
}
};

View File

@ -0,0 +1,67 @@
import mongoose from "mongoose";
const { Schema, model } = mongoose;
const supportSchema = new Schema(
{
ticketId: {
type: String,
required: true,
unique: true,
},
addedBy: {
type: Schema.Types.ObjectId,
ref: "User",
required: true,
},
subject: {
type: String,
required: true,
},
description: {
type: String,
maxLength: [100, "description cannot exceed 100 characters"],
required: [true, "Please Enter product Description"],
},
createdOn: {
type: String,
},
lastreply: {
type: String,
},
status: {
type: String,
enum: ["Open", "Close"],
default: "Open",
},
image: [
{
public_id: {
type: String,
// required: true,
},
url: {
type: String,
// required: true,
},
},
],
message: [
{
message: {
type: String,
default: "",
},
user: {
type: String,
enum: ["admin", "user"],
default: "user",
},
replyDate: {
type: String,
},
},
],
},
{ timestamps: true, versionKey: false }
);
export const Support = model("Support", supportSchema);

View File

@ -0,0 +1,32 @@
import bodyParser from "body-parser";
import { createSupport, deleteImageFromCloudinary, deleteSupport, getAllSupportTicket, getAllSupportTicketofuser, getOneSupportTicket, updateSupport } from "./supportController.js";
import { isAuthenticatedUser, authorizeRoles } from "../../middlewares/auth.js";
import express from "express";
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("/support/create/").post(isAuthenticatedUser,createSupport);
router.route("/support/getAll/").get(isAuthenticatedUser, authorizeRoles("admin"),getAllSupportTicket);
router.route("/support/userticket/").get(isAuthenticatedUser,getAllSupportTicketofuser);
router
.route("/support/delete/:id")
.delete( deleteSupport);
router.route("/support/getOne/:id").get(isAuthenticatedUser, getOneSupportTicket);
router
.route("/support/update/:id")
.patch(isAuthenticatedUser, updateSupport);
router
.route("/support/deleteImage/jatinMor/CustomerSupport/:public_id")
.delete(
isAuthenticatedUser,
authorizeRoles("admin"),
deleteImageFromCloudinary
);
// ---------------------------------------------------------
export default router;

View File

@ -3,7 +3,7 @@ import { Testimonial } from "./TestimonialModel.js";
export const AddNewTestimonial = async (req, res) => { export const AddNewTestimonial = async (req, res) => {
try { try {
if (!req?.user) return res.status(400).json({ message: "please login !" }); if (!req?.user) return res.status(400).json({ message: "please login !" });
// console.log(req?.user) // console.log(req?.user);
if (req.files) { if (req.files) {
let getImg = req.files.image; let getImg = req.files.image;
@ -36,8 +36,6 @@ export const AddNewTestimonial = async (req, res) => {
export const FindAllTestimonial = async (req, res) => { export const FindAllTestimonial = async (req, res) => {
try { try {
if (!req?.user) return res.status(400).json({ message: "please login !" });
// console.log(req?.user)
const testimonial = await Testimonial.find().sort({ createdAt: -1 }); const testimonial = await Testimonial.find().sort({ createdAt: -1 });
if (testimonial) { if (testimonial) {
@ -68,6 +66,7 @@ export const FindOneTestimonial = async (req, res) => {
return res.status(400).json({ message: "please give ID !" }); return res.status(400).json({ message: "please give ID !" });
const testimonial = await Testimonial.findById(req.params.id); const testimonial = await Testimonial.findById(req.params.id);
// console.log(testimonial);
if (testimonial) { if (testimonial) {
return res.status(200).json({ return res.status(200).json({
success: true, success: true,
@ -82,3 +81,125 @@ export const FindOneTestimonial = async (req, res) => {
}); });
} }
}; };
// 3.update testimonials
export const updatetesTimonial = async (req, res) => {
try {
// Check if the user is authenticated
if (!req.user) {
return res.status(400).json({ message: "Please login!" });
}
// Destructure request body
const { name, company, testimonial } = req.body;
// Get the authenticated user's ID
const userId = req.user._id;
// Prepare an object for the updated testimonial data
const updatedTestimonialData = {
name,
company,
testimonial,
user: userId, // Assign the authenticated user's ID to the testimonial's user field
};
// Check if files are uploaded
if (req.files && req.files.image) {
// If image file is uploaded, upload it to cloudinary
const uploadedImage = req.files.image;
const result = await cloudinary.v2.uploader.upload(
uploadedImage.tempFilePath,
{
folder: "GetSygnal/Testimonial",
}
);
// Prepare the image object with public_id and url
const image = {
public_id: result.public_id,
url: result.secure_url,
};
// Assign the uploaded image to the testimonial's image field
updatedTestimonialData.image = image;
}
// console.log(updatedTestimonialData);
// Update the testimonial in the database
const modifiedTestimonial = await Testimonial.findOneAndUpdate(
{ _id: req.params.id },
{ $set: updatedTestimonialData },
{ new: true }
);
return res.status(200).json({
success: true,
ModifyTestimonial: modifiedTestimonial,
});
} catch (error) {
res.status(500).json({
success: false,
msg: error.message ? error.message : "Something went wrong!",
});
}
};
export const deleteImageFromCloudinary = async (req, res) => {
const { public_id } = req.params;
try {
if (!public_id) {
return res.status(400).json({
success: false,
msg: "Please Provide Product ID!",
});
}
const response = await cloudinary.v2.uploader.destroy(public_id);
if (response) {
res.status(200).json({
success: true,
msg: "Product Deleted Successfully!!",
});
}
} catch (error) {
res.status(500).json({
success: false,
msg: error.message ? error.message : "Something went wrong!",
});
}
};
//delete one Product
export const deleteTestimonial = async (req, res) => {
try {
if (!req?.user) return res.status(400).json({ message: "please login !" });
// console.log(req?.user)
if (!req.params.id)
return res.status(400).json({ message: "please give ID !" });
// console.log(req.params.id)
const gettestimonial = await Testimonial.findById(req.params.id);
// console.log(gettestimonial)
if (!gettestimonial) {
return res
.status(404)
.json({ success: false, msg: "Testimonial not Found!" });
}
// Deleting Images From Cloudinary
await cloudinary.v2.uploader.destroy(gettestimonial.image.public_id);
//-------------------------//
const testimonial = await Testimonial.findByIdAndDelete(req.params.id);
if (!testimonial) {
return res.status(404).json({ message: "Testimonial Not Found" });
}
await testimonial.remove();
res
.status(200)
.json({ success: true, msg: "Testimonial Deleted Successfully!!" });
} catch (error) {
res.status(500).json({
success: false,
msg: error.message ? error.message : "Something went wrong!",
});
}
};

View File

@ -4,6 +4,9 @@ import {
AddNewTestimonial, AddNewTestimonial,
FindAllTestimonial, FindAllTestimonial,
FindOneTestimonial, FindOneTestimonial,
deleteImageFromCloudinary,
deleteTestimonial,
updatetesTimonial,
} from "./TestimonialController.js"; } from "./TestimonialController.js";
const router = express.Router(); const router = express.Router();
@ -11,9 +14,19 @@ const router = express.Router();
router.route("/new").post(isAuthenticatedUser, AddNewTestimonial); router.route("/new").post(isAuthenticatedUser, AddNewTestimonial);
router router
.route("/getAll") .route("/getAll")
.get(isAuthenticatedUser, authorizeRoles("admin"), FindAllTestimonial); .get(FindAllTestimonial);
router.route("/getOne/:id").get(isAuthenticatedUser, FindOneTestimonial); router.route("/getOne/:id").get(isAuthenticatedUser, FindOneTestimonial);
router
// router.route("/product/getAll/").get(getAllProduct) .route("/delete/:id")
.delete(isAuthenticatedUser, authorizeRoles("admin"), deleteTestimonial);
router
.route("/update/:id")
.patch(isAuthenticatedUser, authorizeRoles("admin"), updatetesTimonial);
router
.route("/deleteImage/GetSygnal/Testimonial/:public_id")
.delete(
isAuthenticatedUser,
authorizeRoles("admin"),
deleteImageFromCloudinary
);
export default router; export default router;