return [map { $_->{id} } @$rows];
}
}
+
+
__PACKAGE__->register_method(
method => "resource_list_by_attrs",
api_name => "open-ils.booking.resources.filtered_id_list",
$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",
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;
}
+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;
}
.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 -%]
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 {
[% 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
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;
[% 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 */
--- /dev/null
+[% PROCESS "opac/parts/header.tt2";
+ PROCESS "opac/parts/misc_util.tt2";
+ WRAPPER "opac/parts/myopac/base.tt2";
+ myopac_page = "reservations";
+%]
+<h3 class="sr-only">[% l('Reservations') %]</h3>
+[% IF ctx.reservations.size %]
+ <table id="acct_reservations_main_header" class="table_no_border_space table_no_cell_pad item_list_padding">
+ <tr>
+ <th scope="col">[% l('Resource type') %]</th>
+ <th scope="col">[% l('Reservation start time') %]</th>
+ <th scope="col">[% l('Reservation end time') %]</th>
+ <th scope="col">[% l('Pickup location') %]</th>
+ <th scope="col">[% l('Status') %]</th>
+ </tr>
+ [% FOREACH r IN ctx.reservations %]
+ <tr>
+ <td>[% r.resource_type_name %]</td>
+ <td>[% date.format(ctx.parse_datetime(r.start_time, r.pickup_lib), DATE_FORMAT _ ' %I:%M %p') %]</td>
+ <td>[% date.format(ctx.parse_datetime(r.end_time, r.pickup_lib), DATE_FORMAT _ ' %I:%M %p') %]</td>
+ <td><a href="../library/[% r.shortname %]">[% r.pickup_name %]</a></td>
+ <td>
+ [% 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 %]
+ </td>
+ </tr>
+ [% END %]
+ </table>
+[% ELSE %]
+ [% l('You have no current reservations') %]
+[% END %]
+[% END %]
{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 = "../"
%]
--- /dev/null
+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.
+
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.
+====================
+