package admin
import (
"api-service/internal/config"
"api-service/internal/database"
"context"
"database/sql"
"encoding/json"
"fmt"
"net/http"
"strconv"
"time"
"github.com/gin-gonic/gin"
)
type Ruangan struct {
No int
Nama string
JumlahTT int
KodeKelas sql.NullString
KodeAplicare sql.NullString
NamaRuang sql.NullString
StAktif int
}
type AdminHandler struct {
db database.Service
}
type AdminHandlerConfig struct {
Config *config.Config
}
func NewAdminHandler(cfg AdminHandlerConfig) *AdminHandler {
return &AdminHandler{db: database.New(cfg.Config)}
}
func (h *AdminHandler) getRuangan(ctx context.Context) ([]Ruangan, error) {
db, err := h.db.GetDB("simrs")
if err != nil {
return nil, fmt.Errorf("koneksi simrs gagal: %w", err)
}
rows, err := db.QueryContext(ctx, `
SELECT no, nama, jumlah_tt, kode_kelas, kode_aplicare, nama_ruang, st_aktif
FROM m_ruang
WHERE subsistem LIKE '%RAWAT INAP%'
ORDER BY no
`)
if err != nil {
return nil, err
}
defer rows.Close()
var result []Ruangan
for rows.Next() {
var r Ruangan
if err := rows.Scan(&r.No, &r.Nama, &r.JumlahTT,
&r.KodeKelas, &r.KodeAplicare, &r.NamaRuang, &r.StAktif); err != nil {
return nil, err
}
result = append(result, r)
}
return result, rows.Err()
}
// GetPage — GET /admin/aplicares
func (h *AdminHandler) GetPage(c *gin.Context) {
ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second)
defer cancel()
ruangans, err := h.getRuangan(ctx)
if err != nil {
c.String(http.StatusInternalServerError, "Error: "+err.Error())
return
}
type RuanganJSON struct {
No int `json:"no"`
Nama string `json:"nama"`
JumlahTT int `json:"jumlah_tt"`
KodeKelas string `json:"kode_kelas"`
KodeAplicare string `json:"kode_aplicare"`
NamaRuang string `json:"nama_ruang"`
SudahMapping bool `json:"sudah_mapping"`
StAktif int `json:"st_aktif"`
}
var data []RuanganJSON
belumMapping := 0
for _, r := range ruangans {
sudah := r.KodeKelas.Valid && r.KodeKelas.String != "" &&
r.KodeAplicare.Valid && r.KodeAplicare.String != ""
if !sudah {
belumMapping++
}
data = append(data, RuanganJSON{
No: r.No,
Nama: r.Nama,
JumlahTT: r.JumlahTT,
KodeKelas: r.KodeKelas.String,
KodeAplicare: r.KodeAplicare.String,
NamaRuang: r.NamaRuang.String,
SudahMapping: sudah,
StAktif: r.StAktif,
})
}
jsonData, _ := json.Marshal(data)
html := `
Admin Aplicares
`
c.Header("Content-Type", "text/html; charset=utf-8")
c.String(http.StatusOK, html)
}
func kelasOptions() string {
opts := `
`
return opts
}
// GetRuangan — GET /api/v1/admin/aplicares/ruangan (JSON)
func (h *AdminHandler) GetRuangan(c *gin.Context) {
ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second)
defer cancel()
ruangans, err := h.getRuangan(ctx)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
type Resp struct {
No int `json:"no"`
Nama string `json:"nama"`
JumlahTT int `json:"jumlah_tt"`
KodeKelas string `json:"kode_kelas"`
KodeAplicare string `json:"kode_aplicare"`
NamaRuang string `json:"nama_ruang"`
SudahMapping bool `json:"sudah_mapping"`
}
var data []Resp
belum := 0
for _, r := range ruangans {
sudah := r.KodeKelas.Valid && r.KodeKelas.String != "" &&
r.KodeAplicare.Valid && r.KodeAplicare.String != ""
if !sudah {
belum++
}
data = append(data, Resp{
No: r.No, Nama: r.Nama, JumlahTT: r.JumlahTT,
KodeKelas: r.KodeKelas.String, KodeAplicare: r.KodeAplicare.String,
NamaRuang: r.NamaRuang.String, SudahMapping: sudah,
})
}
c.JSON(http.StatusOK, gin.H{
"total": len(data), "belum_mapping": belum,
"sudah_mapping": len(data) - belum, "data": data,
})
}
// UpdateRuangan — PUT /api/v1/admin/aplicares/ruangan/:no
func (h *AdminHandler) UpdateRuangan(c *gin.Context) {
no, err := strconv.Atoi(c.Param("no"))
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "no tidak valid"})
return
}
var body struct {
KodeKelas string `json:"kode_kelas"`
KodeAplicare string `json:"kode_aplicare"`
NamaRuang string `json:"nama_ruang"`
JumlahTT int `json:"jumlah_tt"`
StAktif int `json:"st_aktif"`
}
if err := c.ShouldBindJSON(&body); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if body.KodeKelas == "" || body.KodeAplicare == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "kode_kelas dan kode_aplicare wajib diisi"})
return
}
db, err := h.db.GetDB("simrs")
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "koneksi DB gagal"})
return
}
ctx, cancel := context.WithTimeout(c.Request.Context(), 10*time.Second)
defer cancel()
result, err := db.ExecContext(ctx, `
UPDATE m_ruang SET kode_kelas=$1, kode_aplicare=$2, nama_ruang=$3, jumlah_tt=$4, st_aktif=$5 WHERE no=$6
`, body.KodeKelas, body.KodeAplicare, body.NamaRuang, body.JumlahTT, body.StAktif, no)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "update gagal: " + err.Error()})
return
}
rowsAffected, _ := result.RowsAffected()
if rowsAffected == 0 {
c.JSON(http.StatusOK, gin.H{"error": "tidak ada row yang terupdate, no=" + fmt.Sprintf("%d", no)})
return
}
c.JSON(http.StatusOK, gin.H{"message": "berhasil diupdate", "no": no, "rows_affected": rowsAffected})
}
// CreateRuangan — POST /api/v1/admin/aplicares/ruangan
func (h *AdminHandler) CreateRuangan(c *gin.Context) {
var body struct {
Nama string `json:"nama"`
JumlahTT int `json:"jumlah_tt"`
KodeKelas string `json:"kode_kelas"`
KodeAplicare string `json:"kode_aplicare"`
NamaRuang string `json:"nama_ruang"`
}
if err := c.ShouldBindJSON(&body); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if body.Nama == "" || body.KodeKelas == "" || body.KodeAplicare == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "nama, kode_kelas, kode_aplicare wajib diisi"})
return
}
db, err := h.db.GetDB("simrs")
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "koneksi DB gagal"})
return
}
ctx, cancel := context.WithTimeout(c.Request.Context(), 10*time.Second)
defer cancel()
// Auto generate no = MAX(no) + 1
var maxNo int
err = db.QueryRowContext(ctx, `SELECT COALESCE(MAX(no), 0) FROM m_ruang`).Scan(&maxNo)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "gagal generate no: " + err.Error()})
return
}
newNo := maxNo + 1
_, err = db.ExecContext(ctx, `
INSERT INTO m_ruang (no, nama, jumlah_tt, subsistem, st_aktif, kode_kelas, kode_aplicare, nama_ruang)
VALUES ($1, $2, $3, 'RAWAT INAP', 1, $4, $5, $6)
`, newNo, body.Nama, body.JumlahTT, body.KodeKelas, body.KodeAplicare, body.NamaRuang)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "insert gagal: " + err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"message": "ruangan berhasil ditambahkan", "no": newNo})
}