Merge branch 'master' of https://github.com/cheminova2024/cheminova-api
This commit is contained in:
commit
24e84e7186
5
app.js
5
app.js
@ -189,7 +189,7 @@ import leave from "./resources/Leaves/LeaveRoute.js";
|
|||||||
import notification from "./resources/Notification/notificationRoute.js"
|
import notification from "./resources/Notification/notificationRoute.js"
|
||||||
//Inventory
|
//Inventory
|
||||||
import InventoryRoute from "./resources/Inventory/InventoryRoute.js";
|
import InventoryRoute from "./resources/Inventory/InventoryRoute.js";
|
||||||
|
import SalesRoute from "./resources/Sales/SalesRoute.js";
|
||||||
|
|
||||||
// PD Order place
|
// PD Order place
|
||||||
|
|
||||||
@ -268,7 +268,8 @@ app.use("/api",notification)
|
|||||||
app.use("/api",PdOrderRoute)
|
app.use("/api",PdOrderRoute)
|
||||||
//Inventory
|
//Inventory
|
||||||
app.use("/api/inventory", InventoryRoute);
|
app.use("/api/inventory", InventoryRoute);
|
||||||
|
// Sales
|
||||||
|
app.use("/api/sales", SalesRoute);
|
||||||
//Task
|
//Task
|
||||||
app.use("/api/task", TaskRoute);
|
app.use("/api/task", TaskRoute);
|
||||||
|
|
||||||
|
BIN
public/temp/tmp-1-1725337456945
Normal file
BIN
public/temp/tmp-1-1725337456945
Normal file
Binary file not shown.
BIN
public/temp/tmp-1-1725339783126
Normal file
BIN
public/temp/tmp-1-1725339783126
Normal file
Binary file not shown.
BIN
public/temp/tmp-2-1725337492515
Normal file
BIN
public/temp/tmp-2-1725337492515
Normal file
Binary file not shown.
BIN
public/temp/tmp-3-1725337576243
Normal file
BIN
public/temp/tmp-3-1725337576243
Normal file
Binary file not shown.
193
resources/Sales/SalesController.js
Normal file
193
resources/Sales/SalesController.js
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
import { Sales } from "./SalesModel.js";
|
||||||
|
import User from "../user/userModel.js";
|
||||||
|
import { KYC } from "../KYC/KycModel.js";
|
||||||
|
import ShippingAddress from "../ShippingAddresses/ShippingAddressModel.js";
|
||||||
|
import TerritoryManager from "../TerritoryManagers/TerritoryManagerModel.js";
|
||||||
|
import SalesCoordinator from "../SalesCoOrdinators/SalesCoOrdinatorModel.js";
|
||||||
|
import crypto from "crypto";
|
||||||
|
// Add Sales data
|
||||||
|
const parseDate = (dateStr) => {
|
||||||
|
const [day, month, year] = dateStr.split("/").map(Number);
|
||||||
|
// Create a UTC date object to ensure the correct date is stored
|
||||||
|
return new Date(Date.UTC(year, month - 1, day));
|
||||||
|
};
|
||||||
|
export const addSales = async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { products, addedFor, addedForId, tradename, date } = req.body;
|
||||||
|
const userId = req.user._id;
|
||||||
|
const userType = req.userType;
|
||||||
|
// console.log("req.user", req.user);
|
||||||
|
const currentYear = new Date().getFullYear().toString().slice(-2);
|
||||||
|
const randomChars = crypto.randomBytes(4).toString("hex").toUpperCase();
|
||||||
|
const uniqueId = `${currentYear}-${randomChars}`;
|
||||||
|
// console.log("uniqueId", uniqueId);
|
||||||
|
// Convert the date from DD/MM/YYYY string to Date object
|
||||||
|
const parsedDate = parseDate(date);
|
||||||
|
const newSales = new Sales({
|
||||||
|
userId,
|
||||||
|
userType,
|
||||||
|
addedFor,
|
||||||
|
addedForId,
|
||||||
|
products,
|
||||||
|
uniqueId,
|
||||||
|
tradename,
|
||||||
|
date: parsedDate,
|
||||||
|
});
|
||||||
|
// console.log("newSales", newSales);
|
||||||
|
await newSales.save();
|
||||||
|
res.status(201).json({
|
||||||
|
success: true,
|
||||||
|
message: "Sales added successfully",
|
||||||
|
data: newSales,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ success: false, message: "Server error", error });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getAllSales = async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { page = 1, show = 10, startDate, endDate, name } = req.query;
|
||||||
|
const query = {};
|
||||||
|
|
||||||
|
if (startDate && endDate) {
|
||||||
|
const start = new Date(startDate);
|
||||||
|
const end = new Date(endDate);
|
||||||
|
|
||||||
|
if (start.toDateString() === end.toDateString()) {
|
||||||
|
query.createdAt = {
|
||||||
|
$gte: start,
|
||||||
|
$lt: new Date(start).setDate(start.getDate() + 1),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
query.createdAt = {
|
||||||
|
$gte: start,
|
||||||
|
$lte: new Date(end).setDate(end.getDate() + 1),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else if (startDate && endDate === "") {
|
||||||
|
query.createdAt = {
|
||||||
|
$gte: new Date(startDate),
|
||||||
|
$lte: new Date(),
|
||||||
|
};
|
||||||
|
} else if (endDate && startDate === "") {
|
||||||
|
query.createdAt = {
|
||||||
|
$lte: new Date(endDate),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const allSales = await Sales.find(query).sort({ createdAt: -1 });
|
||||||
|
|
||||||
|
// Populate additional details
|
||||||
|
const populatedSales = await Promise.all(
|
||||||
|
allSales.map(async (Sales) => {
|
||||||
|
let user = null;
|
||||||
|
if (Sales.userType === "TerritoryManager") {
|
||||||
|
user = await TerritoryManager.findById(Sales.userId);
|
||||||
|
} else if (Sales.userType === "SalesCoordinator") {
|
||||||
|
user = await SalesCoordinator.findById(Sales.userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
let addedForData = null;
|
||||||
|
let tradeName = null;
|
||||||
|
|
||||||
|
if (Sales.addedFor === "PrincipalDistributor") {
|
||||||
|
addedForData = await User.findById(Sales.addedForId);
|
||||||
|
if (addedForData) {
|
||||||
|
const shippingAddress = await ShippingAddress.findOne({
|
||||||
|
user: addedForData._id,
|
||||||
|
});
|
||||||
|
addedForData = {
|
||||||
|
...addedForData.toObject(),
|
||||||
|
shippingAddress,
|
||||||
|
};
|
||||||
|
tradeName =
|
||||||
|
addedForData.shippingAddress?.tradeName?.toLowerCase() || "";
|
||||||
|
}
|
||||||
|
} else if (Sales.addedFor === "RetailDistributor") {
|
||||||
|
addedForData = await KYC.findById(Sales.addedForId);
|
||||||
|
tradeName = addedForData?.trade_name?.toLowerCase() || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...Sales.toObject(),
|
||||||
|
user,
|
||||||
|
addedForData,
|
||||||
|
tradeName,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// Apply name filter if the name parameter is provided
|
||||||
|
let filteredSales = populatedSales;
|
||||||
|
if (name) {
|
||||||
|
filteredSales = filteredSales.filter(
|
||||||
|
(Sales) =>
|
||||||
|
Sales.tradeName && Sales.tradeName.includes(name.toLowerCase())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate total count of filtered data
|
||||||
|
const total_data = filteredSales.length;
|
||||||
|
|
||||||
|
// Apply pagination after filtering
|
||||||
|
const paginatedSales = filteredSales.slice((page - 1) * show, page * show);
|
||||||
|
|
||||||
|
// Calculate total pages
|
||||||
|
const total_pages = Math.ceil(total_data / show);
|
||||||
|
|
||||||
|
// Send response with pagination info
|
||||||
|
res.status(200).json({
|
||||||
|
total_data,
|
||||||
|
total_pages,
|
||||||
|
current_page: Number(page),
|
||||||
|
Sales: paginatedSales,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error in getAllSales:", error);
|
||||||
|
res.status(500).json({ message: error.message });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get single Sales
|
||||||
|
export const getSingleSales = async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { id } = req.params;
|
||||||
|
|
||||||
|
const Sales = await Sales.findById(id);
|
||||||
|
if (!Sales) {
|
||||||
|
return res.status(404).json({ message: "Sales not found" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate user details based on userType
|
||||||
|
let user = null;
|
||||||
|
if (Sales.userType === "TerritoryManager") {
|
||||||
|
user = await TerritoryManager.findById(Sales.userId);
|
||||||
|
} else if (Sales.userType === "SalesCoOrdinator") {
|
||||||
|
user = await SalesCoordinator.findById(Sales.userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate addedFor details based on addedFor
|
||||||
|
let addedForData = null;
|
||||||
|
if (Sales.addedFor === "PrincipalDistributor") {
|
||||||
|
addedForData = await User.findById(Sales.addedForId);
|
||||||
|
const shippingAddress = await ShippingAddress.findOne({
|
||||||
|
user: addedForData._id,
|
||||||
|
});
|
||||||
|
addedForData = {
|
||||||
|
...addedForData.toObject(),
|
||||||
|
shippingAddress,
|
||||||
|
};
|
||||||
|
} else if (Sales.addedFor === "RetailDistributor") {
|
||||||
|
addedForData = await KYC.findById(Sales.addedForId);
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
...Sales.toObject(),
|
||||||
|
user,
|
||||||
|
addedForData,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ message: error.message });
|
||||||
|
}
|
||||||
|
};
|
64
resources/Sales/SalesModel.js
Normal file
64
resources/Sales/SalesModel.js
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import mongoose from 'mongoose';
|
||||||
|
|
||||||
|
// Define Product record schema
|
||||||
|
const ProductRecordSchema = new mongoose.Schema({
|
||||||
|
SKU: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
ProductName: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
QuantitySold: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
SalesAmount: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
comments:{
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Define main Sales schema
|
||||||
|
const SalesSchema = new mongoose.Schema({
|
||||||
|
uniqueId: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
unique: true,
|
||||||
|
},
|
||||||
|
userId: {
|
||||||
|
type: mongoose.Schema.Types.ObjectId,
|
||||||
|
refPath: 'userType',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
userType: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
enum: ['SalesCoOrdinator', 'TerritoryManager'],
|
||||||
|
},
|
||||||
|
addedFor: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
enum: ['PrincipalDistributor', 'RetailDistributor'],
|
||||||
|
},
|
||||||
|
addedForId: {
|
||||||
|
type: mongoose.Schema.Types.ObjectId,
|
||||||
|
refPath: 'addedFor',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
tradename: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
date: {
|
||||||
|
type: Date,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
products: [ProductRecordSchema],
|
||||||
|
}, { timestamps: true, versionKey: false });
|
||||||
|
|
||||||
|
export const Sales = mongoose.model('Sales', SalesSchema);
|
25
resources/Sales/SalesRoute.js
Normal file
25
resources/Sales/SalesRoute.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import express from "express";
|
||||||
|
import { addSales,getAllSales,getSingleSales } from "./SalesController.js";
|
||||||
|
import { isAuthenticatedSalesCoOrdinator } from "../../middlewares/SalesCoOrdinatorAuth.js";
|
||||||
|
import { isAuthenticatedTerritoryManager } from "../../middlewares/TerritoryManagerAuth.js";
|
||||||
|
import { authorizeRoles, isAuthenticatedUser } from "../../middlewares/auth.js";
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
// Route to add Sales data
|
||||||
|
router.post("/add-SC", isAuthenticatedSalesCoOrdinator, addSales);
|
||||||
|
router.post("/add-TM", isAuthenticatedTerritoryManager, addSales);
|
||||||
|
|
||||||
|
// Admin routes
|
||||||
|
router.get(
|
||||||
|
"/all",
|
||||||
|
isAuthenticatedUser,
|
||||||
|
authorizeRoles("admin"),
|
||||||
|
getAllSales
|
||||||
|
);
|
||||||
|
router.get(
|
||||||
|
"/:id",
|
||||||
|
isAuthenticatedUser,
|
||||||
|
authorizeRoles("admin"),
|
||||||
|
getSingleSales
|
||||||
|
);
|
||||||
|
export default router;
|
@ -5,7 +5,7 @@ import { sendPushNotification } from "../../Utils/sendPushNotification.js";
|
|||||||
import SalesCoOrdinator from "../SalesCoOrdinators/SalesCoOrdinatorModel.js";
|
import SalesCoOrdinator from "../SalesCoOrdinators/SalesCoOrdinatorModel.js";
|
||||||
import TerritoryManager from "../TerritoryManagers/TerritoryManagerModel.js";
|
import TerritoryManager from "../TerritoryManagers/TerritoryManagerModel.js";
|
||||||
// Function to update task statuses
|
// Function to update task statuses
|
||||||
const updateOverdueTasks = async () => {
|
export const updateOverdueTasks = async () => {
|
||||||
try {
|
try {
|
||||||
const currentDate = new Date();
|
const currentDate = new Date();
|
||||||
const currentDateOnly = new Date(currentDate.setHours(0, 0, 0, 0));
|
const currentDateOnly = new Date(currentDate.setHours(0, 0, 0, 0));
|
||||||
@ -40,9 +40,9 @@ const updateOverdueTasks = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Schedule the cron job to run daily at midnight
|
// Schedule the cron job to run daily at midnight
|
||||||
cron.schedule("10 1 * * *", updateOverdueTasks, {
|
// cron.schedule("5 9 * * *", updateOverdueTasks, {
|
||||||
timezone: "Asia/Kolkata",
|
// timezone: "Asia/Kolkata",
|
||||||
});
|
// });
|
||||||
|
|
||||||
// cron.schedule("30 9 * * *", updateOverdueTasks);
|
// cron.schedule("30 9 * * *", updateOverdueTasks);
|
||||||
|
|
||||||
@ -262,7 +262,7 @@ export const updateTaskStatus = async (req, res) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch the FCM token of the Territory Manager
|
// Fetch the FCM token of the Territory Manager
|
||||||
const territoryManager = await TerritoryManager.findById(task.taskAssignedBy);
|
const territoryManager = await TerritoryManager.findById(task.taskAssignedBy);
|
||||||
|
|
||||||
if (!territoryManager) {
|
if (!territoryManager) {
|
||||||
|
@ -49,20 +49,20 @@ const TaskSchema = new mongoose.Schema(
|
|||||||
type: String,
|
type: String,
|
||||||
enum: ['PrincipalDistributor', 'RetailDistributor'],
|
enum: ['PrincipalDistributor', 'RetailDistributor'],
|
||||||
required: function () {
|
required: function () {
|
||||||
return this.task === "Update Inventory Data" || this.task === "Visit RD/PD";
|
return this.task === "Update Inventory Data" || this.task === "Visit RD/PD" || this.task === "Update Sales Data";
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
addedForId: {
|
addedForId: {
|
||||||
type: mongoose.Schema.Types.ObjectId,
|
type: mongoose.Schema.Types.ObjectId,
|
||||||
refPath: 'addedFor',
|
refPath: 'addedFor',
|
||||||
required: function () {
|
required: function () {
|
||||||
return this.task === "Update Inventory Data" || this.task === "Visit RD/PD";
|
return this.task === "Update Inventory Data" || this.task === "Visit RD/PD" || this.task === "Update Sales Data";
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
tradename: {
|
tradename: {
|
||||||
type: String,
|
type: String,
|
||||||
required: function () {
|
required: function () {
|
||||||
return this.task === "Update Inventory Data" || this.task === "Visit RD/PD";
|
return this.task === "Update Inventory Data" || this.task === "Visit RD/PD" || this.task === "Update Sales Data";
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -3,7 +3,8 @@ dotenv.config();
|
|||||||
import app from "./app.js";
|
import app from "./app.js";
|
||||||
import connectDatabase from "./database/db.js";
|
import connectDatabase from "./database/db.js";
|
||||||
import cloudinary from "cloudinary";
|
import cloudinary from "cloudinary";
|
||||||
|
import cron from "node-cron";
|
||||||
|
import {updateOverdueTasks} from "./resources/Task/TaskController.js ";
|
||||||
// Connecting to database
|
// Connecting to database
|
||||||
connectDatabase();
|
connectDatabase();
|
||||||
|
|
||||||
@ -28,6 +29,10 @@ app.get("/", (req, res) => {
|
|||||||
res.send("API is running..");
|
res.send("API is running..");
|
||||||
});
|
});
|
||||||
// }
|
// }
|
||||||
|
// Schedule the cron job
|
||||||
|
cron.schedule("10 0 * * *", updateOverdueTasks, {
|
||||||
|
timezone: "Asia/Kolkata",
|
||||||
|
});
|
||||||
//<---------deployement------------->
|
//<---------deployement------------->
|
||||||
const server = app.listen(process.env.PORT, () => {
|
const server = app.listen(process.env.PORT, () => {
|
||||||
console.log(`Server is working on http://localhost:${process.env.PORT}`);
|
console.log(`Server is working on http://localhost:${process.env.PORT}`);
|
||||||
|
Loading…
Reference in New Issue
Block a user