diff --git a/src/module/pendaftaran/entity/pendaftaran.go b/src/module/pendaftaran/entity/pendaftaran.go index c75acc7c43dc24c1dd4b98c65a0f22fc342c8cdd..94fb813fca4af68afd817855c37dc0b068030fc0 100644 --- a/src/module/pendaftaran/entity/pendaftaran.go +++ b/src/module/pendaftaran/entity/pendaftaran.go @@ -59,6 +59,42 @@ type RekapPendaftaran struct { InterviewAt time.Time `json:"jadwal_interview"` } +type RekapPendaftaranTimta struct { + ID string `json:"mahasiswa_id"` + Nama string `json:"mahasiswa_nama"` + Nim string `json:"nim"` + PembimbingNama string `json:"pembimbing_nama"` + Status string `json:"status"` + PendaftaranId string `json:"pendaftaran_id"` +} + +type RiwayatPendaftaran struct { + ID string `json:"id"` + InterviewAt string `json:"jadwalInterview"` + JalurPilihan string `json:"jalurPilihan"` + WaktuPengiriman string `json:"waktuPengiriman"` + Status string `json:"status"` + Judul string `json:"judulTopik"` + Deskripsi string `json:"deskripsiTopik"` +} + +type DosenPembimbing struct { + IDPendaftaran string `json:"pendaftaran_id"` + ID string `json:"id"` + Nama string `json:"nama"` +} + +type RiwayatPendaftaranRes struct { + ID string `json:"id"` + InterviewAt string `json:"jadwalInterview"` + JalurPilihan string `json:"jalurPilihan"` + WaktuPengiriman string `json:"waktuPengiriman"` + Status string `json:"status"` + Judul string `json:"judulTopik"` + Deskripsi string `json:"deskripsiTopik"` + DosenPembimbing []DosenPembimbing `json:"dosenPembimbing"` +} + type DetailRekapPendaftara struct { Judul string `json:"judulTopik"` Deskripsi string `json:"deskripsiTopik"` @@ -78,6 +114,11 @@ type UpdateStatusReq struct { Status string `json:"status"` } +type UpdateStatusByIdReq struct { + IDPendaftaran string `json:"id_pendaftaran"` + Status string `json:"status"` +} + type Stats struct { Diterima StatsItem `json:"diterima"` SedangProses StatsItem `json:"sedang_proses"` diff --git a/src/module/pendaftaran/internal/repository/pendaftaran.go b/src/module/pendaftaran/internal/repository/pendaftaran.go index 52c3528a898c094944971b43f791395b7a2534ae..1fd535b639b0c42c9159931eb4606f40f29d10bc 100644 --- a/src/module/pendaftaran/internal/repository/pendaftaran.go +++ b/src/module/pendaftaran/internal/repository/pendaftaran.go @@ -210,6 +210,20 @@ func (repo *PendaftaranRepo) UpdateStatus(status string, idDosen string, idMahas return nil } +func (repo *PendaftaranRepo) UpdateStatusById(status string, idPendaftaran string) error { + updates := map[string]interface{}{ + "status": status, + } + + if err := repo.DBWrite.Table("pendaftaran_ta"). + Where("id = ?", idPendaftaran). + Updates(updates).Error; err != nil { + return err + } + + return nil +} + func (repo *PendaftaranRepo) CountApproved(idDosen string) (int64, error) { var count int64 @@ -245,3 +259,100 @@ func (repo *PendaftaranRepo) CountRejected(idDosen string) (int64, error) { return count, nil } + +func (repo *PendaftaranRepo) CountApprovedAll() (int64, error) { + var count int64 + + if err := repo.DBRead.Table("pendaftaran_ta"). + Where("status = ?", "APPROVED"). + Count(&count).Error; err != nil { + return 0, err + } + + return count, nil +} +func (repo *PendaftaranRepo) CountProsesAll() (int64, error) { + var count int64 + + if err := repo.DBRead.Table("pendaftaran_ta"). + Where("status = ? ", "NOT_ASSIGNED"). + Or("status = ? ", "INTERVIEW"). + Count(&count).Error; err != nil { + return 0, err + } + + return count, nil +} + +func (repo *PendaftaranRepo) CountRejectedAll() (int64, error) { + var count int64 + + if err := repo.DBRead.Table("pendaftaran_ta"). + Where("status = ?", "REJECTED"). + Count(&count).Error; err != nil { + return 0, err + } + + return count, nil +} + +func (repo *PendaftaranRepo) GetDosbingName(idMahasiswa string) (string, error) { + var dosbingName string + + query := ` + SELECT p.nama + FROM pengguna p + JOIN dosen_bimbingan db ON p.id = db.dosen_id + JOIN pendaftaran_ta pt ON db.pendaftaran_id = pt.id + WHERE pt.id_mahasiswa = ? + ORDER BY pt.waktu_pengiriman DESC + LIMIT 1; + ` + + if err := repo.DBRead.Raw(query, idMahasiswa).Scan(&dosbingName).Error; err != nil { + return "", err + } + + return dosbingName, nil +} + +func (repo *PendaftaranRepo) GetAllPendaftaran() ([]entity.RekapPendaftaran, error) { + var res []entity.RekapPendaftaran + err := repo.DBRead.Table("pendaftaran_ta"). + Select("pendaftaran_ta.id, pendaftaran_ta.id_mahasiswa, pendaftaran_ta.status, pendaftaran_ta.interview_at, pengguna.nama, pengguna.nim"). + Joins("JOIN pengguna on pendaftaran_ta.id_mahasiswa = pengguna.id"). + Scan(&res).Error + if err != nil { + return nil, err + } + + return res, nil +} + +func (repo *PendaftaranRepo) GetRiwayatPendaftaran(idMahasiswa string) ([]entity.RiwayatPendaftaran, error) { + var res []entity.RiwayatPendaftaran + err := repo.DBRead.Table("pendaftaran_ta"). + Select("pendaftaran_ta.id, pendaftaran_ta.jalur_pilihan, pendaftaran_ta.status, pendaftaran_ta.interview_at, pendaftaran_ta.waktu_pengiriman, topik.judul, topik.deskripsi"). + Joins("JOIN topik on pendaftaran_ta.id_topik = topik.id"). + Where("pendaftaran_ta.id_mahasiswa = ?", idMahasiswa). + Scan(&res).Error + if err != nil { + return nil, err + } + + return res, nil +} + +func (repo *PendaftaranRepo) GetDosbingForPendaftaran(idMahasiswa string) ([]entity.DosenPembimbing, error) { + var res []entity.DosenPembimbing + err := repo.DBRead.Table("pendaftaran_ta"). + Select("pendaftaran_ta.id as id_pendaftaran, pengguna.id, pengguna.nama"). + Joins("JOIN pengguna on pendaftaran_ta.id_dosen = pengguna.id"). + Where("pendaftaran_ta.id_mahasiswa = ?", idMahasiswa). + Scan(&res).Error + if err != nil { + return nil, err + } + + return res, nil +} diff --git a/src/module/pendaftaran/internal/usecase/pendaftaran.go b/src/module/pendaftaran/internal/usecase/pendaftaran.go index 109d4bd190916fed52567144eb5876180903c8de..90f6c946d1dede4557067b150196292f0361411e 100644 --- a/src/module/pendaftaran/internal/usecase/pendaftaran.go +++ b/src/module/pendaftaran/internal/usecase/pendaftaran.go @@ -22,6 +22,10 @@ type PendaftaranUsecase interface { UpdateInterview(interviewAt string, idDosen string, idMahasiswa string) error UpdateStatus(status string, idDosen string, idMahasiswa string) error GetStatisticsPendaftaran(idDosen string) (entity.Stats, error) + GetRekapPendaftaranTimta() ([]entity.RekapPendaftaranTimta, error) + GetStatisticsPendaftaranTimta() (entity.Stats, error) + UpdateStatusById(status string, idPendaftaran string) error + GetRiwayatPendaftaran(idMahasiswa string) ([]entity.RiwayatPendaftaranRes, error) } type PendaftaranUc struct { @@ -95,6 +99,83 @@ func (uc *PendaftaranUc) UpdateStatus(status string, idDosen string, idMahasiswa return uc.pendaftaranRepo.UpdateStatus(status, idDosen, idMahasiswa) } +func (uc *PendaftaranUc) UpdateStatusById(status string, idPendaftaran string) error { + if status == "" { + return errors.New("interview timestamp cannot be empty") + } + return uc.pendaftaranRepo.UpdateStatusById(status, idPendaftaran) +} + +func (uc *PendaftaranUc) GetRiwayatPendaftaran(idMahasiswa string) ([]entity.RiwayatPendaftaranRes, error) { + // Retrieve dosen pembimbing information + dosBing, err := uc.pendaftaranRepo.GetDosbingForPendaftaran(idMahasiswa) + if err != nil { + return []entity.RiwayatPendaftaranRes{}, err + } + + // Retrieve riwayat pendaftaran + riwPen, err := uc.pendaftaranRepo.GetRiwayatPendaftaran(idMahasiswa) + if err != nil { + return []entity.RiwayatPendaftaranRes{}, err + } + + var riwayatPendaftarans []entity.RiwayatPendaftaranRes + for _, riw := range riwPen { + var dosenPembimbings []entity.DosenPembimbing + + for _, dos := range dosBing { + if dos.IDPendaftaran == riw.ID { + dosenPembimbing := entity.DosenPembimbing{ + ID: dos.ID, + Nama: dos.Nama, + } + dosenPembimbings = append(dosenPembimbings, dosenPembimbing) + } + } + + // Create the RiwayatPendaftaranRes struct + riwayatPendaftaran := entity.RiwayatPendaftaranRes{ + ID: riw.ID, + InterviewAt: riw.InterviewAt, + JalurPilihan: riw.JalurPilihan, + WaktuPengiriman: riw.WaktuPengiriman, + Status: riw.Status, + Judul: riw.Judul, + Deskripsi: riw.Deskripsi, + DosenPembimbing: dosenPembimbings, + } + + riwayatPendaftarans = append(riwayatPendaftarans, riwayatPendaftaran) + } + + return riwayatPendaftarans, nil +} + +func (uc *PendaftaranUc) GetRekapPendaftaranTimta() ([]entity.RekapPendaftaranTimta, error) { + var rekapPendaftarans []entity.RekapPendaftaranTimta + allPendaftaran, err := uc.pendaftaranRepo.GetAllPendaftaran() + if err != nil { + return []entity.RekapPendaftaranTimta{}, nil + } + for _, pendaftaran := range allPendaftaran { + dosbingName, err := uc.pendaftaranRepo.GetDosbingName(pendaftaran.IDMahasiswa) + if err != nil { + return []entity.RekapPendaftaranTimta{}, nil + } + rekapPendaftaran := entity.RekapPendaftaranTimta{ + ID: pendaftaran.IDMahasiswa, + Nama: pendaftaran.Nama, + Nim: pendaftaran.Nim, + PembimbingNama: dosbingName, + Status: pendaftaran.Status, + PendaftaranId: pendaftaran.ID, + } + rekapPendaftarans = append(rekapPendaftarans, rekapPendaftaran) + } + return rekapPendaftarans, nil + +} + func (uc *PendaftaranUc) GetStatisticsPendaftaran(idDosen string) (entity.Stats, error) { approved, err := uc.pendaftaranRepo.CountApproved(idDosen) if err != nil { @@ -131,3 +212,40 @@ func (uc *PendaftaranUc) GetStatisticsPendaftaran(idDosen string) (entity.Stats, } return stats, nil } + +func (uc *PendaftaranUc) GetStatisticsPendaftaranTimta() (entity.Stats, error) { + approved, err := uc.pendaftaranRepo.CountApprovedAll() + if err != nil { + return entity.Stats{}, err + } + proses, err := uc.pendaftaranRepo.CountProsesAll() + if err != nil { + return entity.Stats{}, err + } + rejected, err := uc.pendaftaranRepo.CountRejectedAll() + if err != nil { + return entity.Stats{}, err + } + total := approved + proses + rejected + percApproved := approved / total * 100 + percProses := proses / total * 100 + perRejected := rejected / total * 100 + diterima := entity.StatsItem{ + Amount: approved, + Percentage: percApproved, + } + sedangProses := entity.StatsItem{ + Amount: proses, + Percentage: percProses, + } + ditolak := entity.StatsItem{ + Amount: rejected, + Percentage: perRejected, + } + stats := entity.Stats{ + Diterima: diterima, + SedangProses: sedangProses, + Ditolak: ditolak, + } + return stats, nil +} diff --git a/src/module/pendaftaran/internal/usecase/repository.go b/src/module/pendaftaran/internal/usecase/repository.go index f7a1733f46ad9821e04c66764c8c79fd11a0ebd3..6cf957f115d861f0faca65c8a2697ca4424b8878 100644 --- a/src/module/pendaftaran/internal/usecase/repository.go +++ b/src/module/pendaftaran/internal/usecase/repository.go @@ -23,4 +23,12 @@ type PendaftaranRepository interface { CountApproved(idDosen string) (int64, error) CountProses(idDosen string) (int64, error) CountRejected(idDosen string) (int64, error) + CountApprovedAll() (int64, error) + CountProsesAll() (int64, error) + CountRejectedAll() (int64, error) + GetDosbingName(idMahasiswa string) (string, error) + GetAllPendaftaran() ([]entity.RekapPendaftaran, error) + UpdateStatusById(status string, idPendaftaran string) error + GetRiwayatPendaftaran(idMahasiswa string) ([]entity.RiwayatPendaftaran, error) + GetDosbingForPendaftaran(idMahasiswa string) ([]entity.DosenPembimbing, error) } diff --git a/src/module/pendaftaran/transport/admin_handler.go b/src/module/pendaftaran/transport/admin_handler.go index fe8144de9130bfac5a05307d9b72d7440d63fc29..2f5aae3e5fac5405d43fb755b238b2965137effc 100644 --- a/src/module/pendaftaran/transport/admin_handler.go +++ b/src/module/pendaftaran/transport/admin_handler.go @@ -36,10 +36,14 @@ func (t *AdminPendaftaranHandler) MountAdmin(group *echo.Group) { group.GET("/pendaftaran-by-periode", t.GetPendaftaranByPeriode) group.GET("/pendaftaran-by-id", t.GetPendaftaranById) group.GET("/rekap-pendaftaran", t.GetRekapPendaftaranDosen) + group.GET("/rekap-pendaftaran-timta", t.GetRekapPendaftaranTimta) group.GET("/detail-rekap-pendaftaran", t.GetDetailRekapPendafataran) group.PUT("/update-interview", t.UpdateInterview) group.PUT("/update-status", t.UpdateStatus) + group.PUT("/update-status-by-id", t.UpdateStatusById) group.GET("/statistics", t.GetStatistics) + group.GET("/statistics-timta", t.GetStatisticsTimta) + group.GET("/riwayat-pendaftaran", t.GetRiwayatPendaftaran) } // AddPendaftaran adds a new pendaftaran record. @@ -115,6 +119,25 @@ func (t *AdminPendaftaranHandler) GetRekapPendaftaranDosen(c echo.Context) error return c.JSON(http.StatusOK, utils.ResponseDetailOutput(true, http.StatusOK, "Rekap successfully retreived", rekap)) } +func (t *AdminPendaftaranHandler) GetRekapPendaftaranTimta(c echo.Context) error { + rekap, err := t.pendaftaranUsecase.GetRekapPendaftaranTimta() + if err != nil { + return c.JSON(http.StatusBadRequest, utils.ResponseDetailOutput(false, http.StatusBadRequest, err.Error(), nil)) + } + + return c.JSON(http.StatusOK, utils.ResponseDetailOutput(true, http.StatusOK, "Rekap successfully retreived", rekap)) +} + +func (t *AdminPendaftaranHandler) GetRiwayatPendaftaran(c echo.Context) error { + idMahasiswa := c.QueryParam("id_mahasiswa") + riwayat, err := t.pendaftaranUsecase.GetRiwayatPendaftaran(idMahasiswa) + if err != nil { + return c.JSON(http.StatusBadRequest, utils.ResponseDetailOutput(false, http.StatusBadRequest, err.Error(), nil)) + } + + return c.JSON(http.StatusOK, utils.ResponseDetailOutput(true, http.StatusOK, "riwayat successfully retreived", riwayat)) +} + func (t *AdminPendaftaranHandler) GetDetailRekapPendafataran(c echo.Context) error { payload, ok := c.Get("authPayload").(utils.Payload) if !ok { @@ -163,6 +186,19 @@ func (t *AdminPendaftaranHandler) UpdateStatus(c echo.Context) error { return c.JSON(http.StatusOK, utils.ResponseDetailOutput(true, http.StatusOK, "Interview successfully updated", err)) } +func (t *AdminPendaftaranHandler) UpdateStatusById(c echo.Context) error { + request := new(entity.UpdateStatusByIdReq) + if err := c.Bind(&request); err != nil { + return c.JSON(http.StatusBadRequest, utils.ResponseDetailOutput(false, http.StatusBadRequest, err.Error(), nil)) + } + err := t.pendaftaranUsecase.UpdateStatusById(request.Status, request.IDPendaftaran) + if err != nil { + return c.JSON(http.StatusBadRequest, utils.ResponseDetailOutput(false, http.StatusBadRequest, err.Error(), nil)) + } + + return c.JSON(http.StatusOK, utils.ResponseDetailOutput(true, http.StatusOK, "Interview successfully updated", err)) +} + func (t *AdminPendaftaranHandler) GetStatistics(c echo.Context) error { payload, ok := c.Get("authPayload").(utils.Payload) if !ok { @@ -176,6 +212,15 @@ func (t *AdminPendaftaranHandler) GetStatistics(c echo.Context) error { return c.JSON(http.StatusOK, utils.ResponseDetailOutput(true, http.StatusOK, "stats successfully updated", stats)) } +func (t *AdminPendaftaranHandler) GetStatisticsTimta(c echo.Context) error { + stats, err := t.pendaftaranUsecase.GetStatisticsPendaftaranTimta() + if err != nil { + return c.JSON(http.StatusBadRequest, utils.ResponseDetailOutput(false, http.StatusBadRequest, err.Error(), nil)) + } + + return c.JSON(http.StatusOK, utils.ResponseDetailOutput(true, http.StatusOK, "stats successfully updated", stats)) +} + func (t *AdminPendaftaranHandler) GetPendaftaranById(c echo.Context) error { id := c.QueryParam("id") listGroupLimit, err := t.pendaftaranUsecase.GetPendaftaranById(id)