]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/Application/Search/Biblio.pm
updated mods parser with new virtual_record fields
[working/Evergreen.git] / Open-ILS / src / perlmods / OpenILS / Application / Search / Biblio.pm
1 package OpenILS::Application::Search::Biblio;
2 use base qw/OpenSRF::Application/;
3 use strict; use warnings;
4
5 use OpenILS::EX;
6
7 use JSON;
8 use OpenILS::Utils::Fieldmapper;
9 use OpenILS::Utils::ModsParser;
10 use OpenSRF::Utils::SettingsClient;
11
12 use OpenILS::Application::AppUtils;
13
14 use JSON;
15
16 use Time::HiRes qw(time);
17 use OpenSRF::EX qw(:try);
18 use Digest::MD5 qw(md5_hex);
19
20 use XML::LibXML;
21 use XML::LibXSLT;
22
23 my $apputils = "OpenILS::Application::AppUtils";
24
25 # Houses biblio search utilites 
26
27 __PACKAGE__->register_method(
28         method  => "biblio_search_marc",
29         api_name        => "open-ils.search.biblio.marc",
30         argc            => 1, 
31         note            => "Searches biblio information by marc tag",
32 );
33
34 sub biblio_search_marc {
35
36         my( $self, $client, $search_hash, $string ) = @_;
37
38         warn "Building biblio marc session\n";
39         my $session = OpenSRF::AppSession->create("open-ils.storage");
40
41         use Data::Dumper;
42         warn "Sending biblio marc request. String $string\nSearch hash: " . Dumper($search_hash);
43         my $request = $session->request( 
44                         "open-ils.storage.direct.metabib.full_rec.search_fts.index_vector.atomic", 
45                         restrict => $search_hash, 
46                         term            => $string );
47         my $data = $request->gather(1);
48
49         warn Dumper $data;
50
51         $session->finish();
52         $session->disconnect();
53
54         return $data;
55
56 }
57
58
59
60 # ---------------------------------------------------------------------------
61 # takes a list of record id's and turns the docs into friendly 
62 # mods structures. Creates one MODS structure for each doc id.
63 # ---------------------------------------------------------------------------
64 sub _records_to_mods {
65         my @ids = @_;
66         
67         my @results;
68         my @marcxml_objs;
69
70         my $session = OpenSRF::AppSession->create("open-ils.storage");
71         my $request = $session->request(
72                         "open-ils.storage.direct.biblio.record_entry.batch.retrieve",  @ids );
73
74         my $last_content = undef;
75
76         while( my $response = $request->recv() ) {
77
78                 if( $last_content ) {
79                         my $u = OpenILS::Utils::ModsParser->new();
80                         $u->start_mods_batch( $last_content->marc );
81                         my $mods = $u->finish_mods_batch();
82                         $mods->doc_id($last_content->id());
83                         warn "Turning doc " . $mods->doc_id() . " into MODS\n";
84                         $last_content = undef;
85                         push @results, $mods;
86                 }
87
88                 next unless $response;
89
90                 if($response->isa("OpenSRF::EX")) {
91                         throw $response ($response->stringify);
92                 }
93
94                 $last_content = $response->content;
95
96         }
97
98         if( $last_content ) {
99                 my $u = OpenILS::Utils::ModsParser->new();
100                 $u->start_mods_batch( $last_content->marc );
101                 my $mods = $u->finish_mods_batch();
102                 $mods->doc_id($last_content->id());
103                 push @results, $mods;
104         }
105
106         $request->finish();
107         $session->finish();
108         $session->disconnect();
109
110         return \@results;
111
112 }
113
114 __PACKAGE__->register_method(
115         method  => "record_id_to_mods",
116         api_name        => "open-ils.search.biblio.record.mods.retrieve",
117         argc            => 1, 
118         note            => "Provide ID, we provide the mods"
119 );
120
121 # converts a record into a mods object with copy counts attached
122 sub record_id_to_mods {
123
124         my( $self, $client, $org_id, $id ) = @_;
125
126         my $mods_list = _records_to_mods( $id );
127         my $mods_obj = $mods_list->[0];
128         my $cmethod = $self->method_lookup(
129                         "open-ils.search.biblio.record.copy_count");
130         my ($count) = $cmethod->run($org_id, $id);
131         $mods_obj->copy_count($count);
132
133         return $mods_obj;
134 }
135
136
137 __PACKAGE__->register_method(
138         method  => "record_id_to_mods_slim",
139         api_name        => "open-ils.search.biblio.record.mods_slim.retrieve",
140         argc            => 1, 
141         note            => "Provide ID, we provide the mods"
142 );
143
144 # converts a record into a mods object with NO copy counts attached
145 sub record_id_to_mods_slim {
146
147         my( $self, $client, $id ) = @_;
148         warn "Retrieving MODS object for record $id\n";
149         return undef unless(defined $id);
150
151         my $mods_list = _records_to_mods( $id );
152         my $mods_obj = $mods_list->[0];
153         return $mods_obj;
154 }
155
156
157 # Returns the number of copies attached to a record based on org location
158 __PACKAGE__->register_method(
159         method  => "record_id_to_copy_count",
160         api_name        => "open-ils.search.biblio.record.copy_count",
161 );
162
163 __PACKAGE__->register_method(
164         method  => "record_id_to_copy_count",
165         api_name        => "open-ils.search.biblio.metarecord.copy_count",
166 );
167
168 __PACKAGE__->register_method(
169         method  => "record_id_to_copy_count",
170         api_name        => "open-ils.search.biblio.metarecord.copy_count.staff",
171 );
172 sub record_id_to_copy_count {
173         my( $self, $client, $org_id, $record_id ) = @_;
174
175         my $method = "open-ils.storage.biblio.record_entry.copy_count.atomic";
176         my $key = "record";
177         if($self->api_name =~ /metarecord/) {
178                 $method = "open-ils.storage.metabib.metarecord.copy_count.atomic";
179                 $key = "metarecord";
180         }
181
182         if($self->api_name =~ /staff/ ) {
183                 $method =~ s/atomic/staff\.atomic/og;
184                 warn "Doing staff search $method\n";
185         }
186
187
188         my $session = OpenSRF::AppSession->create("open-ils.storage");
189         warn "copy_count retrieve $record_id\n";
190         return undef unless(defined $record_id);
191
192         my $request = $session->request(
193                 $method, org_unit => $org_id => $key => $record_id );
194
195
196         my $count = $request->gather(1);
197         $session->disconnect();
198         return [ sort { $a->{depth} <=> $b->{depth} } @$count ];
199
200 }
201
202
203 # used for cat search classes
204 my $cat_search_hash =  {
205
206         author => [ 
207                 { tag => "100", subfield => "a"} ,
208                 { tag => "700", subfield => "a"}, 
209         ],
210
211         title => [ 
212                 { tag => "245", subfield => "a"},
213                 { tag => "242", subfield => "a"}, 
214                 { tag => "240", subfield => "a"},
215                 { tag => "210", subfield => "a"},
216         ],
217
218         subject => [ 
219                 { tag => "650", subfield => "_" }, 
220         ],
221
222         tcn     => [
223                 { tag => "035", subfield => "_" },
224         ],
225
226         isbn    => [
227                 { tag => "020", subfield => "a" },
228         ],
229
230 };
231
232
233 __PACKAGE__->register_method(
234         method  => "biblio_search_tcn",
235         api_name        => "open-ils.search.biblio.tcn",
236         argc            => 3, 
237         note            => "Retrieve a record by TCN",
238 );
239
240 sub biblio_search_tcn {
241
242         my( $self, $client, $tcn ) = @_;
243
244         $tcn =~ s/.*?(\w+)\s*$/$1/o;
245         warn "Searching TCN $tcn\n";
246
247         my $session = OpenSRF::AppSession->create( "open-ils.storage" );
248         my $request = $session->request( 
249                         "open-ils.storage.direct.biblio.record_entry.search.tcn_value", $tcn );
250         my $record_entry = $request->gather(1);
251
252         my @ids;
253         for my $record (@$record_entry) {
254                 push @ids, $record->id;
255         }
256
257         $session->disconnect();
258
259         warn "received ID's for tcn search @ids\n";
260         my $size = @ids;
261
262         return { count => $size, ids => \@ids };
263
264 }
265
266
267 # --------------------------------------------------------------------------------
268 # ISBN
269
270 __PACKAGE__->register_method(
271         method  => "biblio_search_isbn",
272         api_name        => "open-ils.search.biblio.isbn",
273 );
274
275 sub biblio_search_isbn { 
276         my( $self, $client, $isbn ) = @_;
277         throw OpenSRF::EX::InvalidArg 
278
279                 ("biblio_search_isbn needs an ISBN to search")
280                         unless defined $isbn;
281
282         warn "biblio search for ISBN $isbn\n";
283         my $method = $self->method_lookup("open-ils.search.biblio.marc");
284         my ($records) = $method->run( $cat_search_hash->{isbn}, $isbn );
285
286         return { count => 0 } unless($records and @$records);
287         my $size = @$records;
288         return { count => $size, ids => $records };
289 }
290
291
292
293 # --------------------------------------------------------------------------------
294
295 __PACKAGE__->register_method(
296         method  => "biblio_barcode_to_copy",
297         api_name        => "open-ils.search.asset.copy.find_by_barcode",
298 );
299
300 # turns a barcode into a copy object
301 sub biblio_barcode_to_copy { 
302         my( $self, $client, $barcode ) = @_;
303
304         throw OpenSRF::EX::InvalidArg 
305                 ("search.biblio.barcode needs a barcode to search")
306                         unless defined $barcode;
307
308         warn "copy search for barcode $barcode\n";
309         my $record = OpenILS::Application::AppUtils->simple_scalar_request(
310                         "open-ils.storage", 
311                         "open-ils.storage.direct.asset.copy.search.barcode",
312                         $barcode );
313
314         return undef unless($record);
315         return $record->[0];
316
317 }
318
319 __PACKAGE__->register_method(
320         method  => "biblio_id_to_copy",
321         api_name        => "open-ils.search.asset.copy.batch.retrieve",
322 );
323
324 # turns a barcode into a copy object
325 sub biblio_id_to_copy { 
326         my( $self, $client, $ids ) = @_;
327
328         throw OpenSRF::EX::InvalidArg 
329                 ("search.biblio.batch.retrieve needs a id to search")
330                         unless defined $ids;
331
332         warn "copy search for ids @$ids\n";
333         my $record = OpenILS::Application::AppUtils->simple_scalar_request(
334                         "open-ils.storage", 
335                         "open-ils.storage.direct.asset.copy.batch.retrieve.atomic",
336                         @$ids );
337
338         return $record;
339
340 }
341
342
343 __PACKAGE__->register_method(
344         method  => "fleshed_copy_retrieve_batch",
345         api_name        => "open-ils.search.asset.copy.fleshed.batch.retrieve",
346 );
347
348 sub fleshed_copy_retrieve_batch { 
349         my( $self, $client, $ids ) = @_;
350
351         throw OpenSRF::EX::InvalidArg 
352                 ("search.biblio.batch.retrieve needs a id to search")
353                         unless defined $ids;
354
355         warn "fleshed copy search for id @$ids\n";
356         my $copy = OpenILS::Application::AppUtils->simple_scalar_request(
357                         "open-ils.storage", 
358                         "open-ils.storage.fleshed.asset.copy.batch.retrieve.atomic",
359                         @$ids );
360
361         return $copy;
362 }
363
364 __PACKAGE__->register_method(
365         method  => "fleshed_copy_retrieve",
366         api_name        => "open-ils.search.asset.copy.fleshed.retrieve",
367 );
368
369 sub fleshed_copy_retrieve_batch { 
370         my( $self, $client, $id ) = @_;
371
372         return undef unless defined $id;
373         warn "copy retrieve for id $id\n";
374         return OpenILS::Application::AppUtils->simple_scalar_request(
375                         "open-ils.storage", 
376                         "open-ils.storage.fleshed.asset.copy.retrieve.atomic",
377                         $id );
378 }
379
380
381
382 __PACKAGE__->register_method(
383         method  => "biblio_barcode_to_title",
384         api_name        => "open-ils.search.biblio.find_by_barcode",
385 );
386
387 sub biblio_barcode_to_title {
388         my( $self, $client, $barcode ) = @_;
389
390         if(!$barcode) {
391                 throw OpenSRF::EX::ERROR 
392                         ("Not enough args to find_by_barcode");
393         }
394
395         my $title = $apputils->simple_scalar_request(
396                 "open-ils.storage",
397                 "open-ils.storage.biblio.record_entry.retrieve_by_barcode",
398                 $barcode );
399
400         if($title) {
401                 return { ids => [ $title->id ], count => 1 };
402         } else {
403                 return { count => 0 };
404         }
405
406 }
407
408
409 __PACKAGE__->register_method(
410         method  => "biblio_copy_to_mods",
411         api_name        => "open-ils.search.biblio.copy.mods.retrieve",
412 );
413
414 # takes a copy object and returns it fleshed mods object
415 sub biblio_copy_to_mods {
416         my( $self, $client, $copy ) = @_;
417
418         throw OpenSRF::EX::InvalidArgs 
419                 ("copy.mods.retrieve needs a copy") unless( $copy );
420
421         new Fieldmapper::asset::copy($copy);
422
423         my $volume = OpenILS::Application::AppUtils->simple_scalar_request(
424                 "open-ils.storage",
425                 "open-ils.storage.direct.asset.call_number.retrieve",
426                 $copy->call_number() );
427
428         my $mods = _records_to_mods($volume->record());
429         $mods = shift @$mods;
430         $volume->copies([$copy]);
431         push @{$mods->call_numbers()}, $volume;
432
433         return $mods;
434 }
435
436
437 sub barcode_to_mods {
438
439 }
440
441
442 # --------------------------------------------------------------------------------
443
444
445
446 __PACKAGE__->register_method(
447         method  => "cat_biblio_search_class",
448         api_name        => "open-ils.search.cat.biblio.class",
449 );
450
451
452 sub cat_biblio_search_class {
453
454         my( $self, $client, $org_id, $class, $sort, $string ) = @_;
455
456         throw OpenSRF::EX::InvalidArg 
457                 ("Not enough args to open-ils.search.cat.biblio.class")
458                         unless( defined($org_id) and $class and $sort and $string );
459
460
461         my $search_hash;
462
463         my $method = $self->method_lookup("open-ils.search.biblio.marc");
464         if(!$method) {
465                 throw OpenSRF::EX::PANIC 
466                         ("Can't lookup method 'open-ils.search.biblio.marc'");
467         }
468
469         my ($records) = $method->run( $cat_search_hash->{$class}, $string );
470
471         my @ids;
472         for my $i (@$records) { push @ids, $i->[0]; }
473
474         my $mods_list = _records_to_mods( @ids );
475         return undef unless (ref($mods_list) eq "ARRAY");
476
477         # ---------------------------------------------------------------
478         # append copy count information to the mods objects
479         my $session = OpenSRF::AppSession->create("open-ils.storage");
480
481         my $request = $session->request(
482                 "open-ils.storage.direct.biblio.record_copy_count.batch",  $org_id, @ids );
483
484         for my $id (@ids) {
485
486                 warn "receiving copy counts for doc $id\n";
487
488                 my $response = $request->recv();
489                 next unless $response;
490
491                 if( $response and UNIVERSAL::isa($response, "Error")) {
492                         throw $response ($response->stringify);
493                 }
494
495                 my $count = $response->content;
496                 my $mods_obj = undef;
497                 for my $m (@$mods_list) {
498                         $mods_obj = $m if ($m->doc_id() == $id)
499                 }
500                 if($mods_obj) {
501                         $mods_obj->copy_count($count);
502                 }
503
504                 $client->respond( $mods_obj );
505
506         }       
507         $request->finish();
508
509         $session->finish();
510         $session->disconnect();
511         $session->kill_me();
512         # ---------------------------------------------------------------
513
514         return undef;
515 }
516
517
518
519 =head comment
520 __PACKAGE__->register_method(
521         method  => "cat_biblio_search_class_id",
522         api_name        => "open-ils.search.cat.biblio.class.id",
523         argc            => 3, 
524         note            => "Searches biblio information by search class and returns the IDs",
525 );
526
527 sub cat_biblio_search_class_id {
528
529         my( $self, $client, $org_id, $class, $string, $limit, $offset ) = @_;
530
531         $offset ||= 0;
532         $limit  ||= 100;
533         $limit -= 1;
534
535
536         my $bool = ($class eq "subject" || $class eq "keyword");
537         $string = OpenILS::Application::Search->filter_search($string, $bool);
538
539         if(!$string) { 
540                 return OpenILS::EX->new("SEARCH_TOO_LARGE")->ex();
541         }
542
543         warn "Searching cat.biblio.class.id string: $string offset: $offset limit: $limit\n";
544
545         throw OpenSRF::EX::InvalidArg 
546                 ("Not enough args to open-ils.search.cat.biblio.class")
547                         unless( defined($org_id) and $class and $string );
548
549
550         my $search_hash;
551
552         my $cache_key = md5_hex( $org_id . $class . $string );
553         my $id_array = OpenILS::Application::SearchCache->get_cache($cache_key);
554
555         if(ref($id_array)) {
556                 warn "Returning class search from cache\n";
557                 my $size = @$id_array;
558                 my @ids = @$id_array[ $offset..($offset+$limit) ];
559                 return { count => $size, ids => \@ids };
560         }
561
562         my $method = $self->method_lookup("open-ils.search.biblio.marc");
563         if(!$method) {
564                 throw OpenSRF::EX::PANIC 
565                         ("Can't lookup method 'open-ils.search.biblio.marc'");
566         }
567
568         my ($records) = $method->run( $cat_search_hash->{$class}, $string );
569
570         my @cache_ids;
571
572         for my $i (@$records) { 
573                 if(defined($i->[0])) {
574                         push @cache_ids, $i->[0]; 
575                 }
576         }
577
578         my @ids = @cache_ids[ $offset..($offset+$limit) ];
579         my $size = @$records;
580
581         OpenILS::Application::SearchCache->put_cache( 
582                         $cache_key, \@cache_ids, $size );
583
584         return { count =>$size, ids => \@ids };
585
586 }
587 =cut
588
589 __PACKAGE__->register_method(
590         method  => "biblio_search_class_count",
591         api_name        => "open-ils.search.biblio.class.count",
592 );
593
594 __PACKAGE__->register_method(
595         method  => "biblio_search_class_count",
596         api_name        => "open-ils.search.biblio.class.count.staff",
597 );
598
599 sub biblio_search_class_count {
600
601         my( $self, $client, $class, $string, $org_id, $org_type ) = @_;
602
603         warn "org: $org_id : depth: $org_type\n";
604
605         $org_id         = "1" unless defined($org_id); # xxx
606         $org_type       = 0     unless defined($org_type);
607
608         warn "Searching biblio.class.id\n" . 
609                 "string: $string "              . 
610                 "org_id: $org_id\n"             .
611                 "depth: $org_type\n" ;
612
613         my $bool = ($class eq "subject" || $class eq "keyword");
614         $string = OpenILS::Application::Search->filter_search($string, $bool);
615
616         if(!$string) { 
617                 return OpenILS::EX->new("SEARCH_TOO_LARGE")->ex;
618         }
619
620                 
621         if( !defined($org_id) or !$class or !$string ) {
622                 warn "not enbough args to metarecord search\n";
623                 throw OpenSRF::EX::InvalidArg 
624                         ("Not enough args to open-ils.search.cat.biblio.class")
625         }
626
627         $class =~ s/\s+//g;
628
629         if( ($class ne "title") and ($class ne "author") and 
630                 ($class ne "subject") and ($class ne "keyword") 
631                 and ($class ne "series"  )) {
632                 warn "Invalid search class: $class\n";
633                 throw OpenSRF::EX::InvalidArg ("Not a valid search class: $class")
634         }
635
636         # grab the mr id's from storage
637
638         my $method = "open-ils.storage.cachable.metabib.$class.search_fts.metarecord_count";
639         if($self->api_name =~ /staff/) { 
640                 $method = "$method.staff"; 
641                 $method =~ s/\.cachable//o;
642         }
643         warn "Performing count method $method\n";
644         warn "API name " . $self->api_name() . "\n";
645
646         my $session = OpenSRF::AppSession->create('open-ils.storage');
647
648         my $request = $session->request( $method, 
649                         term => $string, 
650                         org_unit => $org_id, 
651                         cache_page_size => 1,
652                         depth =>$org_type );
653
654         my $count = $request->gather(1);
655         warn "Received count $count\n";
656
657         return $count;
658 }
659
660
661 __PACKAGE__->register_method(
662         method  => "biblio_search_class",
663         api_name        => "open-ils.search.biblio.class",
664 );
665
666 __PACKAGE__->register_method(
667         method  => "biblio_search_class",
668         api_name        => "open-ils.search.biblio.class.unordered",
669 );
670
671 __PACKAGE__->register_method(
672         method  => "biblio_search_class",
673         api_name        => "open-ils.search.biblio.class.staff",
674 );
675
676 __PACKAGE__->register_method(
677         method  => "biblio_search_class",
678         api_name        => "open-ils.search.biblio.class.unordered.staff",
679 );
680
681 sub biblio_search_class {
682
683         my( $self, $client, $class, $string, 
684                         $org_id, $org_type, $limit, $offset ) = @_;
685
686         warn "org: $org_id : depth: $org_type : limit: $limit :  offset: $offset\n";
687
688         $offset         = 0     unless (defined($offset) and $offset > 0);
689         $limit          = 100 unless (defined($limit) and $limit > 0);
690         $org_id         = "1" unless (defined($org_id)); # xxx
691         $org_type       = 0     unless (defined($org_type));
692
693         warn "Searching biblio.class.id\n" . 
694                 "string: $string "              . 
695                 "\noffset: $offset\n"   .
696                 "limit: $limit\n"                       .
697                 "org_id: $org_id\n"             .
698                 "depth: $org_type\n" ;
699
700         warn "Search filtering string " . time() . "\n";
701         $string = OpenILS::Application::Search->filter_search($string);
702         if(!$string) { return undef; }
703
704         if( !defined($org_id) or !$class or !$string ) {
705                 warn "not enbough args to metarecord search\n";
706                 throw OpenSRF::EX::InvalidArg 
707                         ("Not enough args to open-ils.search.cat.biblio.class")
708         }
709
710         $class =~ s/\s+//g;
711
712         if( ($class ne "title") and ($class ne "author") and 
713                 ($class ne "subject") and ($class ne "keyword") 
714                 and ($class ne "series") ) {
715                 warn "Invalid search class: $class\n";
716                 throw OpenSRF::EX::InvalidArg ("Not a valid search class: $class")
717         }
718
719         #my $method = "open-ils.storage.metabib.$class.search_fts.metarecord.atomic";
720         my $method = "open-ils.storage.cachable.metabib.$class.search_fts.metarecord.atomic";
721
722         if($self->api_name =~ /order/) {
723                 $method = "open-ils.storage.cachable.metabib.$class.search_fts.metarecord.unordered.atomic",
724                 #$method = "open-ils.storage.metabib.$class.search_fts.metarecord.unordered.atomic";
725         }
726
727         if($self->api_name =~ /staff/) { 
728                 $method =~ s/atomic/staff\.atomic/og;
729                 $method =~ s/\.cachable//o;
730         }
731
732         warn "Performing search method $method\n";
733         warn "MR search method is $method\n";
734
735         my $session = OpenSRF::AppSession->create('open-ils.storage');
736
737         warn "Search making request " . time() . "\n";
738         my $request = $session->request(        
739                 $method,
740                 term            => $string, 
741                 org_unit => $org_id, 
742                 depth           => $org_type, 
743                 limit           => $limit,
744                 offset  => $offset,
745                 cache_page_size => 200,
746                 );
747
748         my $records = $request->gather(1);
749         warn "Search request complete " . time() . "\n";
750
751         my @all_ids;
752
753         use Data::Dumper;
754         warn "Received " . scalar(@$records) . " id's from class search\n";
755
756         # if we just get one, it won't be wrapped in an array
757         if(!ref($records->[0])) {
758                 $records = [$records]; } 
759         for my $i (@$records) { 
760                 if(defined($i)) {
761                         push @all_ids, $i; 
762                 }
763         }
764
765         my @ids = @all_ids;
766         @ids = grep { defined($_->[0]) } @ids;
767
768         $session->finish();
769         $session->disconnect();
770
771         return { ids => \@ids };
772
773 }
774
775
776
777
778 __PACKAGE__->register_method(
779         method  => "biblio_mrid_to_modsbatch",
780         api_name        => "open-ils.search.biblio.metarecord.mods_slim.retrieve",
781 );
782
783 sub biblio_mrid_to_modsbatch {
784         my( $self, $client, $mrid ) = @_;
785
786         throw OpenSRF::EX::InvalidArg 
787                 ("search.biblio.metarecord_to_mods requires mr id")
788                         unless defined( $mrid );
789
790
791         my $metarecord = OpenILS::Application::AppUtils->simple_scalar_request( "open-ils.storage", 
792                         "open-ils.storage.direct.metabib.metarecord.retrieve", $mrid );
793
794         if(!$metarecord) {
795                 throw OpenSRF::EX::ERROR ("No metarecord exists with the given id: $mrid");
796         }
797
798         my $master_id = $metarecord->master_record();
799
800
801         # check for existing mods
802         if($metarecord->mods()){
803                 warn "We already have mods for " . $metarecord->id . "\n";
804                 my $perl = JSON->JSON2perl($metarecord->mods());
805                 return Fieldmapper::metabib::virtual_record->new($perl);
806         }
807
808
809
810         warn "Creating mods batch for metarecord $mrid\n";
811         my $id_hash = biblio_mrid_to_record_ids( undef, undef,  $mrid );
812         my @ids = @{$id_hash->{ids}};
813
814         if(@ids < 1) { return undef; }
815
816         warn "Master ID is $master_id\n";
817         # grab the master record to start the mods batch 
818
819         my $record = OpenILS::Application::AppUtils->simple_scalar_request( "open-ils.storage", 
820                         "open-ils.storage.direct.biblio.record_entry.retrieve", $master_id );
821
822         if(!$record) {
823                 throw OpenSRF::EX::ERROR 
824                         ("No record returned with id $master_id");
825         }
826
827         my $u = OpenILS::Utils::ModsParser->new();
828         use Data::Dumper;
829         $u->start_mods_batch( $record->marc );
830         my $main_doc_id = $record->id();
831
832         @ids = grep { $_ ne $master_id } @ids;
833
834         # now we have to collect all of the marc objects and push them into a mods batch
835         my $session = OpenSRF::AppSession->create("open-ils.storage");
836         my $request = $session->request(
837                 "open-ils.storage.direct.biblio.record_entry.batch.retrieve",  @ids );
838
839         while( my $response = $request->recv() ) {
840
841                 next unless $response;
842                 if(UNIVERSAL::isa( $response,"OpenSRF::EX")) {
843                         throw $response ($response->stringify);
844                 }
845
846                 my $content = $response->content;
847
848                 if( $content ) {
849                         $u->push_mods_batch( $content->marc );
850                 }
851         }
852
853         my $mods = $u->finish_mods_batch();
854         $mods->doc_id($mrid);
855         $request->finish();
856
857         $client->respond_complete($mods);
858
859         my $mods_string = JSON->perl2JSON($mods->decast);
860
861         $metarecord->mods($mods_string);
862
863         my $req = $session->request( 
864                         "open-ils.storage.direct.metabib.metarecord.update", 
865                         $metarecord );
866
867
868         $req->gather(1);
869
870         $session->finish();
871         $session->disconnect();
872
873         return undef;
874
875 }
876
877
878
879 # converts a mr id into a list of record ids
880
881 __PACKAGE__->register_method(
882         method  => "biblio_mrid_to_record_ids",
883         api_name        => "open-ils.search.biblio.metarecord_to_records",
884 );
885
886 sub biblio_mrid_to_record_ids {
887         my( $self, $client, $mrid ) = @_;
888
889         throw OpenSRF::EX::InvalidArg 
890                 ("search.biblio.metarecord_to_record_ids requires mr id")
891                         unless defined( $mrid );
892
893         warn "Searching for record for MR $mrid\n";
894
895         my $mrmaps = OpenILS::Application::AppUtils->simple_scalar_request( 
896                         "open-ils.storage", 
897                         #"open-ils.storage.direct.metabib.metarecord_source_map.search.metarecord", $mrid );
898                         "open-ils.storage.ordered.metabib.metarecord.records.atomic", 
899                         $mrid );
900
901
902         #my @ids;
903         #for my $map (@$mrmaps) { push @ids, $map->source(); }
904         #warn "Recovered id's [@ids] for mr $mrid\n";
905         #my $size = @ids;
906
907         my $size = @$mrmaps;    
908
909         return { count => $size, ids => $mrmaps };
910
911 }
912
913
914
915 __PACKAGE__->register_method(
916         method  => "biblio_record_to_marc_html",
917         api_name        => "open-ils.search.biblio.record.html" );
918
919 my $parser              = XML::LibXML->new();
920 my $xslt                        = XML::LibXSLT->new();
921 my $marc_sheet;
922
923 my $settings_client = OpenSRF::Utils::SettingsClient->new();
924 sub biblio_record_to_marc_html {
925         my( $self, $client, $recordid ) = @_;
926
927         if( !$marc_sheet ) {
928                 my $dir = $settings_client->config_value( "dirs", "xsl" );
929                 my $xsl = $settings_client->config_value(
930                         "apps", "open-ils.search", "app_settings", "marc_html_xsl" );
931
932                 $xsl = $parser->parse_file("$dir/$xsl");
933                 $marc_sheet = $xslt->parse_stylesheet( $xsl );
934         }
935
936
937         my $record = $apputils->simple_scalar_request(
938                 "open-ils.storage", 
939                 "open-ils.storage.direct.biblio.record_entry.retrieve",
940                 $recordid );
941
942         my $xmldoc = $parser->parse_string($record->marc);
943         my $html = $marc_sheet->transform($xmldoc);
944         $html = $html->toString();
945         return $html;
946
947 }
948
949
950
951 __PACKAGE__->register_method(
952         method  => "retrieve_all_copy_locations",
953         api_name        => "open-ils.search.config.copy_location.retrieve.all" );
954
955 my $shelving_locations;
956 sub retrieve_all_copy_locations {
957         my( $self, $client ) = @_;
958         if(!$shelving_locations) {
959                 $shelving_locations = $apputils->simple_scalar_request(
960                         "open-ils.storage", 
961                         "open-ils.storage.direct.asset.copy_location.retrieve.all.atomic");
962         }
963         return $shelving_locations;
964 }
965
966
967
968 __PACKAGE__->register_method(
969         method  => "retrieve_all_copy_statuses",
970         api_name        => "open-ils.search.config.copy_status.retrieve.all" );
971
972 my $copy_statuses;
973 sub retrieve_all_copy_statuses {
974         my( $self, $client ) = @_;
975         if(!$copy_statuses) {
976                 $copy_statuses = $apputils->simple_scalar_request(
977                         "open-ils.storage",
978                         "open-ils.storage.direct.config.copy_status.retrieve.all.atomic" );
979         }
980         return $copy_statuses;
981 }
982
983
984 __PACKAGE__->register_method(
985         method  => "copy_counts_per_org",
986         api_name        => "open-ils.search.biblio.copy_counts.retrieve");
987
988 sub copy_counts_per_org {
989         my( $self, $client, $record_id ) = @_;
990         my $counts = $apputils->simple_scalar_request(
991                 "open-ils.storage",
992                 "open-ils.storage.biblio.record_entry.global_copy_count.atomic",
993                 $record_id );
994         $counts = [ sort {$a->[0] <=> $b->[0]} @$counts ];
995         return $counts;
996 }
997
998
999
1000
1001 1;