Merge remote-tracking branch 'origin/new/bug_6679'
[koha_gimpoz] / C4 / Items.pm
index be080c0..0756832 100644 (file)
@@ -34,6 +34,8 @@ require C4::Reserves;
 use C4::Charset;
 use C4::Acquisition;
 use List::MoreUtils qw/any/;
 use C4::Charset;
 use C4::Acquisition;
 use List::MoreUtils qw/any/;
+use Data::Dumper; # used as part of logging item record changes, not just for
+                  # debugging; so please don't remove this
 
 use vars qw($VERSION @ISA @EXPORT);
 
 
 use vars qw($VERSION @ISA @EXPORT);
 
@@ -67,15 +69,19 @@ BEGIN {
         GetItemsByBiblioitemnumber
         GetItemsInfo
        GetItemsLocationInfo
         GetItemsByBiblioitemnumber
         GetItemsInfo
        GetItemsLocationInfo
+       GetHostItemsInfo
         get_itemnumbers_of
         get_itemnumbers_of
+       get_hostitemnumbers_of
         GetItemnumberFromBarcode
         GetBarcodeFromItemnumber
         GetItemnumberFromBarcode
         GetBarcodeFromItemnumber
-      GetHiddenItemnumbers
-
+        GetHiddenItemnumbers
                DelItemCheck
                MoveItemFromBiblio 
                GetLatestAcquisitions
         CartToShelf
                DelItemCheck
                MoveItemFromBiblio 
                GetLatestAcquisitions
         CartToShelf
+
+       GetAnalyticsCount
+        GetItemHolds
     );
 }
 
     );
 }
 
@@ -262,9 +268,6 @@ sub AddItem {
        my ( $itemnumber, $error ) = _koha_new_item( $item, $item->{barcode} );
     $item->{'itemnumber'} = $itemnumber;
 
        my ( $itemnumber, $error ) = _koha_new_item( $item, $item->{barcode} );
     $item->{'itemnumber'} = $itemnumber;
 
-    # create MARC tag representing item and add to bib
-    #my $new_item_marc = _marc_from_item_hash($item, $frameworkcode, $unlinked_item_subfields);
-    #_add_item_field_to_biblio($new_item_marc, $item->{'biblionumber'}, $frameworkcode );
     ModZebra( $item->{biblionumber}, "specialUpdate", "biblioserver", undef, undef );
    
     logaction("CATALOGUING", "ADD", $itemnumber, "item") if C4::Context->preference("CataloguingLog");
     ModZebra( $item->{biblionumber}, "specialUpdate", "biblioserver", undef, undef );
    
     logaction("CATALOGUING", "ADD", $itemnumber, "item") if C4::Context->preference("CataloguingLog");
@@ -398,6 +401,8 @@ Note that only columns that can be directly
 changed from the cataloging and serials
 item editors are included in this hash.
 
 changed from the cataloging and serials
 item editors are included in this hash.
 
+Returns item record
+
 =cut
 
 my %default_values_for_mod_from_marc = (
 =cut
 
 my %default_values_for_mod_from_marc = (
@@ -416,6 +421,7 @@ my %default_values_for_mod_from_marc = (
     itemnotes            => undef, 
     itype                => undef, 
     location             => undef, 
     itemnotes            => undef, 
     itype                => undef, 
     location             => undef, 
+    permanent_location   => undef,
     materials            => undef, 
     notforloan           => 0,
     paidfor              => undef, 
     materials            => undef, 
     notforloan           => 0,
     paidfor              => undef, 
@@ -446,7 +452,8 @@ sub ModItemFromMarc {
     }
     my $unlinked_item_subfields = _get_unlinked_item_subfields( $localitemmarc, $frameworkcode );
 
     }
     my $unlinked_item_subfields = _get_unlinked_item_subfields( $localitemmarc, $frameworkcode );
 
-    return ModItem($item, $biblionumber, $itemnumber, $dbh, $frameworkcode, $unlinked_item_subfields); 
+    ModItem($item, $biblionumber, $itemnumber, $dbh, $frameworkcode, $unlinked_item_subfields); 
+    return $item;
 }
 
 =head2 ModItem
 }
 
 =head2 ModItem
@@ -495,6 +502,9 @@ sub ModItem {
     };
 
     $item->{'itemnumber'} = $itemnumber or return undef;
     };
 
     $item->{'itemnumber'} = $itemnumber or return undef;
+
+    $item->{onloan} = undef if $item->{itemlost};
+
     _set_derived_columns_for_mod($item);
     _do_column_fixes_for_mod($item);
     # FIXME add checks
     _set_derived_columns_for_mod($item);
     _do_column_fixes_for_mod($item);
     # FIXME add checks
@@ -507,9 +517,9 @@ sub ModItem {
     # update items table
     _koha_modify_item($item);
 
     # update items table
     _koha_modify_item($item);
 
-    # update biblio MARC XML
-    my $whole_item = GetItem($itemnumber) or die "FAILED GetItem($itemnumber)";
-    ModZebra( $whole_item->{biblionumber}, "specialUpdate", "biblioserver", undef, undef );
+    # request that bib be reindexed so that searching on current
+    # item status is possible
+    ModZebra( $biblionumber, "specialUpdate", "biblioserver", undef, undef );
 
     logaction("CATALOGUING", "MODIFY", $itemnumber, Dumper($item)) if C4::Context->preference("CataloguingLog");
 }
 
     logaction("CATALOGUING", "MODIFY", $itemnumber, Dumper($item)) if C4::Context->preference("CataloguingLog");
 }
@@ -577,6 +587,7 @@ sub DelItem {
     # backup the record
     my $copy2deleted = $dbh->prepare("UPDATE deleteditems SET marc=? WHERE itemnumber=?");
     $copy2deleted->execute( $record->as_usmarc(), $itemnumber );
     # backup the record
     my $copy2deleted = $dbh->prepare("UPDATE deleteditems SET marc=? WHERE itemnumber=?");
     $copy2deleted->execute( $record->as_usmarc(), $itemnumber );
+    # This last update statement makes that the timestamp column in deleteditems is updated too. If you remove these lines, please add a line to update the timestamp separately. See Bugzilla report 7146 and Biblio.pm (DelBiblio).
 
     #search item field code
     logaction("CATALOGUING", "DELETE", $itemnumber, "item") if C4::Context->preference("CataloguingLog");
 
     #search item field code
     logaction("CATALOGUING", "DELETE", $itemnumber, "item") if C4::Context->preference("CataloguingLog");
@@ -1113,16 +1124,12 @@ sub GetItemsByBiblioitemnumber {
 
 =head2 GetItemsInfo
 
 
 =head2 GetItemsInfo
 
-  @results = GetItemsInfo($biblionumber, $type);
+  @results = GetItemsInfo($biblionumber);
 
 
-Returns information about books with the given biblionumber.
-
-C<$type> may be either C<intra> or anything else. If it is not set to
-C<intra>, then the search will exclude lost, very overdue, and
-withdrawn items.
+Returns information about items with the given biblionumber.
 
 C<GetItemsInfo> returns a list of references-to-hash. Each element
 
 C<GetItemsInfo> returns a list of references-to-hash. Each element
-contains a number of keys. Most of them are table items from the
+contains a number of keys. Most of them are attributes from the
 C<biblio>, C<biblioitems>, C<items>, and C<itemtypes> tables in the
 Koha database. Other keys include:
 
 C<biblio>, C<biblioitems>, C<items>, and C<itemtypes> tables in the
 Koha database. Other keys include:
 
@@ -1158,7 +1165,7 @@ If this is set, it is set to C<One Order>.
 =cut
 
 sub GetItemsInfo {
 =cut
 
 sub GetItemsInfo {
-    my ( $biblionumber, $type ) = @_;
+    my ( $biblionumber ) = @_;
     my $dbh   = C4::Context->dbh;
     # note biblioitems.* must be avoided to prevent large marc and marcxml fields from killing performance.
     my $query = "
     my $dbh   = C4::Context->dbh;
     # note biblioitems.* must be avoided to prevent large marc and marcxml fields from killing performance.
     my $query = "
@@ -1180,7 +1187,7 @@ sub GetItemsInfo {
            itemtypes.notforloan as notforloan_per_itemtype,
            branchurl
      FROM items
            itemtypes.notforloan as notforloan_per_itemtype,
            branchurl
      FROM items
-     LEFT JOIN branches ON items.homebranch = branches.branchcode
+     LEFT JOIN branches ON items.holdingbranch = branches.branchcode
      LEFT JOIN biblio      ON      biblio.biblionumber     = items.biblionumber
      LEFT JOIN biblioitems ON biblioitems.biblioitemnumber = items.biblioitemnumber
      LEFT JOIN itemtypes   ON   itemtypes.itemtype         = "
      LEFT JOIN biblio      ON      biblio.biblionumber     = items.biblionumber
      LEFT JOIN biblioitems ON biblioitems.biblioitemnumber = items.biblioitemnumber
      LEFT JOIN itemtypes   ON   itemtypes.itemtype         = "
@@ -1207,6 +1214,7 @@ sub GetItemsInfo {
             $data->{cardnumber}     = $idata->{cardnumber};
             $data->{surname}     = $idata->{surname};
             $data->{firstname}     = $idata->{firstname};
             $data->{cardnumber}     = $idata->{cardnumber};
             $data->{surname}     = $idata->{surname};
             $data->{firstname}     = $idata->{firstname};
+            $data->{lastreneweddate} = $idata->{lastreneweddate};
             $datedue                = $idata->{'date_due'};
         if (C4::Context->preference("IndependantBranches")){
         my $userenv = C4::Context->userenv;
             $datedue                = $idata->{'date_due'};
         if (C4::Context->preference("IndependantBranches")){
         my $userenv = C4::Context->userenv;
@@ -1399,6 +1407,46 @@ sub GetItemsLocationInfo {
        return @results;
 }
 
        return @results;
 }
 
+=head2 GetHostItemsInfo
+
+       $hostiteminfo = GetHostItemsInfo($hostfield);
+       Returns the iteminfo for items linked to records via a host field
+
+=cut
+
+sub GetHostItemsInfo {
+       my ($record) = @_;
+       my @returnitemsInfo;
+
+       if (C4::Context->preference('marcflavour') eq 'MARC21' ||
+        C4::Context->preference('marcflavour') eq 'NORMARC'){
+           foreach my $hostfield ( $record->field('773') ) {
+               my $hostbiblionumber = $hostfield->subfield("0");
+               my $linkeditemnumber = $hostfield->subfield("9");
+               my @hostitemInfos = GetItemsInfo($hostbiblionumber);
+               foreach my $hostitemInfo (@hostitemInfos){
+                       if ($hostitemInfo->{itemnumber} eq $linkeditemnumber){
+                               push (@returnitemsInfo,$hostitemInfo);
+                               last;
+                       }
+               }
+           }
+       } elsif ( C4::Context->preference('marcflavour') eq 'UNIMARC'){
+           foreach my $hostfield ( $record->field('461') ) {
+               my $hostbiblionumber = $hostfield->subfield("0");
+               my $linkeditemnumber = $hostfield->subfield("9");
+               my @hostitemInfos = GetItemsInfo($hostbiblionumber);
+               foreach my $hostitemInfo (@hostitemInfos){
+                       if ($hostitemInfo->{itemnumber} eq $linkeditemnumber){
+                               push (@returnitemsInfo,$hostitemInfo);
+                               last;
+                       }
+               }
+           }
+       }
+       return @returnitemsInfo;
+}
+
 
 =head2 GetLastAcquisitions
 
 
 =head2 GetLastAcquisitions
 
@@ -1486,6 +1534,53 @@ sub get_itemnumbers_of {
     return \%itemnumbers_of;
 }
 
     return \%itemnumbers_of;
 }
 
+=head2 get_hostitemnumbers_of
+
+  my @itemnumbers_of = get_hostitemnumbers_of($biblionumber);
+
+Given a biblionumber, return the list of corresponding itemnumbers that are linked to it via host fields
+
+Return a reference on a hash where key is a biblionumber and values are
+references on array of itemnumbers.
+
+=cut
+
+
+sub get_hostitemnumbers_of {
+       my ($biblionumber) = @_;
+       my $marcrecord = GetMarcBiblio($biblionumber);
+        my (@returnhostitemnumbers,$tag, $biblio_s, $item_s);
+       
+       my $marcflavor = C4::Context->preference('marcflavour');
+       if ($marcflavor eq 'MARC21' || $marcflavor eq 'NORMARC') {
+        $tag='773';
+        $biblio_s='0';
+        $item_s='9';
+    } elsif ($marcflavor eq 'UNIMARC') {
+        $tag='461';
+        $biblio_s='0';
+        $item_s='9';
+    }
+
+    foreach my $hostfield ( $marcrecord->field($tag) ) {
+        my $hostbiblionumber = $hostfield->subfield($biblio_s);
+        my $linkeditemnumber = $hostfield->subfield($item_s);
+        my @itemnumbers;
+        if (my $itemnumbers = get_itemnumbers_of($hostbiblionumber)->{$hostbiblionumber})
+        {
+            @itemnumbers = @$itemnumbers;
+        }
+        foreach my $itemnumber (@itemnumbers){
+            if ($itemnumber eq $linkeditemnumber){
+                push (@returnhostitemnumbers,$itemnumber);
+                last;
+            }
+        }
+    }
+    return @returnhostitemnumbers;
+}
+
+
 =head2 GetItemnumberFromBarcode
 
   $result = GetItemnumberFromBarcode($barcode);
 =head2 GetItemnumberFromBarcode
 
   $result = GetItemnumberFromBarcode($barcode);
@@ -1975,9 +2070,9 @@ sub _koha_new_item {
             homebranch          = ?,
             price               = ?,
             replacementprice    = ?,
             homebranch          = ?,
             price               = ?,
             replacementprice    = ?,
-            replacementpricedate = NOW(),
+            replacementpricedate = ?,
             datelastborrowed    = ?,
             datelastborrowed    = ?,
-            datelastseen        = NOW(),
+            datelastseen        = ?,
             stack               = ?,
             notforloan          = ?,
             damaged             = ?,
             stack               = ?,
             notforloan          = ?,
             damaged             = ?,
@@ -1989,6 +2084,7 @@ sub _koha_new_item {
             holdingbranch       = ?,
             paidfor             = ?,
             location            = ?,
             holdingbranch       = ?,
             paidfor             = ?,
             location            = ?,
+            permanent_location            = ?,
             onloan              = ?,
             issues              = ?,
             renewals            = ?,
             onloan              = ?,
             issues              = ?,
             renewals            = ?,
@@ -2005,6 +2101,7 @@ sub _koha_new_item {
             stocknumber         = ?
           ";
     my $sth = $dbh->prepare($query);
             stocknumber         = ?
           ";
     my $sth = $dbh->prepare($query);
+    my $today = C4::Dates->today('iso');
    $sth->execute(
             $item->{'biblionumber'},
             $item->{'biblioitemnumber'},
    $sth->execute(
             $item->{'biblionumber'},
             $item->{'biblioitemnumber'},
@@ -2014,7 +2111,9 @@ sub _koha_new_item {
             $item->{'homebranch'},
             $item->{'price'},
             $item->{'replacementprice'},
             $item->{'homebranch'},
             $item->{'price'},
             $item->{'replacementprice'},
+            $item->{'replacementpricedate'} || $today,
             $item->{datelastborrowed},
             $item->{datelastborrowed},
+            $item->{datelastseen} || $today,
             $item->{stack},
             $item->{'notforloan'},
             $item->{'damaged'},
             $item->{stack},
             $item->{'notforloan'},
             $item->{'damaged'},
@@ -2026,6 +2125,7 @@ sub _koha_new_item {
             $item->{'holdingbranch'},
             $item->{'paidfor'},
             $item->{'location'},
             $item->{'holdingbranch'},
             $item->{'paidfor'},
             $item->{'location'},
+            $item->{'permanent_location'},
             $item->{'onloan'},
             $item->{'issues'},
             $item->{'renewals'},
             $item->{'onloan'},
             $item->{'issues'},
             $item->{'renewals'},
@@ -2041,10 +2141,15 @@ sub _koha_new_item {
             $item->{'copynumber'},
             $item->{'stocknumber'},
     );
             $item->{'copynumber'},
             $item->{'stocknumber'},
     );
-    my $itemnumber = $dbh->{'mysql_insertid'};
+
+    my $itemnumber;
     if ( defined $sth->errstr ) {
         $error.="ERROR in _koha_new_item $query".$sth->errstr;
     }
     if ( defined $sth->errstr ) {
         $error.="ERROR in _koha_new_item $query".$sth->errstr;
     }
+    else {
+        $itemnumber = $dbh->{'mysql_insertid'};
+    }
+
     return ( $itemnumber, $error );
 }
 
     return ( $itemnumber, $error );
 }
 
@@ -2093,35 +2198,39 @@ sub DelItemCheck {
     my ( $dbh, $biblionumber, $itemnumber ) = @_;
     my $error;
 
     my ( $dbh, $biblionumber, $itemnumber ) = @_;
     my $error;
 
+        my $countanalytics=GetAnalyticsCount($itemnumber);
+
+
     # check that there is no issue on this item before deletion.
     my $sth=$dbh->prepare("select * from issues i where i.itemnumber=?");
     $sth->execute($itemnumber);
 
     my $item = GetItem($itemnumber);
     # check that there is no issue on this item before deletion.
     my $sth=$dbh->prepare("select * from issues i where i.itemnumber=?");
     $sth->execute($itemnumber);
 
     my $item = GetItem($itemnumber);
-    my $onloan = $sth->fetchrow;
-    if ($onloan) {
-        $error = "book_on_loan";
+    my $onloan=$sth->fetchrow;
+
+    if ($onloan){
+        $error = "book_on_loan" 
     }
     }
-    elsif (C4::Context->preference("IndependantBranches") and (C4::Context->userenv->{branch} ne $item->{C4::Context->preference("HomeOrHoldingBranch")||'homebranch'})){
+    elsif ( C4::Context->userenv->{flags} & 1 and
+            C4::Context->preference("IndependantBranches") and
+           (C4::Context->userenv->{branch} ne
+             $item->{C4::Context->preference("HomeOrHoldingBranch")||'homebranch'}) )
+    {
         $error = "not_same_branch";
         $error = "not_same_branch";
-    } 
-    else {
-       if ($onloan){ 
-           $error = "book_on_loan" 
-       }
-       else {
-           # check it doesnt have a waiting reserve
-           $sth=$dbh->prepare("SELECT * FROM reserves WHERE (found = 'W' or found = 'T') AND itemnumber = ?");
-           $sth->execute($itemnumber);
-           my $reserve=$sth->fetchrow;
-           if ($reserve) {
-               $error = "book_reserved";
-           } 
-           else {
-               DelItem($dbh, $biblionumber, $itemnumber);
-               return 1;
-           }
-       }
+    }
+       else{
+        # check it doesnt have a waiting reserve
+        $sth=$dbh->prepare("SELECT * FROM reserves WHERE (found = 'W' or found = 'T') AND itemnumber = ?");
+        $sth->execute($itemnumber);
+        my $reserve=$sth->fetchrow;
+        if ($reserve){
+            $error = "book_reserved";
+        } elsif ($countanalytics > 0){
+               $error = "linked_analytics";
+       } else {
+            DelItem($dbh, $biblionumber, $itemnumber);
+            return 1;
+        }
     }
     return $error;
 }
     }
     return $error;
 }
@@ -2239,68 +2348,6 @@ sub _marc_from_item_hash {
     return $item_marc;
 }
 
     return $item_marc;
 }
 
-=head2 _add_item_field_to_biblio
-
-  _add_item_field_to_biblio($item_marc, $biblionumber, $frameworkcode);
-
-Adds the fields from a MARC record containing the
-representation of a Koha item record to the MARC
-biblio record.  The input C<$item_marc> record
-is expect to contain just one field, the embedded
-item information field.
-
-=cut
-
-sub _add_item_field_to_biblio {
-    my ($item_marc, $biblionumber, $frameworkcode) = @_;
-
-    my $biblio_marc = GetMarcBiblio($biblionumber);
-    foreach my $field ($item_marc->fields()) {
-        $biblio_marc->append_fields($field);
-    }
-
-    ModBiblioMarc($biblio_marc, $biblionumber, $frameworkcode);
-}
-
-=head2 _replace_item_field_in_biblio
-
-  &_replace_item_field_in_biblio($item_marc, $biblionumber, $itemnumber, $frameworkcode)
-
-Given a MARC::Record C<$item_marc> containing one tag with the MARC 
-representation of the item, examine the biblio MARC
-for the corresponding tag for that item and 
-replace it with the tag from C<$item_marc>.
-
-=cut
-
-sub _replace_item_field_in_biblio {
-    my ($ItemRecord, $biblionumber, $itemnumber, $frameworkcode) = @_;
-    my $dbh = C4::Context->dbh;
-    
-    # get complete MARC record & replace the item field by the new one
-    my $completeRecord = GetMarcBiblio($biblionumber);
-    my ($itemtag,$itemsubfield) = GetMarcFromKohaField("items.itemnumber",$frameworkcode);
-    my $itemField = $ItemRecord->field($itemtag);
-    my @items = $completeRecord->field($itemtag);
-    my $found = 0;
-    foreach (@items) {
-        if ($_->subfield($itemsubfield) eq $itemnumber) {
-            $_->replace_with($itemField);
-            $found = 1;
-        }
-    }
-  
-    unless ($found) { 
-        # If we haven't found the matching field,
-        # just add it.  However, this means that
-        # there is likely a bug.
-        $completeRecord->append_fields($itemField);
-    }
-
-    # save the record
-    #ModBiblioMarc($completeRecord, $biblionumber, $frameworkcode);
-}
-
 =head2 _repack_item_errors
 
 Add an error message hash generated by C<CheckItemPreSave>
 =head2 _repack_item_errors
 
 Add an error message hash generated by C<CheckItemPreSave>
@@ -2400,4 +2447,51 @@ sub  _parse_unlinked_item_subfields_from_xml {
     return $unlinked_subfields;
 }
 
     return $unlinked_subfields;
 }
 
+=head2 GetAnalyticsCount
+
+  $count= &GetAnalyticsCount($itemnumber)
+
+counts Usage of itemnumber in Analytical bibliorecords. 
+
+=cut
+
+sub GetAnalyticsCount {
+    my ($itemnumber) = @_;
+    if (C4::Context->preference('NoZebra')) {
+        # Read the index Koha-Auth-Number for this authid and count the lines
+        my $result = C4::Search::NZanalyse("hi=$itemnumber");
+        my @tab = split /;/,$result;
+        return scalar @tab;
+    } else {
+        ### ZOOM search here
+        my $query;
+        $query= "hi=".$itemnumber;
+                my ($err,$res,$result) = C4::Search::SimpleSearch($query,0,10);
+        return ($result);
+    }
+}
+
+=head2 GetItemHolds
+
+=over 4
+$holds = &GetItemHolds($biblionumber, $itemnumber);
+
+=back
+
+This function return the count of holds with $biblionumber and $itemnumber
+
+=cut
+
+sub GetItemHolds {
+    my ($biblionumber, $itemnumber) = @_;
+    my $holds;
+    my $dbh            = C4::Context->dbh;
+    my $query          = "SELECT count(*)
+        FROM  reserves
+        WHERE biblionumber=? AND itemnumber=?";
+    my $sth = $dbh->prepare($query);
+    $sth->execute($biblionumber, $itemnumber);
+    $holds = $sth->fetchrow;
+    return $holds;
+}
 1;
 1;