DanzApp-BE-Test / controllers /class_booking_controller.go
lifedebugger's picture
Deploy files from GitHub repository
a1d832a
package controllers
import (
"abdanhafidz.com/go-boilerplate/models/dto"
"abdanhafidz.com/go-boilerplate/services"
"github.com/gin-gonic/gin"
)
type ClassBookingController interface {
GetBookingOptions(ctx *gin.Context)
BookClass(ctx *gin.Context)
GetClassBookingDetail(ctx *gin.Context)
GetClassBookingsByFilter(ctx *gin.Context)
CreateClassBooking(ctx *gin.Context)
UpdateClassBooking(ctx *gin.Context)
DeleteClassBooking(ctx *gin.Context)
ReduceCapacity(ctx *gin.Context)
}
type classBookingController struct {
classService services.ClassService
}
func NewClassBookingController(classService services.ClassService) ClassBookingController {
return &classBookingController{
classService: classService,
}
}
// GetBookingOptions godoc
// @Summary Get Class Booking Options
// @Description Get available slots and class types for a specific class to be booked.
// @Tags Class Booking
// @Accept json
// @Produce json
// @Param classId path string true "Class ID"
// @Success 200 {object} dto.ClassBookingOptionsResponse
// @Failure 400 {object} dto.ErrorResponse
// @Failure 404 {object} dto.ErrorResponse
// @Security BearerAuth
// @Router /api/v1/bookings/classes/{classId}/options [get]
func (c *classBookingController) GetBookingOptions(ctx *gin.Context) {
classId := ctx.Param("classId")
res, err := c.classService.GetClassBookingOptions(ctx.Request.Context(), classId)
ResponseJSON(ctx, "", res, err)
}
// BookClass godoc
// @Summary Book a Class
// @Description Book a specific slot and type of a class. Returns Xendit checkout URL if payment is required.
// @Tags Class Booking
// @Accept json
// @Produce json
// @Param request body dto.BookClassRequest true "Class Booking Data"
// @Success 201 {object} dto.BookClassResponse
// @Failure 400 {object} dto.ErrorResponse
// @Failure 401 {object} dto.ErrorResponse
// @Security BearerAuth
// @Router /api/v1/bookings/classes [post]
func (c *classBookingController) BookClass(ctx *gin.Context) {
req, err := RequestJSON[dto.BookClassRequest](ctx)
if err != nil {
return
}
userId := ParseUserId(ctx)
if userId == "" {
return
}
res, err := c.classService.BookClass(ctx.Request.Context(), userId, req)
if err != nil {
ResponseJSON(ctx, req, res, err)
return
}
ctx.JSON(201, gin.H{
"success": true,
"message": "Class booked successfully",
"data": res,
})
}
// GetClassBookingDetail godoc
// @Summary Get Class Booking Detail
// @Description Get class booking details by booking ID
// @Tags Class Booking
// @Accept json
// @Produce json
// @Param booking_id query string true "Booking ID"
// @Success 200 {object} dto.CreateClassBookingResponse
// @Failure 400 {object} dto.ErrorResponse
// @Security BearerAuth
// @Router /api/v1/bookings/classes [get]
func (c *classBookingController) GetClassBookingDetail(ctx *gin.Context) {
bookingID := ctx.Query("booking_id")
if bookingID == "" {
ctx.JSON(400, gin.H{"error": "booking_id is required"})
return
}
res, err := c.classService.GetClassBookingDetail(ctx.Request.Context(), bookingID)
ResponseJSON(ctx, "", res, err)
}
// GetClassBookingsByFilter godoc
// @Summary Get Class Bookings By Filter
// @Description Get a list of class bookings filtered by user ID
// @Tags Class Booking
// @Accept json
// @Produce json
// @Param user_id query string true "User ID"
// @Success 200 {array} dto.CreateClassBookingResponse
// @Failure 400 {object} dto.ErrorResponse
// @Security BearerAuth
// @Router /api/v1/bookings/classes/filters [get]
func (c *classBookingController) GetClassBookingsByFilter(ctx *gin.Context) {
userID := ctx.Query("user_id")
if userID == "" {
ctx.JSON(400, gin.H{"error": "user_id is required"})
return
}
res, err := c.classService.GetClassBookingsByFilter(ctx.Request.Context(), userID)
ResponseJSON(ctx, "", res, err)
}
// CreateClassBooking godoc
// @Summary Create a new Class Booking (Direct)
// @Description Create a class booking with a specific payload (direct booking)
// @Tags Class Booking
// @Accept json
// @Produce json
// @Param request body dto.CreateClassBookingRequest true "Class Booking Data"
// @Success 201 {object} dto.CreateClassBookingResponse
// @Failure 400 {object} dto.ErrorResponse
// @Security BearerAuth
// @Router /api/v1/bookings/classes/create [post]
func (c *classBookingController) CreateClassBooking(ctx *gin.Context) {
req, err := RequestJSON[dto.CreateClassBookingRequest](ctx)
if err != nil {
return
}
userID := ParseUserId(ctx)
if userID == "" {
return
}
res, err := c.classService.CreateClassBooking(ctx.Request.Context(), userID, req)
if err != nil {
ResponseJSON(ctx, req, res, err)
return
}
ctx.JSON(201, res)
}
// UpdateClassBooking godoc
// @Summary Partially Update a Class Booking
// @Description Partially update a class booking. JSON fields (payment_details, available_slots, available_types) are deep-merged — only provided keys are overwritten.
// @Tags Class Booking
// @Accept json
// @Produce json
// @Param booking_id query string true "Booking ID"
// @Param request body dto.UpdateClassBookingRequest true "Fields to update"
// @Success 200 {object} dto.UpdateClassBookingResponse
// @Failure 400 {object} dto.ErrorResponse
// @Failure 404 {object} dto.ErrorResponse
// @Security BearerAuth
// @Router /api/v1/bookings/classes/update [put]
func (c *classBookingController) UpdateClassBooking(ctx *gin.Context) {
bookingID := ctx.Query("booking_id")
if bookingID == "" {
ctx.JSON(400, gin.H{"error": "booking_id is required"})
return
}
req, err := RequestJSON[dto.UpdateClassBookingRequest](ctx)
if err != nil {
return
}
res, err := c.classService.UpdateClassBooking(ctx.Request.Context(), bookingID, req)
if err != nil {
ResponseJSON(ctx, req, res, err)
return
}
ctx.JSON(200, res)
}
// DeleteClassBooking godoc
// @Summary Delete a Class Booking
// @Description Delete a class booking record by booking ID.
// @Tags Class Booking
// @Accept json
// @Produce json
// @Param booking_id query string true "Booking ID"
// @Success 200 {object} map[string]interface{}
// @Failure 400 {object} dto.ErrorResponse
// @Failure 404 {object} dto.ErrorResponse
// @Security BearerAuth
// @Router /api/v1/bookings/classes/delete [post]
func (c *classBookingController) DeleteClassBooking(ctx *gin.Context) {
bookingID := ctx.Query("booking_id")
if bookingID == "" {
ctx.JSON(400, gin.H{"error": "booking_id is required"})
return
}
err := c.classService.DeleteClassBooking(ctx.Request.Context(), bookingID)
if err != nil {
ctx.JSON(400, gin.H{"success": false, "message": err.Error()})
return
}
ctx.JSON(200, gin.H{"success": true, "message": "Booking deleted successfully"})
}
// ReduceCapacity godoc
// @Summary Reduce Capacity
// @Description Reduce available capacity of a specific ticket type in a slot for a class
// @Tags Class Booking
// @Accept json
// @Produce json
// @Param request body dto.ReduceCapacityRequest true "Reduce Capacity Data"
// @Success 200 {object} dto.ClassBookingOptionsResponse
// @Failure 400 {object} dto.ErrorResponse
// @Failure 500 {object} dto.ErrorResponse
// @Security BearerAuth
// @Router /api/v1/bookings/classes/reduce-capacity [post]
func (c *classBookingController) ReduceCapacity(ctx *gin.Context) {
req, err := RequestJSON[dto.ReduceCapacityRequest](ctx)
if err != nil {
return
}
res, err := c.classService.ReduceCapacity(ctx.Request.Context(), req)
if err != nil {
ctx.JSON(500, gin.H{"success": false, "message": err.Error()})
return
}
ctx.JSON(200, res)
}