From cd5792c708a96ec9704e6af7c112edc8c91f9f7c Mon Sep 17 00:00:00 2001 From: Jim Benton <3331+jim@users.noreply.github.com> Date: Mon, 25 Nov 2024 11:42:58 -0600 Subject: [PATCH] Return items on a reservation (#1764) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # What it does * Adds the ability for a staff member to mark items on a reservation as returned at the end of a loan. * Restructures the "Pickups" tab to be the "Items" tab on a reservation. Now all item manipulation (both while building up the specific items to be borrowed and when they are returned later on) happen on the same page/tab. * Deletes an unused partial: `app/views/account/reservations/_profile.html.erb`. # Why it is important We need to have a accept items that are returned to us 😄 # UI Change Screenshot ![2024-11-19 18 36 54](https://github.com/user-attachments/assets/a278e1ab-9213-4b10-95b1-f9a79b863284) # Implementation notes * It's possible we could avoid the turbo stream shenanigans in this flow, but I started working on this before we merged in the page refresh morphing stuff in #1738. I will see if that simplification is possible while tackling future parts of the reservation flow. --- .../reservations/check_ins_controller.rb | 67 +++++++++++++++++++ .../pending_reservation_items_controller.rb | 2 +- .../admin/reservations/pickups_controller.rb | 9 --- .../reservation_loans_controller.rb | 4 ++ app/forms/reservation_loan_lookup_form.rb | 6 ++ app/helpers/reservations_helper.rb | 2 +- app/lib/reservation_state_machine.rb | 3 +- .../account/reservations/_profile.html.erb | 23 ------- .../admin/reservations/_profile.html.erb | 2 +- .../reservations/check_ins/_form.html.erb | 6 ++ .../check_ins/create.turbo_stream.erb | 19 ++++++ .../reservation_loans/_form.html.erb | 2 +- .../_reservation_hold.html.erb} | 19 +++++- .../reservation_loans/create.turbo_stream.erb | 2 +- .../index.html.erb} | 4 ++ config/initializers/lograge.rb | 2 +- config/routes.rb | 4 +- .../{ => reservations}/reservations_test.rb | 64 ++++++++++++++---- 18 files changed, 183 insertions(+), 57 deletions(-) create mode 100644 app/controllers/admin/reservations/check_ins_controller.rb delete mode 100644 app/controllers/admin/reservations/pickups_controller.rb create mode 100644 app/forms/reservation_loan_lookup_form.rb delete mode 100644 app/views/account/reservations/_profile.html.erb create mode 100644 app/views/admin/reservations/check_ins/_form.html.erb create mode 100644 app/views/admin/reservations/check_ins/create.turbo_stream.erb rename app/views/admin/reservations/{pickups/_reservation_hold.erb => reservation_loans/_reservation_hold.html.erb} (61%) rename app/views/admin/reservations/{pickups/show.html.erb => reservation_loans/index.html.erb} (79%) rename test/system/admin/{ => reservations}/reservations_test.rb (84%) diff --git a/app/controllers/admin/reservations/check_ins_controller.rb b/app/controllers/admin/reservations/check_ins_controller.rb new file mode 100644 index 000000000..c5a6a24bc --- /dev/null +++ b/app/controllers/admin/reservations/check_ins_controller.rb @@ -0,0 +1,67 @@ +module Admin + module Reservations + class CheckInsController < BaseController + def create + if (reservation_item_id = reservation_loan_lookup_params[:reservable_item_id]) + @reservable_item = ReservableItem.find_by(id: reservation_item_id) + if !@reservable_item + render_form_with_error("no item found with this ID") + return + end + @reservation_loan = @reservation.reservation_loans.find_by(reservable_item_id: @reservable_item.id) + elsif (reservation_loan_id = reservation_loan_lookup_params[:reservation_loan_id]) + @reservation_loan = @reservation.reservation_loans.find_by(id: reservation_loan_id) + end + + if !@reservation_loan + render_form_with_error("not found on this reservation") + return + end + + if @reservation_loan.checked_in_at.present? + render_form_with_error("already marked as returned") + return + end + + @reservation_loan.update(checked_in_at: Time.current) + @reservation_hold = @reservation_loan.reservation_hold + end + + def destroy + if (reservation_loan_id = params[:id]) + @reservation_loan = @reservation.reservation_loans.find_by(id: reservation_loan_id) + end + + if !@reservation_loan + render_form_with_error("not found on this reservation") + return + end + + if @reservation_loan.checked_in_at.blank? + render_form_with_error("not marked as returned") + return + end + + @reservation_loan.update(checked_in_at: nil) + @reservation_hold = @reservation_loan.reservation_hold + render :create + end + + private + + def render_form_with_error(message) + @reservation_loan_lookup_form = ReservationLoanLookupForm.new + @reservation_loan_lookup_form.errors.add(:reservable_item_id, message) + render_form + end + + def render_form + render partial: "admin/reservations/check_ins/form", locals: {reservation: @reservation, reservation_loan_lookup_form: @reservation_loan_lookup_form}, status: :unprocessable_entity + end + + def reservation_loan_lookup_params + params.require(:reservation_loan_lookup_form).permit(:reservable_item_id, :reservation_loan_id) + end + end + end +end diff --git a/app/controllers/admin/reservations/pending_reservation_items_controller.rb b/app/controllers/admin/reservations/pending_reservation_items_controller.rb index 12ee392aa..ed68d3cd8 100644 --- a/app/controllers/admin/reservations/pending_reservation_items_controller.rb +++ b/app/controllers/admin/reservations/pending_reservation_items_controller.rb @@ -9,7 +9,7 @@ def update if result.success? render_turbo_response( turbo_stream: turbo_stream.action(:redirect, - admin_reservation_pickup_path(@pending_reservation_item.reservation)) + admin_reservation_loans_path(@pending_reservation_item.reservation)) ) else render_turbo_response :error diff --git a/app/controllers/admin/reservations/pickups_controller.rb b/app/controllers/admin/reservations/pickups_controller.rb deleted file mode 100644 index a6852316d..000000000 --- a/app/controllers/admin/reservations/pickups_controller.rb +++ /dev/null @@ -1,9 +0,0 @@ -module Admin - module Reservations - class PickupsController < BaseController - def show - # eager load reservation_holds: [:item_pool, reservation_loans: :reservable_item] - end - end - end -end diff --git a/app/controllers/admin/reservations/reservation_loans_controller.rb b/app/controllers/admin/reservations/reservation_loans_controller.rb index 58eeafb59..dab837395 100644 --- a/app/controllers/admin/reservations/reservation_loans_controller.rb +++ b/app/controllers/admin/reservations/reservation_loans_controller.rb @@ -3,6 +3,10 @@ module Reservations class ReservationLoansController < BaseController before_action :set_reservation_loan, only: :destroy + def index + # TODO some eager loading? + end + # There are two wolves inside this method. If :reservation_hold_id is passed, it means # that we're creating a ReservationLoan for an ItemPool without uniquely numbered items. # Otherwise, we're creating a ReservationLoan for an individual ReservableItem. diff --git a/app/forms/reservation_loan_lookup_form.rb b/app/forms/reservation_loan_lookup_form.rb new file mode 100644 index 000000000..966835210 --- /dev/null +++ b/app/forms/reservation_loan_lookup_form.rb @@ -0,0 +1,6 @@ +class ReservationLoanLookupForm + include ActiveModel::Model + include ActiveModel::Attributes + + attribute :reservable_item_id +end diff --git a/app/helpers/reservations_helper.rb b/app/helpers/reservations_helper.rb index bb95b0171..5ec1c53dd 100644 --- a/app/helpers/reservations_helper.rb +++ b/app/helpers/reservations_helper.rb @@ -18,7 +18,7 @@ def default_reservation_tab_path(reservation) if manager.requested? || manager.pending? admin_reservation_path(reservation) else - admin_reservation_pickup_path(reservation) + admin_reservation_loans_path(reservation) end end diff --git a/app/lib/reservation_state_machine.rb b/app/lib/reservation_state_machine.rb index 5e2fc5391..67dabe503 100644 --- a/app/lib/reservation_state_machine.rb +++ b/app/lib/reservation_state_machine.rb @@ -14,8 +14,7 @@ event :ready, from: :building, to: :ready event :borrow, from: :ready, to: :borrowed - event :return, from: :borrowed, to: :returned - event :unresolve, from: [:borrowed, :returned], to: :unresolved + event :unresolve, from: :borrowed, to: :unresolved event :resolve, from: :unresolved, to: :returned event :cancel, from: any_state, to: :cancelled diff --git a/app/views/account/reservations/_profile.html.erb b/app/views/account/reservations/_profile.html.erb deleted file mode 100644 index add088ac2..000000000 --- a/app/views/account/reservations/_profile.html.erb +++ /dev/null @@ -1,23 +0,0 @@ -
-
-
-
-
    - <%= icon_stat "user", "org", title: "organization" %> - <%= icon_stat "clock", @reservation.started_at.to_formatted_s(:long), title: "pickup" %> - <%= icon_stat "corner-down-left", @reservation.ended_at.to_formatted_s(:long), title: "return" %> - <%= icon_stat "info", @reservation.status, title: "status" %> -
-
-
-
- -
- - - - <%= yield %> -
diff --git a/app/views/admin/reservations/_profile.html.erb b/app/views/admin/reservations/_profile.html.erb index 66407a81a..3ad715d0a 100644 --- a/app/views/admin/reservations/_profile.html.erb +++ b/app/views/admin/reservations/_profile.html.erb @@ -52,7 +52,7 @@