public GenericObjectResponse <ReservationRequestResponse> RequestReservation(long roomId, [FromBody] ReservationRequestPayload payload) { long?userId = AuthenticationService.IsAuthorized(Request, UserRole.RoomOwner, UserRole.Coach); if (userId == null) { Response.StatusCode = 401; return(new GenericObjectResponse <ReservationRequestResponse>("")); } ReservationRequestPayload trimmedPayload = new ReservationRequestPayload() { Description = payload.Description, RentStart = payload.RentStart.TrimDate(DateTimePrecision.Minute).ToLocalDate(), RentEnd = payload.RentEnd.TrimDate(DateTimePrecision.Minute).ToLocalDate() }; ReservationValidationService reservationValidationService = new ReservationValidationService(); GenericStatusMessage roomAvailabilityValidation = reservationValidationService.ValidateRoomAvailability(roomId, trimmedPayload); if (!roomAvailabilityValidation.Success) { Response.StatusCode = 400; return(new GenericObjectResponse <ReservationRequestResponse>(roomAvailabilityValidation.Message)); } ReservationManipulationService reservationManipulationService = new ReservationManipulationService(); return(reservationManipulationService.AddReservation(roomId, userId.Value, trimmedPayload)); }
public WorkingHours GetMatchingWorkingHours(ReservationRequestPayload payload, Room room) { int reservationStartTime = payload.RentStart.ToMinutes(); int resevationEndTime = payload.RentEnd.ToMinutes(); Days reservationDay = payload.RentStart.ToDaysEnum(); return(room.WorkingHours.FirstOrDefault(x => x.Day == reservationDay && x.TimeStart <= reservationStartTime && x.TimeEnd >= resevationEndTime)); }
public GenericStatusMessage ValidateRoomAvailability(long roomId, ReservationRequestPayload payload) { using (ReservationDataContext context = new ReservationDataContext()) { Room room = context.Rooms.Include(x => x.WorkingHours).SingleOrDefault(x => x.Id == roomId && x.IsActive); return(ValidateRoomAvailability(context, room, payload)); } }
public GenericListResponse <AvailableReservationTime> GetRoomAvailableTimes(long roomId, DateTime?startDate, int duration, int take) { using (ReservationDataContext context = new ReservationDataContext()) { if (duration <= 0) { return(new GenericListResponse <AvailableReservationTime>("Invalid duration.")); } var roomQuery = context.Rooms.Include(x => x.WorkingHours).Include(x => x.Reservations); var room = roomQuery.SingleOrDefault(x => x.Id == roomId); if (room == null) { return(new GenericListResponse <AvailableReservationTime>("Room not found.")); } List <AvailableReservationTime> availableTimes = new List <AvailableReservationTime>(); DateTime now = DateTime.Now; DateTime currentDateTemp = (startDate != null && startDate > now ? startDate.Value.ToLocalDate() : now); DateTime currentDate = currentDateTemp.Date; int limit = 1440 - duration; ReservationValidationService reservationValidationService = new ReservationValidationService(); while (availableTimes.Count < take) { for (int i = 0; i < limit && availableTimes.Count < take; i += 30) { DateTime rentStart = currentDate + TimeSpan.FromMinutes(i); if (rentStart < now) { continue; } ReservationRequestPayload payload = new ReservationRequestPayload { RentStart = rentStart, RentEnd = rentStart + TimeSpan.FromMinutes(duration) }; GenericStatusMessage availability = reservationValidationService.ValidateRoomAvailability(context, room, payload); if (availability.Success) { var matchedWorkingHours = reservationValidationService.GetMatchingWorkingHours(payload, room); availableTimes.Add(new AvailableReservationTime { RentStart = rentStart, Price = PriceHelper.CalculatePrice(matchedWorkingHours.PriceForHour, rentStart, payload.RentEnd) }); } } currentDate += TimeSpan.FromDays(1); } return(new GenericListResponse <AvailableReservationTime>(availableTimes, availableTimes.Count)); } }
private GenericStatusMessage ValidateRoomAvailability(ReservationDataContext context, ReservationRequest request) { Room room = context.Rooms.Include(x => x.WorkingHours).SingleOrDefault(x => x.Id == request.RoomId); ReservationRequestPayload payload = new ReservationRequestPayload { RentStart = request.RentStart, RentEnd = request.RentEnd, Description = request.Description }; return(ValidateRoomAvailability(context, room, payload)); }
public GenericObjectResponse <ReservationRequestResponse> AddReservation(long roomId, long requesterId, ReservationRequestPayload payload) { ReservationValidationService reservationValidationService = new ReservationValidationService(); using (ReservationDataContext context = new ReservationDataContext()) { Room room = context.Rooms.Include(x => x.WorkingHours).Single(x => x.Id == roomId); WorkingHours matchedWorkingHours = reservationValidationService.GetMatchingWorkingHours(payload, room); ReservationRequest reservationRequest = new ReservationRequest() { RentStart = payload.RentStart, RentEnd = payload.RentEnd, Status = ReservationStatus.Pending, Description = payload.Description, FinalPrice = PriceHelper.CalculatePrice(matchedWorkingHours.PriceForHour, payload.RentStart, payload.RentEnd), RoomId = roomId, UserId = requesterId }; context.ReservationRequests.Add(reservationRequest); context.SaveChanges(); return(new GenericObjectResponse <ReservationRequestResponse>(ConvertToResponse(reservationRequest))); } }
public GenericStatusMessage ValidateRoomAvailability(ReservationDataContext context, Room room, ReservationRequestPayload payload) { if (room == null) { return(new GenericStatusMessage(false, "Room not found or is not currently active.")); } if (payload.RentStart.Date != payload.RentEnd.Date) { return(new GenericStatusMessage(false, "Rent start and rent end should be on the same day.")); } if (payload.RentStart >= payload.RentEnd) { return(new GenericStatusMessage(false, "Rent start can't be after rent end.")); } if (GetMatchingWorkingHours(payload, room) == null) { return(new GenericStatusMessage(false, "Reservation is not in the rooms working hours.")); } var todaysReservations = context.ReservationRequests.Where(x => x.RoomId == room.Id && x.Status == ReservationStatus.Approved && DbFunctions.TruncateTime(x.RentStart) == DbFunctions.TruncateTime(payload.RentStart)).ToList(); bool collision = todaysReservations.Any(x => { bool startValidation = payload.RentStart > x.RentStart && payload.RentStart < x.RentEnd; bool endValidation = payload.RentEnd > x.RentStart && payload.RentEnd < x.RentEnd; bool sameTimeValidation = payload.RentStart == x.RentStart && payload.RentEnd == x.RentEnd; return(startValidation || endValidation || sameTimeValidation); }); if (collision) { return(new GenericStatusMessage(false, "Reservation collides with an already approved reservation.")); } return(new GenericStatusMessage(true)); }