Bug 19618: Add ability to place holds for members of a club in intranet
authorAgustin Moyano <agustinmoyano@theke.io>
Thu, 5 Sep 2019 17:13:27 +0000 (14:13 -0300)
committerMartin Renvoize <martin.renvoize@ptfs-europe.com>
Tue, 1 Oct 2019 07:05:57 +0000 (08:05 +0100)
This patch adds the ability to place a hold for each member of a club in random order.

To test:
1) apply this patch
2) create 2 clubs, (club names should have some part in common, and some part different for each other)
3) in one of them add at least 6 members
4) enter patron clubs management and click on "Actions" button
SUCCESS.1 => club with members has a new action called "search to hold"
5) click on search to hold
SUCCESS.2 => in the list of bilios there appears an action called "Place hold for <club name>"
6) click on "Place hold for <club name>"
SUCCESS.3 => a new window appears where you can select pickup location (defaults to club's library, if any), and the list of members.
7) go back to the list of bilios in the catalog and click on "Forget <club name>"
8) click on "Holds" action of any biblio
SUCCESS.4 => a search box appears with two tabs: Patrons and Clubs
9) click on Clubs tab and search by the common part of clubs names
SUCCESS.5 => a list of clubs that matches the search appears. If you click on any of them, the same page as SUCCESS.3 appears.
10) go back to the search box in SUCCESS.4 and search by the different part of the name.
SUCCESS.6 => because there is only one club that matches search criteria, the same page as SUCCESS.3 appears;
11) Sign off

Sponsored-by: Southeast Kansas Library - SEKLS
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>

Koha/Club/Enrollment.pm
catalogue/search.pl
koha-tmpl/intranet-tmpl/prog/en/includes/clubs-table.inc [new file with mode: 0644]
koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/results.tt
koha-tmpl/intranet-tmpl/prog/en/modules/clubs/clubs.tt
koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt
koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt
reserve/request.pl

index 168f55b..2b4e627 100644 (file)
@@ -24,6 +24,8 @@ use Carp;
 use Koha::Database;
 use Koha::Clubs;
 use Koha::Patrons;
+use Koha::DateUtils qw(dt_from_string);
+use DateTime;
 
 use base qw(Koha::Object);
 
@@ -71,6 +73,20 @@ sub patron {
     return scalar Koha::Patrons->find( $self->borrowernumber() );
 }
 
+=head3 is_canceled
+Determines if enrollment is canceled
+=cut
+
+sub is_canceled {
+    my ( $self ) = @_;
+
+    return 0 unless $self->date_canceled;
+    my $today = dt_from_string;
+    my $date_canceled = dt_from_string( $self->date_canceled );
+
+    return DateTime->compare($date_canceled, $today) < 1;
+}
+
 =head3 type
 
 =cut
index a3a7015..8f460de 100755 (executable)
@@ -203,6 +203,14 @@ if($cgi->cookie("holdfor")){
     );
 }
 
+if($cgi->cookie("holdforclub")){
+    my $holdfor_club = Koha::Clubs->find( $cgi->cookie("holdforclub") );
+    $template->param(
+        holdforclub => $cgi->cookie("holdforclub"),
+        holdforclub_name => $holdfor_club->name,
+    );
+}
+
 # get biblionumbers stored in the cart
 my @cart_list;
 
diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/clubs-table.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/clubs-table.inc
new file mode 100644 (file)
index 0000000..62027b1
--- /dev/null
@@ -0,0 +1,111 @@
+<table id="clubs-table">
+    <thead>
+        <tr>
+            <th>Name</th>
+            <th>Template</th>
+            <th>Description</th>
+            [% UNLESS destination == 'holds' %]
+                <th>Public enrollment</th>
+                <th>Email required</th>
+            [% END %]
+            <th>Library</th>
+            <th>Start date</th>
+            <th>End date</th>
+            <th>Enrolled patrons</th>
+            [% UNLESS destination == 'holds' %]
+                <th>&nbsp;</th>
+            [% END %]
+        </tr>
+    </thead>
+    <tbody>
+        [% FOREACH c IN clubs %]
+            [% IF destination == 'holds' %]
+                [% IF multi_hold %]
+                    [% SET data_url = "/cgi-bin/koha/reserve/request.pl?club=" _ c.id _ "&amp;multi_hold=1&amp;biblionumbers=" _ biblionumbers %]
+                [% ELSE %]
+                    [% SET data_url = "/cgi-bin/koha/reserve/request.pl?club=" _ c.id _ "&amp;biblionumber=" _ biblionumber %]
+                [% END %]
+                <tr class="clickable" data-url="[% data_url | html %]">
+            [% ELSE %]
+                <tr>
+            [% END %]
+                <td>[% c.name | html %]</td>
+                <td>[% c.club_template.name | html %]</td>
+                <td>[% c.description | html %]</td>
+                [% UNLESS destination == 'holds' %]
+                    <td>
+                        [% IF c.club_template.is_enrollable_from_opac %]
+                            Yes
+                        [% ELSE %]
+                            No
+                        [% END %]
+                    </td>
+                    <td>
+                        [% IF c.club_template.is_email_required %]
+                            Yes
+                        [% ELSE %]
+                            No
+                        [% END %]
+                    </td>
+                [% END %]
+                <td>[% Branches.GetName( c.branchcode ) | html %]</td>
+                <td>
+                    [% IF c.date_start %]
+                        [% c.date_start | $KohaDates %]
+                    [% END %]
+                </td>
+                <td>
+                    [% IF c.date_end %]
+                        [% c.date_end | $KohaDates %]
+                    [% END %]
+                </td>
+                <td>
+                    [% c.club_enrollments.count | html %]
+                </td>
+                [% UNLESS destination == 'holds' %]
+                    <td class="actions">
+                        <div class="dropdown">
+                            <a class="btn btn-default btn-xs dropdown-toggle" id="clubactions[% c.id | html %]" role="button" data-toggle="dropdown" href="#">
+                                Actions <b class="caret"></b>
+                            </a>
+                            <ul class="dropdown-menu pull-right" role="menu" aria-labelledby="clubactions[% c.id | html %]">
+                                [% IF ( c.club_enrollments.count ) %]
+                                    <li>
+                                        <a href="club-enrollments.pl?id=[% c.id | uri %]">
+                                            <i class="fa fa-list-ul"></i> Enrollments
+                                        </a>
+                                    </li>
+                                [% ELSE %]
+                                    <li class="disabled">
+                                        <a href="club-enrollments.pl?id=[% c.id | uri %]">
+                                            <i class="fa fa-list-ul"></i> Enrollments
+                                        </a>
+                                    </li>
+                                [% END %]
+                                [% IF CAN_user_clubs_edit_clubs %]
+                                    <li>
+                                        <a href="clubs-add-modify.pl?id=[% c.id | uri %]">
+                                            <i class="fa fa-pencil"></i> Edit
+                                        </a>
+                                    </li>
+                                    <li>
+                                        <a href="#" onclick='ConfirmDeleteClub([% c.id | html %], "[% c.name | html %]", $(this) ); return false;'>
+                                            <i class="fa fa-trash"></i> Delete
+                                        </a>
+                                    </li>
+                                [% END %]
+                                [% IF ( c.club_enrollments.count ) %]
+                                    <li>
+                                        <a href="#" onclick="SearchToHold([% c.id | html %])">
+                                            <i class="fa fa-search"></i> Search to hold
+                                        </a>
+                                    </li>
+                                [% END %]
+                            </ul>
+                        </div>
+                    </td>
+                [% END %]
+            </tr>
+        [% END %]
+    </tbody>
+</table> <!-- /.clubs-table -->
\ No newline at end of file
index c8af35f..3d9bbe9 100644 (file)
                             [% END # /IF virtualshelves %]
 
                             [% IF ( CAN_user_reserveforothers_place_holds && DisplayMultiPlaceHold ) %]
-                                [% IF ( holdfor ) %]
+                                [% IF ( holdfor or holdforclub ) %]
                                     <div id="placeholdc" class="btn-group">
                                         <button class="btn btn-default btn-xs placehold"><i class="fa fa-sticky-note-o"></i> Place hold</button>
                                         <button class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown">
                                         </button>
                                         <ul class="dropdown-menu">
                                             <li><a href="#" class="placehold">Place hold</a></li>
-                                            <li><a href="#" class="placeholdfor">Place hold for [% holdfor_firstname | html %] [% holdfor_surname | html %] ([% holdfor_cardnumber | html %])</a></li>
-                                            <li class="divider"></li>
-                                            <li><a href="#" id="forgetholdfor">Forget  [% holdfor_firstname | html %] [% holdfor_surname | html %] ([% holdfor_cardnumber | html %])</a></li>
+                                            [% IF holdfor %]
+                                                <li><a href="#" class="placeholdfor">Place hold for [% holdfor_firstname | html %] [% holdfor_surname | html %] ([% holdfor_cardnumber | html %])</a></li>
+                                                <li class="divider"></li>
+                                                <li><a href="#" id="forgetholdfor">Forget  [% holdfor_firstname | html %] [% holdfor_surname | html %] ([% holdfor_cardnumber | html %])</a></li>
+                                            [% END %]
+                                            [% IF holdforclub %]
+                                                <li><a href="#" class="placeholdforclub">Place hold for [% holdforclub_name | html %]</a></li>
+                                                <li class="divider"></li>
+                                                <li><a href="#" id="forgetholdforclub">Forget  [% holdforclub_name | html %]</a></li>
+                                            [% END %]
                                         </ul>
                                     </div>
                                 [% ELSE %]
                                                         [% IF CAN_user_reserveforothers_place_holds %]
                                                             <a id="reserve_[% SEARCH_RESULT.biblionumber | html %]" href="/cgi-bin/koha/reserve/request.pl?biblionumber=[% SEARCH_RESULT.biblionumber | html %]">Holds ([% Biblio.HoldsCount( SEARCH_RESULT.biblionumber ) | html %])</a>
                                                             [% IF ( holdfor ) %] <span class="holdforlink">| <a href="/cgi-bin/koha/reserve/request.pl?biblionumber=[% SEARCH_RESULT.biblionumber | uri %]&amp;findborrower=[% holdfor_cardnumber | uri %]">Place hold for [% holdfor_firstname | html %] [% holdfor_surname | html %] ([% holdfor_cardnumber | html %])</a></span>[% END %]
+                                                            [% IF ( holdforclub ) %] <span class="holdforlink">| <a href="/cgi-bin/koha/reserve/request.pl?biblionumber=[% SEARCH_RESULT.biblionumber | uri %]&amp;club=[% holdforclub | uri %]">Place hold for [% holdforclub_name | html %]</a></span>[% END %]
                                                         [% ELSE %]
                                                             Holds ([% Biblio.HoldsCount( SEARCH_RESULT.biblionumber ) | html %])
                                                         [% END %]
                     <!-- Value will be set here by placeHold() -->
                     <input id="hold_form_biblios" type="hidden" name="biblionumbers" value="" />
                     <input type="hidden" name="findborrower" id="holdFor" value="" />
+                    <input type="hidden" name="club" id="holdForClub" value="" />
                     <input type="hidden" name="multi_hold" value="1"/>
                 </form>
 
 
             $("#searchheader").on("click",".placehold", function(){
                 $("#holdFor").val("");
+                $("#holdForClub").val("");
                 placeHold();
                 $(".btn-group").removeClass("open");
                 return false;
                 return false;
             });
 
-            $("#forgetholdfor").click(function(){
-                forgetPatron();
+            $(".placeholdforclub").click(function(){
+                holdForClub();
+                $(".btn-group").removeClass("open");
+                return false;
+            });
+
+            $("#forgetholdfor, #forgetholdforclub").click(function(){
+                forgetPatronAndClub();
                 $(".btn-group").removeClass("open");
                 return false;
             });
             return false;
         }
 
-        function forgetPatron(){
+        function forgetPatronAndClub(){
             $.removeCookie("holdfor", { path: '/' });
+            $.removeCookie("holdforclub", { path: '/' });
             $(".holdforlink").remove();
             $("#placeholdc").html("<a class=\"btn btn-default btn-xs placehold\" href=\"#\"><i class=\"fa fa-sticky-note-o\"></i> "+_("Place hold")+"</a>");
         }
 
         function holdfor(){
             $("#holdFor").val("");
+            $("#holdForClub").val("");
             placeHold();
         }
 
             $("#holdFor").val("[% holdfor_cardnumber | html %]");
             placeHold();
         }
+
+        function holdForClub() {
+            $("#holdForClub").val("[% holdforclub | html %]");
+            placeHold();
+        }
     </script>
 [% END %]
 
index 42d50ff..e4176a9 100644 (file)
                 [% END %]
 
                 [% IF clubs %]
-                    <table id="clubs-table">
-                        <thead>
-                            <tr>
-                                <th>Name</th>
-                                <th>Template</th>
-                                <th>Description</th>
-                                <th>Public enrollment</th>
-                                <th>Email required</th>
-                                <th>Library</th>
-                                <th>Start date</th>
-                                <th>End date</th>
-                                <th>Enrolled patrons</th>
-                                <th>&nbsp;</th>
-                            </tr>
-                        </thead>
-                        <tbody>
-                            [% FOREACH c IN clubs %]
-                                <tr>
-                                    <td>[% c.name | html %]</td>
-                                    <td>[% c.club_template.name | html %]</td>
-                                    <td>[% c.description | html %]</td>
-                                    <td>
-                                        [% IF c.club_template.is_enrollable_from_opac %]
-                                            Yes
-                                        [% ELSE %]
-                                            No
-                                        [% END %]
-                                    </td>
-                                    <td>
-                                        [% IF c.club_template.is_email_required %]
-                                            Yes
-                                        [% ELSE %]
-                                            No
-                                        [% END %]
-                                    </td>
-                                    <td>[% Branches.GetName( c.branchcode ) | html %]</td>
-                                    <td>
-                                        [% IF c.date_start %]
-                                            [% c.date_start | $KohaDates %]
-                                        [% END %]
-                                    </td>
-                                    <td>
-                                        [% IF c.date_end %]
-                                            [% c.date_end | $KohaDates %]
-                                        [% END %]
-                                    </td>
-                                    <td>
-                                        [% c.club_enrollments.count | html %]
-                                    </td>
-                                    <td class="actions">
-                                        <div class="dropdown">
-                                            <a class="btn btn-default btn-xs dropdown-toggle" id="clubactions[% c.id | html %]" role="button" data-toggle="dropdown" href="#">
-                                                Actions <b class="caret"></b>
-                                            </a>
-                                            <ul class="dropdown-menu pull-right" role="menu" aria-labelledby="clubactions[% c.id | html %]">
-                                                [% IF ( c.club_enrollments.count ) %]
-                                                    <li>
-                                                        <a href="club-enrollments.pl?id=[% c.id | uri %]">
-                                                            <i class="fa fa-list-ul"></i> Enrollments
-                                                        </a>
-                                                    </li>
-                                                [% ELSE %]
-                                                    <li class="disabled">
-                                                        <a href="club-enrollments.pl?id=[% c.id | uri %]">
-                                                            <i class="fa fa-list-ul"></i> Enrollments
-                                                        </a>
-                                                    </li>
-                                                [% END %]
-                                                [% IF CAN_user_clubs_edit_clubs %]
-                                                    <li>
-                                                        <a href="clubs-add-modify.pl?id=[% c.id | uri %]">
-                                                            <i class="fa fa-pencil"></i> Edit
-                                                        </a>
-                                                    </li>
-                                                    <li>
-                                                        <a href="#" onclick='ConfirmDeleteClub([% c.id | html %], "[% c.name | html %]", $(this) ); return false;'>
-                                                            <i class="fa fa-trash"></i> Delete
-                                                        </a>
-                                                    </li>
-                                                [% END %]
-                                            </ul>
-                                        </div>
-                                    </td>
-                                </tr>
-                            [% END %]
-                        </tbody>
-                    </table> <!-- /.clubs-table -->
+                    [% INCLUDE 'clubs-table.inc' %]
                 [% ELSE %]
                     [% IF club_templates %]
                         <div class="dialog message">No clubs defined.</div>
                 });
             }
         }
+
+        function SearchToHold(club_id) {
+            var date = new Date();
+            date.setTime(date.getTime() + (10 * 60 * 1000));
+            $.cookie("holdforclub", club_id, { path: "/", expires: date });
+            location.href="/cgi-bin/koha/catalogue/search.pl";
+        }
     </script>
 [% END %]
 
index 4a046b6..1cbc7af 100644 (file)
             if ( $('#clubs-tab').length ) {
                 $('#clubs-tab-link').on('click', function() {
                     $('#clubs-tab').text(_("Loading..."));
-                    $('#clubs-tab').load('/cgi-bin/koha/clubs/patron-clubs-tab.pl?borrowernumber=[% borrowernumber | html %]');
+                    $('#clubs-tab').load('/cgi-bin/koha/clubs/patron-clubs-tab.pl?borrowernumber=[% patron.borrowernumber | html %]');
                 });
             }
 
index 91e4ebb..5b0c482 100644 (file)
@@ -73,7 +73,7 @@
                 <h1>Confirm holds</h1>
             [% END %]
 
-            [% UNLESS patron OR patron.borrowernumber OR noitems %]
+            [% UNLESS club OR patron OR patron.borrowernumber OR noitems %]
                 [% IF ( messageborrower ) %]
                     <div class="dialog alert">
                         <h3>Patron not found</h3>
                     </div>
                 [% END %]
 
-                <form  id="holds_patronsearch" action="request.pl?biblionumber=[% biblionumber | html %]" method="post">
-                    <fieldset id="circ_holds_selectborrower" class="brief">
-                        [% UNLESS borrowers %]
-                            <label for="patron">Patron: </label>
-                            <div class="hint">Enter patron card number or partial name:</div>
-                            <input type="text" size="40" id="patron" class="focus" name="findborrower" autocomplete="off" />
-                            <input type="submit" value="Search" />
-                            [% IF multi_hold %]
-                                <input type="hidden" name="multi_hold" value="[% multi_hold | html %]"/>
-                                <input type="hidden" name="biblionumbers" value="[% biblionumbers | html %]"/>
-                            [% ELSE %]
-                                <input type="hidden" name="biblionumber" value="[% biblionumber | html %]" />
-                            [% END %]
-                        [% ELSE %]
+                [% IF ( messageclub ) %]
+                    <div class="dialog alert">
+                        <h3>Club not found</h3>
+                        <p>No club with this name, please, try another</p>
+                    </div>
+                [% END %]
+                <fieldset class="brief">
+                    <label>Seach Patrons or clubs</label>
+                    <div id="circ_holds_select">
+                        <ul class="nav nav-tabs" role="tablist">
+                            <li role="presentation"><a href="#holds_patronsearch_pane" aria-controls="holds_patronsearch_pane" role="tab" data-toggle="tab">Patrons</a></li>
+                            <li role="presentation"><a href="#holds_clubsearch_pane" aria-controls="holds_clubsearch_pane" role="tab" data-toggle="tab">Clubs</a></li>
+                        </ul>
+                        <div class="tab-content">
+                            <div role="tabpanel" class="tab-pane" id="holds_patronsearch_pane">
+                                <form  id="holds_patronsearch" action="request.pl?biblionumber=[% biblionumber | html %]" method="post">
+                                    <div class="hint">Enter patron card number or partial name:</div>
+                                    <input type="text" size="40" id="patron" class="focus" name="findborrower" autocomplete="off" />
+                                    <input type="submit" value="Search" />
+                                    [% IF multi_hold %]
+                                        <input type="hidden" name="multi_hold" value="[% multi_hold | html %]"/>
+                                        <input type="hidden" name="biblionumbers" value="[% biblionumbers | html %]"/>
+                                    [% ELSE %]
+                                        <input type="hidden" name="biblionumber" value="[% biblionumber | html %]" />
+                                    [% END %]
+
+                                    [% IF ( multi_hold ) %]
+                                        <input type="hidden" name="multi_hold" value="[% multi_hold | html %]"/>
+                                        <input type="hidden" name="biblionumbers" value="[% biblionumbers | html %]"/>
+                                    [% END %]
+                                </form> <!-- /#holds_patronsearch -->
+                            </div>
+                            <div role="tabpanel" class="tab-pane" id="holds_clubsearch_pane">
+                                <form  id="holds_clubsearch" action="request.pl?biblionumber=[% biblionumber | html %]" method="post">
+                                    <div class="hint">Enter club id or partial name:</div>
+                                    <input type="text" size="40" id="club" class="focus" name="findclub" autocomplete="off" />
+                                    <input type="submit" value="Search" />
+                                    [% IF multi_hold %]
+                                        <input type="hidden" name="multi_hold" value="[% multi_hold | html %]"/>
+                                        <input type="hidden" name="biblionumbers" value="[% biblionumbers | html %]"/>
+                                    [% ELSE %]
+                                        <input type="hidden" name="biblionumber" value="[% biblionumber | html %]" />
+                                    [% END %]
+
+                                    [% IF ( multi_hold ) %]
+                                        <input type="hidden" name="multi_hold" value="[% multi_hold | html %]"/>
+                                        <input type="hidden" name="biblionumbers" value="[% biblionumbers | html %]"/>
+                                    [% END %]
+                                </form> <!-- /#holds_patronsearch -->
+                            </div>
+                        </div>
+                    </div>
+                    <p>
+                        [% IF borrowers %]
                             [% INCLUDE 'circ-patron-search-results.inc' destination = "holds" %]
+                        [% ELSIF clubs %]
+                            [% INCLUDE 'clubs-table.inc' destination = "holds" %]
                         [% END %]
-                    </fieldset> <!-- /#circ_holds_selectborrower -->
+                    </p>
+                </fieldset>
+            [% ELSIF club %]
+                <div class="dialog alert hide clubalert">
+                </div>
+                <fieldset class="rows">
+                    <legend>Hold details</legend>
+                    <form action="/api/v1/clubs/[% club.id | html %]/holds" method="post" name="form" id="club-request-form">
 
-                    [% IF ( multi_hold ) %]
-                        <input type="hidden" name="multi_hold" value="[% multi_hold | html %]"/>
-                        <input type="hidden" name="biblionumbers" value="[% biblionumbers | html %]"/>
-                    [% END %]
-                </form> <!-- /#holds_patronsearch -->
+                        [% IF ( multi_hold ) %]
+                            <input type="hidden" name="multi_hold" value="[% multi_hold | html %]"/>
+                            <input type="hidden" name="biblionumbers" id="multi_hold_bibs" value="[% biblionumbers | html %]"/>
+                            <input type="hidden" name="bad_bibs" id="bad_bibs" value=""/>
+                            <input type="hidden" name="request" value="any"/>
+                            [% FOREACH biblioloo IN biblioloop %]
+                                <input type="hidden" name="title_[% biblioloo.biblionumber | html %]" value="[% biblioloo.title | html %]"/>
+                                <input type="hidden" name="rank_[% biblioloo.biblionumber | html %]" value="[% biblioloo.rank | html %]"/>
+                            [% END %]
+                        [% ELSE %]
+                            <input type="hidden" name="biblionumber" value="[% biblionumber | html %]" />
+                            <input type="hidden" name="title" value="[% biblio.title | html %]" />
+                            <input type="hidden" name="rank-request" value="[% fixedRank | html %]" />
+                        [% END # /IF multi_hold %]
+                        <ol>
+                            <li>
+                                <span class="label">Club: </span> [% club.name | html %]
+                            </li>
+                            <li>
+                                <span class="label">Description: </span> [% club.description | html %]
+                            </li>
+                            <li>
+                                <label for="pickup">Pickup at:</label>
+                                <select name="pickup" size="1" id="pickup">
+                                    [% PROCESS options_for_libraries libraries => Branches.all({ selected => club.branchcode, search_params => { pickup_location => 1 } }) %]
+                                </select>
+                            </li>
+                        </ol>
+                        <h2 style="padding: 0 1em;">Members</h2>
+                        <ol>
+                            [% FOREACH member IN members %]
+                                [% SET patron = member.patron %]
+                                <li style="padding: 0.5em 1em;">
+                                    <div><a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% patron.borrowernumber | uri %]">[% patron.firstname | html %] [% patron.surname | html %] ([% patron.cardnumber | html %])</a></div>
+                                    [% IF member.exceeded_maxreserves %]
+                                        <div>
+                                            <i class="fa fa-error"></i>
+                                            <strong>Too many holds: </strong> Patron can only place a maximum of [% maxreserves | html %] total holds.
+                                        </div>
+                                    [% END %]
+                                    [% IF ( member.expiry ) %]
+                                        <div>
+                                            <i class="fa fa-warning"></i>
+                                            <strong>Account has expired</strong>
+                                        </div>
+                                    [% END %]
+                                    [% IF patron.is_debarred %]
+                                        <div>
+                                            <i class="fa fa-warning"></i>
+                                            <strong>Patron has restrictions</strong>
+                                        </div>
+                                    [% END %]
+                                    [% IF amount_outstanding && Koha.Preference('maxoutstanding') && amount_outstanding > Koha.Preference('maxoutstanding') %]
+                                        <div>
+                                            <i class="fa fa-warning"></i>
+                                            <strong>Patron has outstanding fines: [% member.amount_outstanding | $Price %]</strong>
+                                        </div>
+                                    [% END %]
 
+                                    [% IF ( member.diffbranch ) %]
+                                        <div>
+                                            <i class="fa fa-warning"></i>
+                                            <strong>Pickup library is different.</strong> Patron's home library: ([% Branches.GetName(patron.branchcode) | html %] / [% patron.branchcode | html %] )
+                                        </div>
+                                    [% END %]
+                                </li>
+                            [% END %]
+                        </ol>
+                        [% UNLESS ( multi_hold ) %]
+                            <fieldset class="action">
+                                <input type="submit" value="Place hold" />
+                            </fieldset>
+                        [% ELSE %]
+                            <table id="requesttitles">
+                                <tr>
+                                    <th>&nbsp;</th>
+                                    <th>Title</th>
+                                    [% UNLESS ( item_level_itypes ) %]
+                                        <th>Item type</th>
+                                    [% END %]
+                                    <th>Priority</th>
+                                    <th>Information</th>
+                                </tr>
+                                [% FOREACH biblioloo IN biblioloop %]
+                                    [% IF ( biblioloo.warn ) %]
+                                        <tr class="onissue">
+                                    [% ELSE %]
+                                        <tr>
+                                    [% END %]
+                                        <td>
+                                            [% UNLESS ( biblioloo.warn ) %]
+                                                    <input class="multi_hold_item_checkbox" type="checkbox" checked="checked" title="[% biblioloo.biblionumber | html %]"/>
+                                                </td>
+                                            [% END %]
+                                        <td>
+                                            <ul>
+                                                <li>
+                                                    <a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% biblioloo.biblionumber | uri %]">[% biblioloo.title | html %]</a>
+                                                </li>
+                                                [% IF ( biblioloo.publicationyear ) %]
+                                                    <li>
+                                                        <span class="label">Publication year:</span> [% biblioloo.publicationyear | html %]
+                                                    </li>
+                                                [% END %]
+                                            </ul>
+                                            [% IF ( biblioloo.warn ) %]
+                                                <span class="not_holdable" title="[% biblioloo.biblionumber | html %]"></span>
+                                            [% END %]
+                                        </td>
+                                        [% UNLESS ( item_level_itypes ) %]
+                                            <td>
+                                                <img src="[% biblioloo.imageurl | html %]" alt="[% biblioloo.itypename | html %]" title="[% biblioloo.itypename | html %]" />
+                                            </td>
+                                        [% END %]
+                                        <td>[% biblioloo.rank | html %]</td>
+                                        <td>
+                                            [% IF ( biblioloo.checked_previously ) %]
+                                                <span>Patron has previously checked out this title</span><br/>
+                                            [% END %]
+                                            [% IF ( biblioloo.alreadyres ) %]
+                                                <ul>
+                                            [% ELSE %]
+                                                [% IF ( biblioloo.none_avail ) %]
+                                                    <ul>
+                                                [% END %]
+                                            [% END %]
+
+                                            [% IF ( biblioloo.alreadyres ) %]
+                                                <li>
+                                                    <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% patron.borrowernumber | uri %]">[% patron.firstname | html %] [% patron.surname | html %]</a>
+                                                    <strong>already has a hold</strong> on this item
+                                                </li>
+                                            [% END %]
+                                            [% IF ( biblioloo.none_avail ) %]
+                                                <li> <strong>No items are available</strong> to be placed on hold</li>
+                                            [% END %]
+
+                                            [% IF ( biblioloo.alreadyres ) %]
+                                                </ul>
+                                            [% ELSE %]
+                                                [% IF ( biblioloo.none_avail ) %]
+                                                    </ul>
+                                                [% END %]
+                                            [% END %]
+                                        </td>
+                                    </tr>
+                                [% END # /FOREACH biblioloo %]
+                            </table> <!-- /#requesttitles -->
+                        [% END %]
+                    </form>
+                </fieldset>
             [% ELSIF NOT noitems # /UNLESS patron %]
 
                 [% IF ( checked_previously && !multi_hold ) %]
 
                 <fieldset class="rows">
                     <legend>Hold details</legend>
-                    <form action="placerequest.pl" method="post" name="form" id="hold-request-form">
+                    <form action="/api/v1/holds" method="post" name="form" id="hold-request-form">
 
                         <input type="hidden" name="borrowernumber" value="[% patron.borrowernumber | html %]" />
                         <input type="hidden" name="type" value="str8" />
         columns_settings_borrowers_table = [% ColumnsSettings.GetColumns( 'circ', 'circulation', 'table_borrowers', 'json' ) | $raw %]
 
         $(document).ready(function() {
+            [% UNLESS clubs %]
+                $('#circ_holds_select').tabs({active: 0});
+            [% ELSE %]
+                $('#circ_holds_select').tabs({active: 1});
+            [% END %]
             function ToggleHoldsToPlace() {
                 if ( $("#requestany").prop('checked') ) {
                     $("#holds_to_place_count").prop('disabled', false);
                 "margin-right":"0em"
             });
 
+            $("#club-request-form").on("submit", function() {
+                let $t = $(this);
+                $('.clubalert').addClass('hide');
+                let options = {
+                    url: $t.attr('action'),
+                    method: $t.attr('method').toUpperCase(),
+                    contentType: 'application/json',
+                    data: JSON.stringify({
+                        biblio_id: biblionumber,
+                        pickup_library_id: $('select[name="pickup"]').val()
+                    })
+                };
+                if($('input[name="checkitem"]:checked').length)
+                    options.data.item_id = $('input[name="checkitem"]:checked').val();
+                $.ajax(options)
+                    .then(function(result) {
+                        let url = 'request.pl?biblionumber='+biblionumber+($('input[name="multi_hold"]').length && $('input[name="multi_hold"]').val()?'&multi_hold=1':'');
+                        document.location = url;
+                    })
+                    .fail(function(err) {
+                        $('.clubalert').removeClass('hide').html(err.responseJSON.error);
+                    });
+                return false;
+            });
+
             [% UNLESS ( multi_hold ) %]
                 $("#hold-request-form").on("submit", function(){
                     return check();
index 49ea545..c783243 100755 (executable)
@@ -53,6 +53,7 @@ use Koha::Items;
 use Koha::ItemTypes;
 use Koha::Libraries;
 use Koha::Patrons;
+use Koha::Clubs;
 
 my $dbh = C4::Context->dbh;
 my $input = new CGI;
@@ -75,8 +76,12 @@ my $itemtypes = { map { $_->{itemtype} => $_ } @{ Koha::ItemTypes->search_with_l
 my $findborrower = $input->param('findborrower');
 $findborrower = '' unless defined $findborrower;
 $findborrower =~ s|,| |g;
+my $findclub = $input->param('findclub');
+$findclub = '' unless defined $findclub && !$findborrower;
 my $borrowernumber_hold = $input->param('borrowernumber') || '';
+my $club_hold = $input->param('club')||'';
 my $messageborrower;
+my $messageclub;
 my $warnings;
 my $messages;
 my $exceeded_maxreserves;
@@ -135,6 +140,25 @@ if ($findborrower) {
     }
 }
 
+if($findclub) {
+    my $club = Koha::Clubs->find( { name => $findclub } );
+    if( $club ) {
+        $club_hold = $club->id;
+    } else {
+        my @clubs = Koha::Clubs->search( [
+            { name => { like => '%'.$findclub.'%' } },
+            { description => { like => '%'.$findclub.'%' } }
+        ] );
+        if( scalar @clubs == 1 ) {
+            $club_hold = $clubs[0]->id;
+        } elsif ( @clubs ) {
+            $template->param( clubs => \@clubs );
+        } else {
+            $messageclub = "'$findclub'";
+        }
+    }
+}
+
 my @biblionumbers = ();
 my $biblionumber = $input->param('biblionumber');
 my $biblionumbers = $input->param('biblionumbers');
@@ -203,7 +227,54 @@ if ($borrowernumber_hold && !$action) {
     );
 }
 
-$template->param( messageborrower => $messageborrower );
+if ($club_hold && !$borrowernumber_hold && !$action) {
+    my $club = Koha::Clubs->find($club_hold);
+
+    my $enrollments = $club->club_enrollments;
+
+    my $maxreserves = C4::Context->preference('maxreserves');
+    my $new_reserves_count = scalar( @biblionumbers );
+
+    my @members;
+
+    while(my $enrollment = $enrollments->next) {
+        next if $enrollment->is_canceled;
+        my $member = { patron => $enrollment->patron->unblessed };
+        my $reserves_count = $enrollment->patron->holds->count;
+        if ( $maxreserves
+            && ( $reserves_count + $new_reserves_count > $maxreserves ) )
+        {
+            $member->{new_reserves_allowed} = $maxreserves - $reserves_count > 0
+                ? $maxreserves - $reserves_count
+                : 0;
+            $member->{exceeded_maxreserves} = 1;
+        }
+        my $expiry_date = $enrollment->patron->dateexpiry;
+        $member->{expiry} = 0; # flag set if patron account has expired
+        if ($expiry_date and $expiry_date ne '0000-00-00' and
+            Date_to_Days(split /-/,$date) > Date_to_Days(split /-/,$expiry_date)) {
+            $member->{expiry} = 1;
+        }
+        $member->{amount_outstanding} = $enrollment->patron->account->balance;
+        if ( $enrollment->patron->branchcode ne C4::Context->userenv->{'branch'} ) {
+            $member->{diffbranch} = 1;
+        }
+
+        push @members, $member;
+    }
+
+    $template->param(
+        club                => $club,
+        members             => \@members,
+        maxreserves         => $maxreserves,
+        new_reserves_count  => $new_reserves_count
+    );
+}
+
+$template->param(
+    messageborrower => $messageborrower,
+    messageclub     => $messageclub
+);
 
 # FIXME launch another time GetMember perhaps until (Joubu: Why?)
 my $patron = Koha::Patrons->find( $borrowernumber_hold );