updated absensi

This commit is contained in:
2025-10-15 15:25:11 +07:00
parent 96d206d892
commit 9389edf24d
5 changed files with 108 additions and 15 deletions

View File

@@ -6,6 +6,10 @@ const history = async (req, res) => {
return response; return response;
}; };
const getAll = async (req, res) => {
const response = await services.getAll(req, res)
}
const create = async (req, res) => { const create = async (req, res) => {
const response = await services.create(req, res); const response = await services.create(req, res);
return response; return response;
@@ -26,10 +30,17 @@ const destroy = async (req, res) => {
return response; return response;
}; };
const checkLocation = async (req, res) => {
const response = await services.checkLocation(req, res)
return response
}
module.exports = { module.exports = {
create, create,
history, history,
update, update,
destroy, destroy,
clockOut clockOut,
getAll,
checkLocation
} }

View File

@@ -9,10 +9,18 @@ router.get('/history', apiKey, jwt, (req, res) => {
controller.history(req, res); controller.history(req, res);
}) })
router.get('/', apiKey, (req, res) => {
controller.getAll(req, res)
})
router.post('/', jwt, apiKey, upload.single('attendances'), (req, res) => { router.post('/', jwt, apiKey, upload.single('attendances'), (req, res) => {
controller.create(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) => { router.post('/clock-out', jwt, apiKey, (req, res) => {
controller.clockOut(req, res) controller.clockOut(req, res)
}) })

View File

@@ -7,8 +7,6 @@ const moment = require('moment-timezone')
const path = require("path"); const path = require("path");
const fs = require("fs"); const fs = require("fs");
const axios = require("axios"); const axios = require("axios");
const User = db.User const User = db.User
const Attedances = db.Attedances const Attedances = db.Attedances
const Branch = db.Branch 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)`); return response.failed(res, 400, `Lokasi di luar area kantor (${distance.toFixed(2)} meter)`);
} }
let finalPhotoUrl = null; let finalPhotoUrl = null;
if (req.file) { if (req.file) {
@@ -112,8 +111,6 @@ const create = async (req, res) => {
finalPhotoUrl = filePath.replace("public", "").replace(/\\/g, "/"); finalPhotoUrl = filePath.replace("public", "").replace(/\\/g, "/");
} }
// === Absen masuk === // === Absen masuk ===
attendance = await Attedances.create({ attendance = await Attedances.create({
user_id, user_id,
@@ -130,6 +127,7 @@ const create = async (req, res) => {
await t.commit(); await t.commit();
return response.success(res, { return response.success(res, {
...attendance.toJSON(), ...attendance.toJSON(),
branch_name: branch.name,
clock_in: moment(attendance.clock_in).tz('Asia/Jakarta').format('YYYY-MM-DD HH:mm:ss'), clock_in: moment(attendance.clock_in).tz('Asia/Jakarta').format('YYYY-MM-DD HH:mm:ss'),
clock_out: attendance.clock_out clock_out: attendance.clock_out
? moment(attendance.clock_out).tz('Asia/Jakarta').format('YYYY-MM-DD HH:mm:ss') ? 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(); await t.rollback();
return response.failed(res, 400, 'Sudah absen pulang hari ini'); 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) // Set jam pulang (tanpa cek lokasi)
attendance.clock_out = now.toDate(); attendance.clock_out = now.toDate();
@@ -180,6 +179,7 @@ const clockOut = async (req, res) => {
return response.success(res, { return response.success(res, {
...attendance.toJSON(), ...attendance.toJSON(),
branch_name: branch.name,
clock_in: moment(attendance.clock_in).tz('Asia/Jakarta').format('YYYY-MM-DD HH:mm:ss'), 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'), clock_out: moment(attendance.clock_out).tz('Asia/Jakarta').format('YYYY-MM-DD HH:mm:ss'),
work_duration: attendance.work_duration, 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 update = async (req, res) => {
const t = await sequelize.transaction(); const t = await sequelize.transaction();
@@ -255,18 +279,18 @@ const update = async (req, res) => {
const user_id = req.user.id; const user_id = req.user.id;
const body = req.body; const body = req.body;
const categories = await Category.findOne({ const attedances = await Attedances.findOne({
where: { id }, where: { id },
transaction: t transaction: t
}); });
const categoriesUpdate = await categories.update({ const attedancesUpdate = await attedances.update({
...body, ...body,
user_id, user_id,
}, { transaction: t }); }, { transaction: t });
await t.commit(); await t.commit();
return response.success(res, categoriesUpdate, 'Category Berhasil Di update'); return response.success(res, attedancesUpdate, 'Category Berhasil Di update');
} catch (error) { } catch (error) {
await t.rollback(); await t.rollback();
errorHandler(error, req, res); errorHandler(error, req, res);
@@ -278,20 +302,20 @@ const destroy = async (req, res) => {
const t = await sequelize.transaction(); const t = await sequelize.transaction();
try { try {
const id = req.params.id; const id = req.params.id;
const category = await Category.findOne({ const attendance = await Attedances.findOne({
where: { id }, where: { id },
transaction: t, transaction: t,
}); });
if (!category) { if (!attendance) {
await t.rollback(); 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(); await t.commit();
return response.success(res, null, 'Category berhasil dihapus'); return response.success(res, null, 'Attendance berhasil dihapus');
} catch (error) { } catch (error) {
await t.rollback(); await t.rollback();
errorHandler(error, req, res); 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 = { module.exports = {
create, create,
destroy, destroy,
history, history,
update, update,
clockOut clockOut,
getAll,
checkLocation
} }

View File

@@ -16,7 +16,7 @@ router.put('/:id', apiKey, jwt, (req, res) => {
controller.update(req, res) controller.update(req, res)
}) })
router.put('/:id', apiKey, jwt, (req, res) => { router.delete('/:id', apiKey, jwt, (req, res) => {
controller.destroy(req, res) controller.destroy(req, res)
}) })