bookings.go 3.7 KB

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