Update fines cronjob: remove redundant scripts, remove some superfluous code in remai...
[koha_fer] / C4 / Biblio.pm
index 06b4883..e4e2dc2 100755 (executable)
@@ -239,16 +239,32 @@ sub AddBiblio {
     # now add the record
     $biblionumber = ModBiblioMarc( $record, $biblionumber, $frameworkcode ) unless $defer_marc_save;
       
-    &logaction(C4::Context->userenv->{'number'},"CATALOGUING","ADD",$biblionumber,"biblio") 
-        if C4::Context->preference("CataloguingLog");
+    logaction("CATALOGUING", "ADD", $biblionumber, "biblio") if C4::Context->preference("CataloguingLog");
 
     return ( $biblionumber, $biblioitemnumber );
 }
 
 =head2 ModBiblio
 
+=over 4
+
     ModBiblio( $record,$biblionumber,$frameworkcode);
-    Exported function (core API) to modify a biblio
+
+=back
+
+Replace an existing bib record identified by C<$biblionumber>
+with one supplied by the MARC::Record object C<$record>.  The embedded
+item, biblioitem, and biblionumber fields from the previous
+version of the bib record replace any such fields of those tags that
+are present in C<$record>.  Consequently, ModBiblio() is not
+to be used to try to modify item records.
+
+C<$frameworkcode> specifies the MARC framework to use
+when storing the modified bib record; among other things,
+this controls how MARC fields get mapped to display columns
+in the C<biblio> and C<biblioitems> tables, as well as
+which fields are used to store embedded item, biblioitem,
+and biblionumber data for indexing.
 
 =cut
 
@@ -256,7 +272,7 @@ sub ModBiblio {
     my ( $record, $biblionumber, $frameworkcode ) = @_;
     if (C4::Context->preference("CataloguingLog")) {
         my $newrecord = GetMarcBiblio($biblionumber);
-        &logaction(C4::Context->userenv->{'number'},"CATALOGUING","MODIFY",$biblionumber,"BEFORE=>".$newrecord->as_formatted);
+        logaction("CATALOGUING", "MODIFY", $biblionumber, "BEFORE=>".$newrecord->as_formatted);
     }
     
     my $dbh = C4::Context->dbh;
@@ -266,6 +282,13 @@ sub ModBiblio {
     # get the items before and append them to the biblio before updating the record, atm we just have the biblio
     my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField("items.itemnumber",$frameworkcode);
     my $oldRecord = GetMarcBiblio( $biblionumber );
+
+    # delete any item fields from incoming record to avoid
+    # duplication or incorrect data - use AddItem() or ModItem()
+    # to change items
+    foreach my $field ($record->field($itemtag)) {
+        $record->delete_field($field);
+    }
     
     # parse each item, and, for an unknown reason, re-encode each subfield 
     # if you don't do that, the record will have encoding mixed
@@ -388,8 +411,8 @@ sub DelBiblio {
     # from being generated by _koha_delete_biblioitems
     $error = _koha_delete_biblio( $dbh, $biblionumber );
 
-    &logaction(C4::Context->userenv->{'number'},"CATALOGUING","DELETE",$biblionumber,"") 
-        if C4::Context->preference("CataloguingLog");
+    logaction("CATALOGUING", "DELETE", $biblionumber, "") if C4::Context->preference("CataloguingLog");
+
     return;
 }
 
@@ -697,7 +720,7 @@ sub GetMarcStructure {
     {
         $res->{$tag}->{lib} =
           ( $forlibrarian or !$libopac ) ? $liblibrarian : $libopac;
-        $res->{$tab}->{tab}        = "";
+        $res->{$tag}->{tab}        = "";
         $res->{$tag}->{mandatory}  = $mandatory;
         $res->{$tag}->{repeatable} = $repeatable;
     }
@@ -815,11 +838,14 @@ sub GetMarcFromKohaField {
 
 =over 4
 
-Returns MARC::Record of the biblionumber passed in parameter.
-the marc record contains both biblio & item datas
+my $record = GetMarcBiblio($biblionumber);
 
 =back
 
+Returns MARC::Record representing bib identified by
+C<$biblionumber>.  If no bib exists, returns undef.
+The MARC record contains both biblio & item data.
+
 =cut
 
 sub GetMarcBiblio {
@@ -997,7 +1023,7 @@ sub GetMarcSubjects {
         my $subfield9 = $field->subfield('9');
         for my $subject_subfield (@subfields ) {
             # don't load unimarc subfields 3,4,5
-            next if (($marcflavour eq "UNIMARC") and ($subject_subfield->[0] =~ (3|4|5) ) );
+            next if (($marcflavour eq "UNIMARC") and ($subject_subfield->[0] =~ /3|4|5/ ) );
             my $code = $subject_subfield->[0];
             my $value = $subject_subfield->[1];
             my $linkvalue = $value;
@@ -1061,7 +1087,7 @@ sub GetMarcAuthors {
         my $subfield9 = $field->subfield('9');
         for my $authors_subfield (@subfields) {
             # don't load unimarc subfields 3, 5
-            next if ($marcflavour eq 'UNIMARC' and ($authors_subfield->[0] =~ (3|5) ) );
+            next if ($marcflavour eq 'UNIMARC' and ($authors_subfield->[0] =~ /3|5/ ) );
             my $subfieldcode = $authors_subfield->[0];
             my $value = $authors_subfield->[1];
             my $linkvalue = $value;
@@ -1069,7 +1095,7 @@ sub GetMarcAuthors {
             my $operator = " and " unless $count_auth==0;
             # if we have an authority link, use that as the link, otherwise use standard searching
             if ($subfield9) {
-                @link_loop = ({'limit' => 'Koha-Auth-Number' ,link => "$subfield9" });
+                @link_loop = ({'limit' => 'an' ,link => "$subfield9" });
             }
             else {
                 # reset $linkvalue if UNIMARC author responsibility
@@ -1111,17 +1137,29 @@ sub GetMarcUrls {
         for my $note ( $field->subfield('z')) {
             push @notes , {note => $note};
         }        
-        $marcurl = {  MARCURL => $url,
-                      notes => \@notes,
-                    };
         if($marcflavour eq 'MARC21') {
             my $s3 = $field->subfield('3');
             my $link = $field->subfield('y');
-            $marcurl->{'linktext'} = $link || $s3 || $url ;;
+                       unless($url =~ /^\w+:/) {
+                               if($field->indicator(1) eq '7') {
+                                       $url = $field->subfield('2') . "://" . $url;
+                               } elsif ($field->indicator(1) eq '1') {
+                                       $url = 'ftp://' . $url;
+                               } else {  
+                                       #  properly, this should be if ind1=4,
+                                       #  however we will assume http protocol since we're building a link.
+                                       $url = 'http://' . $url;
+                               }
+                       }
+                       # TODO handle ind 2 (relationship)
+               $marcurl = {  MARCURL => $url,
+                      notes => \@notes,
+            };
+            $marcurl->{'linktext'} = $link || $s3 || C4::Context->preference('URLLinkText') || $url ;;
             $marcurl->{'part'} = $s3 if($link);
             $marcurl->{'toc'} = 1 if($s3 =~ /^[Tt]able/) ;
         } else {
-            $marcurl->{'linktext'} = $url;
+            $marcurl->{'linktext'} = $url || C4::Context->preference('URLLinkText') ;
         }
         push @marcurls, $marcurl;    
     }
@@ -1452,10 +1490,12 @@ sub TransformHtmlToXml {
     L<$record> = TransformHtmlToMarc(L<$params>,L<$cgi>)
     L<$params> is a ref to an array as below:
     {
-        'tag_010_indicator_531951' ,
+        'tag_010_indicator1_531951' ,
+        'tag_010_indicator2_531951' ,
         'tag_010_code_a_531951_145735' ,
         'tag_010_subfield_a_531951_145735' ,
-        'tag_200_indicator_873510' ,
+        'tag_200_indicator1_873510' ,
+        'tag_200_indicator2_873510' ,
         'tag_200_code_a_873510_673465' ,
         'tag_200_subfield_a_873510_673465' ,
         'tag_200_code_b_873510_704318' ,
@@ -1473,7 +1513,21 @@ sub TransformHtmlToXml {
 sub TransformHtmlToMarc {
     my $params = shift;
     my $cgi    = shift;
-    
+   
+    # explicitly turn on the UTF-8 flag for all
+    # 'tag_' parameters to avoid incorrect character
+    # conversion later on
+    my $cgi_params = $cgi->Vars;
+    foreach my $param_name (keys %$cgi_params) {
+        if ($param_name =~ /^tag_/) {
+            my $param_value = $cgi_params->{$param_name};
+            if (utf8::decode($param_value)) {
+                $cgi_params->{$param_name} = $param_value;
+            } 
+            # FIXME - need to do something if string is not valid UTF-8
+        }
+    }
+   
     # creating a new record
     my $record  = MARC::Record->new();
     my $i=0;
@@ -1500,20 +1554,20 @@ sub TransformHtmlToMarc {
             }
             push @fields,$newfield if($newfield);
         } 
-        elsif ($param =~ /^tag_(\d*)_indicator_/){ # new field start when having 'input name="..._indicator_..."
+        elsif ($param =~ /^tag_(\d*)_indicator1_/){ # new field start when having 'input name="..._indicator1_..."
             my $tag  = $1;
             
             my $ind1 = substr($cgi->param($param),0,1);
-            my $ind2 = substr($cgi->param($param),1,1);
+            my $ind2 = substr($cgi->param($params->[$i+1]),0,1);
             $newfield=0;
-            my $j=$i+1;
+            my $j=$i+2;
             
             if($tag < 10){ # no code for theses fields
     # in MARC editor, 000 contains the leader.
                 if ($tag eq '000' ) {
                     $record->leader($cgi->param($params->[$j+1])) if length($cgi->param($params->[$j+1]))==24;
     # between 001 and 009 (included)
-                } else {
+                } elsif ($cgi->param($params->[$j+1]) ne '') {
                     $newfield = MARC::Field->new(
                         $tag,
                         $cgi->param($params->[$j+1]),
@@ -1524,13 +1578,13 @@ sub TransformHtmlToMarc {
                 while($params->[$j] =~ /_code_/){ # browse all it's subfield
                     my $inner_param = $params->[$j];
                     if ($newfield){
-                        if($cgi->param($params->[$j+1])){  # only if there is a value (code => value)
+                        if($cgi->param($params->[$j+1]) ne ''){  # only if there is a value (code => value)
                             $newfield->add_subfields(
                                 $cgi->param($inner_param) => $cgi->param($params->[$j+1])
                             );
                         }
                     } else {
-                        if ( $cgi->param($params->[$j+1]) ) { # creating only if there is a value (code => value)
+                        if ( $cgi->param($params->[$j+1]) ne '' ) { # creating only if there is a value (code => value)
                             $newfield = MARC::Field->new(
                                 $tag,
                                 ''.$ind1,
@@ -1826,7 +1880,7 @@ Returns a hash with all the fields for Display a given item data in a template
 
 sub PrepareItemrecordDisplay {
 
-    my ( $bibnum, $itemnum ) = @_;
+    my ( $bibnum, $itemnum, $defaultvalues ) = @_;
 
     my $dbh = C4::Context->dbh;
     my $frameworkcode = &GetFrameworkCode( $bibnum );
@@ -1855,11 +1909,7 @@ sub PrepareItemrecordDisplay {
                   $tagslib->{$tag}->{$subfield}->{'kohafield'};
 
          #        $subfield_data{marc_lib}=$tagslib->{$tag}->{$subfield}->{lib};
-                $subfield_data{marc_lib} =
-                    "<span id=\"error\" title=\""
-                  . $tagslib->{$tag}->{$subfield}->{lib} . "\">"
-                  . substr( $tagslib->{$tag}->{$subfield}->{lib}, 0, 12 )
-                  . "</span>";
+                $subfield_data{marc_lib} = $tagslib->{$tag}->{$subfield}->{lib};
                 $subfield_data{mandatory} =
                   $tagslib->{$tag}->{$subfield}->{mandatory};
                 $subfield_data{repeatable} =
@@ -1885,6 +1935,26 @@ sub PrepareItemrecordDisplay {
                         $value = $temp->subfield($CNsubfield);
                     }
                 }
+                if ( $tagslib->{$tag}->{$subfield}->{kohafield} eq
+                    'items.itemcallnumber'
+                    && $defaultvalues->{'callnumber'} )
+                {
+                    my $temp = $itemrecord->field($subfield) if ($itemrecord);
+                    unless ($temp) {
+                        $value = $defaultvalues->{'callnumber'};
+                    }
+                }
+                if ( ($tagslib->{$tag}->{$subfield}->{kohafield} eq
+                    'items.holdingbranch' ||
+                    $tagslib->{$tag}->{$subfield}->{kohafield} eq
+                    'items.homebranch')          
+                    && $defaultvalues->{'branchcode'} )
+                {
+                    my $temp = $itemrecord->field($subfield) if ($itemrecord);
+                    unless ($temp) {
+                        $value = $defaultvalues->{branchcode};
+                    }
+                }
                 if ( $tagslib->{$tag}->{$subfield}->{authorised_value} ) {
                     my @authorised_values;
                     my %authorised_lib;
@@ -1974,7 +2044,7 @@ sub PrepareItemrecordDisplay {
                 }
                 elsif ( $tagslib->{$tag}->{$subfield}->{thesaurus_category} ) {
                     $subfield_data{marc_value} =
-"<input type=\"text\" name=\"field_value\"  size=47 maxlength=255> <a href=\"javascript:Dopop('cataloguing/thesaurus_popup.pl?category=$tagslib->{$tag}->{$subfield}->{thesaurus_category}&index=',)\">...</a>";
+"<input type=\"text\" name=\"field_value\"  size=\"47\" maxlength=\"255\" /> <a href=\"javascript:Dopop('cataloguing/thesaurus_popup.pl?category=$tagslib->{$tag}->{$subfield}->{thesaurus_category}&index=',)\">...</a>";
 
 #"
 # COMMENTED OUT because No $i is provided with this API.
@@ -1989,7 +2059,7 @@ sub PrepareItemrecordDisplay {
                 }
                 else {
                     $subfield_data{marc_value} =
-"<input type=\"text\" name=\"field_value\" value=\"$value\" size=50 maxlength=255>";
+"<input type=\"text\" name=\"field_value\" value=\"$value\" size=\"50\" maxlength=\"255\" />";
                 }
                 push( @loop_data, \%subfield_data );
             }
@@ -2070,8 +2140,8 @@ sub ModZebra {
         # lock the nozebra table : we will read index lines, update them in Perl process
         # and write everything in 1 transaction.
         # lock the table to avoid someone else overwriting what we are doing
-        $dbh->do('LOCK TABLES nozebra WRITE,biblio WRITE,biblioitems WRITE, systempreferences WRITE, auth_types WRITE, auth_header WRITE');
-        my %result; # the result hash that will be builded by deletion / add, and written on mySQL at the end, to improve speed
+        $dbh->do('LOCK TABLES nozebra WRITE,biblio WRITE,biblioitems WRITE, systempreferences WRITE, auth_types WRITE, auth_header WRITE, auth_subfield_structure READ');
+        my %result; # the result hash that will be built by deletion / add, and written on mySQL at the end, to improve speed
         if ($op eq 'specialUpdate') {
             # OK, we have to add or update the record
             # 1st delete (virtually, in indexes), if record actually exists
@@ -2093,7 +2163,6 @@ sub ModZebra {
             }
         }
         $dbh->do('UNLOCK TABLES');
-
     } else {
         #
         # we use zebra, just fill zebraqueue table
@@ -2169,12 +2238,13 @@ sub _DelBiblioNoZebra {
         $title = lc($record->subfield($titletag,$titlesubfield));
     } else {
         # for authorities, the "title" is the $a mainentry
-        my $authref = C4::AuthoritiesMarc::GetAuthType($record->subfield(152,'b'));
+        my ($auth_type_tag, $auth_type_sf) = C4::AuthoritiesMarc::get_auth_type_location();
+        my $authref = C4::AuthoritiesMarc::GetAuthType($record->subfield($auth_type_tag, $auth_type_sf));
         warn "ERROR : authtype undefined for ".$record->as_formatted unless $authref;
         $title = $record->subfield($authref->{auth_tag_to_report},'a');
         $index{'mainmainentry'}= $authref->{'auth_tag_to_report'}.'a';
         $index{'mainentry'}    = $authref->{'auth_tag_to_report'}.'*';
-        $index{'auth_type'}    = '152b';
+        $index{'auth_type'}    = "${auth_type_tag}${auth_type_sf}";
     }
     
     my %result;
@@ -2263,12 +2333,13 @@ sub _AddBiblioNoZebra {
     } else {
         # warn "server : $server";
         # for authorities, the "title" is the $a mainentry
-        my $authref = C4::AuthoritiesMarc::GetAuthType($record->subfield(152,'b'));
+        my ($auth_type_tag, $auth_type_sf) = C4::AuthoritiesMarc::get_auth_type_location();
+        my $authref = C4::AuthoritiesMarc::GetAuthType($record->subfield($auth_type_tag, $auth_type_sf));
         warn "ERROR : authtype undefined for ".$record->as_formatted unless $authref;
         $title = $record->subfield($authref->{auth_tag_to_report},'a');
         $index{'mainmainentry'} = $authref->{auth_tag_to_report}.'a';
         $index{'mainentry'}     = $authref->{auth_tag_to_report}.'*';
-        $index{'auth_type'}     = '152b';
+        $index{'auth_type'}    = "${auth_type_tag}${auth_type_sf}";
     }
 
     # remove blancks comma (that could cause problem when decoding the string for CQL retrieval) and regexp specific values
@@ -2284,7 +2355,7 @@ sub _AddBiblioNoZebra {
             my $tag = $field->tag();
             my $subfieldcode = $subfield->[0];
             my $indexed=0;
-            warn "INDEXING :".$subfield->[1];
+            warn "INDEXING :".$subfield->[1];
             # check each index to see if the subfield is stored somewhere
             # otherwise, store it in __RAW__ index
             foreach my $key (keys %index) {
@@ -2442,7 +2513,7 @@ sub _koha_marc_update_bib_ids {
 
         # drop old field and create new one...
         $old_field = $record->field($biblio_tag);
-        $record->delete_field($old_field);
+        $record->delete_field($old_field) if $old_field;
         $record->append_fields($new_field);
 
         # deal with biblioitemnumber
@@ -2455,7 +2526,7 @@ sub _koha_marc_update_bib_ids {
         }
         # drop old field and create new one...
         $old_field = $record->field($biblioitem_tag);
-        $record->delete_field($old_field);
+        $record->delete_field($old_field) if $old_field;
         $record->insert_fields_ordered($new_field);
 
     } else {
@@ -2468,7 +2539,7 @@ sub _koha_marc_update_bib_ids {
 
         # drop old field and create new one...
         my $old_field = $record->field($biblio_tag);
-        $record->delete_field($old_field);
+        $record->delete_field($old_field) if $old_field;
         $record->insert_fields_ordered($new_field);
     }
 }
@@ -3074,6 +3145,68 @@ sub set_service_options {
     return $serviceOptions;
 }
 
+=head3 get_biblio_authorised_values
+
+  find the types and values for all authorised values assigned to this biblio.
+
+  parameters:
+    biblionumber
+
+  returns: a hashref malling the authorised value to the value set for this biblionumber
+
+      $authorised_values = {
+                             'Scent'     => 'flowery',
+                             'Audience'  => 'Young Adult',
+                             'itemtypes' => 'SER',
+                           };
+
+  Notes: forlibrarian should probably be passed in, and called something different.
+
+
+=cut
+
+sub get_biblio_authorised_values {
+    my $biblionumber = shift;
+    
+    my $forlibrarian = 1; # are we in staff or opac?
+    my $frameworkcode = GetFrameworkCode( $biblionumber );
+
+    my $authorised_values;
+
+    my $record  = GetMarcBiblio( $biblionumber )
+      or return $authorised_values;
+    my $tagslib = GetMarcStructure( $forlibrarian, $frameworkcode )
+      or return $authorised_values;
+
+    # assume that these entries in the authorised_value table are bibliolevel.
+    # ones that start with 'item%' are item level.
+    my $query = q(SELECT distinct authorised_value, kohafield
+                    FROM marc_subfield_structure
+                    WHERE authorised_value !=''
+                      AND (kohafield like 'biblio%'
+                       OR  kohafield like '') );
+    my $bibliolevel_authorised_values = C4::Context->dbh->selectall_hashref( $query, 'authorised_value' );
+    
+    foreach my $tag ( keys( %$tagslib ) ) {
+        foreach my $subfield ( keys( %{$tagslib->{ $tag }} ) ) {
+            # warn "checking $subfield. type is: " . ref $tagslib->{ $tag }{ $subfield };
+            if ( 'HASH' eq ref $tagslib->{ $tag }{ $subfield } ) {
+                if ( exists $tagslib->{ $tag }{ $subfield }{'authorised_value'} && exists $bibliolevel_authorised_values->{ $tagslib->{ $tag }{ $subfield }{'authorised_value'} } ) {
+                    if ( defined $record->field( $tag ) ) {
+                        my $this_subfield_value = $record->field( $tag )->subfield( $subfield );
+                        if ( defined $this_subfield_value ) {
+                            $authorised_values->{ $tagslib->{ $tag }{ $subfield }{'authorised_value'} } = $this_subfield_value;
+                        }
+                    }
+                }
+            }
+        }
+    }
+    # warn ( Data::Dumper->Dump( [ $authorised_values ], [ 'authorised_values' ] ) );
+    return $authorised_values;
+}
+
+
 1;
 
 __END__