diff --git a/controllers/notification_error_sparepart.controller.js b/controllers/notification_error_sparepart.controller.js new file mode 100644 index 0000000..31e9eef --- /dev/null +++ b/controllers/notification_error_sparepart.controller.js @@ -0,0 +1,61 @@ +const NotificationErrorSparepart = require('../services/notification_error_sparepart.service'); +const { setResponse, setResponsePaging, checkValidate } = require('../helpers/utils'); +const { updateNotificationErrorSparepartSchema, insertNotificationErrorSparepartSchema } = require('../validate/notification_error_sparepart.schema'); + +class NotificationErrorSparepartController { + + static async getAll(req, res) { + const queryParams = req.query; + const results = await NotificationErrorSparepart.getAll(queryParams); + const response = await setResponsePaging(queryParams, results, 'Notification Error Sparepart found'); + + res.status(response.statusCode).json(response); + } + + static async getById(req, res) { + const { id } = req.params; + const results = await NotificationErrorSparepart.getById(id); + const response = await setResponse(results, 'Notification Error Sparepart found'); + + res.status(response.statusCode).json(response); + } + + static async create(req, res) { + const { error, value } = await checkValidate(insertNotificationErrorSparepartSchema, req); + + if (error) { + return res.status(400).json(setResponse(error, 'Validation failed', 400)); + } + + const results = await NotificationErrorSparepart.create(value); + const response = await setResponse(results, 'Notification Error Sparepart created successfully'); + + res.status(response.statusCode).json(response); + } + + static async update(req, res) { + const { id } = req.params; + const { error, value } = await checkValidate(updateNotificationErrorSparepartSchema, req); + + if (error) { + return res.status(400).json(setResponse(error, 'Validation failed', 400)); + } + + const results = await NotificationErrorSparepart.update(id, value); + const response = await setResponse(results, 'Notification Error Sparepart updated successfully'); + + res.status(response.statusCode).json(response); + } + + static async delete(req, res) { + const { id } = req.params; + const { contact_id } = req.body; + + const results = await NotificationErrorSparepart.delete(id, contact_id); + const response = await setResponse(results, 'Notification Error Sparepart deleted successfully'); + + res.status(response.statusCode).json(response); + } +} + +module.exports = NotificationErrorSparepartController; diff --git a/db/notification_error_sparepart.db.js b/db/notification_error_sparepart.db.js new file mode 100644 index 0000000..17b9288 --- /dev/null +++ b/db/notification_error_sparepart.db.js @@ -0,0 +1,128 @@ +const pool = require("../config"); + +const getAllNotificationErrorSparepartDb = async (searchParams = {}) => { + let queryParams = []; + + if (searchParams.limit) { + const page = Number(searchParams.page ?? 1) - 1; + queryParams = [Number(searchParams.limit ?? 10), page]; + } + + const { whereOrConditions, whereParamOr } = pool.buildStringOrIlike( + [ + "a.brand_sparepart_id", + "a.contact_id", + "b.sparepart_name", + "d.contact_name", + "d.contact_type" + ], + searchParams.criteria, + queryParams + ); + + if (whereParamOr) queryParams = whereParamOr; + + const { whereConditions, whereParamAnd } = pool.buildFilterQuery( + [ + { column: "a.brand_sparepart_id", param: searchParams.name, type: "int" }, + { column: "a.contact_id", param: searchParams.code, type: "int" }, + { column: "a.unit", param: searchParams.unit, type: "string" }, + { column: "b.sparepart_name", param: searchParams.device, type: "string" }, + { column: "d.contact_name", param: searchParams.device, type: "string" }, + { column: "d.contact_type", param: searchParams.device, type: "string" }, + ], + queryParams + ); + + if (whereParamAnd) queryParams = whereParamAnd; + + const queryText = ` + SELECT + COUNT(*) OVER() AS total_data, + a.*, + b.sparepart_name, + b.brand_sparepart_description, + d.contact_name, + d.contact_type + FROM notification_error_sparepart a + + LEFT JOIN brand_sparepart b ON a.brand_sparepart_id = b.brand_sparepart_id + + LEFT JOIN contact d on a.contact_id = d.contact_id + + WHERE a.deleted_at IS NULL + ${whereConditions.length > 0 ? ` AND ${whereConditions.join(" AND ")}` : ""} + ${whereOrConditions ? ` ${whereOrConditions}` : ""} + ORDER BY a.notification_error_sparepart_id ASC + ${searchParams.limit ? `OFFSET $2 * $1 ROWS FETCH NEXT $1 ROWS ONLY` : ''} + `; + + const result = await pool.query(queryText, queryParams); + + const total = + result?.recordset?.length > 0 + ? parseInt(result.recordset[0].total_data, 10) + : 0; + + return { data: result.recordset, total }; +}; + +const getNotificationErrorSparepartByIdDb = async (id) => { + const queryText = ` + SELECT + a.*, + b.sparepart_name, + b.brand_sparepart_description, + d.contact_name, + d.contact_type + FROM notification_error_sparepart a + LEFT JOIN brand_sparepart b ON a.brand_sparepart_id = b.brand_sparepart_id + LEFT JOIN contact d on a.contact_id = d.contact_id + WHERE a.notification_error_sparepart_id = $1 + AND a.deleted_at IS NULL + `; + const result = await pool.query(queryText, [id]); + return result.recordset?.[0] || null; +}; + + +const createNotificationErrorSparepartDb = async (store) => { + const { query: queryText, values } = pool.buildDynamicInsert("notification_error_sparepart", store); + const result = await pool.query(queryText, values); + const insertedId = result.recordset?.[0]?.inserted_id; + + return insertedId ? await getNotificationErrorSparepartByIdDb(insertedId) : null; +}; + +const updateNotificationErrorSparepartDb = async (id, data) => { + const store = { ...data }; + const whereData = { notification_error_sparepart_id: id }; + + const { query: queryText, values } = pool.buildDynamicUpdate( + "notification_error_sparepart", + store, + whereData + ); + + await pool.query(`${queryText} AND deleted_at IS NULL`, values); + return getNotificationErrorSparepartByIdDb(id); +}; + +// Soft delete tag +const deleteNotificationErrorSparepartDb = async (id, deletedBy) => { + const queryText = ` + UPDATE notification_error_sparepart + SET deleted_at = CURRENT_TIMESTAMP, deleted_by = $1 + WHERE notification_error_sparepart_id = $2 AND deleted_at IS NULL + `; + await pool.query(queryText, [deletedBy, id]); + return true; +}; + +module.exports = { + getAllNotificationErrorSparepartDb, + getNotificationErrorSparepartByIdDb, + createNotificationErrorSparepartDb, + updateNotificationErrorSparepartDb, + deleteNotificationErrorSparepartDb, +}; diff --git a/routes/index.js b/routes/index.js index 141c7f5..6ea3e3e 100644 --- a/routes/index.js +++ b/routes/index.js @@ -15,6 +15,7 @@ const UserSchedule = require("./user_schedule.route") const historyValue = require("./history_value.route") const contact = require("./contact.route") const notification = require("./notification.route") +const notificationErrorSparepart = require("./notification_error_sparepart.route") router.use("/auth", auth); router.use("/user", users); @@ -32,6 +33,6 @@ router.use("/user-schedule", UserSchedule) router.use("/history", historyValue) router.use("/contact", contact) router.use("/notification", notification) - +router.use("/notification-sparepart", notificationErrorSparepart) module.exports = router; diff --git a/routes/notification_error_sparepart.route.js b/routes/notification_error_sparepart.route.js new file mode 100644 index 0000000..4798692 --- /dev/null +++ b/routes/notification_error_sparepart.route.js @@ -0,0 +1,23 @@ +const express = require('express'); +const NotificationErrorSparepartController = require('../controllers/notification_error_sparepart.controller'); +const verifyToken = require('../middleware/verifyToken'); +const verifyAccess = require('../middleware/verifyAccess'); + +const router = express.Router(); + +// =========================== +// Notification Erro rSparepart Routes +// =========================== + +router + .route('/') + .get(verifyToken.verifyAccessToken, NotificationErrorSparepartController.getAll) + .post(verifyToken.verifyAccessToken, verifyAccess(), NotificationErrorSparepartController.create); + +router + .route('/:id') + .get(verifyToken.verifyAccessToken, NotificationErrorSparepartController.getById) + .put(verifyToken.verifyAccessToken, verifyAccess(), NotificationErrorSparepartController.update) + .delete(verifyToken.verifyAccessToken, verifyAccess(), NotificationErrorSparepartController.delete); + +module.exports = router; diff --git a/services/notification_error_sparepart.service.js b/services/notification_error_sparepart.service.js new file mode 100644 index 0000000..31f38fb --- /dev/null +++ b/services/notification_error_sparepart.service.js @@ -0,0 +1,85 @@ +const { + getAllNotificationErrorSparepartDb, + getNotificationErrorSparepartByIdDb, + createNotificationErrorSparepartDb, + updateNotificationErrorSparepartDb, + deleteNotificationErrorSparepartDb, +} = require("../db/notification_error_sparepart.db"); + +const { getContactByIdDb } = require("../db/contact.db"); +const { ErrorHandler } = require("../helpers/error"); + +class NotificationErrorSparepartService { + static _checkAccess(contactType) { + if (contactType !== "gudang") { + throw new ErrorHandler( + 403, + "Akses ditolak. Hanya contact_type 'gudang' yang dapat create/update/delete." + ); + } + } + + static async getAll(param) { + return await getAllNotificationErrorSparepartDb(param); + } + + static async getById(id) { + const result = await getNotificationErrorSparepartByIdDb(id); + + if (result.length < 1) + throw new ErrorHandler(404, "Notification Error Sparepart not found"); + + return result; + } + + static async create(data) { + const contactResult = await getContactByIdDb(data.contact_id); + + if (!contactResult || contactResult.length < 1) + throw new ErrorHandler(404, "Contact tidak ditemukan"); + + const contact = contactResult[0]; + + this._checkAccess(contact.contact_type); + + return await createNotificationErrorSparepartDb(data); + } + + static async update(id, data) { + const contactResult = await getContactByIdDb(data.contact_id); + + if (!contactResult || contactResult.length < 1) + throw new ErrorHandler(404, "Contact tidak ditemukan"); + + const contact = contactResult[0]; + + this._checkAccess(contact.contact_type); + + const exist = await getNotificationErrorSparepartByIdDb(id); + + if (exist.length < 1) + throw new ErrorHandler(404, "Notification Error Sparepart not found"); + + return await updateNotificationErrorSparepartDb(id, data); + } + + static async delete(id, contact_id) { + const contactResult = await getContactByIdDb(contact_id); + + if (!contactResult || contactResult.length < 1) + throw new ErrorHandler(404, "Contact tidak ditemukan"); + + const contact = contactResult[0]; + + this._checkAccess(contact.contact_type); + + const exist = await getNotificationErrorSparepartByIdDb(id); + + if (exist.length < 1) + throw new ErrorHandler(404, "Notification Error Sparepart not found"); + + return await deleteNotificationErrorSparepartDb(id); + } +} + +module.exports = NotificationErrorSparepartService; diff --git a/validate/notification_error_sparepart.schema.js b/validate/notification_error_sparepart.schema.js new file mode 100644 index 0000000..3751b1b --- /dev/null +++ b/validate/notification_error_sparepart.schema.js @@ -0,0 +1,30 @@ +const Joi = require("joi"); + +const insertNotificationErrorSparepartSchema = Joi.object({ + contact_id: Joi.number().required(), + + brand_sparepart_id: Joi.number().required(), + + is_verification: Joi.boolean().required(), + + is_available: Joi.boolean().required(), + + is_active: Joi.boolean().required(), +}); + +const updateNotificationErrorSparepartSchema = Joi.object({ + contact_id: Joi.number().required(), + + brand_sparepart_id: Joi.number().optional(), + + is_verification: Joi.boolean().optional(), + + is_available: Joi.boolean().optional(), + + is_active: Joi.boolean().optional(), +}); + +module.exports = { + insertNotificationErrorSparepartSchema, + updateNotificationErrorSparepartSchema, +};