1 package OpenILS::Application::Cat::BibCommon;
2 use strict; use warnings;
3 use OpenILS::Utils::CStoreEditor q/:funcs/;
4 use OpenSRF::Utils::Logger qw($logger);
5 use OpenILS::Application::AppUtils;
6 use OpenILS::Utils::Fieldmapper;
7 use OpenILS::Const qw/:const/;
8 use OpenSRF::AppSession;
10 my $U = 'OpenILS::Application::AppUtils';
11 my $MARC_NAMESPACE = 'http://www.loc.gov/MARC21/slim';
14 # ---------------------------------------------------------------------------
15 # Shared bib mangling code. Do not publish methods from here.
16 # ---------------------------------------------------------------------------
19 sub biblio_record_replace_marc {
20 my($class, $e, $recid, $newxml, $source, $fixtcn, $override) = @_;
22 my $rec = $e->retrieve_biblio_record_entry($recid)
23 or return $e->die_event;
25 # See if there is a different record in the database that has our TCN value
26 # If we're not updating the TCN, all we care about it the marcdoc
27 # XXX should .update even bother with the tcn_info if it's not going to replace it?
28 # there is the potential for returning a TCN_EXISTS event, even though no replacement happens
30 my( $tcn, $tsource, $marcdoc, $evt);
32 if($fixtcn or $override) {
34 ($tcn, $tsource, $marcdoc, $evt) =
35 _find_tcn_info($e, $newxml, $override, $recid);
39 $rec->tcn_value($tcn) if ($tcn);
40 $rec->tcn_source($tsource);
44 $marcdoc = __make_marc_doc($newxml);
48 $rec->source(bib_source_from_name($source)) if $source;
49 $rec->editor($e->requestor->id);
50 $rec->edit_date('now');
51 $rec->marc( $U->entityize( $marcdoc->documentElement->toString ) );
52 $e->update_biblio_record_entry($rec) or return $e->die_event;
54 # we don't care about the result, just fire off the request
55 my $ses = OpenSRF::AppSession->create('open-ils.ingest');
56 $ses->request('open-ils.ingest.full.biblio.record', $recid);
61 sub biblio_record_xml_import {
62 my($class, $e, $xml, $source, $auto_tcn, $override) = @_;
64 my( $evt, $tcn, $tcn_source, $marcdoc );
67 # auto_tcn forces a blank TCN value so the DB will have to generate one for us
68 $marcdoc = __make_marc_doc($xml);
70 ( $tcn, $tcn_source, $marcdoc, $evt ) = _find_tcn_info($e, $xml, $override);
74 $logger->info("user ".$e->requestor->id.
75 " creating new biblio entry with tcn=$tcn and tcn_source $tcn_source");
77 my $record = Fieldmapper::biblio::record_entry->new;
79 $record->source(bib_source_from_name($source)) if $source;
80 $record->tcn_source($tcn_source);
81 $record->tcn_value($tcn) if ($tcn);
82 $record->creator($e->requestor->id);
83 $record->editor($e->requestor->id);
84 $record->create_date('now');
85 $record->edit_date('now');
86 $record->marc($U->entityize($marcdoc->documentElement->toString));
88 $record = $e->create_biblio_record_entry($record) or return $e->die_event;
89 $logger->info("marc create/import created new record ".$record->id);
91 # we don't care about the result, just fire off the request
92 my $ses = OpenSRF::AppSession->create('open-ils.ingest');
93 $ses->request('open-ils.ingest.full.biblio.record', $record->id);
100 my $marcxml = XML::LibXML->new->parse_string($xml);
101 $marcxml->documentElement->setNamespace($MARC_NAMESPACE, "marc", 1 );
102 $marcxml->documentElement->setNamespace($MARC_NAMESPACE);
110 my $override = shift;
111 my $existing_rec = shift || 0;
114 my $marcxml = __make_marc_doc($xml);
116 my $xpath = '//marc:controlfield[@tag="001"]';
117 my $tcn = $marcxml->documentElement->findvalue($xpath);
118 $logger->info("biblio import located 001 (tcn) value of $tcn");
120 $xpath = '//marc:controlfield[@tag="003"]';
121 my $tcn_source = $marcxml->documentElement->findvalue($xpath) || "System Local";
123 if(my $rec = _tcn_exists($editor, $tcn, $tcn_source, $existing_rec) ) {
126 $tcn = find_free_tcn( $marcxml, $editor, $existing_rec );
128 # if we're overriding, try to find a different TCN to use
131 # XXX Create ALLOW_ALT_TCN permission check support
133 $logger->info("tcn value $tcn already exists, attempting to override");
141 'OPEN_TCN_NOT_FOUND',
142 payload => $marcxml->toString())
148 $logger->warn("tcn value $origtcn already exists in import/create");
150 # otherwise, return event
156 'TCN_EXISTS', payload => {
166 return ($tcn, $tcn_source, $marcxml);
173 my $existing_rec = shift;
177 my $xpath = '//marc:datafield[@tag="039"]/subfield[@code="a"]';
178 my ($tcn) = $marcxml->documentElement->findvalue($xpath) =~ /(\w+)\s*$/o;
179 $xpath = '//marc:datafield[@tag="039"]/subfield[@code="b"]';
180 my $tcn_source = $marcxml->documentElement->findvalue($xpath) || "System Local";
182 if(_tcn_exists($editor, $tcn, $tcn_source, $existing_rec)) {
190 $xpath = '//marc:datafield[@tag="020"]/subfield[@code="a"]';
191 ($tcn) = $marcxml->documentElement->findvalue($xpath) =~ /(\w+)\s*$/o;
192 $tcn_source = "ISBN";
193 if(_tcn_exists($editor, $tcn, $tcn_source, $existing_rec)) {$tcn = undef;}
197 $xpath = '//marc:datafield[@tag="022"]/subfield[@code="a"]';
198 ($tcn) = $marcxml->documentElement->findvalue($xpath) =~ /(\w+)\s*$/o;
199 $tcn_source = "ISSN";
200 if(_tcn_exists($editor, $tcn, $tcn_source, $existing_rec)) {$tcn = undef;}
204 $xpath = '//marc:datafield[@tag="010"]';
205 ($tcn) = $marcxml->documentElement->findvalue($xpath) =~ /(\w+)\s*$/o;
206 $tcn_source = "LCCN";
207 if(_tcn_exists($editor, $tcn, $tcn_source, $existing_rec)) {$tcn = undef;}
211 $xpath = '//marc:datafield[@tag="035"]/subfield[@code="a"]';
212 ($tcn) = $marcxml->documentElement->findvalue($xpath) =~ /(\w+)\s*$/o;
213 $tcn_source = "System Legacy";
214 if(_tcn_exists($editor, $tcn, $tcn_source, $existing_rec)) {$tcn = undef;}
217 $marcxml->documentElement->removeChild(
218 $marcxml->documentElement->findnodes( '//datafield[@tag="035"]' )
223 return undef unless $tcn;
226 my $df = $marcxml->createElementNS( 'http://www.loc.gov/MARC21/slim', 'datafield');
227 $df->setAttribute( tag => '039' );
228 $df->setAttribute( ind1 => ' ' );
229 $df->setAttribute( ind2 => ' ' );
230 $marcxml->documentElement->appendChild( $df );
232 my $sfa = $marcxml->createElementNS( 'http://www.loc.gov/MARC21/slim', 'subfield');
233 $sfa->setAttribute( code => 'a' );
234 $sfa->appendChild( $marcxml->createTextNode( $tcn ) );
235 $df->appendChild( $sfa );
237 my $sfb = $marcxml->createElementNS( 'http://www.loc.gov/MARC21/slim', 'subfield');
238 $sfb->setAttribute( code => 'b' );
239 $sfb->appendChild( $marcxml->createTextNode( $tcn_source ) );
240 $df->appendChild( $sfb );
252 my $existing_rec = shift || 0;
254 if(!$tcn) {return 0;}
256 $logger->debug("tcn_exists search for tcn $tcn and source $source and id $existing_rec");
258 # XXX why does the source matter?
259 # my $req = $session->request(
260 # { tcn_value => $tcn, tcn_source => $source, deleted => 'f' } );
262 my $recs = $editor->search_biblio_record_entry(
263 {tcn_value => $tcn, deleted => 'f', id => {'!=' => $existing_rec}}, {idlist =>1});
266 $logger->debug("_tcn_exists is true for tcn : $tcn ($source)");
270 $logger->debug("_tcn_exists is false for tcn : $tcn ($source)");