location controller updated with heading and created new models and controllers for remaining modules

This commit is contained in:
Shibi Chakkaravarthy
2026-05-04 20:57:03 +05:30
parent 1245e09111
commit 54d9508dc8
31 changed files with 2140 additions and 96 deletions
+263 -39
View File
@@ -2,15 +2,19 @@ import { createAccess } from "../models/Access/operations.js";
import { createRole, getAllRoles } from "../models/Role/operations.js";
import {
createDesignation,
updateDesignation,
getAllDesignations,
} from "../models/Designation/operations.js";
import { aggregateUser } from "../models/User/operations.js";
import {
createDepartment,
getAllDepartments,
} from "../models/Department/operations.js";
import { getAllVenues, createVenue } from "../models/Venue/operations.js";
import { coordinatesToGeoJson } from "../helpers/geoJson.helper.js";
import { getLocationsByQuery } from "../models/Location/operations.js";
import dayjs from "dayjs";
import { ObjectId } from "mongodb";
export const createAccessController = async (req, res) => {
try {
@@ -31,57 +35,36 @@ export const createAccessController = async (req, res) => {
}
};
export const getAllMetadataController = async (req, res) => {
export const updateDesignationController = async (req, res, next) => {
try {
const roles = await getAllRoles();
const designations = await getAllDesignations();
const departments = await getAllDepartments();
const branches = await getAllVenues({ category: "OWN" });
const metadata = {
roles,
designations,
departments,
branches,
};
res.status(200).json({ result: metadata });
const { id } = req.params;
const designation = await updateDesignation(id, req.body);
res.status(200).json({ result: designation });
} catch (error) {
res.status(500).json({ error: error.message });
console.log("updateDesignationController Error", error);
next(error);
}
};
export const getAllRolesController = async (req, res) => {
export const updateDepartmentController = async (req, res, next) => {
try {
const roles = await getAllRoles();
res.status(200).json({ result: roles });
const { id } = req.params;
const department = await updateDepartment(id, req.body);
res.status(200).json({ result: department });
} catch (error) {
res.status(500).json({ error: error.message });
console.log("updateDepartmentController Error", error);
next(error);
}
};
export const getAllDesignationsController = async (req, res) => {
export const updateRoleController = async (req, res, next) => {
try {
const designations = await getAllDesignations();
res.status(200).json({ result: designations });
const { id } = req.params;
const role = await updateRole(id, req.body);
res.status(200).json({ result: role });
} catch (error) {
res.status(500).json({ error: error.message });
}
};
export const getAllDepartmentsController = async (req, res) => {
try {
const departments = await getAllDepartments();
res.status(200).json({ result: departments });
} catch (error) {
res.status(500).json({ error: error.message });
}
};
export const getAllBranchesController = async (req, res) => {
try {
const branches = await getAllVenues({ category: "OWN" });
res.status(200).json({ result: branches });
} catch (error) {
res.status(500).json({ error: error.message });
console.log("updateRoleController Error", error);
next(error);
}
};
@@ -149,3 +132,244 @@ export const createBranchController = async (req, res) => {
res.status(500).json({ error: error.message });
}
};
export const getAllEmployeeController = async (req, res, next) => {
try {
const pipeline = [
{
$match: {
isActive: true,
},
},
{
$lookup: {
from: "profiles",
localField: "_id",
foreignField: "user",
as: "profile",
},
},
{
$unwind: {
path: "$profile",
preserveNullAndEmptyArrays: true,
},
},
{
$lookup: {
from: "accesses",
localField: "_id",
foreignField: "user",
as: "access",
},
},
{
$unwind: {
path: "$access",
preserveNullAndEmptyArrays: true,
},
},
{
$lookup: {
from: "designations",
localField: "access.designation",
foreignField: "_id",
as: "designation",
},
},
{
$unwind: {
path: "$designation",
preserveNullAndEmptyArrays: true,
},
},
{
$lookup: {
from: "departments",
localField: "access.department",
foreignField: "_id",
as: "department",
},
},
{
$unwind: {
path: "$department",
preserveNullAndEmptyArrays: true,
},
},
{
$project: {
_id: 1,
name: 1,
id: 1,
profile: 1,
designation: "$designation.name",
department: "$department.name",
},
},
];
const data = await aggregateUser(pipeline);
res.status(200).json({ result: data });
} catch (error) {
console.log("getAllEmployeeController Error", error);
next(error);
}
};
export const getAllMetadataController = async (req, res) => {
try {
const roles = await getAllRoles();
const designations = await getAllDesignations();
const departments = await getAllDepartments();
const branches = await getAllVenues({ category: "OWN" });
const metadata = {
roles,
designations,
departments,
branches,
};
res.status(200).json({ result: metadata });
} catch (error) {
res.status(500).json({ error: error.message });
}
};
export const getAllBranchesController = async (req, res) => {
try {
const branches = await getAllVenues({ category: "OWN" });
res.status(200).json({ result: branches });
} catch (error) {
res.status(500).json({ error: error.message });
}
};
export const getEmployeeDetailsController = async (req, res, next) => {
try {
const { id } = req.params;
const pipeline = [
{
$match: {
_id: new ObjectId.createFromHexString(id),
},
},
{
$lookup: {
from: "profiles",
localField: "_id",
foreignField: "user",
as: "profile",
},
},
{
$unwind: {
path: "$profile",
preserveNullAndEmptyArrays: true,
},
},
{
$lookup: {
from: "accesses",
localField: "_id",
foreignField: "user",
as: "access",
},
},
{
$unwind: {
path: "$access",
preserveNullAndEmptyArrays: true,
},
},
{
$lookup: {
from: "designations",
localField: "access.designation",
foreignField: "_id",
as: "designation",
},
},
{
$unwind: {
path: "$designation",
preserveNullAndEmptyArrays: true,
},
},
{
$lookup: {
from: "departments",
localField: "access.department",
foreignField: "_id",
as: "department",
},
},
{
$unwind: {
path: "$department",
preserveNullAndEmptyArrays: true,
},
},
{
$lookup: {
from: "roles",
localField: "access.role",
foreignField: "_id",
as: "role",
},
},
{
$unwind: {
path: "$role",
preserveNullAndEmptyArrays: true,
},
},
{
$lookup: {
from: "venues",
localField: "access.branch",
foreignField: "_id",
as: "branches",
},
},
{
$project: {
_id: 1,
name: 1,
department: "$department.name",
designation: "$designation.name",
role: "$role.name",
profile: 1,
branches: 1,
},
},
];
const [data] = await aggregateUser(pipeline);
res.status(200).json({ result: data });
} catch (error) {
console.log("getEmployeeDetails Error", error);
next(error);
}
};
export const getEmployeeLocationHistoryController = async (req, res, next) => {
try {
const { user } = req.params;
const { date = dayjs().subtract(330, "minute").toISOString() } = req.query;
const start = dayjs(date).startOf("day").toISOString();
const end = dayjs(date).endOf("day").toISOString();
console.log("Start Date", start, end, user);
const locations = await getLocationsByQuery({
user,
createdOn: { $gte: start, $lte: end },
});
console.log("LOCATIONS", locations);
res.status(200).json({ result: locations });
} catch (error) {
console.log("getEmployeeLocationHistory Error", error);
next(error);
}
};
+63
View File
@@ -0,0 +1,63 @@
import {
createAssignment,
updateAssignment,
getAssignmentsByQuery,
} from "../models/Assignment/operations.js";
import dayjs from "dayjs";
export const createAssignmentHandler = async (req, res) => {
try {
const { user } = res.locals;
const previousAssignment = await updateAssignment(req.body.venue, {
isActive: false,
});
const assignment = await createAssignment({
...req.body,
createdOn: dayjs().toISOString(),
createdBy: user.id,
});
res.status(201).json({ result: { assignment, previousAssignment } });
} catch (error) {
res.status(500).json({ message: "Error creating assignment", error });
}
};
export const updateAssignmentHandler = async (req, res) => {
try {
const { id } = req.params;
const assignment = await updateAssignment(id, req.body);
res.status(200).json({ result: assignment });
} catch (error) {
res.status(500).json({ message: "Error updating assignment", error });
}
};
export const getAssignmentsByUserHandler = async (req, res) => {
try {
const { id } = req.params;
const assignment = await getAssignmentsByQuery({ user: id });
res.status(200).json({ result: assignment });
} catch (error) {
res.status(500).json({ message: "Error getting assignment", error });
}
};
export const deactivateAssignmentHandler = async (req, res) => {
try {
const { id } = req.params;
const assignment = await updateAssignment(id, { isActive: false });
res.status(200).json({ result: assignment });
} catch (error) {
res.status(500).json({ message: "Error deactivating assignment", error });
}
};
export const getAssignmentByVenueHandler = async (req, res) => {
try {
const { id } = req.params;
const assignment = await getAssignmentsByQuery({ venue: id });
res.status(200).json({ result: assignment });
} catch (error) {
res.status(500).json({ message: "Error getting assignment", error });
}
};
+39
View File
@@ -4,6 +4,42 @@ import {
getLocationByRadius,
} from "../models/Location/operations";
/*
Sample Location Payload
{
"extras": {},
"activity": {
"confidence": 100,
"type": "still"
},
"timestamp": "2026-04-25T17:31:25.320Z",
"battery": {
"level": 0.57,
"is_charging": false
},
"recorded_at": "2026-04-25T17:31:25.388Z",
"age": 0.074,
"is_moving": false,
"event": "motionchange",
"uuid": "4c476d94-b7db-4823-9270-805235ed0ec8",
"coords": {
"ellipsoidal_altitude": 0,
"altitude": 0,
"altitude_accuracy": 0.5,
"heading_accuracy": -1,
"heading": -1,
"speed": 0,
"accuracy": 5,
"longitude": 77.48675,
"speed_accuracy": 0.5,
"latitude": 9.9707883
},
"odometer_error": 0,
"odometer": 0
}
*/
export const createLocationController = async (req, res) => {
try {
const { user } = res.locals;
@@ -11,6 +47,9 @@ export const createLocationController = async (req, res) => {
const dbPayload = {
battery: location.battery.level,
coordinates: location.coords,
event: location.event,
heading: location.coords.heading,
activity: location?.activity?.type,
recorded_at: location.recorded_at,
};
const uploaded = await createLocation({ ...dbPayload, user: user?.id });
+194
View File
@@ -0,0 +1,194 @@
import {
createPartner,
getPartnerById,
getPartnerByQuery,
getPartnersByQuery,
getAllPartners,
updatePartner,
aggregatePartner,
} from "../models/Partner/operations";
import dayjs from "dayjs";
import { ObjectId } from "mongodb";
export const createPartnerController = async (req, res) => {
try {
const { user } = res.locals;
const partner = await createPartner({
...req.body,
createdBy: user.id,
createdOn: dayjs().toISOString(),
});
res.status(200).json({ result: partner });
} catch (error) {
console.log("createPartnerController Error", error);
next(error);
}
};
export const getPartnerController = async (req, res, next) => {
try {
const { id } = req.params;
const pipeline = [
// 1. Match the specific partner (Satisfies Req #1)
{
$match: {
_id: ObjectId.createFromHexString(id),
},
},
// 2. Fetch all invoices for this partner
{
$lookup: {
from: "invoices", // Ensure this matches your actual collection name
localField: "_id",
foreignField: "customer",
as: "partnerInvoices",
},
},
// 3. Calculate Invoice Metrics without unwinding (Satisfies Reqs #3, #4, #5)
{
$addFields: {
totalInvoicesCount: { $size: "$partnerInvoices" },
pendingOrPartialInvoicesCount: {
$size: {
$filter: {
input: "$partnerInvoices",
as: "invoice",
cond: {
$in: ["$$invoice.status", ["PENDING", "PARTIAL"]],
},
},
},
},
// Note: Your schema uses "PAID", assuming that correlates to "COMPLETED"
totalInvoicesAmount: { $sum: "$partnerInvoices.total" },
},
},
// 4. Remove the heavy invoices array from memory before doing more lookups
{
$project: {
partnerInvoices: 0,
},
},
// 5. Lookup Venues and nested Users/Profiles (Satisfies Reqs #2 & #6)
{
$lookup: {
from: "venues",
let: { partnerId: "$_id" },
pipeline: [
// Match venues to the partner (Assuming 'entity' field links to Partner _id)
{
$match: {
$expr: { $eq: ["$entity", "$$partnerId"] },
},
},
// Lookup Assignments for this specific venue
{
$lookup: {
from: "assignments",
let: { venueId: "$_id" },
pipeline: [
{
$match: {
$expr: { $eq: ["$venue", "$$venueId"] },
isActive: true, // Optional: ensuring we only get active assignments
},
},
// Lookup the User for the assignment
{
$lookup: {
from: "users",
localField: "user",
foreignField: "_id",
as: "userDetails",
},
},
{
$unwind: {
path: "$userDetails",
preserveNullAndEmptyArrays: true,
},
},
// Lookup the Profile for the assigned User
{
$lookup: {
from: "profiles",
localField: "user",
foreignField: "user",
as: "userProfile",
},
},
{
$unwind: {
path: "$userProfile",
preserveNullAndEmptyArrays: true,
},
},
// Clean up the assignment shape
{
$project: {
_id: 1,
targetedVisits: 1,
user: "$userDetails",
profile: "$userProfile",
},
},
],
as: "assignedUsers",
},
},
],
as: "venues",
},
},
];
const partner = await aggregatePartner(pipeline);
if (!partner?.length) {
throw new Error("Partner not found");
}
res.status(200).json({ result: partner[0] || {} });
} catch (error) {
console.log("getPartnerController Error", error);
next(error);
}
};
export const getAllPartnersController = async (req, res) => {
try {
const partners = await getAllPartners();
res.status(200).json({ result: partners });
} catch (error) {
console.log("getAllPartnersController Error", error);
next(error);
}
};
export const updatePartnerController = async (req, res) => {
try {
const { id } = req.params;
const partner = await updatePartner(id, req.body);
res.status(200).json({ result: partner });
} catch (error) {
console.log("updatePartnerController Error", error);
next(error);
}
};
export const deletePartnerController = async (req, res, next) => {
try {
const { id } = req.params;
const partner = await updatePartner(id, { isActive: false });
res.status(200).json({ result: partner });
} catch (error) {
console.log("deletePartnerController Error", error);
next(error);
}
};
+1 -2
View File
@@ -20,7 +20,7 @@ export const createOrEditProfileController = async (req, res, next) => {
}
};
export const getProfileController = async (req, res, next) => {
export const getOwnProfileController = async (req, res, next) => {
try {
const { user } = res.locals;
const profile = await getProfileByQuery({ userId: user.id });
@@ -30,4 +30,3 @@ export const getProfileController = async (req, res, next) => {
next(error);
}
};
+71
View File
@@ -0,0 +1,71 @@
import {
createVenue,
getVenueById,
getVenuesByQuery,
getAllVenues,
updateVenue,
aggregateVenue,
} from "../models/Venue/operations.js";
import { coordinatesToGeoJson } from "../helpers/geoJson.helper.js";
import dayjs from "dayjs";
export const createVenueController = async (req, res, next) => {
try {
const { user } = res.locals;
const { location } = req.body;
const geoJson = coordinatesToGeoJson({
latitude: location.lat,
longitude: location.lng,
});
const dbPayload = {
...req.body,
location: geoJson,
createdBy: user.id,
createdOn: dayjs().toISOString(),
};
const venue = await createVenue(dbPayload);
res.status(200).json({ result: venue });
} catch (error) {
console.log("createVenueController Error", error);
next(error);
}
};
export const deleteVenueController = async (req, res, next) => {
try {
const { id } = req.params;
const venue = await updateVenue(id, { isActive: false });
res.status(200).json({ result: venue });
} catch (error) {
console.log("deleteVenueController Error", error);
next(error);
}
};
export const getVenuesByEntityController = async (req, res, next) => {
try {
const { id } = req.params;
const venues = await getVenuesByQuery({ entity: id });
res.status(200).json({ result: venues });
} catch (error) {
console.log("getVenuesByEntity Error", error);
next(error);
}
};
export const getVenueController = async (req, res, next) => {
try {
const { id } = req.params;
const venue = await getVenueById(id);
res.status(200).json({ result: venue });
} catch (error) {
console.log("getVenueController Error", error);
next(error);
}
};
+11 -2
View File
@@ -11,7 +11,7 @@ import {
import dayjs from "dayjs";
import mongoose from "mongoose";
import { coordinatesToGeoJson } from "../helpers/geoJson.helper.js";
import bcrypt from "bcryptjs";
import bcrypt from "bcrypt";
export const createEmployee = async (req, res) => {
const session = await mongoose.startSession();
@@ -41,7 +41,7 @@ export const createEmployee = async (req, res) => {
throw { code: 400, message: "ID already assigned for Another Employee" };
}
const employee = await User.create(
const [employee] = await User.create(
[
{
name,
@@ -49,11 +49,15 @@ export const createEmployee = async (req, res) => {
hash,
createdOn: dayjs().toISOString(),
createdBy: user.id,
isFirstTime: true,
isActive: true,
},
],
{ session },
);
console.log("EMPLOYEE", employee);
const profile = await Profile.create(
[
{
@@ -83,8 +87,13 @@ export const createEmployee = async (req, res) => {
],
{ session },
);
await session.commitTransaction();
session.endSession();
res.status(200).json({ result: access });
} catch (error) {
console.log("createEmployee Error", error);
await session.abortTransaction();
session.endSession();
res.status(500).json({ error: error.message });
}
};