Bug 30728: Only trigger real-time holds queue update if enabled
[koha.git] / Koha / BackgroundJob / BatchDeleteBiblio.pm
1 package Koha::BackgroundJob::BatchDeleteBiblio;
2
3 use Modern::Perl;
4 use JSON qw( encode_json decode_json );
5
6 use C4::Biblio;
7
8 use Koha::BackgroundJob::BatchUpdateBiblioHoldsQueue;
9 use Koha::DateUtils qw( dt_from_string );
10 use Koha::SearchEngine;
11 use Koha::SearchEngine::Indexer;
12
13 use base 'Koha::BackgroundJob';
14
15 =head1 NAME
16
17 Koha::BackgroundJob::BatchDeleteBiblio - Batch delete bibliographic records
18
19 This is a subclass of Koha::BackgroundJob.
20
21 =head1 API
22
23 =head2 Class methods
24
25 =head3 job_type
26
27 Define the job type of this job: batch_biblio_record_deletion
28
29 =cut
30
31 sub job_type {
32     return 'batch_biblio_record_deletion';
33 }
34
35 =head3 process
36
37 Process the job.
38
39 =cut
40
41 sub process {
42     my ( $self, $args ) = @_;
43
44     if ( $self->status eq 'cancelled' ) {
45         return;
46     }
47
48     # FIXME If the job has already been started, but started again (worker has been restart for instance)
49     # Then we will start from scratch and so double delete the same records
50
51     my $job_progress = 0;
52     $self->started_on(dt_from_string)
53         ->progress($job_progress)
54         ->status('started')
55         ->store;
56
57     my $mmtid = $args->{mmtid};
58     my @record_ids = @{ $args->{record_ids} };
59
60     my $report = {
61         total_records => scalar @record_ids,
62         total_success => 0,
63     };
64     my @messages;
65     my $schema = Koha::Database->new->schema;
66     RECORD_IDS: for my $record_id ( sort { $a <=> $b } @record_ids ) {
67
68         last if $self->get_from_storage->status eq 'cancelled';
69
70         next unless $record_id;
71
72         $schema->storage->txn_begin;
73
74         my $biblionumber = $record_id;
75         # First, checking if issues exist.
76         # If yes, nothing to do
77         my $biblio = Koha::Biblios->find( $biblionumber );
78
79         # TODO Replace with $biblio->get_issues->count
80         if ( C4::Biblio::CountItemsIssued( $biblionumber ) ) {
81             push @messages, {
82                 type => 'warning',
83                 code => 'item_issued',
84                 biblionumber => $biblionumber,
85             };
86             $schema->storage->txn_rollback;
87             $self->progress( ++$job_progress )->store;
88             next;
89         }
90
91         # Cancel reserves
92         my $holds = $biblio->holds;
93         while ( my $hold = $holds->next ) {
94             eval{
95                 $hold->cancel({ skip_holds_queue => 1 });
96             };
97             if ( $@ ) {
98                 push @messages, {
99                     type => 'error',
100                     code => 'reserve_not_cancelled',
101                     biblionumber => $biblionumber,
102                     reserve_id => $hold->reserve_id,
103                     error => "$@",
104                 };
105                 $schema->storage->txn_rollback;
106                 $self->progress( ++$job_progress )->store;
107                 next RECORD_IDS;
108             }
109         }
110
111         # Delete items
112         my $items = Koha::Items->search({ biblionumber => $biblionumber });
113         while ( my $item = $items->next ) {
114             my $deleted = $item->safe_delete({ skip_record_index => 1, skip_holds_queue => 1 });
115             unless ( $deleted ) {
116                 push @messages, {
117                     type => 'error',
118                     code => 'item_not_deleted',
119                     biblionumber => $biblionumber,
120                     itemnumber => $item->itemnumber,
121                     error => @{$deleted->messages}[0]->message,
122                 };
123                 $schema->storage->txn_rollback;
124                 $self->progress( ++$job_progress )->store;
125                 next RECORD_IDS;
126             }
127         }
128
129         # Finally, delete the biblio
130         my $error = eval {
131             C4::Biblio::DelBiblio( $biblionumber, { skip_record_index => 1, skip_holds_queue => 1 } );
132         };
133         if ( $error or $@ ) {
134             push @messages, {
135                 type => 'error',
136                 code => 'biblio_not_deleted',
137                 biblionumber => $biblionumber,
138                 error => ($@ ? $@ : $error),
139             };
140             $schema->storage->txn_rollback;
141             $self->progress( ++$job_progress )->store;
142             next;
143         }
144
145         push @messages, {
146             type => 'success',
147             code => 'biblio_deleted',
148             biblionumber => $biblionumber,
149         };
150         $report->{total_success}++;
151         $schema->storage->txn_commit;
152         $self->progress( ++$job_progress )->store;
153     }
154
155     my @deleted_biblionumbers =
156       map { $_->{code} eq 'biblio_deleted' ? $_->{biblionumber} : () }
157           @messages;
158
159     if ( @deleted_biblionumbers ) {
160         my $indexer = Koha::SearchEngine::Indexer->new({ index => $Koha::SearchEngine::BIBLIOS_INDEX });
161         $indexer->index_records( \@deleted_biblionumbers, "recordDelete", "biblioserver" );
162
163         Koha::BackgroundJob::BatchUpdateBiblioHoldsQueue->new->enqueue(
164             {
165                 biblio_ids => \@deleted_biblionumbers
166             }
167         ) if C4::Context->preference('RealTimeHoldsQueue');
168     }
169
170     my $job_data = decode_json $self->data;
171     $job_data->{messages} = \@messages;
172     $job_data->{report} = $report;
173
174     $self->ended_on(dt_from_string)
175         ->data(encode_json $job_data);
176     $self->status('finished') if $self->status ne 'cancelled';
177     $self->store;
178 }
179
180 =head3 enqueue
181
182 Enqueue the new job
183
184 =cut
185
186 sub enqueue {
187     my ( $self, $args) = @_;
188
189     # TODO Raise exception instead
190     return unless exists $args->{record_ids};
191
192     my @record_ids = @{ $args->{record_ids} };
193
194     $self->SUPER::enqueue({
195         job_size => scalar @record_ids,
196         job_args => {record_ids => \@record_ids,},
197         queue    => 'long_tasks',
198     });
199 }
200
201 1;