Bug 27783: Rename queues and adjust currently defined jobs
[koha.git] / Koha / BackgroundJob / BatchDeleteItem.pm
1 package Koha::BackgroundJob::BatchDeleteItem;
2
3 # This file is part of Koha.
4 #
5 # Koha is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # Koha is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18 =head1 NAME
19
20 Koha::BackgroundJob::BatchDeleteItem - Background job derived class to process item deletion in batch
21
22 =cut
23
24 use Modern::Perl;
25 use JSON qw( encode_json decode_json );
26 use List::MoreUtils qw( uniq );
27 use Try::Tiny;
28
29 use Koha::DateUtils qw( dt_from_string );
30 use Koha::Items;
31
32 use base 'Koha::BackgroundJob';
33
34 =head1 API
35
36 =head2 Class methods
37
38 =head3 job_type
39
40 Return the job type 'batch_item_record_deletion'.
41
42 =cut
43
44 sub job_type {
45     return 'batch_item_record_deletion';
46 }
47
48 =head3 process
49
50     Koha::BackgroundJobs->find($id)->process(
51         {
52             record_ids => \@itemnumbers,
53             deleted_biblios => 0|1,
54         }
55     );
56
57 Will delete all the items that have been passed for deletion.
58
59 When deleted_biblios is passed, if we deleted the last item of a biblio,
60 the bibliographic record will be deleted as well.
61
62 The search engine's index will be updated according to the changes made
63 to the deleted bibliographic recods.
64
65 The generated report will be:
66   {
67     deleted_itemnumbers => \@list_of_itemnumbers,
68     not_deleted_itemnumbers => \@list_of_itemnumbers,
69     deleted_biblionumbers=> \@list_of_biblionumbers,
70   }
71
72 =cut
73
74 sub process {
75     my ( $self, $args ) = @_;
76
77     if ( $self->status eq 'cancelled' ) {
78         return;
79     }
80
81     # FIXME If the job has already been started, but started again (worker has been restart for instance)
82     # Then we will start from scratch and so double delete the same records
83
84     my $job_progress = 0;
85     $self->started_on(dt_from_string)->progress($job_progress)
86       ->status('started')->store;
87
88     my @record_ids     = @{ $args->{record_ids} };
89     my $delete_biblios = $args->{delete_biblios};
90
91     my $report = {
92         total_records => scalar @record_ids,
93         total_success => 0,
94     };
95     my @messages;
96     my $schema = Koha::Database->new->schema;
97     my ( @deleted_itemnumbers, @not_deleted_itemnumbers,
98         @deleted_biblionumbers );
99
100     try {
101         my $schema = Koha::Database->new->schema;
102         $schema->txn_do(
103             sub {
104                 my (@biblionumbers);
105                 for my $record_id ( sort { $a <=> $b } @record_ids ) {
106
107                     last if $self->get_from_storage->status eq 'cancelled';
108
109                     my $item = Koha::Items->find($record_id) || next;
110
111                     my $return = $item->safe_delete;
112                     unless ( $return ) {
113
114                         # FIXME Do we need to rollback the whole transaction if a deletion failed?
115                         push @not_deleted_itemnumbers, $item->itemnumber;
116                         push @messages,
117                           {
118                             type         => 'error',
119                             code         => 'item_not_deleted',
120                             itemnumber   => $item->itemnumber,
121                             biblionumber => $item->biblionumber,
122                             barcode      => $item->barcode,
123                             title        => $item->biblio->title,
124                             reason       => @{$return->messages}[0]->message,
125                           };
126
127                         next;
128                     }
129
130                     push @deleted_itemnumbers, $item->itemnumber;
131                     push @biblionumbers,       $item->biblionumber;
132
133                     $report->{total_success}++;
134                     $self->progress( ++$job_progress )->store;
135                 }
136
137                 # If there are no items left, delete the biblio
138                 if ( $delete_biblios && @biblionumbers ) {
139                     for my $biblionumber ( uniq @biblionumbers ) {
140                         my $items_count =
141                           Koha::Biblios->find($biblionumber)->items->count;
142                         if ( $items_count == 0 ) {
143                             my $error = C4::Biblio::DelBiblio( $biblionumber,
144                                 { skip_record_index => 1 } );
145                             unless ($error) {
146                                 push @deleted_biblionumbers, $biblionumber;
147                             }
148                         }
149                     }
150
151                     if (@deleted_biblionumbers) {
152                         my $indexer = Koha::SearchEngine::Indexer->new(
153                             { index => $Koha::SearchEngine::BIBLIOS_INDEX } );
154
155                         $indexer->index_records( \@deleted_biblionumbers,
156                             'recordDelete', "biblioserver", undef );
157                     }
158                 }
159             }
160         );
161     }
162     catch {
163
164         warn $_;
165
166         push @messages,
167           {
168             type  => 'error',
169             code  => 'unknown',
170             error => $_,
171           };
172
173         die "Something terrible has happened!"
174           if ( $_ =~ /Rollback failed/ );    # Rollback failed
175     };
176
177     $report->{deleted_itemnumbers}     = \@deleted_itemnumbers;
178     $report->{not_deleted_itemnumbers} = \@not_deleted_itemnumbers;
179     $report->{deleted_biblionumbers}   = \@deleted_biblionumbers;
180
181     my $job_data = decode_json $self->data;
182     $job_data->{messages} = \@messages;
183     $job_data->{report}   = $report;
184
185     $self->ended_on(dt_from_string)->data( encode_json $job_data);
186     $self->status('finished') if $self->status ne 'cancelled';
187     $self->store;
188 }
189
190 =head3 enqueue
191
192     Koha::BackgroundJob::BatchDeleteItem->new->enqueue(
193         {
194             record_ids => \@itemnumbers,
195             deleted_biblios => 0|1,
196         }
197     );
198
199 Enqueue the job.
200
201 =cut
202
203 sub enqueue {
204     my ( $self, $args ) = @_;
205
206     # TODO Raise exception instead
207     return unless exists $args->{record_ids};
208
209     my @record_ids = @{ $args->{record_ids} };
210     my $delete_biblios = $args->{delete_biblios} || 0;
211
212     $self->SUPER::enqueue(
213         {
214             job_size => scalar @record_ids,
215             job_args => {
216                 record_ids     => \@record_ids,
217                 delete_biblios => $delete_biblios,
218             },
219             queue    => 'long_tasks',
220         }
221     );
222 }
223
224 1;