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
167 changes: 167 additions & 0 deletions src/controllers/kitchenandinventory/KIInventoryController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
const KIInventoryItem = require('../../models/kitchenandinventory/KIInventoryItems');

const KIInventoryController = () => {
const addItem = async (req, res) => {
const {
name,
storedQuantity,
unit,
type,
monthlyUsage,
category,
expiryDate,
location,
onsite,
reorderAt,
lastHarvestDate,
nextHarvestDate,
nextHarvestQuantity,
} = req.body;
const newItem = new KIInventoryItem({
name,
storedQuantity,
presentQuantity: storedQuantity,
unit,
type,
monthlyUsage,
category,
expiryDate,
location,
onsite,
reorderAt,
lastHarvestDate,
nextHarvestDate,
nextHarvestQuantity,
});
try {
const savedItem = await newItem.save();
res.status(201).json({
message: 'Inventory item added successfully',
data: savedItem,
});
} catch (error) {
res.status(400).json({ message: error.message });
}
};
const getItems = async (req, res) => {
try {
const items = await KIInventoryItem.find(null, { __v: 0 }).lean().sort({ createdAt: -1 });
res.status(200).json({ message: 'All Items fetched successfully.', data: items });
} catch (err) {
res.status(400).json({ message: 'Something went wrong while fetching items.' });
}
};
const getItemsByCategory = async (req, res) => {
const { category } = req.params;
try {
const items = await KIInventoryItem.find({ category }, { __v: 0 })
.lean()
.sort({ createdAt: -1 });
res.status(200).json({ message: 'Items fetched successfully.', data: items });
} catch (err) {
res.status(400).json({ message: 'Something went wrong while fetching items.' });
}
};
const getPreservedStock = async (req, res) => {
const oneyearFromNow = new Date();
oneyearFromNow.setFullYear(oneyearFromNow.getFullYear() + 1);
try {
const items = await KIInventoryItem.find(
{ category: 'INGREDIENT', expiryDate: { $gte: oneyearFromNow } },
{ __v: 0 },
)
.lean()
.sort({ presentQuantity: -1 });
res.status(200).json({ message: 'Preserved stock items fetched successfully.', data: items });
} catch (err) {
res
.status(400)
.json({ message: 'Something went wrong while fetching preserved stock items.' });
}
};
const updateOnUsage = async (req, res) => {
const { itemId, usedQuantity } = req.body;
if (usedQuantity <= 0) {
return res.status(400).json({ message: 'Used quantity must be greater than zero.' });
}
try {
const item = await KIInventoryItem.findById(itemId);
if (!item) {
return res.status(404).json({ message: 'Item not found.' });
}
if (item.expiryDate < new Date()) {
return res.status(400).json({ message: `This item was expired on ${item.expiryDate}` });
}
let present = item.presentQuantity;
present -= usedQuantity;
if (present < 0) {
present = 0;
}
item.presentQuantity = present;
item.updatedAt = new Date();
await item.save();
res.status(200).json({ message: 'Item usage updated successfully.', data: item });
} catch (err) {
res.status(400).json({ message: err.message });
}
};
const updateStoredQuantity = async (req, res) => {
const { itemId, addedQuantity, newExpiry } = req.body;
if (addedQuantity <= 0) {
return res.status(400).json({ message: 'Added quantity must be greater than zero.' });
}
if (newExpiry && new Date(newExpiry) < new Date()) {
return res.status(400).json({ message: 'New expiry date must be a future date.' });
}
try {
const item = await KIInventoryItem.findById(itemId);
if (!item) {
return res.status(404).json({ message: 'Item not found.' });
}
if (item.presentQuantity === 0 || item.expiryDate < new Date()) {
item.storedQuantity = addedQuantity;
item.presentQuantity = 0;
} else {
item.storedQuantity += addedQuantity;
}
item.presentQuantity += addedQuantity;
if (newExpiry) {
item.expiryDate = newExpiry;
}
item.updatedAt = new Date();
await item.save();
res.status(200).json({ message: 'Stored quantity updated successfully.', data: item });
} catch (err) {
res.status(400).json({ message: err.message });
}
};
const updateNextHarvest = async (req, res) => {
const { itemId, lastHarvestSuccess, nextHarvestDate, nextHarvestQuantity } = req.body;
try {
const item = await KIInventoryItem.findById(itemId);
if (!item) {
return res.status(404).json({ message: 'Item not found.' });
}
if (lastHarvestSuccess) {
item.lastHarvestDate = item.nextHarvestDate;
}
item.nextHarvestDate = nextHarvestDate;
item.nextHarvestQuantity = nextHarvestQuantity;
item.updatedAt = new Date();
await item.save();
res.status(200).json({ message: 'Next harvest details updated successfully.', data: item });
} catch (err) {
res.status(400).json({ message: err.message });
}
};
return {
addItem,
getItems,
getItemsByCategory,
getPreservedStock,
updateOnUsage,
updateStoredQuantity,
updateNextHarvest,
};
};
module.exports = KIInventoryController;
26 changes: 26 additions & 0 deletions src/models/kitchenandinventory/KIInventoryItems.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const mongoose = require('mongoose');

const KIInventoryItemSchema = new mongoose.Schema({
name: { type: String, required: true, trim: true, minlength: 3, maxlength: 50 },
presentQuantity: { type: Number, required: false },
storedQuantity: { type: Number, required: true, min: 0 },
unit: { type: String, required: true },
type: { type: String, required: true, trim: true },
monthlyUsage: { type: Number, required: true },
reorderAt: { type: Number, required: true },
category: {
type: String,
required: true,
enum: ['INGREDIENT', 'EQUIPEMENTANDSUPPLIES', 'SEEDS', 'CANNINGSUPPLIES', 'ANIMALSUPPLIES'],
},
createdAt: { type: Date, default: Date.now },
updatedAt: { type: Date, default: Date.now },
expiryDate: { type: Date, required: true, min: Date.now },
location: { type: String, optional: true },
onsite: { type: Boolean, default: false },
lastHarvestDate: { type: Date, optional: true, max: Date.now },
nextHarvestDate: { type: Date, optional: true, min: Date.now },
nextHarvestQuantity: { type: Number, optional: true },
});

module.exports = mongoose.model('KIInventoryItem', KIInventoryItemSchema);
18 changes: 18 additions & 0 deletions src/routes/kitchenandinventory/KIInventoryRouter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const express = require('express');
const controller = require('../../controllers/kitchenandinventory/KIInventoryController')();

const router = function () {
const inventoryRouter = express.Router();
// Routes for inventory items
inventoryRouter.route('/items').post(controller.addItem); // Route to add a new inventory item
inventoryRouter.route('/items').get(controller.getItems); // Route to get all inventory items
inventoryRouter.route('/items/:category').get(controller.getItemsByCategory); // Route to get items by category
inventoryRouter.route('/items/ingredients/preserved').get(controller.getPreservedStock); // Route to get preserved items
// Below update endpoints are non-idempotent and meant to be used for specific actions
inventoryRouter.route('/items/usage').post(controller.updateOnUsage); // Route to update item on usage
inventoryRouter.route('/items/storedQuantity').post(controller.updateStoredQuantity); // Route to update stored quantity
inventoryRouter.route('/items/nextHarvest').put(controller.updateNextHarvest); // Route to update next harvest details
return inventoryRouter;
};

module.exports = router;
25 changes: 25 additions & 0 deletions src/startup/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,9 @@ const badgeSystemRouter = require('../routes/educationPortal/badgeSystemRouter')

const promotionDetailsRouter = require('../routes/promotionDetailsRouter');

// Kitchen and Inventory portal routes
const kitchenInventoryRouter = require('../routes/kitchenandinventory/KIInventoryRouter')();

module.exports = function (app) {
app.use('/api', forgotPwdRouter);
app.use('/api', loginRouter);
Expand Down Expand Up @@ -514,4 +517,26 @@ module.exports = function (app) {
app.use('/api', projectMaterialRouter);
app.use('/api/bm', bmRentalChart);
app.use('/api/lb', lbWishlistsRouter);
app.use('/api/lb', listingAvailablityRouter);
// lb dashboard
app.use('/api/lb', bidTermsRouter);
app.use('/api/lb', bidsRouter);
app.use('/api/lb', paymentsRouter);
app.use('/api/lb', webhookRouter);
app.use('/api/lb', bidNotificationsRouter);
app.use('/api/lb', bidDeadlinesRouter);
app.use('/api/lb', SMSRouter);
app.use('/api', materialCostRouter);

// education portal
app.use('/api/education', badgeSystemRouter);

app.use('/api/lp', lessonPlanSubmissionRouter);

app.use('/api/education', browsableLessonPlanRouter);

app.use('/api/educator/reports', downloadReportRouter);

// Kitchen and Inventory portal routes
app.use('/api/kitchenandinventory/inventory', kitchenInventoryRouter);
};
Loading