Compare commits

..
10 Commits
48 changed files with 3829 additions and 130 deletions
+284 -26
View File
@@ -1,15 +1,24 @@
import { createAccess } from "../models/Access/operations.js"; import { createAccess } from "../models/Access/operations.js";
import { createRole, getAllRoles } from "../models/Role/operations.js"; import {
createRole,
getAllRoles,
updateRole,
} from "../models/Role/operations.js";
import { import {
createDesignation, createDesignation,
updateDesignation,
getAllDesignations, getAllDesignations,
} from "../models/Designation/operations.js"; } from "../models/Designation/operations.js";
import { aggregateUser } from "../models/User/operations.js";
import { import {
createDepartment, createDepartment,
getAllDepartments, getAllDepartments,
} from "../models/Department/operations.js"; } from "../models/Department/operations.js";
import { createBranch, getAllBranches } from "../models/Branch/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 dayjs from "dayjs";
import { ObjectId } from "mongodb";
export const createAccessController = async (req, res) => { export const createAccessController = async (req, res) => {
try { try {
@@ -30,39 +39,37 @@ export const createAccessController = async (req, res) => {
} }
}; };
export const getAllRolesController = async (req, res) => { export const updateDesignationController = async (req, res, next) => {
try { try {
const roles = await getAllRoles(); const { id } = req.params;
res.status(200).json({ result: roles }); const designation = await updateDesignation(id, req.body);
res.status(200).json({ result: designation });
} catch (error) { } catch (error) {
res.status(500).json({ error: error.message }); console.log("updateDesignationController Error", error);
next(error);
} }
}; };
export const getAllDesignationsController = async (req, res) => { export const updateDepartmentController = async (req, res, next) => {
try { try {
const designations = await getAllDesignations(); const { id } = req.params;
res.status(200).json({ result: designations }); const department = await updateDepartment(id, req.body);
res.status(200).json({ result: department });
} catch (error) { } catch (error) {
res.status(500).json({ error: error.message }); console.log("updateDepartmentController Error", error);
next(error);
} }
}; };
export const getAllDepartmentsController = async (req, res) => { export const updateRoleController = async (req, res, next) => {
try { try {
const departments = await getAllDepartments(); const { id } = req.params;
res.status(200).json({ result: departments }); console.log("REQ BODY", req.body, id);
const role = await updateRole(id, req.body);
res.status(200).json({ result: role });
} catch (error) { } catch (error) {
res.status(500).json({ error: error.message }); console.log("updateRoleController Error", error);
} next(error);
};
export const getAllBranchesController = async (req, res) => {
try {
const branches = await getAllBranches();
res.status(200).json({ result: branches });
} catch (error) {
res.status(500).json({ error: error.message });
} }
}; };
@@ -76,6 +83,7 @@ export const createRoleController = async (req, res) => {
}); });
res.status(200).json({ result: role }); res.status(200).json({ result: role });
} catch (error) { } catch (error) {
console.log("createRoleController Error", error);
res.status(500).json({ error: error.message }); res.status(500).json({ error: error.message });
} }
}; };
@@ -111,13 +119,263 @@ export const createDepartmentController = async (req, res) => {
export const createBranchController = async (req, res) => { export const createBranchController = async (req, res) => {
try { try {
const { user } = res.locals; const { user } = res.locals;
const branch = await createBranch({ const { coordinates } = req.body;
const geoJson = coordinatesToGeoJson({
latitude: coordinates.lat,
longitude: coordinates.lng,
});
const dbPayload = {
...req.body, ...req.body,
category: "OWN",
location: geoJson,
createdBy: user.id, createdBy: user.id,
createdOn: dayjs().toISOString(), createdOn: dayjs().toISOString(),
}); };
res.status(200).json({ result: branch }); const venue = await createVenue(dbPayload);
res.status(200).json({ result: venue });
} catch (error) { } catch (error) {
res.status(500).json({ error: error.message }); 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: 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: 1,
designation: 1,
role: 1,
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);
}
};
+150
View File
@@ -0,0 +1,150 @@
import {
createAssignment,
updateAssignment,
getAssignmentsByQuery,
aggregateAssignment,
} from "../models/Assignment/operations.js";
import dayjs from "dayjs";
import { ObjectId } from "mongodb";
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,
isActive: true,
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 pipeline = [
{
$match: {
user: ObjectId?.createFromHexString(id),
isActive: true,
},
},
{
$lookup: {
from: "venues",
localField: "venue",
foreignField: "_id",
as: "venue",
},
},
{
$unwind: {
path: "$venue",
},
},
{
$lookup: {
from: "partners",
localField: "venue.entity",
foreignField: "_id",
as: "partner",
},
},
{
$unwind: {
path: "$partner",
},
},
];
const assignment = await aggregateAssignment(pipeline);
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 });
}
};
export const getAssignmentByIdHandler = async (req, res) => {
try {
const { id } = req.params;
const pipeline = [
{
$match: {
_id: ObjectId.createFromHexString(id),
},
},
{
$lookup: {
from: "venues",
localField: "venue",
foreignField: "_id",
as: "venue",
},
},
{
$unwind: {
path: "$venue",
preserveNullAndEmptyArrays: true,
},
},
{
$lookup: {
from: "partners",
localField: "venue.entity",
foreignField: "_id",
as: "partner",
},
},
{
$unwind: {
path: "$partner",
preserveNullAndEmptyArrays: true,
},
},
];
const assignment = await aggregateAssignment(pipeline);
console.log("ASSIGNMENT", assignment);
res.status(200).json({ result: assignment[0] });
} catch (error) {
res.status(500).json({ message: "Error getting assignment", error });
}
};
+145 -3
View File
@@ -3,14 +3,111 @@ import {
getLocationByQuery, getLocationByQuery,
getLocationByRadius, getLocationByRadius,
} from "../models/Location/operations"; } from "../models/Location/operations";
import { aggregateAssignment } from "../models/Assignment/operations";
import { ObjectId } from "mongodb";
/*
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
}
Geofence Event {
event: 'geofence',
is_moving: true,
uuid: 'dfa0f17d-017f-4fd1-beca-67e62f0087d9',
timestamp: '2026-06-15T18:15:08.430Z',
recorded_at: '2026-06-15T18:15:08.607Z',
age: 0.179,
odometer: 345.61,
odometer_error: 16.68,
coords: {
latitude: 13.1243472,
longitude: 80.1428553,
accuracy: 3.45,
speed: 1.01,
speed_accuracy: 0.19,
heading: 280.72,
heading_accuracy: 12.79,
altitude: -51.9,
ellipsoidal_altitude: -51.9,
altitude_accuracy: 1.11
},
activity: { type: 'walking', confidence: 100 },
battery: { is_charging: false, level: 0.69 },
geofence: {
identifier: '6a2e128af72b4c6184fd53ea-6a1f658f8fc61da8a1809091-6a2e126bf72b4c6184fd5310',
action: 'EXIT',
timestamp: '2026-06-15T18:15:08.612Z',
extras: {
venue: '6a2e126bf72b4c6184fd5310',
partner: '6a1f658f8fc61da8a1809091'
}
},
extras: {}
*/
export const createLocationController = async (req, res) => { export const createLocationController = async (req, res) => {
try { try {
const { user } = res.locals; const { user } = res.locals;
console.log("BG LOCATIONREQUEST BODY", req.body, user); const { location } = req.body;
// const location = await createLocation({ ...req.body, user: user?.id }); if (location.event === "geofence") {
res.status(200).json({ location: "location" }); console.log("Geofence Event", location);
}
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,
};
if (location.event === "geofence") {
const [assignment, partner, venue] =
location?.geofence?.identifier?.split("-");
const geofencePayload = {
assignment,
partner,
venue,
action: location?.geofence?.action,
};
dbPayload.geofence = geofencePayload;
}
const uploaded = await createLocation({ ...dbPayload, user: user?.id });
res.status(200).json({ result: uploaded });
} catch (error) { } catch (error) {
console.log("createLocationController Error", error);
res.status(500).json({ error: error.message }); res.status(500).json({ error: error.message });
} }
}; };
@@ -23,3 +120,48 @@ export const getLocationController = async (req, res) => {
res.status(500).json({ error: error.message }); res.status(500).json({ error: error.message });
} }
}; };
export const getMyAssignedVenuesHandler = async (req, res, next) => {
try {
const { user } = res.locals;
const pipeline = [
{
$match: {
user: ObjectId?.createFromHexString(user.id),
isActive: true,
},
},
{
$lookup: {
from: "venues",
localField: "venue",
foreignField: "_id",
as: "venue",
},
},
{
$unwind: {
path: "$venue",
},
},
{
$lookup: {
from: "partners",
localField: "venue.entity",
foreignField: "_id",
as: "partner",
},
},
{
$unwind: {
path: "$partner",
},
},
];
const assignment = await aggregateAssignment(pipeline);
res.status(200).json({ result: assignment });
} catch (error) {
console.log("getMyAssignedVenuesHandler Error", error);
next(error);
}
};
+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);
}
};
+70
View File
@@ -0,0 +1,70 @@
import {
createProduct,
updateProduct,
getAllProducts,
getProductByQuery,
getProductById,
deleteProduct,
} from "../models/Product/operations";
import dayjs from "dayjs";
export const createProductController = async (req, res, next) => {
try {
const { user } = res.locals;
const product = await createProduct({
...req.body,
createdBy: user.id,
createdOn: dayjs().toISOString(),
});
res.status(200).json({
result: product,
});
} catch (error) {
console.log("createProductController Error", error);
next(error);
}
};
export const updateProductController = async (req, res, next) => {
try {
const { id } = req.params;
const product = await updateProduct(id, {
...req.body,
});
res.status(200).json({
result: product,
});
} catch (error) {
console.log("updateProductController Error", error);
next(error);
}
};
export const getAllProductsController = async (req, res, next) => {
try {
const products = await getAllProducts();
res.status(200).json({
result: products,
});
} catch (error) {
console.log("getAllProductsController Error", error);
next(error);
}
};
export const deleteProductController = async (req, res, next) => {
try {
const { id } = req.params;
const product = await deleteProduct(id);
res.status(200).json({
result: product,
});
} catch (error) {
console.log("deleteProductController 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 { try {
const { user } = res.locals; const { user } = res.locals;
const profile = await getProfileByQuery({ userId: user.id }); const profile = await getProfileByQuery({ userId: user.id });
@@ -30,4 +30,3 @@ export const getProfileController = async (req, res, next) => {
next(error); next(error);
} }
}; };
+79
View File
@@ -0,0 +1,79 @@
import dayjs from "dayjs";
import {
createVendor,
updateVendor,
deleteVendor,
getVendorsByQuery,
getVendorById,
getAllVendors,
} from "../models/Vendor/operations";
export const createVendorController = async (req, res, next) => {
try {
const { user } = res.locals;
const vendor = await createVendor({
...req.body,
createdBy: user?.id,
createdOn: dayjs().toISOString(),
});
res.status(201).json({ result: vendor });
} catch (error) {
console.log("createVendorController Error", error);
next(error);
}
};
export const updateVendorController = async (req, res, next) => {
try {
const { id } = req.params;
const vendor = await updateVendor(id, req.body);
res.status(200).json({ result: vendor });
} catch (error) {
console.log("updateVendorController Error", error);
next(error);
}
};
export const getActiveVendorsController = async (req, res, next) => {
try {
const vendors = await getVendorsByQuery({ isActive: true });
res.status(200).json({ result: vendors });
} catch (error) {
console.log("getActiveVendorsController Error", error);
next(error);
}
};
export const getAllVendorsController = async (req, res, next) => {
try {
const vendors = await getAllVendors();
res.status(200).json({ result: vendors });
} catch (error) {
console.log("getAllVendorsController Error", error);
next(error);
}
};
export const deactivateVendorController = async (req, res, next) => {
try {
const { id } = req.params;
const deactivatedVendor = await updateVendor(id, { isActive: false });
res.status(200).json({ result: deactivatedVendor });
} catch (error) {
console.log("deactivateVendorController Error", error);
next(error);
}
};
export const getVendorByIdController = async (req, res, next) => {
try {
const { id } = req.params;
const vendor = await getVendorById(id);
res.status(200).json({ result: vendor });
} catch (error) {
console.log("getVendorByIdController Error", error);
next(error);
}
};
+176
View File
@@ -0,0 +1,176 @@
import {
createVenue,
getVenueById,
getVenuesByQuery,
getAllVenues,
updateVenue,
aggregateVenue,
} from "../models/Venue/operations.js";
import { ObjectId } from "mongodb";
import { aggregateAssignment } from "../models/Assignment/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);
}
};
export const getAssignedVenuesController = async (req, res, next) => {
try {
const { userId } = req.params;
// const { user } = res.locals;
const assignedVenues = await aggregateAssignment([
{
$match: {
user: ObjectId.createFromHexString(userId),
isActive: true,
},
},
{
$lookup: {
from: "venues",
localField: "venue",
foreignField: "_id",
as: "venue",
},
},
{
$unwind: {
path: "$venue",
preserveNullAndEmptyArrays: true,
},
},
{
$lookup: {
from: "partners",
localField: "venue.entity",
foreignField: "_id",
as: "partner",
},
},
{
$unwind: {
path: "$partner",
preserveNullAndEmptyArrays: true,
},
},
]);
res.status(200).json({ result: assignedVenues });
} catch (error) {
console.log("getAssignedVenues Error", error);
next(error);
}
};
export const getUnassignedVenuesController = async (req, res, next) => {
try {
const unassignedVenues = await aggregateVenue([
{
$match: {
category: "PARTNER"
},
},
{
$lookup: {
from: "assignments",
localField: "_id",
foreignField: "venue",
pipeline: [
{
$match: {
isActive: true,
},
},
],
as: "activeAssignments",
},
},
{
$match: {
$or: [
{ activeAssignments: { $size: 0 } },
{ activeAssignments: { $exists: false } },
],
},
},
{
$lookup: {
from: "partners",
localField: "entity",
foreignField: "_id",
as: "partner",
},
},
{
$unwind: {
path: "$partner",
preserveNullAndEmptyArrays: true,
},
},
]);
res.status(200).json({ result: unassignedVenues });
} catch (error) {
console.log("getUnassignedVenuesController Error", error);
next(error);
}
};
+99 -1
View File
@@ -1 +1,99 @@
import { User, Access, Profile, Team } from "../models/index.js"; import {
User,
Access,
Profile,
Team,
Branch,
Partner,
Vendor,
Venue,
} from "../models/index.js";
import dayjs from "dayjs";
import mongoose from "mongoose";
import { coordinatesToGeoJson } from "../helpers/geoJson.helper.js";
import bcrypt from "bcrypt";
export const createEmployee = async (req, res) => {
const session = await mongoose.startSession();
session.startTransaction();
try {
const { user } = res.locals;
const {
name,
mobile,
id,
password,
address,
city,
state,
pincode,
email,
designation,
department,
branch,
role,
} = req.body;
const hash = await bcrypt.hash(password, 10);
const userExists = await User.exists({ id });
if (userExists) {
throw { code: 400, message: "ID already assigned for Another Employee" };
}
const [employee] = await User.create(
[
{
name,
id,
hash,
createdOn: dayjs().toISOString(),
createdBy: user.id,
isFirstTime: true,
isActive: true,
},
],
{ session },
);
console.log("EMPLOYEE", employee);
const profile = await Profile.create(
[
{
user: employee?._id,
mobile,
address,
city,
email,
state,
pincode,
isActive: true,
},
],
{ session },
);
const access = await Access.create(
[
{
user: employee?._id,
designation,
department,
branch,
role,
createdBy: user.id,
createdOn: dayjs().toISOString(),
},
],
{ 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 });
}
};
+90 -16
View File
@@ -60,10 +60,10 @@ export default {
}, },
}, },
}, },
"/admin/designations": { "/admin/metadata": {
get: { get: {
tags: ["Admin"], tags: ["Admin"],
summary: "Get All Designations", summary: "Get All Metadata",
responses: { responses: {
200: { 200: {
description: "OK", description: "OK",
@@ -72,22 +72,10 @@ export default {
}, },
}, },
}, },
"/admin/departments": { "/admin/employees": {
get: { get: {
tags: ["Admin"], tags: ["Admin"],
summary: "Get All Departments", summary: "Get All Employees",
responses: {
200: {
description: "OK",
content: {},
},
},
},
},
"/admin/roles": {
get: {
tags: ["Admin"],
summary: "Get All Roles",
responses: { responses: {
200: { 200: {
description: "OK", description: "OK",
@@ -238,4 +226,90 @@ export default {
}, },
}, },
}, },
"/admin/role/{id}": {
patch: {
tags: ["Admin"],
summary: "Edit New Role",
parameters: [
{
in: "path",
name: "id",
},
],
requestBody: {
required: true,
content: {
"application/json": {
schema: {
type: "object",
properties: {
name: {
type: "string",
required: true,
},
},
},
},
},
},
responses: {
200: {
description: "OK",
content: {},
},
},
},
},
"/admin/employee/{id}": {
get: {
tags: ["Admin"],
summary: "Get Employee Details by ID",
parameters: [
{
in: "path",
name: "id",
required: true,
schema: {
type: "string",
},
},
],
responses: {
200: {
description: "OK",
content: {},
},
},
},
},
"/admin/employee/{user}/locations": {
get: {
tags: ["Admin"],
summary: "Get Employee Details by ID",
parameters: [
{
in: "path",
name: "user",
required: true,
schema: {
type: "string",
},
},
{
in: "query",
name: "date",
required: true,
schema: {
type: "string",
},
},
],
responses: {
200: {
description: "OK",
content: {},
},
},
},
},
}; };
+168
View File
@@ -0,0 +1,168 @@
export default {
"/assignment": {
post: {
tags: ["Assignment"],
summary: "Create an assignment",
requestBody: {
content: {
"application/json": {
schema: {
type: "object",
properties: {
user: {
type: "string",
required: true,
},
venue: {
type: "string",
required: true,
},
targetedVisits: {
type: "number",
required: true,
},
},
},
},
},
},
responses: {
200: {
description: "OK",
content: {},
},
},
},
},
"/assignment/{id}": {
patch: {
tags: ["Assignment"],
summary: "Update an assignment",
parameters: [
{
in: "path",
name: "id",
required: true,
schema: {
type: "string",
},
},
],
requestBody: {
content: {
"application/json": {
schema: {
type: "object",
properties: {
user: {
type: "string",
required: true,
},
venue: {
type: "string",
required: true,
},
targetedVisits: {
type: "number",
required: true,
},
},
},
},
},
},
responses: {
200: {
description: "OK",
content: {},
},
},
},
get: {
tags: ["Assignment"],
summary: "Update an assignment",
parameters: [
{
in: "path",
name: "id",
required: true,
schema: {
type: "string",
},
},
],
responses: {
200: {
description: "OK",
content: {},
},
},
},
delete: {
tags: ["Assignment"],
summary: "Delete an assignment",
parameters: [
{
in: "path",
name: "id",
required: true,
schema: {
type: "string",
},
},
],
responses: {
200: {
description: "OK",
content: {},
},
},
},
},
"/assignment/user/{id}": {
get: {
tags: ["Assignment"],
summary: "Get all assignments for a user",
parameters: [
{
in: "path",
name: "id",
description: "User ID",
required: true,
schema: {
type: "string",
},
},
],
responses: {
200: {
description: "OK",
content: {},
},
},
},
},
"/assignment/venue/{id}": {
get: {
tags: ["Assignment"],
summary: "Get all assignments for a Venue",
parameters: [
{
in: "path",
name: "id",
description: "Venue ID",
required: true,
schema: {
type: "string",
},
},
],
responses: {
200: {
description: "OK",
content: {},
},
},
},
},
};
File diff suppressed because it is too large Load Diff
+11 -1
View File
@@ -4,7 +4,12 @@ import upload from "./upload.js";
import user from "./user.js"; import user from "./user.js";
import profile from "./profile.js"; import profile from "./profile.js";
import admin from "./admin.js"; import admin from "./admin.js";
import location from "./location.js" import location from "./location.js";
import assignment from "./assignment.js";
import partner from "./partner.js";
import venue from "./venue.js";
import product from "./product.js";
import vendor from "./vendor.js";
const GENERAL_CONFIG = { const GENERAL_CONFIG = {
openapi: "3.0.1", openapi: "3.0.1",
@@ -47,6 +52,11 @@ let paths = {
...location, ...location,
...upload, ...upload,
...admin, ...admin,
...assignment,
...partner,
...venue,
...product,
...vendor,
}; };
const getSwaggerDocument = () => { const getSwaggerDocument = () => {
+12 -1
View File
@@ -32,7 +32,6 @@ export default {
type: "string", type: "string",
required: false, required: false,
}, },
}, },
}, },
}, },
@@ -46,4 +45,16 @@ export default {
}, },
}, },
}, },
"/location/venues/assigned/me": {
get: {
tags: ["Location"],
summary: "Get Assigned Venues for creating Geofence",
responses: {
200: {
description: "OK",
content: {},
},
},
},
},
}; };
+216
View File
@@ -0,0 +1,216 @@
export default {
"/partner": {
get: {
tags: ["Partner"],
summary: "Get all Partners",
responses: {
200: {
description: "OK",
content: {},
},
},
},
post: {
tags: ["Partner"],
summary: "Create New Partner",
requestBody: {
required: true,
content: {
"application/json": {
schema: {
type: "object",
properties: {
name: {
type: "string",
required: true,
},
email: {
type: "string",
required: true,
},
phone: {
type: "string",
required: true,
},
address: {
type: "string",
required: true,
},
city: {
type: "string",
required: true,
},
state: {
type: "string",
required: true,
},
pincode: {
type: "string",
required: true,
},
contactPersons: {
type: "array",
required: true,
items: {
type: "object",
properties: {
name: {
type: "string",
required: true,
},
email: {
type: "string",
required: true,
},
mobile: {
type: "string",
required: true,
},
designation: {
type: "string",
required: true,
},
},
},
},
},
},
},
},
},
responses: {
200: {
description: "OK",
content: {},
},
},
},
},
"/partner/{id}": {
get: {
tags: ["Partner"],
summary: "Get Partner Details by ID",
parameters: [
{
in: "path",
name: "id",
required: true,
schema: {
type: "string",
},
},
],
responses: {
200: {
description: "OK",
content: {},
},
},
},
patch: {
tags: ["Partner"],
summary: "Update Partner Details by ID",
parameters: [
{
in: "path",
name: "id",
required: true,
schema: {
type: "string",
},
},
],
requestBody: {
required: true,
content: {
"application/json": {
schema: {
type: "object",
properties: {
name: {
type: "string",
required: true,
},
email: {
type: "string",
required: true,
},
phone: {
type: "string",
required: true,
},
address: {
type: "string",
required: true,
},
city: {
type: "string",
required: true,
},
state: {
type: "string",
required: true,
},
pincode: {
type: "string",
required: true,
},
contactPersons: {
type: "array",
required: true,
items: {
type: "object",
properties: {
name: {
type: "string",
required: true,
},
email: {
type: "string",
required: true,
},
mobile: {
type: "string",
required: true,
},
designation: {
type: "string",
required: true,
},
},
},
},
},
},
},
},
},
responses: {
200: {
description: "OK",
content: {},
},
},
},
delete: {
tags: ["Partner"],
summary: "Deactivate Partner by ID",
parameters: [
{
in: "path",
name: "id",
required: true,
schema: {
type: "string",
},
},
],
responses: {
200: {
description: "OK",
content: {},
},
},
},
},
};
+176
View File
@@ -0,0 +1,176 @@
export default {
"/product": {
post: {
summary: "Create a New Product",
tags: ["Product"],
requestBody: {
content: {
"application/json": {
schema: {
type: "object",
properties: {
sku: {
type: "string",
required: true,
},
name: {
type: "string",
required: true,
},
stock: {
type: "number",
required: true,
},
buyingPrice: {
type: "number",
required: true,
},
sellingPrice: {
type: "number",
required: true,
},
description: {
type: "string",
required: true,
},
gst: {
type: "number",
required: true,
},
hsn: {
type: "string",
required: true,
},
stock: {
type: "number",
required: true,
},
vendors: {
type: "array",
items: {
type: "string",
},
required: true,
},
},
},
},
},
},
responses: {
200: {
description: "OK",
content: {},
},
},
},
get: {
summary: "Get All Products",
tags: ["Product"],
responses: {
200: {
description: "OK",
content: {},
},
},
},
},
"/product/{id}": {
patch: {
summary: "Update a Product",
tags: ["Product"],
parameters: [
{
name: "id",
in: "path",
required: true,
description: "Product ID",
schema: {
type: "string",
},
},
],
requestBody: {
content: {
"application/json": {
schema: {
type: "object",
properties: {
sku: {
type: "string",
required: true,
},
name: {
type: "string",
required: true,
},
stock: {
type: "number",
required: true,
},
buyingPrice: {
type: "number",
required: true,
},
sellingPrice: {
type: "number",
required: true,
},
description: {
type: "string",
required: true,
},
gst: {
type: "number",
required: true,
},
hsn: {
type: "string",
required: true,
},
stock: {
type: "number",
required: true,
},
vendors: {
type: "array",
items: {
type: "string",
},
required: true,
},
},
},
},
},
},
responses: {
200: {
description: "OK",
content: {},
},
},
},
delete: {
summary: "Delete a Product",
tags: ["Product"],
parameters: [
{
name: "id",
in: "path",
required: true,
description: "Product ID",
schema: {
type: "string",
},
},
],
responses: {
200: {
description: "OK",
content: {},
},
},
},
},
};
+222
View File
@@ -0,0 +1,222 @@
export default {
"/vendor/all": {
get: {
summary: "Get All Vendors",
tags: ["Vendor"],
responses: {
200: {
description: "OK",
content: {},
},
},
},
},
"/vendor/{id}": {
get: {
summary: "Get Vendor Details",
tags: ["Vendor"],
parameters: [
{
in: "path",
required: true,
description: "Vendor ID",
schema: {
type: "string",
},
},
],
responses: {
200: {
description: "OK",
content: {},
},
},
},
patch: {
summary: "Get Vendor Details",
tags: ["Vendor"],
parameters: [
{
in: "path",
required: true,
description: "Vendor ID",
schema: {
type: "string",
},
},
],
requestBody: {
content: {
"application/json": {
schema: {
type: "object",
properties: {
name: {
type: "string",
required: true,
},
email: {
type: "string",
required: true,
},
mobile: {
type: "string",
required: true,
},
address: {
type: "string",
required: true,
},
city: {
type: "string",
required: true,
},
state: {
type: "string",
required: true,
},
picode: {
type: "string",
required: true,
},
isActive: {
type: "boolean",
required: true,
},
contactPersons: {
type: "array",
items: {
type: "object",
properties: {
name: {
type: "string",
required: true,
},
email: {
type: "string",
required: true,
},
mobile: {
type: "string",
required: true,
},
designation: {
type: "string",
required: true,
},
},
},
},
},
},
},
},
},
responses: {
200: {
description: "OK",
content: {},
},
},
},
delete: {
summary: "Deactivate Vendor",
tags: ["Vendor"],
parameters: [
{
in: "path",
required: true,
description: "Vendor ID",
schema: {
type: "string",
},
},
],
responses: {
200: {
description: "OK",
content: {},
},
},
},
},
"/vendor": {
post: {
summary: "Create New Vendor",
tags: ["Vendor"],
requestBody: {
content: {
"application/json": {
schema: {
type: "object",
properties: {
name: {
type: "string",
required: true,
},
email: {
type: "string",
required: true,
},
mobile: {
type: "string",
required: true,
},
address: {
type: "string",
required: true,
},
city: {
type: "string",
required: true,
},
state: {
type: "string",
required: true,
},
picode: {
type: "string",
required: true,
},
isActive: {
type: "boolean",
required: true,
},
contactPersons: {
type: "array",
items: {
type: "object",
properties: {
name: {
type: "string",
required: true,
},
email: {
type: "string",
required: true,
},
mobile: {
type: "string",
required: true,
},
designation: {
type: "string",
required: true,
},
},
},
},
},
},
},
},
},
responses: {
200: {
description: "OK",
content: {},
},
},
},
},
};
+156
View File
@@ -0,0 +1,156 @@
import { response } from "express";
export default {
"/venue/": {
post: {
tags: ["Venues"],
summary: "Create New Venue",
requestBody: {
content: {
"application/json": {
schema: {
type: "object",
properties: {
name: {
type: "string",
required: true,
},
category: {
type: "string",
required: true,
},
type: {
type: "string",
required: true,
},
entity: {
type: "string",
required: true,
},
address: {
type: "string",
required: true,
},
city: {
type: "string",
required: true,
},
state: {
type: "string",
required: true,
},
pincode: {
type: "string",
required: true,
},
contactPerson: {
type: "object",
required: true,
properties: {
name: {
type: "string",
required: true,
},
email: {
type: "string",
required: true,
},
mobile: {
type: "string",
required: true,
},
designation: {
type: "string",
required: true,
},
},
location: {
type: "object",
required: true,
properties: {
latitude: {
type: "number",
required: true,
},
longitude: {
type: "number",
required: true,
},
},
},
},
},
},
},
},
},
},
},
"/venue/entity/{id}": {
get: {
tags: ["Venues"],
summary: "Get Venues by Entity",
parameters: [
{
in: "path",
name: "id",
description: "Entity ID",
required: true,
schema: {
type: "string",
},
},
],
response: {
200: {
description: "Success",
content: {},
},
},
},
},
"/venue/{id}": {
get: {
tags: ["Venues"],
summary: "Get Venue by ID",
parameters: [
{
in: "path",
name: "id",
description: "Venue ID",
required: true,
schema: {
type: "string",
},
},
],
respose: {
200: {
description: "Success",
content: {},
},
},
},
delete: {
tags: ["Venues"],
summary: "Delete Venue by ID",
parameters: [
{
in: "path",
name: "id",
description: "Venue ID",
required: true,
schema: {
type: "string",
},
},
],
respose: {
200: {
description: "Success",
content: {},
},
},
},
},
};
+29 -2
View File
@@ -11,7 +11,16 @@ import swaggerUi from "swagger-ui-express";
import swaggerDoc from "./documentation/documentation.json"; import swaggerDoc from "./documentation/documentation.json";
import getSwaggerDocument from "./documentation"; import getSwaggerDocument from "./documentation";
// import socketState from "./state/socketState.js"; // import socketState from "./state/socketState.js";
import { AdminRoutes, UserRoutes, LocationRoutes } from "./routes"; import {
AdminRoutes,
UserRoutes,
LocationRoutes,
AssignmentRoutes,
PartnerRoutes,
VenueRoutes,
ProductRoutes,
VendorRoutes,
} from "./routes";
dotenv.config(); dotenv.config();
@@ -37,13 +46,31 @@ db.once("open", () =>
const app = express(); const app = express();
app.use(cors()); app.use(
cors({
origin: [
"http://localhost:1420",
"tauri://localhost",
"https://tauri.localhost",
"http://tauri.localhost",
],
}),
);
app.use(express.json()); app.use(express.json());
app.get("/test", (req, res, next) => {
res.json({status: "success"})
})
app.use("/v0/docs", swaggerUi.serve, swaggerUi.setup(swaggerDoc)); app.use("/v0/docs", swaggerUi.serve, swaggerUi.setup(swaggerDoc));
app.use("/v0/user", UserRoutes); app.use("/v0/user", UserRoutes);
app.use("/v0/admin", AdminRoutes); app.use("/v0/admin", AdminRoutes);
app.use("/v0/location", LocationRoutes); app.use("/v0/location", LocationRoutes);
app.use("/v0/assignment", AssignmentRoutes);
app.use("/v0/partner", PartnerRoutes);
app.use("/v0/venue", VenueRoutes);
app.use("/v0/product", ProductRoutes);
app.use("/v0/vendor", VendorRoutes);
app.use((err, req, res, next) => { app.use((err, req, res, next) => {
const statusCode = err.status || 500; const statusCode = err.status || 500;
BIN
View File
Binary file not shown.
+8
View File
@@ -36,6 +36,14 @@ const schema = new Schema({
type: Date, type: Date,
required: true, required: true,
}, },
city: {
type: String,
required: true,
},
state: {
type: String,
required: true,
},
}); });
export default model("access", schema); export default model("access", schema);
+30 -1
View File
@@ -1,5 +1,34 @@
import { model, Schema, Types } from "mongoose"; import { model, Schema, Types } from "mongoose";
const schema = new Schema({}); const schema = new Schema({
createdOn: {
type: Date,
required: true,
},
createdBy: {
type: Types.ObjectId,
required: true,
ref: "user",
},
isActive: {
type: Boolean,
default: true,
},
user: {
type: Types.ObjectId,
required: true,
ref: "user",
},
venue: {
type: Types.ObjectId,
required: true,
ref: "venue",
},
targetedVisits: {
type: Number,
required: true,
default: 5,
},
});
export default model("assignment", schema); export default model("assignment", schema);
+6 -1
View File
@@ -10,11 +10,16 @@ export const getAssignmentById = async (id) => {
return await Model.findById(id); return await Model.findById(id);
}; };
// Read (Get by Query) // Read (Get One by Query)
export const getAssignmentByQuery = async (query) => { export const getAssignmentByQuery = async (query) => {
return await Model.findOne(query); return await Model.findOne(query);
} }
// Read (Get All by Query)
export const getAssignmentsByQuery = async (query) => {
return await Model.find(query);
};
// Read (Get all) // Read (Get all)
export const getAllAssignments = async () => { export const getAllAssignments = async () => {
return await Model.find(); return await Model.find();
-10
View File
@@ -1,10 +0,0 @@
import { model, Schema, Types } from "mongoose";
const schema = new Schema({
createdOn: {
type: Date,
required: true
}
});
export default model("branch", schema);
+1 -1
View File
@@ -33,7 +33,7 @@ const schema = new Schema({
type: { type: {
type: String, type: String,
required: true, required: true,
enum: ["HQ", "Branch", "Warehouse", "BackOffice"], enum: ["HQ", "BRANCH", "WAREHOUSE"],
}, },
}); });
+104 -1
View File
@@ -1,5 +1,108 @@
import { model, Schema, Types } from "mongoose"; import { model, Schema, Types } from "mongoose";
const schema = new Schema({}); const paymentHistorySchema = new Schema({
amount: {
type: Number,
required: true,
},
paymentDate: {
type: Date,
required: true,
},
paymentMethod: {
type: String,
required: true,
},
transactionId: {
type: String,
required: true,
},
createdOn: {
type: Date,
required: true,
},
createdBy: {
type: Types.ObjectId,
ref: "user",
required: true,
},
});
const itemSchema = new Schema({
id: {
type: Types.ObjectId,
required: true,
},
unitCostPrice: {
type: Number,
required: true,
},
unitSellingPrice: {
type: Number,
required: true,
},
qty: {
type: Number,
required: true,
},
taxPercent: {
type: Number,
required: true,
},
taxAmount: {
type: Number,
required: true,
},
discount: {
type: Number,
required: true,
},
total: {
type: Number,
required: true,
},
});
const schema = new Schema({
customer: {
type: Types.ObjectId,
ref: "partner",
required: true,
},
items: {
type: [itemSchema],
required: true,
},
netTotal: {
type: Number,
required: true,
},
total: {
type: Number,
required: true,
},
status: {
type: String,
enum: ["PENDING", "COMPLETED", "PARTIAL"],
default: "PENDING",
},
dueDate: {
type: Date,
required: true,
},
createdOn: {
type: Date,
required: true,
},
createdBy: {
type: Types.ObjectId,
ref: "user",
required: true,
},
paymentHistory: {
type: [paymentHistorySchema],
default: [],
},
});
export default model("invoice", schema); export default model("invoice", schema);
+35 -3
View File
@@ -1,6 +1,23 @@
import { model, Schema, Types } from "mongoose"; import { model, Schema, Types } from "mongoose";
import { locationSchema } from "../../helpers"; import { locationSchema } from "../../helpers";
const geofenceSchema = new Schema({
venue: {
type: Types.ObjectId,
required: false,
ref: "venue",
},
assignment: {
type: Types.ObjectId,
required: false,
ref: "assignment",
},
action: {
type: String,
required: false,
},
});
const schema = new Schema({ const schema = new Schema({
user: { user: {
type: Types.ObjectId, type: Types.ObjectId,
@@ -12,10 +29,25 @@ const schema = new Schema({
type: Date, type: Date,
required: true, required: true,
}, },
venue: { battery: {
type: Types.ObjectId, type: Number,
required: true,
},
event: {
type: String,
required: false,
},
activity: {
type: String,
required: false,
},
heading: {
type: Number,
required: false,
},
geofence: {
type: geofenceSchema,
required: false, required: false,
ref: "venue",
}, },
}); });
+5 -4
View File
@@ -7,7 +7,7 @@ export const createLocation = async (data) => {
return await Model.create({ return await Model.create({
...data, ...data,
coordinates: geoJson, coordinates: geoJson,
createdOn: dayjs().toISOString(), createdOn: data?.recorded_at,
}); });
}; };
@@ -17,12 +17,13 @@ export const getLocationById = async (id) => {
}; };
// Read (Get by Query) // Read (Get by Query)
export const getLocationByQuery = async (query) => { export const getLocationsByQuery = async (query) => {
return await Model.findOne(query); console.log("QUERY", query);
return await Model.find(query).sort({ createdOn: -1 });
}; };
// Read (Get by Radius) // Read (Get by Radius)
export const getLocationByRadius = async (radius) => { export const getLocationsByRadius = async (radius) => {
return await Model.find(query); return await Model.find(query);
}; };
+16 -2
View File
@@ -20,10 +20,17 @@ const contactPersonSchema = new Schema({
}); });
const schema = new Schema({ const schema = new Schema({
id: {
type: String,
required: true,
},
name: { name: {
type: String, type: String,
required: true, required: true,
}, },
tags: {
type: [String],
},
createdBy: { createdBy: {
type: Types.ObjectId, type: Types.ObjectId,
required: true, required: true,
@@ -37,7 +44,7 @@ const schema = new Schema({
type: String, type: String,
required: true, required: true,
}, },
mobile: { phone: {
type: String, type: String,
required: true, required: true,
}, },
@@ -57,11 +64,18 @@ const schema = new Schema({
type: String, type: String,
required: true, required: true,
}, },
gst: {
type: String,
required: true,
},
isActive: { isActive: {
type: Boolean, type: Boolean,
default: true, default: true,
}, },
contactPersons: [contactPersonSchema], contactPersons: {
type: [contactPersonSchema],
required: true,
},
}); });
export default model("partner", schema); export default model("partner", schema);
+6 -1
View File
@@ -13,7 +13,12 @@ export const getPartnerById = async (id) => {
// Read (Get by Query) // Read (Get by Query)
export const getPartnerByQuery = async (query) => { export const getPartnerByQuery = async (query) => {
return await Model.findOne(query); return await Model.findOne(query);
} };
// Read (Get all)
export const getPartnersByQuery = async (query) => {
return await Model.find(query);
};
// Read (Get all) // Read (Get all)
export const getAllPartners = async () => { export const getAllPartners = async () => {
+4
View File
@@ -25,6 +25,10 @@ const schema = new Schema({
type: Number, type: Number,
required: true, required: true,
}, },
hsn: {
type: String,
required: true,
},
stock: { stock: {
type: Number, type: Number,
required: true, required: true,
+10 -1
View File
@@ -17,7 +17,16 @@ export const getProductByQuery = async (query) => {
// Read (Get all) // Read (Get all)
export const getAllProducts = async () => { export const getAllProducts = async () => {
return await Model.find(); return await Model.aggregate([
{
$lookup: {
from: "vendors",
localField: "vendors",
foreignField: "_id",
as: "vendors"
}
}
]);
}; };
// Update // Update
+5
View File
@@ -13,6 +13,10 @@ const schema = new Schema({
type: String, type: String,
required: true, required: true,
}, },
email: {
type: String,
required: false,
},
state: { state: {
type: String, type: String,
required: true, required: true,
@@ -28,6 +32,7 @@ const schema = new Schema({
user: { user: {
type: Types.ObjectId, type: Types.ObjectId,
required: true, required: true,
ref: 'user'
}, },
}); });
+8
View File
@@ -18,6 +18,8 @@ const moduleSchema = new Schema({
"salary", "salary",
"vendor", "vendor",
"expense", "expense",
"venue",
"metadata",
"product", "product",
"invoice", "invoice",
"partner", "partner",
@@ -28,6 +30,12 @@ const moduleSchema = new Schema({
"inventoryLog", "inventoryLog",
], ],
}, },
region: {
type: String,
required: true,
default: "CITY",
enum: ["CITY", "STATE", "COUNTRY"],
},
permission: { permission: {
type: String, type: String,
required: true, required: true,
+10 -1
View File
@@ -15,7 +15,7 @@ const schema = new Schema({
}, },
refreshToken: { refreshToken: {
type: String, type: String,
required: true, required: false,
}, },
isFirstTime: { isFirstTime: {
type: Boolean, type: Boolean,
@@ -25,6 +25,15 @@ const schema = new Schema({
type: Date, type: Date,
required: true, required: true,
}, },
createdBy: {
type: Types.ObjectId,
required: true,
ref: "user",
},
isActive: {
type: Boolean,
required: true,
},
}); });
export default model("user", schema); export default model("user", schema);
+7 -2
View File
@@ -10,10 +10,15 @@ export const getVendorById = async (id) => {
return await Model.findById(id); return await Model.findById(id);
}; };
// Read (Get by Query) // Read (Get One by Query)
export const getVendorByQuery = async (query) => { export const getVendorByQuery = async (query) => {
return await Model.findOne(query); return await Model.findOne(query);
} };
// Read (Get All by Query)
export const getVendorsByQuery = async (query) => {
return await Model.find(query);
};
// Read (Get all) // Read (Get all)
export const getAllVendors = async () => { export const getAllVendors = async () => {
+41 -10
View File
@@ -1,6 +1,25 @@
import { model, Schema, Types } from "mongoose"; import { model, Schema, Types } from "mongoose";
import { locationSchema } from "../../helpers"; import { locationSchema } from "../../helpers";
const contactPersonSchema = new Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
mobile: {
type: String,
required: true,
},
designation: {
type: String,
required: true,
},
});
const schema = new Schema({ const schema = new Schema({
name: { name: {
type: String, type: String,
@@ -15,6 +34,22 @@ const schema = new Schema({
type: Date, type: Date,
required: true, required: true,
}, },
address: {
type: String,
required: true,
},
city: {
type: String,
required: true,
},
state: {
type: String,
required: true,
},
pincode: {
type: String,
required: true,
},
location: locationSchema, location: locationSchema,
category: { category: {
type: String, type: String,
@@ -25,19 +60,15 @@ const schema = new Schema({
type: { type: {
type: String, type: String,
required: true, required: true,
enum: [ enum: ["HQ", "BRANCH", "WAREHOUSE"],
"HQ",
"BRANCH",
"WAREHOUSE",
"VENDOR",
"PARTNER",
"DISTRIBUTOR",
"CLIENT",
],
}, },
entity: { entity: {
type: Types.ObjectId, type: Types.ObjectId,
required: true, required: false,
},
contactPerson: {
type: contactPersonSchema,
required: false,
}, },
}); });
+5 -5
View File
@@ -11,13 +11,13 @@ export const getVenueById = async (id) => {
}; };
// Read (Get by Query) // Read (Get by Query)
export const getVenueByQuery = async (query) => { export const getVenuesByQuery = async (query) => {
return await Model.findOne(query); return await Model.find(query);
} };
// Read (Get all) // Read (Get all)
export const getAllVenues = async () => { export const getAllVenues = async (query = {}) => {
return await Model.find(); return await Model.find(query);
}; };
// Update // Update
+1
View File
@@ -19,3 +19,4 @@ export { default as Designation } from "./Designation/model";
export { default as Inventory } from "./Inventory/model"; export { default as Inventory } from "./Inventory/model";
export { default as InventoryLog } from "./InventoryLog/model"; export { default as InventoryLog } from "./InventoryLog/model";
export { default as Role } from "./Role/model"; export { default as Role } from "./Role/model";
export { default as Venue } from "./Venue/model";
+22 -11
View File
@@ -3,36 +3,45 @@ import { authorize } from "../middlewares/jwt.middleware";
import { import {
createAccessController, createAccessController,
getAllBranchesController, getAllBranchesController,
getAllDesignationsController, getAllMetadataController,
getAllDepartmentsController,
getAllRolesController,
createBranchController, createBranchController,
createDepartmentController, createDepartmentController,
createDesignationController, createDesignationController,
createRoleController, createRoleController,
updateRoleController,
getAllEmployeeController,
getEmployeeDetailsController,
getEmployeeLocationHistoryController,
} from "../controllers/admin.controller"; } from "../controllers/admin.controller";
import { createEmployee } from "../controllers/workflow.controller";
const router = new Router(); const router = new Router();
router.post("/access", authorize("access", "write"), createAccessController); router.post("/access", authorize("access", "write"), createAccessController);
router.get("/branches", authorize("branch", "read"), getAllBranchesController); router.get("/branches", authorize("branch", "read"), getAllBranchesController);
router.get( router.get(
"/designations", "/metadata",
authorize("designation", "read"), authorize("designation", "read"),
getAllDesignationsController, getAllMetadataController,
); );
router.get(
"/departments",
authorize("department", "read"),
getAllDepartmentsController,
);
router.get("/roles", authorize("role", "read"), getAllRolesController);
router.post("/branch", authorize("branch", "write"), createBranchController); router.post("/branch", authorize("branch", "write"), createBranchController);
router.post( router.post(
"/department", "/department",
authorize("department", "write"), authorize("department", "write"),
createDepartmentController, createDepartmentController,
); );
router.get("/employees", authorize("user", "read"), getAllEmployeeController);
router.post("/employee", authorize("user", "write"), createEmployee);
router.get(
"/employee/:id",
authorize("user", "read"),
getEmployeeDetailsController,
);
router.get(
"/employee/:user/locations",
authorize("user", "read"),
getEmployeeLocationHistoryController,
);
router.post( router.post(
"/designation", "/designation",
authorize("designation", "write"), authorize("designation", "write"),
@@ -40,4 +49,6 @@ router.post(
); );
router.post("/role", authorize("role", "write"), createRoleController); router.post("/role", authorize("role", "write"), createRoleController);
router.patch("/role/:id", authorize("role", "write"), updateRoleController);
export default router; export default router;
+33
View File
@@ -0,0 +1,33 @@
import { Router } from "express";
import {
createAssignmentHandler,
updateAssignmentHandler,
getAssignmentsByUserHandler,
deactivateAssignmentHandler,
getAssignmentByVenueHandler,
getAssignmentByIdHandler,
} from "../controllers/assignment.controller";
import { authorize } from "../middlewares/jwt.middleware";
const router = new Router();
router.post("/", authorize("assignment", "write"), createAssignmentHandler);
router.patch("/:id", authorize("assignment", "write"), updateAssignmentHandler);
router.get("/:id", authorize("assignment", "read"), getAssignmentByIdHandler);
router.get(
"/user/:id",
authorize("assignment", "read"),
getAssignmentsByUserHandler,
);
router.delete(
"/:id",
authorize("assignment", "write"),
deactivateAssignmentHandler,
);
router.get(
"/venue/:id",
authorize("assignment", "read"),
getAssignmentByVenueHandler,
);
export default router;
+5
View File
@@ -2,3 +2,8 @@ export { default as UserRoutes } from "./user.route";
export { default as ProfileRoutes } from "./profile.route"; export { default as ProfileRoutes } from "./profile.route";
export { default as AdminRoutes } from "./admin.route"; export { default as AdminRoutes } from "./admin.route";
export { default as LocationRoutes } from "./location.route"; export { default as LocationRoutes } from "./location.route";
export { default as AssignmentRoutes } from "./assignment.route";
export { default as VenueRoutes } from "./venue.route";
export { default as PartnerRoutes } from "./partner.route";
export { default as ProductRoutes } from "./product.route";
export { default as VendorRoutes } from "./vendor.route";
+14 -2
View File
@@ -1,6 +1,12 @@
import { Router } from "express"; import { Router } from "express";
import { authorizeWithEncryptedKey } from "../middlewares/jwt.middleware"; import {
import { createLocationController } from "../controllers/location.controller"; authorize,
authorizeWithEncryptedKey,
} from "../middlewares/jwt.middleware";
import {
createLocationController,
getMyAssignedVenuesHandler,
} from "../controllers/location.controller";
const router = new Router(); const router = new Router();
@@ -10,4 +16,10 @@ router.post(
createLocationController, createLocationController,
); );
router.get(
"/venues/assigned/me",
authorize("generic", "generic"),
getMyAssignedVenuesHandler,
);
export default router; export default router;
+20
View File
@@ -0,0 +1,20 @@
import { Router } from "express";
import {
createPartnerController,
getPartnerController,
getPartnersController,
getAllPartnersController,
updatePartnerController,
deletePartnerController,
} from "../controllers/partner.controller";
import { authorize } from "../middlewares/jwt.middleware";
const router = new Router();
router.post("/", authorize("partner", "write"), createPartnerController);
router.get("/", authorize("partner", "read"), getAllPartnersController);
router.get("/:id", authorize("partner", "read"), getPartnerController);
router.patch("/:id", authorize("partner", "write"), updatePartnerController);
router.delete("/:id", authorize("partner", "write"), deletePartnerController);
export default router;
+17
View File
@@ -0,0 +1,17 @@
import { Router } from "express";
import { authorize } from "../middlewares/jwt.middleware";
import {
createProductController,
deleteProductController,
getAllProductsController,
updateProductController,
} from "../controllers/product.controller";
const router = Router();
router.post("/", authorize("product", "write"), createProductController);
router.get("/", authorize("product", "read"), getAllProductsController);
router.patch("/:id", authorize("product", "write"), updateProductController);
router.delete("/:id", authorize("product", "delete"), deleteProductController);
export default router;
+2 -2
View File
@@ -1,7 +1,7 @@
import { Router } from "express"; import { Router } from "express";
import { import {
createOrEditProfileController, createOrEditProfileController,
getProfileController, getOwnProfileController,
} from "../controllers/profile.controller"; } from "../controllers/profile.controller";
import { authorize } from "../middlewares/jwt.middleware"; import { authorize } from "../middlewares/jwt.middleware";
@@ -12,6 +12,6 @@ router.post(
authorize("generic", "generic"), authorize("generic", "generic"),
createOrEditProfileController, createOrEditProfileController,
); );
router.get("/", authorize("generic", "generic"), getProfileController); router.get("/", authorize("generic", "generic"), getOwnProfileController);
export default router; export default router;
+25
View File
@@ -0,0 +1,25 @@
import { Router } from "express";
import {
createVendorController,
updateVendorController,
getActiveVendorsController,
getAllVendorsController,
deactivateVendorController,
getVendorByIdController,
} from "../controllers/vendor.controller";
import { authorize } from "../middlewares/jwt.middleware";
const router = Router();
router.post("/", authorize("vendor", "write"), createVendorController);
router.patch("/:id", authorize("vendor", "write"), updateVendorController);
router.get("/active", authorize("vendor", "read"), getActiveVendorsController);
router.get("/all", authorize("vendor", "read"), getAllVendorsController);
router.delete(
"/:id",
authorize("vendor", "delete"),
deactivateVendorController,
);
router.get("/:id", authorize("vendor", "read"), getVendorByIdController);
export default router;
+33
View File
@@ -0,0 +1,33 @@
import { Router } from "express";
import {
createVenueController,
deleteVenueController,
getVenuesByEntityController,
getVenueController,
getAssignedVenuesController,
getUnassignedVenuesController,
} from "../controllers/venue.controller";
import { authorize } from "../middlewares/jwt.middleware";
const router = new Router();
router.post("/", authorize("venue", "write"), createVenueController);
router.get(
"/entity/:id",
authorize("venue", "read"),
getVenuesByEntityController,
);
router.get("/details/:id", authorize("venue", "read"), getVenueController);
router.get(
"/assigned/:userId",
authorize("venue", "read"),
getAssignedVenuesController,
);
router.get(
"/unassigned",
authorize("venue", "read"),
getUnassignedVenuesController,
);
router.delete("/:id", authorize("venue", "write"), deleteVenueController);
export default router;