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
25 use MARC::File::USMARC;
31 use C4::Log; # logaction
33 use vars qw($VERSION @ISA @EXPORT);
35 # set the version for version checking
36 $VERSION = do { my @v = '$Revision$' =~ /\d+/g; shift(@v).".".join( "_", map { sprintf "%03d", $_ } @v ); };
38 @ISA = qw( Exporter );
42 # to add biblios or items
43 push @EXPORT, qw( &AddBiblio &AddItem );
51 &GetBiblioItemByBiblioNumber
52 &GetBiblioFromItemNumber
70 &GetAuthorisedValueDesc
84 &ModItemInMarconefield
94 # those functions are exported but should not be used
95 # they are usefull is few circumstances, so are exported.
96 # but don't use them unless you're a core developer ;-)
109 &PrepareItemrecordDisplay
115 C4::Biblio - cataloging management functions
119 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:
123 =item 1. in the biblio,biblioitems,items, etc tables, which are limited to a one-to-one mapping to underlying MARC data
125 =item 2. as raw MARC in the Zebra index and storage engine
127 =item 3. as raw MARC the biblioitems.marc and biblioitems.marcxml
131 In the 3.0 version of Koha, the authoritative record-level information is in biblioitems.marcxml
133 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.
137 =item 1. Compared with MySQL, Zebra is slow to update an index for small data changes -- especially for proc-intensive operations like circulation
139 =item 2. Zebra's index has been known to crash and a backup of the data is necessary to rebuild it in such cases
143 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:
147 =item 1. Add*/Mod*/Del*/ - high-level external functions suitable for being called from external scripts to manage the collection
149 =item 2. _koha_* - low-level internal functions for managing the koha tables
151 =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.
153 =item 4. Zebra functions used to update the Zebra index
155 =item 5. internal helper functions such as char_decode, checkitems, etc. Some of these probably belong in Koha.pm
159 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 :
163 =item 1. save datas in biblio and biblioitems table, that gives us a biblionumber and a biblioitemnumber
165 =item 2. add the biblionumber and biblioitemnumber into the MARC records
167 =item 3. save the marc record
171 When dealing with items, we must :
175 =item 1. save the item in items table, that gives us an itemnumber
177 =item 2. add the itemnumber to the item MARC field
179 =item 3. overwrite the MARC record (with the added item) into biblioitems.marc(xml)
181 When modifying a biblio or an item, the behaviour is quite similar.
185 =head1 EXPORTED FUNCTIONS
191 ($biblionumber,$biblioitemnumber) = AddBiblio($record,$frameworkcode);
192 Exported function (core API) for adding a new biblio to koha.
199 my ( $record, $frameworkcode ) = @_;
201 my $biblioitemnumber;
202 my $dbh = C4::Context->dbh;
203 # transform the data into koha-table style data
204 my $olddata = TransformMarcToKoha( $dbh, $record, $frameworkcode );
205 $biblionumber = _koha_add_biblio( $dbh, $olddata, $frameworkcode );
206 $olddata->{'biblionumber'} = $biblionumber;
207 $biblioitemnumber = _koha_add_biblioitem( $dbh, $olddata );
209 # we must add bibnum and bibitemnum in MARC::Record...
210 # we build the new field with biblionumber and biblioitemnumber
211 # we drop the original field
212 # we add the new builded field.
213 ( my $biblio_tag, my $biblio_subfield ) = GetMarcFromKohaField($dbh,"biblio.biblionumber",$frameworkcode);
214 ( my $biblioitem_tag, my $biblioitem_subfield ) = GetMarcFromKohaField($dbh,"biblioitems.biblioitemnumber",$frameworkcode);
218 # biblionumber & biblioitemnumber are in different fields
219 if ( $biblio_tag != $biblioitem_tag ) {
221 # deal with biblionumber
222 if ( $biblio_tag < 10 ) {
223 $newfield = MARC::Field->new( $biblio_tag, $biblionumber );
227 MARC::Field->new( $biblio_tag, '', '',
228 "$biblio_subfield" => $biblionumber );
231 # drop old field and create new one...
232 my $old_field = $record->field($biblio_tag);
233 $record->delete_field($old_field);
234 $record->append_fields($newfield);
236 # deal with biblioitemnumber
237 if ( $biblioitem_tag < 10 ) {
238 $newfield = MARC::Field->new( $biblioitem_tag, $biblioitemnumber, );
242 MARC::Field->new( $biblioitem_tag, '', '',
243 "$biblioitem_subfield" => $biblioitemnumber, );
245 # drop old field and create new one...
246 $old_field = $record->field($biblioitem_tag);
247 $record->delete_field($old_field);
248 $record->insert_fields_ordered($newfield);
250 # biblionumber & biblioitemnumber are in the same field (can't be <10 as fields <10 have only 1 value)
253 my $newfield = MARC::Field->new(
255 "$biblio_subfield" => $biblionumber,
256 "$biblioitem_subfield" => $biblioitemnumber
259 # drop old field and create new one...
260 my $old_field = $record->field($biblio_tag);
261 $record->delete_field($old_field);
262 $record->insert_fields_ordered($newfield);
267 ModBiblioMarc( $record, $biblionumber, $frameworkcode );
269 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","ADD",$biblionumber,"biblio")
270 if C4::Context->preference("CataloguingLog");
272 return ( $biblionumber, $biblioitemnumber );
279 $biblionumber = AddItem( $record, $biblionumber)
280 Exported function (core API) for adding a new item to Koha
287 my ( $record, $biblionumber ) = @_;
288 my $dbh = C4::Context->dbh;
291 my $frameworkcode = GetFrameworkCode( $biblionumber );
292 my $item = &TransformMarcToKoha( $dbh, $record, $frameworkcode );
294 # needs old biblionumber and biblioitemnumber
295 $item->{'biblionumber'} = $biblionumber;
298 "select biblioitemnumber,itemtype from biblioitems where biblionumber=?"
300 $sth->execute( $item->{'biblionumber'} );
302 ( $item->{'biblioitemnumber'}, $itemtype ) = $sth->fetchrow;
305 "select notforloan from itemtypes where itemtype='$itemtype'");
307 my $notforloan = $sth->fetchrow;
308 ##Change the notforloan field if $notforloan found
309 if ( $notforloan > 0 ) {
310 $item->{'notforloan'} = $notforloan;
311 &MARCitemchange( $record, "items.notforloan", $notforloan );
313 if ( !$item->{'dateaccessioned'} || $item->{'dateaccessioned'} eq '' ) {
316 my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) =
321 "$year-" . sprintf( "%0.2d", $mon ) . "-" . sprintf( "%0.2d", $mday );
322 $item->{'dateaccessioned'} = $date;
323 &MARCitemchange( $record, "items.dateaccessioned", $date );
325 my ( $itemnumber, $error ) =
326 &_koha_new_items( $dbh, $item, $item->{barcode} );
328 # add itemnumber to MARC::Record before adding the item.
331 "select tagfield,tagsubfield from marc_subfield_structure where frameworkcode=? and kohafield=?"
333 &TransformKohaToMarcOneField( $sth, $record, "items.itemnumber", $itemnumber,
337 &AddItemInMarc( $record, $item->{'biblionumber'},$frameworkcode );
339 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","ADD",$itemnumber,"item")
340 if C4::Context->preference("CataloguingLog");
342 return ($item->{biblionumber}, $item->{biblioitemnumber},$itemnumber);
349 ModBiblio( $record,$biblionumber,$frameworkcode);
350 Exported function (core API) to modify a biblio
357 my ( $record, $biblionumber, $frameworkcode ) = @_;
359 if (C4::Context->preference("CataloguingLog")) {
360 my $newrecord = GetMarcBiblio($biblionumber);
361 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","MODIFY",$biblionumber,$newrecord->as_formatted)
364 my $dbh = C4::Context->dbh;
366 $frameworkcode = "" unless $frameworkcode;
368 # update the MARC record with the new record data
369 &ModBiblioMarc($record, $biblionumber, $frameworkcode );
371 # load the koha-table data object
372 my $oldbiblio = TransformMarcToKoha( $dbh, $record, $frameworkcode );
374 # modify the other koha tables
375 my $biblionumber = _koha_modify_biblio( $dbh, $oldbiblio );
376 _koha_modify_biblioitem( $dbh, $oldbiblio );
385 Exported function (core API) for modifying an item in Koha.
392 my ( $record, $biblionumber, $itemnumber, $delete, $new_item_hashref )
396 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","MODIFY",$itemnumber,$record->as_formatted)
397 if C4::Context->preference("CataloguingLog");
399 my $dbh = C4::Context->dbh;
401 # if we have a MARC record, we're coming from cataloging and so
402 # we do the whole routine: update the MARC and zebra, then update the koha
405 my $frameworkcode = GetFrameworkCode( $biblionumber );
406 ModItemInMarc( $record, $biblionumber, $itemnumber, $frameworkcode );
407 my $olditem = TransformMarcToKoha( $dbh, $record, $frameworkcode );
408 _koha_modify_item( $dbh, $olditem );
409 return $biblionumber;
412 # otherwise, we're just looking to modify something quickly
413 # (like a status) so we just update the koha tables
414 elsif ($new_item_hashref) {
415 _koha_modify_item( $dbh, $new_item_hashref );
419 =head2 ModBiblioframework
423 ModBiblioframework($biblionumber,$frameworkcode);
424 Exported function to modify a biblio framework
430 sub ModBiblioframework {
431 my ( $biblionumber, $frameworkcode ) = @_;
432 my $dbh = C4::Context->dbh;
435 "UPDATE biblio SET frameworkcode=? WHERE biblionumber=$biblionumber");
436 $sth->execute($frameworkcode);
440 =head2 ModItemInMarconefield
444 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)
445 &ModItemInMarconefield( $biblionumber, $itemnumber, $itemfield, $newvalue )
451 sub ModItemInMarconefield {
452 my ( $biblionumber, $itemnumber, $itemfield, $newvalue ) = @_;
453 my $dbh = C4::Context->dbh;
454 if ( !defined $newvalue ) {
458 my $record = GetMarcItem( $biblionumber, $itemnumber );
459 my ($tagfield, $tagsubfield) = GetMarcFromKohaField($dbh, $itemfield,'');
460 if ($tagfield && $tagsubfield) {
461 my $tag = $record->field($tagfield);
463 # my $tagsubs = $record->field($tagfield)->subfield($tagsubfield);
464 $tag->update( $tagsubfield => $newvalue );
465 $record->delete_field($tag);
466 $record->insert_fields_ordered($tag);
467 &ModItemInMarc( $record, $biblionumber, $itemnumber, 0 );
476 &ModItemInMarc( $record, $biblionumber, $itemnumber )
483 my ( $ItemRecord, $biblionumber, $itemnumber, $frameworkcode) = @_;
484 my $dbh = C4::Context->dbh;
486 # get complete MARC record & replace the item field by the new one
487 my $completeRecord = GetMarcBiblio($biblionumber);
488 my ($itemtag,$itemsubfield) = GetMarcFromKohaField($dbh,"items.itemnumber",$frameworkcode);
489 my $itemField = $ItemRecord->field($itemtag);
490 my @items = $completeRecord->field($itemtag);
492 if ($_->subfield($itemsubfield) eq $itemnumber) {
493 # $completeRecord->delete_field($_);
494 $_->replace_with($itemField);
498 my $sth = $dbh->prepare("update biblioitems set marc=?,marcxml=? where biblionumber=?");
499 $sth->execute( $completeRecord->as_usmarc(), $completeRecord->as_xml_record(),$biblionumber );
501 ModZebra($biblionumber,"specialUpdate","biblioserver");
508 my $error = &DelBiblio($dbh,$biblionumber);
509 Exported function (core API) for deleting a biblio in koha.
510 Deletes biblio record from Zebra and Koha tables (biblio,biblioitems,items)
511 Also backs it up to deleted* tables
512 Checks to make sure there are not issues on any of the items
514 C<$error> : undef unless an error occurs
521 my ( $biblionumber ) = @_;
522 my $dbh = C4::Context->dbh;
523 my $error; # for error handling
525 # First make sure there are no items with issues are still attached
528 "SELECT biblioitemnumber FROM biblioitems WHERE biblionumber=?");
529 $sth->execute($biblionumber);
530 while ( my $biblioitemnumber = $sth->fetchrow ) {
531 my @issues = C4::Circulation::Circ2::itemissues($biblioitemnumber);
532 foreach my $issue (@issues) {
533 if ( ( $issue->{date_due} )
534 && ( $issue->{date_due} ne "Available" ) )
537 #FIXME: we need a status system in Biblio like in Circ to return standard codes and messages
538 # instead of hard-coded strings
540 "Item is checked out to a patron -- you must return it before deleting the Biblio";
544 return $error if $error;
547 ModZebra($biblionumber,"delete_record","biblioserver");
549 # delete biblio from Koha tables and save in deletedbiblio
550 $error = &_koha_delete_biblio( $dbh, $biblionumber );
552 # delete biblioitems and items from Koha tables and save in deletedbiblioitems,deleteditems
555 "SELECT biblioitemnumber FROM biblioitems WHERE biblionumber=?");
556 $sth->execute($biblionumber);
557 while ( my $biblioitemnumber = $sth->fetchrow ) {
559 # delete this biblioitem
560 $error = &_koha_delete_biblioitems( $dbh, $biblioitemnumber );
561 return $error if $error;
566 "SELECT itemnumber FROM items WHERE biblioitemnumber=?");
567 $items_sth->execute($biblioitemnumber);
568 while ( my $itemnumber = $items_sth->fetchrow ) {
569 $error = &_koha_delete_item( $dbh, $itemnumber );
570 return $error if $error;
573 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","DELETE",$biblionumber,"")
574 if C4::Context->preference("CataloguingLog");
582 DelItem( $biblionumber, $itemnumber );
583 Exported function (core API) for deleting an item record in Koha.
590 my ( $biblionumber, $itemnumber ) = @_;
591 my $dbh = C4::Context->dbh;
592 &_koha_delete_item( $dbh, $itemnumber );
593 # get the MARC record
594 my $record = GetMarcBiblio($biblionumber);
595 my $frameworkcode = GetFrameworkCode($biblionumber);
599 $dbh->prepare("UPDATE deleteditems SET marc=? WHERE itemnumber=?");
600 $copy2deleted->execute( $record->as_usmarc(), $itemnumber );
602 #search item field code
603 my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField($dbh,"items.itemnumber",$frameworkcode);
604 my @fields = $record->field($itemtag);
605 # delete the item specified
606 foreach my $field (@fields) {
607 if ( $field->subfield($itemsubfield) eq $itemnumber ) {
608 $record->delete_field($field);
611 &ModBiblioMarc( $record, $biblionumber, $frameworkcode );
612 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","DELETE",$itemnumber,"item")
613 if C4::Context->preference("CataloguingLog");
620 $data = &GetBiblioData($biblionumber);
621 Returns information about the book with the given biblionumber.
622 C<&GetBiblioData> returns a reference-to-hash. The keys are the fields in
623 the C<biblio> and C<biblioitems> tables in the
625 In addition, C<$data-E<gt>{subject}> is the list of the book's
626 subjects, separated by C<" , "> (space, comma, space).
627 If there are multiple biblioitems with the given biblionumber, only
628 the first one is considered.
636 my $dbh = C4::Context->dbh;
639 SELECT * , biblioitems.notes AS bnotes, biblio.notes
641 LEFT JOIN biblioitems ON biblio.biblionumber = biblioitems.biblionumber
642 LEFT JOIN itemtypes ON biblioitems.itemtype = itemtypes.itemtype
643 WHERE biblio.biblionumber = ?
644 AND biblioitems.biblionumber = biblio.biblionumber
646 my $sth = $dbh->prepare($query);
647 $sth->execute($bibnum);
649 $data = $sth->fetchrow_hashref;
653 } # sub GetBiblioData
660 @results = &GetItemsInfo($biblionumber, $type);
662 Returns information about books with the given biblionumber.
664 C<$type> may be either C<intra> or anything else. If it is not set to
665 C<intra>, then the search will exclude lost, very overdue, and
668 C<&GetItemsInfo> returns a list of references-to-hash. Each element
669 contains a number of keys. Most of them are table items from the
670 C<biblio>, C<biblioitems>, C<items>, and C<itemtypes> tables in the
671 Koha database. Other keys include:
675 =item C<$data-E<gt>{branchname}>
677 The name (not the code) of the branch to which the book belongs.
679 =item C<$data-E<gt>{datelastseen}>
681 This is simply C<items.datelastseen>, except that while the date is
682 stored in YYYY-MM-DD format in the database, here it is converted to
683 DD/MM/YYYY format. A NULL date is returned as C<//>.
685 =item C<$data-E<gt>{datedue}>
687 =item C<$data-E<gt>{class}>
689 This is the concatenation of C<biblioitems.classification>, the book's
690 Dewey code, and C<biblioitems.subclass>.
692 =item C<$data-E<gt>{ocount}>
694 I think this is the number of copies of the book available.
696 =item C<$data-E<gt>{order}>
698 If this is set, it is set to C<One Order>.
707 my ( $biblionumber, $type ) = @_;
708 my $dbh = C4::Context->dbh;
709 my $query = "SELECT *,items.notforloan as itemnotforloan
710 FROM items, biblio, biblioitems
711 LEFT JOIN itemtypes on biblioitems.itemtype = itemtypes.itemtype
712 WHERE items.biblionumber = ?
713 AND biblioitems.biblioitemnumber = items.biblioitemnumber
714 AND biblio.biblionumber = items.biblionumber
715 ORDER BY items.dateaccessioned desc
717 my $sth = $dbh->prepare($query);
718 $sth->execute($biblionumber);
721 my ( $date_due, $count_reserves );
723 while ( my $data = $sth->fetchrow_hashref ) {
725 my $isth = $dbh->prepare(
726 "SELECT issues.*,borrowers.cardnumber
727 FROM issues, borrowers
729 AND returndate IS NULL
730 AND issues.borrowernumber=borrowers.borrowernumber"
732 $isth->execute( $data->{'itemnumber'} );
733 if ( my $idata = $isth->fetchrow_hashref ) {
734 $data->{borrowernumber} = $idata->{borrowernumber};
735 $data->{cardnumber} = $idata->{cardnumber};
736 $datedue = format_date( $idata->{'date_due'} );
738 if ( $datedue eq '' ) {
739 #$datedue="Available";
740 my ( $restype, $reserves ) =
741 C4::Reserves2::CheckReserves( $data->{'itemnumber'} );
745 $count_reserves = $restype;
750 #get branch information.....
751 my $bsth = $dbh->prepare(
752 "SELECT * FROM branches WHERE branchcode = ?
755 $bsth->execute( $data->{'holdingbranch'} );
756 if ( my $bdata = $bsth->fetchrow_hashref ) {
757 $data->{'branchname'} = $bdata->{'branchname'};
759 my $date = format_date( $data->{'datelastseen'} );
760 $data->{'datelastseen'} = $date;
761 $data->{'datedue'} = $datedue;
762 $data->{'count_reserves'} = $count_reserves;
764 # get notforloan complete status if applicable
765 my $sthnflstatus = $dbh->prepare(
766 'SELECT authorised_value
767 FROM marc_subfield_structure
768 WHERE kohafield="items.notforloan"
772 $sthnflstatus->execute;
773 my ($authorised_valuecode) = $sthnflstatus->fetchrow;
774 if ($authorised_valuecode) {
775 $sthnflstatus = $dbh->prepare(
776 "SELECT lib FROM authorised_values
778 AND authorised_value=?"
780 $sthnflstatus->execute( $authorised_valuecode,
781 $data->{itemnotforloan} );
782 my ($lib) = $sthnflstatus->fetchrow;
783 $data->{notforloan} = $lib;
786 # my stack procedures
787 my $stackstatus = $dbh->prepare(
788 'SELECT authorised_value
789 FROM marc_subfield_structure
790 WHERE kohafield="items.stack"
793 $stackstatus->execute;
795 ($authorised_valuecode) = $stackstatus->fetchrow;
796 if ($authorised_valuecode) {
797 $stackstatus = $dbh->prepare(
799 FROM authorised_values
801 AND authorised_value=?
804 $stackstatus->execute( $authorised_valuecode, $data->{stack} );
805 my ($lib) = $stackstatus->fetchrow;
806 $data->{stack} = $lib;
808 $results[$i] = $data;
820 $itemstatushash = &getitemstatus($fwkcode);
821 returns information about status.
822 Can be MARC dependant.
824 But basically could be can be loan or not
825 Create a status selector with the following code
827 =head3 in PERL SCRIPT
829 my $itemstatushash = getitemstatus;
831 foreach my $thisstatus (keys %$itemstatushash) {
832 my %row =(value => $thisstatus,
833 statusname => $itemstatushash->{$thisstatus}->{'statusname'},
835 push @itemstatusloop, \%row;
837 $template->param(statusloop=>\@itemstatusloop);
842 <select name="statusloop">
843 <option value="">Default</option>
844 <!-- TMPL_LOOP name="statusloop" -->
845 <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="statusname" --></option>
853 # returns a reference to a hash of references to status...
856 my $dbh = C4::Context->dbh;
858 $fwk = '' unless ($fwk);
859 my ( $tag, $subfield ) =
860 GetMarcFromKohaField( $dbh, "items.notforloan", $fwk );
861 if ( $tag and $subfield ) {
864 "select authorised_value from marc_subfield_structure where tagfield=? and tagsubfield=? and frameworkcode=?"
866 $sth->execute( $tag, $subfield, $fwk );
867 if ( my ($authorisedvaluecat) = $sth->fetchrow ) {
870 "select authorised_value, lib from authorised_values where category=? order by lib"
872 $authvalsth->execute($authorisedvaluecat);
873 while ( my ( $authorisedvalue, $lib ) = $authvalsth->fetchrow ) {
874 $itemstatus{$authorisedvalue} = $lib;
890 $itemstatus{"1"} = "Not For Loan";
894 =head2 getitemlocation
898 $itemlochash = &getitemlocation($fwk);
899 returns informations about location.
900 where fwk stands for an optional framework code.
901 Create a location selector with the following code
903 =head3 in PERL SCRIPT
905 my $itemlochash = getitemlocation;
907 foreach my $thisloc (keys %$itemlochash) {
908 my $selected = 1 if $thisbranch eq $branch;
909 my %row =(locval => $thisloc,
910 selected => $selected,
911 locname => $itemlochash->{$thisloc},
913 push @itemlocloop, \%row;
915 $template->param(itemlocationloop => \@itemlocloop);
919 <select name="location">
920 <option value="">Default</option>
921 <!-- TMPL_LOOP name="itemlocationloop" -->
922 <option value="<!-- TMPL_VAR name="locval" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="locname" --></option>
930 sub GetItemLocation {
932 # returns a reference to a hash of references to location...
935 my $dbh = C4::Context->dbh;
937 $fwk = '' unless ($fwk);
938 my ( $tag, $subfield ) =
939 GetMarcFromKohaField( $dbh, "items.location", $fwk );
940 if ( $tag and $subfield ) {
943 "select authorised_value from marc_subfield_structure where tagfield=? and tagsubfield=? and frameworkcode=?"
945 $sth->execute( $tag, $subfield, $fwk );
946 if ( my ($authorisedvaluecat) = $sth->fetchrow ) {
949 "select authorised_value, lib from authorised_values where category=? order by lib"
951 $authvalsth->execute($authorisedvaluecat);
952 while ( my ( $authorisedvalue, $lib ) = $authvalsth->fetchrow ) {
953 $itemlocation{$authorisedvalue} = $lib;
956 return \%itemlocation;
969 $itemlocation{"1"} = "Not For Loan";
970 return \%itemlocation;
973 =head2 &GetBiblioItemData
977 $itemdata = &GetBiblioItemData($biblioitemnumber);
979 Looks up the biblioitem with the given biblioitemnumber. Returns a
980 reference-to-hash. The keys are the fields from the C<biblio>,
981 C<biblioitems>, and C<itemtypes> tables in the Koha database, except
982 that C<biblioitems.notes> is given as C<$itemdata-E<gt>{bnotes}>.
989 sub GetBiblioItemData {
991 my $dbh = C4::Context->dbh;
994 "Select *,biblioitems.notes as bnotes from biblioitems, biblio,itemtypes where biblio.biblionumber = biblioitems.biblionumber and biblioitemnumber = ? and biblioitems.itemtype = itemtypes.itemtype"
998 $sth->execute($bibitem);
1000 $data = $sth->fetchrow_hashref;
1004 } # sub &GetBiblioItemData
1006 =head2 GetItemFromBarcode
1010 $result = GetItemFromBarcode($barcode);
1016 sub GetItemFromBarcode {
1018 my $dbh = C4::Context->dbh;
1021 $dbh->prepare("SELECT itemnumber from items where items.barcode=?");
1022 $rq->execute($barcode);
1023 my ($result) = $rq->fetchrow;
1027 =head2 GetBiblioItemByBiblioNumber
1031 NOTE : This function has been copy/paste from C4/Biblio.pm from head before zebra integration.
1037 sub GetBiblioItemByBiblioNumber {
1038 my ($biblionumber) = @_;
1039 my $dbh = C4::Context->dbh;
1040 my $sth = $dbh->prepare("Select * from biblioitems where biblionumber = ?");
1044 $sth->execute($biblionumber);
1046 while ( my $data = $sth->fetchrow_hashref ) {
1047 push @results, $data;
1054 =head2 GetBiblioFromItemNumber
1058 $item = &GetBiblioFromItemNumber($itemnumber);
1060 Looks up the item with the given itemnumber.
1062 C<&itemnodata> returns a reference-to-hash whose keys are the fields
1063 from the C<biblio>, C<biblioitems>, and C<items> tables in the Koha
1071 sub GetBiblioFromItemNumber {
1072 my ( $itemnumber ) = @_;
1073 my $dbh = C4::Context->dbh;
1075 my $sth = $dbh->prepare(
1076 "SELECT * FROM biblio,items,biblioitems
1077 WHERE items.itemnumber = ?
1078 AND biblio.biblionumber = items.biblionumber
1079 AND biblioitems.biblioitemnumber = items.biblioitemnumber"
1082 $sth->execute($itemnumber);
1083 my $data = $sth->fetchrow_hashref;
1092 ( $count, @results ) = &GetBiblio($biblionumber);
1099 my ($biblionumber) = @_;
1100 my $dbh = C4::Context->dbh;
1101 my $sth = $dbh->prepare("Select * from biblio where biblionumber = ?");
1104 $sth->execute($biblionumber);
1105 while ( my $data = $sth->fetchrow_hashref ) {
1106 $results[$count] = $data;
1110 return ( $count, @results );
1113 =head2 get_itemnumbers_of
1117 my @itemnumbers_of = get_itemnumbers_of(@biblionumbers);
1119 Given a list of biblionumbers, return the list of corresponding itemnumbers
1120 for each biblionumber.
1122 Return a reference on a hash where keys are biblionumbers and values are
1123 references on array of itemnumbers.
1129 sub get_itemnumbers_of {
1130 my @biblionumbers = @_;
1132 my $dbh = C4::Context->dbh;
1138 WHERE biblionumber IN (?' . ( ',?' x scalar @biblionumbers - 1 ) . ')
1140 my $sth = $dbh->prepare($query);
1141 $sth->execute(@biblionumbers);
1145 while ( my ( $itemnumber, $biblionumber ) = $sth->fetchrow_array ) {
1146 push @{ $itemnumbers_of{$biblionumber} }, $itemnumber;
1149 return \%itemnumbers_of;
1152 =head2 GetItemInfosOf
1156 GetItemInfosOf(@itemnumbers);
1162 sub GetItemInfosOf {
1163 my @itemnumbers = @_;
1168 WHERE itemnumber IN (' . join( ',', @itemnumbers ) . ')
1170 return get_infos_of( $query, 'itemnumber' );
1173 =head2 GetBiblioItemInfosOf
1177 GetBiblioItemInfosOf(@biblioitemnumbers);
1183 sub GetBiblioItemInfosOf {
1184 my @biblioitemnumbers = @_;
1187 SELECT biblioitemnumber,
1191 WHERE biblioitemnumber IN (' . join( ',', @biblioitemnumbers ) . ')
1193 return get_infos_of( $query, 'biblioitemnumber' );
1196 =head1 FUNCTIONS FOR HANDLING MARC MANAGEMENT
1198 =head2 GetMarcStructure
1202 $res = GetMarcStructure($dbh,$forlibrarian,$frameworkcode);
1204 Returns a reference to a big hash of hash, with the Marc structure fro the given frameworkcode
1206 $forlibrarian :if set to 1, the MARC descriptions are the librarians ones, otherwise it's the public (OPAC) ones
1207 $frameworkcode : the framework code to read
1215 sub GetMarcStructure {
1216 my ( $dbh, $forlibrarian, $frameworkcode ) = @_;
1217 $frameworkcode = "" unless $frameworkcode;
1219 my $libfield = ( $forlibrarian eq 1 ) ? 'liblibrarian' : 'libopac';
1221 # check that framework exists
1224 "select count(*) from marc_tag_structure where frameworkcode=?");
1225 $sth->execute($frameworkcode);
1226 my ($total) = $sth->fetchrow;
1227 $frameworkcode = "" unless ( $total > 0 );
1230 "select tagfield,liblibrarian,libopac,mandatory,repeatable from marc_tag_structure where frameworkcode=? order by tagfield"
1232 $sth->execute($frameworkcode);
1233 my ( $liblibrarian, $libopac, $tag, $res, $tab, $mandatory, $repeatable );
1235 while ( ( $tag, $liblibrarian, $libopac, $mandatory, $repeatable ) =
1238 $res->{$tag}->{lib} =
1239 ( $forlibrarian or !$libopac ) ? $liblibrarian : $libopac;
1240 # why the hell do we need to explicitly decode utf8 ?
1241 # that's a good question, but we must do it...
1243 utf8::decode($res->{$tag}->{lib});
1244 # warn "$liblibrarian";
1245 $res->{$tab}->{tab} = ""; # XXX
1246 $res->{$tag}->{mandatory} = $mandatory;
1247 $res->{$tag}->{repeatable} = $repeatable;
1252 "select tagfield,tagsubfield,liblibrarian,libopac,tab, mandatory, repeatable,authorised_value,authtypecode,value_builder,kohafield,seealso,hidden,isurl,link,defaultvalue from marc_subfield_structure where frameworkcode=? order by tagfield,tagsubfield"
1254 $sth->execute($frameworkcode);
1257 my $authorised_value;
1269 $tag, $subfield, $liblibrarian,
1271 $mandatory, $repeatable, $authorised_value,
1272 $authtypecode, $value_builder, $kohafield,
1273 $seealso, $hidden, $isurl,
1279 $res->{$tag}->{$subfield}->{lib} =
1280 ( $forlibrarian or !$libopac ) ? $liblibrarian : $libopac;
1281 $res->{$tag}->{$subfield}->{tab} = $tab;
1282 $res->{$tag}->{$subfield}->{mandatory} = $mandatory;
1283 $res->{$tag}->{$subfield}->{repeatable} = $repeatable;
1284 $res->{$tag}->{$subfield}->{authorised_value} = $authorised_value;
1285 $res->{$tag}->{$subfield}->{authtypecode} = $authtypecode;
1286 $res->{$tag}->{$subfield}->{value_builder} = $value_builder;
1287 $res->{$tag}->{$subfield}->{kohafield} = $kohafield;
1288 $res->{$tag}->{$subfield}->{seealso} = $seealso;
1289 $res->{$tag}->{$subfield}->{hidden} = $hidden;
1290 $res->{$tag}->{$subfield}->{isurl} = $isurl;
1291 $res->{$tag}->{$subfield}->{link} = $link;
1292 $res->{$tag}->{$subfield}->{defaultvalue} = $defaultvalue;
1297 =head2 GetMarcFromKohaField
1301 ($MARCfield,$MARCsubfield)=GetMarcFromKohaField($dbh,$kohafield,$frameworkcode);
1302 Returns the MARC fields & subfields mapped to the koha field
1303 for the given frameworkcode
1309 sub GetMarcFromKohaField {
1310 my ( $dbh, $kohafield, $frameworkcode ) = @_;
1311 return 0, 0 unless $kohafield;
1312 my $relations = C4::Context->marcfromkohafield;
1314 $relations->{$frameworkcode}->{$kohafield}->[0],
1315 $relations->{$frameworkcode}->{$kohafield}->[1]
1319 =head2 GetMarcBiblio
1323 Returns MARC::Record of the biblionumber passed in parameter.
1324 the marc record contains both biblio & item datas
1331 my $biblionumber = shift;
1332 my $dbh = C4::Context->dbh;
1334 $dbh->prepare("select marcxml from biblioitems where biblionumber=? ");
1335 $sth->execute($biblionumber);
1336 my ($marcxml) = $sth->fetchrow;
1337 # warn "marcxml : $marcxml";
1338 MARC::File::XML->default_record_format(C4::Context->preference('marcflavour'));
1339 $marcxml =~ s/\x1e//g;
1340 $marcxml =~ s/\x1f//g;
1341 $marcxml =~ s/\x1d//g;
1342 $marcxml =~ s/\x0f//g;
1343 $marcxml =~ s/\x0c//g;
1344 my $record = MARC::Record->new();
1345 $record = MARC::Record::new_from_xml( $marcxml, "utf8",C4::Context->preference('marcflavour')) if $marcxml;
1353 my $marcxml = GetXmlBiblio($biblionumber);
1355 Returns biblioitems.marcxml of the biblionumber passed in parameter.
1356 The XML contains both biblio & item datas
1363 my ( $biblionumber ) = @_;
1364 my $dbh = C4::Context->dbh;
1366 $dbh->prepare("select marcxml from biblioitems where biblionumber=? ");
1367 $sth->execute($biblionumber);
1368 my ($marcxml) = $sth->fetchrow;
1372 =head2 GetAuthorisedValueDesc
1376 my $subfieldvalue =get_authorised_value_desc(
1377 $tag, $subf[$i][0],$subf[$i][1], '', $taglib);
1378 Retrieve the complete description for a given authorised value.
1384 sub GetAuthorisedValueDesc {
1385 my ( $tag, $subfield, $value, $framework, $tagslib ) = @_;
1386 my $dbh = C4::Context->dbh;
1389 if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq "branches" ) {
1390 return C4::Branch::GetBranchName($value);
1394 if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq "itemtypes" ) {
1395 return getitemtypeinfo($value);
1398 #---- "true" authorized value
1399 my $category = $tagslib->{$tag}->{$subfield}->{'authorised_value'};
1401 if ( $category ne "" ) {
1404 "select lib from authorised_values where category = ? and authorised_value = ?"
1406 $sth->execute( $category, $value );
1407 my $data = $sth->fetchrow_hashref;
1408 return $data->{'lib'};
1411 return $value; # if nothing is found return the original value
1419 Returns MARC::Record of the item passed in parameter.
1426 my ( $biblionumber, $itemnumber ) = @_;
1427 my $dbh = C4::Context->dbh;
1428 my $newrecord = MARC::Record->new();
1429 my $marcflavour = C4::Context->preference('marcflavour');
1431 my $marcxml = GetXmlBiblio($biblionumber);
1432 my $record = MARC::Record->new();
1433 # warn "marcxml :$marcxml";
1434 $record = MARC::Record::new_from_xml( $marcxml, "utf8", $marcflavour );
1435 # warn "record :".$record->as_formatted;
1436 # now, find where the itemnumber is stored & extract only the item
1437 my ( $itemnumberfield, $itemnumbersubfield ) =
1438 GetMarcFromKohaField( $dbh, 'items.itemnumber', '' );
1439 my @fields = $record->field($itemnumberfield);
1440 foreach my $field (@fields) {
1441 if ( $field->subfield($itemnumbersubfield) eq $itemnumber ) {
1442 $newrecord->insert_fields_ordered($field);
1452 $marcnotesarray = GetMarcNotes( $record, $marcflavour );
1453 Get all notes from the MARC record and returns them in an array.
1454 The note are stored in differents places depending on MARC flavour
1461 my ( $record, $marcflavour ) = @_;
1463 if ( $marcflavour eq "MARC21" ) {
1466 else { # assume unimarc if not marc21
1473 foreach my $field ( $record->field($scope) ) {
1474 my $value = $field->as_string();
1475 if ( $note ne "" ) {
1476 $marcnote = { marcnote => $note, };
1477 push @marcnotes, $marcnote;
1480 if ( $note ne $value ) {
1481 $note = $note . " " . $value;
1486 $marcnote = { marcnote => $note };
1487 push @marcnotes, $marcnote; #load last tag into array
1490 } # end GetMarcNotes
1492 =head2 GetMarcSubjects
1496 $marcsubjcts = GetMarcSubjects($record,$marcflavour);
1497 Get all subjects from the MARC record and returns them in an array.
1498 The subjects are stored in differents places depending on MARC flavour
1504 sub GetMarcSubjects {
1505 my ( $record, $marcflavour ) = @_;
1506 my ( $mintag, $maxtag );
1507 if ( $marcflavour eq "MARC21" ) {
1511 else { # assume unimarc if not marc21
1518 foreach my $field ( $record->fields ) {
1519 next unless $field->tag() >= $mintag && $field->tag() <= $maxtag;
1520 my @subfields = $field->subfields();
1524 for my $subject_subfield ( @subfields ) {
1525 my $code = $subject_subfield->[0];
1526 $label .= $subject_subfield->[1] . " and su-to:" unless ( $code == 9 );
1528 $link = "Koha-Auth-Number:".$subject_subfield->[1];
1533 $link =~ s/ and\ssu-to:$//;
1546 return \@marcsubjcts;
1547 } #end GetMarcSubjects
1549 =head2 GetMarcAuthors
1553 authors = GetMarcAuthors($record,$marcflavour);
1554 Get all authors from the MARC record and returns them in an array.
1555 The authors are stored in differents places depending on MARC flavour
1561 sub GetMarcAuthors {
1562 my ( $record, $marcflavour ) = @_;
1563 my ( $mintag, $maxtag );
1564 if ( $marcflavour eq "MARC21" ) {
1568 else { # assume unimarc if not marc21
1575 foreach my $field ( $record->fields ) {
1576 next unless $field->tag() >= $mintag && $field->tag() <= $maxtag;
1578 my @subfields = $field->subfields();
1581 for my $authors_subfield (@subfields) {
1582 if ($count_auth ne '0'){
1586 my $subfieldcode = $authors_subfield->[0];
1587 my $value = $authors_subfield->[1];
1588 $hash{'tag'} = $field->tag;
1589 $hash{value} .= $value . " " if ($subfieldcode != 9) ;
1590 $hash{link} .= $value if ($subfieldcode eq 9);
1592 push @marcauthors, \%hash;
1594 return \@marcauthors;
1597 =head2 GetMarcSeries
1601 $marcseriessarray = GetMarcSeries($record,$marcflavour);
1602 Get all series from the MARC record and returns them in an array.
1603 The series are stored in differents places depending on MARC flavour
1610 my ($record, $marcflavour) = @_;
1611 my ($mintag, $maxtag);
1612 if ($marcflavour eq "MARC21") {
1615 } else { # assume unimarc if not marc21
1625 foreach my $field ($record->field('440'), $record->field('490')) {
1627 #my $value = $field->subfield('a');
1628 #$marcsubjct = {MARCSUBJCT => $value,};
1629 my @subfields = $field->subfields();
1630 #warn "subfields:".join " ", @$subfields;
1633 for my $series_subfield (@subfields) {
1635 undef $volume_number;
1636 # see if this is an instance of a volume
1637 if ($series_subfield->[0] eq 'v') {
1641 my $code = $series_subfield->[0];
1642 my $value = $series_subfield->[1];
1643 my $linkvalue = $value;
1644 $linkvalue =~ s/(\(|\))//g;
1645 my $operator = " and " unless $counter==0;
1646 push @link_loop, {link => $linkvalue, operator => $operator };
1647 my $separator = C4::Context->preference("authoritysep") unless $counter==0;
1648 if ($volume_number) {
1649 push @subfields_loop, {volumenum => $value};
1652 push @subfields_loop, {code => $code, value => $value, link_loop => \@link_loop, separator => $separator, volumenum => $volume_number};
1656 push @marcseries, { MARCSERIES_SUBFIELDS_LOOP => \@subfields_loop };
1657 #$marcsubjct = {MARCSUBJCT => $field->as_string(),};
1658 #push @marcsubjcts, $marcsubjct;
1662 my $marcseriessarray=\@marcseries;
1663 return $marcseriessarray;
1664 } #end getMARCseriess
1666 =head2 GetFrameworkCode
1670 $frameworkcode = GetFrameworkCode( $biblionumber )
1676 sub GetFrameworkCode {
1677 my ( $biblionumber ) = @_;
1678 my $dbh = C4::Context->dbh;
1680 $dbh->prepare("select frameworkcode from biblio where biblionumber=?");
1681 $sth->execute($biblionumber);
1682 my ($frameworkcode) = $sth->fetchrow;
1683 return $frameworkcode;
1686 =head2 TransformKohaToMarc
1690 $record = TransformKohaToMarc( $hash )
1691 This function builds partial MARC::Record from a hash
1692 Hash entries can be from biblio or biblioitems.
1693 This function is called in acquisition module, to create a basic catalogue entry from user entry
1699 sub TransformKohaToMarc {
1702 my $dbh = C4::Context->dbh;
1705 "select tagfield,tagsubfield from marc_subfield_structure where frameworkcode=? and kohafield=?"
1707 my $record = MARC::Record->new();
1708 foreach (keys %{$hash}) {
1709 &TransformKohaToMarcOneField( $sth, $record, $_,
1715 =head2 TransformKohaToMarcOneField
1719 $record = TransformKohaToMarcOneField( $sth, $record, $kohafieldname, $value, $frameworkcode );
1725 sub TransformKohaToMarcOneField {
1726 my ( $sth, $record, $kohafieldname, $value, $frameworkcode ) = @_;
1727 $frameworkcode='' unless $frameworkcode;
1731 if ( !defined $sth ) {
1732 my $dbh = C4::Context->dbh;
1735 "select tagfield,tagsubfield from marc_subfield_structure where frameworkcode=? and kohafield=?"
1738 $sth->execute( $frameworkcode, $kohafieldname );
1739 if ( ( $tagfield, $tagsubfield ) = $sth->fetchrow ) {
1740 my $tag = $record->field($tagfield);
1742 $tag->update( $tagsubfield => $value );
1743 $record->delete_field($tag);
1744 $record->insert_fields_ordered($tag);
1747 $record->add_fields( $tagfield, " ", " ", $tagsubfield => $value );
1753 =head2 TransformHtmlToXml
1757 $xml = TransformHtmlToXml( $tags, $subfields, $values, $indicator, $ind_tag )
1763 sub TransformHtmlToXml {
1764 my ( $tags, $subfields, $values, $indicator, $ind_tag ) = @_;
1765 my $xml = MARC::File::XML::header('UTF-8');
1766 if ( C4::Context->preference('marcflavour') eq 'UNIMARC' ) {
1767 MARC::File::XML->default_record_format('UNIMARC');
1768 use POSIX qw(strftime);
1769 my $string = strftime( "%Y%m%d", localtime(time) );
1770 $string = sprintf( "%-*s", 35, $string );
1771 substr( $string, 22, 6, "frey50" );
1772 $xml .= "<datafield tag=\"100\" ind1=\"\" ind2=\"\">\n";
1773 $xml .= "<subfield code=\"a\">$string</subfield>\n";
1774 $xml .= "</datafield>\n";
1780 for ( my $i = 0 ; $i <= @$tags ; $i++ ) {
1781 @$values[$i] =~ s/&/&/g;
1782 @$values[$i] =~ s/</</g;
1783 @$values[$i] =~ s/>/>/g;
1784 @$values[$i] =~ s/"/"/g;
1785 @$values[$i] =~ s/'/'/g;
1786 if ( !utf8::is_utf8( @$values[$i] ) ) {
1787 utf8::decode( @$values[$i] );
1789 if ( ( @$tags[$i] ne $prevtag ) ) {
1790 $j++ unless ( @$tags[$i] eq "" );
1792 $xml .= "</datafield>\n";
1793 if ( ( @$tags[$i] && @$tags[$i] > 10 )
1794 && ( @$values[$i] ne "" ) )
1796 my $ind1 = substr( @$indicator[$j], 0, 1 );
1798 if ( @$indicator[$j] ) {
1799 $ind2 = substr( @$indicator[$j], 1, 1 );
1802 warn "Indicator in @$tags[$i] is empty";
1806 "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
1808 "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
1816 if ( @$values[$i] ne "" ) {
1819 if ( @$tags[$i] eq "000" ) {
1820 $xml .= "<leader>@$values[$i]</leader>\n";
1823 # rest of the fixed fields
1825 elsif ( @$tags[$i] < 10 ) {
1827 "<controlfield tag=\"@$tags[$i]\">@$values[$i]</controlfield>\n";
1831 my $ind1 = substr( @$indicator[$j], 0, 1 );
1832 my $ind2 = substr( @$indicator[$j], 1, 1 );
1834 "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
1836 "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
1842 else { # @$tags[$i] eq $prevtag
1843 if ( @$values[$i] eq "" ) {
1847 my $ind1 = substr( @$indicator[$j], 0, 1 );
1848 my $ind2 = substr( @$indicator[$j], 1, 1 );
1850 "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
1854 "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
1857 $prevtag = @$tags[$i];
1859 $xml .= MARC::File::XML::footer();
1864 =head2 TransformHtmlToMarc
1868 $record = TransformHtmlToMarc( $dbh, $rtags, $rsubfields, $rvalues, %indicators )
1874 sub TransformHtmlToMarc {
1875 my ( $dbh, $rtags, $rsubfields, $rvalues, %indicators ) = @_;
1877 my $record = MARC::Record->new();
1879 # my %subfieldlist=();
1880 my $prevvalue; # if tag <10
1881 my $field; # if tag >=10
1882 for ( my $i = 0 ; $i < @$rtags ; $i++ ) {
1883 next unless @$rvalues[$i];
1885 # rebuild MARC::Record
1886 # warn "0=>".@$rtags[$i].@$rsubfields[$i]." = ".@$rvalues[$i].": ";
1887 if ( @$rtags[$i] ne $prevtag ) {
1888 if ( $prevtag < 10 ) {
1891 if ( $prevtag ne '000' ) {
1892 $record->insert_fields_ordered(
1893 ( sprintf "%03s", $prevtag ), $prevvalue );
1897 $record->leader($prevvalue);
1904 $record->insert_fields_ordered($field);
1907 $indicators{ @$rtags[$i] } .= ' ';
1908 if ( @$rtags[$i] < 10 ) {
1909 $prevvalue = @$rvalues[$i];
1914 $field = MARC::Field->new(
1915 ( sprintf "%03s", @$rtags[$i] ),
1916 substr( $indicators{ @$rtags[$i] }, 0, 1 ),
1917 substr( $indicators{ @$rtags[$i] }, 1, 1 ),
1918 @$rsubfields[$i] => @$rvalues[$i]
1921 $prevtag = @$rtags[$i];
1924 if ( @$rtags[$i] < 10 ) {
1925 $prevvalue = @$rvalues[$i];
1928 if ( length( @$rvalues[$i] ) > 0 ) {
1929 $field->add_subfields( @$rsubfields[$i] => @$rvalues[$i] );
1932 $prevtag = @$rtags[$i];
1936 # the last has not been included inside the loop... do it now !
1937 $record->insert_fields_ordered($field) if $field;
1939 # warn "HTML2MARC=".$record->as_formatted;
1940 $record->encoding('UTF-8');
1942 # $record->MARC::File::USMARC::update_leader();
1946 =head2 TransformMarcToKoha
1950 $result = TransformMarcToKoha( $dbh, $record, $frameworkcode )
1956 sub TransformMarcToKoha {
1957 my ( $dbh, $record, $frameworkcode ) = @_;
1960 "select tagfield,tagsubfield from marc_subfield_structure where frameworkcode=? and kohafield=?"
1963 my $sth2 = $dbh->prepare("SHOW COLUMNS from biblio");
1966 while ( ($field) = $sth2->fetchrow ) {
1968 &TransformMarcToKohaOneField( "biblio", $field, $record, $result,
1971 $sth2 = $dbh->prepare("SHOW COLUMNS from biblioitems");
1973 while ( ($field) = $sth2->fetchrow ) {
1974 if ( $field eq 'notes' ) { $field = 'bnotes'; }
1976 &TransformMarcToKohaOneField( "biblioitems", $field, $record, $result,
1979 $sth2 = $dbh->prepare("SHOW COLUMNS from items");
1981 while ( ($field) = $sth2->fetchrow ) {
1983 &TransformMarcToKohaOneField( "items", $field, $record, $result,
1988 # modify copyrightdate to keep only the 1st year found
1989 my $temp = $result->{'copyrightdate'};
1990 $temp =~ m/c(\d\d\d\d)/; # search cYYYY first
1992 $result->{'copyrightdate'} = $1;
1994 else { # if no cYYYY, get the 1st date.
1995 $temp =~ m/(\d\d\d\d)/;
1996 $result->{'copyrightdate'} = $1;
1999 # modify publicationyear to keep only the 1st year found
2000 $temp = $result->{'publicationyear'};
2001 $temp =~ m/c(\d\d\d\d)/; # search cYYYY first
2003 $result->{'publicationyear'} = $1;
2005 else { # if no cYYYY, get the 1st date.
2006 $temp =~ m/(\d\d\d\d)/;
2007 $result->{'publicationyear'} = $1;
2012 =head2 TransformMarcToKohaOneField
2016 $result = TransformMarcToKohaOneField( $kohatable, $kohafield, $record, $result, $frameworkcode )
2022 sub TransformMarcToKohaOneField {
2024 # FIXME ? if a field has a repeatable subfield that is used in old-db, only the 1st will be retrieved...
2025 my ( $kohatable, $kohafield, $record, $result, $frameworkcode ) = @_;
2028 my ( $tagfield, $subfield ) =
2029 GetMarcFromKohaField( "", $kohatable . "." . $kohafield,
2031 foreach my $field ( $record->field($tagfield) ) {
2032 if ( $field->tag() < 10 ) {
2033 if ( $result->{$kohafield} ) {
2034 $result->{$kohafield} .= " | " . $field->data();
2037 $result->{$kohafield} = $field->data();
2041 if ( $field->subfields ) {
2042 my @subfields = $field->subfields();
2043 foreach my $subfieldcount ( 0 .. $#subfields ) {
2044 if ( $subfields[$subfieldcount][0] eq $subfield ) {
2045 if ( $result->{$kohafield} ) {
2046 $result->{$kohafield} .=
2047 " | " . $subfields[$subfieldcount][1];
2050 $result->{$kohafield} =
2051 $subfields[$subfieldcount][1];
2060 =head1 OTHER FUNCTIONS
2066 my $string = char_decode( $string, $encoding );
2068 converts ISO 5426 coded string to UTF-8
2069 sloppy code : should be improved in next issue
2076 my ( $string, $encoding ) = @_;
2079 $encoding = C4::Context->preference("marcflavour") unless $encoding;
2080 if ( $encoding eq "UNIMARC" ) {
2150 # this handles non-sorting blocks (if implementation requires this)
2151 $string = nsb_clean($_);
2153 elsif ( $encoding eq "USMARC" || $encoding eq "MARC21" ) {
2212 #Additional Turkish characters
2215 s/(\xf0)s/\xc5\x9f/gm;
2216 s/(\xf0)S/\xc5\x9e/gm;
2219 s/\xe7\x49/\\xc4\xb0/gm;
2220 s/(\xe6)G/\xc4\x9e/gm;
2221 s/(\xe6)g/ğ\xc4\x9f/gm;
2224 s/(\xe8|\xc8)o/ö/gm;
2225 s/(\xe8|\xc8)O/Ö/gm;
2226 s/(\xe8|\xc8)u/ü/gm;
2227 s/(\xe8|\xc8)U/Ü/gm;
2228 s/\xc2\xb8/\xc4\xb1/gm;
2231 # this handles non-sorting blocks (if implementation requires this)
2232 $string = nsb_clean($_);
2241 my $string = nsb_clean( $string, $encoding );
2248 my $NSB = '\x88'; # NSB : begin Non Sorting Block
2249 my $NSE = '\x89'; # NSE : Non Sorting Block end
2250 # handles non sorting blocks
2254 s/[ ]{0,1}$NSE/) /gm;
2259 =head2 PrepareItemrecordDisplay
2263 PrepareItemrecordDisplay($itemrecord,$bibnum,$itemumber);
2265 Returns a hash with all the fields for Display a given item data in a template
2271 sub PrepareItemrecordDisplay {
2273 my ( $bibnum, $itemnum ) = @_;
2275 my $dbh = C4::Context->dbh;
2276 my $frameworkcode = &GetFrameworkCode( $bibnum );
2277 my ( $itemtagfield, $itemtagsubfield ) =
2278 &GetMarcFromKohaField( $dbh, "items.itemnumber", $frameworkcode );
2279 my $tagslib = &GetMarcStructure( $dbh, 1, $frameworkcode );
2280 my $itemrecord = GetMarcItem( $bibnum, $itemnum) if ($itemnum);
2282 my $authorised_values_sth =
2284 "select authorised_value,lib from authorised_values where category=? order by lib"
2286 foreach my $tag ( sort keys %{$tagslib} ) {
2287 my $previous_tag = '';
2289 # loop through each subfield
2291 foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
2292 next if ( subfield_is_koha_internal_p($subfield) );
2293 next if ( $tagslib->{$tag}->{$subfield}->{'tab'} ne "10" );
2295 $subfield_data{tag} = $tag;
2296 $subfield_data{subfield} = $subfield;
2297 $subfield_data{countsubfield} = $cntsubf++;
2298 $subfield_data{kohafield} =
2299 $tagslib->{$tag}->{$subfield}->{'kohafield'};
2301 # $subfield_data{marc_lib}=$tagslib->{$tag}->{$subfield}->{lib};
2302 $subfield_data{marc_lib} =
2303 "<span id=\"error\" title=\""
2304 . $tagslib->{$tag}->{$subfield}->{lib} . "\">"
2305 . substr( $tagslib->{$tag}->{$subfield}->{lib}, 0, 12 )
2307 $subfield_data{mandatory} =
2308 $tagslib->{$tag}->{$subfield}->{mandatory};
2309 $subfield_data{repeatable} =
2310 $tagslib->{$tag}->{$subfield}->{repeatable};
2311 $subfield_data{hidden} = "display:none"
2312 if $tagslib->{$tag}->{$subfield}->{hidden};
2314 ( $x, $value ) = _find_value( $tag, $subfield, $itemrecord )
2316 $value =~ s/"/"/g;
2318 # search for itemcallnumber if applicable
2319 if ( $tagslib->{$tag}->{$subfield}->{kohafield} eq
2320 'items.itemcallnumber'
2321 && C4::Context->preference('itemcallnumber') )
2324 substr( C4::Context->preference('itemcallnumber'), 0, 3 );
2326 substr( C4::Context->preference('itemcallnumber'), 3, 1 );
2327 my $temp = $itemrecord->field($CNtag) if ($itemrecord);
2329 $value = $temp->subfield($CNsubfield);
2332 if ( $tagslib->{$tag}->{$subfield}->{authorised_value} ) {
2333 my @authorised_values;
2336 # builds list, depending on authorised value...
2338 if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq
2341 if ( ( C4::Context->preference("IndependantBranches") )
2342 && ( C4::Context->userenv->{flags} != 1 ) )
2346 "select branchcode,branchname from branches where branchcode = ? order by branchname"
2348 $sth->execute( C4::Context->userenv->{branch} );
2349 push @authorised_values, ""
2351 $tagslib->{$tag}->{$subfield}->{mandatory} );
2352 while ( my ( $branchcode, $branchname ) =
2353 $sth->fetchrow_array )
2355 push @authorised_values, $branchcode;
2356 $authorised_lib{$branchcode} = $branchname;
2362 "select branchcode,branchname from branches order by branchname"
2365 push @authorised_values, ""
2367 $tagslib->{$tag}->{$subfield}->{mandatory} );
2368 while ( my ( $branchcode, $branchname ) =
2369 $sth->fetchrow_array )
2371 push @authorised_values, $branchcode;
2372 $authorised_lib{$branchcode} = $branchname;
2378 elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq
2383 "select itemtype,description from itemtypes order by description"
2386 push @authorised_values, ""
2387 unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
2388 while ( my ( $itemtype, $description ) =
2389 $sth->fetchrow_array )
2391 push @authorised_values, $itemtype;
2392 $authorised_lib{$itemtype} = $description;
2395 #---- "true" authorised value
2398 $authorised_values_sth->execute(
2399 $tagslib->{$tag}->{$subfield}->{authorised_value} );
2400 push @authorised_values, ""
2401 unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
2402 while ( my ( $value, $lib ) =
2403 $authorised_values_sth->fetchrow_array )
2405 push @authorised_values, $value;
2406 $authorised_lib{$value} = $lib;
2409 $subfield_data{marc_value} = CGI::scrolling_list(
2410 -name => 'field_value',
2411 -values => \@authorised_values,
2412 -default => "$value",
2413 -labels => \%authorised_lib,
2419 elsif ( $tagslib->{$tag}->{$subfield}->{thesaurus_category} ) {
2420 $subfield_data{marc_value} =
2421 "<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>";
2424 # COMMENTED OUT because No $i is provided with this API.
2425 # And thus, no value_builder can be activated.
2426 # BUT could be thought over.
2427 # } elsif ($tagslib->{$tag}->{$subfield}->{'value_builder'}) {
2428 # my $plugin="value_builder/".$tagslib->{$tag}->{$subfield}->{'value_builder'};
2430 # my $extended_param = plugin_parameters($dbh,$itemrecord,$tagslib,$i,0);
2431 # my ($function_name,$javascript) = plugin_javascript($dbh,$record,$tagslib,$i,0);
2432 # $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";
2435 $subfield_data{marc_value} =
2436 "<input type=\"text\" name=\"field_value\" value=\"$value\" size=50 maxlength=255>";
2438 push( @loop_data, \%subfield_data );
2442 my $itemnumber = $itemrecord->subfield( $itemtagfield, $itemtagsubfield )
2443 if ( $itemrecord && $itemrecord->field($itemtagfield) );
2445 'itemtagfield' => $itemtagfield,
2446 'itemtagsubfield' => $itemtagsubfield,
2447 'itemnumber' => $itemnumber,
2448 'iteminformation' => \@loop_data
2454 # true ModZebra commented until indexdata fixes zebraDB crashes (it seems they occur on multiple updates
2456 # replaced by a zebraqueue table, that is filled with ModZebra to run.
2457 # the table is emptied by misc/cronjobs/zebraqueue_start.pl script
2458 # =head2 ModZebrafiles
2460 # &ModZebrafiles( $dbh, $biblionumber, $record, $folder, $server );
2464 # sub ModZebrafiles {
2466 # my ( $dbh, $biblionumber, $record, $folder, $server ) = @_;
2470 # C4::Context->zebraconfig($server)->{directory} . "/" . $folder . "/";
2471 # unless ( opendir( DIR, "$zebradir" ) ) {
2472 # warn "$zebradir not found";
2476 # my $filename = $zebradir . $biblionumber;
2479 # open( OUTPUT, ">", $filename . ".xml" );
2480 # print OUTPUT $record;
2489 ModZebra( $dbh, $biblionumber, $op, $server );
2496 ###Accepts a $server variable thus we can use it for biblios authorities or other zebra dbs
2497 my ( $biblionumber, $op, $server ) = @_;
2498 my $dbh=C4::Context->dbh;
2499 #warn "SERVER:".$server;
2501 # true ModZebra commented until indexdata fixes zebraDB crashes (it seems they occur on multiple updates
2503 # replaced by a zebraqueue table, that is filled with ModZebra to run.
2504 # the table is emptied by misc/cronjobs/zebraqueue_start.pl script
2506 my $sth=$dbh->prepare("insert into zebraqueue (biblio_auth_number ,server,operation) values(?,?,?)");
2507 $sth->execute($biblionumber,$server,$op);
2514 # my $reconnect = 0;
2519 # $Zconnbiblio[0] = C4::Context->Zconn( $server, 0, 1 );
2521 # if ( $server eq "biblioserver" ) {
2523 # # it's unclear to me whether this should be in xml or MARC format
2524 # # but it is clear it should be nabbed from zebra rather than from
2526 # $record = GetMarcBiblio($biblionumber);
2527 # $record = $record->as_xml_record() if $record;
2528 # # warn "RECORD $biblionumber => ".$record;
2529 # $shadow="biblioservershadow";
2531 # # warn "RECORD $biblionumber => ".$record;
2532 # $shadow = "biblioservershadow";
2535 # elsif ( $server eq "authorityserver" ) {
2536 # $record = C4::AuthoritiesMarc::XMLgetauthority( $dbh, $biblionumber );
2537 # $shadow = "authorityservershadow";
2538 # } ## Add other servers as necessary
2540 # my $Zpackage = $Zconnbiblio[0]->package();
2541 # $Zpackage->option( action => $op );
2542 # $Zpackage->option( record => $record );
2545 # $Zpackage->send("update");
2549 # while ( ( $i = ZOOM::event( \@Zconnbiblio ) ) != 0 ) {
2550 # $event = $Zconnbiblio[0]->last_event();
2551 # last if $event == ZOOM::Event::ZEND;
2554 # my ( $error, $errmsg, $addinfo, $diagset ) = $Zconnbiblio[0]->error_x();
2555 # if ( $error == 10000 && $reconnect == 0 )
2556 # { ## This is serious ZEBRA server is not available -reconnect
2557 # warn "problem with zebra server connection";
2559 # my $res = system('sc start "Z39.50 Server" >c:/zebraserver/error.log');
2561 # #warn "Trying to restart ZEBRA Server";
2562 # #goto "reconnect";
2564 # elsif ( $error == 10007 && $tried < 2 )
2565 # { ## timeout --another 30 looonng seconds for this update
2566 # $tried = $tried + 1;
2567 # warn "warn: timeout, trying again";
2570 # elsif ( $error == 10004 && $recon == 0 ) { ##Lost connection -reconnect
2572 # warn "error: reconnecting to zebra";
2575 # # as a last resort, we save the data to the filesystem to be indexed in batch
2579 # "Error-$server $op $biblionumber /errcode:, $error, /MSG:,$errmsg,$addinfo \n";
2580 # $Zpackage->destroy();
2581 # $Zconnbiblio[0]->destroy();
2582 # ModZebrafiles( $dbh, $biblionumber, $record, $op, $server );
2585 # if ( C4::Context->$shadow ) {
2586 # $Zpackage->send('commit');
2587 # while ( ( $i = ZOOM::event( \@Zconnbiblio ) ) != 0 ) {
2589 # #waiting zebra to finish;
2592 # $Zpackage->destroy();
2595 =head1 INTERNAL FUNCTIONS
2597 =head2 MARCitemchange
2601 &MARCitemchange( $record, $itemfield, $newvalue )
2603 Function to update a single value in an item field.
2604 Used twice, could probably be replaced by something else, but works well...
2612 sub MARCitemchange {
2613 my ( $record, $itemfield, $newvalue ) = @_;
2614 my $dbh = C4::Context->dbh;
2616 my ( $tagfield, $tagsubfield ) =
2617 GetMarcFromKohaField( $dbh, $itemfield, "" );
2618 if ( ($tagfield) && ($tagsubfield) ) {
2619 my $tag = $record->field($tagfield);
2621 $tag->update( $tagsubfield => $newvalue );
2622 $record->delete_field($tag);
2623 $record->insert_fields_ordered($tag);
2628 =head2 _koha_add_biblio
2632 _koha_add_biblio($dbh,$biblioitem);
2634 Internal function to add a biblio ($biblio is a hash with the values)
2640 sub _koha_add_biblio {
2641 my ( $dbh, $biblio, $frameworkcode ) = @_;
2642 my $sth = $dbh->prepare("Select max(biblionumber) from biblio");
2644 my $data = $sth->fetchrow_arrayref;
2645 my $biblionumber = $$data[0] + 1;
2648 if ( $biblio->{'seriestitle'} ) { $series = 1 }
2650 $sth = $dbh->prepare(
2652 SET biblionumber = ?, title = ?, author = ?, copyrightdate = ?, serial = ?, seriestitle = ?, notes = ?, abstract = ?, unititle = ?, frameworkcode = ? "
2655 $biblionumber, $biblio->{'title'},
2656 $biblio->{'author'}, $biblio->{'copyrightdate'},
2657 $biblio->{'serial'}, $biblio->{'seriestitle'},
2658 $biblio->{'notes'}, $biblio->{'abstract'},
2659 $biblio->{'unititle'}, $frameworkcode
2663 return ($biblionumber);
2670 ($indicators, $value) = _find_value($tag, $subfield, $record,$encoding);
2672 Find the given $subfield in the given $tag in the given
2673 MARC::Record $record. If the subfield is found, returns
2674 the (indicators, value) pair; otherwise, (undef, undef) is
2678 Such a function is used in addbiblio AND additem and serial-edit and maybe could be used in Authorities.
2679 I suggest we export it from this module.
2686 my ( $tagfield, $insubfield, $record, $encoding ) = @_;
2689 if ( $tagfield < 10 ) {
2690 if ( $record->field($tagfield) ) {
2691 push @result, $record->field($tagfield)->data();
2698 foreach my $field ( $record->field($tagfield) ) {
2699 my @subfields = $field->subfields();
2700 foreach my $subfield (@subfields) {
2701 if ( @$subfield[0] eq $insubfield ) {
2702 push @result, @$subfield[1];
2703 $indicator = $field->indicator(1) . $field->indicator(2);
2708 return ( $indicator, @result );
2711 =head2 _koha_modify_biblio
2715 Internal function for updating the biblio table
2721 sub _koha_modify_biblio {
2722 my ( $dbh, $biblio ) = @_;
2724 # FIXME: this code could be made more portable by not hard-coding the values that are supposed to be in biblio table
2727 "Update biblio set title = ?, author = ?, abstract = ?, copyrightdate = ?, seriestitle = ?, serial = ?, unititle = ?, notes = ? where biblionumber = ?"
2730 $biblio->{'title'}, $biblio->{'author'},
2731 $biblio->{'abstract'}, $biblio->{'copyrightdate'},
2732 $biblio->{'seriestitle'}, $biblio->{'serial'},
2733 $biblio->{'unititle'}, $biblio->{'notes'},
2734 $biblio->{'biblionumber'}
2737 return ( $biblio->{'biblionumber'} );
2740 =head2 _koha_modify_biblioitem
2744 _koha_modify_biblioitem( $dbh, $biblioitem );
2750 sub _koha_modify_biblioitem {
2751 my ( $dbh, $biblioitem ) = @_;
2753 ##Recalculate LC in case it changed --TG
2755 $biblioitem->{'itemtype'} = $dbh->quote( $biblioitem->{'itemtype'} );
2756 $biblioitem->{'url'} = $dbh->quote( $biblioitem->{'url'} );
2757 $biblioitem->{'isbn'} = $dbh->quote( $biblioitem->{'isbn'} );
2758 $biblioitem->{'issn'} = $dbh->quote( $biblioitem->{'issn'} );
2759 $biblioitem->{'publishercode'} =
2760 $dbh->quote( $biblioitem->{'publishercode'} );
2761 $biblioitem->{'publicationyear'} =
2762 $dbh->quote( $biblioitem->{'publicationyear'} );
2763 $biblioitem->{'classification'} =
2764 $dbh->quote( $biblioitem->{'classification'} );
2765 $biblioitem->{'dewey'} = $dbh->quote( $biblioitem->{'dewey'} );
2766 $biblioitem->{'subclass'} = $dbh->quote( $biblioitem->{'subclass'} );
2767 $biblioitem->{'illus'} = $dbh->quote( $biblioitem->{'illus'} );
2768 $biblioitem->{'pages'} = $dbh->quote( $biblioitem->{'pages'} );
2769 $biblioitem->{'volumeddesc'} = $dbh->quote( $biblioitem->{'volumeddesc'} );
2770 $biblioitem->{'bnotes'} = $dbh->quote( $biblioitem->{'bnotes'} );
2771 $biblioitem->{'size'} = $dbh->quote( $biblioitem->{'size'} );
2772 $biblioitem->{'place'} = $dbh->quote( $biblioitem->{'place'} );
2773 $biblioitem->{'ccode'} = $dbh->quote( $biblioitem->{'ccode'} );
2774 $biblioitem->{'biblionumber'} =
2775 $dbh->quote( $biblioitem->{'biblionumber'} );
2777 $query = "Update biblioitems set
2778 itemtype = $biblioitem->{'itemtype'},
2779 url = $biblioitem->{'url'},
2780 isbn = $biblioitem->{'isbn'},
2781 issn = $biblioitem->{'issn'},
2782 publishercode = $biblioitem->{'publishercode'},
2783 publicationyear = $biblioitem->{'publicationyear'},
2784 classification = $biblioitem->{'classification'},
2785 dewey = $biblioitem->{'dewey'},
2786 subclass = $biblioitem->{'subclass'},
2787 illus = $biblioitem->{'illus'},
2788 pages = $biblioitem->{'pages'},
2789 volumeddesc = $biblioitem->{'volumeddesc'},
2790 notes = $biblioitem->{'bnotes'},
2791 size = $biblioitem->{'size'},
2792 place = $biblioitem->{'place'},
2793 ccode = $biblioitem->{'ccode'}
2794 where biblionumber = $biblioitem->{'biblionumber'}";
2797 if ( $dbh->errstr ) {
2802 =head2 _koha_add_biblioitem
2806 _koha_add_biblioitem( $dbh, $biblioitem );
2808 Internal function to add a biblioitem
2814 sub _koha_add_biblioitem {
2815 my ( $dbh, $biblioitem ) = @_;
2817 # my $dbh = C4Connect;
2818 my $sth = $dbh->prepare("SELECT max(biblioitemnumber) FROM biblioitems");
2823 $data = $sth->fetchrow_arrayref;
2824 $bibitemnum = $$data[0] + 1;
2828 $sth = $dbh->prepare(
2829 "INSERT INTO biblioitems SET
2830 biblioitemnumber = ?, biblionumber = ?,
2831 volume = ?, number = ?,
2832 classification = ?, itemtype = ?,
2834 issn = ?, dewey = ?,
2835 subclass = ?, publicationyear = ?,
2836 publishercode = ?, volumedate = ?,
2837 volumeddesc = ?, illus = ?,
2838 pages = ?, notes = ?,
2840 marc = ?, lcsort =?,
2841 place = ?, ccode = ?
2845 calculatelc( $biblioitem->{'classification'} )
2846 . $biblioitem->{'subclass'};
2848 $bibitemnum, $biblioitem->{'biblionumber'},
2849 $biblioitem->{'volume'}, $biblioitem->{'number'},
2850 $biblioitem->{'classification'}, $biblioitem->{'itemtype'},
2851 $biblioitem->{'url'}, $biblioitem->{'isbn'},
2852 $biblioitem->{'issn'}, $biblioitem->{'dewey'},
2853 $biblioitem->{'subclass'}, $biblioitem->{'publicationyear'},
2854 $biblioitem->{'publishercode'}, $biblioitem->{'volumedate'},
2855 $biblioitem->{'volumeddesc'}, $biblioitem->{'illus'},
2856 $biblioitem->{'pages'}, $biblioitem->{'bnotes'},
2857 $biblioitem->{'size'}, $biblioitem->{'lccn'},
2858 $biblioitem->{'marc'}, $biblioitem->{'place'},
2859 $lcsort, $biblioitem->{'ccode'}
2862 return ($bibitemnum);
2865 =head2 _koha_new_items
2869 _koha_new_items( $dbh, $item, $barcode );
2875 sub _koha_new_items {
2876 my ( $dbh, $item, $barcode ) = @_;
2878 # my $dbh = C4Connect;
2879 my $sth = $dbh->prepare("Select max(itemnumber) from items");
2885 $data = $sth->fetchrow_hashref;
2886 $itemnumber = $data->{'max(itemnumber)'} + 1;
2888 ## Now calculate lccalnumber
2889 my ($cutterextra) = itemcalculator(
2891 $item->{'biblioitemnumber'},
2892 $item->{'itemcallnumber'}
2895 # FIXME the "notforloan" field seems to be named "loan" in some places. workaround bugfix.
2896 if ( $item->{'loan'} ) {
2897 $item->{'notforloan'} = $item->{'loan'};
2900 # if dateaccessioned is provided, use it. Otherwise, set to NOW()
2901 if ( $item->{'dateaccessioned'} eq '' || !$item->{'dateaccessioned'} ) {
2903 $sth = $dbh->prepare(
2904 "Insert into items set
2905 itemnumber = ?, biblionumber = ?,
2906 multivolumepart = ?,
2907 biblioitemnumber = ?, barcode = ?,
2908 booksellerid = ?, dateaccessioned = NOW(),
2909 homebranch = ?, holdingbranch = ?,
2910 price = ?, replacementprice = ?,
2911 replacementpricedate = NOW(), datelastseen = NOW(),
2912 multivolume = ?, stack = ?,
2913 itemlost = ?, wthdrawn = ?,
2914 paidfor = ?, itemnotes = ?,
2915 itemcallnumber =?, notforloan = ?,
2916 location = ?, Cutterextra = ?
2920 $itemnumber, $item->{'biblionumber'},
2921 $item->{'multivolumepart'}, $item->{'biblioitemnumber'},
2922 $barcode, $item->{'booksellerid'},
2923 $item->{'homebranch'}, $item->{'holdingbranch'},
2924 $item->{'price'}, $item->{'replacementprice'},
2925 $item->{multivolume}, $item->{stack},
2926 $item->{itemlost}, $item->{wthdrawn},
2927 $item->{paidfor}, $item->{'itemnotes'},
2928 $item->{'itemcallnumber'}, $item->{'notforloan'},
2929 $item->{'location'}, $cutterextra
2933 $sth = $dbh->prepare(
2934 "INSERT INTO items SET
2935 itemnumber = ?, biblionumber = ?,
2936 multivolumepart = ?,
2937 biblioitemnumber = ?, barcode = ?,
2938 booksellerid = ?, dateaccessioned = ?,
2939 homebranch = ?, holdingbranch = ?,
2940 price = ?, replacementprice = ?,
2941 replacementpricedate = NOW(), datelastseen = NOW(),
2942 multivolume = ?, stack = ?,
2943 itemlost = ?, wthdrawn = ?,
2944 paidfor = ?, itemnotes = ?,
2945 itemcallnumber = ?, notforloan = ?,
2951 $itemnumber, $item->{'biblionumber'},
2952 $item->{'multivolumepart'}, $item->{'biblioitemnumber'},
2953 $barcode, $item->{'booksellerid'},
2954 $item->{'dateaccessioned'}, $item->{'homebranch'},
2955 $item->{'holdingbranch'}, $item->{'price'},
2956 $item->{'replacementprice'}, $item->{multivolume},
2957 $item->{stack}, $item->{itemlost},
2958 $item->{wthdrawn}, $item->{paidfor},
2959 $item->{'itemnotes'}, $item->{'itemcallnumber'},
2960 $item->{'notforloan'}, $item->{'location'},
2964 if ( defined $sth->errstr ) {
2965 $error .= $sth->errstr;
2967 return ( $itemnumber, $error );
2970 =head2 _koha_modify_item
2974 _koha_modify_item( $dbh, $item, $op );
2980 sub _koha_modify_item {
2981 my ( $dbh, $item, $op ) = @_;
2982 $item->{'itemnum'} = $item->{'itemnumber'} unless $item->{'itemnum'};
2984 # if all we're doing is setting statuses, just update those and get out
2985 if ( $op eq "setstatus" ) {
2987 "UPDATE items SET itemlost=?,wthdrawn=?,binding=? WHERE itemnumber=?";
2989 $item->{'itemlost'}, $item->{'wthdrawn'},
2990 $item->{'binding'}, $item->{'itemnumber'}
2992 my $sth = $dbh->prepare($query);
2993 $sth->execute(@bind);
2997 ## Now calculate lccalnumber
2999 itemcalculator( $dbh, $item->{'bibitemnum'}, $item->{'itemcallnumber'} );
3001 my $query = "UPDATE items SET
3002 barcode=?,itemnotes=?,itemcallnumber=?,notforloan=?,location=?,multivolumepart=?,multivolume=?,stack=?,wthdrawn=?,holdingbranch=?,homebranch=?,cutterextra=?, onloan=?, binding=?";
3005 $item->{'barcode'}, $item->{'notes'},
3006 $item->{'itemcallnumber'}, $item->{'notforloan'},
3007 $item->{'location'}, $item->{multivolumepart},
3008 $item->{multivolume}, $item->{stack},
3009 $item->{wthdrawn}, $item->{holdingbranch},
3010 $item->{homebranch}, $cutterextra,
3011 $item->{onloan}, $item->{binding}
3013 if ( $item->{'lost'} ne '' ) {
3015 "update items set biblioitemnumber=?,barcode=?,itemnotes=?,homebranch=?,
3016 itemlost=?,wthdrawn=?,itemcallnumber=?,notforloan=?,
3017 location=?,multivolumepart=?,multivolume=?,stack=?,wthdrawn=?,holdingbranch=?,cutterextra=?,onloan=?, binding=?";
3019 $item->{'bibitemnum'}, $item->{'barcode'},
3020 $item->{'notes'}, $item->{'homebranch'},
3021 $item->{'lost'}, $item->{'wthdrawn'},
3022 $item->{'itemcallnumber'}, $item->{'notforloan'},
3023 $item->{'location'}, $item->{multivolumepart},
3024 $item->{multivolume}, $item->{stack},
3025 $item->{wthdrawn}, $item->{holdingbranch},
3026 $cutterextra, $item->{onloan},
3029 if ( $item->{homebranch} ) {
3030 $query .= ",homebranch=?";
3031 push @bind, $item->{homebranch};
3033 if ( $item->{holdingbranch} ) {
3034 $query .= ",holdingbranch=?";
3035 push @bind, $item->{holdingbranch};
3038 $query .= " where itemnumber=?";
3039 push @bind, $item->{'itemnum'};
3040 if ( $item->{'replacement'} ne '' ) {
3041 $query =~ s/ where/,replacementprice='$item->{'replacement'}' where/;
3043 my $sth = $dbh->prepare($query);
3044 $sth->execute(@bind);
3048 =head2 _koha_delete_biblio
3052 $error = _koha_delete_biblio($dbh,$biblionumber);
3054 Internal sub for deleting from biblio table -- also saves to deletedbiblio
3056 C<$dbh> - the database handle
3057 C<$biblionumber> - the biblionumber of the biblio to be deleted
3063 # FIXME: add error handling
3065 sub _koha_delete_biblio {
3066 my ( $dbh, $biblionumber ) = @_;
3068 # get all the data for this biblio
3069 my $sth = $dbh->prepare("SELECT * FROM biblio WHERE biblionumber=?");
3070 $sth->execute($biblionumber);
3072 if ( my $data = $sth->fetchrow_hashref ) {
3074 # save the record in deletedbiblio
3075 # find the fields to save
3076 my $query = "INSERT INTO deletedbiblio SET ";
3078 foreach my $temp ( keys %$data ) {
3079 $query .= "$temp = ?,";
3080 push( @bind, $data->{$temp} );
3083 # replace the last , by ",?)"
3085 my $bkup_sth = $dbh->prepare($query);
3086 $bkup_sth->execute(@bind);
3090 my $del_sth = $dbh->prepare("DELETE FROM biblio WHERE biblionumber=?");
3091 $del_sth->execute($biblionumber);
3098 =head2 _koha_delete_biblioitems
3102 $error = _koha_delete_biblioitems($dbh,$biblioitemnumber);
3104 Internal sub for deleting from biblioitems table -- also saves to deletedbiblioitems
3106 C<$dbh> - the database handle
3107 C<$biblionumber> - the biblioitemnumber of the biblioitem to be deleted
3113 # FIXME: add error handling
3115 sub _koha_delete_biblioitems {
3116 my ( $dbh, $biblioitemnumber ) = @_;
3118 # get all the data for this biblioitem
3120 $dbh->prepare("SELECT * FROM biblioitems WHERE biblioitemnumber=?");
3121 $sth->execute($biblioitemnumber);
3123 if ( my $data = $sth->fetchrow_hashref ) {
3125 # save the record in deletedbiblioitems
3126 # find the fields to save
3127 my $query = "INSERT INTO deletedbiblioitems SET ";
3129 foreach my $temp ( keys %$data ) {
3130 $query .= "$temp = ?,";
3131 push( @bind, $data->{$temp} );
3134 # replace the last , by ",?)"
3136 my $bkup_sth = $dbh->prepare($query);
3137 $bkup_sth->execute(@bind);
3140 # delete the biblioitem
3142 $dbh->prepare("DELETE FROM biblioitems WHERE biblioitemnumber=?");
3143 $del_sth->execute($biblioitemnumber);
3150 =head2 _koha_delete_item
3154 _koha_delete_item( $dbh, $itemnum );
3156 Internal function to delete an item record from the koha tables
3162 sub _koha_delete_item {
3163 my ( $dbh, $itemnum ) = @_;
3165 my $sth = $dbh->prepare("select * from items where itemnumber=?");
3166 $sth->execute($itemnum);
3167 my $data = $sth->fetchrow_hashref;
3169 my $query = "Insert into deleteditems set ";
3171 foreach my $temp ( keys %$data ) {
3172 $query .= "$temp = ?,";
3173 push( @bind, $data->{$temp} );
3178 $sth = $dbh->prepare($query);
3179 $sth->execute(@bind);
3181 $sth = $dbh->prepare("Delete from items where itemnumber=?");
3182 $sth->execute($itemnum);
3186 =head1 UNEXPORTED FUNCTIONS
3192 $lc = calculatelc($classification);
3199 my ($classification) = @_;
3200 $classification =~ s/^\s+|\s+$//g;
3205 for ( $i = 0 ; $i < length($classification) ; $i++ ) {
3206 my $c = ( substr( $classification, $i, 1 ) );
3207 if ( $c ge '0' && $c le '9' ) {
3209 $lc2 = substr( $classification, $i );
3213 $lc1 .= substr( $classification, $i, 1 );
3218 my $other = length($lc1);
3225 for ( 1 .. ( 4 - $other ) ) {
3234 ##Find the decimal part of $lc2
3235 my $pos = index( $lc2, "." );
3236 if ( $pos < 0 ) { $pos = length($lc2); }
3237 if ( $pos >= 0 && $pos < 5 ) {
3238 ##Pad lc2 with zeros to create a 5digit decimal needed in marc record to sort as numeric
3240 for ( 1 .. ( 5 - $pos ) ) {
3244 $lc2 = $extras . $lc2;
3245 return ( $lc1 . $lc2 );
3248 =head2 itemcalculator
3252 $cutterextra = itemcalculator( $dbh, $biblioitem, $callnumber );
3258 sub itemcalculator {
3259 my ( $dbh, $biblioitem, $callnumber ) = @_;
3262 "select classification, subclass from biblioitems where biblioitemnumber=?"
3265 $sth->execute($biblioitem);
3266 my ( $classification, $subclass ) = $sth->fetchrow;
3267 my $all = $classification . " " . $subclass;
3268 my $total = length($all);
3269 my $cutterextra = substr( $callnumber, $total - 1 );
3271 return $cutterextra;
3274 =head2 ModBiblioMarc
3278 &ModBiblioMarc($newrec,$biblionumber,$frameworkcode);
3280 Add MARC data for a biblio to koha
3282 Function exported, but should NOT be used, unless you really know what you're doing
3290 # pass the MARC::Record to this function, and it will create the records in the marc tables
3291 my ( $record, $biblionumber, $frameworkcode ) = @_;
3292 my $dbh = C4::Context->dbh;
3293 my @fields = $record->fields();
3294 if ( !$frameworkcode ) {
3295 $frameworkcode = "";
3298 $dbh->prepare("UPDATE biblio SET frameworkcode=? WHERE biblionumber=?");
3299 $sth->execute( $frameworkcode, $biblionumber );
3301 my $encoding = C4::Context->preference("marcflavour");
3303 # deal with UNIMARC field 100 (encoding) : create it if needed & set encoding to unicode
3304 if ( $encoding eq "UNIMARC" ) {
3306 if ( $record->subfield( 100, "a" ) ) {
3307 $string = $record->subfield( 100, "a" );
3308 my $f100 = $record->field(100);
3309 $record->delete_field($f100);
3312 $string = POSIX::strftime( "%Y%m%d", localtime );
3314 $string = sprintf( "%-*s", 35, $string );
3316 substr( $string, 22, 6, "frey50" );
3317 unless ( $record->subfield( 100, "a" ) ) {
3318 $record->insert_grouped_field(
3319 MARC::Field->new( 100, "", "", "a" => $string ) );
3322 # warn "biblionumber : ".$biblionumber;
3325 "update biblioitems set marc=?,marcxml=? where biblionumber=?");
3326 $sth->execute( $record->as_usmarc(), $record->as_xml_record(),
3328 # warn $record->as_xml_record();
3330 ModZebra($biblionumber,"specialUpdate","biblioserver");
3331 return $biblionumber;
3334 =head2 AddItemInMarc
3338 $newbiblionumber = AddItemInMarc( $record, $biblionumber, $frameworkcode );
3340 Add an item in a MARC record and save the MARC record
3342 Function exported, but should NOT be used, unless you really know what you're doing
3350 # pass the MARC::Record to this function, and it will create the records in the marc tables
3351 my ( $record, $biblionumber, $frameworkcode ) = @_;
3352 my $newrec = &GetMarcBiblio($biblionumber);
3355 my @fields = $record->fields();
3356 foreach my $field (@fields) {
3357 $newrec->append_fields($field);
3360 # FIXME: should we be making sure the biblionumbers are the same?
3361 my $newbiblionumber =
3362 &ModBiblioMarc( $newrec, $biblionumber, $frameworkcode );
3363 return $newbiblionumber;
3366 =head2 z3950_extended_services
3368 z3950_extended_services($serviceType,$serviceOptions,$record);
3370 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.
3372 C<$serviceType> one of: itemorder,create,drop,commit,update,xmlupdate
3374 C<$serviceOptions> a has of key/value pairs. For instance, if service_type is 'update', $service_options should contain:
3376 action => update action, one of specialUpdate, recordInsert, recordReplace, recordDelete, elementUpdate.
3380 recordidOpaque => Opaque Record ID (user supplied) or recordidNumber => Record ID number (system number).
3381 syntax => the record syntax (transfer syntax)
3382 databaseName = Database from connection object
3384 To set serviceOptions, call set_service_options($serviceType)
3386 C<$record> the record, if one is needed for the service type
3388 A record should be in XML. You can convert it to XML from MARC by running it through marc2xml().
3392 sub z3950_extended_services {
3393 my ( $server, $serviceType, $action, $serviceOptions ) = @_;
3395 # get our connection object
3396 my $Zconn = C4::Context->Zconn( $server, 0, 1 );
3398 # create a new package object
3399 my $Zpackage = $Zconn->package();
3402 $Zpackage->option( action => $action );
3404 if ( $serviceOptions->{'databaseName'} ) {
3405 $Zpackage->option( databaseName => $serviceOptions->{'databaseName'} );
3407 if ( $serviceOptions->{'recordIdNumber'} ) {
3409 recordIdNumber => $serviceOptions->{'recordIdNumber'} );
3411 if ( $serviceOptions->{'recordIdOpaque'} ) {
3413 recordIdOpaque => $serviceOptions->{'recordIdOpaque'} );
3416 # this is an ILL request (Zebra doesn't support it, but Koha could eventually)
3417 #if ($serviceType eq 'itemorder') {
3418 # $Zpackage->option('contact-name' => $serviceOptions->{'contact-name'});
3419 # $Zpackage->option('contact-phone' => $serviceOptions->{'contact-phone'});
3420 # $Zpackage->option('contact-email' => $serviceOptions->{'contact-email'});
3421 # $Zpackage->option('itemorder-item' => $serviceOptions->{'itemorder-item'});
3424 if ( $serviceOptions->{record} ) {
3425 $Zpackage->option( record => $serviceOptions->{record} );
3427 # can be xml or marc
3428 if ( $serviceOptions->{'syntax'} ) {
3429 $Zpackage->option( syntax => $serviceOptions->{'syntax'} );
3433 # send the request, handle any exception encountered
3434 eval { $Zpackage->send($serviceType) };
3435 if ( $@ && $@->isa("ZOOM::Exception") ) {
3436 return "error: " . $@->code() . " " . $@->message() . "\n";
3439 # free up package resources
3440 $Zpackage->destroy();
3443 =head2 set_service_options
3445 my $serviceOptions = set_service_options($serviceType);
3447 C<$serviceType> itemorder,create,drop,commit,update,xmlupdate
3449 Currently, we only support 'create', 'commit', and 'update'. 'drop' support will be added as soon as Zebra supports it.
3453 sub set_service_options {
3454 my ($serviceType) = @_;
3457 # FIXME: This needs to be an OID ... if we ever need 'syntax' this sub will need to change
3458 # $serviceOptions->{ 'syntax' } = ''; #zebra doesn't support syntaxes other than xml
3460 if ( $serviceType eq 'commit' ) {
3464 if ( $serviceType eq 'create' ) {
3468 if ( $serviceType eq 'drop' ) {
3469 die "ERROR: 'drop' not currently supported (by Zebra)";
3471 return $serviceOptions;
3474 END { } # module clean-up code here (global destructor)
3482 Koha Developement team <info@koha.org>
3484 Paul POULAIN paul.poulain@free.fr
3486 Joshua Ferraro jmf@liblime.com
3492 # Revision 1.194 2007/03/30 12:00:42 tipaul
3493 # why the hell do we need to explicitly utf8 decode this string ? I really don't know, but it seems it's mandatory, otherwise, tag descriptions are not properly encoded...
3495 # Revision 1.193 2007/03/29 16:45:53 tipaul
3496 # Code cleaning of Biblio.pm (continued)
3498 # All subs have be cleaned :
3501 # - reordering Biblio.pm completly
3502 # - using only naming conventions
3504 # Seems to have broken nothing, but it still has to be heavily tested.
3505 # Note that Biblio.pm is now much more efficient than previously & probably more reliable as well.
3507 # Revision 1.192 2007/03/29 13:30:31 tipaul
3509 # == Biblio.pm cleaning (useless) ==
3510 # * some sub declaration dropped
3511 # * removed modbiblio sub
3512 # * removed moditem sub
3513 # * removed newitems. It was used only in finishrecieve. Replaced by a TransformKohaToMarc+AddItem, that is better.
3514 # * removed MARCkoha2marcItem
3515 # * removed MARCdelsubfield declaration
3516 # * removed MARCkoha2marcBiblio
3518 # == Biblio.pm cleaning (naming conventions) ==
3519 # * MARCgettagslib renamed to GetMarcStructure
3520 # * MARCgetitems renamed to GetMarcItem
3521 # * MARCfind_frameworkcode renamed to GetFrameworkCode
3522 # * MARCmarc2koha renamed to TransformMarcToKoha
3523 # * MARChtml2marc renamed to TransformHtmlToMarc
3524 # * MARChtml2xml renamed to TranformeHtmlToXml
3525 # * zebraop renamed to ModZebra
3528 # * removing MARC=OFF related scripts (in cataloguing directory)
3529 # * removed checkitems (function related to MARC=off feature, that is completly broken in head. If someone want to reintroduce it, hard work coming...)
3530 # * removed getitemsbybiblioitem (used only by MARC=OFF scripts, that is removed as well)
3532 # Revision 1.191 2007/03/29 09:42:13 tipaul
3533 # adding default value new feature into cataloguing. The system (definition) part has already been added by toins
3535 # Revision 1.190 2007/03/29 08:45:19 hdl
3536 # Deleting ignore_errors(1) pour MARC::Charset
3538 # Revision 1.189 2007/03/28 10:39:16 hdl
3539 # removing $dbh as a parameter in AuthoritiesMarc functions
3540 # And reporting all differences into the scripts taht relies on those functions.