Bug 21142: Open uploaded files in utf-8 - batch mod/del
[koha.git] / tools / batch_delete_records.pl
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 use Koha::Authorities;
32 use Koha::Biblios;
33
34 my $input = new CGI;
35 my $op = $input->param('op') // q|form|;
36 my $recordtype = $input->param('recordtype') // 'biblio';
37
38 my ($template, $loggedinuser, $cookie) = get_template_and_user({
39         template_name => 'tools/batch_delete_records.tt',
40         query => $input,
41         type => "intranet",
42         authnotrequired => 0,
43         flagsrequired => { tools => 'records_batchdel' },
44 });
45
46 my @records;
47 my @messages;
48 if ( $op eq 'form' ) {
49     # Display the form
50     $template->param( op => 'form' );
51 } elsif ( $op eq 'list' ) {
52     # List all records to process
53     my @record_ids;
54     if ( my $bib_list = $input->param('bib_list') ) {
55         # Come from the basket
56         @record_ids = split /\//, $bib_list;
57         $recordtype = 'biblio';
58     } elsif ( my $uploadfile = $input->param('uploadfile') ) {
59         # A file of id is given
60         binmode $uploadfile, ':encoding(UTF-8)';
61         while ( my $content = <$uploadfile> ) {
62             next unless $content;
63             $content =~ s/[\r\n]*$//;
64             push @record_ids, $content if $content;
65         }
66     } else {
67         # The user enters manually the list of id
68         push @record_ids, split( /\s\n/, $input->param('recordnumber_list') );
69     }
70
71     for my $record_id ( uniq @record_ids ) {
72         if ( $recordtype eq 'biblio' ) {
73             # Retrieve biblio information
74             my $biblio = Koha::Biblios->find( $record_id );
75             unless ( $biblio ) {
76                 push @messages, {
77                     type => 'warning',
78                     code => 'biblio_not_exists',
79                     biblionumber => $record_id,
80                 };
81                 next;
82             }
83             my $holds_count = $biblio->holds->count;
84             $biblio = $biblio->unblessed;
85             my $record = &GetMarcBiblio({ biblionumber => $record_id });
86             $biblio->{subtitle} = GetRecordValue( 'subtitle', $record, GetFrameworkCode( $record_id ) );
87             $biblio->{itemnumbers} = C4::Items::GetItemnumbersForBiblio( $record_id );
88             $biblio->{holds_count} = $holds_count;
89             $biblio->{issues_count} = C4::Biblio::CountItemsIssued( $record_id );
90             push @records, $biblio;
91         } else {
92             # Retrieve authority information
93             my $authority = C4::AuthoritiesMarc::GetAuthority( $record_id );
94             unless ( $authority ) {
95                 push @messages, {
96                     type => 'warning',
97                     code => 'authority_not_exists',
98                     authid => $record_id,
99                 };
100                 next;
101             }
102
103             $authority = {
104                 authid => $record_id,
105                 summary => C4::AuthoritiesMarc::BuildSummary( $authority, $record_id ),
106                 count_usage => Koha::Authorities->get_usage_count({ authid => $record_id }),
107             };
108             push @records, $authority;
109         }
110     }
111     $template->param(
112         records => \@records,
113         op => 'list',
114     );
115 } elsif ( $op eq 'delete' ) {
116     # We want to delete selected records!
117     my @record_ids = $input->multi_param('record_id');
118     my $schema = Koha::Database->new->schema;
119
120     my $error;
121     my $report = {
122         total_records => 0,
123         total_success => 0,
124     };
125     RECORD_IDS: for my $record_id ( sort { $a <=> $b } @record_ids ) {
126         $report->{total_records}++;
127         next unless $record_id;
128         $schema->storage->txn_begin;
129
130         if ( $recordtype eq 'biblio' ) {
131             # Biblios
132             my $biblionumber = $record_id;
133             # First, checking if issues exist.
134             # If yes, nothing to do
135             my $biblio = Koha::Biblios->find( $biblionumber );
136
137             # TODO Replace with $biblio->get_issues->count
138             if ( C4::Biblio::CountItemsIssued( $biblionumber ) ) {
139                 push @messages, {
140                     type => 'warning',
141                     code => 'item_issued',
142                     biblionumber => $biblionumber,
143                 };
144                 $schema->storage->txn_rollback;
145                 next;
146             }
147
148             # Cancel reserves
149             my $holds = $biblio->holds;
150             while ( my $hold = $holds->next ) {
151                 eval{
152                     $hold->cancel;
153                 };
154                 if ( $@ ) {
155                     push @messages, {
156                         type => 'error',
157                         code => 'reserve_not_cancelled',
158                         biblionumber => $biblionumber,
159                         reserve_id => $hold->reserve_id,
160                         error => $@,
161                     };
162                     $schema->storage->txn_rollback;
163                     next RECORD_IDS;
164                 }
165             }
166
167             # Delete items
168             my @itemnumbers = @{ C4::Items::GetItemnumbersForBiblio( $biblionumber ) };
169             ITEMNUMBER: for my $itemnumber ( @itemnumbers ) {
170                 my $error = eval { C4::Items::DelItemCheck( $biblionumber, $itemnumber ) };
171                 if ( $error != 1 or $@ ) {
172                     push @messages, {
173                         type => 'error',
174                         code => 'item_not_deleted',
175                         biblionumber => $biblionumber,
176                         itemnumber => $itemnumber,
177                         error => ($@ ? $@ : $error),
178                     };
179                     $schema->storage->txn_rollback;
180                     next RECORD_IDS;
181                 }
182             }
183
184             # Finally, delete the biblio
185             my $error = eval {
186                 C4::Biblio::DelBiblio( $biblionumber );
187             };
188             if ( $error or $@ ) {
189                 push @messages, {
190                     type => 'error',
191                     code => 'biblio_not_deleted',
192                     biblionumber => $biblionumber,
193                     error => ($@ ? $@ : $error),
194                 };
195                 $schema->storage->txn_rollback;
196                 next;
197             }
198
199             push @messages, {
200                 type => 'success',
201                 code => 'biblio_deleted',
202                 biblionumber => $biblionumber,
203             };
204             $report->{total_success}++;
205             $schema->storage->txn_commit;
206         } else {
207             # Authorities
208             my $authid = $record_id;
209             eval { C4::AuthoritiesMarc::DelAuthority({ authid => $authid }) };
210             if ( $@ ) {
211                 push @messages, {
212                     type => 'error',
213                     code => 'authority_not_deleted',
214                     authid => $authid,
215                     error => ($@ ? $@ : 0),
216                 };
217                 $schema->storage->txn_rollback;
218                 next;
219             } else {
220                 push @messages, {
221                     type => 'success',
222                     code => 'authority_deleted',
223                     authid => $authid,
224                 };
225                 $report->{total_success}++;
226                 $schema->storage->txn_commit;
227             }
228         }
229     }
230     $template->param(
231         op => 'report',
232         report => $report,
233     );
234 }
235
236 $template->param(
237     messages => \@messages,
238     recordtype => $recordtype,
239 );
240
241 output_html_with_http_headers $input, $cookie, $template->output;