View | Details | Raw Unified | Return to bug 23258
Collapse All | Expand All

(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/modholds.tt (+276 lines)
Line 0 Link Here
1
[% USE raw %]
2
[% USE Asset %]
3
[% USE Koha %]
4
[% USE KohaDates %]
5
[% USE Branches %]
6
[% USE Categories %]
7
[% USE TablesSettings %]
8
[% PROCESS 'i18n.inc' %]
9
[% SET footerjs = 1 %]
10
[% INCLUDE 'doc-head-open.inc' %]
11
<title
12
    >[% FILTER collapse %]
13
        [% IF ( op == 'show' or op == 'show_results' ) %]
14
            [% IF ( op == 'show' ) %]
15
                [% t("Modifications") | html %]
16
                &rsaquo;
17
            [% ELSE %]
18
                [% t("Results") | html %]
19
                &rsaquo;
20
            [% END %]
21
        [% END %]
22
        [% t("Batch holds modification") | html %]
23
        &rsaquo; [% t("Tools") | html %] &rsaquo; [% t("Koha") | html %]
24
    [% END %]</title
25
>
26
[% INCLUDE 'doc-head-close.inc' %]
27
</head>
28
29
<body id="tools_modholds" class="tools">
30
[% WRAPPER 'header.inc' %]
31
    [% INCLUDE 'cat-search.inc' %]
32
[% END %]
33
34
[% WRAPPER 'sub-header.inc' %]
35
    [% WRAPPER breadcrumbs %]
36
        [% WRAPPER breadcrumb_item %]
37
            <a href="/cgi-bin/koha/tools/tools-home.pl">Tools</a>
38
        [% END %]
39
        [% IF ( op == 'show' or op == 'show_results' ) %]
40
            [% WRAPPER breadcrumb_item %]
41
                <a href="/cgi-bin/koha/tools/modholds.pl">Batch holds modification</a>
42
            [% END %]
43
            [% IF ( op == 'show' ) %]
44
                [% WRAPPER breadcrumb_item bc_active= 1 %]
45
                    [% t("Modifications") | html %]
46
                [% END %]
47
            [% ELSE %]
48
                [% WRAPPER breadcrumb_item bc_active= 1 %]
49
                    [% t("Results")| html %]
50
                [% END %]
51
            [% END %]
52
        [% ELSE %]
53
            [% WRAPPER breadcrumb_item bc_active= 1 %]
54
                <span>Batch holds modification</span>
55
            [% END %]
56
        [% END %]
57
    [% END #/ WRAPPER breadcrumbs %]
58
[% END #/ WRAPPER sub-header.inc %]
59
60
[% WRAPPER 'main-container.inc' aside='tools-menu' %]
61
    [% IF ( op == 'show_form' ) %]
62
        <h1>Batch holds modification</h1>
63
        <form id="holds_batchmod_form" method="post" enctype="multipart/form-data" action="/cgi-bin/koha/tools/modholds.pl">
64
            [% INCLUDE 'csrf-token.inc' %]
65
            <input type="hidden" name="op" value="cud-show" />
66
            <fieldset class="rows">
67
                <legend>Use a file of barcodes</legend>
68
                <ol>
69
                    <li>
70
                        <label for="barcodesuploadfile">File: </label> <input type="file" id="barcodesuploadfile" name="barcodesuploadfile" />
71
                        <div class="hint">File must contain one barcode per line.</div>
72
                    </li>
73
                </ol>
74
            </fieldset>
75
            <fieldset class="rows">
76
                <legend>Or list barcodes one by one</legend>
77
                <ol>
78
                    <li>
79
                        <label for="barcodeslist">Barcodes list (one barcode per line): </label>
80
                        <textarea rows="10" cols="30" id="barcodeslist" name="barcodeslist">[% barcodeslist | html %]</textarea>
81
                    </li>
82
                </ol>
83
            </fieldset>
84
            <fieldset class="rows">
85
                <legend>Action</legend>
86
                <ol>
87
                    <li>
88
                        <input type="radio" name="action" id="action_place_holds" value="place" checked="checked" />
89
                        <label for="action_place_holds">Place holds</label>
90
                    </li>
91
                    <li>
92
                        <input type="radio" name="action" id="action_cancel_holds" value="cancel" />
93
                        <label for="action_cancel_holds">Cancel holds</label>
94
                    </li>
95
                </ol>
96
            </fieldset>
97
            <fieldset class="rows">
98
                <legend id="action_type_legend">Place holds for</legend>
99
                <ol>
100
                    <li id="patron_search_line">
101
                        <label for="find_patron">Patron search: </label>
102
                        <input autocomplete="off" id="find_patron" type="text" style="width:150px" class="noEnterSubmit required" required="required" />
103
                        <input type="hidden" name="borrowernumber" id="borrowernumber" />
104
                    </li>
105
                    <li>
106
                        <label for="branch">Pickup at:</label>
107
                        <select name="branch" id="branch">
108
                            [% PROCESS options_for_libraries libraries => Branches.all( unfiltered => 1 ) %]
109
                        </select>
110
                    </li>
111
                </ol>
112
            </fieldset>
113
            <fieldset class="action">
114
                <input type="submit" class="btn btn-primary" value="Continue" />
115
                <a class="cancel" href="/cgi-bin/koha/tools/modholds.pl">Cancel</a>
116
            </fieldset>
117
        </form>
118
    [% END %]
119
120
    [% IF ( op == 'show' ||  op == 'cud-show' ) && ( !barcodes || !borrowernumber ) # Alert if no barcodes given %]
121
        [% op = 'noshow' # Change op to prevent display in code below %]
122
        <h1>Batch holds modification</h1>
123
        <div class="alert alert-warning">
124
            [% IF (!barcodes) %]<p>No barcodes given.</p>[% END %]
125
            [% IF (!borrowernumber) %]<p>No patron given.</p>[% END %]
126
            <form action="/cgi-bin/koha/tools/modholds.pl" method="get">
127
                <button type="submit" class="btn btn-default approve"><i class="fa fa-fw fa-check"></i> OK</button>
128
            </form>
129
        </div>
130
    [% END #Alert if no barcodes %]
131
132
    [% BLOCK show_holds_list %]
133
        [% IF holds %]
134
            <div id="cataloguing_additem_itemlist" class="page-section">
135
                <table id="holdst">
136
                    <thead>
137
                        <tr>
138
                            [% IF op == 'show' %]<th>Hold</th>[% END %]
139
                            <th>Title</th>
140
                            <th>Item</th>
141
                            <th>Current holds</th>
142
                            [% IF op == 'show' %]<th>Comment</th>[% END %]
143
                        </tr>
144
                    </thead>
145
                    <tbody>
146
                        [% FOREACH hold IN holds %]
147
                            <tr>
148
                                [% IF op == 'show' %]<td><input type="checkbox" name="holdable" [% IF !hold.holdable %]disabled="disabled"[% ELSE %]checked="checked"[% END %] value="[% hold.itemnumber | html %]" /></td>[% END %]
149
                                <td><a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% hold.biblionumber | uri %]">[% hold.title | html %]</a></td>
150
                                <td><a href="/cgi-bin/koha/catalogue/moredetail.pl?biblionumber=[% hold.biblionumber | uri %]&itemnumber=[% hold.itemnumber | uri %]">[% hold.barcode | html %]</a></td>
151
                                <td><a href="/cgi-bin/koha/reserve/request.pl?biblionumber=[% hold.biblionumber | uri %]">Show holds</a></td>
152
                                [% IF op == 'show' %]<td>[% IF !hold.holdable %]<div class="alert alert-warning">This item cannot be placed on hold</div>[% END %]</td>[% END %]
153
                            </tr>
154
                        [% END %]
155
                    </tbody>
156
                </table>
157
            </div>
158
        [% END %]
159
    [% END %]
160
161
    [% IF ( op == 'show' or op == 'show_results' ) %]
162
        <h1>Batch holds modification</h1>
163
        [% UNLESS ( op == 'show' ) %]
164
            <h2>Results</h2>
165
        [% END %]
166
        [% IF ( notfoundbarcodes ) %]
167
            <div class="alert alert-warning"><p>Warning, the following barcodes were not found:</p></div>
168
169
            <div class="page-section">
170
                <table style="margin:auto;">
171
                    <thead>
172
                        <tr><th>Barcodes not found</th></tr>
173
                    </thead>
174
                    <tbody>
175
                        [% FOREACH notfoundbarcode IN notfoundbarcodes %]
176
                            <tr><td>[% notfoundbarcode.barcode | html %]</td></tr>
177
                        [% END %]
178
                    </tbody>
179
                </table>
180
            </div>
181
            <!-- /.page-section -->
182
        [% END %]
183
184
        [% IF ( op == 'show_results' ) %]
185
            <p>
186
                [% IF place %]
187
                    The following items have been placed on hold
188
                [% END %]
189
                [% IF cancel %]
190
                    The following holds were canceled
191
                [% END %]
192
                for patron: <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% borrowernumber | uri %]">[% borrowersurname | html %][% IF ( borrowerfirstname ) %], [% borrowerfirstname | html %][% END %]</a></p
193
            >
194
            [% IF place %]
195
                <p>Pickup location: [% Branches.GetName( branch ) | html %]</p>
196
            [% END %]
197
            [% PROCESS show_holds_list %]
198
        [% END %]
199
200
        [% IF ( op == 'show' ) %]
201
            <form name="f" action="modholds.pl" method="post" id="batchmod-borrowers-form">
202
                [% INCLUDE 'csrf-token.inc' %]
203
                <input type="hidden" name="op" value="cud-do" />
204
                [% IF ( holds ) %]
205
                    <div class="btn-toolbar selections-toolbar">
206
                        <a id="selectallbutton" href="#"><i class="fa fa-check"></i> Select all</a> | <a id="clearallbutton" href="#"><i class="fa fa-times"></i> Clear all</a>
207
                    </div>
208
                    [% PROCESS show_holds_list %]
209
                    <input type="hidden" name="op" value="cud-do" />
210
                    <input type="hidden" name="action" value="[% action | html %]" />
211
                    <input type="hidden" name="branch" value="[% branch | html %]" />
212
                    <input type="hidden" name="borrowernumber" value="[% borrowernumber | html %]" />
213
                    <fieldset class="action">
214
                        <input type="submit" class="submit" value="Submit" />
215
                        <a href="/cgi-bin/koha/tool/modholds.pl" class="cancel">Cancel</a>
216
                    </fieldset>
217
                [% END %]
218
            </form>
219
        [% END %]
220
    [% END %]
221
    [% IF ( op == 'show_results' ) %]
222
        <p>
223
            <a href="/cgi-bin/koha/tools/modholds.pl" title="New batch holds modification">New batch holds modification</a>
224
        </p>
225
    [% END %]
226
[% END %]
227
228
[% MACRO jsinclude BLOCK %]
229
    [% INCLUDE 'calendar.inc' %]
230
    [% INCLUDE 'datatables.inc' %]
231
    [% Asset.js("js/tools-menu.js") | $raw %]
232
    [% Asset.js("js/members-patron-selections.js") | $raw %]
233
    <script>
234
        $(document).ready(function() {
235
236
            [% IF ( op == 'show_form' ) %]
237
                patron_autocomplete($("#find_patron"), {
238
                    'on-select-callback': function( event, ui ) {
239
                        var field = ui.item.patron_id;
240
                        $("#find_patron").val(ui.item.firstname + " " + ( ui.item.middle_name || "" ) + " " + ui.item.surname).focus();
241
                        $("#borrowernumber").val(ui.item.patron_id);
242
                        return false;
243
                    }
244
                });
245
246
                $("input[name='action']").change(function(){
247
                    selected_value = $("input[name='action']:checked").val();
248
                    if (selected_value == "place") {
249
                        $("#action_type_legend").text(__("Place holds for"));
250
                        $("#branch").prop("disabled", false);
251
                    } else {
252
                        $("#action_type_legend").text(__("Cancel holds for"));
253
                        $("#branch").prop("disabled", true);
254
                    }
255
                });
256
            [% END %]
257
258
            [% IF holds %]
259
                $("#selectallbutton").click(function() {
260
                    $("#holdst").find("input:checkbox").each(function() {
261
                        $(this).prop("checked", true);
262
                    });
263
                    return false;
264
                });
265
                $("#clearallbutton").click(function() {
266
                    $("#holdst").find("input:checkbox").each(function() {
267
                        $(this).prop("checked", false);
268
                    });
269
                    return false;
270
                });
271
            [% END %]
272
        });
273
    </script>
274
[% END %]
275
276
[% INCLUDE 'intranet-bottom.inc' %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt (+5 lines)
Lines 73-78 Link Here
73
                    <dd>Create printable patron cards</dd>
73
                    <dd>Create printable patron cards</dd>
74
                [% END %]
74
                [% END %]
75
75
76
                [% IF ( CAN_user_reserveforothers ) %]
77
                    <dt><a href="/cgi-bin/koha/tools/modholds.pl">Batch place or cancel holds</a></dt>
78
                    <dd>Batch place holds or cancel holds</dd>
79
                [% END %]
80
76
                [% IF ( CAN_user_tools_delete_anonymize_patrons ) %]
81
                [% IF ( CAN_user_tools_delete_anonymize_patrons ) %]
77
                    <dt><a href="/cgi-bin/koha/tools/cleanborrowers.pl">Batch patron deletion and anonymization</a></dt>
82
                    <dt><a href="/cgi-bin/koha/tools/cleanborrowers.pl">Batch patron deletion and anonymization</a></dt>
78
                    <dd>Batch delete patrons and delete patron circulation history</dd>
83
                    <dd>Batch delete patrons and delete patron circulation history</dd>
(-)a/tools/modholds.pl (-1 / +204 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/perl
2
3
# Copyright 2025 BibLibre
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
# modborrowers.pl
21
#
22
# Batch Edit Patrons
23
# Modification for patron's fields:
24
# surname firstname branchcode categorycode city state zipcode country sort1
25
# sort2 dateenrolled dateexpiry borrowernotes protected
26
# And for patron attributes.
27
28
use Modern::Perl;
29
use CGI      qw ( -utf8 );
30
use C4::Auth qw( get_template_and_user );
31
use C4::Members;
32
use C4::Reserves qw( CanItemBeReserved AddReserve );
33
use C4::Output   qw( output_html_with_http_headers );
34
use C4::Context;
35
use Koha::DateUtils    qw( dt_from_string );
36
use Koha::List::Patron qw( GetPatronLists );
37
use Koha::Libraries;
38
use Koha::Patron::Categories;
39
use Koha::Patron::Debarments qw( AddDebarment DelDebarment );
40
use Koha::Patrons;
41
use List::MoreUtils qw(uniq);
42
use Koha::Patron::Messages;
43
44
my $input          = CGI->new;
45
my $op             = $input->param('op') || 'show_form';
46
my $action         = $input->param('action');
47
my $branch         = $input->param('branch');
48
my $borrowernumber = $input->param('borrowernumber');
49
50
my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
51
    {
52
        template_name => "tools/modholds.tt",
53
        query         => $input,
54
        type          => "intranet",
55
        flagsrequired => { reserveforothers => "*" },
56
    }
57
);
58
59
my $logged_in_user = Koha::Patrons->find($loggedinuser);
60
61
if ( $logged_in_user->is_superlibrarian ) {
62
    $template->param( CAN_user_reserveforothers => 1 );
63
}
64
65
my $dbh = C4::Context->dbh;
66
67
# Show borrower informations
68
if ( $op eq 'cud-show' || $op eq 'show' ) {
69
    my @barcodes;
70
    my @notfoundbarcodes;
71
    my @itemnumbers;
72
    my $borrower = Koha::Patrons->find( { borrowernumber => $borrowernumber } );
73
74
    # Get cardnumbers from a file or the input area
75
    if ( my $barcodeslist = $input->param('barcodeslist') ) {
76
77
        # User submitted a list of barcodes
78
        push @barcodes, split( /\s\n/, $barcodeslist );
79
    } elsif ( my $barcodesuploadfile = $input->param('barcodesuploadfile') ) {
80
81
        # User uploaded a file of card numbers
82
        binmode $barcodesuploadfile, ':encoding(UTF-8)';
83
        while ( my $content = <$barcodesuploadfile> ) {
84
            next unless $content;
85
            $content =~ s/[\r\n]*$//;
86
            push @barcodes, $content if $content;
87
        }
88
    }
89
90
    @barcodes = uniq(@barcodes);
91
92
    for my $barcode (@barcodes) {
93
        chomp $barcode;
94
        my $item = Koha::Items->find( { barcode => $barcode } );
95
        if ($item) {
96
            push @itemnumbers, $item->itemnumber;
97
        } else {
98
            push @notfoundbarcodes, $barcode;
99
        }
100
101
        if (@notfoundbarcodes) {
102
            my @notfoundbarcodesloop = map { { barcode => $_ } } @notfoundbarcodes;
103
            $template->param( notfoundbarcodes => \@notfoundbarcodesloop );
104
        }
105
        my @holdloop;
106
        if (@itemnumbers) {
107
            foreach my $itemnumber (@itemnumbers) {
108
                my $item     = Koha::Items->find( { itemnumber => $itemnumber } );
109
                my $biblio   = Koha::Biblios->find( { biblionumber => $item->biblionumber } );
110
                my $holdable = CanItemBeReserved( $borrower, $item )->{status};
111
                push @holdloop,
112
                    {
113
                    'biblionumber' => $biblio->biblionumber,
114
                    'title'        => $biblio->title,
115
                    'itemnumber'   => $item->itemnumber,
116
                    'barcode'      => $item->barcode,
117
                    'holdable'     => ( $action eq "cancel" || $holdable eq 'OK' )
118
                    ? 1
119
                    : 0,
120
                    };
121
            }
122
123
        }
124
        $op = "show";
125
        $template->param(
126
            show              => 1,
127
            holds             => \@holdloop,
128
            barcodes          => \@barcodes,
129
            borrowernumber    => $borrowernumber,
130
            borrowersurname   => $borrower->surname,
131
            borrowerfirstname => $borrower->firstname,
132
            branch            => $branch,
133
            action            => $action,
134
            op                => $op
135
        );
136
    }
137
}
138
139
# Process modifications
140
if ( $op eq 'cud-do' ) {
141
142
    $op = "show_results";    # We have process modifications, the user want to view its
143
144
    my $branch         = $input->param('branch');
145
    my $borrowernumber = $input->param('borrowernumber');
146
    my $action         = $input->param('action');
147
    my @itemnumbers    = $input->multi_param('holdable');
148
    my @holdloop;
149
    foreach my $itemnumber (@itemnumbers) {
150
        my $item         = Koha::Items->find( { itemnumber => $itemnumber } );
151
        my $biblionumber = $item->biblionumber;
152
        my $biblio       = Koha::Biblios->find( { biblionumber => $item->biblionumber } );
153
154
        if ( $action eq "place" ) {
155
            my $reserve_id = AddReserve(
156
                {
157
                    branchcode     => $branch,
158
                    borrowernumber => $borrowernumber,
159
                    biblionumber   => $biblionumber,
160
                    itemnumber     => $itemnumber
161
                }
162
            );
163
        } else {
164
            my $holds = Koha::Holds->search(
165
                {
166
                    itemnumber     => $itemnumber,
167
                    borrowernumber => $borrowernumber
168
                }
169
            );
170
            if ($holds) {
171
                while ( my $hold = $holds->next ) {
172
                    $hold->cancel;
173
                }
174
            }
175
        }
176
        push @holdloop,
177
            {
178
            'biblionumber' => $biblio->biblionumber,
179
            'title'        => $biblio->title,
180
            'itemnumber'   => $item->itemnumber,
181
            'barcode'      => $item->barcode,
182
            };
183
    }
184
    my $borrower = Koha::Patrons->find( { borrowernumber => $borrowernumber } );
185
    $template->param(
186
        result            => 1,
187
        holds             => \@holdloop,
188
        borrowernumber    => $borrowernumber,
189
        borrowersurname   => $borrower->surname,
190
        borrowerfirstname => $borrower->firstname,
191
        branch            => $branch,
192
        cancel            => $action eq "cancel" ? 1 : 0,
193
        place             => $action eq "place"  ? 1 : 0,
194
        op                => $op
195
    );
196
197
    #    $template->param( errors => \@errors );
198
}
199
200
$template->param(
201
    op => $op,
202
);
203
output_html_with_http_headers $input, $cookie, $template->output;
204
exit;

Return to bug 23258