updated absensi
This commit is contained in:
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
})
|
||||
|
||||
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user