Bug 31351: Koha::BackgroundJob: Let database connection object handle utf8 transcoding
[koha.git] / Koha / BackgroundJob / BatchUpdateItem.pm
1 package Koha::BackgroundJob::BatchUpdateItem;
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 use Modern::Perl;
19 use JSON;
20 use List::MoreUtils qw( uniq );
21 use Try::Tiny;
22
23 use MARC::Record;
24 use MARC::Field;
25
26 use C4::Biblio;
27 use C4::Items;
28
29 use Koha::DateUtils qw( dt_from_string );
30 use Koha::SearchEngine::Indexer;
31 use Koha::Items;
32 use Koha::UI::Table::Builder::Items;
33
34 use base 'Koha::BackgroundJob';
35
36 =head1 NAME
37
38 Koha::BackgroundJob::BatchUpdateItem - Background job derived class to process item modification in batch
39
40 =head1 API
41
42 =head2 Class methods
43
44 =head3 job_type
45
46 Define the job type of this job: batch_item_record_modification
47
48 =cut
49
50 sub job_type {
51     return 'batch_item_record_modification';
52 }
53
54 =head3 process
55
56     Koha::BackgroundJobs->find($id)->process(
57         {
58             record_ids => \@itemnumbers,
59             new_values => {
60                 itemnotes => $new_item_notes,
61                 k         => $k,
62             },
63             regex_mod => {
64                 itemnotes_nonpublic => {
65                     search => 'foo',
66                     replace => 'bar',
67                     modifiers => 'gi',
68                 },
69             },
70             exclude_from_local_holds_priority => 1|0
71         }
72     );
73
74 Process the modification.
75
76 new_values allows to set a new value for given fields.
77 The key can be one of the item's column name, or one subfieldcode of a MARC subfields not linked with a Koha field.
78
79 regex_mod allows to modify existing subfield's values using a regular expression.
80
81 =cut
82
83 sub process {
84     my ( $self, $args ) = @_;
85
86     if ( $self->status eq 'cancelled' ) {
87         return;
88     }
89
90     # FIXME If the job has already been started, but started again (worker has been restart for instance)
91     # Then we will start from scratch and so double process the same records
92
93     my $job_progress = 0;
94     $self->started_on(dt_from_string)->progress($job_progress)
95       ->status('started')->store;
96
97     my @record_ids = @{ $args->{record_ids} };
98     my $regex_mod  = $args->{regex_mod};
99     my $new_values = $args->{new_values};
100     my $exclude_from_local_holds_priority =
101       $args->{exclude_from_local_holds_priority};
102
103     my $report = {
104         total_records            => scalar @record_ids,
105         modified_fields          => 0,
106     };
107
108     try {
109         my ($results) =
110           Koha::Items->search( { itemnumber => \@record_ids } )
111           ->batch_update(
112             {
113                 regex_mod  => $regex_mod,
114                 new_values => $new_values,
115                 exclude_from_local_holds_priority =>
116                   $exclude_from_local_holds_priority,
117                 callback => sub {
118                     my ($progress) = @_;
119                     $self->progress($progress)->store;
120                 },
121             }
122           );
123         $report->{modified_itemnumbers} = $results->{modified_itemnumbers};
124         $report->{modified_fields}      = $results->{modified_fields};
125     }
126     catch {
127         warn $_;
128         die "Something terrible has happened!"
129           if ( $_ =~ /Rollback failed/ );    # Rollback failed
130     };
131
132     my $json = JSON->new;
133     $self->discard_changes;
134     my $job_data = $json->decode($self->data);
135     $job_data->{report} = $report;
136
137     $self->ended_on(dt_from_string)->data($json->encode($job_data));
138     $self->status('finished') if $self->status ne 'cancelled';
139     $self->store;
140 }
141
142 =head3 enqueue
143
144 Enqueue the new job
145
146 =cut
147
148 sub enqueue {
149     my ( $self, $args ) = @_;
150
151     # TODO Raise exception instead
152     return unless exists $args->{record_ids};
153
154     my @record_ids = @{ $args->{record_ids} };
155
156     $self->SUPER::enqueue(
157         {
158             job_size => scalar @record_ids,
159             job_args => {%$args},
160             queue    => 'long_tasks',
161         }
162     );
163 }
164
165 =head3 additional_report
166
167 Sent the infos to generate the table containing the details of the modified items.
168
169 =cut
170
171 sub additional_report {
172     my ( $self, $args ) = @_;
173
174     return unless $self->report->{modified_itemnumbers};
175
176     my $itemnumbers = $self->report->{modified_itemnumbers};
177     if ( scalar(@$itemnumbers) > C4::Context->preference('MaxItemsToDisplayForBatchMod') ) {
178         return { too_many_items_display => 1 };
179     } else {
180         my $items_table =
181           Koha::UI::Table::Builder::Items->new( { itemnumbers => $itemnumbers } )
182           ->build_table;
183
184         return {
185             items            => $items_table->{items},
186             item_header_loop => $items_table->{headers},
187         };
188     }
189 }
190
191 1;