3 # Copyright 2000-2002 Katipo Communications
5 # This file is part of Koha.
7 # Koha is free software; you can redistribute it and/or modify it under the
8 # terms of the GNU General Public License as published by the Free Software
9 # Foundation; either version 2 of the License, or (at your option) any later
12 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License along with
17 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
18 # Suite 330, Boston, MA 02111-1307 USA
26 use MARC::File::USMARC;
31 use C4::Log; # logaction
34 use vars qw($VERSION @ISA @EXPORT);
39 @ISA = qw( Exporter );
43 # to add biblios or items
44 push @EXPORT, qw( &AddBiblio &AddItem );
52 &GetBiblioItemByBiblioNumber
53 &GetBiblioFromItemNumber
73 &GetItemsByBiblioitemnumber
74 &GetItemnumberFromBarcode
78 &GetAuthorisedValueDesc
82 &GetPublisherNameFromIsbn
94 &ModItemInMarconefield
105 # those functions are exported but should not be used
106 # they are usefull is few circumstances, so are exported.
107 # but don't use them unless you're a core developer ;-)
116 &TransformHtmlToMarc2
119 &PrepareItemrecordDisplay
126 C4::Biblio - cataloging management functions
130 Biblio.pm contains functions for managing storage and editing of bibliographic data within Koha. Most of the functions in this module are used for cataloging records: adding, editing, or removing biblios, biblioitems, or items. Koha's stores bibliographic information in three places:
134 =item 1. in the biblio,biblioitems,items, etc tables, which are limited to a one-to-one mapping to underlying MARC data
136 =item 2. as raw MARC in the Zebra index and storage engine
138 =item 3. as raw MARC the biblioitems.marc and biblioitems.marcxml
142 In the 3.0 version of Koha, the authoritative record-level information is in biblioitems.marcxml
144 Because the data isn't completely normalized there's a chance for information to get out of sync. The design choice to go with a un-normalized schema was driven by performance and stability concerns. However, if this occur, it can be considered as a bug : The API is (or should be) complete & the only entry point for all biblio/items managements.
148 =item 1. Compared with MySQL, Zebra is slow to update an index for small data changes -- especially for proc-intensive operations like circulation
150 =item 2. Zebra's index has been known to crash and a backup of the data is necessary to rebuild it in such cases
154 Because of this design choice, the process of managing storage and editing is a bit convoluted. Historically, Biblio.pm's grown to an unmanagable size and as a result we have several types of functions currently:
158 =item 1. Add*/Mod*/Del*/ - high-level external functions suitable for being called from external scripts to manage the collection
160 =item 2. _koha_* - low-level internal functions for managing the koha tables
162 =item 3. Marc management function : as the MARC record is stored in biblioitems.marc(xml), some subs dedicated to it's management are in this package. They should be used only internally by Biblio.pm, the only official entry points being AddBiblio, AddItem, ModBiblio, ModItem.
164 =item 4. Zebra functions used to update the Zebra index
166 =item 5. internal helper functions such as char_decode, checkitems, etc. Some of these probably belong in Koha.pm
170 The MARC record (in biblioitems.marcxml) contains the complete marc record, including items. It also contains the biblionumber. That is the reason why it is not stored directly by AddBiblio, with all other fields . To save a biblio, we need to :
174 =item 1. save datas in biblio and biblioitems table, that gives us a biblionumber and a biblioitemnumber
176 =item 2. add the biblionumber and biblioitemnumber into the MARC records
178 =item 3. save the marc record
182 When dealing with items, we must :
186 =item 1. save the item in items table, that gives us an itemnumber
188 =item 2. add the itemnumber to the item MARC field
190 =item 3. overwrite the MARC record (with the added item) into biblioitems.marc(xml)
192 When modifying a biblio or an item, the behaviour is quite similar.
196 =head1 EXPORTED FUNCTIONS
202 ($biblionumber,$biblioitemnumber) = AddBiblio($record,$frameworkcode);
203 Exported function (core API) for adding a new biblio to koha.
210 my ( $record, $frameworkcode ) = @_;
211 my ($biblionumber,$biblioitemnumber,$error);
212 my $dbh = C4::Context->dbh;
213 # transform the data into koha-table style data
214 my $olddata = TransformMarcToKoha( $dbh, $record, $frameworkcode );
215 ($biblionumber,$error) = _koha_add_biblio( $dbh, $olddata, $frameworkcode );
216 $olddata->{'biblionumber'} = $biblionumber;
217 ($biblioitemnumber,$error) = _koha_add_biblioitem( $dbh, $olddata );
219 # we must add bibnum and bibitemnum in MARC::Record...
220 # we build the new field with biblionumber and biblioitemnumber
221 # we drop the original field
222 # we add the new builded field.
223 ( my $biblio_tag, my $biblio_subfield ) = GetMarcFromKohaField("biblio.biblionumber",$frameworkcode);
224 ( my $biblioitem_tag, my $biblioitem_subfield ) = GetMarcFromKohaField("biblioitems.biblioitemnumber",$frameworkcode);
228 # biblionumber & biblioitemnumber are in different fields
229 if ( $biblio_tag != $biblioitem_tag ) {
231 # deal with biblionumber
232 if ( $biblio_tag < 10 ) {
233 $newfield = MARC::Field->new( $biblio_tag, $biblionumber );
237 MARC::Field->new( $biblio_tag, '', '',
238 "$biblio_subfield" => $biblionumber );
241 # drop old field and create new one...
242 my $old_field = $record->field($biblio_tag);
243 $record->delete_field($old_field);
244 $record->append_fields($newfield);
246 # deal with biblioitemnumber
247 if ( $biblioitem_tag < 10 ) {
248 $newfield = MARC::Field->new( $biblioitem_tag, $biblioitemnumber, );
252 MARC::Field->new( $biblioitem_tag, '', '',
253 "$biblioitem_subfield" => $biblioitemnumber, );
255 # drop old field and create new one...
256 $old_field = $record->field($biblioitem_tag);
257 $record->delete_field($old_field);
258 $record->insert_fields_ordered($newfield);
260 # biblionumber & biblioitemnumber are in the same field (can't be <10 as fields <10 have only 1 value)
263 my $newfield = MARC::Field->new(
265 "$biblio_subfield" => $biblionumber,
266 "$biblioitem_subfield" => $biblioitemnumber
269 # drop old field and create new one...
270 my $old_field = $record->field($biblio_tag);
271 $record->delete_field($old_field);
272 $record->insert_fields_ordered($newfield);
276 $biblionumber = ModBiblioMarc( $record, $biblionumber, $frameworkcode );
278 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","ADD",$biblionumber,"biblio")
279 if C4::Context->preference("CataloguingLog");
281 return ( $biblionumber, $biblioitemnumber );
288 $biblionumber = AddItem( $record, $biblionumber)
289 Exported function (core API) for adding a new item to Koha
296 my ( $record, $biblionumber ) = @_;
297 my $dbh = C4::Context->dbh;
300 my $frameworkcode = GetFrameworkCode( $biblionumber );
301 my $item = &TransformMarcToKoha( $dbh, $record, $frameworkcode );
303 # needs old biblionumber and biblioitemnumber
304 $item->{'biblionumber'} = $biblionumber;
307 "SELECT biblioitemnumber,itemtype FROM biblioitems WHERE biblionumber=?"
309 $sth->execute( $item->{'biblionumber'} );
311 ( $item->{'biblioitemnumber'}, $itemtype ) = $sth->fetchrow;
314 "SELECT notforloan FROM itemtypes WHERE itemtype='$itemtype'");
316 my $notforloan = $sth->fetchrow;
317 ##Change the notforloan field if $notforloan found
318 if ( $notforloan > 0 ) {
319 $item->{'notforloan'} = $notforloan;
320 &MARCitemchange( $record, "items.notforloan", $notforloan );
322 if ( !$item->{'dateaccessioned'} || $item->{'dateaccessioned'} eq '' ) {
325 my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) =
330 "$year-" . sprintf( "%0.2d", $mon ) . "-" . sprintf( "%0.2d", $mday );
331 $item->{'dateaccessioned'} = $date;
332 &MARCitemchange( $record, "items.dateaccessioned", $date );
334 my ( $itemnumber, $error ) = &_koha_new_items( $dbh, $item, $item->{barcode} );
335 # add itemnumber to MARC::Record before adding the item.
336 $sth = $dbh->prepare(
337 "SELECT tagfield,tagsubfield
338 FROM marc_subfield_structure
339 WHERE frameworkcode=?
342 &TransformKohaToMarcOneField( $sth, $record, "items.itemnumber", $itemnumber,
346 &AddItemInMarc( $record, $item->{'biblionumber'},$frameworkcode );
348 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","ADD",$itemnumber,"item")
349 if C4::Context->preference("CataloguingLog");
351 return ($item->{biblionumber}, $item->{biblioitemnumber},$itemnumber);
356 ModBiblio( $record,$biblionumber,$frameworkcode);
357 Exported function (core API) to modify a biblio
362 my ( $record, $biblionumber, $frameworkcode ) = @_;
363 if (C4::Context->preference("CataloguingLog")) {
364 my $newrecord = GetMarcBiblio($biblionumber);
365 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","MODIFY",$biblionumber,"BEFORE=>".$newrecord->as_formatted);
368 my $dbh = C4::Context->dbh;
370 $frameworkcode = "" unless $frameworkcode;
372 # get the items before and append them to the biblio before updating the record, atm we just have the biblio
373 my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField("items.itemnumber",$frameworkcode);
374 my $oldRecord = GetMarcBiblio( $biblionumber );
376 # parse each item, and, for an unknown reason, re-encode each subfield
377 # if you don't do that, the record will have encoding mixed
378 # and the biblio will be re-encoded.
379 # strange, I (Paul P.) searched more than 1 day to understand what happends
380 # but could only solve the problem this way...
381 my @fields = $oldRecord->field( $itemtag );
382 foreach my $fielditem ( @fields ){
384 foreach ($fielditem->subfields()) {
386 $field->add_subfields(Encode::encode('utf-8',$_->[0]) => Encode::encode('utf-8',$_->[1]));
388 $field = MARC::Field->new("$itemtag",'','',Encode::encode('utf-8',$_->[0]) => Encode::encode('utf-8',$_->[1]));
391 $record->append_fields($field);
394 # adding biblionumber
395 my ($tag_biblionumber, $subfield_biblionumber) = GetMarcFromKohaField('biblio.biblionumber',$frameworkcode);
396 if ($tag_biblionumber < 10) {
397 $record->append_fields(
399 $tag_biblionumber, $biblionumber
401 ) unless $record->field($tag_biblionumber);
403 $record->append_fields(
405 $tag_biblionumber,'','',$subfield_biblionumber => $biblionumber
407 ) unless ($record->subfield($tag_biblionumber,$subfield_biblionumber));
409 # update the MARC record (that now contains biblio and items) with the new record data
410 &ModBiblioMarc( $record, $biblionumber, $frameworkcode );
412 # load the koha-table data object
413 my $oldbiblio = TransformMarcToKoha( $dbh, $record, $frameworkcode );
415 # modify the other koha tables
418 warn Dumper($oldbiblio);
420 _koha_modify_biblio( $dbh, $oldbiblio );
421 _koha_modify_biblioitem( $dbh, $oldbiblio );
429 Exported function (core API) for modifying an item in Koha.
436 my ( $record, $biblionumber, $itemnumber, $delete, $new_item_hashref )
440 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","MODIFY",$itemnumber,$record->as_formatted)
441 if C4::Context->preference("CataloguingLog");
443 my $dbh = C4::Context->dbh;
445 # if we have a MARC record, we're coming from cataloging and so
446 # we do the whole routine: update the MARC and zebra, then update the koha
449 my $frameworkcode = GetFrameworkCode( $biblionumber );
450 ModItemInMarc( $record, $biblionumber, $itemnumber, $frameworkcode );
451 my $olditem = TransformMarcToKoha( $dbh, $record, $frameworkcode,'items');
452 _koha_modify_item( $dbh, $olditem );
453 return $biblionumber;
456 # otherwise, we're just looking to modify something quickly
457 # (like a status) so we just update the koha tables
458 elsif ($new_item_hashref) {
459 _koha_modify_item( $dbh, $new_item_hashref );
463 sub ModItemTransfer {
464 my ( $itemnumber, $frombranch, $tobranch ) = @_;
466 my $dbh = C4::Context->dbh;
468 #new entry in branchtransfers....
469 my $sth = $dbh->prepare(
470 "INSERT INTO branchtransfers (itemnumber, frombranch, datesent, tobranch)
471 VALUES (?, ?, NOW(), ?)");
472 $sth->execute($itemnumber, $frombranch, $tobranch);
473 #update holdingbranch in items .....
475 "UPDATE items SET holdingbranch = ? WHERE items.itemnumber = ?");
476 $sth->execute($tobranch,$itemnumber);
477 &ModDateLastSeen($itemnumber);
478 $sth = $dbh->prepare(
479 "SELECT biblionumber FROM items WHERE itemnumber=?"
481 $sth->execute($itemnumber);
482 while ( my ( $biblionumber ) = $sth->fetchrow ) {
483 &ModItemInMarconefield( $biblionumber, $itemnumber,
484 'items.holdingbranch', $tobranch );
489 =head2 ModBiblioframework
491 ModBiblioframework($biblionumber,$frameworkcode);
492 Exported function to modify a biblio framework
496 sub ModBiblioframework {
497 my ( $biblionumber, $frameworkcode ) = @_;
498 my $dbh = C4::Context->dbh;
499 my $sth = $dbh->prepare(
500 "UPDATE biblio SET frameworkcode=? WHERE biblionumber=$biblionumber"
502 $sth->execute($frameworkcode);
506 =head2 ModItemInMarconefield
510 modify only 1 field in a MARC item (mainly used for holdingbranch, but could also be used for status modif - moving a book to "lost" on a long overdu for example)
511 &ModItemInMarconefield( $biblionumber, $itemnumber, $itemfield, $newvalue )
517 sub ModItemInMarconefield {
518 my ( $biblionumber, $itemnumber, $itemfield, $newvalue ) = @_;
519 my $dbh = C4::Context->dbh;
520 if ( !defined $newvalue ) {
524 my $record = GetMarcItem( $biblionumber, $itemnumber );
525 my ($tagfield, $tagsubfield) = GetMarcFromKohaField( $itemfield,'');
526 if ($tagfield && $tagsubfield) {
527 my $tag = $record->field($tagfield);
529 # my $tagsubs = $record->field($tagfield)->subfield($tagsubfield);
530 $tag->update( $tagsubfield => $newvalue );
531 $record->delete_field($tag);
532 $record->insert_fields_ordered($tag);
533 &ModItemInMarc( $record, $biblionumber, $itemnumber, 0 );
542 &ModItemInMarc( $record, $biblionumber, $itemnumber )
549 my ( $ItemRecord, $biblionumber, $itemnumber, $frameworkcode) = @_;
550 my $dbh = C4::Context->dbh;
552 # get complete MARC record & replace the item field by the new one
553 my $completeRecord = GetMarcBiblio($biblionumber);
554 my ($itemtag,$itemsubfield) = GetMarcFromKohaField("items.itemnumber",$frameworkcode);
555 my $itemField = $ItemRecord->field($itemtag);
556 my @items = $completeRecord->field($itemtag);
558 if ($_->subfield($itemsubfield) eq $itemnumber) {
559 # $completeRecord->delete_field($_);
560 $_->replace_with($itemField);
564 my $sth = $dbh->prepare("UPDATE biblioitems SET marc=?,marcxml=? WHERE biblionumber=?");
565 $sth->execute( $completeRecord->as_usmarc(), $completeRecord->as_xml_record(),$biblionumber );
567 ModZebra($biblionumber,"specialUpdate","biblioserver",$completeRecord);
570 =head2 ModDateLastSeen
572 &ModDateLastSeen($itemnum)
573 Mark item as seen. Is called when an item is issued, returned or manually marked during inventory/stocktaking
574 C<$itemnum> is the item number
578 sub ModDateLastSeen {
580 my $dbh = C4::Context->dbh;
583 "UPDATE items SET itemlost=0,datelastseen = NOW() WHERE items.itemnumber = ?"
585 $sth->execute($itemnum);
592 my $error = &DelBiblio($dbh,$biblionumber);
593 Exported function (core API) for deleting a biblio in koha.
594 Deletes biblio record from Zebra and Koha tables (biblio,biblioitems,items)
595 Also backs it up to deleted* tables
596 Checks to make sure there are not issues on any of the items
598 C<$error> : undef unless an error occurs
605 my ( $biblionumber ) = @_;
606 my $dbh = C4::Context->dbh;
607 my $error; # for error handling
609 # First make sure this biblio has no items attached
610 my $sth = $dbh->prepare("SELECT itemnumber FROM items WHERE biblionumber=?");
611 $sth->execute($biblionumber);
612 if (my $itemnumber = $sth->fetchrow){
613 # Fix this to use a status the template can understand
614 $error .= "This Biblio has items attached, please delete them first before deleting this biblio ";
617 return $error if $error;
619 # Delete in Zebra. Be careful NOT to move this line after _koha_delete_biblio
620 # for at least 2 reasons :
621 # - we need to read the biblio if NoZebra is set (to remove it from the indexes
622 # - if something goes wrong, the biblio may be deleted from Koha but not from zebra
623 # and we would have no way to remove it (except manually in zebra, but I bet it would be very hard to handle the problem)
624 ModZebra($biblionumber, "delete_record", "biblioserver", undef);
626 # delete biblio from Koha tables and save in deletedbiblio
627 $error = &_koha_delete_biblio( $dbh, $biblionumber );
629 # delete biblioitems and items from Koha tables and save in deletedbiblioitems,deleteditems
632 "SELECT biblioitemnumber FROM biblioitems WHERE biblionumber=?");
633 $sth->execute($biblionumber);
634 while ( my $biblioitemnumber = $sth->fetchrow ) {
636 # delete this biblioitem
637 $error = &_koha_delete_biblioitems( $dbh, $biblioitemnumber );
638 return $error if $error;
640 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","DELETE",$biblionumber,"")
641 if C4::Context->preference("CataloguingLog");
649 DelItem( $biblionumber, $itemnumber );
650 Exported function (core API) for deleting an item record in Koha.
657 my ( $dbh, $biblionumber, $itemnumber ) = @_;
658 my $dbh = C4::Context->dbh;
660 # check the item has no current issues
663 &_koha_delete_item( $dbh, $itemnumber );
665 # get the MARC record
666 my $record = GetMarcBiblio($biblionumber);
667 my $frameworkcode = GetFrameworkCode($biblionumber);
670 my $copy2deleted = $dbh->prepare("UPDATE deleteditems SET marc=? WHERE itemnumber=?");
671 $copy2deleted->execute( $record->as_usmarc(), $itemnumber );
673 #search item field code
674 my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField("items.itemnumber",$frameworkcode);
675 my @fields = $record->field($itemtag);
677 # delete the item specified
678 foreach my $field (@fields) {
679 if ( $field->subfield($itemsubfield) eq $itemnumber ) {
680 $record->delete_field($field);
683 &ModBiblioMarc( $record, $biblionumber, $frameworkcode );
684 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","DELETE",$itemnumber,"item")
685 if C4::Context->preference("CataloguingLog");
692 $data = &GetBiblioData($biblionumber);
693 Returns information about the book with the given biblionumber.
694 C<&GetBiblioData> returns a reference-to-hash. The keys are the fields in
695 the C<biblio> and C<biblioitems> tables in the
697 In addition, C<$data-E<gt>{subject}> is the list of the book's
698 subjects, separated by C<" , "> (space, comma, space).
699 If there are multiple biblioitems with the given biblionumber, only
700 the first one is considered.
708 my $dbh = C4::Context->dbh;
711 SELECT * , biblioitems.notes AS bnotes, itemtypes.notforloan as bi_notforloan, biblio.notes
713 LEFT JOIN biblioitems ON biblio.biblionumber = biblioitems.biblionumber
714 LEFT JOIN itemtypes ON biblioitems.itemtype = itemtypes.itemtype
715 WHERE biblio.biblionumber = ?
716 AND biblioitems.biblionumber = biblio.biblionumber
718 my $sth = $dbh->prepare($query);
719 $sth->execute($bibnum);
721 $data = $sth->fetchrow_hashref;
725 } # sub GetBiblioData
732 @results = &GetItemsInfo($biblionumber, $type);
734 Returns information about books with the given biblionumber.
736 C<$type> may be either C<intra> or anything else. If it is not set to
737 C<intra>, then the search will exclude lost, very overdue, and
740 C<&GetItemsInfo> returns a list of references-to-hash. Each element
741 contains a number of keys. Most of them are table items from the
742 C<biblio>, C<biblioitems>, C<items>, and C<itemtypes> tables in the
743 Koha database. Other keys include:
747 =item C<$data-E<gt>{branchname}>
749 The name (not the code) of the branch to which the book belongs.
751 =item C<$data-E<gt>{datelastseen}>
753 This is simply C<items.datelastseen>, except that while the date is
754 stored in YYYY-MM-DD format in the database, here it is converted to
755 DD/MM/YYYY format. A NULL date is returned as C<//>.
757 =item C<$data-E<gt>{datedue}>
759 =item C<$data-E<gt>{class}>
761 This is the concatenation of C<biblioitems.classification>, the book's
762 Dewey code, and C<biblioitems.subclass>.
764 =item C<$data-E<gt>{ocount}>
766 I think this is the number of copies of the book available.
768 =item C<$data-E<gt>{order}>
770 If this is set, it is set to C<One Order>.
779 my ( $biblionumber, $type ) = @_;
780 my $dbh = C4::Context->dbh;
781 my $query = "SELECT *,items.notforloan as itemnotforloan
783 LEFT JOIN biblio ON biblio.biblionumber = items.biblionumber
784 LEFT JOIN biblioitems ON biblioitems.biblioitemnumber = items.biblioitemnumber
785 LEFT JOIN itemtypes on biblioitems.itemtype = itemtypes.itemtype
786 WHERE items.biblionumber = ?
787 ORDER BY items.dateaccessioned desc
789 my $sth = $dbh->prepare($query);
790 $sth->execute($biblionumber);
793 my ( $date_due, $count_reserves );
795 while ( my $data = $sth->fetchrow_hashref ) {
797 my $isth = $dbh->prepare(
798 "SELECT issues.*,borrowers.cardnumber,borrowers.surname,borrowers.firstname
799 FROM issues LEFT JOIN borrowers ON issues.borrowernumber=borrowers.borrowernumber
801 AND returndate IS NULL"
803 $isth->execute( $data->{'itemnumber'} );
804 if ( my $idata = $isth->fetchrow_hashref ) {
805 $data->{borrowernumber} = $idata->{borrowernumber};
806 $data->{cardnumber} = $idata->{cardnumber};
807 $data->{surname} = $idata->{surname};
808 $data->{firstname} = $idata->{firstname};
809 $datedue = format_date( $idata->{'date_due'} );
811 if ( $datedue eq '' ) {
812 #$datedue="Available";
813 my ( $restype, $reserves ) =
814 C4::Reserves::CheckReserves( $data->{'itemnumber'} );
818 $count_reserves = $restype;
823 #get branch information.....
824 my $bsth = $dbh->prepare(
825 "SELECT * FROM branches WHERE branchcode = ?
828 $bsth->execute( $data->{'holdingbranch'} );
829 if ( my $bdata = $bsth->fetchrow_hashref ) {
830 $data->{'branchname'} = $bdata->{'branchname'};
832 my $date = format_date( $data->{'datelastseen'} );
833 $data->{'datelastseen'} = $date;
834 $data->{'datedue'} = $datedue;
835 $data->{'count_reserves'} = $count_reserves;
837 # get notforloan complete status if applicable
838 my $sthnflstatus = $dbh->prepare(
839 'SELECT authorised_value
840 FROM marc_subfield_structure
841 WHERE kohafield="items.notforloan"
845 $sthnflstatus->execute;
846 my ($authorised_valuecode) = $sthnflstatus->fetchrow;
847 if ($authorised_valuecode) {
848 $sthnflstatus = $dbh->prepare(
849 "SELECT lib FROM authorised_values
851 AND authorised_value=?"
853 $sthnflstatus->execute( $authorised_valuecode,
854 $data->{itemnotforloan} );
855 my ($lib) = $sthnflstatus->fetchrow;
856 $data->{notforloan} = $lib;
859 # my stack procedures
860 my $stackstatus = $dbh->prepare(
861 'SELECT authorised_value
862 FROM marc_subfield_structure
863 WHERE kohafield="items.stack"
866 $stackstatus->execute;
868 ($authorised_valuecode) = $stackstatus->fetchrow;
869 if ($authorised_valuecode) {
870 $stackstatus = $dbh->prepare(
872 FROM authorised_values
874 AND authorised_value=?
877 $stackstatus->execute( $authorised_valuecode, $data->{stack} );
878 my ($lib) = $stackstatus->fetchrow;
879 $data->{stack} = $lib;
881 $results[$i] = $data;
893 $itemstatushash = &getitemstatus($fwkcode);
894 returns information about status.
895 Can be MARC dependant.
897 But basically could be can be loan or not
898 Create a status selector with the following code
900 =head3 in PERL SCRIPT
902 my $itemstatushash = getitemstatus;
904 foreach my $thisstatus (keys %$itemstatushash) {
905 my %row =(value => $thisstatus,
906 statusname => $itemstatushash->{$thisstatus}->{'statusname'},
908 push @itemstatusloop, \%row;
910 $template->param(statusloop=>\@itemstatusloop);
915 <select name="statusloop">
916 <option value="">Default</option>
917 <!-- TMPL_LOOP name="statusloop" -->
918 <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="statusname" --></option>
926 # returns a reference to a hash of references to status...
929 my $dbh = C4::Context->dbh;
931 $fwk = '' unless ($fwk);
932 my ( $tag, $subfield ) =
933 GetMarcFromKohaField( "items.notforloan", $fwk );
934 if ( $tag and $subfield ) {
937 "SELECT authorised_value
938 FROM marc_subfield_structure
944 $sth->execute( $tag, $subfield, $fwk );
945 if ( my ($authorisedvaluecat) = $sth->fetchrow ) {
948 "SELECT authorised_value,lib
949 FROM authorised_values
954 $authvalsth->execute($authorisedvaluecat);
955 while ( my ( $authorisedvalue, $lib ) = $authvalsth->fetchrow ) {
956 $itemstatus{$authorisedvalue} = $lib;
972 $itemstatus{"1"} = "Not For Loan";
976 =head2 getitemlocation
980 $itemlochash = &getitemlocation($fwk);
981 returns informations about location.
982 where fwk stands for an optional framework code.
983 Create a location selector with the following code
985 =head3 in PERL SCRIPT
987 my $itemlochash = getitemlocation;
989 foreach my $thisloc (keys %$itemlochash) {
990 my $selected = 1 if $thisbranch eq $branch;
991 my %row =(locval => $thisloc,
992 selected => $selected,
993 locname => $itemlochash->{$thisloc},
995 push @itemlocloop, \%row;
997 $template->param(itemlocationloop => \@itemlocloop);
1001 <select name="location">
1002 <option value="">Default</option>
1003 <!-- TMPL_LOOP name="itemlocationloop" -->
1004 <option value="<!-- TMPL_VAR name="locval" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="locname" --></option>
1012 sub GetItemLocation {
1014 # returns a reference to a hash of references to location...
1017 my $dbh = C4::Context->dbh;
1019 $fwk = '' unless ($fwk);
1020 my ( $tag, $subfield ) =
1021 GetMarcFromKohaField( "items.location", $fwk );
1022 if ( $tag and $subfield ) {
1025 "SELECT authorised_value
1026 FROM marc_subfield_structure
1029 AND frameworkcode=?"
1031 $sth->execute( $tag, $subfield, $fwk );
1032 if ( my ($authorisedvaluecat) = $sth->fetchrow ) {
1035 "SELECT authorised_value,lib
1036 FROM authorised_values
1040 $authvalsth->execute($authorisedvaluecat);
1041 while ( my ( $authorisedvalue, $lib ) = $authvalsth->fetchrow ) {
1042 $itemlocation{$authorisedvalue} = $lib;
1044 $authvalsth->finish;
1045 return \%itemlocation;
1058 $itemlocation{"1"} = "Not For Loan";
1059 return \%itemlocation;
1064 $items = GetLostItems($where,$orderby);
1066 This function get the items lost into C<$items>.
1071 C<$where> is a hashref. it containts a field of the items table as key
1072 and the value to match as value.
1073 C<$orderby> is a field of the items table.
1076 C<$items> is a reference to an array full of hasref which keys are items' table column.
1078 =item usage in the perl script:
1081 $where{barcode} = 0001548;
1082 my $items = GetLostItems( \%where, "homebranch" );
1083 $template->param(itemsloop => $items);
1090 # Getting input args.
1092 my $orderby = shift;
1093 my $dbh = C4::Context->dbh;
1098 WHERE itemlost IS NOT NULL
1101 foreach my $key (keys %$where) {
1102 $query .= " AND " . $key . " LIKE '%" . $where->{$key} . "%'";
1104 $query .= " ORDER BY ".$orderby if defined $orderby;
1106 my $sth = $dbh->prepare($query);
1109 while ( my $row = $sth->fetchrow_hashref ){
1115 =head2 GetItemsForInventory
1117 $itemlist = GetItemsForInventory($minlocation,$maxlocation,$datelastseen,$offset,$size)
1119 Retrieve a list of title/authors/barcode/callnumber, for biblio inventory.
1121 The sub returns a list of hashes, containing itemnumber, author, title, barcode & item callnumber.
1122 It is ordered by callnumber,title.
1124 The minlocation & maxlocation parameters are used to specify a range of item callnumbers
1125 the datelastseen can be used to specify that you want to see items not seen since a past date only.
1126 offset & size can be used to retrieve only a part of the whole listing (defaut behaviour)
1130 sub GetItemsForInventory {
1131 my ( $minlocation, $maxlocation,$location, $datelastseen, $branch, $offset, $size ) = @_;
1132 my $dbh = C4::Context->dbh;
1134 if ($datelastseen) {
1135 $datelastseen=format_date_in_iso($datelastseen);
1137 "SELECT itemnumber,barcode,itemcallnumber,title,author,biblio.biblionumber,datelastseen
1139 LEFT JOIN biblio ON items.biblionumber=biblio.biblionumber
1140 WHERE itemcallnumber>= ?
1141 AND itemcallnumber <=?
1142 AND (datelastseen< ? OR datelastseen IS NULL)";
1143 $query.= " AND items.location=".$dbh->quote($location) if $location;
1144 $query.= " AND items.homebranch=".$dbh->quote($branch) if $branch;
1145 $query .= " ORDER BY itemcallnumber,title";
1146 $sth = $dbh->prepare($query);
1147 $sth->execute( $minlocation, $maxlocation, $datelastseen );
1151 SELECT itemnumber,barcode,itemcallnumber,biblio.biblionumber,title,author,datelastseen
1153 LEFT JOIN biblio ON items.biblionumber=biblio.biblionumber
1154 WHERE itemcallnumber>= ?
1155 AND itemcallnumber <=?";
1156 $query.= " AND items.location=".$dbh->quote($location) if $location;
1157 $query.= " AND items.homebranch=".$dbh->quote($branch) if $branch;
1158 $query .= " ORDER BY itemcallnumber,title";
1159 $sth = $dbh->prepare($query);
1160 $sth->execute( $minlocation, $maxlocation );
1163 while ( my $row = $sth->fetchrow_hashref ) {
1164 $offset-- if ($offset);
1165 $row->{datelastseen}=format_date($row->{datelastseen});
1166 if ( ( !$offset ) && $size ) {
1167 push @results, $row;
1174 =head2 &GetBiblioItemData
1178 $itemdata = &GetBiblioItemData($biblioitemnumber);
1180 Looks up the biblioitem with the given biblioitemnumber. Returns a
1181 reference-to-hash. The keys are the fields from the C<biblio>,
1182 C<biblioitems>, and C<itemtypes> tables in the Koha database, except
1183 that C<biblioitems.notes> is given as C<$itemdata-E<gt>{bnotes}>.
1190 sub GetBiblioItemData {
1191 my ($biblioitemnumber) = @_;
1192 my $dbh = C4::Context->dbh;
1195 "SELECT *,biblioitems.notes AS bnotes
1196 FROM biblioitems,biblio,itemtypes
1197 WHERE biblio.biblionumber = biblioitems.biblionumber
1198 AND biblioitemnumber = ? "
1201 $sth->execute($biblioitemnumber);
1202 $data = $sth->fetchrow_hashref;
1205 } # sub &GetBiblioItemData
1207 =head2 GetItemnumberFromBarcode
1211 $result = GetItemnumberFromBarcode($barcode);
1217 sub GetItemnumberFromBarcode {
1219 my $dbh = C4::Context->dbh;
1222 $dbh->prepare("SELECT itemnumber FROM items WHERE items.barcode=?");
1223 $rq->execute($barcode);
1224 my ($result) = $rq->fetchrow;
1228 =head2 GetBiblioItemByBiblioNumber
1232 NOTE : This function has been copy/paste from C4/Biblio.pm from head before zebra integration.
1238 sub GetBiblioItemByBiblioNumber {
1239 my ($biblionumber) = @_;
1240 my $dbh = C4::Context->dbh;
1241 my $sth = $dbh->prepare("Select * FROM biblioitems WHERE biblionumber = ?");
1245 $sth->execute($biblionumber);
1247 while ( my $data = $sth->fetchrow_hashref ) {
1248 push @results, $data;
1255 =head2 GetBiblioFromItemNumber
1259 $item = &GetBiblioFromItemNumber($itemnumber);
1261 Looks up the item with the given itemnumber.
1263 C<&itemnodata> returns a reference-to-hash whose keys are the fields
1264 from the C<biblio>, C<biblioitems>, and C<items> tables in the Koha
1272 sub GetBiblioFromItemNumber {
1273 my ( $itemnumber ) = @_;
1274 my $dbh = C4::Context->dbh;
1275 my $sth = $dbh->prepare(
1276 "SELECT * FROM items
1277 LEFT JOIN biblio ON biblio.biblionumber = items.biblionumber
1278 LEFT JOIN biblioitems ON biblioitems.biblioitemnumber = items.biblioitemnumber
1279 WHERE items.itemnumber = ?"
1282 $sth->execute($itemnumber);
1283 my $data = $sth->fetchrow_hashref;
1292 ( $count, @results ) = &GetBiblio($biblionumber);
1299 my ($biblionumber) = @_;
1300 my $dbh = C4::Context->dbh;
1301 my $sth = $dbh->prepare("SELECT * FROM biblio WHERE biblionumber = ?");
1304 $sth->execute($biblionumber);
1305 while ( my $data = $sth->fetchrow_hashref ) {
1306 $results[$count] = $data;
1310 return ( $count, @results );
1317 $data = &GetItem($itemnumber,$barcode);
1319 return Item information, for a given itemnumber or barcode
1326 my ($itemnumber,$barcode) = @_;
1327 my $dbh = C4::Context->dbh;
1329 my $sth = $dbh->prepare("
1331 WHERE itemnumber = ?");
1332 $sth->execute($itemnumber);
1333 my $data = $sth->fetchrow_hashref;
1336 my $sth = $dbh->prepare("
1340 $sth->execute($barcode);
1341 my $data = $sth->fetchrow_hashref;
1346 =head2 get_itemnumbers_of
1350 my @itemnumbers_of = get_itemnumbers_of(@biblionumbers);
1352 Given a list of biblionumbers, return the list of corresponding itemnumbers
1353 for each biblionumber.
1355 Return a reference on a hash where keys are biblionumbers and values are
1356 references on array of itemnumbers.
1362 sub get_itemnumbers_of {
1363 my @biblionumbers = @_;
1365 my $dbh = C4::Context->dbh;
1371 WHERE biblionumber IN (?' . ( ',?' x scalar @biblionumbers - 1 ) . ')
1373 my $sth = $dbh->prepare($query);
1374 $sth->execute(@biblionumbers);
1378 while ( my ( $itemnumber, $biblionumber ) = $sth->fetchrow_array ) {
1379 push @{ $itemnumbers_of{$biblionumber} }, $itemnumber;
1382 return \%itemnumbers_of;
1385 =head2 GetItemInfosOf
1389 GetItemInfosOf(@itemnumbers);
1395 sub GetItemInfosOf {
1396 my @itemnumbers = @_;
1401 WHERE itemnumber IN (' . join( ',', @itemnumbers ) . ')
1403 return get_infos_of( $query, 'itemnumber' );
1406 =head2 GetItemsByBiblioitemnumber
1410 GetItemsByBiblioitemnumber($biblioitemnumber);
1412 Returns an arrayref of hashrefs suitable for use in a TMPL_LOOP
1413 Called by moredetail.pl
1419 sub GetItemsByBiblioitemnumber {
1420 my ( $bibitem ) = @_;
1421 my $dbh = C4::Context->dbh;
1422 my $sth = $dbh->prepare("SELECT * FROM items WHERE items.biblioitemnumber = ?") || die $dbh->errstr;
1423 # Get all items attached to a biblioitem
1426 $sth->execute($bibitem) || die $sth->errstr;
1427 while ( my $data = $sth->fetchrow_hashref ) {
1428 # Foreach item, get circulation information
1429 my $sth2 = $dbh->prepare( "SELECT * FROM issues,borrowers
1430 WHERE itemnumber = ?
1431 AND returndate is NULL
1432 AND issues.borrowernumber = borrowers.borrowernumber"
1434 $sth2->execute( $data->{'itemnumber'} );
1435 if ( my $data2 = $sth2->fetchrow_hashref ) {
1436 # if item is out, set the due date and who it is out too
1437 $data->{'date_due'} = $data2->{'date_due'};
1438 $data->{'cardnumber'} = $data2->{'cardnumber'};
1439 $data->{'borrowernumber'} = $data2->{'borrowernumber'};
1442 # set date_due to blank, so in the template we check itemlost, and wthdrawn
1443 $data->{'date_due'} = '';
1446 # Find the last 3 people who borrowed this item.
1447 my $query2 = "SELECT * FROM issues, borrowers WHERE itemnumber = ?
1448 AND issues.borrowernumber = borrowers.borrowernumber
1449 AND returndate is not NULL
1450 ORDER BY returndate desc,timestamp desc LIMIT 3";
1451 $sth2 = $dbh->prepare($query2) || die $dbh->errstr;
1452 $sth2->execute( $data->{'itemnumber'} ) || die $sth2->errstr;
1454 while ( my $data2 = $sth2->fetchrow_hashref ) {
1455 $data->{"timestamp$i2"} = $data2->{'timestamp'};
1456 $data->{"card$i2"} = $data2->{'cardnumber'};
1457 $data->{"borrower$i2"} = $data2->{'borrowernumber'};
1461 push(@results,$data);
1468 =head2 GetBiblioItemInfosOf
1472 GetBiblioItemInfosOf(@biblioitemnumbers);
1478 sub GetBiblioItemInfosOf {
1479 my @biblioitemnumbers = @_;
1482 SELECT biblioitemnumber,
1486 WHERE biblioitemnumber IN (' . join( ',', @biblioitemnumbers ) . ')
1488 return get_infos_of( $query, 'biblioitemnumber' );
1491 =head1 FUNCTIONS FOR HANDLING MARC MANAGEMENT
1493 =head2 GetMarcStructure
1497 $res = GetMarcStructure($forlibrarian,$frameworkcode);
1499 Returns a reference to a big hash of hash, with the Marc structure for the given frameworkcode
1500 $forlibrarian :if set to 1, the MARC descriptions are the librarians ones, otherwise it's the public (OPAC) ones
1501 $frameworkcode : the framework code to read
1507 sub GetMarcStructure {
1508 my ( $forlibrarian, $frameworkcode ) = @_;
1509 my $dbh=C4::Context->dbh;
1510 $frameworkcode = "" unless $frameworkcode;
1512 my $libfield = ( $forlibrarian eq 1 ) ? 'liblibrarian' : 'libopac';
1514 # check that framework exists
1517 "SELECT COUNT(*) FROM marc_tag_structure WHERE frameworkcode=?");
1518 $sth->execute($frameworkcode);
1519 my ($total) = $sth->fetchrow;
1520 $frameworkcode = "" unless ( $total > 0 );
1523 "SELECT tagfield,liblibrarian,libopac,mandatory,repeatable
1524 FROM marc_tag_structure
1525 WHERE frameworkcode=?
1528 $sth->execute($frameworkcode);
1529 my ( $liblibrarian, $libopac, $tag, $res, $tab, $mandatory, $repeatable );
1531 while ( ( $tag, $liblibrarian, $libopac, $mandatory, $repeatable ) =
1534 $res->{$tag}->{lib} =
1535 ( $forlibrarian or !$libopac ) ? $liblibrarian : $libopac;
1536 $res->{$tab}->{tab} = "";
1537 $res->{$tag}->{mandatory} = $mandatory;
1538 $res->{$tag}->{repeatable} = $repeatable;
1543 "SELECT tagfield,tagsubfield,liblibrarian,libopac,tab,mandatory,repeatable,authorised_value,authtypecode,value_builder,kohafield,seealso,hidden,isurl,link,defaultvalue
1544 FROM marc_subfield_structure
1545 WHERE frameworkcode=?
1546 ORDER BY tagfield,tagsubfield
1550 $sth->execute($frameworkcode);
1553 my $authorised_value;
1565 $tag, $subfield, $liblibrarian,
1567 $mandatory, $repeatable, $authorised_value,
1568 $authtypecode, $value_builder, $kohafield,
1569 $seealso, $hidden, $isurl,
1575 $res->{$tag}->{$subfield}->{lib} =
1576 ( $forlibrarian or !$libopac ) ? $liblibrarian : $libopac;
1577 $res->{$tag}->{$subfield}->{tab} = $tab;
1578 $res->{$tag}->{$subfield}->{mandatory} = $mandatory;
1579 $res->{$tag}->{$subfield}->{repeatable} = $repeatable;
1580 $res->{$tag}->{$subfield}->{authorised_value} = $authorised_value;
1581 $res->{$tag}->{$subfield}->{authtypecode} = $authtypecode;
1582 $res->{$tag}->{$subfield}->{value_builder} = $value_builder;
1583 $res->{$tag}->{$subfield}->{kohafield} = $kohafield;
1584 $res->{$tag}->{$subfield}->{seealso} = $seealso;
1585 $res->{$tag}->{$subfield}->{hidden} = $hidden;
1586 $res->{$tag}->{$subfield}->{isurl} = $isurl;
1587 $res->{$tag}->{$subfield}->{'link'} = $link;
1588 $res->{$tag}->{$subfield}->{defaultvalue} = $defaultvalue;
1593 =head2 GetUsedMarcStructure
1595 the same function as GetMarcStructure expcet it just take field
1596 in tab 0-9. (used field)
1598 my $results = GetUsedMarcStructure($frameworkcode);
1600 L<$results> is a ref to an array which each case containts a ref
1601 to a hash which each keys is the columns from marc_subfield_structure
1603 L<$frameworkcode> is the framework code.
1607 sub GetUsedMarcStructure($){
1608 my $frameworkcode = shift || '';
1609 my $dbh = C4::Context->dbh;
1612 FROM marc_subfield_structure
1614 AND frameworkcode = ?
1617 my $sth = $dbh->prepare($query);
1618 $sth->execute($frameworkcode);
1619 while (my $row = $sth->fetchrow_hashref){
1625 =head2 GetMarcFromKohaField
1629 ($MARCfield,$MARCsubfield)=GetMarcFromKohaField($kohafield,$frameworkcode);
1630 Returns the MARC fields & subfields mapped to the koha field
1631 for the given frameworkcode
1637 sub GetMarcFromKohaField {
1638 my ( $kohafield, $frameworkcode ) = @_;
1639 return 0, 0 unless $kohafield;
1640 my $relations = C4::Context->marcfromkohafield;
1642 $relations->{$frameworkcode}->{$kohafield}->[0],
1643 $relations->{$frameworkcode}->{$kohafield}->[1]
1647 =head2 GetMarcBiblio
1651 Returns MARC::Record of the biblionumber passed in parameter.
1652 the marc record contains both biblio & item datas
1659 my $biblionumber = shift;
1660 my $dbh = C4::Context->dbh;
1662 $dbh->prepare("SELECT marcxml FROM biblioitems WHERE biblionumber=? ");
1663 $sth->execute($biblionumber);
1664 my ($marcxml) = $sth->fetchrow;
1665 MARC::File::XML->default_record_format(C4::Context->preference('marcflavour'));
1666 $marcxml =~ s/\x1e//g;
1667 $marcxml =~ s/\x1f//g;
1668 $marcxml =~ s/\x1d//g;
1669 $marcxml =~ s/\x0f//g;
1670 $marcxml =~ s/\x0c//g;
1672 my $record = MARC::Record->new();
1674 $record = eval {MARC::Record::new_from_xml( $marcxml, "utf8",C4::Context->preference('marcflavour'))} if ($marcxml);
1676 # $record = MARC::Record::new_from_usmarc( $marc) if $marc;
1684 my $marcxml = GetXmlBiblio($biblionumber);
1686 Returns biblioitems.marcxml of the biblionumber passed in parameter.
1687 The XML contains both biblio & item datas
1694 my ( $biblionumber ) = @_;
1695 my $dbh = C4::Context->dbh;
1697 $dbh->prepare("SELECT marcxml FROM biblioitems WHERE biblionumber=? ");
1698 $sth->execute($biblionumber);
1699 my ($marcxml) = $sth->fetchrow;
1703 =head2 GetAuthorisedValueDesc
1707 my $subfieldvalue =get_authorised_value_desc(
1708 $tag, $subf[$i][0],$subf[$i][1], '', $taglib);
1709 Retrieve the complete description for a given authorised value.
1715 sub GetAuthorisedValueDesc {
1716 my ( $tag, $subfield, $value, $framework, $tagslib ) = @_;
1717 my $dbh = C4::Context->dbh;
1720 if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq "branches" ) {
1721 return C4::Branch::GetBranchName($value);
1725 if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq "itemtypes" ) {
1726 return getitemtypeinfo($value)->{description};
1729 #---- "true" authorized value
1730 my $category = $tagslib->{$tag}->{$subfield}->{'authorised_value'};
1731 if ( $category ne "" ) {
1734 "SELECT lib FROM authorised_values WHERE category = ? AND authorised_value = ?"
1736 $sth->execute( $category, $value );
1737 my $data = $sth->fetchrow_hashref;
1738 return $data->{'lib'};
1741 return $value; # if nothing is found return the original value
1749 Returns MARC::Record of the item passed in parameter.
1756 my ( $biblionumber, $itemnumber ) = @_;
1757 my $dbh = C4::Context->dbh;
1758 my $newrecord = MARC::Record->new();
1759 my $marcflavour = C4::Context->preference('marcflavour');
1761 my $marcxml = GetXmlBiblio($biblionumber);
1762 my $record = MARC::Record->new();
1763 $record = MARC::Record::new_from_xml( $marcxml, "utf8", $marcflavour );
1764 # now, find where the itemnumber is stored & extract only the item
1765 my ( $itemnumberfield, $itemnumbersubfield ) =
1766 GetMarcFromKohaField( 'items.itemnumber', '' );
1767 my @fields = $record->field($itemnumberfield);
1768 foreach my $field (@fields) {
1769 if ( $field->subfield($itemnumbersubfield) eq $itemnumber ) {
1770 $newrecord->insert_fields_ordered($field);
1782 $marcnotesarray = GetMarcNotes( $record, $marcflavour );
1783 Get all notes from the MARC record and returns them in an array.
1784 The note are stored in differents places depending on MARC flavour
1791 my ( $record, $marcflavour ) = @_;
1793 if ( $marcflavour eq "MARC21" ) {
1796 else { # assume unimarc if not marc21
1803 foreach my $field ( $record->field($scope) ) {
1804 my $value = $field->as_string();
1805 if ( $note ne "" ) {
1806 $marcnote = { marcnote => $note, };
1807 push @marcnotes, $marcnote;
1810 if ( $note ne $value ) {
1811 $note = $note . " " . $value;
1816 $marcnote = { marcnote => $note };
1817 push @marcnotes, $marcnote; #load last tag into array
1820 } # end GetMarcNotes
1822 =head2 GetMarcSubjects
1826 $marcsubjcts = GetMarcSubjects($record,$marcflavour);
1827 Get all subjects from the MARC record and returns them in an array.
1828 The subjects are stored in differents places depending on MARC flavour
1834 sub GetMarcSubjects {
1835 my ( $record, $marcflavour ) = @_;
1836 my ( $mintag, $maxtag );
1837 if ( $marcflavour eq "MARC21" ) {
1841 else { # assume unimarc if not marc21
1848 foreach my $field ( $record->fields ) {
1849 next unless $field->tag() >= $mintag && $field->tag() <= $maxtag;
1850 my @subfields = $field->subfields();
1854 my $authoritysep=C4::Context->preference("authoritysep");
1855 for my $subject_subfield ( @subfields ) {
1857 $marcflavour ne 'MARC21'
1859 ($subject_subfield->[0] eq '3') or
1860 ($subject_subfield->[0] eq '4') or
1861 ($subject_subfield->[0] eq '5')
1867 my $code = $subject_subfield->[0];
1868 $label .= $subject_subfield->[1].$authoritysep unless ( $code == 9 );
1869 $link .= " and su-to:".$subject_subfield->[1] unless ( $code == 9 );
1871 $link = "an:".$subject_subfield->[1];
1875 $link =~ s/ and\ssu-to:$//;
1878 $label =~ s/$authoritysep$//;
1885 return \@marcsubjcts;
1886 } #end GetMarcSubjects
1888 =head2 GetMarcAuthors
1892 authors = GetMarcAuthors($record,$marcflavour);
1893 Get all authors from the MARC record and returns them in an array.
1894 The authors are stored in differents places depending on MARC flavour
1900 sub GetMarcAuthors {
1901 my ( $record, $marcflavour ) = @_;
1902 my ( $mintag, $maxtag );
1903 # tagslib useful for UNIMARC author reponsabilities
1904 my $tagslib = &GetMarcStructure( 1, '' ); # FIXME : we don't have the framework available, we take the default framework. May be bugguy on some setups, will be usually correct.
1905 if ( $marcflavour eq "MARC21" ) {
1909 elsif ( $marcflavour eq "UNIMARC" ) { # assume unimarc if not marc21
1918 foreach my $field ( $record->fields ) {
1919 next unless $field->tag() >= $mintag && $field->tag() <= $maxtag;
1921 my @subfields = $field->subfields();
1923 for my $authors_subfield (@subfields) {
1924 #unimarc-specific line
1925 next if ($marcflavour eq 'UNIMARC' and (($authors_subfield->[0] eq '3') or ($authors_subfield->[0] eq '5')));
1926 my $subfieldcode = $authors_subfield->[0];
1928 # deal with UNIMARC author responsibility
1929 if ( $marcflavour eq 'UNIMARC' and ($authors_subfield->[0] eq '4')) {
1930 $value = "(".GetAuthorisedValueDesc( $field->tag(), $authors_subfield->[0], $authors_subfield->[1], '', $tagslib ).")";
1932 $value = $authors_subfield->[1];
1934 $hash{tag} = $field->tag;
1935 $hash{value} .= $value . " " if ($subfieldcode != 9) ;
1936 $hash{link} .= $value if ($subfieldcode eq 9);
1938 push @marcauthors, \%hash;
1940 return \@marcauthors;
1947 $marcurls = GetMarcUrls($record,$marcflavour);
1948 Returns arrayref of URLs from MARC data, suitable to pass to tmpl loop.
1949 Assumes web resources (not uncommon in MARC21 to omit resource type ind)
1956 my ($record, $marcflavour) = @_;
1959 for my $field ($record->field('856')) {
1960 my $url = $field->subfield('u');
1962 for my $note ( $field->subfield('z')) {
1963 push @notes , {note => $note};
1965 $marcurl = { MARCURL => $url,
1968 if($marcflavour eq 'MARC21') {
1969 my $s3 = $field->subfield('3');
1970 my $link = $field->subfield('y');
1971 $marcurl->{'linktext'} = $link || $s3 || $url ;;
1972 $marcurl->{'part'} = $s3 if($link);
1973 $marcurl->{'toc'} = 1 if($s3 =~ /^[Tt]able/) ;
1975 $marcurl->{'linktext'} = $url;
1977 push @marcurls, $marcurl;
1982 =head2 GetMarcSeries
1986 $marcseriesarray = GetMarcSeries($record,$marcflavour);
1987 Get all series from the MARC record and returns them in an array.
1988 The series are stored in differents places depending on MARC flavour
1995 my ($record, $marcflavour) = @_;
1996 my ($mintag, $maxtag);
1997 if ($marcflavour eq "MARC21") {
2000 } else { # assume unimarc if not marc21
2010 foreach my $field ($record->field('440'), $record->field('490')) {
2012 #my $value = $field->subfield('a');
2013 #$marcsubjct = {MARCSUBJCT => $value,};
2014 my @subfields = $field->subfields();
2015 #warn "subfields:".join " ", @$subfields;
2018 for my $series_subfield (@subfields) {
2020 undef $volume_number;
2021 # see if this is an instance of a volume
2022 if ($series_subfield->[0] eq 'v') {
2026 my $code = $series_subfield->[0];
2027 my $value = $series_subfield->[1];
2028 my $linkvalue = $value;
2029 $linkvalue =~ s/(\(|\))//g;
2030 my $operator = " and " unless $counter==0;
2031 push @link_loop, {link => $linkvalue, operator => $operator };
2032 my $separator = C4::Context->preference("authoritysep") unless $counter==0;
2033 if ($volume_number) {
2034 push @subfields_loop, {volumenum => $value};
2037 push @subfields_loop, {code => $code, value => $value, link_loop => \@link_loop, separator => $separator, volumenum => $volume_number};
2041 push @marcseries, { MARCSERIES_SUBFIELDS_LOOP => \@subfields_loop };
2042 #$marcsubjct = {MARCSUBJCT => $field->as_string(),};
2043 #push @marcsubjcts, $marcsubjct;
2047 my $marcseriessarray=\@marcseries;
2048 return $marcseriessarray;
2049 } #end getMARCseriess
2051 =head2 GetFrameworkCode
2055 $frameworkcode = GetFrameworkCode( $biblionumber )
2061 sub GetFrameworkCode {
2062 my ( $biblionumber ) = @_;
2063 my $dbh = C4::Context->dbh;
2064 my $sth = $dbh->prepare("SELECT frameworkcode FROM biblio WHERE biblionumber=?");
2065 $sth->execute($biblionumber);
2066 my ($frameworkcode) = $sth->fetchrow;
2067 return $frameworkcode;
2070 =head2 GetPublisherNameFromIsbn
2072 $name = GetPublishercodeFromIsbn($isbn);
2079 sub GetPublisherNameFromIsbn($){
2081 $isbn =~ s/[- _]//g;
2083 my @codes = (split '-', DisplayISBN($isbn));
2084 my $code = $codes[0].$codes[1].$codes[2];
2085 my $dbh = C4::Context->dbh;
2087 SELECT distinct publishercode
2090 AND publishercode IS NOT NULL
2093 my $sth = $dbh->prepare($query);
2094 $sth->execute("$code%");
2095 my $name = $sth->fetchrow;
2096 return $name if length $name;
2100 =head2 TransformKohaToMarc
2104 $record = TransformKohaToMarc( $hash )
2105 This function builds partial MARC::Record from a hash
2106 Hash entries can be from biblio or biblioitems.
2107 This function is called in acquisition module, to create a basic catalogue entry from user entry
2113 sub TransformKohaToMarc {
2116 my $dbh = C4::Context->dbh;
2119 "SELECT tagfield,tagsubfield FROM marc_subfield_structure WHERE frameworkcode=? AND kohafield=?"
2121 my $record = MARC::Record->new();
2122 foreach (keys %{$hash}) {
2123 &TransformKohaToMarcOneField( $sth, $record, $_,
2129 =head2 TransformKohaToMarcOneField
2133 $record = TransformKohaToMarcOneField( $sth, $record, $kohafieldname, $value, $frameworkcode );
2139 sub TransformKohaToMarcOneField {
2140 my ( $sth, $record, $kohafieldname, $value, $frameworkcode ) = @_;
2141 $frameworkcode='' unless $frameworkcode;
2145 if ( !defined $sth ) {
2146 my $dbh = C4::Context->dbh;
2147 $sth = $dbh->prepare(
2148 "SELECT tagfield,tagsubfield FROM marc_subfield_structure WHERE frameworkcode=? AND kohafield=?"
2151 $sth->execute( $frameworkcode, $kohafieldname );
2152 if ( ( $tagfield, $tagsubfield ) = $sth->fetchrow ) {
2153 my $tag = $record->field($tagfield);
2155 $tag->update( $tagsubfield => $value );
2156 $record->delete_field($tag);
2157 $record->insert_fields_ordered($tag);
2160 $record->add_fields( $tagfield, " ", " ", $tagsubfield => $value );
2166 =head2 TransformHtmlToXml
2170 $xml = TransformHtmlToXml( $tags, $subfields, $values, $indicator, $ind_tag, $auth_type )
2172 $auth_type contains :
2173 - nothing : rebuild a biblio, un UNIMARC the encoding is in 100$a pos 26/27
2174 - UNIMARCAUTH : rebuild an authority. In UNIMARC, the encoding is in 100$a pos 13/14
2175 - ITEM : rebuild an item : in UNIMARC, 100$a, it's in the biblio ! (otherwise, we would get 2 100 fields !)
2181 sub TransformHtmlToXml {
2182 my ( $tags, $subfields, $values, $indicator, $ind_tag, $auth_type ) = @_;
2183 my $xml = MARC::File::XML::header('UTF-8');
2184 $auth_type = C4::Context->preference('marcflavour') unless $auth_type;
2185 MARC::File::XML->default_record_format($auth_type);
2186 # in UNIMARC, field 100 contains the encoding
2187 # check that there is one, otherwise the
2188 # MARC::Record->new_from_xml will fail (and Koha will die)
2189 my $unimarc_and_100_exist=0;
2190 $unimarc_and_100_exist=1 if $auth_type eq 'ITEM'; # if we rebuild an item, no need of a 100 field
2195 for ( my $i = 0 ; $i <= @$tags ; $i++ ) {
2196 if (C4::Context->preference('marcflavour') eq 'UNIMARC' and @$tags[$i] eq "100" and @$subfields[$i] eq "a") {
2197 # if we have a 100 field and it's values are not correct, skip them.
2198 # if we don't have any valid 100 field, we will create a default one at the end
2199 my $enc = substr( @$values[$i], 26, 2 );
2200 if ($enc eq '01' or $enc eq '50' or $enc eq '03') {
2201 $unimarc_and_100_exist=1;
2206 @$values[$i] =~ s/&/&/g;
2207 @$values[$i] =~ s/</</g;
2208 @$values[$i] =~ s/>/>/g;
2209 @$values[$i] =~ s/"/"/g;
2210 @$values[$i] =~ s/'/'/g;
2211 # if ( !utf8::is_utf8( @$values[$i] ) ) {
2212 # utf8::decode( @$values[$i] );
2214 if ( ( @$tags[$i] ne $prevtag ) ) {
2215 $j++ unless ( @$tags[$i] eq "" );
2217 $xml .= "</datafield>\n";
2218 if ( ( @$tags[$i] && @$tags[$i] > 10 )
2219 && ( @$values[$i] ne "" ) )
2221 my $ind1 = substr( @$indicator[$j], 0, 1 );
2223 if ( @$indicator[$j] ) {
2224 $ind2 = substr( @$indicator[$j], 1, 1 );
2227 warn "Indicator in @$tags[$i] is empty";
2231 "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
2233 "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
2241 if ( @$values[$i] ne "" ) {
2244 if ( @$tags[$i] eq "000" ) {
2245 $xml .= "<leader>@$values[$i]</leader>\n";
2248 # rest of the fixed fields
2250 elsif ( @$tags[$i] < 10 ) {
2252 "<controlfield tag=\"@$tags[$i]\">@$values[$i]</controlfield>\n";
2256 my $ind1 = substr( @$indicator[$j], 0, 1 );
2257 my $ind2 = substr( @$indicator[$j], 1, 1 );
2259 "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
2261 "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
2267 else { # @$tags[$i] eq $prevtag
2268 if ( @$values[$i] eq "" ) {
2272 my $ind1 = substr( @$indicator[$j], 0, 1 );
2273 my $ind2 = substr( @$indicator[$j], 1, 1 );
2275 "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
2279 "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
2282 $prevtag = @$tags[$i];
2284 if (C4::Context->preference('marcflavour') and !$unimarc_and_100_exist) {
2285 # warn "SETTING 100 for $auth_type";
2286 use POSIX qw(strftime);
2287 my $string = strftime( "%Y%m%d", localtime(time) );
2288 # set 50 to position 26 is biblios, 13 if authorities
2290 $pos=13 if $auth_type eq 'UNIMARCAUTH';
2291 $string = sprintf( "%-*s", 35, $string );
2292 substr( $string, $pos , 6, "50" );
2293 $xml .= "<datafield tag=\"100\" ind1=\"\" ind2=\"\">\n";
2294 $xml .= "<subfield code=\"a\">$string</subfield>\n";
2295 $xml .= "</datafield>\n";
2297 $xml .= MARC::File::XML::footer();
2301 =head2 TransformHtmlToMarc
2303 L<$record> = TransformHtmlToMarc(L<$params>,L<$cgi>)
2304 L<$params> is a ref to an array as below:
2306 'tag_010_indicator_531951' ,
2307 'tag_010_code_a_531951_145735' ,
2308 'tag_010_subfield_a_531951_145735' ,
2309 'tag_200_indicator_873510' ,
2310 'tag_200_code_a_873510_673465' ,
2311 'tag_200_subfield_a_873510_673465' ,
2312 'tag_200_code_b_873510_704318' ,
2313 'tag_200_subfield_b_873510_704318' ,
2314 'tag_200_code_e_873510_280822' ,
2315 'tag_200_subfield_e_873510_280822' ,
2316 'tag_200_code_f_873510_110730' ,
2317 'tag_200_subfield_f_873510_110730' ,
2319 L<$cgi> is the CGI object which containts the value.
2320 L<$record> is the MARC::Record object.
2324 sub TransformHtmlToMarc {
2328 # creating a new record
2329 my $record = MARC::Record->new();
2332 while ($params->[$i]){ # browse all CGI params
2333 my $param = $params->[$i];
2335 # if we are on biblionumber, store it in the MARC::Record (it may not be in the edited fields)
2336 if ($param eq 'biblionumber') {
2337 my ( $biblionumbertagfield, $biblionumbertagsubfield ) =
2338 &GetMarcFromKohaField( "biblio.biblionumber", '' );
2339 if ($biblionumbertagfield < 10) {
2340 $newfield = MARC::Field->new(
2341 $biblionumbertagfield,
2342 $cgi->param($param),
2345 $newfield = MARC::Field->new(
2346 $biblionumbertagfield,
2349 "$biblionumbertagsubfield" => $cgi->param($param),
2352 push @fields,$newfield if($newfield);
2354 elsif ($param =~ /^tag_(\d*)_indicator_/){ # new field start when having 'input name="..._indicator_..."
2357 my $ind1 = substr($cgi->param($param),0,1);
2358 my $ind2 = substr($cgi->param($param),1,1);
2362 if($tag < 10){ # no code for theses fields
2363 # in MARC editor, 000 contains the leader.
2364 if ($tag eq '000' ) {
2365 $record->leader($cgi->param($params->[$j+1])) if length($cgi->param($params->[$j+1]))==24;
2366 # between 001 and 009 (included)
2368 $newfield = MARC::Field->new(
2370 $cgi->param($params->[$j+1]),
2373 # > 009, deal with subfields
2375 while($params->[$j] =~ /_code_/){ # browse all it's subfield
2376 my $inner_param = $params->[$j];
2378 if($cgi->param($params->[$j+1])){ # only if there is a value (code => value)
2379 $newfield->add_subfields(
2380 $cgi->param($inner_param) => $cgi->param($params->[$j+1])
2384 if ( $cgi->param($params->[$j+1]) ) { # creating only if there is a value (code => value)
2385 $newfield = MARC::Field->new(
2389 $cgi->param($inner_param) => $cgi->param($params->[$j+1]),
2396 push @fields,$newfield if($newfield);
2401 $record->append_fields(@fields);
2405 =head2 TransformMarcToKoha
2409 $result = TransformMarcToKoha( $dbh, $record, $frameworkcode )
2415 sub TransformMarcToKoha {
2416 my ( $dbh, $record, $frameworkcode, $table ) = @_;
2419 # sometimes we only want to return the items data
2420 if ($table eq 'items') {
2421 my $sth = $dbh->prepare("SHOW COLUMNS FROM items");
2423 while ( (my $field) = $sth->fetchrow ) {
2424 $result = &TransformMarcToKohaOneField( "items", $field, $record, $result, $frameworkcode );
2429 my $sth2 = $dbh->prepare("SHOW COLUMNS FROM biblio");
2432 while ( ($field) = $sth2->fetchrow ) {
2433 $result = &TransformMarcToKohaOneField( "biblio", $field, $record, $result, $frameworkcode );
2435 my $sth2 = $dbh->prepare("SHOW COLUMNS FROM biblioitems");
2437 while ( ($field) = $sth2->fetchrow ) {
2438 if ( $field eq 'notes' ) { $field = 'bnotes'; }
2439 $result = &TransformMarcToKohaOneField( "biblioitems", $field, $record, $result, $frameworkcode );
2441 $sth2 = $dbh->prepare("SHOW COLUMNS FROM items");
2443 while ( ($field) = $sth2->fetchrow ) {
2444 $result = &TransformMarcToKohaOneField( "items", $field, $record, $result, $frameworkcode );
2447 # modify copyrightdate to keep only the 1st year found
2448 my $temp = $result->{'copyrightdate'};
2449 $temp =~ m/c(\d\d\d\d)/; # search cYYYY first
2451 $result->{'copyrightdate'} = $1;
2453 else { # if no cYYYY, get the 1st date.
2454 $temp =~ m/(\d\d\d\d)/;
2455 $result->{'copyrightdate'} = $1;
2458 # modify publicationyear to keep only the 1st year found
2459 $temp = $result->{'publicationyear'};
2460 $temp =~ m/c(\d\d\d\d)/; # search cYYYY first
2462 $result->{'publicationyear'} = $1;
2464 else { # if no cYYYY, get the 1st date.
2465 $temp =~ m/(\d\d\d\d)/;
2466 $result->{'publicationyear'} = $1;
2471 =head2 TransformMarcToKohaOneField
2475 $result = TransformMarcToKohaOneField( $kohatable, $kohafield, $record, $result, $frameworkcode )
2481 sub TransformMarcToKohaOneField {
2483 # FIXME ? if a field has a repeatable subfield that is used in old-db,
2484 # only the 1st will be retrieved...
2485 my ( $kohatable, $kohafield, $record, $result, $frameworkcode ) = @_;
2487 my ( $tagfield, $subfield ) =
2488 GetMarcFromKohaField( $kohatable . "." . $kohafield,
2490 foreach my $field ( $record->field($tagfield) ) {
2491 if ( $field->tag() < 10 ) {
2492 if ( $result->{$kohafield} ) {
2493 $result->{$kohafield} .= " | " . $field->data();
2496 $result->{$kohafield} = $field->data();
2500 if ( $field->subfields ) {
2501 my @subfields = $field->subfields();
2502 foreach my $subfieldcount ( 0 .. $#subfields ) {
2503 if ( $subfields[$subfieldcount][0] eq $subfield ) {
2504 if ( $result->{$kohafield} ) {
2505 $result->{$kohafield} .=
2506 " | " . $subfields[$subfieldcount][1];
2509 $result->{$kohafield} =
2510 $subfields[$subfieldcount][1];
2520 =head1 OTHER FUNCTIONS
2526 my $string = char_decode( $string, $encoding );
2528 converts ISO 5426 coded string to UTF-8
2529 sloppy code : should be improved in next issue
2536 my ( $string, $encoding ) = @_;
2539 $encoding = C4::Context->preference("marcflavour") unless $encoding;
2540 if ( $encoding eq "UNIMARC" ) {
2610 # this handles non-sorting blocks (if implementation requires this)
2611 $string = nsb_clean($_);
2613 elsif ( $encoding eq "USMARC" || $encoding eq "MARC21" ) {
2672 #Additional Turkish characters
2675 s/(\xf0)s/\xc5\x9f/gm;
2676 s/(\xf0)S/\xc5\x9e/gm;
2679 s/\xe7\x49/\\xc4\xb0/gm;
2680 s/(\xe6)G/\xc4\x9e/gm;
2681 s/(\xe6)g/ğ\xc4\x9f/gm;
2684 s/(\xe8|\xc8)o/ö/gm;
2685 s/(\xe8|\xc8)O/Ö/gm;
2686 s/(\xe8|\xc8)u/ü/gm;
2687 s/(\xe8|\xc8)U/Ü/gm;
2688 s/\xc2\xb8/\xc4\xb1/gm;
2691 # this handles non-sorting blocks (if implementation requires this)
2692 $string = nsb_clean($_);
2701 my $string = nsb_clean( $string, $encoding );
2708 my $NSB = '\x88'; # NSB : begin Non Sorting Block
2709 my $NSE = '\x89'; # NSE : Non Sorting Block end
2710 # handles non sorting blocks
2714 s/[ ]{0,1}$NSE/) /gm;
2719 =head2 PrepareItemrecordDisplay
2723 PrepareItemrecordDisplay($itemrecord,$bibnum,$itemumber);
2725 Returns a hash with all the fields for Display a given item data in a template
2731 sub PrepareItemrecordDisplay {
2733 my ( $bibnum, $itemnum ) = @_;
2735 my $dbh = C4::Context->dbh;
2736 my $frameworkcode = &GetFrameworkCode( $bibnum );
2737 my ( $itemtagfield, $itemtagsubfield ) =
2738 &GetMarcFromKohaField( "items.itemnumber", $frameworkcode );
2739 my $tagslib = &GetMarcStructure( 1, $frameworkcode );
2740 my $itemrecord = GetMarcItem( $bibnum, $itemnum) if ($itemnum);
2742 my $authorised_values_sth =
2744 "SELECT authorised_value,lib FROM authorised_values WHERE category=? ORDER BY lib"
2746 foreach my $tag ( sort keys %{$tagslib} ) {
2747 my $previous_tag = '';
2749 # loop through each subfield
2751 foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
2752 next if ( subfield_is_koha_internal_p($subfield) );
2753 next if ( $tagslib->{$tag}->{$subfield}->{'tab'} ne "10" );
2755 $subfield_data{tag} = $tag;
2756 $subfield_data{subfield} = $subfield;
2757 $subfield_data{countsubfield} = $cntsubf++;
2758 $subfield_data{kohafield} =
2759 $tagslib->{$tag}->{$subfield}->{'kohafield'};
2761 # $subfield_data{marc_lib}=$tagslib->{$tag}->{$subfield}->{lib};
2762 $subfield_data{marc_lib} =
2763 "<span id=\"error\" title=\""
2764 . $tagslib->{$tag}->{$subfield}->{lib} . "\">"
2765 . substr( $tagslib->{$tag}->{$subfield}->{lib}, 0, 12 )
2767 $subfield_data{mandatory} =
2768 $tagslib->{$tag}->{$subfield}->{mandatory};
2769 $subfield_data{repeatable} =
2770 $tagslib->{$tag}->{$subfield}->{repeatable};
2771 $subfield_data{hidden} = "display:none"
2772 if $tagslib->{$tag}->{$subfield}->{hidden};
2774 ( $x, $value ) = _find_value( $tag, $subfield, $itemrecord )
2776 $value =~ s/"/"/g;
2778 # search for itemcallnumber if applicable
2779 if ( $tagslib->{$tag}->{$subfield}->{kohafield} eq
2780 'items.itemcallnumber'
2781 && C4::Context->preference('itemcallnumber') )
2784 substr( C4::Context->preference('itemcallnumber'), 0, 3 );
2786 substr( C4::Context->preference('itemcallnumber'), 3, 1 );
2787 my $temp = $itemrecord->field($CNtag) if ($itemrecord);
2789 $value = $temp->subfield($CNsubfield);
2792 if ( $tagslib->{$tag}->{$subfield}->{authorised_value} ) {
2793 my @authorised_values;
2796 # builds list, depending on authorised value...
2798 if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq
2801 if ( ( C4::Context->preference("IndependantBranches") )
2802 && ( C4::Context->userenv->{flags} != 1 ) )
2806 "SELECT branchcode,branchname FROM branches WHERE branchcode = ? ORDER BY branchname"
2808 $sth->execute( C4::Context->userenv->{branch} );
2809 push @authorised_values, ""
2811 $tagslib->{$tag}->{$subfield}->{mandatory} );
2812 while ( my ( $branchcode, $branchname ) =
2813 $sth->fetchrow_array )
2815 push @authorised_values, $branchcode;
2816 $authorised_lib{$branchcode} = $branchname;
2822 "SELECT branchcode,branchname FROM branches ORDER BY branchname"
2825 push @authorised_values, ""
2827 $tagslib->{$tag}->{$subfield}->{mandatory} );
2828 while ( my ( $branchcode, $branchname ) =
2829 $sth->fetchrow_array )
2831 push @authorised_values, $branchcode;
2832 $authorised_lib{$branchcode} = $branchname;
2838 elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq
2843 "SELECT itemtype,description FROM itemtypes ORDER BY description"
2846 push @authorised_values, ""
2847 unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
2848 while ( my ( $itemtype, $description ) =
2849 $sth->fetchrow_array )
2851 push @authorised_values, $itemtype;
2852 $authorised_lib{$itemtype} = $description;
2855 #---- "true" authorised value
2858 $authorised_values_sth->execute(
2859 $tagslib->{$tag}->{$subfield}->{authorised_value} );
2860 push @authorised_values, ""
2861 unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
2862 while ( my ( $value, $lib ) =
2863 $authorised_values_sth->fetchrow_array )
2865 push @authorised_values, $value;
2866 $authorised_lib{$value} = $lib;
2869 $subfield_data{marc_value} = CGI::scrolling_list(
2870 -name => 'field_value',
2871 -values => \@authorised_values,
2872 -default => "$value",
2873 -labels => \%authorised_lib,
2879 elsif ( $tagslib->{$tag}->{$subfield}->{thesaurus_category} ) {
2880 $subfield_data{marc_value} =
2881 "<input type=\"text\" name=\"field_value\" size=47 maxlength=255> <a href=\"javascript:Dopop('cataloguing/thesaurus_popup.pl?category=$tagslib->{$tag}->{$subfield}->{thesaurus_category}&index=',)\">...</a>";
2884 # COMMENTED OUT because No $i is provided with this API.
2885 # And thus, no value_builder can be activated.
2886 # BUT could be thought over.
2887 # } elsif ($tagslib->{$tag}->{$subfield}->{'value_builder'}) {
2888 # my $plugin="value_builder/".$tagslib->{$tag}->{$subfield}->{'value_builder'};
2890 # my $extended_param = plugin_parameters($dbh,$itemrecord,$tagslib,$i,0);
2891 # my ($function_name,$javascript) = plugin_javascript($dbh,$record,$tagslib,$i,0);
2892 # $subfield_data{marc_value}="<input type=\"text\" value=\"$value\" name=\"field_value\" size=47 maxlength=255 DISABLE READONLY OnFocus=\"javascript:Focus$function_name()\" OnBlur=\"javascript:Blur$function_name()\"> <a href=\"javascript:Clic$function_name()\">...</a> $javascript";
2895 $subfield_data{marc_value} =
2896 "<input type=\"text\" name=\"field_value\" value=\"$value\" size=50 maxlength=255>";
2898 push( @loop_data, \%subfield_data );
2902 my $itemnumber = $itemrecord->subfield( $itemtagfield, $itemtagsubfield )
2903 if ( $itemrecord && $itemrecord->field($itemtagfield) );
2905 'itemtagfield' => $itemtagfield,
2906 'itemtagsubfield' => $itemtagsubfield,
2907 'itemnumber' => $itemnumber,
2908 'iteminformation' => \@loop_data
2914 # true ModZebra commented until indexdata fixes zebraDB crashes (it seems they occur on multiple updates
2916 # replaced by a zebraqueue table, that is filled with ModZebra to run.
2917 # the table is emptied by misc/cronjobs/zebraqueue_start.pl script
2918 # =head2 ModZebrafiles
2920 # &ModZebrafiles( $dbh, $biblionumber, $record, $folder, $server );
2924 # sub ModZebrafiles {
2926 # my ( $dbh, $biblionumber, $record, $folder, $server ) = @_;
2930 # C4::Context->zebraconfig($server)->{directory} . "/" . $folder . "/";
2931 # unless ( opendir( DIR, "$zebradir" ) ) {
2932 # warn "$zebradir not found";
2936 # my $filename = $zebradir . $biblionumber;
2939 # open( OUTPUT, ">", $filename . ".xml" );
2940 # print OUTPUT $record;
2949 ModZebra( $biblionumber, $op, $server, $newRecord );
2951 $biblionumber is the biblionumber we want to index
2952 $op is specialUpdate or delete, and is used to know what we want to do
2953 $server is the server that we want to update
2954 $newRecord is the MARC::Record containing the new record. It is usefull only when NoZebra=1, and is used to know what to add to the nozebra database. (the record in mySQL being, if it exist, the previous record, the one just before the modif. We need both : the previous and the new one.
2961 ###Accepts a $server variable thus we can use it for biblios authorities or other zebra dbs
2962 my ( $biblionumber, $op, $server, $newRecord ) = @_;
2963 my $dbh=C4::Context->dbh;
2965 # true ModZebra commented until indexdata fixes zebraDB crashes (it seems they occur on multiple updates
2967 # replaced by a zebraqueue table, that is filled with ModZebra to run.
2968 # the table is emptied by misc/cronjobs/zebraqueue_start.pl script
2970 if (C4::Context->preference("NoZebra")) {
2971 # lock the nozebra table : we will read index lines, update them in Perl process
2972 # and write everything in 1 transaction.
2973 # lock the table to avoid someone else overwriting what we are doing
2974 $dbh->do('LOCK TABLES nozebra WRITE,biblio WRITE,biblioitems WRITE, systempreferences WRITE, auth_types WRITE, auth_header WRITE');
2975 my %result; # the result hash that will be builded by deletion / add, and written on mySQL at the end, to improve speed
2977 if ($server eq 'biblioserver') {
2978 $record= GetMarcBiblio($biblionumber);
2980 $record= C4::AuthoritiesMarc::GetAuthority($biblionumber);
2982 if ($op eq 'specialUpdate') {
2983 # OK, we have to add or update the record
2984 # 1st delete (virtually, in indexes) ...
2985 %result = _DelBiblioNoZebra($biblionumber,$record,$server);
2986 # ... add the record
2987 %result=_AddBiblioNoZebra($biblionumber,$newRecord, $server, %result);
2989 # it's a deletion, delete the record...
2990 # warn "DELETE the record $biblionumber on $server".$record->as_formatted;
2991 %result=_DelBiblioNoZebra($biblionumber,$record,$server);
2993 # ok, now update the database...
2994 my $sth = $dbh->prepare("UPDATE nozebra SET biblionumbers=? WHERE server=? AND indexname=? AND value=?");
2995 foreach my $key (keys %result) {
2996 foreach my $index (keys %{$result{$key}}) {
2997 $sth->execute($result{$key}->{$index}, $server, $key, $index);
3000 $dbh->do('UNLOCK TABLES');
3004 # we use zebra, just fill zebraqueue table
3006 my $sth=$dbh->prepare("INSERT INTO zebraqueue (biblio_auth_number,server,operation) VALUES(?,?,?)");
3007 $sth->execute($biblionumber,$server,$op);
3012 =head2 GetNoZebraIndexes
3014 %indexes = GetNoZebraIndexes;
3016 return the data from NoZebraIndexes syspref.
3020 sub GetNoZebraIndexes {
3021 my $index = C4::Context->preference('NoZebraIndexes');
3023 foreach my $line (split /('|"),/,$index) {
3024 $line =~ /(.*)=>(.*)/;
3025 my $index = substr($1,1); # get the index, don't forget to remove initial ' or "
3027 $index =~ s/'|"| //g;
3028 $fields =~ s/'|"| //g;
3029 $indexes{$index}=$fields;
3034 =head1 INTERNAL FUNCTIONS
3036 =head2 _DelBiblioNoZebra($biblionumber,$record,$server);
3038 function to delete a biblio in NoZebra indexes
3039 This function does NOT delete anything in database : it reads all the indexes entries
3040 that have to be deleted & delete them in the hash
3041 The SQL part is done either :
3042 - after the Add if we are modifying a biblio (delete + add again)
3043 - immediatly after this sub if we are doing a true deletion.
3044 $server can be 'biblioserver' or 'authorityserver' : it indexes biblios or authorities (in the same table, $server being part of the table itself
3049 sub _DelBiblioNoZebra {
3050 my ($biblionumber, $record, $server)=@_;
3053 my $dbh = C4::Context->dbh;
3057 if ($server eq 'biblioserver') {
3058 %index=GetNoZebraIndexes;
3059 # get title of the record (to store the 10 first letters with the index)
3060 my ($titletag,$titlesubfield) = GetMarcFromKohaField('biblio.title');
3061 $title = lc($record->subfield($titletag,$titlesubfield));
3063 # for authorities, the "title" is the $a mainentry
3064 my $authref = C4::AuthoritiesMarc::GetAuthType($record->subfield(152,'b'));
3065 warn "ERROR : authtype undefined for ".$record->as_formatted unless $authref;
3066 $title = $record->subfield($authref->{auth_tag_to_report},'a');
3067 $index{'mainmainentry'}= $authref->{'auth_tag_to_report'}.'a';
3068 $index{'mainentry'} = $authref->{'auth_tag_to_report'}.'*';
3069 $index{'auth_type'} = '152b';
3073 # remove blancks comma (that could cause problem when decoding the string for CQL retrieval) and regexp specific values
3074 $title =~ s/ |,|;|\[|\]|\(|\)|\*|-|'|=//g;
3075 # limit to 10 char, should be enough, and limit the DB size
3076 $title = substr($title,0,10);
3078 my $sth2=$dbh->prepare('SELECT biblionumbers FROM nozebra WHERE server=? AND indexname=? AND value=?');
3079 foreach my $field ($record->fields()) {
3080 #parse each subfield
3081 next if $field->tag <10;
3082 foreach my $subfield ($field->subfields()) {
3083 my $tag = $field->tag();
3084 my $subfieldcode = $subfield->[0];
3086 # check each index to see if the subfield is stored somewhere
3087 # otherwise, store it in __RAW__ index
3088 foreach my $key (keys %index) {
3089 # warn "examining $key index : ".$index{$key}." for $tag $subfieldcode";
3090 if ($index{$key} =~ /$tag\*/ or $index{$key} =~ /$tag$subfieldcode/) {
3092 my $line= lc $subfield->[1];
3093 # remove meaningless value in the field...
3094 $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:/ /g;
3095 # ... and split in words
3096 foreach (split / /,$line) {
3097 next unless $_; # skip empty values (multiple spaces)
3098 # if the entry is already here, do nothing, the biblionumber has already be removed
3099 unless ($result{$key}->{$_} =~ /$biblionumber,$title\-(\d);/) {
3100 # get the index value if it exist in the nozebra table and remove the entry, otherwise, do nothing
3101 $sth2->execute($server,$key,$_);
3102 my $existing_biblionumbers = $sth2->fetchrow;
3104 if ($existing_biblionumbers) {
3105 # warn " existing for $key $_: $existing_biblionumbers";
3106 $result{$key}->{$_} =$existing_biblionumbers;
3107 $result{$key}->{$_} =~ s/$biblionumber,$title\-(\d);//;
3113 # the subfield is not indexed, store it in __RAW__ index anyway
3115 my $line= lc $subfield->[1];
3116 $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:/ /g;
3117 # ... and split in words
3118 foreach (split / /,$line) {
3119 next unless $_; # skip empty values (multiple spaces)
3120 # if the entry is already here, do nothing, the biblionumber has already be removed
3121 unless ($result{'__RAW__'}->{$_} =~ /$biblionumber,$title\-(\d);/) {
3122 # get the index value if it exist in the nozebra table and remove the entry, otherwise, do nothing
3123 $sth2->execute($server,'__RAW__',$_);
3124 my $existing_biblionumbers = $sth2->fetchrow;
3126 if ($existing_biblionumbers) {
3127 $result{'__RAW__'}->{$_} =$existing_biblionumbers;
3128 $result{'__RAW__'}->{$_} =~ s/$biblionumber,$title\-(\d);//;
3138 =head2 _AddBiblioNoZebra($biblionumber, $record, $server, %result);
3140 function to add a biblio in NoZebra indexes
3144 sub _AddBiblioNoZebra {
3145 my ($biblionumber, $record, $server, %result)=@_;
3146 my $dbh = C4::Context->dbh;
3150 if ($server eq 'biblioserver') {
3151 %index=GetNoZebraIndexes;
3152 # get title of the record (to store the 10 first letters with the index)
3153 my ($titletag,$titlesubfield) = GetMarcFromKohaField('biblio.title');
3154 $title = lc($record->subfield($titletag,$titlesubfield));
3156 # warn "server : $server";
3157 # for authorities, the "title" is the $a mainentry
3158 my $authref = C4::AuthoritiesMarc::GetAuthType($record->subfield(152,'b'));
3159 warn "ERROR : authtype undefined for ".$record->as_formatted unless $authref;
3160 $title = $record->subfield($authref->{auth_tag_to_report},'a');
3161 $index{'mainmainentry'} = $authref->{auth_tag_to_report}.'a';
3162 $index{'mainentry'} = $authref->{auth_tag_to_report}.'*';
3163 $index{'auth_type'} = '152b';
3166 # remove blancks comma (that could cause problem when decoding the string for CQL retrieval) and regexp specific values
3167 $title =~ s/ |,|;|\[|\]|\(|\)|\*|-|'|=//g;
3168 # limit to 10 char, should be enough, and limit the DB size
3169 $title = substr($title,0,10);
3171 my $sth2=$dbh->prepare('SELECT biblionumbers FROM nozebra WHERE server=? AND indexname=? AND value=?');
3172 foreach my $field ($record->fields()) {
3173 #parse each subfield
3174 next if $field->tag <10;
3175 foreach my $subfield ($field->subfields()) {
3176 my $tag = $field->tag();
3177 my $subfieldcode = $subfield->[0];
3179 # check each index to see if the subfield is stored somewhere
3180 # otherwise, store it in __RAW__ index
3181 foreach my $key (keys %index) {
3182 # warn "examining $key index : ".$index{$key}." for $tag $subfieldcode";
3183 if ($index{$key} =~ /$tag\*/ or $index{$key} =~ /$tag$subfieldcode/) {
3185 my $line= lc $subfield->[1];
3186 # remove meaningless value in the field...
3187 $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:/ /g;
3188 # ... and split in words
3189 foreach (split / /,$line) {
3190 next unless $_; # skip empty values (multiple spaces)
3191 # if the entry is already here, improve weight
3192 # warn "managing $_";
3193 if ($result{$key}->{"$_"} =~ /$biblionumber,$title\-(\d);/) {
3195 $result{$key}->{"$_"} =~ s/$biblionumber,$title\-(\d);//;
3196 $result{$key}->{"$_"} .= "$biblionumber,$title-$weight;";
3198 # get the value if it exist in the nozebra table, otherwise, create it
3199 $sth2->execute($server,$key,$_);
3200 my $existing_biblionumbers = $sth2->fetchrow;
3202 if ($existing_biblionumbers) {
3203 $result{$key}->{"$_"} =$existing_biblionumbers;
3205 $result{$key}->{"$_"} =~ s/$biblionumber,$title\-(\d);//;
3206 $result{$key}->{"$_"} .= "$biblionumber,$title-$weight;";
3207 # create a new ligne for this entry
3209 # warn "INSERT : $server / $key / $_";
3210 $dbh->do('INSERT INTO nozebra SET server='.$dbh->quote($server).', indexname='.$dbh->quote($key).',value='.$dbh->quote($_));
3211 $result{$key}->{"$_"}.="$biblionumber,$title-1;";
3217 # the subfield is not indexed, store it in __RAW__ index anyway
3219 my $line= lc $subfield->[1];
3220 $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:/ /g;
3221 # ... and split in words
3222 foreach (split / /,$line) {
3223 next unless $_; # skip empty values (multiple spaces)
3224 # if the entry is already here, improve weight
3225 if ($result{'__RAW__'}->{"$_"} =~ /$biblionumber,$title\-(\d);/) {
3227 $result{'__RAW__'}->{"$_"} =~ s/$biblionumber,$title\-(\d);//;
3228 $result{'__RAW__'}->{"$_"} .= "$biblionumber,$title-$weight;";
3230 # get the value if it exist in the nozebra table, otherwise, create it
3231 $sth2->execute($server,'__RAW__',$_);
3232 my $existing_biblionumbers = $sth2->fetchrow;
3234 if ($existing_biblionumbers) {
3235 $result{'__RAW__'}->{"$_"} =$existing_biblionumbers;
3237 $result{'__RAW__'}->{"$_"} =~ s/$biblionumber,$title\-(\d);//;
3238 $result{'__RAW__'}->{"$_"} .= "$biblionumber,$title-$weight;";
3239 # create a new ligne for this entry
3241 $dbh->do('INSERT INTO nozebra SET server='.$dbh->quote($server).', indexname="__RAW__",value='.$dbh->quote($_));
3242 $result{'__RAW__'}->{"$_"}.="$biblionumber,$title-1;";
3253 =head2 MARCitemchange
3257 &MARCitemchange( $record, $itemfield, $newvalue )
3259 Function to update a single value in an item field.
3260 Used twice, could probably be replaced by something else, but works well...
3268 sub MARCitemchange {
3269 my ( $record, $itemfield, $newvalue ) = @_;
3270 my $dbh = C4::Context->dbh;
3272 my ( $tagfield, $tagsubfield ) =
3273 GetMarcFromKohaField( $itemfield, "" );
3274 if ( ($tagfield) && ($tagsubfield) ) {
3275 my $tag = $record->field($tagfield);
3277 $tag->update( $tagsubfield => $newvalue );
3278 $record->delete_field($tag);
3279 $record->insert_fields_ordered($tag);
3287 ($indicators, $value) = _find_value($tag, $subfield, $record,$encoding);
3289 Find the given $subfield in the given $tag in the given
3290 MARC::Record $record. If the subfield is found, returns
3291 the (indicators, value) pair; otherwise, (undef, undef) is
3295 Such a function is used in addbiblio AND additem and serial-edit and maybe could be used in Authorities.
3296 I suggest we export it from this module.
3303 my ( $tagfield, $insubfield, $record, $encoding ) = @_;
3306 if ( $tagfield < 10 ) {
3307 if ( $record->field($tagfield) ) {
3308 push @result, $record->field($tagfield)->data();
3315 foreach my $field ( $record->field($tagfield) ) {
3316 my @subfields = $field->subfields();
3317 foreach my $subfield (@subfields) {
3318 if ( @$subfield[0] eq $insubfield ) {
3319 push @result, @$subfield[1];
3320 $indicator = $field->indicator(1) . $field->indicator(2);
3325 return ( $indicator, @result );
3328 =head2 _koha_add_biblio
3332 my ($biblionumber,$error) = _koha_add_biblio($dbh,$biblioitem);
3334 Internal function to add a biblio ($biblio is a hash with the values)
3340 sub _koha_add_biblio {
3341 my ( $dbh, $biblio, $frameworkcode ) = @_;
3345 # get the next biblionumber
3346 my $sth = $dbh->prepare("SELECT MAX(biblionumber) FROM biblio");
3348 my $data = $sth->fetchrow_arrayref();
3349 my $biblionumber = $$data[0] + 1;
3350 # set the series flag
3352 if ( $biblio->{'seriestitle'} ) { $serial = 1 };
3357 SET biblionumber = ?,
3369 $sth = $dbh->prepare($query);
3373 $biblio->{'author'},
3375 $biblio->{'unititle'},
3378 $biblio->{'seriestitle'},
3379 $biblio->{'copyrightdate'},
3380 $biblio->{'abstract'}
3383 if ( $dbh->errstr ) {
3384 $error.="ERROR in _koha_add_biblio $query".$dbh->errstr;
3389 #warn "LEAVING _koha_add_biblio: ".$biblionumber."\n";
3390 return ($biblionumber,$error);
3393 =head2 _koha_modify_biblio
3397 my ($biblionumber,$error) == _koha_modify_biblio($dbh,$biblio);
3399 Internal function for updating the biblio table
3405 sub _koha_modify_biblio {
3406 my ( $dbh, $biblio ) = @_;
3411 SET frameworkcode = ?,
3420 WHERE biblionumber = ?
3423 my $sth = $dbh->prepare($query);
3426 $biblio->{'frameworkcode'},
3427 $biblio->{'author'},
3429 $biblio->{'unititle'},
3431 $biblio->{'serial'},
3432 $biblio->{'seriestitle'},
3433 $biblio->{'copyrightdate'},
3434 $biblio->{'abstract'},
3435 $biblio->{'biblionumber'}
3436 ) if $biblio->{'biblionumber'};
3438 if ( $dbh->errstr || !$biblio->{'biblionumber'} ) {
3439 $error.="ERROR in _koha_modify_biblio $query".$dbh->errstr;
3442 return ( $biblio->{'biblionumber'},$error );
3445 =head2 _koha_modify_biblioitem
3449 my ($biblioitemnumber,$error) = _koha_modify_biblioitem( $dbh, $biblioitem );
3455 sub _koha_modify_biblioitem {
3456 my ( $dbh, $biblioitem ) = @_;
3459 # re-calculate the cn_sort, it may have changed
3460 my ($cn_sort) = GetClassSort($biblioitem->{'cn_source'}, $biblioitem->{'cn_class'}, $biblioitem->{'cn_item'} );
3464 SET biblionumber = ?,
3470 publicationyear = ?,
3474 collectiontitle = ?,
3476 collectionvolume= ?,
3477 editionstatement= ?,
3478 editionresponsibility = ?,
3494 where biblioitemnumber = ?
3496 my $sth = $dbh->prepare($query);
3498 $biblioitem->{'biblionumber'},
3499 $biblioitem->{'volume'},
3500 $biblioitem->{'number'},
3501 $biblioitem->{'itemtype'},
3502 $biblioitem->{'isbn'},
3503 $biblioitem->{'issn'},
3504 $biblioitem->{'publicationyear'},
3505 $biblioitem->{'publishercode'},
3506 $biblioitem->{'volumedate'},
3507 $biblioitem->{'volumedesc'},
3508 $biblioitem->{'collectiontitle'},
3509 $biblioitem->{'collectionissn'},
3510 $biblioitem->{'collectionvolume'},
3511 $biblioitem->{'editionstatement'},
3512 $biblioitem->{'editionresponsibility'},
3513 $biblioitem->{'illus'},
3514 $biblioitem->{'pages'},
3515 $biblioitem->{'bnotes'},
3516 $biblioitem->{'size'},
3517 $biblioitem->{'place'},
3518 $biblioitem->{'lccn'},
3519 $biblioitem->{'marc'},
3520 $biblioitem->{'url'},
3521 $biblioitem->{'cn_source'},
3522 $biblioitem->{'cn_class'},
3523 $biblioitem->{'cn_item'},
3524 $biblioitem->{'cn_suffix'},
3526 $biblioitem->{'totalissues'},
3527 $biblioitem->{'marcxml'},
3528 $biblioitem->{'biblioitemnumber'}
3530 if ( $dbh->errstr ) {
3531 $error.="ERROR in _koha_modify_biblioitem $query".$dbh->errstr;
3534 return ($biblioitem->{'biblioitemnumber'},$error);
3537 =head2 _koha_add_biblioitem
3541 my ($biblioitemnumber,$error) = _koha_add_biblioitem( $dbh, $biblioitem );
3543 Internal function to add a biblioitem
3549 sub _koha_add_biblioitem {
3550 my ( $dbh, $biblioitem ) = @_;
3552 my $sth = $dbh->prepare("SELECT MAX(biblioitemnumber) FROM biblioitems");
3554 my $data = $sth->fetchrow_arrayref;
3555 my $bibitemnum = $$data[0] + 1;
3558 my ($cn_sort) = GetClassSort($biblioitem->{'cn_source'}, $biblioitem->{'cn_class'}, $biblioitem->{'cn_item'} );
3560 "INSERT INTO biblioitems SET
3561 biblioitemnumber = ?,
3568 publicationyear = ?,
3572 collectiontitle = ?,
3574 collectionvolume= ?,
3575 editionstatement= ?,
3576 editionresponsibility = ?,
3592 my $sth = $dbh->prepare($query);
3595 $biblioitem->{'biblionumber'},
3596 $biblioitem->{'volume'},
3597 $biblioitem->{'number'},
3598 $biblioitem->{'itemtype'},
3599 $biblioitem->{'isbn'},
3600 $biblioitem->{'issn'},
3601 $biblioitem->{'publicationyear'},
3602 $biblioitem->{'publishercode'},
3603 $biblioitem->{'volumedate'},
3604 $biblioitem->{'volumedesc'},
3605 $biblioitem->{'collectiontitle'},
3606 $biblioitem->{'collectionissn'},
3607 $biblioitem->{'collectionvolume'},
3608 $biblioitem->{'editionstatement'},
3609 $biblioitem->{'editionresponsibility'},
3610 $biblioitem->{'illus'},
3611 $biblioitem->{'pages'},
3612 $biblioitem->{'bnotes'},
3613 $biblioitem->{'size'},
3614 $biblioitem->{'place'},
3615 $biblioitem->{'lccn'},
3616 $biblioitem->{'marc'},
3617 $biblioitem->{'url'},
3618 $biblioitem->{'cn_source'},
3619 $biblioitem->{'cn_class'},
3620 $biblioitem->{'cn_item'},
3621 $biblioitem->{'cn_suffix'},
3623 $biblioitem->{'totalissues'}
3625 if ( $dbh->errstr ) {
3626 $error.="ERROR in _koha_add_biblioitem $query".$dbh->errstr;
3630 return ($bibitemnum,$error);
3633 =head2 _koha_new_items
3637 my ($itemnumber,$error) = _koha_new_items( $dbh, $item, $barcode );
3643 sub _koha_new_items {
3644 my ( $dbh, $item, $barcode ) = @_;
3647 my $sth = $dbh->prepare("SELECT MAX(itemnumber) FROM items");
3649 my $data = $sth->fetchrow_hashref;
3650 my $itemnumber = $data->{'MAX(itemnumber)'} + 1;
3653 my ($items_cn_sort) = GetClassSort($item->{'cn_source'}, $item->{'itemcallnumber'}, "");
3655 # if dateaccessioned is provided, use it. Otherwise, set to NOW()
3656 if ( $item->{'dateaccessioned'} eq '' || !$item->{'dateaccessioned'} ) {
3657 my $today = C4::Dates->new();
3658 $item->{'dateaccessioned'} = $today->output("iso"); #TODO: check time issues
3661 "INSERT INTO items SET
3664 biblioitemnumber = ?,
3666 dateaccessioned = ?,
3670 replacementprice = ?,
3671 replacementpricedate = NOW(),
3672 datelastborrowed = ?,
3673 datelastseen = NOW(),
3692 my $sth = $dbh->prepare($query);
3695 $item->{'biblionumber'},
3696 $item->{'biblioitemnumber'},
3698 $item->{'dateaccessioned'},
3699 $item->{'booksellerid'},
3700 $item->{'homebranch'},
3702 $item->{'replacementprice'},
3703 $item->{datelastborrowed},
3705 $item->{'notforloan'},
3707 $item->{'itemlost'},
3708 $item->{'wthdrawn'},
3709 $item->{'itemcallnumber'},
3710 $item->{'restricted'},
3711 $item->{'itemnotes'},
3712 $item->{'holdingbranch'},
3714 $item->{'location'},
3716 $item->{'cn_source'},
3719 $item->{'materials'},
3722 if ( defined $sth->errstr ) {
3723 $error.="ERROR in _koha_new_items $query".$sth->errstr;
3726 return ( $itemnumber, $error );
3729 =head2 _koha_modify_item
3733 my ($itemnumber,$error) =_koha_modify_item( $dbh, $item, $op );
3739 sub _koha_modify_item {
3740 my ( $dbh, $item ) = @_;
3743 # calculate items_cn_sort
3744 my ($items_cn_sort) = GetClassSort($item->{'cn_source'}, $item->{'itemcallnumber'}, "");
3746 my $query = "UPDATE items SET ";
3748 for my $key ( keys %$item ) {
3749 # special cases first
3750 if ($key eq 'cn_sort') {
3751 $query.="cn_sort=?,";
3752 push @bind, $items_cn_sort;
3757 push @bind, $item->{$key};
3761 $query .= " WHERE itemnumber=?";
3762 push @bind, $item->{'itemnumber'};
3763 my $sth = $dbh->prepare($query);
3764 $sth->execute(@bind);
3765 if ( $dbh->errstr ) {
3766 $error.="ERROR in _koha_modify_item $query".$dbh->errstr;
3770 return ($item->{'itemnumber'},$error);
3773 =head2 _koha_delete_biblio
3777 $error = _koha_delete_biblio($dbh,$biblionumber);
3779 Internal sub for deleting from biblio table -- also saves to deletedbiblio
3781 C<$dbh> - the database handle
3782 C<$biblionumber> - the biblionumber of the biblio to be deleted
3788 # FIXME: add error handling
3790 sub _koha_delete_biblio {
3791 my ( $dbh, $biblionumber ) = @_;
3793 # get all the data for this biblio
3794 my $sth = $dbh->prepare("SELECT * FROM biblio WHERE biblionumber=?");
3795 $sth->execute($biblionumber);
3797 if ( my $data = $sth->fetchrow_hashref ) {
3799 # save the record in deletedbiblio
3800 # find the fields to save
3801 my $query = "INSERT INTO deletedbiblio SET ";
3803 foreach my $temp ( keys %$data ) {
3804 $query .= "$temp = ?,";
3805 push( @bind, $data->{$temp} );
3808 # replace the last , by ",?)"
3810 my $bkup_sth = $dbh->prepare($query);
3811 $bkup_sth->execute(@bind);
3815 my $del_sth = $dbh->prepare("DELETE FROM biblio WHERE biblionumber=?");
3816 $del_sth->execute($biblionumber);
3823 =head2 _koha_delete_biblioitems
3827 $error = _koha_delete_biblioitems($dbh,$biblioitemnumber);
3829 Internal sub for deleting from biblioitems table -- also saves to deletedbiblioitems
3831 C<$dbh> - the database handle
3832 C<$biblionumber> - the biblioitemnumber of the biblioitem to be deleted
3838 # FIXME: add error handling
3840 sub _koha_delete_biblioitems {
3841 my ( $dbh, $biblioitemnumber ) = @_;
3843 # get all the data for this biblioitem
3845 $dbh->prepare("SELECT * FROM biblioitems WHERE biblioitemnumber=?");
3846 $sth->execute($biblioitemnumber);
3848 if ( my $data = $sth->fetchrow_hashref ) {
3850 # save the record in deletedbiblioitems
3851 # find the fields to save
3852 my $query = "INSERT INTO deletedbiblioitems SET ";
3854 foreach my $temp ( keys %$data ) {
3855 $query .= "$temp = ?,";
3856 push( @bind, $data->{$temp} );
3859 # replace the last , by ",?)"
3861 my $bkup_sth = $dbh->prepare($query);
3862 $bkup_sth->execute(@bind);
3865 # delete the biblioitem
3867 $dbh->prepare("DELETE FROM biblioitems WHERE biblioitemnumber=?");
3868 $del_sth->execute($biblioitemnumber);
3875 =head2 _koha_delete_item
3879 _koha_delete_item( $dbh, $itemnum );
3881 Internal function to delete an item record from the koha tables
3887 sub _koha_delete_item {
3888 my ( $dbh, $itemnum ) = @_;
3890 # save the deleted item to deleteditems table
3891 my $sth = $dbh->prepare("SELECT * FROM items WHERE itemnumber=?");
3892 $sth->execute($itemnum);
3893 my $data = $sth->fetchrow_hashref();
3895 my $query = "INSERT INTO deleteditems SET ";
3897 foreach my $key ( keys %$data ) {
3898 $query .= "$key = ?,";
3899 push( @bind, $data->{$key} );
3902 $sth = $dbh->prepare($query);
3903 $sth->execute(@bind);
3906 # delete from items table
3907 $sth = $dbh->prepare("DELETE FROM items WHERE itemnumber=?");
3908 $sth->execute($itemnum);
3913 =head1 UNEXPORTED FUNCTIONS
3915 =head2 ModBiblioMarc
3917 &ModBiblioMarc($newrec,$biblionumber,$frameworkcode);
3919 Add MARC data for a biblio to koha
3921 Function exported, but should NOT be used, unless you really know what you're doing
3927 # pass the MARC::Record to this function, and it will create the records in the marc field
3928 my ( $record, $biblionumber, $frameworkcode ) = @_;
3929 my $dbh = C4::Context->dbh;
3930 my @fields = $record->fields();
3931 if ( !$frameworkcode ) {
3932 $frameworkcode = "";
3935 $dbh->prepare("UPDATE biblio SET frameworkcode=? WHERE biblionumber=?");
3936 $sth->execute( $frameworkcode, $biblionumber );
3938 my $encoding = C4::Context->preference("marcflavour");
3940 # deal with UNIMARC field 100 (encoding) : create it if needed & set encoding to unicode
3941 if ( $encoding eq "UNIMARC" ) {
3943 if ( length($record->subfield( 100, "a" )) == 35 ) {
3944 $string = $record->subfield( 100, "a" );
3945 my $f100 = $record->field(100);
3946 $record->delete_field($f100);
3949 $string = POSIX::strftime( "%Y%m%d", localtime );
3951 $string = sprintf( "%-*s", 35, $string );
3953 substr( $string, 22, 6, "frey50" );
3954 unless ( $record->subfield( 100, "a" ) ) {
3955 $record->insert_grouped_field(
3956 MARC::Field->new( 100, "", "", "a" => $string ) );
3959 ModZebra($biblionumber,"specialUpdate","biblioserver",$record);
3962 "UPDATE biblioitems SET marc=?,marcxml=? WHERE biblionumber=?");
3963 $sth->execute( $record->as_usmarc(), $record->as_xml_record($encoding),
3966 return $biblionumber;
3969 =head2 AddItemInMarc
3973 $newbiblionumber = AddItemInMarc( $record, $biblionumber, $frameworkcode );
3975 Add an item in a MARC record and save the MARC record
3977 Function exported, but should NOT be used, unless you really know what you're doing
3985 # pass the MARC::Record to this function, and it will create the records in the marc tables
3986 my ( $record, $biblionumber, $frameworkcode ) = @_;
3987 my $newrec = &GetMarcBiblio($biblionumber);
3990 my @fields = $record->fields();
3991 foreach my $field (@fields) {
3992 $newrec->append_fields($field);
3995 # FIXME: should we be making sure the biblionumbers are the same?
3996 my $newbiblionumber =
3997 &ModBiblioMarc( $newrec, $biblionumber, $frameworkcode );
3998 return $newbiblionumber;
4001 =head2 z3950_extended_services
4003 z3950_extended_services($serviceType,$serviceOptions,$record);
4005 z3950_extended_services is used to handle all interactions with Zebra's extended serices package, which is employed to perform all management of the MARC data stored in Zebra.
4007 C<$serviceType> one of: itemorder,create,drop,commit,update,xmlupdate
4009 C<$serviceOptions> a has of key/value pairs. For instance, if service_type is 'update', $service_options should contain:
4011 action => update action, one of specialUpdate, recordInsert, recordReplace, recordDelete, elementUpdate.
4015 recordidOpaque => Opaque Record ID (user supplied) or recordidNumber => Record ID number (system number).
4016 syntax => the record syntax (transfer syntax)
4017 databaseName = Database from connection object
4019 To set serviceOptions, call set_service_options($serviceType)
4021 C<$record> the record, if one is needed for the service type
4023 A record should be in XML. You can convert it to XML from MARC by running it through marc2xml().
4027 sub z3950_extended_services {
4028 my ( $server, $serviceType, $action, $serviceOptions ) = @_;
4030 # get our connection object
4031 my $Zconn = C4::Context->Zconn( $server, 0, 1 );
4033 # create a new package object
4034 my $Zpackage = $Zconn->package();
4037 $Zpackage->option( action => $action );
4039 if ( $serviceOptions->{'databaseName'} ) {
4040 $Zpackage->option( databaseName => $serviceOptions->{'databaseName'} );
4042 if ( $serviceOptions->{'recordIdNumber'} ) {
4044 recordIdNumber => $serviceOptions->{'recordIdNumber'} );
4046 if ( $serviceOptions->{'recordIdOpaque'} ) {
4048 recordIdOpaque => $serviceOptions->{'recordIdOpaque'} );
4051 # this is an ILL request (Zebra doesn't support it, but Koha could eventually)
4052 #if ($serviceType eq 'itemorder') {
4053 # $Zpackage->option('contact-name' => $serviceOptions->{'contact-name'});
4054 # $Zpackage->option('contact-phone' => $serviceOptions->{'contact-phone'});
4055 # $Zpackage->option('contact-email' => $serviceOptions->{'contact-email'});
4056 # $Zpackage->option('itemorder-item' => $serviceOptions->{'itemorder-item'});
4059 if ( $serviceOptions->{record} ) {
4060 $Zpackage->option( record => $serviceOptions->{record} );
4062 # can be xml or marc
4063 if ( $serviceOptions->{'syntax'} ) {
4064 $Zpackage->option( syntax => $serviceOptions->{'syntax'} );
4068 # send the request, handle any exception encountered
4069 eval { $Zpackage->send($serviceType) };
4070 if ( $@ && $@->isa("ZOOM::Exception") ) {
4071 return "error: " . $@->code() . " " . $@->message() . "\n";
4074 # free up package resources
4075 $Zpackage->destroy();
4078 =head2 set_service_options
4080 my $serviceOptions = set_service_options($serviceType);
4082 C<$serviceType> itemorder,create,drop,commit,update,xmlupdate
4084 Currently, we only support 'create', 'commit', and 'update'. 'drop' support will be added as soon as Zebra supports it.
4088 sub set_service_options {
4089 my ($serviceType) = @_;
4092 # FIXME: This needs to be an OID ... if we ever need 'syntax' this sub will need to change
4093 # $serviceOptions->{ 'syntax' } = ''; #zebra doesn't support syntaxes other than xml
4095 if ( $serviceType eq 'commit' ) {
4099 if ( $serviceType eq 'create' ) {
4103 if ( $serviceType eq 'drop' ) {
4104 die "ERROR: 'drop' not currently supported (by Zebra)";
4106 return $serviceOptions;
4109 =head2 GetItemsCount
4111 $count = &GetItemsCount( $biblionumber);
4112 this function return count of item with $biblionumber
4116 my ( $biblionumber ) = @_;
4117 my $dbh = C4::Context->dbh;
4118 my $query = "SELECT count(*)
4120 WHERE biblionumber=?";
4121 my $sth = $dbh->prepare($query);
4122 $sth->execute($biblionumber);
4123 my $count = $sth->fetchrow;
4128 END { } # module clean-up code here (global destructor)
4136 Koha Developement team <info@koha.org>
4138 Paul POULAIN paul.poulain@free.fr
4140 Joshua Ferraro jmf@liblime.com