← Index
NYTProf Performance Profile   « block view • line view • sub view »
For /usr/share/koha/opac/cgi-bin/opac/opac-search.pl
  Run on Tue Oct 15 17:10:45 2013
Reported on Tue Oct 15 17:12:42 2013

Filename/usr/share/koha/lib/C4/Items.pm
StatementsExecuted 1577 statements in 300ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
251112.0ms839msC4::Items::::GetItemsInfoC4::Items::GetItemsInfo
32111.75ms125msC4::Items::::GetHiddenItemnumbersC4::Items::GetHiddenItemnumbers
111105µs172µsC4::Items::::BEGIN@33C4::Items::BEGIN@33
11135µs35µsC4::Items::::BEGIN@38C4::Items::BEGIN@38
11135µs46µsC4::Items::::BEGIN@21C4::Items::BEGIN@21
11127µs98µsC4::Items::::BEGIN@32C4::Items::BEGIN@32
11126µs1.02msC4::Items::::BEGIN@26C4::Items::BEGIN@26
11124µs30µsC4::Items::::BEGIN@25C4::Items::BEGIN@25
11123µs123µsC4::Items::::BEGIN@24C4::Items::BEGIN@24
11121µs238µsC4::Items::::BEGIN@31C4::Items::BEGIN@31
11120µs135µsC4::Items::::BEGIN@36C4::Items::BEGIN@36
11120µs1.34msC4::Items::::BEGIN@27C4::Items::BEGIN@27
11118µs99µsC4::Items::::BEGIN@28C4::Items::BEGIN@28
11118µs257µsC4::Items::::BEGIN@30C4::Items::BEGIN@30
11116µs38µsC4::Items::::BEGIN@29C4::Items::BEGIN@29
0000s0sC4::Items::::AddItemC4::Items::AddItem
0000s0sC4::Items::::AddItemBatchFromMarcC4::Items::AddItemBatchFromMarc
0000s0sC4::Items::::AddItemFromMarcC4::Items::AddItemFromMarc
0000s0sC4::Items::::CartToShelfC4::Items::CartToShelf
0000s0sC4::Items::::CheckItemPreSaveC4::Items::CheckItemPreSave
0000s0sC4::Items::::DelItemC4::Items::DelItem
0000s0sC4::Items::::DelItemCheckC4::Items::DelItemCheck
0000s0sC4::Items::::GetAnalyticsCountC4::Items::GetAnalyticsCount
0000s0sC4::Items::::GetBarcodeFromItemnumberC4::Items::GetBarcodeFromItemnumber
0000s0sC4::Items::::GetHostItemsInfoC4::Items::GetHostItemsInfo
0000s0sC4::Items::::GetItemC4::Items::GetItem
0000s0sC4::Items::::GetItemHoldsC4::Items::GetItemHolds
0000s0sC4::Items::::GetItemInfosOfC4::Items::GetItemInfosOf
0000s0sC4::Items::::GetItemLocationC4::Items::GetItemLocation
0000s0sC4::Items::::GetItemStatusC4::Items::GetItemStatus
0000s0sC4::Items::::GetItemnumberFromBarcodeC4::Items::GetItemnumberFromBarcode
0000s0sC4::Items::::GetItemnumbersForBiblioC4::Items::GetItemnumbersForBiblio
0000s0sC4::Items::::GetItemsByBiblioitemnumberC4::Items::GetItemsByBiblioitemnumber
0000s0sC4::Items::::GetItemsCountC4::Items::GetItemsCount
0000s0sC4::Items::::GetItemsForInventoryC4::Items::GetItemsForInventory
0000s0sC4::Items::::GetItemsLocationInfoC4::Items::GetItemsLocationInfo
0000s0sC4::Items::::GetLastAcquisitionsC4::Items::GetLastAcquisitions
0000s0sC4::Items::::GetLostItemsC4::Items::GetLostItems
0000s0sC4::Items::::GetMarcItemC4::Items::GetMarcItem
0000s0sC4::Items::::Item2MarcC4::Items::Item2Marc
0000s0sC4::Items::::ModDateLastSeenC4::Items::ModDateLastSeen
0000s0sC4::Items::::ModItemC4::Items::ModItem
0000s0sC4::Items::::ModItemFromMarcC4::Items::ModItemFromMarc
0000s0sC4::Items::::ModItemTransferC4::Items::ModItemTransfer
0000s0sC4::Items::::MoveItemFromBiblioC4::Items::MoveItemFromBiblio
0000s0sC4::Items::::PrepareItemrecordDisplayC4::Items::PrepareItemrecordDisplay
0000s0sC4::Items::::SearchItemsC4::Items::SearchItems
0000s0sC4::Items::::ShelfToCartC4::Items::ShelfToCart
0000s0sC4::Items::::__ANON__[:1668]C4::Items::__ANON__[:1668]
0000s0sC4::Items::::_calc_items_cn_sortC4::Items::_calc_items_cn_sort
0000s0sC4::Items::::_do_column_fixes_for_modC4::Items::_do_column_fixes_for_mod
0000s0sC4::Items::::_find_valueC4::Items::_find_value
0000s0sC4::Items::::_get_items_columnsC4::Items::_get_items_columns
0000s0sC4::Items::::_get_single_item_columnC4::Items::_get_single_item_column
0000s0sC4::Items::::_get_unlinked_item_subfieldsC4::Items::_get_unlinked_item_subfields
0000s0sC4::Items::::_get_unlinked_subfields_xmlC4::Items::_get_unlinked_subfields_xml
0000s0sC4::Items::::_koha_delete_itemC4::Items::_koha_delete_item
0000s0sC4::Items::::_koha_modify_itemC4::Items::_koha_modify_item
0000s0sC4::Items::::_koha_new_itemC4::Items::_koha_new_item
0000s0sC4::Items::::_marc_from_item_hashC4::Items::_marc_from_item_hash
0000s0sC4::Items::::_parse_unlinked_item_subfields_from_xmlC4::Items::_parse_unlinked_item_subfields_from_xml
0000s0sC4::Items::::_repack_item_errorsC4::Items::_repack_item_errors
0000s0sC4::Items::::_set_defaults_for_addC4::Items::_set_defaults_for_add
0000s0sC4::Items::::_set_derived_columns_for_addC4::Items::_set_derived_columns_for_add
0000s0sC4::Items::::_set_derived_columns_for_modC4::Items::_set_derived_columns_for_mod
0000s0sC4::Items::::get_authorised_value_imagesC4::Items::get_authorised_value_images
0000s0sC4::Items::::get_hostitemnumbers_ofC4::Items::get_hostitemnumbers_of
0000s0sC4::Items::::get_item_authorised_valuesC4::Items::get_item_authorised_values
0000s0sC4::Items::::get_itemnumbers_ofC4::Items::get_itemnumbers_of
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1package C4::Items;
2
3# Copyright 2007 LibLime, Inc.
4# Parts Copyright Biblibre 2010
5#
6# This file is part of Koha.
7#
8# Koha is free software; you can redistribute it and/or modify it under the
9# terms of the GNU General Public License as published by the Free Software
10# Foundation; either version 2 of the License, or (at your option) any later
11# version.
12#
13# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
14# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License along
18# with Koha; if not, write to the Free Software Foundation, Inc.,
19# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
21361µs257µs
# spent 46µs (35+11) within C4::Items::BEGIN@21 which was called: # once (35µs+11µs) by C4::Reserves::BEGIN@29 at line 21
use strict;
# spent 46µs making 1 call to C4::Items::BEGIN@21 # spent 11µs making 1 call to strict::import
22#use warnings; FIXME - Bug 2505
23
24358µs2224µs
# spent 123µs (23+100) within C4::Items::BEGIN@24 which was called: # once (23µs+100µs) by C4::Reserves::BEGIN@29 at line 24
use Carp;
# spent 123µs making 1 call to C4::Items::BEGIN@24 # spent 100µs making 1 call to Exporter::import
25356µs235µs
# spent 30µs (24+6) within C4::Items::BEGIN@25 which was called: # once (24µs+6µs) by C4::Reserves::BEGIN@29 at line 25
use C4::Context;
# spent 30µs making 1 call to C4::Items::BEGIN@25 # spent 6µs making 1 call to C4::Context::import
26364µs22.02ms
# spent 1.02ms (26µs+996µs) within C4::Items::BEGIN@26 which was called: # once (26µs+996µs) by C4::Reserves::BEGIN@29 at line 26
use C4::Koha;
# spent 1.02ms making 1 call to C4::Items::BEGIN@26 # spent 996µs making 1 call to Exporter::import
27383µs22.66ms
# spent 1.34ms (20µs+1.32) within C4::Items::BEGIN@27 which was called: # once (20µs+1.32ms) by C4::Reserves::BEGIN@29 at line 27
use C4::Biblio;
# spent 1.34ms making 1 call to C4::Items::BEGIN@27 # spent 1.32ms making 1 call to Exporter::import
28340µs2180µs
# spent 99µs (18+81) within C4::Items::BEGIN@28 which was called: # once (18µs+81µs) by C4::Reserves::BEGIN@29 at line 28
use C4::Dates qw/format_date format_date_in_iso/;
# spent 99µs making 1 call to C4::Items::BEGIN@28 # spent 81µs making 1 call to Exporter::import
29334µs260µs
# spent 38µs (16+22) within C4::Items::BEGIN@29 which was called: # once (16µs+22µs) by C4::Reserves::BEGIN@29 at line 29
use MARC::Record;
# spent 38µs making 1 call to C4::Items::BEGIN@29 # spent 22µs making 1 call to Exporter::import
30356µs2496µs
# spent 257µs (18+239) within C4::Items::BEGIN@30 which was called: # once (18µs+239µs) by C4::Reserves::BEGIN@29 at line 30
use C4::ClassSource;
# spent 257µs making 1 call to C4::Items::BEGIN@30 # spent 239µs making 1 call to Exporter::import
31363µs2454µs
# spent 238µs (21+216) within C4::Items::BEGIN@31 which was called: # once (21µs+216µs) by C4::Reserves::BEGIN@29 at line 31
use C4::Log;
# spent 238µs making 1 call to C4::Items::BEGIN@31 # spent 216µs making 1 call to Exporter::import
32368µs2168µs
# spent 98µs (27+71) within C4::Items::BEGIN@32 which was called: # once (27µs+71µs) by C4::Reserves::BEGIN@29 at line 32
use List::MoreUtils qw/any/;
# spent 98µs making 1 call to C4::Items::BEGIN@32 # spent 71µs making 1 call to Exporter::import
33379µs2240µs
# spent 172µs (105+68) within C4::Items::BEGIN@33 which was called: # once (105µs+68µs) by C4::Reserves::BEGIN@29 at line 33
use Data::Dumper; # used as part of logging item record changes, not just for
# spent 172µs making 1 call to C4::Items::BEGIN@33 # spent 68µs making 1 call to Exporter::import
34 # debugging; so please don't remove this
35
363172µs2249µs
# spent 135µs (20+115) within C4::Items::BEGIN@36 which was called: # once (20µs+115µs) by C4::Reserves::BEGIN@29 at line 36
use vars qw($VERSION @ISA @EXPORT);
# spent 135µs making 1 call to C4::Items::BEGIN@36 # spent 114µs making 1 call to vars::import
37
38
# spent 35µs within C4::Items::BEGIN@38 which was called: # once (35µs+0s) by C4::Reserves::BEGIN@29 at line 90
BEGIN {
3914µs $VERSION = 3.07.00.049;
40
4112µs require Exporter;
42114µs @ISA = qw( Exporter );
43
44 # function exports
45118µs @EXPORT = qw(
46 GetItem
47 AddItemFromMarc
48 AddItem
49 AddItemBatchFromMarc
50 ModItemFromMarc
51 Item2Marc
52 ModItem
53 ModDateLastSeen
54 ModItemTransfer
55 DelItem
56
57 CheckItemPreSave
58
59 GetItemStatus
60 GetItemLocation
61 GetLostItems
62 GetItemsForInventory
63 GetItemsCount
64 GetItemInfosOf
65 GetItemsByBiblioitemnumber
66 GetItemsInfo
67 GetItemsLocationInfo
68 GetHostItemsInfo
69 GetItemnumbersForBiblio
70 get_itemnumbers_of
71 get_hostitemnumbers_of
72 GetItemnumberFromBarcode
73 GetBarcodeFromItemnumber
74 GetHiddenItemnumbers
75 DelItemCheck
76 MoveItemFromBiblio
77 GetLatestAcquisitions
78
79 CartToShelf
80 ShelfToCart
81
82 GetAnalyticsCount
83 GetItemHolds
84
85 SearchItems
86
87 PrepareItemrecordDisplay
88
89 );
90113.8ms135µs}
# spent 35µs making 1 call to C4::Items::BEGIN@38
91
92=head1 NAME
93
- -
133=head2 GetItem
134
- -
143sub GetItem {
144 my ($itemnumber,$barcode, $serial) = @_;
145 my $dbh = C4::Context->dbh;
146 my $data;
147 if ($itemnumber) {
148 my $sth = $dbh->prepare("
149 SELECT * FROM items
150 WHERE itemnumber = ?");
151 $sth->execute($itemnumber);
152 $data = $sth->fetchrow_hashref;
153 } else {
154 my $sth = $dbh->prepare("
155 SELECT * FROM items
156 WHERE barcode = ?"
157 );
158 $sth->execute($barcode);
159 $data = $sth->fetchrow_hashref;
160 }
161 if ( $serial) {
162 my $ssth = $dbh->prepare("SELECT serialseq,publisheddate from serialitems left join serial on serialitems.serialid=serial.serialid where serialitems.itemnumber=?");
163 $ssth->execute($data->{'itemnumber'}) ;
164 ($data->{'serialseq'} , $data->{'publisheddate'}) = $ssth->fetchrow_array();
165 }
166 #if we don't have an items.itype, use biblioitems.itemtype.
167 if( ! $data->{'itype'} ) {
168 my $sth = $dbh->prepare("SELECT itemtype FROM biblioitems WHERE biblionumber = ?");
169 $sth->execute($data->{'biblionumber'});
170 ($data->{'itype'}) = $sth->fetchrow_array;
171 }
172 return $data;
173} # sub GetItem
174
175=head2 CartToShelf
176
- -
187sub CartToShelf {
188 my ( $itemnumber ) = @_;
189
190 unless ( $itemnumber ) {
191 croak "FAILED CartToShelf() - no itemnumber supplied";
192 }
193
194 my $item = GetItem($itemnumber);
195 if ( $item->{location} eq 'CART' ) {
196 $item->{location} = $item->{permanent_location};
197 ModItem($item, undef, $itemnumber);
198 }
199}
200
201=head2 ShelfToCart
202
- -
210sub ShelfToCart {
211 my ( $itemnumber ) = @_;
212
213 unless ( $itemnumber ) {
214 croak "FAILED ShelfToCart() - no itemnumber supplied";
215 }
216
217 my $item = GetItem($itemnumber);
218 $item->{'location'} = 'CART';
219 ModItem($item, undef, $itemnumber);
220}
221
222=head2 AddItemFromMarc
223
- -
232sub AddItemFromMarc {
233 my ( $source_item_marc, $biblionumber ) = @_;
234 my $dbh = C4::Context->dbh;
235
236 # parse item hash from MARC
237 my $frameworkcode = GetFrameworkCode( $biblionumber );
238 my ($itemtag,$itemsubfield)=GetMarcFromKohaField("items.itemnumber",$frameworkcode);
239
240 my $localitemmarc=MARC::Record->new;
241 $localitemmarc->append_fields($source_item_marc->field($itemtag));
242 my $item = &TransformMarcToKoha( $dbh, $localitemmarc, $frameworkcode ,'items');
243 my $unlinked_item_subfields = _get_unlinked_item_subfields($localitemmarc, $frameworkcode);
244 return AddItem($item, $biblionumber, $dbh, $frameworkcode, $unlinked_item_subfields);
245}
246
247=head2 AddItem
248
- -
268sub AddItem {
269 my $item = shift;
270 my $biblionumber = shift;
271
272 my $dbh = @_ ? shift : C4::Context->dbh;
273 my $frameworkcode = @_ ? shift : GetFrameworkCode( $biblionumber );
274 my $unlinked_item_subfields;
275 if (@_) {
276 $unlinked_item_subfields = shift
277 };
278
279 # needs old biblionumber and biblioitemnumber
280 $item->{'biblionumber'} = $biblionumber;
281 my $sth = $dbh->prepare("SELECT biblioitemnumber FROM biblioitems WHERE biblionumber=?");
282 $sth->execute( $item->{'biblionumber'} );
283 ($item->{'biblioitemnumber'}) = $sth->fetchrow;
284
285 _set_defaults_for_add($item);
286 _set_derived_columns_for_add($item);
287 $item->{'more_subfields_xml'} = _get_unlinked_subfields_xml($unlinked_item_subfields);
288 # FIXME - checks here
289 unless ( $item->{itype} ) { # default to biblioitem.itemtype if no itype
290 my $itype_sth = $dbh->prepare("SELECT itemtype FROM biblioitems WHERE biblionumber = ?");
291 $itype_sth->execute( $item->{'biblionumber'} );
292 ( $item->{'itype'} ) = $itype_sth->fetchrow_array;
293 }
294
295 my ( $itemnumber, $error ) = _koha_new_item( $item, $item->{barcode} );
296 $item->{'itemnumber'} = $itemnumber;
297
298 ModZebra( $item->{biblionumber}, "specialUpdate", "biblioserver" );
299
300 logaction("CATALOGUING", "ADD", $itemnumber, "item") if C4::Context->preference("CataloguingLog");
301
302 return ($item->{biblionumber}, $item->{biblioitemnumber}, $itemnumber);
303}
304
305=head2 AddItemBatchFromMarc
306
- -
350sub AddItemBatchFromMarc {
351 my ($record, $biblionumber, $biblioitemnumber, $frameworkcode) = @_;
352 my $error;
353 my @itemnumbers = ();
354 my @errors = ();
355 my $dbh = C4::Context->dbh;
356
357 # We modify the record, so lets work on a clone so we don't change the
358 # original.
359 $record = $record->clone();
360 # loop through the item tags and start creating items
361 my @bad_item_fields = ();
362 my ($itemtag, $itemsubfield) = &GetMarcFromKohaField("items.itemnumber",'');
363 my $item_sequence_num = 0;
364 ITEMFIELD: foreach my $item_field ($record->field($itemtag)) {
365 $item_sequence_num++;
366 # we take the item field and stick it into a new
367 # MARC record -- this is required so far because (FIXME)
368 # TransformMarcToKoha requires a MARC::Record, not a MARC::Field
369 # and there is no TransformMarcFieldToKoha
370 my $temp_item_marc = MARC::Record->new();
371 $temp_item_marc->append_fields($item_field);
372
373 # add biblionumber and biblioitemnumber
374 my $item = TransformMarcToKoha( $dbh, $temp_item_marc, $frameworkcode, 'items' );
375 my $unlinked_item_subfields = _get_unlinked_item_subfields($temp_item_marc, $frameworkcode);
376 $item->{'more_subfields_xml'} = _get_unlinked_subfields_xml($unlinked_item_subfields);
377 $item->{'biblionumber'} = $biblionumber;
378 $item->{'biblioitemnumber'} = $biblioitemnumber;
379
380 # check for duplicate barcode
381 my %item_errors = CheckItemPreSave($item);
382 if (%item_errors) {
383 push @errors, _repack_item_errors($item_sequence_num, $item, \%item_errors);
384 push @bad_item_fields, $item_field;
385 next ITEMFIELD;
386 }
387
388 _set_defaults_for_add($item);
389 _set_derived_columns_for_add($item);
390 my ( $itemnumber, $error ) = _koha_new_item( $item, $item->{barcode} );
391 warn $error if $error;
392 push @itemnumbers, $itemnumber; # FIXME not checking error
393 $item->{'itemnumber'} = $itemnumber;
394
395 logaction("CATALOGUING", "ADD", $itemnumber, "item") if C4::Context->preference("CataloguingLog");
396
397 my $new_item_marc = _marc_from_item_hash($item, $frameworkcode, $unlinked_item_subfields);
398 $item_field->replace_with($new_item_marc->field($itemtag));
399 }
400
401 # remove any MARC item fields for rejected items
402 foreach my $item_field (@bad_item_fields) {
403 $record->delete_field($item_field);
404 }
405
406 # update the MARC biblio
407 # $biblionumber = ModBiblioMarc( $record, $biblionumber, $frameworkcode );
408
409 return (\@itemnumbers, \@errors);
410}
411
412=head2 ModItemFromMarc
413
- -
438134µsmy %default_values_for_mod_from_marc = (
439 barcode => undef,
440 booksellerid => undef,
441 ccode => undef,
442 'items.cn_source' => undef,
443 coded_location_qualifier => undef,
444 copynumber => undef,
445 damaged => 0,
446# dateaccessioned => undef,
447 enumchron => undef,
448 holdingbranch => undef,
449 homebranch => undef,
450 itemcallnumber => undef,
451 itemlost => 0,
452 itemnotes => undef,
453 itype => undef,
454 location => undef,
455 permanent_location => undef,
456 materials => undef,
457 notforloan => 0,
458 paidfor => undef,
459 price => undef,
460 replacementprice => undef,
461 replacementpricedate => undef,
462 restricted => undef,
463 stack => undef,
464 stocknumber => undef,
465 uri => undef,
466 wthdrawn => 0,
467);
468
469sub ModItemFromMarc {
470 my $item_marc = shift;
471 my $biblionumber = shift;
472 my $itemnumber = shift;
473
474 my $dbh = C4::Context->dbh;
475 my $frameworkcode = GetFrameworkCode($biblionumber);
476 my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField( "items.itemnumber", $frameworkcode );
477
478 my $localitemmarc = MARC::Record->new;
479 $localitemmarc->append_fields( $item_marc->field($itemtag) );
480 my $item = &TransformMarcToKoha( $dbh, $localitemmarc, $frameworkcode, 'items' );
481 foreach my $item_field ( keys %default_values_for_mod_from_marc ) {
482 $item->{$item_field} = $default_values_for_mod_from_marc{$item_field} unless (exists $item->{$item_field});
483 }
484 my $unlinked_item_subfields = _get_unlinked_item_subfields( $localitemmarc, $frameworkcode );
485
486 ModItem($item, $biblionumber, $itemnumber, $dbh, $frameworkcode, $unlinked_item_subfields);
487 return $item;
488}
489
490=head2 ModItem
491
- -
515sub ModItem {
516 my $item = shift;
517 my $biblionumber = shift;
518 my $itemnumber = shift;
519
520 # if $biblionumber is undefined, get it from the current item
521 unless (defined $biblionumber) {
522 $biblionumber = _get_single_item_column('biblionumber', $itemnumber);
523 }
524
525 my $dbh = @_ ? shift : C4::Context->dbh;
526 my $frameworkcode = @_ ? shift : GetFrameworkCode( $biblionumber );
527
528 my $unlinked_item_subfields;
529 if (@_) {
530 $unlinked_item_subfields = shift;
531 $item->{'more_subfields_xml'} = _get_unlinked_subfields_xml($unlinked_item_subfields);
532 };
533
534 $item->{'itemnumber'} = $itemnumber or return;
535
536 $item->{onloan} = undef if $item->{itemlost};
537
538 _set_derived_columns_for_mod($item);
539 _do_column_fixes_for_mod($item);
540 # FIXME add checks
541 # duplicate barcode
542 # attempt to change itemnumber
543 # attempt to change biblionumber (if we want
544 # an API to relink an item to a different bib,
545 # it should be a separate function)
546
547 # update items table
548 _koha_modify_item($item);
549
550 # request that bib be reindexed so that searching on current
551 # item status is possible
552 ModZebra( $biblionumber, "specialUpdate", "biblioserver" );
553
554 logaction("CATALOGUING", "MODIFY", $itemnumber, Dumper($item)) if C4::Context->preference("CataloguingLog");
555}
556
557=head2 ModItemTransfer
558
- -
566sub ModItemTransfer {
567 my ( $itemnumber, $frombranch, $tobranch ) = @_;
568
569 my $dbh = C4::Context->dbh;
570
571 # Remove the 'shelving cart' location status if it is being used.
572 CartToShelf( $itemnumber ) if ( C4::Context->preference("ReturnToShelvingCart") );
573
574 #new entry in branchtransfers....
575 my $sth = $dbh->prepare(
576 "INSERT INTO branchtransfers (itemnumber, frombranch, datesent, tobranch)
577 VALUES (?, ?, NOW(), ?)");
578 $sth->execute($itemnumber, $frombranch, $tobranch);
579
580 ModItem({ holdingbranch => $tobranch }, undef, $itemnumber);
581 ModDateLastSeen($itemnumber);
582 return;
583}
584
585=head2 ModDateLastSeen
586
- -
594sub ModDateLastSeen {
595 my ($itemnumber) = @_;
596
597 my $today = C4::Dates->new();
598 ModItem({ itemlost => 0, datelastseen => $today->output("iso") }, undef, $itemnumber);
599}
600
601=head2 DelItem
602
- -
609sub DelItem {
610 my ( $dbh, $biblionumber, $itemnumber ) = @_;
611
612 # FIXME check the item has no current issues
613
614 _koha_delete_item( $dbh, $itemnumber );
615
616 # get the MARC record
617 my $record = GetMarcBiblio($biblionumber);
618 ModZebra( $biblionumber, "specialUpdate", "biblioserver" );
619
620 # backup the record
621 my $copy2deleted = $dbh->prepare("UPDATE deleteditems SET marc=? WHERE itemnumber=?");
622 $copy2deleted->execute( $record->as_usmarc(), $itemnumber );
623 # 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).
624
625 #search item field code
626 logaction("CATALOGUING", "DELETE", $itemnumber, "item") if C4::Context->preference("CataloguingLog");
627}
628
629=head2 CheckItemPreSave
630
- -
671sub CheckItemPreSave {
672 my $item_ref = shift;
673 require C4::Branch;
674
675 my %errors = ();
676
677 # check for duplicate barcode
678 if (exists $item_ref->{'barcode'} and defined $item_ref->{'barcode'}) {
679 my $existing_itemnumber = GetItemnumberFromBarcode($item_ref->{'barcode'});
680 if ($existing_itemnumber) {
681 if (!exists $item_ref->{'itemnumber'} # new item
682 or $item_ref->{'itemnumber'} != $existing_itemnumber) { # existing item
683 $errors{'duplicate_barcode'} = $item_ref->{'barcode'};
684 }
685 }
686 }
687
688 # check for valid home branch
689 if (exists $item_ref->{'homebranch'} and defined $item_ref->{'homebranch'}) {
690 my $branch_name = C4::Branch::GetBranchName($item_ref->{'homebranch'});
691 unless (defined $branch_name) {
692 # relies on fact that branches.branchname is a non-NULL column,
693 # so GetBranchName returns undef only if branch does not exist
694 $errors{'invalid_homebranch'} = $item_ref->{'homebranch'};
695 }
696 }
697
698 # check for valid holding branch
699 if (exists $item_ref->{'holdingbranch'} and defined $item_ref->{'holdingbranch'}) {
700 my $branch_name = C4::Branch::GetBranchName($item_ref->{'holdingbranch'});
701 unless (defined $branch_name) {
702 # relies on fact that branches.branchname is a non-NULL column,
703 # so GetBranchName returns undef only if branch does not exist
704 $errors{'invalid_holdingbranch'} = $item_ref->{'holdingbranch'};
705 }
706 }
707
708 return %errors;
709
710}
711
712=head1 EXPORTED SPECIAL ACCESSOR FUNCTIONS
713
- -
725=head2 GetItemStatus
726
- -
763sub GetItemStatus {
764
765 # returns a reference to a hash of references to status...
766 my ($fwk) = @_;
767 my %itemstatus;
768 my $dbh = C4::Context->dbh;
769 my $sth;
770 $fwk = '' unless ($fwk);
771 my ( $tag, $subfield ) =
772 GetMarcFromKohaField( "items.notforloan", $fwk );
773 if ( $tag and $subfield ) {
774 my $sth =
775 $dbh->prepare(
776 "SELECT authorised_value
777 FROM marc_subfield_structure
778 WHERE tagfield=?
779 AND tagsubfield=?
780 AND frameworkcode=?
781 "
782 );
783 $sth->execute( $tag, $subfield, $fwk );
784 if ( my ($authorisedvaluecat) = $sth->fetchrow ) {
785 my $authvalsth =
786 $dbh->prepare(
787 "SELECT authorised_value,lib
788 FROM authorised_values
789 WHERE category=?
790 ORDER BY lib
791 "
792 );
793 $authvalsth->execute($authorisedvaluecat);
794 while ( my ( $authorisedvalue, $lib ) = $authvalsth->fetchrow ) {
795 $itemstatus{$authorisedvalue} = $lib;
796 }
797 return \%itemstatus;
798 exit 1;
799 }
800 else {
801
802 #No authvalue list
803 # build default
804 }
805 }
806
807 #No authvalue list
808 #build default
809 $itemstatus{"1"} = "Not For Loan";
810 return \%itemstatus;
811}
812
813=head2 GetItemLocation
814
- -
851sub GetItemLocation {
852
853 # returns a reference to a hash of references to location...
854 my ($fwk) = @_;
855 my %itemlocation;
856 my $dbh = C4::Context->dbh;
857 my $sth;
858 $fwk = '' unless ($fwk);
859 my ( $tag, $subfield ) =
860 GetMarcFromKohaField( "items.location", $fwk );
861 if ( $tag and $subfield ) {
862 my $sth =
863 $dbh->prepare(
864 "SELECT authorised_value
865 FROM marc_subfield_structure
866 WHERE tagfield=?
867 AND tagsubfield=?
868 AND frameworkcode=?"
869 );
870 $sth->execute( $tag, $subfield, $fwk );
871 if ( my ($authorisedvaluecat) = $sth->fetchrow ) {
872 my $authvalsth =
873 $dbh->prepare(
874 "SELECT authorised_value,lib
875 FROM authorised_values
876 WHERE category=?
877 ORDER BY lib"
878 );
879 $authvalsth->execute($authorisedvaluecat);
880 while ( my ( $authorisedvalue, $lib ) = $authvalsth->fetchrow ) {
881 $itemlocation{$authorisedvalue} = $lib;
882 }
883 return \%itemlocation;
884 exit 1;
885 }
886 else {
887
888 #No authvalue list
889 # build default
890 }
891 }
892
893 #No authvalue list
894 #build default
895 $itemlocation{"1"} = "Not For Loan";
896 return \%itemlocation;
897}
898
899=head2 GetLostItems
900
- -
933sub GetLostItems {
934 # Getting input args.
935 my $where = shift;
936 my $orderby = shift;
937 my $dbh = C4::Context->dbh;
938
939 my $query = "
940 SELECT title, author, lib, itemlost, authorised_value, barcode, datelastseen, price, replacementprice, homebranch,
941 itype, itemtype, holdingbranch, location, itemnotes, items.biblionumber as biblionumber
942 FROM items
943 LEFT JOIN biblio ON (items.biblionumber = biblio.biblionumber)
944 LEFT JOIN biblioitems ON (items.biblionumber = biblioitems.biblionumber)
945 LEFT JOIN authorised_values ON (items.itemlost = authorised_values.authorised_value)
946 WHERE
947 authorised_values.category = 'LOST'
948 AND itemlost IS NOT NULL
949 AND itemlost <> 0
950 ";
951 my @query_parameters;
952 foreach my $key (keys %$where) {
953 $query .= " AND $key LIKE ?";
954 push @query_parameters, "%$where->{$key}%";
955 }
956 my @ordervalues = qw/title author homebranch itype barcode price replacementprice lib datelastseen location/;
957
958 if ( defined $orderby && grep($orderby, @ordervalues)) {
959 $query .= ' ORDER BY '.$orderby;
960 }
961
962 my $sth = $dbh->prepare($query);
963 $sth->execute( @query_parameters );
964 my $items = [];
965 while ( my $row = $sth->fetchrow_hashref ){
966 push @$items, $row;
967 }
968 return $items;
969}
970
971=head2 GetItemsForInventory
972
- -
990sub GetItemsForInventory {
991 my ( $minlocation, $maxlocation,$location, $itemtype, $ignoreissued, $datelastseen, $branchcode, $branch, $offset, $size, $statushash ) = @_;
992 my $dbh = C4::Context->dbh;
993 my ( @bind_params, @where_strings );
994
995 my $query = <<'END_SQL';
996SELECT items.itemnumber, barcode, itemcallnumber, title, author, biblio.biblionumber, datelastseen
997FROM items
998 LEFT JOIN biblio ON items.biblionumber = biblio.biblionumber
999 LEFT JOIN biblioitems on items.biblionumber = biblioitems.biblionumber
1000END_SQL
1001 if ($statushash){
1002 for my $authvfield (keys %$statushash){
1003 if ( scalar @{$statushash->{$authvfield}} > 0 ){
1004 my $joinedvals = join ',', @{$statushash->{$authvfield}};
1005 push @where_strings, "$authvfield in (" . $joinedvals . ")";
1006 }
1007 }
1008 }
1009
1010 if ($minlocation) {
1011 push @where_strings, 'itemcallnumber >= ?';
1012 push @bind_params, $minlocation;
1013 }
1014
1015 if ($maxlocation) {
1016 push @where_strings, 'itemcallnumber <= ?';
1017 push @bind_params, $maxlocation;
1018 }
1019
1020 if ($datelastseen) {
1021 $datelastseen = format_date_in_iso($datelastseen);
1022 push @where_strings, '(datelastseen < ? OR datelastseen IS NULL)';
1023 push @bind_params, $datelastseen;
1024 }
1025
1026 if ( $location ) {
1027 push @where_strings, 'items.location = ?';
1028 push @bind_params, $location;
1029 }
1030
1031 if ( $branchcode ) {
1032 if($branch eq "homebranch"){
1033 push @where_strings, 'items.homebranch = ?';
1034 }else{
1035 push @where_strings, 'items.holdingbranch = ?';
1036 }
1037 push @bind_params, $branchcode;
1038 }
1039
1040 if ( $itemtype ) {
1041 push @where_strings, 'biblioitems.itemtype = ?';
1042 push @bind_params, $itemtype;
1043 }
1044
1045 if ( $ignoreissued) {
1046 $query .= "LEFT JOIN issues ON items.itemnumber = issues.itemnumber ";
1047 push @where_strings, 'issues.date_due IS NULL';
1048 }
1049
1050 if ( @where_strings ) {
1051 $query .= 'WHERE ';
1052 $query .= join ' AND ', @where_strings;
1053 }
1054 $query .= ' ORDER BY items.cn_sort, itemcallnumber, title';
1055 my $sth = $dbh->prepare($query);
1056 $sth->execute( @bind_params );
1057
1058 my @results;
1059 $size--;
1060 while ( my $row = $sth->fetchrow_hashref ) {
1061 $offset-- if ($offset);
1062 $row->{datelastseen}=format_date($row->{datelastseen});
1063 if ( ( !$offset ) && $size ) {
1064 push @results, $row;
1065 $size--;
1066 }
1067 }
1068 return \@results;
1069}
1070
1071=head2 GetItemsCount
1072
- -
1079sub GetItemsCount {
1080 my ( $biblionumber ) = @_;
1081 my $dbh = C4::Context->dbh;
1082 my $query = "SELECT count(*)
1083 FROM items
1084 WHERE biblionumber=?";
1085 my $sth = $dbh->prepare($query);
1086 $sth->execute($biblionumber);
1087 my $count = $sth->fetchrow;
1088 return ($count);
1089}
1090
1091=head2 GetItemInfosOf
1092
- -
1097sub GetItemInfosOf {
1098 my @itemnumbers = @_;
1099
1100 my $query = '
1101 SELECT *
1102 FROM items
1103 WHERE itemnumber IN (' . join( ',', @itemnumbers ) . ')
1104 ';
1105 return get_infos_of( $query, 'itemnumber' );
1106}
1107
1108=head2 GetItemsByBiblioitemnumber
1109
- -
1117sub GetItemsByBiblioitemnumber {
1118 my ( $bibitem ) = @_;
1119 my $dbh = C4::Context->dbh;
1120 my $sth = $dbh->prepare("SELECT * FROM items WHERE items.biblioitemnumber = ?") || die $dbh->errstr;
1121 # Get all items attached to a biblioitem
1122 my $i = 0;
1123 my @results;
1124 $sth->execute($bibitem) || die $sth->errstr;
1125 while ( my $data = $sth->fetchrow_hashref ) {
1126 # Foreach item, get circulation information
1127 my $sth2 = $dbh->prepare( "SELECT * FROM issues,borrowers
1128 WHERE itemnumber = ?
1129 AND issues.borrowernumber = borrowers.borrowernumber"
1130 );
1131 $sth2->execute( $data->{'itemnumber'} );
1132 if ( my $data2 = $sth2->fetchrow_hashref ) {
1133 # if item is out, set the due date and who it is out too
1134 $data->{'date_due'} = $data2->{'date_due'};
1135 $data->{'cardnumber'} = $data2->{'cardnumber'};
1136 $data->{'borrowernumber'} = $data2->{'borrowernumber'};
1137 }
1138 else {
1139 # set date_due to blank, so in the template we check itemlost, and wthdrawn
1140 $data->{'date_due'} = '';
1141 } # else
1142 # Find the last 3 people who borrowed this item.
1143 my $query2 = "SELECT * FROM old_issues, borrowers WHERE itemnumber = ?
1144 AND old_issues.borrowernumber = borrowers.borrowernumber
1145 ORDER BY returndate desc,timestamp desc LIMIT 3";
1146 $sth2 = $dbh->prepare($query2) || die $dbh->errstr;
1147 $sth2->execute( $data->{'itemnumber'} ) || die $sth2->errstr;
1148 my $i2 = 0;
1149 while ( my $data2 = $sth2->fetchrow_hashref ) {
1150 $data->{"timestamp$i2"} = $data2->{'timestamp'};
1151 $data->{"card$i2"} = $data2->{'cardnumber'};
1152 $data->{"borrower$i2"} = $data2->{'borrowernumber'};
1153 $i2++;
1154 }
1155 push(@results,$data);
1156 }
1157 return (\@results);
1158}
1159
1160=head2 GetItemsInfo
1161
- -
1202
# spent 839ms (12.0+827) within C4::Items::GetItemsInfo which was called 25 times, avg 33.5ms/call: # 25 times (12.0ms+827ms) by C4::XSLT::buildKohaItemsNamespace at line 248 of /usr/share/koha/lib/C4/XSLT.pm, avg 33.5ms/call
sub GetItemsInfo {
12032542µs my ( $biblionumber ) = @_;
120425156µs2523.9ms my $dbh = C4::Context->dbh;
# spent 23.9ms making 25 calls to C4::Context::dbh, avg 957µs/call
1205 # note biblioitems.* must be avoided to prevent large marc and marcxml fields from killing performance.
120625237µs25229µs my $query = "
# spent 229µs making 25 calls to C4::Context::preference, avg 9µs/call
1207 SELECT items.*,
1208 biblio.*,
1209 biblioitems.volume,
1210 biblioitems.number,
1211 biblioitems.itemtype,
1212 biblioitems.isbn,
1213 biblioitems.issn,
1214 biblioitems.publicationyear,
1215 biblioitems.publishercode,
1216 biblioitems.volumedate,
1217 biblioitems.volumedesc,
1218 biblioitems.lccn,
1219 biblioitems.url,
1220 items.notforloan as itemnotforloan,
1221 itemtypes.description,
1222 itemtypes.notforloan as notforloan_per_itemtype,
1223 holding.branchurl,
1224 holding.branchname,
1225 holding.opac_info as branch_opac_info
1226 FROM items
1227 LEFT JOIN branches AS holding ON items.holdingbranch = holding.branchcode
1228 LEFT JOIN branches AS home ON items.homebranch=home.branchcode
1229 LEFT JOIN biblio ON biblio.biblionumber = items.biblionumber
1230 LEFT JOIN biblioitems ON biblioitems.biblioitemnumber = items.biblioitemnumber
1231 LEFT JOIN itemtypes ON itemtypes.itemtype = "
1232 . (C4::Context->preference('item-level_itypes') ? 'items.itype' : 'biblioitems.itemtype');
12332521µs $query .= " WHERE items.biblionumber = ? ORDER BY home.branchname, items.enumchron, LPAD( items.copynumber, 8, '0' ), items.dateaccessioned DESC" ;
123425437µs504.62ms my $sth = $dbh->prepare($query);
# spent 2.48ms making 25 calls to DBI::db::prepare, avg 99µs/call # spent 2.14ms making 25 calls to DBD::mysql::db::prepare, avg 86µs/call
12352584.9ms2584.5ms $sth->execute($biblionumber);
# spent 84.5ms making 25 calls to DBI::st::execute, avg 3.38ms/call
12362540µs my $i = 0;
12372514µs my @results;
12382510µs my $serial;
1239
124025614µs506.54ms my $isth = $dbh->prepare(
# spent 3.49ms making 25 calls to DBI::db::prepare, avg 139µs/call # spent 3.06ms making 25 calls to DBD::mysql::db::prepare, avg 122µs/call
1241 "SELECT issues.*,borrowers.cardnumber,borrowers.surname,borrowers.firstname,borrowers.branchcode as bcode
1242 FROM issues LEFT JOIN borrowers ON issues.borrowernumber=borrowers.borrowernumber
1243 WHERE itemnumber = ?"
1244 );
124525320µs503.50ms my $ssth = $dbh->prepare("SELECT serialseq,publisheddate from serialitems left join serial on serialitems.serialid=serial.serialid where serialitems.itemnumber=? ");
# spent 1.87ms making 25 calls to DBI::db::prepare, avg 75µs/call # spent 1.62ms making 25 calls to DBD::mysql::db::prepare, avg 65µs/call
1246256.91ms45910.4ms while ( my $data = $sth->fetchrow_hashref ) {
# spent 6.37ms making 57 calls to DBI::st::fetchrow_hashref, avg 112µs/call # spent 1.33ms making 192 calls to DBI::common::DESTROY, avg 7µs/call # spent 1.25ms making 57 calls to DBI::common::FETCH, avg 22µs/call # spent 1.07ms making 57 calls to DBI::st::fetch, avg 19µs/call # spent 335µs making 96 calls to DBD::_mem::common::DESTROY, avg 3µs/call
12473241µs my $datedue = '';
12483244.9ms3244.4ms $isth->execute( $data->{'itemnumber'} );
# spent 44.4ms making 32 calls to DBI::st::execute, avg 1.39ms/call
1249321.76ms962.30ms if ( my $idata = $isth->fetchrow_hashref ) {
# spent 1.53ms making 32 calls to DBI::st::fetchrow_hashref, avg 48µs/call # spent 509µs making 32 calls to DBI::common::FETCH, avg 16µs/call # spent 255µs making 32 calls to DBI::st::fetch, avg 8µs/call
1250 $data->{borrowernumber} = $idata->{borrowernumber};
1251 $data->{cardnumber} = $idata->{cardnumber};
1252 $data->{surname} = $idata->{surname};
1253 $data->{firstname} = $idata->{firstname};
1254 $data->{lastreneweddate} = $idata->{lastreneweddate};
1255 $datedue = $idata->{'date_due'};
1256 if (C4::Context->preference("IndependantBranches")){
1257 my $userenv = C4::Context->userenv;
1258 if ( ($userenv) && ( $userenv->{flags} % 2 != 1 ) ) {
1259 $data->{'NOTSAMEBRANCH'} = 1 if ($idata->{'bcode'} ne $userenv->{branch});
1260 }
1261 }
1262 }
126332127µs if ( $data->{'serial'}) {
1264 $ssth->execute($data->{'itemnumber'}) ;
1265 ($data->{'serialseq'} , $data->{'publisheddate'}) = $ssth->fetchrow_array();
1266 $serial = 1;
1267 }
1268 #get branch information.....
126932427µs644.89ms my $bsth = $dbh->prepare(
# spent 2.60ms making 32 calls to DBI::db::prepare, avg 81µs/call # spent 2.29ms making 32 calls to DBD::mysql::db::prepare, avg 72µs/call
1270 "SELECT * FROM branches WHERE branchcode = ?
1271 "
1272 );
12733235.9ms3235.5ms $bsth->execute( $data->{'holdingbranch'} );
# spent 35.5ms making 32 calls to DBI::st::execute, avg 1.11ms/call
1274322.74ms963.33ms if ( my $bdata = $bsth->fetchrow_hashref ) {
# spent 2.33ms making 32 calls to DBI::st::fetchrow_hashref, avg 73µs/call # spent 576µs making 32 calls to DBI::common::FETCH, avg 18µs/call # spent 428µs making 32 calls to DBI::st::fetch, avg 13µs/call
1275 $data->{'branchname'} = $bdata->{'branchname'};
1276 }
12773292µs $data->{'datedue'} = $datedue;
1278
1279 # get notforloan complete status if applicable
128032349µs12868.0ms if ( my $code = C4::Koha::GetAuthValCode( 'items.notforloan', $data->{frameworkcode} ) ) {
# spent 67.5ms making 32 calls to C4::Koha::GetAuthValCode, avg 2.11ms/call # spent 418µs making 64 calls to DBI::common::DESTROY, avg 7µs/call # spent 106µs making 32 calls to DBD::_mem::common::DESTROY, avg 3µs/call
128132416µs12870.2ms $data->{notforloanvalue} = C4::Koha::GetKohaAuthorisedValueLib( $code, $data->{itemnotforloan} );
# spent 69.8ms making 32 calls to C4::Koha::GetKohaAuthorisedValueLib, avg 2.18ms/call # spent 308µs making 64 calls to DBI::common::DESTROY, avg 5µs/call # spent 77µs making 32 calls to DBD::_mem::common::DESTROY, avg 2µs/call
128232227µs12871.1ms $data->{notforloanvalueopac} = C4::Koha::GetKohaAuthorisedValueLib( $code, $data->{itemnotforloan}, 1 );
# spent 70.7ms making 32 calls to C4::Koha::GetKohaAuthorisedValueLib, avg 2.21ms/call # spent 275µs making 64 calls to DBI::common::DESTROY, avg 4µs/call # spent 111µs making 32 calls to DBD::_mem::common::DESTROY, avg 3µs/call
1283 }
1284
1285 # get restricted status and description if applicable
128632248µs12868.0ms if ( my $code = C4::Koha::GetAuthValCode( 'items.restricted', $data->{frameworkcode} ) ) {
# spent 67.5ms making 32 calls to C4::Koha::GetAuthValCode, avg 2.11ms/call # spent 410µs making 64 calls to DBI::common::DESTROY, avg 6µs/call # spent 84µs making 32 calls to DBD::_mem::common::DESTROY, avg 3µs/call
128732435µs12869.9ms $data->{restrictedopac} = C4::Koha::GetKohaAuthorisedValueLib( $code, $data->{restricted}, 1 );
# spent 69.5ms making 32 calls to C4::Koha::GetKohaAuthorisedValueLib, avg 2.17ms/call # spent 279µs making 64 calls to DBI::common::DESTROY, avg 4µs/call # spent 68µs making 32 calls to DBD::_mem::common::DESTROY, avg 2µs/call
128832238µs12871.5ms $data->{restricted} = C4::Koha::GetKohaAuthorisedValueLib( $code, $data->{restricted} );
# spent 71.2ms making 32 calls to C4::Koha::GetKohaAuthorisedValueLib, avg 2.22ms/call # spent 278µs making 64 calls to DBI::common::DESTROY, avg 4µs/call # spent 67µs making 32 calls to DBD::_mem::common::DESTROY, avg 2µs/call
1289 }
1290
1291 # my stack procedures
129232323µs188101ms if ( my $code = C4::Koha::GetAuthValCode( 'items.stack', $data->{frameworkcode} ) ) {
# spent 67.8ms making 32 calls to C4::Koha::GetAuthValCode, avg 2.12ms/call # spent 32.7ms making 15 calls to C4::Koha::GetKohaAuthorisedValueLib, avg 2.18ms/call # spent 550µs making 94 calls to DBI::common::DESTROY, avg 6µs/call # spent 125µs making 47 calls to DBD::_mem::common::DESTROY, avg 3µs/call
1293 $data->{stack} = C4::Koha::GetKohaAuthorisedValueLib( $code, $data->{stack} );
1294 }
1295
1296 # Get restricted value
1297
129832411µs644.93ms my $restrictedstatus = $dbh->prepare(
# spent 2.61ms making 32 calls to DBI::db::prepare, avg 81µs/call # spent 2.32ms making 32 calls to DBD::mysql::db::prepare, avg 73µs/call
1299 "SELECT lib
1300 FROM authorised_values
1301 WHERE category=?
1302 AND authorised_value=?
1303 "
1304 );
13053232.9ms3232.5ms $restrictedstatus->execute( 'RESTRICTED', $data->{'restricted'});
# spent 32.5ms making 32 calls to DBI::st::execute, avg 1.02ms/call
130632719µs32436µs my ($lib) = $restrictedstatus->fetchrow;
# spent 436µs making 32 calls to DBI::st::fetchrow, avg 14µs/call
130732117µs $data->{restrictedvalue} = $lib;
1308 # Find the last 3 people who borrowed this item.
130932454µs644.42ms my $sth2 = $dbh->prepare("SELECT * FROM old_issues,borrowers
# spent 2.39ms making 32 calls to DBI::db::prepare, avg 75µs/call # spent 2.04ms making 32 calls to DBD::mysql::db::prepare, avg 64µs/call
1310 WHERE itemnumber = ?
1311 AND old_issues.borrowernumber = borrowers.borrowernumber
1312 ORDER BY returndate DESC
1313 LIMIT 3");
13143257.0ms3256.5ms $sth2->execute($data->{'itemnumber'});
# spent 56.5ms making 32 calls to DBI::st::execute, avg 1.77ms/call
13153243µs my $ii = 0;
1316323.19ms964.60ms while (my $data2 = $sth2->fetchrow_hashref()) {
# spent 2.86ms making 32 calls to DBI::st::fetchrow_hashref, avg 90µs/call # spent 1.38ms making 32 calls to DBI::common::FETCH, avg 43µs/call # spent 358µs making 32 calls to DBI::st::fetch, avg 11µs/call
1317 $data->{"timestamp$ii"} = $data2->{'timestamp'} if $data2->{'timestamp'};
1318 $data->{"card$ii"} = $data2->{'cardnumber'} if $data2->{'cardnumber'};
1319 $data->{"borrower$ii"} = $data2->{'borrowernumber'} if $data2->{'borrowernumber'};
1320 $ii++;
1321 }
1322
13233277µs $results[$i] = $data;
1324323.85ms $i++;
1325 }
13262526µs if($serial) {
1327 return( sort { ($b->{'publisheddate'} || $b->{'enumchron'}) cmp ($a->{'publisheddate'} || $a->{'enumchron'}) } @results );
1328 } else {
1329253.23ms return (@results);
1330 }
1331}
1332
1333=head2 GetItemsLocationInfo
1334
- -
1376sub GetItemsLocationInfo {
1377 my $biblionumber = shift;
1378 my @results;
1379
1380 my $dbh = C4::Context->dbh;
1381 my $query = "SELECT a.branchname as homebranch, b.branchname as holdingbranch,
1382 location, itemcallnumber, cn_sort
1383 FROM items, branches as a, branches as b
1384 WHERE homebranch = a.branchcode AND holdingbranch = b.branchcode
1385 AND biblionumber = ?
1386 ORDER BY cn_sort ASC";
1387 my $sth = $dbh->prepare($query);
1388 $sth->execute($biblionumber);
1389
1390 while ( my $data = $sth->fetchrow_hashref ) {
1391 $data->{location_intranet} = GetKohaAuthorisedValueLib('LOC', $data->{location});
1392 $data->{location_opac}= GetKohaAuthorisedValueLib('LOC', $data->{location}, 1);
1393 push @results, $data;
1394 }
1395 return @results;
1396}
1397
1398=head2 GetHostItemsInfo
1399
- -
1405sub GetHostItemsInfo {
1406 my ($record) = @_;
1407 my @returnitemsInfo;
1408
1409 if (C4::Context->preference('marcflavour') eq 'MARC21' ||
1410 C4::Context->preference('marcflavour') eq 'NORMARC'){
1411 foreach my $hostfield ( $record->field('773') ) {
1412 my $hostbiblionumber = $hostfield->subfield("0");
1413 my $linkeditemnumber = $hostfield->subfield("9");
1414 my @hostitemInfos = GetItemsInfo($hostbiblionumber);
1415 foreach my $hostitemInfo (@hostitemInfos){
1416 if ($hostitemInfo->{itemnumber} eq $linkeditemnumber){
1417 push (@returnitemsInfo,$hostitemInfo);
1418 last;
1419 }
1420 }
1421 }
1422 } elsif ( C4::Context->preference('marcflavour') eq 'UNIMARC'){
1423 foreach my $hostfield ( $record->field('461') ) {
1424 my $hostbiblionumber = $hostfield->subfield("0");
1425 my $linkeditemnumber = $hostfield->subfield("9");
1426 my @hostitemInfos = GetItemsInfo($hostbiblionumber);
1427 foreach my $hostitemInfo (@hostitemInfos){
1428 if ($hostitemInfo->{itemnumber} eq $linkeditemnumber){
1429 push (@returnitemsInfo,$hostitemInfo);
1430 last;
1431 }
1432 }
1433 }
1434 }
1435 return @returnitemsInfo;
1436}
1437
1438
1439=head2 GetLastAcquisitions
1440
- -
1446sub GetLastAcquisitions {
1447 my ($data,$max) = @_;
1448
1449 my $itemtype = C4::Context->preference('item-level_itypes') ? 'itype' : 'itemtype';
1450
1451 my $number_of_branches = @{$data->{branches}};
1452 my $number_of_itemtypes = @{$data->{itemtypes}};
1453
1454
1455 my @where = ('WHERE 1 ');
1456 $number_of_branches and push @where
1457 , 'AND holdingbranch IN ('
1458 , join(',', ('?') x $number_of_branches )
1459 , ')'
1460 ;
1461
1462 $number_of_itemtypes and push @where
1463 , "AND $itemtype IN ("
1464 , join(',', ('?') x $number_of_itemtypes )
1465 , ')'
1466 ;
1467
1468 my $query = "SELECT biblio.biblionumber as biblionumber, title, dateaccessioned
1469 FROM items RIGHT JOIN biblio ON (items.biblionumber=biblio.biblionumber)
1470 RIGHT JOIN biblioitems ON (items.biblioitemnumber=biblioitems.biblioitemnumber)
1471 @where
1472 GROUP BY biblio.biblionumber
1473 ORDER BY dateaccessioned DESC LIMIT $max";
1474
1475 my $dbh = C4::Context->dbh;
1476 my $sth = $dbh->prepare($query);
1477
1478 $sth->execute((@{$data->{branches}}, @{$data->{itemtypes}}));
1479
1480 my @results;
1481 while( my $row = $sth->fetchrow_hashref){
1482 push @results, {date => $row->{dateaccessioned}
1483 , biblionumber => $row->{biblionumber}
1484 , title => $row->{title}};
1485 }
1486
1487 return @results;
1488}
1489
1490=head2 GetItemnumbersForBiblio
1491
- -
1498sub GetItemnumbersForBiblio {
1499 my $biblionumber = shift;
1500 my @items;
1501 my $dbh = C4::Context->dbh;
1502 my $sth = $dbh->prepare("SELECT itemnumber FROM items WHERE biblionumber = ?");
1503 $sth->execute($biblionumber);
1504 while (my $result = $sth->fetchrow_hashref) {
1505 push @items, $result->{'itemnumber'};
1506 }
1507 return \@items;
1508}
1509
1510=head2 get_itemnumbers_of
1511
- -
1522sub get_itemnumbers_of {
1523 my @biblionumbers = @_;
1524
1525 my $dbh = C4::Context->dbh;
1526
1527 my $query = '
1528 SELECT itemnumber,
1529 biblionumber
1530 FROM items
1531 WHERE biblionumber IN (?' . ( ',?' x scalar @biblionumbers - 1 ) . ')
1532 ';
1533 my $sth = $dbh->prepare($query);
1534 $sth->execute(@biblionumbers);
1535
1536 my %itemnumbers_of;
1537
1538 while ( my ( $itemnumber, $biblionumber ) = $sth->fetchrow_array ) {
1539 push @{ $itemnumbers_of{$biblionumber} }, $itemnumber;
1540 }
1541
1542 return \%itemnumbers_of;
1543}
1544
1545=head2 get_hostitemnumbers_of
1546
- -
1557sub get_hostitemnumbers_of {
1558 my ($biblionumber) = @_;
1559 my $marcrecord = GetMarcBiblio($biblionumber);
1560 my (@returnhostitemnumbers,$tag, $biblio_s, $item_s);
1561
1562 my $marcflavor = C4::Context->preference('marcflavour');
1563 if ($marcflavor eq 'MARC21' || $marcflavor eq 'NORMARC') {
1564 $tag='773';
1565 $biblio_s='0';
1566 $item_s='9';
1567 } elsif ($marcflavor eq 'UNIMARC') {
1568 $tag='461';
1569 $biblio_s='0';
1570 $item_s='9';
1571 }
1572
1573 foreach my $hostfield ( $marcrecord->field($tag) ) {
1574 my $hostbiblionumber = $hostfield->subfield($biblio_s);
1575 my $linkeditemnumber = $hostfield->subfield($item_s);
1576 my @itemnumbers;
1577 if (my $itemnumbers = get_itemnumbers_of($hostbiblionumber)->{$hostbiblionumber})
1578 {
1579 @itemnumbers = @$itemnumbers;
1580 }
1581 foreach my $itemnumber (@itemnumbers){
1582 if ($itemnumber eq $linkeditemnumber){
1583 push (@returnhostitemnumbers,$itemnumber);
1584 last;
1585 }
1586 }
1587 }
1588 return @returnhostitemnumbers;
1589}
1590
1591
1592=head2 GetItemnumberFromBarcode
1593
- -
1598sub GetItemnumberFromBarcode {
1599 my ($barcode) = @_;
1600 my $dbh = C4::Context->dbh;
1601
1602 my $rq =
1603 $dbh->prepare("SELECT itemnumber FROM items WHERE items.barcode=?");
1604 $rq->execute($barcode);
1605 my ($result) = $rq->fetchrow;
1606 return ($result);
1607}
1608
1609=head2 GetBarcodeFromItemnumber
1610
- -
1615sub GetBarcodeFromItemnumber {
1616 my ($itemnumber) = @_;
1617 my $dbh = C4::Context->dbh;
1618
1619 my $rq =
1620 $dbh->prepare("SELECT barcode FROM items WHERE items.itemnumber=?");
1621 $rq->execute($itemnumber);
1622 my ($result) = $rq->fetchrow;
1623 return ($result);
1624}
1625
1626=head2 GetHiddenItemnumbers
1627
- -
1636
# spent 125ms (1.75+123) within C4::Items::GetHiddenItemnumbers which was called 32 times, avg 3.90ms/call: # 32 times (1.75ms+123ms) by C4::Search::searchResults at line 1851 of /usr/share/koha/lib/C4/Search.pm, avg 3.90ms/call
sub GetHiddenItemnumbers {
16373262µs my (@items) = @_;
16383215µs my @resultitems;
1639
164032195µs322.79ms my $yaml = C4::Context->preference('OpacHiddenItems');
# spent 2.79ms making 32 calls to C4::Context::preference, avg 87µs/call
16413235µs $yaml = "$yaml\n\n"; # YAML is anal on ending \n. Surplus does not hurt
16423212µs my $hidingrules;
164332130µs eval {
164432226µs3287.5ms $hidingrules = YAML::Load($yaml);
# spent 87.5ms making 32 calls to YAML::Load, avg 2.73ms/call
1645 };
16463218µs if ($@) {
1647 warn "Unable to parse OpacHiddenItems syspref : $@";
1648 return ();
1649 }
165032347µs3232.8ms my $dbh = C4::Context->dbh;
# spent 32.8ms making 32 calls to C4::Context::dbh, avg 1.03ms/call
1651
1652 # For each item
16533297µs foreach my $item (@items) {
1654
1655 # We check each rule
165632300µs foreach my $field (keys %$hidingrules) {
1657 my $val;
1658 if (exists $item->{$field}) {
1659 $val = $item->{$field};
1660 }
1661 else {
1662 my $query = "SELECT $field from items where itemnumber = ?";
1663 $val = $dbh->selectrow_array($query, undef, $item->{'itemnumber'});
1664 }
1665 $val = '' unless defined $val;
1666
1667 # If the results matches the values in the yaml file
1668 if (any { $val eq $_ } @{$hidingrules->{$field}}) {
1669
1670 # We add the itemnumber to the list
1671 push @resultitems, $item->{'itemnumber'};
1672
1673 # If at least one rule matched for an item, no need to test the others
1674 last;
1675 }
1676 }
1677 }
167832260µs return @resultitems;
1679}
1680
1681=head3 get_item_authorised_values
1682
- -
1707sub get_item_authorised_values {
1708 my $itemnumber = shift;
1709
1710 # assume that these entries in the authorised_value table are item level.
1711 my $query = q(SELECT distinct authorised_value, kohafield
1712 FROM marc_subfield_structure
1713 WHERE kohafield like 'item%'
1714 AND authorised_value != '' );
1715
1716 my $itemlevel_authorised_values = C4::Context->dbh->selectall_hashref( $query, 'authorised_value' );
1717 my $iteminfo = GetItem( $itemnumber );
1718 # warn( Data::Dumper->Dump( [ $itemlevel_authorised_values ], [ 'itemlevel_authorised_values' ] ) );
1719 my $return;
1720 foreach my $this_authorised_value ( keys %$itemlevel_authorised_values ) {
1721 my $field = $itemlevel_authorised_values->{ $this_authorised_value }->{'kohafield'};
1722 $field =~ s/^items\.//;
1723 if ( exists $iteminfo->{ $field } ) {
1724 $return->{ $this_authorised_value } = $iteminfo->{ $field };
1725 }
1726 }
1727 # warn( Data::Dumper->Dump( [ $return ], [ 'return' ] ) );
1728 return $return;
1729}
1730
1731=head3 get_authorised_value_images
1732
- -
1754sub get_authorised_value_images {
1755 my $authorised_values = shift;
1756
1757 my @imagelist;
1758
1759 my $authorised_value_list = GetAuthorisedValues();
1760 # warn ( Data::Dumper->Dump( [ $authorised_value_list ], [ 'authorised_value_list' ] ) );
1761 foreach my $this_authorised_value ( @$authorised_value_list ) {
1762 if ( exists $authorised_values->{ $this_authorised_value->{'category'} }
1763 && $authorised_values->{ $this_authorised_value->{'category'} } eq $this_authorised_value->{'authorised_value'} ) {
1764 # warn ( Data::Dumper->Dump( [ $this_authorised_value ], [ 'this_authorised_value' ] ) );
1765 if ( defined $this_authorised_value->{'imageurl'} ) {
1766 push @imagelist, { imageurl => C4::Koha::getitemtypeimagelocation( 'intranet', $this_authorised_value->{'imageurl'} ),
1767 label => $this_authorised_value->{'lib'},
1768 category => $this_authorised_value->{'category'},
1769 value => $this_authorised_value->{'authorised_value'}, };
1770 }
1771 }
1772 }
1773
1774 # warn ( Data::Dumper->Dump( [ \@imagelist ], [ 'imagelist' ] ) );
1775 return \@imagelist;
1776
1777}
1778
1779=head1 LIMITED USE FUNCTIONS
1780
- -
1789=head2 GetMarcItem
1790
- -
1800sub GetMarcItem {
1801 my ( $biblionumber, $itemnumber ) = @_;
1802
1803 # GetMarcItem has been revised so that it does the following:
1804 # 1. Gets the item information from the items table.
1805 # 2. Converts it to a MARC field for storage in the bib record.
1806 #
1807 # The previous behavior was:
1808 # 1. Get the bib record.
1809 # 2. Return the MARC tag corresponding to the item record.
1810 #
1811 # The difference is that one treats the items row as authoritative,
1812 # while the other treats the MARC representation as authoritative
1813 # under certain circumstances.
1814
1815 my $itemrecord = GetItem($itemnumber);
1816
1817 # Tack on 'items.' prefix to column names so that TransformKohaToMarc will work.
1818 # Also, don't emit a subfield if the underlying field is blank.
1819
1820
1821 return Item2Marc($itemrecord,$biblionumber);
1822
1823}
1824sub Item2Marc {
1825 my ($itemrecord,$biblionumber)=@_;
1826 my $mungeditem = {
1827 map {
1828 defined($itemrecord->{$_}) && $itemrecord->{$_} ne '' ? ("items.$_" => $itemrecord->{$_}) : ()
1829 } keys %{ $itemrecord }
1830 };
1831 my $itemmarc = TransformKohaToMarc($mungeditem);
1832 my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField("items.itemnumber",GetFrameworkCode($biblionumber)||'');
1833
1834 my $unlinked_item_subfields = _parse_unlinked_item_subfields_from_xml($mungeditem->{'items.more_subfields_xml'});
1835 if (defined $unlinked_item_subfields and $#$unlinked_item_subfields > -1) {
1836 foreach my $field ($itemmarc->field($itemtag)){
1837 $field->add_subfields(@$unlinked_item_subfields);
1838 }
1839 }
1840 return $itemmarc;
1841}
1842
1843=head1 PRIVATE FUNCTIONS AND VARIABLES
1844
- -
1851=head2 %derived_columns
1852
- -
186818µsmy %derived_columns = (
1869 'items.cn_sort' => {
1870 'itemcallnumber' => 1,
1871 'items.cn_source' => 1,
1872 'BUILDER' => \&_calc_items_cn_sort,
1873 }
1874);
1875
1876=head2 _set_derived_columns_for_add
1877
- -
1886sub _set_derived_columns_for_add {
1887 my $item = shift;
1888
1889 foreach my $column (keys %derived_columns) {
1890 my $builder = $derived_columns{$column}->{'BUILDER'};
1891 my $source_values = {};
1892 foreach my $source_column (keys %{ $derived_columns{$column} }) {
1893 next if $source_column eq 'BUILDER';
1894 $source_values->{$source_column} = $item->{$source_column};
1895 }
1896 $builder->($item, $source_values);
1897 }
1898}
1899
1900=head2 _set_derived_columns_for_mod
1901
- -
1921sub _set_derived_columns_for_mod {
1922 my $item = shift;
1923
1924 foreach my $column (keys %derived_columns) {
1925 my $builder = $derived_columns{$column}->{'BUILDER'};
1926 my $source_values = {};
1927 my %missing_sources = ();
1928 my $must_recalc = 0;
1929 foreach my $source_column (keys %{ $derived_columns{$column} }) {
1930 next if $source_column eq 'BUILDER';
1931 if (exists $item->{$source_column}) {
1932 $must_recalc = 1;
1933 $source_values->{$source_column} = $item->{$source_column};
1934 } else {
1935 $missing_sources{$source_column} = 1;
1936 }
1937 }
1938 if ($must_recalc) {
1939 foreach my $source_column (keys %missing_sources) {
1940 $source_values->{$source_column} = _get_single_item_column($source_column, $item->{'itemnumber'});
1941 }
1942 $builder->($item, $source_values);
1943 }
1944 }
1945}
1946
1947=head2 _do_column_fixes_for_mod
1948
- -
1960sub _do_column_fixes_for_mod {
1961 my $item = shift;
1962
1963 if (exists $item->{'notforloan'} and
1964 (not defined $item->{'notforloan'} or $item->{'notforloan'} eq '')) {
1965 $item->{'notforloan'} = 0;
1966 }
1967 if (exists $item->{'damaged'} and
1968 (not defined $item->{'damaged'} or $item->{'damaged'} eq '')) {
1969 $item->{'damaged'} = 0;
1970 }
1971 if (exists $item->{'itemlost'} and
1972 (not defined $item->{'itemlost'} or $item->{'itemlost'} eq '')) {
1973 $item->{'itemlost'} = 0;
1974 }
1975 if (exists $item->{'wthdrawn'} and
1976 (not defined $item->{'wthdrawn'} or $item->{'wthdrawn'} eq '')) {
1977 $item->{'wthdrawn'} = 0;
1978 }
1979 if (exists $item->{'location'} && !exists $item->{'permanent_location'}) {
1980 $item->{'permanent_location'} = $item->{'location'};
1981 }
1982 if (exists $item->{'timestamp'}) {
1983 delete $item->{'timestamp'};
1984 }
1985}
1986
1987=head2 _get_single_item_column
1988
- -
1996sub _get_single_item_column {
1997 my $column = shift;
1998 my $itemnumber = shift;
1999
2000 my $dbh = C4::Context->dbh;
2001 my $sth = $dbh->prepare("SELECT $column FROM items WHERE itemnumber = ?");
2002 $sth->execute($itemnumber);
2003 my ($value) = $sth->fetchrow();
2004 return $value;
2005}
2006
2007=head2 _calc_items_cn_sort
2008
- -
2015sub _calc_items_cn_sort {
2016 my $item = shift;
2017 my $source_values = shift;
2018
2019 $item->{'items.cn_sort'} = GetClassSort($source_values->{'items.cn_source'}, $source_values->{'itemcallnumber'}, "");
2020}
2021
2022=head2 _set_defaults_for_add
2023
- -
2057sub _set_defaults_for_add {
2058 my $item = shift;
2059 $item->{dateaccessioned} ||= C4::Dates->new->output('iso');
2060 $item->{$_} ||= 0 for (qw( notforloan damaged itemlost wthdrawn));
2061}
2062
2063=head2 _koha_new_item
2064
- -
2071sub _koha_new_item {
2072 my ( $item, $barcode ) = @_;
2073 my $dbh=C4::Context->dbh;
2074 my $error;
2075 my $query =
2076 "INSERT INTO items SET
2077 biblionumber = ?,
2078 biblioitemnumber = ?,
2079 barcode = ?,
2080 dateaccessioned = ?,
2081 booksellerid = ?,
2082 homebranch = ?,
2083 price = ?,
2084 replacementprice = ?,
2085 replacementpricedate = ?,
2086 datelastborrowed = ?,
2087 datelastseen = ?,
2088 stack = ?,
2089 notforloan = ?,
2090 damaged = ?,
2091 itemlost = ?,
2092 wthdrawn = ?,
2093 itemcallnumber = ?,
2094 coded_location_qualifier = ?,
2095 restricted = ?,
2096 itemnotes = ?,
2097 holdingbranch = ?,
2098 paidfor = ?,
2099 location = ?,
2100 permanent_location = ?,
2101 onloan = ?,
2102 issues = ?,
2103 renewals = ?,
2104 reserves = ?,
2105 cn_source = ?,
2106 cn_sort = ?,
2107 ccode = ?,
2108 itype = ?,
2109 materials = ?,
2110 uri = ?,
2111 enumchron = ?,
2112 more_subfields_xml = ?,
2113 copynumber = ?,
2114 stocknumber = ?
2115 ";
2116 my $sth = $dbh->prepare($query);
2117 my $today = C4::Dates->today('iso');
2118 $sth->execute(
2119 $item->{'biblionumber'},
2120 $item->{'biblioitemnumber'},
2121 $barcode,
2122 $item->{'dateaccessioned'},
2123 $item->{'booksellerid'},
2124 $item->{'homebranch'},
2125 $item->{'price'},
2126 $item->{'replacementprice'},
2127 $item->{'replacementpricedate'} || $today,
2128 $item->{datelastborrowed},
2129 $item->{datelastseen} || $today,
2130 $item->{stack},
2131 $item->{'notforloan'},
2132 $item->{'damaged'},
2133 $item->{'itemlost'},
2134 $item->{'wthdrawn'},
2135 $item->{'itemcallnumber'},
2136 $item->{'coded_location_qualifier'},
2137 $item->{'restricted'},
2138 $item->{'itemnotes'},
2139 $item->{'holdingbranch'},
2140 $item->{'paidfor'},
2141 $item->{'location'},
2142 $item->{'permanent_location'},
2143 $item->{'onloan'},
2144 $item->{'issues'},
2145 $item->{'renewals'},
2146 $item->{'reserves'},
2147 $item->{'items.cn_source'},
2148 $item->{'items.cn_sort'},
2149 $item->{'ccode'},
2150 $item->{'itype'},
2151 $item->{'materials'},
2152 $item->{'uri'},
2153 $item->{'enumchron'},
2154 $item->{'more_subfields_xml'},
2155 $item->{'copynumber'},
2156 $item->{'stocknumber'},
2157 );
2158
2159 my $itemnumber;
2160 if ( defined $sth->errstr ) {
2161 $error.="ERROR in _koha_new_item $query".$sth->errstr;
2162 }
2163 else {
2164 $itemnumber = $dbh->{'mysql_insertid'};
2165 }
2166
2167 return ( $itemnumber, $error );
2168}
2169
2170=head2 MoveItemFromBiblio
2171
- -
2180sub MoveItemFromBiblio {
2181 my ($itemnumber, $frombiblio, $tobiblio) = @_;
2182 my $dbh = C4::Context->dbh;
2183 my $sth = $dbh->prepare("SELECT biblioitemnumber FROM biblioitems WHERE biblionumber = ?");
2184 $sth->execute( $tobiblio );
2185 my ( $tobiblioitem ) = $sth->fetchrow();
2186 $sth = $dbh->prepare("UPDATE items SET biblioitemnumber = ?, biblionumber = ? WHERE itemnumber = ? AND biblionumber = ?");
2187 my $return = $sth->execute($tobiblioitem, $tobiblio, $itemnumber, $frombiblio);
2188 if ($return == 1) {
2189 ModZebra( $tobiblio, "specialUpdate", "biblioserver" );
2190 ModZebra( $frombiblio, "specialUpdate", "biblioserver" );
2191 # Checking if the item we want to move is in an order
2192 require C4::Acquisition;
2193 my $order = C4::Acquisition::GetOrderFromItemnumber($itemnumber);
2194 if ($order) {
2195 # Replacing the biblionumber within the order if necessary
2196 $order->{'biblionumber'} = $tobiblio;
2197 C4::Acquisition::ModOrder($order);
2198 }
2199 return $tobiblio;
2200 }
2201 return;
2202}
2203
2204=head2 DelItemCheck
2205
- -
2212sub DelItemCheck {
2213 my ( $dbh, $biblionumber, $itemnumber ) = @_;
2214 my $error;
2215
2216 my $countanalytics=GetAnalyticsCount($itemnumber);
2217
2218
2219 # check that there is no issue on this item before deletion.
2220 my $sth=$dbh->prepare("select * from issues i where i.itemnumber=?");
2221 $sth->execute($itemnumber);
2222
2223 my $item = GetItem($itemnumber);
2224 my $onloan=$sth->fetchrow;
2225
2226 if ($onloan){
2227 $error = "book_on_loan"
2228 }
2229 elsif ( !( C4::Context->userenv->{flags} & 1 )
2230 and C4::Context->preference("IndependantBranches")
2231 and ( C4::Context->userenv->{branch} ne $item->{'homebranch'} ) )
2232 {
2233 $error = "not_same_branch";
2234 }
2235 else{
2236 # check it doesnt have a waiting reserve
2237 $sth=$dbh->prepare("SELECT * FROM reserves WHERE (found = 'W' or found = 'T') AND itemnumber = ?");
2238 $sth->execute($itemnumber);
2239 my $reserve=$sth->fetchrow;
2240 if ($reserve){
2241 $error = "book_reserved";
2242 } elsif ($countanalytics > 0){
2243 $error = "linked_analytics";
2244 } else {
2245 DelItem($dbh, $biblionumber, $itemnumber);
2246 return 1;
2247 }
2248 }
2249 return $error;
2250}
2251
2252=head2 _koha_modify_item
2253
- -
2261sub _koha_modify_item {
2262 my ( $item ) = @_;
2263 my $dbh=C4::Context->dbh;
2264 my $error;
2265
2266 my $query = "UPDATE items SET ";
2267 my @bind;
2268 for my $key ( keys %$item ) {
2269 next if ( $key eq 'itemnumber' );
2270 $query.="$key=?,";
2271 push @bind, $item->{$key};
2272 }
2273 $query =~ s/,$//;
2274 $query .= " WHERE itemnumber=?";
2275 push @bind, $item->{'itemnumber'};
2276 my $sth = C4::Context->dbh->prepare($query);
2277 $sth->execute(@bind);
2278 if ( C4::Context->dbh->errstr ) {
2279 $error.="ERROR in _koha_modify_item $query".$dbh->errstr;
2280 warn $error;
2281 }
2282 return ($item->{'itemnumber'},$error);
2283}
2284
2285=head2 _koha_delete_item
2286
- -
2293sub _koha_delete_item {
2294 my ( $dbh, $itemnum ) = @_;
2295
2296 # save the deleted item to deleteditems table
2297 my $sth = $dbh->prepare("SELECT * FROM items WHERE itemnumber=?");
2298 $sth->execute($itemnum);
2299 my $data = $sth->fetchrow_hashref();
2300 my $query = "INSERT INTO deleteditems SET ";
2301 my @bind = ();
2302 foreach my $key ( keys %$data ) {
2303 $query .= "$key = ?,";
2304 push( @bind, $data->{$key} );
2305 }
2306 $query =~ s/\,$//;
2307 $sth = $dbh->prepare($query);
2308 $sth->execute(@bind);
2309
2310 # delete from items table
2311 $sth = $dbh->prepare("DELETE FROM items WHERE itemnumber=?");
2312 $sth->execute($itemnum);
2313 return;
2314}
2315
2316=head2 _marc_from_item_hash
2317
- -
2331sub _marc_from_item_hash {
2332 my $item = shift;
2333 my $frameworkcode = shift;
2334 my $unlinked_item_subfields;
2335 if (@_) {
2336 $unlinked_item_subfields = shift;
2337 }
2338
2339 # Tack on 'items.' prefix to column names so lookup from MARC frameworks will work
2340 # Also, don't emit a subfield if the underlying field is blank.
2341 my $mungeditem = { map { (defined($item->{$_}) and $item->{$_} ne '') ?
2342 (/^items\./ ? ($_ => $item->{$_}) : ("items.$_" => $item->{$_}))
2343 : () } keys %{ $item } };
2344
2345 my $item_marc = MARC::Record->new();
2346 foreach my $item_field ( keys %{$mungeditem} ) {
2347 my ( $tag, $subfield ) = GetMarcFromKohaField( $item_field, $frameworkcode );
2348 next unless defined $tag and defined $subfield; # skip if not mapped to MARC field
2349 my @values = split(/\s?\|\s?/, $mungeditem->{$item_field}, -1);
2350 foreach my $value (@values){
2351 if ( my $field = $item_marc->field($tag) ) {
2352 $field->add_subfields( $subfield => $value );
2353 } else {
2354 my $add_subfields = [];
2355 if (defined $unlinked_item_subfields and ref($unlinked_item_subfields) eq 'ARRAY' and $#$unlinked_item_subfields > -1) {
2356 $add_subfields = $unlinked_item_subfields;
2357 }
2358 $item_marc->add_fields( $tag, " ", " ", $subfield => $value, @$add_subfields );
2359 }
2360 }
2361 }
2362
2363 return $item_marc;
2364}
2365
2366=head2 _repack_item_errors
2367
- -
2373sub _repack_item_errors {
2374 my $item_sequence_num = shift;
2375 my $item_ref = shift;
2376 my $error_ref = shift;
2377
2378 my @repacked_errors = ();
2379
2380 foreach my $error_code (sort keys %{ $error_ref }) {
2381 my $repacked_error = {};
2382 $repacked_error->{'item_sequence'} = $item_sequence_num;
2383 $repacked_error->{'item_barcode'} = exists($item_ref->{'barcode'}) ? $item_ref->{'barcode'} : '';
2384 $repacked_error->{'error_code'} = $error_code;
2385 $repacked_error->{'error_information'} = $error_ref->{$error_code};
2386 push @repacked_errors, $repacked_error;
2387 }
2388
2389 return @repacked_errors;
2390}
2391
2392=head2 _get_unlinked_item_subfields
2393
- -
2398sub _get_unlinked_item_subfields {
2399 my $original_item_marc = shift;
2400 my $frameworkcode = shift;
2401
2402 my $marcstructure = GetMarcStructure(1, $frameworkcode);
2403
2404 # assume that this record has only one field, and that that
2405 # field contains only the item information
2406 my $subfields = [];
2407 my @fields = $original_item_marc->fields();
2408 if ($#fields > -1) {
2409 my $field = $fields[0];
2410 my $tag = $field->tag();
2411 foreach my $subfield ($field->subfields()) {
2412 if (defined $subfield->[1] and
2413 $subfield->[1] ne '' and
2414 !$marcstructure->{$tag}->{$subfield->[0]}->{'kohafield'}) {
2415 push @$subfields, $subfield->[0] => $subfield->[1];
2416 }
2417 }
2418 }
2419 return $subfields;
2420}
2421
2422=head2 _get_unlinked_subfields_xml
2423
- -
2428sub _get_unlinked_subfields_xml {
2429 my $unlinked_item_subfields = shift;
2430
2431 my $xml;
2432 if (defined $unlinked_item_subfields and ref($unlinked_item_subfields) eq 'ARRAY' and $#$unlinked_item_subfields > -1) {
2433 my $marc = MARC::Record->new();
2434 # use of tag 999 is arbitrary, and doesn't need to match the item tag
2435 # used in the framework
2436 $marc->append_fields(MARC::Field->new('999', ' ', ' ', @$unlinked_item_subfields));
2437 $marc->encoding("UTF-8");
2438 $xml = $marc->as_xml("USMARC");
2439 }
2440
2441 return $xml;
2442}
2443
2444=head2 _parse_unlinked_item_subfields_from_xml
2445
- -
2450sub _parse_unlinked_item_subfields_from_xml {
2451 my $xml = shift;
2452 require C4::Charset;
2453 return unless defined $xml and $xml ne "";
2454 my $marc = MARC::Record->new_from_xml(C4::Charset::StripNonXmlChars($xml),'UTF-8');
2455 my $unlinked_subfields = [];
2456 my @fields = $marc->fields();
2457 if ($#fields > -1) {
2458 foreach my $subfield ($fields[0]->subfields()) {
2459 push @$unlinked_subfields, $subfield->[0] => $subfield->[1];
2460 }
2461 }
2462 return $unlinked_subfields;
2463}
2464
2465=head2 GetAnalyticsCount
2466
- -
2473sub GetAnalyticsCount {
2474 my ($itemnumber) = @_;
2475 require C4::Search;
2476
2477 ### ZOOM search here
2478 my $query;
2479 $query= "hi=".$itemnumber;
2480 my ($err,$res,$result) = C4::Search::SimpleSearch($query,0,10);
2481 return ($result);
2482}
2483
2484=head2 GetItemHolds
2485
- -
2495sub GetItemHolds {
2496 my ($biblionumber, $itemnumber) = @_;
2497 my $holds;
2498 my $dbh = C4::Context->dbh;
2499 my $query = "SELECT count(*)
2500 FROM reserves
2501 WHERE biblionumber=? AND itemnumber=?";
2502 my $sth = $dbh->prepare($query);
2503 $sth->execute($biblionumber, $itemnumber);
2504 $holds = $sth->fetchrow;
2505 return $holds;
2506}
2507
2508# Return the list of the column names of items table
2509sub _get_items_columns {
2510 my $dbh = C4::Context->dbh;
2511 my $sth = $dbh->column_info(undef, undef, 'items', '%');
2512 $sth->execute;
2513 my $results = $sth->fetchall_hashref('COLUMN_NAME');
2514 return keys %$results;
2515}
2516
2517=head2 SearchItems
2518
- -
2528sub SearchItems {
2529 my ($field, $value) = @_;
2530
2531 my $dbh = C4::Context->dbh;
2532 my @columns = _get_items_columns;
2533 my $results = [];
2534 if(0 < grep /^$field$/, @columns) {
2535 my $query = "SELECT $field FROM items WHERE $field = ?";
2536 my $sth = $dbh->prepare( $query );
2537 $sth->execute( $value );
2538 $results = $sth->fetchall_arrayref({});
2539 }
2540 return $results;
2541}
2542
2543
2544=head1 OTHER FUNCTIONS
2545
- -
2561sub _find_value {
2562 my ( $tagfield, $insubfield, $record, $encoding ) = @_;
2563 my @result;
2564 my $indicator;
2565 if ( $tagfield < 10 ) {
2566 if ( $record->field($tagfield) ) {
2567 push @result, $record->field($tagfield)->data();
2568 } else {
2569 push @result, "";
2570 }
2571 } else {
2572 foreach my $field ( $record->field($tagfield) ) {
2573 my @subfields = $field->subfields();
2574 foreach my $subfield (@subfields) {
2575 if ( @$subfield[0] eq $insubfield ) {
2576 push @result, @$subfield[1];
2577 $indicator = $field->indicator(1) . $field->indicator(2);
2578 }
2579 }
2580 }
2581 }
2582 return ( $indicator, @result );
2583}
2584
2585
2586=head2 PrepareItemrecordDisplay
2587
- -
2596sub PrepareItemrecordDisplay {
2597
2598 my ( $bibnum, $itemnum, $defaultvalues, $frameworkcode ) = @_;
2599
2600 my $dbh = C4::Context->dbh;
2601 $frameworkcode = &GetFrameworkCode($bibnum) if $bibnum;
2602 my ( $itemtagfield, $itemtagsubfield ) = &GetMarcFromKohaField( "items.itemnumber", $frameworkcode );
2603 my $tagslib = &GetMarcStructure( 1, $frameworkcode );
2604
2605 # return nothing if we don't have found an existing framework.
2606 return q{} unless $tagslib;
2607 my $itemrecord;
2608 if ($itemnum) {
2609 $itemrecord = C4::Items::GetMarcItem( $bibnum, $itemnum );
2610 }
2611 my @loop_data;
2612
2613 my $branch_limit = C4::Context->userenv ? C4::Context->userenv->{"branch"} : "";
2614 my $query = qq{
2615 SELECT authorised_value,lib FROM authorised_values
2616 };
2617 $query .= qq{
2618 LEFT JOIN authorised_values_branches ON ( id = av_id )
2619 } if $branch_limit;
2620 $query .= qq{
2621 WHERE category = ?
2622 };
2623 $query .= qq{ AND ( branchcode = ? OR branchcode IS NULL )} if $branch_limit;
2624 $query .= qq{ ORDER BY lib};
2625 my $authorised_values_sth = $dbh->prepare( $query );
2626 foreach my $tag ( sort keys %{$tagslib} ) {
2627 my $previous_tag = '';
2628 if ( $tag ne '' ) {
2629
2630 # loop through each subfield
2631 my $cntsubf;
2632 foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
2633 next if ( subfield_is_koha_internal_p($subfield) );
2634 next if ( $tagslib->{$tag}->{$subfield}->{'tab'} ne "10" );
2635 my %subfield_data;
2636 $subfield_data{tag} = $tag;
2637 $subfield_data{subfield} = $subfield;
2638 $subfield_data{countsubfield} = $cntsubf++;
2639 $subfield_data{kohafield} = $tagslib->{$tag}->{$subfield}->{'kohafield'};
2640 $subfield_data{id} = "tag_".$tag."_subfield_".$subfield."_".int(rand(1000000));
2641
2642 # $subfield_data{marc_lib}=$tagslib->{$tag}->{$subfield}->{lib};
2643 $subfield_data{marc_lib} = $tagslib->{$tag}->{$subfield}->{lib};
2644 $subfield_data{mandatory} = $tagslib->{$tag}->{$subfield}->{mandatory};
2645 $subfield_data{repeatable} = $tagslib->{$tag}->{$subfield}->{repeatable};
2646 $subfield_data{hidden} = "display:none"
2647 if $tagslib->{$tag}->{$subfield}->{hidden};
2648 my ( $x, $defaultvalue );
2649 if ($itemrecord) {
2650 ( $x, $defaultvalue ) = _find_value( $tag, $subfield, $itemrecord );
2651 }
2652 $defaultvalue = $tagslib->{$tag}->{$subfield}->{defaultvalue} unless $defaultvalue;
2653 if ( !defined $defaultvalue ) {
2654 $defaultvalue = q||;
2655 } else {
2656 $defaultvalue =~ s/"/&quot;/g;
2657 }
2658
2659 # search for itemcallnumber if applicable
2660 if ( $tagslib->{$tag}->{$subfield}->{kohafield} eq 'items.itemcallnumber'
2661 && C4::Context->preference('itemcallnumber') ) {
2662 my $CNtag = substr( C4::Context->preference('itemcallnumber'), 0, 3 );
2663 my $CNsubfield = substr( C4::Context->preference('itemcallnumber'), 3, 1 );
2664 if ( $itemrecord and my $field = $itemrecord->field($CNtag) ) {
2665 $defaultvalue = $field->subfield($CNsubfield);
2666 }
2667 }
2668 if ( $tagslib->{$tag}->{$subfield}->{kohafield} eq 'items.itemcallnumber'
2669 && $defaultvalues
2670 && $defaultvalues->{'callnumber'} ) {
2671 if( $itemrecord and $defaultvalues and not $itemrecord->field($subfield) ){
2672 # if the item record exists, only use default value if the item has no callnumber
2673 $defaultvalue = $defaultvalues->{callnumber};
2674 } elsif ( !$itemrecord and $defaultvalues ) {
2675 # if the item record *doesn't* exists, always use the default value
2676 $defaultvalue = $defaultvalues->{callnumber};
2677 }
2678 }
2679 if ( ( $tagslib->{$tag}->{$subfield}->{kohafield} eq 'items.holdingbranch' || $tagslib->{$tag}->{$subfield}->{kohafield} eq 'items.homebranch' )
2680 && $defaultvalues
2681 && $defaultvalues->{'branchcode'} ) {
2682 if ( $itemrecord and $defaultvalues and not $itemrecord->field($subfield) ) {
2683 $defaultvalue = $defaultvalues->{branchcode};
2684 }
2685 }
2686 if ( ( $tagslib->{$tag}->{$subfield}->{kohafield} eq 'items.location' )
2687 && $defaultvalues
2688 && $defaultvalues->{'location'} ) {
2689
2690 if ( $itemrecord and $defaultvalues and not $itemrecord->field($subfield) ) {
2691 # if the item record exists, only use default value if the item has no locationr
2692 $defaultvalue = $defaultvalues->{location};
2693 } elsif ( !$itemrecord and $defaultvalues ) {
2694 # if the item record *doesn't* exists, always use the default value
2695 $defaultvalue = $defaultvalues->{location};
2696 }
2697 }
2698 if ( $tagslib->{$tag}->{$subfield}->{authorised_value} ) {
2699 my @authorised_values;
2700 my %authorised_lib;
2701
2702 # builds list, depending on authorised value...
2703 #---- branch
2704 if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq "branches" ) {
2705 if ( ( C4::Context->preference("IndependantBranches") )
2706 && ( C4::Context->userenv->{flags} % 2 != 1 ) ) {
2707 my $sth = $dbh->prepare( "SELECT branchcode,branchname FROM branches WHERE branchcode = ? ORDER BY branchname" );
2708 $sth->execute( C4::Context->userenv->{branch} );
2709 push @authorised_values, ""
2710 unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
2711 while ( my ( $branchcode, $branchname ) = $sth->fetchrow_array ) {
2712 push @authorised_values, $branchcode;
2713 $authorised_lib{$branchcode} = $branchname;
2714 }
2715 } else {
2716 my $sth = $dbh->prepare( "SELECT branchcode,branchname FROM branches ORDER BY branchname" );
2717 $sth->execute;
2718 push @authorised_values, ""
2719 unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
2720 while ( my ( $branchcode, $branchname ) = $sth->fetchrow_array ) {
2721 push @authorised_values, $branchcode;
2722 $authorised_lib{$branchcode} = $branchname;
2723 }
2724 }
2725
2726 $defaultvalue = C4::Context->userenv->{branch};
2727 if ( $defaultvalues and $defaultvalues->{branchcode} ) {
2728 $defaultvalue = $defaultvalues->{branchcode};
2729 }
2730
2731 #----- itemtypes
2732 } elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq "itemtypes" ) {
2733 my $sth = $dbh->prepare( "SELECT itemtype,description FROM itemtypes ORDER BY description" );
2734 $sth->execute;
2735 push @authorised_values, ""
2736 unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
2737 while ( my ( $itemtype, $description ) = $sth->fetchrow_array ) {
2738 push @authorised_values, $itemtype;
2739 $authorised_lib{$itemtype} = $description;
2740 }
2741 #---- class_sources
2742 } elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq "cn_source" ) {
2743 push @authorised_values, "" unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
2744
2745 my $class_sources = GetClassSources();
2746 my $default_source = C4::Context->preference("DefaultClassificationSource");
2747
2748 foreach my $class_source (sort keys %$class_sources) {
2749 next unless $class_sources->{$class_source}->{'used'} or
2750 ($class_source eq $default_source);
2751 push @authorised_values, $class_source;
2752 $authorised_lib{$class_source} = $class_sources->{$class_source}->{'description'};
2753 }
2754
2755 $defaultvalue = $default_source;
2756
2757 #---- "true" authorised value
2758 } else {
2759 $authorised_values_sth->execute(
2760 $tagslib->{$tag}->{$subfield}->{authorised_value},
2761 $branch_limit ? $branch_limit : ()
2762 );
2763 push @authorised_values, ""
2764 unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
2765 while ( my ( $value, $lib ) = $authorised_values_sth->fetchrow_array ) {
2766 push @authorised_values, $value;
2767 $authorised_lib{$value} = $lib;
2768 }
2769 }
2770 $subfield_data{marc_value} = CGI::scrolling_list(
2771 -name => 'field_value',
2772 -values => \@authorised_values,
2773 -default => "$defaultvalue",
2774 -labels => \%authorised_lib,
2775 -size => 1,
2776 -tabindex => '',
2777 -multiple => 0,
2778 );
2779 } elsif ( $tagslib->{$tag}->{$subfield}->{value_builder} ) {
2780 # opening plugin
2781 my $plugin = C4::Context->intranetdir . "/cataloguing/value_builder/" . $tagslib->{$tag}->{$subfield}->{'value_builder'};
2782 if (do $plugin) {
2783 my $extended_param = plugin_parameters( $dbh, undef, $tagslib, $subfield_data{id}, undef );
2784 my ( $function_name, $javascript ) = plugin_javascript( $dbh, undef, $tagslib, $subfield_data{id}, undef );
2785 $subfield_data{random} = int(rand(1000000)); # why do we need 2 different randoms?
2786 $subfield_data{marc_value} = qq[<input tabindex="1" id="$subfield_data{id}" name="field_value" class="input_marceditor" size="67" maxlength="255"
2787 onfocus="Focus$function_name($subfield_data{random}, '$subfield_data{id}');"
2788 onblur=" Blur$function_name($subfield_data{random}, '$subfield_data{id}');" />
2789 <a href="#" class="buttonDot" onclick="Clic$function_name('$subfield_data{id}'); return false;" title="Tag Editor">...</a>
2790 $javascript];
2791 } else {
2792 warn "Plugin Failed: $plugin";
2793 $subfield_data{marc_value} = qq(<input tabindex="1" id="$subfield_data{id}" name="field_value" class="input_marceditor" size="67" maxlength="255" />); # supply default input form
2794 }
2795 }
2796 elsif ( $tag eq '' ) { # it's an hidden field
2797 $subfield_data{marc_value} = qq(<input type="hidden" tabindex="1" id="$subfield_data{id}" name="field_value" class="input_marceditor" size="67" maxlength="255" value="$defaultvalue" />);
2798 }
2799 elsif ( $tagslib->{$tag}->{$subfield}->{'hidden'} ) { # FIXME: shouldn't input type be "hidden" ?
2800 $subfield_data{marc_value} = qq(<input type="text" tabindex="1" id="$subfield_data{id}" name="field_value" class="input_marceditor" size="67" maxlength="255" value="$defaultvalue" />);
2801 }
2802 elsif ( length($defaultvalue) > 100
2803 or (C4::Context->preference("marcflavour") eq "UNIMARC" and
2804 300 <= $tag && $tag < 400 && $subfield eq 'a' )
2805 or (C4::Context->preference("marcflavour") eq "MARC21" and
2806 500 <= $tag && $tag < 600 )
2807 ) {
2808 # oversize field (textarea)
2809 $subfield_data{marc_value} = qq(<textarea tabindex="1" id="$subfield_data{id}" name="field_value" class="input_marceditor" size="67" maxlength="255">$defaultvalue</textarea>\n");
2810 } else {
2811 $subfield_data{marc_value} = "<input type=\"text\" name=\"field_value\" value=\"$defaultvalue\" size=\"50\" maxlength=\"255\" />";
2812 }
2813 push( @loop_data, \%subfield_data );
2814 }
2815 }
2816 }
2817 my $itemnumber;
2818 if ( $itemrecord && $itemrecord->field($itemtagfield) ) {
2819 $itemnumber = $itemrecord->subfield( $itemtagfield, $itemtagsubfield );
2820 }
2821 return {
2822 'itemtagfield' => $itemtagfield,
2823 'itemtagsubfield' => $itemtagsubfield,
2824 'itemnumber' => $itemnumber,
2825 'iteminformation' => \@loop_data
2826 };
2827}
2828
2829117µs1;