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

(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/tools-menu.inc (+3 lines)
Lines 56-61 Link Here
56
    [% IF ( CAN_user_tools_items_batchmod ) %]
56
    [% IF ( CAN_user_tools_items_batchmod ) %]
57
	<li><a href="/cgi-bin/koha/tools/batchMod.pl">Batch item modification</a></li>
57
	<li><a href="/cgi-bin/koha/tools/batchMod.pl">Batch item modification</a></li>
58
    [% END %]
58
    [% END %]
59
    [% IF CAN_user_tools_records_batchdel %]
60
      <li><a href="/cgi-bin/koha/tools/batch_delete_records.pl">Batch record deletion</a></li>
61
    [% END %]
59
    [% IF ( CAN_user_tools_export_catalog ) %]
62
    [% IF ( CAN_user_tools_export_catalog ) %]
60
    <li><a href="/cgi-bin/koha/tools/export.pl">Export data</a></li>
63
    <li><a href="/cgi-bin/koha/tools/export.pl">Export data</a></li>
61
    [% END %]
64
    [% END %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/basket/basket.tt (+6 lines)
Lines 101-106 function placeHold () { Link Here
101
        [% END %]
101
        [% END %]
102
        </ul>
102
        </ul>
103
    </div>
103
    </div>
104
    <div class="btn-group">
105
        <a class="btn btn-small dropdown-toggle" data-toggle="dropdown" href="#" id="actioncart"><i class="icon-play"></i> Actions <span class="caret"></span> </a>
106
        <ul class="dropdown-menu">
107
            <li><a href="/cgi-bin/koha/tools/batch_delete_records.pl?op=list&amp;bib_list=[% bib_list %]&amp;type=biblio">Delete</a></li>
108
        </ul>
109
    </div>
104
    <a class="btn btn-small" href="basket.pl" onclick="printBasket(); return false;"><i class="icon-print"></i> Print</a>
110
    <a class="btn btn-small" href="basket.pl" onclick="printBasket(); return false;"><i class="icon-print"></i> Print</a>
105
    <a class="btn btn-small" href="basket.pl" onclick="delBasket('popup'); return false;"><i class="icon-trash"></i> Empty and close</a>
111
    <a class="btn btn-small" href="basket.pl" onclick="delBasket('popup'); return false;"><i class="icon-trash"></i> Empty and close</a>
106
    <a class="btn btn-small close" href="basket.pl"><i class="icon-remove-sign"></i> Hide window</a>
112
    <a class="btn btn-small close" href="basket.pl"><i class="icon-remove-sign"></i> Hide window</a>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/batch_delete_records.tt (+237 lines)
Line 0 Link Here
1
[% PROCESS 'authorities-search-results.inc' %]
2
[% INCLUDE 'doc-head-open.inc' %]
3
<title>Koha &rsaquo; Tools &rsaquo; Batch record deletion</title>
4
[% INCLUDE 'doc-head-close.inc' %]
5
<link rel="stylesheet" type="text/css" href="[% themelang %]/css/datatables.css" />
6
<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.dataTables.min.js"></script>
7
[% INCLUDE 'datatables-strings.inc' %]
8
<script type="text/javascript" src="[% themelang %]/js/datatables.js"></script>
9
<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.checkboxes.min.js"></script>
10
<script type="text/javascript">
11
//<![CDATA[
12
var MSG_CANNOT_BE_DELETED = _("This record cannot be deleted, at least one item is currently issued");
13
$(document).ready(function() {
14
  $("#selectall").click(function(e){
15
    e.preventDefault();
16
    $(".records").checkCheckboxes();
17
  });
18
  $("#clearall").click(function(e){
19
    e.preventDefault();
20
    $(".records").unCheckCheckboxes();
21
  });
22
  $("#selectwithoutitems").click(function(e){
23
    e.preventDefault();
24
    $("#biblios").checkCheckboxes(":input[data-items='0']");
25
  });
26
  $("#selectnotreserved").click(function(e){
27
    e.preventDefault();
28
    $("#biblios").checkCheckboxes(":input[data-reserves='0']");
29
30
  });
31
  $("#clearlinkedtobiblio").click(function(e){
32
    e.preventDefault();
33
    $("#authorities").unCheckCheckboxes(":not(input[data-usage='0'])");
34
  });
35
  $("#selectall").click();
36
37
  [% IF recordtype == 'biblio' %]
38
    $(".records input:checkbox[data-issues!='0']").each(function(){
39
      $(this).attr('title', MSG_CANNOT_BE_DELETED)
40
      $(this).attr('disabled', true);
41
      $(this).attr('checked', false);
42
      $(this).parents('tr').find('td').css('background-color', 'red');
43
    });
44
  [% END %]
45
46
  $("table#biblios").dataTable($.extend(true, {}, dataTablesDefaults, {
47
    "aoColumnDefs": [
48
      { "aTargets": [ 0 ], "bSortable": false, "bSearchable": false },
49
      { "aTargets": [ 3, 4 ], "sType": "num-html" }
50
    ],
51
    "sDom": 't',
52
    "aaSorting": [],
53
    "bPaginate": false
54
  }));
55
56
  $("table#authorities").dataTable($.extend(true, {}, dataTablesDefaults, {
57
    "aoColumnDefs": [
58
      { "aTargets": [ 0 ], "bSortable": false, "bSearchable": false },
59
      { "aTargets": [ 3 ], "sType": "num-html" }
60
    ],
61
    "sDom": 't',
62
    "aaSorting": [],
63
    "bPaginate": false
64
  }));
65
});
66
//]]>
67
</script>
68
</head>
69
<body id="tools_batch_delete_records" class="tools">
70
[% INCLUDE 'header.inc' %]
71
[% INCLUDE 'cat-search.inc' %]
72
73
<div id="breadcrumbs">
74
    <a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo;
75
    <a href="/cgi-bin/koha/tools/tools-home.pl">Tools</a> &rsaquo;
76
    <a href="/cgi-bin/koha/tools/batch_delete_records.pl">Batch record deletion</a>
77
</div>
78
79
<div id="doc3" class="yui-t2">
80
<div id="bd">
81
<div id="yui-main">
82
<div class="yui-b">
83
  <h1>Batch record deletion</h1>
84
  [% FOREACH message IN messages %]
85
    [% IF message.type == 'success' %]
86
      <div class="dialog message">
87
    [% ELSIF message.type == 'warning' %]
88
      <div class="dialog alert">
89
    [% ELSIF message.type == 'error' %]
90
      <div class="dialog error" style="margin:auto;">
91
    [% END %]
92
    [% IF message.code == 'biblio_not_exists' %]
93
      The biblionumber [% message.biblionumber %] does not exist in the database.
94
    [% ELSIF message.code == 'authority_not_exists' %]
95
      The authority id [% message.authid %] does not exist in the database.
96
    [% ELSIF message.code == 'item_issued' %]
97
      At least one item issued for the biblio [% message.biblionumber %].
98
    [% ELSIF message.code == 'reserve_not_cancelled' %]
99
      The biblio [% message.biblionumber %] has not been deleted. A reserve (reserve_id [% message.reserve_id %]) caused an error on cancel.
100
    [% ELSIF message.code == 'item_not_deleted' %]
101
      The biblio [% message.biblionumber %] has not been deleted. An item (itemnumber [% message.itemnumber %]) caused an error on delete.
102
    [% ELSIF message.code == 'biblio_not_deleted' %]
103
      The biblio [% message.biblionumber %] has not been deleted. An error occurred on deleting it.
104
    [% ELSIF message.code == 'authority_not_deleted' %]
105
      The authority [% message.authid %] has not been deleted. An error occurred on deleting it.
106
    [% ELSIF message.code == 'biblio_deleted' %]
107
      The biblio [% message.biblionumber %] has successfully been deleted.
108
    [% ELSIF message.code == 'authority_deleted' %]
109
      The authority [% message.authid %] has successfully been deleted.
110
    [% END %]
111
    [% IF message.error %]
112
      (The error was: [% message.error%], see the Koha logfile for more information).
113
    [% END %]
114
    </div>
115
  [% END %]
116
  [% IF op == 'form' %]
117
    <form method="post" enctype="multipart/form-data" action="/cgi-bin/koha/tools/batch_delete_records.pl">
118
      <fieldset class="rows">
119
        <legend>Record type</legend>
120
        <ol>
121
          <li><label for="biblio_type">Biblios: </label><input type="radio" name="recordtype" value="biblio" id="biblio_type" checked="checked" /></li>
122
          <li><label for="authority_type">Authorities: </label><input type="radio" name="recordtype" value="authority" id="authority_type" /></li>
123
        </ol>
124
      </fieldset>
125
      <fieldset class="rows">
126
        <legend>Use a file</legend>
127
        <ol>
128
          <li><label for="uploadfile">File: </label> <input type="file" id="uploadfile" name="uploadfile" /></li>
129
        </ol>
130
      </fieldset>
131
      <fieldset class="rows">
132
        <legend>Or enter a list of record numbers</legend>
133
        <ol>
134
          <li>
135
            <label for="recordnumber_list">Record number list (one per line): </label>
136
            <textarea rows="10" cols="30" id="recordnumber_list" name="recordnumber_list"></textarea>
137
          </li>
138
        </ol>
139
      </fieldset>
140
      <fieldset class="action">
141
        <input type="hidden" name="op" value="list" />
142
        <input type="submit" value="Continue" class="button" />
143
        <a class="cancel" href="/cgi-bin/koha/tools/tools-home.pl">Cancel</a>
144
      </fieldset>
145
    </form>
146
  [% ELSIF op == 'list' %]
147
    [% IF records %]
148
      [% IF recordtype == 'biblio' %]
149
        <div id="toolbar">
150
          <a id="selectall" href="#">Select All</a>
151
          | <a id="clearall" href="#">Clear All</a>
152
          | <a id="selectwithoutitems" href="#">Select without items</a>
153
          | <a id="selectnotreserved" href="#">Select not reserved</a>
154
        </div>
155
        <form action="/cgi-bin/koha/tools/batch_delete_records.pl" method="post">
156
          <table id="biblios" class="records">
157
            <thead>
158
              <tr>
159
                <th></th>
160
                <th>Biblionumber</th>
161
                <th>Title</th>
162
                <th>Items</th>
163
                <th>Reserves</th>
164
                <th>Issues</th>
165
              </tr>
166
            </thead>
167
            <tbody>
168
              [% FOR biblio IN records %]
169
                <tr>
170
                  <td><input type="checkbox" name="record_id" value="[% biblio.biblionumber %]" data-items="[% biblio.itemnumbers.size %]" data-issues="[% biblio.issues_count %]" data-reserves="[% biblio.reserves.size %]" /></td>
171
                  <td>[% biblio.biblionumber %]</td>
172
                  <td><a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% biblio.biblionumber %]">[% biblio.title %]</a></td>
173
                  <td><a href="/cgi-bin/koha/catalogue/moredetail.pl?biblionumber=[% biblio.biblionumber %]">[% biblio.itemnumbers.size %]</a></td>
174
                  <td><a href="/cgi-bin/koha/reserve/request.pl?biblionumber=[% biblio.biblionumber %]">[% biblio.reserves.size %]</a></td>
175
                  <td><a href="/cgi-bin/koha/catalogue/issuehistory.pl?biblionumber=[% biblio.biblionumber %]">[% biblio.issues_count %]</a></td>
176
                </tr>
177
              [% END %]
178
            </tbody>
179
          </table>
180
          <div class="note">Reminder: this action will delete all selected biblios, attached subscriptions, existing holds and items!</div>
181
      [% ELSE %]
182
        <div id="toolbar">
183
          <a id="selectall" href="#">Select All</a>
184
          | <a id="clearall" href="#">Clear All</a>
185
          | <a id="clearlinkedtobiblio" href="#">Clear linked to biblio </a>
186
        </div>
187
        <form action="/cgi-bin/koha/tools/batch_delete_records.pl" method="post">
188
          <table id="authorities" class="records">
189
            <thead>
190
              <tr>
191
                <th></th>
192
                <th>Authid</th>
193
                <th>Summary</th>
194
                <th>Used in</th>
195
              </tr>
196
            </thead>
197
            <tbody>
198
              [% FOR authority IN records %]
199
                <tr>
200
                  <td><input type="checkbox" name="record_id" value="[% authority.authid %]" data-usage="[% authority.count_usage %]" /></td>
201
                  <td><a href="/cgi-bin/koha/authorities/detail.pl?authid=[% authority.authid %]">[% authority.authid %]</a></td>
202
                  <td>[% PROCESS authresult summary=authority.summary %]</td>
203
                  <td><a href="/cgi-bin/koha/catalogue/search.pl?type=intranet&op=do_search&idx=an,phr&q=[% authority.authid %]">[% authority.count_usage %] biblio(s)</a></td>
204
                </tr>
205
              [% END %]
206
            </tbody>
207
          </table>
208
          <div class="note">Reminder: this action will delete all selected authorities!</div>
209
      [% END %]
210
        <fieldset class="action">
211
          <input type="hidden" name="op" value="delete" />
212
          <input type="hidden" name="recordtype" value="[% recordtype %]" />
213
          <input type="submit" value="Delete selected records" class="button" />
214
          <a class="cancel" href="/cgi-bin/koha/tools/batch_delete_records.pl">Cancel</a>
215
        </fieldset>
216
      </form>
217
    [% ELSE %]
218
      There is no record ids defined.
219
    [% END %]
220
  [% ELSIF op == 'report' %]
221
    [% IF report.total_records == report.total_success %]
222
      All records have successfully been deleted!
223
    [% ELSE %]
224
      [% report.total_success %] / [% report.total_records %] records have successfully been deleted.
225
      Some errors occurred.
226
    [% END %]
227
    <p><a href="/cgi-bin/koha/tools/batch_delete_records.pl" title="New batch record deletion">New batch record deletion</a></p>
228
  [% ELSE %]
229
    No action defined for the template.
230
  [% END %]
231
</div>
232
</div>
233
<div class="yui-b">
234
  [% INCLUDE 'tools-menu.inc' %]
235
</div>
236
</div>
237
[% INCLUDE 'intranet-bottom.inc' %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt (-1 / +6 lines)
Lines 121-127 Link Here
121
    <dt><a href="/cgi-bin/koha/tools/batchMod.pl">Batch item modification</a></dt>
121
    <dt><a href="/cgi-bin/koha/tools/batchMod.pl">Batch item modification</a></dt>
122
    <dd>Modify items in a batch</dd>
122
    <dd>Modify items in a batch</dd>
123
    [% END %]
123
    [% END %]
124
    
124
125
    [% IF CAN_user_tools_records_batchdel %]
126
      <dt><a href="/cgi-bin/koha/tools/batch_delete_records.pl">Batch record deletion</a></dt>
127
      <dd>Delete a batch of records (biblios or authorities)</dd>
128
    [% END %]
129
125
    [% IF ( CAN_user_tools_export_catalog ) %]
130
    [% IF ( CAN_user_tools_export_catalog ) %]
126
    <dt><a href="/cgi-bin/koha/tools/export.pl">Export data</a></dt>
131
    <dt><a href="/cgi-bin/koha/tools/export.pl">Export data</a></dt>
127
    <dd>Export bibliographic, holdings, and authority records</dd>
132
    <dd>Export bibliographic, holdings, and authority records</dd>
(-)a/tools/batch_delete_records.pl (-1 / +230 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/perl
2
3
# This file is part of Koha.
4
#
5
# Copyright 2013 BibLibre
6
#
7
# Koha is free software; you can redistribute it and/or modify
8
# it under the terms of the GNU General Public License as
9
# published by the Free Software Foundation; either version 3
10
# of the License, or (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
18
# Public License along with Koha; if not, see
19
# <http://www.gnu.org/licenses>
20
21
use Modern::Perl;
22
23
use CGI;
24
use List::MoreUtils qw( uniq );
25
26
use C4::Auth;
27
use C4::Output;
28
use C4::AuthoritiesMarc;
29
use C4::Biblio;
30
31
my $input = new CGI;
32
my $dbh = C4::Context->dbh;
33
my $op = $input->param('op') // q|form|;
34
my $recordtype = $input->param('recordtype') // 'biblio';
35
36
my ($template, $loggedinuser, $cookie) = get_template_and_user({
37
        template_name => 'tools/batch_delete_records.tt',
38
        query => $input,
39
        type => "intranet",
40
        authnotrequired => 0,
41
        flagsrequired => { tools => 'biblio_batchdel' },
42
});
43
44
my @records;
45
my @messages;
46
if ( $op eq 'form' ) {
47
    # Display the form
48
    $template->param( op => 'form' );
49
} elsif ( $op eq 'list' ) {
50
    # List all records to process
51
    my @record_ids;
52
    if ( my $bib_list = $input->param('bib_list') ) {
53
        # Come from the basket
54
        @record_ids = split /\//, $bib_list;
55
        $recordtype = 'biblio';
56
    } elsif ( my $uploadfile = $input->param('uploadfile') ) {
57
        # A file of id is given
58
        while ( my $content = <$uploadfile> ) {
59
            next unless $content;
60
            $content =~ s/[\r\n]*$//;
61
            push @record_ids, $content if $content;
62
        }
63
    } else {
64
        # The user enters manually the list of id
65
        push @record_ids, split( /\s\n/, $input->param('recordnumber_list') );
66
    }
67
68
    for my $record_id ( uniq @record_ids ) {
69
        if ( $recordtype eq 'biblio' ) {
70
            # Retrieve biblio information
71
            my $biblio = C4::Biblio::GetBiblio( $record_id );
72
            unless ( $biblio ) {
73
                push @messages, {
74
                    type => 'warning',
75
                    code => 'biblio_not_exists',
76
                    biblionumber => $record_id,
77
                };
78
                next;
79
            }
80
            $biblio->{itemnumbers} = C4::Items::GetItemnumbersForBiblio( $record_id );
81
            $biblio->{reserves} = C4::Reserves::GetReservesFromBiblionumber( $record_id );
82
            $biblio->{issues_count} = C4::Biblio::CountItemsIssued( $record_id );
83
            push @records, $biblio;
84
        } else {
85
            # Retrieve authority information
86
            my $authority = C4::AuthoritiesMarc::GetAuthority( $record_id );
87
            unless ( $authority ) {
88
                push @messages, {
89
                    type => 'warning',
90
                    code => 'authority_not_exists',
91
                    authid => $record_id,
92
                };
93
                next;
94
            }
95
96
            $authority = {
97
                authid => $record_id,
98
                summary => C4::AuthoritiesMarc::BuildSummary( $authority, $record_id ),
99
                count_usage => C4::AuthoritiesMarc::CountUsage( $record_id ),
100
            };
101
            push @records, $authority;
102
        }
103
    }
104
    $template->param(
105
        records => \@records,
106
        op => 'list',
107
    );
108
} elsif ( $op eq 'delete' ) {
109
    # We want to delete selected records!
110
    my @record_ids = $input->param('record_id');
111
    my $dbh = C4::Context->dbh;
112
    $dbh->{AutoCommit} = 0;
113
    $dbh->{RaiseError} = 1;
114
115
    my $error;
116
    my $report = {
117
        total_records => 0,
118
        total_success => 0,
119
    };
120
    RECORD_IDS: for my $record_id ( sort { $a <=> $b } @record_ids ) {
121
        $report->{total_records}++;
122
        next unless $record_id;
123
        if ( $recordtype eq 'biblio' ) {
124
            # Biblios
125
            my $biblionumber = $record_id;
126
            # First, checking if issues exist.
127
            # If yes, nothing to do
128
            if ( C4::Biblio::CountItemsIssued( $biblionumber ) ) {
129
                push @messages, {
130
                    type => 'warning',
131
                    code => 'item_issued',
132
                    biblionumber => $biblionumber,
133
                };
134
                $dbh->rollback;
135
                next;
136
            }
137
138
            # Cancel reserves
139
            my $reserves = C4::Reserves::GetReservesFromBiblionumber( $biblionumber );
140
            for my $reserve ( @$reserves ) {
141
                eval{
142
                    C4::Reserves::CancelReserve( { reserve_id => $reserve->{reserve_id} } );
143
                };
144
                if ( $@ ) {
145
                    push @messages, {
146
                        type => 'error',
147
                        code => 'reserve_not_cancelled',
148
                        biblionumber => $biblionumber,
149
                        reserve_id => $reserve->{reserve_id},
150
                        error => $@,
151
                    };
152
                    $dbh->rollback;
153
                    next RECORD_IDS;
154
                }
155
            }
156
157
            # Delete items
158
            my @itemnumbers = @{ C4::Items::GetItemnumbersForBiblio( $biblionumber ) };
159
            ITEMNUMBER: for my $itemnumber ( @itemnumbers ) {
160
                my $error = eval { C4::Items::DelItemCheck( $dbh, $biblionumber, $itemnumber ) };
161
                if ( $error != 1 or $@ ) {
162
                    push @messages, {
163
                        type => 'error',
164
                        code => 'item_not_deleted',
165
                        biblionumber => $biblionumber,
166
                        itemnumber => $itemnumber,
167
                        error => ($@ ? $@ : $error),
168
                    };
169
                    $dbh->rollback;
170
                    next BIBLIONUMBER;
171
                }
172
            }
173
174
            # Finally, delete the biblio
175
            my $error = eval {
176
                C4::Biblio::DelBiblio( $biblionumber );
177
            };
178
            if ( $error or $@ ) {
179
                push @messages, {
180
                    type => 'error',
181
                    code => 'biblio_not_deleted',
182
                    biblionumber => $biblionumber,
183
                    error => ($@ ? $@ : $error),
184
                };
185
                $dbh->rollback;
186
                next;
187
            }
188
189
            push @messages, {
190
                type => 'success',
191
                code => 'biblio_deleted',
192
                biblionumber => $biblionumber,
193
            };
194
            $report->{total_success}++;
195
            $dbh->commit;
196
        } else {
197
            # Authorities
198
            my $authid = $record_id;
199
            my $r = eval { C4::AuthoritiesMarc::DelAuthority( $authid ) };
200
            if ( $r eq '0E0' or $@ ) {
201
                push @messages, {
202
                    type => 'error',
203
                    code => 'authority_not_deleted',
204
                    authid => $authid,
205
                    error => ($@ ? $@ : 0),
206
                };
207
                $dbh->rollback;
208
                next;
209
            } else {
210
                push @messages, {
211
                    type => 'success',
212
                    code => 'authority_deleted',
213
                    authid => $authid,
214
                };
215
                $dbh->commit;
216
            }
217
        }
218
    }
219
    $template->param(
220
        op => 'report',
221
        report => $report,
222
    );
223
}
224
225
$template->param(
226
    messages => \@messages,
227
    recordtype => $recordtype,
228
);
229
230
output_html_with_http_headers $input, $cookie, $template->output;

Return to bug 12403