Filename | /usr/share/koha/lib/C4/Items.pm |
Statements | Executed 1577 statements in 300ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
25 | 1 | 1 | 12.0ms | 839ms | GetItemsInfo | C4::Items::
32 | 1 | 1 | 1.75ms | 125ms | GetHiddenItemnumbers | C4::Items::
1 | 1 | 1 | 105µs | 172µs | BEGIN@33 | C4::Items::
1 | 1 | 1 | 35µs | 35µs | BEGIN@38 | C4::Items::
1 | 1 | 1 | 35µs | 46µs | BEGIN@21 | C4::Items::
1 | 1 | 1 | 27µs | 98µs | BEGIN@32 | C4::Items::
1 | 1 | 1 | 26µs | 1.02ms | BEGIN@26 | C4::Items::
1 | 1 | 1 | 24µs | 30µs | BEGIN@25 | C4::Items::
1 | 1 | 1 | 23µs | 123µs | BEGIN@24 | C4::Items::
1 | 1 | 1 | 21µs | 238µs | BEGIN@31 | C4::Items::
1 | 1 | 1 | 20µs | 135µs | BEGIN@36 | C4::Items::
1 | 1 | 1 | 20µs | 1.34ms | BEGIN@27 | C4::Items::
1 | 1 | 1 | 18µs | 99µs | BEGIN@28 | C4::Items::
1 | 1 | 1 | 18µs | 257µs | BEGIN@30 | C4::Items::
1 | 1 | 1 | 16µs | 38µs | BEGIN@29 | C4::Items::
0 | 0 | 0 | 0s | 0s | AddItem | C4::Items::
0 | 0 | 0 | 0s | 0s | AddItemBatchFromMarc | C4::Items::
0 | 0 | 0 | 0s | 0s | AddItemFromMarc | C4::Items::
0 | 0 | 0 | 0s | 0s | CartToShelf | C4::Items::
0 | 0 | 0 | 0s | 0s | CheckItemPreSave | C4::Items::
0 | 0 | 0 | 0s | 0s | DelItem | C4::Items::
0 | 0 | 0 | 0s | 0s | DelItemCheck | C4::Items::
0 | 0 | 0 | 0s | 0s | GetAnalyticsCount | C4::Items::
0 | 0 | 0 | 0s | 0s | GetBarcodeFromItemnumber | C4::Items::
0 | 0 | 0 | 0s | 0s | GetHostItemsInfo | C4::Items::
0 | 0 | 0 | 0s | 0s | GetItem | C4::Items::
0 | 0 | 0 | 0s | 0s | GetItemHolds | C4::Items::
0 | 0 | 0 | 0s | 0s | GetItemInfosOf | C4::Items::
0 | 0 | 0 | 0s | 0s | GetItemLocation | C4::Items::
0 | 0 | 0 | 0s | 0s | GetItemStatus | C4::Items::
0 | 0 | 0 | 0s | 0s | GetItemnumberFromBarcode | C4::Items::
0 | 0 | 0 | 0s | 0s | GetItemnumbersForBiblio | C4::Items::
0 | 0 | 0 | 0s | 0s | GetItemsByBiblioitemnumber | C4::Items::
0 | 0 | 0 | 0s | 0s | GetItemsCount | C4::Items::
0 | 0 | 0 | 0s | 0s | GetItemsForInventory | C4::Items::
0 | 0 | 0 | 0s | 0s | GetItemsLocationInfo | C4::Items::
0 | 0 | 0 | 0s | 0s | GetLastAcquisitions | C4::Items::
0 | 0 | 0 | 0s | 0s | GetLostItems | C4::Items::
0 | 0 | 0 | 0s | 0s | GetMarcItem | C4::Items::
0 | 0 | 0 | 0s | 0s | Item2Marc | C4::Items::
0 | 0 | 0 | 0s | 0s | ModDateLastSeen | C4::Items::
0 | 0 | 0 | 0s | 0s | ModItem | C4::Items::
0 | 0 | 0 | 0s | 0s | ModItemFromMarc | C4::Items::
0 | 0 | 0 | 0s | 0s | ModItemTransfer | C4::Items::
0 | 0 | 0 | 0s | 0s | MoveItemFromBiblio | C4::Items::
0 | 0 | 0 | 0s | 0s | PrepareItemrecordDisplay | C4::Items::
0 | 0 | 0 | 0s | 0s | SearchItems | C4::Items::
0 | 0 | 0 | 0s | 0s | ShelfToCart | C4::Items::
0 | 0 | 0 | 0s | 0s | __ANON__[:1668] | C4::Items::
0 | 0 | 0 | 0s | 0s | _calc_items_cn_sort | C4::Items::
0 | 0 | 0 | 0s | 0s | _do_column_fixes_for_mod | C4::Items::
0 | 0 | 0 | 0s | 0s | _find_value | C4::Items::
0 | 0 | 0 | 0s | 0s | _get_items_columns | C4::Items::
0 | 0 | 0 | 0s | 0s | _get_single_item_column | C4::Items::
0 | 0 | 0 | 0s | 0s | _get_unlinked_item_subfields | C4::Items::
0 | 0 | 0 | 0s | 0s | _get_unlinked_subfields_xml | C4::Items::
0 | 0 | 0 | 0s | 0s | _koha_delete_item | C4::Items::
0 | 0 | 0 | 0s | 0s | _koha_modify_item | C4::Items::
0 | 0 | 0 | 0s | 0s | _koha_new_item | C4::Items::
0 | 0 | 0 | 0s | 0s | _marc_from_item_hash | C4::Items::
0 | 0 | 0 | 0s | 0s | _parse_unlinked_item_subfields_from_xml | C4::Items::
0 | 0 | 0 | 0s | 0s | _repack_item_errors | C4::Items::
0 | 0 | 0 | 0s | 0s | _set_defaults_for_add | C4::Items::
0 | 0 | 0 | 0s | 0s | _set_derived_columns_for_add | C4::Items::
0 | 0 | 0 | 0s | 0s | _set_derived_columns_for_mod | C4::Items::
0 | 0 | 0 | 0s | 0s | get_authorised_value_images | C4::Items::
0 | 0 | 0 | 0s | 0s | get_hostitemnumbers_of | C4::Items::
0 | 0 | 0 | 0s | 0s | get_item_authorised_values | C4::Items::
0 | 0 | 0 | 0s | 0s | get_itemnumbers_of | C4::Items::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | package 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 | |||||
21 | 3 | 61µs | 2 | 57µ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 # 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 | |||||
24 | 3 | 58µs | 2 | 224µ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 # spent 123µs making 1 call to C4::Items::BEGIN@24
# spent 100µs making 1 call to Exporter::import |
25 | 3 | 56µs | 2 | 35µ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 # spent 30µs making 1 call to C4::Items::BEGIN@25
# spent 6µs making 1 call to C4::Context::import |
26 | 3 | 64µs | 2 | 2.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 # spent 1.02ms making 1 call to C4::Items::BEGIN@26
# spent 996µs making 1 call to Exporter::import |
27 | 3 | 83µs | 2 | 2.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 # spent 1.34ms making 1 call to C4::Items::BEGIN@27
# spent 1.32ms making 1 call to Exporter::import |
28 | 3 | 40µs | 2 | 180µ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 # spent 99µs making 1 call to C4::Items::BEGIN@28
# spent 81µs making 1 call to Exporter::import |
29 | 3 | 34µs | 2 | 60µ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 # spent 38µs making 1 call to C4::Items::BEGIN@29
# spent 22µs making 1 call to Exporter::import |
30 | 3 | 56µs | 2 | 496µ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 # spent 257µs making 1 call to C4::Items::BEGIN@30
# spent 239µs making 1 call to Exporter::import |
31 | 3 | 63µs | 2 | 454µ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 # spent 238µs making 1 call to C4::Items::BEGIN@31
# spent 216µs making 1 call to Exporter::import |
32 | 3 | 68µs | 2 | 168µ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 # spent 98µs making 1 call to C4::Items::BEGIN@32
# spent 71µs making 1 call to Exporter::import |
33 | 3 | 79µs | 2 | 240µ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 # 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 | |||||
36 | 3 | 172µs | 2 | 249µ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 # 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 | ||||
39 | 4 | 37µs | $VERSION = 3.07.00.049; | ||
40 | |||||
41 | require Exporter; | ||||
42 | @ISA = qw( Exporter ); | ||||
43 | |||||
44 | # function exports | ||||
45 | @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 | ); | ||||
90 | 1 | 13.8ms | 1 | 35µs | } # spent 35µs making 1 call to C4::Items::BEGIN@38 |
91 | |||||
92 | =head1 NAME | ||||
93 | |||||
- - | |||||
133 | =head2 GetItem | ||||
134 | |||||
- - | |||||
143 | sub 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 | |||||
- - | |||||
187 | sub 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 | |||||
- - | |||||
210 | sub 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 | |||||
- - | |||||
232 | sub 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 | |||||
- - | |||||
268 | sub 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 | |||||
- - | |||||
350 | sub 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 | |||||
- - | |||||
438 | 1 | 34µs | my %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 | |||||
469 | sub 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 | |||||
- - | |||||
515 | sub 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 | |||||
- - | |||||
566 | sub 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 | |||||
- - | |||||
594 | sub 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 | |||||
- - | |||||
609 | sub 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 | |||||
- - | |||||
671 | sub 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 | |||||
- - | |||||
763 | sub 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 | |||||
- - | |||||
851 | sub 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 | |||||
- - | |||||
933 | sub 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 | |||||
- - | |||||
990 | sub 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'; | ||||
996 | SELECT items.itemnumber, barcode, itemcallnumber, title, author, biblio.biblionumber, datelastseen | ||||
997 | FROM items | ||||
998 | LEFT JOIN biblio ON items.biblionumber = biblio.biblionumber | ||||
999 | LEFT JOIN biblioitems on items.biblionumber = biblioitems.biblionumber | ||||
1000 | END_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 | |||||
- - | |||||
1079 | sub 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 | |||||
- - | |||||
1097 | sub 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 | |||||
- - | |||||
1117 | sub 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 | ||||
1203 | 1150 | 283ms | my ( $biblionumber ) = @_; | ||
1204 | 25 | 23.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. | ||||
1206 | 25 | 229µ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'); | ||||
1233 | $query .= " WHERE items.biblionumber = ? ORDER BY home.branchname, items.enumchron, LPAD( items.copynumber, 8, '0' ), items.dateaccessioned DESC" ; | ||||
1234 | 1 | 166µs | 50 | 4.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 |
1235 | 25 | 84.5ms | $sth->execute($biblionumber); # spent 84.5ms making 25 calls to DBI::st::execute, avg 3.38ms/call | ||
1236 | my $i = 0; | ||||
1237 | my @results; | ||||
1238 | my $serial; | ||||
1239 | |||||
1240 | 1 | 171µs | 50 | 6.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 | ); | ||||
1245 | 1 | 163µs | 50 | 3.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 |
1246 | 459 | 10.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 | ||
1247 | my $datedue = ''; | ||||
1248 | 32 | 44.4ms | $isth->execute( $data->{'itemnumber'} ); # spent 44.4ms making 32 calls to DBI::st::execute, avg 1.39ms/call | ||
1249 | 96 | 2.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 | } | ||||
1263 | if ( $data->{'serial'}) { | ||||
1264 | $ssth->execute($data->{'itemnumber'}) ; | ||||
1265 | ($data->{'serialseq'} , $data->{'publisheddate'}) = $ssth->fetchrow_array(); | ||||
1266 | $serial = 1; | ||||
1267 | } | ||||
1268 | #get branch information..... | ||||
1269 | 1 | 167µs | 64 | 4.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 | ); | ||||
1273 | 32 | 35.5ms | $bsth->execute( $data->{'holdingbranch'} ); # spent 35.5ms making 32 calls to DBI::st::execute, avg 1.11ms/call | ||
1274 | 96 | 3.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 | } | ||||
1277 | $data->{'datedue'} = $datedue; | ||||
1278 | |||||
1279 | # get notforloan complete status if applicable | ||||
1280 | 128 | 68.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 | ||
1281 | 128 | 70.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 | ||
1282 | 128 | 71.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 | ||||
1286 | 128 | 68.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 | ||
1287 | 128 | 69.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 | ||
1288 | 128 | 71.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 | ||||
1292 | 188 | 101ms | 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 | |||||
1298 | 1 | 156µs | 64 | 4.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 | ); | ||||
1305 | 32 | 32.5ms | $restrictedstatus->execute( 'RESTRICTED', $data->{'restricted'}); # spent 32.5ms making 32 calls to DBI::st::execute, avg 1.02ms/call | ||
1306 | 32 | 436µs | my ($lib) = $restrictedstatus->fetchrow; # spent 436µs making 32 calls to DBI::st::fetchrow, avg 14µs/call | ||
1307 | $data->{restrictedvalue} = $lib; | ||||
1308 | # Find the last 3 people who borrowed this item. | ||||
1309 | 1 | 210µs | 64 | 4.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"); | ||||
1314 | 32 | 56.5ms | $sth2->execute($data->{'itemnumber'}); # spent 56.5ms making 32 calls to DBI::st::execute, avg 1.77ms/call | ||
1315 | my $ii = 0; | ||||
1316 | 96 | 4.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 | |||||
1323 | $results[$i] = $data; | ||||
1324 | $i++; | ||||
1325 | } | ||||
1326 | if($serial) { | ||||
1327 | return( sort { ($b->{'publisheddate'} || $b->{'enumchron'}) cmp ($a->{'publisheddate'} || $a->{'enumchron'}) } @results ); | ||||
1328 | } else { | ||||
1329 | return (@results); | ||||
1330 | } | ||||
1331 | } | ||||
1332 | |||||
1333 | =head2 GetItemsLocationInfo | ||||
1334 | |||||
- - | |||||
1376 | sub 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 | |||||
- - | |||||
1405 | sub 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 | |||||
- - | |||||
1446 | sub 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 | |||||
- - | |||||
1498 | sub 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 | |||||
- - | |||||
1522 | sub 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 | |||||
- - | |||||
1557 | sub 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 | |||||
- - | |||||
1598 | sub 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 | |||||
- - | |||||
1615 | sub 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 | ||||
1637 | 384 | 1.70ms | my (@items) = @_; | ||
1638 | my @resultitems; | ||||
1639 | |||||
1640 | 32 | 2.79ms | my $yaml = C4::Context->preference('OpacHiddenItems'); # spent 2.79ms making 32 calls to C4::Context::preference, avg 87µs/call | ||
1641 | $yaml = "$yaml\n\n"; # YAML is anal on ending \n. Surplus does not hurt | ||||
1642 | my $hidingrules; | ||||
1643 | eval { | ||||
1644 | 32 | 87.5ms | $hidingrules = YAML::Load($yaml); # spent 87.5ms making 32 calls to YAML::Load, avg 2.73ms/call | ||
1645 | }; | ||||
1646 | if ($@) { | ||||
1647 | warn "Unable to parse OpacHiddenItems syspref : $@"; | ||||
1648 | return (); | ||||
1649 | } | ||||
1650 | 32 | 32.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 | ||||
1653 | foreach my $item (@items) { | ||||
1654 | |||||
1655 | # We check each rule | ||||
1656 | 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 | } | ||||
1678 | return @resultitems; | ||||
1679 | } | ||||
1680 | |||||
1681 | =head3 get_item_authorised_values | ||||
1682 | |||||
- - | |||||
1707 | sub 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 | |||||
- - | |||||
1754 | sub 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 | |||||
- - | |||||
1800 | sub 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 | } | ||||
1824 | sub 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 | |||||
- - | |||||
1868 | 1 | 8µs | my %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 | |||||
- - | |||||
1886 | sub _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 | |||||
- - | |||||
1921 | sub _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 | |||||
- - | |||||
1960 | sub _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 | |||||
- - | |||||
1996 | sub _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 | |||||
- - | |||||
2015 | sub _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 | |||||
- - | |||||
2057 | sub _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 | |||||
- - | |||||
2071 | sub _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 | |||||
- - | |||||
2180 | sub 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 | |||||
- - | |||||
2212 | sub 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 | |||||
- - | |||||
2261 | sub _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 | |||||
- - | |||||
2293 | sub _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 | |||||
- - | |||||
2331 | sub _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 | |||||
- - | |||||
2373 | sub _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 | |||||
- - | |||||
2398 | sub _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 | |||||
- - | |||||
2428 | sub _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 | |||||
- - | |||||
2450 | sub _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 | |||||
- - | |||||
2473 | sub 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 | |||||
- - | |||||
2495 | sub 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 | ||||
2509 | sub _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 | |||||
- - | |||||
2528 | sub 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 | |||||
- - | |||||
2561 | sub _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 | |||||
- - | |||||
2596 | sub 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/"/"/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 | |||||
2829 | 1 | 17µs | 1; |