Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 128 additions & 0 deletions src/controllers/kitchenInventory/kitchenOrderController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/* eslint-disable max-lines-per-function */
const mongoose = require('mongoose');
const Supplier = require('../../models/kitchenInventory/supplier');
const Order = require('../../models/kitchenInventory/order');

const kitchenOrderController = function () {
// POST /orders/{id}
const createOrder = async (req, res) => {
try {
const { supplierId } = req.body;

if (!mongoose.Types.ObjectId.isValid(supplierId)) {
return res.status(400).json('Invalid Supplier id');
}

const supplier = await Supplier.findById(supplierId);

if (!supplier || !supplier.isActive) {

Check warning on line 18 in src/controllers/kitchenInventory/kitchenOrderController.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Prefer using an optional chain expression instead, as it's more concise and easier to read.

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HGNRest&issues=AZ0zawFPPU4l3pg_wVkz&open=AZ0zawFPPU4l3pg_wVkz&pullRequest=2047
return res.status(400).json('Supplier Not Found');
}

const order = new Order(req.body);

Check failure on line 22 in src/controllers/kitchenInventory/kitchenOrderController.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Change this code to not use user-controlled data for mass assignment in database operations.

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HGNRest&issues=AZ0zawFPPU4l3pg_wVk1&open=AZ0zawFPPU4l3pg_wVk1&pullRequest=2047
const saved = await order.save();
res.status(201).json(saved);
} catch (err) {
res.status(400).json(err);
}
};

// GET /orders
const getOrders = async (req, res) => {
try {
const filter = {};

if (req.query.supplierId) {
if (!mongoose.Types.ObjectId.isValid(req.query.supplierId)) {
return res.status(400).send('Invalid Supplier Id');
}
filter.supplierId = mongoose.Types.ObjectId(req.query.supplierId);
}

if (req.query.status) {
filter.status = req.query.status;
}

const results = await Order.find(filter)

Check failure on line 46 in src/controllers/kitchenInventory/kitchenOrderController.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Change this code to not construct database queries directly from user-controlled data.

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HGNRest&issues=AZ0zawFPPU4l3pg_wVk0&open=AZ0zawFPPU4l3pg_wVk0&pullRequest=2047
.populate({ path: 'supplierId', select: 'name email phone' })
.sort({ orderDate: -1 })
.lean();
res.status(200).send(results);
} catch (err) {
res.status(500).send(err);
}
};

// GET /order/{id}
const getOrderById = async (req, res) => {
const { orderId } = req.params;
if (!mongoose.Types.ObjectId.isValid(orderId)) {
return res.status(400).send('Invalid order id');
}

try {
const order = await Order.findById(orderId);
if (!order) {
return res.status(404).json('Order Not Found');
}

res.status(200).json(order);
} catch (err) {
res.status(500).send(err);
}
};

// PUT /supplier/{id}
const updateOrder = async (req, res) => {
const { orderId } = req.params;

if (!mongoose.Types.ObjectId.isValid(orderId)) {
return res.status(400).send('Invalid order id');
}

try {
if (req.body.items && req.body.items.length > 0) {
req.body.totalAmount = req.body.items.reduce(
(sum, item) => sum + item.quantity * item.pricePerItem,
0,
);
}
const updated = await Order.findByIdAndUpdate(orderId, req.body, { new: true });
if (!updated) {
return res.status(404).json('Order Not Found');
}
res.status(200).send(updated);
} catch (err) {
res.status(400).json(err);
}
};

// DELETE /order/{id}
const deleteOrder = async (req, res) => {
const { orderId } = req.params;

if (!mongoose.Types.ObjectId.isValid(orderId)) {
res.status(400).json('Invalid Order Id');
}

try {
const removed = await Order.findByIdAndDelete(orderId);
if (!removed) {
return res.status(404).json('Order Not Found');
}
res.status(200).json({ message: 'Deleted' });
} catch (err) {
res.status(500).json(err);
}
};

return {
createOrder,
getOrders,
getOrderById,
updateOrder,
deleteOrder,
};
};

module.exports = kitchenOrderController;
129 changes: 129 additions & 0 deletions src/controllers/kitchenInventory/kitchenSupplierController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/* eslint-disable max-lines-per-function */
const mongoose = require('mongoose');
const Supplier = require('../../models/kitchenInventory/supplier');
const Order = require('../../models/kitchenInventory/order');

const kitchenSupplierController = function () {
const createSupplier = async (req, res) => {
try {
const existingSupplier = await Supplier.findOne({
name: { $regex: new RegExp(`^${req.body.name}$`, 'i') },
});
if (existingSupplier) return res.status(400).json('Supplier already exists');

const supplier = new Supplier(req.body);

Check failure on line 14 in src/controllers/kitchenInventory/kitchenSupplierController.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Change this code to not use user-controlled data for mass assignment in database operations.

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HGNRest&issues=AZ0zawFcPU4l3pg_wVk3&open=AZ0zawFcPU4l3pg_wVk3&pullRequest=2047
const result = await supplier.save();
res.status(201).json(result);
} catch (err) {
res.status(400).json(err.message);
}
};

const getSuppliers = async (req, res) => {
try {
const results = await Supplier.find().lean();
res.status(200).json(results);
} catch (err) {
res.status(500).json(err.message);
}
};

const getSupplierById = async (req, res) => {
const { supplierId } = req.params;

if (!mongoose.Types.ObjectId.isValid(supplierId)) {
return res.status(400).json('Invalid Supplier');
}

try {
const supplier = await Supplier.findById(supplierId).lean();
if (!supplier) {
return res.status(404).json('Supplier Not found');
}

const agg = await Order.aggregate([
{
$match: {
supplierId: new mongoose.Types.ObjectId(supplierId),
status: 'Delivered',
actualDeliveryDate: { $exists: true },
},
},
{
$project: {
diffDays: {
$divide: [{ $subtract: ['$actualDeliveryDate', '$orderDate'] }, 1000 * 60 * 60 * 24],
},
},
},
{
$group: {
_id: null,
totalOrders: { $sum: 1 },
avgDeliveryDays: { $avg: '$diffDays' },
},
},
]);

const totals = agg[0] || { totalOrders: 0, avgDeliveryDays: 0 };

const response = {
...supplier,
attributes: supplier.specialities || [],
totalOrders: totals.totalOrders || 0,
avgDeliveryDays:
totals.avgDeliveryDays !== undefined ? Number(totals.avgDeliveryDays.toFixed(2)) : 0,

Check warning on line 75 in src/controllers/kitchenInventory/kitchenSupplierController.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Unexpected negated condition.

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HGNRest&issues=AZ0zawFcPU4l3pg_wVk2&open=AZ0zawFcPU4l3pg_wVk2&pullRequest=2047
};

res.status(200).json(response);
} catch (err) {
res.status(500).json(err.message);
}
};

const updateSupplier = async (req, res) => {
const { supplierId } = req.params;

if (!mongoose.Types.ObjectId.isValid(supplierId)) {
return res.status(400).json('Invalid Supplier Id');
}
try {
req.body.updated = Date.now();
const updated = await Supplier.findByIdAndUpdate(supplierId, req.body, { new: true });
if (!updated) {
return res.status(404).json('Supplier Not Found');
}
res.status(200).json(updated);
} catch (err) {
res.status(400).json(err);
}
};

const deleteSupplier = async (req, res) => {
const { supplierId } = req.params;

if (!mongoose.Types.ObjectId.isValid(supplierId)) {
return res.status(400).json('Invalid Supplier Id');
}

try {
const removed = await Supplier.findByIdAndDelete(supplierId);
if (!removed) {
return res.status(404).json('Supplier Not Found');
}
res.status(200).json({ message: 'Deleted' });
} catch (err) {
res.status(500).json(err);
}
};

return {
createSupplier,
getSuppliers,
getSupplierById,
updateSupplier,
deleteSupplier,
};
};

module.exports = kitchenSupplierController;
63 changes: 63 additions & 0 deletions src/models/kitchenInventory/order.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
const mongoose = require('mongoose');

const { Schema } = mongoose;

const Order = new Schema({
supplierId: {
type: Schema.Types.ObjectId,
ref: 'supplier',
required: true,
},
status: {
type: String,
required: true,
enum: ['Pending', 'Ordered', 'Shipped', 'Delivered', 'Cancelled'],
default: 'Pending',
},
orderDate: {
type: Date,
default: Date.now,
},
expectedDeliveryDate: {
type: Date,
},
actualDeliveryDate: {
type: Date,
},
items: [
{
itemName: {
type: String,
required: true,
trim: true,
},
quantity: {
type: Number,
required: true,
min: 1,
},
pricePerItem: {
type: Number,
required: true,
min: 0,
},
},
],
totalAmount: {
type: Number,
default: 0,
},
created: {
type: Date,
default: Date.now,
},
});

Order.pre('save', function (next) {
if (this.items && this.items.length > 0) {
this.totalAmount = this.items.reduce((sum, item) => sum + item.quantity * item.pricePerItem, 0);
}
next();
});

module.exports = mongoose.model('order', Order, 'orders');
55 changes: 55 additions & 0 deletions src/models/kitchenInventory/supplier.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
const mongoose = require('mongoose');

const { Schema } = mongoose;

const Supplier = new Schema({
name: {
type: String,
required: true,
trim: true,
},
contact: {
type: String,
trim: true,
},
email: {
type: String,
required: true,
lowercase: true,
match: [/^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/, 'Provide Valid email address'],
},
phone: {
type: String,
required: true,
trim: true,
},
specialities: [
{
type: String,
trim: true,
},
],
website: {
type: String,
trim: true,
match: [
/^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([/\w .-]*)*\/?$/,

Check warning on line 36 in src/models/kitchenInventory/supplier.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Rework this part of the regex to not match the empty string.

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HGNRest&issues=AZ0zawDkPU4l3pg_wVky&open=AZ0zawDkPU4l3pg_wVky&pullRequest=2047
'Provide valid website url',
],
},
isActive: {
type: Boolean,
default: true,
},
created: {
type: Date,
required: true,
default: Date.now,
},
updated: {
type: Date,
default: Date.now,
},
});

module.exports = mongoose.model('supplier', Supplier, 'suppliers');
17 changes: 17 additions & 0 deletions src/routes/kitchenInventory/kitchenOrderRouter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const express = require('express');

const routes = function () {
const controller = require('../../controllers/kitchenInventory/kitchenOrderController')();
const kitchenOrderRouter = express.Router();

kitchenOrderRouter.route('/orders').get(controller.getOrders).post(controller.createOrder);
kitchenOrderRouter
.route('/orders/:orderId')
.get(controller.getOrderById)
.put(controller.updateOrder)
.delete(controller.deleteOrder);

return kitchenOrderRouter;
};

module.exports = routes;
Loading
Loading