diff --git a/backend/controllers/bookingcontroller.go b/backend/controllers/bookingcontroller.go index 6b215fc..5490711 100644 --- a/backend/controllers/bookingcontroller.go +++ b/backend/controllers/bookingcontroller.go @@ -4,6 +4,7 @@ import ( "fmt" "net/http" "s-class-backend/config" + "s-class-backend/helpers" // Import helper pembuat kode acak "s-class-backend/models" "time" @@ -25,15 +26,13 @@ func CreateBooking(c *gin.Context) { return } - // --- PERBAIKAN DI SINI (Handle UUID) --- - // Ambil user_id dari context (hasil login) + // --- Handle UUID --- userIDInterface, exists := c.Get("user_id") if !exists { c.JSON(http.StatusUnauthorized, gin.H{"error": "User ID tidak ditemukan"}) return } - // Konversi interface{} ke string dulu, baru ke UUID userIDStr, ok := userIDInterface.(string) if !ok { c.JSON(http.StatusInternalServerError, gin.H{"error": "Format User ID token salah"}) @@ -45,7 +44,6 @@ func CreateBooking(c *gin.Context) { c.JSON(http.StatusInternalServerError, gin.H{"error": "Gagal memproses User ID"}) return } - // --------------------------------------- // Validasi Waktu if input.EndTime.Before(input.StartTime) { @@ -73,9 +71,8 @@ func CreateBooking(c *gin.Context) { Status: "Pending", } - // Tampilkan error asli database jika gagal if err := config.DB.Create(&booking).Error; err != nil { - fmt.Println("Error DB:", err) // Print error ke terminal + fmt.Println("Error DB:", err) c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } @@ -85,23 +82,19 @@ func CreateBooking(c *gin.Context) { "data": booking, }) } + func GetUserBookings(c *gin.Context) { var bookings []models.Booking - // 1. Ambil User ID dan Role dari token yang sedang login userID, _ := c.Get("user_id") role, _ := c.Get("role") - // 2. Cek apakah dia Admin if role == "admin" { - // Jika ADMIN: Ambil SEMUA data peminjaman dari semua user, urutkan dari yang terbaru - // Kita juga ambil data Room dan User agar detailnya lengkap if err := config.DB.Preload("Room").Preload("User").Order("created_at desc").Find(&bookings).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } } else { - // Jika MAHASISWA: Ambil HANYA data peminjaman miliknya sendiri if err := config.DB.Preload("Room").Where("user_id = ?", userID).Order("created_at desc").Find(&bookings).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return @@ -112,34 +105,42 @@ func GetUserBookings(c *gin.Context) { } type UpdateStatusInput struct { - Status string `json:"status" binding:"required"` // Isinya: 'Approved', 'Rejected', 'Completed', 'Cancelled' + Status string `json:"status" binding:"required"` } -// --- FUNGSI 3: UPDATE STATUS (ADMIN) --- +// --- FUNGSI UPDATE STATUS (ADMIN) --- func UpdateBookingStatus(c *gin.Context) { - // 1. Ambil ID Booking dari URL (misal: /bookings/123) bookingID := c.Param("id") - // 2. Cek apakah booking ada? var booking models.Booking if err := config.DB.First(&booking, "booking_id = ?", bookingID).Error; err != nil { c.JSON(http.StatusNotFound, gin.H{"error": "Booking tidak ditemukan"}) return } - // 3. Validasi Input JSON var input UpdateStatusInput if err := c.ShouldBindJSON(&input); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } - // 4. Update Status ke Database booking.Status = input.Status + + // 👇 LOGIKA PEMBUATAN REDEEM CODE 👇 + if input.Status == "Approved" { + // Buat kode dari helper jika sebelumnya belum punya kode + if booking.RedeemCode == "" { + booking.RedeemCode = helpers.GenerateRedeemCode() + } + } else if input.Status == "Rejected" || input.Status == "Cancelled" { + // Kosongkan kode jika peminjaman ditolak/dibatalkan + booking.RedeemCode = "" + } + config.DB.Save(&booking) c.JSON(http.StatusOK, gin.H{ "message": "Status booking berhasil diperbarui!", "data": booking, }) -} +} \ No newline at end of file diff --git a/backend/helpers/generator.go b/backend/helpers/generator.go new file mode 100644 index 0000000..f7184fd --- /dev/null +++ b/backend/helpers/generator.go @@ -0,0 +1,21 @@ +package helpers + +import ( + "math/rand" + "time" +) + +// GenerateRedeemCode membuat kode unik 6 karakter kombinasi Angka dan Huruf +func GenerateRedeemCode() string { + // Inisialisasi seed random berdasarkan waktu sekarang + rand.Seed(time.Now().UnixNano()) + + // Karakter yang diizinkan (Kombinasi Huruf Besar dan Angka) + charset := "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + + code := make([]byte, 6) // Panjang kode = 6 karakter + for i := range code { + code[i] = charset[rand.Intn(len(charset))] + } + return string(code) +} \ No newline at end of file diff --git a/backend/models/entity.go b/backend/models/entity.go index 667d688..fb767e0 100644 --- a/backend/models/entity.go +++ b/backend/models/entity.go @@ -30,17 +30,19 @@ type Room struct { type Booking struct { BookingID uuid.UUID `gorm:"type:uuid;default:uuid_generate_v4();primaryKey" json:"booking_id"` - // Tambahkan references:UserID - UserID uuid.UUID `gorm:"type:uuid;not null" json:"user_id"` - User User `gorm:"foreignKey:UserID;references:UserID" json:"user,omitempty"` + UserID uuid.UUID `gorm:"type:uuid;not null" json:"user_id"` + User User `gorm:"foreignKey:UserID;references:UserID" json:"user,omitempty"` - // Tambahkan references:RoomID - RoomID uint `gorm:"not null" json:"room_id"` - Room Room `gorm:"foreignKey:RoomID;references:RoomID" json:"room"` + RoomID uint `gorm:"not null" json:"room_id"` + Room Room `gorm:"foreignKey:RoomID;references:RoomID" json:"room"` StartTime time.Time `gorm:"not null" json:"start_time"` EndTime time.Time `gorm:"not null" json:"end_time"` Purpose string `gorm:"not null" json:"purpose"` Status string `gorm:"type:booking_status;default:'Pending'" json:"status"` + + // 👇 PASTIKAN BARIS INI ADA DI DALAM SINI 👇 + RedeemCode string `gorm:"type:varchar(10)" json:"redeem_code"` + CreatedAt time.Time `json:"created_at"` -} \ No newline at end of file +}