Bug 13552: (follow-up) Add debar option to batch patron modification
[koha.git] / tools / batch_record_modification.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 qw( get_template_and_user );
27 use C4::Output qw( output_html_with_http_headers );
28 use C4::AuthoritiesMarc qw( BuildSummary ModAuthority );
29 use C4::BackgroundJob;
30 use C4::Biblio qw( GetMarcBiblio ModBiblio );
31 use C4::MarcModificationTemplates qw( GetModificationTemplateActions GetModificationTemplates ModifyRecordWithTemplate );
32
33 use Koha::Biblios;
34 use Koha::MetadataRecord::Authority;
35 use Koha::Virtualshelves;
36
37 my $input = new CGI;
38 our $dbh = C4::Context->dbh;
39 my $op = $input->param('op') // q|form|;
40 my $recordtype = $input->param('recordtype') // 'biblio';
41 my $mmtid = $input->param('marc_modification_template_id');
42
43 my ( @messages );
44
45 my ( $template, $loggedinuser, $cookie ) = get_template_and_user({
46         template_name => 'tools/batch_record_modification.tt',
47         query => $input,
48         type => "intranet",
49         authnotrequired => 0,
50         flagsrequired => { tools => 'records_batchmod' },
51 });
52
53
54 my $sessionID = $input->cookie("CGISESSID");
55
56 my $runinbackground = $input->param('runinbackground');
57 my $completedJobID = $input->param('completedJobID');
58 if ( $completedJobID ) {
59     my $job = C4::BackgroundJob->fetch($sessionID, $completedJobID);
60     my $report = $job->get('report');
61     my $messages = $job->get('messages');
62     $template->param(
63         report => $report,
64         messages => $messages,
65         view => 'report',
66     );
67     output_html_with_http_headers $input, $cookie, $template->output;
68     $job->clear();
69     exit;
70 }
71
72 $template->param( lists => scalar Koha::Virtualshelves->search([{ category => 1, owner => $loggedinuser }, { category => 2 }]) );
73
74 my @templates = GetModificationTemplates( $mmtid );
75 unless ( @templates ) {
76     $op = 'error';
77     $template->param(
78         view => 'errors',
79         errors => ['no_template_defined'],
80     );
81     output_html_with_http_headers $input, $cookie, $template->output;
82     exit;
83 }
84
85 if ( $mmtid ) {
86     my @actions = GetModificationTemplateActions( $mmtid );
87     unless ( @actions ) {
88         $op = 'form';
89         push @messages, {
90             type => 'error',
91             code => 'no_action_defined_for_the_template',
92             mmtid => $mmtid,
93         };
94     }
95 }
96
97 if ( $op eq 'form' ) {
98     # Display the form
99     $template->param(
100         view => 'form',
101     );
102 } elsif ( $op eq 'list' ) {
103     # List all records to process
104     my ( @records, @record_ids );
105     if ( my $bib_list = $input->param('bib_list') ) {
106         # Come from the basket
107         @record_ids = split /\//, $bib_list;
108         $recordtype = 'biblio';
109     } elsif ( my $uploadfile = $input->param('uploadfile') ) {
110         # A file of id is given
111         binmode $uploadfile, ':encoding(UTF-8)';
112         while ( my $content = <$uploadfile> ) {
113             next unless $content;
114             $content =~ s/[\r\n]*$//;
115             push @record_ids, $content if $content;
116         }
117     } elsif ( my $shelf_number = $input->param('shelf_number') ) {
118         my $shelf = Koha::Virtualshelves->find($shelf_number);
119         my $contents = $shelf->get_contents;
120         while ( my $content = $contents->next ) {
121             my $biblionumber = $content->biblionumber;
122             push @record_ids, $biblionumber;
123         }
124     } else {
125         # The user enters manually the list of id
126         push @record_ids, split( /\s\n/, $input->param('recordnumber_list') );
127     }
128
129     for my $record_id ( uniq @record_ids ) {
130         if ( $recordtype eq 'biblio' ) {
131             # Retrieve biblio information
132             my $biblio = Koha::Biblios->find( $record_id );
133             unless ( $biblio ) {
134                 push @messages, {
135                     type => 'warning',
136                     code => 'biblio_not_exists',
137                     biblionumber => $record_id,
138                 };
139                 next;
140             }
141             push @records, $biblio;
142         } else {
143             # Retrieve authority information
144             my $authority = Koha::MetadataRecord::Authority->get_from_authid( $record_id );
145             unless ( $authority ) {
146                 push @messages, {
147                     type => 'warning',
148                     code => 'authority_not_exists',
149                     authid => $record_id,
150                 };
151                 next;
152             }
153
154             push @records, {
155                 authid => $record_id,
156                 summary => C4::AuthoritiesMarc::BuildSummary( $authority->record, $record_id ),
157             };
158         }
159     }
160     $template->param(
161         records => \@records,
162         mmtid => $mmtid,
163         view => 'list',
164     );
165 } elsif ( $op eq 'modify' ) {
166     # We want to modify selected records!
167     my @record_ids = $input->multi_param('record_id');
168
169     my ( $job );
170     if ( $runinbackground ) {
171         my $job_size = scalar( @record_ids );
172         $job = C4::BackgroundJob->new( $sessionID, "FIXME", '/cgi-bin/koha/tools/batch_record_modification.pl', $job_size );
173         my $job_id = $job->id;
174         if (my $pid = fork) {
175             $dbh->{InactiveDestroy}  = 1;
176
177             my $reply = CGI->new("");
178             print $reply->header(-type => 'text/html');
179             print '{"jobID":"' . $job_id . '"}';
180             exit 0;
181         } elsif (defined $pid) {
182             close STDOUT;
183         } else {
184             warn "fork failed while attempting to run tools/batch_record_modification.pl as a background job";
185             exit 0;
186         }
187     }
188
189     my $report = {
190         total_records => 0,
191         total_success => 0,
192     };
193     my $progress = 0;
194     $dbh->{RaiseError} = 1;
195     RECORD_IDS: for my $record_id ( sort { $a <=> $b } @record_ids ) {
196         $report->{total_records}++;
197         next unless $record_id;
198
199         if ( $recordtype eq 'biblio' ) {
200             # Biblios
201             my $biblionumber = $record_id;
202
203             # Finally, modify the biblio
204             my $error = eval {
205                 my $record = GetMarcBiblio({ biblionumber => $biblionumber });
206                 ModifyRecordWithTemplate( $mmtid, $record );
207                 my $frameworkcode = C4::Biblio::GetFrameworkCode( $biblionumber );
208                 ModBiblio( $record, $biblionumber, $frameworkcode );
209             };
210             if ( $error and $error != 1 or $@ ) { # ModBiblio returns 1 if everything as gone well
211                 push @messages, {
212                     type => 'error',
213                     code => 'biblio_not_modified',
214                     biblionumber => $biblionumber,
215                     error => ($@ ? $@ : $error),
216                 };
217             } else {
218                 push @messages, {
219                     type => 'success',
220                     code => 'biblio_modified',
221                     biblionumber => $biblionumber,
222                 };
223                 $report->{total_success}++;
224             }
225         } else {
226             # Authorities
227             my $authid = $record_id;
228             my $error = eval {
229                 my $authority = Koha::MetadataRecord::Authority->get_from_authid( $authid );
230                 my $record = $authority->record;
231                 ModifyRecordWithTemplate( $mmtid, $record );
232                 ModAuthority( $authid, $record, $authority->authtypecode );
233             };
234             if ( $error and $error != $authid or $@ ) {
235                 push @messages, {
236                     type => 'error',
237                     code => 'authority_not_modified',
238                     authid => $authid,
239                     error => ($@ ? $@ : 0),
240                 };
241             } else {
242                 push @messages, {
243                     type => 'success',
244                     code => 'authority_modified',
245                     authid => $authid,
246                 };
247                 $report->{total_success}++;
248             }
249         }
250
251         $job->set({
252             view => 'report',
253             report => $report,
254             messages => \@messages,
255         });
256         $job->progress( ++$progress ) if $runinbackground;
257     }
258
259     if ($runinbackground) {
260         $job->finish if defined $job;
261     } else {
262         $template->param(
263             view => 'report',
264             report => $report,
265             messages => \@messages,
266         );
267     }
268 }
269
270 $template->param(
271     messages => \@messages,
272     recordtype => $recordtype,
273     MarcModificationTemplatesLoop => \@templates,
274 );
275
276 output_html_with_http_headers $input, $cookie, $template->output;