diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 000000000..1ad899dbc Binary files /dev/null and b/.DS_Store differ diff --git a/Rakefile b/Rakefile new file mode 100644 index 000000000..3391136e7 --- /dev/null +++ b/Rakefile @@ -0,0 +1,10 @@ +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..25e892b12 --- /dev/null +++ b/lib/block.rb @@ -0,0 +1,34 @@ +require 'date' +require 'pry' + +module Hotel + class Block < Reservation + + RATE_DISCOUNT = 0.8 + + attr_accessor :block_size, :reserved_rooms + + def initialize(input) + super + + @block_size = input[:block_size] + @reserved_rooms = Array.new + + if block_size > 5 + raise StandardError.new('The maximum bock size is 5 rooms.') + elsif block_size < 2 + raise StandardError.new('The minimum block size is 2 rooms.') + end + + end + + def calculate_cost + duration = Integer(check_out- check_in) + reservation_cost = duration * (RATE * RATE_DISCOUNT) + return reservation_cost + end + + + + end # end of block +end # end of module diff --git a/lib/hotel_manager.rb b/lib/hotel_manager.rb new file mode 100644 index 000000000..0f7f199cc --- /dev/null +++ b/lib/hotel_manager.rb @@ -0,0 +1,85 @@ +require 'date' +require 'pry' + +module Hotel + class HotelManager + + attr_reader :room_list + attr_accessor :reservations + + def initialize + @room_list = load_rooms + @reservations = Array.new + # puts "A new hotel manager has been created." + end + + def load_rooms + room_list = Array(1..20) + return room_list + end + + def get_reservation_id + + if @reservations == [] + next_reservation_id = 1 + # puts "The next reservation will be #{next_reservation_id}" + return next_reservation_id + else + next_reservation_id = @reservations.length + 1 + # puts "The next reservation will be #{next_reservation_id}" + return next_reservation_id + end + end + + def reservations_by_date(date) + reservation_list = [] + @reservations.each do |reservation| + if reservation.stay_date_list.include?(date) + reservation_list << reservation + end + end + return reservation_list + end + + def find_available_rooms(start_date, end_date) + potential_dates = (start_date..(end_date - 1)).to_a + unavailable_rooms = [] + @reservations.each do |reservation| + date_check_list = reservation.stay_date_list + checked_date_list = date_check_list - potential_dates + if checked_date_list.length < date_check_list.length + unavailable_rooms << reservation.room_id + end + end + + if unavailable_rooms.length == 20 + raise StandardError.new('There are no available rooms at this time.') + elsif unavailable_rooms.length > 0 + available_rooms = @room_list - unavailable_rooms + else + available_rooms = @room_list + end + return available_rooms + end + + def get_available_room(check_in_date, check_out_date) + potential_rooms = find_available_rooms(check_in_date, check_out_date) + next_room_id = potential_rooms.first + # puts "the next room id will be #{next_room_id}" + return next_room_id + end + + def add_reservation(check_in_date, check_out_date) + new_reservation = Hotel::Reservation.new({reservation_id: get_reservation_id, room_id: get_available_room(check_in_date, check_out_date), check_in: check_in_date, check_out: check_out_date}) + @reservations.push(new_reservation) + # puts "the new reservation is #{new_reservation}." + return new_reservation + end + + def add_block(block_size, check_in_date, check_out_date) + new_block = Hotel::Block.new({reservation_id: get_reservation_id, block_size: block_size, check_in: check_in_date, check_out: check_out_date}) + @reservations.push(new_block) + end + + end # end of class +end # end of module diff --git a/lib/reservation.rb b/lib/reservation.rb new file mode 100644 index 000000000..f2a242e2d --- /dev/null +++ b/lib/reservation.rb @@ -0,0 +1,38 @@ +require 'date' +require 'pry' + +module Hotel + class Reservation + + RATE = 200.00 + + attr_accessor :reservation_id, :room_id, :check_in, :check_out + + def initialize(input) + @reservation_id = input[:reservation_id] + @room_id = input[:room_id] + @check_in = input[:check_in] + @check_out = input[:check_out] + + if check_in == check_out + raise StandardError.new('The start date and the end date cannot be the same date.') + elsif check_in > check_out + raise StandardError.new('The end date cannot be before the start date.') + end + + end + + def stay_date_list + list_of_dates = (@check_in..@check_out).to_a + list_of_dates = list_of_dates[0..-2] + return list_of_dates + end + + def calculate_cost + duration = Integer(check_out- check_in) + reservation_cost = duration * RATE + return reservation_cost + end + + end # end of class +end # end of module diff --git a/specs/block_spec.rb b/specs/block_spec.rb new file mode 100644 index 000000000..c9c3f4252 --- /dev/null +++ b/specs/block_spec.rb @@ -0,0 +1,51 @@ +require_relative "spec_helper.rb" + +describe 'block' do + describe 'initialize' do + it 'instantiates the class properties as the correct class type' do + input = {reservation_id: 1, block_size: 2, check_in: Date.new(2018, 7, 06), check_out: Date.new(2018, 7, 10)} + @new_block = Hotel::Block.new(input) + + @new_block.reservation_id.must_be_kind_of Integer + @new_block.block_size.must_be_kind_of Integer + @new_block.check_in.must_be_kind_of Date + @new_block.check_out.must_be_kind_of Date + @new_block.reserved_rooms.must_be_kind_of Array + end + + it 'raises an error if provided an invalid date range' do + + # the start and end dates are the same + proc{ + @new_block = Hotel::Block({reservation_id: 1, block_size: 2, check_in: Date.new(2018, 5, 25), check_out: Date.new(2018, 5, 25)}) + }.must_raise StandardError + + # the start date is after the end date + proc{ + @new_block1 = Hotel::Block({reservation_id: 1, block_size: 2, check_in: Date.new(2018, 5, 25), check_out: Date.new(2018, 5, 19)}) + }.must_raise StandardError + end + + it 'raises an error if provided an invalid block size' do + + proc{ + @new_block = Hotel::Block({reservation_id: 1, block_size: 6, check_in: Date.new(2018, 5, 25), check_out: Date.new(2018, 5, 26)}) + }.must_raise StandardError + + proc{ + @new_block = Hotel::Block({reservation_id: 1, block_size: 1, check_in: Date.new(2018, 5, 25), check_out: Date.new(2018, 5, 26)}) + }.must_raise StandardError + end + end # end of describe initialize + + describe 'calculate_cost' do + it 'calculates cost based on block rate not reservation rate' do + input = {reservation_id: 1, block_size: 2, check_in: Date.new(2018, 7, 06), check_out: Date.new(2018, 7, 10)} + @new_block = Hotel::Block.new(input) + + @new_block.calculate_cost.must_equal 640 + end + end + + +end # end of describe Block diff --git a/specs/hotel_manager_spec.rb b/specs/hotel_manager_spec.rb new file mode 100644 index 000000000..9875c0f8f --- /dev/null +++ b/specs/hotel_manager_spec.rb @@ -0,0 +1,149 @@ +require_relative "spec_helper.rb" + +describe 'HotelManager' do + describe 'initialize' do + before do + @new_hotel = Hotel::HotelManager.new + end + it 'can create a new instance of HotelManager' do + @new_hotel.must_be_instance_of Hotel::HotelManager + end # end of can create new instance + + # it 'can call class properties when instantiated' do + # [room_list, reservations].each do |prop| + # @new_hotel.must_respond_to prop + # end + # end + + it 'instantiates the properties correctly' do + @new_hotel.room_list.must_be_kind_of Array + @new_hotel.reservations.must_be_kind_of Array + @new_hotel.reservations.length.must_equal 0 + end + end # end of describe initialize + + describe 'load_rooms' do + it 'correctly creates room_list array' do + @new_hotel = Hotel::HotelManager.new + @new_hotel.room_list.length.must_equal 20 + end + end # end of describe load_rooms + + describe 'get_reservation_id' do + it 'correctly generates the next reservation_id when no reservations' do + @new_hotel = Hotel::HotelManager.new + @new_hotel.reservations.length.must_equal 0 + @new_hotel.get_reservation_id.must_equal 1 + end + it 'correctly generates the next reservation_id when reservations already exist' do + @new_hotel = Hotel::HotelManager.new + @new_hotel.reservations = [1, 2, 3] + @new_hotel.reservations.length.must_equal 3 + @new_hotel.get_reservation_id.must_equal 4 + end + + end # end of describe 'get_reservation_id' + + describe 'get_available_room' do + it 'must return an appropriate room id' do + @new_hotel = Hotel::HotelManager.new + @start_date = Date.new(2018, 5, 26) + @end_date = Date.new(2018, 5, 28) + room_id = @new_hotel.get_available_room(@start_date, @end_date) + room_id.must_be_kind_of Integer + room_id.must_be :>, 0 + room_id.must_be :<, 21 + end + end # end of get_available_room + + describe 'add_reservation' do + it 'creates an instance of Reservation' do + @new_hotel = Hotel::HotelManager.new + + @new_hotel.add_reservation(Date.new(2018, 3, 25), Date.new(2018, 3, 28)).must_be_instance_of Hotel::Reservation + end + + it 'adds the reservation to array of reservations' do + @new_hotel = Hotel::HotelManager.new + @new_hotel.reservations.length.must_equal 0 + @new_hotel.add_reservation(Date.new(2018, 3, 25), Date.new(2018, 3, 28)) + @new_hotel.reservations.length.must_equal 1 + end + end # end of describe add_reservation + + describe 'reservations_by_date' do + before do + @overlap_date = Date.new(2018, 5, 26) + @new_hotel = Hotel::HotelManager.new + + # Two should contain the overlap date + @new_hotel.add_reservation(@overlap_date - 1, @overlap_date + 1) + @new_hotel.add_reservation(@overlap_date - 5, @overlap_date + 3) + + # One should not + @new_hotel.add_reservation(@overlap_date - 20, @overlap_date - 15) + # puts "This is to check what is in #{@new_hotel}" + end + + it 'returns an array of reservations for a specific date' do + # binding.pry + reservation_list = @new_hotel.reservations_by_date(@overlap_date) + reservation_list.must_be_instance_of Array + reservation_list.length.must_equal 2 + reservation_list.each do |res| + res.must_be_instance_of Hotel::Reservation + end + end + + end # end of describe reservations_by_date + + describe 'find_available_rooms' do + + it 'returns correct size list when 1 overlapping date' do + @begin_date = Date.new(2018, 5, 26) + @end_date = Date.new(2018, 5, 28) + @new_hotel = Hotel::HotelManager.new + + # one reservation should affect returned array + @new_hotel.add_reservation(@begin_date - 2, @end_date + 3) + @new_hotel.add_reservation(@begin_date + 45, @end_date + 47) + @new_hotel.find_available_rooms(@begin_date, @end_date).length.must_equal 19 + end + + it 'returns correct size list when no overlapping dates' do + @begin_date = Date.new(2018, 5, 26) + @end_date = Date.new(2018, 5, 28) + @new_hotel = Hotel::HotelManager.new + # neither reservation should affect returned array + @new_hotel.add_reservation(@begin_date - 20, @end_date - 15) + @new_hotel.add_reservation(@begin_date + 45, @end_date + 47) + @new_hotel.find_available_rooms(@begin_date, @end_date).length.must_equal 20 + end + + it 'raises an error if there are no available rooms' do + proc{ + @new_hotel = Hotel::HotelManager.new + check_in_date = Date.new(2018, 3, 12) + check_out_date = Date.new(2018, 3, 20) + 21.times do + @new_hotel.add_reservation(check_in_date, check_out_date) + end + @new_hotel.find_available_rooms(Date.new(2018, 3, 12), Date.new(2018, 3, 20)) + }.must_raise StandardError + end + end # end of describe find_available_rooms + +end # end of describe HotelManager + + + + # Two should contain the overlap date + # @new_hotel.add_reservation(@begin_date - 1, @overlap_date + 1) + # @new_hotel.add_reservation(@begin_date- 5, @end_date + 3) + # + # # One should not + # @new_hotel.add_reservation(@begin_date - 20, @end_date - 15) + +# check_in_date = Date.new(2018, 4, 15) +# check_out_date = Date.new(2018, 4, 24) +# @new_hotel.add_reservation(check_in_date, check_out_date) diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb new file mode 100644 index 000000000..598c2d150 --- /dev/null +++ b/specs/reservation_spec.rb @@ -0,0 +1,57 @@ +require_relative "spec_helper.rb" + +describe 'reservation' do + describe 'initialize' do + before do + @new_reservation = Hotel::Reservation.new({reservation_id: 1, room_id: 2, check_in: Date.new(2018, 5, 25), check_out: Date.new(2018, 5, 27)}) + end + + it 'instantiates the class properties as the correct class type' do + @new_reservation.reservation_id.must_be_kind_of Integer + @new_reservation.room_id.must_be_kind_of Integer + @new_reservation.check_in.must_be_kind_of Date + @new_reservation.check_out.must_be_kind_of Date + end + + it 'raises an error if provided an invalid date range' do + + # the start and end dates are the same + proc{ + @new_reservation = Hotel::Reservation.new({reservation_id: 1, room_id: 2, check_in: Date.new(2018, 5, 25), check_out: Date.new(2018, 5, 25)}) + }.must_raise StandardError + + # the start date is after the end date + proc{ + @new_reservation1 = Hotel::Reservation.new({reservation_id: 1, room_id: 2, check_in: Date.new(2018, 5, 25), check_out: Date.new(2018, 5, 19)}) + }.must_raise StandardError + end + + end # end of initialize + + describe 'stay_date_list' do + before do + @new_reservation = Hotel::Reservation.new({reservation_id: 1, room_id: 2, check_in: Date.new(2018, 5, 25), check_out: Date.new(2018, 5, 27)}) + end + + it 'returns a list of dates that are covered by a reservation' do + date_list = @new_reservation.stay_date_list + date_list.must_be_kind_of Array + date_list[0].must_be_instance_of Date + date_list.length.must_equal 2 + end + + end + + describe 'calculate_duration_of_stay' do + before do + @new_reservation = Hotel::Reservation.new({reservation_id: 1, room_id: 2, check_in: Date.new(2018, 5, 25), check_out: Date.new(2018, 5, 27)}) + end + + it 'returns a float of the correct cost' do + cost = @new_reservation.calculate_cost + cost.must_be_kind_of Float + cost.must_equal 400.00 + end + end # end of describe calculate_cost + +end # end of describe Reservation diff --git a/specs/spec_helper.rb b/specs/spec_helper.rb new file mode 100644 index 000000000..0ce377c57 --- /dev/null +++ b/specs/spec_helper.rb @@ -0,0 +1,15 @@ +require 'simplecov' +SimpleCov.start do + add_filter "/specs/" +end +require 'minitest' +require 'minitest/autorun' +require 'minitest/reporters' +# Add simplecov + +Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new + +# Require_relative your lib files here! +require_relative '../lib/hotel_manager' +require_relative '../lib/reservation' +require_relative '../lib/block'