bookings.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. package handlers
  2. import (
  3. "encoding/json"
  4. "net/http"
  5. "time"
  6. "github.com/go-chi/chi/v5"
  7. "github.com/photoplaces/backend/internal/middleware"
  8. "github.com/photoplaces/backend/internal/models"
  9. "github.com/photoplaces/backend/internal/repository"
  10. "github.com/photoplaces/backend/internal/validator"
  11. )
  12. type BookingHandler struct {
  13. bookingRepo *repository.BookingRepo
  14. placeRepo *repository.PlaceRepo
  15. }
  16. func NewBookingHandler(bookingRepo *repository.BookingRepo, placeRepo *repository.PlaceRepo) *BookingHandler {
  17. return &BookingHandler{bookingRepo: bookingRepo, placeRepo: placeRepo}
  18. }
  19. type createBookingRequest struct {
  20. PlaceID string `json:"place_id" validate:"required,uuid"`
  21. StartTime string `json:"start_time" validate:"required,datetime=2006-01-02T15:04:05Z07:00"`
  22. EndTime string `json:"end_time" validate:"required,datetime=2006-01-02T15:04:05Z07:00"`
  23. Comment *string `json:"comment" validate:"omitempty,max=1000"`
  24. }
  25. func (h *BookingHandler) Create(w http.ResponseWriter, r *http.Request) {
  26. userID := middleware.GetUserID(r.Context())
  27. var req createBookingRequest
  28. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  29. writeError(w, http.StatusBadRequest, "invalid request body")
  30. return
  31. }
  32. if err := validator.Validate(req); err != nil {
  33. writeValidationError(w, err)
  34. return
  35. }
  36. start, _ := time.Parse(time.RFC3339, req.StartTime)
  37. end, _ := time.Parse(time.RFC3339, req.EndTime)
  38. if !end.After(start) {
  39. writeError(w, http.StatusBadRequest, "end_time must be after start_time")
  40. return
  41. }
  42. available, err := h.bookingRepo.IsTimeSlotAvailable(r.Context(), req.PlaceID, start, end)
  43. if err != nil {
  44. writeError(w, http.StatusInternalServerError, err.Error())
  45. return
  46. }
  47. if !available {
  48. writeError(w, http.StatusConflict, "time slot is not available")
  49. return
  50. }
  51. totalPrice, err := h.bookingRepo.CalculateTotalPrice(r.Context(), req.PlaceID, start, end)
  52. if err != nil {
  53. writeError(w, http.StatusInternalServerError, err.Error())
  54. return
  55. }
  56. booking := &models.Booking{
  57. PlaceID: req.PlaceID,
  58. UserID: userID,
  59. StartTime: start,
  60. EndTime: end,
  61. TotalPrice: totalPrice,
  62. Currency: "RUB",
  63. Comment: strPtr(req.Comment),
  64. }
  65. if err := h.bookingRepo.Create(r.Context(), booking); err != nil {
  66. writeError(w, http.StatusInternalServerError, err.Error())
  67. return
  68. }
  69. writeJSON(w, http.StatusCreated, booking)
  70. }
  71. func (h *BookingHandler) ListMy(w http.ResponseWriter, r *http.Request) {
  72. userID := middleware.GetUserID(r.Context())
  73. bookings, err := h.bookingRepo.ListByUser(r.Context(), userID)
  74. if err != nil {
  75. writeError(w, http.StatusInternalServerError, err.Error())
  76. return
  77. }
  78. if bookings == nil {
  79. bookings = []*models.Booking{}
  80. }
  81. writeJSON(w, http.StatusOK, map[string]interface{}{"data": bookings})
  82. }
  83. func (h *BookingHandler) Cancel(w http.ResponseWriter, r *http.Request) {
  84. id := chi.URLParam(r, "id")
  85. userID := middleware.GetUserID(r.Context())
  86. booking, err := h.bookingRepo.GetByID(r.Context(), id)
  87. if err != nil {
  88. writeError(w, http.StatusInternalServerError, err.Error())
  89. return
  90. }
  91. if booking == nil {
  92. writeError(w, http.StatusNotFound, "booking not found")
  93. return
  94. }
  95. if booking.UserID != userID {
  96. writeError(w, http.StatusForbidden, "not your booking")
  97. return
  98. }
  99. if err := h.bookingRepo.UpdateStatus(r.Context(), id, "cancelled"); err != nil {
  100. writeError(w, http.StatusInternalServerError, err.Error())
  101. return
  102. }
  103. writeJSON(w, http.StatusOK, map[string]string{"status": "cancelled"})
  104. }
  105. func (h *BookingHandler) Confirm(w http.ResponseWriter, r *http.Request) {
  106. id := chi.URLParam(r, "id")
  107. if err := h.bookingRepo.UpdateStatus(r.Context(), id, "confirmed"); err != nil {
  108. writeError(w, http.StatusInternalServerError, err.Error())
  109. return
  110. }
  111. writeJSON(w, http.StatusOK, map[string]string{"status": "confirmed"})
  112. }