1 package C4::MarcModificationTemplates;
3 # This file is part of Koha.
5 # Copyright 2010 Kyle M Hall <kyle.m.hall@gmail.com>
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
29 use vars qw(@ISA @EXPORT);
34 &GetModificationTemplates
35 &AddModificationTemplate
36 &DelModificationTemplate
38 &GetModificationTemplateAction
39 &GetModificationTemplateActions
41 &AddModificationTemplateAction
42 &ModModificationTemplateAction
43 &DelModificationTemplateAction
44 &MoveModificationTemplateAction
46 &ModifyRecordsWithTemplate
47 &ModifyRecordWithTemplate
54 C4::MarcModificationTemplates - Module to manage MARC Modification Templates
58 MARC Modification Templates are a tool for marc batch imports,
59 so that librarians can set up templates for various vendors'
60 files telling Koha what fields to insert data into.
66 =head2 GetModificationTemplates
68 my @templates = GetModificationTemplates( $template_id );
70 Passing optional $template_id marks it as the selected template.
74 sub GetModificationTemplates {
75 my ( $template_id ) = @_;
77 my $dbh = C4::Context->dbh;
78 my $sth = $dbh->prepare("SELECT * FROM marc_modification_templates ORDER BY name");
82 while ( my $template = $sth->fetchrow_hashref() ) {
83 $template->{'selected'} = 1
84 if $template_id && $template->{'template_id'} eq $template_id;
85 push( @templates, $template );
92 AddModificationTemplate
94 $template_id = AddModificationTemplate( $template_name[, $template_id ] );
96 If $template_id is supplied, the actions from that template will be copied
97 into the newly created template.
100 sub AddModificationTemplate {
101 my ( $template_name, $template_id_copy ) = @_;
103 my $dbh = C4::Context->dbh;
104 my $sth = $dbh->prepare("INSERT INTO marc_modification_templates ( name ) VALUES ( ? )");
105 $sth->execute( $template_name );
107 $sth = $dbh->prepare("SELECT * FROM marc_modification_templates WHERE name = ?");
108 $sth->execute( $template_name );
109 my $row = $sth->fetchrow_hashref();
110 my $template_id = $row->{'template_id'};
112 if ( $template_id_copy ) {
113 my @actions = GetModificationTemplateActions( $template_id_copy );
114 foreach my $action ( @actions ) {
115 AddModificationTemplateAction(
118 $action->{'field_number'},
119 $action->{'from_field'},
120 $action->{'from_subfield'},
121 $action->{'field_value'},
122 $action->{'to_field'},
123 $action->{'to_subfield'},
124 $action->{'to_regex_search'},
125 $action->{'to_regex_replace'},
126 $action->{'to_regex_modifiers'},
127 $action->{'conditional'},
128 $action->{'conditional_field'},
129 $action->{'conditional_subfield'},
130 $action->{'conditional_comparison'},
131 $action->{'conditional_value'},
132 $action->{'conditional_regex'},
133 $action->{'description'},
143 DelModificationTemplate
145 DelModificationTemplate( $template_id );
148 sub DelModificationTemplate {
149 my ( $template_id ) = @_;
151 my $dbh = C4::Context->dbh;
152 my $sth = $dbh->prepare("DELETE FROM marc_modification_templates WHERE template_id = ?");
153 $sth->execute( $template_id );
157 GetModificationTemplateAction
159 my $action = GetModificationTemplateAction( $mmta_id );
162 sub GetModificationTemplateAction {
163 my ( $mmta_id ) = @_;
165 my $dbh = C4::Context->dbh;
166 my $sth = $dbh->prepare("SELECT * FROM marc_modification_template_actions WHERE mmta_id = ?");
167 $sth->execute( $mmta_id );
168 my $action = $sth->fetchrow_hashref();
174 GetModificationTemplateActions
176 my @actions = GetModificationTemplateActions( $template_id );
179 sub GetModificationTemplateActions {
180 my ( $template_id ) = @_;
182 my $dbh = C4::Context->dbh;
183 my $sth = $dbh->prepare("SELECT * FROM marc_modification_template_actions WHERE template_id = ? ORDER BY ordering");
184 $sth->execute( $template_id );
187 while ( my $action = $sth->fetchrow_hashref() ) {
188 push( @actions, $action );
195 AddModificationTemplateAction
197 AddModificationTemplateAction(
198 $template_id, $action, $field_number,
199 $from_field, $from_subfield, $field_value,
200 $to_field, $to_subfield, $to_regex_search, $to_regex_replace, $to_regex_modifiers
201 $conditional, $conditional_field, $conditional_subfield,
202 $conditional_comparison, $conditional_value,
203 $conditional_regex, $description
206 Adds a new action to the given modification template.
210 sub AddModificationTemplateAction {
225 $conditional_subfield,
226 $conditional_comparison,
232 $conditional ||= undef;
233 $conditional_comparison ||= undef;
234 $conditional_regex ||= '0';
236 my $dbh = C4::Context->dbh;
237 my $sth = $dbh->prepare( 'SELECT MAX(ordering) + 1 AS next_ordering FROM marc_modification_template_actions WHERE template_id = ?' );
238 $sth->execute( $template_id );
239 my $row = $sth->fetchrow_hashref;
240 my $ordering = $row->{'next_ordering'} || 1;
243 INSERT INTO marc_modification_template_actions (
259 conditional_subfield,
260 conditional_comparison,
265 VALUES ( NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )";
267 $sth = $dbh->prepare( $query );
284 $conditional_subfield,
285 $conditional_comparison,
293 ModModificationTemplateAction
295 ModModificationTemplateAction(
296 $mmta_id, $action, $field_number, $from_field,
297 $from_subfield, $field_value, $to_field,
298 $to_subfield, $to_regex_search, $to_regex_replace, $to_regex_modifiers, $conditional,
299 $conditional_field, $conditional_subfield,
300 $conditional_comparison, $conditional_value,
301 $conditional_regex, $description
304 Modifies an existing action.
308 sub ModModificationTemplateAction {
323 $conditional_subfield,
324 $conditional_comparison,
330 my $dbh = C4::Context->dbh;
331 $conditional ||= undef;
332 $conditional_comparison ||= undef;
333 $conditional_regex ||= '0';
336 UPDATE marc_modification_template_actions SET
345 to_regex_replace = ?,
346 to_regex_modifiers = ?,
348 conditional_field = ?,
349 conditional_subfield = ?,
350 conditional_comparison = ?,
351 conditional_value = ?,
352 conditional_regex = ?,
356 my $sth = $dbh->prepare( $query );
371 $conditional_subfield,
372 $conditional_comparison,
382 DelModificationTemplateAction
384 DelModificationTemplateAction( $mmta_id );
386 Deletes the given template action.
389 sub DelModificationTemplateAction {
390 my ( $mmta_id ) = @_;
392 my $action = GetModificationTemplateAction( $mmta_id );
394 my $dbh = C4::Context->dbh;
395 my $sth = $dbh->prepare("DELETE FROM marc_modification_template_actions WHERE mmta_id = ?");
396 $sth->execute( $mmta_id );
398 $sth = $dbh->prepare("UPDATE marc_modification_template_actions SET ordering = ordering - 1 WHERE template_id = ? AND ordering > ?");
399 $sth->execute( $action->{'template_id'}, $action->{'ordering'} );
403 MoveModificationTemplateAction
405 MoveModificationTemplateAction( $mmta_id, $where );
407 Changes the order for the given action.
408 Options for $where are 'up', 'down', 'top' and 'bottom'
410 sub MoveModificationTemplateAction {
411 my ( $mmta_id, $where ) = @_;
413 my $action = GetModificationTemplateAction( $mmta_id );
415 return if ( $action->{'ordering'} eq '1' && ( $where eq 'up' || $where eq 'top' ) );
416 return if ( $action->{'ordering'} eq GetModificationTemplateActions( $action->{'template_id'} ) && ( $where eq 'down' || $where eq 'bottom' ) );
418 my $dbh = C4::Context->dbh;
421 if ( $where eq 'up' || $where eq 'down' ) {
423 ## For up and down, we just swap the ordering number with the one above or below it.
425 ## Change the ordering for the other action
426 $query = "UPDATE marc_modification_template_actions SET ordering = ? WHERE template_id = ? AND ordering = ?";
428 my $ordering = $action->{'ordering'};
429 $ordering-- if ( $where eq 'up' );
430 $ordering++ if ( $where eq 'down' );
432 $sth = $dbh->prepare( $query );
433 $sth->execute( $action->{'ordering'}, $action->{'template_id'}, $ordering );
435 ## Change the ordering for this action
436 $query = "UPDATE marc_modification_template_actions SET ordering = ? WHERE mmta_id = ?";
437 $sth = $dbh->prepare( $query );
438 $sth->execute( $ordering, $action->{'mmta_id'} );
440 } elsif ( $where eq 'top' ) {
442 $sth = $dbh->prepare('UPDATE marc_modification_template_actions SET ordering = ordering + 1 WHERE template_id = ? AND ordering < ?');
443 $sth->execute( $action->{'template_id'}, $action->{'ordering'} );
445 $sth = $dbh->prepare('UPDATE marc_modification_template_actions SET ordering = 1 WHERE mmta_id = ?');
446 $sth->execute( $mmta_id );
448 } elsif ( $where eq 'bottom' ) {
450 my $ordering = GetModificationTemplateActions( $action->{'template_id'} );
452 $sth = $dbh->prepare('UPDATE marc_modification_template_actions SET ordering = ordering - 1 WHERE template_id = ? AND ordering > ?');
453 $sth->execute( $action->{'template_id'}, $action->{'ordering'} );
455 $sth = $dbh->prepare('UPDATE marc_modification_template_actions SET ordering = ? WHERE mmta_id = ?');
456 $sth->execute( $ordering, $mmta_id );
463 ModifyRecordsWithTemplate
465 ModifyRecordsWithTemplate( $template_id, $batch );
467 Accepts a template id and a MARC::Batch object.
470 sub ModifyRecordsWithTemplate {
471 my ( $template_id, $batch ) = @_;
473 while ( my $record = $batch->next() ) {
474 ModifyRecordWithTemplate( $template_id, $record );
479 ModifyRecordWithTemplate
481 ModifyRecordWithTemplate( $template_id, $record )
483 Accepts a MARC::Record object ( $record ) and modifies
484 it based on the actions for the given $template_id
487 sub ModifyRecordWithTemplate {
488 my ( $template_id, $record ) = @_;
490 my $current_date = dt_from_string()->ymd();
492 $branchcode = C4::Context->userenv->{branch} if C4::Context->userenv;
494 my @actions = GetModificationTemplateActions( $template_id );
496 foreach my $a ( @actions ) {
497 my $action = $a->{'action'};
498 my $field_number = $a->{'field_number'} // 1;
499 my $from_field = $a->{'from_field'};
500 my $from_subfield = $a->{'from_subfield'};
501 my $field_value = $a->{'field_value'};
502 my $to_field = $a->{'to_field'};
503 my $to_subfield = $a->{'to_subfield'};
504 my $to_regex_search = $a->{'to_regex_search'};
505 my $to_regex_replace = $a->{'to_regex_replace'};
506 my $to_regex_modifiers = $a->{'to_regex_modifiers'};
507 my $conditional = $a->{'conditional'};
508 my $conditional_field = $a->{'conditional_field'};
509 my $conditional_subfield = $a->{'conditional_subfield'};
510 my $conditional_comparison = $a->{'conditional_comparison'};
511 my $conditional_value = $a->{'conditional_value'};
512 my $conditional_regex = $a->{'conditional_regex'};
514 if ( $field_value ) {
515 $field_value =~ s/__CURRENTDATE__/$current_date/g;
516 $field_value =~ s/__BRANCHCODE__/$branchcode/g;
520 my $field_numbers = [];
521 if ( $conditional ) {
522 if ( $conditional_comparison eq 'exists' ) {
523 $field_numbers = field_exists({
525 field => $conditional_field,
526 subfield => $conditional_subfield,
528 $do = $conditional eq 'if'
530 : not @$field_numbers;
532 elsif ( $conditional_comparison eq 'not_exists' ) {
533 $field_numbers = field_exists({
535 field => $conditional_field,
536 subfield => $conditional_subfield
538 $do = $conditional eq 'if'
539 ? not @$field_numbers
542 elsif ( $conditional_comparison eq 'equals' ) {
543 $field_numbers = field_equals({
545 value => $conditional_value,
546 field => $conditional_field,
547 subfield => $conditional_subfield,
548 is_regex => $conditional_regex,
550 $do = $conditional eq 'if'
552 : not @$field_numbers;
554 elsif ( $conditional_comparison eq 'not_equals' ) {
555 $field_numbers = field_equals({
557 value => $conditional_value,
558 field => $conditional_field,
559 subfield => $conditional_subfield,
560 is_regex => $conditional_regex,
567 field => $conditional_field,
568 subfield => $conditional_subfield
573 $field_numbers = [Koha::MoreUtils::singleton ( @$field_numbers, @$all_fields ) ];
574 if ( $from_field == $conditional_field ){
575 $do = $conditional eq 'if'
577 : not @$field_numbers;
579 $do = $conditional eq 'if'
580 ? not @$field_numbers
588 # field_number == 0 if all field need to be updated
589 # or 1 if only the first field need to be updated
591 # A condition has been given
592 if ( @$field_numbers > 0 ) {
593 if ( $field_number == 1 ) {
594 # We want only the first
595 if ( $from_field == $conditional_field ){
596 # want first field matching condition
597 $field_numbers = [ $field_numbers->[0] ];
599 # condition doesn't match, so just want first occurrence of from field
600 $field_numbers = [ 1 ];
603 unless ( $from_field == $conditional_field ){
604 # condition doesn't match from fields so need all occurrences of from fields for action
605 $field_numbers = field_exists({
607 field => $from_field,
608 subfield => $from_subfield,
613 # There was no condition
615 if ( $field_number == 1 ) {
616 # We want to process the first field
617 $field_numbers = [ 1 ];
621 if ( $action eq 'copy_field' ) {
624 from_field => $from_field,
625 from_subfield => $from_subfield,
626 to_field => $to_field,
627 to_subfield => $to_subfield,
629 search => $to_regex_search,
630 replace => $to_regex_replace,
631 modifiers => $to_regex_modifiers
633 field_numbers => $field_numbers,
636 elsif ( $action eq 'copy_and_replace_field' ) {
637 copy_and_replace_field({
639 from_field => $from_field,
640 from_subfield => $from_subfield,
641 to_field => $to_field,
642 to_subfield => $to_subfield,
644 search => $to_regex_search,
645 replace => $to_regex_replace,
646 modifiers => $to_regex_modifiers
648 field_numbers => $field_numbers,
651 elsif ( $action eq 'add_field' ) {
654 field => $from_field,
655 subfield => $from_subfield,
656 values => [ $field_value ],
657 field_numbers => $field_numbers,
660 elsif ( $action eq 'update_field' ) {
663 field => $from_field,
664 subfield => $from_subfield,
665 values => [ $field_value ],
666 field_numbers => $field_numbers,
669 elsif ( $action eq 'move_field' ) {
672 from_field => $from_field,
673 from_subfield => $from_subfield,
674 to_field => $to_field,
675 to_subfield => $to_subfield,
677 search => $to_regex_search,
678 replace => $to_regex_replace,
679 modifiers => $to_regex_modifiers
681 field_numbers => $field_numbers,
684 elsif ( $action eq 'delete_field' ) {
687 field => $from_field,
688 subfield => $from_subfield,
689 field_numbers => $field_numbers,