Spaces:
Runtime error
Runtime error
| 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) | |
| } | |