From a28f18e1b40bc8577cdc353cfb6732e26d964953 Mon Sep 17 00:00:00 2001 From: Jane Sandberg Date: Mon, 15 Oct 2018 12:00:00 -0500 Subject: [PATCH] LP1797934: Add a patron's booking reservations to their OPAC account This commit creates a new tab in the patron OPAC account area where a patron can view their current bookings. Signed-off-by: Jane Sandberg Signed-off-by: Remington Steed Signed-off-by: Dan Wells --- .../lib/OpenILS/Application/Booking.pm | 55 +++++++++++++++++++ .../perlmods/lib/OpenILS/WWW/EGCatLoader.pm | 1 + .../lib/OpenILS/WWW/EGCatLoader/Account.pm | 14 +++++ Open-ILS/src/templates/opac/css/style.css.tt2 | 14 ++--- .../templates/opac/myopac/reservations.tt2 | 39 +++++++++++++ .../src/templates/opac/parts/myopac/base.tt2 | 3 +- .../add_booking_reservations_to_opac.adoc | 13 +++++ docs/opac/my_account.adoc | 21 +++++++ 8 files changed, 152 insertions(+), 8 deletions(-) create mode 100644 Open-ILS/src/templates/opac/myopac/reservations.tt2 create mode 100644 docs/RELEASE_NOTES_NEXT/OPAC/add_booking_reservations_to_opac.adoc diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Booking.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Booking.pm index 09680b8331..a715f88259 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Booking.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Booking.pm @@ -455,6 +455,8 @@ sub resource_list_by_attrs { return [map { $_->{id} } @$rows]; } } + + __PACKAGE__->register_method( method => "resource_list_by_attrs", api_name => "open-ils.booking.resources.filtered_id_list", @@ -600,6 +602,59 @@ sub reservation_list_by_filters { $e->disconnect; return $bresv_list ? $bresv_list : []; } + +__PACKAGE__->register_method( + method => "upcoming_reservation_list_by_user", + api_name => "open-ils.booking.reservations.upcoming_reservation_list_by_user", + argc => 2, + signature=> { + params => [ + {type => 'string', desc => 'Authentication token'}, + {type => 'User ID', type => 'number', desc => 'User ID'}, + ], + return => { desc => "Information about all reservations for a user that haven't yet ended." }, + }, + notes => "You can send undef/NULL as the User ID to get reservations for the logged in user." +); + +sub upcoming_reservation_list_by_user { + my ($self, $conn, $auth, $user_id) = @_; + my $e = new_editor(authtoken => $auth); + return $e->event unless $e->checkauth; + + $user_id = $e->requestor->id unless defined $user_id; + + unless($e->requestor->id == $user_id) { + my $user = $e->retrieve_actor_user($user_id) or return $e->event; + return $e->event unless $e->allowed('VIEW_TRANSACTION'); + } + + my $select = { 'bresv' => [qw/start_time end_time cancel_time capture_time pickup_time pickup_lib/], + 'brsrc' => [ 'barcode' ], + 'brt' => [{'column' => 'name', 'alias' => 'resource_type_name'}], + 'aou' => ['shortname', {'column' => 'name', 'alias' => 'pickup_name'}] }; + + my $from = { 'bresv' => {'brsrc' => {'field' => 'id', 'fkey' => 'current_resource'}, + 'brt' => {'field' => 'id', 'fkey' => 'target_resource_type'}, + 'aou' => {'field' => 'id', 'fkey' => 'pickup_lib'}} }; + + my $query = { + 'select' => $select, + 'from' => $from, + 'where' => { 'usr' => $user_id, 'return_time' => undef, 'end_time' => {'>' => gmtime_ISO8601() }}, + 'order_by' => [{ class => bresv => field => start_time => direction => 'asc' }] + }; + + my $cstore = OpenSRF::AppSession->connect('open-ils.cstore'); + my $rows = $cstore->request( + 'open-ils.cstore.json_query.atomic', $query + )->gather(1); + $cstore->disconnect; + $e->disconnect; + return [] if not @$rows; + return $rows; +} + __PACKAGE__->register_method( method => "reservation_list_by_filters", api_name => "open-ils.booking.reservations.filtered_id_list", diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm index 2bf6704742..19a3b258a8 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm @@ -229,6 +229,7 @@ sub load { return $self->load_myopac_prefs_settings if $path =~ m|opac/myopac/prefs_settings|; return $self->load_myopac_prefs_my_lists if $path =~ m|opac/myopac/prefs_my_lists|; return $self->load_myopac_prefs if $path =~ m|opac/myopac/prefs|; + return $self->load_myopac_reservations if $path =~ m|opac/myopac/reservations|; return $self->load_sms_cn if $path =~ m|opac/sms_cn|; return Apache2::Const::OK; diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm index 19e8fbc538..3ec7900939 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm @@ -2886,6 +2886,20 @@ sub load_myopac_circ_history_export { } +sub load_myopac_reservations { + my $self = shift; + my $e = $self->editor; + my $ctx = $self->ctx; + + my $upcoming = $U->simplereq("open-ils.booking", "open-ils.booking.reservations.upcoming_reservation_list_by_user", + $e->authtoken, undef + ); + + $ctx->{reservations} = $upcoming; + return Apache2::Const::OK; + +} + sub load_password_reset { my $self = shift; my $cgi = $self->cgi; diff --git a/Open-ILS/src/templates/opac/css/style.css.tt2 b/Open-ILS/src/templates/opac/css/style.css.tt2 index 31bd8171fd..6c1dc7070d 100644 --- a/Open-ILS/src/templates/opac/css/style.css.tt2 +++ b/Open-ILS/src/templates/opac/css/style.css.tt2 @@ -1381,13 +1381,13 @@ div.result_table_utils_cont { } .hold_note_title { font-weight: bold; } -#acct_checked_main_header td, #acct_holds_main_header td, #acct_fines_main_header td, #acct_fines_confirm_header td, #acct_fees_main_header td,#acct_checked_hist_header td, #acct_holds_hist_header td, #acct_list_header td, #acct_list_header_anon td, #temp_list_holds td, #acct_messages_main_header td, #ebook_circs_main_table td, #ebook_holds_main_table td { +#acct_checked_main_header td, #acct_holds_main_header td, #acct_fines_main_header td, #acct_fines_confirm_header td, #acct_fees_main_header td,#acct_checked_hist_header td, #acct_holds_hist_header td, #acct_list_header td, #acct_list_header_anon td, #temp_list_holds td, #acct_messages_main_header td, #ebook_circs_main_table td, #ebook_holds_main_table td, #acct_reservations_main_header td { background-color: [% css_colors.background %]; padding: 10px; border: 1px solid #d3d3d3; } -#acct_checked_main_header th, #acct_holds_main_header th, #acct_fines_main_header th, #acct_fines_confirm_header th, #acct_fees_main_header th, #acct_checked_hist_header th, #acct_holds_hist_header th, #acct_list_header th, #acct_list_header_anon th, #temp_list_holds th, #acct_messages_main_header th, #ebook_holds_main_table th { +#acct_checked_main_header th, #acct_holds_main_header th, #acct_fines_main_header th, #acct_fines_confirm_header th, #acct_fees_main_header th, #acct_checked_hist_header th, #acct_holds_hist_header th, #acct_list_header th, #acct_list_header_anon th, #temp_list_holds th, #acct_messages_main_header th, #ebook_holds_main_table th, #acct_reservations_main_header th { [% IF rtl == 't' -%] text-align: right; [% ELSE -%] @@ -3123,7 +3123,7 @@ a.preflib_change { border-bottom: none; } /* Force table to not be like tables anymore */ - table#acct_checked_main_header thead tr th, table#acct_holds_main_header thead tr th, table#acct_checked_hist_header thead tr th, table#acct_holds_hist_header thead tr th, table#ebook_circs_main_table thead tr th, table#ebook_holds_main_table thead tr th { + table#acct_checked_main_header thead tr th, table#acct_holds_main_header thead tr th, table#acct_checked_hist_header thead tr th, table#acct_holds_hist_header thead tr th, table#ebook_circs_main_table thead tr th, table#ebook_holds_main_table thead tr th, table#acct_reservations_main_header tr th{ display: block; } table#acct_checked_main_header tbody tr td, table#acct_holds_main_header tbody tr td, table#acct_checked_hist_header tbody tr td, table#acct_holds_hist_header tbody tr td, table#ebook_circs_main_table tbody tr td, table#ebook_holds_main_table tbody tr td { @@ -3141,11 +3141,11 @@ a.preflib_change { [% END -%] } - table#acct_checked_main_header, table#acct_holds_main_header, table#acct_checked_hist_header, table#acct_holds_hist_header, table#ebook_circs_main_table, table#ebook_holds_main_table { + table#acct_checked_main_header, table#acct_holds_main_header, table#acct_checked_hist_header, table#acct_holds_hist_header, table#ebook_circs_main_table, table#ebook_holds_main_table, table#acct_reservations_main_header { width: 90%; } - table#acct_checked_main_header tr, table#acct_holds_main_header tr, table#acct_checked_hist_header tr { border: 1px solid #ddd; } + table#acct_checked_main_header tr, table#acct_holds_main_header tr, table#acct_checked_hist_header tr, table#acct_reservations_main_header { border: 1px solid #ddd; } /* Holds history gets large white border to mimic header cell on other account screens that provide visual cue for next title. We should do @@ -3156,7 +3156,7 @@ a.preflib_change { table#acct_holds_hist_header tr, table#ebook_circs_main_table tr, table#ebook_holds_main_table tr { border-top: 25px solid #fff; } - table#acct_checked_main_header td, table#acct_holds_main_header td, table#acct_checked_hist_header td, table#acct_holds_hist_header td, table#ebook_circs_main_table td, table#ebook_holds_main_table td { + table#acct_checked_main_header td, table#acct_holds_main_header td, table#acct_checked_hist_header td, table#acct_holds_hist_header td, table#ebook_circs_main_table td, table#ebook_holds_main_table td, table#acct_reservations_main_header td { /* Behave like a "row" */ border: none; border-bottom: 1px solid #eee; @@ -3168,7 +3168,7 @@ a.preflib_change { [% END -%] } - table#acct_checked_main_header td:before, table#acct_holds_main_header td:before, table#acct_checked_hist_header td:before, table#acct_holds_hist_header td:before, table#ebook_circs_main_table td:before, table#ebook_holds_main_table td:before { + table#acct_checked_main_header td:before, table#acct_holds_main_header td:before, table#acct_checked_hist_header td:before, table#acct_holds_hist_header td:before, table#ebook_circs_main_table td:before, table#ebook_holds_main_table td:before, table#acct_reservations_main_header td { /* Now like a table header */ position: absolute; /* Top/left values mimic padding */ diff --git a/Open-ILS/src/templates/opac/myopac/reservations.tt2 b/Open-ILS/src/templates/opac/myopac/reservations.tt2 new file mode 100644 index 0000000000..d134246f30 --- /dev/null +++ b/Open-ILS/src/templates/opac/myopac/reservations.tt2 @@ -0,0 +1,39 @@ +[% PROCESS "opac/parts/header.tt2"; + PROCESS "opac/parts/misc_util.tt2"; + WRAPPER "opac/parts/myopac/base.tt2"; + myopac_page = "reservations"; +%] +

[% l('Reservations') %]

+[% IF ctx.reservations.size %] + + + + + + + + + [% FOREACH r IN ctx.reservations %] + + + + + + + + [% END %] +
[% l('Resource type') %][% l('Reservation start time') %][% l('Reservation end time') %][% l('Pickup location') %][% l('Status') %]
[% r.resource_type_name %][% date.format(ctx.parse_datetime(r.start_time, r.pickup_lib), DATE_FORMAT _ ' %I:%M %p') %][% date.format(ctx.parse_datetime(r.end_time, r.pickup_lib), DATE_FORMAT _ ' %I:%M %p') %][% r.pickup_name %] + [% IF r.cancel_time %] + [% l('Canceled') %] + [% ELSIF r.pickup_time %] + [% l('Checked Out') %] + [% ELSIF r.capture_time %] + [% l('Ready for Pickup') %] + [% ELSE %] + [% l('Reserved') %] + [% END %] +
+[% ELSE %] + [% l('You have no current reservations') %] +[% END %] +[% END %] diff --git a/Open-ILS/src/templates/opac/parts/myopac/base.tt2 b/Open-ILS/src/templates/opac/parts/myopac/base.tt2 index 15cf56e628..2153a1d358 100644 --- a/Open-ILS/src/templates/opac/parts/myopac/base.tt2 +++ b/Open-ILS/src/templates/opac/parts/myopac/base.tt2 @@ -6,7 +6,8 @@ {url => "circs", name => l("Items Checked Out")}, {url => "holds", name => l("Holds")}, {url => "prefs", name => l("Account Preferences")}, - {url => "lists", name => l("My Lists")} + {url => "lists", name => l("My Lists")}, + {url => "reservations", name => l("Reservations")} ]; skin_root = "../" %] diff --git a/docs/RELEASE_NOTES_NEXT/OPAC/add_booking_reservations_to_opac.adoc b/docs/RELEASE_NOTES_NEXT/OPAC/add_booking_reservations_to_opac.adoc new file mode 100644 index 0000000000..fb724c3885 --- /dev/null +++ b/docs/RELEASE_NOTES_NEXT/OPAC/add_booking_reservations_to_opac.adoc @@ -0,0 +1,13 @@ +View upcoming booking reservations in the OPAC +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A new tab in the My Account section of the OPAC shows +patrons information about reservations on their account. +Here, patrons can check on upcoming reservations, as +well as reservations they currently have checked out. + +Note: this interface pulls its timezone from the Library +Settings Editor. Make sure that you have a timezone +listed for your library in the Library Settings Editor +before using this feature. + diff --git a/docs/opac/my_account.adoc b/docs/opac/my_account.adoc index 240e6ab31f..3366eccb7a 100644 --- a/docs/opac/my_account.adoc +++ b/docs/opac/my_account.adoc @@ -270,3 +270,24 @@ image::media/message_center12.PNG[Message Center 12] NOTE: Patron deleted messages will still appear in the patron's account in the staff client under Other -> Message Center. + +Reservations +^^^^^^^^^^^^ + +When patrons place a reservation for a particular item at a particular time, +they can check on its status using the *Reservations* tab. + +After they initially place a reservation, its status will display as _Reserved_. +After staff capture the reservation, the status will change to _Ready for Pickup_. +After the patron picks up the reservation, the status will change to _Checked Out_. +Finally, after the patron returns the item, the reservation will be removed from +the list. + +[NOTE] +==================== +This interface pulls its timezone from the Library +Settings Editor. Make sure that you have a timezone +listed for your library in the Library Settings Editor +before using this feature. +==================== + -- 2.43.2