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