From 3896f4103d7057af85908614b1c160d7fa0008ec Mon Sep 17 00:00:00 2001 From: Muhammad Afif Date: Tue, 14 Oct 2025 11:11:56 +0700 Subject: [PATCH] add: CRUD schedule --- controllers/schedule.controller.js | 71 ++++++++++++++++++++++++ db/schedule.db.js | 50 ++++++----------- routes/index.js | 2 + routes/schedule.route.js | 17 ++++++ services/schedule.service.js | 88 ++++++++++++++++++++++++++++++ validate/schedule.schema.js | 28 ++++++++++ 6 files changed, 224 insertions(+), 32 deletions(-) diff --git a/controllers/schedule.controller.js b/controllers/schedule.controller.js index e69de29..f8798b3 100644 --- a/controllers/schedule.controller.js +++ b/controllers/schedule.controller.js @@ -0,0 +1,71 @@ +const ScheduleService = require('../services/schedule.service'); +const { setResponse, setResponsePaging, checkValidate } = require('../helpers/utils'); +const { updateScheduleSchema, insertScheduleSchema } = require('../validate/schedule.schema'); + +class ScheduleController { + // Get all Schedule + static async getAll(req, res) { + const queryParams = req.query; + + const results = await ScheduleService.getAllSchedule(queryParams); + const response = await setResponsePaging(queryParams, results, 'Schedule found') + + res.status(response.statusCode).json(response); + } + + // Get Schedule by ID + static async getById(req, res) { + const { id } = req.params; + + const results = await ScheduleService.getScheduleById(id); + const response = await setResponse(results, 'Schedule found') + + res.status(response.statusCode).json(response); + } + + // Create Schedule + static async create(req, res) { + const { error, value } = await checkValidate(insertScheduleSchema, req) + + if (error) { + return res.status(400).json(setResponse(error, 'Validation failed', 400)); + } + + value.userId = req.user.user_id + + const results = await ScheduleService.insertScheduleDb(value); + const response = await setResponse(results, 'Schedule created successfully') + + return res.status(response.statusCode).json(response); + } + + // Update Schedule + static async update(req, res) { + const { id } = req.params; + + const { error, value } = checkValidate(updateScheduleSchema, req) + + if (error) { + return res.status(400).json(setResponse(error, 'Validation failed', 400)); + } + + value.userId = req.user.user_id + + const results = await ScheduleService.updateSchedule(id, value); + const response = await setResponse(results, 'Schedule updated successfully') + + res.status(response.statusCode).json(response); + } + + // Soft delete Schedule + static async delete(req, res) { + const { id } = req.params; + + const results = await ScheduleService.deleteSchedule(id, req.user.user_id); + const response = await setResponse(results, 'Schedule deleted successfully') + + res.status(response.statusCode).json(response); + } +} + +module.exports = ScheduleController; diff --git a/db/schedule.db.js b/db/schedule.db.js index 8c0df04..814d5f7 100644 --- a/db/schedule.db.js +++ b/db/schedule.db.js @@ -1,5 +1,5 @@ const pool = require("../config"); -const formattedDate = require("../utils/date"); +// const formattedDate = require("../utils/date"); // Get all schedules const getAllScheduleDb = async (searchParams = {}) => { @@ -27,15 +27,11 @@ const getAllScheduleDb = async (searchParams = {}) => { SELECT COUNT(*) OVER() AS total_data, a.*, - b.shift_id, b.shift_name, b.start_time, - b.end_time, - c.user_schedule_id, - c.user_id + b.end_time FROM schedule a LEFT JOIN m_shift b ON a.shift_id = b.shift_id - LEFT JOIN user_schedule c ON a.schedule_id = c.user_schedule_id WHERE a.deleted_at IS NULL ${whereConditions.length > 0 ? ` AND ${whereConditions.join(" AND ")}` : ""} ${whereOrConditions ? ` ${whereOrConditions}` : ""} @@ -44,47 +40,36 @@ const getAllScheduleDb = async (searchParams = {}) => { `; const result = await pool.query(queryText, queryParams); - - const data = result.recordset.map((item) => ({ - ...item, - schedule_date: item.schedule_date - ? formattedDate(item.schedule_date) - : null, - })); - - const total = - result?.recordset?.length > 0 - ? parseInt(result.recordset[0].total_data, 10) - : 0; - - return { data, total }; + const total = + result?.recordset?.length > 0 + ? parseInt(result.recordset[0].total_data, 10) + : 0; + + return { data: result.recordset, total }; }; const getScheduleByIdDb = async (id) => { const queryText = ` SELECT a.*, - b.shift_id, b.shift_name, b.start_time, - b.end_time, - c.user_schedule_id, - c.user_id + b.end_time FROM schedule a LEFT JOIN m_shift b ON a.shift_id = b.shift_id - LEFT JOIN user_schedule c ON a.schedule_id = c.user_schedule_id WHERE a.schedule_id = $1 AND a.deleted_at IS NULL `; const result = await pool.query(queryText, [id]); - const data = result.recordset.map((item) => ({ - ...item, - schedule_date: item.schedule_date - ? formattedDate(item.schedule_date) - : null, - })); + return result.recordset?.[0] || null; +}; - return data; +const insertScheduleDb = async (store) => { + const { query: queryText, values } = pool.buildDynamicInsert("schedule", store); + const result = await pool.query(queryText, values); + const insertedId = result.recordset?.[0]?.inserted_id; + + return insertedId ? await getScheduleByIdDb(insertedId) : null; }; const updateScheduleDb = async (id, data) => { @@ -115,6 +100,7 @@ const deleteScheduleDb = async (id, deletedBy) => { module.exports = { getAllScheduleDb, getScheduleByIdDb, + insertScheduleDb, updateScheduleDb, deleteScheduleDb, }; diff --git a/routes/index.js b/routes/index.js index 7e351bb..85b34ce 100644 --- a/routes/index.js +++ b/routes/index.js @@ -6,6 +6,7 @@ const roles = require('./roles.route') const tags = require("./tags.route") const subSection = require("./sub_section.route") const shift = require("./shift.route") +const schedule = require("./schedule.route") router.use("/auth", auth); router.use("/user", users); @@ -14,6 +15,7 @@ router.use("/roles", roles); router.use("/tags", tags); router.use("/plant-sub-section", subSection); router.use("/shift", shift) +router.use("/schedule", schedule) module.exports = router; diff --git a/routes/schedule.route.js b/routes/schedule.route.js index e69de29..4c5e3e2 100644 --- a/routes/schedule.route.js +++ b/routes/schedule.route.js @@ -0,0 +1,17 @@ +const express = require('express'); +const ScheduleController = require('../controllers/schedule.controller'); +const verifyToken = require("../middleware/verifyToken") +const verifyAccess = require("../middleware/verifyAccess") + +const router = express.Router(); + +router.route("/") + .get(verifyToken.verifyAccessToken, ScheduleController.getAll) + .post(verifyToken.verifyAccessToken, verifyAccess(), ScheduleController.create); + +router.route("/:id") + .get(verifyToken.verifyAccessToken, ScheduleController.getById) + .put(verifyToken.verifyAccessToken, verifyAccess(), ScheduleController.update) + .delete(verifyToken.verifyAccessToken, verifyAccess(), ScheduleController.delete); + +module.exports = router; \ No newline at end of file diff --git a/services/schedule.service.js b/services/schedule.service.js index e69de29..ea33e1d 100644 --- a/services/schedule.service.js +++ b/services/schedule.service.js @@ -0,0 +1,88 @@ +const { + getAllScheduleDb, + getScheduleByIdDb, + insertScheduleDb, + updateScheduleDb, + deleteScheduleDb +} = require('../db/schedule.db'); +const { ErrorHandler } = require('../helpers/error'); + +class ScheduleService { + // Get all Schedule + static async getAllSchedule(param) { + try { + const results = await getAllScheduleDb(param); + + results.data.map(element => { + }); + + return results + } catch (error) { + throw new ErrorHandler(error.statusCode, error.message); + } + } + + // Get Schedule by ID + static async getScheduleById(id) { + try { + const result = await getScheduleByIdDb(id); + + if (result.length < 1) throw new ErrorHandler(404, 'Schedule not found'); + + return result; + } catch (error) { + throw new ErrorHandler(error.statusCode, error.message); + } + } + + // Create Schedule + static async insertScheduleDb(data) { + try { + if (!data || typeof data !== 'object') data = {}; + + const result = await insertScheduleDb(data); + + return result; + } catch (error) { + throw new ErrorHandler(error.statusCode, error.message); + } + } + + // Update Schedule + static async updateSchedule(id, data) { + try { + if (!data || typeof data !== 'object') data = {}; + + const dataExist = await getScheduleByIdDb(id); + + if (dataExist.length < 1) { + throw new ErrorHandler(404, 'Schedule not found'); + } + + const result = await updateScheduleDb(id, data); + + return result; + } catch (error) { + throw new ErrorHandler(error.statusCode, error.message); + } + } + + // Soft delete Schedule + static async deleteSchedule(id, userId) { + try { + const dataExist = await getScheduleByIdDb(id); + + if (dataExist.length < 1) { + throw new ErrorHandler(404, 'Schedule not found'); + } + + const result = await deleteScheduleDb(id, userId); + + return result; + } catch (error) { + throw new ErrorHandler(error.statusCode, error.message); + } + } +} + +module.exports = ScheduleService; diff --git a/validate/schedule.schema.js b/validate/schedule.schema.js index e69de29..5252030 100644 --- a/validate/schedule.schema.js +++ b/validate/schedule.schema.js @@ -0,0 +1,28 @@ +// ======================== +// Schedule Validation + +const Joi = require("joi"); + +const datePattern = /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/; + +const insertScheduleSchema = Joi.object({ + schedule_date: Joi.string().pattern(datePattern).required().messages({ + "string.pattern.base": "schedule_date harus dalam format YYYY-MM-DD", + "any.required": "schedule_date wajib diisi", + }), + is_active: Joi.boolean().required(), + shift_id: Joi.number(), +}); + +const updateScheduleSchema = Joi.object({ + schedule_date: Joi.string().pattern(datePattern).messages({ + "string.pattern.base": "schedule_date harus dalam format YYYY-MM-DD", + }), + is_active: Joi.boolean(), + shift_id: Joi.number(), +}).min(1); + +module.exports = { + insertScheduleSchema, + updateScheduleSchema, +};