From 9fd133c2a7f2fe9994d985c22e1d6846825791cf Mon Sep 17 00:00:00 2001 From: Sibunnayak Date: Wed, 4 Sep 2024 12:22:29 +0530 Subject: [PATCH] Sales Update --- app.js | 5 +- resources/Sales/SalesController.js | 193 +++++++++++++++++++++++++++++ resources/Sales/SalesModel.js | 64 ++++++++++ resources/Sales/SalesRoute.js | 25 ++++ resources/Task/TaskModel.js | 8 +- server.js | 2 +- 6 files changed, 290 insertions(+), 7 deletions(-) create mode 100644 resources/Sales/SalesController.js create mode 100644 resources/Sales/SalesModel.js create mode 100644 resources/Sales/SalesRoute.js diff --git a/app.js b/app.js index 63a657f..1949d2f 100644 --- a/app.js +++ b/app.js @@ -189,7 +189,7 @@ import leave from "./resources/Leaves/LeaveRoute.js"; import notification from "./resources/Notification/notificationRoute.js" //Inventory import InventoryRoute from "./resources/Inventory/InventoryRoute.js"; - +import SalesRoute from "./resources/Sales/SalesRoute.js"; // PD Order place @@ -268,7 +268,8 @@ app.use("/api",notification) app.use("/api",PdOrderRoute) //Inventory app.use("/api/inventory", InventoryRoute); - +// Sales +app.use("/api/sales", SalesRoute); //Task app.use("/api/task", TaskRoute); diff --git a/resources/Sales/SalesController.js b/resources/Sales/SalesController.js new file mode 100644 index 0000000..783fc46 --- /dev/null +++ b/resources/Sales/SalesController.js @@ -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 }); + } +}; diff --git a/resources/Sales/SalesModel.js b/resources/Sales/SalesModel.js new file mode 100644 index 0000000..3a12b56 --- /dev/null +++ b/resources/Sales/SalesModel.js @@ -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); diff --git a/resources/Sales/SalesRoute.js b/resources/Sales/SalesRoute.js new file mode 100644 index 0000000..29f99fe --- /dev/null +++ b/resources/Sales/SalesRoute.js @@ -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; diff --git a/resources/Task/TaskModel.js b/resources/Task/TaskModel.js index 1bd77fd..24c29e5 100644 --- a/resources/Task/TaskModel.js +++ b/resources/Task/TaskModel.js @@ -12,7 +12,7 @@ const TaskSchema = new mongoose.Schema( task: { type: String, required: true, - enum: ["Visit RD/PD", "Update Sales Data", "Update Inventory Data", "Collect KYC"], + enum: ["Visit RD/PD", "Update Sales Data", "Update Inventory Data", "Collect KYC","Update Sales"], }, note: { type: String, @@ -49,20 +49,20 @@ const TaskSchema = new mongoose.Schema( type: String, enum: ['PrincipalDistributor', 'RetailDistributor'], 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"; }, }, addedForId: { type: mongoose.Schema.Types.ObjectId, refPath: 'addedFor', 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"; }, }, tradename: { type: String, 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"; }, }, }, diff --git a/server.js b/server.js index e8ac2df..63c5878 100644 --- a/server.js +++ b/server.js @@ -30,7 +30,7 @@ app.get("/", (req, res) => { }); // } // Schedule the cron job -cron.schedule("55 8 * * *", updateOverdueTasks, { +cron.schedule("19 9 * * *", updateOverdueTasks, { timezone: "Asia/Kolkata", }); //<---------deployement------------->