From 1ba6e6a51a773dbbc5e896d402842d9b8bc0b6c3 Mon Sep 17 00:00:00 2001 From: Jane Sandberg Date: Tue, 4 Sep 2018 14:31:57 -0700 Subject: [PATCH] LP1790727: Add a daily schedule view of existing bookings To test: 1) Apply this commit. 2) Add some booking resources. The quickest way to do this is to open up a bib record in Holdings View, right click on an item, and Make it Bookable. 3) Add some reservations to those booking resources. A simple way to do this is to go to a patron's record, click Other > Create / Cancel Booking Reservations, and entering the barcodes from step 1. 4) Go to Booking > Daily Schedule. 5) Select the correct Library, Resource, and Date. 6) Make sure that you can view all those reservations you added at step 3. 7) Make sure that pressing Print prints the schedule in a satisfactory way. 8) Make sure that all the advanced options work as expected. Signed-off-by: Jane Sandberg Signed-off-by: Christine Burns --- Open-ILS/src/eg2/src/app/staff/nav.component.html | 4 + .../templates/staff/booking/t_daily_schedule.tt2 | 55 ++++++++ Open-ILS/src/templates/staff/css/booking.css.tt2 | 17 +++ Open-ILS/src/templates/staff/navbar.tt2 | 6 + .../print_templates/t_booking_daily_schedule.tt2 | 20 +++ Open-ILS/web/js/ui/default/staff/booking/app.js | 138 ++++++++++++++++++++- .../Circulation/booking_daily_view.adoc | 7 ++ docs/circulation/booking.adoc | 35 ++++++ 8 files changed, 281 insertions(+), 1 deletion(-) create mode 100644 Open-ILS/src/templates/staff/booking/t_daily_schedule.tt2 create mode 100644 Open-ILS/src/templates/staff/css/booking.css.tt2 create mode 100644 Open-ILS/src/templates/staff/share/print_templates/t_booking_daily_schedule.tt2 create mode 100644 docs/RELEASE_NOTES_NEXT/Circulation/booking_daily_view.adoc diff --git a/Open-ILS/src/eg2/src/app/staff/nav.component.html b/Open-ILS/src/eg2/src/app/staff/nav.component.html index 92209218e6..b83aab514f 100644 --- a/Open-ILS/src/eg2/src/app/staff/nav.component.html +++ b/Open-ILS/src/eg2/src/app/staff/nav.component.html @@ -310,6 +310,10 @@ trending_down Return Reservations + + schedule + Daily Schedule + diff --git a/Open-ILS/src/templates/staff/booking/t_daily_schedule.tt2 b/Open-ILS/src/templates/staff/booking/t_daily_schedule.tt2 new file mode 100644 index 0000000000..41c21cbda6 --- /dev/null +++ b/Open-ILS/src/templates/staff/booking/t_daily_schedule.tt2 @@ -0,0 +1,55 @@ +

[% l('Daily Schedule') %]

+
+
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ +
+
+
+
+ +
+
+
+ + +
+
[% l('Make sure the start time is before the end time') %]
+
+
+
+
+

{{date | date:date_format}}

+
+
+
{{sched.row|date:time_format}}
+
+
+ + [% l('[_1], [_2] [_3]', + '{{r.patron.family_name()}}', + '{{r.patron.first_given_name()}}', + '{{r.patron.second_given_name()}}') %] + [% l('Busy') %] + ({{r.start_time | egOrgDate:'h:mm':context_ou}} - {{r.end_time | egOrgDate: 'h:mm':context_ou}}) + [% l(', ') %] + + +
+
+
+
+
diff --git a/Open-ILS/src/templates/staff/css/booking.css.tt2 b/Open-ILS/src/templates/staff/css/booking.css.tt2 new file mode 100644 index 0000000000..9be08be97e --- /dev/null +++ b/Open-ILS/src/templates/staff/css/booking.css.tt2 @@ -0,0 +1,17 @@ +.schedule-row { + border-top: 1px dotted #777; + height: 30px; +} + +.bg-primary { + height: 30px; +} + +.start-after { + top: 5px; +} + +.end-before { + bottom: 5px; +} + diff --git a/Open-ILS/src/templates/staff/navbar.tt2 b/Open-ILS/src/templates/staff/navbar.tt2 index eb1d4719c6..1add08cc34 100644 --- a/Open-ILS/src/templates/staff/navbar.tt2 +++ b/Open-ILS/src/templates/staff/navbar.tt2 @@ -464,6 +464,12 @@ [% l('Return Reservations') %] +
  • + + + [% l('Daily Schedule') %] + +
  • diff --git a/Open-ILS/src/templates/staff/share/print_templates/t_booking_daily_schedule.tt2 b/Open-ILS/src/templates/staff/share/print_templates/t_booking_daily_schedule.tt2 new file mode 100644 index 0000000000..dfacb244d7 --- /dev/null +++ b/Open-ILS/src/templates/staff/share/print_templates/t_booking_daily_schedule.tt2 @@ -0,0 +1,20 @@ +

    {{barcode}} - {{date | date:date_format}}

    + + + + + +
    {{sched.row|date:time_format}} + + + [% l('[_1], [_2] [_3]', + '{{r.patron.family_name()}}', + '{{r.patron.first_given_name()}}', + '{{r.patron.second_given_name()}}') %] + [% l('Busy') %] + ({{r.start_time | egOrgDate:'h:mm':context_ou}} - {{r.end_time | egOrgDate: 'h:mm':context_ou}}) + + ... + + +
    diff --git a/Open-ILS/web/js/ui/default/staff/booking/app.js b/Open-ILS/web/js/ui/default/staff/booking/app.js index 5f116d1461..da061e70d9 100644 --- a/Open-ILS/web/js/ui/default/staff/booking/app.js +++ b/Open-ILS/web/js/ui/default/staff/booking/app.js @@ -17,6 +17,13 @@ angular.module('egBooking', resolve : resolver }); + // daily view + $routeProvider.when('/booking/daily_schedule', { + templateUrl: './booking/t_daily_schedule', + controller: 'BookingDailyScheduleCtrl', + resolve : resolver + }); + // default page $routeProvider.otherwise({ templateUrl : './t_splash', @@ -24,6 +31,136 @@ angular.module('egBooking', }); }]) +.controller('BookingDailyScheduleCtrl', + ['$scope', 'egCore', 'egOrgDateFilter', + function($scope, egCore, egOrgDateFilter) { + $scope.context_ou = egCore.org.get(egCore.auth.user().ws_ou()); + $scope.date = new Date(); + $scope.date.setHours(0, 0, 0, 0); + $scope.startTime = new Date($scope.date.getTime() + egCore.date.intervalToSeconds('9 hours')); + $scope.endTime = new Date($scope.date.getTime() + egCore.date.intervalToSeconds('17 hours')); + + $scope.date_format = 'mediumDate'; + egCore.org.settings(['format.date']).then(function(set) { + if (set['format.date']) $scope.date_format = set['format.date']; + }); + $scope.time_format = 'shortTime'; + $scope.resource_list = []; + egCore.hatch.getItem('booking.daily_schedule.resource_id') + .then(function(resource_id){ + if (resource_id) $scope.resource = resource_id; + }); + + egCore.hatch.getItem('booking.daily_schedule.show_names') + .then(function(show_names){ + if (show_names) $scope.show_names = show_names; + }); + $scope.on_show_names_changed = function(){ + egCore.hatch.setItem('booking.daily_schedule.show_names', $scope.show_names); + } + + $scope.$watch('startTime',function(newValue,oldValue){ + $scope.fix_date(newValue); + $scope.populate_display(); + }); + $scope.$watch('endTime',function(newValue,oldValue){ + $scope.fix_date(newValue); + $scope.populate_display(); + }); + $scope.$watch('resource',function(newValue,oldValue){ + $scope.populate_display(); + egCore.hatch.setItem('booking.daily_schedule.resource_id', $scope.resource); + }); + $scope.$watch('date',function(newValue,oldValue){ + if ($scope.resource) { + $scope.populate_display(); + } + $scope.guess_display_times(); + $scope.fix_date($scope.startTime); + $scope.fix_date($scope.endTime); + }); + + $scope.fix_date = function(time) { + time.setFullYear($scope.date.getFullYear(), $scope.date.getMonth(), $scope.date.getDate()); + time.setSeconds(0); + } + + $scope.populate_display = function() { + if ($scope.resource) { + egCore.pcrud.search('bresv', + {current_resource: $scope.resource, + start_time: {"<": egOrgDateFilter($scope.endTime, 'yyyy-MM-dd HH:mm:ss', $scope.context_ou)}, + end_time: {">": egOrgDateFilter($scope.startTime, 'yyyy-MM-dd HH:mm:ss', $scope.context_ou)}, + cancel_time: null}, + {flesh: 1, flesh_fields: {'bresv' : ['usr']}}, {atomic: true}).then( + function(response) { + $scope.schedule = [] + var start_distance_from_half_hour = ($scope.startTime.getMinutes() % 30); + var current_working_time = new Date($scope.startTime.getTime()); + $scope.fix_date(current_working_time); + var working_end_time = new Date($scope.endTime.getTime()); + $scope.fix_date(working_end_time); + var next_working_time = new Date(current_working_time.getTime()); + do { + next_working_time.setMinutes(current_working_time.getMinutes() + ((current_working_time.getMinutes() % 30) ? (30 - (current_working_time.getMinutes() % 30)) : 30)); + var reservations = []; + angular.forEach(response, function (r) { + rs = new Date(r.start_time()); + re = new Date(r.end_time()); + if ((rs < next_working_time) && (re > current_working_time)) { + reservation = {patron: r.usr(), end_time: re}; + reservation.continuation = (rs < current_working_time) ? true : false; + reservation.ends_early = (re < next_working_time) ? true : false; + reservation.starts_late = (rs > current_working_time) ? true : false; + reservation.start_time = (rs >= current_working_time) ? rs : undefined; + reservations.push(reservation); + }}) + $scope.schedule.push({'row': current_working_time.getTime(), 'reservations': reservations}); + current_working_time.setTime(next_working_time.getTime()); + } while (current_working_time < working_end_time) + })}}; + + $scope.print_schedule = function() { + print_data = { schedule: $scope.schedule, + show_names: $scope.show_names, + time_format: $scope.time_format, + date_format: $scope.date_format, + date: $scope.date, + barcode: egCore.idl.toHash($scope.resource_list).find(r => {return r.id == $scope.resource}).barcode } + return egCore.print.print({ + template : 'booking_daily_schedule', + scope: print_data + }); + } + + $scope.get_booking_resources = function() { + egCore.pcrud.search('brsrc', {owner: $scope.context_ou.id()}, {}, {atomic: true}) + .then(function(list) { + $scope.resource_list = list; + }); + }; + + $scope.handle_changed_ou = function () { + $scope.guess_display_times(); + $scope.get_booking_resources(); + } + + $scope.guess_display_times = function() { + var selected_day = $scope.date.getDay(); + egCore.pcrud.retrieve('aouhoo', $scope.context_ou.id()).then(function(hours){ + $scope.hours = hours; + selected_day_eg_style = (selected_day + 6) % 7; + o = ($scope.$eval("hours.dow_" + selected_day_eg_style + "_open()")).split(':'); + c = ($scope.$eval("hours.dow_" + selected_day_eg_style + "_close()")).split(':'); + $scope.startTime = new Date($scope.date.getTime()); + $scope.startTime.setSeconds(egCore.date.intervalToSeconds(o[0] + ' hours') + egCore.date.intervalToSeconds(o[1] + ' minutes')); + $scope.endTime = new Date($scope.date.getTime()); + $scope.endTime.setSeconds(egCore.date.intervalToSeconds(c[0] + ' hours') + egCore.date.intervalToSeconds(c[1] + ' minutes')); + }); + } + +}]) + .controller('EmbedBookingCtl', ['$scope','$routeParams','$location','egCore', function($scope , $routeParams , $location , egCore) { @@ -43,4 +180,3 @@ function($scope , $routeParams , $location , egCore) { console.log('Loading Booking URL: ' + $scope.booking_url); }]) - diff --git a/docs/RELEASE_NOTES_NEXT/Circulation/booking_daily_view.adoc b/docs/RELEASE_NOTES_NEXT/Circulation/booking_daily_view.adoc new file mode 100644 index 0000000000..242a3f1205 --- /dev/null +++ b/docs/RELEASE_NOTES_NEXT/Circulation/booking_daily_view.adoc @@ -0,0 +1,7 @@ +Booking Daily Schedule +^^^^^^^^^^^^^^^^^^^^^^ + +The booking module now includes a schedule view, where users can view and print all the reservations +on a particular resource for a particular day. This feature is specifically designed for libraries +that use the booking module to handle room reservations. + diff --git a/docs/circulation/booking.adoc b/docs/circulation/booking.adoc index 18a62ae1a2..cbc500b6f6 100644 --- a/docs/circulation/booking.adoc +++ b/docs/circulation/booking.adoc @@ -263,9 +263,44 @@ Cancel a reservation on reservation creation screen 5) Select those that you want to cancel, then click Cancel Selected. +Daily Schedule +~~~~~~~~~~~~~~ +indexterm:[bookings,daily schedule] +indexterm:[daily schedule] +indexterm:[reservations,daily schedule] +.Use case +**** +The Daily Schedule can be helpful for printing out a list of room reservations, +or for seeing how much a particular resource is being used on a particular day. +**** + +To print the daily schedule for a particular resource and day: + +. Go to Booking -> Daily Schedule. +. Select the library you're interested in viewing. +. Select the barcode of the resource that you'd like to view. +. Select the date that you'd like to view. +. When you are satisfied with the display, you can press the Print button to +print your schedule. + +[TIP] +To protect patron privacy, you can anonymize the reservations by clicking the +_Show advanced options_ button, then unchecking the Show Patron Names checkbox. + +Changing hours for the daily schedule +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +By default, the daily schedule displays the times that your library is +marked as open. To change the hours, click the _Show advanced options_ +button, then use the time pickers to change the display times. + +[NOTE] +An administrator can change the hours that your Library is marked as open +by going to Administration -> Server Administration -> Organizational Units. + -- 2.11.0