diff --git a/.gitignore b/.gitignore index 5e1422c9c..c0ac3dc53 100644 --- a/.gitignore +++ b/.gitignore @@ -48,3 +48,4 @@ build-iPhoneSimulator/ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: .rvmrc +coverage diff --git a/lib/date_range.rb b/lib/date_range.rb new file mode 100644 index 000000000..bd1e176ad --- /dev/null +++ b/lib/date_range.rb @@ -0,0 +1,44 @@ +require "date" + +# - I can view a list of rooms that are not reserved for a given date range, so that I can see all available rooms for that day +# - I can make a reservation of a room for a given date range, and that room will not be part of any other reservation overlapping that date range +# - I want an exception raised if I try to reserve a room during a date range when all rooms are reserved, so that I cannot make two reservations for the same room that overlap by date + +class Date_Range + attr_reader :check_in_date, :check_out_date + + # this is were we will handle the date, taking in the check in date and out date + # if the check out date is more higher that checking in date the date is invalide + # Example 2001,2 3 > 2001 2,4 + def initialize(check_in_date, check_out_date) + unless check_out_date > check_in_date + raise ArgumentError, "These dates are invalid." + end + @check_in_date = check_in_date + @check_out_date = check_out_date + end + + # every time Date_Range is called it takes in check in and out dates as parms + # setting check_in and check_out allows me to compare two date ranges for overlap + # if there is no overlap then return false + # Example 2001,2 3 2001 2,4 + def overlaps_in_reservations?(new_date_range) + if (new_date_range.check_in_date >= @check_out_date) || (new_date_range.check_out_date <= @check_in_date) + return false + else + return true + end + end + + def number_of_nights? + return @check_out_date - @check_in_date + end +end + +# def contains(date) +# if date >= @check_in_date && date < @check_out_date +# return true +# else +# return false +# end +# end diff --git a/lib/hotel_block.rb b/lib/hotel_block.rb new file mode 100644 index 000000000..2f834945a --- /dev/null +++ b/lib/hotel_block.rb @@ -0,0 +1,23 @@ +class Hotel_Block < Date_Range + attr_accessor :room_info, :check_in_date, :check_out_date, :room_rate + + def initialize(room_ids, check_in_date, check_out_date, room_rate, hotel_block_id) + # room_info maps a room_id to whether it has been occupied or not. So to begin with, all rooms in a hotel block are not occupied. They are set to a value of false, indicating that they are not occupied. + @room_info = + h = Hash[*room_ids.collect { |room_ids| [room_ids, (false)] }.flatten] + @check_in_date = check_in_date + @check_out_date = check_out_date + @room_rate = room_rate + @hotel_block_id = hotel_block_id + end + + def check_rooms_available + @room_info.each do |room_id, occupied| + # If a room has occupied set to false, we know it is available. + if occupied == false + return true + end + end + return false + end +end diff --git a/lib/hotel_dispatcher.rb b/lib/hotel_dispatcher.rb new file mode 100644 index 000000000..363b0a8a6 --- /dev/null +++ b/lib/hotel_dispatcher.rb @@ -0,0 +1,102 @@ +require "date" +require "pry" +require_relative "date_range" +require_relative "reservation" +require_relative "room" +require_relative "hotel_block" + +class HotelManager < Date_Range + attr_reader :rooms + attr_accessor :reservations + + def initialize + @rooms = make_rooms + @hotel_blocks = [] + @hotel_block_counter = 0 + end + + # - The hotel has 20 rooms, and they are numbered 1 through 20 + # - In this method we make a rooms spanning 1 - 20 + # - Each room is placed in an array which because an room array + def make_rooms + room_array = [] + (1..20).each do |room_num| + room_array << Room.new(room_num) + end + return room_array + end + + # Here we check the room availability by taking in the check in and out date as parms + # Those parms are then used to create a new Instantation of a date range + # By setting that new instantion of a date range as a variable we can then + # Go into each room and check that said date range + def check_room_available?(check_in_date, check_out_date) + date_range = Date_Range.new(check_in_date, check_out_date) + @rooms.each do |room| + # If no res has any overlap return true # + if room.check_overlap_with_room_reservations(date_range) + return true + end + end + # However if there is return false because there is a overlap. No room available whatsoever# + return false + end + + def find_all_resevations + all_res = [] + @rooms.each do |room| + room.reservations.each do |res| + all_res << res + end + end + all_res << @hotel_blocks + return all_res + end + + def create_reservation(check_in_date, check_out_date) + # Need to determine if which room to use for the reservation. + + # Iterate over list of rooms. + # Find room that has availability. + # First room that has no time conflict is the room, we choose to use for the reservation. + # If no rooms have availability during the checkin_date to checkout_date, we should return an error/ raise an error. + + date_range = Date_Range.new(check_in_date, check_out_date) + @rooms.each do |room| + # If no res has any overlap return true # + if room.check_overlap_with_room_reservations(date_range) + room.create_new_reservation(check_in_date, check_out_date) + return true + end + end + # # Raise exception as no room is available during the requested date_range. + raise Exception.new "There are no rooms available for this date range" + end + + # This method is used to create a Hotel Block + # Takes in Room Ids and check in and check out date + # inside the method we create a method we create a variable called new requested_date_range which uses the Date_Range class + # room_ids is the number of rooms + # need to raise error if more than 5 rooms + # using the make rooms we + def create_room_block(room_ids, check_in_date, check_out_date, room_rate) + requested_date_range = Date_Range.new(check_in_date, check_out_date) + room_ids.each do |room_id| + room = @rooms[room_id] + if !room.check_overlap_with_room_reservations(requested_date_range) + raise Exception.new "One of the rooms in the hotel block requested is unavailable" + end + end + + # Go to each room and add the reservation for the given date range + # room_ids.each do |room_id| + # room = @rooms[room_id] + # room.create_new_reservation(check_in_date, check_out_date, true) + # end + + + # Create the HotelBlock object and add it to the list of hotel_blocks + @hotel_blocks << Hotel_Block.new(room_ids, check_in_date, check_out_date, room_rate, @hotel_block_counter) + @hotel_block_counter += 1 + end +end diff --git a/lib/reservation.rb b/lib/reservation.rb new file mode 100644 index 000000000..2a9760b99 --- /dev/null +++ b/lib/reservation.rb @@ -0,0 +1,31 @@ +require_relative "date_range" + +class Reservation < Date_Range + attr_accessor :room_num, :check_in_date, :check_out_date + + def initialize(room_num, check_in_date, check_out_date, hotel_block_reservation = false) + @room = room_num + @check_in_date = check_in_date + @check_out_date = check_out_date + @hotel_block_reservation = hotel_block_reservation + end + + #each time the employee creates a reservation it is created here + + # Every room is identical, and a room always costs $200/night + def total_cost_for_stay + number_of_nights? * 200 + end +end + +# take in the Room class add_res method, converts date range into number of nights, each night * $200 less the one night +# def number_of_nights? +# @room.add_reservation(check_in_date, check_out_date) +# num_of_nights = check_out_date - check_in_date - 1 +# return num_of_nights.to_i +# end + +# def total +# total_cost_for_stay = number_of_nights? * 200 +# return total_cost_for_stay +# end diff --git a/lib/room.rb b/lib/room.rb new file mode 100644 index 000000000..67b7b8b65 --- /dev/null +++ b/lib/room.rb @@ -0,0 +1,27 @@ +# require_relative 'date_range' +# require_relative 'reservation' + +class Room < Date_Range + # currently a room is only a room + attr_accessor :reservations, :room_num + + def initialize(room_num) + @room_num = room_num + @reservations = [] + end + + def check_overlap_with_room_reservations(requested_date_range) + # check if the check_in and check_out date overlaps with any other reservations for the room. + # Return true if no reservation conflicts with the checkin and checkout date. + if !@reservations.any? { |res| res.overlaps_in_reservations?(requested_date_range) } + return true + end + return false + end + + def create_new_reservation(check_in_date, check_out_date, hotel_block_reservation = false) + new_res = Reservation.new(room_num, check_in_date, check_out_date, hotel_block_reservation) + @reservations << new_res + return new_res + end +end diff --git a/test/date_range_test.rb b/test/date_range_test.rb new file mode 100644 index 000000000..35caa33a3 --- /dev/null +++ b/test/date_range_test.rb @@ -0,0 +1,109 @@ +#date range (1) 2001,2,1 - 2001, 2,10 9 nights +#date range (2) 2001,2,1 - 2001, 2,4 3 nights +#date range (3) 2001,1,31 - 2001,2,4 4 nights +#date range (4) 2001,2,4 - 2001, 2,8 4 nights +#date range (5) 2001,2,8 - 2001, 2,10 2 nights +#date range (6) 2001,2,8 - 2001, 2,12 4 nights +#date range (7) 2001,2,12 - 2001,2,14 4 nights + +require_relative "test_helper" + +describe "Instanitates a new Date Range" do + let(:check_in_date) { Date.new(2001, 2, 1) } + let(:check_out_date) { Date.new(2001, 2, 3) } + + it "Initialize Date Range" do + new_date = Date_Range.new(check_in_date, check_out_date) + expect(new_date).must_be_kind_of Date_Range + end + + describe "Checks Overlaps" do + let(:check_in_date) { Date.new(2001, 2, 1) } + let(:check_out_date) { Date.new(2001, 2, 4) } + let(:date_range_1) { Date_Range.new(check_in_date, check_out_date) } + + it "both date ranges are the exact same" do + # Arrange + date_range_2 = Date_Range.new(check_in_date, check_out_date) + # Act + test_date_range = date_range_1.overlaps_in_reservations?(date_range_2) + # Assert + expect(test_date_range).must_equal true + end + + it " New date range fails within current date range" do + # Arrange + start_two = Date.new(2001, 2, 2) + end_two = Date.new(2001, 2, 3) + date_range_2 = Date_Range.new(start_two, end_two) + # Act + test_date_range = date_range_1.overlaps_in_reservations?(date_range_2) + # Assert + expect(test_date_range).must_equal true + end + + it "New date range starts before current date range - ends after after current check in" do + # Arrange + start_two = Date.new(2001, 1, 31) + end_two = Date.new(2001, 2, 2) + date_range_2 = Date_Range.new(start_two, end_two) + # Act + test_date_range = date_range_1.overlaps_in_reservations?(date_range_2) + # Assert + expect(test_date_range).must_equal true + end + + it "New date range check in starts prior to current date range end - ends after " do + # Arrange + start_two = Date.new(2001, 2, 3) + end_two = Date.new(2001, 2, 6) + date_range_2 = Date_Range.new(start_two, end_two) + # Act + test_date_range = date_range_1.overlaps_in_reservations?(date_range_2) + # Assert + expect(test_date_range).must_equal true + end + + it "New date range spans the length of the whole current reservation " do + # Arrange + start_two = Date.new(2001, 2, 3) + end_two = Date.new(2001, 2, 6) + date_range_2 = Date_Range.new(start_two, end_two) + # Act + test_date_range = date_range_1.overlaps_in_reservations?(date_range_2) + # Assert + expect(test_date_range).must_equal true + end + + it " New range check in same as check out for current - Return False" do + # Arrange + start_two = Date.new(2001, 2, 4) + end_two = Date.new(2001, 2, 7) + date_range_2 = Date_Range.new(start_two, end_two) + # Act + test_date_range = date_range_1.overlaps_in_reservations?(date_range_2) + # Assert + expect(test_date_range).must_equal false + end + + it " New date check in end before current check in" do + # Arrange + start_two = Date.new(2001, 1, 28) + end_two = Date.new(2001, 2, 1) + date_range_2 = Date_Range.new(start_two, end_two) + # Act + test_date_range = date_range_1.overlaps_in_reservations?(date_range_2) + # Assert + expect(test_date_range).must_equal false + end + describe "Calulates number of nights " do + let(:check_in_date) { Date.new(2001, 2, 3) } + let(:check_out_date) { Date.new(2001, 2, 6) } + + it "Correctly calulates number of nights" do + res = Reservation.new(Room.new(1), check_in_date, check_out_date) + expect(res.number_of_nights?).must_equal 3 + end + end + end # inside describe +end # top describe diff --git a/test/hotel_block_test.rb b/test/hotel_block_test.rb new file mode 100644 index 000000000..0082cac85 --- /dev/null +++ b/test/hotel_block_test.rb @@ -0,0 +1,29 @@ +require_relative "test_helper" + +describe "Instanitates a new Hotel Block" do + let(:room_ids) { 5 } + let(:room_info) { 5 } + let(:hotel_block_id) { 101 } + let(:room_rate) { 150 } + let(:check_in_date) { Date.new(2001, 2, 1) } + let(:check_out_date) { Date.new(2001, 2, 3) } + + it "Initialize Hotel Block" do + room_ids = [1, 2, 3, 4, 5] + new_hotel_block = Hotel_Block.new(room_ids, check_in_date, check_out_date, room_rate, hotel_block_id) + expect(new_hotel_block).must_be_kind_of Hotel_Block + end + + it "Correctly show Check room availablity as occupied" do + room_ids = [1, 2, 3, 4, 5] + new_hotel_block = Hotel_Block.new(room_ids, check_in_date, check_out_date, room_rate, hotel_block_id) + expect(new_hotel_block.check_rooms_available).must_equal true + end + + it "Correctly show Check room availablity as occupied" do + room_ids = [1, 2, 3, 4, 5] + new_hotel_block = Hotel_Block.new(room_ids, check_in_date, check_out_date, room_rate, hotel_block_id) + new_hotel_block.room_info = {1=> true,2=> true,3=> true,4=> true,5=> true} + expect(new_hotel_block.check_rooms_available).must_equal false + end +end diff --git a/test/hotel_dispatcher_test.rb b/test/hotel_dispatcher_test.rb new file mode 100644 index 000000000..cb0c3e273 --- /dev/null +++ b/test/hotel_dispatcher_test.rb @@ -0,0 +1,85 @@ +require_relative "test_helper" +require "hotel_dispatcher" + +describe "HotelDispatcher class" do + def build_test_dispatcher + HotelManager.new + end + + describe "Initializer" do + it "is an instance of HotelDispatcher" do + hotel_dispatcher = build_test_dispatcher + expect(hotel_dispatcher).must_be_kind_of HotelManager + end + + it "can makes all rooms" do + hotel_dispatcher = build_test_dispatcher + room_array = hotel_dispatcher.make_rooms + expect(room_array.length).must_equal 20 + end + end + + describe "Can create a reservation" do + let(:room_ids) { 5 } + let(:room_info) { 5 } + let(:hotel_block_id) { 101 } + let(:room_rate) { 150 } + let(:check_in_date) { Date.new(2001, 2, 3) } + let(:check_out_date) { Date.new(2001, 2, 6) } + + it "Return true if reservation is can be created" do + hotel_dispatcher = build_test_dispatcher + hotel_dispatcher.make_rooms + new_res = hotel_dispatcher.create_reservation(check_in_date, check_out_date) + expect(new_res).must_equal true + end + + it "Raises error if no reservation available " do + hotel_dispatcher = build_test_dispatcher + hotel_dispatcher.rooms.each do |room| + room.create_new_reservation(Date.today, Date.today + 3) + end + expect { new_res = hotel_dispatcher.create_reservation(Date.today, Date.today + 3) }.must_raise Exception + end + end + + describe "Can create a Hotel room block??????" do + let(:check_in_date) { Date.new(2001, 2, 3) } + let(:check_out_date) { Date.new(2001, 2, 6) } + it "Raise expection if reservation is can't be created" do + hotel_dispatcher = build_test_dispatcher + room_ids = [1, 2, 3] + hotel_dispatcher.rooms.each do |room| + room.create_new_reservation(Date.today, Date.today + 3) + end + expect { new_res = hotel_dispatcher.create_room_block(room_ids, Date.today, Date.today + 3, 150) }.must_raise Exception + end + # it "Creates a successfull room block" do + + # end + + it "Check room availablity " do + hotel_dispatcher = build_test_dispatcher + + hotel_dispatcher.rooms.each do |room| + room.create_new_reservation(Date.today, Date.today + 3, hotel_block_reservation = false) + end + results = hotel_dispatcher.check_room_available?(Date.today, Date.today + 3) + expect(results).must_equal false + end + end + describe " Find all res" do + it "finds all res" do + hotel_dispatcher = build_test_dispatcher + all_res = [] + hotel_dispatcher.rooms.each do |room| + all_res << room.create_new_reservation(Date.today, Date.today + 3, hotel_block_reservation = false) + end + find_all = hotel_dispatcher.find_all_resevations + all_res.each do |res| + expect(find_all).must_include res + end + end + end +end + diff --git a/test/reservation_test.rb b/test/reservation_test.rb new file mode 100644 index 000000000..1c65a09c5 --- /dev/null +++ b/test/reservation_test.rb @@ -0,0 +1,18 @@ +require "date" +require_relative "test_helper" + +describe "Reservation class" do + describe "Initializer" do + let(:check_in_date) { Date.new(2001, 2, 3) } + let(:check_out_date) { Date.new(2001, 2, 6) } + it "is an instance of Reservation" do + res = Reservation.new(Room.new(1), check_in_date, check_out_date) + expect(res).must_be_kind_of Reservation + end + + it "takes in the date" do + res = Reservation.new(Room.new(1), check_in_date, check_out_date) + expect(res.total_cost_for_stay).must_equal 600 + end + end +end diff --git a/test/room_test.rb b/test/room_test.rb new file mode 100644 index 000000000..304bdf77b --- /dev/null +++ b/test/room_test.rb @@ -0,0 +1,30 @@ +require_relative "test_helper" + +describe "Room class" do + describe "Initializer" do + let(:check_in_date) { Date.new(2001, 2, 1) } + let(:check_out_date) { Date.new(2001, 2, 3) } + let(:date_range_1) { Date_Range.new(check_in_date, check_out_date) } + it "is an instance of Room" do + test_room = Room.new(1) + expect(test_room).must_be_kind_of Room + end + + it "Can create mutliple reservations for 1 room" do + room = Room.new(1) + all_res = [] + 5.times do |index| + all_res << room.create_new_reservation(Date.today, Date.today + 3, hotel_block_reservation = false) + end + expect(all_res.length).must_equal 5 + end + + it "Can check overlap within rooms" do + room = Room.new(1) + requested_date_range = Date_Range.new(check_in_date, check_out_date) + room.create_new_reservation(check_in_date, check_out_date, hotel_block_reservation = false) + all_res = room.check_overlap_with_room_reservations(requested_date_range) + expect(all_res).must_equal false + end + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb index c3a7695cf..952c0ff52 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,8 +1,16 @@ -# Add simplecov +require "simplecov" +SimpleCov.start + require "minitest" require "minitest/autorun" require "minitest/reporters" +require "minitest/skip_dsl" Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new # require_relative your lib files here! +# test/test_helper.rb +# require_relative "/lib/hotel_block.rb" +# require_relative "/lib/date_range.rb" +# require_relative "/lib/hotel_dispatch.rb" +# require_relative "/lib/reservation.rb"