From 9389edf24d1d8e9430f0e161137059f594fc18ba Mon Sep 17 00:00:00 2001 From: Tirta Aditya Date: Wed, 15 Oct 2025 15:25:11 +0700 Subject: [PATCH] updated absensi --- .../absensi/controllers/absensi.controller.js | 13 ++- ...tegory.resource.js => absensi.resource.js} | 0 app/modules/absensi/routes/absensi.route.js | 8 ++ .../absensi/services/absensi.service.js | 100 +++++++++++++++--- app/modules/branch/routes/branch.route.js | 2 +- 5 files changed, 108 insertions(+), 15 deletions(-) rename app/modules/absensi/resources/{category.resource.js => absensi.resource.js} (100%) diff --git a/app/modules/absensi/controllers/absensi.controller.js b/app/modules/absensi/controllers/absensi.controller.js index d628663..575b2e8 100644 --- a/app/modules/absensi/controllers/absensi.controller.js +++ b/app/modules/absensi/controllers/absensi.controller.js @@ -6,6 +6,10 @@ const history = async (req, res) => { return response; }; +const getAll = async (req, res) => { + const response = await services.getAll(req, res) +} + const create = async (req, res) => { const response = await services.create(req, res); return response; @@ -26,10 +30,17 @@ const destroy = async (req, res) => { return response; }; +const checkLocation = async (req, res) => { + const response = await services.checkLocation(req, res) + return response +} + module.exports = { create, history, update, destroy, - clockOut + clockOut, + getAll, + checkLocation } \ No newline at end of file diff --git a/app/modules/absensi/resources/category.resource.js b/app/modules/absensi/resources/absensi.resource.js similarity index 100% rename from app/modules/absensi/resources/category.resource.js rename to app/modules/absensi/resources/absensi.resource.js diff --git a/app/modules/absensi/routes/absensi.route.js b/app/modules/absensi/routes/absensi.route.js index 295b15d..72a955e 100644 --- a/app/modules/absensi/routes/absensi.route.js +++ b/app/modules/absensi/routes/absensi.route.js @@ -9,10 +9,18 @@ router.get('/history', apiKey, jwt, (req, res) => { controller.history(req, res); }) +router.get('/', apiKey, (req, res) => { + controller.getAll(req, res) +}) + router.post('/', jwt, apiKey, upload.single('attendances'), (req, res) => { controller.create(req, res) }) +router.get('/check-location', apiKey, jwt, (req, res) => { + controller.checkLocation(req, res) +}) + router.post('/clock-out', jwt, apiKey, (req, res) => { controller.clockOut(req, res) }) diff --git a/app/modules/absensi/services/absensi.service.js b/app/modules/absensi/services/absensi.service.js index 0e36d80..3937c87 100644 --- a/app/modules/absensi/services/absensi.service.js +++ b/app/modules/absensi/services/absensi.service.js @@ -7,8 +7,6 @@ const moment = require('moment-timezone') const path = require("path"); const fs = require("fs"); const axios = require("axios"); - - const User = db.User const Attedances = db.Attedances const Branch = db.Branch @@ -90,6 +88,7 @@ const create = async (req, res) => { return response.failed(res, 400, `Lokasi di luar area kantor (${distance.toFixed(2)} meter)`); } + let finalPhotoUrl = null; if (req.file) { @@ -112,8 +111,6 @@ const create = async (req, res) => { finalPhotoUrl = filePath.replace("public", "").replace(/\\/g, "/"); } - - // === Absen masuk === attendance = await Attedances.create({ user_id, @@ -130,6 +127,7 @@ const create = async (req, res) => { await t.commit(); return response.success(res, { ...attendance.toJSON(), + branch_name: branch.name, clock_in: moment(attendance.clock_in).tz('Asia/Jakarta').format('YYYY-MM-DD HH:mm:ss'), clock_out: attendance.clock_out ? moment(attendance.clock_out).tz('Asia/Jakarta').format('YYYY-MM-DD HH:mm:ss') @@ -165,6 +163,7 @@ const clockOut = async (req, res) => { await t.rollback(); return response.failed(res, 400, 'Sudah absen pulang hari ini'); } + const branch = await Branch.findOne({ where: { id: user.branch_id } }); // Set jam pulang (tanpa cek lokasi) attendance.clock_out = now.toDate(); @@ -180,6 +179,7 @@ const clockOut = async (req, res) => { return response.success(res, { ...attendance.toJSON(), + branch_name: branch.name, clock_in: moment(attendance.clock_in).tz('Asia/Jakarta').format('YYYY-MM-DD HH:mm:ss'), clock_out: moment(attendance.clock_out).tz('Asia/Jakarta').format('YYYY-MM-DD HH:mm:ss'), work_duration: attendance.work_duration, @@ -246,7 +246,31 @@ const history = async (req, res) => { } }; +const getAll = async (req, res) => { + try { + + const today = moment().tz('Asia/Jakarta').format('YYYY-MM-DD'); + const attendances = await Attedances.findAll({ + where: { + date: today + }, + include: [ + { + model: User, + as: 'user', + attributes: ['id', 'name', 'email'] + } + ], + order: [['created_at', 'DESC']] + }); + + return response.success(res, attendances, 'List kehadiran hari ini'); + } catch (error) { + console.error(error); + return response.error(res, 'Gagal mengambil data absensi hari ini'); + } +}; const update = async (req, res) => { const t = await sequelize.transaction(); @@ -255,18 +279,18 @@ const update = async (req, res) => { const user_id = req.user.id; const body = req.body; - const categories = await Category.findOne({ + const attedances = await Attedances.findOne({ where: { id }, transaction: t }); - const categoriesUpdate = await categories.update({ + const attedancesUpdate = await attedances.update({ ...body, user_id, }, { transaction: t }); await t.commit(); - return response.success(res, categoriesUpdate, 'Category Berhasil Di update'); + return response.success(res, attedancesUpdate, 'Category Berhasil Di update'); } catch (error) { await t.rollback(); errorHandler(error, req, res); @@ -278,20 +302,20 @@ const destroy = async (req, res) => { const t = await sequelize.transaction(); try { const id = req.params.id; - const category = await Category.findOne({ + const attendance = await Attedances.findOne({ where: { id }, transaction: t, }); - if (!category) { + if (!attendance) { await t.rollback(); - return response.failed(res, 404, 'Category tidak ditemukan'); + return response.failed(res, 404, 'Attendance tidak ditemukan'); } - await category.destroy({ transaction: t }); + await attendance.destroy({ transaction: t }); await t.commit(); - return response.success(res, null, 'Category berhasil dihapus'); + return response.success(res, null, 'Attendance berhasil dihapus'); } catch (error) { await t.rollback(); errorHandler(error, req, res); @@ -299,11 +323,61 @@ const destroy = async (req, res) => { } }; +const checkLocation = async (req, res) => { + try { + const user_id = req.user.id; + const { lat, lng } = req.query; + + if (!lat || !lng) { + return response.failed(res, 400, 'Latitude dan longitude wajib dikirim'); + } + + const user = await User.findOne({ where: { id: user_id } }); + if (!user) return response.failed(res, 404, 'User tidak ditemukan'); + + const branch = await Branch.findOne({ where: { id: user.branch_id } }); + if (!branch) return response.failed(res, 404, 'Data kantor tidak ditemukan'); + + // Hitung jarak user dengan kantor (dalam meter) + const distanceMeters = getDistance(branch.lat, branch.lng, lat, lng); + + // Otomatis ubah ke km jika lebih dari 1000 meter + const isKm = distanceMeters >= 1000; + const distance = isKm ? distanceMeters / 1000 : distanceMeters; + const unit = isKm ? 'km' : 'm'; + + // Radius tetap pakai meter (biar konsisten) + const allowedRadius = parseFloat(process.env.ABSENCE_RADIUS) || 100; + + if (distanceMeters <= allowedRadius) { + return response.success(res, { + inOffice: true, + branch_name: branch.name, + distance: distance.toFixed(2), + unit, + message: `Anda sedang berada di lokasi ${branch.name}, silakan absen.`, + }); + } + + return response.success(res, { + inOffice: false, + branch_name: branch.name, + distance: distance.toFixed(2), + unit, + message: `Anda berada di luar area kantor ${distance.toFixed(2)} ${unit} dari ${branch.name}.`, + }); + } catch (error) { + errorHandler(error, req, res); + return response.failed(res, 500, error.message); + } +}; module.exports = { create, destroy, history, update, - clockOut + clockOut, + getAll, + checkLocation } \ No newline at end of file diff --git a/app/modules/branch/routes/branch.route.js b/app/modules/branch/routes/branch.route.js index 171f91c..086cdff 100644 --- a/app/modules/branch/routes/branch.route.js +++ b/app/modules/branch/routes/branch.route.js @@ -16,7 +16,7 @@ router.put('/:id', apiKey, jwt, (req, res) => { controller.update(req, res) }) -router.put('/:id', apiKey, jwt, (req, res) => { +router.delete('/:id', apiKey, jwt, (req, res) => { controller.destroy(req, res) })