Files
careit/backendcareit_v4/handlers/routes.go
2026-01-27 15:48:29 +07:00

884 lines
21 KiB
Go

package handlers
import (
"encoding/json"
"errors"
"log"
"net/http"
"strconv"
"strings"
"backendcareit/database"
"backendcareit/middleware"
"backendcareit/models"
"backendcareit/services"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
func RegisterRoutes(r *gin.Engine) {
// Routes get dokter
r.GET("/dokter", listDokterHandler)
// Routes get ruangan
r.GET("/ruangan", listRuanganHandler)
// Routes get icd9 icd10
r.GET("/icd10", listICD10Handler)
r.GET("/icd9", listICD9Handler)
// Health check
r.GET("/", healthHandler)
// Routes tarif
r.GET("/tarifBPJSRawatInap", listTarifBPJSRawatInapHandler)
r.GET("/tarifBPJS/:kode", detailTarifBPJSRawatInapHandler)
r.GET("/tarifBPJSRawatJalan", listTarifBPJSRawatJalanHandler)
r.GET("/tarifBPJSRawatJalan/:kode", detailTarifBPJSRawatJalanHandler)
r.GET("/tarifRS", listTarifRSHandler)
r.GET("/tarifRS/:kode", detailTarifRSHandler)
r.GET("/tarifRSByKategori/:kategori", listTarifRSByKategoriHandler)
// Routes pasien & billing
r.GET("/pasien/search", SearchPasienHandler)
r.GET("/pasien/:id", GetPasien)
r.POST("/billing", CreateBillingHandler)
r.GET("/billing/aktif", GetBillingAktifByNamaHandler)
r.PUT("/billing/:id", UpdateBillingHandler)
//close billing
r.POST("/billing/close", CloseBillingHandler)
//get all billing aktif
r.GET("/billing/aktif/all", GetAllBillingaktifhandler)
//admin edit inacbg
r.PUT("/admin/inacbg", EditINACBGAdminHandler)
// Admin: get all billing
r.GET("/admin/billing", GetAllBillingHandler)
// Admin: get riwayat billing (sudah ditutup)
r.GET("/admin/riwayat-billing", GetRiwayatBillingHandler)
// Admin: get riwayat billing with all patient data
r.GET("/admin/riwayat-pasien-all", GetRiwayatPasienAllHandler)
// Admin: get billing by ID
r.GET("/admin/billing/:id", GetBillingByIDHandler)
// Admin: post INACBG
r.POST("/admin/inacbg", PostINACBGAdminHandler)
// Admin: get ruangan dengan pasien
r.GET("/admin/ruangan-dengan-pasien", GetRuanganWithPasienHandler)
// Login dokter
r.POST("/login", LoginDokterHandler(database.DB))
// login admin
r.POST("/admin/login", LoginAdminHandler(database.DB))
}
// Coba tes koneksi dulu ya
func healthHandler(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"status": "ok",
"message": "Server berjalan",
})
}
//Handler buat /admin/billing
func GetAllBillingHandler(c *gin.Context) {
data, err := services.GetAllBilling(database.DB)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"status": "error",
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"status": "success",
"data": data,
})
}
// Handler buat /admin/billing/:id
func GetBillingByIDHandler(c *gin.Context) {
id := c.Param("id")
data, err := services.GetBillingByID(database.DB, id)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"status": "error",
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"status": "success",
"data": data,
})
}
// edit inacbg admin
func EditINACBGAdminHandler(c *gin.Context) {
var input models.Edit_INACBG_Request
// Ensure JSON
if c.GetHeader("Content-Type") != "application/json" {
c.JSON(http.StatusBadRequest, gin.H{
"status": "error",
"message": "Content-Type harus application/json",
})
return
}
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"status": "error",
"message": "Data tidak valid",
"error": err.Error(),
})
return
}
if err := services.Edit_INACBG_Admin(database.DB, input); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"status": "error",
"message": "Gagal mengedit INACBG",
"error": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"status": "success",
"message": "INACBG berhasil diupdate",
})
}
// Post INACBG from admin
func PostINACBGAdminHandler(c *gin.Context) {
var input models.Post_INACBG_Admin
// Ensure JSON
if c.GetHeader("Content-Type") != "application/json" {
c.JSON(http.StatusBadRequest, gin.H{
"status": "error",
"message": "Content-Type harus application/json",
})
return
}
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"status": "error",
"message": "Data tidak valid",
"error": err.Error(),
})
return
}
if err := services.Post_INACBG_Admin(database.DB, input); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"status": "error",
"message": "Gagal memproses INACBG",
"error": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"status": "success",
"message": "INACBG berhasil disimpan",
})
}
// List tarif BPJS Rawat Inap
func listTarifBPJSRawatInapHandler(c *gin.Context) {
data, err := services.GetTarifBPJSRawatInap()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"status": "error",
"message": "Gagal mengambil data",
})
return
}
c.JSON(http.StatusOK, data)
}
func detailTarifBPJSRawatInapHandler(c *gin.Context) {
kode := c.Param("kode")
data, err := services.GetTarifBPJSRawatInapByKode(kode)
if err != nil {
if services.IsNotFound(err) {
c.JSON(http.StatusNotFound, gin.H{
"status": "not_found",
"message": "Kode tidak ditemukan",
})
return
}
c.JSON(http.StatusInternalServerError, gin.H{
"status": "error",
"message": "Gagal mengambil data",
})
return
}
c.JSON(http.StatusOK, data)
}
// List tarif BPJS Rawat Jalan
func listTarifBPJSRawatJalanHandler(c *gin.Context) {
data, err := services.GetTarifBPJSRawatJalan()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"status": "error",
"message": "Gagal mengambil data",
})
return
}
c.JSON(http.StatusOK, data)
}
func detailTarifBPJSRawatJalanHandler(c *gin.Context) {
kode := c.Param("kode")
data, err := services.GetTarifBPJSRawatJalanByKode(kode)
if err != nil {
if services.IsNotFound(err) {
c.JSON(http.StatusNotFound, gin.H{
"status": "not_found",
"message": "Kode tidak ditemukan",
})
return
}
c.JSON(http.StatusInternalServerError, gin.H{
"status": "error",
"message": "Gagal mengambil data",
})
return
}
c.JSON(http.StatusOK, data)
}
// List tarif RS
func listTarifRSHandler(c *gin.Context) {
data, err := services.GetTarifRS()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"status": "error",
"message": "Gagal mengambil data",
})
return
}
c.JSON(http.StatusOK, data)
}
func detailTarifRSHandler(c *gin.Context) {
kode := c.Param("kode")
data, err := services.GetTarifRSByKode(kode)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"status": "error",
"message": "Gagal mengambil data",
})
return
}
c.JSON(http.StatusOK, data)
}
func listTarifRSByKategoriHandler(c *gin.Context) {
kategori := c.Param("kategori")
data, err := services.GetTarifRSByKategori(kategori)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"status": "error",
"message": "Gagal mengambil data",
})
return
}
c.JSON(http.StatusOK, data)
}
// ICD9
func listICD9Handler(c *gin.Context) {
data, err := services.GetICD9()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"status": "error",
"message": "Gagal mengambil data",
})
return
}
c.JSON(http.StatusOK, data)
}
// ICD10
func listICD10Handler(c *gin.Context) {
data, err := services.GetICD10()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"status": "error",
"message": "Gagal mengambil data",
})
return
}
c.JSON(http.StatusOK, data)
}
// ruangan
func listRuanganHandler(c *gin.Context) {
data, err := services.GetRuangan()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"status": "error",
"message": "Gagal mengambil data",
})
return
}
c.JSON(http.StatusOK, data)
}
// GetRuanganWithPasienHandler - Ambil ruangan yang punya pasien
func GetRuanganWithPasienHandler(c *gin.Context) {
data, err := services.GetRuanganWithPasien(database.DB)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"status": "error",
"message": "Gagal mengambil data",
})
return
}
c.JSON(http.StatusOK, data)
}
// dokter
func listDokterHandler(c *gin.Context) {
data, err := services.GetDokter()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"status": "error",
"message": "Gagal mengambil data",
})
return
}
c.JSON(http.StatusOK, data)
}
//Liat pasien sudah atau belum
func GetPasien(c *gin.Context) {
idStr := c.Param("id")
// Konversi string ke int
id, err := strconv.Atoi(idStr)
if err != nil {
c.JSON(400, gin.H{
"message": "ID pasien harus berupa angka",
})
return
}
pasien, err := services.GetPasienByID(id)
if err != nil {
c.JSON(404, gin.H{
"message": "Pasien tidak ditemukan",
})
return
}
c.JSON(200, gin.H{
"message": "Data pasien ditemukan",
"data": pasien,
})
}
//add pasien baru
// CreateBillingHandler handler untuk membuat billing baru dari data frontend
func CreateBillingHandler(c *gin.Context) {
// Pastikan JSON
contentType := c.GetHeader("Content-Type")
if contentType != "application/json" {
c.JSON(http.StatusBadRequest, gin.H{
"status": "error",
"message": "Content-Type harus application/json",
"error": "Content-Type yang diterima: " + contentType,
})
return
}
// Gunakan map untuk menerima JSON fleksibel (bisa string atau array untuk nama_dokter)
var rawData map[string]interface{}
if err := c.ShouldBindJSON(&rawData); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"status": "error",
"message": "Data tidak valid",
"error": err.Error(),
})
return
}
// Konversi nama_dokter dari string ke array jika perlu
if namaDokterRaw, ok := rawData["nama_dokter"]; ok {
switch v := namaDokterRaw.(type) {
case string:
// Jika string, konversi ke array dengan 1 elemen
if v != "" {
rawData["nama_dokter"] = []string{v}
} else {
rawData["nama_dokter"] = []string{}
}
case []interface{}:
// Jika sudah array, konversi ke []string
namaDokterArray := make([]string, 0, len(v))
for _, item := range v {
if str, ok := item.(string); ok && str != "" {
namaDokterArray = append(namaDokterArray, str)
}
}
rawData["nama_dokter"] = namaDokterArray
case []string:
// Sudah dalam format yang benar
rawData["nama_dokter"] = v
default:
rawData["nama_dokter"] = []string{}
}
}
// Konversi map ke BillingRequest
var input models.BillingRequest
// Marshal dan unmarshal untuk konversi yang aman
jsonData, err := json.Marshal(rawData)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"status": "error",
"message": "Gagal memproses data",
"error": err.Error(),
})
return
}
if err := json.Unmarshal(jsonData, &input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"status": "error",
"message": "Data tidak valid",
"error": err.Error(),
})
return
}
// Panggil service → return 5 data
billing, pasien, tindakanList, icd9List, icd10List, err :=
services.DataFromFE(input)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"status": "error",
"message": "Gagal membuat billing",
"error": err.Error(),
})
return
}
// Response lengkap ke FE
c.JSON(http.StatusOK, gin.H{
"status": "success",
"message": "Billing berhasil dibuat",
"data": gin.H{
"pasien": pasien,
"billing": billing,
"tindakan_rs": tindakanList,
"icd9": icd9List,
"icd10": icd10List,
},
})
}
// GetBillingAktifByNamaHandler - Ambil billing aktif berdasarkan nama
// Endpoint: GET /billing/aktif?nama_pasien=...
// Mengembalikan billing aktif + semua tindakan & ICD & dokter & INACBG & DPJP
func GetBillingAktifByNamaHandler(c *gin.Context) {
nama := c.Query("nama_pasien")
if strings.TrimSpace(nama) == "" {
c.JSON(http.StatusBadRequest, gin.H{
"status": "error",
"message": "nama_pasien wajib diisi",
})
return
}
billing, tindakan, icd9, icd10, dokter, inacbgRI, inacbgRJ, dpjp, err := services.GetBillingDetailAktifByNama(nama)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
c.JSON(http.StatusNotFound, gin.H{
"status": "not_found",
"message": "Billing aktif untuk pasien tersebut tidak ditemukan",
})
return
}
c.JSON(http.StatusInternalServerError, gin.H{
"status": "error",
"message": "Gagal mengambil data billing",
"error": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"status": "success",
"message": "Billing aktif ditemukan",
"data": gin.H{
"billing": billing,
"tindakan_rs": tindakan,
"icd9": icd9,
"icd10": icd10,
"dokter": dokter,
"inacbg_ri": inacbgRI,
"inacbg_rj": inacbgRJ,
"id_dpjp": dpjp,
},
})
}
//search pasien by nama handler
func SearchPasienHandler(c *gin.Context) {
nama := c.Query("nama")
pasien, err := services.SearchPasienByNama(nama)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"status": "error",
"message": "Gagal mengambil data pasien",
})
return
}
c.JSON(http.StatusOK, gin.H{
"status": "success",
"data": pasien,
})
}
// Login dokter
func LoginDokterHandler(db *gorm.DB) gin.HandlerFunc {
return func(c *gin.Context) {
var req models.LoginRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"status": "error",
"message": "Payload login tidak valid",
"error": err.Error(),
})
return
}
email := strings.TrimSpace(strings.ToLower(req.Email))
var dokter models.Dokter
if err := db.Where("LOWER(\"Email_UB\") = ? OR LOWER(\"Email_Pribadi\") = ?", email, email).
First(&dokter).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
c.JSON(http.StatusUnauthorized, gin.H{
"status": "error",
"message": "Email atau password salah",
})
return
}
c.JSON(http.StatusInternalServerError, gin.H{
"status": "error",
"message": "Gagal memproses login",
"error": err.Error(),
})
return
}
// Password check — skip if password column is empty
if dokter.Password != "" && dokter.Password != req.Password {
c.JSON(http.StatusUnauthorized, gin.H{
"status": "error",
"message": "Email atau password salah",
})
return
}
token, err := middleware.GenerateToken(dokter, email)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"status": "error",
"message": "Gagal membuat token",
"error": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"status": "success",
"token": token,
"dokter": gin.H{
"id": dokter.ID_Dokter,
"nama": dokter.Nama_Dokter,
"ksm": dokter.KSM,
"email": email,
},
})
}
}
// SendEmailTestHandler handler untuk test email
func SendEmailTestHandler(c *gin.Context) {
if err := services.SendEmailTest(); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"status": "error",
"message": "Gagal mengirim email test",
"error": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"status": "success",
"message": "Email test berhasil dikirim ke stylohype685@gmail.com dan pasaribumonica2@gmail.com",
})
}
// SendEmailCustomHandler - kirim email tes ke daftar penerima yang diberikan
func SendEmailCustomHandler(c *gin.Context) {
var req struct {
To []string `json:"to" binding:"required,min=1"`
Subject string `json:"subject"`
Body string `json:"body"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"status": "error", "message": "Request harus JSON dengan field 'to' sebagai array email"})
return
}
subject := req.Subject
if strings.TrimSpace(subject) == "" {
subject = "Test Email - Sistem Billing Care IT"
}
body := req.Body
if strings.TrimSpace(body) == "" {
body = "<p>Ini adalah email test dari sistem billing Care IT.</p>"
}
if err := services.SendEmailToMultiple(req.To, subject, body); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"status": "error", "message": "Gagal mengirim email", "error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"status": "success", "message": "Email test berhasil dikirim"})
}
func LoginAdminHandler(db *gorm.DB) gin.HandlerFunc {
return func(c *gin.Context) {
var req struct {
Nama_Admin string `json:"Nama_Admin" binding:"required"`
Password string `json:"Password" binding:"required"`
}
// Bind & validate
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": "Nama_Admin dan Password harus diisi",
})
return
}
// Trim dan normalize input
namaAdmin := strings.TrimSpace(req.Nama_Admin)
if namaAdmin == "" {
c.JSON(http.StatusBadRequest, gin.H{
"error": "Nama_Admin tidak boleh kosong",
})
return
}
// Query admin_ruangan dengan case-insensitive
var admin models.Admin_Ruangan //Admin_Ruangan
if err := db.Where("LOWER(\"Nama_Admin\") = ?", strings.ToLower(namaAdmin)).First(&admin).Error; err != nil {
c.JSON(http.StatusUnauthorized, gin.H{
"error": "Admin tidak ditemukan",
})
return
}
// Check password
if admin.Password != req.Password {
c.JSON(http.StatusUnauthorized, gin.H{
"error": "Password salah",
})
return
}
// Generate token & return
token, err := middleware.GenerateTokenAdmin(admin, req.Nama_Admin)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"error": "Gagal membuat token",
})
return
}
c.JSON(http.StatusOK, gin.H{
"status": "success",
"token": token,
"admin": gin.H{
"id": admin.ID_Admin,
"nama_admin": admin.Nama_Admin,
"id_ruangan": admin.ID_Ruangan,
},
})
}
}
// UpdateBillingHandler - update identitas pasien dalam billing
func UpdateBillingHandler(c *gin.Context) {
idStr := c.Param("id")
billingId, err := strconv.Atoi(idStr)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"status": "error",
"message": "ID billing tidak valid",
"error": err.Error(),
})
return
}
// Parse request body
var updateReq struct {
Nama_Pasien string `json:"nama_pasien"`
Usia int `json:"usia"`
Jenis_Kelamin string `json:"jenis_kelamin"`
Ruangan string `json:"ruangan"`
Kelas string `json:"kelas"`
Tindakan_Rs []string `json:"tindakan_rs"`
ICD9 []string `json:"icd9"`
ICD10 []string `json:"icd10"`
Billing_sign *string `json:"billing_sign"` // Optional: jika dikirimkan akan diupdate
Total_Tarif_RS *float64 `json:"total_tarif_rs"` // Optional: jika dikirimkan akan diupdate
}
if err := c.ShouldBindJSON(&updateReq); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"status": "error",
"message": "Data tidak valid",
"error": err.Error(),
})
return
}
// Panggil service untuk update dengan lookup kode
if err := services.EditPasienComplete(billingId, updateReq.Nama_Pasien, updateReq.Usia, updateReq.Jenis_Kelamin, updateReq.Ruangan, updateReq.Kelas, updateReq.Tindakan_Rs, updateReq.ICD9, updateReq.ICD10, updateReq.Billing_sign, updateReq.Total_Tarif_RS); err != nil {
log.Printf("[EDIT_HANDLER] ERROR - Service returned error: %v\n", err)
c.JSON(http.StatusInternalServerError, gin.H{
"status": "error",
"message": "Gagal update data billing",
"error": err.Error(),
"details": err.Error(), // Add details untuk debugging
})
return
}
c.JSON(http.StatusOK, gin.H{
"status": "success",
"message": "Data billing berhasil diupdate",
})
}
// CloseBillingHandler - handler untuk menutup billing
func CloseBillingHandler(c *gin.Context) {
var closeReq models.Close_billing
// Pastikan JSON
if c.GetHeader("Content-Type") != "application/json" {
c.JSON(http.StatusBadRequest, gin.H{
"status": "error",
"message": "Content-Type harus application/json",
})
return
}
if err := c.ShouldBindJSON(&closeReq); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"status": "error",
"message": "Data tidak valid",
"error": err.Error(),
})
return
}
if err := services.CloseBilling(closeReq); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"status": "error",
"message": "Gagal menutup billing",
"error": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"status": "success",
"message": "Billing berhasil ditutup",
})
}
// GetRiwayatBillingHandler - Handler buat ngambil riwayat billing yang udah ditutup
func GetRiwayatBillingHandler(c *gin.Context) {
data, err := services.GetAllRiwayatpasien(database.DB)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"status": "error",
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"status": "success",
"data": data,
})
}
func GetAllBillingaktifhandler(c *gin.Context) {
data, err := services.GetAllBillingaktif(database.DB)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"status": "error",
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"status": "success",
"data": data,
})
}
// GetRiwayatPasienAllHandler - Handler buat ngambil riwayat pasien lengkap
func GetRiwayatPasienAllHandler(c *gin.Context) {
data, err := services.GetRiwayatPasienAll(database.DB)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"status": "error",
"message": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"status": "success",
"data": data,
})
}