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 (+236 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
[% INCLUDE 'datatables.inc' %]
7
<script type="text/javascript" src="[% interface %]/lib/jquery/plugins/jquery.checkboxes.min.js"></script>
8
<script type="text/javascript">
9
//<![CDATA[
10
var MSG_CANNOT_BE_DELETED = _("This record cannot be deleted, at least one item is currently issued");
11
$(document).ready(function() {
12
  $("#selectall").click(function(e){
13
    e.preventDefault();
14
    $(".records").checkCheckboxes();
15
  });
16
  $("#clearall").click(function(e){
17
    e.preventDefault();
18
    $(".records").unCheckCheckboxes();
19
  });
20
  $("#selectwithoutitems").click(function(e){
21
    e.preventDefault();
22
    $("#biblios").checkCheckboxes(":input[data-items='0']:not(:disabled)");
23
  });
24
  $("#selectnotreserved").click(function(e){
25
    e.preventDefault();
26
    $("#biblios").checkCheckboxes(":input[data-reserves='0']:not(:disabled)");
27
28
  });
29
  $("#clearlinkedtobiblio").click(function(e){
30
    e.preventDefault();
31
    $("#authorities").unCheckCheckboxes(":not(input[data-usage='0'])");
32
  });
33
  $("#selectall").click();
34
35
  [% IF recordtype == 'biblio' %]
36
    $(".records input:checkbox[data-issues!='0']").each(function(){
37
      $(this).attr('title', MSG_CANNOT_BE_DELETED)
38
      $(this).attr('disabled', true);
39
      $(this).attr('checked', false);
40
      $(this).parents('tr').find('td').css('background-color', 'red');
41
    });
42
  [% END %]
43
44
  $("table#biblios").dataTable($.extend(true, {}, dataTablesDefaults, {
45
    "aoColumnDefs": [
46
      { "aTargets": [ 0 ], "bSortable": false, "bSearchable": false },
47
      { "aTargets": [ 3, 4 ], "sType": "num-html" }
48
    ],
49
    "sDom": 't',
50
    "aaSorting": [],
51
    "bPaginate": false
52
  }));
53
54
  $("table#authorities").dataTable($.extend(true, {}, dataTablesDefaults, {
55
    "aoColumnDefs": [
56
      { "aTargets": [ 0 ], "bSortable": false, "bSearchable": false },
57
      { "aTargets": [ 3 ], "sType": "num-html" }
58
    ],
59
    "sDom": 't',
60
    "aaSorting": [],
61
    "bPaginate": false
62
  }));
63
});
64
//]]>
65
</script>
66
</head>
67
<body id="tools_batch_delete_records" class="tools">
68
[% INCLUDE 'header.inc' %]
69
[% INCLUDE 'cat-search.inc' %]
70
71
<div id="breadcrumbs">
72
    <a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo;
73
    <a href="/cgi-bin/koha/tools/tools-home.pl">Tools</a> &rsaquo;
74
    <a href="/cgi-bin/koha/tools/batch_delete_records.pl">Batch record deletion</a>
75
</div>
76
77
<div id="doc3" class="yui-t2">
78
<div id="bd">
79
<div id="yui-main">
80
<div class="yui-b">
81
  <h1>Batch record deletion</h1>
82
  [% FOREACH message IN messages %]
83
    [% IF message.type == 'success' %]
84
      <div class="dialog message">
85
    [% ELSIF message.type == 'warning' %]
86
      <div class="dialog alert">
87
    [% ELSIF message.type == 'error' %]
88
      <div class="dialog error" style="margin:auto;">
89
    [% END %]
90
    [% IF message.code == 'biblio_not_exists' %]
91
      The biblionumber [% message.biblionumber %] does not exist in the database.
92
    [% ELSIF message.code == 'authority_not_exists' %]
93
      The authority id [% message.authid %] does not exist in the database.
94
    [% ELSIF message.code == 'item_issued' %]
95
      At least one item issued for the biblio [% message.biblionumber %].
96
    [% ELSIF message.code == 'reserve_not_cancelled' %]
97
      The biblio [% message.biblionumber %] has not been deleted. A reserve (reserve_id [% message.reserve_id %]) caused an error on cancel.
98
    [% ELSIF message.code == 'item_not_deleted' %]
99
      The biblio [% message.biblionumber %] has not been deleted. An item (itemnumber [% message.itemnumber %]) caused an error on delete.
100
    [% ELSIF message.code == 'biblio_not_deleted' %]
101
      The biblio [% message.biblionumber %] has not been deleted. An error occurred on deleting it.
102
    [% ELSIF message.code == 'authority_not_deleted' %]
103
      The authority [% message.authid %] has not been deleted. An error occurred on deleting it.
104
    [% ELSIF message.code == 'biblio_deleted' %]
105
      The biblio [% message.biblionumber %] has successfully been deleted.
106
    [% ELSIF message.code == 'authority_deleted' %]
107
      The authority [% message.authid %] has successfully been deleted.
108
    [% END %]
109
    [% IF message.error %]
110
      (The error was: [% message.error%], see the Koha logfile for more information).
111
    [% END %]
112
    </div>
113
  [% END %]
114
  [% IF op == 'form' %]
115
    <form method="post" enctype="multipart/form-data" action="/cgi-bin/koha/tools/batch_delete_records.pl">
116
      <fieldset class="rows">
117
        <legend>Record type</legend>
118
        <ol>
119
          <li><label for="biblio_type">Biblios: </label><input type="radio" name="recordtype" value="biblio" id="biblio_type" checked="checked" /></li>
120
          <li><label for="authority_type">Authorities: </label><input type="radio" name="recordtype" value="authority" id="authority_type" /></li>
121
        </ol>
122
      </fieldset>
123
      <fieldset class="rows">
124
        <legend>Use a file</legend>
125
        <ol>
126
          <li><label for="uploadfile">File: </label> <input type="file" id="uploadfile" name="uploadfile" /></li>
127
        </ol>
128
      </fieldset>
129
      <fieldset class="rows">
130
        <legend>Or enter a list of record numbers</legend>
131
        <ol>
132
          <li>
133
            <label for="recordnumber_list">Record number list (one per line): </label>
134
            <textarea rows="10" cols="30" id="recordnumber_list" name="recordnumber_list"></textarea>
135
          </li>
136
        </ol>
137
      </fieldset>
138
      <fieldset class="action">
139
        <input type="hidden" name="op" value="list" />
140
        <input type="submit" value="Continue" class="button" />
141
        <a class="cancel" href="/cgi-bin/koha/tools/tools-home.pl">Cancel</a>
142
      </fieldset>
143
    </form>
144
  [% ELSIF op == 'list' %]
145
    [% IF records %]
146
      [% IF recordtype == 'biblio' %]
147
        <div id="toolbar">
148
          <a id="selectall" href="#">Select All</a>
149
          | <a id="clearall" href="#">Clear All</a>
150
          | <a id="selectwithoutitems" href="#">Select without items</a>
151
          | <a id="selectnotreserved" href="#">Select not reserved</a>
152
        </div>
153
        <form action="/cgi-bin/koha/tools/batch_delete_records.pl" method="post">
154
          <table id="biblios" class="records">
155
            <thead>
156
              <tr>
157
                <th></th>
158
                <th>Biblionumber</th>
159
                <th>Title</th>
160
                <th>Items</th>
161
                <th>Reserves</th>
162
                <th>Issues</th>
163
              </tr>
164
            </thead>
165
            <tbody>
166
              [% FOR biblio IN records %]
167
                <tr>
168
                  <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>
169
                  <td>[% biblio.biblionumber %]</td>
170
                  <td><a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% biblio.biblionumber %]">[% biblio.title %]</a></td>
171
                  <td><a href="/cgi-bin/koha/catalogue/moredetail.pl?biblionumber=[% biblio.biblionumber %]">[% biblio.itemnumbers.size %]</a></td>
172
                  <td><a href="/cgi-bin/koha/reserve/request.pl?biblionumber=[% biblio.biblionumber %]">[% biblio.reserves.size %]</a></td>
173
                  <td><a href="/cgi-bin/koha/catalogue/issuehistory.pl?biblionumber=[% biblio.biblionumber %]">[% biblio.issues_count %]</a></td>
174
                </tr>
175
              [% END %]
176
            </tbody>
177
          </table>
178
          <div class="note">Reminder: this action will delete all selected biblios, attached subscriptions, existing holds and items!</div>
179
      [% ELSE %]
180
        <div id="toolbar">
181
          <a id="selectall" href="#">Select All</a>
182
          | <a id="clearall" href="#">Clear All</a>
183
          | <a id="clearlinkedtobiblio" href="#">Clear linked to biblio </a>
184
        </div>
185
        <form action="/cgi-bin/koha/tools/batch_delete_records.pl" method="post">
186
          <table id="authorities" class="records">
187
            <thead>
188
              <tr>
189
                <th></th>
190
                <th>Authid</th>
191
                <th>Summary</th>
192
                <th>Used in</th>
193
              </tr>
194
            </thead>
195
            <tbody>
196
              [% FOR authority IN records %]
197
                <tr>
198
                  <td><input type="checkbox" name="record_id" value="[% authority.authid %]" data-usage="[% authority.count_usage %]" /></td>
199
                  <td><a href="/cgi-bin/koha/authorities/detail.pl?authid=[% authority.authid %]">[% authority.authid %]</a></td>
200
                  <td>[% PROCESS authresult summary=authority.summary %]</td>
201
                  <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>
202
                </tr>
203
              [% END %]
204
            </tbody>
205
          </table>
206
          <div class="note">Reminder: this action will delete all selected authorities!</div>
207
      [% END %]
208
        <fieldset class="action">
209
          <input type="hidden" name="op" value="delete" />
210
          <input type="hidden" name="recordtype" value="[% recordtype %]" />
211
          <input type="submit" value="Delete selected records" class="button" />
212
          <a class="cancel" href="/cgi-bin/koha/tools/batch_delete_records.pl">Cancel</a>
213
        </fieldset>
214
      </form>
215
    [% ELSE %]
216
      There is no record ids defined.
217
    [% END %]
218
  [% ELSIF op == 'report' %]
219
    [% IF report.total_records == report.total_success %]
220
      All records have successfully been deleted!
221
    [% ELSIF report.total_success == 0 %]
222
      No record has been deleted, some errors occurred.
223
    [% ELSE %]
224
      [% report.total_success %] / [% report.total_records %] records have successfully been deleted but some errors occurred.
225
    [% END %]
226
    <p><a href="/cgi-bin/koha/tools/batch_delete_records.pl" title="New batch record deletion">New batch record deletion</a></p>
227
  [% ELSE %]
228
    No action defined for the template.
229
  [% END %]
230
</div>
231
</div>
232
<div class="yui-b">
233
  [% INCLUDE 'tools-menu.inc' %]
234
</div>
235
</div>
236
[% 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 / +231 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({ biblionumber => $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 => $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
                $report->{total_success}++;
216
                $dbh->commit;
217
            }
218
        }
219
    }
220
    $template->param(
221
        op => 'report',
222
        report => $report,
223
    );
224
}
225
226
$template->param(
227
    messages => \@messages,
228
    recordtype => $recordtype,
229
);
230
231
output_html_with_http_headers $input, $cookie, $template->output;

Return to bug 12403