LP#1772680: Implementation of Checkout, Hold, and other enhancements
authorJaswinder Singh <Jaswinder.Singh0011@gmail.com>
Mon, 18 Jun 2018 05:06:31 +0000 (01:06 -0400)
committerGalen Charlton <gmc@equinoxinitiative.org>
Tue, 4 Jun 2019 21:32:47 +0000 (17:32 -0400)
Signed-off-by: Jaswinder Singh <jaswinder.singh0011@gmail.com>
Signed-off-by: Galen Charlton <gmc@equinoxinitiative.org>
Open-ILS/src/perlmods/lib/OpenILS/Application/EbookAPI.pm
Open-ILS/src/perlmods/lib/OpenILS/Application/EbookAPI/RBDigital.pm
Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/RBDigitalRecord.pm
Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/RBDigitalSearch.pm
Open-ILS/src/templates/opac/ebook_api/rbdigital/parts/item_parser.tt2
Open-ILS/src/templates/opac/ebook_api/rbdigital/parts/record/summary.tt2
Open-ILS/src/templates/opac/ebook_api/rbdigital/parts/result/table.tt2
Open-ILS/src/templates/opac/ebook_api/rbdigital/record.tt2
Open-ILS/src/templates/opac/ebook_api/rbdigital/results.tt2
Open-ILS/web/js/ui/default/opac/ebook_api/ebook.js
Open-ILS/web/js/ui/default/opac/ebook_api/rbdigital.js

index 3db3d36..e80e079 100755 (executable)
@@ -536,15 +536,15 @@ sub do_xact {
     $logger->info("EbookAPI: doing $action for title $title_id...");
 
     # verify that user is authenticated in EG
-    my $e = new_editor(authtoken => $auth);
-    if (!$e->checkauth) {
-        $logger->error("EbookAPI: authentication failed: " . $e->die_event);
+    my $editor = new_editor(authtoken => $auth);
+    if (!$editor->checkauth) {
+        $logger->error("EbookAPI: authentication failed: " . $editor->die_event);
         return;
     }
 
     my $handler = new_handler($session_id);
 
-    my $user_token = _get_user_token($handler, $e, $barcode);
+    my $user_token = _get_user_token($handler, $editor, $barcode);
 
     # handler method constructs and submits request (and handles any external authentication)
     my $res;
@@ -557,6 +557,8 @@ sub do_xact {
     } else {
         $res = $handler->$action($title_id, $user_token);
     }
+
+
     if (defined ($res)) {
         return $res;
     } else {
@@ -564,6 +566,7 @@ sub do_xact {
         return;
     }
 }
+
 __PACKAGE__->register_method(
     method => 'do_xact',
     api_name => 'open-ils.ebook_api.checkout',
@@ -777,6 +780,7 @@ sub _get_patron_xacts {
     }
 }
 
+
 # Call this method to retrieve the user token/patron id
 sub _get_user_token {
     my ($handler, $editor, $barcode)  = @_;
@@ -1288,7 +1292,6 @@ __PACKAGE__->register_method(
     }
 );
 
-
 __PACKAGE__->register_method(
     method    => "do_wishlist",
     api_name  => "open-ils.ebook_api.patron.wishlist",
@@ -1349,7 +1352,7 @@ sub do_wishlist {
     } elsif ($action eq 'delete') {
         return $handler->delete_from_wishlist($patron_id, $isbn);
     } elsif ($action eq 'get') {
-        return $handler->get_wishlist($patron_id, $isbn);
+        return $handler->get_wishlist($patron_id);
     }
 
     $logger->error("EbookAPI: unsupported wishlist action requested");
@@ -1721,4 +1724,5 @@ __PACKAGE__->register_method(
         }
     }
 );
+
 1;
index 2d2cba1..ddfedc7 100755 (executable)
@@ -173,6 +173,7 @@ sub do_patron_auth {
     my ($self, $username, $email) = @_;
     my $patron_id = 0;
 
+
     if ($email) {
         # first try to authenticate the user with a email
         $patron_id = $self->_get_patron_id($email);
@@ -482,34 +483,34 @@ sub get_title_summary {
     return undef;
 }
 
-# GET //api.{domain}/v1/libraries/$library_id/patron-books/Wishlist/$isbn
+# GET //api.{domain}/v1/libraries/$library_id/patrons/$patron_id/wishlist
 sub get_wishlist {
-    my ($self, $patron_id, $isbn) = @_;
+    my ($self, $patron_id) = @_;
     my $base_uri = $self->{base_uri};
     my $library_id = $self->{library_id};
     my $session_id = $self->{session_id};
     my $req;
     
-    $logger->error("EbookAPI: Getting wishlist for ISBN: $isbn from RBDigital.");
+    $logger->error("EbookAPI: Getting wishlist for Patron: $patron_id from RBDigital.");
     $req = {
         method => 'GET',
-        uri    => "$base_uri/libraries/$library_id/patron-books/Wishlist/$isbn",
+        uri    => "$base_uri/libraries/$library_id/patrons/$patron_id/wishlist",
         headers => {
             'Authorization' => 'Basic ' . $self->{basic_token}
         }
     };
 
     my $res = $self->request($req, $session_id);
-    if (defined($res)) {
+    if (defined($res) && $res->{is_success}) {
         return $res;
     } else {
-        $logger->error("EbookAPI: could not get ISBN: $isbn from RBDigital portal.");
+        $logger->error("EbookAPI: could not get patron wishlist from RBDigital portal.");
     }
 
     return undef;
 }
 
-# POST //api.{domain}/v1/libraries/$library_id/patron-books/Wishlist/$isbn
+# POST //api.{domain}/v1/libraries/$library_id/patrons/$patron_id/books/wishlist/$isbn
 sub add_to_wishlist {
     my ($self, $patron_id, $isbn) = @_;
     my $base_uri = $self->{base_uri};
@@ -520,7 +521,7 @@ sub add_to_wishlist {
     $logger->error("EbookAPI: Adding ISBN: $isbn to a RBDigital wishlist.");
     $req = {
         method => 'POST',
-        uri    => "$base_uri/libraries/$library_id/patrons/$patron_id/books/Wishlist/$isbn",
+        uri    => "$base_uri/libraries/$library_id/patrons/$patron_id/books/wishlist/$isbn",
         headers => {
             'Authorization' => 'Basic ' . $self->{basic_token},
             'Content-Length' => '0'
@@ -543,7 +544,7 @@ sub add_to_wishlist {
     return { message => "Vendor API error" };
 }
 
-# POST //api.{domain}/v1/libraries/$library_id/patron-books/Wishlist/$isbn
+# DELETE //api.{domain}/v1/libraries/$library_id/patrons/$patrong_id/wishlist/$isbn
 sub delete_from_wishlist {
     my ($self, $patron_id, $isbn) = @_;
     my $base_uri = $self->{base_uri};
@@ -554,7 +555,7 @@ sub delete_from_wishlist {
     $logger->error("EbookAPI: Removing ISBN: $isbn from a RBDigital wishlist.");
     $req = {
         method => 'DELETE',
-        uri    => "$base_uri/libraries/$library_id/patrons/$patron_id/books/Wishlist/$isbn",
+        uri    => "$base_uri/libraries/$library_id/patrons/$patron_id/books/wishlist/$isbn",
         headers => {
             'Authorization' => 'Basic ' . $self->{basic_token}
         }
@@ -649,7 +650,7 @@ sub checkout {
     my $req;
     $req = {
         method => 'POST',
-        uri    => "$base_uri/libraries/$library_id/patrons/$patron_id/books/checkouts/$isbn",
+        uri    => "$base_uri/libraries/$library_id/patrons/$patron_id/books/checkout/$isbn",
         headers => {
             'Authorization' => 'Basic ' . $self->{basic_token},
             'Content-Length' => '0'
@@ -657,14 +658,12 @@ sub checkout {
     };
     
     my $res = $self->request($req, $session_id);
-
-    # HTTP 200 response indicates success, HTTP 409 indicates checkout limit reached
     if (defined ($res)) {
         if ($res->{is_success}) {
-            return $res;
+            return $res->{content};
         } else {
             $logger->error("EbookAPI: checkout failed for RBDigital title $isbn");
-            return { error_msg => $res->{content} };
+            return $res->{content};
         }
     } else {
         $logger->error("EbookAPI: no response received from RBDigital server");
@@ -737,37 +736,106 @@ sub checkin {
     }
 }
 
+# POST //api.{domain}/v1/libraries/$library_id/patrons/$patron_id/books/hold/$isbn
 sub place_hold {
+    my ($self, $isbn, $patron_id, $param) = @_;
+    my $base_uri = $self->{base_uri};
+    my $library_id = $self->{library_id};
+    my $session_id = $self->{session_id};
+    my $req;
+    
+    $logger->info("EbookAPI: Placing ISBN: $isbn to a RBDigital hold list.");
+    $req = {
+        method => 'POST',
+        uri    => "$base_uri/libraries/$library_id/patrons/$patron_id/books/hold/$isbn",
+        headers => {
+            'Authorization' => 'Basic ' . $self->{basic_token},
+            'Content-Length' => '0'
+        }
+    };
+
+    my $res = $self->request($req, $session_id);
+
+    if (defined ($res)) {
+        if ($res->{is_success}) {
+            return $res->{content};
+        } else {
+            $logger->error("EbookAPI: could not place ISBN: $isbn on hold at RBDigital portal: ".$res->{content}->{message});
+            return $res->{content};
+        }
+    } else {
+        $logger->error("EbookAPI: no response received from RBDigital server.");
+    }
+
+    return { message => "Vendor API error" };
 }
 
 sub cancel_hold {
+    my ($self, $isbn, $patron_id, $param) = @_;
+    my $base_uri = $self->{base_uri};
+    my $library_id = $self->{library_id};
+    my $session_id = $self->{session_id};
+    my $req;
+    
+    $logger->info("EbookAPI: Removing ISBN: $isbn from RBDigital hold list.");
+    $req = {
+        method => 'DELETE',
+        uri    => "$base_uri/libraries/$library_id/patrons/$patron_id/books/hold/$isbn",
+        headers => {
+            'Authorization' => 'Basic ' . $self->{basic_token},
+            'Content-Length' => '0'
+        }
+    };
+
+    my $res = $self->request($req, $session_id);
+
+    if (defined ($res)) {
+        if ($res->{is_success}) {
+            return $res->{content};
+        } else {
+            $logger->error("EbookAPI: could not cancel hold for ISBN: $isbn on RBDigital portal: ".$res->{content}->{message});
+            return $res->{content};
+        }
+    } else {
+        $logger->error("EbookAPI: no response received from RBDigital server.");
+    }
+
+    return { message => "Vendor API error" };
 }
 
-# GET //api.{domain}/v1/libraries/{libraryId}/patrons/{patronId}/checkouts/all
+# GET //api.{domain}/v1/libraries/$library_id/patrons/$patron_id/checkouts
 sub get_patron_checkouts {
     my ($self, $patron_id) = @_;
     my $base_uri = $self->{base_uri};
     my $library_id = $self->{library_id};
     my $session_id = $self->{session_id};
-    my $req = {
+    my $req;
+    
+    $logger->info("EbookAPI: Getting checkout list for Patron: $patron_id from RBDigital.");
+    $req = {
         method => 'GET',
-        uri    => "$base_uri/libraries/$library_id/patrons/$patron_id/checkouts/all"
+        uri    => "$base_uri/libraries/$library_id/patrons/$patron_id/checkouts",
+        headers => {
+            'Authorization' => 'Basic ' . $self->{basic_token}
+        }
     };
+
     my $res = $self->request($req, $session_id);
 
     my $checkouts = [];
     if (defined ($res)) {
-        $logger->info("EbookAPI: received response for RBDigital checkouts: " . Dumper $res);
+        $logger->debug("EbookAPI: received response for RBDigital checkouts: " . Dumper($res));
         foreach my $checkout (@{$res->{content}}) {
             push @$checkouts, {
                 xact_id => $checkout->{transactionId},
                 title_id => $checkout->{isbn},
                 due_date => $checkout->{expiration},
-                download_url => $checkout->{downloadUrl},
+                download_url => $checkout->{files}->[0]->{downloadUrl},
                 title => $checkout->{title},
                 author => $checkout->{authors}
             };
         };
+
         $logger->info("EbookAPI: retrieved " . scalar(@$checkouts) . " RBDigital checkouts for patron $patron_id");
         $self->{checkouts} = $checkouts;
         return $self->{checkouts};
@@ -775,9 +843,12 @@ sub get_patron_checkouts {
         $logger->error("EbookAPI: failed to retrieve RBDigital checkouts for patron $patron_id");
         return;
     }
+
+    return undef;
 }
 
-# GET //api.{domain}/v1/libraries/{libraryId}/patrons/{patronId}/holds/all
+
+# GET //api.{domain}/v1/libraries/{libraryId}/patrons/{patronId}/holds
 sub get_patron_holds {
     my ($self, $patron_id) = @_;
     my $base_uri = $self->{base_uri};
@@ -785,7 +856,10 @@ sub get_patron_holds {
     my $session_id = $self->{session_id};
     my $req = {
         method => 'GET',
-        uri    => "$base_uri/libraries/$library_id/patrons/$patron_id/holds/all"
+        uri    => "$base_uri/libraries/$library_id/patrons/$patron_id/holds",
+        headers => {
+            'Authorization' => 'Basic ' . $self->{basic_token}
+        }
     };
     my $res = $self->request($req, $session_id);
 
@@ -1047,16 +1121,13 @@ sub save_search_field_values {
     my $ebook_rsfm_req = $pcrud->request('open-ils.pcrud.search.ebook_rsfm.atomic', "ANONYMOUS",
         {
             search_fields_id => $search_fields_id,
-            digital_services_field_code => $digital_services_field_code
+            digital_services_field_code => $digital_services_field_code,
+            evergreen_field_code => $evergreen_field_code
         }
     )->recv(); 
 
     if ($ebook_rsfm_req && defined($ebook_rsfm_req->content->[0])) {
-        if ($ebook_rsfm_req->content->[0]->evergreen_field_code eq $evergreen_field_code) {
-            return { status => "failed", message => "Duplicate entry found! Please try selecting different values" }; 
-        }
-        
-        return { status => "failed", message => "The value '$digital_services_field_value' already exists! Please try selecting different values." }; 
+        return { status => "failed", message => "Duplicate entry found! Please try selecting different values" };
     }
 
     # Now, Save an entry to rbdigital.search_field_mappings table
index 414e9c9..9c6cbcf 100755 (executable)
@@ -50,6 +50,15 @@ sub load_rbdigital_record {
         $ctx->{recommended_books} = _get_book_recommendations($self->editor->authtoken, $session_id, $isbn, $media_format, $page_index, $page_size);
     }
 
+    #Get Patron Wishlist
+    # Return hash reference of wishlist {isbn => true}
+    $ctx->{wishlist} = _get_patron_wishlist($self->editor->authtoken, $session_id);
+
+    $ctx->{checkouts} = _get_patron_checkouts($self->editor->authtoken, $session_id);
+
+    $ctx->{holds} = _get_patron_holds($self->editor->authtoken, $session_id);
+    
+
     $self->ctx->{copy_depth} = $self->cgi->param('copy_depth');
 
     my $copy_limit = int($self->cgi->param('copy_limit') || 10);
@@ -66,7 +75,7 @@ sub load_rbdigital_record {
         $self->_load_lists_and_settings;
         $self->timelog("load user lists and settings");
     }
-
+    
     return Apache2::Const::OK;
 }
 
index 71caf30..9011b33 100755 (executable)
@@ -14,6 +14,7 @@ my $U = 'OpenILS::Application::AppUtils';
 use constant EBOOK_API_VENDOR => 'rbdigital';
 use constant EBOOK_API_OU => 1;
 
+# This method will load the admin area of the Advanced Search Tab Content
 sub load_rbdigital_advanced {
     my $self = shift;
     $self->ctx->{search_filters} = {};
@@ -240,6 +241,12 @@ sub load_rbdigital_results {
         
         $logger->info('EbookAPI: RBDigitalSearch Basic Search Record Count: '. scalar @$record_ids);
 
+        #Get Patron Wishlist
+        # Return hash reference of wishlist {isbn => true}
+        $ctx->{wishlist} = _get_patron_wishlist($self->editor->authtoken, $session_id);
+
+        $ctx->{checkouts} = _get_patron_checkouts($self->editor->authtoken, $session_id);
+
         # Add values to returned query structure for GUI to process
         $ctx->{ids} = $record_ids;
         $ctx->{records} = $results->{content}->{content}->{items};
@@ -256,6 +263,76 @@ sub load_rbdigital_results {
     return Apache2::Const::OK;
 }
 
+sub _get_patron_wishlist {
+    my ($authtoken, $session_id) = @_;
+
+    my $ebookapi_session = OpenSRF::AppSession->create('open-ils.ebook_api');
+    my $wishlist_req = $ebookapi_session->request('open-ils.ebook_api.patron.wishlist',$authtoken, $session_id,'','get')->recv();
+
+    my %wishlist_ref;
+    
+    if (defined($wishlist_req->{content}->{content})) {
+        $logger->info('EbookAPI: RBDigitalSearch Patron Wishlist API call was successful');
+        # Loop over the wishlist contents and build hash array for easier to use in the UI: { isbn => '1', ...}
+        $logger->info("Wishlist response: ".Dumper($wishlist_req->{content}->{content}));
+        foreach my $value (@{$wishlist_req->{content}->{content}}) {
+            $wishlist_ref{$value->{isbn}} = "1";
+        }
+    } else {
+        %wishlist_ref = {};
+        $logger->error('EbookAPI: RBDigitalSearch Patron Wishlist API call failed');
+    }
+
+    return \%wishlist_ref;
+}
+
+sub _get_patron_holds {
+    
+    my ($authtoken, $session_id) = @_;
+    my $barcode = '';
+    my $ebookapi_session = OpenSRF::AppSession->create('open-ils.ebook_api');
+    my $holds_req = $ebookapi_session->request('open-ils.ebook_api.patron.get_holds',$authtoken, $session_id, $barcode)->recv();
+
+    my %holds_ref;
+    
+    if (defined($holds_req->content)) {
+        $logger->info('EbookAPI: RBDigitalSearch Patron Holds API call was successful');
+        # Loop over the holds contents and build hash array for easier to use in the UI: { isbn => '1', ...}
+        $logger->info("Holds response: " . Dumper($holds_req->content));
+        foreach my $value (@{$holds_req->content}) {
+            $holds_ref{$value->{title_id}} = "1"; 
+        }
+    } else {
+        %holds_ref = {};
+        $logger->error('EbookAPI: RBDigitalSearch Patron Wishlist API call failed');
+    }
+
+    return \%holds_ref;
+}
+
+sub _get_patron_checkouts {
+    my ($authtoken, $session_id) = @_;
+
+    my $ebookapi_session = OpenSRF::AppSession->create('open-ils.ebook_api');
+    my $checkouts_req = $ebookapi_session->request('open-ils.ebook_api.patron.get_checkouts',$authtoken, $session_id)->recv();
+
+    my %checkouts_ref;
+    
+    if (defined($checkouts_req->content)) {
+        $logger->info('EbookAPI: RBDigitalSearch Patron Checkouts API call was successful');
+        # Loop over the checkout contents and build hash array for easier to use in the UI: { isbn => '1', ...}
+        $logger->info("Checkout response: " . Dumper($checkouts_req->content));
+        foreach my $value (@{$checkouts_req->content}) {
+            $checkouts_ref{$value->{title_id}} = $value->{download_url}; 
+        }
+    } else {
+        %checkouts_ref = {};
+        $logger->error('EbookAPI: RBDigitalSearch Patron Wishlist API call failed');
+    }
+
+    return \%checkouts_ref;
+}
+
 sub _is_authorized {
     my ($authtoken, $session_id) = @_;
     my $ebookapi_session = OpenSRF::AppSession->create('open-ils.ebook_api');
@@ -329,7 +406,7 @@ sub _search {
         $logger->debug('EbookAPI: RBDigitalSearch search result: '.Dumper($search_results));
        
         if (defined($search_results->{content}->{is_success}) && $search_results->{content}->{is_success} eq '1') {
-            $logger->error('EbookAPI: RBDigitalSearch Basic Search API call was successful');
+            $logger->info('EbookAPI: RBDigitalSearch Basic Search API call was successful');
         } else {
             $logger->error('EbookAPI: RBDigitalSearch Basic Search API call failed');
             return Apache2::Const::OK;
index 8d2043c..b497753 100755 (executable)
 
     # Get Series information
     series_search_url = mkurl(ctx.opac_root _ vendor_search_uri, {qtype => 'series', query => ebook_record_item.series.token});
-    ebook_item.series = ebook_item.series _ '<a href="'_ series_search_url _ '">' _ ebook_record_item.series.text _ '</a>';
-        
+    IF ebook_record_item.series.text; 
+        ebook_item.series = ebook_item.series _ '<a href="'_ series_search_url _ '">' _ ebook_record_item.series.text _ '</a>';
+    END;
+
     # Loop over IMAGES array and get the medium image link
     FOREACH pair IN ebook_record_item.images;
         IF pair.name == 'medium';
index c565ec4..6ae9404 100755 (executable)
@@ -1,6 +1,5 @@
 [%  PROCESS "opac/parts/misc_util.tt2";
     USE ResolverResolver;
-    USE Dumper;
 
     PROCESS "opac/ebook_api/rbdigital/parts/file_formats.tt2";
     ctx.page_title = ctx.title_info.item.bookTitle.text | html;
@@ -9,13 +8,13 @@
     ebook_record_item = ctx.title_info.item;
     ebook_record_item.summary = ctx.title_summary.summary;
     ebook_record_item.recommended_books = ctx.recommended_books;
+    ebook_isbn = ebook_record_item.isbn;
     
     PROCESS "opac/ebook_api/rbdigital/parts/item_parser.tt2";
 %]
-
 <!-- ****************** rdetail_summary.xml ***************************** -->
 <!-- Ebook Spinner -->
-<span id="ebook_spinner" class="hidden">&nbsp;&nbsp;<img style="width:20px;height:auto" src="[% ctx.media_prefix %]/opac/images/progressbar_green.gif[% ctx.cache_key %]" alt="[% l("Processing...") %]"/></span>
+<span id="ebook_spinner" class="hidden">&nbsp;Processing ...&nbsp;&nbsp;<img style="width:20px;height:auto" src="[% ctx.media_prefix %]/opac/images/progressbar_green.gif[% ctx.cache_key %]" alt="[% l("Processing...") %]"/></span>
 <abbr class="unapi-id" title='tag:[% ctx.hostname %],[% date.format(date.now, '%Y') %]:biblio-record_entry/[% ebook_item.isbn %]'></abbr>
 <hr />
 
         <div id="rdetail_actions_div">
             [% IF ebook_item.isTitleAvailable == true; %]
                 <div class="rdetail_aux_utils ebook_action">
-                    <a id="[%- ebook_item.isbn -%]_ebook_checkout" href=""
+                [% IF ctx.checkouts.$ebook_isbn != ""; %]
+                    <a id="[% ebook_item.isbn %]_ebook_checkout_download_link" 
+                        href="#"
+                        data-downloadurl="[% ctx.checkouts.$ebook_isbn; %]"
+                        class="no-dec ebook_checkout_download_link" 
+                        rel="nofollow" vocab="" 
+                        data-isbn="[% ebook_item.isbn %]">
+                    <img src="[% ctx.media_prefix %]/images/minus_sign.png[% ctx.cache_key %]" alt="" />&nbsp;[% l("Download") %]</a>
+
+                [% ELSE; %]
+                    <a id="[%- ebook_item.isbn -%]_ebook_checkout" 
+                        href=""
+                        data-isbn="[% ebook_item.isbn %]"
                         class="no-dec checkout ebook_checkout_link" rel="nofollow" vocab=""><img src="[% ctx.media_prefix %]/images/green_check.png[% ctx.cache_key %]"
                         [% img_alt(l('Check Out [_1]', ebook_item.title)) %]/>
                     <span>[% l('Check Out E-Item') %]</span></a>
+                    
+                 [% END; %]
+                 </div>
+            [% END; %]
+
+            [% IF ctx.checkouts.$ebook_isbn == ""; %]
+                
+                <div id="[% ebook_item.isbn %]_ebook_hold" class="rdetail_aux_utils ebook_action">
+                    <a id="[% ebook_item.isbn %]_ebook_place_hold" 
+                        href="#" data-isbn="[% ebook_item.isbn %]"
+                        class="no-dec ebook_place_hold [% IF ctx.holds.$ebook_isbn == "1"; %] hidden [% END; %]" rel="nofollow" vocab="">
+                        <img src="[% ctx.media_prefix %]/images/green_check.png[% ctx.cache_key %]"
+                        [% img_alt(l('Place Hold on [_1]', ebook_item.title)) %]/>
+                    <span>[% l('Place Hold on E-Item') %]</span></a>
+
+                    <a id="[% ebook_item.isbn %]_ebook_cancel_hold"
+                        href="#" data-isbn="[% ebook_item.isbn %]"
+                        class="no-dec ebook_cancel_hold [% IF ctx.holds.$ebook_isbn != "1"; %] hidden [% END; %]" rel="nofollow" vocab="">
+                        <img src="[% ctx.media_prefix %]/images/minus_sign.png[% ctx.cache_key %]"
+                        [% img_alt(l('Cancel Hold on [_1]', ebook_item.title)) %]/>
+                    <span>[% l('Cancel Hold on E-Item') %]</span></a>
                 </div>
             [% END; %]
-            <div id="[% ebook_item.isbn %]_ebook_place_hold" class="rdetail_aux_utils ebook_action">
-                <a href="#" 
-                class="no-dec ebook_place_hold" rel="nofollow" vocab=""><img src="[% ctx.media_prefix %]/images/green_check.png[% ctx.cache_key %]"
-                    [% img_alt(l('Place Hold on [_1]', ebook_item.title)) %]/>
-                <span>[% l('Place Hold on E-Item') %]</span></a>
-            </div>
-            
+
             <div class="rdetail_aux_utils">
             <!-- Display Wishlist option -->
             [% IF !ctx.is_staff %]
-                <a id="[% ebook_item.isbn %]_ebook_wishlist_add" href="#" class="no-dec ebook_wishlist_link_add" rel="nofollow" data-isbn="[% ebook_item.isbn %]">
+                <a id="[% ebook_item.isbn %]_ebook_wishlist_add" href="#" class="no-dec ebook_wishlist_link_add [% IF ctx.wishlist.$ebook_isbn == "1"; %] hidden [% END; %]" rel="nofollow" data-isbn="[% ebook_item.isbn %]">
                     <img src="[% ctx.media_prefix %]/images/clipboard.png[% ctx.cache_key %]" alt="" />&nbsp;[% l("Add to Wishlist") %]</a>
 
-                <a id="[% ebook_item.isbn %]_ebook_wishlist_remove" href="#" class="no-dec ebook_wishlist_link_remove hidden" rel="nofollow" vocab="" data-isbn="[% ebook_item.isbn %]">
+                <a id="[% ebook_item.isbn %]_ebook_wishlist_remove" href="#" class="no-dec ebook_wishlist_link_remove [% IF ctx.wishlist.$ebook_isbn != "1"; %] hidden [% END; %]" rel="nofollow" vocab="" data-isbn="[% ebook_item.isbn %]">
                     <img src="[% ctx.media_prefix %]/images/minus_sign.png[% ctx.cache_key %]" alt="" />&nbsp;[% l("Remove from Wishlist") %]</a>
             [% END %]
             </div>
@@ -160,7 +186,7 @@ END;
     </li>
     [%- END %]
 
-    [%- IF ebook_item.series && !ebook_item.series.search("Default Blank"); %]
+    [%- IF ebook_item.series != "" && !ebook_item.series.search("Default Blank"); %]
     <li id='rdetail_series'>
         <strong class='rdetail_label'>[% l("Series:") %]</strong>
         <span class='rdetail_value'>[% ebook_item.series %]</span>
@@ -174,7 +200,7 @@ END;
     <tbody>
         <tr>
         <td class="rdetail_content_type">Short Description: </td>
-        <td class="rdetail_content_value" property="keywords">[%- ebook_item.shortDescription %]<br></td>
+        <td class="rdetail_content_value" property="keywords">&nbsp;[%- ebook_item.shortDescription %]<br></td>
         </tr>
     </tbody>
 </table>
index 672b2bb..0d75804 100755 (executable)
@@ -7,11 +7,12 @@
     IF ctx.result_stop > ctx.hit_count; ctx.result_stop = ctx.hit_count; END;
 
     result_count = ctx.result_start;
-    USE Dumper;
 %]
-[% PROCESS "opac/parts/result/paginate.tt2" %] 
-[% ctx.results_count_header = PROCESS results_count_header;
-    ctx.results_count_header %]
+[% PROCESS "opac/parts/result/paginate.tt2" %]
+[% ctx.results_count_header = PROCESS results_count_header; 
+   ctx.results_count_header;
+%]
+
 [% IF ctx.bookbag %]
 <div id="result-bookbag-heading">
     <div class="result-bookbag-name">[% ctx.bookbag.name | html %]</div>
@@ -44,6 +45,8 @@
                         FOR rec IN ctx.records;
                             ebook_record_item = rec.item;
                             PROCESS "opac/ebook_api/rbdigital/parts/item_parser.tt2";
+                            #ebook_item variable is populated inside the item_parser file
+                            ebook_isbn = ebook_item.isbn;
 
                     -%]
                         <tr class="result_table_row">
@@ -367,27 +370,39 @@ END;
                                                     <div class="result_table_utils">
                                                         [% IF ebook_item.isTitleAvailable == true; %]
                                                         <div id="[%- rec.item.isbn -%]_ebook_checkout" class="results_aux_utils result_util ebook_action">
-                                                            <a href="[% mkurl(ctx.opac_root _ '/myopac/ebook_checkout',
-                                                                {title => args.ebook.ebook_id, vendor => args.ebook.vendor, action => 'checkout'},
-                                                                ['query','tag','subfield','term','_special','sort','page']) %]"
-                                                                [% html_text_attr('title', l('Check Out [_1]', ebook_item.title)) %]
-                                                                    class="no-dec" rel="nofollow" vocab=""><img
-                                                                src="[% ctx.media_prefix %]/images/green_check.png[% ctx.cache_key %]"
-                                                                alt=""/><span class="result_place_hold">[% l('Check Out E-Item') %]</span></a>
+                                                            [% IF ctx.checkouts.$ebook_isbn != ""; %]
+                                                                <a id="[% ebook_item.isbn %]_ebook_checkout_download_link" 
+                                                                    href="#"
+                                                                    data-downloadurl="[% ctx.checkouts.$ebook_isbn; %]"
+                                                                    class="no-dec ebook_checkout_download_link" 
+                                                                    rel="nofollow" vocab="" 
+                                                                    data-isbn="[% ebook_item.isbn %]">
+                                                                <img src="[% ctx.media_prefix %]/images/minus_sign.png[% ctx.cache_key %]" alt="" />&nbsp;[% l("Download") %]</a>
+
+                                                            [% ELSE; %]
+                                                                <a href="[% mkurl(ctx.opac_root _ '/myopac/ebook_checkout',
+                                                                    {title => args.ebook.ebook_id, vendor => args.ebook.vendor, action => 'checkout'},
+                                                                    ['query','tag','subfield','term','_special','sort','page']) %]"
+                                                                    [% html_text_attr('title', l('Check Out [_1]', ebook_item.title)) %]
+                                                                    data-isbn="[% ebook_item.isbn %]" 
+                                                                    class="no-dec ebook_checkout_link" rel="nofollow" vocab="">
+                                                                <img src="[% ctx.media_prefix %]/images/green_check.png[% ctx.cache_key %]"
+                                                                    alt=""/><span class="result_place_hold">[% l('Check Out E-Item') %]</span></a>                                                            
+                                                            [% END; %]
                                                         </div>
                                                         [% END; %]
                                                     [% IF !ctx.is_meta %]
                                                         <div class="results_aux_utils result_util">
-                                                        [% IF !ctx.is_staff;
-                                                        
-                                                        %]      
-                                                            <a id="[% ebook_item.isbn %]_ebook_wishlist_add" href="#" class="no-dec ebook_wishlist_link_add" 
-                                                                [% html_text_attr('title', title_label) %] rel="nofollow" data-isbn="[% ebook_item.isbn %]">
-                                                                <img src="[% ctx.media_prefix %]/images/clipboard.png[% ctx.cache_key %]" alt="" />&nbsp;[% l("Add to Wishlist") %]</a>
-
-                                                            <a id="[% ebook_item.isbn %]_ebook_wishlist_remove" href="#" class="no-dec ebook_wishlist_link_remove hidden" rel="nofollow" vocab="" data-isbn="[% ebook_item.isbn %]">
-                                                                <img src="[% ctx.media_prefix %]/images/minus_sign.png[% ctx.cache_key %]" alt="" />&nbsp;[% l("Remove from Wishlist") %]</a>
-                                                        [% END %]
+                                                        [%  IF !ctx.is_staff; %]
+                                                                <a id="[% ebook_item.isbn %]_ebook_wishlist_add" href="#" 
+                                                                    class="no-dec ebook_wishlist_link_add [% IF ctx.wishlist.$ebook_isbn == "1"; %] hidden [% END; %]" 
+                                                                    [% html_text_attr('title', title_label) %] rel="nofollow" data-isbn="[% ebook_item.isbn %]">
+                                                                    <img src="[% ctx.media_prefix %]/images/clipboard.png[% ctx.cache_key %]" alt="" />&nbsp;[% l("Add to Wishlist") %]</a>
+                                                                    
+                                                                <a id="[% ebook_item.isbn %]_ebook_wishlist_remove" href="#" 
+                                                                    class="no-dec ebook_wishlist_link_remove [% IF ctx.wishlist.$ebook_isbn != "1"; %] hidden [% END; %]" rel="nofollow" vocab="" data-isbn="[% ebook_item.isbn %]">
+                                                                    <img src="[% ctx.media_prefix %]/images/minus_sign.png[% ctx.cache_key %]" alt="" />&nbsp;[% l("Remove from Wishlist") %]</a>
+                                                        [% END; %]
                                                         </div>
                                                     [% END %]
                                                        
index f6d656f..a6288df 100755 (executable)
@@ -6,7 +6,7 @@
     canon = ctx.proto _ '://' _ ctx.hostname _ mkurl('', {}, 1);
     ctx.metalinks.push('<link rel="canonical" href="' _ canon  _ '" />');
     ctx.metalinks.push('<meta property="og:url" content="' _ canon  _ '" />');
-    IF CGI.param("expand"); basic_search = "f"; END;    
+    IF CGI.param("expand"); basic_search = "f"; END;
 -%]
     <h2 class="sr-only">[% l('Record Details') %]</h2>
     [% INCLUDE "opac/ebook_api/rbdigital/parts/searchbar.tt2" %]
index 4a91bdb..029888a 100755 (executable)
@@ -23,7 +23,9 @@
     PROCESS "opac/parts/misc_util.tt2";
     PROCESS get_library;
 -%]
-    
+    <!-- EBook Spinner -->
+    <span id="ebook_spinner" class="hidden">&nbsp;Processing ...&nbsp;&nbsp;<img style="width:20px;height:auto" src="[% ctx.media_prefix %]/opac/images/progressbar_green.gif[% ctx.cache_key %]" alt="[% l("Processing...") %]"/></span>
+
     <h2 class="sr-only">[% l('Search Results') %]</h2>
     <form action="[% ctx.opac_root _ vendor_search_uri %]" method="get">
     [% INCLUDE "opac/ebook_api/rbdigital/parts/searchbar.tt2" took_care_of_form=1 %]
         [% END %]
         <div id="results_header_bar" [%- IF ctx.metarecord %]class="hidden"[% END -%]>
             <div id="results_header_inner">
-                <div class="results_header_btns">
-                    <a href="[% mkurl(ctx.opac_root _ '/home', {$loc_name => loc_value, 'detail_record_view' => show_detail_view}, 1) %]">[% l('Another Search') %]</a>
-                </div>
-                <div class="results_header_btns">
-                    <a href="[% mkurl(ctx.opac_root _ '/advanced',{}, expert_search_parms.merge(browse_search_parms, facet_search_parms)) %]">[% l('Advanced Search') %]</a>
-                </div>
                 <div id="refine_hits" class="results_header_btns result_block_visible"><a onclick="getFacety();">[% l('Refine these results') %]</a></div>
                 <div id="return_to_hits" class="results_header_btns"><a onclick="getResulty();">[% l('Back to results') %]</a></div>
                 [% IF ctx.mylist.size %]
index 521a307..1bcec2d 100755 (executable)
@@ -71,61 +71,73 @@ Ebook.prototype.getHoldings = function(callback) {
 }
 
 Ebook.prototype.checkout = function(authtoken, patron_id, callback) {
-    var ses = this.ses || dojo.cookie(this.vendor);
     var ebook = this;
-    // get selected checkout format (optional, used by OverDrive)
-    var checkout_format;
-    var format_selector = dojo.byId('checkout-format');
-    if (format_selector) {
-        checkout_format = format_selector.value;
-    }
-    // perform checkout
-    new OpenSRF.ClientSession('open-ils.ebook_api').request({
-        method: 'open-ils.ebook_api.checkout',
-        params: [ authtoken, ses, ebook.id, patron_id, checkout_format ],
-        async: true,
-        oncomplete: function(r) {
-            var resp = r.recv();
-            if (resp) {
-                console.log('checkout response: ' + resp.content());
-                return callback(resp.content());
-            }
+    //Reload new session (if any)
+    checkSession(this.vendor, function(vendor_cookie_name) {
+        var ses = ebook.ses || dojo.cookie(vendor_cookie_name);
+
+        // get selected checkout format (optional, used by OverDrive)
+        var checkout_format;
+        var format_selector = dojo.byId('checkout-format');
+        if (format_selector) {
+            checkout_format = format_selector.value;
         }
-    }).send();
+        // perform checkout
+        new OpenSRF.ClientSession('open-ils.ebook_api').request({
+            method: 'open-ils.ebook_api.checkout',
+            params: [ authtoken, ses, ebook.id, patron_id, checkout_format ],
+            async: true,
+            oncomplete: function(r) {
+                var resp = r.recv();
+                if (resp) {
+                    console.log('checkout response: ' + resp.content());
+                    return callback(resp.content());
+                }
+            }
+        }).send();
+    });
 }
 
 Ebook.prototype.placeHold = function(authtoken, patron_id, callback) {
-    var ses = this.ses || dojo.cookie(this.vendor);
     var ebook = this;
-    new OpenSRF.ClientSession('open-ils.ebook_api').request({
-        method: 'open-ils.ebook_api.place_hold',
-        params: [ authtoken, ses, ebook.id, patron_id, patron_email ],
-        async: true,
-        oncomplete: function(r) {
-            var resp = r.recv();
-            if (resp) {
-                console.log('place hold response: ' + resp.content());
-                return callback(resp.content());
+
+    //Reload new session (if any)
+    checkSession(this.vendor, function(vendor_cookie_name) {
+        var ses = ebook.ses || dojo.cookie(vendor_cookie_name);
+
+        new OpenSRF.ClientSession('open-ils.ebook_api').request({
+            method: 'open-ils.ebook_api.place_hold',
+            params: [ authtoken, ses, ebook.id, patron_id ],
+            async: true,
+            oncomplete: function(r) {
+                var resp = r.recv();
+                if (resp) {
+                    console.log('place hold response: ' + resp.content());
+                    return callback(resp.content(), ebook.id);
+                }
             }
-        }
-    }).send();
+        }).send();
+    });
 }
 
 Ebook.prototype.cancelHold = function(authtoken, patron_id, callback) {
-    var ses = this.ses || dojo.cookie(this.vendor);
     var ebook = this;
-    new OpenSRF.ClientSession('open-ils.ebook_api').request({
-        method: 'open-ils.ebook_api.cancel_hold',
-        params: [ authtoken, ses, ebook.id, patron_id ],
-        async: true,
-        oncomplete: function(r) {
-            var resp = r.recv();
-            if (resp) {
-                console.log('cancel hold response: ' + resp.content());
-                return callback(resp.content());
+    //Reload new session (if any)
+    checkSession(this.vendor, function(vendor_cookie_name) {
+        var ses = ebook.ses || dojo.cookie(vendor_cookie_name);
+        new OpenSRF.ClientSession('open-ils.ebook_api').request({
+            method: 'open-ils.ebook_api.cancel_hold',
+            params: [ authtoken, ses, ebook.id, patron_id ],
+            async: true,
+            oncomplete: function(r) {
+                var resp = r.recv();
+                if (resp) {
+                    console.log('cancel hold response: ' + resp.content());
+                    return callback(resp.content(), ebook.id);
+                }
             }
-        }
-    }).send();
+        }).send();
+    });
 }
 
 Ebook.prototype.download = function() {
index 3bc259f..7e828e1 100755 (executable)
@@ -28,12 +28,17 @@ $( document ).ready(function() {
 });
 
 function setupEventHandlers() {
-    $('.ebook_checkout_link').on('click',function(event) {
-        console.log('Not implement');
+    $(document).on("click", ".ebook_checkout_link", function () {
+        showEbookSpinner($(this), true);
+        var isbn = $(this).data('isbn');
+        ebook_rbdigital.id = isbn;
+        
+        ebook_rbdigital.checkout(authtoken, rbdigitalPatronId, checkoutAddCallback);
+        return false;
     });
 
     $(document).on("click", ".ebook_wishlist_link_add", function () {
-        showEbookSpinner($(this));
+        showEbookSpinner($(this), true);
         var isbn = $(this).data('isbn');
         ebook_rbdigital.id = isbn;
         
@@ -42,7 +47,7 @@ function setupEventHandlers() {
     });
 
     $(document).on("click", ".ebook_wishlist_link_remove", function () {
-        showEbookSpinner($(this));
+        showEbookSpinner($(this), true);
         var isbn = $(this).data('isbn');
         ebook_rbdigital.id = isbn;
         ebook_rbdigital.wishlist(authtoken, 'delete', wishlistRemoveCallback);
@@ -114,7 +119,7 @@ function setupEventHandlers() {
         } else if (eg_selected_optgroup != rbdigital_selected_optgroup) {
             showNotification('Invalid Selection','Please select both Text values or Dropdown values from selections!','error');
         } else {
-            showEbookSpinner($(this));
+            showEbookSpinner($(this), false);
             field_type = eg_selected_optgroup.indexOf("Dropdown") == 0 ? "dropdown" : "text";
             ebook_rbdigital.saveSearchField(authtoken, vendor_rbdigital.name, eg_search_field, rbdigital_search_field, field_type, saveSearchFieldCallback);
         }
@@ -135,7 +140,7 @@ function setupEventHandlers() {
             evergreen_field_code = eg_selected_value[0];
             evergreen_field_value = eg_selected_value[1];
             digital_services_search_field_value = $('#ds_search_field_values option:selected').text();
-
+            showEbookSpinner($(this), false);
             ebook_rbdigital.saveSearchFieldValue(authtoken, $('#txtSearchFieldsID').val(), evergreen_field_code, evergreen_field_value, 
                 digital_services_field_code, digital_services_search_field_value, saveSearchFieldValueCallback);
         }
@@ -152,20 +157,61 @@ function setupEventHandlers() {
         
         //Store search_fields_id to a hidden input element
         $('#txtSearchFieldsID').val(search_fields_id);
-
+        showEbookSpinner($(this), false);
         populateSeachFieldValuesForSelection(eg_search_field, digital_services_field);
         ebook_rbdigital.getMappedSearchFieldValues(authtoken, search_fields_id, getMappedSearchFieldValuesCallback);
     });
 
+    //Remove Search Field
     $(document).on('click', '.removeSearchField', function () {
         var search_fields_id = $(this).attr('data-id');
         ebook_rbdigital.removeSearchField(authtoken, search_fields_id, removeSearchFieldCallback);
     });
 
+    //Remove Search Field Value
     $(document).on('click', '.removeSearchFieldValue', function () {
         var search_field_mappings_id = $(this).attr('data-id');
         ebook_rbdigital.removeSearchFieldValue(authtoken, search_field_mappings_id, removeSearchFieldValueCallback);
     });
+
+    //Place Hold
+    $(document).on('click', '.ebook_place_hold', function () {
+        var isbn = $(this).data('isbn');
+        ebook_rbdigital.id = isbn;
+        showEbookSpinner($(this), true);
+        ebook_rbdigital.placeHold(authtoken, rbdigitalPatronId, placeHoldCallback);
+    });
+
+    //Cancel Hold
+    $(document).on('click', '.ebook_cancel_hold', function () {
+        var isbn = $(this).data('isbn');
+        ebook_rbdigital.id = isbn;
+        showEbookSpinner($(this), true);
+        ebook_rbdigital.cancelHold(authtoken, rbdigitalPatronId, cancelHoldCallback);
+    });
+
+    //Download File
+    $(document).on('click', '.ebook_checkout_download_link', function () {
+        var that = $(this);
+        var downloadUrl = that.attr('data-downloadurl');
+        showEbookSpinner(that);
+        //Change http protocol to https to avoid browser error on Mixed contents
+        if (downloadUrl.indexOf('https') == -1) {
+            downloadUrl = downloadUrl.replace("http", "https");
+        }
+        
+        //Make an ajax call to get a download link
+        $.ajax({
+            type: 'GET',
+            url: downloadUrl, 
+            success: function(result){
+                console.log('success');
+                console.log(result.url);
+                window.open(result.url, '_self');
+                hideEbookSpinner();
+            }
+        });
+    });
 }
 
 function showNotification(title, text, type) {
@@ -176,25 +222,77 @@ function showNotification(title, text, type) {
     });
 }
 
-function showEbookSpinner(adjacent_element) {
+function showEbookSpinner(adjacent_element, is_hide_adjacent_element) {
     //Add an ebook spinner right to the adjacent element
     $(adjacent_element).after(ebook_spinner);
     ebook_spinner.removeClass('hidden');
+
+    if (is_hide_adjacent_element) {
+        adjacent_element.addClass('hidden');
+    }
 }
 
 function hideEbookSpinner() {
     ebook_spinner.addClass('hidden');
 }
 
+function placeHoldCallback(responseContents, isbn) {
+    if (responseContents.message == "success") {
+        showNotification('Success','Item placed on hold!','success');
+        $("#"+isbn+"_ebook_place_hold").addClass('hidden');
+        $("#"+isbn+"_ebook_cancel_hold").removeClass('hidden');
+    } else if (responseContents.message.indexOf("already exists") > 1) {
+        showNotification('Warning','The requested item is already on hold!','info');
+        $("#"+isbn+"_ebook_place_hold").addClass('hidden');
+        $("#"+isbn+"_ebook_cancel_hold").removeClass('hidden');
+    } else {
+        showNotification('Unknown Error','Unable to place item on hold. Please try it again!','error');
+        console.log(responseContents.message);
+    }
+    hideEbookSpinner();
+}
+
+function cancelHoldCallback(responseContents, isbn) {
+    if (responseContents.message == "success") {
+        showNotification('Success','Item is no loger on hold!','success');
+        $("#"+isbn+"_ebook_place_hold").removeClass('hidden');
+        $("#"+isbn+"_ebook_cancel_hold").addClass('hidden');
+    } else if (responseContents.message.indexOf("already exists") > 1) {
+        showNotification('Warning','The requested item is not on hold!','info');
+        $("#"+isbn+"_ebook_place_hold").removeClass('hidden');
+        $("#"+isbn+"_ebook_cancel_hold").addClass('hidden');
+    } else {
+        showNotification('Unknown Error','Unable to cancel item on hold. Please try it again!','error');
+        console.log(responseContents.message);
+    }
+    hideEbookSpinner();
+}
+
+function checkoutAddCallback(responseContents) {
+    if (responseContents.message == "success") {
+        showNotification('Success','Succesfully checked out item!','success');
+        location.reload();
+    } else if (responseContents.message.indexOf("already exists") > 1) {
+        showNotification('Warning','The requested item has been already checked out!','info');
+        console.log("Item already exists");
+    } else {
+        showNotification('Unknown Error','Unable to checkout the item. Please try it again!','error');
+        console.log(responseContents.message);
+    }
+}
+
 //Process post ajax call to add wishlist to patron's account
 function wishlistAddCallback(responseContents, isbn) {
     if (responseContents.message == "success") {
+        showNotification('Success','Succesfully added to your wishlist!','success');
         $("#"+isbn+"_ebook_wishlist_add").addClass('hidden');
         $("#"+isbn+"_ebook_wishlist_remove").removeClass('hidden');
     } else if (responseContents.message.indexOf("already exists") > 1) {
         $("#"+isbn+"_ebook_wishlist_add").addClass('hidden');
         $("#"+isbn+"_ebook_wishlist_remove").removeClass('hidden');
+        showNotification('Warning','The requested item is already in your wishlist!','info');
     } else {
+        showNotification('Unknown Error','Unable to add to your wishlist. Please try it again!','error');
         console.log(responseContents.message);
     }
     hideEbookSpinner();
@@ -203,13 +301,13 @@ function wishlistAddCallback(responseContents, isbn) {
 //Process post ajax call to remove wishlist to patron's account
 function wishlistRemoveCallback(responseContents, isbn) {
     if (responseContents.message == "success") {
-        console.log(responseContents.message);
+        showNotification('Success','Succesfully removed from your wishlist!','success');
         $("#"+isbn+"_ebook_wishlist_add").removeClass('hidden');
         $("#"+isbn+"_ebook_wishlist_remove").addClass('hidden');
     } else {
+        showNotification('Unknown Error','Unable to remove from your wishlist. Please try it again!','error');
         console.log(responseContents.message);
-    }  
-    
+    }
     hideEbookSpinner();
 }
 
@@ -276,7 +374,9 @@ function saveSearchFieldValueCallback(responseContents) {
         showNotification("Success", "Search Field value Saved", "success");
     } else {
         showNotification("Error", "Unable to save entry", "error");
-    }  
+    }
+
+    hideEbookSpinner();
 }
 
 function removeSearchFieldValueCallback(responseContents, search_field_mappings_id) {
@@ -286,6 +386,8 @@ function removeSearchFieldValueCallback(responseContents, search_field_mappings_
     } else {
         showNotification("Error", "Unable to remove entry", "error");
     }
+
+    hideEbookSpinner();
 }
 
 function populateSeachFieldValuesForSelection(eg_search_field, digital_services_field) {
@@ -350,7 +452,9 @@ function getMappedSearchFieldValuesCallback(responseContents) {
         }
     } else {
         showNotification("Error", "No data was found! Please contact system admin to load the data.", "error");
-    }  
+    }
+
+    hideEbookSpinner();
 }
 
 function getCookie(cname) {