Email notification of reservation capture
authorJeff Davis <jdavis@sitka.bclibraries.ca>
Tue, 30 Aug 2011 21:03:16 +0000 (14:03 -0700)
committerMike Rylander <mrylander@gmail.com>
Wed, 7 Sep 2011 20:53:38 +0000 (16:53 -0400)
When a reserved resource is captured, Evergreen does not notify the patron
that the resource is ready for pickup. (As far as I am aware this is true
of all versions of Evergreen that include bookings.) This could give rise
to situations where the patron goes to pick up the resource at the specified
time, only to find that it hasn't been captured and is currently unavailable.

This change gives you a checkbox to enable email notification when creating
the reservation, and adds a hook, reactor, and validator so that you can
create an action trigger to send the emails.

Signed-off-by: Mike Rylander <mrylander@gmail.com>
Open-ILS/examples/fm_IDL.xml
Open-ILS/src/perlmods/lib/OpenILS/Application/Booking.pm
Open-ILS/src/perlmods/lib/OpenILS/Application/Trigger/Validator.pm
Open-ILS/src/sql/Pg/095.schema.booking.sql
Open-ILS/src/sql/Pg/950.data.seed-values.sql
Open-ILS/src/sql/Pg/upgrade/XXXX.schema.add-reservation-email-notify.sql [new file with mode: 0644]
Open-ILS/web/js/dojo/openils/booking/nls/reservation.js
Open-ILS/web/js/ui/default/booking/reservation.js
Open-ILS/web/templates/default/booking/reservation.tt2

index cabc99c..3204a80 100644 (file)
@@ -3566,6 +3566,7 @@ SELECT  usr,
                        <field reporter:label="Request Library" name="request_lib" reporter:datatype="link"/>
                        <field reporter:label="Pickup Library" name="pickup_lib" reporter:datatype="link"/>
                        <field reporter:label="Capture Staff" name="capture_staff" reporter:datatype="link"/>
+                       <field reporter:label="Notify by Email?" name="email_notify" reporter:datatype="bool"/>
                        <field reporter:label="Attribute Value Maps" name="attr_val_maps" oils_persist:virtual="true" reporter:datatype="link"/>
                </fields>
                <links>
index 5e75fa8..781bded 100644 (file)
@@ -192,7 +192,7 @@ __PACKAGE__->register_method(
 sub create_bresv {
     my ($self, $client, $authtoken,
         $target_user_barcode, $datetime_range, $pickup_lib,
-        $brt, $brsrc_list, $attr_values) = @_;
+        $brt, $brsrc_list, $attr_values, $email_notify) = @_;
 
     $brsrc_list = [ undef ] if not defined $brsrc_list;
     return undef if scalar(@$brsrc_list) < 1; # Empty list not ok.
@@ -212,6 +212,7 @@ sub create_bresv {
         $bresv->pickup_lib($pickup_lib);
         $bresv->start_time($datetime_range->[0]);
         $bresv->end_time($datetime_range->[1]);
+        $bresv->email_notify(1) if $email_notify;
 
         # A little sanity checking: don't agree to put a reservation on a
         # brsrc and a brt when they don't match.  In fact, bomb out of
@@ -304,6 +305,7 @@ __PACKAGE__->register_method(
             {type => 'int', desc => 'Booking resource type'},
             {type => 'list', desc => 'Booking resource (undef ok; empty not ok)'},
             {type => 'array', desc => 'Attribute values selected'},
+            {type => 'bool', desc => 'Email notification?'},
         ],
         return => { desc => "A hash containing the new bresv and a list " .
             "of new bravm"}
@@ -1097,6 +1099,12 @@ sub capture_reservation {
 
     $e->commit or return $e->die_event;
 
+    # create action trigger event to notify that reservation is available
+    if ($reservation->email_notify) {
+        my $ses = OpenSRF::AppSession->create('open-ils.trigger');
+        $ses->request('open-ils.trigger.event.autocreate', 'reservation.available', $reservation, $reservation->pickup_lib);
+    }
+
     # XXX I'm not sure whether these last two elements of the payload
     # actually get used anywhere.
     $ret->{"resource"} = $reservation->current_resource;
index 98e18cc..54847b3 100644 (file)
@@ -84,6 +84,19 @@ sub HoldIsAvailable {
     return 0;
 }
 
+sub ReservationIsAvailable {
+    my $self = shift;
+    my $env = shift;
+    my $reservation = $env->{target};
+
+    return 1 if
+        !$reservation->cancel_time and
+        $reservation->capture_time and
+        $reservation->current_resource;
+
+    return 0;
+}
+
 sub HoldIsCancelled {
     my $self = shift;
     my $env = shift;
index 6d75582..453057b 100644 (file)
@@ -128,7 +128,8 @@ CREATE TABLE booking.reservation (
        pickup_lib       INT            REFERENCES actor.org_unit(id)
                                        DEFERRABLE INITIALLY DEFERRED,
        capture_staff    INT            REFERENCES actor.usr(id)
-                                       DEFERRABLE INITIALLY DEFERRED
+                                       DEFERRABLE INITIALLY DEFERRED,
+       email_notify     BOOLEAN        NOT NULL DEFAULT FALSE
 ) INHERITS (money.billable_xact);
 
 ALTER TABLE booking.reservation ADD PRIMARY KEY (id);
index d16f77f..a8084a2 100644 (file)
@@ -9797,3 +9797,21 @@ INSERT INTO config.org_unit_setting_type ( name, label, description, datatype )
     'bool'
 );
 
+INSERT INTO action_trigger.hook ( key, core_type, description, passive ) VALUES (
+    'reservation.available',
+    'bresv',
+    'A reservation is available for pickup',
+    false
+);
+
+INSERT INTO action_trigger.validator ( module, description ) VALUES (
+    'ReservationIsAvailable',
+    'Checked that a reserved resource is available for checkout'
+);
+
+INSERT INTO config.org_unit_setting_type ( name, label, description, datatype ) VALUES (
+    'booking.allow_email_notify',
+    'booking.allow_email_notify',
+    'Permit email notification when a reservation is ready for pickup.',
+    'bool'
+);
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.add-reservation-email-notify.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.add-reservation-email-notify.sql
new file mode 100644 (file)
index 0000000..cca875a
--- /dev/null
@@ -0,0 +1,17 @@
+BEGIN;
+
+-- add notify columns to booking.reservation
+ALTER TABLE booking.reservation
+  ADD COLUMN email_notify BOOLEAN NOT NULL DEFAULT FALSE;
+
+-- create the hook and validator
+INSERT INTO action_trigger.hook (key, core_type, description, passive)
+  VALUES ('reservation.available', 'bresv', 'A reservation is available for pickup', false);
+INSERT INTO action_trigger.validator (module, description)
+  VALUES ('ReservationIsAvailable','Checked that a reserved resource is available for checkout');
+
+-- create org unit setting to toggle checkbox display
+INSERT INTO config.org_unit_setting_type (name, label, description, datatype)
+  VALUES ('booking.allow_email_notify', 'booking.allow_email_notify', 'Permit email notification when a reservation is ready for pickup.', 'bool');
+
+COMMIT;
index 8c39198..9b23c58 100644 (file)
@@ -56,5 +56,6 @@
     "AUTO_arbitrary_resource": "Enter the barcode of a cataloged, bookable resource:",
     "AUTO_explain_bookable": "To reserve an item that is not yet registered as a bookable resource, find it in the catalog or under <em>Display Item</em>, and select <em>Make Item Bookable</em> or <em>Book Item Now</em> there.",
     "AUTO_pickup_lib_selector": "Choose the pickup library for this reservation:",
+    "AUTO_email_notify": "Send email notification when resource is available for pickup.",
     "AUTO_or": "- Or -"
 }
index 7893384..fcaf572 100644 (file)
@@ -293,6 +293,7 @@ function create_bresv(resource_list) {
         alert(localeStrings.INVALID_TS_RANGE);
         return;
     }
+    var email_notify = document.getElementById("email_notify").checked ? true : false;
     var results;
     try {
         results = fieldmapper.standardRequest(
@@ -304,7 +305,8 @@ function create_bresv(resource_list) {
                 pickup_lib_selected,
                 our_brt.id(),
                 resource_list,
-                attr_value_table.get_all_values()
+                attr_value_table.get_all_values(),
+                email_notify
             ]
         );
     } catch (E) {
@@ -590,6 +592,10 @@ function init_resv_iface_sel() {
 }
 
 function init_reservation_interface(widget) {
+    /* Show or hide the email notification checkbox depending on org unit setting. */
+    if (!aous_cache["booking.allow_email_notify"]) {
+        hide_dom_element(document.getElementById("contain_email_notify"));
+    }
     /* Save a global reference to the brt we're going to reserve */
     if (widget && (widget.selectedIndex != undefined)) {
         our_brt = brt_list[widget.selectedIndex];
@@ -804,7 +810,7 @@ function init_aous_cache() {
     /* The following method call could be given a longer
      * list of OU settings to fetch in the future if needed. */
     var results = fieldmapper.aou.fetchOrgSettingBatch(
-        openils.User.user.ws_ou(), ["booking.require_successful_targeting"]
+        openils.User.user.ws_ou(), ["booking.require_successful_targeting", "booking.allow_email_notify"]
     );
     if (results && !is_ils_event(results)) {
         for (var k in results) {
index 5eb4a1d..a0edd9d 100644 (file)
                         id="pickup_lib_selector" jsId="pickup_lib_selector"
                         searchAttr="shortname" labelAttr="shortname"></select>
                 </div>
+                <div id="contain_email_notify" class="nice_vertical_padding">
+                    <input type="checkbox" name="email_notify" id="email_notify" />
+                    <label class="AUTO_email_notify" for="email_notify"></label>
+                </div>
                 <div class="nice_vertical_padding">
                     <span class="two_buttons">
                         <input type="button"