X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=C4%2FItems.pm;h=c9818a0cb3cc34ed1b4f264467759bad58fc1bed;hb=25b2445176529bd87e199dcc72f967702156805c;hp=74196e959ed62877555a79701c170f3c46ed086c;hpb=0411957f73fa047285f53dca61b19fee3213ce9f;p=koha.git diff --git a/C4/Items.pm b/C4/Items.pm index 74196e959e..c9818a0cb3 100644 --- a/C4/Items.pm +++ b/C4/Items.pm @@ -49,6 +49,7 @@ BEGIN { ModDateLastSeen ModItemTransfer DelItem + DelItemCheck CheckItemPreSave @@ -224,6 +225,12 @@ sub AddItem { _set_derived_columns_for_add($item); $item->{'more_subfields_xml'} = _get_unlinked_subfields_xml($unlinked_item_subfields); # FIXME - checks here + unless ( $item->{itype} ) { # default to biblioitem.itemtype if no itype + my $itype_sth = $dbh->prepare("SELECT itemtype FROM biblioitems WHERE biblionumber = ?"); + $itype_sth->execute( $item->{'biblionumber'} ); + ( $item->{'itype'} ) = $itype_sth->fetchrow_array; + } + my ( $itemnumber, $error ) = _koha_new_item( $item, $item->{barcode} ); $item->{'itemnumber'} = $itemnumber; @@ -356,8 +363,49 @@ C object containing an embedded item field. This API is meant for the use of C; for other purposes, C should be used. +This function uses the hash %default_values_for_mod_from_marc, +which contains default values for item fields to +apply when modifying an item. This is needed beccause +if an item field's value is cleared, TransformMarcToKoha +does not include the column in the +hash that's passed to ModItem, which without +use of this hash makes it impossible to clear +an item field's value. See bug 2466. + +Note that only columns that can be directly +changed from the cataloging and serials +item editors are included in this hash. + =cut +my %default_values_for_mod_from_marc = ( + barcode => undef, + booksellerid => undef, + ccode => undef, + 'items.cn_source' => undef, + copynumber => undef, + damaged => 0, + dateaccessioned => undef, + enumchron => undef, + holdingbranch => undef, + homebranch => undef, + itemcallnumber => undef, + itemlost => 0, + itemnotes => undef, + itype => undef, + location => undef, + materials => undef, + notforloan => 0, + paidfor => undef, + price => undef, + replacementprice => undef, + replacementpricedate => undef, + restricted => undef, + stack => undef, + uri => undef, + wthdrawn => 0, +); + sub ModItemFromMarc { my $item_marc = shift; my $biblionumber = shift; @@ -366,6 +414,9 @@ sub ModItemFromMarc { my $dbh = C4::Context->dbh; my $frameworkcode = GetFrameworkCode( $biblionumber ); my $item = &TransformMarcToKoha( $dbh, $item_marc, $frameworkcode ); + foreach my $item_field (keys %default_values_for_mod_from_marc) { + $item->{$item_field} = $default_values_for_mod_from_marc{$item_field} unless exists $item->{$item_field}; + } my $unlinked_item_subfields = _get_unlinked_item_subfields($item_marc, $frameworkcode); return ModItem($item, $biblionumber, $itemnumber, $dbh, $frameworkcode, $unlinked_item_subfields); @@ -536,6 +587,47 @@ sub DelItem { logaction("CATALOGUING", "DELETE", $itemnumber, "item") if C4::Context->preference("CataloguingLog"); } +=head2 DelItemCheck + +=over 4 + +DelItemCheck($dbh, $biblionumber, $itemnumber); + +=back + +Exported function (core API) for deleting an item record in Koha if there no current issue. + +=cut + +sub DelItemCheck { + my ( $dbh, $biblionumber, $itemnumber ) = @_; + my $error; + + # 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 $onloan=$sth->fetchrow; + + $sth->finish(); + if ($onloan){ + $error = "book_on_loan" + }else{ + # check it doesnt have a waiting reserve + $sth=$dbh->prepare("SELECT * FROM reserves WHERE found = 'W' AND itemnumber = ?"); + $sth->execute($itemnumber); + my $reserve=$sth->fetchrow; + $sth->finish(); + if ($reserve){ + $error = "book_reserved"; + }else{ + DelItem($dbh, $biblionumber, $itemnumber); + return 1; + } + } + return $error; +} + =head2 CheckItemPreSave =over 4 @@ -883,23 +975,24 @@ sub GetLostItems { my $query = " SELECT * - FROM items, biblio, authorised_values + FROM items + LEFT JOIN biblio ON (items.biblionumber = biblio.biblionumber) + LEFT JOIN biblioitems ON (items.biblionumber = biblioitems.biblionumber) + LEFT JOIN authorised_values ON (items.itemlost = authorised_values.authorised_value) WHERE - items.biblionumber = biblio.biblionumber - AND items.itemlost = authorised_values.authorised_value - AND authorised_values.category = 'LOST' + authorised_values.category = 'LOST' AND itemlost IS NOT NULL AND itemlost <> 0 - "; my @query_parameters; foreach my $key (keys %$where) { $query .= " AND $key LIKE ?"; push @query_parameters, "%$where->{$key}%"; } - if ( defined $orderby ) { - $query .= ' ORDER BY ?'; - push @query_parameters, $orderby; + my @ordervalues = qw/title author homebranch itype barcode price replacementprice lib datelastseen location/; + + if ( defined $orderby && grep($orderby, @ordervalues)) { + $query .= ' ORDER BY '.$orderby; } my $sth = $dbh->prepare($query); @@ -915,57 +1008,77 @@ sub GetLostItems { =over 4 -$itemlist = GetItemsForInventory($minlocation,$maxlocation,$datelastseen,$offset,$size) +$itemlist = GetItemsForInventory($minlocation, $maxlocation, $location, $itemtype $datelastseen, $branch, $offset, $size); =back Retrieve a list of title/authors/barcode/callnumber, for biblio inventory. -The sub returns a list of hashes, containing itemnumber, author, title, barcode & item callnumber. -It is ordered by callnumber,title. +The sub returns a reference to a list of hashes, each containing +itemnumber, author, title, barcode, item callnumber, and date last +seen. It is ordered by callnumber then title. -The minlocation & maxlocation parameters are used to specify a range of item callnumbers +The required minlocation & maxlocation parameters are used to specify a range of item callnumbers the datelastseen can be used to specify that you want to see items not seen since a past date only. offset & size can be used to retrieve only a part of the whole listing (defaut behaviour) =cut sub GetItemsForInventory { - my ( $minlocation, $maxlocation,$location, $itemtype, $datelastseen, $branch, $offset, $size ) = @_; + my ( $minlocation, $maxlocation,$location, $itemtype, $ignoreissued, $datelastseen, $branch, $offset, $size ) = @_; my $dbh = C4::Context->dbh; - my $sth; + my ( @bind_params, @where_strings ); + + my $query = <<'END_SQL'; +SELECT items.itemnumber, barcode, itemcallnumber, title, author, biblio.biblionumber, datelastseen +FROM items + LEFT JOIN biblio ON items.biblionumber = biblio.biblionumber + LEFT JOIN biblioitems on items.biblionumber = biblioitems.biblionumber +END_SQL + + if ($minlocation) { + push @where_strings, 'itemcallnumber >= ?'; + push @bind_params, $minlocation; + } + + if ($maxlocation) { + push @where_strings, 'itemcallnumber <= ?'; + push @bind_params, $maxlocation; + } + if ($datelastseen) { - $datelastseen=format_date_in_iso($datelastseen); - my $query = - "SELECT itemnumber,barcode,itemcallnumber,title,author,biblio.biblionumber,datelastseen - FROM items - LEFT JOIN biblio ON items.biblionumber=biblio.biblionumber - LEFT JOIN biblioitems on items.biblionumber=biblioitems.biblionumber - WHERE itemcallnumber>= ? - AND itemcallnumber <=? - AND (datelastseen< ? OR datelastseen IS NULL)"; - $query.= " AND items.location=".$dbh->quote($location) if $location; - $query.= " AND items.homebranch=".$dbh->quote($branch) if $branch; - $query.= " AND biblioitems.itemtype=".$dbh->quote($itemtype) if $itemtype; - $query .= " ORDER BY itemcallnumber,title"; - $sth = $dbh->prepare($query); - $sth->execute( $minlocation, $maxlocation, $datelastseen ); + $datelastseen = format_date_in_iso($datelastseen); + push @where_strings, '(datelastseen < ? OR datelastseen IS NULL)'; + push @bind_params, $datelastseen; + } + + if ( $location ) { + push @where_strings, 'items.location = ?'; + push @bind_params, $location; + } + + if ( $branch ) { + push @where_strings, 'items.homebranch = ?'; + push @bind_params, $branch; + } + + if ( $itemtype ) { + push @where_strings, 'biblioitems.itemtype = ?'; + push @bind_params, $itemtype; } - else { - my $query =" - SELECT itemnumber,barcode,itemcallnumber,biblio.biblionumber,title,author,datelastseen - FROM items - LEFT JOIN biblio ON items.biblionumber=biblio.biblionumber - LEFT JOIN biblioitems on items.biblionumber=biblioitems.biblionumber - WHERE itemcallnumber>= ? - AND itemcallnumber <=?"; - $query.= " AND items.location=".$dbh->quote($location) if $location; - $query.= " AND items.homebranch=".$dbh->quote($branch) if $branch; - $query.= " AND biblioitems.itemtype=".$dbh->quote($itemtype) if $itemtype; - $query .= " ORDER BY itemcallnumber,title"; - $sth = $dbh->prepare($query); - $sth->execute( $minlocation, $maxlocation ); + if ( $ignoreissued) { + $query .= "LEFT JOIN issues ON items.itemnumber = issues.itemnumber "; + push @where_strings, 'issues.date_due IS NULL'; } + + if ( @where_strings ) { + $query .= 'WHERE '; + $query .= join ' AND ', @where_strings; + } + $query .= ' ORDER BY itemcallnumber, title'; + my $sth = $dbh->prepare($query); + $sth->execute( @bind_params ); + my @results; $size--; while ( my $row = $sth->fetchrow_hashref ) { @@ -1136,14 +1249,29 @@ If this is set, it is set to C. sub GetItemsInfo { my ( $biblionumber, $type ) = @_; my $dbh = C4::Context->dbh; - my $query = "SELECT *,items.notforloan as itemnotforloan - FROM items - LEFT JOIN biblio ON biblio.biblionumber = items.biblionumber - LEFT JOIN biblioitems ON biblioitems.biblioitemnumber = items.biblioitemnumber"; - $query .= (C4::Context->preference('item-level_itypes')) ? - " LEFT JOIN itemtypes on items.itype = itemtypes.itemtype " - : " LEFT JOIN itemtypes on biblioitems.itemtype = itemtypes.itemtype "; - $query .= "WHERE items.biblionumber = ? ORDER BY items.dateaccessioned desc" ; + # note biblioitems.* must be avoided to prevent large marc and marcxml fields from killing performance. + my $query = " + SELECT items.*, + biblio.*, + biblioitems.volume, + biblioitems.number, + biblioitems.itemtype, + biblioitems.isbn, + biblioitems.issn, + biblioitems.publicationyear, + biblioitems.publishercode, + biblioitems.volumedate, + biblioitems.volumedesc, + biblioitems.lccn, + biblioitems.url, + items.notforloan as itemnotforloan, + itemtypes.description + FROM items + LEFT JOIN biblio ON biblio.biblionumber = items.biblionumber + LEFT JOIN biblioitems ON biblioitems.biblioitemnumber = items.biblioitemnumber + LEFT JOIN itemtypes ON itemtypes.itemtype = " + . (C4::Context->preference('item-level_itypes') ? 'items.itype' : 'biblioitems.itemtype'); + $query .= " WHERE items.biblionumber = ? ORDER BY items.dateaccessioned desc" ; my $sth = $dbh->prepare($query); $sth->execute($biblionumber); my $i = 0; @@ -1219,6 +1347,7 @@ sub GetItemsInfo { my ($lib) = $sthnflstatus->fetchrow; $data->{notforloanvalue} = $lib; } + $data->{itypenotforloan} = $data->{notforloan} if (C4::Context->preference('item-level_itypes')); # my stack procedures my $stackstatus = $dbh->prepare( @@ -1246,6 +1375,7 @@ sub GetItemsInfo { my $sth2 = $dbh->prepare("SELECT * FROM old_issues,borrowers WHERE itemnumber = ? AND old_issues.borrowernumber = borrowers.borrowernumber + ORDER BY returndate DESC LIMIT 3"); $sth2->execute($data->{'itemnumber'}); my $ii = 0; @@ -1259,7 +1389,6 @@ sub GetItemsInfo { $results[$i] = $data; $i++; } - $sth->finish; if($serial) { return( sort { ($b->{'publisheddate'} || $b->{'enumchron'}) cmp ($a->{'publisheddate'} || $a->{'enumchron'}) } @results ); } else { @@ -1414,7 +1543,7 @@ sub get_authorised_value_images { && $authorised_values->{ $this_authorised_value->{'category'} } eq $this_authorised_value->{'authorised_value'} ) { # warn ( Data::Dumper->Dump( [ $this_authorised_value ], [ 'this_authorised_value' ] ) ); if ( defined $this_authorised_value->{'imageurl'} ) { - push @imagelist, { imageurl => C4::Koha::getitemtypeimagesrc( 'intranet' ) . '/' . $this_authorised_value->{'imageurl'}, + push @imagelist, { imageurl => C4::Koha::getitemtypeimagelocation( 'intranet', $this_authorised_value->{'imageurl'} ), label => $this_authorised_value->{'lib'}, category => $this_authorised_value->{'category'}, value => $this_authorised_value->{'authorised_value'}, }; @@ -1471,7 +1600,11 @@ sub GetMarcItem { # Tack on 'items.' prefix to column names so that TransformKohaToMarc will work. # Also, don't emit a subfield if the underlying field is blank. - my $mungeditem = { map { $itemrecord->{$_} ne '' ? ("items.$_" => $itemrecord->{$_}) : () } keys %{ $itemrecord } }; + my $mungeditem = { + map { + defined($itemrecord->{$_}) && $itemrecord->{$_} ne '' ? ("items.$_" => $itemrecord->{$_}) : () + } keys %{ $itemrecord } + }; my $itemmarc = TransformKohaToMarc($mungeditem); my $unlinked_item_subfields = _parse_unlinked_item_subfields_from_xml($mungeditem->{'items.more_subfields_xml'}); @@ -1720,20 +1853,8 @@ C sub _set_defaults_for_add { my $item = shift; - - # if dateaccessioned is provided, use it. Otherwise, set to NOW() - if (!(exists $item->{'dateaccessioned'}) || - ($item->{'dateaccessioned'} eq '')) { - # FIXME add check for invalid date - my $today = C4::Dates->new(); - $item->{'dateaccessioned'} = $today->output("iso"); #TODO: check time issues - } - - # various item status fields cannot be null - $item->{'notforloan'} = 0 unless exists $item->{'notforloan'} and defined $item->{'notforloan'} and $item->{'notforloan'} ne ''; - $item->{'damaged'} = 0 unless exists $item->{'damaged'} and defined $item->{'damaged'} and $item->{'damaged'} ne ''; - $item->{'itemlost'} = 0 unless exists $item->{'itemlost'} and defined $item->{'itemlost'} and $item->{'itemlost'} ne ''; - $item->{'wthdrawn'} = 0 unless exists $item->{'wthdrawn'} and defined $item->{'wthdrawn'} and $item->{'wthdrawn'} ne ''; + $item->{dateaccessioned} ||= C4::Dates->new->output('iso'); + $item->{$_} ||= 0 for (qw( notforloan damaged itemlost wthdrawn)); } =head2 _koha_new_item @@ -1785,9 +1906,10 @@ sub _koha_new_item { ccode = ?, itype = ?, materials = ?, - uri = ?, + uri = ?, enumchron = ?, - more_subfields_xml = ? + more_subfields_xml = ?, + copynumber = ? "; my $sth = $dbh->prepare($query); $sth->execute( @@ -1822,7 +1944,8 @@ sub _koha_new_item { $item->{'materials'}, $item->{'uri'}, $item->{'enumchron'}, - $item->{'more_subfields_xml'}, + $item->{'more_subfields_xml'}, + $item->{'copynumber'}, ); my $itemnumber = $dbh->{'mysql_insertid'}; if ( defined $sth->errstr ) {