X-Git-Url: http://koha-dev.rot13.org:8081/gitweb/?a=blobdiff_plain;f=C4%2FItems.pm;h=0756832232702be5d7c04aa2c60a465d1e978a5e;hb=a1ec82845372cd888021220f056d465e9e65f4f2;hp=d2936081c243daacbf6466af85bdf99744c705c3;hpb=a4b2280b6be100727e5d6f85b9e6fe58392febf0;p=koha_gimpoz diff --git a/C4/Items.pm b/C4/Items.pm index d2936081c2..0756832232 100644 --- a/C4/Items.pm +++ b/C4/Items.pm @@ -33,6 +33,9 @@ use C4::Branch; require C4::Reserves; 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); @@ -65,14 +68,20 @@ BEGIN { GetItemInfosOf GetItemsByBiblioitemnumber GetItemsInfo + GetItemsLocationInfo + GetHostItemsInfo get_itemnumbers_of + get_hostitemnumbers_of GetItemnumberFromBarcode GetBarcodeFromItemnumber - + GetHiddenItemnumbers DelItemCheck MoveItemFromBiblio GetLatestAcquisitions CartToShelf + + GetAnalyticsCount + GetItemHolds ); } @@ -259,9 +268,7 @@ sub AddItem { 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"); @@ -367,7 +374,7 @@ sub AddItemBatchFromMarc { } # update the MARC biblio - $biblionumber = ModBiblioMarc( $record, $biblionumber, $frameworkcode ); + # $biblionumber = ModBiblioMarc( $record, $biblionumber, $frameworkcode ); return (\@itemnumbers, \@errors); } @@ -394,6 +401,8 @@ Note that only columns that can be directly changed from the cataloging and serials item editors are included in this hash. +Returns item record + =cut my %default_values_for_mod_from_marc = ( @@ -412,6 +421,7 @@ my %default_values_for_mod_from_marc = ( itemnotes => undef, itype => undef, location => undef, + permanent_location => undef, materials => undef, notforloan => 0, paidfor => undef, @@ -442,7 +452,8 @@ sub ModItemFromMarc { } 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 @@ -491,6 +502,9 @@ sub ModItem { }; $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 @@ -503,18 +517,11 @@ sub ModItem { # update items table _koha_modify_item($item); - # update biblio MARC XML - my $whole_item = GetItem($itemnumber) or die "FAILED GetItem($itemnumber)"; + # request that bib be reindexed so that searching on current + # item status is possible + ModZebra( $biblionumber, "specialUpdate", "biblioserver", undef, undef ); - unless (defined $unlinked_item_subfields) { - $unlinked_item_subfields = _parse_unlinked_item_subfields_from_xml($whole_item->{'more_subfields_xml'}); - } - my $new_item_marc = _marc_from_item_hash($whole_item, $frameworkcode, $unlinked_item_subfields) - or die "FAILED _marc_from_item_hash($whole_item, $frameworkcode)"; - - _replace_item_field_in_biblio($new_item_marc, $biblionumber, $itemnumber, $frameworkcode); - ($new_item_marc eq '0') and die "$new_item_marc is '0', not hashref"; # logaction line would crash anyway - logaction("CATALOGUING", "MODIFY", $itemnumber, $new_item_marc->as_formatted) if C4::Context->preference("CataloguingLog"); + logaction("CATALOGUING", "MODIFY", $itemnumber, Dumper($item)) if C4::Context->preference("CataloguingLog"); } =head2 ModItemTransfer @@ -575,23 +582,14 @@ sub DelItem { # get the MARC record my $record = GetMarcBiblio($biblionumber); - my $frameworkcode = GetFrameworkCode($biblionumber); + ModZebra( $biblionumber, "specialUpdate", "biblioserver", undef, undef ); # 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 - my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField("items.itemnumber",$frameworkcode); - my @fields = $record->field($itemtag); - - # delete the item specified - foreach my $field (@fields) { - if ( $field->subfield($itemsubfield) eq $itemnumber ) { - $record->delete_field($field); - } - } - &ModBiblioMarc( $record, $biblionumber, $frameworkcode ); logaction("CATALOGUING", "DELETE", $itemnumber, "item") if C4::Context->preference("CataloguingLog"); } @@ -1126,16 +1124,12 @@ sub GetItemsByBiblioitemnumber { =head2 GetItemsInfo - @results = GetItemsInfo($biblionumber, $type); + @results = GetItemsInfo($biblionumber); -Returns information about books with the given biblionumber. - -C<$type> may be either C or anything else. If it is not set to -C, then the search will exclude lost, very overdue, and -withdrawn items. +Returns information about items with the given biblionumber. C 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, C, C, and C tables in the Koha database. Other keys include: @@ -1171,7 +1165,7 @@ If this is set, it is set to C. =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 = " @@ -1193,7 +1187,7 @@ sub GetItemsInfo { 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 = " @@ -1220,6 +1214,7 @@ sub GetItemsInfo { $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; @@ -1347,6 +1342,112 @@ sub GetItemsInfo { } } +=head2 GetItemsLocationInfo + + my @itemlocinfo = GetItemsLocationInfo($biblionumber); + +Returns the branch names, shelving location and itemcallnumber for each item attached to the biblio in question + +C returns a list of references-to-hash. Data returned: + +=over 2 + +=item C<$data-E{homebranch}> + +Branch Name of the item's homebranch + +=item C<$data-E{holdingbranch}> + +Branch Name of the item's holdingbranch + +=item C<$data-E{location}> + +Item's shelving location code + +=item C<$data-E{location_intranet}> + +The intranet description for the Shelving Location as set in authorised_values 'LOC' + +=item C<$data-E{location_opac}> + +The OPAC description for the Shelving Location as set in authorised_values 'LOC'. Falls back to intranet description if no OPAC +description is set. + +=item C<$data-E{itemcallnumber}> + +Item's itemcallnumber + +=item C<$data-E{cn_sort}> + +Item's call number normalized for sorting + +=back + +=cut + +sub GetItemsLocationInfo { + my $biblionumber = shift; + my @results; + + my $dbh = C4::Context->dbh; + my $query = "SELECT a.branchname as homebranch, b.branchname as holdingbranch, + location, itemcallnumber, cn_sort + FROM items, branches as a, branches as b + WHERE homebranch = a.branchcode AND holdingbranch = b.branchcode + AND biblionumber = ? + ORDER BY cn_sort ASC"; + my $sth = $dbh->prepare($query); + $sth->execute($biblionumber); + + while ( my $data = $sth->fetchrow_hashref ) { + $data->{location_intranet} = GetKohaAuthorisedValueLib('LOC', $data->{location}); + $data->{location_opac}= GetKohaAuthorisedValueLib('LOC', $data->{location}, 1); + push @results, $data; + } + 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 my $lastacq = GetLastAcquisitions({'branches' => ('branch1','branch2'), @@ -1433,6 +1534,53 @@ sub get_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); @@ -1467,6 +1615,57 @@ sub GetBarcodeFromItemnumber { return ($result); } +=head2 GetHiddenItemnumbers + +=over 4 + +$result = GetHiddenItemnumbers(@items); + +=back + +=cut + +sub GetHiddenItemnumbers { + my (@items) = @_; + my @resultitems; + + my $yaml = C4::Context->preference('OpacHiddenItems'); + my $hidingrules; + eval { + $hidingrules = YAML::Load($yaml); + }; + if ($@) { + warn "Unable to parse OpacHiddenItems syspref : $@"; + return (); + } else { + my $dbh = C4::Context->dbh; + + # For each item + foreach my $item (@items) { + + # We check each rule + foreach my $field (keys %$hidingrules) { + my $query = "SELECT $field from items where itemnumber = ?"; + my $sth = $dbh->prepare($query); + $sth->execute($item->{'itemnumber'}); + my ($result) = $sth->fetchrow; + + # If the results matches the values in the yaml file + if (any { $result eq $_ } @{$hidingrules->{$field}}) { + + # We add the itemnumber to the list + push @resultitems, $item->{'itemnumber'}; + + # If at least one rule matched for an item, no need to test the others + last; + } + } + } + return @resultitems; + } + + } + =head3 get_item_authorised_values find the types and values for all authorised values assigned to this item. @@ -1871,9 +2070,9 @@ sub _koha_new_item { homebranch = ?, price = ?, replacementprice = ?, - replacementpricedate = NOW(), + replacementpricedate = ?, datelastborrowed = ?, - datelastseen = NOW(), + datelastseen = ?, stack = ?, notforloan = ?, damaged = ?, @@ -1885,6 +2084,7 @@ sub _koha_new_item { holdingbranch = ?, paidfor = ?, location = ?, + permanent_location = ?, onloan = ?, issues = ?, renewals = ?, @@ -1901,6 +2101,7 @@ sub _koha_new_item { stocknumber = ? "; my $sth = $dbh->prepare($query); + my $today = C4::Dates->today('iso'); $sth->execute( $item->{'biblionumber'}, $item->{'biblioitemnumber'}, @@ -1910,7 +2111,9 @@ sub _koha_new_item { $item->{'homebranch'}, $item->{'price'}, $item->{'replacementprice'}, + $item->{'replacementpricedate'} || $today, $item->{datelastborrowed}, + $item->{datelastseen} || $today, $item->{stack}, $item->{'notforloan'}, $item->{'damaged'}, @@ -1922,6 +2125,7 @@ sub _koha_new_item { $item->{'holdingbranch'}, $item->{'paidfor'}, $item->{'location'}, + $item->{'permanent_location'}, $item->{'onloan'}, $item->{'issues'}, $item->{'renewals'}, @@ -1937,10 +2141,15 @@ sub _koha_new_item { $item->{'copynumber'}, $item->{'stocknumber'}, ); - my $itemnumber = $dbh->{'mysql_insertid'}; + + my $itemnumber; if ( defined $sth->errstr ) { $error.="ERROR in _koha_new_item $query".$sth->errstr; } + else { + $itemnumber = $dbh->{'mysql_insertid'}; + } + return ( $itemnumber, $error ); } @@ -1963,59 +2172,18 @@ sub MoveItemFromBiblio { $sth = $dbh->prepare("UPDATE items SET biblioitemnumber = ?, biblionumber = ? WHERE itemnumber = ? AND biblionumber = ?"); my $return = $sth->execute($tobiblioitem, $tobiblio, $itemnumber, $frombiblio); if ($return == 1) { - - # Getting framework - my $frameworkcode = GetFrameworkCode($frombiblio); - - # Getting marc field for itemnumber - my ($itemtag, $itemsubfield) = GetMarcFromKohaField('items.itemnumber', $frameworkcode); - - # Getting the record we want to move the item from - my $record = GetMarcBiblio($frombiblio); - - # The item we want to move - my $item; - - # For each item - foreach my $fielditem ($record->field($itemtag)){ - # If it is the item we want to move - if ($fielditem->subfield($itemsubfield) == $itemnumber) { - # We save it - $item = $fielditem; - # Then delete it from the record - $record->delete_field($fielditem) - } - } - - # If we found an item (should always true, except in case of database-marcxml inconsistency) - if ($item) { - + ModZebra( $tobiblio, "specialUpdate", "biblioserver", undef, undef ); + ModZebra( $frombiblio, "specialUpdate", "biblioserver", undef, undef ); # Checking if the item we want to move is in an order - my $order = GetOrderFromItemnumber($itemnumber); + my $order = GetOrderFromItemnumber($itemnumber); if ($order) { - # Replacing the biblionumber within the order if necessary - $order->{'biblionumber'} = $tobiblio; + # Replacing the biblionumber within the order if necessary + $order->{'biblionumber'} = $tobiblio; ModOrder($order); } - - # Saving the modification - ModBiblioMarc($record, $frombiblio, $frameworkcode); - - # Getting the record we want to move the item to - $record = GetMarcBiblio($tobiblio); - - # Inserting the previously saved item - $record->insert_fields_ordered($item); - - # Saving the modification - ModBiblioMarc($record, $tobiblio, $frameworkcode); - - } else { - return undef; + return $tobiblio; } - } else { - return undef; - } + return; } =head2 DelItemCheck @@ -2030,35 +2198,39 @@ sub DelItemCheck { 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); - 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"; - } - 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; } @@ -2176,68 +2348,6 @@ sub _marc_from_item_hash { 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 @@ -2337,4 +2447,51 @@ sub _parse_unlinked_item_subfields_from_xml { 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;