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
73 &GetAuthorisedValueDesc
87 &ModItemInMarconefield
98 # those functions are exported but should not be used
99 # they are usefull is few circumstances, so are exported.
100 # but don't use them unless you're a core developer ;-)
113 &PrepareItemrecordDisplay
119 C4::Biblio - cataloging management functions
123 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:
127 =item 1. in the biblio,biblioitems,items, etc tables, which are limited to a one-to-one mapping to underlying MARC data
129 =item 2. as raw MARC in the Zebra index and storage engine
131 =item 3. as raw MARC the biblioitems.marc and biblioitems.marcxml
135 In the 3.0 version of Koha, the authoritative record-level information is in biblioitems.marcxml
137 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.
141 =item 1. Compared with MySQL, Zebra is slow to update an index for small data changes -- especially for proc-intensive operations like circulation
143 =item 2. Zebra's index has been known to crash and a backup of the data is necessary to rebuild it in such cases
147 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:
151 =item 1. Add*/Mod*/Del*/ - high-level external functions suitable for being called from external scripts to manage the collection
153 =item 2. _koha_* - low-level internal functions for managing the koha tables
155 =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.
157 =item 4. Zebra functions used to update the Zebra index
159 =item 5. internal helper functions such as char_decode, checkitems, etc. Some of these probably belong in Koha.pm
163 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 :
167 =item 1. save datas in biblio and biblioitems table, that gives us a biblionumber and a biblioitemnumber
169 =item 2. add the biblionumber and biblioitemnumber into the MARC records
171 =item 3. save the marc record
175 When dealing with items, we must :
179 =item 1. save the item in items table, that gives us an itemnumber
181 =item 2. add the itemnumber to the item MARC field
183 =item 3. overwrite the MARC record (with the added item) into biblioitems.marc(xml)
185 When modifying a biblio or an item, the behaviour is quite similar.
189 =head1 EXPORTED FUNCTIONS
195 ($biblionumber,$biblioitemnumber) = AddBiblio($record,$frameworkcode);
196 Exported function (core API) for adding a new biblio to koha.
203 my ( $record, $frameworkcode ) = @_;
205 my $biblioitemnumber;
206 my $dbh = C4::Context->dbh;
207 # transform the data into koha-table style data
208 my $olddata = TransformMarcToKoha( $dbh, $record, $frameworkcode );
209 $biblionumber = _koha_add_biblio( $dbh, $olddata, $frameworkcode );
210 $olddata->{'biblionumber'} = $biblionumber;
211 $biblioitemnumber = _koha_add_biblioitem( $dbh, $olddata );
213 # we must add bibnum and bibitemnum in MARC::Record...
214 # we build the new field with biblionumber and biblioitemnumber
215 # we drop the original field
216 # we add the new builded field.
217 ( my $biblio_tag, my $biblio_subfield ) = GetMarcFromKohaField($dbh,"biblio.biblionumber",$frameworkcode);
218 ( my $biblioitem_tag, my $biblioitem_subfield ) = GetMarcFromKohaField($dbh,"biblioitems.biblioitemnumber",$frameworkcode);
222 # biblionumber & biblioitemnumber are in different fields
223 if ( $biblio_tag != $biblioitem_tag ) {
225 # deal with biblionumber
226 if ( $biblio_tag < 10 ) {
227 $newfield = MARC::Field->new( $biblio_tag, $biblionumber );
231 MARC::Field->new( $biblio_tag, '', '',
232 "$biblio_subfield" => $biblionumber );
235 # drop old field and create new one...
236 my $old_field = $record->field($biblio_tag);
237 $record->delete_field($old_field);
238 $record->append_fields($newfield);
240 # deal with biblioitemnumber
241 if ( $biblioitem_tag < 10 ) {
242 $newfield = MARC::Field->new( $biblioitem_tag, $biblioitemnumber, );
246 MARC::Field->new( $biblioitem_tag, '', '',
247 "$biblioitem_subfield" => $biblioitemnumber, );
249 # drop old field and create new one...
250 $old_field = $record->field($biblioitem_tag);
251 $record->delete_field($old_field);
252 $record->insert_fields_ordered($newfield);
254 # biblionumber & biblioitemnumber are in the same field (can't be <10 as fields <10 have only 1 value)
257 my $newfield = MARC::Field->new(
259 "$biblio_subfield" => $biblionumber,
260 "$biblioitem_subfield" => $biblioitemnumber
263 # drop old field and create new one...
264 my $old_field = $record->field($biblio_tag);
265 $record->delete_field($old_field);
266 $record->insert_fields_ordered($newfield);
271 ModBiblioMarc( $record, $biblionumber, $frameworkcode );
273 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","ADD",$biblionumber,"biblio")
274 if C4::Context->preference("CataloguingLog");
276 return ( $biblionumber, $biblioitemnumber );
283 $biblionumber = AddItem( $record, $biblionumber)
284 Exported function (core API) for adding a new item to Koha
291 my ( $record, $biblionumber ) = @_;
292 my $dbh = C4::Context->dbh;
295 my $frameworkcode = GetFrameworkCode( $biblionumber );
296 my $item = &TransformMarcToKoha( $dbh, $record, $frameworkcode );
298 # needs old biblionumber and biblioitemnumber
299 $item->{'biblionumber'} = $biblionumber;
302 "select biblioitemnumber,itemtype from biblioitems where biblionumber=?"
304 $sth->execute( $item->{'biblionumber'} );
306 ( $item->{'biblioitemnumber'}, $itemtype ) = $sth->fetchrow;
309 "select notforloan from itemtypes where itemtype='$itemtype'");
311 my $notforloan = $sth->fetchrow;
312 ##Change the notforloan field if $notforloan found
313 if ( $notforloan > 0 ) {
314 $item->{'notforloan'} = $notforloan;
315 &MARCitemchange( $record, "items.notforloan", $notforloan );
317 if ( !$item->{'dateaccessioned'} || $item->{'dateaccessioned'} eq '' ) {
320 my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) =
325 "$year-" . sprintf( "%0.2d", $mon ) . "-" . sprintf( "%0.2d", $mday );
326 $item->{'dateaccessioned'} = $date;
327 &MARCitemchange( $record, "items.dateaccessioned", $date );
329 my ( $itemnumber, $error ) =
330 &_koha_new_items( $dbh, $item, $item->{barcode} );
332 # add itemnumber to MARC::Record before adding the item.
335 "select tagfield,tagsubfield from marc_subfield_structure where frameworkcode=? and kohafield=?"
337 &TransformKohaToMarcOneField( $sth, $record, "items.itemnumber", $itemnumber,
341 &AddItemInMarc( $record, $item->{'biblionumber'},$frameworkcode );
343 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","ADD",$itemnumber,"item")
344 if C4::Context->preference("CataloguingLog");
346 return ($item->{biblionumber}, $item->{biblioitemnumber},$itemnumber);
353 ModBiblio( $record,$biblionumber,$frameworkcode);
354 Exported function (core API) to modify a biblio
361 my ( $record, $biblionumber, $frameworkcode ) = @_;
363 if (C4::Context->preference("CataloguingLog")) {
364 my $newrecord = GetMarcBiblio($biblionumber);
365 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","MODIFY",$biblionumber,$newrecord->as_formatted)
368 my $dbh = C4::Context->dbh;
370 $frameworkcode = "" unless $frameworkcode;
372 # update the MARC record with the new record data
373 &ModBiblioMarc($record, $biblionumber, $frameworkcode );
375 # load the koha-table data object
376 my $oldbiblio = TransformMarcToKoha( $dbh, $record, $frameworkcode );
378 # modify the other koha tables
379 my $biblionumber = _koha_modify_biblio( $dbh, $oldbiblio );
380 _koha_modify_biblioitem( $dbh, $oldbiblio );
389 Exported function (core API) for modifying an item in Koha.
396 my ( $record, $biblionumber, $itemnumber, $delete, $new_item_hashref )
400 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","MODIFY",$itemnumber,$record->as_formatted)
401 if C4::Context->preference("CataloguingLog");
403 my $dbh = C4::Context->dbh;
405 # if we have a MARC record, we're coming from cataloging and so
406 # we do the whole routine: update the MARC and zebra, then update the koha
409 my $frameworkcode = GetFrameworkCode( $biblionumber );
410 ModItemInMarc( $record, $biblionumber, $itemnumber, $frameworkcode );
411 my $olditem = TransformMarcToKoha( $dbh, $record, $frameworkcode );
412 _koha_modify_item( $dbh, $olditem );
413 return $biblionumber;
416 # otherwise, we're just looking to modify something quickly
417 # (like a status) so we just update the koha tables
418 elsif ($new_item_hashref) {
419 _koha_modify_item( $dbh, $new_item_hashref );
423 =head2 ModBiblioframework
427 ModBiblioframework($biblionumber,$frameworkcode);
428 Exported function to modify a biblio framework
434 sub ModBiblioframework {
435 my ( $biblionumber, $frameworkcode ) = @_;
436 my $dbh = C4::Context->dbh;
439 "UPDATE biblio SET frameworkcode=? WHERE biblionumber=$biblionumber");
440 $sth->execute($frameworkcode);
444 =head2 ModItemInMarconefield
448 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)
449 &ModItemInMarconefield( $biblionumber, $itemnumber, $itemfield, $newvalue )
455 sub ModItemInMarconefield {
456 my ( $biblionumber, $itemnumber, $itemfield, $newvalue ) = @_;
457 my $dbh = C4::Context->dbh;
458 if ( !defined $newvalue ) {
462 my $record = GetMarcItem( $biblionumber, $itemnumber );
463 my ($tagfield, $tagsubfield) = GetMarcFromKohaField($dbh, $itemfield,'');
464 if ($tagfield && $tagsubfield) {
465 my $tag = $record->field($tagfield);
467 # my $tagsubs = $record->field($tagfield)->subfield($tagsubfield);
468 $tag->update( $tagsubfield => $newvalue );
469 $record->delete_field($tag);
470 $record->insert_fields_ordered($tag);
471 &ModItemInMarc( $record, $biblionumber, $itemnumber, 0 );
480 &ModItemInMarc( $record, $biblionumber, $itemnumber )
487 my ( $ItemRecord, $biblionumber, $itemnumber, $frameworkcode) = @_;
488 my $dbh = C4::Context->dbh;
490 # get complete MARC record & replace the item field by the new one
491 my $completeRecord = GetMarcBiblio($biblionumber);
492 my ($itemtag,$itemsubfield) = GetMarcFromKohaField($dbh,"items.itemnumber",$frameworkcode);
493 my $itemField = $ItemRecord->field($itemtag);
494 my @items = $completeRecord->field($itemtag);
496 if ($_->subfield($itemsubfield) eq $itemnumber) {
497 # $completeRecord->delete_field($_);
498 $_->replace_with($itemField);
502 my $sth = $dbh->prepare("update biblioitems set marc=?,marcxml=? where biblionumber=?");
503 $sth->execute( $completeRecord->as_usmarc(), $completeRecord->as_xml_record(),$biblionumber );
505 ModZebra($biblionumber,"specialUpdate","biblioserver");
508 =head2 ModDateLastSeen
510 &ModDateLastSeen($itemnum)
511 Mark item as seen. Is called when an item is issued, returned or manually marked during inventory/stocktaking
512 C<$itemnum> is the item number
516 sub ModDateLastSeen {
518 my $dbh = C4::Context->dbh;
521 "update items set itemlost=0, datelastseen = now() where items.itemnumber = ?"
523 $sth->execute($itemnum);
530 my $error = &DelBiblio($dbh,$biblionumber);
531 Exported function (core API) for deleting a biblio in koha.
532 Deletes biblio record from Zebra and Koha tables (biblio,biblioitems,items)
533 Also backs it up to deleted* tables
534 Checks to make sure there are not issues on any of the items
536 C<$error> : undef unless an error occurs
543 my ( $biblionumber ) = @_;
544 my $dbh = C4::Context->dbh;
545 my $error; # for error handling
547 # First make sure there are no items with issues are still attached
550 "SELECT biblioitemnumber FROM biblioitems WHERE biblionumber=?");
551 $sth->execute($biblionumber);
552 while ( my $biblioitemnumber = $sth->fetchrow ) {
553 my @issues = C4::Circulation::Circ2::itemissues($biblioitemnumber);
554 foreach my $issue (@issues) {
555 if ( ( $issue->{date_due} )
556 && ( $issue->{date_due} ne "Available" ) )
559 #FIXME: we need a status system in Biblio like in Circ to return standard codes and messages
560 # instead of hard-coded strings
562 "Item is checked out to a patron -- you must return it before deleting the Biblio";
566 return $error if $error;
569 ModZebra($biblionumber,"delete_record","biblioserver");
571 # delete biblio from Koha tables and save in deletedbiblio
572 $error = &_koha_delete_biblio( $dbh, $biblionumber );
574 # delete biblioitems and items from Koha tables and save in deletedbiblioitems,deleteditems
577 "SELECT biblioitemnumber FROM biblioitems WHERE biblionumber=?");
578 $sth->execute($biblionumber);
579 while ( my $biblioitemnumber = $sth->fetchrow ) {
581 # delete this biblioitem
582 $error = &_koha_delete_biblioitems( $dbh, $biblioitemnumber );
583 return $error if $error;
588 "SELECT itemnumber FROM items WHERE biblioitemnumber=?");
589 $items_sth->execute($biblioitemnumber);
590 while ( my $itemnumber = $items_sth->fetchrow ) {
591 $error = &_koha_delete_item( $dbh, $itemnumber );
592 return $error if $error;
595 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","DELETE",$biblionumber,"")
596 if C4::Context->preference("CataloguingLog");
604 DelItem( $biblionumber, $itemnumber );
605 Exported function (core API) for deleting an item record in Koha.
612 my ( $biblionumber, $itemnumber ) = @_;
613 my $dbh = C4::Context->dbh;
614 &_koha_delete_item( $dbh, $itemnumber );
615 # get the MARC record
616 my $record = GetMarcBiblio($biblionumber);
617 my $frameworkcode = GetFrameworkCode($biblionumber);
621 $dbh->prepare("UPDATE deleteditems SET marc=? WHERE itemnumber=?");
622 $copy2deleted->execute( $record->as_usmarc(), $itemnumber );
624 #search item field code
625 my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField($dbh,"items.itemnumber",$frameworkcode);
626 my @fields = $record->field($itemtag);
627 # delete the item specified
628 foreach my $field (@fields) {
629 if ( $field->subfield($itemsubfield) eq $itemnumber ) {
630 $record->delete_field($field);
633 &ModBiblioMarc( $record, $biblionumber, $frameworkcode );
634 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","DELETE",$itemnumber,"item")
635 if C4::Context->preference("CataloguingLog");
642 $data = &GetBiblioData($biblionumber);
643 Returns information about the book with the given biblionumber.
644 C<&GetBiblioData> returns a reference-to-hash. The keys are the fields in
645 the C<biblio> and C<biblioitems> tables in the
647 In addition, C<$data-E<gt>{subject}> is the list of the book's
648 subjects, separated by C<" , "> (space, comma, space).
649 If there are multiple biblioitems with the given biblionumber, only
650 the first one is considered.
658 my $dbh = C4::Context->dbh;
661 SELECT * , biblioitems.notes AS bnotes, biblio.notes
663 LEFT JOIN biblioitems ON biblio.biblionumber = biblioitems.biblionumber
664 LEFT JOIN itemtypes ON biblioitems.itemtype = itemtypes.itemtype
665 WHERE biblio.biblionumber = ?
666 AND biblioitems.biblionumber = biblio.biblionumber
668 my $sth = $dbh->prepare($query);
669 $sth->execute($bibnum);
671 $data = $sth->fetchrow_hashref;
675 } # sub GetBiblioData
682 @results = &GetItemsInfo($biblionumber, $type);
684 Returns information about books with the given biblionumber.
686 C<$type> may be either C<intra> or anything else. If it is not set to
687 C<intra>, then the search will exclude lost, very overdue, and
690 C<&GetItemsInfo> returns a list of references-to-hash. Each element
691 contains a number of keys. Most of them are table items from the
692 C<biblio>, C<biblioitems>, C<items>, and C<itemtypes> tables in the
693 Koha database. Other keys include:
697 =item C<$data-E<gt>{branchname}>
699 The name (not the code) of the branch to which the book belongs.
701 =item C<$data-E<gt>{datelastseen}>
703 This is simply C<items.datelastseen>, except that while the date is
704 stored in YYYY-MM-DD format in the database, here it is converted to
705 DD/MM/YYYY format. A NULL date is returned as C<//>.
707 =item C<$data-E<gt>{datedue}>
709 =item C<$data-E<gt>{class}>
711 This is the concatenation of C<biblioitems.classification>, the book's
712 Dewey code, and C<biblioitems.subclass>.
714 =item C<$data-E<gt>{ocount}>
716 I think this is the number of copies of the book available.
718 =item C<$data-E<gt>{order}>
720 If this is set, it is set to C<One Order>.
729 my ( $biblionumber, $type ) = @_;
730 my $dbh = C4::Context->dbh;
731 my $query = "SELECT *,items.notforloan as itemnotforloan
732 FROM items, biblio, biblioitems
733 LEFT JOIN itemtypes on biblioitems.itemtype = itemtypes.itemtype
734 WHERE items.biblionumber = ?
735 AND biblioitems.biblioitemnumber = items.biblioitemnumber
736 AND biblio.biblionumber = items.biblionumber
737 ORDER BY items.dateaccessioned desc
739 my $sth = $dbh->prepare($query);
740 $sth->execute($biblionumber);
743 my ( $date_due, $count_reserves );
745 while ( my $data = $sth->fetchrow_hashref ) {
747 my $isth = $dbh->prepare(
748 "SELECT issues.*,borrowers.cardnumber
749 FROM issues, borrowers
751 AND returndate IS NULL
752 AND issues.borrowernumber=borrowers.borrowernumber"
754 $isth->execute( $data->{'itemnumber'} );
755 if ( my $idata = $isth->fetchrow_hashref ) {
756 $data->{borrowernumber} = $idata->{borrowernumber};
757 $data->{cardnumber} = $idata->{cardnumber};
758 $datedue = format_date( $idata->{'date_due'} );
760 if ( $datedue eq '' ) {
761 #$datedue="Available";
762 my ( $restype, $reserves ) =
763 C4::Reserves2::CheckReserves( $data->{'itemnumber'} );
767 $count_reserves = $restype;
772 #get branch information.....
773 my $bsth = $dbh->prepare(
774 "SELECT * FROM branches WHERE branchcode = ?
777 $bsth->execute( $data->{'holdingbranch'} );
778 if ( my $bdata = $bsth->fetchrow_hashref ) {
779 $data->{'branchname'} = $bdata->{'branchname'};
781 my $date = format_date( $data->{'datelastseen'} );
782 $data->{'datelastseen'} = $date;
783 $data->{'datedue'} = $datedue;
784 $data->{'count_reserves'} = $count_reserves;
786 # get notforloan complete status if applicable
787 my $sthnflstatus = $dbh->prepare(
788 'SELECT authorised_value
789 FROM marc_subfield_structure
790 WHERE kohafield="items.notforloan"
794 $sthnflstatus->execute;
795 my ($authorised_valuecode) = $sthnflstatus->fetchrow;
796 if ($authorised_valuecode) {
797 $sthnflstatus = $dbh->prepare(
798 "SELECT lib FROM authorised_values
800 AND authorised_value=?"
802 $sthnflstatus->execute( $authorised_valuecode,
803 $data->{itemnotforloan} );
804 my ($lib) = $sthnflstatus->fetchrow;
805 $data->{notforloan} = $lib;
808 # my stack procedures
809 my $stackstatus = $dbh->prepare(
810 'SELECT authorised_value
811 FROM marc_subfield_structure
812 WHERE kohafield="items.stack"
815 $stackstatus->execute;
817 ($authorised_valuecode) = $stackstatus->fetchrow;
818 if ($authorised_valuecode) {
819 $stackstatus = $dbh->prepare(
821 FROM authorised_values
823 AND authorised_value=?
826 $stackstatus->execute( $authorised_valuecode, $data->{stack} );
827 my ($lib) = $stackstatus->fetchrow;
828 $data->{stack} = $lib;
830 $results[$i] = $data;
842 $itemstatushash = &getitemstatus($fwkcode);
843 returns information about status.
844 Can be MARC dependant.
846 But basically could be can be loan or not
847 Create a status selector with the following code
849 =head3 in PERL SCRIPT
851 my $itemstatushash = getitemstatus;
853 foreach my $thisstatus (keys %$itemstatushash) {
854 my %row =(value => $thisstatus,
855 statusname => $itemstatushash->{$thisstatus}->{'statusname'},
857 push @itemstatusloop, \%row;
859 $template->param(statusloop=>\@itemstatusloop);
864 <select name="statusloop">
865 <option value="">Default</option>
866 <!-- TMPL_LOOP name="statusloop" -->
867 <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="statusname" --></option>
875 # returns a reference to a hash of references to status...
878 my $dbh = C4::Context->dbh;
880 $fwk = '' unless ($fwk);
881 my ( $tag, $subfield ) =
882 GetMarcFromKohaField( $dbh, "items.notforloan", $fwk );
883 if ( $tag and $subfield ) {
886 "select authorised_value from marc_subfield_structure where tagfield=? and tagsubfield=? and frameworkcode=?"
888 $sth->execute( $tag, $subfield, $fwk );
889 if ( my ($authorisedvaluecat) = $sth->fetchrow ) {
892 "select authorised_value, lib from authorised_values where category=? order by lib"
894 $authvalsth->execute($authorisedvaluecat);
895 while ( my ( $authorisedvalue, $lib ) = $authvalsth->fetchrow ) {
896 $itemstatus{$authorisedvalue} = $lib;
912 $itemstatus{"1"} = "Not For Loan";
916 =head2 getitemlocation
920 $itemlochash = &getitemlocation($fwk);
921 returns informations about location.
922 where fwk stands for an optional framework code.
923 Create a location selector with the following code
925 =head3 in PERL SCRIPT
927 my $itemlochash = getitemlocation;
929 foreach my $thisloc (keys %$itemlochash) {
930 my $selected = 1 if $thisbranch eq $branch;
931 my %row =(locval => $thisloc,
932 selected => $selected,
933 locname => $itemlochash->{$thisloc},
935 push @itemlocloop, \%row;
937 $template->param(itemlocationloop => \@itemlocloop);
941 <select name="location">
942 <option value="">Default</option>
943 <!-- TMPL_LOOP name="itemlocationloop" -->
944 <option value="<!-- TMPL_VAR name="locval" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="locname" --></option>
952 sub GetItemLocation {
954 # returns a reference to a hash of references to location...
957 my $dbh = C4::Context->dbh;
959 $fwk = '' unless ($fwk);
960 my ( $tag, $subfield ) =
961 GetMarcFromKohaField( $dbh, "items.location", $fwk );
962 if ( $tag and $subfield ) {
965 "select authorised_value from marc_subfield_structure where tagfield=? and tagsubfield=? and frameworkcode=?"
967 $sth->execute( $tag, $subfield, $fwk );
968 if ( my ($authorisedvaluecat) = $sth->fetchrow ) {
971 "select authorised_value, lib from authorised_values where category=? order by lib"
973 $authvalsth->execute($authorisedvaluecat);
974 while ( my ( $authorisedvalue, $lib ) = $authvalsth->fetchrow ) {
975 $itemlocation{$authorisedvalue} = $lib;
978 return \%itemlocation;
991 $itemlocation{"1"} = "Not For Loan";
992 return \%itemlocation;
997 $items = GetLostItems($where,$orderby);
999 This function get the items lost into C<$items>.
1004 C<$where> is a hashref. it containts a field of the items table as key
1005 and the value to match as value.
1006 C<$orderby> is a field of the items table.
1009 C<$items> is a reference to an array full of hasref which keys are items' table column.
1011 =item usage in the perl script:
1014 $where{barcode} = 0001548;
1015 my $items = GetLostItems( \%where, "homebranch" );
1016 $template->param(itemsloop => $items);
1023 # Getting input args.
1025 my $orderby = shift;
1026 my $dbh = C4::Context->dbh;
1031 WHERE itemlost IS NOT NULL
1034 foreach my $key (keys %$where) {
1035 $query .= " AND " . $key . " LIKE '%" . $where->{$key} . "%'";
1037 $query .= " ORDER BY ".$orderby if defined $orderby;
1039 my $sth = $dbh->prepare($query);
1042 while ( my $row = $sth->fetchrow_hashref ){
1048 =head2 GetItemsForInventory
1050 $itemlist = GetItemsForInventory($minlocation,$maxlocation,$datelastseen,$offset,$size)
1052 Retrieve a list of title/authors/barcode/callnumber, for biblio inventory.
1054 The sub returns a list of hashes, containing itemnumber, author, title, barcode & item callnumber.
1055 It is ordered by callnumber,title.
1057 The minlocation & maxlocation parameters are used to specify a range of item callnumbers
1058 the datelastseen can be used to specify that you want to see items not seen since a past date only.
1059 offset & size can be used to retrieve only a part of the whole listing (defaut behaviour)
1063 sub GetItemsForInventory {
1064 my ( $minlocation, $maxlocation, $datelastseen, $branch, $offset, $size ) = @_;
1065 my $dbh = C4::Context->dbh;
1067 if ($datelastseen) {
1069 "SELECT itemnumber,barcode,itemcallnumber,title,author,datelastseen
1071 LEFT JOIN biblio ON items.biblionumber=biblio.biblionumber
1072 WHERE itemcallnumber>= ?
1073 AND itemcallnumber <=?
1074 AND (datelastseen< ? OR datelastseen IS NULL)";
1075 $query.= " AND items.homebranch=".$dbh->quote($branch) if $branch;
1076 $query .= " ORDER BY itemcallnumber,title";
1077 $sth = $dbh->prepare($query);
1078 $sth->execute( $minlocation, $maxlocation, $datelastseen );
1082 SELECT itemnumber,barcode,itemcallnumber,title,author,datelastseen
1084 LEFT JOIN biblio ON items.biblionumber=biblio.biblionumber
1085 WHERE itemcallnumber>= ?
1086 AND itemcallnumber <=?";
1087 $query.= " AND items.homebranch=".$dbh->quote($branch) if $branch;
1088 $query .= " ORDER BY itemcallnumber,title";
1089 $sth = $dbh->prepare($query);
1090 $sth->execute( $minlocation, $maxlocation );
1093 while ( my $row = $sth->fetchrow_hashref ) {
1094 $offset-- if ($offset);
1095 if ( ( !$offset ) && $size ) {
1096 push @results, $row;
1103 =head2 &GetBiblioItemData
1107 $itemdata = &GetBiblioItemData($biblioitemnumber);
1109 Looks up the biblioitem with the given biblioitemnumber. Returns a
1110 reference-to-hash. The keys are the fields from the C<biblio>,
1111 C<biblioitems>, and C<itemtypes> tables in the Koha database, except
1112 that C<biblioitems.notes> is given as C<$itemdata-E<gt>{bnotes}>.
1119 sub GetBiblioItemData {
1121 my $dbh = C4::Context->dbh;
1124 "Select *,biblioitems.notes as bnotes from biblioitems, biblio,itemtypes where biblio.biblionumber = biblioitems.biblionumber and biblioitemnumber = ? and biblioitems.itemtype = itemtypes.itemtype"
1128 $sth->execute($bibitem);
1130 $data = $sth->fetchrow_hashref;
1134 } # sub &GetBiblioItemData
1136 =head2 GetItemFromBarcode
1140 $result = GetItemFromBarcode($barcode);
1146 sub GetItemFromBarcode {
1148 my $dbh = C4::Context->dbh;
1151 $dbh->prepare("SELECT itemnumber from items where items.barcode=?");
1152 $rq->execute($barcode);
1153 my ($result) = $rq->fetchrow;
1157 =head2 GetBiblioItemByBiblioNumber
1161 NOTE : This function has been copy/paste from C4/Biblio.pm from head before zebra integration.
1167 sub GetBiblioItemByBiblioNumber {
1168 my ($biblionumber) = @_;
1169 my $dbh = C4::Context->dbh;
1170 my $sth = $dbh->prepare("Select * from biblioitems where biblionumber = ?");
1174 $sth->execute($biblionumber);
1176 while ( my $data = $sth->fetchrow_hashref ) {
1177 push @results, $data;
1184 =head2 GetBiblioFromItemNumber
1188 $item = &GetBiblioFromItemNumber($itemnumber);
1190 Looks up the item with the given itemnumber.
1192 C<&itemnodata> returns a reference-to-hash whose keys are the fields
1193 from the C<biblio>, C<biblioitems>, and C<items> tables in the Koha
1201 sub GetBiblioFromItemNumber {
1202 my ( $itemnumber ) = @_;
1203 my $dbh = C4::Context->dbh;
1205 my $sth = $dbh->prepare(
1206 "SELECT * FROM biblio,items,biblioitems
1207 WHERE items.itemnumber = ?
1208 AND biblio.biblionumber = items.biblionumber
1209 AND biblioitems.biblioitemnumber = items.biblioitemnumber"
1212 $sth->execute($itemnumber);
1213 my $data = $sth->fetchrow_hashref;
1222 ( $count, @results ) = &GetBiblio($biblionumber);
1229 my ($biblionumber) = @_;
1230 my $dbh = C4::Context->dbh;
1231 my $sth = $dbh->prepare("Select * from biblio where biblionumber = ?");
1234 $sth->execute($biblionumber);
1235 while ( my $data = $sth->fetchrow_hashref ) {
1236 $results[$count] = $data;
1240 return ( $count, @results );
1247 $data = &GetItem($itemnumber,$barcode);
1249 return Item information, for a given itemnumber or barcode
1256 my ($itemnumber,$barcode) = @_;
1257 my $dbh = C4::Context->dbh;
1259 my $sth = $dbh->prepare("
1261 WHERE itemnumber = ?");
1262 $sth->execute($itemnumber);
1263 my $data = $sth->fetchrow_hashref;
1266 my $sth = $dbh->prepare("
1270 $sth->execute($barcode);
1271 my $data = $sth->fetchrow_hashref;
1276 =head2 get_itemnumbers_of
1280 my @itemnumbers_of = get_itemnumbers_of(@biblionumbers);
1282 Given a list of biblionumbers, return the list of corresponding itemnumbers
1283 for each biblionumber.
1285 Return a reference on a hash where keys are biblionumbers and values are
1286 references on array of itemnumbers.
1292 sub get_itemnumbers_of {
1293 my @biblionumbers = @_;
1295 my $dbh = C4::Context->dbh;
1301 WHERE biblionumber IN (?' . ( ',?' x scalar @biblionumbers - 1 ) . ')
1303 my $sth = $dbh->prepare($query);
1304 $sth->execute(@biblionumbers);
1308 while ( my ( $itemnumber, $biblionumber ) = $sth->fetchrow_array ) {
1309 push @{ $itemnumbers_of{$biblionumber} }, $itemnumber;
1312 return \%itemnumbers_of;
1315 =head2 GetItemInfosOf
1319 GetItemInfosOf(@itemnumbers);
1325 sub GetItemInfosOf {
1326 my @itemnumbers = @_;
1331 WHERE itemnumber IN (' . join( ',', @itemnumbers ) . ')
1333 return get_infos_of( $query, 'itemnumber' );
1336 =head2 GetBiblioItemInfosOf
1340 GetBiblioItemInfosOf(@biblioitemnumbers);
1346 sub GetBiblioItemInfosOf {
1347 my @biblioitemnumbers = @_;
1350 SELECT biblioitemnumber,
1354 WHERE biblioitemnumber IN (' . join( ',', @biblioitemnumbers ) . ')
1356 return get_infos_of( $query, 'biblioitemnumber' );
1359 =head1 FUNCTIONS FOR HANDLING MARC MANAGEMENT
1361 =head2 GetMarcStructure
1365 $res = GetMarcStructure($dbh,$forlibrarian,$frameworkcode);
1367 Returns a reference to a big hash of hash, with the Marc structure fro the given frameworkcode
1369 $forlibrarian :if set to 1, the MARC descriptions are the librarians ones, otherwise it's the public (OPAC) ones
1370 $frameworkcode : the framework code to read
1378 sub GetMarcStructure {
1379 my ( $dbh, $forlibrarian, $frameworkcode ) = @_;
1380 $frameworkcode = "" unless $frameworkcode;
1382 my $libfield = ( $forlibrarian eq 1 ) ? 'liblibrarian' : 'libopac';
1384 # check that framework exists
1387 "select count(*) from marc_tag_structure where frameworkcode=?");
1388 $sth->execute($frameworkcode);
1389 my ($total) = $sth->fetchrow;
1390 $frameworkcode = "" unless ( $total > 0 );
1393 "select tagfield,liblibrarian,libopac,mandatory,repeatable from marc_tag_structure where frameworkcode=? order by tagfield"
1395 $sth->execute($frameworkcode);
1396 my ( $liblibrarian, $libopac, $tag, $res, $tab, $mandatory, $repeatable );
1398 while ( ( $tag, $liblibrarian, $libopac, $mandatory, $repeatable ) =
1401 $res->{$tag}->{lib} =
1402 ( $forlibrarian or !$libopac ) ? $liblibrarian : $libopac;
1403 # why the hell do we need to explicitly decode utf8 ?
1404 # that's a good question, but we must do it...
1406 utf8::decode($res->{$tag}->{lib});
1407 # warn "$liblibrarian";
1408 $res->{$tab}->{tab} = ""; # XXX
1409 $res->{$tag}->{mandatory} = $mandatory;
1410 $res->{$tag}->{repeatable} = $repeatable;
1415 "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"
1417 $sth->execute($frameworkcode);
1420 my $authorised_value;
1432 $tag, $subfield, $liblibrarian,
1434 $mandatory, $repeatable, $authorised_value,
1435 $authtypecode, $value_builder, $kohafield,
1436 $seealso, $hidden, $isurl,
1442 $res->{$tag}->{$subfield}->{lib} =
1443 ( $forlibrarian or !$libopac ) ? $liblibrarian : $libopac;
1444 $res->{$tag}->{$subfield}->{tab} = $tab;
1445 $res->{$tag}->{$subfield}->{mandatory} = $mandatory;
1446 $res->{$tag}->{$subfield}->{repeatable} = $repeatable;
1447 $res->{$tag}->{$subfield}->{authorised_value} = $authorised_value;
1448 $res->{$tag}->{$subfield}->{authtypecode} = $authtypecode;
1449 $res->{$tag}->{$subfield}->{value_builder} = $value_builder;
1450 $res->{$tag}->{$subfield}->{kohafield} = $kohafield;
1451 $res->{$tag}->{$subfield}->{seealso} = $seealso;
1452 $res->{$tag}->{$subfield}->{hidden} = $hidden;
1453 $res->{$tag}->{$subfield}->{isurl} = $isurl;
1454 $res->{$tag}->{$subfield}->{link} = $link;
1455 $res->{$tag}->{$subfield}->{defaultvalue} = $defaultvalue;
1460 =head2 GetMarcFromKohaField
1464 ($MARCfield,$MARCsubfield)=GetMarcFromKohaField($dbh,$kohafield,$frameworkcode);
1465 Returns the MARC fields & subfields mapped to the koha field
1466 for the given frameworkcode
1472 sub GetMarcFromKohaField {
1473 my ( $dbh, $kohafield, $frameworkcode ) = @_;
1474 return 0, 0 unless $kohafield;
1475 my $relations = C4::Context->marcfromkohafield;
1477 $relations->{$frameworkcode}->{$kohafield}->[0],
1478 $relations->{$frameworkcode}->{$kohafield}->[1]
1482 =head2 GetMarcBiblio
1486 Returns MARC::Record of the biblionumber passed in parameter.
1487 the marc record contains both biblio & item datas
1494 my $biblionumber = shift;
1495 my $dbh = C4::Context->dbh;
1497 $dbh->prepare("select marcxml from biblioitems where biblionumber=? ");
1498 $sth->execute($biblionumber);
1499 my ($marcxml) = $sth->fetchrow;
1500 # warn "marcxml : $marcxml";
1501 MARC::File::XML->default_record_format(C4::Context->preference('marcflavour'));
1502 $marcxml =~ s/\x1e//g;
1503 $marcxml =~ s/\x1f//g;
1504 $marcxml =~ s/\x1d//g;
1505 $marcxml =~ s/\x0f//g;
1506 $marcxml =~ s/\x0c//g;
1507 my $record = MARC::Record->new();
1508 $record = MARC::Record::new_from_xml( $marcxml, "utf8",C4::Context->preference('marcflavour')) if $marcxml;
1516 my $marcxml = GetXmlBiblio($biblionumber);
1518 Returns biblioitems.marcxml of the biblionumber passed in parameter.
1519 The XML contains both biblio & item datas
1526 my ( $biblionumber ) = @_;
1527 my $dbh = C4::Context->dbh;
1529 $dbh->prepare("select marcxml from biblioitems where biblionumber=? ");
1530 $sth->execute($biblionumber);
1531 my ($marcxml) = $sth->fetchrow;
1535 =head2 GetAuthorisedValueDesc
1539 my $subfieldvalue =get_authorised_value_desc(
1540 $tag, $subf[$i][0],$subf[$i][1], '', $taglib);
1541 Retrieve the complete description for a given authorised value.
1547 sub GetAuthorisedValueDesc {
1548 my ( $tag, $subfield, $value, $framework, $tagslib ) = @_;
1549 my $dbh = C4::Context->dbh;
1552 if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq "branches" ) {
1553 return C4::Branch::GetBranchName($value);
1557 if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq "itemtypes" ) {
1558 return getitemtypeinfo($value);
1561 #---- "true" authorized value
1562 my $category = $tagslib->{$tag}->{$subfield}->{'authorised_value'};
1564 if ( $category ne "" ) {
1567 "select lib from authorised_values where category = ? and authorised_value = ?"
1569 $sth->execute( $category, $value );
1570 my $data = $sth->fetchrow_hashref;
1571 return $data->{'lib'};
1574 return $value; # if nothing is found return the original value
1582 Returns MARC::Record of the item passed in parameter.
1589 my ( $biblionumber, $itemnumber ) = @_;
1590 my $dbh = C4::Context->dbh;
1591 my $newrecord = MARC::Record->new();
1592 my $marcflavour = C4::Context->preference('marcflavour');
1594 my $marcxml = GetXmlBiblio($biblionumber);
1595 my $record = MARC::Record->new();
1596 # warn "marcxml :$marcxml";
1597 $record = MARC::Record::new_from_xml( $marcxml, "utf8", $marcflavour );
1598 # warn "record :".$record->as_formatted;
1599 # now, find where the itemnumber is stored & extract only the item
1600 my ( $itemnumberfield, $itemnumbersubfield ) =
1601 GetMarcFromKohaField( $dbh, 'items.itemnumber', '' );
1602 my @fields = $record->field($itemnumberfield);
1603 foreach my $field (@fields) {
1604 if ( $field->subfield($itemnumbersubfield) eq $itemnumber ) {
1605 $newrecord->insert_fields_ordered($field);
1617 $marcnotesarray = GetMarcNotes( $record, $marcflavour );
1618 Get all notes from the MARC record and returns them in an array.
1619 The note are stored in differents places depending on MARC flavour
1626 my ( $record, $marcflavour ) = @_;
1628 if ( $marcflavour eq "MARC21" ) {
1631 else { # assume unimarc if not marc21
1638 foreach my $field ( $record->field($scope) ) {
1639 my $value = $field->as_string();
1640 if ( $note ne "" ) {
1641 $marcnote = { marcnote => $note, };
1642 push @marcnotes, $marcnote;
1645 if ( $note ne $value ) {
1646 $note = $note . " " . $value;
1651 $marcnote = { marcnote => $note };
1652 push @marcnotes, $marcnote; #load last tag into array
1655 } # end GetMarcNotes
1657 =head2 GetMarcSubjects
1661 $marcsubjcts = GetMarcSubjects($record,$marcflavour);
1662 Get all subjects from the MARC record and returns them in an array.
1663 The subjects are stored in differents places depending on MARC flavour
1669 sub GetMarcSubjects {
1670 my ( $record, $marcflavour ) = @_;
1671 my ( $mintag, $maxtag );
1672 if ( $marcflavour eq "MARC21" ) {
1676 else { # assume unimarc if not marc21
1683 foreach my $field ( $record->fields ) {
1684 next unless $field->tag() >= $mintag && $field->tag() <= $maxtag;
1685 my @subfields = $field->subfields();
1689 for my $subject_subfield ( @subfields ) {
1690 my $code = $subject_subfield->[0];
1691 $label .= $subject_subfield->[1] . " and su-to:" unless ( $code == 9 );
1693 $link = "Koha-Auth-Number:".$subject_subfield->[1];
1698 $link =~ s/ and\ssu-to:$//;
1711 return \@marcsubjcts;
1712 } #end GetMarcSubjects
1714 =head2 GetMarcAuthors
1718 authors = GetMarcAuthors($record,$marcflavour);
1719 Get all authors from the MARC record and returns them in an array.
1720 The authors are stored in differents places depending on MARC flavour
1726 sub GetMarcAuthors {
1727 my ( $record, $marcflavour ) = @_;
1728 my ( $mintag, $maxtag );
1729 if ( $marcflavour eq "MARC21" ) {
1733 else { # assume unimarc if not marc21
1740 foreach my $field ( $record->fields ) {
1741 next unless $field->tag() >= $mintag && $field->tag() <= $maxtag;
1743 my @subfields = $field->subfields();
1746 for my $authors_subfield (@subfields) {
1747 if ($count_auth ne '0'){
1751 my $subfieldcode = $authors_subfield->[0];
1752 my $value = $authors_subfield->[1];
1753 $hash{'tag'} = $field->tag;
1754 $hash{value} .= $value . " " if ($subfieldcode != 9) ;
1755 $hash{link} .= $value if ($subfieldcode eq 9);
1757 push @marcauthors, \%hash;
1759 return \@marcauthors;
1762 =head2 GetMarcSeries
1766 $marcseriessarray = GetMarcSeries($record,$marcflavour);
1767 Get all series from the MARC record and returns them in an array.
1768 The series are stored in differents places depending on MARC flavour
1775 my ($record, $marcflavour) = @_;
1776 my ($mintag, $maxtag);
1777 if ($marcflavour eq "MARC21") {
1780 } else { # assume unimarc if not marc21
1790 foreach my $field ($record->field('440'), $record->field('490')) {
1792 #my $value = $field->subfield('a');
1793 #$marcsubjct = {MARCSUBJCT => $value,};
1794 my @subfields = $field->subfields();
1795 #warn "subfields:".join " ", @$subfields;
1798 for my $series_subfield (@subfields) {
1800 undef $volume_number;
1801 # see if this is an instance of a volume
1802 if ($series_subfield->[0] eq 'v') {
1806 my $code = $series_subfield->[0];
1807 my $value = $series_subfield->[1];
1808 my $linkvalue = $value;
1809 $linkvalue =~ s/(\(|\))//g;
1810 my $operator = " and " unless $counter==0;
1811 push @link_loop, {link => $linkvalue, operator => $operator };
1812 my $separator = C4::Context->preference("authoritysep") unless $counter==0;
1813 if ($volume_number) {
1814 push @subfields_loop, {volumenum => $value};
1817 push @subfields_loop, {code => $code, value => $value, link_loop => \@link_loop, separator => $separator, volumenum => $volume_number};
1821 push @marcseries, { MARCSERIES_SUBFIELDS_LOOP => \@subfields_loop };
1822 #$marcsubjct = {MARCSUBJCT => $field->as_string(),};
1823 #push @marcsubjcts, $marcsubjct;
1827 my $marcseriessarray=\@marcseries;
1828 return $marcseriessarray;
1829 } #end getMARCseriess
1831 =head2 GetFrameworkCode
1835 $frameworkcode = GetFrameworkCode( $biblionumber )
1841 sub GetFrameworkCode {
1842 my ( $biblionumber ) = @_;
1843 my $dbh = C4::Context->dbh;
1845 $dbh->prepare("select frameworkcode from biblio where biblionumber=?");
1846 $sth->execute($biblionumber);
1847 my ($frameworkcode) = $sth->fetchrow;
1848 return $frameworkcode;
1851 =head2 TransformKohaToMarc
1855 $record = TransformKohaToMarc( $hash )
1856 This function builds partial MARC::Record from a hash
1857 Hash entries can be from biblio or biblioitems.
1858 This function is called in acquisition module, to create a basic catalogue entry from user entry
1864 sub TransformKohaToMarc {
1867 my $dbh = C4::Context->dbh;
1870 "select tagfield,tagsubfield from marc_subfield_structure where frameworkcode=? and kohafield=?"
1872 my $record = MARC::Record->new();
1873 foreach (keys %{$hash}) {
1874 &TransformKohaToMarcOneField( $sth, $record, $_,
1880 =head2 TransformKohaToMarcOneField
1884 $record = TransformKohaToMarcOneField( $sth, $record, $kohafieldname, $value, $frameworkcode );
1890 sub TransformKohaToMarcOneField {
1891 my ( $sth, $record, $kohafieldname, $value, $frameworkcode ) = @_;
1892 $frameworkcode='' unless $frameworkcode;
1896 if ( !defined $sth ) {
1897 my $dbh = C4::Context->dbh;
1900 "select tagfield,tagsubfield from marc_subfield_structure where frameworkcode=? and kohafield=?"
1903 $sth->execute( $frameworkcode, $kohafieldname );
1904 if ( ( $tagfield, $tagsubfield ) = $sth->fetchrow ) {
1905 my $tag = $record->field($tagfield);
1907 $tag->update( $tagsubfield => $value );
1908 $record->delete_field($tag);
1909 $record->insert_fields_ordered($tag);
1912 $record->add_fields( $tagfield, " ", " ", $tagsubfield => $value );
1918 =head2 TransformHtmlToXml
1922 $xml = TransformHtmlToXml( $tags, $subfields, $values, $indicator, $ind_tag )
1928 sub TransformHtmlToXml {
1929 my ( $tags, $subfields, $values, $indicator, $ind_tag ) = @_;
1930 my $xml = MARC::File::XML::header('UTF-8');
1931 if ( C4::Context->preference('marcflavour') eq 'UNIMARC' ) {
1932 MARC::File::XML->default_record_format('UNIMARC');
1933 use POSIX qw(strftime);
1934 my $string = strftime( "%Y%m%d", localtime(time) );
1935 $string = sprintf( "%-*s", 35, $string );
1936 substr( $string, 22, 6, "frey50" );
1937 $xml .= "<datafield tag=\"100\" ind1=\"\" ind2=\"\">\n";
1938 $xml .= "<subfield code=\"a\">$string</subfield>\n";
1939 $xml .= "</datafield>\n";
1945 for ( my $i = 0 ; $i <= @$tags ; $i++ ) {
1946 @$values[$i] =~ s/&/&/g;
1947 @$values[$i] =~ s/</</g;
1948 @$values[$i] =~ s/>/>/g;
1949 @$values[$i] =~ s/"/"/g;
1950 @$values[$i] =~ s/'/'/g;
1951 if ( !utf8::is_utf8( @$values[$i] ) ) {
1952 utf8::decode( @$values[$i] );
1954 if ( ( @$tags[$i] ne $prevtag ) ) {
1955 $j++ unless ( @$tags[$i] eq "" );
1957 $xml .= "</datafield>\n";
1958 if ( ( @$tags[$i] && @$tags[$i] > 10 )
1959 && ( @$values[$i] ne "" ) )
1961 my $ind1 = substr( @$indicator[$j], 0, 1 );
1963 if ( @$indicator[$j] ) {
1964 $ind2 = substr( @$indicator[$j], 1, 1 );
1967 warn "Indicator in @$tags[$i] is empty";
1971 "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
1973 "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
1981 if ( @$values[$i] ne "" ) {
1984 if ( @$tags[$i] eq "000" ) {
1985 $xml .= "<leader>@$values[$i]</leader>\n";
1988 # rest of the fixed fields
1990 elsif ( @$tags[$i] < 10 ) {
1992 "<controlfield tag=\"@$tags[$i]\">@$values[$i]</controlfield>\n";
1996 my $ind1 = substr( @$indicator[$j], 0, 1 );
1997 my $ind2 = substr( @$indicator[$j], 1, 1 );
1999 "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
2001 "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
2007 else { # @$tags[$i] eq $prevtag
2008 if ( @$values[$i] eq "" ) {
2012 my $ind1 = substr( @$indicator[$j], 0, 1 );
2013 my $ind2 = substr( @$indicator[$j], 1, 1 );
2015 "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
2019 "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
2022 $prevtag = @$tags[$i];
2024 $xml .= MARC::File::XML::footer();
2029 =head2 TransformHtmlToMarc
2033 $record = TransformHtmlToMarc( $dbh, $rtags, $rsubfields, $rvalues, %indicators )
2039 sub TransformHtmlToMarc {
2040 my ( $dbh, $rtags, $rsubfields, $rvalues, %indicators ) = @_;
2042 my $record = MARC::Record->new();
2044 # my %subfieldlist=();
2045 my $prevvalue; # if tag <10
2046 my $field; # if tag >=10
2047 for ( my $i = 0 ; $i < @$rtags ; $i++ ) {
2048 next unless @$rvalues[$i];
2050 # rebuild MARC::Record
2051 # warn "0=>".@$rtags[$i].@$rsubfields[$i]." = ".@$rvalues[$i].": ";
2052 if ( @$rtags[$i] ne $prevtag ) {
2053 if ( $prevtag < 10 ) {
2056 if ( $prevtag ne '000' ) {
2057 $record->insert_fields_ordered(
2058 ( sprintf "%03s", $prevtag ), $prevvalue );
2062 $record->leader($prevvalue);
2069 $record->insert_fields_ordered($field);
2072 $indicators{ @$rtags[$i] } .= ' ';
2073 if ( @$rtags[$i] < 10 ) {
2074 $prevvalue = @$rvalues[$i];
2079 $field = MARC::Field->new(
2080 ( sprintf "%03s", @$rtags[$i] ),
2081 substr( $indicators{ @$rtags[$i] }, 0, 1 ),
2082 substr( $indicators{ @$rtags[$i] }, 1, 1 ),
2083 @$rsubfields[$i] => @$rvalues[$i]
2086 $prevtag = @$rtags[$i];
2089 if ( @$rtags[$i] < 10 ) {
2090 $prevvalue = @$rvalues[$i];
2093 if ( length( @$rvalues[$i] ) > 0 ) {
2094 $field->add_subfields( @$rsubfields[$i] => @$rvalues[$i] );
2097 $prevtag = @$rtags[$i];
2101 # the last has not been included inside the loop... do it now !
2102 $record->insert_fields_ordered($field) if $field;
2104 # warn "HTML2MARC=".$record->as_formatted;
2105 $record->encoding('UTF-8');
2107 # $record->MARC::File::USMARC::update_leader();
2111 =head2 TransformMarcToKoha
2115 $result = TransformMarcToKoha( $dbh, $record, $frameworkcode )
2121 sub TransformMarcToKoha {
2122 my ( $dbh, $record, $frameworkcode ) = @_;
2125 "select tagfield,tagsubfield from marc_subfield_structure where frameworkcode=? and kohafield=?"
2128 my $sth2 = $dbh->prepare("SHOW COLUMNS from biblio");
2131 while ( ($field) = $sth2->fetchrow ) {
2133 &TransformMarcToKohaOneField( "biblio", $field, $record, $result,
2136 $sth2 = $dbh->prepare("SHOW COLUMNS from biblioitems");
2138 while ( ($field) = $sth2->fetchrow ) {
2139 if ( $field eq 'notes' ) { $field = 'bnotes'; }
2141 &TransformMarcToKohaOneField( "biblioitems", $field, $record, $result,
2144 $sth2 = $dbh->prepare("SHOW COLUMNS from items");
2146 while ( ($field) = $sth2->fetchrow ) {
2148 &TransformMarcToKohaOneField( "items", $field, $record, $result,
2153 # modify copyrightdate to keep only the 1st year found
2154 my $temp = $result->{'copyrightdate'};
2155 $temp =~ m/c(\d\d\d\d)/; # search cYYYY first
2157 $result->{'copyrightdate'} = $1;
2159 else { # if no cYYYY, get the 1st date.
2160 $temp =~ m/(\d\d\d\d)/;
2161 $result->{'copyrightdate'} = $1;
2164 # modify publicationyear to keep only the 1st year found
2165 $temp = $result->{'publicationyear'};
2166 $temp =~ m/c(\d\d\d\d)/; # search cYYYY first
2168 $result->{'publicationyear'} = $1;
2170 else { # if no cYYYY, get the 1st date.
2171 $temp =~ m/(\d\d\d\d)/;
2172 $result->{'publicationyear'} = $1;
2177 =head2 TransformMarcToKohaOneField
2181 $result = TransformMarcToKohaOneField( $kohatable, $kohafield, $record, $result, $frameworkcode )
2187 sub TransformMarcToKohaOneField {
2189 # FIXME ? if a field has a repeatable subfield that is used in old-db, only the 1st will be retrieved...
2190 my ( $kohatable, $kohafield, $record, $result, $frameworkcode ) = @_;
2193 my ( $tagfield, $subfield ) =
2194 GetMarcFromKohaField( "", $kohatable . "." . $kohafield,
2196 foreach my $field ( $record->field($tagfield) ) {
2197 if ( $field->tag() < 10 ) {
2198 if ( $result->{$kohafield} ) {
2199 $result->{$kohafield} .= " | " . $field->data();
2202 $result->{$kohafield} = $field->data();
2206 if ( $field->subfields ) {
2207 my @subfields = $field->subfields();
2208 foreach my $subfieldcount ( 0 .. $#subfields ) {
2209 if ( $subfields[$subfieldcount][0] eq $subfield ) {
2210 if ( $result->{$kohafield} ) {
2211 $result->{$kohafield} .=
2212 " | " . $subfields[$subfieldcount][1];
2215 $result->{$kohafield} =
2216 $subfields[$subfieldcount][1];
2225 =head1 OTHER FUNCTIONS
2231 my $string = char_decode( $string, $encoding );
2233 converts ISO 5426 coded string to UTF-8
2234 sloppy code : should be improved in next issue
2241 my ( $string, $encoding ) = @_;
2244 $encoding = C4::Context->preference("marcflavour") unless $encoding;
2245 if ( $encoding eq "UNIMARC" ) {
2315 # this handles non-sorting blocks (if implementation requires this)
2316 $string = nsb_clean($_);
2318 elsif ( $encoding eq "USMARC" || $encoding eq "MARC21" ) {
2377 #Additional Turkish characters
2380 s/(\xf0)s/\xc5\x9f/gm;
2381 s/(\xf0)S/\xc5\x9e/gm;
2384 s/\xe7\x49/\\xc4\xb0/gm;
2385 s/(\xe6)G/\xc4\x9e/gm;
2386 s/(\xe6)g/ğ\xc4\x9f/gm;
2389 s/(\xe8|\xc8)o/ö/gm;
2390 s/(\xe8|\xc8)O/Ö/gm;
2391 s/(\xe8|\xc8)u/ü/gm;
2392 s/(\xe8|\xc8)U/Ü/gm;
2393 s/\xc2\xb8/\xc4\xb1/gm;
2396 # this handles non-sorting blocks (if implementation requires this)
2397 $string = nsb_clean($_);
2406 my $string = nsb_clean( $string, $encoding );
2413 my $NSB = '\x88'; # NSB : begin Non Sorting Block
2414 my $NSE = '\x89'; # NSE : Non Sorting Block end
2415 # handles non sorting blocks
2419 s/[ ]{0,1}$NSE/) /gm;
2424 =head2 PrepareItemrecordDisplay
2428 PrepareItemrecordDisplay($itemrecord,$bibnum,$itemumber);
2430 Returns a hash with all the fields for Display a given item data in a template
2436 sub PrepareItemrecordDisplay {
2438 my ( $bibnum, $itemnum ) = @_;
2440 my $dbh = C4::Context->dbh;
2441 my $frameworkcode = &GetFrameworkCode( $bibnum );
2442 my ( $itemtagfield, $itemtagsubfield ) =
2443 &GetMarcFromKohaField( $dbh, "items.itemnumber", $frameworkcode );
2444 my $tagslib = &GetMarcStructure( $dbh, 1, $frameworkcode );
2445 my $itemrecord = GetMarcItem( $bibnum, $itemnum) if ($itemnum);
2447 my $authorised_values_sth =
2449 "select authorised_value,lib from authorised_values where category=? order by lib"
2451 foreach my $tag ( sort keys %{$tagslib} ) {
2452 my $previous_tag = '';
2454 # loop through each subfield
2456 foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
2457 next if ( subfield_is_koha_internal_p($subfield) );
2458 next if ( $tagslib->{$tag}->{$subfield}->{'tab'} ne "10" );
2460 $subfield_data{tag} = $tag;
2461 $subfield_data{subfield} = $subfield;
2462 $subfield_data{countsubfield} = $cntsubf++;
2463 $subfield_data{kohafield} =
2464 $tagslib->{$tag}->{$subfield}->{'kohafield'};
2466 # $subfield_data{marc_lib}=$tagslib->{$tag}->{$subfield}->{lib};
2467 $subfield_data{marc_lib} =
2468 "<span id=\"error\" title=\""
2469 . $tagslib->{$tag}->{$subfield}->{lib} . "\">"
2470 . substr( $tagslib->{$tag}->{$subfield}->{lib}, 0, 12 )
2472 $subfield_data{mandatory} =
2473 $tagslib->{$tag}->{$subfield}->{mandatory};
2474 $subfield_data{repeatable} =
2475 $tagslib->{$tag}->{$subfield}->{repeatable};
2476 $subfield_data{hidden} = "display:none"
2477 if $tagslib->{$tag}->{$subfield}->{hidden};
2479 ( $x, $value ) = _find_value( $tag, $subfield, $itemrecord )
2481 $value =~ s/"/"/g;
2483 # search for itemcallnumber if applicable
2484 if ( $tagslib->{$tag}->{$subfield}->{kohafield} eq
2485 'items.itemcallnumber'
2486 && C4::Context->preference('itemcallnumber') )
2489 substr( C4::Context->preference('itemcallnumber'), 0, 3 );
2491 substr( C4::Context->preference('itemcallnumber'), 3, 1 );
2492 my $temp = $itemrecord->field($CNtag) if ($itemrecord);
2494 $value = $temp->subfield($CNsubfield);
2497 if ( $tagslib->{$tag}->{$subfield}->{authorised_value} ) {
2498 my @authorised_values;
2501 # builds list, depending on authorised value...
2503 if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq
2506 if ( ( C4::Context->preference("IndependantBranches") )
2507 && ( C4::Context->userenv->{flags} != 1 ) )
2511 "select branchcode,branchname from branches where branchcode = ? order by branchname"
2513 $sth->execute( C4::Context->userenv->{branch} );
2514 push @authorised_values, ""
2516 $tagslib->{$tag}->{$subfield}->{mandatory} );
2517 while ( my ( $branchcode, $branchname ) =
2518 $sth->fetchrow_array )
2520 push @authorised_values, $branchcode;
2521 $authorised_lib{$branchcode} = $branchname;
2527 "select branchcode,branchname from branches order by branchname"
2530 push @authorised_values, ""
2532 $tagslib->{$tag}->{$subfield}->{mandatory} );
2533 while ( my ( $branchcode, $branchname ) =
2534 $sth->fetchrow_array )
2536 push @authorised_values, $branchcode;
2537 $authorised_lib{$branchcode} = $branchname;
2543 elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq
2548 "select itemtype,description from itemtypes order by description"
2551 push @authorised_values, ""
2552 unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
2553 while ( my ( $itemtype, $description ) =
2554 $sth->fetchrow_array )
2556 push @authorised_values, $itemtype;
2557 $authorised_lib{$itemtype} = $description;
2560 #---- "true" authorised value
2563 $authorised_values_sth->execute(
2564 $tagslib->{$tag}->{$subfield}->{authorised_value} );
2565 push @authorised_values, ""
2566 unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
2567 while ( my ( $value, $lib ) =
2568 $authorised_values_sth->fetchrow_array )
2570 push @authorised_values, $value;
2571 $authorised_lib{$value} = $lib;
2574 $subfield_data{marc_value} = CGI::scrolling_list(
2575 -name => 'field_value',
2576 -values => \@authorised_values,
2577 -default => "$value",
2578 -labels => \%authorised_lib,
2584 elsif ( $tagslib->{$tag}->{$subfield}->{thesaurus_category} ) {
2585 $subfield_data{marc_value} =
2586 "<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>";
2589 # COMMENTED OUT because No $i is provided with this API.
2590 # And thus, no value_builder can be activated.
2591 # BUT could be thought over.
2592 # } elsif ($tagslib->{$tag}->{$subfield}->{'value_builder'}) {
2593 # my $plugin="value_builder/".$tagslib->{$tag}->{$subfield}->{'value_builder'};
2595 # my $extended_param = plugin_parameters($dbh,$itemrecord,$tagslib,$i,0);
2596 # my ($function_name,$javascript) = plugin_javascript($dbh,$record,$tagslib,$i,0);
2597 # $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";
2600 $subfield_data{marc_value} =
2601 "<input type=\"text\" name=\"field_value\" value=\"$value\" size=50 maxlength=255>";
2603 push( @loop_data, \%subfield_data );
2607 my $itemnumber = $itemrecord->subfield( $itemtagfield, $itemtagsubfield )
2608 if ( $itemrecord && $itemrecord->field($itemtagfield) );
2610 'itemtagfield' => $itemtagfield,
2611 'itemtagsubfield' => $itemtagsubfield,
2612 'itemnumber' => $itemnumber,
2613 'iteminformation' => \@loop_data
2619 # true ModZebra commented until indexdata fixes zebraDB crashes (it seems they occur on multiple updates
2621 # replaced by a zebraqueue table, that is filled with ModZebra to run.
2622 # the table is emptied by misc/cronjobs/zebraqueue_start.pl script
2623 # =head2 ModZebrafiles
2625 # &ModZebrafiles( $dbh, $biblionumber, $record, $folder, $server );
2629 # sub ModZebrafiles {
2631 # my ( $dbh, $biblionumber, $record, $folder, $server ) = @_;
2635 # C4::Context->zebraconfig($server)->{directory} . "/" . $folder . "/";
2636 # unless ( opendir( DIR, "$zebradir" ) ) {
2637 # warn "$zebradir not found";
2641 # my $filename = $zebradir . $biblionumber;
2644 # open( OUTPUT, ">", $filename . ".xml" );
2645 # print OUTPUT $record;
2654 ModZebra( $dbh, $biblionumber, $op, $server );
2661 ###Accepts a $server variable thus we can use it for biblios authorities or other zebra dbs
2662 my ( $biblionumber, $op, $server ) = @_;
2663 my $dbh=C4::Context->dbh;
2664 #warn "SERVER:".$server;
2666 # true ModZebra commented until indexdata fixes zebraDB crashes (it seems they occur on multiple updates
2668 # replaced by a zebraqueue table, that is filled with ModZebra to run.
2669 # the table is emptied by misc/cronjobs/zebraqueue_start.pl script
2671 my $sth=$dbh->prepare("insert into zebraqueue (biblio_auth_number ,server,operation) values(?,?,?)");
2672 $sth->execute($biblionumber,$server,$op);
2679 # my $reconnect = 0;
2684 # $Zconnbiblio[0] = C4::Context->Zconn( $server, 0, 1 );
2686 # if ( $server eq "biblioserver" ) {
2688 # # it's unclear to me whether this should be in xml or MARC format
2689 # # but it is clear it should be nabbed from zebra rather than from
2691 # $record = GetMarcBiblio($biblionumber);
2692 # $record = $record->as_xml_record() if $record;
2693 # # warn "RECORD $biblionumber => ".$record;
2694 # $shadow="biblioservershadow";
2696 # # warn "RECORD $biblionumber => ".$record;
2697 # $shadow = "biblioservershadow";
2700 # elsif ( $server eq "authorityserver" ) {
2701 # $record = C4::AuthoritiesMarc::XMLgetauthority( $dbh, $biblionumber );
2702 # $shadow = "authorityservershadow";
2703 # } ## Add other servers as necessary
2705 # my $Zpackage = $Zconnbiblio[0]->package();
2706 # $Zpackage->option( action => $op );
2707 # $Zpackage->option( record => $record );
2710 # $Zpackage->send("update");
2714 # while ( ( $i = ZOOM::event( \@Zconnbiblio ) ) != 0 ) {
2715 # $event = $Zconnbiblio[0]->last_event();
2716 # last if $event == ZOOM::Event::ZEND;
2719 # my ( $error, $errmsg, $addinfo, $diagset ) = $Zconnbiblio[0]->error_x();
2720 # if ( $error == 10000 && $reconnect == 0 )
2721 # { ## This is serious ZEBRA server is not available -reconnect
2722 # warn "problem with zebra server connection";
2724 # my $res = system('sc start "Z39.50 Server" >c:/zebraserver/error.log');
2726 # #warn "Trying to restart ZEBRA Server";
2727 # #goto "reconnect";
2729 # elsif ( $error == 10007 && $tried < 2 )
2730 # { ## timeout --another 30 looonng seconds for this update
2731 # $tried = $tried + 1;
2732 # warn "warn: timeout, trying again";
2735 # elsif ( $error == 10004 && $recon == 0 ) { ##Lost connection -reconnect
2737 # warn "error: reconnecting to zebra";
2740 # # as a last resort, we save the data to the filesystem to be indexed in batch
2744 # "Error-$server $op $biblionumber /errcode:, $error, /MSG:,$errmsg,$addinfo \n";
2745 # $Zpackage->destroy();
2746 # $Zconnbiblio[0]->destroy();
2747 # ModZebrafiles( $dbh, $biblionumber, $record, $op, $server );
2750 # if ( C4::Context->$shadow ) {
2751 # $Zpackage->send('commit');
2752 # while ( ( $i = ZOOM::event( \@Zconnbiblio ) ) != 0 ) {
2754 # #waiting zebra to finish;
2757 # $Zpackage->destroy();
2760 =head1 INTERNAL FUNCTIONS
2762 =head2 MARCitemchange
2766 &MARCitemchange( $record, $itemfield, $newvalue )
2768 Function to update a single value in an item field.
2769 Used twice, could probably be replaced by something else, but works well...
2777 sub MARCitemchange {
2778 my ( $record, $itemfield, $newvalue ) = @_;
2779 my $dbh = C4::Context->dbh;
2781 my ( $tagfield, $tagsubfield ) =
2782 GetMarcFromKohaField( $dbh, $itemfield, "" );
2783 if ( ($tagfield) && ($tagsubfield) ) {
2784 my $tag = $record->field($tagfield);
2786 $tag->update( $tagsubfield => $newvalue );
2787 $record->delete_field($tag);
2788 $record->insert_fields_ordered($tag);
2793 =head2 _koha_add_biblio
2797 _koha_add_biblio($dbh,$biblioitem);
2799 Internal function to add a biblio ($biblio is a hash with the values)
2805 sub _koha_add_biblio {
2806 my ( $dbh, $biblio, $frameworkcode ) = @_;
2807 my $sth = $dbh->prepare("Select max(biblionumber) from biblio");
2809 my $data = $sth->fetchrow_arrayref;
2810 my $biblionumber = $$data[0] + 1;
2813 if ( $biblio->{'seriestitle'} ) { $series = 1 }
2815 $sth = $dbh->prepare(
2817 SET biblionumber = ?, title = ?, author = ?, copyrightdate = ?, serial = ?, seriestitle = ?, notes = ?, abstract = ?, unititle = ?, frameworkcode = ? "
2820 $biblionumber, $biblio->{'title'},
2821 $biblio->{'author'}, $biblio->{'copyrightdate'},
2822 $biblio->{'serial'}, $biblio->{'seriestitle'},
2823 $biblio->{'notes'}, $biblio->{'abstract'},
2824 $biblio->{'unititle'}, $frameworkcode
2828 return ($biblionumber);
2835 ($indicators, $value) = _find_value($tag, $subfield, $record,$encoding);
2837 Find the given $subfield in the given $tag in the given
2838 MARC::Record $record. If the subfield is found, returns
2839 the (indicators, value) pair; otherwise, (undef, undef) is
2843 Such a function is used in addbiblio AND additem and serial-edit and maybe could be used in Authorities.
2844 I suggest we export it from this module.
2851 my ( $tagfield, $insubfield, $record, $encoding ) = @_;
2854 if ( $tagfield < 10 ) {
2855 if ( $record->field($tagfield) ) {
2856 push @result, $record->field($tagfield)->data();
2863 foreach my $field ( $record->field($tagfield) ) {
2864 my @subfields = $field->subfields();
2865 foreach my $subfield (@subfields) {
2866 if ( @$subfield[0] eq $insubfield ) {
2867 push @result, @$subfield[1];
2868 $indicator = $field->indicator(1) . $field->indicator(2);
2873 return ( $indicator, @result );
2876 =head2 _koha_modify_biblio
2880 Internal function for updating the biblio table
2886 sub _koha_modify_biblio {
2887 my ( $dbh, $biblio ) = @_;
2889 # FIXME: this code could be made more portable by not hard-coding the values that are supposed to be in biblio table
2892 "Update biblio set title = ?, author = ?, abstract = ?, copyrightdate = ?, seriestitle = ?, serial = ?, unititle = ?, notes = ? where biblionumber = ?"
2895 $biblio->{'title'}, $biblio->{'author'},
2896 $biblio->{'abstract'}, $biblio->{'copyrightdate'},
2897 $biblio->{'seriestitle'}, $biblio->{'serial'},
2898 $biblio->{'unititle'}, $biblio->{'notes'},
2899 $biblio->{'biblionumber'}
2902 return ( $biblio->{'biblionumber'} );
2905 =head2 _koha_modify_biblioitem
2909 _koha_modify_biblioitem( $dbh, $biblioitem );
2915 sub _koha_modify_biblioitem {
2916 my ( $dbh, $biblioitem ) = @_;
2918 ##Recalculate LC in case it changed --TG
2920 $biblioitem->{'itemtype'} = $dbh->quote( $biblioitem->{'itemtype'} );
2921 $biblioitem->{'url'} = $dbh->quote( $biblioitem->{'url'} );
2922 $biblioitem->{'isbn'} = $dbh->quote( $biblioitem->{'isbn'} );
2923 $biblioitem->{'issn'} = $dbh->quote( $biblioitem->{'issn'} );
2924 $biblioitem->{'publishercode'} =
2925 $dbh->quote( $biblioitem->{'publishercode'} );
2926 $biblioitem->{'publicationyear'} =
2927 $dbh->quote( $biblioitem->{'publicationyear'} );
2928 $biblioitem->{'classification'} =
2929 $dbh->quote( $biblioitem->{'classification'} );
2930 $biblioitem->{'dewey'} = $dbh->quote( $biblioitem->{'dewey'} );
2931 $biblioitem->{'subclass'} = $dbh->quote( $biblioitem->{'subclass'} );
2932 $biblioitem->{'illus'} = $dbh->quote( $biblioitem->{'illus'} );
2933 $biblioitem->{'pages'} = $dbh->quote( $biblioitem->{'pages'} );
2934 $biblioitem->{'volumeddesc'} = $dbh->quote( $biblioitem->{'volumeddesc'} );
2935 $biblioitem->{'bnotes'} = $dbh->quote( $biblioitem->{'bnotes'} );
2936 $biblioitem->{'size'} = $dbh->quote( $biblioitem->{'size'} );
2937 $biblioitem->{'place'} = $dbh->quote( $biblioitem->{'place'} );
2938 $biblioitem->{'ccode'} = $dbh->quote( $biblioitem->{'ccode'} );
2939 $biblioitem->{'biblionumber'} =
2940 $dbh->quote( $biblioitem->{'biblionumber'} );
2942 $query = "Update biblioitems set
2943 itemtype = $biblioitem->{'itemtype'},
2944 url = $biblioitem->{'url'},
2945 isbn = $biblioitem->{'isbn'},
2946 issn = $biblioitem->{'issn'},
2947 publishercode = $biblioitem->{'publishercode'},
2948 publicationyear = $biblioitem->{'publicationyear'},
2949 classification = $biblioitem->{'classification'},
2950 dewey = $biblioitem->{'dewey'},
2951 subclass = $biblioitem->{'subclass'},
2952 illus = $biblioitem->{'illus'},
2953 pages = $biblioitem->{'pages'},
2954 volumeddesc = $biblioitem->{'volumeddesc'},
2955 notes = $biblioitem->{'bnotes'},
2956 size = $biblioitem->{'size'},
2957 place = $biblioitem->{'place'},
2958 ccode = $biblioitem->{'ccode'}
2959 where biblionumber = $biblioitem->{'biblionumber'}";
2962 if ( $dbh->errstr ) {
2967 =head2 _koha_add_biblioitem
2971 _koha_add_biblioitem( $dbh, $biblioitem );
2973 Internal function to add a biblioitem
2979 sub _koha_add_biblioitem {
2980 my ( $dbh, $biblioitem ) = @_;
2982 # my $dbh = C4Connect;
2983 my $sth = $dbh->prepare("SELECT max(biblioitemnumber) FROM biblioitems");
2988 $data = $sth->fetchrow_arrayref;
2989 $bibitemnum = $$data[0] + 1;
2993 $sth = $dbh->prepare(
2994 "INSERT INTO biblioitems SET
2995 biblioitemnumber = ?, biblionumber = ?,
2996 volume = ?, number = ?,
2997 classification = ?, itemtype = ?,
2999 issn = ?, dewey = ?,
3000 subclass = ?, publicationyear = ?,
3001 publishercode = ?, volumedate = ?,
3002 volumeddesc = ?, illus = ?,
3003 pages = ?, notes = ?,
3005 marc = ?, lcsort =?,
3006 place = ?, ccode = ?
3010 calculatelc( $biblioitem->{'classification'} )
3011 . $biblioitem->{'subclass'};
3013 $bibitemnum, $biblioitem->{'biblionumber'},
3014 $biblioitem->{'volume'}, $biblioitem->{'number'},
3015 $biblioitem->{'classification'}, $biblioitem->{'itemtype'},
3016 $biblioitem->{'url'}, $biblioitem->{'isbn'},
3017 $biblioitem->{'issn'}, $biblioitem->{'dewey'},
3018 $biblioitem->{'subclass'}, $biblioitem->{'publicationyear'},
3019 $biblioitem->{'publishercode'}, $biblioitem->{'volumedate'},
3020 $biblioitem->{'volumeddesc'}, $biblioitem->{'illus'},
3021 $biblioitem->{'pages'}, $biblioitem->{'bnotes'},
3022 $biblioitem->{'size'}, $biblioitem->{'lccn'},
3023 $biblioitem->{'marc'}, $biblioitem->{'place'},
3024 $lcsort, $biblioitem->{'ccode'}
3027 return ($bibitemnum);
3030 =head2 _koha_new_items
3034 _koha_new_items( $dbh, $item, $barcode );
3040 sub _koha_new_items {
3041 my ( $dbh, $item, $barcode ) = @_;
3043 # my $dbh = C4Connect;
3044 my $sth = $dbh->prepare("Select max(itemnumber) from items");
3050 $data = $sth->fetchrow_hashref;
3051 $itemnumber = $data->{'max(itemnumber)'} + 1;
3053 ## Now calculate lccalnumber
3054 my ($cutterextra) = itemcalculator(
3056 $item->{'biblioitemnumber'},
3057 $item->{'itemcallnumber'}
3060 # FIXME the "notforloan" field seems to be named "loan" in some places. workaround bugfix.
3061 if ( $item->{'loan'} ) {
3062 $item->{'notforloan'} = $item->{'loan'};
3065 # if dateaccessioned is provided, use it. Otherwise, set to NOW()
3066 if ( $item->{'dateaccessioned'} eq '' || !$item->{'dateaccessioned'} ) {
3068 $sth = $dbh->prepare(
3069 "Insert into items set
3070 itemnumber = ?, biblionumber = ?,
3071 multivolumepart = ?,
3072 biblioitemnumber = ?, barcode = ?,
3073 booksellerid = ?, dateaccessioned = NOW(),
3074 homebranch = ?, holdingbranch = ?,
3075 price = ?, replacementprice = ?,
3076 replacementpricedate = NOW(), datelastseen = NOW(),
3077 multivolume = ?, stack = ?,
3078 itemlost = ?, wthdrawn = ?,
3079 paidfor = ?, itemnotes = ?,
3080 itemcallnumber =?, notforloan = ?,
3081 location = ?, Cutterextra = ?
3085 $itemnumber, $item->{'biblionumber'},
3086 $item->{'multivolumepart'}, $item->{'biblioitemnumber'},
3087 $barcode, $item->{'booksellerid'},
3088 $item->{'homebranch'}, $item->{'holdingbranch'},
3089 $item->{'price'}, $item->{'replacementprice'},
3090 $item->{multivolume}, $item->{stack},
3091 $item->{itemlost}, $item->{wthdrawn},
3092 $item->{paidfor}, $item->{'itemnotes'},
3093 $item->{'itemcallnumber'}, $item->{'notforloan'},
3094 $item->{'location'}, $cutterextra
3098 $sth = $dbh->prepare(
3099 "INSERT INTO items SET
3100 itemnumber = ?, biblionumber = ?,
3101 multivolumepart = ?,
3102 biblioitemnumber = ?, barcode = ?,
3103 booksellerid = ?, dateaccessioned = ?,
3104 homebranch = ?, holdingbranch = ?,
3105 price = ?, replacementprice = ?,
3106 replacementpricedate = NOW(), datelastseen = NOW(),
3107 multivolume = ?, stack = ?,
3108 itemlost = ?, wthdrawn = ?,
3109 paidfor = ?, itemnotes = ?,
3110 itemcallnumber = ?, notforloan = ?,
3116 $itemnumber, $item->{'biblionumber'},
3117 $item->{'multivolumepart'}, $item->{'biblioitemnumber'},
3118 $barcode, $item->{'booksellerid'},
3119 $item->{'dateaccessioned'}, $item->{'homebranch'},
3120 $item->{'holdingbranch'}, $item->{'price'},
3121 $item->{'replacementprice'}, $item->{multivolume},
3122 $item->{stack}, $item->{itemlost},
3123 $item->{wthdrawn}, $item->{paidfor},
3124 $item->{'itemnotes'}, $item->{'itemcallnumber'},
3125 $item->{'notforloan'}, $item->{'location'},
3129 if ( defined $sth->errstr ) {
3130 $error .= $sth->errstr;
3132 return ( $itemnumber, $error );
3135 =head2 _koha_modify_item
3139 _koha_modify_item( $dbh, $item, $op );
3145 sub _koha_modify_item {
3146 my ( $dbh, $item, $op ) = @_;
3147 $item->{'itemnum'} = $item->{'itemnumber'} unless $item->{'itemnum'};
3149 # if all we're doing is setting statuses, just update those and get out
3150 if ( $op eq "setstatus" ) {
3152 "UPDATE items SET itemlost=?,wthdrawn=?,binding=? WHERE itemnumber=?";
3154 $item->{'itemlost'}, $item->{'wthdrawn'},
3155 $item->{'binding'}, $item->{'itemnumber'}
3157 my $sth = $dbh->prepare($query);
3158 $sth->execute(@bind);
3162 ## Now calculate lccalnumber
3164 itemcalculator( $dbh, $item->{'bibitemnum'}, $item->{'itemcallnumber'} );
3166 my $query = "UPDATE items SET
3167 barcode=?,itemnotes=?,itemcallnumber=?,notforloan=?,location=?,multivolumepart=?,multivolume=?,stack=?,wthdrawn=?,holdingbranch=?,homebranch=?,cutterextra=?, onloan=?, binding=?";
3170 $item->{'barcode'}, $item->{'notes'},
3171 $item->{'itemcallnumber'}, $item->{'notforloan'},
3172 $item->{'location'}, $item->{multivolumepart},
3173 $item->{multivolume}, $item->{stack},
3174 $item->{wthdrawn}, $item->{holdingbranch},
3175 $item->{homebranch}, $cutterextra,
3176 $item->{onloan}, $item->{binding}
3178 if ( $item->{'lost'} ne '' ) {
3180 "update items set biblioitemnumber=?,barcode=?,itemnotes=?,homebranch=?,
3181 itemlost=?,wthdrawn=?,itemcallnumber=?,notforloan=?,
3182 location=?,multivolumepart=?,multivolume=?,stack=?,wthdrawn=?,holdingbranch=?,cutterextra=?,onloan=?, binding=?";
3184 $item->{'bibitemnum'}, $item->{'barcode'},
3185 $item->{'notes'}, $item->{'homebranch'},
3186 $item->{'lost'}, $item->{'wthdrawn'},
3187 $item->{'itemcallnumber'}, $item->{'notforloan'},
3188 $item->{'location'}, $item->{multivolumepart},
3189 $item->{multivolume}, $item->{stack},
3190 $item->{wthdrawn}, $item->{holdingbranch},
3191 $cutterextra, $item->{onloan},
3194 if ( $item->{homebranch} ) {
3195 $query .= ",homebranch=?";
3196 push @bind, $item->{homebranch};
3198 if ( $item->{holdingbranch} ) {
3199 $query .= ",holdingbranch=?";
3200 push @bind, $item->{holdingbranch};
3203 $query .= " where itemnumber=?";
3204 push @bind, $item->{'itemnum'};
3205 if ( $item->{'replacement'} ne '' ) {
3206 $query =~ s/ where/,replacementprice='$item->{'replacement'}' where/;
3208 my $sth = $dbh->prepare($query);
3209 $sth->execute(@bind);
3213 =head2 _koha_delete_biblio
3217 $error = _koha_delete_biblio($dbh,$biblionumber);
3219 Internal sub for deleting from biblio table -- also saves to deletedbiblio
3221 C<$dbh> - the database handle
3222 C<$biblionumber> - the biblionumber of the biblio to be deleted
3228 # FIXME: add error handling
3230 sub _koha_delete_biblio {
3231 my ( $dbh, $biblionumber ) = @_;
3233 # get all the data for this biblio
3234 my $sth = $dbh->prepare("SELECT * FROM biblio WHERE biblionumber=?");
3235 $sth->execute($biblionumber);
3237 if ( my $data = $sth->fetchrow_hashref ) {
3239 # save the record in deletedbiblio
3240 # find the fields to save
3241 my $query = "INSERT INTO deletedbiblio SET ";
3243 foreach my $temp ( keys %$data ) {
3244 $query .= "$temp = ?,";
3245 push( @bind, $data->{$temp} );
3248 # replace the last , by ",?)"
3250 my $bkup_sth = $dbh->prepare($query);
3251 $bkup_sth->execute(@bind);
3255 my $del_sth = $dbh->prepare("DELETE FROM biblio WHERE biblionumber=?");
3256 $del_sth->execute($biblionumber);
3263 =head2 _koha_delete_biblioitems
3267 $error = _koha_delete_biblioitems($dbh,$biblioitemnumber);
3269 Internal sub for deleting from biblioitems table -- also saves to deletedbiblioitems
3271 C<$dbh> - the database handle
3272 C<$biblionumber> - the biblioitemnumber of the biblioitem to be deleted
3278 # FIXME: add error handling
3280 sub _koha_delete_biblioitems {
3281 my ( $dbh, $biblioitemnumber ) = @_;
3283 # get all the data for this biblioitem
3285 $dbh->prepare("SELECT * FROM biblioitems WHERE biblioitemnumber=?");
3286 $sth->execute($biblioitemnumber);
3288 if ( my $data = $sth->fetchrow_hashref ) {
3290 # save the record in deletedbiblioitems
3291 # find the fields to save
3292 my $query = "INSERT INTO deletedbiblioitems SET ";
3294 foreach my $temp ( keys %$data ) {
3295 $query .= "$temp = ?,";
3296 push( @bind, $data->{$temp} );
3299 # replace the last , by ",?)"
3301 my $bkup_sth = $dbh->prepare($query);
3302 $bkup_sth->execute(@bind);
3305 # delete the biblioitem
3307 $dbh->prepare("DELETE FROM biblioitems WHERE biblioitemnumber=?");
3308 $del_sth->execute($biblioitemnumber);
3315 =head2 _koha_delete_item
3319 _koha_delete_item( $dbh, $itemnum );
3321 Internal function to delete an item record from the koha tables
3327 sub _koha_delete_item {
3328 my ( $dbh, $itemnum ) = @_;
3330 my $sth = $dbh->prepare("select * from items where itemnumber=?");
3331 $sth->execute($itemnum);
3332 my $data = $sth->fetchrow_hashref;
3334 my $query = "Insert into deleteditems set ";
3336 foreach my $temp ( keys %$data ) {
3337 $query .= "$temp = ?,";
3338 push( @bind, $data->{$temp} );
3343 $sth = $dbh->prepare($query);
3344 $sth->execute(@bind);
3346 $sth = $dbh->prepare("Delete from items where itemnumber=?");
3347 $sth->execute($itemnum);
3351 =head1 UNEXPORTED FUNCTIONS
3357 $lc = calculatelc($classification);
3364 my ($classification) = @_;
3365 $classification =~ s/^\s+|\s+$//g;
3370 for ( $i = 0 ; $i < length($classification) ; $i++ ) {
3371 my $c = ( substr( $classification, $i, 1 ) );
3372 if ( $c ge '0' && $c le '9' ) {
3374 $lc2 = substr( $classification, $i );
3378 $lc1 .= substr( $classification, $i, 1 );
3383 my $other = length($lc1);
3390 for ( 1 .. ( 4 - $other ) ) {
3399 ##Find the decimal part of $lc2
3400 my $pos = index( $lc2, "." );
3401 if ( $pos < 0 ) { $pos = length($lc2); }
3402 if ( $pos >= 0 && $pos < 5 ) {
3403 ##Pad lc2 with zeros to create a 5digit decimal needed in marc record to sort as numeric
3405 for ( 1 .. ( 5 - $pos ) ) {
3409 $lc2 = $extras . $lc2;
3410 return ( $lc1 . $lc2 );
3413 =head2 itemcalculator
3417 $cutterextra = itemcalculator( $dbh, $biblioitem, $callnumber );
3423 sub itemcalculator {
3424 my ( $dbh, $biblioitem, $callnumber ) = @_;
3427 "select classification, subclass from biblioitems where biblioitemnumber=?"
3430 $sth->execute($biblioitem);
3431 my ( $classification, $subclass ) = $sth->fetchrow;
3432 my $all = $classification . " " . $subclass;
3433 my $total = length($all);
3434 my $cutterextra = substr( $callnumber, $total - 1 );
3436 return $cutterextra;
3439 =head2 ModBiblioMarc
3443 &ModBiblioMarc($newrec,$biblionumber,$frameworkcode);
3445 Add MARC data for a biblio to koha
3447 Function exported, but should NOT be used, unless you really know what you're doing
3455 # pass the MARC::Record to this function, and it will create the records in the marc tables
3456 my ( $record, $biblionumber, $frameworkcode ) = @_;
3457 my $dbh = C4::Context->dbh;
3458 my @fields = $record->fields();
3459 if ( !$frameworkcode ) {
3460 $frameworkcode = "";
3463 $dbh->prepare("UPDATE biblio SET frameworkcode=? WHERE biblionumber=?");
3464 $sth->execute( $frameworkcode, $biblionumber );
3466 my $encoding = C4::Context->preference("marcflavour");
3468 # deal with UNIMARC field 100 (encoding) : create it if needed & set encoding to unicode
3469 if ( $encoding eq "UNIMARC" ) {
3471 if ( $record->subfield( 100, "a" ) ) {
3472 $string = $record->subfield( 100, "a" );
3473 my $f100 = $record->field(100);
3474 $record->delete_field($f100);
3477 $string = POSIX::strftime( "%Y%m%d", localtime );
3479 $string = sprintf( "%-*s", 35, $string );
3481 substr( $string, 22, 6, "frey50" );
3482 unless ( $record->subfield( 100, "a" ) ) {
3483 $record->insert_grouped_field(
3484 MARC::Field->new( 100, "", "", "a" => $string ) );
3487 # warn "biblionumber : ".$biblionumber;
3490 "update biblioitems set marc=?,marcxml=? where biblionumber=?");
3491 $sth->execute( $record->as_usmarc(), $record->as_xml_record(),
3493 # warn $record->as_xml_record();
3495 ModZebra($biblionumber,"specialUpdate","biblioserver");
3496 return $biblionumber;
3499 =head2 AddItemInMarc
3503 $newbiblionumber = AddItemInMarc( $record, $biblionumber, $frameworkcode );
3505 Add an item in a MARC record and save the MARC record
3507 Function exported, but should NOT be used, unless you really know what you're doing
3515 # pass the MARC::Record to this function, and it will create the records in the marc tables
3516 my ( $record, $biblionumber, $frameworkcode ) = @_;
3517 my $newrec = &GetMarcBiblio($biblionumber);
3520 my @fields = $record->fields();
3521 foreach my $field (@fields) {
3522 $newrec->append_fields($field);
3525 # FIXME: should we be making sure the biblionumbers are the same?
3526 my $newbiblionumber =
3527 &ModBiblioMarc( $newrec, $biblionumber, $frameworkcode );
3528 return $newbiblionumber;
3531 =head2 z3950_extended_services
3533 z3950_extended_services($serviceType,$serviceOptions,$record);
3535 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.
3537 C<$serviceType> one of: itemorder,create,drop,commit,update,xmlupdate
3539 C<$serviceOptions> a has of key/value pairs. For instance, if service_type is 'update', $service_options should contain:
3541 action => update action, one of specialUpdate, recordInsert, recordReplace, recordDelete, elementUpdate.
3545 recordidOpaque => Opaque Record ID (user supplied) or recordidNumber => Record ID number (system number).
3546 syntax => the record syntax (transfer syntax)
3547 databaseName = Database from connection object
3549 To set serviceOptions, call set_service_options($serviceType)
3551 C<$record> the record, if one is needed for the service type
3553 A record should be in XML. You can convert it to XML from MARC by running it through marc2xml().
3557 sub z3950_extended_services {
3558 my ( $server, $serviceType, $action, $serviceOptions ) = @_;
3560 # get our connection object
3561 my $Zconn = C4::Context->Zconn( $server, 0, 1 );
3563 # create a new package object
3564 my $Zpackage = $Zconn->package();
3567 $Zpackage->option( action => $action );
3569 if ( $serviceOptions->{'databaseName'} ) {
3570 $Zpackage->option( databaseName => $serviceOptions->{'databaseName'} );
3572 if ( $serviceOptions->{'recordIdNumber'} ) {
3574 recordIdNumber => $serviceOptions->{'recordIdNumber'} );
3576 if ( $serviceOptions->{'recordIdOpaque'} ) {
3578 recordIdOpaque => $serviceOptions->{'recordIdOpaque'} );
3581 # this is an ILL request (Zebra doesn't support it, but Koha could eventually)
3582 #if ($serviceType eq 'itemorder') {
3583 # $Zpackage->option('contact-name' => $serviceOptions->{'contact-name'});
3584 # $Zpackage->option('contact-phone' => $serviceOptions->{'contact-phone'});
3585 # $Zpackage->option('contact-email' => $serviceOptions->{'contact-email'});
3586 # $Zpackage->option('itemorder-item' => $serviceOptions->{'itemorder-item'});
3589 if ( $serviceOptions->{record} ) {
3590 $Zpackage->option( record => $serviceOptions->{record} );
3592 # can be xml or marc
3593 if ( $serviceOptions->{'syntax'} ) {
3594 $Zpackage->option( syntax => $serviceOptions->{'syntax'} );
3598 # send the request, handle any exception encountered
3599 eval { $Zpackage->send($serviceType) };
3600 if ( $@ && $@->isa("ZOOM::Exception") ) {
3601 return "error: " . $@->code() . " " . $@->message() . "\n";
3604 # free up package resources
3605 $Zpackage->destroy();
3608 =head2 set_service_options
3610 my $serviceOptions = set_service_options($serviceType);
3612 C<$serviceType> itemorder,create,drop,commit,update,xmlupdate
3614 Currently, we only support 'create', 'commit', and 'update'. 'drop' support will be added as soon as Zebra supports it.
3618 sub set_service_options {
3619 my ($serviceType) = @_;
3622 # FIXME: This needs to be an OID ... if we ever need 'syntax' this sub will need to change
3623 # $serviceOptions->{ 'syntax' } = ''; #zebra doesn't support syntaxes other than xml
3625 if ( $serviceType eq 'commit' ) {
3629 if ( $serviceType eq 'create' ) {
3633 if ( $serviceType eq 'drop' ) {
3634 die "ERROR: 'drop' not currently supported (by Zebra)";
3636 return $serviceOptions;
3639 END { } # module clean-up code here (global destructor)
3647 Koha Developement team <info@koha.org>
3649 Paul POULAIN paul.poulain@free.fr
3651 Joshua Ferraro jmf@liblime.com
3657 # Revision 1.195 2007/04/04 16:46:22 tipaul
3658 # HUGE COMMIT : code cleaning circulation.
3660 # some stuff to do, i'll write a mail on koha-devel NOW !
3662 # Revision 1.194 2007/03/30 12:00:42 tipaul
3663 # 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...
3665 # Revision 1.193 2007/03/29 16:45:53 tipaul
3666 # Code cleaning of Biblio.pm (continued)
3668 # All subs have be cleaned :
3671 # - reordering Biblio.pm completly
3672 # - using only naming conventions
3674 # Seems to have broken nothing, but it still has to be heavily tested.
3675 # Note that Biblio.pm is now much more efficient than previously & probably more reliable as well.
3677 # Revision 1.192 2007/03/29 13:30:31 tipaul
3679 # == Biblio.pm cleaning (useless) ==
3680 # * some sub declaration dropped
3681 # * removed modbiblio sub
3682 # * removed moditem sub
3683 # * removed newitems. It was used only in finishrecieve. Replaced by a TransformKohaToMarc+AddItem, that is better.
3684 # * removed MARCkoha2marcItem
3685 # * removed MARCdelsubfield declaration
3686 # * removed MARCkoha2marcBiblio
3688 # == Biblio.pm cleaning (naming conventions) ==
3689 # * MARCgettagslib renamed to GetMarcStructure
3690 # * MARCgetitems renamed to GetMarcItem
3691 # * MARCfind_frameworkcode renamed to GetFrameworkCode
3692 # * MARCmarc2koha renamed to TransformMarcToKoha
3693 # * MARChtml2marc renamed to TransformHtmlToMarc
3694 # * MARChtml2xml renamed to TranformeHtmlToXml
3695 # * zebraop renamed to ModZebra
3698 # * removing MARC=OFF related scripts (in cataloguing directory)
3699 # * removed checkitems (function related to MARC=off feature, that is completly broken in head. If someone want to reintroduce it, hard work coming...)
3700 # * removed getitemsbybiblioitem (used only by MARC=OFF scripts, that is removed as well)
3702 # Revision 1.191 2007/03/29 09:42:13 tipaul
3703 # adding default value new feature into cataloguing. The system (definition) part has already been added by toins
3705 # Revision 1.190 2007/03/29 08:45:19 hdl
3706 # Deleting ignore_errors(1) pour MARC::Charset
3708 # Revision 1.189 2007/03/28 10:39:16 hdl
3709 # removing $dbh as a parameter in AuthoritiesMarc functions
3710 # And reporting all differences into the scripts taht relies on those functions.