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
125 MARC::Charset->ignore_errors(1);
128 C4::Biblio - acquisitions and cataloging management functions
132 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:
136 =item 1. in the biblio,biblioitems,items, etc tables, which are limited to a one-to-one mapping to underlying MARC data
138 =item 2. as raw MARC in the Zebra index and storage engine
140 =item 3. as raw MARC the biblioitems.marc
144 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.
146 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:
150 =item 1. Compared with MySQL, Zebra is slow to update an index for small data changes -- especially for proc-intensive operations like circulation
152 =item 2. Zebra's index has been known to crash and a backup of the data is necessary to rebuild it in such cases
156 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:
160 =item 1. Add*/Mod*/Del*/ - high-level external functions suitable for being called from external scripts to manage the collection
162 =item 2. _koha_* - low-level internal functions for managing the koha tables
164 =item 3. MARC* functions for interacting with the MARC data in both biblioitems.marc Zebra (biblioitems.marc is authoritative)
166 =item 4. Zebra functions used to update the Zebra index
168 =item 5. internal helper functions such as char_decode, checkitems, etc. Some of these probably belong in Koha.pm
170 =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)
172 In time, as we solidify the new API these older functions will be weeded out.
176 =head1 EXPORTED FUNCTIONS
180 ($biblionumber,$biblioitemnumber) = AddBiblio($record,$frameworkcode);
182 Exported function (core API) for adding a new biblio to koha.
187 my ( $record, $frameworkcode ) = @_;
190 my $dbh = C4::Context->dbh;
191 # transform the data into koha-table style data
192 my $olddata = MARCmarc2koha( $dbh, $record, $frameworkcode );
193 $oldbibnum = _koha_add_biblio( $dbh, $olddata, $frameworkcode );
194 $olddata->{'biblionumber'} = $oldbibnum;
195 $oldbibitemnum = _koha_add_biblioitem( $dbh, $olddata );
197 # we must add bibnum and bibitemnum in MARC::Record...
198 # we build the new field with biblionumber and biblioitemnumber
199 # we drop the original field
200 # we add the new builded field.
201 # NOTE : Works only if the field is ONLY for biblionumber and biblioitemnumber
202 # (steve and paul : thinks 090 is a good choice)
205 "SELECT tagfield,tagsubfield
206 FROM marc_subfield_structure
209 $sth->execute("biblio.biblionumber");
210 ( my $tagfield1, my $tagsubfield1 ) = $sth->fetchrow;
211 $sth->execute("biblioitems.biblioitemnumber");
212 ( my $tagfield2, my $tagsubfield2 ) = $sth->fetchrow;
216 # biblionumber & biblioitemnumber are in different fields
217 if ( $tagfield1 != $tagfield2 ) {
219 # deal with biblionumber
220 if ( $tagfield1 < 10 ) {
221 $newfield = MARC::Field->new( $tagfield1, $oldbibnum, );
225 MARC::Field->new( $tagfield1, '', '',
226 "$tagsubfield1" => $oldbibnum, );
229 # drop old field and create new one...
230 my $old_field = $record->field($tagfield1);
231 $record->delete_field($old_field);
232 $record->append_fields($newfield);
234 # deal with biblioitemnumber
235 if ( $tagfield2 < 10 ) {
236 $newfield = MARC::Field->new( $tagfield2, $oldbibitemnum, );
240 MARC::Field->new( $tagfield2, '', '',
241 "$tagsubfield2" => $oldbibitemnum, );
243 # drop old field and create new one...
244 $old_field = $record->field($tagfield2);
245 $record->delete_field($old_field);
246 $record->insert_fields_ordered($newfield);
248 # biblionumber & biblioitemnumber are in the same field (can't be <10 as fields <10 have only 1 value)
251 my $newfield = MARC::Field->new(
253 "$tagsubfield1" => $oldbibnum,
254 "$tagsubfield2" => $oldbibitemnum
257 # drop old field and create new one...
258 my $old_field = $record->field($tagfield1);
259 $record->delete_field($old_field);
260 $record->insert_fields_ordered($newfield);
263 ###NEU specific add cataloguers cardnumber as well
264 my $cardtag = C4::Context->preference('cataloguersfield');
266 my $tag = substr( $cardtag, 0, 3 );
267 my $subf = substr( $cardtag, 3, 1 );
268 my $me = C4::Context->userenv;
269 my $cataloger = $me->{'cardnumber'} if ($me);
270 my $newtag = MARC::Field->new( $tag, '', '', $subf => $cataloger )
272 $record->delete_field($newtag);
273 $record->insert_fields_ordered($newtag);
278 MARCaddbiblio( $record, $oldbibnum, $frameworkcode );
280 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","ADD",$biblionumber,"biblio")
281 if C4::Context->preference("CataloguingLog");
283 return ( $biblionumber, $oldbibitemnum );
288 $biblionumber = AddItem( $record, $biblionumber)
290 Exported function (core API) for adding a new item to Koha
295 my ( $record, $biblionumber ) = @_;
296 my $dbh = C4::Context->dbh;
299 my $frameworkcode = MARCfind_frameworkcode( $biblionumber );
300 my $item = &MARCmarc2koha( $dbh, $record, $frameworkcode );
302 # needs old biblionumber and biblioitemnumber
303 $item->{'biblionumber'} = $biblionumber;
306 "select biblioitemnumber,itemtype from biblioitems where biblionumber=?"
308 $sth->execute( $item->{'biblionumber'} );
310 ( $item->{'biblioitemnumber'}, $itemtype ) = $sth->fetchrow;
313 "select notforloan from itemtypes where itemtype='$itemtype'");
315 my $notforloan = $sth->fetchrow;
316 ##Change the notforloan field if $notforloan found
317 if ( $notforloan > 0 ) {
318 $item->{'notforloan'} = $notforloan;
319 &MARCitemchange( $record, "items.notforloan", $notforloan );
321 if ( !$item->{'dateaccessioned'} || $item->{'dateaccessioned'} eq '' ) {
324 my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) =
329 "$year-" . sprintf( "%0.2d", $mon ) . "-" . sprintf( "%0.2d", $mday );
330 $item->{'dateaccessioned'} = $date;
331 &MARCitemchange( $record, "items.dateaccessioned", $date );
333 my ( $itemnumber, $error ) =
334 &_koha_new_items( $dbh, $item, $item->{barcode} );
336 # add itemnumber to MARC::Record before adding the item.
339 "select tagfield,tagsubfield from marc_subfield_structure where frameworkcode=? and kohafield=?"
341 &MARCkoha2marcOnefield( $sth, $record, "items.itemnumber", $itemnumber,
344 ##NEU specific add cataloguers cardnumber as well
345 my $cardtag = C4::Context->preference('itemcataloguersubfield');
347 $sth->execute( $frameworkcode, "items.itemnumber" );
348 my ( $itemtag, $subtag ) = $sth->fetchrow;
349 my $me = C4::Context->userenv;
350 my $cataloguer = $me->{'cardnumber'} if ($me);
351 my $newtag = $record->field($itemtag);
352 $newtag->update( $cardtag => $cataloguer ) if ($me);
353 $record->delete_field($newtag);
354 $record->append_fields($newtag);
358 &MARCadditem( $record, $item->{'biblionumber'},$frameworkcode );
360 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","ADD",$itemnumber,"item")
361 if C4::Context->preference("CataloguingLog");
363 return ($item->{biblionumber}, $item->{biblioitemnumber},$itemnumber);
368 ModBiblio( $record,$biblionumber,$frameworkcode);
370 Exported function (core API) to modify a biblio
375 my ( $record, $biblionumber, $frameworkcode ) = @_;
377 if (C4::Context->preference("CataloguingLog")) {
378 my $newrecord = GetMarcBiblio($biblionumber);
379 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","MODIFY",$biblionumber,$newrecord->as_formatted)
382 my $dbh = C4::Context->dbh;
384 $frameworkcode = "" unless $frameworkcode;
386 # update the MARC record with the new record data
387 &MARCmodbiblio( $dbh, $biblionumber, $record, $frameworkcode, 1 );
389 # load the koha-table data object
390 my $oldbiblio = MARCmarc2koha( $dbh, $record, $frameworkcode );
392 # modify the other koha tables
393 my $oldbiblionumber = _koha_modify_biblio( $dbh, $oldbiblio );
394 _koha_modify_biblioitem( $dbh, $oldbiblio );
401 Exported function (core API) for modifying an item in Koha.
406 my ( $record, $biblionumber, $itemnumber, $delete, $new_item_hashref )
410 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","MODIFY",$itemnumber,$record->as_formatted)
411 if C4::Context->preference("CataloguingLog");
413 my $dbh = C4::Context->dbh;
415 # if we have a MARC record, we're coming from cataloging and so
416 # we do the whole routine: update the MARC and zebra, then update the koha
419 my $frameworkcode = MARCfind_frameworkcode( $biblionumber );
420 MARCmoditem( $record, $biblionumber, $itemnumber, $frameworkcode, $delete );
421 my $olditem = MARCmarc2koha( $dbh, $record, $frameworkcode );
422 _koha_modify_item( $dbh, $olditem );
423 return $biblionumber;
426 # otherwise, we're just looking to modify something quickly
427 # (like a status) so we just update the koha tables
428 elsif ($new_item_hashref) {
429 _koha_modify_item( $dbh, $new_item_hashref );
433 =head2 ModBiblioframework
435 ModBiblioframework($biblionumber,$frameworkcode);
437 Exported function to modify a biblio framework
441 sub ModBiblioframework {
442 my ( $biblionumber, $frameworkcode ) = @_;
443 my $dbh = C4::Context->dbh;
446 "UPDATE biblio SET frameworkcode=? WHERE biblionumber=$biblionumber");
448 warn "IN ModBiblioframework";
449 $sth->execute($frameworkcode);
455 my $error = &DelBiblio($dbh,$biblionumber);
457 Exported function (core API) for deleting a biblio in koha.
459 Deletes biblio record from Zebra and Koha tables (biblio,biblioitems,items)
461 Also backs it up to deleted* tables
463 Checks to make sure there are not issues on any of the items
466 C<$error> : undef unless an error occurs
471 my ( $biblionumber ) = @_;
472 my $dbh = C4::Context->dbh;
473 my $error; # for error handling
475 # First make sure there are no items with issues are still attached
478 "SELECT biblioitemnumber FROM biblioitems WHERE biblionumber=?");
479 $sth->execute($biblionumber);
480 while ( my $biblioitemnumber = $sth->fetchrow ) {
481 my @issues = C4::Circulation::Circ2::itemissues($biblioitemnumber);
482 foreach my $issue (@issues) {
483 if ( ( $issue->{date_due} )
484 && ( $issue->{date_due} ne "Available" ) )
487 #FIXME: we need a status system in Biblio like in Circ to return standard codes and messages
488 # instead of hard-coded strings
490 "Item is checked out to a patron -- you must return it before deleting the Biblio";
494 return $error if $error;
497 zebraop($biblionumber,"delete_record","biblioserver");
499 # delete biblio from Koha tables and save in deletedbiblio
500 $error = &_koha_delete_biblio( $dbh, $biblionumber );
502 # delete biblioitems and items from Koha tables and save in deletedbiblioitems,deleteditems
505 "SELECT biblioitemnumber FROM biblioitems WHERE biblionumber=?");
506 $sth->execute($biblionumber);
507 while ( my $biblioitemnumber = $sth->fetchrow ) {
509 # delete this biblioitem
510 $error = &_koha_delete_biblioitems( $dbh, $biblioitemnumber );
511 return $error if $error;
516 "SELECT itemnumber FROM items WHERE biblioitemnumber=?");
517 $items_sth->execute($biblioitemnumber);
518 while ( my $itemnumber = $items_sth->fetchrow ) {
519 $error = &_koha_delete_items( $dbh, $itemnumber );
520 return $error if $error;
523 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","DELETE",$biblionumber,"")
524 if C4::Context->preference("CataloguingLog");
530 DelItem( $biblionumber, $itemnumber );
532 Exported function (core API) for deleting an item record in Koha.
537 my ( $biblionumber, $itemnumber ) = @_;
538 my $dbh = C4::Context->dbh;
539 &_koha_delete_item( $dbh, $itemnumber );
540 my $newrec = &MARCdelitem( $biblionumber, $itemnumber );
541 &MARCaddbiblio( $newrec, $biblionumber, MARCfind_frameworkcode($biblionumber) );
542 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","DELETE",$itemnumber,"item")
543 if C4::Context->preference("CataloguingLog");
548 $data = &GetBiblioData($biblionumber, $type);
550 Returns information about the book with the given biblionumber.
554 C<&GetBiblioData> returns a reference-to-hash. The keys are the fields in
555 the C<biblio> and C<biblioitems> tables in the
558 In addition, C<$data-E<gt>{subject}> is the list of the book's
559 subjects, separated by C<" , "> (space, comma, space).
561 If there are multiple biblioitems with the given biblionumber, only
562 the first one is considered.
568 my ( $bibnum, $type ) = @_;
569 my $dbh = C4::Context->dbh;
572 SELECT * , biblioitems.notes AS bnotes, biblio.notes
574 LEFT JOIN biblioitems ON biblio.biblionumber = biblioitems.biblionumber
575 LEFT JOIN itemtypes ON biblioitems.itemtype = itemtypes.itemtype
576 WHERE biblio.biblionumber = ?
577 AND biblioitems.biblionumber = biblio.biblionumber
579 my $sth = $dbh->prepare($query);
580 $sth->execute($bibnum);
582 $data = $sth->fetchrow_hashref;
586 } # sub GetBiblioData
591 @results = &GetItemsInfo($biblionumber, $type);
593 Returns information about books with the given biblionumber.
595 C<$type> may be either C<intra> or anything else. If it is not set to
596 C<intra>, then the search will exclude lost, very overdue, and
599 C<&GetItemsInfo> returns a list of references-to-hash. Each element
600 contains a number of keys. Most of them are table items from the
601 C<biblio>, C<biblioitems>, C<items>, and C<itemtypes> tables in the
602 Koha database. Other keys include:
606 =item C<$data-E<gt>{branchname}>
608 The name (not the code) of the branch to which the book belongs.
610 =item C<$data-E<gt>{datelastseen}>
612 This is simply C<items.datelastseen>, except that while the date is
613 stored in YYYY-MM-DD format in the database, here it is converted to
614 DD/MM/YYYY format. A NULL date is returned as C<//>.
616 =item C<$data-E<gt>{datedue}>
618 =item C<$data-E<gt>{class}>
620 This is the concatenation of C<biblioitems.classification>, the book's
621 Dewey code, and C<biblioitems.subclass>.
623 =item C<$data-E<gt>{ocount}>
625 I think this is the number of copies of the book available.
627 =item C<$data-E<gt>{order}>
629 If this is set, it is set to C<One Order>.
637 my ( $biblionumber, $type ) = @_;
638 my $dbh = C4::Context->dbh;
639 my $query = "SELECT *,items.notforloan as itemnotforloan
640 FROM items, biblio, biblioitems
641 LEFT JOIN itemtypes on biblioitems.itemtype = itemtypes.itemtype
642 WHERE items.biblionumber = ?
643 AND biblioitems.biblioitemnumber = items.biblioitemnumber
644 AND biblio.biblionumber = items.biblionumber
645 ORDER BY items.dateaccessioned desc
647 my $sth = $dbh->prepare($query);
648 $sth->execute($biblionumber);
651 my ( $date_due, $count_reserves );
653 while ( my $data = $sth->fetchrow_hashref ) {
655 my $isth = $dbh->prepare(
656 "SELECT issues.*,borrowers.cardnumber
657 FROM issues, borrowers
659 AND returndate IS NULL
660 AND issues.borrowernumber=borrowers.borrowernumber"
662 $isth->execute( $data->{'itemnumber'} );
663 if ( my $idata = $isth->fetchrow_hashref ) {
664 $data->{borrowernumber} = $idata->{borrowernumber};
665 $data->{cardnumber} = $idata->{cardnumber};
666 $datedue = format_date( $idata->{'date_due'} );
668 if ( $datedue eq '' ) {
669 #$datedue="Available";
670 my ( $restype, $reserves ) =
671 C4::Reserves2::CheckReserves( $data->{'itemnumber'} );
675 $count_reserves = $restype;
680 #get branch information.....
681 my $bsth = $dbh->prepare(
682 "SELECT * FROM branches WHERE branchcode = ?
685 $bsth->execute( $data->{'holdingbranch'} );
686 if ( my $bdata = $bsth->fetchrow_hashref ) {
687 $data->{'branchname'} = $bdata->{'branchname'};
689 my $date = format_date( $data->{'datelastseen'} );
690 $data->{'datelastseen'} = $date;
691 $data->{'datedue'} = $datedue;
692 $data->{'count_reserves'} = $count_reserves;
694 # get notforloan complete status if applicable
695 my $sthnflstatus = $dbh->prepare(
696 'SELECT authorised_value
697 FROM marc_subfield_structure
698 WHERE kohafield="items.notforloan"
702 $sthnflstatus->execute;
703 my ($authorised_valuecode) = $sthnflstatus->fetchrow;
704 if ($authorised_valuecode) {
705 $sthnflstatus = $dbh->prepare(
706 "SELECT lib FROM authorised_values
708 AND authorised_value=?"
710 $sthnflstatus->execute( $authorised_valuecode,
711 $data->{itemnotforloan} );
712 my ($lib) = $sthnflstatus->fetchrow;
713 $data->{notforloan} = $lib;
716 # my stack procedures
717 my $stackstatus = $dbh->prepare(
718 'SELECT authorised_value
719 FROM marc_subfield_structure
720 WHERE kohafield="items.stack"
723 $stackstatus->execute;
725 ($authorised_valuecode) = $stackstatus->fetchrow;
726 if ($authorised_valuecode) {
727 $stackstatus = $dbh->prepare(
729 FROM authorised_values
731 AND authorised_value=?
734 $stackstatus->execute( $authorised_valuecode, $data->{stack} );
735 my ($lib) = $stackstatus->fetchrow;
736 $data->{stack} = $lib;
738 $results[$i] = $data;
748 $itemstatushash = &getitemstatus($fwkcode);
749 returns information about status.
750 Can be MARC dependant.
752 But basically could be can be loan or not
753 Create a status selector with the following code
755 =head3 in PERL SCRIPT
757 my $itemstatushash = getitemstatus;
759 foreach my $thisstatus (keys %$itemstatushash) {
760 my %row =(value => $thisstatus,
761 statusname => $itemstatushash->{$thisstatus}->{'statusname'},
763 push @itemstatusloop, \%row;
765 $template->param(statusloop=>\@itemstatusloop);
769 <select name="statusloop">
770 <option value="">Default</option>
771 <!-- TMPL_LOOP name="statusloop" -->
772 <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="statusname" --></option>
780 # returns a reference to a hash of references to status...
783 my $dbh = C4::Context->dbh;
785 $fwk = '' unless ($fwk);
786 my ( $tag, $subfield ) =
787 MARCfind_marc_from_kohafield( $dbh, "items.notforloan", $fwk );
788 if ( $tag and $subfield ) {
791 "select authorised_value from marc_subfield_structure where tagfield=? and tagsubfield=? and frameworkcode=?"
793 $sth->execute( $tag, $subfield, $fwk );
794 if ( my ($authorisedvaluecat) = $sth->fetchrow ) {
797 "select authorised_value, lib from authorised_values where category=? order by lib"
799 $authvalsth->execute($authorisedvaluecat);
800 while ( my ( $authorisedvalue, $lib ) = $authvalsth->fetchrow ) {
801 $itemstatus{$authorisedvalue} = $lib;
817 $itemstatus{"1"} = "Not For Loan";
821 =head2 getitemlocation
823 $itemlochash = &getitemlocation($fwk);
824 returns informations about location.
825 where fwk stands for an optional framework code.
826 Create a location selector with the following code
828 =head3 in PERL SCRIPT
830 my $itemlochash = getitemlocation;
832 foreach my $thisloc (keys %$itemlochash) {
833 my $selected = 1 if $thisbranch eq $branch;
834 my %row =(locval => $thisloc,
835 selected => $selected,
836 locname => $itemlochash->{$thisloc},
838 push @itemlocloop, \%row;
840 $template->param(itemlocationloop => \@itemlocloop);
843 <select name="location">
844 <option value="">Default</option>
845 <!-- TMPL_LOOP name="itemlocationloop" -->
846 <option value="<!-- TMPL_VAR name="locval" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="locname" --></option>
852 sub GetItemLocation {
854 # returns a reference to a hash of references to location...
857 my $dbh = C4::Context->dbh;
859 $fwk = '' unless ($fwk);
860 my ( $tag, $subfield ) =
861 MARCfind_marc_from_kohafield( $dbh, "items.location", $fwk );
862 if ( $tag and $subfield ) {
865 "select authorised_value from marc_subfield_structure where tagfield=? and tagsubfield=? and frameworkcode=?"
867 $sth->execute( $tag, $subfield, $fwk );
868 if ( my ($authorisedvaluecat) = $sth->fetchrow ) {
871 "select authorised_value, lib from authorised_values where category=? order by lib"
873 $authvalsth->execute($authorisedvaluecat);
874 while ( my ( $authorisedvalue, $lib ) = $authvalsth->fetchrow ) {
875 $itemlocation{$authorisedvalue} = $lib;
878 return \%itemlocation;
891 $itemlocation{"1"} = "Not For Loan";
892 return \%itemlocation;
895 =head2 &GetBiblioItemData
897 $itemdata = &GetBiblioItemData($biblioitemnumber);
899 Looks up the biblioitem with the given biblioitemnumber. Returns a
900 reference-to-hash. The keys are the fields from the C<biblio>,
901 C<biblioitems>, and C<itemtypes> tables in the Koha database, except
902 that C<biblioitems.notes> is given as C<$itemdata-E<gt>{bnotes}>.
907 sub GetBiblioItemData {
909 my $dbh = C4::Context->dbh;
912 "Select *,biblioitems.notes as bnotes from biblioitems, biblio,itemtypes where biblio.biblionumber = biblioitems.biblionumber and biblioitemnumber = ? and biblioitems.itemtype = itemtypes.itemtype"
916 $sth->execute($bibitem);
918 $data = $sth->fetchrow_hashref;
922 } # sub &GetBiblioItemData
924 =head2 GetItemFromBarcode
926 $result = GetItemFromBarcode($barcode);
930 sub GetItemFromBarcode {
932 my $dbh = C4::Context->dbh;
935 $dbh->prepare("SELECT itemnumber from items where items.barcode=?");
936 $rq->execute($barcode);
937 my ($result) = $rq->fetchrow;
941 =head2 GetBiblioItemByBiblioNumber
943 NOTE : This function has been copy/paste from C4/Biblio.pm from head before zebra integration.
947 sub GetBiblioItemByBiblioNumber {
948 my ($biblionumber) = @_;
949 my $dbh = C4::Context->dbh;
950 my $sth = $dbh->prepare("Select * from biblioitems where biblionumber = ?");
954 $sth->execute($biblionumber);
956 while ( my $data = $sth->fetchrow_hashref ) {
957 push @results, $data;
964 =head2 GetBiblioFromItemNumber
966 $item = &GetBiblioFromItemNumber($itemnumber);
968 Looks up the item with the given itemnumber.
970 C<&itemnodata> returns a reference-to-hash whose keys are the fields
971 from the C<biblio>, C<biblioitems>, and C<items> tables in the Koha
977 sub GetBiblioFromItemNumber {
978 my ( $itemnumber ) = @_;
979 my $dbh = C4::Context->dbh;
981 my $sth = $dbh->prepare(
982 "SELECT * FROM biblio,items,biblioitems
983 WHERE items.itemnumber = ?
984 AND biblio.biblionumber = items.biblionumber
985 AND biblioitems.biblioitemnumber = items.biblioitemnumber"
988 $sth->execute($itemnumber);
989 my $data = $sth->fetchrow_hashref;
996 ( $count, @results ) = &GetBiblio($biblionumber);
1001 my ($biblionumber) = @_;
1002 my $dbh = C4::Context->dbh;
1003 my $sth = $dbh->prepare("Select * from biblio where biblionumber = ?");
1006 $sth->execute($biblionumber);
1007 while ( my $data = $sth->fetchrow_hashref ) {
1008 $results[$count] = $data;
1012 return ( $count, @results );
1015 =head2 getitemsbybiblioitem
1017 ( $count, @results ) = &getitemsbybiblioitem($biblioitemnum);
1021 sub getitemsbybiblioitem {
1022 my ($biblioitemnum) = @_;
1023 my $dbh = C4::Context->dbh;
1024 my $sth = $dbh->prepare(
1025 "Select * from items, biblio where
1026 biblio.biblionumber = items.biblionumber and biblioitemnumber
1030 # || die "Cannot prepare $query\n" . $dbh->errstr;
1034 $sth->execute($biblioitemnum);
1036 # || die "Cannot execute $query\n" . $sth->errstr;
1037 while ( my $data = $sth->fetchrow_hashref ) {
1038 $results[$count] = $data;
1043 return ( $count, @results );
1044 } # sub getitemsbybiblioitem
1046 =head2 get_itemnumbers_of
1048 my @itemnumbers_of = get_itemnumbers_of(@biblionumbers);
1050 Given a list of biblionumbers, return the list of corresponding itemnumbers
1051 for each biblionumber.
1053 Return a reference on a hash where keys are biblionumbers and values are
1054 references on array of itemnumbers.
1058 sub get_itemnumbers_of {
1059 my @biblionumbers = @_;
1061 my $dbh = C4::Context->dbh;
1067 WHERE biblionumber IN (?' . ( ',?' x scalar @biblionumbers - 1 ) . ')
1069 my $sth = $dbh->prepare($query);
1070 $sth->execute(@biblionumbers);
1074 while ( my ( $itemnumber, $biblionumber ) = $sth->fetchrow_array ) {
1075 push @{ $itemnumbers_of{$biblionumber} }, $itemnumber;
1078 return \%itemnumbers_of;
1083 $record = getRecord( $server, $koha_query, $recordSyntax );
1085 get a single record in piggyback mode from Zebra and return it in the requested record syntax
1087 default record syntax is XML
1092 my ( $server, $koha_query, $recordSyntax ) = @_;
1093 $recordSyntax = "xml" unless $recordSyntax;
1094 my $Zconn = C4::Context->Zconn( $server, 0, 1, 1, $recordSyntax );
1095 my $rs = $Zconn->search( new ZOOM::Query::CCL2RPN( $koha_query, $Zconn ) );
1096 if ( $rs->record(0) ) {
1097 return $rs->record(0)->raw();
1101 =head2 GetItemInfosOf
1103 GetItemInfosOf(@itemnumbers);
1107 sub GetItemInfosOf {
1108 my @itemnumbers = @_;
1113 WHERE itemnumber IN (' . join( ',', @itemnumbers ) . ')
1115 return get_infos_of( $query, 'itemnumber' );
1118 =head2 GetBiblioItemInfosOf
1120 GetBiblioItemInfosOf(@biblioitemnumbers);
1124 sub GetBiblioItemInfosOf {
1125 my @biblioitemnumbers = @_;
1128 SELECT biblioitemnumber,
1132 WHERE biblioitemnumber IN (' . join( ',', @biblioitemnumbers ) . ')
1134 return get_infos_of( $query, 'biblioitemnumber' );
1137 =head2 z3950_extended_services
1139 z3950_extended_services($serviceType,$serviceOptions,$record);
1141 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.
1143 C<$serviceType> one of: itemorder,create,drop,commit,update,xmlupdate
1145 C<$serviceOptions> a has of key/value pairs. For instance, if service_type is 'update', $service_options should contain:
1147 action => update action, one of specialUpdate, recordInsert, recordReplace, recordDelete, elementUpdate.
1151 recordidOpaque => Opaque Record ID (user supplied) or recordidNumber => Record ID number (system number).
1152 syntax => the record syntax (transfer syntax)
1153 databaseName = Database from connection object
1155 To set serviceOptions, call set_service_options($serviceType)
1157 C<$record> the record, if one is needed for the service type
1159 A record should be in XML. You can convert it to XML from MARC by running it through marc2xml().
1163 sub z3950_extended_services {
1164 my ( $server, $serviceType, $action, $serviceOptions ) = @_;
1166 # get our connection object
1167 my $Zconn = C4::Context->Zconn( $server, 0, 1 );
1169 # create a new package object
1170 my $Zpackage = $Zconn->package();
1173 $Zpackage->option( action => $action );
1175 if ( $serviceOptions->{'databaseName'} ) {
1176 $Zpackage->option( databaseName => $serviceOptions->{'databaseName'} );
1178 if ( $serviceOptions->{'recordIdNumber'} ) {
1180 recordIdNumber => $serviceOptions->{'recordIdNumber'} );
1182 if ( $serviceOptions->{'recordIdOpaque'} ) {
1184 recordIdOpaque => $serviceOptions->{'recordIdOpaque'} );
1187 # this is an ILL request (Zebra doesn't support it, but Koha could eventually)
1188 #if ($serviceType eq 'itemorder') {
1189 # $Zpackage->option('contact-name' => $serviceOptions->{'contact-name'});
1190 # $Zpackage->option('contact-phone' => $serviceOptions->{'contact-phone'});
1191 # $Zpackage->option('contact-email' => $serviceOptions->{'contact-email'});
1192 # $Zpackage->option('itemorder-item' => $serviceOptions->{'itemorder-item'});
1195 if ( $serviceOptions->{record} ) {
1196 $Zpackage->option( record => $serviceOptions->{record} );
1198 # can be xml or marc
1199 if ( $serviceOptions->{'syntax'} ) {
1200 $Zpackage->option( syntax => $serviceOptions->{'syntax'} );
1204 # send the request, handle any exception encountered
1205 eval { $Zpackage->send($serviceType) };
1206 if ( $@ && $@->isa("ZOOM::Exception") ) {
1207 return "error: " . $@->code() . " " . $@->message() . "\n";
1210 # free up package resources
1211 $Zpackage->destroy();
1214 =head2 set_service_options
1216 my $serviceOptions = set_service_options($serviceType);
1218 C<$serviceType> itemorder,create,drop,commit,update,xmlupdate
1220 Currently, we only support 'create', 'commit', and 'update'. 'drop' support will be added as soon as Zebra supports it.
1224 sub set_service_options {
1225 my ($serviceType) = @_;
1228 # FIXME: This needs to be an OID ... if we ever need 'syntax' this sub will need to change
1229 # $serviceOptions->{ 'syntax' } = ''; #zebra doesn't support syntaxes other than xml
1231 if ( $serviceType eq 'commit' ) {
1235 if ( $serviceType eq 'create' ) {
1239 if ( $serviceType eq 'drop' ) {
1240 die "ERROR: 'drop' not currently supported (by Zebra)";
1242 return $serviceOptions;
1245 =head1 FUNCTIONS FOR HANDLING MARC MANAGEMENT
1247 =head2 MARCgettagslib
1251 sub MARCgettagslib {
1252 my ( $dbh, $forlibrarian, $frameworkcode ) = @_;
1253 $frameworkcode = "" unless $frameworkcode;
1255 my $libfield = ( $forlibrarian eq 1 ) ? 'liblibrarian' : 'libopac';
1257 # check that framework exists
1260 "select count(*) from marc_tag_structure where frameworkcode=?");
1261 $sth->execute($frameworkcode);
1262 my ($total) = $sth->fetchrow;
1263 $frameworkcode = "" unless ( $total > 0 );
1266 "select tagfield,liblibrarian,libopac,mandatory,repeatable from marc_tag_structure where frameworkcode=? order by tagfield"
1268 $sth->execute($frameworkcode);
1269 my ( $liblibrarian, $libopac, $tag, $res, $tab, $mandatory, $repeatable );
1271 while ( ( $tag, $liblibrarian, $libopac, $mandatory, $repeatable ) =
1274 $res->{$tag}->{lib} =
1275 ( $forlibrarian or !$libopac ) ? $liblibrarian : $libopac;
1276 $res->{$tab}->{tab} = ""; # XXX
1277 $res->{$tag}->{mandatory} = $mandatory;
1278 $res->{$tag}->{repeatable} = $repeatable;
1283 "select tagfield,tagsubfield,liblibrarian,libopac,tab, mandatory, repeatable,authorised_value,authtypecode,value_builder,kohafield,seealso,hidden,isurl,link from marc_subfield_structure where frameworkcode=? order by tagfield,tagsubfield"
1285 $sth->execute($frameworkcode);
1288 my $authorised_value;
1299 $tag, $subfield, $liblibrarian,
1301 $mandatory, $repeatable, $authorised_value,
1302 $authtypecode, $value_builder, $kohafield,
1303 $seealso, $hidden, $isurl,
1309 $res->{$tag}->{$subfield}->{lib} =
1310 ( $forlibrarian or !$libopac ) ? $liblibrarian : $libopac;
1311 $res->{$tag}->{$subfield}->{tab} = $tab;
1312 $res->{$tag}->{$subfield}->{mandatory} = $mandatory;
1313 $res->{$tag}->{$subfield}->{repeatable} = $repeatable;
1314 $res->{$tag}->{$subfield}->{authorised_value} = $authorised_value;
1315 $res->{$tag}->{$subfield}->{authtypecode} = $authtypecode;
1316 $res->{$tag}->{$subfield}->{value_builder} = $value_builder;
1317 $res->{$tag}->{$subfield}->{kohafield} = $kohafield;
1318 $res->{$tag}->{$subfield}->{seealso} = $seealso;
1319 $res->{$tag}->{$subfield}->{hidden} = $hidden;
1320 $res->{$tag}->{$subfield}->{isurl} = $isurl;
1321 $res->{$tag}->{$subfield}->{link} = $link;
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.189 2007/03/28 10:39:16 hdl
3701 # removing $dbh as a parameter in AuthoritiesMarc functions
3702 # And reporting all differences into the scripts taht relies on those functions.
3704 # Revision 1.188 2007/03/09 14:31:47 tipaul
3705 # rel_3_0 moved to HEAD
3707 # Revision 1.178.2.59 2007/02/28 10:01:13 toins
3708 # reporting bug fix from 2.2.7.1 to rel_3_0
3710 # BUGFIX/improvement : limiting MARCsubject to 610 as 676 is dewey, and is somewhere else
3712 # Revision 1.178.2.58 2007/02/05 16:50:01 toins
3713 # fix a mod_perl bug:
3714 # There was a global var modified into an internal function in {MARC|ISBD}detail.pl.
3715 # Moving this function in Biblio.pm
3717 # Revision 1.178.2.57 2007/01/25 09:37:58 tipaul
3720 # Revision 1.178.2.56 2007/01/24 13:50:26 tipaul
3722 # removing newbiblio & newbiblioitems subs.
3725 # IMHO, all biblio handling is better handled if they are done in a single place, the subs with MARC::Record as parameters.
3726 # 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.
3727 # 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.
3729 # Revision 1.178.2.55 2007/01/17 18:07:17 alaurin
3730 # bugfixing for zebraqueue_start and biblio.pm :
3732 # - Zebraqueue_start : restoring function of deletion in zebraqueue DB list
3734 # -biblio.pm : changing method of default_record_format, now we have :
3735 # MARC::File::XML->default_record_format(C4::Context->preference('marcflavour'));
3737 # with this line the encoding in zebra seems to be ok (in unimarc and marc21)
3739 # Revision 1.178.2.54 2007/01/16 15:00:03 tipaul
3740 # donc try to delete the biblio in koha, just fill zebraqueue table !
3742 # Revision 1.178.2.53 2007/01/16 10:24:11 tipaul
3744 # when modifying or deleting an item, the biblio frameworkcode was emptied.
3746 # Revision 1.178.2.52 2007/01/15 17:20:55 toins
3747 # *** empty log message ***
3749 # Revision 1.178.2.51 2007/01/15 15:16:44 hdl
3750 # Uncommenting zebraop.
3752 # Revision 1.178.2.50 2007/01/15 14:59:09 hdl
3753 # Adding creation of an unexpected serial any time.
3755 # USING Date::Calc and not Date::Manip.
3756 # WARNING : There are still some Bugs in next issue date management. (Date::Calc donot wrap easily next year calculation.)
3758 # Revision 1.178.2.49 2007/01/12 10:12:30 toins
3759 # writing $record->as_formatted in the log when Modifying an item.
3761 # Revision 1.178.2.48 2007/01/11 16:33:04 toins
3762 # write $record->as_formatted into the log.
3764 # Revision 1.178.2.47 2007/01/10 16:46:27 toins
3765 # Theses modules need to use C4::Log.
3767 # Revision 1.178.2.46 2007/01/10 16:31:15 toins
3768 # new systems preferences :
3769 # - CataloguingLog (log the update/creation/deletion of a notice if set to 1)
3770 # - BorrowersLog ( idem for borrowers )
3771 # - IssueLog (log all issue if set to 1)
3772 # - ReturnLog (log all return if set to 1)
3773 # - SusbcriptionLog (log all creation/deletion/update of a subcription)
3775 # All of theses are in a new tab called 'LOGFeatures' in systempreferences.pl
3777 # Revision 1.178.2.45 2007/01/09 10:31:09 toins
3778 # sync with dev_week. ( new function : GetMarcSeries )
3780 # Revision 1.178.2.44 2007/01/04 17:41:32 tipaul
3781 # 2 major bugfixes :
3782 # - deletion of an item deleted the whole biblio because of a wrong API
3783 # - create an item was bugguy for default framework
3785 # Revision 1.178.2.43 2006/12/22 15:09:53 toins
3786 # removing C4::Database;
3788 # Revision 1.178.2.42 2006/12/20 16:51:00 tipaul
3790 # - adding a new table : when a biblio is added/modified/ deleted, an entry is entered in this table
3791 # - the zebraqueue_start.pl script read it & does the stuff.
3793 # code coming from head (tumer). it can be run every minut instead of once every day for dev_week code.
3795 # 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 !
3797 # Revision 1.178.2.41 2006/12/20 08:54:44 toins
3798 # GetXmlBiblio wasn't exported.
3800 # Revision 1.178.2.40 2006/12/19 16:45:56 alaurin
3801 # bugfixing, for zebra and authorities
3803 # Revision 1.178.2.39 2006/12/08 17:55:44 toins
3804 # GetMarcAuthors now get authors for all subfields
3806 # Revision 1.178.2.38 2006/12/07 15:42:14 toins
3807 # synching opac & intranet.
3808 # fix some broken link & bugs.
3809 # removing warn compilation.
3811 # Revision 1.178.2.37 2006/12/07 11:09:39 tipaul
3813 # 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.
3814 # BUT for bulkmarcimport & mod_perl, the zebra conn must be persistant.
3816 # Revision 1.178.2.36 2006/12/06 16:54:21 alaurin
3817 # restore function zebraop for delete biblios :
3819 # 1) restore C4::Circulation::Circ2::itemissues, (was missing)
3820 # 2) restore zebraop value : delete_record
3822 # Revision 1.178.2.35 2006/12/06 10:02:12 alaurin
3823 # bugfixing for delete a biblio :
3825 # restore itemissue fonction .... :
3827 # other is pointed, zebra error 224... for biblio is not deleted in zebra ..
3830 # Revision 1.178.2.34 2006/12/06 09:14:25 toins
3831 # Correct the link to the MARC subjects.
3833 # Revision 1.178.2.33 2006/12/05 11:35:29 toins
3834 # Biblio.pm cleaned.
3835 # additionalauthors, bibliosubject, bibliosubtitle tables are now unused.
3836 # Some functions renamed according to the coding guidelines.
3838 # Revision 1.178.2.32 2006/12/04 17:39:57 alaurin
3841 # restore zebraop for update zebra
3843 # Revision 1.178.2.31 2006/12/01 17:00:19 tipaul
3844 # additem needs $frameworkcode
3846 # Revision 1.178.2.30 2006/11/30 18:23:51 toins
3847 # theses scripts don't need to use C4::Search.
3849 # Revision 1.178.2.29 2006/11/30 17:17:01 toins
3850 # following functions moved from Search.p to Biblio.pm :
3857 # Revision 1.178.2.28 2006/11/28 15:15:03 toins
3858 # sync with dev_week.
3859 # (deleteditems table wasn't getting populaated because the execute was commented out. This puts it back
3860 # -- some table changes are needed as well, I'll commit those separately.)
3862 # Revision 1.178.2.27 2006/11/20 16:52:05 alaurin
3865 # correcting in _koha_modify_biblioitem : restore the biblionumber line .
3867 # now the sql update of biblioitems is ok ....
3869 # Revision 1.178.2.26 2006/11/17 14:57:21 tipaul
3870 # code cleaning : moving bornum, borrnum, bornumber to a correct "borrowernumber"
3872 # Revision 1.178.2.25 2006/11/17 13:18:58 tipaul
3873 # code cleaning : removing use of "bib", and replacing with "biblionumber"
3875 # WARNING : I tried to do carefully, but there are probably some mistakes.
3876 # So if you encounter a problem you didn't have before, look for this change !!!
3877 # anyway, I urge everybody to use only "biblionumber", instead of "bib", "bi", "biblio" or anything else. will be easier to maintain !!!
3879 # Revision 1.178.2.24 2006/11/17 11:18:47 tipaul
3880 # * removing useless subs
3881 # * moving bibid to biblionumber where needed
3883 # Revision 1.178.2.23 2006/11/17 09:39:04 btoumi
3884 # bug fix double declaration of variable in same function
3886 # Revision 1.178.2.22 2006/11/15 15:15:50 hdl
3887 # Final First Version for New Facility for subscription management.
3890 # use serials-collection.pl for history display
3891 # and serials-edit.pl for serial edition
3892 # subscription add and detail adds a new branch information to help IndependantBranches Library to manage different subscriptions for a serial
3894 # This is aimed at replacing serials-receive and statecollection.
3896 # Revision 1.178.2.21 2006/11/15 14:49:38 tipaul
3897 # in some cases, there are invalid utf8 chars in XML (at least in SANOP). this commit remove them on the fly.
3898 # 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...
3900 # Revision 1.178.2.20 2006/10/31 17:20:49 toins
3901 # * moving bibitemdata from search to here.
3902 # * using _koha_modify_biblio instead of OLDmodbiblio.
3904 # Revision 1.178.2.19 2006/10/20 15:26:41 toins
3905 # sync with dev_week.
3907 # Revision 1.178.2.18 2006/10/19 11:57:04 btoumi
3908 # bug fix : wrong syntax in sub call
3910 # Revision 1.178.2.17 2006/10/17 09:54:42 toins
3911 # ccode (re)-integration.
3913 # Revision 1.178.2.16 2006/10/16 16:20:34 toins
3914 # MARCgetbiblio cleaned up.
3916 # Revision 1.178.2.15 2006/10/11 14:26:56 tipaul
3917 # handling of UNIMARC :
3918 # - better management of field 100 = automatic creation of the field if needed & filling encoding to unicode.
3919 # - 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
3920 # - fixing a bug on MARCgetitem, that uses biblioitems.marc and not biblioitems.marcxml
3922 # Revision 1.178.2.14 2006/10/11 07:59:36 tipaul
3923 # removing hardcoded ccode fiels in biblioitems
3925 # Revision 1.178.2.13 2006/10/10 14:21:24 toins
3926 # Biblio.pm now returns a true value.
3928 # Revision 1.178.2.12 2006/10/09 16:44:23 toins
3929 # Sync with dev_week.
3931 # Revision 1.178.2.11 2006/10/06 13:23:49 toins
3932 # Synch with dev_week.
3934 # Revision 1.178.2.10 2006/10/02 09:32:02 hdl
3935 # Adding GetItemStatus and GetItemLocation function in order to make serials-receive.pl work.
3937 # *************WARNING.***************
3938 # tested for UNIMARC and using 'marcflavour' system preferences to set defaut_record_format.
3940 # Revision 1.178.2.9 2006/09/26 07:54:20 hdl
3941 # Bug FIX: Correct accents for UNIMARC biblio MARC details.
3942 # (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)
3944 # Revision 1.178.2.8 2006/09/25 14:46:22 hdl
3945 # Now using iso2709 MARC data for MARC.
3946 # (Works better for accents than XML)
3948 # Revision 1.178.2.7 2006/09/20 13:44:14 hdl
3949 # Bug Fixing : Cataloguing was broken for UNIMARC.