feat(lamaran): reset lamaran dan rollover batch, serta menambahkan snapshot posisi lamaran mhs ke tabel user

This commit is contained in:
Muhammad Zhafran Ilham
2026-07-01 18:05:17 +07:00
parent dda89a7d1a
commit c31c91fb8a
6 changed files with 309 additions and 31 deletions
@@ -172,6 +172,32 @@ class LamaranMagangController {
}
}
async deleteAllLamaranMagang(req, res) {
try {
const result = await lamaranMagangService.deleteAllLamaranMagang();
if (result.err) {
return response(res, 'fail', result);
}
return response(
res,
'success',
result,
'Data lamaran magang dan mahasiswa berhasil dibersihkan, batch baru berhasil dibuat',
SUCCESS.OK
);
} catch (err) {
return response(
res,
'fail',
error(new InternalServerError(err.message)),
'Terjadi kesalahan yang tidak terduga',
ERROR.INTERNAL_ERROR
);
}
}
async exportLamaranToExcel(req, res) {
try {
const result = await lamaranMagangService.exportToExcel();
@@ -163,6 +163,134 @@ class LamaranMagangRepository {
});
}
async findAllMahasiswaForCleanup() {
return prisma.mahasiswa.findMany({
select: {
id: true,
cv_path: true,
portofolio_path: true,
},
});
}
async deleteAllLamaranMagang() {
return prisma.$transaction(async (tx) => {
const internUsers = await tx.user.findMany({
where: {
role: "intern",
id_lamaran_magang: {
not: null,
},
},
select: {
id: true,
intern_position: true,
intern_interest_group: true,
lamaran_magang: {
select: {
lowongan_magang: {
select: {
posisi: true,
kelompok_peminatan: true,
},
},
},
},
},
});
for (const user of internUsers) {
const lowongan = user.lamaran_magang?.lowongan_magang;
await tx.user.update({
where: {
id: user.id,
},
data: {
intern_position: user.intern_position || lowongan?.posisi || null,
intern_interest_group:
user.intern_interest_group || lowongan?.kelompok_peminatan || null,
},
});
}
const detachedUsers = await tx.user.updateMany({
where: {
OR: [
{
id_mahasiswa: {
not: null,
},
},
{
id_lamaran_magang: {
not: null,
},
},
],
},
data: {
id_mahasiswa: null,
id_lamaran_magang: null,
},
});
const deletedLamaranMagang = await tx.lamaranMagang.deleteMany({});
const deletedMahasiswa = await tx.mahasiswa.deleteMany({});
const latestBatch = await tx.batch.findFirst({
orderBy: {
batch_number: "desc",
},
});
const previousActiveBatch = await tx.batch.findFirst({
where: {
is_active: true,
},
orderBy: {
batch_number: "desc",
},
});
if (previousActiveBatch) {
await tx.batch.update({
where: {
id: previousActiveBatch.id,
},
data: {
is_active: false,
},
});
}
const newBatch = await tx.batch.create({
data: {
batch_number: latestBatch ? latestBatch.batch_number + 1 : 1,
is_active: true,
},
});
return {
detached_users: detachedUsers.count,
deleted_lamaran_magang: deletedLamaranMagang.count,
deleted_mahasiswa: deletedMahasiswa.count,
previous_active_batch: previousActiveBatch
? {
id: previousActiveBatch.id,
batch_number: previousActiveBatch.batch_number,
is_active: false,
}
: null,
new_active_batch: {
id: newBatch.id,
batch_number: newBatch.batch_number,
is_active: newBatch.is_active,
},
};
});
}
async getStatistics({ query }) {
let where = {};
@@ -238,7 +366,7 @@ class LamaranMagangRepository {
: Prisma.sql``;
const data = await prisma.$queryRaw`
SELECT
SELECT
m.negara,
COUNT(*) as total,
SUM(lm.status = 'diterima') as diterima,
@@ -266,7 +394,7 @@ class LamaranMagangRepository {
: Prisma.sql``;
const data = await prisma.$queryRaw`
SELECT
SELECT
m.universitas,
COUNT(*) as total,
SUM(lm.status = 'diterima') as diterima,
@@ -202,6 +202,10 @@ class LamaranMagangService {
let generatedPassword = null;
if (status === "diterima") {
// Menyimpan posisi dan kelompok peminatan intern
const internPosition = checkResult.data.lowongan_magang?.posisi || null;
const internInterestGroup = checkResult.data.lowongan_magang?.kelompok_peminatan || null;
const existingUser = await prisma.user.findFirst({
where: {
OR: [
@@ -227,9 +231,21 @@ class LamaranMagangService {
email: checkResult.data.mahasiswa.email,
password: hashedPassword,
role: "intern",
intern_position: internPosition,
intern_interest_group: internInterestGroup,
is_active: true,
},
});
} else {
await prisma.user.update({
where: {
id: existingUser.id,
},
data: {
intern_position: existingUser.intern_position || internPosition,
intern_interest_group:existingUser.intern_interest_group || internInterestGroup,
},
});
}
}
@@ -267,6 +283,43 @@ class LamaranMagangService {
}
}
async deleteAllLamaranMagang() {
try {
const mahasiswaList = await lamaranMagangRepository.findAllMahasiswaForCleanup();
const result = await lamaranMagangRepository.deleteAllLamaranMagang();
let deletedFiles = 0;
const failedFiles = [];
for (const mahasiswa of mahasiswaList) {
const files = [mahasiswa.cv_path, mahasiswa.portofolio_path];
for (const filePath of files) {
if (!filePath) continue;
try {
const fileName = path.basename(filePath);
await deleteFileIfExists(fileName);
deletedFiles += 1;
} catch (fileErr) {
failedFiles.push({
file_path: filePath,
error: fileErr.message,
});
}
}
}
return data({
...result,
deleted_files: deletedFiles,
failed_files: failedFiles,
});
} catch (err) {
return error(err);
}
}
async exportToExcel() {
try {
const lamaranList = await lamaranMagangRepository.findAll({});