# Copyright 2000-2002 Katipo Communications
# Copyright 2010 BibLibre
+# Copyright 2011 Equinox Software, Inc.
#
# This file is part of Koha.
#
use C4::Charset;
require C4::Heading;
require C4::Serials;
+require C4::Items;
use vars qw($VERSION @ISA @EXPORT);
&GetUsedMarcStructure
&GetXmlBiblio
&GetCOinSBiblio
+ &GetMarcPrice
+ &GetMarcQuantity
&GetAuthorisedValueDesc
&GetMarcStructure
my $dbh = C4::Context->dbh;
# transform the data into koha-table style data
+ SetUTF8Flag($record);
my $olddata = TransformMarcToKoha( $dbh, $record, $frameworkcode );
( $biblionumber, $error ) = _koha_add_biblio( $dbh, $olddata, $frameworkcode );
$olddata->{'biblionumber'} = $biblionumber;
logaction( "CATALOGUING", "MODIFY", $biblionumber, "BEFORE=>" . $newrecord->as_formatted );
}
+ SetUTF8Flag($record);
my $dbh = C4::Context->dbh;
$frameworkcode = "" unless $frameworkcode;
- # get the items before and append them to the biblio before updating the record, atm we just have the biblio
- my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField( "items.itemnumber", $frameworkcode );
- my $oldRecord = GetMarcBiblio($biblionumber);
-
- # delete any item fields from incoming record to avoid
- # duplication or incorrect data - use AddItem() or ModItem()
- # to change items
- foreach my $field ( $record->field($itemtag) ) {
- $record->delete_field($field);
- }
-
- # parse each item, and, for an unknown reason, re-encode each subfield
- # if you don't do that, the record will have encoding mixed
- # and the biblio will be re-encoded.
- # strange, I (Paul P.) searched more than 1 day to understand what happends
- # but could only solve the problem this way...
- my @fields = $oldRecord->field($itemtag);
- foreach my $fielditem (@fields) {
- my $field;
- foreach ( $fielditem->subfields() ) {
- if ($field) {
- $field->add_subfields( Encode::encode( 'utf-8', $_->[0] ) => Encode::encode( 'utf-8', $_->[1] ) );
- } else {
- $field = MARC::Field->new( "$itemtag", '', '', Encode::encode( 'utf-8', $_->[0] ) => Encode::encode( 'utf-8', $_->[1] ) );
- }
- }
- $record->append_fields($field);
- }
+ _strip_item_fields($record, $frameworkcode);
foreach my $field ($record->fields()) {
if (! $field->is_control_field()) {
return 1;
}
+=head2 _strip_item_fields
+
+ _strip_item_fields($record, $frameworkcode)
+
+Utility routine to remove item tags from a
+MARC bib.
+
+=cut
+
+sub _strip_item_fields {
+ my $record = shift;
+ my $frameworkcode = shift;
+ # get the items before and append them to the biblio before updating the record, atm we just have the biblio
+ my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField( "items.itemnumber", $frameworkcode );
+
+ # delete any item fields from incoming record to avoid
+ # duplication or incorrect data - use AddItem() or ModItem()
+ # to change items
+ foreach my $field ( $record->field($itemtag) ) {
+ $record->delete_field($field);
+ }
+}
+
=head2 ModBiblioframework
ModBiblioframework($biblionumber,$frameworkcode);
sub GetISBDView {
my ( $biblionumber, $template ) = @_;
- my $record = GetMarcBiblio($biblionumber);
+ my $record = GetMarcBiblio($biblionumber, 1);
+ return undef unless defined $record;
my $itemtype = &GetFrameworkCode($biblionumber);
my ( $holdingbrtagf, $holdingbrtagsubf ) = &GetMarcFromKohaField( "items.holdingbranch", $itemtype );
my $tagslib = &GetMarcStructure( 1, $itemtype );
=head2 GetMarcBiblio
- my $record = GetMarcBiblio($biblionumber);
+ my $record = GetMarcBiblio($biblionumber, [$embeditems]);
Returns MARC::Record representing bib identified by
C<$biblionumber>. If no bib exists, returns undef.
-The MARC record contains both biblio & item data.
+C<$embeditems>. If set to true, items data are included.
+The MARC record contains biblio data, and items data if $embeditems is set to true.
=cut
sub GetMarcBiblio {
my $biblionumber = shift;
+ my $embeditems = shift || 0;
my $dbh = C4::Context->dbh;
my $sth = $dbh->prepare("SELECT marcxml FROM biblioitems WHERE biblionumber=? ");
$sth->execute($biblionumber);
if ($marcxml) {
$record = eval { MARC::Record::new_from_xml( $marcxml, "utf8", C4::Context->preference('marcflavour') ) };
if ($@) { warn " problem with :$biblionumber : $@ \n$marcxml"; }
+ return unless $record;
+
+ C4::Biblio::EmbedItemsInMarcBiblio($record, $biblionumber) if ($embeditems);
# $record = MARC::Record::new_from_usmarc( $marc) if $marc;
return $record;
my $isbn = '';
my $issn = '';
my $publisher = '';
-
- if ( C4::Context->preference("marcflavour") eq "UNIMARC" ) {
- my $fmts6;
- my $fmts7;
- %$fmts6 = (
- 'a' => 'book',
- 'b' => 'manuscript',
- 'c' => 'book',
- 'd' => 'manuscript',
- 'e' => 'map',
- 'f' => 'map',
- 'g' => 'film',
- 'i' => 'audioRecording',
- 'j' => 'audioRecording',
- 'k' => 'artwork',
- 'l' => 'document',
- 'm' => 'computerProgram',
- 'r' => 'document',
-
- );
- %$fmts7 = (
- 'a' => 'journalArticle',
- 's' => 'journal',
- );
-
- $genre = $fmts6->{$pos6} ? $fmts6->{$pos6} : 'book';
-
- if ( $genre eq 'book' ) {
+ my $pages = '';
+ my $titletype = 'b';
+
+ # For the purposes of generating COinS metadata, LDR/06-07 can be
+ # considered the same for UNIMARC and MARC21
+ my $fmts6;
+ my $fmts7;
+ %$fmts6 = (
+ 'a' => 'book',
+ 'b' => 'manuscript',
+ 'c' => 'book',
+ 'd' => 'manuscript',
+ 'e' => 'map',
+ 'f' => 'map',
+ 'g' => 'film',
+ 'i' => 'audioRecording',
+ 'j' => 'audioRecording',
+ 'k' => 'artwork',
+ 'l' => 'document',
+ 'm' => 'computerProgram',
+ 'o' => 'document',
+ 'r' => 'document',
+ );
+ %$fmts7 = (
+ 'a' => 'journalArticle',
+ 's' => 'journal',
+ );
+
+ $genre = $fmts6->{$pos6} ? $fmts6->{$pos6} : 'book';
+
+ if ( $genre eq 'book' ) {
$genre = $fmts7->{$pos7} if $fmts7->{$pos7};
- }
+ }
- ##### We must transform mtx to a valable mtx and document type ####
- if ( $genre eq 'book' ) {
+ ##### We must transform mtx to a valable mtx and document type ####
+ if ( $genre eq 'book' ) {
$mtx = 'book';
- } elsif ( $genre eq 'journal' ) {
+ } elsif ( $genre eq 'journal' ) {
$mtx = 'journal';
- } elsif ( $genre eq 'journalArticle' ) {
+ $titletype = 'j';
+ } elsif ( $genre eq 'journalArticle' ) {
$mtx = 'journal';
$genre = 'article';
- } else {
+ $titletype = 'a';
+ } else {
$mtx = 'dc';
- }
+ }
- $genre = ( $mtx eq 'dc' ) ? "&rft.type=$genre" : "&rft.genre=$genre";
+ $genre = ( $mtx eq 'dc' ) ? "&rft.type=$genre" : "&rft.genre=$genre";
+
+ if ( C4::Context->preference("marcflavour") eq "UNIMARC" ) {
# Setting datas
$aulast = $record->subfield( '700', 'a' );
} else {
# MARC21 need some improve
- my $fmts;
- $mtx = 'book';
- $genre = "&rft.genre=book";
# Setting datas
if ( $record->field('100') ) {
$oauthors .= "&rft.au=$au";
}
}
- $title = "&rft.btitle=" . $record->subfield( '245', 'a' );
+ $title = "&rft." . $titletype . "title=" . $record->subfield( '245', 'a' );
$subtitle = $record->subfield( '245', 'b' ) || '';
$title .= $subtitle;
- $pubyear = $record->subfield( '260', 'c' ) || '';
- $publisher = $record->subfield( '260', 'b' ) || '';
- $isbn = $record->subfield( '020', 'a' ) || '';
- $issn = $record->subfield( '022', 'a' ) || '';
+ if ($titletype eq 'a') {
+ $pubyear = substr $record->field('008')->data(), 7, 4;
+ $isbn = $record->subfield( '773', 'z' ) || '';
+ $issn = $record->subfield( '773', 'x' ) || '';
+ if ($mtx eq 'journal') {
+ $title .= "&rft.title=" . (($record->subfield( '773', 't' ) || $record->subfield( '773', 'a')));
+ } else {
+ $title .= "&rft.btitle=" . (($record->subfield( '773', 't' ) || $record->subfield( '773', 'a')) || '');
+ }
+ foreach my $rel ($record->subfield( '773', 'g' )) {
+ if ($pages) {
+ $pages .= ', ';
+ }
+ $pages .= $rel;
+ }
+ } else {
+ $pubyear = $record->subfield( '260', 'c' ) || '';
+ $publisher = $record->subfield( '260', 'b' ) || '';
+ $isbn = $record->subfield( '020', 'a' ) || '';
+ $issn = $record->subfield( '022', 'a' ) || '';
+ }
}
my $coins_value =
-"ctx_ver=Z39.88-2004&rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3A$mtx$genre$title&rft.isbn=$isbn&rft.issn=$issn&rft.aulast=$aulast&rft.aufirst=$aufirst$oauthors&rft.pub=$publisher&rft.date=$pubyear";
+"ctx_ver=Z39.88-2004&rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3A$mtx$genre$title&rft.isbn=$isbn&rft.issn=$issn&rft.aulast=$aulast&rft.aufirst=$aufirst$oauthors&rft.pub=$publisher&rft.date=$pubyear&rft.pages=$pages";
$coins_value =~ s/(\ |&[^a])/\+/g;
$coins_value =~ s/\"/\"\;/g;
return $coins_value;
}
+
+=head2 GetMarcPrice
+
+return the prices in accordance with the Marc format.
+=cut
+
+sub GetMarcPrice {
+ my ( $record, $marcflavour ) = @_;
+ my @listtags;
+ my $subfield;
+
+ if ( $marcflavour eq "MARC21" ) {
+ @listtags = ('345', '020');
+ $subfield="c";
+ } elsif ( $marcflavour eq "UNIMARC" ) {
+ @listtags = ('345', '010');
+ $subfield="d";
+ } else {
+ return;
+ }
+
+ for my $field ( $record->field(@listtags) ) {
+ for my $subfield_value ($field->subfield($subfield)){
+ #check value
+ return $subfield_value if ($subfield_value);
+ }
+ }
+ return 0; # no price found
+}
+
+=head2 GetMarcQuantity
+
+return the quantity of a book. Used in acquisition only, when importing a file an iso2709 from a bookseller
+Warning : this is not really in the marc standard. In Unimarc, Electre (the most widely used bookseller) use the 969$a
+
+=cut
+
+sub GetMarcQuantity {
+ my ( $record, $marcflavour ) = @_;
+ my @listtags;
+ my $subfield;
+
+ if ( $marcflavour eq "MARC21" ) {
+ return 0
+ } elsif ( $marcflavour eq "UNIMARC" ) {
+ @listtags = ('969');
+ $subfield="a";
+ } else {
+ return;
+ }
+
+ for my $field ( $record->field(@listtags) ) {
+ for my $subfield_value ($field->subfield($subfield)){
+ #check value
+ if ($subfield_value) {
+ # in France, the cents separator is the , but sometimes, ppl use a .
+ # in this case, the price will be x100 when unformatted ! Replace the . by a , to get a proper price calculation
+ $subfield_value =~ s/\./,/ if C4::Context->preference("CurrencyFormat") eq "FR";
+ return $subfield_value;
+ }
+ }
+ }
+ return 0; # no price found
+}
+
+
=head2 GetAuthorisedValueDesc
my $subfieldvalue =get_authorised_value_desc(
sub GetMarcISBN {
my ( $record, $marcflavour ) = @_;
my $scope;
- if ( $marcflavour eq "MARC21" ) {
- $scope = '020';
- } else { # assume unimarc if not marc21
+ if ( $marcflavour eq "UNIMARC" ) {
$scope = '010';
+ } else { # assume marc21 if not unimarc
+ $scope = '020';
}
my @marcisbns;
my $isbn = "";
sub GetMarcNotes {
my ( $record, $marcflavour ) = @_;
my $scope;
- if ( $marcflavour eq "MARC21" ) {
- $scope = '5..';
- } else { # assume unimarc if not marc21
+ if ( $marcflavour eq "UNIMARC" ) {
$scope = '3..';
+ } else { # assume marc21 if not unimarc
+ $scope = '5..';
}
my @marcnotes;
my $note = "";
sub GetMarcSubjects {
my ( $record, $marcflavour ) = @_;
my ( $mintag, $maxtag );
- if ( $marcflavour eq "MARC21" ) {
- $mintag = "600";
- $maxtag = "699";
- } else { # assume unimarc if not marc21
+ if ( $marcflavour eq "UNIMARC" ) {
$mintag = "600";
$maxtag = "611";
+ } else { # assume marc21 if not unimarc
+ $mintag = "600";
+ $maxtag = "699";
}
my @marcsubjects;
# tagslib useful for UNIMARC author reponsabilities
my $tagslib =
&GetMarcStructure( 1, '' ); # FIXME : we don't have the framework available, we take the default framework. May be buggy on some setups, will be usually correct.
- if ( $marcflavour eq "MARC21" ) {
- $mintag = "700";
- $maxtag = "720";
- } elsif ( $marcflavour eq "UNIMARC" ) { # assume unimarc if not marc21
+ if ( $marcflavour eq "UNIMARC" ) {
$mintag = "700";
$maxtag = "712";
+ } elsif ( $marcflavour eq "MARC21" || $marcflavour eq "NORMARC" ) { # assume marc21 or normarc if not unimarc
+ $mintag = "700";
+ $maxtag = "720";
} else {
return;
}
sub GetMarcSeries {
my ( $record, $marcflavour ) = @_;
my ( $mintag, $maxtag );
- if ( $marcflavour eq "MARC21" ) {
- $mintag = "440";
- $maxtag = "490";
- } else { # assume unimarc if not marc21
+ if ( $marcflavour eq "UNIMARC" ) {
$mintag = "600";
$maxtag = "619";
+ } else { # assume marc21 if not unimarc
+ $mintag = "440";
+ $maxtag = "490";
}
my @marcseries;
-tabindex => '',
-multiple => 0,
);
+ } elsif ( $tagslib->{$tag}->{$subfield}->{value_builder} ) {
+ # opening plugin
+ my $plugin = C4::Context->intranetdir . "/cataloguing/value_builder/" . $tagslib->{$tag}->{$subfield}->{'value_builder'};
+ if (do $plugin) {
+ my $temp;
+ my $extended_param = plugin_parameters( $dbh, $temp, $tagslib, $subfield_data{id}, undef );
+ my ( $function_name, $javascript ) = plugin_javascript( $dbh, $temp, $tagslib, $subfield_data{id}, undef );
+ $subfield_data{random} = int(rand(1000000)); # why do we need 2 different randoms?
+ my $index_subfield = int(rand(1000000));
+ $subfield_data{id} = "tag_".$tag."_subfield_".$subfield."_".$index_subfield;
+ $subfield_data{marc_value} = qq[<input tabindex="1" id="$subfield_data{id}" name="field_value" class="input_marceditor" size="67" maxlength="255"
+ onfocus="Focus$function_name($subfield_data{random}, '$subfield_data{id}');"
+ onblur=" Blur$function_name($subfield_data{random}, '$subfield_data{id}');" />
+ <a href="#" class="buttonDot" onclick="Clic$function_name('$subfield_data{id}'); return false;" title="Tag Editor">...</a>
+ $javascript];
+ } else {
+ warn "Plugin Failed: $plugin";
+ $subfield_data{marc_value} = qq(<input tabindex="1" id="$subfield_data{id}" name="field_value" class="input_marceditor" size="67" maxlength="255" />); # supply default input form
+ }
+ }
+ elsif ( $tag eq '' ) { # it's an hidden field
+ $subfield_data{marc_value} = qq(<input type="hidden" tabindex="1" id="$subfield_data{id}" name="field_value" class="input_marceditor" size="67" maxlength="255" value="$defaultvalue" />);
+ }
+ elsif ( $tagslib->{$tag}->{$subfield}->{'hidden'} ) { # FIXME: shouldn't input type be "hidden" ?
+ $subfield_data{marc_value} = qq(<input type="text" tabindex="1" id="$subfield_data{id}" name="field_value" class="input_marceditor" size="67" maxlength="255" value="$defaultvalue" />);
+ }
+ elsif ( length($defaultvalue) > 100
+ or (C4::Context->preference("marcflavour") eq "UNIMARC" and
+ 300 <= $tag && $tag < 400 && $subfield eq 'a' )
+ or (C4::Context->preference("marcflavour") eq "MARC21" and
+ 500 <= $tag && $tag < 600 )
+ ) {
+ # oversize field (textarea)
+ $subfield_data{marc_value} = qq(<textarea tabindex="1" id="$subfield_data{id}" name="field_value" class="input_marceditor" size="67" maxlength="255">$defaultvalue</textarea>\n");
} else {
$subfield_data{marc_value} = "<input type=\"text\" name=\"field_value\" value=\"$defaultvalue\" size=\"50\" maxlength=\"255\" />";
}
return %indexes;
}
+=head2 EmbedItemsInMarcBiblio
+
+ EmbedItemsInMarcBiblio($marc, $biblionumber);
+
+Given a MARC::Record object containing a bib record,
+modify it to include the items attached to it as 9XX
+per the bib's MARC framework.
+
+=cut
+
+sub EmbedItemsInMarcBiblio {
+ my ($marc, $biblionumber) = @_;
+
+ my $frameworkcode = GetFrameworkCode($biblionumber);
+ _strip_item_fields($marc, $frameworkcode);
+
+ # ... and embed the current items
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare("SELECT itemnumber FROM items WHERE biblionumber = ?");
+ $sth->execute($biblionumber);
+ my @item_fields;
+ my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField( "items.itemnumber", $frameworkcode );
+ while (my ($itemnumber) = $sth->fetchrow_array) {
+ my $item_marc = C4::Items::GetMarcItem($biblionumber, $itemnumber);
+ push @item_fields, $item_marc->field($itemtag);
+ }
+ $marc->insert_fields_ordered(@item_fields);
+}
+
=head1 INTERNAL FUNCTIONS
=head2 _DelBiblioNoZebra($biblionumber,$record,$server);