From c1456bafc265f9a4e7027928461bedbd6dd3653a Mon Sep 17 00:00:00 2001 From: Abhinav Tharamel Date: Wed, 11 Mar 2026 15:49:06 -0500 Subject: [PATCH] feat: add transplanting and harvesting event models, controllers, and routes for Kitchen Inventory Management --- src/controllers/harvestingController.js | 73 ++++++++++++++++++++++ src/controllers/transplantingController.js | 53 ++++++++++++++++ src/models/harvestingEvent.js | 23 +++++++ src/models/transplantingEvent.js | 23 +++++++ src/routes/harvestingRouter.js | 12 ++++ src/routes/transplantingRouter.js | 12 ++++ src/startup/routes.js | 6 ++ 7 files changed, 202 insertions(+) create mode 100644 src/controllers/harvestingController.js create mode 100644 src/controllers/transplantingController.js create mode 100644 src/models/harvestingEvent.js create mode 100644 src/models/transplantingEvent.js create mode 100644 src/routes/harvestingRouter.js create mode 100644 src/routes/transplantingRouter.js diff --git a/src/controllers/harvestingController.js b/src/controllers/harvestingController.js new file mode 100644 index 000000000..08ea4057f --- /dev/null +++ b/src/controllers/harvestingController.js @@ -0,0 +1,73 @@ +const harvestingController = function (HarvestingEvent) { + const postEvent = async (req, res) => { + try { + const { name, related_to, type, expected_date, yield: yieldAmount } = req.body; + + if (!name || !related_to || !type || !expected_date) { + return res.status(400).send({ + error: 'Name, related_to, type, and expected_date are required.', + }); + } + + const validModules = ['Garden', 'Orchard', 'Animals']; + if (!validModules.includes(related_to)) { + return res.status(400).send({ + error: `Invalid related_to value. Must be one of: ${validModules.join(', ')}`, + }); + } + + const validTypes = ['garden harvesting', 'orchard harvesting']; + if (!validTypes.includes(type)) { + return res.status(400).send({ + error: `Invalid type value. Must be one of: ${validTypes.join(', ')}`, + }); + } + + const event = new HarvestingEvent({ + name, + related_to, + type, + expected_date, + yield: yieldAmount, + }); + + await event.save(); + return res.status(201).send(event); + } catch (err) { + // eslint-disable-next-line no-console + console.error('Error creating harvesting event:', err); + return res.status(500).send({ error: 'Internal Server Error' }); + } + }; + + const getEvents = async (req, res) => { + try { + const { type } = req.query; + + const filter = {}; + if (type) { + const validTypes = ['garden harvesting', 'orchard harvesting']; + if (!validTypes.includes(type)) { + return res.status(400).send({ + error: `Invalid type filter. Must be one of: ${validTypes.join(', ')}`, + }); + } + filter.type = type; + } + + const events = await HarvestingEvent.find(filter).sort({ expected_date: 1 }); + return res.status(200).send(events); + } catch (err) { + // eslint-disable-next-line no-console + console.error('Error fetching harvesting events:', err); + return res.status(500).send({ error: 'Internal Server Error' }); + } + }; + + return { + postEvent, + getEvents, + }; +}; + +module.exports = harvestingController; diff --git a/src/controllers/transplantingController.js b/src/controllers/transplantingController.js new file mode 100644 index 000000000..ac72b24da --- /dev/null +++ b/src/controllers/transplantingController.js @@ -0,0 +1,53 @@ +const transplantingController = function (TransplantingEvent) { + const postEvent = async (req, res) => { + try { + const { name, related_to, date, position_from, position_to } = req.body; + + if (!name || !related_to || !date || !position_from || !position_to) { + return res.status(400).send({ + error: 'Name, related_to, date, position_from, and position_to are required.', + }); + } + + const validModules = ['Garden', 'Orchard', 'Animals']; + if (!validModules.includes(related_to)) { + return res.status(400).send({ + error: `Invalid related_to value. Must be one of: ${validModules.join(', ')}`, + }); + } + + const event = new TransplantingEvent({ + name, + related_to, + date, + position_from, + position_to, + }); + + await event.save(); + return res.status(201).send(event); + } catch (err) { + // eslint-disable-next-line no-console + console.error('Error creating transplanting event:', err); + return res.status(500).send({ error: 'Internal Server Error' }); + } + }; + + const getEvents = async (req, res) => { + try { + const events = await TransplantingEvent.find().sort({ date: 1 }); + return res.status(200).send(events); + } catch (err) { + // eslint-disable-next-line no-console + console.error('Error fetching transplanting events:', err); + return res.status(500).send({ error: 'Internal Server Error' }); + } + }; + + return { + postEvent, + getEvents, + }; +}; + +module.exports = transplantingController; diff --git a/src/models/harvestingEvent.js b/src/models/harvestingEvent.js new file mode 100644 index 000000000..279e0731f --- /dev/null +++ b/src/models/harvestingEvent.js @@ -0,0 +1,23 @@ +const mongoose = require('mongoose'); + +const { Schema } = mongoose; + +const HarvestingEventSchema = new Schema({ + name: { type: String, required: true }, + related_to: { + type: String, + enum: ['Garden', 'Orchard', 'Animals'], + required: true, + }, + type: { + type: String, + enum: ['garden harvesting', 'orchard harvesting'], + required: true, + }, + expected_date: { type: Date, required: true }, + yield: { type: Number }, + created_at: { type: Date, default: Date.now }, + updated_at: { type: Date, default: Date.now }, +}); + +module.exports = mongoose.model('harvestingEvent', HarvestingEventSchema, 'harvestingEvents'); diff --git a/src/models/transplantingEvent.js b/src/models/transplantingEvent.js new file mode 100644 index 000000000..24835eb06 --- /dev/null +++ b/src/models/transplantingEvent.js @@ -0,0 +1,23 @@ +const mongoose = require('mongoose'); + +const { Schema } = mongoose; + +const TransplantingEventSchema = new Schema({ + name: { type: String, required: true }, + related_to: { + type: String, + enum: ['Garden', 'Orchard', 'Animals'], + required: true, + }, + date: { type: Date, required: true }, + position_from: { type: String, required: true }, + position_to: { type: String, required: true }, + created_at: { type: Date, default: Date.now }, + updated_at: { type: Date, default: Date.now }, +}); + +module.exports = mongoose.model( + 'transplantingEvent', + TransplantingEventSchema, + 'transplantingEvents', +); diff --git a/src/routes/harvestingRouter.js b/src/routes/harvestingRouter.js new file mode 100644 index 000000000..18b4445c0 --- /dev/null +++ b/src/routes/harvestingRouter.js @@ -0,0 +1,12 @@ +const express = require('express'); + +const routes = function (HarvestingEvent) { + const controller = require('../controllers/harvestingController')(HarvestingEvent); + const harvestingRouter = express.Router(); + + harvestingRouter.route('/').get(controller.getEvents).post(controller.postEvent); + + return harvestingRouter; +}; + +module.exports = routes; diff --git a/src/routes/transplantingRouter.js b/src/routes/transplantingRouter.js new file mode 100644 index 000000000..127527980 --- /dev/null +++ b/src/routes/transplantingRouter.js @@ -0,0 +1,12 @@ +const express = require('express'); + +const routes = function (TransplantingEvent) { + const controller = require('../controllers/transplantingController')(TransplantingEvent); + const transplantingRouter = express.Router(); + + transplantingRouter.route('/').get(controller.getEvents).post(controller.postEvent); + + return transplantingRouter; +}; + +module.exports = routes; diff --git a/src/startup/routes.js b/src/startup/routes.js index 71526e7a1..32df320cc 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -14,6 +14,8 @@ const taskNotification = require('../models/taskNotification'); const badge = require('../models/badge'); const inventoryItem = require('../models/inventoryItem'); const inventoryItemType = require('../models/inventoryItemType'); +const transplantingEvent = require('../models/transplantingEvent'); +const harvestingEvent = require('../models/harvestingEvent'); const role = require('../models/role'); const rolePreset = require('../models/rolePreset'); const ownerMessage = require('../models/ownerMessage'); @@ -145,6 +147,8 @@ const inventoryRouter = require('../routes/inventoryRouter')( project, ); const timeZoneAPIRouter = require('../routes/timeZoneAPIRoutes')(); +const transplantingRouter = require('../routes/transplantingRouter')(transplantingEvent); +const harvestingRouter = require('../routes/harvestingRouter')(harvestingEvent); const profileInitialSetupRouter = require('../routes/profileInitialSetupRouter')( profileInitialSetuptoken, userProfile, @@ -380,6 +384,8 @@ module.exports = function (app) { app.use('/api', taskNotificationRouter); app.use('/api', badgeRouter); app.use('/api', inventoryRouter); + app.use('/api/kitchenandinventory/transplanting', transplantingRouter); + app.use('/api/kitchenandinventory/harvesting', harvestingRouter); app.use('/api', timeZoneAPIRouter); app.use('/api', taskEditSuggestionRouter); app.use('/api', roleRouter);