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
26 use MARC::File::USMARC;
31 use C4::Dates qw/format_date/;
32 use C4::Log; # logaction
34 use vars qw($VERSION @ISA @EXPORT);
39 @ISA = qw( Exporter );
43 # to add biblios or items
44 push @EXPORT, qw( &AddBiblio &AddBiblioAndItems );
52 &GetBiblioItemByBiblioNumber
53 &GetBiblioFromItemNumber
63 &GetItemnumberFromBarcode
66 &GetAuthorisedValueDesc
70 &GetPublisherNameFromIsbn
88 # those functions are exported but should not be used
89 # they are usefull is few circumstances, so are exported.
90 # but don't use them unless you're a core developer ;-)
101 &PrepareItemrecordDisplay
108 C4::Biblio - cataloging management functions
112 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:
116 =item 1. in the biblio,biblioitems,items, etc tables, which are limited to a one-to-one mapping to underlying MARC data
118 =item 2. as raw MARC in the Zebra index and storage engine
120 =item 3. as raw MARC the biblioitems.marc and biblioitems.marcxml
124 In the 3.0 version of Koha, the authoritative record-level information is in biblioitems.marcxml
126 Because the data isn't completely normalized there's a chance for information to get out of sync. The design choice to go with a un-normalized schema was driven by performance and stability concerns. However, if this occur, it can be considered as a bug : The API is (or should be) complete & the only entry point for all biblio/items managements.
130 =item 1. Compared with MySQL, Zebra is slow to update an index for small data changes -- especially for proc-intensive operations like circulation
132 =item 2. Zebra's index has been known to crash and a backup of the data is necessary to rebuild it in such cases
136 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:
140 =item 1. Add*/Mod*/Del*/ - high-level external functions suitable for being called from external scripts to manage the collection
142 =item 2. _koha_* - low-level internal functions for managing the koha tables
144 =item 3. Marc management function : as the MARC record is stored in biblioitems.marc(xml), some subs dedicated to it's management are in this package. They should be used only internally by Biblio.pm, the only official entry points being AddBiblio, AddItem, ModBiblio, ModItem.
146 =item 4. Zebra functions used to update the Zebra index
148 =item 5. internal helper functions such as char_decode, checkitems, etc. Some of these probably belong in Koha.pm
152 The MARC record (in biblioitems.marcxml) contains the complete marc record, including items. It also contains the biblionumber. That is the reason why it is not stored directly by AddBiblio, with all other fields . To save a biblio, we need to :
156 =item 1. save datas in biblio and biblioitems table, that gives us a biblionumber and a biblioitemnumber
158 =item 2. add the biblionumber and biblioitemnumber into the MARC records
160 =item 3. save the marc record
164 When dealing with items, we must :
168 =item 1. save the item in items table, that gives us an itemnumber
170 =item 2. add the itemnumber to the item MARC field
172 =item 3. overwrite the MARC record (with the added item) into biblioitems.marc(xml)
174 When modifying a biblio or an item, the behaviour is quite similar.
178 =head1 EXPORTED FUNCTIONS
184 ($biblionumber,$biblioitemnumber) = AddBiblio($record,$frameworkcode);
185 Exported function (core API) for adding a new biblio to koha.
192 my ( $record, $frameworkcode ) = @_;
193 my ($biblionumber,$biblioitemnumber,$error);
194 my $dbh = C4::Context->dbh;
195 # transform the data into koha-table style data
196 my $olddata = TransformMarcToKoha( $dbh, $record, $frameworkcode );
197 ($biblionumber,$error) = _koha_add_biblio( $dbh, $olddata, $frameworkcode );
198 $olddata->{'biblionumber'} = $biblionumber;
199 ($biblioitemnumber,$error) = _koha_add_biblioitem( $dbh, $olddata );
201 _koha_marc_update_bib_ids($record, $frameworkcode, $biblionumber, $biblioitemnumber);
204 $biblionumber = ModBiblioMarc( $record, $biblionumber, $frameworkcode );
206 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","ADD",$biblionumber,"biblio")
207 if C4::Context->preference("CataloguingLog");
209 return ( $biblionumber, $biblioitemnumber );
212 =head2 AddBiblioAndItems
216 ($biblionumber,$biblioitemnumber, $itemnumber_ref, $error_ref) = AddBiblioAndItems($record, $frameworkcode);
220 Efficiently add a biblio record and create item records from its
221 embedded item fields. This routine is suitable for batch jobs.
223 The goal of this API is to have a similar effect to using AddBiblio
224 and AddItems in succession, but without inefficient repeated
225 parsing of the MARC XML bib record.
227 One functional difference is that the duplicate item barcode
228 check is implemented in this API, instead of relying on
229 the caller to do it, like AddItem does.
231 This function returns the biblionumber and biblioitemnumber of the
232 new bib, an arrayref of new itemsnumbers, and an arrayref of item
233 errors encountered during the processing. Each entry in the errors
234 list is a hashref containing the following keys:
240 Sequence number of original item tag in the MARC record.
244 Item barcode, provide to assist in the construction of
245 useful error messages.
247 =item error_condition
249 Code representing the error condition. Can be 'duplicate_barcode',
250 'invalid_homebranch', or 'invalid_holdingbranch'.
252 =item error_information
254 Additional information appropriate to the error condition.
260 sub AddBiblioAndItems {
261 my ( $record, $frameworkcode ) = @_;
262 my ($biblionumber,$biblioitemnumber,$error);
263 my @itemnumbers = ();
265 my $dbh = C4::Context->dbh;
267 # transform the data into koha-table style data
268 # FIXME - this paragraph copied from AddBiblio
269 my $olddata = TransformMarcToKoha( $dbh, $record, $frameworkcode );
270 ($biblionumber,$error) = _koha_add_biblio( $dbh, $olddata, $frameworkcode );
271 $olddata->{'biblionumber'} = $biblionumber;
272 ($biblioitemnumber,$error) = _koha_add_biblioitem( $dbh, $olddata );
274 # FIXME - this paragraph copied from AddBiblio
275 _koha_marc_update_bib_ids($record, $frameworkcode, $biblionumber, $biblioitemnumber);
277 # now we loop through the item tags and start creating items
278 my @bad_item_fields = ();
279 my ($itemtag, $itemsubfield) = &GetMarcFromKohaField("items.itemnumber",'');
280 my $item_sequence_num = 0;
281 ITEMFIELD: foreach my $item_field ($record->field($itemtag)) {
282 $item_sequence_num++;
283 # we take the item field and stick it into a new
284 # MARC record -- this is required so far because (FIXME)
285 # TransformMarcToKoha requires a MARC::Record, not a MARC::Field
286 # and there is no TransformMarcFieldToKoha
287 my $temp_item_marc = MARC::Record->new();
288 $temp_item_marc->append_fields($item_field);
290 # add biblionumber and biblioitemnumber
291 my $item = TransformMarcToKoha( $dbh, $temp_item_marc, $frameworkcode, 'items' );
292 $item->{'biblionumber'} = $biblionumber;
293 $item->{'biblioitemnumber'} = $biblioitemnumber;
295 # check for duplicate barcode
296 my %item_errors = CheckItemPreSave($item);
298 push @errors, _repack_item_errors($item_sequence_num, $item, \%item_errors);
299 push @bad_item_fields, $item_field;
302 my $duplicate_barcode = exists($item->{'barcode'}) && GetItemnumberFromBarcode($item->{'barcode'});
303 if ($duplicate_barcode) {
304 warn "ERROR: cannot add item $item->{'barcode'} for biblio $biblionumber: duplicate barcode\n";
307 # Make sure item statuses are set to 0 if empty or NULL in both the item and the MARC
308 for ('notforloan', 'damaged','itemlost','wthdrawn') {
309 if (!$item->{$_} or $item->{$_} eq "") {
311 &MARCitemchange( $temp_item_marc, "items.$_", 0 );
315 # FIXME - dateaccessioned stuff copied from AddItem
316 if ( !$item->{'dateaccessioned'} || $item->{'dateaccessioned'} eq '' ) {
319 my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) =
324 "$year-" . sprintf( "%0.2d", $mon ) . "-" . sprintf( "%0.2d", $mday );
325 $item->{'dateaccessioned'} = $date;
326 &MARCitemchange( $temp_item_marc, "items.dateaccessioned", $date );
329 my ( $itemnumber, $error ) = &_koha_new_items( $dbh, $item, $item->{barcode} );
330 warn $error if $error;
331 push @itemnumbers, $itemnumber; # FIXME not checking error
333 # FIXME - not copied from AddItem
334 # FIXME - AddItems equiv code about passing $sth to TransformKohaToMarcOneField is stupid
335 &MARCitemchange( $temp_item_marc, "items.itemnumber", $itemnumber );
337 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","ADD",$itemnumber,"item")
338 if C4::Context->preference("CataloguingLog");
340 $item_field->replace_with($temp_item_marc->field($itemtag));
343 # remove any MARC item fields for rejected items
344 foreach my $item_field (@bad_item_fields) {
345 $record->delete_field($item_field);
349 # FIXME - this paragraph copied from AddBiblio -- however, moved since
350 # since we need to create the items row and plug in the itemnumbers in the
352 $biblionumber = ModBiblioMarc( $record, $biblionumber, $frameworkcode );
354 # FIXME - when using this API, do we log both bib and item add, or just
356 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","ADD",$biblionumber,"biblio")
357 if C4::Context->preference("CataloguingLog");
359 return ( $biblionumber, $biblioitemnumber, \@itemnumbers, \@errors);
363 sub _repack_item_errors {
364 my $item_sequence_num = shift;
365 my $item_ref = shift;
366 my $error_ref = shift;
368 my @repacked_errors = ();
370 foreach my $error_code (sort keys %{ $error_ref }) {
371 my $repacked_error = {};
372 $repacked_error->{'item_sequence'} = $item_sequence_num;
373 $repacked_error->{'item_barcode'} = exists($item_ref->{'barcode'}) ? $item_ref->{'barcode'} : '';
374 $repacked_error->{'error_code'} = $error_code;
375 $repacked_error->{'error_information'} = $error_ref->{$error_code};
376 push @repacked_errors, $repacked_error;
379 return @repacked_errors;
384 ModBiblio( $record,$biblionumber,$frameworkcode);
385 Exported function (core API) to modify a biblio
390 my ( $record, $biblionumber, $frameworkcode ) = @_;
391 if (C4::Context->preference("CataloguingLog")) {
392 my $newrecord = GetMarcBiblio($biblionumber);
393 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","MODIFY",$biblionumber,"BEFORE=>".$newrecord->as_formatted);
396 my $dbh = C4::Context->dbh;
398 $frameworkcode = "" unless $frameworkcode;
400 # get the items before and append them to the biblio before updating the record, atm we just have the biblio
401 my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField("items.itemnumber",$frameworkcode);
402 my $oldRecord = GetMarcBiblio( $biblionumber );
404 # parse each item, and, for an unknown reason, re-encode each subfield
405 # if you don't do that, the record will have encoding mixed
406 # and the biblio will be re-encoded.
407 # strange, I (Paul P.) searched more than 1 day to understand what happends
408 # but could only solve the problem this way...
409 my @fields = $oldRecord->field( $itemtag );
410 foreach my $fielditem ( @fields ){
412 foreach ($fielditem->subfields()) {
414 $field->add_subfields(Encode::encode('utf-8',$_->[0]) => Encode::encode('utf-8',$_->[1]));
416 $field = MARC::Field->new("$itemtag",'','',Encode::encode('utf-8',$_->[0]) => Encode::encode('utf-8',$_->[1]));
419 $record->append_fields($field);
422 # update biblionumber and biblioitemnumber in MARC
423 # FIXME - this is assuming a 1 to 1 relationship between
424 # biblios and biblioitems
425 my $sth = $dbh->prepare("select biblioitemnumber from biblioitems where biblionumber=?");
426 $sth->execute($biblionumber);
427 my ($biblioitemnumber) = $sth->fetchrow;
429 _koha_marc_update_bib_ids($record, $frameworkcode, $biblionumber, $biblioitemnumber);
431 # update the MARC record (that now contains biblio and items) with the new record data
432 &ModBiblioMarc( $record, $biblionumber, $frameworkcode );
434 # load the koha-table data object
435 my $oldbiblio = TransformMarcToKoha( $dbh, $record, $frameworkcode );
437 # modify the other koha tables
438 _koha_modify_biblio( $dbh, $oldbiblio, $frameworkcode );
439 _koha_modify_biblioitem_nonmarc( $dbh, $oldbiblio );
443 =head2 ModBiblioframework
445 ModBiblioframework($biblionumber,$frameworkcode);
446 Exported function to modify a biblio framework
450 sub ModBiblioframework {
451 my ( $biblionumber, $frameworkcode ) = @_;
452 my $dbh = C4::Context->dbh;
453 my $sth = $dbh->prepare(
454 "UPDATE biblio SET frameworkcode=? WHERE biblionumber=?"
456 $sth->execute($frameworkcode, $biblionumber);
464 my $error = &DelBiblio($dbh,$biblionumber);
465 Exported function (core API) for deleting a biblio in koha.
466 Deletes biblio record from Zebra and Koha tables (biblio,biblioitems,items)
467 Also backs it up to deleted* tables
468 Checks to make sure there are not issues on any of the items
470 C<$error> : undef unless an error occurs
477 my ( $biblionumber ) = @_;
478 my $dbh = C4::Context->dbh;
479 my $error; # for error handling
481 # First make sure this biblio has no items attached
482 my $sth = $dbh->prepare("SELECT itemnumber FROM items WHERE biblionumber=?");
483 $sth->execute($biblionumber);
484 if (my $itemnumber = $sth->fetchrow){
485 # Fix this to use a status the template can understand
486 $error .= "This Biblio has items attached, please delete them first before deleting this biblio ";
489 return $error if $error;
491 # Delete in Zebra. Be careful NOT to move this line after _koha_delete_biblio
492 # for at least 2 reasons :
493 # - we need to read the biblio if NoZebra is set (to remove it from the indexes
494 # - if something goes wrong, the biblio may be deleted from Koha but not from zebra
495 # and we would have no way to remove it (except manually in zebra, but I bet it would be very hard to handle the problem)
496 ModZebra($biblionumber, "recordDelete", "biblioserver", undef);
498 # delete biblioitems and items from Koha tables and save in deletedbiblioitems,deleteditems
501 "SELECT biblioitemnumber FROM biblioitems WHERE biblionumber=?");
502 $sth->execute($biblionumber);
503 while ( my $biblioitemnumber = $sth->fetchrow ) {
505 # delete this biblioitem
506 $error = _koha_delete_biblioitems( $dbh, $biblioitemnumber );
507 return $error if $error;
510 # delete biblio from Koha tables and save in deletedbiblio
511 # must do this *after* _koha_delete_biblioitems, otherwise
512 # delete cascade will prevent deletedbiblioitems rows
513 # from being generated by _koha_delete_biblioitems
514 $error = _koha_delete_biblio( $dbh, $biblionumber );
516 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","DELETE",$biblionumber,"")
517 if C4::Context->preference("CataloguingLog");
525 DelItem( $biblionumber, $itemnumber );
526 Exported function (core API) for deleting an item record in Koha.
533 my ( $dbh, $biblionumber, $itemnumber ) = @_;
535 # check the item has no current issues
538 &_koha_delete_item( $dbh, $itemnumber );
540 # get the MARC record
541 my $record = GetMarcBiblio($biblionumber);
542 my $frameworkcode = GetFrameworkCode($biblionumber);
545 my $copy2deleted = $dbh->prepare("UPDATE deleteditems SET marc=? WHERE itemnumber=?");
546 $copy2deleted->execute( $record->as_usmarc(), $itemnumber );
548 #search item field code
549 my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField("items.itemnumber",$frameworkcode);
550 my @fields = $record->field($itemtag);
552 # delete the item specified
553 foreach my $field (@fields) {
554 if ( $field->subfield($itemsubfield) eq $itemnumber ) {
555 $record->delete_field($field);
558 &ModBiblioMarc( $record, $biblionumber, $frameworkcode );
559 &logaction(C4::Context->userenv->{'number'},"CATALOGUING","DELETE",$itemnumber,"item")
560 if C4::Context->preference("CataloguingLog");
563 =head2 CheckItemPreSave
567 my $item_ref = TransformMarcToKoha($marc, 'items');
569 my %errors = CheckItemPreSave($item_ref);
570 if (exists $errors{'duplicate_barcode'}) {
571 print "item has duplicate barcode: ", $errors{'duplicate_barcode'}, "\n";
572 } elsif (exists $errors{'invalid_homebranch'}) {
573 print "item has invalid home branch: ", $errors{'invalid_homebranch'}, "\n";
574 } elsif (exists $errors{'invalid_holdingbranch'}) {
575 print "item has invalid holding branch: ", $errors{'invalid_holdingbranch'}, "\n";
582 Given a hashref containing item fields, determine if it can be
583 inserted or updated in the database. Specifically, checks for
584 database integrity issues, and returns a hash containing any
585 of the following keys, if applicable.
589 =item duplicate_barcode
591 Barcode, if it duplicates one already found in the database.
593 =item invalid_homebranch
595 Home branch, if not defined in branches table.
597 =item invalid_holdingbranch
599 Holding branch, if not defined in branches table.
603 This function does NOT implement any policy-related checks,
604 e.g., whether current operator is allowed to save an
605 item that has a given branch code.
609 sub CheckItemPreSave {
610 my $item_ref = shift;
614 # check for duplicate barcode
615 if (exists $item_ref->{'barcode'} and defined $item_ref->{'barcode'}) {
616 my $existing_itemnumber = GetItemnumberFromBarcode($item_ref->{'barcode'});
617 if ($existing_itemnumber) {
618 if (!exists $item_ref->{'itemnumber'} # new item
619 or $item_ref->{'itemnumber'} != $existing_itemnumber) { # existing item
620 $errors{'duplicate_barcode'} = $item_ref->{'barcode'};
625 # check for valid home branch
626 if (exists $item_ref->{'homebranch'} and defined $item_ref->{'homebranch'}) {
627 my $branch_name = GetBranchName($item_ref->{'homebranch'});
628 unless (defined $branch_name) {
629 # relies on fact that branches.branchname is a non-NULL column,
630 # so GetBranchName returns undef only if branch does not exist
631 $errors{'invalid_homebranch'} = $item_ref->{'homebranch'};
635 # check for valid holding branch
636 if (exists $item_ref->{'holdingbranch'} and defined $item_ref->{'holdingbranch'}) {
637 my $branch_name = GetBranchName($item_ref->{'holdingbranch'});
638 unless (defined $branch_name) {
639 # relies on fact that branches.branchname is a non-NULL column,
640 # so GetBranchName returns undef only if branch does not exist
641 $errors{'invalid_holdingbranch'} = $item_ref->{'holdingbranch'};
653 $data = &GetBiblioData($biblionumber);
654 Returns information about the book with the given biblionumber.
655 C<&GetBiblioData> returns a reference-to-hash. The keys are the fields in
656 the C<biblio> and C<biblioitems> tables in the
658 In addition, C<$data-E<gt>{subject}> is the list of the book's
659 subjects, separated by C<" , "> (space, comma, space).
660 If there are multiple biblioitems with the given biblionumber, only
661 the first one is considered.
669 my $dbh = C4::Context->dbh;
671 # my $query = C4::Context->preference('item-level_itypes') ?
672 # " SELECT * , biblioitems.notes AS bnotes, biblio.notes
674 # LEFT JOIN biblioitems ON biblio.biblionumber = biblioitems.biblionumber
675 # WHERE biblio.biblionumber = ?
676 # AND biblioitems.biblionumber = biblio.biblionumber
679 my $query = " SELECT * , biblioitems.notes AS bnotes, itemtypes.notforloan as bi_notforloan, biblio.notes
681 LEFT JOIN biblioitems ON biblio.biblionumber = biblioitems.biblionumber
682 LEFT JOIN itemtypes ON biblioitems.itemtype = itemtypes.itemtype
683 WHERE biblio.biblionumber = ?
684 AND biblioitems.biblionumber = biblio.biblionumber ";
686 my $sth = $dbh->prepare($query);
687 $sth->execute($bibnum);
689 $data = $sth->fetchrow_hashref;
693 } # sub GetBiblioData
695 =head2 &GetBiblioItemData
699 $itemdata = &GetBiblioItemData($biblioitemnumber);
701 Looks up the biblioitem with the given biblioitemnumber. Returns a
702 reference-to-hash. The keys are the fields from the C<biblio>,
703 C<biblioitems>, and C<itemtypes> tables in the Koha database, except
704 that C<biblioitems.notes> is given as C<$itemdata-E<gt>{bnotes}>.
711 sub GetBiblioItemData {
712 my ($biblioitemnumber) = @_;
713 my $dbh = C4::Context->dbh;
714 my $query = "SELECT *,biblioitems.notes AS bnotes
715 FROM biblio, biblioitems ";
716 unless(C4::Context->preference('item-level_itypes')) {
717 $query .= "LEFT JOIN itemtypes on biblioitems.itemtype=itemtypes.itemtype ";
719 $query .= " WHERE biblio.biblionumber = biblioitems.biblionumber
720 AND biblioitemnumber = ? ";
721 my $sth = $dbh->prepare($query);
723 $sth->execute($biblioitemnumber);
724 $data = $sth->fetchrow_hashref;
727 } # sub &GetBiblioItemData
729 =head2 GetItemnumberFromBarcode
733 $result = GetItemnumberFromBarcode($barcode);
739 sub GetItemnumberFromBarcode {
741 my $dbh = C4::Context->dbh;
744 $dbh->prepare("SELECT itemnumber FROM items WHERE items.barcode=?");
745 $rq->execute($barcode);
746 my ($result) = $rq->fetchrow;
750 =head2 GetBiblioItemByBiblioNumber
754 NOTE : This function has been copy/paste from C4/Biblio.pm from head before zebra integration.
760 sub GetBiblioItemByBiblioNumber {
761 my ($biblionumber) = @_;
762 my $dbh = C4::Context->dbh;
763 my $sth = $dbh->prepare("Select * FROM biblioitems WHERE biblionumber = ?");
767 $sth->execute($biblionumber);
769 while ( my $data = $sth->fetchrow_hashref ) {
770 push @results, $data;
777 =head2 GetBiblioFromItemNumber
781 $item = &GetBiblioFromItemNumber($itemnumber,$barcode);
783 Looks up the item with the given itemnumber. if undef, try the barcode.
785 C<&itemnodata> returns a reference-to-hash whose keys are the fields
786 from the C<biblio>, C<biblioitems>, and C<items> tables in the Koha
794 sub GetBiblioFromItemNumber {
795 my ( $itemnumber, $barcode ) = @_;
796 my $dbh = C4::Context->dbh;
799 $sth=$dbh->prepare( "SELECT * FROM items
800 LEFT JOIN biblio ON biblio.biblionumber = items.biblionumber
801 LEFT JOIN biblioitems ON biblioitems.biblioitemnumber = items.biblioitemnumber
802 WHERE items.itemnumber = ?") ;
803 $sth->execute($itemnumber);
805 $sth=$dbh->prepare( "SELECT * FROM items
806 LEFT JOIN biblio ON biblio.biblionumber = items.biblionumber
807 LEFT JOIN biblioitems ON biblioitems.biblioitemnumber = items.biblioitemnumber
808 WHERE items.barcode = ?") ;
809 $sth->execute($barcode);
811 my $data = $sth->fetchrow_hashref;
820 ( $count, @results ) = &GetBiblio($biblionumber);
827 my ($biblionumber) = @_;
828 my $dbh = C4::Context->dbh;
829 my $sth = $dbh->prepare("SELECT * FROM biblio WHERE biblionumber = ?");
832 $sth->execute($biblionumber);
833 while ( my $data = $sth->fetchrow_hashref ) {
834 $results[$count] = $data;
838 return ( $count, @results );
841 =head2 GetBiblioItemInfosOf
845 GetBiblioItemInfosOf(@biblioitemnumbers);
851 sub GetBiblioItemInfosOf {
852 my @biblioitemnumbers = @_;
855 SELECT biblioitemnumber,
859 WHERE biblioitemnumber IN (' . join( ',', @biblioitemnumbers ) . ')
861 return get_infos_of( $query, 'biblioitemnumber' );
864 =head1 FUNCTIONS FOR HANDLING MARC MANAGEMENT
866 =head2 GetMarcStructure
870 $res = GetMarcStructure($forlibrarian,$frameworkcode);
872 Returns a reference to a big hash of hash, with the Marc structure for the given frameworkcode
873 $forlibrarian :if set to 1, the MARC descriptions are the librarians ones, otherwise it's the public (OPAC) ones
874 $frameworkcode : the framework code to read
880 sub GetMarcStructure {
881 my ( $forlibrarian, $frameworkcode ) = @_;
882 my $dbh=C4::Context->dbh;
883 $frameworkcode = "" unless $frameworkcode;
885 my $libfield = ( $forlibrarian eq 1 ) ? 'liblibrarian' : 'libopac';
887 # check that framework exists
890 "SELECT COUNT(*) FROM marc_tag_structure WHERE frameworkcode=?");
891 $sth->execute($frameworkcode);
892 my ($total) = $sth->fetchrow;
893 $frameworkcode = "" unless ( $total > 0 );
896 "SELECT tagfield,liblibrarian,libopac,mandatory,repeatable
897 FROM marc_tag_structure
898 WHERE frameworkcode=?
901 $sth->execute($frameworkcode);
902 my ( $liblibrarian, $libopac, $tag, $res, $tab, $mandatory, $repeatable );
904 while ( ( $tag, $liblibrarian, $libopac, $mandatory, $repeatable ) =
907 $res->{$tag}->{lib} =
908 ( $forlibrarian or !$libopac ) ? $liblibrarian : $libopac;
909 $res->{$tab}->{tab} = "";
910 $res->{$tag}->{mandatory} = $mandatory;
911 $res->{$tag}->{repeatable} = $repeatable;
916 "SELECT tagfield,tagsubfield,liblibrarian,libopac,tab,mandatory,repeatable,authorised_value,authtypecode,value_builder,kohafield,seealso,hidden,isurl,link,defaultvalue
917 FROM marc_subfield_structure
918 WHERE frameworkcode=?
919 ORDER BY tagfield,tagsubfield
923 $sth->execute($frameworkcode);
926 my $authorised_value;
938 $tag, $subfield, $liblibrarian,
940 $mandatory, $repeatable, $authorised_value,
941 $authtypecode, $value_builder, $kohafield,
942 $seealso, $hidden, $isurl,
948 $res->{$tag}->{$subfield}->{lib} =
949 ( $forlibrarian or !$libopac ) ? $liblibrarian : $libopac;
950 $res->{$tag}->{$subfield}->{tab} = $tab;
951 $res->{$tag}->{$subfield}->{mandatory} = $mandatory;
952 $res->{$tag}->{$subfield}->{repeatable} = $repeatable;
953 $res->{$tag}->{$subfield}->{authorised_value} = $authorised_value;
954 $res->{$tag}->{$subfield}->{authtypecode} = $authtypecode;
955 $res->{$tag}->{$subfield}->{value_builder} = $value_builder;
956 $res->{$tag}->{$subfield}->{kohafield} = $kohafield;
957 $res->{$tag}->{$subfield}->{seealso} = $seealso;
958 $res->{$tag}->{$subfield}->{hidden} = $hidden;
959 $res->{$tag}->{$subfield}->{isurl} = $isurl;
960 $res->{$tag}->{$subfield}->{'link'} = $link;
961 $res->{$tag}->{$subfield}->{defaultvalue} = $defaultvalue;
966 =head2 GetUsedMarcStructure
968 the same function as GetMarcStructure expcet it just take field
969 in tab 0-9. (used field)
971 my $results = GetUsedMarcStructure($frameworkcode);
973 L<$results> is a ref to an array which each case containts a ref
974 to a hash which each keys is the columns from marc_subfield_structure
976 L<$frameworkcode> is the framework code.
980 sub GetUsedMarcStructure($){
981 my $frameworkcode = shift || '';
982 my $dbh = C4::Context->dbh;
985 FROM marc_subfield_structure
987 AND frameworkcode = ?
990 my $sth = $dbh->prepare($query);
991 $sth->execute($frameworkcode);
992 while (my $row = $sth->fetchrow_hashref){
998 =head2 GetMarcFromKohaField
1002 ($MARCfield,$MARCsubfield)=GetMarcFromKohaField($kohafield,$frameworkcode);
1003 Returns the MARC fields & subfields mapped to the koha field
1004 for the given frameworkcode
1010 sub GetMarcFromKohaField {
1011 my ( $kohafield, $frameworkcode ) = @_;
1012 return 0, 0 unless $kohafield;
1013 my $relations = C4::Context->marcfromkohafield;
1015 $relations->{$frameworkcode}->{$kohafield}->[0],
1016 $relations->{$frameworkcode}->{$kohafield}->[1]
1020 =head2 GetMarcBiblio
1024 Returns MARC::Record of the biblionumber passed in parameter.
1025 the marc record contains both biblio & item datas
1032 my $biblionumber = shift;
1033 my $dbh = C4::Context->dbh;
1035 $dbh->prepare("SELECT marcxml FROM biblioitems WHERE biblionumber=? ");
1036 $sth->execute($biblionumber);
1037 my ($marcxml) = $sth->fetchrow;
1038 MARC::File::XML->default_record_format(C4::Context->preference('marcflavour'));
1039 $marcxml =~ s/\x1e//g;
1040 $marcxml =~ s/\x1f//g;
1041 $marcxml =~ s/\x1d//g;
1042 $marcxml =~ s/\x0f//g;
1043 $marcxml =~ s/\x0c//g;
1045 my $record = MARC::Record->new();
1047 $record = eval {MARC::Record::new_from_xml( $marcxml, "utf8", C4::Context->preference('marcflavour'))};
1049 # $record = MARC::Record::new_from_usmarc( $marc) if $marc;
1060 my $marcxml = GetXmlBiblio($biblionumber);
1062 Returns biblioitems.marcxml of the biblionumber passed in parameter.
1063 The XML contains both biblio & item datas
1070 my ( $biblionumber ) = @_;
1071 my $dbh = C4::Context->dbh;
1073 $dbh->prepare("SELECT marcxml FROM biblioitems WHERE biblionumber=? ");
1074 $sth->execute($biblionumber);
1075 my ($marcxml) = $sth->fetchrow;
1079 =head2 GetAuthorisedValueDesc
1083 my $subfieldvalue =get_authorised_value_desc(
1084 $tag, $subf[$i][0],$subf[$i][1], '', $taglib, $category);
1085 Retrieve the complete description for a given authorised value.
1087 Now takes $category and $value pair too.
1088 my $auth_value_desc =GetAuthorisedValueDesc(
1089 '','', 'DVD' ,'','','CCODE');
1095 sub GetAuthorisedValueDesc {
1096 my ( $tag, $subfield, $value, $framework, $tagslib, $category ) = @_;
1097 my $dbh = C4::Context->dbh;
1101 if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq "branches" ) {
1102 return C4::Branch::GetBranchName($value);
1106 if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq "itemtypes" ) {
1107 return getitemtypeinfo($value)->{description};
1110 #---- "true" authorized value
1111 $category = $tagslib->{$tag}->{$subfield}->{'authorised_value'}
1114 if ( $category ne "" ) {
1117 "SELECT lib FROM authorised_values WHERE category = ? AND authorised_value = ?"
1119 $sth->execute( $category, $value );
1120 my $data = $sth->fetchrow_hashref;
1121 return $data->{'lib'};
1124 return $value; # if nothing is found return the original value
1132 $marcnotesarray = GetMarcNotes( $record, $marcflavour );
1133 Get all notes from the MARC record and returns them in an array.
1134 The note are stored in differents places depending on MARC flavour
1141 my ( $record, $marcflavour ) = @_;
1143 if ( $marcflavour eq "MARC21" ) {
1146 else { # assume unimarc if not marc21
1153 foreach my $field ( $record->field($scope) ) {
1154 my $value = $field->as_string();
1155 if ( $note ne "" ) {
1156 $marcnote = { marcnote => $note, };
1157 push @marcnotes, $marcnote;
1160 if ( $note ne $value ) {
1161 $note = $note . " " . $value;
1166 $marcnote = { marcnote => $note };
1167 push @marcnotes, $marcnote; #load last tag into array
1170 } # end GetMarcNotes
1172 =head2 GetMarcSubjects
1176 $marcsubjcts = GetMarcSubjects($record,$marcflavour);
1177 Get all subjects from the MARC record and returns them in an array.
1178 The subjects are stored in differents places depending on MARC flavour
1184 sub GetMarcSubjects {
1185 my ( $record, $marcflavour ) = @_;
1186 my ( $mintag, $maxtag );
1187 if ( $marcflavour eq "MARC21" ) {
1191 else { # assume unimarc if not marc21
1201 foreach my $field ( $record->field('6..' )) {
1202 next unless $field->tag() >= $mintag && $field->tag() <= $maxtag;
1204 my @subfields = $field->subfields();
1207 # if there is an authority link, build the link with an= subfield9
1208 my $subfield9 = $field->subfield('9');
1209 for my $subject_subfield (@subfields ) {
1210 # don't load unimarc subfields 3,4,5
1211 next if (($marcflavour eq "UNIMARC") and ($subject_subfield->[0] =~ (3|4|5) ) );
1212 my $code = $subject_subfield->[0];
1213 my $value = $subject_subfield->[1];
1214 my $linkvalue = $value;
1215 $linkvalue =~ s/(\(|\))//g;
1216 my $operator = " and " unless $counter==0;
1218 @link_loop = ({'limit' => 'an' ,link => "$subfield9" });
1220 push @link_loop, {'limit' => 'su', link => $linkvalue, operator => $operator };
1222 my $separator = C4::Context->preference("authoritysep") unless $counter==0;
1224 my @this_link_loop = @link_loop;
1225 push @subfields_loop, {code => $code, value => $value, link_loop => \@this_link_loop, separator => $separator} unless ($subject_subfield->[0] == 9 );
1229 push @marcsubjects, { MARCSUBJECT_SUBFIELDS_LOOP => \@subfields_loop };
1232 return \@marcsubjects;
1233 } #end getMARCsubjects
1235 =head2 GetMarcAuthors
1239 authors = GetMarcAuthors($record,$marcflavour);
1240 Get all authors from the MARC record and returns them in an array.
1241 The authors are stored in differents places depending on MARC flavour
1247 sub GetMarcAuthors {
1248 my ( $record, $marcflavour ) = @_;
1249 my ( $mintag, $maxtag );
1250 # tagslib useful for UNIMARC author reponsabilities
1251 my $tagslib = &GetMarcStructure( 1, '' ); # FIXME : we don't have the framework available, we take the default framework. May be bugguy on some setups, will be usually correct.
1252 if ( $marcflavour eq "MARC21" ) {
1256 elsif ( $marcflavour eq "UNIMARC" ) { # assume unimarc if not marc21
1265 foreach my $field ( $record->fields ) {
1266 next unless $field->tag() >= $mintag && $field->tag() <= $maxtag;
1269 my @subfields = $field->subfields();
1271 # if there is an authority link, build the link with Koha-Auth-Number: subfield9
1272 my $subfield9 = $field->subfield('9');
1273 for my $authors_subfield (@subfields) {
1274 # don't load unimarc subfields 3, 5
1275 next if ($marcflavour eq 'UNIMARC' and ($authors_subfield->[0] =~ (3|5) ) );
1276 my $subfieldcode = $authors_subfield->[0];
1277 my $value = $authors_subfield->[1];
1278 my $linkvalue = $value;
1279 $linkvalue =~ s/(\(|\))//g;
1280 my $operator = " and " unless $count_auth==0;
1281 # if we have an authority link, use that as the link, otherwise use standard searching
1283 @link_loop = ({'limit' => 'Koha-Auth-Number' ,link => "$subfield9" });
1286 # reset $linkvalue if UNIMARC author responsibility
1287 if ( $marcflavour eq 'UNIMARC' and ($authors_subfield->[0] eq '4')) {
1288 $linkvalue = "(".GetAuthorisedValueDesc( $field->tag(), $authors_subfield->[0], $authors_subfield->[1], '', $tagslib ).")";
1290 push @link_loop, {'limit' => 'au', link => $linkvalue, operator => $operator };
1292 my @this_link_loop = @link_loop;
1293 my $separator = C4::Context->preference("authoritysep") unless $count_auth==0;
1294 push @subfields_loop, {code => $subfieldcode, value => $value, link_loop => \@this_link_loop, separator => $separator} unless ($authors_subfield->[0] == 9 );
1297 push @marcauthors, { MARCAUTHOR_SUBFIELDS_LOOP => \@subfields_loop };
1299 return \@marcauthors;
1306 $marcurls = GetMarcUrls($record,$marcflavour);
1307 Returns arrayref of URLs from MARC data, suitable to pass to tmpl loop.
1308 Assumes web resources (not uncommon in MARC21 to omit resource type ind)
1315 my ($record, $marcflavour) = @_;
1318 for my $field ($record->field('856')) {
1319 my $url = $field->subfield('u');
1321 for my $note ( $field->subfield('z')) {
1322 push @notes , {note => $note};
1324 $marcurl = { MARCURL => $url,
1327 if($marcflavour eq 'MARC21') {
1328 my $s3 = $field->subfield('3');
1329 my $link = $field->subfield('y');
1330 $marcurl->{'linktext'} = $link || $s3 || $url ;;
1331 $marcurl->{'part'} = $s3 if($link);
1332 $marcurl->{'toc'} = 1 if($s3 =~ /^[Tt]able/) ;
1334 $marcurl->{'linktext'} = $url;
1336 push @marcurls, $marcurl;
1341 =head2 GetMarcSeries
1345 $marcseriesarray = GetMarcSeries($record,$marcflavour);
1346 Get all series from the MARC record and returns them in an array.
1347 The series are stored in differents places depending on MARC flavour
1354 my ($record, $marcflavour) = @_;
1355 my ($mintag, $maxtag);
1356 if ($marcflavour eq "MARC21") {
1359 } else { # assume unimarc if not marc21
1369 foreach my $field ($record->field('440'), $record->field('490')) {
1371 #my $value = $field->subfield('a');
1372 #$marcsubjct = {MARCSUBJCT => $value,};
1373 my @subfields = $field->subfields();
1374 #warn "subfields:".join " ", @$subfields;
1377 for my $series_subfield (@subfields) {
1379 undef $volume_number;
1380 # see if this is an instance of a volume
1381 if ($series_subfield->[0] eq 'v') {
1385 my $code = $series_subfield->[0];
1386 my $value = $series_subfield->[1];
1387 my $linkvalue = $value;
1388 $linkvalue =~ s/(\(|\))//g;
1389 my $operator = " and " unless $counter==0;
1390 push @link_loop, {link => $linkvalue, operator => $operator };
1391 my $separator = C4::Context->preference("authoritysep") unless $counter==0;
1392 if ($volume_number) {
1393 push @subfields_loop, {volumenum => $value};
1396 push @subfields_loop, {code => $code, value => $value, link_loop => \@link_loop, separator => $separator, volumenum => $volume_number};
1400 push @marcseries, { MARCSERIES_SUBFIELDS_LOOP => \@subfields_loop };
1401 #$marcsubjct = {MARCSUBJCT => $field->as_string(),};
1402 #push @marcsubjcts, $marcsubjct;
1406 my $marcseriessarray=\@marcseries;
1407 return $marcseriessarray;
1408 } #end getMARCseriess
1410 =head2 GetFrameworkCode
1414 $frameworkcode = GetFrameworkCode( $biblionumber )
1420 sub GetFrameworkCode {
1421 my ( $biblionumber ) = @_;
1422 my $dbh = C4::Context->dbh;
1423 my $sth = $dbh->prepare("SELECT frameworkcode FROM biblio WHERE biblionumber=?");
1424 $sth->execute($biblionumber);
1425 my ($frameworkcode) = $sth->fetchrow;
1426 return $frameworkcode;
1429 =head2 GetPublisherNameFromIsbn
1431 $name = GetPublishercodeFromIsbn($isbn);
1438 sub GetPublisherNameFromIsbn($){
1440 $isbn =~ s/[- _]//g;
1442 my @codes = (split '-', DisplayISBN($isbn));
1443 my $code = $codes[0].$codes[1].$codes[2];
1444 my $dbh = C4::Context->dbh;
1446 SELECT distinct publishercode
1449 AND publishercode IS NOT NULL
1452 my $sth = $dbh->prepare($query);
1453 $sth->execute("$code%");
1454 my $name = $sth->fetchrow;
1455 return $name if length $name;
1459 =head2 TransformKohaToMarc
1463 $record = TransformKohaToMarc( $hash )
1464 This function builds partial MARC::Record from a hash
1465 Hash entries can be from biblio or biblioitems.
1466 This function is called in acquisition module, to create a basic catalogue entry from user entry
1472 sub TransformKohaToMarc {
1475 my $dbh = C4::Context->dbh;
1478 "SELECT tagfield,tagsubfield FROM marc_subfield_structure WHERE frameworkcode=? AND kohafield=?"
1480 my $record = MARC::Record->new();
1481 foreach (keys %{$hash}) {
1482 &TransformKohaToMarcOneField( $sth, $record, $_,
1488 =head2 TransformKohaToMarcOneField
1492 $record = TransformKohaToMarcOneField( $sth, $record, $kohafieldname, $value, $frameworkcode );
1498 sub TransformKohaToMarcOneField {
1499 my ( $sth, $record, $kohafieldname, $value, $frameworkcode ) = @_;
1500 $frameworkcode='' unless $frameworkcode;
1504 if ( !defined $sth ) {
1505 my $dbh = C4::Context->dbh;
1506 $sth = $dbh->prepare(
1507 "SELECT tagfield,tagsubfield FROM marc_subfield_structure WHERE frameworkcode=? AND kohafield=?"
1510 $sth->execute( $frameworkcode, $kohafieldname );
1511 if ( ( $tagfield, $tagsubfield ) = $sth->fetchrow ) {
1512 my $tag = $record->field($tagfield);
1514 $tag->update( $tagsubfield => $value );
1515 $record->delete_field($tag);
1516 $record->insert_fields_ordered($tag);
1519 $record->add_fields( $tagfield, " ", " ", $tagsubfield => $value );
1525 =head2 TransformHtmlToXml
1529 $xml = TransformHtmlToXml( $tags, $subfields, $values, $indicator, $ind_tag, $auth_type )
1531 $auth_type contains :
1532 - nothing : rebuild a biblio, un UNIMARC the encoding is in 100$a pos 26/27
1533 - UNIMARCAUTH : rebuild an authority. In UNIMARC, the encoding is in 100$a pos 13/14
1534 - ITEM : rebuild an item : in UNIMARC, 100$a, it's in the biblio ! (otherwise, we would get 2 100 fields !)
1540 sub TransformHtmlToXml {
1541 my ( $tags, $subfields, $values, $indicator, $ind_tag, $auth_type ) = @_;
1542 my $xml = MARC::File::XML::header('UTF-8');
1543 $auth_type = C4::Context->preference('marcflavour') unless $auth_type;
1544 MARC::File::XML->default_record_format($auth_type);
1545 # in UNIMARC, field 100 contains the encoding
1546 # check that there is one, otherwise the
1547 # MARC::Record->new_from_xml will fail (and Koha will die)
1548 my $unimarc_and_100_exist=0;
1549 $unimarc_and_100_exist=1 if $auth_type eq 'ITEM'; # if we rebuild an item, no need of a 100 field
1554 for ( my $i = 0 ; $i <= @$tags ; $i++ ) {
1555 if (C4::Context->preference('marcflavour') eq 'UNIMARC' and @$tags[$i] eq "100" and @$subfields[$i] eq "a") {
1556 # if we have a 100 field and it's values are not correct, skip them.
1557 # if we don't have any valid 100 field, we will create a default one at the end
1558 my $enc = substr( @$values[$i], 26, 2 );
1559 if ($enc eq '01' or $enc eq '50' or $enc eq '03') {
1560 $unimarc_and_100_exist=1;
1565 @$values[$i] =~ s/&/&/g;
1566 @$values[$i] =~ s/</</g;
1567 @$values[$i] =~ s/>/>/g;
1568 @$values[$i] =~ s/"/"/g;
1569 @$values[$i] =~ s/'/'/g;
1570 # if ( !utf8::is_utf8( @$values[$i] ) ) {
1571 # utf8::decode( @$values[$i] );
1573 if ( ( @$tags[$i] ne $prevtag ) ) {
1574 $j++ unless ( @$tags[$i] eq "" );
1576 $xml .= "</datafield>\n";
1577 if ( ( @$tags[$i] && @$tags[$i] > 10 )
1578 && ( @$values[$i] ne "" ) )
1580 my $ind1 = substr( @$indicator[$j], 0, 1 );
1582 if ( @$indicator[$j] ) {
1583 $ind2 = substr( @$indicator[$j], 1, 1 );
1586 warn "Indicator in @$tags[$i] is empty";
1590 "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
1592 "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
1600 if ( @$values[$i] ne "" ) {
1603 if ( @$tags[$i] eq "000" ) {
1604 $xml .= "<leader>@$values[$i]</leader>\n";
1607 # rest of the fixed fields
1609 elsif ( @$tags[$i] < 10 ) {
1611 "<controlfield tag=\"@$tags[$i]\">@$values[$i]</controlfield>\n";
1615 my $ind1 = substr( @$indicator[$j], 0, 1 );
1616 my $ind2 = substr( @$indicator[$j], 1, 1 );
1618 "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
1620 "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
1626 else { # @$tags[$i] eq $prevtag
1627 if ( @$values[$i] eq "" ) {
1631 my $ind1 = substr( @$indicator[$j], 0, 1 );
1632 my $ind2 = substr( @$indicator[$j], 1, 1 );
1634 "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
1638 "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
1641 $prevtag = @$tags[$i];
1643 if (C4::Context->preference('marcflavour') eq 'UNIMARC' and !$unimarc_and_100_exist) {
1644 # warn "SETTING 100 for $auth_type";
1645 use POSIX qw(strftime);
1646 my $string = strftime( "%Y%m%d", localtime(time) );
1647 # set 50 to position 26 is biblios, 13 if authorities
1649 $pos=13 if $auth_type eq 'UNIMARCAUTH';
1650 $string = sprintf( "%-*s", 35, $string );
1651 substr( $string, $pos , 6, "50" );
1652 $xml .= "<datafield tag=\"100\" ind1=\"\" ind2=\"\">\n";
1653 $xml .= "<subfield code=\"a\">$string</subfield>\n";
1654 $xml .= "</datafield>\n";
1656 $xml .= MARC::File::XML::footer();
1660 =head2 TransformHtmlToMarc
1662 L<$record> = TransformHtmlToMarc(L<$params>,L<$cgi>)
1663 L<$params> is a ref to an array as below:
1665 'tag_010_indicator_531951' ,
1666 'tag_010_code_a_531951_145735' ,
1667 'tag_010_subfield_a_531951_145735' ,
1668 'tag_200_indicator_873510' ,
1669 'tag_200_code_a_873510_673465' ,
1670 'tag_200_subfield_a_873510_673465' ,
1671 'tag_200_code_b_873510_704318' ,
1672 'tag_200_subfield_b_873510_704318' ,
1673 'tag_200_code_e_873510_280822' ,
1674 'tag_200_subfield_e_873510_280822' ,
1675 'tag_200_code_f_873510_110730' ,
1676 'tag_200_subfield_f_873510_110730' ,
1678 L<$cgi> is the CGI object which containts the value.
1679 L<$record> is the MARC::Record object.
1683 sub TransformHtmlToMarc {
1687 # creating a new record
1688 my $record = MARC::Record->new();
1691 while ($params->[$i]){ # browse all CGI params
1692 my $param = $params->[$i];
1694 # if we are on biblionumber, store it in the MARC::Record (it may not be in the edited fields)
1695 if ($param eq 'biblionumber') {
1696 my ( $biblionumbertagfield, $biblionumbertagsubfield ) =
1697 &GetMarcFromKohaField( "biblio.biblionumber", '' );
1698 if ($biblionumbertagfield < 10) {
1699 $newfield = MARC::Field->new(
1700 $biblionumbertagfield,
1701 $cgi->param($param),
1704 $newfield = MARC::Field->new(
1705 $biblionumbertagfield,
1708 "$biblionumbertagsubfield" => $cgi->param($param),
1711 push @fields,$newfield if($newfield);
1713 elsif ($param =~ /^tag_(\d*)_indicator_/){ # new field start when having 'input name="..._indicator_..."
1716 my $ind1 = substr($cgi->param($param),0,1);
1717 my $ind2 = substr($cgi->param($param),1,1);
1721 if($tag < 10){ # no code for theses fields
1722 # in MARC editor, 000 contains the leader.
1723 if ($tag eq '000' ) {
1724 $record->leader($cgi->param($params->[$j+1])) if length($cgi->param($params->[$j+1]))==24;
1725 # between 001 and 009 (included)
1727 $newfield = MARC::Field->new(
1729 $cgi->param($params->[$j+1]),
1732 # > 009, deal with subfields
1734 while($params->[$j] =~ /_code_/){ # browse all it's subfield
1735 my $inner_param = $params->[$j];
1737 if($cgi->param($params->[$j+1])){ # only if there is a value (code => value)
1738 $newfield->add_subfields(
1739 $cgi->param($inner_param) => $cgi->param($params->[$j+1])
1743 if ( $cgi->param($params->[$j+1]) ) { # creating only if there is a value (code => value)
1744 $newfield = MARC::Field->new(
1748 $cgi->param($inner_param) => $cgi->param($params->[$j+1]),
1755 push @fields,$newfield if($newfield);
1760 $record->append_fields(@fields);
1764 # cache inverted MARC field map
1765 our $inverted_field_map;
1767 =head2 TransformMarcToKoha
1771 $result = TransformMarcToKoha( $dbh, $record, $frameworkcode )
1775 Extract data from a MARC bib record into a hashref representing
1776 Koha biblio, biblioitems, and items fields.
1779 sub TransformMarcToKoha {
1780 my ( $dbh, $record, $frameworkcode, $limit_table ) = @_;
1784 unless (defined $inverted_field_map) {
1785 $inverted_field_map = _get_inverted_marc_field_map();
1789 if ($limit_table eq 'items') {
1790 $tables{'items'} = 1;
1792 $tables{'items'} = 1;
1793 $tables{'biblio'} = 1;
1794 $tables{'biblioitems'} = 1;
1797 # traverse through record
1798 MARCFIELD: foreach my $field ($record->fields()) {
1799 my $tag = $field->tag();
1800 next MARCFIELD unless exists $inverted_field_map->{$frameworkcode}->{$tag};
1801 if ($field->is_control_field()) {
1802 my $kohafields = $inverted_field_map->{$frameworkcode}->{$tag}->{list};
1803 ENTRY: foreach my $entry (@{ $kohafields }) {
1804 my ($subfield, $table, $column) = @{ $entry };
1805 next ENTRY unless exists $tables{$table};
1806 my $key = _disambiguate($table, $column);
1807 if ($result->{$key}) {
1808 unless (($key eq "biblionumber" or $key eq "biblioitemnumber") and ($field->data() eq "")) {
1809 $result->{$key} .= " | " . $field->data();
1812 $result->{$key} = $field->data();
1816 # deal with subfields
1817 MARCSUBFIELD: foreach my $sf ($field->subfields()) {
1818 my $code = $sf->[0];
1819 next MARCSUBFIELD unless exists $inverted_field_map->{$frameworkcode}->{$tag}->{sfs}->{$code};
1820 my $value = $sf->[1];
1821 SFENTRY: foreach my $entry (@{ $inverted_field_map->{$frameworkcode}->{$tag}->{sfs}->{$code} }) {
1822 my ($table, $column) = @{ $entry };
1823 next SFENTRY unless exists $tables{$table};
1824 my $key = _disambiguate($table, $column);
1825 if ($result->{$key}) {
1826 unless (($key eq "biblionumber" or $key eq "biblioitemnumber") and ($value eq "")) {
1827 $result->{$key} .= " | " . $value;
1830 $result->{$key} = $value;
1837 # modify copyrightdate to keep only the 1st year found
1838 if (exists $result->{'copyrightdate'}) {
1839 my $temp = $result->{'copyrightdate'};
1840 $temp =~ m/c(\d\d\d\d)/; # search cYYYY first
1842 $result->{'copyrightdate'} = $1;
1844 else { # if no cYYYY, get the 1st date.
1845 $temp =~ m/(\d\d\d\d)/;
1846 $result->{'copyrightdate'} = $1;
1850 # modify publicationyear to keep only the 1st year found
1851 if (exists $result->{'publicationyear'}) {
1852 my $temp = $result->{'publicationyear'};
1853 $temp =~ m/c(\d\d\d\d)/; # search cYYYY first
1855 $result->{'publicationyear'} = $1;
1857 else { # if no cYYYY, get the 1st date.
1858 $temp =~ m/(\d\d\d\d)/;
1859 $result->{'publicationyear'} = $1;
1866 sub _get_inverted_marc_field_map {
1867 my $relations = C4::Context->marcfromkohafield;
1870 my $relations = C4::Context->marcfromkohafield;
1872 foreach my $frameworkcode (keys %{ $relations }) {
1873 foreach my $kohafield (keys %{ $relations->{$frameworkcode} }) {
1874 my $tag = $relations->{$frameworkcode}->{$kohafield}->[0];
1875 my $subfield = $relations->{$frameworkcode}->{$kohafield}->[1];
1876 my ($table, $column) = split /[.]/, $kohafield, 2;
1877 push @{ $field_map->{$frameworkcode}->{$tag}->{list} }, [ $subfield, $table, $column ];
1878 push @{ $field_map->{$frameworkcode}->{$tag}->{sfs}->{$subfield} }, [ $table, $column ];
1884 =head2 _disambiguate
1888 $newkey = _disambiguate($table, $field);
1890 This is a temporary hack to distinguish between the
1891 following sets of columns when using TransformMarcToKoha.
1893 items.cn_source & biblioitems.cn_source
1894 items.cn_sort & biblioitems.cn_sort
1896 Columns that are currently NOT distinguished (FIXME
1897 due to lack of time to fully test) are:
1899 biblio.notes and biblioitems.notes
1904 FIXME - this is necessary because prefixing each column
1905 name with the table name would require changing lots
1906 of code and templates, and exposing more of the DB
1907 structure than is good to the UI templates, particularly
1908 since biblio and bibloitems may well merge in a future
1909 version. In the future, it would also be good to
1910 separate DB access and UI presentation field names
1918 my ($table, $column) = @_;
1919 if ($column eq "cn_sort" or $column eq "cn_source") {
1920 return $table . '.' . $column;
1927 =head2 get_koha_field_from_marc
1931 $result->{_disambiguate($table, $field)} = get_koha_field_from_marc($table,$field,$record,$frameworkcode);
1933 Internal function to map data from the MARC record to a specific non-MARC field.
1934 FIXME: this is meant to replace TransformMarcToKohaOneField after more testing.
1940 sub get_koha_field_from_marc {
1941 my ($koha_table,$koha_column,$record,$frameworkcode) = @_;
1942 my ( $tagfield, $subfield ) = GetMarcFromKohaField( $koha_table.'.'.$koha_column, $frameworkcode );
1944 foreach my $field ( $record->field($tagfield) ) {
1945 if ( $field->tag() < 10 ) {
1947 $kohafield .= " | " . $field->data();
1950 $kohafield = $field->data();
1954 if ( $field->subfields ) {
1955 my @subfields = $field->subfields();
1956 foreach my $subfieldcount ( 0 .. $#subfields ) {
1957 if ( $subfields[$subfieldcount][0] eq $subfield ) {
1960 " | " . $subfields[$subfieldcount][1];
1964 $subfields[$subfieldcount][1];
1975 =head2 TransformMarcToKohaOneField
1979 $result = TransformMarcToKohaOneField( $kohatable, $kohafield, $record, $result, $frameworkcode )
1985 sub TransformMarcToKohaOneField {
1987 # FIXME ? if a field has a repeatable subfield that is used in old-db,
1988 # only the 1st will be retrieved...
1989 my ( $kohatable, $kohafield, $record, $result, $frameworkcode ) = @_;
1991 my ( $tagfield, $subfield ) =
1992 GetMarcFromKohaField( $kohatable . "." . $kohafield,
1994 foreach my $field ( $record->field($tagfield) ) {
1995 if ( $field->tag() < 10 ) {
1996 if ( $result->{$kohafield} ) {
1997 $result->{$kohafield} .= " | " . $field->data();
2000 $result->{$kohafield} = $field->data();
2004 if ( $field->subfields ) {
2005 my @subfields = $field->subfields();
2006 foreach my $subfieldcount ( 0 .. $#subfields ) {
2007 if ( $subfields[$subfieldcount][0] eq $subfield ) {
2008 if ( $result->{$kohafield} ) {
2009 $result->{$kohafield} .=
2010 " | " . $subfields[$subfieldcount][1];
2013 $result->{$kohafield} =
2014 $subfields[$subfieldcount][1];
2024 =head1 OTHER FUNCTIONS
2030 my $string = char_decode( $string, $encoding );
2032 converts ISO 5426 coded string to UTF-8
2033 sloppy code : should be improved in next issue
2040 my ( $string, $encoding ) = @_;
2043 $encoding = C4::Context->preference("marcflavour") unless $encoding;
2044 if ( $encoding eq "UNIMARC" ) {
2114 # this handles non-sorting blocks (if implementation requires this)
2115 $string = nsb_clean($_);
2117 elsif ( $encoding eq "USMARC" || $encoding eq "MARC21" ) {
2176 #Additional Turkish characters
2179 s/(\xf0)s/\xc5\x9f/gm;
2180 s/(\xf0)S/\xc5\x9e/gm;
2183 s/\xe7\x49/\\xc4\xb0/gm;
2184 s/(\xe6)G/\xc4\x9e/gm;
2185 s/(\xe6)g/ğ\xc4\x9f/gm;
2188 s/(\xe8|\xc8)o/ö/gm;
2189 s/(\xe8|\xc8)O/Ö/gm;
2190 s/(\xe8|\xc8)u/ü/gm;
2191 s/(\xe8|\xc8)U/Ü/gm;
2192 s/\xc2\xb8/\xc4\xb1/gm;
2195 # this handles non-sorting blocks (if implementation requires this)
2196 $string = nsb_clean($_);
2205 my $string = nsb_clean( $string, $encoding );
2212 my $NSB = '\x88'; # NSB : begin Non Sorting Block
2213 my $NSE = '\x89'; # NSE : Non Sorting Block end
2214 # handles non sorting blocks
2218 s/[ ]{0,1}$NSE/) /gm;
2223 =head2 PrepareItemrecordDisplay
2227 PrepareItemrecordDisplay($itemrecord,$bibnum,$itemumber);
2229 Returns a hash with all the fields for Display a given item data in a template
2235 sub PrepareItemrecordDisplay {
2237 my ( $bibnum, $itemnum ) = @_;
2239 my $dbh = C4::Context->dbh;
2240 my $frameworkcode = &GetFrameworkCode( $bibnum );
2241 my ( $itemtagfield, $itemtagsubfield ) =
2242 &GetMarcFromKohaField( "items.itemnumber", $frameworkcode );
2243 my $tagslib = &GetMarcStructure( 1, $frameworkcode );
2244 my $itemrecord = GetMarcItem( $bibnum, $itemnum) if ($itemnum);
2246 my $authorised_values_sth =
2248 "SELECT authorised_value,lib FROM authorised_values WHERE category=? ORDER BY lib"
2250 foreach my $tag ( sort keys %{$tagslib} ) {
2251 my $previous_tag = '';
2253 # loop through each subfield
2255 foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
2256 next if ( subfield_is_koha_internal_p($subfield) );
2257 next if ( $tagslib->{$tag}->{$subfield}->{'tab'} ne "10" );
2259 $subfield_data{tag} = $tag;
2260 $subfield_data{subfield} = $subfield;
2261 $subfield_data{countsubfield} = $cntsubf++;
2262 $subfield_data{kohafield} =
2263 $tagslib->{$tag}->{$subfield}->{'kohafield'};
2265 # $subfield_data{marc_lib}=$tagslib->{$tag}->{$subfield}->{lib};
2266 $subfield_data{marc_lib} =
2267 "<span id=\"error\" title=\""
2268 . $tagslib->{$tag}->{$subfield}->{lib} . "\">"
2269 . substr( $tagslib->{$tag}->{$subfield}->{lib}, 0, 12 )
2271 $subfield_data{mandatory} =
2272 $tagslib->{$tag}->{$subfield}->{mandatory};
2273 $subfield_data{repeatable} =
2274 $tagslib->{$tag}->{$subfield}->{repeatable};
2275 $subfield_data{hidden} = "display:none"
2276 if $tagslib->{$tag}->{$subfield}->{hidden};
2278 ( $x, $value ) = _find_value( $tag, $subfield, $itemrecord )
2280 $value =~ s/"/"/g;
2282 # search for itemcallnumber if applicable
2283 if ( $tagslib->{$tag}->{$subfield}->{kohafield} eq
2284 'items.itemcallnumber'
2285 && C4::Context->preference('itemcallnumber') )
2288 substr( C4::Context->preference('itemcallnumber'), 0, 3 );
2290 substr( C4::Context->preference('itemcallnumber'), 3, 1 );
2291 my $temp = $itemrecord->field($CNtag) if ($itemrecord);
2293 $value = $temp->subfield($CNsubfield);
2296 if ( $tagslib->{$tag}->{$subfield}->{authorised_value} ) {
2297 my @authorised_values;
2300 # builds list, depending on authorised value...
2302 if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq
2305 if ( ( C4::Context->preference("IndependantBranches") )
2306 && ( C4::Context->userenv->{flags} != 1 ) )
2310 "SELECT branchcode,branchname FROM branches WHERE branchcode = ? ORDER BY branchname"
2312 $sth->execute( C4::Context->userenv->{branch} );
2313 push @authorised_values, ""
2315 $tagslib->{$tag}->{$subfield}->{mandatory} );
2316 while ( my ( $branchcode, $branchname ) =
2317 $sth->fetchrow_array )
2319 push @authorised_values, $branchcode;
2320 $authorised_lib{$branchcode} = $branchname;
2326 "SELECT branchcode,branchname FROM branches ORDER BY branchname"
2329 push @authorised_values, ""
2331 $tagslib->{$tag}->{$subfield}->{mandatory} );
2332 while ( my ( $branchcode, $branchname ) =
2333 $sth->fetchrow_array )
2335 push @authorised_values, $branchcode;
2336 $authorised_lib{$branchcode} = $branchname;
2342 elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq
2347 "SELECT itemtype,description FROM itemtypes ORDER BY description"
2350 push @authorised_values, ""
2351 unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
2352 while ( my ( $itemtype, $description ) =
2353 $sth->fetchrow_array )
2355 push @authorised_values, $itemtype;
2356 $authorised_lib{$itemtype} = $description;
2359 #---- "true" authorised value
2362 $authorised_values_sth->execute(
2363 $tagslib->{$tag}->{$subfield}->{authorised_value} );
2364 push @authorised_values, ""
2365 unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
2366 while ( my ( $value, $lib ) =
2367 $authorised_values_sth->fetchrow_array )
2369 push @authorised_values, $value;
2370 $authorised_lib{$value} = $lib;
2373 $subfield_data{marc_value} = CGI::scrolling_list(
2374 -name => 'field_value',
2375 -values => \@authorised_values,
2376 -default => "$value",
2377 -labels => \%authorised_lib,
2383 elsif ( $tagslib->{$tag}->{$subfield}->{thesaurus_category} ) {
2384 $subfield_data{marc_value} =
2385 "<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>";
2388 # COMMENTED OUT because No $i is provided with this API.
2389 # And thus, no value_builder can be activated.
2390 # BUT could be thought over.
2391 # } elsif ($tagslib->{$tag}->{$subfield}->{'value_builder'}) {
2392 # my $plugin="value_builder/".$tagslib->{$tag}->{$subfield}->{'value_builder'};
2394 # my $extended_param = plugin_parameters($dbh,$itemrecord,$tagslib,$i,0);
2395 # my ($function_name,$javascript) = plugin_javascript($dbh,$record,$tagslib,$i,0);
2396 # $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";
2399 $subfield_data{marc_value} =
2400 "<input type=\"text\" name=\"field_value\" value=\"$value\" size=50 maxlength=255>";
2402 push( @loop_data, \%subfield_data );
2406 my $itemnumber = $itemrecord->subfield( $itemtagfield, $itemtagsubfield )
2407 if ( $itemrecord && $itemrecord->field($itemtagfield) );
2409 'itemtagfield' => $itemtagfield,
2410 'itemtagsubfield' => $itemtagsubfield,
2411 'itemnumber' => $itemnumber,
2412 'iteminformation' => \@loop_data
2418 # true ModZebra commented until indexdata fixes zebraDB crashes (it seems they occur on multiple updates
2420 # replaced by a zebraqueue table, that is filled with ModZebra to run.
2421 # the table is emptied by misc/cronjobs/zebraqueue_start.pl script
2422 # =head2 ModZebrafiles
2424 # &ModZebrafiles( $dbh, $biblionumber, $record, $folder, $server );
2428 # sub ModZebrafiles {
2430 # my ( $dbh, $biblionumber, $record, $folder, $server ) = @_;
2434 # C4::Context->zebraconfig($server)->{directory} . "/" . $folder . "/";
2435 # unless ( opendir( DIR, "$zebradir" ) ) {
2436 # warn "$zebradir not found";
2440 # my $filename = $zebradir . $biblionumber;
2443 # open( OUTPUT, ">", $filename . ".xml" );
2444 # print OUTPUT $record;
2453 ModZebra( $biblionumber, $op, $server, $newRecord );
2455 $biblionumber is the biblionumber we want to index
2456 $op is specialUpdate or delete, and is used to know what we want to do
2457 $server is the server that we want to update
2458 $newRecord is the MARC::Record containing the new record. It is usefull only when NoZebra=1, and is used to know what to add to the nozebra database. (the record in mySQL being, if it exist, the previous record, the one just before the modif. We need both : the previous and the new one.
2465 ###Accepts a $server variable thus we can use it for biblios authorities or other zebra dbs
2466 my ( $biblionumber, $op, $server, $newRecord ) = @_;
2467 my $dbh=C4::Context->dbh;
2469 # true ModZebra commented until indexdata fixes zebraDB crashes (it seems they occur on multiple updates
2471 # replaced by a zebraqueue table, that is filled with ModZebra to run.
2472 # the table is emptied by misc/cronjobs/zebraqueue_start.pl script
2474 if (C4::Context->preference("NoZebra")) {
2475 # lock the nozebra table : we will read index lines, update them in Perl process
2476 # and write everything in 1 transaction.
2477 # lock the table to avoid someone else overwriting what we are doing
2478 $dbh->do('LOCK TABLES nozebra WRITE,biblio WRITE,biblioitems WRITE, systempreferences WRITE, auth_types WRITE, auth_header WRITE');
2479 my %result; # the result hash that will be builded by deletion / add, and written on mySQL at the end, to improve speed
2481 if ($server eq 'biblioserver') {
2482 $record= GetMarcBiblio($biblionumber);
2484 $record= C4::AuthoritiesMarc::GetAuthority($biblionumber);
2486 if ($op eq 'specialUpdate') {
2487 # OK, we have to add or update the record
2488 # 1st delete (virtually, in indexes), if record actually exists
2490 %result = _DelBiblioNoZebra($biblionumber,$record,$server);
2492 # ... add the record
2493 %result=_AddBiblioNoZebra($biblionumber,$newRecord, $server, %result);
2495 # it's a deletion, delete the record...
2496 # warn "DELETE the record $biblionumber on $server".$record->as_formatted;
2497 %result=_DelBiblioNoZebra($biblionumber,$record,$server);
2499 # ok, now update the database...
2500 my $sth = $dbh->prepare("UPDATE nozebra SET biblionumbers=? WHERE server=? AND indexname=? AND value=?");
2501 foreach my $key (keys %result) {
2502 foreach my $index (keys %{$result{$key}}) {
2503 $sth->execute($result{$key}->{$index}, $server, $key, $index);
2506 $dbh->do('UNLOCK TABLES');
2510 # we use zebra, just fill zebraqueue table
2512 my $sth=$dbh->prepare("INSERT INTO zebraqueue (biblio_auth_number,server,operation) VALUES(?,?,?)");
2513 $sth->execute($biblionumber,$server,$op);
2518 =head2 GetNoZebraIndexes
2520 %indexes = GetNoZebraIndexes;
2522 return the data from NoZebraIndexes syspref.
2526 sub GetNoZebraIndexes {
2527 my $index = C4::Context->preference('NoZebraIndexes');
2529 foreach my $line (split /('|"),/,$index) {
2530 $line =~ /(.*)=>(.*)/;
2531 my $index = substr($1,1); # get the index, don't forget to remove initial ' or "
2533 $index =~ s/'|"|\s//g;
2536 $fields =~ s/'|"|\s//g;
2537 $indexes{$index}=$fields;
2542 =head1 INTERNAL FUNCTIONS
2544 =head2 _DelBiblioNoZebra($biblionumber,$record,$server);
2546 function to delete a biblio in NoZebra indexes
2547 This function does NOT delete anything in database : it reads all the indexes entries
2548 that have to be deleted & delete them in the hash
2549 The SQL part is done either :
2550 - after the Add if we are modifying a biblio (delete + add again)
2551 - immediatly after this sub if we are doing a true deletion.
2552 $server can be 'biblioserver' or 'authorityserver' : it indexes biblios or authorities (in the same table, $server being part of the table itself
2557 sub _DelBiblioNoZebra {
2558 my ($biblionumber, $record, $server)=@_;
2561 my $dbh = C4::Context->dbh;
2565 if ($server eq 'biblioserver') {
2566 %index=GetNoZebraIndexes;
2567 # get title of the record (to store the 10 first letters with the index)
2568 my ($titletag,$titlesubfield) = GetMarcFromKohaField('biblio.title');
2569 $title = lc($record->subfield($titletag,$titlesubfield));
2571 # for authorities, the "title" is the $a mainentry
2572 my $authref = C4::AuthoritiesMarc::GetAuthType($record->subfield(152,'b'));
2573 warn "ERROR : authtype undefined for ".$record->as_formatted unless $authref;
2574 $title = $record->subfield($authref->{auth_tag_to_report},'a');
2575 $index{'mainmainentry'}= $authref->{'auth_tag_to_report'}.'a';
2576 $index{'mainentry'} = $authref->{'auth_tag_to_report'}.'*';
2577 $index{'auth_type'} = '152b';
2581 # remove blancks comma (that could cause problem when decoding the string for CQL retrieval) and regexp specific values
2582 $title =~ s/ |,|;|\[|\]|\(|\)|\*|-|'|=//g;
2583 # limit to 10 char, should be enough, and limit the DB size
2584 $title = substr($title,0,10);
2586 my $sth2=$dbh->prepare('SELECT biblionumbers FROM nozebra WHERE server=? AND indexname=? AND value=?');
2587 foreach my $field ($record->fields()) {
2588 #parse each subfield
2589 next if $field->tag <10;
2590 foreach my $subfield ($field->subfields()) {
2591 my $tag = $field->tag();
2592 my $subfieldcode = $subfield->[0];
2594 # check each index to see if the subfield is stored somewhere
2595 # otherwise, store it in __RAW__ index
2596 foreach my $key (keys %index) {
2597 # warn "examining $key index : ".$index{$key}." for $tag $subfieldcode";
2598 if ($index{$key} =~ /$tag\*/ or $index{$key} =~ /$tag$subfieldcode/) {
2600 my $line= lc $subfield->[1];
2601 # remove meaningless value in the field...
2602 $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:/ /g;
2603 # ... and split in words
2604 foreach (split / /,$line) {
2605 next unless $_; # skip empty values (multiple spaces)
2606 # if the entry is already here, do nothing, the biblionumber has already be removed
2607 unless ($result{$key}->{$_} =~ /$biblionumber,$title\-(\d);/) {
2608 # get the index value if it exist in the nozebra table and remove the entry, otherwise, do nothing
2609 $sth2->execute($server,$key,$_);
2610 my $existing_biblionumbers = $sth2->fetchrow;
2612 if ($existing_biblionumbers) {
2613 # warn " existing for $key $_: $existing_biblionumbers";
2614 $result{$key}->{$_} =$existing_biblionumbers;
2615 $result{$key}->{$_} =~ s/$biblionumber,$title\-(\d);//;
2621 # the subfield is not indexed, store it in __RAW__ index anyway
2623 my $line= lc $subfield->[1];
2624 $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:/ /g;
2625 # ... and split in words
2626 foreach (split / /,$line) {
2627 next unless $_; # skip empty values (multiple spaces)
2628 # if the entry is already here, do nothing, the biblionumber has already be removed
2629 unless ($result{'__RAW__'}->{$_} =~ /$biblionumber,$title\-(\d);/) {
2630 # get the index value if it exist in the nozebra table and remove the entry, otherwise, do nothing
2631 $sth2->execute($server,'__RAW__',$_);
2632 my $existing_biblionumbers = $sth2->fetchrow;
2634 if ($existing_biblionumbers) {
2635 $result{'__RAW__'}->{$_} =$existing_biblionumbers;
2636 $result{'__RAW__'}->{$_} =~ s/$biblionumber,$title\-(\d);//;
2646 =head2 _AddBiblioNoZebra($biblionumber, $record, $server, %result);
2648 function to add a biblio in NoZebra indexes
2652 sub _AddBiblioNoZebra {
2653 my ($biblionumber, $record, $server, %result)=@_;
2654 my $dbh = C4::Context->dbh;
2658 if ($server eq 'biblioserver') {
2659 %index=GetNoZebraIndexes;
2660 # get title of the record (to store the 10 first letters with the index)
2661 my ($titletag,$titlesubfield) = GetMarcFromKohaField('biblio.title');
2662 $title = lc($record->subfield($titletag,$titlesubfield));
2664 # warn "server : $server";
2665 # for authorities, the "title" is the $a mainentry
2666 my $authref = C4::AuthoritiesMarc::GetAuthType($record->subfield(152,'b'));
2667 warn "ERROR : authtype undefined for ".$record->as_formatted unless $authref;
2668 $title = $record->subfield($authref->{auth_tag_to_report},'a');
2669 $index{'mainmainentry'} = $authref->{auth_tag_to_report}.'a';
2670 $index{'mainentry'} = $authref->{auth_tag_to_report}.'*';
2671 $index{'auth_type'} = '152b';
2674 # remove blancks comma (that could cause problem when decoding the string for CQL retrieval) and regexp specific values
2675 $title =~ s/ |,|;|\[|\]|\(|\)|\*|-|'|=//g;
2676 # limit to 10 char, should be enough, and limit the DB size
2677 $title = substr($title,0,10);
2679 my $sth2=$dbh->prepare('SELECT biblionumbers FROM nozebra WHERE server=? AND indexname=? AND value=?');
2680 foreach my $field ($record->fields()) {
2681 #parse each subfield
2682 next if $field->tag <10;
2683 foreach my $subfield ($field->subfields()) {
2684 my $tag = $field->tag();
2685 my $subfieldcode = $subfield->[0];
2687 # check each index to see if the subfield is stored somewhere
2688 # otherwise, store it in __RAW__ index
2689 foreach my $key (keys %index) {
2690 # warn "examining $key index : ".$index{$key}." for $tag $subfieldcode";
2691 if ($index{$key} =~ /$tag\*/ or $index{$key} =~ /$tag$subfieldcode/) {
2693 my $line= lc $subfield->[1];
2694 # remove meaningless value in the field...
2695 $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:/ /g;
2696 # ... and split in words
2697 foreach (split / /,$line) {
2698 next unless $_; # skip empty values (multiple spaces)
2699 # if the entry is already here, improve weight
2700 # warn "managing $_";
2701 if ($result{$key}->{"$_"} =~ /$biblionumber,$title\-(\d);/) {
2703 $result{$key}->{"$_"} =~ s/$biblionumber,$title\-(\d);//;
2704 $result{$key}->{"$_"} .= "$biblionumber,$title-$weight;";
2706 # get the value if it exist in the nozebra table, otherwise, create it
2707 $sth2->execute($server,$key,$_);
2708 my $existing_biblionumbers = $sth2->fetchrow;
2710 if ($existing_biblionumbers) {
2711 $result{$key}->{"$_"} =$existing_biblionumbers;
2713 $result{$key}->{"$_"} =~ s/$biblionumber,$title\-(\d);//;
2714 $result{$key}->{"$_"} .= "$biblionumber,$title-$weight;";
2715 # create a new ligne for this entry
2717 # warn "INSERT : $server / $key / $_";
2718 $dbh->do('INSERT INTO nozebra SET server='.$dbh->quote($server).', indexname='.$dbh->quote($key).',value='.$dbh->quote($_));
2719 $result{$key}->{"$_"}.="$biblionumber,$title-1;";
2725 # the subfield is not indexed, store it in __RAW__ index anyway
2727 my $line= lc $subfield->[1];
2728 $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:/ /g;
2729 # ... and split in words
2730 foreach (split / /,$line) {
2731 next unless $_; # skip empty values (multiple spaces)
2732 # if the entry is already here, improve weight
2733 if ($result{'__RAW__'}->{"$_"} =~ /$biblionumber,$title\-(\d);/) {
2735 $result{'__RAW__'}->{"$_"} =~ s/$biblionumber,$title\-(\d);//;
2736 $result{'__RAW__'}->{"$_"} .= "$biblionumber,$title-$weight;";
2738 # get the value if it exist in the nozebra table, otherwise, create it
2739 $sth2->execute($server,'__RAW__',$_);
2740 my $existing_biblionumbers = $sth2->fetchrow;
2742 if ($existing_biblionumbers) {
2743 $result{'__RAW__'}->{"$_"} =$existing_biblionumbers;
2745 $result{'__RAW__'}->{"$_"} =~ s/$biblionumber,$title\-(\d);//;
2746 $result{'__RAW__'}->{"$_"} .= "$biblionumber,$title-$weight;";
2747 # create a new ligne for this entry
2749 $dbh->do('INSERT INTO nozebra SET server='.$dbh->quote($server).', indexname="__RAW__",value='.$dbh->quote($_));
2750 $result{'__RAW__'}->{"$_"}.="$biblionumber,$title-1;";
2761 =head2 MARCitemchange
2765 &MARCitemchange( $record, $itemfield, $newvalue )
2767 Function to update a single value in an item field.
2768 Used twice, could probably be replaced by something else, but works well...
2776 sub MARCitemchange {
2777 my ( $record, $itemfield, $newvalue ) = @_;
2778 my $dbh = C4::Context->dbh;
2780 my ( $tagfield, $tagsubfield ) =
2781 GetMarcFromKohaField( $itemfield, "" );
2782 if ( ($tagfield) && ($tagsubfield) ) {
2783 my $tag = $record->field($tagfield);
2785 $tag->update( $tagsubfield => $newvalue );
2786 $record->delete_field($tag);
2787 $record->insert_fields_ordered($tag);
2795 ($indicators, $value) = _find_value($tag, $subfield, $record,$encoding);
2797 Find the given $subfield in the given $tag in the given
2798 MARC::Record $record. If the subfield is found, returns
2799 the (indicators, value) pair; otherwise, (undef, undef) is
2803 Such a function is used in addbiblio AND additem and serial-edit and maybe could be used in Authorities.
2804 I suggest we export it from this module.
2811 my ( $tagfield, $insubfield, $record, $encoding ) = @_;
2814 if ( $tagfield < 10 ) {
2815 if ( $record->field($tagfield) ) {
2816 push @result, $record->field($tagfield)->data();
2823 foreach my $field ( $record->field($tagfield) ) {
2824 my @subfields = $field->subfields();
2825 foreach my $subfield (@subfields) {
2826 if ( @$subfield[0] eq $insubfield ) {
2827 push @result, @$subfield[1];
2828 $indicator = $field->indicator(1) . $field->indicator(2);
2833 return ( $indicator, @result );
2836 =head2 _koha_marc_update_bib_ids
2840 _koha_marc_update_bib_ids($record, $frameworkcode, $biblionumber, $biblioitemnumber);
2842 Internal function to add or update biblionumber and biblioitemnumber to
2849 sub _koha_marc_update_bib_ids {
2850 my ($record, $frameworkcode, $biblionumber, $biblioitemnumber) = @_;
2852 # we must add bibnum and bibitemnum in MARC::Record...
2853 # we build the new field with biblionumber and biblioitemnumber
2854 # we drop the original field
2855 # we add the new builded field.
2856 my ($biblio_tag, $biblio_subfield ) = GetMarcFromKohaField("biblio.biblionumber",$frameworkcode);
2857 my ($biblioitem_tag, $biblioitem_subfield ) = GetMarcFromKohaField("biblioitems.biblioitemnumber",$frameworkcode);
2859 if ($biblio_tag != $biblioitem_tag) {
2860 # biblionumber & biblioitemnumber are in different fields
2862 # deal with biblionumber
2863 my ($new_field, $old_field);
2864 if ($biblio_tag < 10) {
2865 $new_field = MARC::Field->new( $biblio_tag, $biblionumber );
2868 MARC::Field->new( $biblio_tag, '', '',
2869 "$biblio_subfield" => $biblionumber );
2872 # drop old field and create new one...
2873 $old_field = $record->field($biblio_tag);
2874 $record->delete_field($old_field);
2875 $record->append_fields($new_field);
2877 # deal with biblioitemnumber
2878 if ($biblioitem_tag < 10) {
2879 $new_field = MARC::Field->new( $biblioitem_tag, $biblioitemnumber, );
2882 MARC::Field->new( $biblioitem_tag, '', '',
2883 "$biblioitem_subfield" => $biblioitemnumber, );
2885 # drop old field and create new one...
2886 $old_field = $record->field($biblioitem_tag);
2887 $record->delete_field($old_field);
2888 $record->insert_fields_ordered($new_field);
2891 # biblionumber & biblioitemnumber are in the same field (can't be <10 as fields <10 have only 1 value)
2892 my $new_field = MARC::Field->new(
2893 $biblio_tag, '', '',
2894 "$biblio_subfield" => $biblionumber,
2895 "$biblioitem_subfield" => $biblioitemnumber
2898 # drop old field and create new one...
2899 my $old_field = $record->field($biblio_tag);
2900 $record->delete_field($old_field);
2901 $record->insert_fields_ordered($new_field);
2905 =head2 _koha_add_biblio
2909 my ($biblionumber,$error) = _koha_add_biblio($dbh,$biblioitem);
2911 Internal function to add a biblio ($biblio is a hash with the values)
2917 sub _koha_add_biblio {
2918 my ( $dbh, $biblio, $frameworkcode ) = @_;
2922 # set the series flag
2924 if ( $biblio->{'seriestitle'} ) { $serial = 1 };
2928 SET frameworkcode = ?,
2939 my $sth = $dbh->prepare($query);
2942 $biblio->{'author'},
2944 $biblio->{'unititle'},
2947 $biblio->{'seriestitle'},
2948 $biblio->{'copyrightdate'},
2949 $biblio->{'abstract'}
2952 my $biblionumber = $dbh->{'mysql_insertid'};
2953 if ( $dbh->errstr ) {
2954 $error.="ERROR in _koha_add_biblio $query".$dbh->errstr;
2959 #warn "LEAVING _koha_add_biblio: ".$biblionumber."\n";
2960 return ($biblionumber,$error);
2963 =head2 _koha_modify_biblio
2967 my ($biblionumber,$error) == _koha_modify_biblio($dbh,$biblio,$frameworkcode);
2969 Internal function for updating the biblio table
2975 sub _koha_modify_biblio {
2976 my ( $dbh, $biblio, $frameworkcode ) = @_;
2981 SET frameworkcode = ?,
2990 WHERE biblionumber = ?
2993 my $sth = $dbh->prepare($query);
2997 $biblio->{'author'},
2999 $biblio->{'unititle'},
3001 $biblio->{'serial'},
3002 $biblio->{'seriestitle'},
3003 $biblio->{'copyrightdate'},
3004 $biblio->{'abstract'},
3005 $biblio->{'biblionumber'}
3006 ) if $biblio->{'biblionumber'};
3008 if ( $dbh->errstr || !$biblio->{'biblionumber'} ) {
3009 $error.="ERROR in _koha_modify_biblio $query".$dbh->errstr;
3012 return ( $biblio->{'biblionumber'},$error );
3015 =head2 _koha_modify_biblioitem_nonmarc
3019 my ($biblioitemnumber,$error) = _koha_modify_biblioitem_nonmarc( $dbh, $biblioitem );
3021 Updates biblioitems row except for marc and marcxml, which should be changed
3028 sub _koha_modify_biblioitem_nonmarc {
3029 my ( $dbh, $biblioitem ) = @_;
3032 # re-calculate the cn_sort, it may have changed
3033 my ($cn_sort) = GetClassSort($biblioitem->{'biblioitems.cn_source'}, $biblioitem->{'cn_class'}, $biblioitem->{'cn_item'} );
3037 SET biblionumber = ?,
3043 publicationyear = ?,
3047 collectiontitle = ?,
3049 collectionvolume= ?,
3050 editionstatement= ?,
3051 editionresponsibility = ?,
3065 where biblioitemnumber = ?
3067 my $sth = $dbh->prepare($query);
3069 $biblioitem->{'biblionumber'},
3070 $biblioitem->{'volume'},
3071 $biblioitem->{'number'},
3072 $biblioitem->{'itemtype'},
3073 $biblioitem->{'isbn'},
3074 $biblioitem->{'issn'},
3075 $biblioitem->{'publicationyear'},
3076 $biblioitem->{'publishercode'},
3077 $biblioitem->{'volumedate'},
3078 $biblioitem->{'volumedesc'},
3079 $biblioitem->{'collectiontitle'},
3080 $biblioitem->{'collectionissn'},
3081 $biblioitem->{'collectionvolume'},
3082 $biblioitem->{'editionstatement'},
3083 $biblioitem->{'editionresponsibility'},
3084 $biblioitem->{'illus'},
3085 $biblioitem->{'pages'},
3086 $biblioitem->{'bnotes'},
3087 $biblioitem->{'size'},
3088 $biblioitem->{'place'},
3089 $biblioitem->{'lccn'},
3090 $biblioitem->{'url'},
3091 $biblioitem->{'biblioitems.cn_source'},
3092 $biblioitem->{'cn_class'},
3093 $biblioitem->{'cn_item'},
3094 $biblioitem->{'cn_suffix'},
3096 $biblioitem->{'totalissues'},
3097 $biblioitem->{'biblioitemnumber'}
3099 if ( $dbh->errstr ) {
3100 $error.="ERROR in _koha_modify_biblioitem_nonmarc $query".$dbh->errstr;
3103 return ($biblioitem->{'biblioitemnumber'},$error);
3106 =head2 _koha_add_biblioitem
3110 my ($biblioitemnumber,$error) = _koha_add_biblioitem( $dbh, $biblioitem );
3112 Internal function to add a biblioitem
3118 sub _koha_add_biblioitem {
3119 my ( $dbh, $biblioitem ) = @_;
3122 my ($cn_sort) = GetClassSort($biblioitem->{'biblioitems.cn_source'}, $biblioitem->{'cn_class'}, $biblioitem->{'cn_item'} );
3124 "INSERT INTO biblioitems SET
3131 publicationyear = ?,
3135 collectiontitle = ?,
3137 collectionvolume= ?,
3138 editionstatement= ?,
3139 editionresponsibility = ?,
3155 my $sth = $dbh->prepare($query);
3157 $biblioitem->{'biblionumber'},
3158 $biblioitem->{'volume'},
3159 $biblioitem->{'number'},
3160 $biblioitem->{'itemtype'},
3161 $biblioitem->{'isbn'},
3162 $biblioitem->{'issn'},
3163 $biblioitem->{'publicationyear'},
3164 $biblioitem->{'publishercode'},
3165 $biblioitem->{'volumedate'},
3166 $biblioitem->{'volumedesc'},
3167 $biblioitem->{'collectiontitle'},
3168 $biblioitem->{'collectionissn'},
3169 $biblioitem->{'collectionvolume'},
3170 $biblioitem->{'editionstatement'},
3171 $biblioitem->{'editionresponsibility'},
3172 $biblioitem->{'illus'},
3173 $biblioitem->{'pages'},
3174 $biblioitem->{'bnotes'},
3175 $biblioitem->{'size'},
3176 $biblioitem->{'place'},
3177 $biblioitem->{'lccn'},
3178 $biblioitem->{'marc'},
3179 $biblioitem->{'url'},
3180 $biblioitem->{'biblioitems.cn_source'},
3181 $biblioitem->{'cn_class'},
3182 $biblioitem->{'cn_item'},
3183 $biblioitem->{'cn_suffix'},
3185 $biblioitem->{'totalissues'}
3187 my $bibitemnum = $dbh->{'mysql_insertid'};
3188 if ( $dbh->errstr ) {
3189 $error.="ERROR in _koha_add_biblioitem $query".$dbh->errstr;
3193 return ($bibitemnum,$error);
3196 =head2 _koha_new_items
3200 my ($itemnumber,$error) = _koha_new_items( $dbh, $item, $barcode );
3206 sub _koha_new_items {
3207 my ( $dbh, $item, $barcode ) = @_;
3209 my ($items_cn_sort) = GetClassSort($item->{'items.cn_source'}, $item->{'itemcallnumber'}, "");
3211 # if dateaccessioned is provided, use it. Otherwise, set to NOW()
3212 if ( $item->{'dateaccessioned'} eq '' || !$item->{'dateaccessioned'} ) {
3213 my $today = C4::Dates->new();
3214 $item->{'dateaccessioned'} = $today->output("iso"); #TODO: check time issues
3217 "INSERT INTO items SET
3219 biblioitemnumber = ?,
3221 dateaccessioned = ?,
3225 replacementprice = ?,
3226 replacementpricedate = NOW(),
3227 datelastborrowed = ?,
3228 datelastseen = NOW(),
3251 my $sth = $dbh->prepare($query);
3253 $item->{'biblionumber'},
3254 $item->{'biblioitemnumber'},
3256 $item->{'dateaccessioned'},
3257 $item->{'booksellerid'},
3258 $item->{'homebranch'},
3260 $item->{'replacementprice'},
3261 $item->{datelastborrowed},
3263 $item->{'notforloan'},
3265 $item->{'itemlost'},
3266 $item->{'wthdrawn'},
3267 $item->{'itemcallnumber'},
3268 $item->{'restricted'},
3269 $item->{'itemnotes'},
3270 $item->{'holdingbranch'},
3272 $item->{'location'},
3275 $item->{'renewals'},
3276 $item->{'reserves'},
3277 $item->{'items.cn_source'},
3281 $item->{'materials'},
3284 my $itemnumber = $dbh->{'mysql_insertid'};
3285 if ( defined $sth->errstr ) {
3286 $error.="ERROR in _koha_new_items $query".$sth->errstr;
3289 return ( $itemnumber, $error );
3292 =head2 _koha_delete_biblio
3296 $error = _koha_delete_biblio($dbh,$biblionumber);
3298 Internal sub for deleting from biblio table -- also saves to deletedbiblio
3300 C<$dbh> - the database handle
3301 C<$biblionumber> - the biblionumber of the biblio to be deleted
3307 # FIXME: add error handling
3309 sub _koha_delete_biblio {
3310 my ( $dbh, $biblionumber ) = @_;
3312 # get all the data for this biblio
3313 my $sth = $dbh->prepare("SELECT * FROM biblio WHERE biblionumber=?");
3314 $sth->execute($biblionumber);
3316 if ( my $data = $sth->fetchrow_hashref ) {
3318 # save the record in deletedbiblio
3319 # find the fields to save
3320 my $query = "INSERT INTO deletedbiblio SET ";
3322 foreach my $temp ( keys %$data ) {
3323 $query .= "$temp = ?,";
3324 push( @bind, $data->{$temp} );
3327 # replace the last , by ",?)"
3329 my $bkup_sth = $dbh->prepare($query);
3330 $bkup_sth->execute(@bind);
3334 my $del_sth = $dbh->prepare("DELETE FROM biblio WHERE biblionumber=?");
3335 $del_sth->execute($biblionumber);
3342 =head2 _koha_delete_biblioitems
3346 $error = _koha_delete_biblioitems($dbh,$biblioitemnumber);
3348 Internal sub for deleting from biblioitems table -- also saves to deletedbiblioitems
3350 C<$dbh> - the database handle
3351 C<$biblionumber> - the biblioitemnumber of the biblioitem to be deleted
3357 # FIXME: add error handling
3359 sub _koha_delete_biblioitems {
3360 my ( $dbh, $biblioitemnumber ) = @_;
3362 # get all the data for this biblioitem
3364 $dbh->prepare("SELECT * FROM biblioitems WHERE biblioitemnumber=?");
3365 $sth->execute($biblioitemnumber);
3367 if ( my $data = $sth->fetchrow_hashref ) {
3369 # save the record in deletedbiblioitems
3370 # find the fields to save
3371 my $query = "INSERT INTO deletedbiblioitems SET ";
3373 foreach my $temp ( keys %$data ) {
3374 $query .= "$temp = ?,";
3375 push( @bind, $data->{$temp} );
3378 # replace the last , by ",?)"
3380 my $bkup_sth = $dbh->prepare($query);
3381 $bkup_sth->execute(@bind);
3384 # delete the biblioitem
3386 $dbh->prepare("DELETE FROM biblioitems WHERE biblioitemnumber=?");
3387 $del_sth->execute($biblioitemnumber);
3394 =head2 _koha_delete_item
3398 _koha_delete_item( $dbh, $itemnum );
3400 Internal function to delete an item record from the koha tables
3406 sub _koha_delete_item {
3407 my ( $dbh, $itemnum ) = @_;
3409 # save the deleted item to deleteditems table
3410 my $sth = $dbh->prepare("SELECT * FROM items WHERE itemnumber=?");
3411 $sth->execute($itemnum);
3412 my $data = $sth->fetchrow_hashref();
3414 my $query = "INSERT INTO deleteditems SET ";
3416 foreach my $key ( keys %$data ) {
3417 $query .= "$key = ?,";
3418 push( @bind, $data->{$key} );
3421 $sth = $dbh->prepare($query);
3422 $sth->execute(@bind);
3425 # delete from items table
3426 $sth = $dbh->prepare("DELETE FROM items WHERE itemnumber=?");
3427 $sth->execute($itemnum);
3432 =head1 UNEXPORTED FUNCTIONS
3434 =head2 ModBiblioMarc
3436 &ModBiblioMarc($newrec,$biblionumber,$frameworkcode);
3438 Add MARC data for a biblio to koha
3440 Function exported, but should NOT be used, unless you really know what you're doing
3446 # pass the MARC::Record to this function, and it will create the records in the marc field
3447 my ( $record, $biblionumber, $frameworkcode ) = @_;
3448 my $dbh = C4::Context->dbh;
3449 my @fields = $record->fields();
3450 if ( !$frameworkcode ) {
3451 $frameworkcode = "";
3454 $dbh->prepare("UPDATE biblio SET frameworkcode=? WHERE biblionumber=?");
3455 $sth->execute( $frameworkcode, $biblionumber );
3457 my $encoding = C4::Context->preference("marcflavour");
3459 # deal with UNIMARC field 100 (encoding) : create it if needed & set encoding to unicode
3460 if ( $encoding eq "UNIMARC" ) {
3462 if ( length($record->subfield( 100, "a" )) == 35 ) {
3463 $string = $record->subfield( 100, "a" );
3464 my $f100 = $record->field(100);
3465 $record->delete_field($f100);
3468 $string = POSIX::strftime( "%Y%m%d", localtime );
3470 $string = sprintf( "%-*s", 35, $string );
3472 substr( $string, 22, 6, "frey50" );
3473 unless ( $record->subfield( 100, "a" ) ) {
3474 $record->insert_grouped_field(
3475 MARC::Field->new( 100, "", "", "a" => $string ) );
3478 ModZebra($biblionumber,"specialUpdate","biblioserver",$record);
3481 "UPDATE biblioitems SET marc=?,marcxml=? WHERE biblionumber=?");
3482 $sth->execute( $record->as_usmarc(), $record->as_xml_record($encoding),
3485 return $biblionumber;
3488 =head2 z3950_extended_services
3490 z3950_extended_services($serviceType,$serviceOptions,$record);
3492 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.
3494 C<$serviceType> one of: itemorder,create,drop,commit,update,xmlupdate
3496 C<$serviceOptions> a has of key/value pairs. For instance, if service_type is 'update', $service_options should contain:
3498 action => update action, one of specialUpdate, recordInsert, recordReplace, recordDelete, elementUpdate.
3502 recordidOpaque => Opaque Record ID (user supplied) or recordidNumber => Record ID number (system number).
3503 syntax => the record syntax (transfer syntax)
3504 databaseName = Database from connection object
3506 To set serviceOptions, call set_service_options($serviceType)
3508 C<$record> the record, if one is needed for the service type
3510 A record should be in XML. You can convert it to XML from MARC by running it through marc2xml().
3514 sub z3950_extended_services {
3515 my ( $server, $serviceType, $action, $serviceOptions ) = @_;
3517 # get our connection object
3518 my $Zconn = C4::Context->Zconn( $server, 0, 1 );
3520 # create a new package object
3521 my $Zpackage = $Zconn->package();
3524 $Zpackage->option( action => $action );
3526 if ( $serviceOptions->{'databaseName'} ) {
3527 $Zpackage->option( databaseName => $serviceOptions->{'databaseName'} );
3529 if ( $serviceOptions->{'recordIdNumber'} ) {
3531 recordIdNumber => $serviceOptions->{'recordIdNumber'} );
3533 if ( $serviceOptions->{'recordIdOpaque'} ) {
3535 recordIdOpaque => $serviceOptions->{'recordIdOpaque'} );
3538 # this is an ILL request (Zebra doesn't support it, but Koha could eventually)
3539 #if ($serviceType eq 'itemorder') {
3540 # $Zpackage->option('contact-name' => $serviceOptions->{'contact-name'});
3541 # $Zpackage->option('contact-phone' => $serviceOptions->{'contact-phone'});
3542 # $Zpackage->option('contact-email' => $serviceOptions->{'contact-email'});
3543 # $Zpackage->option('itemorder-item' => $serviceOptions->{'itemorder-item'});
3546 if ( $serviceOptions->{record} ) {
3547 $Zpackage->option( record => $serviceOptions->{record} );
3549 # can be xml or marc
3550 if ( $serviceOptions->{'syntax'} ) {
3551 $Zpackage->option( syntax => $serviceOptions->{'syntax'} );
3555 # send the request, handle any exception encountered
3556 eval { $Zpackage->send($serviceType) };
3557 if ( $@ && $@->isa("ZOOM::Exception") ) {
3558 return "error: " . $@->code() . " " . $@->message() . "\n";
3561 # free up package resources
3562 $Zpackage->destroy();
3565 =head2 set_service_options
3567 my $serviceOptions = set_service_options($serviceType);
3569 C<$serviceType> itemorder,create,drop,commit,update,xmlupdate
3571 Currently, we only support 'create', 'commit', and 'update'. 'drop' support will be added as soon as Zebra supports it.
3575 sub set_service_options {
3576 my ($serviceType) = @_;
3579 # FIXME: This needs to be an OID ... if we ever need 'syntax' this sub will need to change
3580 # $serviceOptions->{ 'syntax' } = ''; #zebra doesn't support syntaxes other than xml
3582 if ( $serviceType eq 'commit' ) {
3586 if ( $serviceType eq 'create' ) {
3590 if ( $serviceType eq 'drop' ) {
3591 die "ERROR: 'drop' not currently supported (by Zebra)";
3593 return $serviceOptions;
3596 END { } # module clean-up code here (global destructor)
3604 Koha Developement team <info@koha.org>
3606 Paul POULAIN paul.poulain@free.fr
3608 Joshua Ferraro jmf@liblime.com