Skip to content

Commit

Permalink
Merge pull request #620 from OneCommunityGlobal/development
Browse files Browse the repository at this point in the history
Backend Release to Main [1.20]
  • Loading branch information
one-community authored Nov 28, 2023
2 parents 81c38ae + 809f0d2 commit dac03d4
Show file tree
Hide file tree
Showing 17 changed files with 471 additions and 100 deletions.
104 changes: 52 additions & 52 deletions package-lock.json

Large diffs are not rendered by default.

19 changes: 19 additions & 0 deletions src/controllers/bmdashboard/bmInventoryTypeController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const bmInventoryTypeController = function (InvType) {
const fetchMaterialTypes = async (req, res) => {
try {
InvType
.find()
.exec()
.then(result => res.status(200).send(result))
.catch(error => res.status(500).send(error));
} catch (err) {
res.json(err);
}
};

return {
fetchMaterialTypes,
};
};

module.exports = bmInventoryTypeController;
64 changes: 62 additions & 2 deletions src/controllers/bmdashboard/bmMaterialsController.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
const mongoose = require('mongoose');

const bmMaterialsController = function (ItemMaterial) {
// use in bmPurchaseMaterials auth check (see below)
// const buildingProject = require('../../models/bmdashboard/buildingProject');

const bmMaterialsController = function (ItemMaterial, BuildingMaterial) {
const bmMaterialsList = async function _matsList(req, res) {
try {
ItemMaterial.find()
Expand Down Expand Up @@ -42,7 +45,64 @@ const bmMaterialsController = function (ItemMaterial) {
res.json(err);
}
};
return { bmMaterialsList };

const bmPurchaseMaterials = async function (req, res) {
const {
projectId,
matTypeId,
quantity,
priority,
brand,
requestor: { requestorId },
} = req.body;
const newPurchaseRecord = {
quantity,
priority,
brand,
requestedBy: requestorId,
};
try {
// check if requestor has permission to make purchase request
//! Note: this code is disabled until permissions are added
// TODO: uncomment this code to execute auth check
// const { buildingManager: bmId } = await buildingProject.findById(projectId, 'buildingManager').exec();
// if (bmId !== requestorId) {
// res.status(403).send({ message: 'You are not authorized to edit this record.' });
// return;
// }

// check if the material is already being used in the project
// if no, add a new document to the collection
// if yes, update the existing document
const doc = await BuildingMaterial.findOne({ project: projectId, itemType: matTypeId });
if (!doc) {
const newDoc = {
itemType: matTypeId,
project: projectId,
purchaseRecord: [newPurchaseRecord],
};
BuildingMaterial
.create(newDoc)
.then(() => res.status(201).send())
.catch(error => res.status(500).send(error));
return;
}
BuildingMaterial
.findOneAndUpdate(
{ _id: mongoose.Types.ObjectId(doc._id) },
{ $push: { purchaseRecord: newPurchaseRecord } },
)
.exec()
.then(() => res.status(201).send())
.catch(error => res.status(500).send(error));
} catch (error) {
res.status(500).send(error);
}
};
return {
bmMaterialsList,
bmPurchaseMaterials,
};
};

module.exports = bmMaterialsController;
7 changes: 6 additions & 1 deletion src/controllers/inventoryController.js
Original file line number Diff line number Diff line change
Expand Up @@ -548,10 +548,15 @@ const inventoryController = function (Item, ItemType) {
}
const itemType = new ItemType();

itemType.type = req.body.type;
itemType.name = req.body.name;
itemType.description = req.body.description;
itemType.uom = req.body.uom;
itemType.totalStock = req.body.totalStock;
itemType.totalAvailable = req.body.totalAvailable;
itemType.projectsUsing = [];
itemType.imageUrl = req.body.imageUrl || req.body.imageURL;
itemType.quantifier = req.body.quantifier;
itemType.link = req.body.link;

itemType.save()
.then(results => res.status(201).send(results))
Expand Down
140 changes: 140 additions & 0 deletions src/controllers/mapLocationsController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
const UserProfile = require('../models/userProfile');
const cache = require('../utilities/nodeCache')();


const mapLocationsController = function (MapLocation) {
const getAllLocations = async function (req, res) {

try {
const users = [];
const results = await UserProfile.find({},
'_id firstName lastName isActive location jobTitle totalTangibleHrs hoursByCategory'
);

results.forEach((item) => {
if (
(item.location?.coords.lat && item.location?.coords.lng && item.totalTangibleHrs >= 10) ||
(item.location?.coords.lat && item.location?.coords.lng && calculateTotalHours(item.hoursByCategory) >= 10)
) {
users.push(item);
}
});
const modifiedUsers = users.map(item => ({
location: item.location,
isActive: item.isActive,
jobTitle: item.jobTitle[0],
_id: item._id,
firstName: item.firstName,
lastName: item.lastName
}));

const mUsers = await MapLocation.find({});
res.status(200).send({ users: modifiedUsers, mUsers });
} catch (err) {
res.status(404).send(err);
}

};
const deleteLocation = async function (req, res) {

if (!req.body.requestor.role === 'Administrator' || !req.body.requestor.role === 'Owner') {
res.status(403).send('You are not authorized to make changes in the teams.');
return;
}
const locationId = req.params.locationId

MapLocation.findOneAndDelete({ _id: locationId })
.then(() => res.status(200).send({ message: "The location was successfully removed!" }))
.catch(error => res.status(500).send({ message: error || "Couldn't remove the location" }));
};
const putUserLocation = async function (req, res) {

if (!req.body.requestor.role === 'Owner') {
res.status(403).send('You are not authorized to make changes in the teams.');
return;
}
const locationData = {
firstName: req.body.firstName,
lastName: req.body.lastName,
jobTitle: req.body.jobTitle,
location: req.body.location,
}
const location = new MapLocation(locationData);

try {
const response = await location.save()
if (!response) {
throw new Error('Something went wrong during saving the location...')
}
res.status(200).send(response);
} catch (err) {
console.log(err.message)
res.status(500).json({ message: err.message || 'Something went wrong...' });
}
};
const updateUserLocation = async function (req, res) {
if (!req.body.requestor.role === 'Owner') {
res.status(403).send('You are not authorized to make changes in the teams.');
return;
}
const userType = req.body.type;
const userId = req.body._id;
const updateData = {
firstName: req.body.firstName,
lastName: req.body.lastName,
jobTitle: req.body.jobTitle,
location: req.body.location,
}

if (req.body.timeZone) {
updateData.timeZone = req.body.timeZone
}

try {
let response;
if (userType === 'user') {
response = await UserProfile.findOneAndUpdate({ _id: userId }, { $set: { ...updateData, jobTitle: [updateData.jobTitle] } }, { new: true });
cache.removeCache('allusers')
cache.removeCache(`user-${userId}`);

cache.setCache(`user-${userId}`, JSON.stringify(response));
} else {
response = await MapLocation.findOneAndUpdate({ _id: userId }, { $set: updateData }, { new: true })
}

if (!response) {
throw new Error('Something went wrong during saving the location...')
}
const newData = {
firstName: response.firstName,
lastName: response.lastName,
jobTitle: response.jobTitle,
location: response.location,
_id: response._id,
type: userType
}

res.status(200).send(newData);
} catch (err) {
console.log(err.message)
res.status(500).json({ message: err.message || 'Something went wrong...' });
}
};

function calculateTotalHours(hoursByCategory) {
let hours = 0;
Object.keys(hoursByCategory).forEach((x) => {
hours += hoursByCategory[x];
});
return hours;
}

return {
getAllLocations,
deleteLocation,
putUserLocation,
updateUserLocation
};
};

module.exports = mapLocationsController;
2 changes: 1 addition & 1 deletion src/controllers/profileInitialSetupController.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ function informManagerMessage(user) {
</tr>
<tr>
<td><strong>Location:</strong></td>
<td>${user.location}</td>
<td>${user.location.userProvided}, ${user.location.country}</td>
</tr>
</table>
<br>
Expand Down
66 changes: 41 additions & 25 deletions src/controllers/timeEntryController.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ const timeEntrycontroller = function (TimeEntry) {
const initialSeconds = timeEntry.totalSeconds;
const initialProjectId = timeEntry.projectId;
const initialIsTangible = timeEntry.isTangible;
// Get the task related to this time entry, if not found, then it's a project and will be null
const findTask = await task.findById(initialProjectId);

timeEntry.notes = req.body.notes;
timeEntry.totalSeconds = totalSeconds;
Expand All @@ -134,19 +136,19 @@ const timeEntrycontroller = function (TimeEntry) {
// initialIsTangible is a bealoon value, req.body.isTangible is a string
// initialProjectId may be a task id or project id, so do not throw error.
try {
if (initialIsTangible === true) {
const initialTask = await task.findById(initialProjectId);
initialTask.hoursLogged -= (initialSeconds / 3600);
await initialTask.save();
}
if (findTask) {
if (initialIsTangible === true) {
findTask.hoursLogged -= (initialSeconds / 3600);
}

if (req.body.isTangible === true) {
findTask.hoursLogged += (totalSeconds / 3600);
}

if (req.body.isTangible === true) {
const editedTask = await task.findById(req.body.projectId);
editedTask.hoursLogged += (totalSeconds / 3600);
await editedTask.save();
await findTask.save();
}
} catch (error) {
console.log('Failed to find task by id');
throw new Error(error);
}

// Update edit history
Expand Down Expand Up @@ -203,10 +205,13 @@ const timeEntrycontroller = function (TimeEntry) {

res.status(200).send({ message: 'Successfully updated time entry' });

// checking if logged in hours exceed estimated time after timeentry edit for a task
const record = await userProfile.findById(timeEntry.personId.toString());
const currentTask = await task.findById(req.body.projectId);
checkTaskOvertime(timeEntry, record, currentTask);
// If the time entry isn't related to a task (i.e. it's a project), then don't check for overtime (Most likely pr team)
if (findTask) {
// checking if logged in hours exceed estimated time after timeentry edit for a task
const record = await userProfile.findById(timeEntry.personId.toString());
const currentTask = await task.findById(req.body.projectId);
checkTaskOvertime(timeEntry, record, currentTask);
}
} catch (err) {
await session.abortTransaction();
return res.status(400).send({ error: err.toString() });
Expand Down Expand Up @@ -271,20 +276,28 @@ const timeEntrycontroller = function (TimeEntry) {
})
.catch(error => res.status(400).send(error));

// Add this tangbile time entry to related task's hoursLogged
if (timeentry.isTangible === true) {
// Get the task related to this time entry, if not found, then it's a project sets to null
const currentTask = await task.findById(req.body.projectId).catch(() => null);

// Add this tangbile time entry to related task's hoursLogged and checks if timeEntry is related to a task
if (timeentry.isTangible === true && currentTask) {
try {
const currentTask = await task.findById(req.body.projectId);
currentTask.hoursLogged += (timeentry.totalSeconds / 3600);
currentTask.hoursLogged += timeentry.totalSeconds / 3600;
await currentTask.save();
} catch (error) {
throw new Error('Failed to find the task by id');
throw new Error(error);
}
}

// checking if logged in hours exceed estimated time after timeentry for a task, only if the time entry is related to a task (It might not be, if it's a project)
if (currentTask) {
try {
const record = await userProfile.findById(timeentry.personId.toString());
checkTaskOvertime(timeentry, record, currentTask);
} catch (error) {
throw new Error(error);
}
}
// checking if logged in hours exceed estimated time after timeentry for a task
const record = await userProfile.findById(timeentry.personId.toString());
const currentTask = await task.findById(req.body.projectId);
checkTaskOvertime(timeentry, record, currentTask);
};

const getTimeEntriesForSpecifiedPeriod = function (req, res) {
Expand Down Expand Up @@ -469,8 +482,11 @@ const timeEntrycontroller = function (TimeEntry) {
if (record.isTangible === true) {
task.findById(record.projectId)
.then((currentTask) => {
currentTask.hoursLogged -= (record.totalSeconds / 3600);
currentTask.save();
// If the time entry isn't related to a task (i.e. it's a project), then don't revert hours (Most likely pr team)
if (currentTask) {
currentTask.hoursLogged -= (record.totalSeconds / 3600);
currentTask.save();
}
})
.catch((error) => {
throw new Error(error);
Expand Down
13 changes: 13 additions & 0 deletions src/models/bmdashboard/buildingInventoryType.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const mongoose = require('mongoose');

const { Schema } = mongoose;

const buildingInventoryType = new Schema({
category: { type: String, enum: ['Consumable', 'Material', 'Tool', 'Equipment'], required: true },
name: { type: String, required: true },
description: { type: String, required: true },
unit: { type: String, required: true }, // unit of measurement
imageUrl: String,
});

module.exports = mongoose.model('buildingInventoryType', buildingInventoryType, 'buildingInventoryTypes');
Loading

0 comments on commit dac03d4

Please sign in to comment.