Bug 27259: Add HomeOrHoldingBranch checks where it was missing from
[koha.git] / authorities / authorities.pl
1 #!/usr/bin/perl
2
3
4 # Copyright 2000-2002 Katipo Communications
5 #
6 # This file is part of Koha.
7 #
8 # Koha is free software; you can redistribute it and/or modify it
9 # under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # Koha is distributed in the hope that it will be useful, but
14 # WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License
19 # along with Koha; if not, see <http://www.gnu.org/licenses>.
20
21 use Modern::Perl;
22
23 use CGI qw ( -utf8 );
24 use C4::Auth qw( get_template_and_user );
25 use C4::Output qw( output_html_with_http_headers );
26 use C4::AuthoritiesMarc qw( AddAuthority ModAuthority GetAuthority GetTagsLabels GetAuthMARCFromKohaField FindDuplicateAuthority );
27 use C4::Context;
28 use Date::Calc qw( Today );
29 use MARC::File::USMARC;
30 use MARC::File::XML;
31 use C4::Biblio qw( TransformHtmlToMarc );
32 use Koha::Authority::Types;
33 use Koha::Import::Records;
34 use Koha::ItemTypes;
35 use vars qw( $tagslib);
36 use vars qw( $authorised_values_sth);
37 use vars qw( $is_a_modif );
38
39 our($authorised_values_sth,$is_a_modif,$usedTagsLib,$mandatory_z3950);
40
41 =head1 FUNCTIONS
42
43 =over
44
45 =item build_authorized_values_list
46
47 builds list, depending on authorised value...
48
49 =cut
50
51 sub build_authorized_values_list {
52     my ( $tag, $subfield, $value, $dbh, $authorised_values_sth,$index_tag,$index_subfield ) = @_;
53
54     my @authorised_values;
55     my %authorised_lib;
56
57     my $category = $tagslib->{$tag}->{$subfield}->{'authorised_value'};
58     push @authorised_values, q{} unless $tagslib->{$tag}->{$subfield}->{mandatory} && $value;
59
60     if ( $category eq "branches" ) {
61         my $sth = $dbh->prepare( "select branchcode,branchname from branches order by branchname" );
62         $sth->execute;
63         while ( my ( $branchcode, $branchname ) = $sth->fetchrow_array ) {
64             push @authorised_values, $branchcode;
65             $authorised_lib{$branchcode} = $branchname;
66         }
67     }
68     elsif ( $category eq "itemtypes" ) {
69         my $itemtypes = Koha::ItemTypes->search_with_localization;
70         while ( my $itemtype = $itemtypes->next ) {
71             push @authorised_values, $itemtype->itemtype;
72             $authorised_lib{$itemtype->itemtype} = $itemtype->translated_description;
73         }
74     }
75     else { # "true" authorised value
76         $authorised_values_sth->execute(
77             $tagslib->{$tag}->{$subfield}->{authorised_value}
78         );
79         while ( my ( $value, $lib ) = $authorised_values_sth->fetchrow_array ) {
80             push @authorised_values, $value;
81             $authorised_lib{$value} = $lib;
82         }
83     }
84
85     return {
86         type     => 'select',
87         id       => "tag_".$tag."_subfield_".$subfield."_".$index_tag."_".$index_subfield,
88         name     => "tag_".$tag."_subfield_".$subfield."_".$index_tag."_".$index_subfield,
89         values   => \@authorised_values,
90         labels   => \%authorised_lib,
91         default  => $value,
92         ( ( grep { $_ eq $category } ( qw(branches itemtypes cn_source) ) ) ? () : ( category => $category ) ),
93     };
94 }
95
96 =item create_input
97
98 builds the <input ...> entry for a subfield.
99
100 =cut
101
102 sub create_input {
103     my ( $tag, $subfield, $value, $index_tag, $rec, $authorised_values_sth, $cgi ) = @_;
104
105     my $index_subfield = CreateKey(); # create a specifique key for each subfield
106
107     # determine maximum length; 9999 bytes per ISO 2709 except for leader and MARC21 008
108     my $max_length = 9999;
109     if ($tag eq '000') {
110         $max_length = 24;
111     } elsif ($tag eq '008' and C4::Context->preference('marcflavour') eq 'MARC21')  {
112         $max_length = 40;
113     }
114
115     # if there is no value provided but a default value in parameters, get it
116     if ($value eq '') {
117         $value = $tagslib->{$tag}->{$subfield}->{defaultvalue} if !$cgi->param('authid'); # only for new records
118         if (!defined $value) {
119             $value = q{};
120         }
121
122         # get today date & replace YYYY, MM, DD if provided in the default value
123         my ( $year, $month, $day ) = Today();
124         $month = sprintf( "%02d", $month );
125         $day   = sprintf( "%02d", $day );
126         $value =~ s/YYYY/$year/g;
127         $value =~ s/MM/$month/g;
128         $value =~ s/DD/$day/g;
129     }
130     my $dbh = C4::Context->dbh;
131
132     # map '@' as "subfield" label for fixed fields
133     # to something that's allowed in a div id.
134     my $id_subfield = $subfield;
135     $id_subfield = "00" if $id_subfield eq "@";
136
137     my %subfield_data = (
138         tag        => $tag,
139         subfield   => $id_subfield,
140         marc_lib       => $tagslib->{$tag}->{$subfield}->{lib},
141         tag_mandatory  => $tagslib->{$tag}->{mandatory},
142         mandatory      => $tagslib->{$tag}->{$subfield}->{mandatory},
143         repeatable     => $tagslib->{$tag}->{$subfield}->{repeatable},
144         kohafield      => $tagslib->{$tag}->{$subfield}->{kohafield},
145         index          => $index_tag,
146         id             => "tag_".$tag."_subfield_".$id_subfield."_".$index_tag."_".$index_subfield,
147         value          => $value,
148         random         => CreateKey(),
149     );
150
151     if(exists $mandatory_z3950->{$tag.$subfield}){
152         $subfield_data{z3950_mandatory} = $mandatory_z3950->{$tag.$subfield};
153     }
154     
155     $subfield_data{visibility} = "display:none;"
156         if( $tagslib->{$tag}->{$subfield}->{hidden} and $value ne ''
157             or ($value eq '' and !$tagslib->{$tag}->{$subfield}->{mandatory})
158         );
159     
160     # it's an authorised field
161     if ( $tagslib->{$tag}->{$subfield}->{authorised_value} ) {
162         $subfield_data{marc_value} =
163         build_authorized_values_list( $tag, $subfield, $value, $dbh,
164             $authorised_values_sth,$index_tag,$index_subfield );
165
166     # it's a thesaurus / authority field
167     }
168     elsif ( $tagslib->{$tag}->{$subfield}->{authtypecode} ) {
169         $subfield_data{marc_value} = {
170             type         => 'text1',
171             id           => $subfield_data{id},
172             name         => $subfield_data{id},
173             value        => $value,
174             authtypecode => $tagslib->{$tag}->{$subfield}->{authtypecode},
175         };
176     }
177     elsif ( $tagslib->{$tag}->{$subfield}->{'value_builder'} ) { # plugin
178         require Koha::FrameworkPlugin;
179         my $plugin = Koha::FrameworkPlugin->new({
180             name => $tagslib->{$tag}->{$subfield}->{'value_builder'},
181         });
182         my $pars=  { dbh => $dbh, record => $rec, tagslib =>$tagslib,
183             id => $subfield_data{id} };
184         $plugin->build( $pars );
185         if( !$plugin->errstr ) {
186             $subfield_data{marc_value} = {
187                 type       => 'text2',
188                 id        => $subfield_data{id},
189                 name      => $subfield_data{id},
190                 value     => $value,
191                 maxlength => $max_length,
192                 javascript => $plugin->javascript,
193                 noclick    => $plugin->noclick,
194             };
195         } else { # warn and supply default field
196             warn $plugin->errstr;
197             $subfield_data{marc_value} = {
198                 type      => 'text',
199                 id        => $subfield_data{id},
200                 name      => $subfield_data{id},
201                 value     => $value,
202                 maxlength => $max_length,
203             };
204         }
205     }
206     # it's an hidden field
207     elsif ( $tag eq '' ) {
208         $subfield_data{marc_value} = {
209             type      => 'hidden',
210             id        => $subfield_data{id},
211             name      => $subfield_data{id},
212             value     => $value,
213             maxlength => $max_length,
214         }
215     }
216     elsif ( $tagslib->{$tag}->{$subfield}->{'hidden'} ) {
217         $subfield_data{marc_value} = {
218             type => 'text',
219             id        => $subfield_data{id},
220             name      => $subfield_data{id},
221             value     => $value,
222             maxlength => $max_length,
223         };
224
225         # it's a standard field
226     }
227     else {
228         if (
229             length($value) > 100
230             or
231             ( C4::Context->preference("marcflavour") eq "UNIMARC" && $tag >= 300
232                 and $tag < 400 && $subfield eq 'a' )
233             or (    $tag >= 600
234                 and $tag < 700
235                 && C4::Context->preference("marcflavour") eq "MARC21" )
236         )
237         {
238             $subfield_data{marc_value} = {
239                 type => 'textarea',
240                 id        => $subfield_data{id},
241                 name      => $subfield_data{id},
242                 value     => $value,
243                 maxlength => $max_length,
244             };
245
246         }
247         else {
248             $subfield_data{marc_value} = {
249                 type => 'text',
250                 id        => $subfield_data{id},
251                 name      => $subfield_data{id},
252                 value     => $value,
253                 maxlength => $max_length,
254             };
255
256         }
257     }
258     if ($cgi->param('tagreport') && $subfield_data{tag} == $cgi->param('tagreport')) {
259         $subfield_data{marc_value}{value} = $cgi->param('tag'. $cgi->param('tagbiblio') . 'subfield' . $subfield_data{subfield});
260     }
261     $subfield_data{'index_subfield'} = $index_subfield;
262     return \%subfield_data;
263 }
264
265 =item format_indicator
266
267 Translate indicator value for output form - specifically, map
268 indicator = ' ' to ''.  This is for the convenience of a cataloger
269 using a mouse to select an indicator input.
270
271 =cut
272
273 sub format_indicator {
274     my $ind_value = shift;
275     return '' if not defined $ind_value;
276     return '' if $ind_value eq ' ';
277     return $ind_value;
278 }
279
280 =item CreateKey
281
282 Create a random value to set it into the input name
283
284 =cut
285
286 sub CreateKey {
287     return int(rand(1000000));
288 }
289
290 =item GetMandatoryFieldZ3950
291
292     This function returns a hashref which contains all mandatory field
293     to search with z3950 server.
294
295 =cut
296
297 sub GetMandatoryFieldZ3950 {
298     my $authtypecode = shift;
299     if ( C4::Context->preference('marcflavour') eq 'MARC21' ){
300         return {
301             '100a' => 'authorpersonal',
302             '110a' => 'authorcorp',
303             '111a' => 'authormeetingcon',
304             '130a' => 'uniformtitle',
305             '150a' => 'subject',
306         };
307     }else{
308         return {
309             '200a' => 'authorpersonal',
310             '210a' => 'authorcorp', #210 in UNIMARC is used for both corporation and meeting
311             '230a' => 'uniformtitle',
312         };
313     }
314 }
315
316 sub build_tabs {
317     my ( $template, $record, $dbh, $input ) = @_;
318
319     # fill arrays
320     my @loop_data = ();
321     my $tag;
322
323     my $authorised_values_sth = $dbh->prepare(
324         "SELECT authorised_value,lib
325         FROM authorised_values
326         WHERE category=? ORDER BY lib"
327     );
328     
329     # in this array, we will push all the 10 tabs
330     # to avoid having 10 tabs in the template : they will all be in the same BIG_LOOP
331     my @BIG_LOOP;
332     my %seen;
333     my @tab_data; # all tags to display
334     
335     foreach my $used ( keys %$tagslib ){
336         push @tab_data,$used if not $seen{$used};
337         $seen{$used}++;
338     }
339         
340     my $max_num_tab=9;
341     # loop through each tab 0 through 9
342     for ( my $tabloop = 0 ; $tabloop <= $max_num_tab ; $tabloop++ ) {
343         my @loop_data = (); #innerloop in the template.
344         my $i = 0;
345         foreach my $tag (sort @tab_data) {
346             $i++;
347             next if ! $tag;
348             my ($indicator1, $indicator2);
349             my $index_tag = CreateKey;
350
351             # if MARC::Record is not empty =>use it as master loop, then add missing subfields that should be in the tab.
352             # if MARC::Record is empty => use tab as master loop.
353             if ( $record && ( $record->field($tag) || $tag eq '000' ) ) {
354                 my @fields;
355                 if ( $tag ne '000' ) {
356                                 @fields = $record->field($tag);
357                 }
358                 else {
359                 push @fields, $record->leader(); # if tag == 000
360                 }
361                 # loop through each field
362                 foreach my $field (@fields) {
363                     
364                     my @subfields_data;
365                     if ( $tag < 10 ) {
366                         my ( $value, $subfield );
367                         if ( $tag ne '000' ) {
368                             $value    = $field->data();
369                             $subfield = "@";
370                         }
371                         else {
372                             $value    = $field;
373                             $subfield = '@';
374                         }
375                         next if ( $tagslib->{$tag}->{$subfield}->{tab} ne $tabloop );
376                         next if $tagslib->{$tag}->{$subfield}->{hidden} && $subfield ne '9';
377                         push(
378                             @subfields_data,
379                             &create_input(
380                                 $tag, $subfield, $value, $index_tag, $record,
381                                 $authorised_values_sth,$input
382                             )
383                         );
384                     }
385                     else {
386                         my @subfields = $field->subfields();
387                         foreach my $subfieldcount ( 0 .. $#subfields ) {
388                             my $subfield = $subfields[$subfieldcount][0];
389                             my $value    = $subfields[$subfieldcount][1];
390                             next if ( length $subfield != 1 );
391                             next if ( $tagslib->{$tag}->{$subfield}->{tab} ne $tabloop );
392                             next if $tagslib->{$tag}->{$subfield}->{hidden} && $subfield ne '9';
393                             push(
394                                 @subfields_data,
395                                 &create_input(
396                                     $tag, $subfield, $value, $index_tag,
397                                     $record, $authorised_values_sth,$input
398                                 )
399                             );
400                         }
401                     }
402
403                     # now, loop again to add parameter subfield that are not in the MARC::Record
404                     foreach my $subfield ( sort( keys %{ $tagslib->{$tag} } ) )
405                     {
406                         next if ( length $subfield != 1 );
407                         next if ( $tagslib->{$tag}->{$subfield}->{tab} ne $tabloop );
408                         next if ( $tag < 10 );
409                         next if $tagslib->{$tag}->{$subfield}->{hidden} && $subfield ne '9';
410                         next if ( defined( $field->subfield($subfield) ) );
411                         push(
412                             @subfields_data,
413                             &create_input(
414                                 $tag, $subfield, '', $index_tag, $record,
415                                 $authorised_values_sth,$input
416                             )
417                         );
418                     }
419                     if ( $#subfields_data >= 0 ) {
420                         # build the tag entry.
421                         # note that the random() field is mandatory. Otherwise, on repeated fields, you'll 
422                         # have twice the same "name" value, and cgi->param() will return only one, making
423                         # all subfields to be merged in a single field.
424                         my %tag_data = (
425                             tag           => $tag,
426                             index         => $index_tag,
427                             tag_lib       => $tagslib->{$tag}->{lib},
428                             repeatable       => $tagslib->{$tag}->{repeatable},
429                             mandatory       => $tagslib->{$tag}->{mandatory},
430                             subfield_loop => \@subfields_data,
431                             fixedfield    => ($tag < 10)?(1):(0),
432                             random        => CreateKey,
433                         );
434                         if ($tag >= 10){ # no indicator for theses tag
435                             $tag_data{indicator1} = format_indicator($field->indicator(1)),
436                             $tag_data{indicator2} = format_indicator($field->indicator(2)),
437                         }
438                         push( @loop_data, \%tag_data );
439                     }
440                 } # foreach $field end
441
442             # if breeding is empty
443             }
444             else {
445                 my @subfields_data;
446                 foreach my $subfield (
447                     sort { $a->{display_order} <=> $b->{display_order} || $a->{subfield} cmp $b->{subfield} }
448                     grep { ref($_) && %$_ } # Not a subfield (values for "important", "lib", "mandatory", etc.) or empty
449                     values %{ $tagslib->{$tag} } )
450                 {
451                     next if $subfield->{hidden} && $subfield->{subfield} ne '9';
452                     next if ( $subfield->{tab} ne $tabloop );
453                     push(
454                         @subfields_data,
455                         &create_input(
456                             $tag, $subfield->{subfield}, '', $index_tag, $record,
457                             $authorised_values_sth,$input
458                         )
459                     );
460                 }
461                 if ( $#subfields_data >= 0 ) {
462                     my %tag_data = (
463                         tag              => $tag,
464                         index            => $index_tag,
465                         tag_lib          => $tagslib->{$tag}->{lib},
466                         repeatable       => $tagslib->{$tag}->{repeatable},
467                         mandatory       => $tagslib->{$tag}->{mandatory},
468                         indicator1       => $indicator1,
469                         indicator2       => $indicator2,
470                         subfield_loop    => \@subfields_data,
471                         tagfirstsubfield => $subfields_data[0],
472                         fixedfield       => ($tag < 10)?(1):(0)
473                     );
474                     
475                     push @loop_data, \%tag_data ;
476                 }
477             }
478         }
479         if ( $#loop_data >= 0 ) {
480             push @BIG_LOOP, {
481                 number    => $tabloop,
482                 innerloop => \@loop_data,
483             };
484         }
485     }
486     $template->param( BIG_LOOP => \@BIG_LOOP );
487 }
488
489
490 sub build_hidden_data {
491     # build hidden data =>
492     # we store everything, even if we show only requested subfields.
493
494     my @loop_data =();
495     my $i=0;
496     foreach my $tag (keys %{$tagslib}) {
497         my $previous_tag = '';
498
499         # loop through each subfield
500         foreach my $subfield (keys %{$tagslib->{$tag}}) {
501             next if ($subfield eq 'lib');
502             next if ($subfield eq 'tab');
503             next if ($subfield eq 'mandatory');
504                 next if ($subfield eq 'repeatable');
505             next if ($tagslib->{$tag}->{$subfield}->{'tab'}  ne "-1");
506             my %subfield_data;
507             $subfield_data{marc_lib}=$tagslib->{$tag}->{$subfield}->{lib};
508             $subfield_data{marc_mandatory}=$tagslib->{$tag}->{$subfield}->{mandatory};
509             $subfield_data{marc_repeatable}=$tagslib->{$tag}->{$subfield}->{repeatable};
510             $subfield_data{marc_value} = {
511                 type => 'hidden_simple',
512                 name => 'field_value[]',
513             };
514             push(@loop_data, \%subfield_data);
515             $i++
516         }
517     }
518 }
519
520 =back
521
522 =cut
523
524
525 # ======================== 
526 #          MAIN 
527 #=========================
528 my $input = CGI->new;
529 my $z3950 = $input->param('z3950');
530 my $error = $input->param('error');
531 my $authid=$input->param('authid'); # if authid exists, it's a modif, not a new authority.
532 my $op = $input->param('op');
533 my $nonav = $input->param('nonav');
534 my $myindex = $input->param('index');
535 my $linkid=$input->param('linkid');
536 my $authtypecode = $input->param('authtypecode');
537 my $breedingid    = $input->param('breedingid');
538
539
540 my $dbh = C4::Context->dbh;
541 if(!$authtypecode) {
542     $authtypecode = $authid ? Koha::Authorities->find($authid)->authtypecode : '';
543 }
544
545 my $authobj = Koha::Authorities->find($authid);
546 my $count = $authobj ? $authobj->get_usage_count : 0;
547
548 my ($template, $loggedinuser, $cookie)
549     = get_template_and_user({template_name => "authorities/authorities.tt",
550                             query => $input,
551                             type => "intranet",
552                             flagsrequired => {editauthorities => 1},
553                             });
554 $template->param(nonav   => $nonav,index=>$myindex,authtypecode=>$authtypecode,breedingid=>$breedingid, count=>$count);
555
556 $tagslib = GetTagsLabels(1,$authtypecode);
557 $mandatory_z3950 = GetMandatoryFieldZ3950($authtypecode);
558
559 my $record;
560 if ($breedingid) {
561     my $import_record = Koha::Import::Records->find($breedingid);
562     if ($import_record) {
563         $record = $import_record->get_marc_record();
564     }
565 } elsif ($authid) {
566     $record = GetAuthority($authid);
567 }
568
569 my ($oldauthnumtagfield,$oldauthnumtagsubfield);
570 my ($oldauthtypetagfield,$oldauthtypetagsubfield);
571 $is_a_modif=0;
572 if ($authid) {
573     $is_a_modif=1;
574     ($oldauthnumtagfield,$oldauthnumtagsubfield) = GetAuthMARCFromKohaField("auth_header.authid",$authtypecode);
575     ($oldauthtypetagfield,$oldauthtypetagsubfield) = GetAuthMARCFromKohaField("auth_header.authtypecode",$authtypecode);
576 }
577 $op ||= q{};
578 #------------------------------------------------------------------------------------------------------------------------------
579 if ($op eq "add") {
580 #------------------------------------------------------------------------------------------------------------------------------
581     # rebuild
582     my @tags = $input->multi_param('tag');
583     my @subfields = $input->multi_param('subfield');
584     my @values = $input->multi_param('field_value');
585     # build indicator hash.
586     my @ind_tag = $input->multi_param('ind_tag');
587     my @indicator = $input->multi_param('indicator');
588     my $record = TransformHtmlToMarc($input, 0);
589
590     my ($duplicateauthid,$duplicateauthvalue);
591      ($duplicateauthid,$duplicateauthvalue) = FindDuplicateAuthority($record,$authtypecode) if ($op eq "add") && (!$is_a_modif);
592     my $confirm_not_duplicate = $input->param('confirm_not_duplicate');
593     # it is not a duplicate (determined either by Koha itself or by user checking it's not a duplicate)
594     if (!$duplicateauthid or $confirm_not_duplicate) {
595         if ($is_a_modif ) {     
596             ModAuthority($authid,$record,$authtypecode);
597         } else {
598             ($authid) = AddAuthority($record,$authid,$authtypecode);
599         }
600         if ($myindex) {
601             print $input->redirect("blinddetail-biblio-search.pl?authid=$authid&index=$myindex");
602         } else {
603             print $input->redirect("detail.pl?authid=$authid");
604         }
605         exit;
606     } else {
607     # it may be a duplicate, warn the user and do nothing
608         build_tabs($template, $record, $dbh, $input);
609         build_hidden_data;
610         $template->param(authid =>$authid,
611                         duplicateauthid     => $duplicateauthid,
612                         duplicateauthvalue  => $duplicateauthvalue->{'authorized'}->[0]->{'heading'},
613                         );
614     }
615 } elsif ($op eq "delete") {
616 #------------------------------------------------------------------------------------------------------------------------------
617         DelAuthority({ authid => $authid });
618         if ($nonav){
619             print $input->redirect("auth_finder.pl");
620         }else{
621             print $input->redirect("authorities-home.pl?authid=0");
622         }
623                 exit;
624 } else {
625 if ($op eq "duplicate")
626         {
627                 $authid = "";
628         }
629         build_tabs ($template, $record, $dbh, $input);
630         build_hidden_data;
631         $template->param(oldauthtypetagfield=>$oldauthtypetagfield, oldauthtypetagsubfield=>$oldauthtypetagsubfield,
632                         oldauthnumtagfield=>$oldauthnumtagfield, oldauthnumtagsubfield=>$oldauthnumtagsubfield,
633                         authid                      => $authid , authtypecode=>$authtypecode,   );
634 }
635
636 my $authority_types = Koha::Authority::Types->search( {}, { order_by => ['authtypetext'] } );
637
638 my $type = $authority_types->find($authtypecode);
639 $template->param(
640     authority_types => $authority_types,
641     authtypecode    => $authtypecode,
642     authid          => $authid,
643     linkid          => $linkid,
644     authtypetext    => $type ? $type->authtypetext : "",
645     hide_marc       => C4::Context->preference('hide_marc'),
646 );
647 output_html_with_http_headers $input, $cookie, $template->output;