diff --git a/Rakefile b/Rakefile new file mode 100644 index 000000000..deb52f2cd --- /dev/null +++ b/Rakefile @@ -0,0 +1,9 @@ +require 'rake/testtask' + +Rake::TestTask.new do |t| + t.libs = ["lib"] + t.warning = true + t.test_files = FileList['specs/*_spec.rb'] +end + +task default: :test diff --git a/lib/block.rb b/lib/block.rb new file mode 100644 index 000000000..73c38e8cb --- /dev/null +++ b/lib/block.rb @@ -0,0 +1,48 @@ +require_relative 'date_range' +require_relative 'reservation' +require_relative 'hotel' + +module Hotel + + class BlockRoom < Reservation + + attr_reader :check_in, :check_out, :num_of_rooms, :discount, :block_of_rooms + + attr_accessor :available_rooms, :booked_rooms + + ## just creating a block of rooms that have not been booked yet## + def initialize(check_in, check_out, num_of_rooms = 5, client = nil, discount = 15, cost = 200) + + super(check_in, check_out, cost) + @discount = discount + @reservation_array << @discount + + if num_of_rooms > 5 + return raise ArgumentError.new("You cannot reserve a block with more than 5 rooms") + end + + @num_of_rooms = num_of_rooms + @reservation_array << @num_of_rooms + + @block_of_rooms = [] + @reservation_array << block_of_rooms + + @available_rooms = @block_of_rooms + @reservation_array << @available_rooms + + @booked_rooms = [] + @reservation_array << @booked_rooms + + + end #initialize + + def check_if_block_has_available_rooms + if @available_rooms.length >= 1 + return true + else + return raise ArgumentError.new("It appears there are no available rooms in block") + end + end + + end #class +end#module diff --git a/lib/date_range.rb b/lib/date_range.rb new file mode 100644 index 000000000..de757a39e --- /dev/null +++ b/lib/date_range.rb @@ -0,0 +1,21 @@ + +module Hotel + + class DateRange + + attr_reader :check_in, :check_out + + def initialize(check_in, check_out) + @check_in = Date.parse(check_in) + @check_out = Date.parse(check_out) + + if @check_in > @check_out + raise ArgumentError.new("Invalid date range") + end + end + + + + end #class + +end #hotel diff --git a/lib/hotel.rb b/lib/hotel.rb new file mode 100644 index 000000000..f7f967693 --- /dev/null +++ b/lib/hotel.rb @@ -0,0 +1,189 @@ +require_relative 'reservation' +require_relative 'block.rb' +require_relative 'date_range' + +module Hotel + + class Hotel + + attr_reader :rooms, :price, :reservation_collection, :block_reservation_collection, :reservation_made + + def initialize(num_of_rooms, price) + @rooms = [] + room_num = 0 + num_of_rooms.times do |room| + room_num += 1 + @rooms << room_num + end #loop + + @price = price + @reservation_collection = [] + @block_reservation_collection = [] + end #initialize + + def make_reservation(check_in, check_out, room_num) + if room_availability(check_in, check_out).include?(room_num) + @reservation_made = Reservation.new(check_in, check_out, room_num) + @reservation_collection << @reservation_made + else + raise ArgumentError.new("It appears the room you requested is booked during that date range") + end + # @reservation_collection << @reservation_made + end + + + def make_block_reservation(check_in, check_out, num_of_rooms) + available_rooms = room_availability(check_in, check_out) + if available_rooms.length >= num_of_rooms + block_reservation = BlockRoom.new(check_in, check_out, num_of_rooms) + block_reservation.block_of_rooms << available_rooms.pop(num_of_rooms) + @block_reservation_collection << block_reservation + return block_reservation.block_of_rooms + else + return raise ArgumentError.new("We do not have enough rooms to reserve a block") + end + end + + # ability to reserve a room within a block of rooms + #needs to match the date range of the block + def reserve_room_in_block(check_in, check_out, num_of_rooms) + + check_in = Date.parse(check_in) + check_out = Date.parse(check_out) + + @block_reservation_collection.each do |entry| + if check_in == entry.check_in && check_out == entry.check_out + if entry.available_rooms[0].length >= num_of_rooms + num_of_rooms.times do + entry.booked_rooms << entry.available_rooms[0].pop + end + return entry.booked_rooms + end + end + end + end + + def blocked_rooms_availability(check_in, check_out) + check_in = Date.parse(check_in) + check_out = Date.parse(check_out) + + @block_reservation_collection.each do |entry| + if check_in == entry.check_in && check_out == entry.check_out + if entry.available_rooms[0].length >= 0 + return true + else false + end + end + end + end + + def date_list_of_reservations(date) + date_list = [] + date = Date.parse(date) + @reservation_collection.each do |entry| + # binding.pry + if entry.check_in <= date && entry.check_out >= date + date_list << [entry.room_num, entry.check_in.to_s, entry.check_out.to_s] + end + end + return date_list + end #def + + def room_availability(check_in, check_out) + #can be string with dates + rooms_available = @rooms.clone + + # [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20] + check_in = Date.parse(check_in) + check_out = Date.parse(check_out) + + if check_in > check_out + raise ArgumentError.new("Invalid date range") + end + + @reservation_collection.each do |entry| + if check_in < entry.check_in && check_in < entry.check_out && check_out < entry.check_out && check_out > entry.check_in + rooms_available.delete(entry.room_num) + elsif check_in > entry.check_in && check_in < entry.check_out && check_out < entry.check_out && check_out > entry.check_in + rooms_available.delete(entry.room_num) + elsif check_in > entry.check_in && check_in < entry.check_out && check_out == entry.check_out && check_out > entry.check_in + rooms_available.delete(entry.room_num) + elsif check_in < entry.check_in && check_in < entry.check_out && check_out > entry.check_in && check_out == entry.check_out + rooms_available.delete(entry.room_num) + elsif check_in > entry.check_in && check_in < entry.check_out && check_out > entry.check_out + rooms_available.delete(entry.room_num) + elsif check_in == entry.check_in && check_in < entry.check_out && check_out > entry.check_in && check_out > entry.check_in + rooms_available.delete(entry.room_num) + end + end + + @block_reservation_collection.each do |entry| + if check_in < entry.check_in && check_in < entry.check_out && check_out < entry.check_out && check_out > entry.check_in + entry.block_of_rooms[0].each do |room| + rooms_available.delete(room) + end + elsif check_in > entry.check_in && check_in < entry.check_out && check_out < entry.check_out && check_out > entry.check_in + entry.block_of_rooms[0].each do |room| + rooms_available.delete(room) + end + elsif check_in > entry.check_in && check_in < entry.check_out && check_out == entry.check_out && check_out > entry.check_in + entry.block_of_rooms[0].each do |room| + rooms_available.delete(room) + end + elsif check_in < entry.check_in && check_in < entry.check_out && check_out > entry.check_in && check_out == entry.check_out + entry.block_of_rooms[0].each do |room| + rooms_available.delete(room) + end + elsif check_in > entry.check_in && check_in < entry.check_out && check_out > entry.check_out + entry.block_of_rooms[0].each do |room| + rooms_available.delete(room) + end + elsif check_in == entry.check_in && check_in < entry.check_out && check_out > entry.check_in && check_out > entry.check_in + entry.block_of_rooms[0].each do |room| + rooms_available.delete(room) + end + end + end + return rooms_available + end #room_availability + + end #class +end #module + + + + + + + + + + + + + + + + + + + + +### second round of logic ### does not work because it will list rooms that are available for a given date range and not couple if the room is taken for another date + + +# if check_in == entry.check_in && check_in < entry.check_out && check_out > entry.check_in && check_out < entry.check_out +# false +# binding.pry +# +# elsif check_in< entry.check_in && check_out == entry.check_in && check_in < entry.check_out +# rooms_available << entry.room_num +# # elsif check_in < entry.check_in && check_in < entry.check_out && check_out == entry.check_in +# # rooms_available << entry.room_num +# elsif check_in == entry.check_out && check_out > entry.check_out +# rooms_available << entry.room_num +# elsif check_in > entry.check_out +# rooms_available << entry.room_num +# # elsif check_in < entry.check_in && check_out < entry.check_in && check_in < entry.check_out +# # rooms_available << entry.room_num +# end diff --git a/lib/reservation.rb b/lib/reservation.rb new file mode 100644 index 000000000..9dfe1aee9 --- /dev/null +++ b/lib/reservation.rb @@ -0,0 +1,33 @@ +require_relative 'date_range'#take note this needs to be included at the top +# require 'Date' + +module Hotel + + class Reservation + + attr_reader :check_in, :check_out, :date_range, :room_num, :cost, :reservation_array + + def initialize(check_in, check_out, room_num, cost = 200) + @reservation_array = [] + + @date_range = DateRange.new(check_in, check_out) + @check_in = @date_range.check_in + @check_out = @date_range.check_out + + + @reservation_array << @date_range + + @room_num = room_num + @reservation_array << @room_num + + @cost = cost + @reservation_array << @cost + end #initialize + + def total_cost + num_nights = (@date_range.check_out - @date_range.check_in).to_i + return num_nights * @cost + end + + end #reservation +end #module diff --git a/specs/block_spec.rb b/specs/block_spec.rb new file mode 100644 index 000000000..b8fe7b273 --- /dev/null +++ b/specs/block_spec.rb @@ -0,0 +1,48 @@ +require_relative 'spec_helper' + +describe "Block child class" do + + describe "initialization" do + before do + @block = Hotel::BlockRoom.new('sept 1 2017', 'sept 2 2017', 3, "Fernandez", 10) + end + + it "Can create an instance of block" do + @block.must_be_instance_of Hotel::BlockRoom + end + + it "Can call methods regarding instance methods created" do + @block.reservation_array.must_be_instance_of Array + @block.num_of_rooms.must_equal 3 + @block.discount.must_equal 10 + @block.check_in.must_be_instance_of Date + @block.check_out.must_be_instance_of Date + @block.block_of_rooms.must_be_instance_of Array + @block.cost.must_equal 200 + @block.booked_rooms.must_be_instance_of Array + @block.available_rooms.must_be_instance_of Array + end + + it "Will return error message if try to book more than 5 rooms in a block" do + proc {Hotel::BlockRoom.new('today', 'tomorrow', 6)}.must_raise ArgumentError + end + + end + + describe "check if block has rooms available" do + before do + @block = Hotel::BlockRoom.new('sept 1 2017', 'sept 2 2017', 3, "Fernandez", 10) + end + + it "Can raise an argument if there aren't rooms available" do + @block.available_rooms = [] + proc {@block.check_if_block_has_available_rooms}.must_raise ArgumentError + end + + it "Can return an array of available rooms" do + @block.available_rooms = [2,3,4] + @block.check_if_block_has_available_rooms.must_equal true + end + end + +end #block describe diff --git a/specs/date_range_spec.rb b/specs/date_range_spec.rb new file mode 100644 index 000000000..bf228c46b --- /dev/null +++ b/specs/date_range_spec.rb @@ -0,0 +1,24 @@ +require_relative 'spec_helper' + +describe "DateRange class" do + let(:check_in) {"Sept 9 2017"} + let(:check_out) {"Sept 15 2017"} + + it "Can be instantiated" do + Hotel::DateRange.new(check_in, check_out).must_be_instance_of Hotel::DateRange + end + + it "Allows access to check_in instance variable" do + new_hotel = Hotel::DateRange.new(check_in, check_out) + new_hotel.check_in.must_be_instance_of Date + new_hotel.check_out.must_be_instance_of Date + end + + it "Checks for invalid date entry - if check in is after check out date" do + check_in_1 = "Sept 9 2017" + check_out_1 = "Sept 8 2017" + proc {Hotel::DateRange.new(check_in_1, check_out_1)}.must_raise ArgumentError + end + + +end diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb new file mode 100644 index 000000000..0e45c0fdf --- /dev/null +++ b/specs/hotel_spec.rb @@ -0,0 +1,147 @@ +require_relative 'spec_helper' + +describe "Hotel class" do + + describe "Instantiation" do + + it "Can be instantiated" do + Hotel::Hotel.new(20, 200).must_be_instance_of Hotel::Hotel + end + + it "Can create an array of rooms" do + Hotel::Hotel.new(20, 200).rooms.length.must_equal 20 + end + + it "Can call the array of rooms" do + Hotel::Hotel.new(20,200).rooms.must_equal [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18, 19, 20] + end + + it "Can call on price of rooms" do + Hotel::Hotel.new(20, 200).price.must_equal 200 + end + + it "can call on collection of reservations array - will be empty" do + Hotel::Hotel.new(20, 200).reservation_collection.must_be_instance_of Array + Hotel::Hotel.new(20, 200).block_reservation_collection.must_be_instance_of Array + + end + end #describe instantiate + + describe "#make reservation" do + before do + @bb_hotel = Hotel::Hotel.new(4, 200) + @bb_hotel.make_reservation('sept 8 2017', 'sept 10 2017', 4) + end + + it "can be instantiated" do + @bb_hotel.reservation_made.reservation_array.must_include 4 + @bb_hotel.reservation_collection.length.must_equal 1 + end + + it "Can call on class reservation methods" do + @bb_hotel.reservation_made.room_num.must_equal 4 + end + + it "Can return an argument error if room is not available for that date range" do + proc { @bb_hotel.make_reservation('sept 8 2017', 'sept 9 2017', 4)}.must_raise ArgumentError + end ####NOTE##### Not sure how to create a test to check if there is no problem with the code + end + + describe "#list of reservations for a specific date" do + before do + @bb_hotel = Hotel::Hotel.new(20, 200) + @bb_hotel.make_reservation('sept 8 2017', 'sept 10 2017', 4) + @bb_hotel.make_reservation('sept 7 2017', 'sept 9 2017', 3) + end + + it "Returns an array of reservations for that date" do + @bb_hotel.date_list_of_reservations('sept 9 2017').must_be_instance_of Array + @bb_hotel.date_list_of_reservations('sept 9 2017').length.must_equal 2 + end + end + + describe "#room availability" do + before do + @hotel = Hotel::Hotel.new(4, 200) + @hotel.make_reservation('sept 3 2017', 'sept 5 2017', 1) + @hotel.make_reservation('sept 5 2017', 'sept 7 2017', 1) + @hotel.make_reservation('sept 2 2017', 'sept 4 2017', 2) + @hotel.make_reservation('sept 6 2017', 'sept 8 2017', 2) + @hotel.make_reservation('sept 3 2017', 'sept 5 2017', 3) + @hotel.make_reservation('sept 2 2017', 'sept 3 2017', 3) + end + + it "Returns an array of available rooms" do + @hotel.room_availability('sept 1 2017', 'sept 4 2017').must_be_instance_of Array + end + + it "Returns the room numbers available for a certain date range" do + @hotel.room_availability('sept 1 2017', 'sept 3 2017').must_equal [1 ,4] + @hotel.room_availability('sept 5 2017', 'sept 6 2017').must_equal [2,3,4] + @hotel.room_availability('sept 7 2017', 'sept 8 2017').must_equal [1,3,4] + @hotel.make_block_reservation('sept 5 2017', 'sept 6 2017', 3) + @hotel.room_availability('sept 5 2017', 'sept 6 2017').must_equal [] + end + + it "Returns an ArgumentError if wrong date range entered" do + proc {@hotel.room_availability('sept 4 2017', 'sept 3 2017')}.must_raise ArgumentError + end + + it "Does not let general public reserve rooms that are in a block" do + end + + it "does not let you overbook a room in a block if that room is being saved in another block" do + end + + end + + describe "make block reservation method" do + before do + @hotel = Hotel::Hotel.new(6, 200) + @hotel.make_reservation('sept 3 2017', 'sept 5 2017', 1) + @hotel.make_reservation('sept 5 2017', 'sept 7 2017', 1) + @hotel.make_reservation('sept 2 2017', 'sept 4 2017', 2) + @hotel.make_reservation('sept 6 2017', 'sept 8 2017', 2) + @hotel.make_reservation('sept 3 2017', 'sept 5 2017', 3) + @hotel.make_reservation('sept 2 2017', 'sept 3 2017', 3) + end + + it "Can create an entry in the block reservations array" do + @hotel.make_block_reservation('sept 1 2017', 'sept 4 2017', 3).must_equal [[4,5,6]] + end + + it "Returns an error message if not enough rooms are availanle to book" do + proc {@hotel.make_block_reservation('sept 1 2017', 'sept 4 2017', 4)}.must_raise ArgumentError + end + + end + + describe "checking room availability and making room reservation in a block" do + before do + @hotel = Hotel::Hotel.new(6, 200) + @hotel.make_reservation('sept 3 2017', 'sept 5 2017', 1) + @hotel.make_reservation('sept 5 2017', 'sept 7 2017', 1) + @hotel.make_reservation('sept 2 2017', 'sept 4 2017', 2) + @hotel.make_reservation('sept 6 2017', 'sept 8 2017', 2) + @hotel.make_reservation('sept 3 2017', 'sept 5 2017', 3) + @hotel.make_reservation('sept 2 2017', 'sept 3 2017', 3) + @hotel.make_block_reservation('sept 1 2017', 'sept 4 2017', 3) + + end + + it "can let you know if a block has rooms available" do + @hotel.blocked_rooms_availability('sept 1 2017', 'sept 4 2017').must_equal true + + end + + it "Can determine if a block has available rooms and move them to booked " do + @hotel.reserve_room_in_block('sept 1 2017', 'sept 4 2017', 2).must_equal [6,5] + end + + it "Does not let general public book a room in a block" do + @hotel.room_availability('sept 1 2017', 'sept 4 2017').must_equal [] + end + + end #describe #block room reservation + +end #describe diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb new file mode 100644 index 000000000..bca9c85f2 --- /dev/null +++ b/specs/reservation_spec.rb @@ -0,0 +1,38 @@ +require_relative 'spec_helper' + + +describe "Reservation class" do + + describe "Initialization" do + before do + @hotel = Hotel::Reservation.new('sept 7 2017', 'sept 9 2017', 18) + end + + it "Can be intialized" do + @hotel.must_be_instance_of Hotel::Reservation + end + + it "Can call on instance variables" do + @hotel.date_range.must_be_instance_of Hotel::DateRange #important - need to include Hotel::DateRange; cannot be DateRange alone + @hotel.room_num.must_equal 18 + @hotel.cost.must_equal 200 + @hotel.reservation_array.must_include 200 + @hotel.reservation_array.must_be_instance_of Array + @hotel.reservation_array.length.must_equal 3 ##note, I thought here it should be 4, but daterange is one instance so check_in and check_out exist together as daterange instance + end # it + + end #describe + + describe " #total_cost" do + before do + @hotel = Hotel::Reservation.new('sept 7 2017', 'sept 9 2017', 18) + @hotel_2 = Hotel::Reservation.new('oct 22 2017', 'oct 28 2017', 20) + end + + it "Can be called" do + @hotel.total_cost.must_equal 400 + @hotel_2.total_cost.must_equal 1200 + end + end + +end #describe diff --git a/specs/spec_helper.rb b/specs/spec_helper.rb new file mode 100644 index 000000000..932a8ee26 --- /dev/null +++ b/specs/spec_helper.rb @@ -0,0 +1,11 @@ +require 'simplecov' +SimpleCov.start + +require 'minitest/autorun' +require 'minitest/reporters' + +require_relative '../lib/hotel' +require_relative '../lib/date_range' +require_relative '../lib/reservation' + +Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new