task updated and product manual completed
This commit is contained in:
parent
768fc3c77f
commit
059e39e13c
3
app.js
3
app.js
@ -132,6 +132,7 @@ app.use(
|
|||||||
//auth
|
//auth
|
||||||
import user from "./resources/user/userRoute.js";
|
import user from "./resources/user/userRoute.js";
|
||||||
import ProductRouter from "./resources/Products/ProductRoute.js";
|
import ProductRouter from "./resources/Products/ProductRoute.js";
|
||||||
|
import ProductManualRouter from "./resources/ProductMannual/ProductManualRoute.js";
|
||||||
//Businesses
|
//Businesses
|
||||||
// import BusinessRoute from "./resources/Businesses/BusinessRoute.js";
|
// import BusinessRoute from "./resources/Businesses/BusinessRoute.js";
|
||||||
|
|
||||||
@ -199,6 +200,8 @@ app.use("/api/v1", user);
|
|||||||
|
|
||||||
//Product
|
//Product
|
||||||
app.use("/api", ProductRouter);
|
app.use("/api", ProductRouter);
|
||||||
|
//Product Manual
|
||||||
|
app.use("/api/productmanual", ProductManualRouter);
|
||||||
//businesses
|
//businesses
|
||||||
// app.use("/api/businesses", BusinessRoute);
|
// app.use("/api/businesses", BusinessRoute);
|
||||||
// Design
|
// Design
|
||||||
|
Binary file not shown.
181
resources/ProductMannual/ProductManualController.js
Normal file
181
resources/ProductMannual/ProductManualController.js
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
import ProductManual from "./ProductManualModel.js";
|
||||||
|
import cloudinary from "../../Utils/cloudinary.js";
|
||||||
|
|
||||||
|
// Create a new product manual
|
||||||
|
export const createProductManual = async (req, res) => {
|
||||||
|
const { title } = req.body;
|
||||||
|
|
||||||
|
try {
|
||||||
|
let productManualDetails;
|
||||||
|
|
||||||
|
// Check if a file is provided
|
||||||
|
if (req.files && req.files.product_manual) {
|
||||||
|
const pdfFile = req.files.product_manual;
|
||||||
|
const result = await cloudinary.v2.uploader.upload(pdfFile.tempFilePath, {
|
||||||
|
folder: "chemiNova/ProductManuals",
|
||||||
|
resource_type: "raw", // For PDF or other non-image files
|
||||||
|
});
|
||||||
|
|
||||||
|
productManualDetails = {
|
||||||
|
public_id: result.public_id,
|
||||||
|
url: result.secure_url,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the product manual
|
||||||
|
const productManual = await ProductManual.create({
|
||||||
|
title,
|
||||||
|
product_manual: productManualDetails,
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(201).json({
|
||||||
|
success: true,
|
||||||
|
productManual,
|
||||||
|
message: "Product manual created successfully",
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error creating product manual:", error);
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
message: error.message || "Internal server error",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get all product manuals
|
||||||
|
export const getAllProductManuals = async (req, res) => {
|
||||||
|
try {
|
||||||
|
const productManuals = await ProductManual.find();
|
||||||
|
res.status(200).json({
|
||||||
|
success: true,
|
||||||
|
productManuals,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching product manuals:", error);
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
message: error.message || "Internal server error",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get a single product manual by ID
|
||||||
|
export const getSingleProductManual = async (req, res) => {
|
||||||
|
const { id } = req.params;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const productManual = await ProductManual.findById(id);
|
||||||
|
|
||||||
|
if (!productManual) {
|
||||||
|
return res.status(404).json({
|
||||||
|
success: false,
|
||||||
|
message: "Product manual not found",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
success: true,
|
||||||
|
productManual,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching product manual:", error);
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
message: error.message || "Internal server error",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update a product manual
|
||||||
|
export const updateProductManual = async (req, res) => {
|
||||||
|
const { id } = req.params;
|
||||||
|
const { title } = req.body;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const productManual = await ProductManual.findById(id);
|
||||||
|
|
||||||
|
if (!productManual) {
|
||||||
|
return res.status(404).json({
|
||||||
|
success: false,
|
||||||
|
message: "Product manual not found",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if a new file is provided
|
||||||
|
if (req.files && req.files.product_manual) {
|
||||||
|
// Delete the old file from Cloudinary
|
||||||
|
if (productManual.product_manual.public_id) {
|
||||||
|
await cloudinary.v2.uploader.destroy(productManual.product_manual.public_id, {
|
||||||
|
resource_type: "raw",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upload the new file to Cloudinary
|
||||||
|
const pdfFile = req.files.product_manual;
|
||||||
|
const result = await cloudinary.v2.uploader.upload(pdfFile.tempFilePath, {
|
||||||
|
folder: "chemiNova/ProductManuals",
|
||||||
|
resource_type: "raw",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update the product manual details
|
||||||
|
productManual.product_manual = {
|
||||||
|
public_id: result.public_id,
|
||||||
|
url: result.secure_url,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the title
|
||||||
|
productManual.title = title || productManual.title;
|
||||||
|
|
||||||
|
await productManual.save();
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
success: true,
|
||||||
|
productManual,
|
||||||
|
message: "Product manual updated successfully",
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error updating product manual:", error);
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
message: error.message || "Internal server error",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Delete a product manual
|
||||||
|
export const deleteProductManual = async (req, res) => {
|
||||||
|
const { id } = req.params;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const productManual = await ProductManual.findById(id);
|
||||||
|
|
||||||
|
if (!productManual) {
|
||||||
|
return res.status(404).json({
|
||||||
|
success: false,
|
||||||
|
message: "Product manual not found",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the file from Cloudinary
|
||||||
|
if (productManual.product_manual.public_id) {
|
||||||
|
await cloudinary.v2.uploader.destroy(productManual.product_manual.public_id, {
|
||||||
|
resource_type: "raw",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the product manual from the database
|
||||||
|
await ProductManual.findByIdAndDelete(id);
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
success: true,
|
||||||
|
message: "Product manual deleted successfully",
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error deleting product manual:", error);
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
message: error.message || "Internal server error",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
25
resources/ProductMannual/ProductManualModel.js
Normal file
25
resources/ProductMannual/ProductManualModel.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import mongoose from "mongoose";
|
||||||
|
|
||||||
|
const ProductManualSchema = new mongoose.Schema(
|
||||||
|
{
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
product_manual: {
|
||||||
|
public_id: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ timestamps: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
const ProductManual = mongoose.model("ProductManual", ProductManualSchema);
|
||||||
|
|
||||||
|
export default ProductManual;
|
90
resources/ProductMannual/ProductManualRoute.js
Normal file
90
resources/ProductMannual/ProductManualRoute.js
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
import express from "express";
|
||||||
|
import {
|
||||||
|
createProductManual,
|
||||||
|
getAllProductManuals,
|
||||||
|
getSingleProductManual,
|
||||||
|
updateProductManual,
|
||||||
|
deleteProductManual,
|
||||||
|
} from "./ProductManualController.js";
|
||||||
|
import {
|
||||||
|
isAuthenticatedUser,
|
||||||
|
authorizeRoles,
|
||||||
|
} from "../../middlewares/auth.js";
|
||||||
|
import { isAuthenticatedSalesCoOrdinator } from "../../middlewares/SalesCoOrdinatorAuth.js";
|
||||||
|
import { isAuthenticatedTerritoryManager } from "../../middlewares/TerritoryManagerAuth.js";
|
||||||
|
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
// Route for creating a product manual (Only Admin can create)
|
||||||
|
router
|
||||||
|
.route("/create")
|
||||||
|
.post(isAuthenticatedUser, authorizeRoles("admin"), createProductManual);
|
||||||
|
|
||||||
|
// Route for getting all product manuals (accessible to Sales Coordinator, Territory Manager, and Admin)
|
||||||
|
router.route("/").get(
|
||||||
|
(req, res, next) => {
|
||||||
|
// Allow access if the user is a sales coordinator, territory manager, or admin
|
||||||
|
isAuthenticatedSalesCoOrdinator(req, res, (err) => {
|
||||||
|
if (err) {
|
||||||
|
isAuthenticatedTerritoryManager(req, res, (err) => {
|
||||||
|
if (err) {
|
||||||
|
isAuthenticatedUser(req, res, (err) => {
|
||||||
|
if (err || !["admin"].includes(req.user.role)) {
|
||||||
|
return res.status(403).json({
|
||||||
|
success: false,
|
||||||
|
message: "Access denied. Unauthorized role.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getAllProductManuals
|
||||||
|
);
|
||||||
|
|
||||||
|
// Route for getting a single product manual by ID (accessible to Sales Coordinator, Territory Manager, and Admin)
|
||||||
|
router.route("/:id").get(
|
||||||
|
(req, res, next) => {
|
||||||
|
// Allow access if the user is a sales coordinator, territory manager, or admin
|
||||||
|
isAuthenticatedSalesCoOrdinator(req, res, (err) => {
|
||||||
|
if (err) {
|
||||||
|
isAuthenticatedTerritoryManager(req, res, (err) => {
|
||||||
|
if (err) {
|
||||||
|
isAuthenticatedUser(req, res, (err) => {
|
||||||
|
if (err || !["admin"].includes(req.user.role)) {
|
||||||
|
return res.status(403).json({
|
||||||
|
success: false,
|
||||||
|
message: "Access denied. Unauthorized role.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getSingleProductManual
|
||||||
|
);
|
||||||
|
// Route to update a product manual by ID
|
||||||
|
router
|
||||||
|
.route("/update/:id")
|
||||||
|
.put(isAuthenticatedUser, authorizeRoles("admin"), updateProductManual);
|
||||||
|
|
||||||
|
// Route to delete a product manual by ID
|
||||||
|
router
|
||||||
|
.route("/delete/:id")
|
||||||
|
.delete(isAuthenticatedUser, authorizeRoles("admin"), deleteProductManual);
|
||||||
|
export default router;
|
||||||
|
// /api/productmanual
|
@ -12,6 +12,7 @@ export const assignTask = async (req, res) => {
|
|||||||
taskAssignedTo,
|
taskAssignedTo,
|
||||||
addedFor,
|
addedFor,
|
||||||
addedForId,
|
addedForId,
|
||||||
|
tradename,
|
||||||
} = req.body;
|
} = req.body;
|
||||||
|
|
||||||
const currentYear = new Date().getFullYear().toString().slice(-2);
|
const currentYear = new Date().getFullYear().toString().slice(-2);
|
||||||
@ -29,6 +30,7 @@ export const assignTask = async (req, res) => {
|
|||||||
taskAssignedBy: req.user._id,
|
taskAssignedBy: req.user._id,
|
||||||
addedFor,
|
addedFor,
|
||||||
addedForId,
|
addedForId,
|
||||||
|
tradename,
|
||||||
});
|
});
|
||||||
|
|
||||||
res.status(201).json({
|
res.status(201).json({
|
||||||
@ -73,8 +75,33 @@ export const getTasksByStatus = async (req, res) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
export const getTasksbytask = async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { task } = req.params;
|
||||||
|
|
||||||
|
// Validate the provided status
|
||||||
|
if (!["Visit RD/PD", "Update Sales Data", "Update Inventory Data", "Collect KYC"].includes(task)) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
message: "Invalid task type provided.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const tasks = await Task.find({
|
||||||
|
taskAssignedTo: req.user._id,
|
||||||
|
task: task,
|
||||||
|
}).sort({ createdAt: -1 });
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
success: true,
|
||||||
|
tasks,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
message: error.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
export const updateTaskStatus = async (req, res) => {
|
export const updateTaskStatus = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { taskId } = req.params;
|
const { taskId } = req.params;
|
||||||
|
@ -12,12 +12,12 @@ const TaskSchema = new mongoose.Schema(
|
|||||||
task: {
|
task: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
enum: ["Visit Retailers", "Update Sales Data", "Update Inventory Data", "Collect KYC"],
|
enum: ["Visit RD/PD", "Update Sales Data", "Update Inventory Data", "Collect KYC"],
|
||||||
},
|
},
|
||||||
note: {
|
note: {
|
||||||
type: String,
|
type: String,
|
||||||
required: function () {
|
required: function () {
|
||||||
return this.task === "Collect KYC";
|
return this.task === "Collect KYC" || this.task === "Visit RD/PD";
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
taskStatus: {
|
taskStatus: {
|
||||||
@ -60,6 +60,12 @@ const TaskSchema = new mongoose.Schema(
|
|||||||
return this.task === "Update Inventory Data";
|
return this.task === "Update Inventory Data";
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
tradename: {
|
||||||
|
type: String,
|
||||||
|
required: function () {
|
||||||
|
return this.task === "Update Inventory Data";
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{ timestamps: true }
|
{ timestamps: true }
|
||||||
);
|
);
|
||||||
|
@ -3,6 +3,7 @@ import {
|
|||||||
assignTask,
|
assignTask,
|
||||||
getTasksByStatus,
|
getTasksByStatus,
|
||||||
updateTaskStatus,
|
updateTaskStatus,
|
||||||
|
getTasksbytask,
|
||||||
} from "./TaskController.js";
|
} from "./TaskController.js";
|
||||||
import { isAuthenticatedSalesCoOrdinator } from "../../middlewares/SalesCoOrdinatorAuth.js";
|
import { isAuthenticatedSalesCoOrdinator } from "../../middlewares/SalesCoOrdinatorAuth.js";
|
||||||
import { isAuthenticatedTerritoryManager } from "../../middlewares/TerritoryManagerAuth.js";
|
import { isAuthenticatedTerritoryManager } from "../../middlewares/TerritoryManagerAuth.js";
|
||||||
@ -22,7 +23,11 @@ router.get(
|
|||||||
isAuthenticatedSalesCoOrdinator,
|
isAuthenticatedSalesCoOrdinator,
|
||||||
getTasksByStatus
|
getTasksByStatus
|
||||||
);
|
);
|
||||||
|
router.get(
|
||||||
|
"/task/type/:task",
|
||||||
|
isAuthenticatedSalesCoOrdinator,
|
||||||
|
getTasksbytask
|
||||||
|
);
|
||||||
// Route to update task status
|
// Route to update task status
|
||||||
router.put(
|
router.put(
|
||||||
"/update-task-status/:taskId",
|
"/update-task-status/:taskId",
|
||||||
|
@ -563,7 +563,19 @@ export const uploadPrincipaldistributors = async (req, res) => {
|
|||||||
uniqueId: item.uniqueId,
|
uniqueId: item.uniqueId,
|
||||||
});
|
});
|
||||||
await distributor.save();
|
await distributor.save();
|
||||||
|
await sendEmail({
|
||||||
|
to: distributor.email,
|
||||||
|
from: process.env.SEND_EMAIL_FROM,
|
||||||
|
subject: `Cheminova Account Created`,
|
||||||
|
html: `
|
||||||
|
Your Principal Distributor Account is created successfully.
|
||||||
|
<br/>Name: <strong>${distributor.name}</strong><br/>
|
||||||
|
<br/>Mobile Number: <strong>${distributor.phone}</strong><br/>
|
||||||
|
<br/>Password: <strong>${password}</strong><br/><br/>
|
||||||
|
<a href="${process.env.PD_APP_URL}/login">Click here to login</a><br/><br/>
|
||||||
|
If you have not requested this email, please ignore it.
|
||||||
|
`,
|
||||||
|
});
|
||||||
// Now create the address for the new user
|
// Now create the address for the new user
|
||||||
const addressData = {
|
const addressData = {
|
||||||
street: item.street,
|
street: item.street,
|
||||||
|
Loading…
Reference in New Issue
Block a user