diff --git a/controllers/notification_error.controller.js b/controllers/notification_error.controller.js index deb6d08..fe5eb0e 100644 --- a/controllers/notification_error.controller.js +++ b/controllers/notification_error.controller.js @@ -25,7 +25,6 @@ class NotificationErrorController { res.status(response.statusCode).json(response); } - static async getById(req, res) { const { id } = req.params; @@ -50,7 +49,10 @@ class NotificationErrorController { const results = await NotificationErrorService.createNotificationError( value ); - const response = await setResponse(results, "Notification created successfully"); + const response = await setResponse( + results, + "Notification created successfully" + ); return res.status(response.statusCode).json(response); } @@ -58,19 +60,38 @@ class NotificationErrorController { static async update(req, res) { const { id } = req.params; - const { error, value } = checkValidate(updateNotificationSchema, req) + const userId = req.user.user_id; - if (error) { - return res.status(400).json(setResponse(error, 'Validation failed', 400)); - } - - value.userId = req.user.user_id - - const results = await NotificationErrorService.updateNotificationError(id, value); - const response = await setResponse(results, 'Notification Error User updated successfully') + const results = await NotificationErrorService.updateNotificationError( + id, + userId + ); + const response = await setResponse( + results, + "Notification Error updated successfully" + ); res.status(response.statusCode).json(response); } + + static async resend(req, res) { + try { + const { id } = req.params; + + const results = await NotificationErrorService.resendNotification(id); + + const response = await setResponse(results, results.message); + + res.status(response.statusCode).json(response); + } catch (error) { + const response = setResponse( + null, + error.message, + error.statusCode || 500 + ); + res.status(response.statusCode).json(response); + } + } } module.exports = NotificationErrorController; diff --git a/controllers/notification_error_user.controller.js b/controllers/notification_error_user.controller.js index c2b4342..0a9973f 100644 --- a/controllers/notification_error_user.controller.js +++ b/controllers/notification_error_user.controller.js @@ -66,6 +66,24 @@ class NotificationErrorUserController { res.status(response.statusCode).json(response); } + + static async resendByUser(req, res) { + try { + const { id, contact_phone } = req.params; + + const results = await NotificationErrorUserService.resendNotificationByUser(id, contact_phone) + + const response = await setResponse( + results, + results.message, + ); + + res.status(response.statusCode).json(response); + } catch (error) { + const response = setResponse(null, error.message, error.statusCode || 500); + res.status(response.statusCode).json(response); + } + } } module.exports = NotificationErrorUserController; diff --git a/db/notification_error.db.js b/db/notification_error.db.js index 75524d9..990f05b 100644 --- a/db/notification_error.db.js +++ b/db/notification_error.db.js @@ -165,11 +165,13 @@ const getUsersNotificationErrorDb = async (id) => { a.notification_error_user_id, a.contact_phone, a.contact_name, - a.is_send + c.is_active FROM notification_error_user a LEFT JOIN notification_error b ON a.notification_error_id = b.notification_error_id + + LEFT JOIN contact c ON a.contact_phone = c.contact_phone WHERE a.notification_error_id = $1 AND a.deleted_at IS NULL diff --git a/db/notification_error_user.db.js b/db/notification_error_user.db.js index 5893d1c..11cf408 100644 --- a/db/notification_error_user.db.js +++ b/db/notification_error_user.db.js @@ -10,10 +10,7 @@ const getAllNotificationErrorUserDb = async (searchParams = {}) => { } const { whereOrConditions, whereParamOr } = pool.buildStringOrIlike( - [ - "a.notification_error_id", - "a.contact_id", - ], + ["a.notification_error_id", "a.contact_id"], searchParams.criteria, queryParams ); @@ -22,7 +19,11 @@ const getAllNotificationErrorUserDb = async (searchParams = {}) => { const { whereConditions, whereParamAnd } = pool.buildFilterQuery( [ - { column: "a.notification_error_id", param: searchParams.name, type: "int" }, + { + column: "a.notification_error_id", + param: searchParams.name, + type: "int", + }, { column: "a.contact_id", param: searchParams.code, type: "int" }, ], queryParams @@ -36,10 +37,14 @@ const getAllNotificationErrorUserDb = async (searchParams = {}) => { a.* FROM notification_error_user a WHERE a.deleted_at IS NULL - ${whereConditions.length > 0 ? ` AND ${whereConditions.join(" AND ")}` : ""} + ${ + whereConditions.length > 0 + ? ` AND ${whereConditions.join(" AND ")}` + : "" + } ${whereOrConditions ? ` ${whereOrConditions}` : ""} ORDER BY a.notification_error_user_id ASC - ${searchParams.limit ? `OFFSET $2 * $1 ROWS FETCH NEXT $1 ROWS ONLY` : ''} + ${searchParams.limit ? `OFFSET $2 * $1 ROWS FETCH NEXT $1 ROWS ONLY` : ""} `; const result = await pool.query(queryText, queryParams); @@ -55,16 +60,38 @@ const getAllNotificationErrorUserDb = async (searchParams = {}) => { const getNotificationErrorUserByIdDb = async (id) => { const queryText = ` SELECT - a.* + a.*, + b. is_active as contact_is_active + FROM notification_error_user a + LEFT JOIN contact b ON a.contact_phone = b.contact_phone WHERE a.notification_error_user_id = $1 AND a.deleted_at IS NULL `; const result = await pool.query(queryText, [id]); return result.recordset; }; +const getNotificationErrorByIdDb = async (notification_error_id) => { + const queryText = ` + SELECT + a.*, + b. is_active as contact_is_active, + c.is_read + + FROM notification_error_user a + LEFT JOIN contact b ON a.contact_phone = b.contact_phone + LEFT JOIN notification_error c ON a.notification_error_id = c.notification_error_id + WHERE a.notification_error_id = $1 AND a.deleted_at IS NULL + `; + const result = await pool.query(queryText, [notification_error_id]); + return result.recordset; +}; + const createNotificationErrorUserDb = async (store) => { - const { query: queryText, values } = pool.buildDynamicInsert("notification_error_user", store); + const { query: queryText, values } = pool.buildDynamicInsert( + "notification_error_user", + store + ); const result = await pool.query(queryText, values); const insertedId = result.recordset?.[0]?.inserted_id; @@ -82,7 +109,7 @@ const updateNotificationErrorUserDb = async (id, data) => { ); await pool.query(`${queryText} AND deleted_at IS NULL`, values); - return getNotificationErrorUserByIdDb(id); + return getNotificationErrorUserByIdDb(id); }; // Soft delete tag @@ -99,6 +126,7 @@ const deleteNotificationErrorUserDb = async (id, deletedBy) => { module.exports = { getAllNotificationErrorUserDb, getNotificationErrorUserByIdDb, + getNotificationErrorByIdDb, createNotificationErrorUserDb, updateNotificationErrorUserDb, deleteNotificationErrorUserDb, diff --git a/routes/notification_error.route.js b/routes/notification_error.route.js index 143a0b2..110cd3d 100644 --- a/routes/notification_error.route.js +++ b/routes/notification_error.route.js @@ -1,21 +1,40 @@ -const express = require('express'); -const NotificationErrorController = require('../controllers/notification_error.controller'); -const verifyToken = require('../middleware/verifyToken'); -const verifyAccess = require('../middleware/verifyAccess'); +const express = require("express"); +const NotificationErrorController = require("../controllers/notification_error.controller"); +const verifyToken = require("../middleware/verifyToken"); +const verifyAccess = require("../middleware/verifyAccess"); const router = express.Router(); router - .route('/') - .get(verifyToken.verifyAccessToken,verifyAccess(), NotificationErrorController.getAll) - - router - .route('/') - .post(verifyToken.verifyAccessToken,verifyAccess(), NotificationErrorController.create) + .route("/") + .get( + verifyToken.verifyAccessToken, + verifyAccess(), + NotificationErrorController.getAll + ); router - .route('/:id') + .route("/") + .post( + verifyToken.verifyAccessToken, + verifyAccess(), + NotificationErrorController.create + ); + +router + .route("/:id") .get(verifyToken.verifyAccessToken, NotificationErrorController.getById) - .put(verifyToken.verifyAccessToken, verifyAccess(), NotificationErrorController.update) + .put( + verifyToken.verifyAccessToken, + verifyAccess(), + NotificationErrorController.update + ); + +router.post( + "/resend/:id", + verifyToken.verifyAccessToken, + verifyAccess(), + NotificationErrorController.resend +); module.exports = router; diff --git a/routes/notification_error_user.route.js b/routes/notification_error_user.route.js index 473a0a7..d245aa6 100644 --- a/routes/notification_error_user.route.js +++ b/routes/notification_error_user.route.js @@ -1,17 +1,38 @@ -const express = require('express'); -const NotificationErrorUserController = require('../controllers/notification_error_user.controller'); -const verifyToken = require("../middleware/verifyToken") -const verifyAccess = require("../middleware/verifyAccess") +const express = require("express"); +const NotificationErrorUserController = require("../controllers/notification_error_user.controller"); +const verifyToken = require("../middleware/verifyToken"); +const verifyAccess = require("../middleware/verifyAccess"); const router = express.Router(); -router.route("/") - .get(verifyToken.verifyAccessToken, NotificationErrorUserController.getAll) - .post(verifyToken.verifyAccessToken, verifyAccess(), NotificationErrorUserController.create); +router + .route("/") + .get(verifyToken.verifyAccessToken, NotificationErrorUserController.getAll) + .post( + verifyToken.verifyAccessToken, + verifyAccess(), + NotificationErrorUserController.create + ); -router.route("/:id") - .get(verifyToken.verifyAccessToken, NotificationErrorUserController.getById) - .put(verifyToken.verifyAccessToken, verifyAccess(), NotificationErrorUserController.update) - .delete(verifyToken.verifyAccessToken, verifyAccess(), NotificationErrorUserController.delete); +router + .route("/:id") + .get(verifyToken.verifyAccessToken, NotificationErrorUserController.getById) + .put( + verifyToken.verifyAccessToken, + verifyAccess(), + NotificationErrorUserController.update + ) + .delete( + verifyToken.verifyAccessToken, + verifyAccess(), + NotificationErrorUserController.delete + ); -module.exports = router; \ No newline at end of file +router.post( + "/resend/:id/:contact_phone", + verifyToken.verifyAccessToken, + verifyAccess(), + NotificationErrorUserController.resendByUser +); + +module.exports = router; diff --git a/services/notification_error.service.js b/services/notification_error.service.js index 3311220..42f5644 100644 --- a/services/notification_error.service.js +++ b/services/notification_error.service.js @@ -17,8 +17,18 @@ const { const { getSparepartsByErrorCodeIdDb } = require("../db/brand_sparepart.db"); +const { + getNotificationErrorByIdDb, +} = require("../db/notification_error_user.db"); + const { getFileUploadByPathDb } = require("../db/file_uploads.db"); +const { + generateTokenRedirect, + shortUrltiny, + sendNotifikasi, +} = require("../db/notification_wa.db"); + const { ErrorHandler } = require("../helpers/error"); class NotificationService { @@ -29,7 +39,10 @@ class NotificationService { if (results && Array.isArray(results.data)) { results.data = await Promise.all( results.data.map(async (notification) => { - const usersNotification = (await getUsersNotificationErrorDb(notification.notification_error_id)) || []; + const usersNotification = + (await getUsersNotificationErrorDb( + notification.notification_error_id + )) || []; return { ...notification, users: usersNotification, @@ -126,21 +139,99 @@ class NotificationService { } } - static async updateNotificationError(id, data) { + static async updateNotificationError(notification_error_id, data) { try { - if (!data || typeof data !== "object") data = {}; + const dataExist = await getNotificationErrorByIdDb(notification_error_id); - const dataExist = await getNotificationByIdDb(id); - - if (dataExist.length < 1) { - throw new ErrorHandler(404, "NotificationErrorUser not found"); + if (!dataExist || (Array.isArray(dataExist) && dataExist.length < 1)) { + throw new ErrorHandler(404, "Notification Error User not found"); } - const result = await updateNotificationErrorDb(id, data); + const notification = Array.isArray(dataExist) ? dataExist[0] : dataExist; - return result; + if (notification.is_read === true) { + throw new ErrorHandler(400, "Notification has already been read"); + } + + if (!notification.is_read) { + const updateStatus = await updateNotificationErrorDb( + notification_error_id, + { is_read: true } + ); + + if (!updateStatus) { + throw new ErrorHandler(500, "Failed to update notification"); + } + } + + return { success: true, message: "Notification marked as read" }; } catch (error) { - throw new ErrorHandler(error.statusCode, error.message); + throw new ErrorHandler(error.statusCode || 500, error.message); + } + } + + static async resendNotification(id) { + try { + const dataExist = await getUsersNotificationErrorDb(id); + + const activeUsers = + dataExist?.filter((user) => user.is_active === true) || []; + + if (activeUsers.length < 1) { + throw new ErrorHandler( + 404, + "No active contacts found for this notification" + ); + } + + if (!dataExist || dataExist.length < 1) { + throw new ErrorHandler(404, "Data Notification Error not found"); + } + + const results = await Promise.all( + dataExist && + activeUsers.map(async (user) => { + const tokenRedirect = await generateTokenRedirect( + user.contact_phone, + user.contact_name, + user.notification_error_id + ); + + const encodedToken = encodeURIComponent(tokenRedirect); + const shortUrl = await shortUrltiny(encodedToken); + + const bodyBase = + `Hai Operator\n` + + `Terjadi peringatan pada device, silahkan cek detail pada link berikut :\n`; + const bodyWithUrl = `${bodyBase}\nšŸ”— ${shortUrl}`; + + const resultSend = await sendNotifikasi( + user.contact_phone, + bodyWithUrl + ); + const isSuccess = resultSend?.error ? false : true; + + await updateNotificationErrorDb(user.notification_error_id, { + is_send: isSuccess, + is_delivered: isSuccess, + }); + + return { + contact_name: user.contact_name, + contact_phone: user.contact_phone, + is_send: isSuccess, + is_delivered: isSuccess, + }; + }) + ); + + return { + notification_error_id: id, + user: results, + message: "Berhasil mengirim ulang notifikasi", + }; + } catch (error) { + throw new ErrorHandler(error.statusCode || 500, error.message); } } } diff --git a/services/notification_error_user.service.js b/services/notification_error_user.service.js index f589a7a..5b37bff 100644 --- a/services/notification_error_user.service.js +++ b/services/notification_error_user.service.js @@ -3,9 +3,16 @@ const { getNotificationErrorUserByIdDb, createNotificationErrorUserDb, updateNotificationErrorUserDb, - deleteNotificationErrorUserDb -} = require('../db/notification_error_user.db'); -const { ErrorHandler } = require('../helpers/error'); + deleteNotificationErrorUserDb, +} = require("../db/notification_error_user.db"); + +const { + generateTokenRedirect, + shortUrltiny, + sendNotifikasi, +} = require("../db/notification_wa.db"); + +const { ErrorHandler } = require("../helpers/error"); class NotificationErrorUserService { // Get all Contact @@ -13,10 +20,9 @@ class NotificationErrorUserService { try { const results = await getAllNotificationErrorUserDb(param); - results.data.map(element => { - }); + results.data.map((element) => {}); - return results + return results; } catch (error) { throw new ErrorHandler(error.statusCode, error.message); } @@ -27,7 +33,8 @@ class NotificationErrorUserService { try { const result = await getNotificationErrorUserByIdDb(id); - if (result.length < 1) throw new ErrorHandler(404, 'NotificationErrorUser not found'); + if (result.length < 1) + throw new ErrorHandler(404, "Notification Error User not found"); return result; } catch (error) { @@ -38,7 +45,7 @@ class NotificationErrorUserService { // Create NotificationErrorUser static async createNotificationErrorUser(data) { try { - if (!data || typeof data !== 'object') data = {}; + if (!data || typeof data !== "object") data = {}; const result = await createNotificationErrorUserDb(data); @@ -51,12 +58,12 @@ class NotificationErrorUserService { // Update NotificationErrorUser static async updateNotificationErrorUser(id, data) { try { - if (!data || typeof data !== 'object') data = {}; + if (!data || typeof data !== "object") data = {}; const dataExist = await getNotificationErrorUserByIdDb(id); if (dataExist.length < 1) { - throw new ErrorHandler(404, 'NotificationErrorUser not found'); + throw new ErrorHandler(404, "Notification Error User not found"); } const result = await updateNotificationErrorUserDb(id, data); @@ -73,7 +80,7 @@ class NotificationErrorUserService { const dataExist = await getNotificationErrorUserByIdDb(id); if (dataExist.length < 1) { - throw new ErrorHandler(404, 'NotificationErrorUser not found'); + throw new ErrorHandler(404, "Notification Error User not found"); } const result = await deleteNotificationErrorUserDb(id, userId); @@ -83,6 +90,79 @@ class NotificationErrorUserService { throw new ErrorHandler(error.statusCode, error.message); } } + + static async resendNotificationByUser(id, contact_phone) { + + try { + const dataExist = await getNotificationErrorUserByIdDb(id); + if (!dataExist || dataExist.length < 1) { + throw new ErrorHandler( + 404, + "Data Notification Error User not found" + ); + } + + const data = dataExist[0]; + + if (data.contact_phone !== contact_phone) { + throw new ErrorHandler( + 404, + `Contact Phone with this phone ${contact_phone} not found.` + ); + } + + if (data.contact_is_active === false) { + throw new ErrorHandler( + 400, + `Contact Phone with this phone ${data.contact_phone} not active.` + ); + } + + const tokenRedirect = await generateTokenRedirect( + data.contact_phone, + data.contact_name, + data.notification_error_id + ); + + const encodedToken = encodeURIComponent(tokenRedirect); + const shortUrl = await shortUrltiny(encodedToken); + + const bodyBase = + `Hai Operator\n` + + `Terjadi peringatan pada device, silahkan cek detail pada link berikut :\n`; + + const bodyWithUrl = `${bodyBase}\nšŸ”— ${shortUrl}`; + + const resultSend = await sendNotifikasi(data.contact_phone, bodyWithUrl); + + const isSuccess = resultSend?.error ? false : true; + + const updateData = { + is_send: isSuccess, + message_error_issue: bodyWithUrl, + }; + + await updateNotificationErrorUserDb(id, updateData); + + if (!isSuccess) { + throw new ErrorHandler( + 500, + `WhatsApp API Gagal mengirim pesan: ${ + resultSend?.message || "Unknown Error" + }` + ); + } + + return { + notification_error_user_id: id, + is_send: isSuccess, + short_url: shortUrl, + message: "Berhasil mengirim ulang notifikasi", + }; + } catch (error) { + throw new ErrorHandler(error.statusCode || 500, error.message); + } + } } module.exports = NotificationErrorUserService; diff --git a/services/notifikasi-wa.service.js b/services/notifikasi-wa.service.js index 210b454..d21a1f5 100644 --- a/services/notifikasi-wa.service.js +++ b/services/notifikasi-wa.service.js @@ -75,6 +75,8 @@ class NotifikasiWaService { let bodyWithUrl = `${param.bodyMessage}\nšŸ”— ${shortUrl}`; + console.log(bodyWithUrl) + param.bodyMessage = bodyWithUrl const resultNotificationErrorUser = await createNotificationErrorUserDb({ diff --git a/validate/notification.schema.js b/validate/notification.schema.js index e4796fb..7e73f9b 100644 --- a/validate/notification.schema.js +++ b/validate/notification.schema.js @@ -40,21 +40,11 @@ const insertNotificationSchema = Joi.object({ // Update Notification Schema // ======================== const updateNotificationSchema = Joi.object({ - is_send: Joi.boolean().optional().messages({ - "boolean.base": "is_send must be a boolean", - }), - - is_delivered: Joi.boolean().optional().messages({ - "boolean.base": "is_delivered must be a boolean", - }), is_read: Joi.boolean().optional().messages({ "boolean.base": "is_read must be a boolean", }), - - is_active: Joi.boolean().optional().messages({ - "boolean.base": "is_active must be a boolean", - }), + }); module.exports = {