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
62 &GetAuthorisedValueDesc
79 # Marc related functions
81 &MARCfind_marc_from_kohafield
82 &MARCfind_frameworkcode
108 &PrepareItemrecordDisplay
126 C4::Biblio - acquisitions and cataloging management functions
130 Biblio.pm contains functions for managing storage and editing of bibliographic data within Koha. Most of the functions in this module are used for cataloging records: adding, editing, or removing biblios, biblioitems, or items. Koha's stores bibliographic information in three places:
134 =item 1. in the biblio,biblioitems,items, etc tables, which are limited to a one-to-one mapping to underlying MARC data
136 =item 2. as raw MARC in the Zebra index and storage engine
138 =item 3. as raw MARC the biblioitems.marc
142 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.
144 Because the data isn't completely normalized there's a chance for information to get out of sync. The design choice to go with a un-normalized schema was driven by performance and stability concerns:
148 =item 1. Compared with MySQL, Zebra is slow to update an index for small data changes -- especially for proc-intensive operations like circulation
150 =item 2. Zebra's index has been known to crash and a backup of the data is necessary to rebuild it in such cases
154 Because of this design choice, the process of managing storage and editing is a bit convoluted. Historically, Biblio.pm's grown to an unmanagable size and as a result we have several types of functions currently:
158 =item 1. Add*/Mod*/Del*/ - high-level external functions suitable for being called from external scripts to manage the collection
160 =item 2. _koha_* - low-level internal functions for managing the koha tables
162 =item 3. MARC* functions for interacting with the MARC data in both biblioitems.marc Zebra (biblioitems.marc is authoritative)
164 =item 4. Zebra functions used to update the Zebra index
166 =item 5. internal helper functions such as char_decode, checkitems, etc. Some of these probably belong in Koha.pm
168 =item 6. other functions that don't belong in Biblio.pm that will be cleaned out in time. (like MARCfind_marc_from_kohafield which belongs in Search.pm)
170 In time, as we solidify the new API these older functions will be weeded out.
174 =head1 EXPORTED FUNCTIONS
178 ($biblionumber,$biblioitemnumber) = AddBiblio($record,$frameworkcode);
180 Exported function (core API) for adding a new biblio to koha.
185 my ( $record, $frameworkcode ) = @_;
188 my $dbh = C4::Context->dbh;
189 # transform the data into koha-table style data
190 my $olddata = MARCmarc2koha( $dbh, $record, $frameworkcode );
191 $oldbibnum = _koha_add_biblio( $dbh, $olddata, $frameworkcode );
192 $olddata->{'biblionumber'} = $oldbibnum;
193 $oldbibitemnum = _koha_add_biblioitem( $dbh, $olddata );
195 # we must add bibnum and bibitemnum in MARC::Record...
196 # we build the new field with biblionumber and biblioitemnumber
197 # we drop the original field
198 # we add the new builded field.
199 # NOTE : Works only if the field is ONLY for biblionumber and biblioitemnumber
200 # (steve and paul : thinks 090 is a good choice)
203 "SELECT tagfield,tagsubfield
204 FROM marc_subfield_structure
207 $sth->execute("biblio.biblionumber");
208 ( my $tagfield1, my $tagsubfield1 ) = $sth->fetchrow;
209 $sth->execute("biblioitems.biblioitemnumber");
210 ( my $tagfield2, my $tagsubfield2 ) = $sth->fetchrow;
214 # biblionumber & biblioitemnumber are in different fields
215 if ( $tagfield1 != $tagfield2 ) {
217 # deal with biblionumber
218 if ( $tagfield1 < 10 ) {
219 $newfield = MARC::Field->new( $tagfield1, $oldbibnum, );
223 MARC::Field->new( $tagfield1, '', '',
224 "$tagsubfield1" => $oldbibnum, );
227 # drop old field and create new one...
228 my $old_field = $record->field($tagfield1);
229 $record->delete_field($old_field);
230 $record->append_fields($newfield);
232 # deal with biblioitemnumber
233 if ( $tagfield2 < 10 ) {
234 $newfield = MARC::Field->new( $tagfield2, $oldbibitemnum, );
238 MARC::Field->new( $tagfield2, '', '',
239 "$tagsubfield2" => $oldbibitemnum, );
241 # drop old field and create new one...
242 $old_field = $record->field($tagfield2);
243 $record->delete_field($old_field);
244 $record->insert_fields_ordered($newfield);
246 # biblionumber & biblioitemnumber are in the same field (can't be <10 as fields <10 have only 1 value)
249 my $newfield = MARC::Field->new(
251 "$tagsubfield1" => $oldbibnum,
252 "$tagsubfield2" => $oldbibitemnum
255 # drop old field and create new one...
256 my $old_field = $record->field($tagfield1);
257 $record->delete_field($old_field);
258 $record->insert_fields_ordered($newfield);
261 ###NEU specific add cataloguers cardnumber as well
262 my $cardtag = C4::Context->preference('cataloguersfield');
264 my $tag = substr( $cardtag, 0, 3 );
265 my $subf = substr( $cardtag, 3, 1 );
266 my $me = C4::Context->userenv;
267 my $cataloger = $me->{'cardnumber'} if ($me);
268 my $newtag = MARC::Field->new( $tag, '', '', $subf => $cataloger )
270 $record->delete_field($newtag);
271 $record->insert_fields_ordered($newtag);
276 MARCaddbiblio( $record, $oldbibnum, $frameworkcode );
278 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","ADD",$biblionumber,"biblio")
279 if C4::Context->preference("CataloguingLog");
281 return ( $biblionumber, $oldbibitemnum );
286 $biblionumber = AddItem( $record, $biblionumber)
288 Exported function (core API) for adding a new item to Koha
293 my ( $record, $biblionumber ) = @_;
294 my $dbh = C4::Context->dbh;
297 my $frameworkcode = MARCfind_frameworkcode( $biblionumber );
298 my $item = &MARCmarc2koha( $dbh, $record, $frameworkcode );
300 # needs old biblionumber and biblioitemnumber
301 $item->{'biblionumber'} = $biblionumber;
304 "select biblioitemnumber,itemtype from biblioitems where biblionumber=?"
306 $sth->execute( $item->{'biblionumber'} );
308 ( $item->{'biblioitemnumber'}, $itemtype ) = $sth->fetchrow;
311 "select notforloan from itemtypes where itemtype='$itemtype'");
313 my $notforloan = $sth->fetchrow;
314 ##Change the notforloan field if $notforloan found
315 if ( $notforloan > 0 ) {
316 $item->{'notforloan'} = $notforloan;
317 &MARCitemchange( $record, "items.notforloan", $notforloan );
319 if ( !$item->{'dateaccessioned'} || $item->{'dateaccessioned'} eq '' ) {
322 my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) =
327 "$year-" . sprintf( "%0.2d", $mon ) . "-" . sprintf( "%0.2d", $mday );
328 $item->{'dateaccessioned'} = $date;
329 &MARCitemchange( $record, "items.dateaccessioned", $date );
331 my ( $itemnumber, $error ) =
332 &_koha_new_items( $dbh, $item, $item->{barcode} );
334 # add itemnumber to MARC::Record before adding the item.
337 "select tagfield,tagsubfield from marc_subfield_structure where frameworkcode=? and kohafield=?"
339 &MARCkoha2marcOnefield( $sth, $record, "items.itemnumber", $itemnumber,
342 ##NEU specific add cataloguers cardnumber as well
343 my $cardtag = C4::Context->preference('itemcataloguersubfield');
345 $sth->execute( $frameworkcode, "items.itemnumber" );
346 my ( $itemtag, $subtag ) = $sth->fetchrow;
347 my $me = C4::Context->userenv;
348 my $cataloguer = $me->{'cardnumber'} if ($me);
349 my $newtag = $record->field($itemtag);
350 $newtag->update( $cardtag => $cataloguer ) if ($me);
351 $record->delete_field($newtag);
352 $record->append_fields($newtag);
356 &MARCadditem( $record, $item->{'biblionumber'},$frameworkcode );
358 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","ADD",$itemnumber,"item")
359 if C4::Context->preference("CataloguingLog");
361 return ($item->{biblionumber}, $item->{biblioitemnumber},$itemnumber);
366 ModBiblio( $record,$biblionumber,$frameworkcode);
368 Exported function (core API) to modify a biblio
373 my ( $record, $biblionumber, $frameworkcode ) = @_;
375 if (C4::Context->preference("CataloguingLog")) {
376 my $newrecord = GetMarcBiblio($biblionumber);
377 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","MODIFY",$biblionumber,$newrecord->as_formatted)
380 my $dbh = C4::Context->dbh;
382 $frameworkcode = "" unless $frameworkcode;
384 # update the MARC record with the new record data
385 &MARCmodbiblio( $dbh, $biblionumber, $record, $frameworkcode, 1 );
387 # load the koha-table data object
388 my $oldbiblio = MARCmarc2koha( $dbh, $record, $frameworkcode );
390 # modify the other koha tables
391 my $oldbiblionumber = _koha_modify_biblio( $dbh, $oldbiblio );
392 _koha_modify_biblioitem( $dbh, $oldbiblio );
399 Exported function (core API) for modifying an item in Koha.
404 my ( $record, $biblionumber, $itemnumber, $delete, $new_item_hashref )
408 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","MODIFY",$itemnumber,$record->as_formatted)
409 if C4::Context->preference("CataloguingLog");
411 my $dbh = C4::Context->dbh;
413 # if we have a MARC record, we're coming from cataloging and so
414 # we do the whole routine: update the MARC and zebra, then update the koha
417 my $frameworkcode = MARCfind_frameworkcode( $biblionumber );
418 MARCmoditem( $record, $biblionumber, $itemnumber, $frameworkcode, $delete );
419 my $olditem = MARCmarc2koha( $dbh, $record, $frameworkcode );
420 _koha_modify_item( $dbh, $olditem );
421 return $biblionumber;
424 # otherwise, we're just looking to modify something quickly
425 # (like a status) so we just update the koha tables
426 elsif ($new_item_hashref) {
427 _koha_modify_item( $dbh, $new_item_hashref );
431 =head2 ModBiblioframework
433 ModBiblioframework($biblionumber,$frameworkcode);
435 Exported function to modify a biblio framework
439 sub ModBiblioframework {
440 my ( $biblionumber, $frameworkcode ) = @_;
441 my $dbh = C4::Context->dbh;
444 "UPDATE biblio SET frameworkcode=? WHERE biblionumber=$biblionumber");
446 warn "IN ModBiblioframework";
447 $sth->execute($frameworkcode);
453 my $error = &DelBiblio($dbh,$biblionumber);
455 Exported function (core API) for deleting a biblio in koha.
457 Deletes biblio record from Zebra and Koha tables (biblio,biblioitems,items)
459 Also backs it up to deleted* tables
461 Checks to make sure there are not issues on any of the items
464 C<$error> : undef unless an error occurs
469 my ( $biblionumber ) = @_;
470 my $dbh = C4::Context->dbh;
471 my $error; # for error handling
473 # First make sure there are no items with issues are still attached
476 "SELECT biblioitemnumber FROM biblioitems WHERE biblionumber=?");
477 $sth->execute($biblionumber);
478 while ( my $biblioitemnumber = $sth->fetchrow ) {
479 my @issues = C4::Circulation::Circ2::itemissues($biblioitemnumber);
480 foreach my $issue (@issues) {
481 if ( ( $issue->{date_due} )
482 && ( $issue->{date_due} ne "Available" ) )
485 #FIXME: we need a status system in Biblio like in Circ to return standard codes and messages
486 # instead of hard-coded strings
488 "Item is checked out to a patron -- you must return it before deleting the Biblio";
492 return $error if $error;
495 zebraop($biblionumber,"delete_record","biblioserver");
497 # delete biblio from Koha tables and save in deletedbiblio
498 $error = &_koha_delete_biblio( $dbh, $biblionumber );
500 # delete biblioitems and items from Koha tables and save in deletedbiblioitems,deleteditems
503 "SELECT biblioitemnumber FROM biblioitems WHERE biblionumber=?");
504 $sth->execute($biblionumber);
505 while ( my $biblioitemnumber = $sth->fetchrow ) {
507 # delete this biblioitem
508 $error = &_koha_delete_biblioitems( $dbh, $biblioitemnumber );
509 return $error if $error;
514 "SELECT itemnumber FROM items WHERE biblioitemnumber=?");
515 $items_sth->execute($biblioitemnumber);
516 while ( my $itemnumber = $items_sth->fetchrow ) {
517 $error = &_koha_delete_items( $dbh, $itemnumber );
518 return $error if $error;
521 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","DELETE",$biblionumber,"")
522 if C4::Context->preference("CataloguingLog");
528 DelItem( $biblionumber, $itemnumber );
530 Exported function (core API) for deleting an item record in Koha.
535 my ( $biblionumber, $itemnumber ) = @_;
536 my $dbh = C4::Context->dbh;
537 &_koha_delete_item( $dbh, $itemnumber );
538 my $newrec = &MARCdelitem( $biblionumber, $itemnumber );
539 &MARCaddbiblio( $newrec, $biblionumber, MARCfind_frameworkcode($biblionumber) );
540 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","DELETE",$itemnumber,"item")
541 if C4::Context->preference("CataloguingLog");
546 $data = &GetBiblioData($biblionumber, $type);
548 Returns information about the book with the given biblionumber.
552 C<&GetBiblioData> returns a reference-to-hash. The keys are the fields in
553 the C<biblio> and C<biblioitems> tables in the
556 In addition, C<$data-E<gt>{subject}> is the list of the book's
557 subjects, separated by C<" , "> (space, comma, space).
559 If there are multiple biblioitems with the given biblionumber, only
560 the first one is considered.
566 my ( $bibnum, $type ) = @_;
567 my $dbh = C4::Context->dbh;
570 SELECT * , biblioitems.notes AS bnotes, biblio.notes
572 LEFT JOIN biblioitems ON biblio.biblionumber = biblioitems.biblionumber
573 LEFT JOIN itemtypes ON biblioitems.itemtype = itemtypes.itemtype
574 WHERE biblio.biblionumber = ?
575 AND biblioitems.biblionumber = biblio.biblionumber
577 my $sth = $dbh->prepare($query);
578 $sth->execute($bibnum);
580 $data = $sth->fetchrow_hashref;
584 } # sub GetBiblioData
589 @results = &GetItemsInfo($biblionumber, $type);
591 Returns information about books with the given biblionumber.
593 C<$type> may be either C<intra> or anything else. If it is not set to
594 C<intra>, then the search will exclude lost, very overdue, and
597 C<&GetItemsInfo> returns a list of references-to-hash. Each element
598 contains a number of keys. Most of them are table items from the
599 C<biblio>, C<biblioitems>, C<items>, and C<itemtypes> tables in the
600 Koha database. Other keys include:
604 =item C<$data-E<gt>{branchname}>
606 The name (not the code) of the branch to which the book belongs.
608 =item C<$data-E<gt>{datelastseen}>
610 This is simply C<items.datelastseen>, except that while the date is
611 stored in YYYY-MM-DD format in the database, here it is converted to
612 DD/MM/YYYY format. A NULL date is returned as C<//>.
614 =item C<$data-E<gt>{datedue}>
616 =item C<$data-E<gt>{class}>
618 This is the concatenation of C<biblioitems.classification>, the book's
619 Dewey code, and C<biblioitems.subclass>.
621 =item C<$data-E<gt>{ocount}>
623 I think this is the number of copies of the book available.
625 =item C<$data-E<gt>{order}>
627 If this is set, it is set to C<One Order>.
635 my ( $biblionumber, $type ) = @_;
636 my $dbh = C4::Context->dbh;
637 my $query = "SELECT *,items.notforloan as itemnotforloan
638 FROM items, biblio, biblioitems
639 LEFT JOIN itemtypes on biblioitems.itemtype = itemtypes.itemtype
640 WHERE items.biblionumber = ?
641 AND biblioitems.biblioitemnumber = items.biblioitemnumber
642 AND biblio.biblionumber = items.biblionumber
643 ORDER BY items.dateaccessioned desc
645 my $sth = $dbh->prepare($query);
646 $sth->execute($biblionumber);
649 my ( $date_due, $count_reserves );
651 while ( my $data = $sth->fetchrow_hashref ) {
653 my $isth = $dbh->prepare(
654 "SELECT issues.*,borrowers.cardnumber
655 FROM issues, borrowers
657 AND returndate IS NULL
658 AND issues.borrowernumber=borrowers.borrowernumber"
660 $isth->execute( $data->{'itemnumber'} );
661 if ( my $idata = $isth->fetchrow_hashref ) {
662 $data->{borrowernumber} = $idata->{borrowernumber};
663 $data->{cardnumber} = $idata->{cardnumber};
664 $datedue = format_date( $idata->{'date_due'} );
666 if ( $datedue eq '' ) {
667 #$datedue="Available";
668 my ( $restype, $reserves ) =
669 C4::Reserves2::CheckReserves( $data->{'itemnumber'} );
673 $count_reserves = $restype;
678 #get branch information.....
679 my $bsth = $dbh->prepare(
680 "SELECT * FROM branches WHERE branchcode = ?
683 $bsth->execute( $data->{'holdingbranch'} );
684 if ( my $bdata = $bsth->fetchrow_hashref ) {
685 $data->{'branchname'} = $bdata->{'branchname'};
687 my $date = format_date( $data->{'datelastseen'} );
688 $data->{'datelastseen'} = $date;
689 $data->{'datedue'} = $datedue;
690 $data->{'count_reserves'} = $count_reserves;
692 # get notforloan complete status if applicable
693 my $sthnflstatus = $dbh->prepare(
694 'SELECT authorised_value
695 FROM marc_subfield_structure
696 WHERE kohafield="items.notforloan"
700 $sthnflstatus->execute;
701 my ($authorised_valuecode) = $sthnflstatus->fetchrow;
702 if ($authorised_valuecode) {
703 $sthnflstatus = $dbh->prepare(
704 "SELECT lib FROM authorised_values
706 AND authorised_value=?"
708 $sthnflstatus->execute( $authorised_valuecode,
709 $data->{itemnotforloan} );
710 my ($lib) = $sthnflstatus->fetchrow;
711 $data->{notforloan} = $lib;
714 # my stack procedures
715 my $stackstatus = $dbh->prepare(
716 'SELECT authorised_value
717 FROM marc_subfield_structure
718 WHERE kohafield="items.stack"
721 $stackstatus->execute;
723 ($authorised_valuecode) = $stackstatus->fetchrow;
724 if ($authorised_valuecode) {
725 $stackstatus = $dbh->prepare(
727 FROM authorised_values
729 AND authorised_value=?
732 $stackstatus->execute( $authorised_valuecode, $data->{stack} );
733 my ($lib) = $stackstatus->fetchrow;
734 $data->{stack} = $lib;
736 $results[$i] = $data;
746 $itemstatushash = &getitemstatus($fwkcode);
747 returns information about status.
748 Can be MARC dependant.
750 But basically could be can be loan or not
751 Create a status selector with the following code
753 =head3 in PERL SCRIPT
755 my $itemstatushash = getitemstatus;
757 foreach my $thisstatus (keys %$itemstatushash) {
758 my %row =(value => $thisstatus,
759 statusname => $itemstatushash->{$thisstatus}->{'statusname'},
761 push @itemstatusloop, \%row;
763 $template->param(statusloop=>\@itemstatusloop);
767 <select name="statusloop">
768 <option value="">Default</option>
769 <!-- TMPL_LOOP name="statusloop" -->
770 <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="statusname" --></option>
778 # returns a reference to a hash of references to status...
781 my $dbh = C4::Context->dbh;
783 $fwk = '' unless ($fwk);
784 my ( $tag, $subfield ) =
785 MARCfind_marc_from_kohafield( $dbh, "items.notforloan", $fwk );
786 if ( $tag and $subfield ) {
789 "select authorised_value from marc_subfield_structure where tagfield=? and tagsubfield=? and frameworkcode=?"
791 $sth->execute( $tag, $subfield, $fwk );
792 if ( my ($authorisedvaluecat) = $sth->fetchrow ) {
795 "select authorised_value, lib from authorised_values where category=? order by lib"
797 $authvalsth->execute($authorisedvaluecat);
798 while ( my ( $authorisedvalue, $lib ) = $authvalsth->fetchrow ) {
799 $itemstatus{$authorisedvalue} = $lib;
815 $itemstatus{"1"} = "Not For Loan";
819 =head2 getitemlocation
821 $itemlochash = &getitemlocation($fwk);
822 returns informations about location.
823 where fwk stands for an optional framework code.
824 Create a location selector with the following code
826 =head3 in PERL SCRIPT
828 my $itemlochash = getitemlocation;
830 foreach my $thisloc (keys %$itemlochash) {
831 my $selected = 1 if $thisbranch eq $branch;
832 my %row =(locval => $thisloc,
833 selected => $selected,
834 locname => $itemlochash->{$thisloc},
836 push @itemlocloop, \%row;
838 $template->param(itemlocationloop => \@itemlocloop);
841 <select name="location">
842 <option value="">Default</option>
843 <!-- TMPL_LOOP name="itemlocationloop" -->
844 <option value="<!-- TMPL_VAR name="locval" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="locname" --></option>
850 sub GetItemLocation {
852 # returns a reference to a hash of references to location...
855 my $dbh = C4::Context->dbh;
857 $fwk = '' unless ($fwk);
858 my ( $tag, $subfield ) =
859 MARCfind_marc_from_kohafield( $dbh, "items.location", $fwk );
860 if ( $tag and $subfield ) {
863 "select authorised_value from marc_subfield_structure where tagfield=? and tagsubfield=? and frameworkcode=?"
865 $sth->execute( $tag, $subfield, $fwk );
866 if ( my ($authorisedvaluecat) = $sth->fetchrow ) {
869 "select authorised_value, lib from authorised_values where category=? order by lib"
871 $authvalsth->execute($authorisedvaluecat);
872 while ( my ( $authorisedvalue, $lib ) = $authvalsth->fetchrow ) {
873 $itemlocation{$authorisedvalue} = $lib;
876 return \%itemlocation;
889 $itemlocation{"1"} = "Not For Loan";
890 return \%itemlocation;
893 =head2 &GetBiblioItemData
895 $itemdata = &GetBiblioItemData($biblioitemnumber);
897 Looks up the biblioitem with the given biblioitemnumber. Returns a
898 reference-to-hash. The keys are the fields from the C<biblio>,
899 C<biblioitems>, and C<itemtypes> tables in the Koha database, except
900 that C<biblioitems.notes> is given as C<$itemdata-E<gt>{bnotes}>.
905 sub GetBiblioItemData {
907 my $dbh = C4::Context->dbh;
910 "Select *,biblioitems.notes as bnotes from biblioitems, biblio,itemtypes where biblio.biblionumber = biblioitems.biblionumber and biblioitemnumber = ? and biblioitems.itemtype = itemtypes.itemtype"
914 $sth->execute($bibitem);
916 $data = $sth->fetchrow_hashref;
920 } # sub &GetBiblioItemData
922 =head2 GetItemFromBarcode
924 $result = GetItemFromBarcode($barcode);
928 sub GetItemFromBarcode {
930 my $dbh = C4::Context->dbh;
933 $dbh->prepare("SELECT itemnumber from items where items.barcode=?");
934 $rq->execute($barcode);
935 my ($result) = $rq->fetchrow;
939 =head2 GetBiblioItemByBiblioNumber
941 NOTE : This function has been copy/paste from C4/Biblio.pm from head before zebra integration.
945 sub GetBiblioItemByBiblioNumber {
946 my ($biblionumber) = @_;
947 my $dbh = C4::Context->dbh;
948 my $sth = $dbh->prepare("Select * from biblioitems where biblionumber = ?");
952 $sth->execute($biblionumber);
954 while ( my $data = $sth->fetchrow_hashref ) {
955 push @results, $data;
962 =head2 GetBiblioFromItemNumber
964 $item = &GetBiblioFromItemNumber($itemnumber);
966 Looks up the item with the given itemnumber.
968 C<&itemnodata> returns a reference-to-hash whose keys are the fields
969 from the C<biblio>, C<biblioitems>, and C<items> tables in the Koha
975 sub GetBiblioFromItemNumber {
976 my ( $itemnumber ) = @_;
977 my $dbh = C4::Context->dbh;
979 my $sth = $dbh->prepare(
980 "SELECT * FROM biblio,items,biblioitems
981 WHERE items.itemnumber = ?
982 AND biblio.biblionumber = items.biblionumber
983 AND biblioitems.biblioitemnumber = items.biblioitemnumber"
986 $sth->execute($itemnumber);
987 my $data = $sth->fetchrow_hashref;
994 ( $count, @results ) = &GetBiblio($biblionumber);
999 my ($biblionumber) = @_;
1000 my $dbh = C4::Context->dbh;
1001 my $sth = $dbh->prepare("Select * from biblio where biblionumber = ?");
1004 $sth->execute($biblionumber);
1005 while ( my $data = $sth->fetchrow_hashref ) {
1006 $results[$count] = $data;
1010 return ( $count, @results );
1013 =head2 getitemsbybiblioitem
1015 ( $count, @results ) = &getitemsbybiblioitem($biblioitemnum);
1019 sub getitemsbybiblioitem {
1020 my ($biblioitemnum) = @_;
1021 my $dbh = C4::Context->dbh;
1022 my $sth = $dbh->prepare(
1023 "Select * from items, biblio where
1024 biblio.biblionumber = items.biblionumber and biblioitemnumber
1028 # || die "Cannot prepare $query\n" . $dbh->errstr;
1032 $sth->execute($biblioitemnum);
1034 # || die "Cannot execute $query\n" . $sth->errstr;
1035 while ( my $data = $sth->fetchrow_hashref ) {
1036 $results[$count] = $data;
1041 return ( $count, @results );
1042 } # sub getitemsbybiblioitem
1044 =head2 get_itemnumbers_of
1046 my @itemnumbers_of = get_itemnumbers_of(@biblionumbers);
1048 Given a list of biblionumbers, return the list of corresponding itemnumbers
1049 for each biblionumber.
1051 Return a reference on a hash where keys are biblionumbers and values are
1052 references on array of itemnumbers.
1056 sub get_itemnumbers_of {
1057 my @biblionumbers = @_;
1059 my $dbh = C4::Context->dbh;
1065 WHERE biblionumber IN (?' . ( ',?' x scalar @biblionumbers - 1 ) . ')
1067 my $sth = $dbh->prepare($query);
1068 $sth->execute(@biblionumbers);
1072 while ( my ( $itemnumber, $biblionumber ) = $sth->fetchrow_array ) {
1073 push @{ $itemnumbers_of{$biblionumber} }, $itemnumber;
1076 return \%itemnumbers_of;
1081 $record = getRecord( $server, $koha_query, $recordSyntax );
1083 get a single record in piggyback mode from Zebra and return it in the requested record syntax
1085 default record syntax is XML
1090 my ( $server, $koha_query, $recordSyntax ) = @_;
1091 $recordSyntax = "xml" unless $recordSyntax;
1092 my $Zconn = C4::Context->Zconn( $server, 0, 1, 1, $recordSyntax );
1093 my $rs = $Zconn->search( new ZOOM::Query::CCL2RPN( $koha_query, $Zconn ) );
1094 if ( $rs->record(0) ) {
1095 return $rs->record(0)->raw();
1099 =head2 GetItemInfosOf
1101 GetItemInfosOf(@itemnumbers);
1105 sub GetItemInfosOf {
1106 my @itemnumbers = @_;
1111 WHERE itemnumber IN (' . join( ',', @itemnumbers ) . ')
1113 return get_infos_of( $query, 'itemnumber' );
1116 =head2 GetBiblioItemInfosOf
1118 GetBiblioItemInfosOf(@biblioitemnumbers);
1122 sub GetBiblioItemInfosOf {
1123 my @biblioitemnumbers = @_;
1126 SELECT biblioitemnumber,
1130 WHERE biblioitemnumber IN (' . join( ',', @biblioitemnumbers ) . ')
1132 return get_infos_of( $query, 'biblioitemnumber' );
1135 =head2 z3950_extended_services
1137 z3950_extended_services($serviceType,$serviceOptions,$record);
1139 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.
1141 C<$serviceType> one of: itemorder,create,drop,commit,update,xmlupdate
1143 C<$serviceOptions> a has of key/value pairs. For instance, if service_type is 'update', $service_options should contain:
1145 action => update action, one of specialUpdate, recordInsert, recordReplace, recordDelete, elementUpdate.
1149 recordidOpaque => Opaque Record ID (user supplied) or recordidNumber => Record ID number (system number).
1150 syntax => the record syntax (transfer syntax)
1151 databaseName = Database from connection object
1153 To set serviceOptions, call set_service_options($serviceType)
1155 C<$record> the record, if one is needed for the service type
1157 A record should be in XML. You can convert it to XML from MARC by running it through marc2xml().
1161 sub z3950_extended_services {
1162 my ( $server, $serviceType, $action, $serviceOptions ) = @_;
1164 # get our connection object
1165 my $Zconn = C4::Context->Zconn( $server, 0, 1 );
1167 # create a new package object
1168 my $Zpackage = $Zconn->package();
1171 $Zpackage->option( action => $action );
1173 if ( $serviceOptions->{'databaseName'} ) {
1174 $Zpackage->option( databaseName => $serviceOptions->{'databaseName'} );
1176 if ( $serviceOptions->{'recordIdNumber'} ) {
1178 recordIdNumber => $serviceOptions->{'recordIdNumber'} );
1180 if ( $serviceOptions->{'recordIdOpaque'} ) {
1182 recordIdOpaque => $serviceOptions->{'recordIdOpaque'} );
1185 # this is an ILL request (Zebra doesn't support it, but Koha could eventually)
1186 #if ($serviceType eq 'itemorder') {
1187 # $Zpackage->option('contact-name' => $serviceOptions->{'contact-name'});
1188 # $Zpackage->option('contact-phone' => $serviceOptions->{'contact-phone'});
1189 # $Zpackage->option('contact-email' => $serviceOptions->{'contact-email'});
1190 # $Zpackage->option('itemorder-item' => $serviceOptions->{'itemorder-item'});
1193 if ( $serviceOptions->{record} ) {
1194 $Zpackage->option( record => $serviceOptions->{record} );
1196 # can be xml or marc
1197 if ( $serviceOptions->{'syntax'} ) {
1198 $Zpackage->option( syntax => $serviceOptions->{'syntax'} );
1202 # send the request, handle any exception encountered
1203 eval { $Zpackage->send($serviceType) };
1204 if ( $@ && $@->isa("ZOOM::Exception") ) {
1205 return "error: " . $@->code() . " " . $@->message() . "\n";
1208 # free up package resources
1209 $Zpackage->destroy();
1212 =head2 set_service_options
1214 my $serviceOptions = set_service_options($serviceType);
1216 C<$serviceType> itemorder,create,drop,commit,update,xmlupdate
1218 Currently, we only support 'create', 'commit', and 'update'. 'drop' support will be added as soon as Zebra supports it.
1222 sub set_service_options {
1223 my ($serviceType) = @_;
1226 # FIXME: This needs to be an OID ... if we ever need 'syntax' this sub will need to change
1227 # $serviceOptions->{ 'syntax' } = ''; #zebra doesn't support syntaxes other than xml
1229 if ( $serviceType eq 'commit' ) {
1233 if ( $serviceType eq 'create' ) {
1237 if ( $serviceType eq 'drop' ) {
1238 die "ERROR: 'drop' not currently supported (by Zebra)";
1240 return $serviceOptions;
1243 =head1 FUNCTIONS FOR HANDLING MARC MANAGEMENT
1245 =head2 MARCgettagslib
1249 sub MARCgettagslib {
1250 my ( $dbh, $forlibrarian, $frameworkcode ) = @_;
1251 $frameworkcode = "" unless $frameworkcode;
1253 my $libfield = ( $forlibrarian eq 1 ) ? 'liblibrarian' : 'libopac';
1255 # check that framework exists
1258 "select count(*) from marc_tag_structure where frameworkcode=?");
1259 $sth->execute($frameworkcode);
1260 my ($total) = $sth->fetchrow;
1261 $frameworkcode = "" unless ( $total > 0 );
1264 "select tagfield,liblibrarian,libopac,mandatory,repeatable from marc_tag_structure where frameworkcode=? order by tagfield"
1266 $sth->execute($frameworkcode);
1267 my ( $liblibrarian, $libopac, $tag, $res, $tab, $mandatory, $repeatable );
1269 while ( ( $tag, $liblibrarian, $libopac, $mandatory, $repeatable ) =
1272 $res->{$tag}->{lib} =
1273 ( $forlibrarian or !$libopac ) ? $liblibrarian : $libopac;
1274 $res->{$tab}->{tab} = ""; # XXX
1275 $res->{$tag}->{mandatory} = $mandatory;
1276 $res->{$tag}->{repeatable} = $repeatable;
1281 "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"
1283 $sth->execute($frameworkcode);
1286 my $authorised_value;
1298 $tag, $subfield, $liblibrarian,
1300 $mandatory, $repeatable, $authorised_value,
1301 $authtypecode, $value_builder, $kohafield,
1302 $seealso, $hidden, $isurl,
1308 $res->{$tag}->{$subfield}->{lib} =
1309 ( $forlibrarian or !$libopac ) ? $liblibrarian : $libopac;
1310 $res->{$tag}->{$subfield}->{tab} = $tab;
1311 $res->{$tag}->{$subfield}->{mandatory} = $mandatory;
1312 $res->{$tag}->{$subfield}->{repeatable} = $repeatable;
1313 $res->{$tag}->{$subfield}->{authorised_value} = $authorised_value;
1314 $res->{$tag}->{$subfield}->{authtypecode} = $authtypecode;
1315 $res->{$tag}->{$subfield}->{value_builder} = $value_builder;
1316 $res->{$tag}->{$subfield}->{kohafield} = $kohafield;
1317 $res->{$tag}->{$subfield}->{seealso} = $seealso;
1318 $res->{$tag}->{$subfield}->{hidden} = $hidden;
1319 $res->{$tag}->{$subfield}->{isurl} = $isurl;
1320 $res->{$tag}->{$subfield}->{link} = $link;
1321 $res->{$tag}->{$subfield}->{defaultvalue} = $defaultvalue;
1326 =head2 MARCfind_marc_from_kohafield
1330 sub MARCfind_marc_from_kohafield {
1331 my ( $dbh, $kohafield, $frameworkcode ) = @_;
1332 return 0, 0 unless $kohafield;
1333 my $relations = C4::Context->marcfromkohafield;
1335 $relations->{$frameworkcode}->{$kohafield}->[0],
1336 $relations->{$frameworkcode}->{$kohafield}->[1]
1340 =head2 MARCaddbiblio
1342 &MARCaddbiblio($newrec,$biblionumber,$frameworkcode);
1344 Add MARC data for a biblio to koha
1350 # pass the MARC::Record to this function, and it will create the records in the marc tables
1351 my ( $record, $biblionumber, $frameworkcode ) = @_;
1352 my $dbh = C4::Context->dbh;
1353 my @fields = $record->fields();
1354 if ( !$frameworkcode ) {
1355 $frameworkcode = "";
1358 $dbh->prepare("UPDATE biblio SET frameworkcode=? WHERE biblionumber=?");
1359 $sth->execute( $frameworkcode, $biblionumber );
1361 my $encoding = C4::Context->preference("marcflavour");
1363 # deal with UNIMARC field 100 (encoding) : create it if needed & set encoding to unicode
1364 if ( $encoding eq "UNIMARC" ) {
1366 if ( $record->subfield( 100, "a" ) ) {
1367 $string = $record->subfield( 100, "a" );
1368 my $f100 = $record->field(100);
1369 $record->delete_field($f100);
1372 $string = POSIX::strftime( "%Y%m%d", localtime );
1374 $string = sprintf( "%-*s", 35, $string );
1376 substr( $string, 22, 6, "frey50" );
1377 unless ( $record->subfield( 100, "a" ) ) {
1378 $record->insert_grouped_field(
1379 MARC::Field->new( 100, "", "", "a" => $string ) );
1382 # warn "biblionumber : ".$biblionumber;
1385 "update biblioitems set marc=?,marcxml=? where biblionumber=?");
1386 $sth->execute( $record->as_usmarc(), $record->as_xml_record(),
1388 # warn $record->as_xml_record();
1390 zebraop($biblionumber,"specialUpdate","biblioserver");
1391 return $biblionumber;
1396 $newbiblionumber = MARCadditem( $record, $biblionumber, $frameworkcode );
1402 # pass the MARC::Record to this function, and it will create the records in the marc tables
1403 my ( $record, $biblionumber, $frameworkcode ) = @_;
1404 my $newrec = &GetMarcBiblio($biblionumber);
1407 my @fields = $record->fields();
1408 foreach my $field (@fields) {
1409 $newrec->append_fields($field);
1412 # FIXME: should we be making sure the biblionumbers are the same?
1413 my $newbiblionumber =
1414 &MARCaddbiblio( $newrec, $biblionumber, $frameworkcode );
1415 return $newbiblionumber;
1418 =head2 GetMarcBiblio
1420 Returns MARC::Record of the biblionumber passed in parameter.
1425 my $biblionumber = shift;
1426 my $dbh = C4::Context->dbh;
1428 $dbh->prepare("select marcxml from biblioitems where biblionumber=? ");
1429 $sth->execute($biblionumber);
1430 my ($marcxml) = $sth->fetchrow;
1431 # warn "marcxml : $marcxml";
1432 MARC::File::XML->default_record_format(C4::Context->preference('marcflavour'));
1433 $marcxml =~ s/\x1e//g;
1434 $marcxml =~ s/\x1f//g;
1435 $marcxml =~ s/\x1d//g;
1436 $marcxml =~ s/\x0f//g;
1437 $marcxml =~ s/\x0c//g;
1438 my $record = MARC::Record->new();
1439 $record = MARC::Record::new_from_xml( $marcxml, "utf8",C4::Context->preference('marcflavour')) if $marcxml;
1445 my $marcxml = GetXmlBiblio($biblionumber);
1447 Returns biblioitems.marcxml of the biblionumber passed in parameter.
1452 my ( $biblionumber ) = @_;
1453 my $dbh = C4::Context->dbh;
1455 $dbh->prepare("select marcxml from biblioitems where biblionumber=? ");
1456 $sth->execute($biblionumber);
1457 my ($marcxml) = $sth->fetchrow;
1461 =head2 GetAuthorisedValueDesc
1463 my $subfieldvalue =get_authorised_value_desc(
1464 $tag, $subf[$i][0],$subf[$i][1], '', $taglib);
1468 sub GetAuthorisedValueDesc {
1469 my ( $tag, $subfield, $value, $framework, $tagslib ) = @_;
1470 my $dbh = C4::Context->dbh;
1473 if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq "branches" ) {
1474 return C4::Branch::GetBranchName($value);
1478 if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq "itemtypes" ) {
1479 return getitemtypeinfo($value);
1482 #---- "true" authorized value
1483 my $category = $tagslib->{$tag}->{$subfield}->{'authorised_value'};
1485 if ( $category ne "" ) {
1488 "select lib from authorised_values where category = ? and authorised_value = ?"
1490 $sth->execute( $category, $value );
1491 my $data = $sth->fetchrow_hashref;
1492 return $data->{'lib'};
1495 return $value; # if nothing is found return the original value
1501 Returns MARC::Record of the item passed in parameter.
1506 my ( $biblionumber, $itemnumber ) = @_;
1507 my $dbh = C4::Context->dbh;
1508 my $newrecord = MARC::Record->new();
1509 my $marcflavour = C4::Context->preference('marcflavour');
1511 my $marcxml = GetXmlBiblio($biblionumber);
1512 my $record = MARC::Record->new();
1513 # warn "marcxml :$marcxml";
1514 $record = MARC::Record::new_from_xml( $marcxml, "utf8", $marcflavour );
1515 # warn "record :".$record->as_formatted;
1516 # now, find where the itemnumber is stored & extract only the item
1517 my ( $itemnumberfield, $itemnumbersubfield ) =
1518 MARCfind_marc_from_kohafield( $dbh, 'items.itemnumber', '' );
1519 my @fields = $record->field($itemnumberfield);
1520 foreach my $field (@fields) {
1521 if ( $field->subfield($itemnumbersubfield) eq $itemnumber ) {
1522 $newrecord->insert_fields_ordered($field);
1530 $marcnotesarray = GetMarcNotes( $record, $marcflavour );
1532 get a single record in piggyback mode from Zebra and return it in the requested record syntax
1534 default record syntax is XML
1539 my ( $record, $marcflavour ) = @_;
1541 if ( $marcflavour eq "MARC21" ) {
1544 else { # assume unimarc if not marc21
1551 foreach my $field ( $record->field($scope) ) {
1552 my $value = $field->as_string();
1553 if ( $note ne "" ) {
1554 $marcnote = { marcnote => $note, };
1555 push @marcnotes, $marcnote;
1558 if ( $note ne $value ) {
1559 $note = $note . " " . $value;
1564 $marcnote = { marcnote => $note };
1565 push @marcnotes, $marcnote; #load last tag into array
1568 } # end GetMarcNotes
1570 =head2 GetMarcSubjects
1572 $marcsubjcts = GetMarcSubjects($record,$marcflavour);
1576 sub GetMarcSubjects {
1577 my ( $record, $marcflavour ) = @_;
1578 my ( $mintag, $maxtag );
1579 if ( $marcflavour eq "MARC21" ) {
1583 else { # assume unimarc if not marc21
1590 foreach my $field ( $record->fields ) {
1591 next unless $field->tag() >= $mintag && $field->tag() <= $maxtag;
1592 my @subfields = $field->subfields();
1596 for my $subject_subfield ( @subfields ) {
1597 my $code = $subject_subfield->[0];
1598 $label .= $subject_subfield->[1] . " and su-to:" unless ( $code == 9 );
1600 $link = "Koha-Auth-Number:".$subject_subfield->[1];
1605 $link =~ s/ and\ssu-to:$//;
1618 return \@marcsubjcts;
1619 } #end GetMarcSubjects
1621 =head2 GetMarcAuthors
1623 authors = GetMarcAuthors($record,$marcflavour);
1627 sub GetMarcAuthors {
1628 my ( $record, $marcflavour ) = @_;
1629 my ( $mintag, $maxtag );
1630 if ( $marcflavour eq "MARC21" ) {
1634 else { # assume unimarc if not marc21
1641 foreach my $field ( $record->fields ) {
1642 next unless $field->tag() >= $mintag && $field->tag() <= $maxtag;
1644 my @subfields = $field->subfields();
1647 for my $authors_subfield (@subfields) {
1648 if ($count_auth ne '0'){
1652 my $subfieldcode = $authors_subfield->[0];
1653 my $value = $authors_subfield->[1];
1654 $hash{'tag'} = $field->tag;
1655 $hash{value} .= $value . " " if ($subfieldcode != 9) ;
1656 $hash{link} .= $value if ($subfieldcode eq 9);
1658 push @marcauthors, \%hash;
1660 return \@marcauthors;
1663 =head2 GetMarcSeries
1665 $marcseriessarray = GetMarcSeries($record,$marcflavour);
1670 my ($record, $marcflavour) = @_;
1671 my ($mintag, $maxtag);
1672 if ($marcflavour eq "MARC21") {
1675 } else { # assume unimarc if not marc21
1685 foreach my $field ($record->field('440'), $record->field('490')) {
1687 #my $value = $field->subfield('a');
1688 #$marcsubjct = {MARCSUBJCT => $value,};
1689 my @subfields = $field->subfields();
1690 #warn "subfields:".join " ", @$subfields;
1693 for my $series_subfield (@subfields) {
1695 undef $volume_number;
1696 # see if this is an instance of a volume
1697 if ($series_subfield->[0] eq 'v') {
1701 my $code = $series_subfield->[0];
1702 my $value = $series_subfield->[1];
1703 my $linkvalue = $value;
1704 $linkvalue =~ s/(\(|\))//g;
1705 my $operator = " and " unless $counter==0;
1706 push @link_loop, {link => $linkvalue, operator => $operator };
1707 my $separator = C4::Context->preference("authoritysep") unless $counter==0;
1708 if ($volume_number) {
1709 push @subfields_loop, {volumenum => $value};
1712 push @subfields_loop, {code => $code, value => $value, link_loop => \@link_loop, separator => $separator, volumenum => $volume_number};
1716 push @marcseries, { MARCSERIES_SUBFIELDS_LOOP => \@subfields_loop };
1717 #$marcsubjct = {MARCSUBJCT => $field->as_string(),};
1718 #push @marcsubjcts, $marcsubjct;
1722 my $marcseriessarray=\@marcseries;
1723 return $marcseriessarray;
1724 } #end getMARCseriess
1726 =head2 MARCmodbiblio
1728 MARCmodbibio($dbh,$biblionumber,$record,$frameworkcode,1);
1730 Modify a biblio record with the option to save items data
1735 my ( $dbh, $biblionumber, $record, $frameworkcode, $keep_items ) = @_;
1737 # delete original record but save the items
1738 my $newrec = &MARCdelbiblio( $biblionumber, $keep_items );
1740 # recreate it and add the new fields
1741 my @fields = $record->fields();
1742 foreach my $field (@fields) {
1744 # this requires a more recent version of MARC::Record
1745 # but ensures the fields are in order
1746 $newrec->insert_fields_ordered($field);
1749 # give back our old leader
1750 $newrec->leader( $record->leader() );
1752 # add the record back with the items info preserved
1753 &MARCaddbiblio( $newrec, $biblionumber, $frameworkcode );
1756 =head2 MARCdelbiblio
1758 &MARCdelbiblio( $biblionumber, $keep_items )
1760 if the keep_item is set to 1, then all items are preserved.
1761 This flag is set when the delbiblio is called by modbiblio
1762 due to a too complex structure of MARC (repeatable fields and subfields),
1763 the best solution for a modif is to delete / recreate the record.
1765 1st of all, copy the MARC::Record to deletedbiblio table => if a true deletion, MARC data will be kept.
1766 if deletion called before MARCmodbiblio => won't do anything, as the oldbiblionumber doesn't
1767 exist in deletedbiblio table
1772 my ( $biblionumber, $keep_items ) = @_;
1773 my $dbh = C4::Context->dbh;
1775 my $record = GetMarcBiblio($biblionumber);
1776 my $oldbiblionumber = $biblionumber;
1778 $dbh->prepare("update deletedbiblio set marc=? where biblionumber=?");
1779 $copy2deleted->execute( $record->as_usmarc(), $oldbiblionumber );
1780 my @fields = $record->fields();
1782 # now, delete in MARC tables.
1783 if ( $keep_items eq 1 ) {
1784 #search item field code
1787 "select tagfield from marc_subfield_structure where kohafield like 'items.%'"
1790 my $itemtag = $sth->fetchrow_hashref->{tagfield};
1792 foreach my $field (@fields) {
1794 if ( $field->tag() ne $itemtag ) {
1795 $record->delete_field($field);
1800 foreach my $field (@fields) {
1802 $record->delete_field($field);
1810 MARCdelitem( $biblionumber, $itemnumber )
1812 delete the item field from the MARC record for the itemnumber specified
1817 my ( $biblionumber, $itemnumber ) = @_;
1818 my $dbh = C4::Context->dbh;
1820 # get the MARC record
1821 my $record = GetMarcBiblio($biblionumber);
1825 $dbh->prepare("UPDATE deleteditems SET marc=? WHERE itemnumber=?");
1826 $copy2deleted->execute( $record->as_usmarc(), $itemnumber );
1828 #search item field code
1831 "SELECT tagfield,tagsubfield FROM marc_subfield_structure WHERE kohafield LIKE 'items.itemnumber'"
1834 my ( $itemtag, $itemsubfield ) = $sth->fetchrow;
1835 my @fields = $record->field($itemtag);
1836 # delete the item specified
1837 foreach my $field (@fields) {
1838 if ( $field->subfield($itemsubfield) eq $itemnumber ) {
1839 $record->delete_field($field);
1845 =head2 MARCmoditemonefield
1847 &MARCmoditemonefield( $biblionumber, $itemnumber, $itemfield, $newvalue )
1851 sub MARCmoditemonefield {
1852 my ( $biblionumber, $itemnumber, $itemfield, $newvalue ) = @_;
1853 my $dbh = C4::Context->dbh;
1854 if ( !defined $newvalue ) {
1858 my $record = MARCgetitem( $biblionumber, $itemnumber );
1862 "select tagfield,tagsubfield from marc_subfield_structure where kohafield=?"
1866 $sth->execute($itemfield);
1867 if ( ( $tagfield, $tagsubfield ) = $sth->fetchrow ) {
1868 my $tag = $record->field($tagfield);
1870 my $tagsubs = $record->field($tagfield)->subfield($tagsubfield);
1871 $tag->update( $tagsubfield => $newvalue );
1872 $record->delete_field($tag);
1873 $record->insert_fields_ordered($tag);
1874 &MARCmoditem( $record, $biblionumber, $itemnumber, 0 );
1881 &MARCmoditem( $record, $biblionumber, $itemnumber, $frameworkcode, $delete )
1886 my ( $record, $biblionumber, $itemnumber, $frameworkcode, $delete ) = @_;
1887 my $dbh = C4::Context->dbh;
1889 # delete this item from MARC
1890 my $newrec = &MARCdelitem( $biblionumber, $itemnumber );
1893 my @fields = $record->fields();
1894 ###NEU specific add cataloguers cardnumber as well
1895 my $cardtag = C4::Context->preference('itemcataloguersubfield');
1897 foreach my $field (@fields) {
1899 my $me = C4::Context->userenv;
1900 my $cataloguer = $me->{'cardnumber'} if ($me);
1901 $field->update( $cardtag => $cataloguer ) if ($me);
1903 $newrec->append_fields($field);
1905 &MARCaddbiblio( $newrec, $biblionumber, $frameworkcode );
1908 =head2 MARCfind_frameworkcode
1910 $frameworkcode = MARCfind_frameworkcode( $biblionumber )
1914 sub MARCfind_frameworkcode {
1915 my ( $biblionumber ) = @_;
1916 my $dbh = C4::Context->dbh;
1918 $dbh->prepare("select frameworkcode from biblio where biblionumber=?");
1919 $sth->execute($biblionumber);
1920 my ($frameworkcode) = $sth->fetchrow;
1921 return $frameworkcode;
1926 $record = Koha2Marc( $hash )
1928 This function builds partial MARC::Record from a hash
1930 Hash entries can be from biblio or biblioitems.
1932 This function is called in acquisition module, to create a basic catalogue entry from user entry
1939 my $dbh = C4::Context->dbh;
1942 "select tagfield,tagsubfield from marc_subfield_structure where frameworkcode=? and kohafield=?"
1944 my $record = MARC::Record->new();
1945 foreach (keys %{$hash}) {
1946 &MARCkoha2marcOnefield( $sth, $record, $_,
1952 =head2 MARCkoha2marcBiblio
1954 $record = MARCkoha2marcBiblio( $biblionumber, $biblioitemnumber )
1956 this function builds partial MARC::Record from the old koha-DB fields
1960 sub MARCkoha2marcBiblio {
1962 my ( $biblionumber, $biblioitemnumber ) = @_;
1963 my $dbh = C4::Context->dbh;
1966 "select tagfield,tagsubfield from marc_subfield_structure where frameworkcode=? and kohafield=?"
1968 my $record = MARC::Record->new();
1970 #--- if biblionumber, then retrieve old-style koha data
1971 if ( $biblionumber > 0 ) {
1972 my $sth2 = $dbh->prepare(
1973 "select biblionumber,author,title,unititle,notes,abstract,serial,seriestitle,copyrightdate,timestamp
1974 from biblio where biblionumber=?"
1976 $sth2->execute($biblionumber);
1977 my $row = $sth2->fetchrow_hashref;
1979 foreach $code ( keys %$row ) {
1980 if ( $row->{$code} ) {
1981 &MARCkoha2marcOnefield( $sth, $record, "biblio." . $code,
1982 $row->{$code}, '' );
1987 #--- if biblioitem, then retrieve old-style koha data
1988 if ( $biblioitemnumber > 0 ) {
1989 my $sth2 = $dbh->prepare(
1990 " SELECT biblioitemnumber,biblionumber,volume,number,classification,
1991 itemtype,url,isbn,issn,dewey,subclass,publicationyear,publishercode,
1992 volumedate,volumeddesc,timestamp,illus,pages,notes AS bnotes,size,place
1994 WHERE biblioitemnumber=?
1997 $sth2->execute($biblioitemnumber);
1998 my $row = $sth2->fetchrow_hashref;
2000 foreach $code ( keys %$row ) {
2001 if ( $row->{$code} ) {
2002 &MARCkoha2marcOnefield( $sth, $record, "biblioitems." . $code,
2003 $row->{$code}, '' );
2010 =head2 MARCkoha2marcItem
2012 $record = MARCkoha2marcItem( $dbh, $biblionumber, $itemnumber );
2016 sub MARCkoha2marcItem {
2018 # this function builds partial MARC::Record from the old koha-DB fields
2019 my ( $dbh, $biblionumber, $itemnumber ) = @_;
2021 # my $dbh=&C4Connect;
2024 "select tagfield,tagsubfield from marc_subfield_structure where frameworkcode=? and kohafield=?"
2026 my $record = MARC::Record->new();
2028 #--- if item, then retrieve old-style koha data
2029 if ( $itemnumber > 0 ) {
2031 # print STDERR "prepare $biblionumber,$itemnumber\n";
2032 my $sth2 = $dbh->prepare(
2033 "SELECT itemnumber,biblionumber,multivolumepart,biblioitemnumber,barcode,dateaccessioned,
2034 booksellerid,homebranch,price,replacementprice,replacementpricedate,datelastborrowed,
2035 datelastseen,multivolume,stack,notforloan,itemlost,wthdrawn,itemcallnumber,issues,renewals,
2036 reserves,restricted,binding,itemnotes,holdingbranch,timestamp,onloan,Cutterextra
2040 $sth2->execute($itemnumber);
2041 my $row = $sth2->fetchrow_hashref;
2043 foreach $code ( keys %$row ) {
2044 if ( $row->{$code} ) {
2045 &MARCkoha2marcOnefield( $sth, $record, "items." . $code,
2046 $row->{$code}, '' );
2053 =head2 MARCkoha2marcOnefield
2055 $record = MARCkoha2marcOnefield( $sth, $record, $kohafieldname, $value, $frameworkcode );
2059 sub MARCkoha2marcOnefield {
2060 my ( $sth, $record, $kohafieldname, $value, $frameworkcode ) = @_;
2061 $frameworkcode='' unless $frameworkcode;
2065 if ( !defined $sth ) {
2066 my $dbh = C4::Context->dbh;
2069 "select tagfield,tagsubfield from marc_subfield_structure where frameworkcode=? and kohafield=?"
2072 $sth->execute( $frameworkcode, $kohafieldname );
2073 if ( ( $tagfield, $tagsubfield ) = $sth->fetchrow ) {
2074 my $tag = $record->field($tagfield);
2076 $tag->update( $tagsubfield => $value );
2077 $record->delete_field($tag);
2078 $record->insert_fields_ordered($tag);
2081 $record->add_fields( $tagfield, " ", " ", $tagsubfield => $value );
2089 $xml = MARChtml2xml( $tags, $subfields, $values, $indicator, $ind_tag )
2094 my ( $tags, $subfields, $values, $indicator, $ind_tag ) = @_;
2095 my $xml = MARC::File::XML::header('UTF-8');
2096 if ( C4::Context->preference('marcflavour') eq 'UNIMARC' ) {
2097 MARC::File::XML->default_record_format('UNIMARC');
2098 use POSIX qw(strftime);
2099 my $string = strftime( "%Y%m%d", localtime(time) );
2100 $string = sprintf( "%-*s", 35, $string );
2101 substr( $string, 22, 6, "frey50" );
2102 $xml .= "<datafield tag=\"100\" ind1=\"\" ind2=\"\">\n";
2103 $xml .= "<subfield code=\"a\">$string</subfield>\n";
2104 $xml .= "</datafield>\n";
2110 for ( my $i = 0 ; $i <= @$tags ; $i++ ) {
2111 @$values[$i] =~ s/&/&/g;
2112 @$values[$i] =~ s/</</g;
2113 @$values[$i] =~ s/>/>/g;
2114 @$values[$i] =~ s/"/"/g;
2115 @$values[$i] =~ s/'/'/g;
2116 if ( !utf8::is_utf8( @$values[$i] ) ) {
2117 utf8::decode( @$values[$i] );
2119 if ( ( @$tags[$i] ne $prevtag ) ) {
2120 $j++ unless ( @$tags[$i] eq "" );
2122 $xml .= "</datafield>\n";
2123 if ( ( @$tags[$i] && @$tags[$i] > 10 )
2124 && ( @$values[$i] ne "" ) )
2126 my $ind1 = substr( @$indicator[$j], 0, 1 );
2128 if ( @$indicator[$j] ) {
2129 $ind2 = substr( @$indicator[$j], 1, 1 );
2132 warn "Indicator in @$tags[$i] is empty";
2136 "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
2138 "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
2146 if ( @$values[$i] ne "" ) {
2149 if ( @$tags[$i] eq "000" ) {
2150 $xml .= "<leader>@$values[$i]</leader>\n";
2153 # rest of the fixed fields
2155 elsif ( @$tags[$i] < 10 ) {
2157 "<controlfield tag=\"@$tags[$i]\">@$values[$i]</controlfield>\n";
2161 my $ind1 = substr( @$indicator[$j], 0, 1 );
2162 my $ind2 = substr( @$indicator[$j], 1, 1 );
2164 "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
2166 "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
2172 else { # @$tags[$i] eq $prevtag
2173 if ( @$values[$i] eq "" ) {
2177 my $ind1 = substr( @$indicator[$j], 0, 1 );
2178 my $ind2 = substr( @$indicator[$j], 1, 1 );
2180 "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
2184 "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
2187 $prevtag = @$tags[$i];
2189 $xml .= MARC::File::XML::footer();
2194 =head2 MARChtml2marc
2196 $record = MARChtml2marc( $dbh, $rtags, $rsubfields, $rvalues, %indicators )
2201 my ( $dbh, $rtags, $rsubfields, $rvalues, %indicators ) = @_;
2203 my $record = MARC::Record->new();
2205 # my %subfieldlist=();
2206 my $prevvalue; # if tag <10
2207 my $field; # if tag >=10
2208 for ( my $i = 0 ; $i < @$rtags ; $i++ ) {
2209 next unless @$rvalues[$i];
2211 # rebuild MARC::Record
2212 # warn "0=>".@$rtags[$i].@$rsubfields[$i]." = ".@$rvalues[$i].": ";
2213 if ( @$rtags[$i] ne $prevtag ) {
2214 if ( $prevtag < 10 ) {
2217 if ( $prevtag ne '000' ) {
2218 $record->insert_fields_ordered(
2219 ( sprintf "%03s", $prevtag ), $prevvalue );
2223 $record->leader($prevvalue);
2230 $record->insert_fields_ordered($field);
2233 $indicators{ @$rtags[$i] } .= ' ';
2234 if ( @$rtags[$i] < 10 ) {
2235 $prevvalue = @$rvalues[$i];
2240 $field = MARC::Field->new(
2241 ( sprintf "%03s", @$rtags[$i] ),
2242 substr( $indicators{ @$rtags[$i] }, 0, 1 ),
2243 substr( $indicators{ @$rtags[$i] }, 1, 1 ),
2244 @$rsubfields[$i] => @$rvalues[$i]
2247 $prevtag = @$rtags[$i];
2250 if ( @$rtags[$i] < 10 ) {
2251 $prevvalue = @$rvalues[$i];
2254 if ( length( @$rvalues[$i] ) > 0 ) {
2255 $field->add_subfields( @$rsubfields[$i] => @$rvalues[$i] );
2258 $prevtag = @$rtags[$i];
2262 # the last has not been included inside the loop... do it now !
2263 $record->insert_fields_ordered($field) if $field;
2265 # warn "HTML2MARC=".$record->as_formatted;
2266 $record->encoding('UTF-8');
2268 # $record->MARC::File::USMARC::update_leader();
2272 =head2 MARCmarc2koha
2274 $result = MARCmarc2koha( $dbh, $record, $frameworkcode )
2279 my ( $dbh, $record, $frameworkcode ) = @_;
2282 "select tagfield,tagsubfield from marc_subfield_structure where frameworkcode=? and kohafield=?"
2285 my $sth2 = $dbh->prepare("SHOW COLUMNS from biblio");
2288 while ( ($field) = $sth2->fetchrow ) {
2290 &MARCmarc2kohaOneField( "biblio", $field, $record, $result,
2293 $sth2 = $dbh->prepare("SHOW COLUMNS from biblioitems");
2295 while ( ($field) = $sth2->fetchrow ) {
2296 if ( $field eq 'notes' ) { $field = 'bnotes'; }
2298 &MARCmarc2kohaOneField( "biblioitems", $field, $record, $result,
2301 $sth2 = $dbh->prepare("SHOW COLUMNS from items");
2303 while ( ($field) = $sth2->fetchrow ) {
2305 &MARCmarc2kohaOneField( "items", $field, $record, $result,
2310 # modify copyrightdate to keep only the 1st year found
2311 my $temp = $result->{'copyrightdate'};
2312 $temp =~ m/c(\d\d\d\d)/; # search cYYYY first
2314 $result->{'copyrightdate'} = $1;
2316 else { # if no cYYYY, get the 1st date.
2317 $temp =~ m/(\d\d\d\d)/;
2318 $result->{'copyrightdate'} = $1;
2321 # modify publicationyear to keep only the 1st year found
2322 $temp = $result->{'publicationyear'};
2323 $temp =~ m/c(\d\d\d\d)/; # search cYYYY first
2325 $result->{'publicationyear'} = $1;
2327 else { # if no cYYYY, get the 1st date.
2328 $temp =~ m/(\d\d\d\d)/;
2329 $result->{'publicationyear'} = $1;
2334 =head2 MARCmarc2kohaOneField
2336 $result = MARCmarc2kohaOneField( $kohatable, $kohafield, $record, $result, $frameworkcode )
2340 sub MARCmarc2kohaOneField {
2342 # FIXME ? if a field has a repeatable subfield that is used in old-db, only the 1st will be retrieved...
2343 my ( $kohatable, $kohafield, $record, $result, $frameworkcode ) = @_;
2346 my ( $tagfield, $subfield ) =
2347 MARCfind_marc_from_kohafield( "", $kohatable . "." . $kohafield,
2349 foreach my $field ( $record->field($tagfield) ) {
2350 if ( $field->tag() < 10 ) {
2351 if ( $result->{$kohafield} ) {
2352 $result->{$kohafield} .= " | " . $field->data();
2355 $result->{$kohafield} = $field->data();
2359 if ( $field->subfields ) {
2360 my @subfields = $field->subfields();
2361 foreach my $subfieldcount ( 0 .. $#subfields ) {
2362 if ( $subfields[$subfieldcount][0] eq $subfield ) {
2363 if ( $result->{$kohafield} ) {
2364 $result->{$kohafield} .=
2365 " | " . $subfields[$subfieldcount][1];
2368 $result->{$kohafield} =
2369 $subfields[$subfieldcount][1];
2379 =head2 MARCitemchange
2381 &MARCitemchange( $record, $itemfield, $newvalue )
2385 sub MARCitemchange {
2386 my ( $record, $itemfield, $newvalue ) = @_;
2387 my $dbh = C4::Context->dbh;
2389 my ( $tagfield, $tagsubfield ) =
2390 MARCfind_marc_from_kohafield( $dbh, $itemfield, "" );
2391 if ( ($tagfield) && ($tagsubfield) ) {
2392 my $tag = $record->field($tagfield);
2394 $tag->update( $tagsubfield => $newvalue );
2395 $record->delete_field($tag);
2396 $record->insert_fields_ordered($tag);
2401 =head1 INTERNAL FUNCTIONS
2403 =head2 _koha_add_biblio
2405 _koha_add_biblio($dbh,$biblioitem);
2407 Internal function to add a biblio ($biblio is a hash with the values)
2411 sub _koha_add_biblio {
2412 my ( $dbh, $biblio, $frameworkcode ) = @_;
2413 my $sth = $dbh->prepare("Select max(biblionumber) from biblio");
2415 my $data = $sth->fetchrow_arrayref;
2416 my $biblionumber = $$data[0] + 1;
2419 if ( $biblio->{'seriestitle'} ) { $series = 1 }
2421 $sth = $dbh->prepare(
2423 SET biblionumber = ?, title = ?, author = ?, copyrightdate = ?, serial = ?, seriestitle = ?, notes = ?, abstract = ?, unititle = ?, frameworkcode = ? "
2426 $biblionumber, $biblio->{'title'},
2427 $biblio->{'author'}, $biblio->{'copyrightdate'},
2428 $biblio->{'serial'}, $biblio->{'seriestitle'},
2429 $biblio->{'notes'}, $biblio->{'abstract'},
2430 $biblio->{'unititle'}, $frameworkcode
2434 return ($biblionumber);
2439 ($indicators, $value) = _find_value($tag, $subfield, $record,$encoding);
2441 Find the given $subfield in the given $tag in the given
2442 MARC::Record $record. If the subfield is found, returns
2443 the (indicators, value) pair; otherwise, (undef, undef) is
2447 Such a function is used in addbiblio AND additem and serial-edit and maybe could be used in Authorities.
2448 I suggest we export it from this module.
2453 my ( $tagfield, $insubfield, $record, $encoding ) = @_;
2456 if ( $tagfield < 10 ) {
2457 if ( $record->field($tagfield) ) {
2458 push @result, $record->field($tagfield)->data();
2465 foreach my $field ( $record->field($tagfield) ) {
2466 my @subfields = $field->subfields();
2467 foreach my $subfield (@subfields) {
2468 if ( @$subfield[0] eq $insubfield ) {
2469 push @result, @$subfield[1];
2470 $indicator = $field->indicator(1) . $field->indicator(2);
2475 return ( $indicator, @result );
2478 =head2 _koha_modify_biblio
2480 Internal function for updating the biblio table
2484 sub _koha_modify_biblio {
2485 my ( $dbh, $biblio ) = @_;
2487 # FIXME: this code could be made more portable by not hard-coding the values that are supposed to be in biblio table
2490 "Update biblio set title = ?, author = ?, abstract = ?, copyrightdate = ?, seriestitle = ?, serial = ?, unititle = ?, notes = ? where biblionumber = ?"
2493 $biblio->{'title'}, $biblio->{'author'},
2494 $biblio->{'abstract'}, $biblio->{'copyrightdate'},
2495 $biblio->{'seriestitle'}, $biblio->{'serial'},
2496 $biblio->{'unititle'}, $biblio->{'notes'},
2497 $biblio->{'biblionumber'}
2500 return ( $biblio->{'biblionumber'} );
2503 =head2 _koha_modify_biblioitem
2505 _koha_modify_biblioitem( $dbh, $biblioitem );
2509 sub _koha_modify_biblioitem {
2510 my ( $dbh, $biblioitem ) = @_;
2512 ##Recalculate LC in case it changed --TG
2514 $biblioitem->{'itemtype'} = $dbh->quote( $biblioitem->{'itemtype'} );
2515 $biblioitem->{'url'} = $dbh->quote( $biblioitem->{'url'} );
2516 $biblioitem->{'isbn'} = $dbh->quote( $biblioitem->{'isbn'} );
2517 $biblioitem->{'issn'} = $dbh->quote( $biblioitem->{'issn'} );
2518 $biblioitem->{'publishercode'} =
2519 $dbh->quote( $biblioitem->{'publishercode'} );
2520 $biblioitem->{'publicationyear'} =
2521 $dbh->quote( $biblioitem->{'publicationyear'} );
2522 $biblioitem->{'classification'} =
2523 $dbh->quote( $biblioitem->{'classification'} );
2524 $biblioitem->{'dewey'} = $dbh->quote( $biblioitem->{'dewey'} );
2525 $biblioitem->{'subclass'} = $dbh->quote( $biblioitem->{'subclass'} );
2526 $biblioitem->{'illus'} = $dbh->quote( $biblioitem->{'illus'} );
2527 $biblioitem->{'pages'} = $dbh->quote( $biblioitem->{'pages'} );
2528 $biblioitem->{'volumeddesc'} = $dbh->quote( $biblioitem->{'volumeddesc'} );
2529 $biblioitem->{'bnotes'} = $dbh->quote( $biblioitem->{'bnotes'} );
2530 $biblioitem->{'size'} = $dbh->quote( $biblioitem->{'size'} );
2531 $biblioitem->{'place'} = $dbh->quote( $biblioitem->{'place'} );
2532 $biblioitem->{'ccode'} = $dbh->quote( $biblioitem->{'ccode'} );
2533 $biblioitem->{'biblionumber'} =
2534 $dbh->quote( $biblioitem->{'biblionumber'} );
2536 $query = "Update biblioitems set
2537 itemtype = $biblioitem->{'itemtype'},
2538 url = $biblioitem->{'url'},
2539 isbn = $biblioitem->{'isbn'},
2540 issn = $biblioitem->{'issn'},
2541 publishercode = $biblioitem->{'publishercode'},
2542 publicationyear = $biblioitem->{'publicationyear'},
2543 classification = $biblioitem->{'classification'},
2544 dewey = $biblioitem->{'dewey'},
2545 subclass = $biblioitem->{'subclass'},
2546 illus = $biblioitem->{'illus'},
2547 pages = $biblioitem->{'pages'},
2548 volumeddesc = $biblioitem->{'volumeddesc'},
2549 notes = $biblioitem->{'bnotes'},
2550 size = $biblioitem->{'size'},
2551 place = $biblioitem->{'place'},
2552 ccode = $biblioitem->{'ccode'}
2553 where biblionumber = $biblioitem->{'biblionumber'}";
2556 if ( $dbh->errstr ) {
2561 =head2 _koha_modify_note
2563 _koha_modify_note( $dbh, $bibitemnum, $note );
2567 sub _koha_modify_note {
2568 my ( $dbh, $bibitemnum, $note ) = @_;
2570 # my $dbh=C4Connect;
2571 my $query = "update biblioitems set notes='$note' where
2572 biblioitemnumber='$bibitemnum'";
2573 my $sth = $dbh->prepare($query);
2578 =head2 _koha_add_biblioitem
2580 _koha_add_biblioitem( $dbh, $biblioitem );
2582 Internal function to add a biblioitem
2586 sub _koha_add_biblioitem {
2587 my ( $dbh, $biblioitem ) = @_;
2589 # my $dbh = C4Connect;
2590 my $sth = $dbh->prepare("SELECT max(biblioitemnumber) FROM biblioitems");
2595 $data = $sth->fetchrow_arrayref;
2596 $bibitemnum = $$data[0] + 1;
2600 $sth = $dbh->prepare(
2601 "INSERT INTO biblioitems SET
2602 biblioitemnumber = ?, biblionumber = ?,
2603 volume = ?, number = ?,
2604 classification = ?, itemtype = ?,
2606 issn = ?, dewey = ?,
2607 subclass = ?, publicationyear = ?,
2608 publishercode = ?, volumedate = ?,
2609 volumeddesc = ?, illus = ?,
2610 pages = ?, notes = ?,
2612 marc = ?, lcsort =?,
2613 place = ?, ccode = ?
2617 calculatelc( $biblioitem->{'classification'} )
2618 . $biblioitem->{'subclass'};
2620 $bibitemnum, $biblioitem->{'biblionumber'},
2621 $biblioitem->{'volume'}, $biblioitem->{'number'},
2622 $biblioitem->{'classification'}, $biblioitem->{'itemtype'},
2623 $biblioitem->{'url'}, $biblioitem->{'isbn'},
2624 $biblioitem->{'issn'}, $biblioitem->{'dewey'},
2625 $biblioitem->{'subclass'}, $biblioitem->{'publicationyear'},
2626 $biblioitem->{'publishercode'}, $biblioitem->{'volumedate'},
2627 $biblioitem->{'volumeddesc'}, $biblioitem->{'illus'},
2628 $biblioitem->{'pages'}, $biblioitem->{'bnotes'},
2629 $biblioitem->{'size'}, $biblioitem->{'lccn'},
2630 $biblioitem->{'marc'}, $biblioitem->{'place'},
2631 $lcsort, $biblioitem->{'ccode'}
2634 return ($bibitemnum);
2637 =head2 _koha_new_items
2639 _koha_new_items( $dbh, $item, $barcode );
2643 sub _koha_new_items {
2644 my ( $dbh, $item, $barcode ) = @_;
2646 # my $dbh = C4Connect;
2647 my $sth = $dbh->prepare("Select max(itemnumber) from items");
2653 $data = $sth->fetchrow_hashref;
2654 $itemnumber = $data->{'max(itemnumber)'} + 1;
2656 ## Now calculate lccalnumber
2657 my ($cutterextra) = itemcalculator(
2659 $item->{'biblioitemnumber'},
2660 $item->{'itemcallnumber'}
2663 # FIXME the "notforloan" field seems to be named "loan" in some places. workaround bugfix.
2664 if ( $item->{'loan'} ) {
2665 $item->{'notforloan'} = $item->{'loan'};
2668 # if dateaccessioned is provided, use it. Otherwise, set to NOW()
2669 if ( $item->{'dateaccessioned'} eq '' || !$item->{'dateaccessioned'} ) {
2671 $sth = $dbh->prepare(
2672 "Insert into items set
2673 itemnumber = ?, biblionumber = ?,
2674 multivolumepart = ?,
2675 biblioitemnumber = ?, barcode = ?,
2676 booksellerid = ?, dateaccessioned = NOW(),
2677 homebranch = ?, holdingbranch = ?,
2678 price = ?, replacementprice = ?,
2679 replacementpricedate = NOW(), datelastseen = NOW(),
2680 multivolume = ?, stack = ?,
2681 itemlost = ?, wthdrawn = ?,
2682 paidfor = ?, itemnotes = ?,
2683 itemcallnumber =?, notforloan = ?,
2684 location = ?, Cutterextra = ?
2688 $itemnumber, $item->{'biblionumber'},
2689 $item->{'multivolumepart'}, $item->{'biblioitemnumber'},
2690 $barcode, $item->{'booksellerid'},
2691 $item->{'homebranch'}, $item->{'holdingbranch'},
2692 $item->{'price'}, $item->{'replacementprice'},
2693 $item->{multivolume}, $item->{stack},
2694 $item->{itemlost}, $item->{wthdrawn},
2695 $item->{paidfor}, $item->{'itemnotes'},
2696 $item->{'itemcallnumber'}, $item->{'notforloan'},
2697 $item->{'location'}, $cutterextra
2701 $sth = $dbh->prepare(
2702 "INSERT INTO items SET
2703 itemnumber = ?, biblionumber = ?,
2704 multivolumepart = ?,
2705 biblioitemnumber = ?, barcode = ?,
2706 booksellerid = ?, dateaccessioned = ?,
2707 homebranch = ?, holdingbranch = ?,
2708 price = ?, replacementprice = ?,
2709 replacementpricedate = NOW(), datelastseen = NOW(),
2710 multivolume = ?, stack = ?,
2711 itemlost = ?, wthdrawn = ?,
2712 paidfor = ?, itemnotes = ?,
2713 itemcallnumber = ?, notforloan = ?,
2719 $itemnumber, $item->{'biblionumber'},
2720 $item->{'multivolumepart'}, $item->{'biblioitemnumber'},
2721 $barcode, $item->{'booksellerid'},
2722 $item->{'dateaccessioned'}, $item->{'homebranch'},
2723 $item->{'holdingbranch'}, $item->{'price'},
2724 $item->{'replacementprice'}, $item->{multivolume},
2725 $item->{stack}, $item->{itemlost},
2726 $item->{wthdrawn}, $item->{paidfor},
2727 $item->{'itemnotes'}, $item->{'itemcallnumber'},
2728 $item->{'notforloan'}, $item->{'location'},
2732 if ( defined $sth->errstr ) {
2733 $error .= $sth->errstr;
2735 return ( $itemnumber, $error );
2738 =head2 _koha_modify_item
2740 _koha_modify_item( $dbh, $item, $op );
2744 sub _koha_modify_item {
2745 my ( $dbh, $item, $op ) = @_;
2746 $item->{'itemnum'} = $item->{'itemnumber'} unless $item->{'itemnum'};
2748 # if all we're doing is setting statuses, just update those and get out
2749 if ( $op eq "setstatus" ) {
2751 "UPDATE items SET itemlost=?,wthdrawn=?,binding=? WHERE itemnumber=?";
2753 $item->{'itemlost'}, $item->{'wthdrawn'},
2754 $item->{'binding'}, $item->{'itemnumber'}
2756 my $sth = $dbh->prepare($query);
2757 $sth->execute(@bind);
2761 ## Now calculate lccalnumber
2763 itemcalculator( $dbh, $item->{'bibitemnum'}, $item->{'itemcallnumber'} );
2765 my $query = "UPDATE items SET
2766 barcode=?,itemnotes=?,itemcallnumber=?,notforloan=?,location=?,multivolumepart=?,multivolume=?,stack=?,wthdrawn=?,holdingbranch=?,homebranch=?,cutterextra=?, onloan=?, binding=?";
2769 $item->{'barcode'}, $item->{'notes'},
2770 $item->{'itemcallnumber'}, $item->{'notforloan'},
2771 $item->{'location'}, $item->{multivolumepart},
2772 $item->{multivolume}, $item->{stack},
2773 $item->{wthdrawn}, $item->{holdingbranch},
2774 $item->{homebranch}, $cutterextra,
2775 $item->{onloan}, $item->{binding}
2777 if ( $item->{'lost'} ne '' ) {
2779 "update items set biblioitemnumber=?,barcode=?,itemnotes=?,homebranch=?,
2780 itemlost=?,wthdrawn=?,itemcallnumber=?,notforloan=?,
2781 location=?,multivolumepart=?,multivolume=?,stack=?,wthdrawn=?,holdingbranch=?,cutterextra=?,onloan=?, binding=?";
2783 $item->{'bibitemnum'}, $item->{'barcode'},
2784 $item->{'notes'}, $item->{'homebranch'},
2785 $item->{'lost'}, $item->{'wthdrawn'},
2786 $item->{'itemcallnumber'}, $item->{'notforloan'},
2787 $item->{'location'}, $item->{multivolumepart},
2788 $item->{multivolume}, $item->{stack},
2789 $item->{wthdrawn}, $item->{holdingbranch},
2790 $cutterextra, $item->{onloan},
2793 if ( $item->{homebranch} ) {
2794 $query .= ",homebranch=?";
2795 push @bind, $item->{homebranch};
2797 if ( $item->{holdingbranch} ) {
2798 $query .= ",holdingbranch=?";
2799 push @bind, $item->{holdingbranch};
2802 $query .= " where itemnumber=?";
2803 push @bind, $item->{'itemnum'};
2804 if ( $item->{'replacement'} ne '' ) {
2805 $query =~ s/ where/,replacementprice='$item->{'replacement'}' where/;
2807 my $sth = $dbh->prepare($query);
2808 $sth->execute(@bind);
2812 =head2 _koha_delete_item
2814 _koha_delete_item( $dbh, $itemnum );
2816 Internal function to delete an item record from the koha tables
2820 sub _koha_delete_item {
2821 my ( $dbh, $itemnum ) = @_;
2823 my $sth = $dbh->prepare("select * from items where itemnumber=?");
2824 $sth->execute($itemnum);
2825 my $data = $sth->fetchrow_hashref;
2827 my $query = "Insert into deleteditems set ";
2829 foreach my $temp ( keys %$data ) {
2830 $query .= "$temp = ?,";
2831 push( @bind, $data->{$temp} );
2836 $sth = $dbh->prepare($query);
2837 $sth->execute(@bind);
2839 $sth = $dbh->prepare("Delete from items where itemnumber=?");
2840 $sth->execute($itemnum);
2844 =head2 _koha_delete_biblio
2846 $error = _koha_delete_biblio($dbh,$biblionumber);
2848 Internal sub for deleting from biblio table -- also saves to deletedbiblio
2850 C<$dbh> - the database handle
2851 C<$biblionumber> - the biblionumber of the biblio to be deleted
2855 # FIXME: add error handling
2857 sub _koha_delete_biblio {
2858 my ( $dbh, $biblionumber ) = @_;
2860 # get all the data for this biblio
2861 my $sth = $dbh->prepare("SELECT * FROM biblio WHERE biblionumber=?");
2862 $sth->execute($biblionumber);
2864 if ( my $data = $sth->fetchrow_hashref ) {
2866 # save the record in deletedbiblio
2867 # find the fields to save
2868 my $query = "INSERT INTO deletedbiblio SET ";
2870 foreach my $temp ( keys %$data ) {
2871 $query .= "$temp = ?,";
2872 push( @bind, $data->{$temp} );
2875 # replace the last , by ",?)"
2877 my $bkup_sth = $dbh->prepare($query);
2878 $bkup_sth->execute(@bind);
2882 my $del_sth = $dbh->prepare("DELETE FROM biblio WHERE biblionumber=?");
2883 $del_sth->execute($biblionumber);
2890 =head2 _koha_delete_biblioitems
2892 $error = _koha_delete_biblioitems($dbh,$biblioitemnumber);
2894 Internal sub for deleting from biblioitems table -- also saves to deletedbiblioitems
2896 C<$dbh> - the database handle
2897 C<$biblionumber> - the biblioitemnumber of the biblioitem to be deleted
2901 # FIXME: add error handling
2903 sub _koha_delete_biblioitems {
2904 my ( $dbh, $biblioitemnumber ) = @_;
2906 # get all the data for this biblioitem
2908 $dbh->prepare("SELECT * FROM biblioitems WHERE biblioitemnumber=?");
2909 $sth->execute($biblioitemnumber);
2911 if ( my $data = $sth->fetchrow_hashref ) {
2913 # save the record in deletedbiblioitems
2914 # find the fields to save
2915 my $query = "INSERT INTO deletedbiblioitems SET ";
2917 foreach my $temp ( keys %$data ) {
2918 $query .= "$temp = ?,";
2919 push( @bind, $data->{$temp} );
2922 # replace the last , by ",?)"
2924 my $bkup_sth = $dbh->prepare($query);
2925 $bkup_sth->execute(@bind);
2928 # delete the biblioitem
2930 $dbh->prepare("DELETE FROM biblioitems WHERE biblioitemnumber=?");
2931 $del_sth->execute($biblioitemnumber);
2938 =head2 _koha_delete_items
2940 $error = _koha_delete_items($dbh,$itemnumber);
2942 Internal sub for deleting from items table -- also saves to deleteditems
2944 C<$dbh> - the database handle
2945 C<$itemnumber> - the itemnumber of the item to be deleted
2949 # FIXME: add error handling
2951 sub _koha_delete_items {
2952 my ( $dbh, $itemnumber ) = @_;
2954 # get all the data for this item
2955 my $sth = $dbh->prepare("SELECT * FROM items WHERE itemnumber=?");
2956 $sth->execute($itemnumber);
2958 if ( my $data = $sth->fetchrow_hashref ) {
2960 # save the record in deleteditems
2961 # find the fields to save
2962 my $query = "INSERT INTO deleteditems SET ";
2964 foreach my $temp ( keys %$data ) {
2965 $query .= "$temp = ?,";
2966 push( @bind, $data->{$temp} );
2969 # replace the last , by ",?)"
2971 my $bkup_sth = $dbh->prepare($query);
2972 $bkup_sth->execute(@bind);
2976 my $del_sth = $dbh->prepare("DELETE FROM items WHERE itemnumber=?");
2977 $del_sth->execute($itemnumber);
2988 $biblionumber = &modbiblio($biblio);
2990 Update a biblio record.
2992 C<$biblio> is a reference-to-hash whose keys are the fields in the
2993 biblio table in the Koha database. All fields must be present, not
2994 just the ones you wish to change.
2996 C<&modbiblio> updates the record defined by
2997 C<$biblio-E<gt>{biblionumber}> with the values in C<$biblio>.
2999 C<&modbiblio> returns C<$biblio-E<gt>{biblionumber}> whether it was
3006 my $dbh = C4::Context->dbh;
3007 my $biblionumber = _koha_modify_biblio( $dbh, $biblio );
3008 my $record = MARCkoha2marcBiblio( $biblionumber, $biblionumber );
3009 MARCmodbiblio( $dbh, $biblionumber, $record, "", 0 );
3010 return ($biblionumber);
3015 &modbibitem($biblioitem)
3020 my ($biblioitem) = @_;
3021 my $dbh = C4::Context->dbh;
3022 &_koha_modify_biblio( $dbh, $biblioitem );
3028 $errors = &newitems( $item, @barcodes );
3033 my ( $item, @barcodes ) = @_;
3034 my $dbh = C4::Context->dbh;
3038 foreach my $barcode (@barcodes) {
3039 ( $itemnumber, $error ) = &_koha_new_items( $dbh, $item, uc($barcode) );
3042 &MARCkoha2marcItem( $dbh, $item->{biblionumber}, $itemnumber );
3043 &MARCadditem( $MARCitem, $item->{biblionumber} );
3050 $errors = &moditem( $item, $op );
3055 my ( $item, $op ) = @_;
3056 my $dbh = C4::Context->dbh;
3057 &_koha_modify_item( $dbh, $item, $op );
3059 # if we're just setting statuses, just update items table
3060 # it's faster and zebra and marc will be synched anyway by the cron job
3061 unless ( $op eq "setstatus" ) {
3062 my $MARCitem = &MARCkoha2marcItem( $dbh, $item->{'biblionumber'},
3063 $item->{'itemnum'} );
3064 &MARCmoditem( $MARCitem, $item->{biblionumber}, $item->{itemnum},
3065 MARCfind_frameworkcode( $item->{biblionumber} ), 0 );
3071 $errors = &checkitems( $count, @barcodes );
3076 my ( $count, @barcodes ) = @_;
3077 my $dbh = C4::Context->dbh;
3079 my $sth = $dbh->prepare("Select * from items where barcode=?");
3080 for ( my $i = 0 ; $i < $count ; $i++ ) {
3081 $barcodes[$i] = uc $barcodes[$i];
3082 $sth->execute( $barcodes[$i] );
3083 if ( my $data = $sth->fetchrow_hashref ) {
3084 $error .= " Duplicate Barcode: $barcodes[$i]";
3091 =head1 OTHER FUNCTIONS
3095 my $string = char_decode( $string, $encoding );
3097 converts ISO 5426 coded string to UTF-8
3098 sloppy code : should be improved in next issue
3103 my ( $string, $encoding ) = @_;
3106 $encoding = C4::Context->preference("marcflavour") unless $encoding;
3107 if ( $encoding eq "UNIMARC" ) {
3177 # this handles non-sorting blocks (if implementation requires this)
3178 $string = nsb_clean($_);
3180 elsif ( $encoding eq "USMARC" || $encoding eq "MARC21" ) {
3239 #Additional Turkish characters
3242 s/(\xf0)s/\xc5\x9f/gm;
3243 s/(\xf0)S/\xc5\x9e/gm;
3246 s/\xe7\x49/\\xc4\xb0/gm;
3247 s/(\xe6)G/\xc4\x9e/gm;
3248 s/(\xe6)g/ğ\xc4\x9f/gm;
3251 s/(\xe8|\xc8)o/ö/gm;
3252 s/(\xe8|\xc8)O/Ö/gm;
3253 s/(\xe8|\xc8)u/ü/gm;
3254 s/(\xe8|\xc8)U/Ü/gm;
3255 s/\xc2\xb8/\xc4\xb1/gm;
3258 # this handles non-sorting blocks (if implementation requires this)
3259 $string = nsb_clean($_);
3264 =head2 PrepareItemrecordDisplay
3266 PrepareItemrecordDisplay($itemrecord,$bibnum,$itemumber);
3268 Returns a hash with all the fields for Display a given item data in a template
3272 sub PrepareItemrecordDisplay {
3274 my ( $bibnum, $itemnum ) = @_;
3276 my $dbh = C4::Context->dbh;
3277 my $frameworkcode = &MARCfind_frameworkcode( $bibnum );
3278 my ( $itemtagfield, $itemtagsubfield ) =
3279 &MARCfind_marc_from_kohafield( $dbh, "items.itemnumber", $frameworkcode );
3280 my $tagslib = &MARCgettagslib( $dbh, 1, $frameworkcode );
3281 my $itemrecord = MARCgetitem( $bibnum, $itemnum) if ($itemnum);
3283 my $authorised_values_sth =
3285 "select authorised_value,lib from authorised_values where category=? order by lib"
3287 foreach my $tag ( sort keys %{$tagslib} ) {
3288 my $previous_tag = '';
3290 # loop through each subfield
3292 foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
3293 next if ( subfield_is_koha_internal_p($subfield) );
3294 next if ( $tagslib->{$tag}->{$subfield}->{'tab'} ne "10" );
3296 $subfield_data{tag} = $tag;
3297 $subfield_data{subfield} = $subfield;
3298 $subfield_data{countsubfield} = $cntsubf++;
3299 $subfield_data{kohafield} =
3300 $tagslib->{$tag}->{$subfield}->{'kohafield'};
3302 # $subfield_data{marc_lib}=$tagslib->{$tag}->{$subfield}->{lib};
3303 $subfield_data{marc_lib} =
3304 "<span id=\"error\" title=\""
3305 . $tagslib->{$tag}->{$subfield}->{lib} . "\">"
3306 . substr( $tagslib->{$tag}->{$subfield}->{lib}, 0, 12 )
3308 $subfield_data{mandatory} =
3309 $tagslib->{$tag}->{$subfield}->{mandatory};
3310 $subfield_data{repeatable} =
3311 $tagslib->{$tag}->{$subfield}->{repeatable};
3312 $subfield_data{hidden} = "display:none"
3313 if $tagslib->{$tag}->{$subfield}->{hidden};
3315 ( $x, $value ) = _find_value( $tag, $subfield, $itemrecord )
3317 $value =~ s/"/"/g;
3319 # search for itemcallnumber if applicable
3320 if ( $tagslib->{$tag}->{$subfield}->{kohafield} eq
3321 'items.itemcallnumber'
3322 && C4::Context->preference('itemcallnumber') )
3325 substr( C4::Context->preference('itemcallnumber'), 0, 3 );
3327 substr( C4::Context->preference('itemcallnumber'), 3, 1 );
3328 my $temp = $itemrecord->field($CNtag) if ($itemrecord);
3330 $value = $temp->subfield($CNsubfield);
3333 if ( $tagslib->{$tag}->{$subfield}->{authorised_value} ) {
3334 my @authorised_values;
3337 # builds list, depending on authorised value...
3339 if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq
3342 if ( ( C4::Context->preference("IndependantBranches") )
3343 && ( C4::Context->userenv->{flags} != 1 ) )
3347 "select branchcode,branchname from branches where branchcode = ? order by branchname"
3349 $sth->execute( C4::Context->userenv->{branch} );
3350 push @authorised_values, ""
3352 $tagslib->{$tag}->{$subfield}->{mandatory} );
3353 while ( my ( $branchcode, $branchname ) =
3354 $sth->fetchrow_array )
3356 push @authorised_values, $branchcode;
3357 $authorised_lib{$branchcode} = $branchname;
3363 "select branchcode,branchname from branches order by branchname"
3366 push @authorised_values, ""
3368 $tagslib->{$tag}->{$subfield}->{mandatory} );
3369 while ( my ( $branchcode, $branchname ) =
3370 $sth->fetchrow_array )
3372 push @authorised_values, $branchcode;
3373 $authorised_lib{$branchcode} = $branchname;
3379 elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq
3384 "select itemtype,description from itemtypes order by description"
3387 push @authorised_values, ""
3388 unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
3389 while ( my ( $itemtype, $description ) =
3390 $sth->fetchrow_array )
3392 push @authorised_values, $itemtype;
3393 $authorised_lib{$itemtype} = $description;
3396 #---- "true" authorised value
3399 $authorised_values_sth->execute(
3400 $tagslib->{$tag}->{$subfield}->{authorised_value} );
3401 push @authorised_values, ""
3402 unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
3403 while ( my ( $value, $lib ) =
3404 $authorised_values_sth->fetchrow_array )
3406 push @authorised_values, $value;
3407 $authorised_lib{$value} = $lib;
3410 $subfield_data{marc_value} = CGI::scrolling_list(
3411 -name => 'field_value',
3412 -values => \@authorised_values,
3413 -default => "$value",
3414 -labels => \%authorised_lib,
3420 elsif ( $tagslib->{$tag}->{$subfield}->{thesaurus_category} ) {
3421 $subfield_data{marc_value} =
3422 "<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>";
3425 # COMMENTED OUT because No $i is provided with this API.
3426 # And thus, no value_builder can be activated.
3427 # BUT could be thought over.
3428 # } elsif ($tagslib->{$tag}->{$subfield}->{'value_builder'}) {
3429 # my $plugin="value_builder/".$tagslib->{$tag}->{$subfield}->{'value_builder'};
3431 # my $extended_param = plugin_parameters($dbh,$itemrecord,$tagslib,$i,0);
3432 # my ($function_name,$javascript) = plugin_javascript($dbh,$record,$tagslib,$i,0);
3433 # $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";
3436 $subfield_data{marc_value} =
3437 "<input type=\"text\" name=\"field_value\" value=\"$value\" size=50 maxlength=255>";
3439 push( @loop_data, \%subfield_data );
3443 my $itemnumber = $itemrecord->subfield( $itemtagfield, $itemtagsubfield )
3444 if ( $itemrecord && $itemrecord->field($itemtagfield) );
3446 'itemtagfield' => $itemtagfield,
3447 'itemtagsubfield' => $itemtagsubfield,
3448 'itemnumber' => $itemnumber,
3449 'iteminformation' => \@loop_data
3455 my $string = nsb_clean( $string, $encoding );
3460 my $NSB = '\x88'; # NSB : begin Non Sorting Block
3461 my $NSE = '\x89'; # NSE : Non Sorting Block end
3462 # handles non sorting blocks
3466 s/[ ]{0,1}$NSE/) /gm;
3473 &zebraopfiles( $dbh, $biblionumber, $record, $folder, $server );
3479 my ( $dbh, $biblionumber, $record, $folder, $server ) = @_;
3483 C4::Context->zebraconfig($server)->{directory} . "/" . $folder . "/";
3484 unless ( opendir( DIR, "$zebradir" ) ) {
3485 warn "$zebradir not found";
3489 my $filename = $zebradir . $biblionumber;
3492 open( OUTPUT, ">", $filename . ".xml" );
3493 print OUTPUT $record;
3500 zebraop( $dbh, $biblionumber, $op, $server );
3505 ###Accepts a $server variable thus we can use it for biblios authorities or other zebra dbs
3506 my ( $biblionumber, $op, $server ) = @_;
3507 my $dbh=C4::Context->dbh;
3508 #warn "SERVER:".$server;
3510 # true zebraop commented until indexdata fixes zebraDB crashes (it seems they occur on multiple updates
3512 # replaced by a zebraqueue table, that is filled with zebraop to run.
3513 # the table is emptied by misc/cronjobs/zebraqueue_start.pl script
3515 my $sth=$dbh->prepare("insert into zebraqueue (biblio_auth_number ,server,operation) values(?,?,?)");
3516 $sth->execute($biblionumber,$server,$op);
3523 # my $reconnect = 0;
3528 # $Zconnbiblio[0] = C4::Context->Zconn( $server, 0, 1 );
3530 # if ( $server eq "biblioserver" ) {
3532 # # it's unclear to me whether this should be in xml or MARC format
3533 # # but it is clear it should be nabbed from zebra rather than from
3535 # $record = GetMarcBiblio($biblionumber);
3536 # $record = $record->as_xml_record() if $record;
3537 # # warn "RECORD $biblionumber => ".$record;
3538 # $shadow="biblioservershadow";
3540 # # warn "RECORD $biblionumber => ".$record;
3541 # $shadow = "biblioservershadow";
3544 # elsif ( $server eq "authorityserver" ) {
3545 # $record = C4::AuthoritiesMarc::XMLgetauthority( $dbh, $biblionumber );
3546 # $shadow = "authorityservershadow";
3547 # } ## Add other servers as necessary
3549 # my $Zpackage = $Zconnbiblio[0]->package();
3550 # $Zpackage->option( action => $op );
3551 # $Zpackage->option( record => $record );
3554 # $Zpackage->send("update");
3558 # while ( ( $i = ZOOM::event( \@Zconnbiblio ) ) != 0 ) {
3559 # $event = $Zconnbiblio[0]->last_event();
3560 # last if $event == ZOOM::Event::ZEND;
3563 # my ( $error, $errmsg, $addinfo, $diagset ) = $Zconnbiblio[0]->error_x();
3564 # if ( $error == 10000 && $reconnect == 0 )
3565 # { ## This is serious ZEBRA server is not available -reconnect
3566 # warn "problem with zebra server connection";
3568 # my $res = system('sc start "Z39.50 Server" >c:/zebraserver/error.log');
3570 # #warn "Trying to restart ZEBRA Server";
3571 # #goto "reconnect";
3573 # elsif ( $error == 10007 && $tried < 2 )
3574 # { ## timeout --another 30 looonng seconds for this update
3575 # $tried = $tried + 1;
3576 # warn "warn: timeout, trying again";
3579 # elsif ( $error == 10004 && $recon == 0 ) { ##Lost connection -reconnect
3581 # warn "error: reconnecting to zebra";
3584 # # as a last resort, we save the data to the filesystem to be indexed in batch
3588 # "Error-$server $op $biblionumber /errcode:, $error, /MSG:,$errmsg,$addinfo \n";
3589 # $Zpackage->destroy();
3590 # $Zconnbiblio[0]->destroy();
3591 # zebraopfiles( $dbh, $biblionumber, $record, $op, $server );
3594 # if ( C4::Context->$shadow ) {
3595 # $Zpackage->send('commit');
3596 # while ( ( $i = ZOOM::event( \@Zconnbiblio ) ) != 0 ) {
3598 # #waiting zebra to finish;
3601 # $Zpackage->destroy();
3606 $lc = calculatelc($classification);
3611 my ($classification) = @_;
3612 $classification =~ s/^\s+|\s+$//g;
3617 for ( $i = 0 ; $i < length($classification) ; $i++ ) {
3618 my $c = ( substr( $classification, $i, 1 ) );
3619 if ( $c ge '0' && $c le '9' ) {
3621 $lc2 = substr( $classification, $i );
3625 $lc1 .= substr( $classification, $i, 1 );
3630 my $other = length($lc1);
3637 for ( 1 .. ( 4 - $other ) ) {
3646 ##Find the decimal part of $lc2
3647 my $pos = index( $lc2, "." );
3648 if ( $pos < 0 ) { $pos = length($lc2); }
3649 if ( $pos >= 0 && $pos < 5 ) {
3650 ##Pad lc2 with zeros to create a 5digit decimal needed in marc record to sort as numeric
3652 for ( 1 .. ( 5 - $pos ) ) {
3656 $lc2 = $extras . $lc2;
3657 return ( $lc1 . $lc2 );
3660 =head2 itemcalculator
3662 $cutterextra = itemcalculator( $dbh, $biblioitem, $callnumber );
3666 sub itemcalculator {
3667 my ( $dbh, $biblioitem, $callnumber ) = @_;
3670 "select classification, subclass from biblioitems where biblioitemnumber=?"
3673 $sth->execute($biblioitem);
3674 my ( $classification, $subclass ) = $sth->fetchrow;
3675 my $all = $classification . " " . $subclass;
3676 my $total = length($all);
3677 my $cutterextra = substr( $callnumber, $total - 1 );
3679 return $cutterextra;
3682 END { } # module clean-up code here (global destructor)
3690 Koha Developement team <info@koha.org>
3692 Paul POULAIN paul.poulain@free.fr
3694 Joshua Ferraro jmf@liblime.com
3700 # Revision 1.191 2007/03/29 09:42:13 tipaul
3701 # adding default value new feature into cataloguing. The system (definition) part has already been added by toins
3703 # Revision 1.190 2007/03/29 08:45:19 hdl
3704 # Deleting ignore_errors(1) pour MARC::Charset
3706 # Revision 1.189 2007/03/28 10:39:16 hdl
3707 # removing $dbh as a parameter in AuthoritiesMarc functions
3708 # And reporting all differences into the scripts taht relies on those functions.
3710 # Revision 1.188 2007/03/09 14:31:47 tipaul
3711 # rel_3_0 moved to HEAD
3713 # Revision 1.178.2.59 2007/02/28 10:01:13 toins
3714 # reporting bug fix from 2.2.7.1 to rel_3_0
3716 # BUGFIX/improvement : limiting MARCsubject to 610 as 676 is dewey, and is somewhere else
3718 # Revision 1.178.2.58 2007/02/05 16:50:01 toins
3719 # fix a mod_perl bug:
3720 # There was a global var modified into an internal function in {MARC|ISBD}detail.pl.
3721 # Moving this function in Biblio.pm
3723 # Revision 1.178.2.57 2007/01/25 09:37:58 tipaul
3726 # Revision 1.178.2.56 2007/01/24 13:50:26 tipaul
3728 # removing newbiblio & newbiblioitems subs.
3731 # IMHO, all biblio handling is better handled if they are done in a single place, the subs with MARC::Record as parameters.
3732 # 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.
3733 # 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.
3735 # Revision 1.178.2.55 2007/01/17 18:07:17 alaurin
3736 # bugfixing for zebraqueue_start and biblio.pm :
3738 # - Zebraqueue_start : restoring function of deletion in zebraqueue DB list
3740 # -biblio.pm : changing method of default_record_format, now we have :
3741 # MARC::File::XML->default_record_format(C4::Context->preference('marcflavour'));
3743 # with this line the encoding in zebra seems to be ok (in unimarc and marc21)
3745 # Revision 1.178.2.54 2007/01/16 15:00:03 tipaul
3746 # donc try to delete the biblio in koha, just fill zebraqueue table !
3748 # Revision 1.178.2.53 2007/01/16 10:24:11 tipaul
3750 # when modifying or deleting an item, the biblio frameworkcode was emptied.
3752 # Revision 1.178.2.52 2007/01/15 17:20:55 toins
3753 # *** empty log message ***
3755 # Revision 1.178.2.51 2007/01/15 15:16:44 hdl
3756 # Uncommenting zebraop.
3758 # Revision 1.178.2.50 2007/01/15 14:59:09 hdl
3759 # Adding creation of an unexpected serial any time.
3761 # USING Date::Calc and not Date::Manip.
3762 # WARNING : There are still some Bugs in next issue date management. (Date::Calc donot wrap easily next year calculation.)
3764 # Revision 1.178.2.49 2007/01/12 10:12:30 toins
3765 # writing $record->as_formatted in the log when Modifying an item.
3767 # Revision 1.178.2.48 2007/01/11 16:33:04 toins
3768 # write $record->as_formatted into the log.
3770 # Revision 1.178.2.47 2007/01/10 16:46:27 toins
3771 # Theses modules need to use C4::Log.
3773 # Revision 1.178.2.46 2007/01/10 16:31:15 toins
3774 # new systems preferences :
3775 # - CataloguingLog (log the update/creation/deletion of a notice if set to 1)
3776 # - BorrowersLog ( idem for borrowers )
3777 # - IssueLog (log all issue if set to 1)
3778 # - ReturnLog (log all return if set to 1)
3779 # - SusbcriptionLog (log all creation/deletion/update of a subcription)
3781 # All of theses are in a new tab called 'LOGFeatures' in systempreferences.pl
3783 # Revision 1.178.2.45 2007/01/09 10:31:09 toins
3784 # sync with dev_week. ( new function : GetMarcSeries )
3786 # Revision 1.178.2.44 2007/01/04 17:41:32 tipaul
3787 # 2 major bugfixes :
3788 # - deletion of an item deleted the whole biblio because of a wrong API
3789 # - create an item was bugguy for default framework
3791 # Revision 1.178.2.43 2006/12/22 15:09:53 toins
3792 # removing C4::Database;
3794 # Revision 1.178.2.42 2006/12/20 16:51:00 tipaul
3796 # - adding a new table : when a biblio is added/modified/ deleted, an entry is entered in this table
3797 # - the zebraqueue_start.pl script read it & does the stuff.
3799 # code coming from head (tumer). it can be run every minut instead of once every day for dev_week code.
3801 # 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 !
3803 # Revision 1.178.2.41 2006/12/20 08:54:44 toins
3804 # GetXmlBiblio wasn't exported.
3806 # Revision 1.178.2.40 2006/12/19 16:45:56 alaurin
3807 # bugfixing, for zebra and authorities
3809 # Revision 1.178.2.39 2006/12/08 17:55:44 toins
3810 # GetMarcAuthors now get authors for all subfields
3812 # Revision 1.178.2.38 2006/12/07 15:42:14 toins
3813 # synching opac & intranet.
3814 # fix some broken link & bugs.
3815 # removing warn compilation.
3817 # Revision 1.178.2.37 2006/12/07 11:09:39 tipaul
3819 # 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.
3820 # BUT for bulkmarcimport & mod_perl, the zebra conn must be persistant.
3822 # Revision 1.178.2.36 2006/12/06 16:54:21 alaurin
3823 # restore function zebraop for delete biblios :
3825 # 1) restore C4::Circulation::Circ2::itemissues, (was missing)
3826 # 2) restore zebraop value : delete_record
3828 # Revision 1.178.2.35 2006/12/06 10:02:12 alaurin
3829 # bugfixing for delete a biblio :
3831 # restore itemissue fonction .... :
3833 # other is pointed, zebra error 224... for biblio is not deleted in zebra ..
3836 # Revision 1.178.2.34 2006/12/06 09:14:25 toins
3837 # Correct the link to the MARC subjects.
3839 # Revision 1.178.2.33 2006/12/05 11:35:29 toins
3840 # Biblio.pm cleaned.
3841 # additionalauthors, bibliosubject, bibliosubtitle tables are now unused.
3842 # Some functions renamed according to the coding guidelines.
3844 # Revision 1.178.2.32 2006/12/04 17:39:57 alaurin
3847 # restore zebraop for update zebra
3849 # Revision 1.178.2.31 2006/12/01 17:00:19 tipaul
3850 # additem needs $frameworkcode
3852 # Revision 1.178.2.30 2006/11/30 18:23:51 toins
3853 # theses scripts don't need to use C4::Search.
3855 # Revision 1.178.2.29 2006/11/30 17:17:01 toins
3856 # following functions moved from Search.p to Biblio.pm :
3863 # Revision 1.178.2.28 2006/11/28 15:15:03 toins
3864 # sync with dev_week.
3865 # (deleteditems table wasn't getting populaated because the execute was commented out. This puts it back
3866 # -- some table changes are needed as well, I'll commit those separately.)
3868 # Revision 1.178.2.27 2006/11/20 16:52:05 alaurin
3871 # correcting in _koha_modify_biblioitem : restore the biblionumber line .
3873 # now the sql update of biblioitems is ok ....
3875 # Revision 1.178.2.26 2006/11/17 14:57:21 tipaul
3876 # code cleaning : moving bornum, borrnum, bornumber to a correct "borrowernumber"
3878 # Revision 1.178.2.25 2006/11/17 13:18:58 tipaul
3879 # code cleaning : removing use of "bib", and replacing with "biblionumber"
3881 # WARNING : I tried to do carefully, but there are probably some mistakes.
3882 # So if you encounter a problem you didn't have before, look for this change !!!
3883 # anyway, I urge everybody to use only "biblionumber", instead of "bib", "bi", "biblio" or anything else. will be easier to maintain !!!
3885 # Revision 1.178.2.24 2006/11/17 11:18:47 tipaul
3886 # * removing useless subs
3887 # * moving bibid to biblionumber where needed
3889 # Revision 1.178.2.23 2006/11/17 09:39:04 btoumi
3890 # bug fix double declaration of variable in same function
3892 # Revision 1.178.2.22 2006/11/15 15:15:50 hdl
3893 # Final First Version for New Facility for subscription management.
3896 # use serials-collection.pl for history display
3897 # and serials-edit.pl for serial edition
3898 # subscription add and detail adds a new branch information to help IndependantBranches Library to manage different subscriptions for a serial
3900 # This is aimed at replacing serials-receive and statecollection.
3902 # Revision 1.178.2.21 2006/11/15 14:49:38 tipaul
3903 # in some cases, there are invalid utf8 chars in XML (at least in SANOP). this commit remove them on the fly.
3904 # 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...
3906 # Revision 1.178.2.20 2006/10/31 17:20:49 toins
3907 # * moving bibitemdata from search to here.
3908 # * using _koha_modify_biblio instead of OLDmodbiblio.
3910 # Revision 1.178.2.19 2006/10/20 15:26:41 toins
3911 # sync with dev_week.
3913 # Revision 1.178.2.18 2006/10/19 11:57:04 btoumi
3914 # bug fix : wrong syntax in sub call
3916 # Revision 1.178.2.17 2006/10/17 09:54:42 toins
3917 # ccode (re)-integration.
3919 # Revision 1.178.2.16 2006/10/16 16:20:34 toins
3920 # MARCgetbiblio cleaned up.
3922 # Revision 1.178.2.15 2006/10/11 14:26:56 tipaul
3923 # handling of UNIMARC :
3924 # - better management of field 100 = automatic creation of the field if needed & filling encoding to unicode.
3925 # - 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
3926 # - fixing a bug on MARCgetitem, that uses biblioitems.marc and not biblioitems.marcxml
3928 # Revision 1.178.2.14 2006/10/11 07:59:36 tipaul
3929 # removing hardcoded ccode fiels in biblioitems
3931 # Revision 1.178.2.13 2006/10/10 14:21:24 toins
3932 # Biblio.pm now returns a true value.
3934 # Revision 1.178.2.12 2006/10/09 16:44:23 toins
3935 # Sync with dev_week.
3937 # Revision 1.178.2.11 2006/10/06 13:23:49 toins
3938 # Synch with dev_week.
3940 # Revision 1.178.2.10 2006/10/02 09:32:02 hdl
3941 # Adding GetItemStatus and GetItemLocation function in order to make serials-receive.pl work.
3943 # *************WARNING.***************
3944 # tested for UNIMARC and using 'marcflavour' system preferences to set defaut_record_format.
3946 # Revision 1.178.2.9 2006/09/26 07:54:20 hdl
3947 # Bug FIX: Correct accents for UNIMARC biblio MARC details.
3948 # (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)
3950 # Revision 1.178.2.8 2006/09/25 14:46:22 hdl
3951 # Now using iso2709 MARC data for MARC.
3952 # (Works better for accents than XML)
3954 # Revision 1.178.2.7 2006/09/20 13:44:14 hdl
3955 # Bug Fixing : Cataloguing was broken for UNIMARC.