4 # This file is part of Koha.
6 # Koha is free software; you can redistribute it and/or modify it
7 # under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
11 # Koha is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with Koha; if not, see <http://www.gnu.org/licenses>.
21 use List::MoreUtils qw( uniq );
22 use Getopt::Long qw( GetOptions );
23 use Pod::Usage qw( pod2usage );
30 use Koha::Biblioitems;
32 use Koha::CsvProfiles;
33 use Koha::Exporter::Record;
34 use Koha::DateUtils qw( dt_from_string output_pref );
49 $starting_biblionumber,
57 $embed_see_from_headings,
62 'format=s' => \$output_format,
63 'date=s' => \$timestamp,
64 'dont_export_items' => \$dont_export_items,
65 'csv_profile_id=s' => \$csv_profile_id,
66 'deleted_barcodes' => \$deleted_barcodes,
68 'filename=s' => \$filename,
69 'record-type=s' => \$record_type,
70 'id_list_file=s' => \$id_list_file,
71 'starting_authid=s' => \$starting_authid,
72 'ending_authid=s' => \$ending_authid,
73 'authtype=s' => \$authtype,
74 'starting_biblionumber=s' => \$starting_biblionumber,
75 'ending_biblionumber=s' => \$ending_biblionumber,
76 'itemtype=s' => \$itemtype,
77 'starting_callnumber=s' => \$starting_callnumber,
78 'ending_callnumber=s' => \$ending_callnumber,
79 'start_accession=s' => \$start_accession,
80 'end_accession=s' => \$end_accession,
81 'marc_conditions=s' => \$marc_conditions,
82 'embed_see_from_headings' => \$embed_see_from_headings,
90 $filename ||= 'koha.mrc';
91 $output_format ||= 'iso2709';
92 $record_type ||= 'bibs';
94 # Retrocompatibility for the format parameter
95 $output_format = 'iso2709' if $output_format eq 'marc';
97 if ( $output_format eq 'csv' and $record_type eq 'auths' ) {
98 pod2usage(q|CSV output is only available for biblio records|);
101 if ( $output_format eq 'csv' and not $csv_profile_id ) {
102 pod2usage(q|Define a csv profile to export in CSV|);
106 if ( $record_type ne 'bibs' and $record_type ne 'auths' ) {
107 pod2usage(q|--record_type is not valid|);
110 if ( $deleted_barcodes and $record_type ne 'bibs' ) {
111 pod2usage(q|--deleted_barcodes can only be used with biblios|);
114 $start_accession = dt_from_string( $start_accession ) if $start_accession;
115 $end_accession = dt_from_string( $end_accession ) if $end_accession;
117 # Parse marc conditions
119 if ($marc_conditions) {
120 foreach my $condition (split(/,\s*/, $marc_conditions)) {
121 if ($condition =~ /^(\d{3})([\w\d]?)(=|(?:!=)|>|<)([^,]+)$/) {
122 push @marc_conditions, [$1, $2, $3, $4];
124 elsif ($condition =~ /^(exists|not_exists)\((\d{3})([\w\d]?)\)$/) {
125 push @marc_conditions, [$2, $3, $1 eq 'exists' ? '?' : '!?'];
128 die("Invalid condititon: $condition");
133 my $dbh = C4::Context->dbh;
136 open STDOUT, '>', $filename if $filename;
141 $timestamp = ($timestamp) ? output_pref({ dt => dt_from_string($timestamp), dateformat => 'iso', dateonly => 0, }): '';
143 if ( $record_type eq 'bibs' ) {
145 if (!$dont_export_items) {
146 push @record_ids, $_->{biblionumber} for @{
147 $dbh->selectall_arrayref(q| (
148 SELECT biblio_metadata.biblionumber
150 LEFT JOIN items USING(biblionumber)
151 WHERE biblio_metadata.timestamp >= ?
152 OR items.timestamp >= ?
154 SELECT biblio_metadata.biblionumber
156 LEFT JOIN deleteditems USING(biblionumber)
157 WHERE biblio_metadata.timestamp >= ?
158 OR deleteditems.timestamp >= ?
159 ) |, { Slice => {} }, ( $timestamp ) x 4 );
162 push @record_ids, $_->{biblionumber} for @{
163 $dbh->selectall_arrayref(q| (
164 SELECT biblio_metadata.biblionumber
166 WHERE biblio_metadata.timestamp >= ?
167 ) |, { Slice => {} }, $timestamp );
172 ( $starting_biblionumber or $ending_biblionumber )
174 "me.biblionumber" => {
175 ( $starting_biblionumber ? ( '>=' => $starting_biblionumber ) : () ),
176 ( $ending_biblionumber ? ( '<=' => $ending_biblionumber ) : () ),
180 ( $starting_callnumber or $ending_callnumber )
183 ( $starting_callnumber ? ( '>=' => $starting_callnumber ) : () ),
184 ( $ending_callnumber ? ( '<=' => $ending_callnumber ) : () ),
188 ( $start_accession or $end_accession )
191 ( $start_accession ? ( '>=' => $start_accession ) : () ),
192 ( $end_accession ? ( '<=' => $end_accession ) : () ),
198 C4::Context->preference('item-level_itypes')
199 ? ( 'items.itype' => $itemtype )
200 : ( 'me.itemtype' => $itemtype )
205 my $biblioitems = Koha::Biblioitems->search( $conditions, { join => 'items' } );
206 while ( my $biblioitem = $biblioitems->next ) {
207 push @record_ids, $biblioitem->biblionumber;
211 elsif ( $record_type eq 'auths' ) {
213 push @record_ids, $_->{authid} for @{
214 $dbh->selectall_arrayref(
218 WHERE modification_time >= ?
219 ) |, { Slice => {} }, $timestamp
224 ( $starting_authid or $ending_authid )
227 ( $starting_authid ? ( '>=' => $starting_authid ) : () ),
228 ( $ending_authid ? ( '<=' => $ending_authid ) : () ),
232 ( $authtype ? ( authtypecode => $authtype ) : () ),
235 # Koha::MetadataRecord::Authority is not a Koha::Object...
236 my $authorities = Koha::Database->new->schema->resultset('AuthHeader')->search($conditions);
237 @record_ids = map { $_->authid } $authorities->all;
241 @record_ids = uniq @record_ids;
242 if ( @record_ids and $id_list_file ) {
243 open my $fh, '<', $id_list_file or die "Cannot open file $id_list_file ($!)";
244 my @filter_record_ids = <$fh>;
245 @filter_record_ids = map { my $id = $_; $id =~ s/[\r\n]*$//; $id } @filter_record_ids;
247 my %record_ids = map { $_ => 1 } @record_ids;
248 @record_ids = grep $record_ids{$_}, @filter_record_ids;
251 if ($deleted_barcodes) {
252 for my $record_id ( @record_ids ) {
253 my $barcode = $dbh->selectall_arrayref(q|
254 SELECT DISTINCT barcode
256 WHERE deleteditems.biblionumber = ?
257 AND barcode IS NOT NULL AND barcode != ''
258 |, { Slice => {} }, $record_id );
259 say $_->{barcode} for @$barcode;
263 Koha::Exporter::Record::export(
264 { record_type => $record_type,
265 record_ids => \@record_ids,
266 record_conditions => @marc_conditions ? \@marc_conditions : undef,
267 format => $output_format,
268 csv_profile_id => $csv_profile_id,
269 export_items => (not $dont_export_items),
270 clean => $clean || 0,
271 embed_see_from_headings => $embed_see_from_headings || 0,
280 export records - This script exports record (biblios or authorities)
284 export_records.pl [-h|--help] [--format=format] [--date=datetime] [--record-type=TYPE] [--dont_export_items] [--deleted_barcodes] [--clean] [--id_list_file=PATH] --filename=outputfile
292 Print a brief help message.
296 --format=FORMAT FORMAT is either 'xml', 'csv' (biblio records only) or 'marc' (default).
300 --date=DATETIME DATETIME should be entered as the 'dateformat' syspref is
301 set (dd/mm/yyyy[ hh:mm:ss] for metric, yyyy-mm-dd[ hh:mm:ss] for iso,
302 mm/dd/yyyy[ hh:mm:ss] for us) records exported are the ones that
303 have been modified since DATETIME.
305 =item B<--record-type>
307 --record-type=TYPE TYPE is 'bibs' or 'auths'.
309 =item B<--dont_export_items>
311 --dont_export_items If enabled, the item infos won't be exported.
313 =item B<--csv_profile_id>
315 --csv_profile_id=ID Generate a CSV file with the given CSV profile id (see tools/csv-profiles.pl)
316 This can only be used to export biblio records.
318 =item B<--deleted_barcodes>
320 --deleted_barcodes If used, a list of barcodes of items deleted since DATE
321 is produced (or from all deleted items if no date is
322 specified). Used only if TYPE is 'bibs'.
326 --clean removes NSE/NSB.
328 =item B<--id_list_file>
330 --id_list_file=PATH PATH is a path to a file containing a list of
331 IDs (biblionumber or authid) with one ID per line.
332 This list works as a filter; it is compatible with
333 other parameters for selecting records.
337 --filename=FILENAME FILENAME used to export the data.
339 =item B<--starting_authid>
341 --starting_authid=ID Export authorities with authid >= ID
343 =item B<--ending_authid>
345 --ending_authid=ID Export authorities with authid <= ID
349 --authtype=AUTHTYPE Export authorities from the given AUTHTYPE
351 =item B<--starting_biblionumber>
353 --starting_biblionumber=ID Export biblio with biblionumber >= ID
355 =item B<--ending_biblionumber>
357 --ending_biblionumber=ID Export biblio with biblionumber <= ID
361 --itemtype=ITEMTYPE Export biblio from the given ITEMTYPE
363 =item B<--starting_callnumber>
365 --starting_callnumber=CALLNUMBER Export biblio with callnumber >=CALLNUMBER
367 =item B<--ending_callnumber>
369 --ending_callnumber=CALLNUMBER Export biblio with callnumber <=CALLNUMBER
371 =item B<--start_accession>
373 --starting_accession=DATE Export biblio with an item accessionned after DATE
375 =item B<--end_accession>
377 --end_accession=DATE Export biblio with an item accessionned after DATE
379 =item B<--marc_conditions>
381 --marc_conditions=CONDITIONS Only include biblios with MARC data matching CONDITIONS.
382 CONDITIONS is on the format: <marc_target><binary_operator><value>,
383 or <unary_operation>(<marc_target>).
384 with multiple conditions separated by commas (,).
385 For example: --marc_conditions="035a!=(EXAMPLE)123,041a=swe".
386 Multiple conditions are all required to match.
387 If <marc_target> has multiple values all values
388 are also required to match.
389 Valid operators are: = (equal to), != (not equal to),
390 > (great than) and < (less than).
392 Two unary operations are also supported:
393 exists(<marc_target>) and not_exists(<marc_target>).
394 For example: --marc_conditions="exists(035a)".
396 "exists(<marc_target)" will include marc records where
397 <marc_target> exists regardless of target value, and
398 "exists(<marc_target>)" will include marc records where
399 no <marc_target> exists.
401 =item B<--embed_see_from_headings>
403 --embed_see_from_headings Embed see from (non-preferred form) headings in bibliographic record.
409 Koha Development Team
417 This file is part of Koha.
419 # Koha is free software; you can redistribute it and/or modify it
420 # under the terms of the GNU General Public License as published by
421 # the Free Software Foundation; either version 3 of the License, or
422 # (at your option) any later version.
424 # Koha is distributed in the hope that it will be useful, but
425 # WITHOUT ANY WARRANTY; without even the implied warranty of
426 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
427 # GNU General Public License for more details.
429 # You should have received a copy of the GNU General Public License
430 # along with Koha; if not, see <http://www.gnu.org/licenses>.