Bug 22721: Remove frameworkcode parameter in GetMarcFromKohaField calls
[koha.git] / Koha / Exporter / Record.pm
1 package Koha::Exporter::Record;
2
3 use Modern::Perl;
4 use MARC::File::XML;
5 use MARC::File::USMARC;
6
7 use C4::AuthoritiesMarc;
8 use C4::Biblio;
9 use C4::Record;
10 use Koha::CsvProfiles;
11 use Koha::Logger;
12 use List::Util qw(all any);
13
14 sub _get_record_for_export {
15     my ($params)           = @_;
16     my $record_type        = $params->{record_type};
17     my $record_id          = $params->{record_id};
18     my $conditions         = $params->{record_conditions};
19     my $dont_export_fields = $params->{dont_export_fields};
20     my $clean              = $params->{clean};
21
22     my $record;
23     if ( $record_type eq 'auths' ) {
24         $record = _get_authority_for_export( { %$params, authid => $record_id } );
25     } elsif ( $record_type eq 'bibs' ) {
26         $record = _get_biblio_for_export( { %$params, biblionumber => $record_id } );
27     } else {
28         Koha::Logger->get->warn( "Record_type $record_type not supported." );
29     }
30     if ( !$record ) {
31         Koha::Logger->get->warn( "Record $record_id could not be exported." );
32         return;
33     }
34
35     # If multiple conditions all are required to match (and)
36     # For matching against multiple marc targets all are also required to match
37     my %operators = (
38         '=' => sub {
39             return $_[0] eq $_[1];
40         },
41         '!=' => sub {
42             return $_[0] ne $_[1];
43         },
44         '>' => sub {
45             return $_[0] gt $_[1];
46         },
47         '<' => sub {
48             return $_[0] lt $_[1];
49         },
50     );
51     if ($conditions) {
52         foreach my $condition (@{$conditions}) {
53             my ($field_tag, $subfield, $operator, $match_value) = @{$condition};
54             my @fields = $record->field($field_tag);
55             my $no_target = 0;
56
57             if (!@fields) {
58                 $no_target = 1;
59             }
60             else {
61                 if ($operator eq '?') {
62                     return unless any { $subfield ? $_->subfield($subfield) : $_->data() } @fields;
63                 } elsif ($operator eq '!?') {
64                     return if any { $subfield ? $_->subfield($subfield) : $_->data() } @fields;
65                 } else {
66                     my $op;
67                     if (exists $operators{$operator}) {
68                         $op = $operators{$operator};
69                     } else {
70                         die("Invalid operator: $op");
71                     }
72                     my @target_values = map { $subfield ? $_->subfield($subfield) : ($_->data()) } @fields;
73                     if (!@target_values) {
74                         $no_target = 1;
75                     }
76                     else {
77                         return unless all { $op->($_, $match_value) } @target_values;
78                     }
79                 }
80             }
81             return if $no_target && $operator ne '!=';
82         }
83     }
84
85     if ($dont_export_fields) {
86         for my $f ( split / /, $dont_export_fields ) {
87             if ( $f =~ m/^(\d{3})(.)?$/ ) {
88                 my ( $field, $subfield ) = ( $1, $2 );
89
90                 # skip if this record doesn't have this field
91                 if ( defined $record->field($field) ) {
92                     if ( defined $subfield ) {
93                         my @tags = $record->field($field);
94                         foreach my $t (@tags) {
95                             $t->delete_subfields($subfield);
96                         }
97                     } else {
98                         $record->delete_fields( $record->field($field) );
99                     }
100                 }
101             }
102         }
103     }
104     C4::Biblio::RemoveAllNsb($record) if $clean;
105     return $record;
106 }
107
108 sub _get_authority_for_export {
109     my ($params) = @_;
110     my $authid = $params->{authid} || return;
111     my $authority = Koha::MetadataRecord::Authority->get_from_authid($authid);
112     return unless $authority;
113     return $authority->record;
114 }
115
116 sub _get_biblio_for_export {
117     my ($params)     = @_;
118     my $biblionumber = $params->{biblionumber};
119     my $itemnumbers  = $params->{itemnumbers};
120     my $export_items = $params->{export_items} // 1;
121     my $only_export_items_for_branches = $params->{only_export_items_for_branches};
122
123     my $record = eval { C4::Biblio::GetMarcBiblio({ biblionumber => $biblionumber }); };
124
125     return if $@ or not defined $record;
126
127     if ($export_items) {
128         C4::Biblio::EmbedItemsInMarcBiblio({
129             marc_record  => $record,
130             biblionumber => $biblionumber,
131             item_numbers => $itemnumbers });
132         if ($only_export_items_for_branches && @$only_export_items_for_branches) {
133             my %export_items_for_branches = map { $_ => 1 } @$only_export_items_for_branches;
134             my ( $homebranchfield, $homebranchsubfield ) = GetMarcFromKohaField( 'items.homebranch' );
135
136             for my $itemfield ( $record->field($homebranchfield) ) {
137                 my $homebranch = $itemfield->subfield($homebranchsubfield);
138                 unless ( $export_items_for_branches{$homebranch} ) {
139                     $record->delete_field($itemfield);
140                 }
141             }
142         }
143     }
144     return $record;
145 }
146
147 sub export {
148     my ($params) = @_;
149
150     my $record_type        = $params->{record_type};
151     my $record_ids         = $params->{record_ids} || [];
152     my $format             = $params->{format};
153     my $itemnumbers        = $params->{itemnumbers} || [];    # Does not make sense with record_type eq auths
154     my $export_items       = $params->{export_items};
155     my $dont_export_fields = $params->{dont_export_fields};
156     my $csv_profile_id     = $params->{csv_profile_id};
157     my $output_filepath    = $params->{output_filepath};
158
159     if( !$record_type ) {
160         Koha::Logger->get->warn( "No record_type given." );
161         return;
162     }
163     return unless @$record_ids;
164
165     my $fh;
166     if ( $output_filepath ) {
167         open $fh, '>', $output_filepath or die "Cannot open file $output_filepath ($!)";
168         select $fh;
169         binmode $fh, ':encoding(UTF-8)' unless $format eq 'csv';
170     } else {
171         binmode STDOUT, ':encoding(UTF-8)' unless $format eq 'csv';
172     }
173
174     if ( $format eq 'iso2709' ) {
175         for my $record_id (@$record_ids) {
176             my $record = _get_record_for_export( { %$params, record_id => $record_id } );
177             next unless $record;
178             my $errorcount_on_decode = eval { scalar( MARC::File::USMARC->decode( $record->as_usmarc )->warnings() ) };
179             if ( $errorcount_on_decode or $@ ) {
180                 my $msg = "Record $record_id could not be exported. " .
181                     ( $@ // '' );
182                 chomp $msg;
183                 Koha::Logger->get->info( $msg );
184                 next;
185             }
186             print $record->as_usmarc();
187         }
188     } elsif ( $format eq 'xml' ) {
189         my $marcflavour = C4::Context->preference("marcflavour");
190         MARC::File::XML->default_record_format( ( $marcflavour eq 'UNIMARC' && $record_type eq 'auths' ) ? 'UNIMARCAUTH' : $marcflavour );
191
192         print MARC::File::XML::header();
193         print "\n";
194         for my $record_id (@$record_ids) {
195             my $record = _get_record_for_export( { %$params, record_id => $record_id } );
196             next unless $record;
197             print MARC::File::XML::record($record);
198             print "\n";
199         }
200         print MARC::File::XML::footer();
201         print "\n";
202     } elsif ( $format eq 'csv' ) {
203         die 'There is no valid csv profile defined for this export'
204             unless Koha::CsvProfiles->find( $csv_profile_id );
205         print marc2csv( $record_ids, $csv_profile_id, $itemnumbers );
206     }
207
208     close $fh if $output_filepath;
209 }
210
211 1;
212
213 __END__
214
215 =head1 NAME
216
217 Koha::Exporter::Records - module to export records (biblios and authorities)
218
219 =head1 SYNOPSIS
220
221 This module provides a public subroutine to export records as xml, csv or iso2709.
222
223 =head2 FUNCTIONS
224
225 =head3 export
226
227     Koha::Exporter::Record::export($params);
228
229 $params is a hashref with some keys:
230
231 It will displays on STDOUT the generated file.
232
233 =over 4
234
235 =item record_type
236
237   Must be set to 'bibs' or 'auths'
238
239 =item record_ids
240
241   The list of the records to export (a list of biblionumber or authid)
242
243 =item format
244
245   The format must be 'csv', 'xml' or 'iso2709'.
246
247 =item itemnumbers
248
249   Generate the item infos only for these itemnumbers.
250
251   Must only be used with biblios.
252
253 =item export_items
254
255   If this flag is set, the items will be exported.
256   Default is ON.
257
258 =item dont_export_fields
259
260   List of fields not to export.
261
262 =item csv_profile_id
263
264   If the format is csv, you have to define a csv_profile_id.
265
266 =cut
267
268 =back
269
270 =head1 LICENSE
271
272 This file is part of Koha.
273
274 Copyright Koha Development Team
275
276 Koha is free software; you can redistribute it and/or modify it
277 under the terms of the GNU General Public License as published by
278 the Free Software Foundation; either version 3 of the License, or
279 (at your option) any later version.
280
281 Koha is distributed in the hope that it will be useful, but
282 WITHOUT ANY WARRANTY; without even the implied warranty of
283 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
284 GNU General Public License for more details.
285
286 You should have received a copy of the GNU General Public License
287 along with Koha; if not, see <http://www.gnu.org/licenses>.