Skip to content
This repository was archived by the owner on Jul 24, 2020. It is now read-only.

Commit db4816c

Browse files
committed
Merge pull request #614 from YaleSTC/614_refactor_res
Refactor Reservation Model.
2 parents 59ce7cf + 27b3f15 commit db4816c

6 files changed

+53
-133
lines changed

app/controllers/reservations_controller.rb

+7-7
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ def checkout
206206
flash[:error] = "No reservation selected."
207207
redirect_to :back and return
208208
# move method to user model TODO
209-
elsif Reservation.overdue_reservations?(reservations_to_be_checked_out.first.reserver) # Checks for any overdue equipment
209+
elsif reservations_to_be_checked_out.first.reserver.overdue_reservations?
210210
error_msgs += "User has overdue equipment."
211211
end
212212

@@ -326,16 +326,16 @@ def upcoming
326326

327327
def manage # initializer
328328
set_user
329-
@check_out_set = Reservation.due_for_checkout(@user)
330-
@check_in_set = Reservation.due_for_checkin(@user)
329+
@check_out_set = @user.due_for_checkout
330+
@check_in_set = @user.due_for_checkin
331331
end
332332

333333
def current
334334
set_user
335-
@user_overdue_reservations_set = [Reservation.overdue_user_reservations(@user)].delete_if{|a| a.empty?}
336-
@user_checked_out_today_reservations_set = [Reservation.checked_out_today_user_reservations(@user)].delete_if{|a| a.empty?}
337-
@user_checked_out_previous_reservations_set = [Reservation.checked_out_previous_user_reservations(@user)].delete_if{|a| a.empty?}
338-
@user_reserved_reservations_set = [Reservation.reserved_user_reservations(@user)].delete_if{|a| a.empty?}
335+
@user_overdue_reservations_set = [Reservation.overdue.for_reserver(@user)].delete_if{|a| a.empty?}
336+
@user_checked_out_today_reservations_set = [Reservation.checked_out_today.for_reserver(@user)].delete_if{|a| a.empty?}
337+
@user_checked_out_previous_reservations_set = [Reservation.checked_out_previous.for_reserver(@user)].delete_if{|a| a.empty?}
338+
@user_reserved_reservations_set = [Reservation.reserved.for_reserver(@user)].delete_if{|a| a.empty?}
339339

340340
render 'current_reservations'
341341
end

app/controllers/users_controller.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def index
2828

2929
def show
3030
@user_reservations = @user.reservations
31-
@all_equipment = Reservation.active_user_reservations(@user)
31+
@all_equipment = Reservation.active.for_reserver(@user)
3232
@show_equipment = { checked_out: @user.reservations.
3333
select {|r| \
3434
(r.status == "checked out") || \

app/models/reservation.rb

+22-117
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ class Reservation < ActiveRecord::Base
5454
scope :denied_requests, lambda {where("approval_status = ?", 'denied')}
5555
scope :missed_requests, lambda {where("approval_status = ? and start_date < ?", 'requested', Time.now.midnight.utc)}
5656

57+
scope :for_reserver, lambda { |reserver| where(reserver_id: reserver) }
58+
5759
#TODO: Why the duplication in checkout_handler and checkout_handler_id (etc)?
5860
attr_accessible :checkout_handler, :checkout_handler_id,
5961
:checkin_handler, :checkin_handler_id, :approval_status,
@@ -77,10 +79,9 @@ def reserver
7779

7880
def status
7981
if checked_out.nil?
80-
# TODO: This needs to take into account requests.
81-
if checked_in.nil? && (approval_status == 'auto' or approval_status == 'approved')
82+
if approval_status == 'auto' or approval_status == 'approved'
8283
due_date >= Date.today ? "reserved" : "missed"
83-
elsif !approval_status.nil?
84+
elsif approval_status
8485
approval_status
8586
else
8687
"?" # ... is this just in case an admin does something absurd in the database?
@@ -118,143 +119,47 @@ def self.validate_set(user, res_array = [])
118119
end
119120

120121

121-
def self.due_for_checkin(user)
122-
Reservation.where("checked_out IS NOT NULL and checked_in IS NULL and reserver_id = ?", user.id).order('due_date ASC') # put most-due ones first
123-
end
124-
125-
def self.due_for_checkout(user)
126-
user.reservations.upcoming
127-
end
128-
129-
def self.overdue_reservations?(user)
130-
Reservation.where("checked_out IS NOT NULL and checked_in IS NULL and reserver_id = ? and due_date < ?", user.id, Time.now.midnight.utc,).order('start_date ASC').count >= 1 #FIXME: does this need the order?
131-
# can't we just use user.reservations.overdue >= 1 (?)
132-
end
133-
134122
def checkout_object_uniqueness(reservations)
135123
object_ids_taken = []
136124
reservations.each do |r|
137-
if !object_ids_taken.include?(r.equipment_object_id) # check to see if we've already taken that one
138-
object_ids_taken << r.equipment_object_id
139-
else
140-
return false # return false if not unique
141-
end
125+
return false if object_ids_taken.include?(r.equipment_object_id)
126+
object_ids_taken << r.equipment_object_id
142127
end
143128
return true # return true if unique
144129
end
145130

146-
147-
def self.active_user_reservations(user)
148-
#TODO: can we use already-defined scopes, here?
149-
prelim = Reservation.where("checked_in IS NULL and reserver_id = ?", user.id).order('start_date ASC')
150-
final = [] # initialize
151-
prelim.collect do |r|
152-
if r.status != "missed" # missed reservations are not actually active
153-
final << r
154-
end
155-
end
156-
final
157-
end
158-
159-
def self.checked_out_today_user_reservations(user)
160-
Reservation.where("checked_out >= ? and checked_in IS NULL and reserver_id = ?", Time.now.midnight.utc, user.id)
161-
end
162-
163-
def self.checked_out_previous_user_reservations(user)
164-
Reservation.where("checked_out < ? and checked_in IS NULL and reserver_id = ? and due_date >= ?", Time.now.midnight.utc, user.id, Time.now.midnight.utc)
165-
end
166-
167-
def self.reserved_user_reservations(user)
168-
Reservation.where("checked_out IS NULL and checked_in IS NULL and due_date >= ? and reserver_id = ?", Time.now.midnight.utc, user.id)
169-
end
170-
171-
def self.overdue_user_reservations(user)
172-
Reservation.where("checked_out IS NOT NULL and checked_in IS NULL and due_date < ? and reserver_id = ?", Time.now.midnight.utc, user.id )
173-
end
174-
175-
def self.check_out_procedures_exist?(reservation)
176-
!reservation.equipment_model.checkout_procedures.nil?
177-
end
178-
179-
def self.check_in_procedures_exist?(reservation)
180-
!reservation.equipment_model.checkin_procedures.nil?
181-
end
182-
183-
def self.empty_reservation?(reservation)
184-
reservation.equipment_object.nil?
185-
end
186-
187131
def late_fee
188132
self.equipment_model.late_fee.to_f
189133
end
190134

191135
def fake_reserver_id # this is necessary for autocomplete! delete me not!
192136
end
193137

194-
# commented out on 2014.06.19. if no problems arise, it may be safely deleted.
195-
# def equipment_list # delete?
196-
# raw_text = ""
197-
# #Reservation.where("reserver_id = ?", @user.id).each do |reservation|
198-
# #if reservation.equipment_model
199-
# # raw_text += "1 x #{reservation.equipment_model.name}\r\n"
200-
# #else
201-
# # raw_text += "1 x *equipment deleted*\r\n"
202-
# #end
203-
# raw_text
204-
# end
205-
206138
def max_renewal_length_available
207-
# available_period is what is returned by the function
208-
# initialize to NIL because once it's set we escape the while loop below
209-
available_period = NIL
210-
renewal_length = self.equipment_model.maximum_renewal_length || 0 # the 'or 0' is to ensure renewal_length never == NIL; effectively
211-
while (renewal_length > 0) and (available_period == NIL)
212-
# the available? method cannot accept dates with time zones, and due_date has a time zone
213-
possible_start = (self.due_date + 1.day).to_date
214-
possible_due = (self.due_date+(renewal_length.days)).to_date
215-
if (self.equipment_model.num_available(possible_start, possible_due) > 0)
216-
# if it's available for the period, set available_period and escape loop
217-
available_period = renewal_length
218-
else
219-
# otherwise shorten reservation renewal period by one day and try again
220-
renewal_length -= 1
221-
end
139+
# determine the max renewal length for a given reservation
140+
eq_model = self.equipment_model
141+
for renewal_length in 1...eq_model.maximum_renewal_length do
142+
break if eq_model.available_count(self.due_date + renewal_length.day) == 0
222143
end
223-
# need this case to account for when renewal_length == 0 and it escapes the while loop
224-
# before available_period is set
225-
return available_period = renewal_length
144+
renewal_length - 1
226145
end
227146

228147
def is_eligible_for_renew?
229148
# determines if a reservation is eligible for renewal, based on how many days before the due
230149
# date it is and the max number of times one is allowed to renew
231150
#
232-
# we need to test if any of the variables are set to NIL, because in that case comparision
233-
# is undefined; that's also why we can't set variables to these function values before
234-
# the if statements
235-
if self.times_renewed == NIL
236-
self.times_renewed = 0
237-
end
151+
self.times_renewed ||= 0
238152

239-
# you can't renew a checked in reservation
240-
if self.checked_in
241-
return false
242-
end
153+
# you can't renew a checked in reservation, or one without an equipment model
154+
return false if self.checked_in || self.equipment_object.nil?
243155

244-
if self.equipment_model.maximum_renewal_times == "unrestricted"
245-
if self.equipment_model.maximum_renewal_days_before_due == "unrestricted"
246-
# if they're both NIL
247-
return true
248-
else
249-
# due_date has a time zone, eradicate with to_date; use to_i to change to integer;
250-
# are we within the date range for which the button should appear?
251-
return ((self.due_date.to_date - Date.today).to_i < self.equipment_model.maximum_renewal_days_before_due)
252-
end
253-
elsif (self.equipment_model.maximum_renewal_days_before_due == "unrestricted")
254-
return (self.times_renewed < self.equipment_model.maximum_renewal_times)
255-
else
256-
# if neither is NIL, check both
257-
return (((self.due_date.to_date - Date.today).to_i < self.equipment_model.maximum_renewal_days_before_due) and (self.times_renewed < self.equipment_model.maximum_renewal_times))
258-
end
156+
max_renewal_times = self.equipment_model.maximum_renewal_times
157+
max_renewal_times = Float::INFINITY if max_renewal_times == 'unrestricted'
158+
159+
max_renewal_days = self.equipment_model.maximum_renewal_days_before_due
160+
max_renewal_days = Float::INFINITY if max_renewal_days == 'unrestricted'
161+
162+
return ((self.due_date.to_date - Date.today).to_i < max_renewal_days ) &&
163+
(self.times_renewed < max_renewal_times)
259164
end
260165
end

app/models/reservation_validations.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ module ReservationValidations
77
# Same for CartReservations and Reservations
88
#TODO: admin override
99
def no_overdue_reservations?
10-
if Reservation.overdue_reservations?(reserver)
10+
if reserver.overdue_reservations?
1111
errors.add(:base, reserver.name + " has overdue reservations that prevent new ones from being created.\n")
1212
return false
1313
end

app/models/user.rb

+15
Original file line numberDiff line numberDiff line change
@@ -103,4 +103,19 @@ def render_name
103103
[((nickname.nil? || nickname.length == 0) ? first_name : nickname), last_name, login].join(" ")
104104
end
105105

106+
107+
# ---- Reservation methods ---- #
108+
109+
def overdue_reservations?
110+
self.reservations.overdue.count > 0
111+
end
112+
113+
def due_for_checkout
114+
self.reservations.upcoming
115+
end
116+
117+
def due_for_checkin
118+
self.reservations.checked_out.order('due_date ASC')
119+
end
120+
106121
end

spec/controllers/reservations_controller_spec.rb

+7-7
Original file line numberDiff line numberDiff line change
@@ -577,11 +577,11 @@
577577
end
578578

579579
it 'assigns @check_out_set correctly' do
580-
expect(assigns(:check_out_set)).to eq(Reservation.due_for_checkout(@user))
580+
expect(assigns(:check_out_set)).to eq(@user.due_for_checkout)
581581
end
582582

583583
it 'assigns @check_in_set correctly' do
584-
expect(assigns(:check_in_set)).to eq(Reservation.due_for_checkin(@user))
584+
expect(assigns(:check_in_set)).to eq(@user.due_for_checkin)
585585
end
586586
end
587587

@@ -634,19 +634,19 @@
634634
end
635635

636636
it 'assigns @user_overdue_reservations_set correctly' do
637-
expect(assigns(:user_overdue_reservations_set)).to eq [Reservation.overdue_user_reservations(@user)].delete_if{|a| a.empty?}
637+
expect(assigns(:user_overdue_reservations_set)).to eq [Reservation.overdue.for_reserver(@user)].delete_if{|a| a.empty?}
638638
end
639639

640640
it 'assigns @user_checked_out_today_reservations_set correctly' do
641-
expect(assigns(:user_checked_out_today_reservations_set)).to eq [Reservation.checked_out_today_user_reservations(@user)].delete_if{|a| a.empty?}
641+
expect(assigns(:user_checked_out_today_reservations_set)).to eq [Reservation.checked_out_today.for_reserver(@user)].delete_if{|a| a.empty?}
642642
end
643643

644644
it 'assigns @user_checked_out_previous_reservations_set correctly' do
645-
expect(assigns(:user_checked_out_previous_reservations_set)).to eq [Reservation.checked_out_previous_user_reservations(@user)].delete_if{|a| a.empty?}
645+
expect(assigns(:user_checked_out_previous_reservations_set)).to eq [Reservation.checked_out_previous.for_reserver(@user)].delete_if{|a| a.empty?}
646646
end
647647

648648
it 'assigns @user_reserved_reservations_set correctly' do
649-
expect(assigns(:user_reserved_reservations_set)).to eq [Reservation.reserved_user_reservations(@user)].delete_if{|a| a.empty?}
649+
expect(assigns(:user_reserved_reservations_set)).to eq [Reservation.reserved.for_reserver(@user)].delete_if{|a| a.empty?}
650650
end
651651
end
652652

@@ -896,4 +896,4 @@
896896
describe '#checkin_email (GET reservations/checkin_email)' do
897897
pending 'E-mails get sent'
898898
end
899-
end
899+
end

0 commit comments

Comments
 (0)