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
91 # Marc related functions
105 &PrepareItemrecordDisplay
113 C4::Biblio - acquisitions and cataloging management functions
117 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:
121 =item 1. in the biblio,biblioitems,items, etc tables, which are limited to a one-to-one mapping to underlying MARC data
123 =item 2. as raw MARC in the Zebra index and storage engine
125 =item 3. as raw MARC the biblioitems.marc
129 In the 2.4 version of Koha, the authoritative record-level information is in biblioitems.marc and the authoritative items information is in the items table.
131 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:
135 =item 1. Compared with MySQL, Zebra is slow to update an index for small data changes -- especially for proc-intensive operations like circulation
137 =item 2. Zebra's index has been known to crash and a backup of the data is necessary to rebuild it in such cases
141 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:
145 =item 1. Add*/Mod*/Del*/ - high-level external functions suitable for being called from external scripts to manage the collection
147 =item 2. _koha_* - low-level internal functions for managing the koha tables
149 =item 3. MARC* functions for interacting with the MARC data in both biblioitems.marc Zebra (biblioitems.marc is authoritative)
151 =item 4. Zebra functions used to update the Zebra index
153 =item 5. internal helper functions such as char_decode, checkitems, etc. Some of these probably belong in Koha.pm
155 =item 6. other functions that don't belong in Biblio.pm that will be cleaned out in time. (like GetMarcFromKohaField which belongs in Search.pm)
157 In time, as we solidify the new API these older functions will be weeded out.
161 =head1 EXPORTED FUNCTIONS
165 ($biblionumber,$biblioitemnumber) = AddBiblio($record,$frameworkcode);
167 Exported function (core API) for adding a new biblio to koha.
172 my ( $record, $frameworkcode ) = @_;
175 my $dbh = C4::Context->dbh;
176 # transform the data into koha-table style data
177 my $olddata = TransformMarcToKoha( $dbh, $record, $frameworkcode );
178 $oldbibnum = _koha_add_biblio( $dbh, $olddata, $frameworkcode );
179 $olddata->{'biblionumber'} = $oldbibnum;
180 $oldbibitemnum = _koha_add_biblioitem( $dbh, $olddata );
182 # we must add bibnum and bibitemnum in MARC::Record...
183 # we build the new field with biblionumber and biblioitemnumber
184 # we drop the original field
185 # we add the new builded field.
186 # NOTE : Works only if the field is ONLY for biblionumber and biblioitemnumber
187 # (steve and paul : thinks 090 is a good choice)
190 "SELECT tagfield,tagsubfield
191 FROM marc_subfield_structure
194 $sth->execute("biblio.biblionumber");
195 ( my $tagfield1, my $tagsubfield1 ) = $sth->fetchrow;
196 $sth->execute("biblioitems.biblioitemnumber");
197 ( my $tagfield2, my $tagsubfield2 ) = $sth->fetchrow;
201 # biblionumber & biblioitemnumber are in different fields
202 if ( $tagfield1 != $tagfield2 ) {
204 # deal with biblionumber
205 if ( $tagfield1 < 10 ) {
206 $newfield = MARC::Field->new( $tagfield1, $oldbibnum, );
210 MARC::Field->new( $tagfield1, '', '',
211 "$tagsubfield1" => $oldbibnum, );
214 # drop old field and create new one...
215 my $old_field = $record->field($tagfield1);
216 $record->delete_field($old_field);
217 $record->append_fields($newfield);
219 # deal with biblioitemnumber
220 if ( $tagfield2 < 10 ) {
221 $newfield = MARC::Field->new( $tagfield2, $oldbibitemnum, );
225 MARC::Field->new( $tagfield2, '', '',
226 "$tagsubfield2" => $oldbibitemnum, );
228 # drop old field and create new one...
229 $old_field = $record->field($tagfield2);
230 $record->delete_field($old_field);
231 $record->insert_fields_ordered($newfield);
233 # biblionumber & biblioitemnumber are in the same field (can't be <10 as fields <10 have only 1 value)
236 my $newfield = MARC::Field->new(
238 "$tagsubfield1" => $oldbibnum,
239 "$tagsubfield2" => $oldbibitemnum
242 # drop old field and create new one...
243 my $old_field = $record->field($tagfield1);
244 $record->delete_field($old_field);
245 $record->insert_fields_ordered($newfield);
248 ###NEU specific add cataloguers cardnumber as well
249 my $cardtag = C4::Context->preference('cataloguersfield');
251 my $tag = substr( $cardtag, 0, 3 );
252 my $subf = substr( $cardtag, 3, 1 );
253 my $me = C4::Context->userenv;
254 my $cataloger = $me->{'cardnumber'} if ($me);
255 my $newtag = MARC::Field->new( $tag, '', '', $subf => $cataloger )
257 $record->delete_field($newtag);
258 $record->insert_fields_ordered($newtag);
263 MARCaddbiblio( $record, $oldbibnum, $frameworkcode );
265 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","ADD",$biblionumber,"biblio")
266 if C4::Context->preference("CataloguingLog");
268 return ( $biblionumber, $oldbibitemnum );
273 $biblionumber = AddItem( $record, $biblionumber)
275 Exported function (core API) for adding a new item to Koha
280 my ( $record, $biblionumber ) = @_;
281 my $dbh = C4::Context->dbh;
284 my $frameworkcode = GetFrameworkCode( $biblionumber );
285 my $item = &TransformMarcToKoha( $dbh, $record, $frameworkcode );
287 # needs old biblionumber and biblioitemnumber
288 $item->{'biblionumber'} = $biblionumber;
291 "select biblioitemnumber,itemtype from biblioitems where biblionumber=?"
293 $sth->execute( $item->{'biblionumber'} );
295 ( $item->{'biblioitemnumber'}, $itemtype ) = $sth->fetchrow;
298 "select notforloan from itemtypes where itemtype='$itemtype'");
300 my $notforloan = $sth->fetchrow;
301 ##Change the notforloan field if $notforloan found
302 if ( $notforloan > 0 ) {
303 $item->{'notforloan'} = $notforloan;
304 &MARCitemchange( $record, "items.notforloan", $notforloan );
306 if ( !$item->{'dateaccessioned'} || $item->{'dateaccessioned'} eq '' ) {
309 my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) =
314 "$year-" . sprintf( "%0.2d", $mon ) . "-" . sprintf( "%0.2d", $mday );
315 $item->{'dateaccessioned'} = $date;
316 &MARCitemchange( $record, "items.dateaccessioned", $date );
318 my ( $itemnumber, $error ) =
319 &_koha_new_items( $dbh, $item, $item->{barcode} );
321 # add itemnumber to MARC::Record before adding the item.
324 "select tagfield,tagsubfield from marc_subfield_structure where frameworkcode=? and kohafield=?"
326 &MARCkoha2marcOnefield( $sth, $record, "items.itemnumber", $itemnumber,
329 ##NEU specific add cataloguers cardnumber as well
330 my $cardtag = C4::Context->preference('itemcataloguersubfield');
332 $sth->execute( $frameworkcode, "items.itemnumber" );
333 my ( $itemtag, $subtag ) = $sth->fetchrow;
334 my $me = C4::Context->userenv;
335 my $cataloguer = $me->{'cardnumber'} if ($me);
336 my $newtag = $record->field($itemtag);
337 $newtag->update( $cardtag => $cataloguer ) if ($me);
338 $record->delete_field($newtag);
339 $record->append_fields($newtag);
343 &MARCadditem( $record, $item->{'biblionumber'},$frameworkcode );
345 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","ADD",$itemnumber,"item")
346 if C4::Context->preference("CataloguingLog");
348 return ($item->{biblionumber}, $item->{biblioitemnumber},$itemnumber);
353 ModBiblio( $record,$biblionumber,$frameworkcode);
355 Exported function (core API) to modify a biblio
360 my ( $record, $biblionumber, $frameworkcode ) = @_;
362 if (C4::Context->preference("CataloguingLog")) {
363 my $newrecord = GetMarcBiblio($biblionumber);
364 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","MODIFY",$biblionumber,$newrecord->as_formatted)
367 my $dbh = C4::Context->dbh;
369 $frameworkcode = "" unless $frameworkcode;
371 # update the MARC record with the new record data
372 &MARCmodbiblio( $dbh, $biblionumber, $record, $frameworkcode, 1 );
374 # load the koha-table data object
375 my $oldbiblio = TransformMarcToKoha( $dbh, $record, $frameworkcode );
377 # modify the other koha tables
378 my $oldbiblionumber = _koha_modify_biblio( $dbh, $oldbiblio );
379 _koha_modify_biblioitem( $dbh, $oldbiblio );
386 Exported function (core API) for modifying an item in Koha.
391 my ( $record, $biblionumber, $itemnumber, $delete, $new_item_hashref )
395 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","MODIFY",$itemnumber,$record->as_formatted)
396 if C4::Context->preference("CataloguingLog");
398 my $dbh = C4::Context->dbh;
400 # if we have a MARC record, we're coming from cataloging and so
401 # we do the whole routine: update the MARC and zebra, then update the koha
404 my $frameworkcode = GetFrameworkCode( $biblionumber );
405 MARCmoditem( $record, $biblionumber, $itemnumber, $frameworkcode, $delete );
406 my $olditem = TransformMarcToKoha( $dbh, $record, $frameworkcode );
407 _koha_modify_item( $dbh, $olditem );
408 return $biblionumber;
411 # otherwise, we're just looking to modify something quickly
412 # (like a status) so we just update the koha tables
413 elsif ($new_item_hashref) {
414 _koha_modify_item( $dbh, $new_item_hashref );
418 =head2 ModBiblioframework
420 ModBiblioframework($biblionumber,$frameworkcode);
422 Exported function to modify a biblio framework
426 sub ModBiblioframework {
427 my ( $biblionumber, $frameworkcode ) = @_;
428 my $dbh = C4::Context->dbh;
431 "UPDATE biblio SET frameworkcode=? WHERE biblionumber=$biblionumber");
433 warn "IN ModBiblioframework";
434 $sth->execute($frameworkcode);
440 my $error = &DelBiblio($dbh,$biblionumber);
442 Exported function (core API) for deleting a biblio in koha.
444 Deletes biblio record from Zebra and Koha tables (biblio,biblioitems,items)
446 Also backs it up to deleted* tables
448 Checks to make sure there are not issues on any of the items
451 C<$error> : undef unless an error occurs
456 my ( $biblionumber ) = @_;
457 my $dbh = C4::Context->dbh;
458 my $error; # for error handling
460 # First make sure there are no items with issues are still attached
463 "SELECT biblioitemnumber FROM biblioitems WHERE biblionumber=?");
464 $sth->execute($biblionumber);
465 while ( my $biblioitemnumber = $sth->fetchrow ) {
466 my @issues = C4::Circulation::Circ2::itemissues($biblioitemnumber);
467 foreach my $issue (@issues) {
468 if ( ( $issue->{date_due} )
469 && ( $issue->{date_due} ne "Available" ) )
472 #FIXME: we need a status system in Biblio like in Circ to return standard codes and messages
473 # instead of hard-coded strings
475 "Item is checked out to a patron -- you must return it before deleting the Biblio";
479 return $error if $error;
482 ModZebra($biblionumber,"delete_record","biblioserver");
484 # delete biblio from Koha tables and save in deletedbiblio
485 $error = &_koha_delete_biblio( $dbh, $biblionumber );
487 # delete biblioitems and items from Koha tables and save in deletedbiblioitems,deleteditems
490 "SELECT biblioitemnumber FROM biblioitems WHERE biblionumber=?");
491 $sth->execute($biblionumber);
492 while ( my $biblioitemnumber = $sth->fetchrow ) {
494 # delete this biblioitem
495 $error = &_koha_delete_biblioitems( $dbh, $biblioitemnumber );
496 return $error if $error;
501 "SELECT itemnumber FROM items WHERE biblioitemnumber=?");
502 $items_sth->execute($biblioitemnumber);
503 while ( my $itemnumber = $items_sth->fetchrow ) {
504 $error = &_koha_delete_items( $dbh, $itemnumber );
505 return $error if $error;
508 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","DELETE",$biblionumber,"")
509 if C4::Context->preference("CataloguingLog");
515 DelItem( $biblionumber, $itemnumber );
517 Exported function (core API) for deleting an item record in Koha.
522 my ( $biblionumber, $itemnumber ) = @_;
523 my $dbh = C4::Context->dbh;
524 &_koha_delete_item( $dbh, $itemnumber );
525 my $newrec = &MARCdelitem( $biblionumber, $itemnumber );
526 &MARCaddbiblio( $newrec, $biblionumber, GetFrameworkCode($biblionumber) );
527 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","DELETE",$itemnumber,"item")
528 if C4::Context->preference("CataloguingLog");
533 $data = &GetBiblioData($biblionumber, $type);
535 Returns information about the book with the given biblionumber.
539 C<&GetBiblioData> returns a reference-to-hash. The keys are the fields in
540 the C<biblio> and C<biblioitems> tables in the
543 In addition, C<$data-E<gt>{subject}> is the list of the book's
544 subjects, separated by C<" , "> (space, comma, space).
546 If there are multiple biblioitems with the given biblionumber, only
547 the first one is considered.
553 my ( $bibnum, $type ) = @_;
554 my $dbh = C4::Context->dbh;
557 SELECT * , biblioitems.notes AS bnotes, biblio.notes
559 LEFT JOIN biblioitems ON biblio.biblionumber = biblioitems.biblionumber
560 LEFT JOIN itemtypes ON biblioitems.itemtype = itemtypes.itemtype
561 WHERE biblio.biblionumber = ?
562 AND biblioitems.biblionumber = biblio.biblionumber
564 my $sth = $dbh->prepare($query);
565 $sth->execute($bibnum);
567 $data = $sth->fetchrow_hashref;
571 } # sub GetBiblioData
576 @results = &GetItemsInfo($biblionumber, $type);
578 Returns information about books with the given biblionumber.
580 C<$type> may be either C<intra> or anything else. If it is not set to
581 C<intra>, then the search will exclude lost, very overdue, and
584 C<&GetItemsInfo> returns a list of references-to-hash. Each element
585 contains a number of keys. Most of them are table items from the
586 C<biblio>, C<biblioitems>, C<items>, and C<itemtypes> tables in the
587 Koha database. Other keys include:
591 =item C<$data-E<gt>{branchname}>
593 The name (not the code) of the branch to which the book belongs.
595 =item C<$data-E<gt>{datelastseen}>
597 This is simply C<items.datelastseen>, except that while the date is
598 stored in YYYY-MM-DD format in the database, here it is converted to
599 DD/MM/YYYY format. A NULL date is returned as C<//>.
601 =item C<$data-E<gt>{datedue}>
603 =item C<$data-E<gt>{class}>
605 This is the concatenation of C<biblioitems.classification>, the book's
606 Dewey code, and C<biblioitems.subclass>.
608 =item C<$data-E<gt>{ocount}>
610 I think this is the number of copies of the book available.
612 =item C<$data-E<gt>{order}>
614 If this is set, it is set to C<One Order>.
622 my ( $biblionumber, $type ) = @_;
623 my $dbh = C4::Context->dbh;
624 my $query = "SELECT *,items.notforloan as itemnotforloan
625 FROM items, biblio, biblioitems
626 LEFT JOIN itemtypes on biblioitems.itemtype = itemtypes.itemtype
627 WHERE items.biblionumber = ?
628 AND biblioitems.biblioitemnumber = items.biblioitemnumber
629 AND biblio.biblionumber = items.biblionumber
630 ORDER BY items.dateaccessioned desc
632 my $sth = $dbh->prepare($query);
633 $sth->execute($biblionumber);
636 my ( $date_due, $count_reserves );
638 while ( my $data = $sth->fetchrow_hashref ) {
640 my $isth = $dbh->prepare(
641 "SELECT issues.*,borrowers.cardnumber
642 FROM issues, borrowers
644 AND returndate IS NULL
645 AND issues.borrowernumber=borrowers.borrowernumber"
647 $isth->execute( $data->{'itemnumber'} );
648 if ( my $idata = $isth->fetchrow_hashref ) {
649 $data->{borrowernumber} = $idata->{borrowernumber};
650 $data->{cardnumber} = $idata->{cardnumber};
651 $datedue = format_date( $idata->{'date_due'} );
653 if ( $datedue eq '' ) {
654 #$datedue="Available";
655 my ( $restype, $reserves ) =
656 C4::Reserves2::CheckReserves( $data->{'itemnumber'} );
660 $count_reserves = $restype;
665 #get branch information.....
666 my $bsth = $dbh->prepare(
667 "SELECT * FROM branches WHERE branchcode = ?
670 $bsth->execute( $data->{'holdingbranch'} );
671 if ( my $bdata = $bsth->fetchrow_hashref ) {
672 $data->{'branchname'} = $bdata->{'branchname'};
674 my $date = format_date( $data->{'datelastseen'} );
675 $data->{'datelastseen'} = $date;
676 $data->{'datedue'} = $datedue;
677 $data->{'count_reserves'} = $count_reserves;
679 # get notforloan complete status if applicable
680 my $sthnflstatus = $dbh->prepare(
681 'SELECT authorised_value
682 FROM marc_subfield_structure
683 WHERE kohafield="items.notforloan"
687 $sthnflstatus->execute;
688 my ($authorised_valuecode) = $sthnflstatus->fetchrow;
689 if ($authorised_valuecode) {
690 $sthnflstatus = $dbh->prepare(
691 "SELECT lib FROM authorised_values
693 AND authorised_value=?"
695 $sthnflstatus->execute( $authorised_valuecode,
696 $data->{itemnotforloan} );
697 my ($lib) = $sthnflstatus->fetchrow;
698 $data->{notforloan} = $lib;
701 # my stack procedures
702 my $stackstatus = $dbh->prepare(
703 'SELECT authorised_value
704 FROM marc_subfield_structure
705 WHERE kohafield="items.stack"
708 $stackstatus->execute;
710 ($authorised_valuecode) = $stackstatus->fetchrow;
711 if ($authorised_valuecode) {
712 $stackstatus = $dbh->prepare(
714 FROM authorised_values
716 AND authorised_value=?
719 $stackstatus->execute( $authorised_valuecode, $data->{stack} );
720 my ($lib) = $stackstatus->fetchrow;
721 $data->{stack} = $lib;
723 $results[$i] = $data;
733 $itemstatushash = &getitemstatus($fwkcode);
734 returns information about status.
735 Can be MARC dependant.
737 But basically could be can be loan or not
738 Create a status selector with the following code
740 =head3 in PERL SCRIPT
742 my $itemstatushash = getitemstatus;
744 foreach my $thisstatus (keys %$itemstatushash) {
745 my %row =(value => $thisstatus,
746 statusname => $itemstatushash->{$thisstatus}->{'statusname'},
748 push @itemstatusloop, \%row;
750 $template->param(statusloop=>\@itemstatusloop);
754 <select name="statusloop">
755 <option value="">Default</option>
756 <!-- TMPL_LOOP name="statusloop" -->
757 <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="statusname" --></option>
765 # returns a reference to a hash of references to status...
768 my $dbh = C4::Context->dbh;
770 $fwk = '' unless ($fwk);
771 my ( $tag, $subfield ) =
772 GetMarcFromKohaField( $dbh, "items.notforloan", $fwk );
773 if ( $tag and $subfield ) {
776 "select authorised_value from marc_subfield_structure where tagfield=? and tagsubfield=? and frameworkcode=?"
778 $sth->execute( $tag, $subfield, $fwk );
779 if ( my ($authorisedvaluecat) = $sth->fetchrow ) {
782 "select authorised_value, lib from authorised_values where category=? order by lib"
784 $authvalsth->execute($authorisedvaluecat);
785 while ( my ( $authorisedvalue, $lib ) = $authvalsth->fetchrow ) {
786 $itemstatus{$authorisedvalue} = $lib;
802 $itemstatus{"1"} = "Not For Loan";
806 =head2 getitemlocation
808 $itemlochash = &getitemlocation($fwk);
809 returns informations about location.
810 where fwk stands for an optional framework code.
811 Create a location selector with the following code
813 =head3 in PERL SCRIPT
815 my $itemlochash = getitemlocation;
817 foreach my $thisloc (keys %$itemlochash) {
818 my $selected = 1 if $thisbranch eq $branch;
819 my %row =(locval => $thisloc,
820 selected => $selected,
821 locname => $itemlochash->{$thisloc},
823 push @itemlocloop, \%row;
825 $template->param(itemlocationloop => \@itemlocloop);
828 <select name="location">
829 <option value="">Default</option>
830 <!-- TMPL_LOOP name="itemlocationloop" -->
831 <option value="<!-- TMPL_VAR name="locval" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="locname" --></option>
837 sub GetItemLocation {
839 # returns a reference to a hash of references to location...
842 my $dbh = C4::Context->dbh;
844 $fwk = '' unless ($fwk);
845 my ( $tag, $subfield ) =
846 GetMarcFromKohaField( $dbh, "items.location", $fwk );
847 if ( $tag and $subfield ) {
850 "select authorised_value from marc_subfield_structure where tagfield=? and tagsubfield=? and frameworkcode=?"
852 $sth->execute( $tag, $subfield, $fwk );
853 if ( my ($authorisedvaluecat) = $sth->fetchrow ) {
856 "select authorised_value, lib from authorised_values where category=? order by lib"
858 $authvalsth->execute($authorisedvaluecat);
859 while ( my ( $authorisedvalue, $lib ) = $authvalsth->fetchrow ) {
860 $itemlocation{$authorisedvalue} = $lib;
863 return \%itemlocation;
876 $itemlocation{"1"} = "Not For Loan";
877 return \%itemlocation;
880 =head2 &GetBiblioItemData
882 $itemdata = &GetBiblioItemData($biblioitemnumber);
884 Looks up the biblioitem with the given biblioitemnumber. Returns a
885 reference-to-hash. The keys are the fields from the C<biblio>,
886 C<biblioitems>, and C<itemtypes> tables in the Koha database, except
887 that C<biblioitems.notes> is given as C<$itemdata-E<gt>{bnotes}>.
892 sub GetBiblioItemData {
894 my $dbh = C4::Context->dbh;
897 "Select *,biblioitems.notes as bnotes from biblioitems, biblio,itemtypes where biblio.biblionumber = biblioitems.biblionumber and biblioitemnumber = ? and biblioitems.itemtype = itemtypes.itemtype"
901 $sth->execute($bibitem);
903 $data = $sth->fetchrow_hashref;
907 } # sub &GetBiblioItemData
909 =head2 GetItemFromBarcode
911 $result = GetItemFromBarcode($barcode);
915 sub GetItemFromBarcode {
917 my $dbh = C4::Context->dbh;
920 $dbh->prepare("SELECT itemnumber from items where items.barcode=?");
921 $rq->execute($barcode);
922 my ($result) = $rq->fetchrow;
926 =head2 GetBiblioItemByBiblioNumber
928 NOTE : This function has been copy/paste from C4/Biblio.pm from head before zebra integration.
932 sub GetBiblioItemByBiblioNumber {
933 my ($biblionumber) = @_;
934 my $dbh = C4::Context->dbh;
935 my $sth = $dbh->prepare("Select * from biblioitems where biblionumber = ?");
939 $sth->execute($biblionumber);
941 while ( my $data = $sth->fetchrow_hashref ) {
942 push @results, $data;
949 =head2 GetBiblioFromItemNumber
951 $item = &GetBiblioFromItemNumber($itemnumber);
953 Looks up the item with the given itemnumber.
955 C<&itemnodata> returns a reference-to-hash whose keys are the fields
956 from the C<biblio>, C<biblioitems>, and C<items> tables in the Koha
962 sub GetBiblioFromItemNumber {
963 my ( $itemnumber ) = @_;
964 my $dbh = C4::Context->dbh;
966 my $sth = $dbh->prepare(
967 "SELECT * FROM biblio,items,biblioitems
968 WHERE items.itemnumber = ?
969 AND biblio.biblionumber = items.biblionumber
970 AND biblioitems.biblioitemnumber = items.biblioitemnumber"
973 $sth->execute($itemnumber);
974 my $data = $sth->fetchrow_hashref;
981 ( $count, @results ) = &GetBiblio($biblionumber);
986 my ($biblionumber) = @_;
987 my $dbh = C4::Context->dbh;
988 my $sth = $dbh->prepare("Select * from biblio where biblionumber = ?");
991 $sth->execute($biblionumber);
992 while ( my $data = $sth->fetchrow_hashref ) {
993 $results[$count] = $data;
997 return ( $count, @results );
1000 =head2 get_itemnumbers_of
1002 my @itemnumbers_of = get_itemnumbers_of(@biblionumbers);
1004 Given a list of biblionumbers, return the list of corresponding itemnumbers
1005 for each biblionumber.
1007 Return a reference on a hash where keys are biblionumbers and values are
1008 references on array of itemnumbers.
1012 sub get_itemnumbers_of {
1013 my @biblionumbers = @_;
1015 my $dbh = C4::Context->dbh;
1021 WHERE biblionumber IN (?' . ( ',?' x scalar @biblionumbers - 1 ) . ')
1023 my $sth = $dbh->prepare($query);
1024 $sth->execute(@biblionumbers);
1028 while ( my ( $itemnumber, $biblionumber ) = $sth->fetchrow_array ) {
1029 push @{ $itemnumbers_of{$biblionumber} }, $itemnumber;
1032 return \%itemnumbers_of;
1037 $record = getRecord( $server, $koha_query, $recordSyntax );
1039 get a single record in piggyback mode from Zebra and return it in the requested record syntax
1041 default record syntax is XML
1046 my ( $server, $koha_query, $recordSyntax ) = @_;
1047 $recordSyntax = "xml" unless $recordSyntax;
1048 my $Zconn = C4::Context->Zconn( $server, 0, 1, 1, $recordSyntax );
1049 my $rs = $Zconn->search( new ZOOM::Query::CCL2RPN( $koha_query, $Zconn ) );
1050 if ( $rs->record(0) ) {
1051 return $rs->record(0)->raw();
1055 =head2 GetItemInfosOf
1057 GetItemInfosOf(@itemnumbers);
1061 sub GetItemInfosOf {
1062 my @itemnumbers = @_;
1067 WHERE itemnumber IN (' . join( ',', @itemnumbers ) . ')
1069 return get_infos_of( $query, 'itemnumber' );
1072 =head2 GetBiblioItemInfosOf
1074 GetBiblioItemInfosOf(@biblioitemnumbers);
1078 sub GetBiblioItemInfosOf {
1079 my @biblioitemnumbers = @_;
1082 SELECT biblioitemnumber,
1086 WHERE biblioitemnumber IN (' . join( ',', @biblioitemnumbers ) . ')
1088 return get_infos_of( $query, 'biblioitemnumber' );
1091 =head2 z3950_extended_services
1093 z3950_extended_services($serviceType,$serviceOptions,$record);
1095 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.
1097 C<$serviceType> one of: itemorder,create,drop,commit,update,xmlupdate
1099 C<$serviceOptions> a has of key/value pairs. For instance, if service_type is 'update', $service_options should contain:
1101 action => update action, one of specialUpdate, recordInsert, recordReplace, recordDelete, elementUpdate.
1105 recordidOpaque => Opaque Record ID (user supplied) or recordidNumber => Record ID number (system number).
1106 syntax => the record syntax (transfer syntax)
1107 databaseName = Database from connection object
1109 To set serviceOptions, call set_service_options($serviceType)
1111 C<$record> the record, if one is needed for the service type
1113 A record should be in XML. You can convert it to XML from MARC by running it through marc2xml().
1117 sub z3950_extended_services {
1118 my ( $server, $serviceType, $action, $serviceOptions ) = @_;
1120 # get our connection object
1121 my $Zconn = C4::Context->Zconn( $server, 0, 1 );
1123 # create a new package object
1124 my $Zpackage = $Zconn->package();
1127 $Zpackage->option( action => $action );
1129 if ( $serviceOptions->{'databaseName'} ) {
1130 $Zpackage->option( databaseName => $serviceOptions->{'databaseName'} );
1132 if ( $serviceOptions->{'recordIdNumber'} ) {
1134 recordIdNumber => $serviceOptions->{'recordIdNumber'} );
1136 if ( $serviceOptions->{'recordIdOpaque'} ) {
1138 recordIdOpaque => $serviceOptions->{'recordIdOpaque'} );
1141 # this is an ILL request (Zebra doesn't support it, but Koha could eventually)
1142 #if ($serviceType eq 'itemorder') {
1143 # $Zpackage->option('contact-name' => $serviceOptions->{'contact-name'});
1144 # $Zpackage->option('contact-phone' => $serviceOptions->{'contact-phone'});
1145 # $Zpackage->option('contact-email' => $serviceOptions->{'contact-email'});
1146 # $Zpackage->option('itemorder-item' => $serviceOptions->{'itemorder-item'});
1149 if ( $serviceOptions->{record} ) {
1150 $Zpackage->option( record => $serviceOptions->{record} );
1152 # can be xml or marc
1153 if ( $serviceOptions->{'syntax'} ) {
1154 $Zpackage->option( syntax => $serviceOptions->{'syntax'} );
1158 # send the request, handle any exception encountered
1159 eval { $Zpackage->send($serviceType) };
1160 if ( $@ && $@->isa("ZOOM::Exception") ) {
1161 return "error: " . $@->code() . " " . $@->message() . "\n";
1164 # free up package resources
1165 $Zpackage->destroy();
1168 =head2 set_service_options
1170 my $serviceOptions = set_service_options($serviceType);
1172 C<$serviceType> itemorder,create,drop,commit,update,xmlupdate
1174 Currently, we only support 'create', 'commit', and 'update'. 'drop' support will be added as soon as Zebra supports it.
1178 sub set_service_options {
1179 my ($serviceType) = @_;
1182 # FIXME: This needs to be an OID ... if we ever need 'syntax' this sub will need to change
1183 # $serviceOptions->{ 'syntax' } = ''; #zebra doesn't support syntaxes other than xml
1185 if ( $serviceType eq 'commit' ) {
1189 if ( $serviceType eq 'create' ) {
1193 if ( $serviceType eq 'drop' ) {
1194 die "ERROR: 'drop' not currently supported (by Zebra)";
1196 return $serviceOptions;
1199 =head1 FUNCTIONS FOR HANDLING MARC MANAGEMENT
1201 =head2 GetMarcStructure
1205 sub GetMarcStructure {
1206 my ( $dbh, $forlibrarian, $frameworkcode ) = @_;
1207 $frameworkcode = "" unless $frameworkcode;
1209 my $libfield = ( $forlibrarian eq 1 ) ? 'liblibrarian' : 'libopac';
1211 # check that framework exists
1214 "select count(*) from marc_tag_structure where frameworkcode=?");
1215 $sth->execute($frameworkcode);
1216 my ($total) = $sth->fetchrow;
1217 $frameworkcode = "" unless ( $total > 0 );
1220 "select tagfield,liblibrarian,libopac,mandatory,repeatable from marc_tag_structure where frameworkcode=? order by tagfield"
1222 $sth->execute($frameworkcode);
1223 my ( $liblibrarian, $libopac, $tag, $res, $tab, $mandatory, $repeatable );
1225 while ( ( $tag, $liblibrarian, $libopac, $mandatory, $repeatable ) =
1228 $res->{$tag}->{lib} =
1229 ( $forlibrarian or !$libopac ) ? $liblibrarian : $libopac;
1230 $res->{$tab}->{tab} = ""; # XXX
1231 $res->{$tag}->{mandatory} = $mandatory;
1232 $res->{$tag}->{repeatable} = $repeatable;
1237 "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"
1239 $sth->execute($frameworkcode);
1242 my $authorised_value;
1254 $tag, $subfield, $liblibrarian,
1256 $mandatory, $repeatable, $authorised_value,
1257 $authtypecode, $value_builder, $kohafield,
1258 $seealso, $hidden, $isurl,
1264 $res->{$tag}->{$subfield}->{lib} =
1265 ( $forlibrarian or !$libopac ) ? $liblibrarian : $libopac;
1266 $res->{$tag}->{$subfield}->{tab} = $tab;
1267 $res->{$tag}->{$subfield}->{mandatory} = $mandatory;
1268 $res->{$tag}->{$subfield}->{repeatable} = $repeatable;
1269 $res->{$tag}->{$subfield}->{authorised_value} = $authorised_value;
1270 $res->{$tag}->{$subfield}->{authtypecode} = $authtypecode;
1271 $res->{$tag}->{$subfield}->{value_builder} = $value_builder;
1272 $res->{$tag}->{$subfield}->{kohafield} = $kohafield;
1273 $res->{$tag}->{$subfield}->{seealso} = $seealso;
1274 $res->{$tag}->{$subfield}->{hidden} = $hidden;
1275 $res->{$tag}->{$subfield}->{isurl} = $isurl;
1276 $res->{$tag}->{$subfield}->{link} = $link;
1277 $res->{$tag}->{$subfield}->{defaultvalue} = $defaultvalue;
1282 =head2 GetMarcFromKohaField
1286 sub GetMarcFromKohaField {
1287 my ( $dbh, $kohafield, $frameworkcode ) = @_;
1288 return 0, 0 unless $kohafield;
1289 my $relations = C4::Context->marcfromkohafield;
1291 $relations->{$frameworkcode}->{$kohafield}->[0],
1292 $relations->{$frameworkcode}->{$kohafield}->[1]
1296 =head2 MARCaddbiblio
1298 &MARCaddbiblio($newrec,$biblionumber,$frameworkcode);
1300 Add MARC data for a biblio to koha
1306 # pass the MARC::Record to this function, and it will create the records in the marc tables
1307 my ( $record, $biblionumber, $frameworkcode ) = @_;
1308 my $dbh = C4::Context->dbh;
1309 my @fields = $record->fields();
1310 if ( !$frameworkcode ) {
1311 $frameworkcode = "";
1314 $dbh->prepare("UPDATE biblio SET frameworkcode=? WHERE biblionumber=?");
1315 $sth->execute( $frameworkcode, $biblionumber );
1317 my $encoding = C4::Context->preference("marcflavour");
1319 # deal with UNIMARC field 100 (encoding) : create it if needed & set encoding to unicode
1320 if ( $encoding eq "UNIMARC" ) {
1322 if ( $record->subfield( 100, "a" ) ) {
1323 $string = $record->subfield( 100, "a" );
1324 my $f100 = $record->field(100);
1325 $record->delete_field($f100);
1328 $string = POSIX::strftime( "%Y%m%d", localtime );
1330 $string = sprintf( "%-*s", 35, $string );
1332 substr( $string, 22, 6, "frey50" );
1333 unless ( $record->subfield( 100, "a" ) ) {
1334 $record->insert_grouped_field(
1335 MARC::Field->new( 100, "", "", "a" => $string ) );
1338 # warn "biblionumber : ".$biblionumber;
1341 "update biblioitems set marc=?,marcxml=? where biblionumber=?");
1342 $sth->execute( $record->as_usmarc(), $record->as_xml_record(),
1344 # warn $record->as_xml_record();
1346 ModZebra($biblionumber,"specialUpdate","biblioserver");
1347 return $biblionumber;
1352 $newbiblionumber = MARCadditem( $record, $biblionumber, $frameworkcode );
1358 # pass the MARC::Record to this function, and it will create the records in the marc tables
1359 my ( $record, $biblionumber, $frameworkcode ) = @_;
1360 my $newrec = &GetMarcBiblio($biblionumber);
1363 my @fields = $record->fields();
1364 foreach my $field (@fields) {
1365 $newrec->append_fields($field);
1368 # FIXME: should we be making sure the biblionumbers are the same?
1369 my $newbiblionumber =
1370 &MARCaddbiblio( $newrec, $biblionumber, $frameworkcode );
1371 return $newbiblionumber;
1374 =head2 GetMarcBiblio
1376 Returns MARC::Record of the biblionumber passed in parameter.
1381 my $biblionumber = shift;
1382 my $dbh = C4::Context->dbh;
1384 $dbh->prepare("select marcxml from biblioitems where biblionumber=? ");
1385 $sth->execute($biblionumber);
1386 my ($marcxml) = $sth->fetchrow;
1387 # warn "marcxml : $marcxml";
1388 MARC::File::XML->default_record_format(C4::Context->preference('marcflavour'));
1389 $marcxml =~ s/\x1e//g;
1390 $marcxml =~ s/\x1f//g;
1391 $marcxml =~ s/\x1d//g;
1392 $marcxml =~ s/\x0f//g;
1393 $marcxml =~ s/\x0c//g;
1394 my $record = MARC::Record->new();
1395 $record = MARC::Record::new_from_xml( $marcxml, "utf8",C4::Context->preference('marcflavour')) if $marcxml;
1401 my $marcxml = GetXmlBiblio($biblionumber);
1403 Returns biblioitems.marcxml of the biblionumber passed in parameter.
1408 my ( $biblionumber ) = @_;
1409 my $dbh = C4::Context->dbh;
1411 $dbh->prepare("select marcxml from biblioitems where biblionumber=? ");
1412 $sth->execute($biblionumber);
1413 my ($marcxml) = $sth->fetchrow;
1417 =head2 GetAuthorisedValueDesc
1419 my $subfieldvalue =get_authorised_value_desc(
1420 $tag, $subf[$i][0],$subf[$i][1], '', $taglib);
1424 sub GetAuthorisedValueDesc {
1425 my ( $tag, $subfield, $value, $framework, $tagslib ) = @_;
1426 my $dbh = C4::Context->dbh;
1429 if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq "branches" ) {
1430 return C4::Branch::GetBranchName($value);
1434 if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq "itemtypes" ) {
1435 return getitemtypeinfo($value);
1438 #---- "true" authorized value
1439 my $category = $tagslib->{$tag}->{$subfield}->{'authorised_value'};
1441 if ( $category ne "" ) {
1444 "select lib from authorised_values where category = ? and authorised_value = ?"
1446 $sth->execute( $category, $value );
1447 my $data = $sth->fetchrow_hashref;
1448 return $data->{'lib'};
1451 return $value; # if nothing is found return the original value
1457 Returns MARC::Record of the item passed in parameter.
1462 my ( $biblionumber, $itemnumber ) = @_;
1463 my $dbh = C4::Context->dbh;
1464 my $newrecord = MARC::Record->new();
1465 my $marcflavour = C4::Context->preference('marcflavour');
1467 my $marcxml = GetXmlBiblio($biblionumber);
1468 my $record = MARC::Record->new();
1469 # warn "marcxml :$marcxml";
1470 $record = MARC::Record::new_from_xml( $marcxml, "utf8", $marcflavour );
1471 # warn "record :".$record->as_formatted;
1472 # now, find where the itemnumber is stored & extract only the item
1473 my ( $itemnumberfield, $itemnumbersubfield ) =
1474 GetMarcFromKohaField( $dbh, 'items.itemnumber', '' );
1475 my @fields = $record->field($itemnumberfield);
1476 foreach my $field (@fields) {
1477 if ( $field->subfield($itemnumbersubfield) eq $itemnumber ) {
1478 $newrecord->insert_fields_ordered($field);
1486 $marcnotesarray = GetMarcNotes( $record, $marcflavour );
1488 get a single record in piggyback mode from Zebra and return it in the requested record syntax
1490 default record syntax is XML
1495 my ( $record, $marcflavour ) = @_;
1497 if ( $marcflavour eq "MARC21" ) {
1500 else { # assume unimarc if not marc21
1507 foreach my $field ( $record->field($scope) ) {
1508 my $value = $field->as_string();
1509 if ( $note ne "" ) {
1510 $marcnote = { marcnote => $note, };
1511 push @marcnotes, $marcnote;
1514 if ( $note ne $value ) {
1515 $note = $note . " " . $value;
1520 $marcnote = { marcnote => $note };
1521 push @marcnotes, $marcnote; #load last tag into array
1524 } # end GetMarcNotes
1526 =head2 GetMarcSubjects
1528 $marcsubjcts = GetMarcSubjects($record,$marcflavour);
1532 sub GetMarcSubjects {
1533 my ( $record, $marcflavour ) = @_;
1534 my ( $mintag, $maxtag );
1535 if ( $marcflavour eq "MARC21" ) {
1539 else { # assume unimarc if not marc21
1546 foreach my $field ( $record->fields ) {
1547 next unless $field->tag() >= $mintag && $field->tag() <= $maxtag;
1548 my @subfields = $field->subfields();
1552 for my $subject_subfield ( @subfields ) {
1553 my $code = $subject_subfield->[0];
1554 $label .= $subject_subfield->[1] . " and su-to:" unless ( $code == 9 );
1556 $link = "Koha-Auth-Number:".$subject_subfield->[1];
1561 $link =~ s/ and\ssu-to:$//;
1574 return \@marcsubjcts;
1575 } #end GetMarcSubjects
1577 =head2 GetMarcAuthors
1579 authors = GetMarcAuthors($record,$marcflavour);
1583 sub GetMarcAuthors {
1584 my ( $record, $marcflavour ) = @_;
1585 my ( $mintag, $maxtag );
1586 if ( $marcflavour eq "MARC21" ) {
1590 else { # assume unimarc if not marc21
1597 foreach my $field ( $record->fields ) {
1598 next unless $field->tag() >= $mintag && $field->tag() <= $maxtag;
1600 my @subfields = $field->subfields();
1603 for my $authors_subfield (@subfields) {
1604 if ($count_auth ne '0'){
1608 my $subfieldcode = $authors_subfield->[0];
1609 my $value = $authors_subfield->[1];
1610 $hash{'tag'} = $field->tag;
1611 $hash{value} .= $value . " " if ($subfieldcode != 9) ;
1612 $hash{link} .= $value if ($subfieldcode eq 9);
1614 push @marcauthors, \%hash;
1616 return \@marcauthors;
1619 =head2 GetMarcSeries
1621 $marcseriessarray = GetMarcSeries($record,$marcflavour);
1626 my ($record, $marcflavour) = @_;
1627 my ($mintag, $maxtag);
1628 if ($marcflavour eq "MARC21") {
1631 } else { # assume unimarc if not marc21
1641 foreach my $field ($record->field('440'), $record->field('490')) {
1643 #my $value = $field->subfield('a');
1644 #$marcsubjct = {MARCSUBJCT => $value,};
1645 my @subfields = $field->subfields();
1646 #warn "subfields:".join " ", @$subfields;
1649 for my $series_subfield (@subfields) {
1651 undef $volume_number;
1652 # see if this is an instance of a volume
1653 if ($series_subfield->[0] eq 'v') {
1657 my $code = $series_subfield->[0];
1658 my $value = $series_subfield->[1];
1659 my $linkvalue = $value;
1660 $linkvalue =~ s/(\(|\))//g;
1661 my $operator = " and " unless $counter==0;
1662 push @link_loop, {link => $linkvalue, operator => $operator };
1663 my $separator = C4::Context->preference("authoritysep") unless $counter==0;
1664 if ($volume_number) {
1665 push @subfields_loop, {volumenum => $value};
1668 push @subfields_loop, {code => $code, value => $value, link_loop => \@link_loop, separator => $separator, volumenum => $volume_number};
1672 push @marcseries, { MARCSERIES_SUBFIELDS_LOOP => \@subfields_loop };
1673 #$marcsubjct = {MARCSUBJCT => $field->as_string(),};
1674 #push @marcsubjcts, $marcsubjct;
1678 my $marcseriessarray=\@marcseries;
1679 return $marcseriessarray;
1680 } #end getMARCseriess
1682 =head2 MARCmodbiblio
1684 MARCmodbibio($dbh,$biblionumber,$record,$frameworkcode,1);
1686 Modify a biblio record with the option to save items data
1691 my ( $dbh, $biblionumber, $record, $frameworkcode, $keep_items ) = @_;
1693 # delete original record but save the items
1694 my $newrec = &MARCdelbiblio( $biblionumber, $keep_items );
1696 # recreate it and add the new fields
1697 my @fields = $record->fields();
1698 foreach my $field (@fields) {
1700 # this requires a more recent version of MARC::Record
1701 # but ensures the fields are in order
1702 $newrec->insert_fields_ordered($field);
1705 # give back our old leader
1706 $newrec->leader( $record->leader() );
1708 # add the record back with the items info preserved
1709 &MARCaddbiblio( $newrec, $biblionumber, $frameworkcode );
1712 =head2 MARCdelbiblio
1714 &MARCdelbiblio( $biblionumber, $keep_items )
1716 if the keep_item is set to 1, then all items are preserved.
1717 This flag is set when the delbiblio is called by modbiblio
1718 due to a too complex structure of MARC (repeatable fields and subfields),
1719 the best solution for a modif is to delete / recreate the record.
1721 1st of all, copy the MARC::Record to deletedbiblio table => if a true deletion, MARC data will be kept.
1722 if deletion called before MARCmodbiblio => won't do anything, as the oldbiblionumber doesn't
1723 exist in deletedbiblio table
1728 my ( $biblionumber, $keep_items ) = @_;
1729 my $dbh = C4::Context->dbh;
1731 my $record = GetMarcBiblio($biblionumber);
1732 my $oldbiblionumber = $biblionumber;
1734 $dbh->prepare("update deletedbiblio set marc=? where biblionumber=?");
1735 $copy2deleted->execute( $record->as_usmarc(), $oldbiblionumber );
1736 my @fields = $record->fields();
1738 # now, delete in MARC tables.
1739 if ( $keep_items eq 1 ) {
1740 #search item field code
1743 "select tagfield from marc_subfield_structure where kohafield like 'items.%'"
1746 my $itemtag = $sth->fetchrow_hashref->{tagfield};
1748 foreach my $field (@fields) {
1750 if ( $field->tag() ne $itemtag ) {
1751 $record->delete_field($field);
1756 foreach my $field (@fields) {
1758 $record->delete_field($field);
1766 MARCdelitem( $biblionumber, $itemnumber )
1768 delete the item field from the MARC record for the itemnumber specified
1773 my ( $biblionumber, $itemnumber ) = @_;
1774 my $dbh = C4::Context->dbh;
1776 # get the MARC record
1777 my $record = GetMarcBiblio($biblionumber);
1781 $dbh->prepare("UPDATE deleteditems SET marc=? WHERE itemnumber=?");
1782 $copy2deleted->execute( $record->as_usmarc(), $itemnumber );
1784 #search item field code
1787 "SELECT tagfield,tagsubfield FROM marc_subfield_structure WHERE kohafield LIKE 'items.itemnumber'"
1790 my ( $itemtag, $itemsubfield ) = $sth->fetchrow;
1791 my @fields = $record->field($itemtag);
1792 # delete the item specified
1793 foreach my $field (@fields) {
1794 if ( $field->subfield($itemsubfield) eq $itemnumber ) {
1795 $record->delete_field($field);
1801 =head2 MARCmoditemonefield
1803 &MARCmoditemonefield( $biblionumber, $itemnumber, $itemfield, $newvalue )
1807 sub MARCmoditemonefield {
1808 my ( $biblionumber, $itemnumber, $itemfield, $newvalue ) = @_;
1809 my $dbh = C4::Context->dbh;
1810 if ( !defined $newvalue ) {
1814 my $record = GetMarcItem( $biblionumber, $itemnumber );
1818 "select tagfield,tagsubfield from marc_subfield_structure where kohafield=?"
1822 $sth->execute($itemfield);
1823 if ( ( $tagfield, $tagsubfield ) = $sth->fetchrow ) {
1824 my $tag = $record->field($tagfield);
1826 my $tagsubs = $record->field($tagfield)->subfield($tagsubfield);
1827 $tag->update( $tagsubfield => $newvalue );
1828 $record->delete_field($tag);
1829 $record->insert_fields_ordered($tag);
1830 &MARCmoditem( $record, $biblionumber, $itemnumber, 0 );
1837 &MARCmoditem( $record, $biblionumber, $itemnumber, $frameworkcode, $delete )
1842 my ( $record, $biblionumber, $itemnumber, $frameworkcode, $delete ) = @_;
1843 my $dbh = C4::Context->dbh;
1845 # delete this item from MARC
1846 my $newrec = &MARCdelitem( $biblionumber, $itemnumber );
1849 my @fields = $record->fields();
1850 ###NEU specific add cataloguers cardnumber as well
1851 my $cardtag = C4::Context->preference('itemcataloguersubfield');
1853 foreach my $field (@fields) {
1855 my $me = C4::Context->userenv;
1856 my $cataloguer = $me->{'cardnumber'} if ($me);
1857 $field->update( $cardtag => $cataloguer ) if ($me);
1859 $newrec->append_fields($field);
1861 &MARCaddbiblio( $newrec, $biblionumber, $frameworkcode );
1864 =head2 GetFrameworkCode
1866 $frameworkcode = GetFrameworkCode( $biblionumber )
1870 sub GetFrameworkCode {
1871 my ( $biblionumber ) = @_;
1872 my $dbh = C4::Context->dbh;
1874 $dbh->prepare("select frameworkcode from biblio where biblionumber=?");
1875 $sth->execute($biblionumber);
1876 my ($frameworkcode) = $sth->fetchrow;
1877 return $frameworkcode;
1882 $record = Koha2Marc( $hash )
1884 This function builds partial MARC::Record from a hash
1886 Hash entries can be from biblio or biblioitems.
1888 This function is called in acquisition module, to create a basic catalogue entry from user entry
1895 my $dbh = C4::Context->dbh;
1898 "select tagfield,tagsubfield from marc_subfield_structure where frameworkcode=? and kohafield=?"
1900 my $record = MARC::Record->new();
1901 foreach (keys %{$hash}) {
1902 &MARCkoha2marcOnefield( $sth, $record, $_,
1908 =head2 MARCkoha2marcOnefield
1910 $record = MARCkoha2marcOnefield( $sth, $record, $kohafieldname, $value, $frameworkcode );
1914 sub MARCkoha2marcOnefield {
1915 my ( $sth, $record, $kohafieldname, $value, $frameworkcode ) = @_;
1916 $frameworkcode='' unless $frameworkcode;
1920 if ( !defined $sth ) {
1921 my $dbh = C4::Context->dbh;
1924 "select tagfield,tagsubfield from marc_subfield_structure where frameworkcode=? and kohafield=?"
1927 $sth->execute( $frameworkcode, $kohafieldname );
1928 if ( ( $tagfield, $tagsubfield ) = $sth->fetchrow ) {
1929 my $tag = $record->field($tagfield);
1931 $tag->update( $tagsubfield => $value );
1932 $record->delete_field($tag);
1933 $record->insert_fields_ordered($tag);
1936 $record->add_fields( $tagfield, " ", " ", $tagsubfield => $value );
1942 =head2 TransformHtmlToXml
1944 $xml = TransformHtmlToXml( $tags, $subfields, $values, $indicator, $ind_tag )
1948 sub TransformHtmlToXml {
1949 my ( $tags, $subfields, $values, $indicator, $ind_tag ) = @_;
1950 my $xml = MARC::File::XML::header('UTF-8');
1951 if ( C4::Context->preference('marcflavour') eq 'UNIMARC' ) {
1952 MARC::File::XML->default_record_format('UNIMARC');
1953 use POSIX qw(strftime);
1954 my $string = strftime( "%Y%m%d", localtime(time) );
1955 $string = sprintf( "%-*s", 35, $string );
1956 substr( $string, 22, 6, "frey50" );
1957 $xml .= "<datafield tag=\"100\" ind1=\"\" ind2=\"\">\n";
1958 $xml .= "<subfield code=\"a\">$string</subfield>\n";
1959 $xml .= "</datafield>\n";
1965 for ( my $i = 0 ; $i <= @$tags ; $i++ ) {
1966 @$values[$i] =~ s/&/&/g;
1967 @$values[$i] =~ s/</</g;
1968 @$values[$i] =~ s/>/>/g;
1969 @$values[$i] =~ s/"/"/g;
1970 @$values[$i] =~ s/'/'/g;
1971 if ( !utf8::is_utf8( @$values[$i] ) ) {
1972 utf8::decode( @$values[$i] );
1974 if ( ( @$tags[$i] ne $prevtag ) ) {
1975 $j++ unless ( @$tags[$i] eq "" );
1977 $xml .= "</datafield>\n";
1978 if ( ( @$tags[$i] && @$tags[$i] > 10 )
1979 && ( @$values[$i] ne "" ) )
1981 my $ind1 = substr( @$indicator[$j], 0, 1 );
1983 if ( @$indicator[$j] ) {
1984 $ind2 = substr( @$indicator[$j], 1, 1 );
1987 warn "Indicator in @$tags[$i] is empty";
1991 "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
1993 "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
2001 if ( @$values[$i] ne "" ) {
2004 if ( @$tags[$i] eq "000" ) {
2005 $xml .= "<leader>@$values[$i]</leader>\n";
2008 # rest of the fixed fields
2010 elsif ( @$tags[$i] < 10 ) {
2012 "<controlfield tag=\"@$tags[$i]\">@$values[$i]</controlfield>\n";
2016 my $ind1 = substr( @$indicator[$j], 0, 1 );
2017 my $ind2 = substr( @$indicator[$j], 1, 1 );
2019 "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
2021 "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
2027 else { # @$tags[$i] eq $prevtag
2028 if ( @$values[$i] eq "" ) {
2032 my $ind1 = substr( @$indicator[$j], 0, 1 );
2033 my $ind2 = substr( @$indicator[$j], 1, 1 );
2035 "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
2039 "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
2042 $prevtag = @$tags[$i];
2044 $xml .= MARC::File::XML::footer();
2049 =head2 TransformHtmlToMarc
2051 $record = TransformHtmlToMarc( $dbh, $rtags, $rsubfields, $rvalues, %indicators )
2055 sub TransformHtmlToMarc {
2056 my ( $dbh, $rtags, $rsubfields, $rvalues, %indicators ) = @_;
2058 my $record = MARC::Record->new();
2060 # my %subfieldlist=();
2061 my $prevvalue; # if tag <10
2062 my $field; # if tag >=10
2063 for ( my $i = 0 ; $i < @$rtags ; $i++ ) {
2064 next unless @$rvalues[$i];
2066 # rebuild MARC::Record
2067 # warn "0=>".@$rtags[$i].@$rsubfields[$i]." = ".@$rvalues[$i].": ";
2068 if ( @$rtags[$i] ne $prevtag ) {
2069 if ( $prevtag < 10 ) {
2072 if ( $prevtag ne '000' ) {
2073 $record->insert_fields_ordered(
2074 ( sprintf "%03s", $prevtag ), $prevvalue );
2078 $record->leader($prevvalue);
2085 $record->insert_fields_ordered($field);
2088 $indicators{ @$rtags[$i] } .= ' ';
2089 if ( @$rtags[$i] < 10 ) {
2090 $prevvalue = @$rvalues[$i];
2095 $field = MARC::Field->new(
2096 ( sprintf "%03s", @$rtags[$i] ),
2097 substr( $indicators{ @$rtags[$i] }, 0, 1 ),
2098 substr( $indicators{ @$rtags[$i] }, 1, 1 ),
2099 @$rsubfields[$i] => @$rvalues[$i]
2102 $prevtag = @$rtags[$i];
2105 if ( @$rtags[$i] < 10 ) {
2106 $prevvalue = @$rvalues[$i];
2109 if ( length( @$rvalues[$i] ) > 0 ) {
2110 $field->add_subfields( @$rsubfields[$i] => @$rvalues[$i] );
2113 $prevtag = @$rtags[$i];
2117 # the last has not been included inside the loop... do it now !
2118 $record->insert_fields_ordered($field) if $field;
2120 # warn "HTML2MARC=".$record->as_formatted;
2121 $record->encoding('UTF-8');
2123 # $record->MARC::File::USMARC::update_leader();
2127 =head2 TransformMarcToKoha
2129 $result = TransformMarcToKoha( $dbh, $record, $frameworkcode )
2133 sub TransformMarcToKoha {
2134 my ( $dbh, $record, $frameworkcode ) = @_;
2137 "select tagfield,tagsubfield from marc_subfield_structure where frameworkcode=? and kohafield=?"
2140 my $sth2 = $dbh->prepare("SHOW COLUMNS from biblio");
2143 while ( ($field) = $sth2->fetchrow ) {
2145 &TransformMarcToKohaOneField( "biblio", $field, $record, $result,
2148 $sth2 = $dbh->prepare("SHOW COLUMNS from biblioitems");
2150 while ( ($field) = $sth2->fetchrow ) {
2151 if ( $field eq 'notes' ) { $field = 'bnotes'; }
2153 &TransformMarcToKohaOneField( "biblioitems", $field, $record, $result,
2156 $sth2 = $dbh->prepare("SHOW COLUMNS from items");
2158 while ( ($field) = $sth2->fetchrow ) {
2160 &TransformMarcToKohaOneField( "items", $field, $record, $result,
2165 # modify copyrightdate to keep only the 1st year found
2166 my $temp = $result->{'copyrightdate'};
2167 $temp =~ m/c(\d\d\d\d)/; # search cYYYY first
2169 $result->{'copyrightdate'} = $1;
2171 else { # if no cYYYY, get the 1st date.
2172 $temp =~ m/(\d\d\d\d)/;
2173 $result->{'copyrightdate'} = $1;
2176 # modify publicationyear to keep only the 1st year found
2177 $temp = $result->{'publicationyear'};
2178 $temp =~ m/c(\d\d\d\d)/; # search cYYYY first
2180 $result->{'publicationyear'} = $1;
2182 else { # if no cYYYY, get the 1st date.
2183 $temp =~ m/(\d\d\d\d)/;
2184 $result->{'publicationyear'} = $1;
2189 =head2 TransformMarcToKohaOneField
2191 $result = TransformMarcToKohaOneField( $kohatable, $kohafield, $record, $result, $frameworkcode )
2195 sub TransformMarcToKohaOneField {
2197 # FIXME ? if a field has a repeatable subfield that is used in old-db, only the 1st will be retrieved...
2198 my ( $kohatable, $kohafield, $record, $result, $frameworkcode ) = @_;
2201 my ( $tagfield, $subfield ) =
2202 GetMarcFromKohaField( "", $kohatable . "." . $kohafield,
2204 foreach my $field ( $record->field($tagfield) ) {
2205 if ( $field->tag() < 10 ) {
2206 if ( $result->{$kohafield} ) {
2207 $result->{$kohafield} .= " | " . $field->data();
2210 $result->{$kohafield} = $field->data();
2214 if ( $field->subfields ) {
2215 my @subfields = $field->subfields();
2216 foreach my $subfieldcount ( 0 .. $#subfields ) {
2217 if ( $subfields[$subfieldcount][0] eq $subfield ) {
2218 if ( $result->{$kohafield} ) {
2219 $result->{$kohafield} .=
2220 " | " . $subfields[$subfieldcount][1];
2223 $result->{$kohafield} =
2224 $subfields[$subfieldcount][1];
2234 =head2 MARCitemchange
2236 &MARCitemchange( $record, $itemfield, $newvalue )
2240 sub MARCitemchange {
2241 my ( $record, $itemfield, $newvalue ) = @_;
2242 my $dbh = C4::Context->dbh;
2244 my ( $tagfield, $tagsubfield ) =
2245 GetMarcFromKohaField( $dbh, $itemfield, "" );
2246 if ( ($tagfield) && ($tagsubfield) ) {
2247 my $tag = $record->field($tagfield);
2249 $tag->update( $tagsubfield => $newvalue );
2250 $record->delete_field($tag);
2251 $record->insert_fields_ordered($tag);
2256 =head1 INTERNAL FUNCTIONS
2258 =head2 _koha_add_biblio
2260 _koha_add_biblio($dbh,$biblioitem);
2262 Internal function to add a biblio ($biblio is a hash with the values)
2266 sub _koha_add_biblio {
2267 my ( $dbh, $biblio, $frameworkcode ) = @_;
2268 my $sth = $dbh->prepare("Select max(biblionumber) from biblio");
2270 my $data = $sth->fetchrow_arrayref;
2271 my $biblionumber = $$data[0] + 1;
2274 if ( $biblio->{'seriestitle'} ) { $series = 1 }
2276 $sth = $dbh->prepare(
2278 SET biblionumber = ?, title = ?, author = ?, copyrightdate = ?, serial = ?, seriestitle = ?, notes = ?, abstract = ?, unititle = ?, frameworkcode = ? "
2281 $biblionumber, $biblio->{'title'},
2282 $biblio->{'author'}, $biblio->{'copyrightdate'},
2283 $biblio->{'serial'}, $biblio->{'seriestitle'},
2284 $biblio->{'notes'}, $biblio->{'abstract'},
2285 $biblio->{'unititle'}, $frameworkcode
2289 return ($biblionumber);
2294 ($indicators, $value) = _find_value($tag, $subfield, $record,$encoding);
2296 Find the given $subfield in the given $tag in the given
2297 MARC::Record $record. If the subfield is found, returns
2298 the (indicators, value) pair; otherwise, (undef, undef) is
2302 Such a function is used in addbiblio AND additem and serial-edit and maybe could be used in Authorities.
2303 I suggest we export it from this module.
2308 my ( $tagfield, $insubfield, $record, $encoding ) = @_;
2311 if ( $tagfield < 10 ) {
2312 if ( $record->field($tagfield) ) {
2313 push @result, $record->field($tagfield)->data();
2320 foreach my $field ( $record->field($tagfield) ) {
2321 my @subfields = $field->subfields();
2322 foreach my $subfield (@subfields) {
2323 if ( @$subfield[0] eq $insubfield ) {
2324 push @result, @$subfield[1];
2325 $indicator = $field->indicator(1) . $field->indicator(2);
2330 return ( $indicator, @result );
2333 =head2 _koha_modify_biblio
2335 Internal function for updating the biblio table
2339 sub _koha_modify_biblio {
2340 my ( $dbh, $biblio ) = @_;
2342 # FIXME: this code could be made more portable by not hard-coding the values that are supposed to be in biblio table
2345 "Update biblio set title = ?, author = ?, abstract = ?, copyrightdate = ?, seriestitle = ?, serial = ?, unititle = ?, notes = ? where biblionumber = ?"
2348 $biblio->{'title'}, $biblio->{'author'},
2349 $biblio->{'abstract'}, $biblio->{'copyrightdate'},
2350 $biblio->{'seriestitle'}, $biblio->{'serial'},
2351 $biblio->{'unititle'}, $biblio->{'notes'},
2352 $biblio->{'biblionumber'}
2355 return ( $biblio->{'biblionumber'} );
2358 =head2 _koha_modify_biblioitem
2360 _koha_modify_biblioitem( $dbh, $biblioitem );
2364 sub _koha_modify_biblioitem {
2365 my ( $dbh, $biblioitem ) = @_;
2367 ##Recalculate LC in case it changed --TG
2369 $biblioitem->{'itemtype'} = $dbh->quote( $biblioitem->{'itemtype'} );
2370 $biblioitem->{'url'} = $dbh->quote( $biblioitem->{'url'} );
2371 $biblioitem->{'isbn'} = $dbh->quote( $biblioitem->{'isbn'} );
2372 $biblioitem->{'issn'} = $dbh->quote( $biblioitem->{'issn'} );
2373 $biblioitem->{'publishercode'} =
2374 $dbh->quote( $biblioitem->{'publishercode'} );
2375 $biblioitem->{'publicationyear'} =
2376 $dbh->quote( $biblioitem->{'publicationyear'} );
2377 $biblioitem->{'classification'} =
2378 $dbh->quote( $biblioitem->{'classification'} );
2379 $biblioitem->{'dewey'} = $dbh->quote( $biblioitem->{'dewey'} );
2380 $biblioitem->{'subclass'} = $dbh->quote( $biblioitem->{'subclass'} );
2381 $biblioitem->{'illus'} = $dbh->quote( $biblioitem->{'illus'} );
2382 $biblioitem->{'pages'} = $dbh->quote( $biblioitem->{'pages'} );
2383 $biblioitem->{'volumeddesc'} = $dbh->quote( $biblioitem->{'volumeddesc'} );
2384 $biblioitem->{'bnotes'} = $dbh->quote( $biblioitem->{'bnotes'} );
2385 $biblioitem->{'size'} = $dbh->quote( $biblioitem->{'size'} );
2386 $biblioitem->{'place'} = $dbh->quote( $biblioitem->{'place'} );
2387 $biblioitem->{'ccode'} = $dbh->quote( $biblioitem->{'ccode'} );
2388 $biblioitem->{'biblionumber'} =
2389 $dbh->quote( $biblioitem->{'biblionumber'} );
2391 $query = "Update biblioitems set
2392 itemtype = $biblioitem->{'itemtype'},
2393 url = $biblioitem->{'url'},
2394 isbn = $biblioitem->{'isbn'},
2395 issn = $biblioitem->{'issn'},
2396 publishercode = $biblioitem->{'publishercode'},
2397 publicationyear = $biblioitem->{'publicationyear'},
2398 classification = $biblioitem->{'classification'},
2399 dewey = $biblioitem->{'dewey'},
2400 subclass = $biblioitem->{'subclass'},
2401 illus = $biblioitem->{'illus'},
2402 pages = $biblioitem->{'pages'},
2403 volumeddesc = $biblioitem->{'volumeddesc'},
2404 notes = $biblioitem->{'bnotes'},
2405 size = $biblioitem->{'size'},
2406 place = $biblioitem->{'place'},
2407 ccode = $biblioitem->{'ccode'}
2408 where biblionumber = $biblioitem->{'biblionumber'}";
2411 if ( $dbh->errstr ) {
2416 =head2 _koha_modify_note
2418 _koha_modify_note( $dbh, $bibitemnum, $note );
2422 sub _koha_modify_note {
2423 my ( $dbh, $bibitemnum, $note ) = @_;
2425 # my $dbh=C4Connect;
2426 my $query = "update biblioitems set notes='$note' where
2427 biblioitemnumber='$bibitemnum'";
2428 my $sth = $dbh->prepare($query);
2433 =head2 _koha_add_biblioitem
2435 _koha_add_biblioitem( $dbh, $biblioitem );
2437 Internal function to add a biblioitem
2441 sub _koha_add_biblioitem {
2442 my ( $dbh, $biblioitem ) = @_;
2444 # my $dbh = C4Connect;
2445 my $sth = $dbh->prepare("SELECT max(biblioitemnumber) FROM biblioitems");
2450 $data = $sth->fetchrow_arrayref;
2451 $bibitemnum = $$data[0] + 1;
2455 $sth = $dbh->prepare(
2456 "INSERT INTO biblioitems SET
2457 biblioitemnumber = ?, biblionumber = ?,
2458 volume = ?, number = ?,
2459 classification = ?, itemtype = ?,
2461 issn = ?, dewey = ?,
2462 subclass = ?, publicationyear = ?,
2463 publishercode = ?, volumedate = ?,
2464 volumeddesc = ?, illus = ?,
2465 pages = ?, notes = ?,
2467 marc = ?, lcsort =?,
2468 place = ?, ccode = ?
2472 calculatelc( $biblioitem->{'classification'} )
2473 . $biblioitem->{'subclass'};
2475 $bibitemnum, $biblioitem->{'biblionumber'},
2476 $biblioitem->{'volume'}, $biblioitem->{'number'},
2477 $biblioitem->{'classification'}, $biblioitem->{'itemtype'},
2478 $biblioitem->{'url'}, $biblioitem->{'isbn'},
2479 $biblioitem->{'issn'}, $biblioitem->{'dewey'},
2480 $biblioitem->{'subclass'}, $biblioitem->{'publicationyear'},
2481 $biblioitem->{'publishercode'}, $biblioitem->{'volumedate'},
2482 $biblioitem->{'volumeddesc'}, $biblioitem->{'illus'},
2483 $biblioitem->{'pages'}, $biblioitem->{'bnotes'},
2484 $biblioitem->{'size'}, $biblioitem->{'lccn'},
2485 $biblioitem->{'marc'}, $biblioitem->{'place'},
2486 $lcsort, $biblioitem->{'ccode'}
2489 return ($bibitemnum);
2492 =head2 _koha_new_items
2494 _koha_new_items( $dbh, $item, $barcode );
2498 sub _koha_new_items {
2499 my ( $dbh, $item, $barcode ) = @_;
2501 # my $dbh = C4Connect;
2502 my $sth = $dbh->prepare("Select max(itemnumber) from items");
2508 $data = $sth->fetchrow_hashref;
2509 $itemnumber = $data->{'max(itemnumber)'} + 1;
2511 ## Now calculate lccalnumber
2512 my ($cutterextra) = itemcalculator(
2514 $item->{'biblioitemnumber'},
2515 $item->{'itemcallnumber'}
2518 # FIXME the "notforloan" field seems to be named "loan" in some places. workaround bugfix.
2519 if ( $item->{'loan'} ) {
2520 $item->{'notforloan'} = $item->{'loan'};
2523 # if dateaccessioned is provided, use it. Otherwise, set to NOW()
2524 if ( $item->{'dateaccessioned'} eq '' || !$item->{'dateaccessioned'} ) {
2526 $sth = $dbh->prepare(
2527 "Insert into items set
2528 itemnumber = ?, biblionumber = ?,
2529 multivolumepart = ?,
2530 biblioitemnumber = ?, barcode = ?,
2531 booksellerid = ?, dateaccessioned = NOW(),
2532 homebranch = ?, holdingbranch = ?,
2533 price = ?, replacementprice = ?,
2534 replacementpricedate = NOW(), datelastseen = NOW(),
2535 multivolume = ?, stack = ?,
2536 itemlost = ?, wthdrawn = ?,
2537 paidfor = ?, itemnotes = ?,
2538 itemcallnumber =?, notforloan = ?,
2539 location = ?, Cutterextra = ?
2543 $itemnumber, $item->{'biblionumber'},
2544 $item->{'multivolumepart'}, $item->{'biblioitemnumber'},
2545 $barcode, $item->{'booksellerid'},
2546 $item->{'homebranch'}, $item->{'holdingbranch'},
2547 $item->{'price'}, $item->{'replacementprice'},
2548 $item->{multivolume}, $item->{stack},
2549 $item->{itemlost}, $item->{wthdrawn},
2550 $item->{paidfor}, $item->{'itemnotes'},
2551 $item->{'itemcallnumber'}, $item->{'notforloan'},
2552 $item->{'location'}, $cutterextra
2556 $sth = $dbh->prepare(
2557 "INSERT INTO items SET
2558 itemnumber = ?, biblionumber = ?,
2559 multivolumepart = ?,
2560 biblioitemnumber = ?, barcode = ?,
2561 booksellerid = ?, dateaccessioned = ?,
2562 homebranch = ?, holdingbranch = ?,
2563 price = ?, replacementprice = ?,
2564 replacementpricedate = NOW(), datelastseen = NOW(),
2565 multivolume = ?, stack = ?,
2566 itemlost = ?, wthdrawn = ?,
2567 paidfor = ?, itemnotes = ?,
2568 itemcallnumber = ?, notforloan = ?,
2574 $itemnumber, $item->{'biblionumber'},
2575 $item->{'multivolumepart'}, $item->{'biblioitemnumber'},
2576 $barcode, $item->{'booksellerid'},
2577 $item->{'dateaccessioned'}, $item->{'homebranch'},
2578 $item->{'holdingbranch'}, $item->{'price'},
2579 $item->{'replacementprice'}, $item->{multivolume},
2580 $item->{stack}, $item->{itemlost},
2581 $item->{wthdrawn}, $item->{paidfor},
2582 $item->{'itemnotes'}, $item->{'itemcallnumber'},
2583 $item->{'notforloan'}, $item->{'location'},
2587 if ( defined $sth->errstr ) {
2588 $error .= $sth->errstr;
2590 return ( $itemnumber, $error );
2593 =head2 _koha_modify_item
2595 _koha_modify_item( $dbh, $item, $op );
2599 sub _koha_modify_item {
2600 my ( $dbh, $item, $op ) = @_;
2601 $item->{'itemnum'} = $item->{'itemnumber'} unless $item->{'itemnum'};
2603 # if all we're doing is setting statuses, just update those and get out
2604 if ( $op eq "setstatus" ) {
2606 "UPDATE items SET itemlost=?,wthdrawn=?,binding=? WHERE itemnumber=?";
2608 $item->{'itemlost'}, $item->{'wthdrawn'},
2609 $item->{'binding'}, $item->{'itemnumber'}
2611 my $sth = $dbh->prepare($query);
2612 $sth->execute(@bind);
2616 ## Now calculate lccalnumber
2618 itemcalculator( $dbh, $item->{'bibitemnum'}, $item->{'itemcallnumber'} );
2620 my $query = "UPDATE items SET
2621 barcode=?,itemnotes=?,itemcallnumber=?,notforloan=?,location=?,multivolumepart=?,multivolume=?,stack=?,wthdrawn=?,holdingbranch=?,homebranch=?,cutterextra=?, onloan=?, binding=?";
2624 $item->{'barcode'}, $item->{'notes'},
2625 $item->{'itemcallnumber'}, $item->{'notforloan'},
2626 $item->{'location'}, $item->{multivolumepart},
2627 $item->{multivolume}, $item->{stack},
2628 $item->{wthdrawn}, $item->{holdingbranch},
2629 $item->{homebranch}, $cutterextra,
2630 $item->{onloan}, $item->{binding}
2632 if ( $item->{'lost'} ne '' ) {
2634 "update items set biblioitemnumber=?,barcode=?,itemnotes=?,homebranch=?,
2635 itemlost=?,wthdrawn=?,itemcallnumber=?,notforloan=?,
2636 location=?,multivolumepart=?,multivolume=?,stack=?,wthdrawn=?,holdingbranch=?,cutterextra=?,onloan=?, binding=?";
2638 $item->{'bibitemnum'}, $item->{'barcode'},
2639 $item->{'notes'}, $item->{'homebranch'},
2640 $item->{'lost'}, $item->{'wthdrawn'},
2641 $item->{'itemcallnumber'}, $item->{'notforloan'},
2642 $item->{'location'}, $item->{multivolumepart},
2643 $item->{multivolume}, $item->{stack},
2644 $item->{wthdrawn}, $item->{holdingbranch},
2645 $cutterextra, $item->{onloan},
2648 if ( $item->{homebranch} ) {
2649 $query .= ",homebranch=?";
2650 push @bind, $item->{homebranch};
2652 if ( $item->{holdingbranch} ) {
2653 $query .= ",holdingbranch=?";
2654 push @bind, $item->{holdingbranch};
2657 $query .= " where itemnumber=?";
2658 push @bind, $item->{'itemnum'};
2659 if ( $item->{'replacement'} ne '' ) {
2660 $query =~ s/ where/,replacementprice='$item->{'replacement'}' where/;
2662 my $sth = $dbh->prepare($query);
2663 $sth->execute(@bind);
2667 =head2 _koha_delete_item
2669 _koha_delete_item( $dbh, $itemnum );
2671 Internal function to delete an item record from the koha tables
2675 sub _koha_delete_item {
2676 my ( $dbh, $itemnum ) = @_;
2678 my $sth = $dbh->prepare("select * from items where itemnumber=?");
2679 $sth->execute($itemnum);
2680 my $data = $sth->fetchrow_hashref;
2682 my $query = "Insert into deleteditems set ";
2684 foreach my $temp ( keys %$data ) {
2685 $query .= "$temp = ?,";
2686 push( @bind, $data->{$temp} );
2691 $sth = $dbh->prepare($query);
2692 $sth->execute(@bind);
2694 $sth = $dbh->prepare("Delete from items where itemnumber=?");
2695 $sth->execute($itemnum);
2699 =head2 _koha_delete_biblio
2701 $error = _koha_delete_biblio($dbh,$biblionumber);
2703 Internal sub for deleting from biblio table -- also saves to deletedbiblio
2705 C<$dbh> - the database handle
2706 C<$biblionumber> - the biblionumber of the biblio to be deleted
2710 # FIXME: add error handling
2712 sub _koha_delete_biblio {
2713 my ( $dbh, $biblionumber ) = @_;
2715 # get all the data for this biblio
2716 my $sth = $dbh->prepare("SELECT * FROM biblio WHERE biblionumber=?");
2717 $sth->execute($biblionumber);
2719 if ( my $data = $sth->fetchrow_hashref ) {
2721 # save the record in deletedbiblio
2722 # find the fields to save
2723 my $query = "INSERT INTO deletedbiblio SET ";
2725 foreach my $temp ( keys %$data ) {
2726 $query .= "$temp = ?,";
2727 push( @bind, $data->{$temp} );
2730 # replace the last , by ",?)"
2732 my $bkup_sth = $dbh->prepare($query);
2733 $bkup_sth->execute(@bind);
2737 my $del_sth = $dbh->prepare("DELETE FROM biblio WHERE biblionumber=?");
2738 $del_sth->execute($biblionumber);
2745 =head2 _koha_delete_biblioitems
2747 $error = _koha_delete_biblioitems($dbh,$biblioitemnumber);
2749 Internal sub for deleting from biblioitems table -- also saves to deletedbiblioitems
2751 C<$dbh> - the database handle
2752 C<$biblionumber> - the biblioitemnumber of the biblioitem to be deleted
2756 # FIXME: add error handling
2758 sub _koha_delete_biblioitems {
2759 my ( $dbh, $biblioitemnumber ) = @_;
2761 # get all the data for this biblioitem
2763 $dbh->prepare("SELECT * FROM biblioitems WHERE biblioitemnumber=?");
2764 $sth->execute($biblioitemnumber);
2766 if ( my $data = $sth->fetchrow_hashref ) {
2768 # save the record in deletedbiblioitems
2769 # find the fields to save
2770 my $query = "INSERT INTO deletedbiblioitems SET ";
2772 foreach my $temp ( keys %$data ) {
2773 $query .= "$temp = ?,";
2774 push( @bind, $data->{$temp} );
2777 # replace the last , by ",?)"
2779 my $bkup_sth = $dbh->prepare($query);
2780 $bkup_sth->execute(@bind);
2783 # delete the biblioitem
2785 $dbh->prepare("DELETE FROM biblioitems WHERE biblioitemnumber=?");
2786 $del_sth->execute($biblioitemnumber);
2793 =head2 _koha_delete_items
2795 $error = _koha_delete_items($dbh,$itemnumber);
2797 Internal sub for deleting from items table -- also saves to deleteditems
2799 C<$dbh> - the database handle
2800 C<$itemnumber> - the itemnumber of the item to be deleted
2804 # FIXME: add error handling
2806 sub _koha_delete_items {
2807 my ( $dbh, $itemnumber ) = @_;
2809 # get all the data for this item
2810 my $sth = $dbh->prepare("SELECT * FROM items WHERE itemnumber=?");
2811 $sth->execute($itemnumber);
2813 if ( my $data = $sth->fetchrow_hashref ) {
2815 # save the record in deleteditems
2816 # find the fields to save
2817 my $query = "INSERT INTO deleteditems SET ";
2819 foreach my $temp ( keys %$data ) {
2820 $query .= "$temp = ?,";
2821 push( @bind, $data->{$temp} );
2824 # replace the last , by ",?)"
2826 my $bkup_sth = $dbh->prepare($query);
2827 $bkup_sth->execute(@bind);
2831 my $del_sth = $dbh->prepare("DELETE FROM items WHERE itemnumber=?");
2832 $del_sth->execute($itemnumber);
2839 =head1 OTHER FUNCTIONS
2843 my $string = char_decode( $string, $encoding );
2845 converts ISO 5426 coded string to UTF-8
2846 sloppy code : should be improved in next issue
2851 my ( $string, $encoding ) = @_;
2854 $encoding = C4::Context->preference("marcflavour") unless $encoding;
2855 if ( $encoding eq "UNIMARC" ) {
2925 # this handles non-sorting blocks (if implementation requires this)
2926 $string = nsb_clean($_);
2928 elsif ( $encoding eq "USMARC" || $encoding eq "MARC21" ) {
2987 #Additional Turkish characters
2990 s/(\xf0)s/\xc5\x9f/gm;
2991 s/(\xf0)S/\xc5\x9e/gm;
2994 s/\xe7\x49/\\xc4\xb0/gm;
2995 s/(\xe6)G/\xc4\x9e/gm;
2996 s/(\xe6)g/ğ\xc4\x9f/gm;
2999 s/(\xe8|\xc8)o/ö/gm;
3000 s/(\xe8|\xc8)O/Ö/gm;
3001 s/(\xe8|\xc8)u/ü/gm;
3002 s/(\xe8|\xc8)U/Ü/gm;
3003 s/\xc2\xb8/\xc4\xb1/gm;
3006 # this handles non-sorting blocks (if implementation requires this)
3007 $string = nsb_clean($_);
3012 =head2 PrepareItemrecordDisplay
3014 PrepareItemrecordDisplay($itemrecord,$bibnum,$itemumber);
3016 Returns a hash with all the fields for Display a given item data in a template
3020 sub PrepareItemrecordDisplay {
3022 my ( $bibnum, $itemnum ) = @_;
3024 my $dbh = C4::Context->dbh;
3025 my $frameworkcode = &GetFrameworkCode( $bibnum );
3026 my ( $itemtagfield, $itemtagsubfield ) =
3027 &GetMarcFromKohaField( $dbh, "items.itemnumber", $frameworkcode );
3028 my $tagslib = &GetMarcStructure( $dbh, 1, $frameworkcode );
3029 my $itemrecord = GetMarcItem( $bibnum, $itemnum) if ($itemnum);
3031 my $authorised_values_sth =
3033 "select authorised_value,lib from authorised_values where category=? order by lib"
3035 foreach my $tag ( sort keys %{$tagslib} ) {
3036 my $previous_tag = '';
3038 # loop through each subfield
3040 foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
3041 next if ( subfield_is_koha_internal_p($subfield) );
3042 next if ( $tagslib->{$tag}->{$subfield}->{'tab'} ne "10" );
3044 $subfield_data{tag} = $tag;
3045 $subfield_data{subfield} = $subfield;
3046 $subfield_data{countsubfield} = $cntsubf++;
3047 $subfield_data{kohafield} =
3048 $tagslib->{$tag}->{$subfield}->{'kohafield'};
3050 # $subfield_data{marc_lib}=$tagslib->{$tag}->{$subfield}->{lib};
3051 $subfield_data{marc_lib} =
3052 "<span id=\"error\" title=\""
3053 . $tagslib->{$tag}->{$subfield}->{lib} . "\">"
3054 . substr( $tagslib->{$tag}->{$subfield}->{lib}, 0, 12 )
3056 $subfield_data{mandatory} =
3057 $tagslib->{$tag}->{$subfield}->{mandatory};
3058 $subfield_data{repeatable} =
3059 $tagslib->{$tag}->{$subfield}->{repeatable};
3060 $subfield_data{hidden} = "display:none"
3061 if $tagslib->{$tag}->{$subfield}->{hidden};
3063 ( $x, $value ) = _find_value( $tag, $subfield, $itemrecord )
3065 $value =~ s/"/"/g;
3067 # search for itemcallnumber if applicable
3068 if ( $tagslib->{$tag}->{$subfield}->{kohafield} eq
3069 'items.itemcallnumber'
3070 && C4::Context->preference('itemcallnumber') )
3073 substr( C4::Context->preference('itemcallnumber'), 0, 3 );
3075 substr( C4::Context->preference('itemcallnumber'), 3, 1 );
3076 my $temp = $itemrecord->field($CNtag) if ($itemrecord);
3078 $value = $temp->subfield($CNsubfield);
3081 if ( $tagslib->{$tag}->{$subfield}->{authorised_value} ) {
3082 my @authorised_values;
3085 # builds list, depending on authorised value...
3087 if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq
3090 if ( ( C4::Context->preference("IndependantBranches") )
3091 && ( C4::Context->userenv->{flags} != 1 ) )
3095 "select branchcode,branchname from branches where branchcode = ? order by branchname"
3097 $sth->execute( C4::Context->userenv->{branch} );
3098 push @authorised_values, ""
3100 $tagslib->{$tag}->{$subfield}->{mandatory} );
3101 while ( my ( $branchcode, $branchname ) =
3102 $sth->fetchrow_array )
3104 push @authorised_values, $branchcode;
3105 $authorised_lib{$branchcode} = $branchname;
3111 "select branchcode,branchname from branches order by branchname"
3114 push @authorised_values, ""
3116 $tagslib->{$tag}->{$subfield}->{mandatory} );
3117 while ( my ( $branchcode, $branchname ) =
3118 $sth->fetchrow_array )
3120 push @authorised_values, $branchcode;
3121 $authorised_lib{$branchcode} = $branchname;
3127 elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq
3132 "select itemtype,description from itemtypes order by description"
3135 push @authorised_values, ""
3136 unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
3137 while ( my ( $itemtype, $description ) =
3138 $sth->fetchrow_array )
3140 push @authorised_values, $itemtype;
3141 $authorised_lib{$itemtype} = $description;
3144 #---- "true" authorised value
3147 $authorised_values_sth->execute(
3148 $tagslib->{$tag}->{$subfield}->{authorised_value} );
3149 push @authorised_values, ""
3150 unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
3151 while ( my ( $value, $lib ) =
3152 $authorised_values_sth->fetchrow_array )
3154 push @authorised_values, $value;
3155 $authorised_lib{$value} = $lib;
3158 $subfield_data{marc_value} = CGI::scrolling_list(
3159 -name => 'field_value',
3160 -values => \@authorised_values,
3161 -default => "$value",
3162 -labels => \%authorised_lib,
3168 elsif ( $tagslib->{$tag}->{$subfield}->{thesaurus_category} ) {
3169 $subfield_data{marc_value} =
3170 "<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>";
3173 # COMMENTED OUT because No $i is provided with this API.
3174 # And thus, no value_builder can be activated.
3175 # BUT could be thought over.
3176 # } elsif ($tagslib->{$tag}->{$subfield}->{'value_builder'}) {
3177 # my $plugin="value_builder/".$tagslib->{$tag}->{$subfield}->{'value_builder'};
3179 # my $extended_param = plugin_parameters($dbh,$itemrecord,$tagslib,$i,0);
3180 # my ($function_name,$javascript) = plugin_javascript($dbh,$record,$tagslib,$i,0);
3181 # $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";
3184 $subfield_data{marc_value} =
3185 "<input type=\"text\" name=\"field_value\" value=\"$value\" size=50 maxlength=255>";
3187 push( @loop_data, \%subfield_data );
3191 my $itemnumber = $itemrecord->subfield( $itemtagfield, $itemtagsubfield )
3192 if ( $itemrecord && $itemrecord->field($itemtagfield) );
3194 'itemtagfield' => $itemtagfield,
3195 'itemtagsubfield' => $itemtagsubfield,
3196 'itemnumber' => $itemnumber,
3197 'iteminformation' => \@loop_data
3203 my $string = nsb_clean( $string, $encoding );
3208 my $NSB = '\x88'; # NSB : begin Non Sorting Block
3209 my $NSE = '\x89'; # NSE : Non Sorting Block end
3210 # handles non sorting blocks
3214 s/[ ]{0,1}$NSE/) /gm;
3219 =head2 ModZebrafiles
3221 &ModZebrafiles( $dbh, $biblionumber, $record, $folder, $server );
3227 my ( $dbh, $biblionumber, $record, $folder, $server ) = @_;
3231 C4::Context->zebraconfig($server)->{directory} . "/" . $folder . "/";
3232 unless ( opendir( DIR, "$zebradir" ) ) {
3233 warn "$zebradir not found";
3237 my $filename = $zebradir . $biblionumber;
3240 open( OUTPUT, ">", $filename . ".xml" );
3241 print OUTPUT $record;
3248 ModZebra( $dbh, $biblionumber, $op, $server );
3253 ###Accepts a $server variable thus we can use it for biblios authorities or other zebra dbs
3254 my ( $biblionumber, $op, $server ) = @_;
3255 my $dbh=C4::Context->dbh;
3256 #warn "SERVER:".$server;
3258 # true ModZebra commented until indexdata fixes zebraDB crashes (it seems they occur on multiple updates
3260 # replaced by a zebraqueue table, that is filled with ModZebra to run.
3261 # the table is emptied by misc/cronjobs/zebraqueue_start.pl script
3263 my $sth=$dbh->prepare("insert into zebraqueue (biblio_auth_number ,server,operation) values(?,?,?)");
3264 $sth->execute($biblionumber,$server,$op);
3271 # my $reconnect = 0;
3276 # $Zconnbiblio[0] = C4::Context->Zconn( $server, 0, 1 );
3278 # if ( $server eq "biblioserver" ) {
3280 # # it's unclear to me whether this should be in xml or MARC format
3281 # # but it is clear it should be nabbed from zebra rather than from
3283 # $record = GetMarcBiblio($biblionumber);
3284 # $record = $record->as_xml_record() if $record;
3285 # # warn "RECORD $biblionumber => ".$record;
3286 # $shadow="biblioservershadow";
3288 # # warn "RECORD $biblionumber => ".$record;
3289 # $shadow = "biblioservershadow";
3292 # elsif ( $server eq "authorityserver" ) {
3293 # $record = C4::AuthoritiesMarc::XMLgetauthority( $dbh, $biblionumber );
3294 # $shadow = "authorityservershadow";
3295 # } ## Add other servers as necessary
3297 # my $Zpackage = $Zconnbiblio[0]->package();
3298 # $Zpackage->option( action => $op );
3299 # $Zpackage->option( record => $record );
3302 # $Zpackage->send("update");
3306 # while ( ( $i = ZOOM::event( \@Zconnbiblio ) ) != 0 ) {
3307 # $event = $Zconnbiblio[0]->last_event();
3308 # last if $event == ZOOM::Event::ZEND;
3311 # my ( $error, $errmsg, $addinfo, $diagset ) = $Zconnbiblio[0]->error_x();
3312 # if ( $error == 10000 && $reconnect == 0 )
3313 # { ## This is serious ZEBRA server is not available -reconnect
3314 # warn "problem with zebra server connection";
3316 # my $res = system('sc start "Z39.50 Server" >c:/zebraserver/error.log');
3318 # #warn "Trying to restart ZEBRA Server";
3319 # #goto "reconnect";
3321 # elsif ( $error == 10007 && $tried < 2 )
3322 # { ## timeout --another 30 looonng seconds for this update
3323 # $tried = $tried + 1;
3324 # warn "warn: timeout, trying again";
3327 # elsif ( $error == 10004 && $recon == 0 ) { ##Lost connection -reconnect
3329 # warn "error: reconnecting to zebra";
3332 # # as a last resort, we save the data to the filesystem to be indexed in batch
3336 # "Error-$server $op $biblionumber /errcode:, $error, /MSG:,$errmsg,$addinfo \n";
3337 # $Zpackage->destroy();
3338 # $Zconnbiblio[0]->destroy();
3339 # ModZebrafiles( $dbh, $biblionumber, $record, $op, $server );
3342 # if ( C4::Context->$shadow ) {
3343 # $Zpackage->send('commit');
3344 # while ( ( $i = ZOOM::event( \@Zconnbiblio ) ) != 0 ) {
3346 # #waiting zebra to finish;
3349 # $Zpackage->destroy();
3354 $lc = calculatelc($classification);
3359 my ($classification) = @_;
3360 $classification =~ s/^\s+|\s+$//g;
3365 for ( $i = 0 ; $i < length($classification) ; $i++ ) {
3366 my $c = ( substr( $classification, $i, 1 ) );
3367 if ( $c ge '0' && $c le '9' ) {
3369 $lc2 = substr( $classification, $i );
3373 $lc1 .= substr( $classification, $i, 1 );
3378 my $other = length($lc1);
3385 for ( 1 .. ( 4 - $other ) ) {
3394 ##Find the decimal part of $lc2
3395 my $pos = index( $lc2, "." );
3396 if ( $pos < 0 ) { $pos = length($lc2); }
3397 if ( $pos >= 0 && $pos < 5 ) {
3398 ##Pad lc2 with zeros to create a 5digit decimal needed in marc record to sort as numeric
3400 for ( 1 .. ( 5 - $pos ) ) {
3404 $lc2 = $extras . $lc2;
3405 return ( $lc1 . $lc2 );
3408 =head2 itemcalculator
3410 $cutterextra = itemcalculator( $dbh, $biblioitem, $callnumber );
3414 sub itemcalculator {
3415 my ( $dbh, $biblioitem, $callnumber ) = @_;
3418 "select classification, subclass from biblioitems where biblioitemnumber=?"
3421 $sth->execute($biblioitem);
3422 my ( $classification, $subclass ) = $sth->fetchrow;
3423 my $all = $classification . " " . $subclass;
3424 my $total = length($all);
3425 my $cutterextra = substr( $callnumber, $total - 1 );
3427 return $cutterextra;
3430 END { } # module clean-up code here (global destructor)
3438 Koha Developement team <info@koha.org>
3440 Paul POULAIN paul.poulain@free.fr
3442 Joshua Ferraro jmf@liblime.com
3448 # Revision 1.192 2007/03/29 13:30:31 tipaul
3450 # == Biblio.pm cleaning (useless) ==
3451 # * some sub declaration dropped
3452 # * removed modbiblio sub
3453 # * removed moditem sub
3454 # * removed newitems. It was used only in finishrecieve. Replaced by a Koha2Marc+AddItem, that is better.
3455 # * removed MARCkoha2marcItem
3456 # * removed MARCdelsubfield declaration
3457 # * removed MARCkoha2marcBiblio
3459 # == Biblio.pm cleaning (naming conventions) ==
3460 # * MARCgettagslib renamed to GetMarcStructure
3461 # * MARCgetitems renamed to GetMarcItem
3462 # * MARCfind_frameworkcode renamed to GetFrameworkCode
3463 # * MARCmarc2koha renamed to TransformMarcToKoha
3464 # * MARChtml2marc renamed to TransformHtmlToMarc
3465 # * MARChtml2xml renamed to TranformeHtmlToXml
3466 # * zebraop renamed to ModZebra
3469 # * removing MARC=OFF related scripts (in cataloguing directory)
3470 # * removed checkitems (function related to MARC=off feature, that is completly broken in head. If someone want to reintroduce it, hard work coming...)
3471 # * removed getitemsbybiblioitem (used only by MARC=OFF scripts, that is removed as well)
3473 # Revision 1.191 2007/03/29 09:42:13 tipaul
3474 # adding default value new feature into cataloguing. The system (definition) part has already been added by toins
3476 # Revision 1.190 2007/03/29 08:45:19 hdl
3477 # Deleting ignore_errors(1) pour MARC::Charset
3479 # Revision 1.189 2007/03/28 10:39:16 hdl
3480 # removing $dbh as a parameter in AuthoritiesMarc functions
3481 # And reporting all differences into the scripts taht relies on those functions.
3483 # Revision 1.188 2007/03/09 14:31:47 tipaul
3484 # rel_3_0 moved to HEAD
3486 # Revision 1.178.2.59 2007/02/28 10:01:13 toins
3487 # reporting bug fix from 2.2.7.1 to rel_3_0
3489 # BUGFIX/improvement : limiting MARCsubject to 610 as 676 is dewey, and is somewhere else
3491 # Revision 1.178.2.58 2007/02/05 16:50:01 toins
3492 # fix a mod_perl bug:
3493 # There was a global var modified into an internal function in {MARC|ISBD}detail.pl.
3494 # Moving this function in Biblio.pm
3496 # Revision 1.178.2.57 2007/01/25 09:37:58 tipaul
3499 # Revision 1.178.2.56 2007/01/24 13:50:26 tipaul
3501 # removing newbiblio & newbiblioitems subs.
3504 # IMHO, all biblio handling is better handled if they are done in a single place, the subs with MARC::Record as parameters.
3505 # newbiblio & newbiblioitems where koha 1.x subs, that are called when MARC=OFF (which is not working anymore in koha 3.0, unless someone reintroduce it), and in acquisition module.
3506 # The Koha2Marc sub moves a hash (with biblio/biblioitems subfield as keys) into a MARC::Record, that can be used to call NewBiblio, the standard biblio manager sub.
3508 # Revision 1.178.2.55 2007/01/17 18:07:17 alaurin
3509 # bugfixing for zebraqueue_start and biblio.pm :
3511 # - Zebraqueue_start : restoring function of deletion in zebraqueue DB list
3513 # -biblio.pm : changing method of default_record_format, now we have :
3514 # MARC::File::XML->default_record_format(C4::Context->preference('marcflavour'));
3516 # with this line the encoding in zebra seems to be ok (in unimarc and marc21)
3518 # Revision 1.178.2.54 2007/01/16 15:00:03 tipaul
3519 # donc try to delete the biblio in koha, just fill zebraqueue table !
3521 # Revision 1.178.2.53 2007/01/16 10:24:11 tipaul
3523 # when modifying or deleting an item, the biblio frameworkcode was emptied.
3525 # Revision 1.178.2.52 2007/01/15 17:20:55 toins
3526 # *** empty log message ***
3528 # Revision 1.178.2.51 2007/01/15 15:16:44 hdl
3529 # Uncommenting ModZebra.
3531 # Revision 1.178.2.50 2007/01/15 14:59:09 hdl
3532 # Adding creation of an unexpected serial any time.
3534 # USING Date::Calc and not Date::Manip.
3535 # WARNING : There are still some Bugs in next issue date management. (Date::Calc donot wrap easily next year calculation.)
3537 # Revision 1.178.2.49 2007/01/12 10:12:30 toins
3538 # writing $record->as_formatted in the log when Modifying an item.
3540 # Revision 1.178.2.48 2007/01/11 16:33:04 toins
3541 # write $record->as_formatted into the log.
3543 # Revision 1.178.2.47 2007/01/10 16:46:27 toins
3544 # Theses modules need to use C4::Log.
3546 # Revision 1.178.2.46 2007/01/10 16:31:15 toins
3547 # new systems preferences :
3548 # - CataloguingLog (log the update/creation/deletion of a notice if set to 1)
3549 # - BorrowersLog ( idem for borrowers )
3550 # - IssueLog (log all issue if set to 1)
3551 # - ReturnLog (log all return if set to 1)
3552 # - SusbcriptionLog (log all creation/deletion/update of a subcription)
3554 # All of theses are in a new tab called 'LOGFeatures' in systempreferences.pl
3556 # Revision 1.178.2.45 2007/01/09 10:31:09 toins
3557 # sync with dev_week. ( new function : GetMarcSeries )
3559 # Revision 1.178.2.44 2007/01/04 17:41:32 tipaul
3560 # 2 major bugfixes :
3561 # - deletion of an item deleted the whole biblio because of a wrong API
3562 # - create an item was bugguy for default framework
3564 # Revision 1.178.2.43 2006/12/22 15:09:53 toins
3565 # removing C4::Database;
3567 # Revision 1.178.2.42 2006/12/20 16:51:00 tipaul
3569 # - adding a new table : when a biblio is added/modified/ deleted, an entry is entered in this table
3570 # - the zebraqueue_start.pl script read it & does the stuff.
3572 # code coming from head (tumer). it can be run every minut instead of once every day for dev_week code.
3574 # I just have commented the previous code (=real time update) in Biblio.pm, we will be able to reactivate it once indexdata fixes zebra update bug !
3576 # Revision 1.178.2.41 2006/12/20 08:54:44 toins
3577 # GetXmlBiblio wasn't exported.
3579 # Revision 1.178.2.40 2006/12/19 16:45:56 alaurin
3580 # bugfixing, for zebra and authorities
3582 # Revision 1.178.2.39 2006/12/08 17:55:44 toins
3583 # GetMarcAuthors now get authors for all subfields
3585 # Revision 1.178.2.38 2006/12/07 15:42:14 toins
3586 # synching opac & intranet.
3587 # fix some broken link & bugs.
3588 # removing warn compilation.
3590 # Revision 1.178.2.37 2006/12/07 11:09:39 tipaul
3592 # the ->destroy() line destroys the zebra connection. When we are running koha as cgi, it's not a problem, as the script dies after each request.
3593 # BUT for bulkmarcimport & mod_perl, the zebra conn must be persistant.
3595 # Revision 1.178.2.36 2006/12/06 16:54:21 alaurin
3596 # restore function ModZebra for delete biblios :
3598 # 1) restore C4::Circulation::Circ2::itemissues, (was missing)
3599 # 2) restore ModZebra value : delete_record
3601 # Revision 1.178.2.35 2006/12/06 10:02:12 alaurin
3602 # bugfixing for delete a biblio :
3604 # restore itemissue fonction .... :
3606 # other is pointed, zebra error 224... for biblio is not deleted in zebra ..
3609 # Revision 1.178.2.34 2006/12/06 09:14:25 toins
3610 # Correct the link to the MARC subjects.
3612 # Revision 1.178.2.33 2006/12/05 11:35:29 toins
3613 # Biblio.pm cleaned.
3614 # additionalauthors, bibliosubject, bibliosubtitle tables are now unused.
3615 # Some functions renamed according to the coding guidelines.
3617 # Revision 1.178.2.32 2006/12/04 17:39:57 alaurin
3620 # restore ModZebra for update zebra
3622 # Revision 1.178.2.31 2006/12/01 17:00:19 tipaul
3623 # additem needs $frameworkcode
3625 # Revision 1.178.2.30 2006/11/30 18:23:51 toins
3626 # theses scripts don't need to use C4::Search.
3628 # Revision 1.178.2.29 2006/11/30 17:17:01 toins
3629 # following functions moved from Search.p to Biblio.pm :
3636 # Revision 1.178.2.28 2006/11/28 15:15:03 toins
3637 # sync with dev_week.
3638 # (deleteditems table wasn't getting populaated because the execute was commented out. This puts it back
3639 # -- some table changes are needed as well, I'll commit those separately.)
3641 # Revision 1.178.2.27 2006/11/20 16:52:05 alaurin
3644 # correcting in _koha_modify_biblioitem : restore the biblionumber line .
3646 # now the sql update of biblioitems is ok ....
3648 # Revision 1.178.2.26 2006/11/17 14:57:21 tipaul
3649 # code cleaning : moving bornum, borrnum, bornumber to a correct "borrowernumber"
3651 # Revision 1.178.2.25 2006/11/17 13:18:58 tipaul
3652 # code cleaning : removing use of "bib", and replacing with "biblionumber"
3654 # WARNING : I tried to do carefully, but there are probably some mistakes.
3655 # So if you encounter a problem you didn't have before, look for this change !!!
3656 # anyway, I urge everybody to use only "biblionumber", instead of "bib", "bi", "biblio" or anything else. will be easier to maintain !!!
3658 # Revision 1.178.2.24 2006/11/17 11:18:47 tipaul
3659 # * removing useless subs
3660 # * moving bibid to biblionumber where needed
3662 # Revision 1.178.2.23 2006/11/17 09:39:04 btoumi
3663 # bug fix double declaration of variable in same function
3665 # Revision 1.178.2.22 2006/11/15 15:15:50 hdl
3666 # Final First Version for New Facility for subscription management.
3669 # use serials-collection.pl for history display
3670 # and serials-edit.pl for serial edition
3671 # subscription add and detail adds a new branch information to help IndependantBranches Library to manage different subscriptions for a serial
3673 # This is aimed at replacing serials-receive and statecollection.
3675 # Revision 1.178.2.21 2006/11/15 14:49:38 tipaul
3676 # in some cases, there are invalid utf8 chars in XML (at least in SANOP). this commit remove them on the fly.
3677 # Not sure it's a good idea to keep them in biblio.pm, let me know your opinion on koha-devel if you think it's a bad idea...
3679 # Revision 1.178.2.20 2006/10/31 17:20:49 toins
3680 # * moving bibitemdata from search to here.
3681 # * using _koha_modify_biblio instead of OLDmodbiblio.
3683 # Revision 1.178.2.19 2006/10/20 15:26:41 toins
3684 # sync with dev_week.
3686 # Revision 1.178.2.18 2006/10/19 11:57:04 btoumi
3687 # bug fix : wrong syntax in sub call
3689 # Revision 1.178.2.17 2006/10/17 09:54:42 toins
3690 # ccode (re)-integration.
3692 # Revision 1.178.2.16 2006/10/16 16:20:34 toins
3693 # MARCgetbiblio cleaned up.
3695 # Revision 1.178.2.15 2006/10/11 14:26:56 tipaul
3696 # handling of UNIMARC :
3697 # - better management of field 100 = automatic creation of the field if needed & filling encoding to unicode.
3698 # - better management of encoding (MARC::File::XML new_from_xml()). This fix works only on my own version of M:F:XML, i think the actual one is buggy & have reported the problem to perl4lib mailing list
3699 # - fixing a bug on GetMarcItem, that uses biblioitems.marc and not biblioitems.marcxml
3701 # Revision 1.178.2.14 2006/10/11 07:59:36 tipaul
3702 # removing hardcoded ccode fiels in biblioitems
3704 # Revision 1.178.2.13 2006/10/10 14:21:24 toins
3705 # Biblio.pm now returns a true value.
3707 # Revision 1.178.2.12 2006/10/09 16:44:23 toins
3708 # Sync with dev_week.
3710 # Revision 1.178.2.11 2006/10/06 13:23:49 toins
3711 # Synch with dev_week.
3713 # Revision 1.178.2.10 2006/10/02 09:32:02 hdl
3714 # Adding GetItemStatus and GetItemLocation function in order to make serials-receive.pl work.
3716 # *************WARNING.***************
3717 # tested for UNIMARC and using 'marcflavour' system preferences to set defaut_record_format.
3719 # Revision 1.178.2.9 2006/09/26 07:54:20 hdl
3720 # Bug FIX: Correct accents for UNIMARC biblio MARC details.
3721 # (Adding the use of default_record_format in MARCgetbiblio if UNIMARC marcflavour is chosen. This should be widely used as soon as we use xml records)
3723 # Revision 1.178.2.8 2006/09/25 14:46:22 hdl
3724 # Now using iso2709 MARC data for MARC.
3725 # (Works better for accents than XML)
3727 # Revision 1.178.2.7 2006/09/20 13:44:14 hdl
3728 # Bug Fixing : Cataloguing was broken for UNIMARC.