This commit is contained in:
Sibunnayak 2024-09-18 20:14:50 +05:30
commit ec4284bfc4
14 changed files with 478 additions and 13 deletions

View File

@ -1,5 +1,6 @@
import SalesCoOrdinator from "../resources/SalesCoOrdinators/SalesCoOrdinatorModel.js";
import TerritoryManager from "../resources/TerritoryManagers/TerritoryManagerModel.js";
import User from "../resources/user/userModel.js";
import { sendPushNotification } from "./sendPushNotification.js";
export const rejectKYC = async (userId, title, message) => {
@ -25,3 +26,24 @@ export const rejectKYC = async (userId, title, message) => {
console.error("No FCM token found for user:", userId);
}
};
export const createKYC = async (userId, title, message) => {
// Try to find the user in SalesCoordinator model
console.log(userId);
let user = await User.findById(userId);
console.log(user);
// Get the user's FCM token
const userToken = user ? user.fcm_token : null;
// const userToken =
// "dRnjl8F3S8GA6_BnBfloWZ:APA91bFvuiA4pEQr03Kymqtw2N207VDHwzLlfz_OPWzhTtdAAWmPLF8cQSx0WYmiaL9g-PIbzvGrmzDzxNiyq58w9Gws6p2tDlDeqycqU17W74gi36xkGSUqlzNiFoTiDDNp7OFDdVPK";
console.log(userToken);
if (userToken) {
// Send the push notification
// const message = `Your KYC has been rejected. Reason: ${reason}`;
await sendPushNotification(userToken, title, message);
console.log("sent to device ");
} else {
console.error("No FCM token found for user:", userId);
}
};

6
app.js
View File

@ -197,6 +197,8 @@ import SalesRoute from "./resources/Sales/SalesRoute.js";
import PdOrderRoute from './resources/PD_Orders/pdOrderRoute.js'
import RDOrderRoute from "./resources/RD_Ordes/rdOrderRoutes.js"
import TaskRoute from "./resources/Task/TaskRoute.js";
// visit RD and PD
import VisitRDandPDRoute from "./resources/VisitRD&PD/VisitRD&PDRoute.js";
@ -276,8 +278,10 @@ app.use("/api/inventory", InventoryRoute);
app.use("/api/sales", SalesRoute);
//Task
app.use("/api/task", TaskRoute);
// RD Rotuts
// RD Rotuts auth
app.use("/api",RDRoute)
// RD Order routes
app.use("/api",RDOrderRoute)
// visit RD and PD
app.use("/api", VisitRDandPDRoute);
//config specialty

View File

@ -12,6 +12,7 @@ export const isAuthenticatedRD = async (req, res, next) => {
});
}
const getToken = req.headers;
console.log(getToken);
// console.log(getToken);
//remove Bearer from token
const fronttoken = getToken.authorization.slice(7);
@ -23,8 +24,8 @@ export const isAuthenticatedRD = async (req, res, next) => {
message: "incorrect token",
});
}
// console.log(frontdecoded);
const fuser = await RetailDistributor.findById(frontdecoded.id);
console.log(frontdecoded);
const fuser = await RetailDistributor.findById(frontdecoded._id);
// console.log(fuser);
req.user = fuser;

View File

@ -2,7 +2,7 @@ import mongoose from "mongoose";
import cloudinary from "../../Utils/cloudinary.js";
import { KYC } from "./KycModel.js";
import User from "../user/userModel.js";
import { rejectKYC } from "../../Utils/rejectKyc.js";
import { createKYC, rejectKYC } from "../../Utils/rejectKyc.js";
import SalesCoOrdinator from "../SalesCoOrdinators/SalesCoOrdinatorModel.js";
import TerritoryManager from "../TerritoryManagers/TerritoryManagerModel.js";
import { Notification } from "../Notification/notificationModal.js";
@ -105,6 +105,19 @@ export const createKyc = async (req, res) => {
notes,
});
if (principal_distributer) {
await createKYC(
kyc.principal_distributer,
"KYC Created",
`${trade_name} sent request to approve the KYC .`
);
await Notification.create({
title: "KYC Created",
msg: `KYC created for the trade name ${name}`,
kyc_ref: kyc._id,
added_for: kyc.principal_distributer,
});
}
if (kyc) {
return res
.status(201)
@ -573,4 +586,3 @@ export const saveFCMTokenForTM = async (req, res) => {
res.status(500).send("Internal Server Error");
}
};

View File

@ -3,6 +3,7 @@ import { Notification } from "./notificationModal.js";
export const getNotification = async (req, res) => {
try {
// Ensure req.user._id is defined and valid
console.log("req came here ");
if (!req.user || !req.user._id) {
return res.status(400).json({ return_message: "Invalid user ID" });
}
@ -18,7 +19,7 @@ export const getNotification = async (req, res) => {
.json({ return_message: "Fetched notifications", notifications });
}
return res.status(404).json({ return_message: "No notifications found" });
return res.status(402).json({ return_message: "No notifications found" });
} catch (error) {
return res
.status(500)

View File

@ -2,6 +2,7 @@ import express from "express";
import { isAuthenticatedSalesCoOrdinator } from "../../middlewares/SalesCoOrdinatorAuth.js";
import { getNotification } from "./notificationController.js";
import { isAuthenticatedTerritoryManager } from "../../middlewares/TerritoryManagerAuth.js";
import { isAuthenticatedUser } from "../../middlewares/auth.js";
const router = express.Router();
@ -21,4 +22,6 @@ router
.route("/get-notification-tm/:id")
.get(isAuthenticatedTerritoryManager, getNotification);
router.route("/get-notification-pd").get(isAuthenticatedUser, getNotification);
export default router;

View File

@ -0,0 +1,194 @@
import RetailDistributor from "../RetailDistributor/RetailDistributorModel.js";
import { RdOrder } from "./rdOrderModal.js";
// Controller to create a new order by RD
export const createOrderRD = async (req, res) => {
try {
const {
paymentMode,
shipTo,
billTo,
orderItems,
subtotal,
gstTotal,
grandTotal,
} = req.body;
const rdId = req.user._id;
// Fetch the Retail Distributor (RD) to find the associated Principal Distributor (PD)
const rd = await RetailDistributor.findById(rdId).populate(
"principal_distributer"
);
if (!rd) {
return res.status(404).json({ message: "Retail Distributor not found" });
}
const pdId = rd.principal_distributer._id; // Get the associated PD
// Create the order
const newOrder = new RdOrder({
paymentMode,
shipTo,
billTo,
orderItem: orderItems.map((item) => ({
productId: item._id,
SKU: item.SKU,
name: item.name,
categoryName: item.category.categoryName, // Store category name
brandName: item.brand.brandName, // Store brand name
price: item.price,
GST: item.GST,
HSN_Code: item.HSN_Code,
description: item.description,
image: item.image,
quantity: item.count,
})),
subtotal,
gstTotal,
grandTotal,
addedBy: rdId, // The RD who placed the order (Retail Distributor)
pd: pdId, // Reference to the PD associated with the RD
});
await newOrder.save();
res
.status(201)
.json({ message: "Order placed successfully", order: newOrder });
} catch (error) {
res.status(500).json({ message: "Server error", error });
}
};
export const getPlacedOrdersForRD = async (req, res) => {
try {
const rdId = req.user?._id; // Assuming the Retail Distributor's ID is obtained from the authenticated request
if (!rdId) {
return res.status(401).json({ message: "Unauthorized access" });
}
// Extract page and limit from query parameters, with default values
const page = parseInt(req.query.page, 10) || 1;
const limit = parseInt(req.query.limit, 10) || 5;
// Calculate how many documents to skip for pagination
const skip = (page - 1) * limit;
// Fetch total count of orders for this RD (for pagination purposes)
const totalOrders = await RdOrder.countDocuments({ addedBy: rdId });
// Fetch orders for the logged-in RD
const placedOrders = await RdOrder.find({ addedBy: rdId })
.sort({ createdAt: -1 }) // Sort by creation date, newest first
.skip(skip) // Skip documents for pagination
.limit(limit); // Limit number of documents returned
if (!placedOrders || placedOrders.length === 0) {
return res
.status(404)
.json({ message: "No orders found for this Retail Distributor" });
}
// Send the paginated order list and total count of orders
res.status(200).json({ placedOrders, totalOrders });
} catch (error) {
console.error(error);
res.status(500).json({ message: "Server error", error });
}
};
export const getSinglePlacedOrderForRD = async (req, res) => {
try {
const rdId = req.user?._id;
if (!rdId) {
return res.status(401).json({ message: "Unauthorized access" });
} // Assuming the Retail Distributor's ID is obtained from the authenticated request
const orderId = req.params.id; // Assuming the order ID is passed in the URL as a parameter
if (!rdId) {
return res.status(401).json({ message: "Unauthorized access" });
}
if (!orderId) {
return res.status(400).json({ message: "Order ID is required" });
}
// Fetch the specific order for the logged-in RD
const order = await RdOrder.findOne({ _id: orderId, addedBy: rdId });
if (!order) {
return res
.status(404)
.json({ message: "Order not found for this Retail Distributor" });
}
// Send the single order document
res.status(200).json({ singleOrder: order });
} catch (error) {
console.error(error);
res.status(500).json({ message: "Server error", error });
}
};
export const getPlacedOrdersForPD = async (req, res) => {
try {
const pdId = req.user?._id;
if (!pdId) {
return res.status(401).json({ return_message: "Unauthorized access " });
}
// Extract page and limit from query parameters
const page = parseInt(req.query.page, 10) || 1;
const limit = parseInt(req.query.limit, 10) || 5;
// Calculate the number of documents to skip
const skip = (page - 1) * limit;
const totalOrders = await RdOrder.countDocuments({ pd: pdId });
// Fetch all orders where the PD is associated with the order
const plcaedOrders = await RdOrder.find({ pd: pdId })
.sort({ createdAt: -1 })
.skip(skip)
.limit(limit);
if (!plcaedOrders || plcaedOrders.length === 0) {
return res
.status(404)
.json({ message: "No orders found for this Principal Distributor" });
}
res.status(200).json({ plcaedOrders, totalOrders });
} catch (error) {
console.error(error);
res.status(500).json({ message: "Server error", error });
}
};
export const getSinglePlacedOrderForPD = async (req, res) => {
try {
const pdId = req.user?._id; // Assuming the Principal Distributor's ID is obtained from the authenticated request
const orderId = req.params.id; // Assuming the order ID is passed in the URL as a parameter
if (!pdId) {
return res.status(401).json({ message: "Unauthorized access" });
}
if (!orderId) {
return res.status(400).json({ message: "Order ID is required" });
}
// Fetch the specific order for the logged-in PD
const order = await RdOrder.findOne({ _id: orderId, pd: pdId });
if (!order) {
return res
.status(404)
.json({ message: "Order not found for this Principal Distributor" });
}
// Send the single order document
res.status(200).json({ singleOrder: order });
} catch (error) {
console.error(error);
res.status(500).json({ message: "Server error", error });
}
};

View File

@ -0,0 +1,156 @@
import mongoose, { Schema } from "mongoose";
import { nanoid } from "nanoid"; // To generate unique 6-char IDs
const orderItemSchema = new Schema({
productId: {
type: Schema.Types.ObjectId,
ref: "Product",
required: true,
},
SKU: {
type: String,
required: true,
},
name: {
type: String,
required: true,
},
categoryName: {
type: String, // Directly store category name
required: true,
},
brandName: {
type: String, // Directly store brand name
required: true,
},
price: {
type: Number,
required: true,
},
GST: {
type: Number,
required: true,
},
HSN_Code: {
type: Number,
required: true,
},
description: {
type: String,
},
image: [
{
public_id: String,
url: String,
},
],
quantity: {
type: Number,
required: true,
default: 1,
},
});
const StatusHistorySchema = new mongoose.Schema({
status: {
type: String,
enum: ["new", "dispatched", "cancelled", "processing", "delivered"], // Ensure this matches your status enum
required: true,
},
timestamp: {
type: Date,
default: Date.now,
},
});
const rdOrderSchema = new Schema(
{
paymentMode: {
type: String,
enum: ["cheque", "online-transfer", "credit"],
required: true,
},
shipTo: {
type: String,
required: true,
},
billTo: {
type: String,
required: true,
},
orderItem: [orderItemSchema],
subtotal: {
type: Number,
required: true,
},
gstTotal: {
type: Number,
required: true,
},
grandTotal: {
type: Number,
required: true,
},
status: {
type: String,
enum: ["new", "dispatched", "cancelled", "processing", "delivered"],
default: "new",
},
statusUpdatedAt: {
type: Date,
default: Date.now,
},
uniqueId: {
type: String,
unique: true,
default: () => nanoid(6), // Generates a 6-character unique ID
},
addedBy: {
type: Schema.Types.ObjectId,
ref: "RetailDistributor", // Reference to the RD placing the order
required: true,
},
pd: {
type: mongoose.Schema.Types.ObjectId,
ref: "User", // Reference to the PD associated with the RD
required: true,
},
status_timeline: {
new: { type: Date },
paid: { type: Date },
processing: { type: Date },
dispatched: { type: Date },
delivered: { type: Date },
cancelled: { type: Date },
returned: { type: Date },
},
iscancelled: {
type: Boolean,
default: false,
},
order_Cancelled_Reason: {
type: String,
},
courier_name: { type: String },
courier_tracking_id: { type: String },
isDelivered: { type: Boolean, required: true, default: false },
DeliveredDate: { type: String, default: "" },
statusHistory: [StatusHistorySchema], // Add this field to store the status history
},
{ timestamps: true }
);
// Middleware to update the statusUpdatedAt field whenever status changes
rdOrderSchema.pre("save", function (next) {
if (this.isModified("status")) {
this.statusUpdatedAt = Date.now();
// Add the new status and timestamp to statusHistory
this.statusHistory.push({
status: this.status,
timestamp: this.statusUpdatedAt,
});
}
next();
});
export const RdOrder = mongoose.model("RdOrder", rdOrderSchema);

View File

@ -0,0 +1,28 @@
import express from "express";
import {
createOrderRD,
getPlacedOrdersForPD,
getPlacedOrdersForRD,
getSinglePlacedOrderForPD,
getSinglePlacedOrderForRD,
} from "./rdOrderController.js";
import { isAuthenticatedRD } from "../../middlewares/rdAuth.js";
import { isAuthenticatedUser } from "../../middlewares/auth.js";
const router = express.Router();
router.route("/rd-place-order").post(isAuthenticatedRD, createOrderRD);
router.route("/rd-place-order").get(isAuthenticatedRD, getPlacedOrdersForRD);
router
.route("/rd-place-order/:id")
.get(isAuthenticatedRD, getSinglePlacedOrderForRD);
// routes for the PD
router
.route("/pd-get-all-place-order")
.get(isAuthenticatedUser, getPlacedOrdersForPD);
router
.route("/pd-get-all-place-order/:id")
.get(isAuthenticatedUser, getSinglePlacedOrderForPD);
export default router;

View File

@ -78,10 +78,18 @@ const RetailDistributorSchema = new mongoose.Schema(
RetailDistributorSchema.pre("save", function (next) {
// Only set defaults if the document is new (not yet saved)
if (this.isNew) {
if (!this.mappedSC && this.userType === "SalesCoOrdinator" && this.addedBy) {
if (
!this.mappedSC &&
this.userType === "SalesCoOrdinator" &&
this.addedBy
) {
this.mappedSC = this.addedBy;
}
if (!this.mappedTM && this.userType === "TerritoryManager" && this.addedBy) {
if (
!this.mappedTM &&
this.userType === "TerritoryManager" &&
this.addedBy
) {
this.mappedTM = this.addedBy;
}
}
@ -106,7 +114,7 @@ RetailDistributorSchema.pre("save", function (next) {
// JWT TOKEN
RetailDistributorSchema.methods.getJWTToken = function () {
return jwt.sign({ id: this._id }, process.env.JWT_SECRET, {
return jwt.sign({ _id: this._id }, process.env.JWT_SECRET, {
expiresIn: "1d", // Token will expire in 1 day
});
};

View File

@ -1320,3 +1320,30 @@ export const updateEmployeeById = catchAsyncErrors(async (req, res, next) => {
});
}
});
export const saveFCMTokenForUser = async (req, res) => {
const { fcmToken } = req.body;
const userId = req.user._id;
try {
// Fetch the current FCM token for the user
const user = await User.findById(userId);
if (!user) {
return res.status(404).send("User not found");
}
// Check if the new FCM token is different from the current one
if (user.fcm_token && user.fcm_token === fcmToken) {
return res.status(200).send("FCM Token is already up to date");
}
// Update the FCM token
user.fcm_token = fcmToken;
await user.save();
res.status(200).send("FCM Token saved successfully");
} catch (error) {
console.error("Error saving FCM Token:", error);
res.status(500).send("Internal Server Error");
}
};

View File

@ -87,6 +87,10 @@ const userSchema = new mongoose.Schema(
accessTo: {},
resetPasswordToken: String,
resetPasswordExpire: Date,
fcm_token: {
type: String,
default: null,
},
},
{ timestamps: true }
);
@ -123,7 +127,10 @@ userSchema.methods.comparePassword = async function (password) {
// Generating Reset Token
userSchema.methods.getResetPasswordToken = function () {
const resetToken = crypto.randomBytes(20).toString("hex");
this.resetPasswordToken = crypto.createHash("sha256").update(resetToken).digest("hex");
this.resetPasswordToken = crypto
.createHash("sha256")
.update(resetToken)
.digest("hex");
this.resetPasswordExpire = Date.now() + 15 * 60 * 1000; // 15 minutes
return resetToken;
};

View File

@ -21,6 +21,7 @@ import {
unmappedSCinPrincipalDistributor,
mappedbySC,
getAllPrincipalDistributorbyscId,
saveFCMTokenForUser,
} from "./userController.js";
import { isAuthenticatedUser, authorizeRoles } from "../../middlewares/auth.js";
@ -44,7 +45,7 @@ router
authorizeRoles("admin"),
uploadPrincipaldistributors
);
//mapping start
//mapping start
router
.route("/admin/users")
.get(isAuthenticatedUser, authorizeRoles("admin", "Employee"), getAllUser);
@ -55,7 +56,7 @@ router
authorizeRoles("admin"),
getAllPrincipalDistributorbytmId
);
router
router
.route("/getbySCId/:id")
.get(
isAuthenticatedUser,
@ -123,5 +124,6 @@ router
router.route("/user/password/update").put(isAuthenticatedUser, updatePassword);
router.route("/user/update/profile").put(isAuthenticatedUser, updateProfile);
router.route("/user/fcm-token").post(isAuthenticatedUser, saveFCMTokenForUser);
export default router;

View File

@ -4,7 +4,7 @@ import app from "./app.js";
import connectDatabase from "./database/db.js";
import cloudinary from "cloudinary";
import cron from "node-cron";
import {updateOverdueTasks} from "./resources/Task/TaskController.js ";
import { updateOverdueTasks } from "./resources/Task/TaskController.js ";
// Connecting to database
connectDatabase();