diff --git a/src/controllers/kitchenandinventory/KIInventoryController.js b/src/controllers/kitchenandinventory/KIInventoryController.js new file mode 100644 index 000000000..ad79dac1c --- /dev/null +++ b/src/controllers/kitchenandinventory/KIInventoryController.js @@ -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; diff --git a/src/models/kitchenandinventory/KIInventoryItems.js b/src/models/kitchenandinventory/KIInventoryItems.js new file mode 100644 index 000000000..891661117 --- /dev/null +++ b/src/models/kitchenandinventory/KIInventoryItems.js @@ -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); diff --git a/src/routes/kitchenandinventory/KIInventoryRouter.js b/src/routes/kitchenandinventory/KIInventoryRouter.js new file mode 100644 index 000000000..dc4fcf83f --- /dev/null +++ b/src/routes/kitchenandinventory/KIInventoryRouter.js @@ -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; diff --git a/src/startup/routes.js b/src/startup/routes.js index d6df3e3e1..11ad41709 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -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); @@ -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); };