1 package OpenILS::Application::Search::Biblio;
2 use base qw/OpenSRF::Application/;
3 use strict; use warnings;
8 use OpenILS::Utils::Fieldmapper;
9 use OpenILS::Utils::ModsParser;
10 use OpenSRF::Utils::SettingsClient;
12 use OpenILS::Application::AppUtils;
16 use Time::HiRes qw(time);
17 use OpenSRF::EX qw(:try);
18 use Digest::MD5 qw(md5_hex);
23 my $apputils = "OpenILS::Application::AppUtils";
25 # Houses biblio search utilites
28 __PACKAGE__->register_method(
30 api_name => "open-ils.search.test");
32 sub test { return "test"; }
36 __PACKAGE__->register_method(
37 method => "biblio_search_marc",
38 api_name => "open-ils.search.biblio.marc",
40 note => "Searches biblio information by marc tag",
43 sub biblio_search_marc {
45 my( $self, $client, $search_hash, $string ) = @_;
47 warn "Building biblio marc session\n";
48 my $session = OpenSRF::AppSession->create("open-ils.storage");
51 warn "Sending biblio marc request. String $string\nSearch hash: " . Dumper($search_hash);
52 my $request = $session->request(
53 "open-ils.storage.direct.metabib.full_rec.search_fts.index_vector.atomic",
54 restrict => $search_hash,
56 my $data = $request->gather(1);
61 $session->disconnect();
69 # ---------------------------------------------------------------------------
70 # takes a list of record id's and turns the docs into friendly
71 # mods structures. Creates one MODS structure for each doc id.
72 # ---------------------------------------------------------------------------
73 sub _records_to_mods {
79 my $session = OpenSRF::AppSession->create("open-ils.storage");
80 my $request = $session->request(
81 "open-ils.storage.direct.biblio.record_entry.batch.retrieve", @ids );
83 my $last_content = undef;
85 while( my $response = $request->recv() ) {
88 my $u = OpenILS::Utils::ModsParser->new();
89 $u->start_mods_batch( $last_content->marc );
90 my $mods = $u->finish_mods_batch();
91 $mods->doc_id($last_content->id());
92 warn "Turning doc " . $mods->doc_id() . " into MODS\n";
93 $last_content = undef;
97 next unless $response;
99 if($response->isa("OpenSRF::EX")) {
100 throw $response ($response->stringify);
103 $last_content = $response->content;
107 if( $last_content ) {
108 my $u = OpenILS::Utils::ModsParser->new();
109 $u->start_mods_batch( $last_content->marc );
110 my $mods = $u->finish_mods_batch();
111 $mods->doc_id($last_content->id());
112 push @results, $mods;
117 $session->disconnect();
123 __PACKAGE__->register_method(
124 method => "record_id_to_mods",
125 api_name => "open-ils.search.biblio.record.mods.retrieve",
127 note => "Provide ID, we provide the mods"
130 # converts a record into a mods object with copy counts attached
131 sub record_id_to_mods {
133 my( $self, $client, $org_id, $id ) = @_;
135 my $mods_list = _records_to_mods( $id );
136 my $mods_obj = $mods_list->[0];
137 my $cmethod = $self->method_lookup(
138 "open-ils.search.biblio.record.copy_count");
139 my ($count) = $cmethod->run($org_id, $id);
140 $mods_obj->copy_count($count);
147 __PACKAGE__->register_method(
148 method => "record_id_to_mods_slim",
149 api_name => "open-ils.search.biblio.record.mods_slim.retrieve",
151 note => "Provide ID, we provide the mods"
154 # converts a record into a mods object with NO copy counts attached
155 sub record_id_to_mods_slim {
156 my( $self, $client, $id ) = @_;
157 return undef unless defined $id;
159 if(ref($id) and ref($id) == 'ARRAY') {
160 return _records_to_mods( @$id );
162 my $mods_list = _records_to_mods( $id );
163 my $mods_obj = $mods_list->[0];
168 # Returns the number of copies attached to a record based on org location
169 __PACKAGE__->register_method(
170 method => "record_id_to_copy_count",
171 api_name => "open-ils.search.biblio.record.copy_count",
174 __PACKAGE__->register_method(
175 method => "record_id_to_copy_count",
176 api_name => "open-ils.search.biblio.metarecord.copy_count",
179 __PACKAGE__->register_method(
180 method => "record_id_to_copy_count",
181 api_name => "open-ils.search.biblio.metarecord.copy_count.staff",
183 sub record_id_to_copy_count {
184 my( $self, $client, $org_id, $record_id ) = @_;
186 my $method = "open-ils.storage.biblio.record_entry.copy_count.atomic";
188 if($self->api_name =~ /metarecord/) {
189 $method = "open-ils.storage.metabib.metarecord.copy_count.atomic";
193 if($self->api_name =~ /staff/ ) {
194 $method =~ s/atomic/staff\.atomic/og;
195 warn "Doing staff search $method\n";
199 my $session = OpenSRF::AppSession->create("open-ils.storage");
200 warn "copy_count retrieve $record_id\n";
201 return undef unless(defined $record_id);
203 my $request = $session->request(
204 $method, org_unit => $org_id => $key => $record_id );
207 my $count = $request->gather(1);
208 $session->disconnect();
209 return [ sort { $a->{depth} <=> $b->{depth} } @$count ];
214 # used for cat search classes
215 my $cat_search_hash = {
218 { tag => "100", subfield => "a"} ,
219 { tag => "700", subfield => "a"},
223 { tag => "245", subfield => "a"},
224 { tag => "242", subfield => "a"},
225 { tag => "240", subfield => "a"},
226 { tag => "210", subfield => "a"},
230 { tag => "650", subfield => "_" },
234 { tag => "035", subfield => "_" },
238 { tag => "020", subfield => "a" },
244 __PACKAGE__->register_method(
245 method => "biblio_search_tcn",
246 api_name => "open-ils.search.biblio.tcn",
248 note => "Retrieve a record by TCN",
251 sub biblio_search_tcn {
253 my( $self, $client, $tcn ) = @_;
255 $tcn =~ s/.*?(\w+)\s*$/$1/o;
256 warn "Searching TCN $tcn\n";
258 my $session = OpenSRF::AppSession->create( "open-ils.storage" );
259 my $request = $session->request(
260 "open-ils.storage.direct.biblio.record_entry.search.tcn_value.atomic", $tcn );
261 my $record_entry = $request->gather(1);
264 for my $record (@$record_entry) {
265 push @ids, $record->id;
268 $session->disconnect();
270 warn "received ID's for tcn search @ids\n";
273 return { count => $size, ids => \@ids };
278 # --------------------------------------------------------------------------------
281 __PACKAGE__->register_method(
282 method => "biblio_search_isbn",
283 api_name => "open-ils.search.biblio.isbn",
286 sub biblio_search_isbn {
287 my( $self, $client, $isbn ) = @_;
288 throw OpenSRF::EX::InvalidArg
290 ("biblio_search_isbn needs an ISBN to search")
291 unless defined $isbn;
293 warn "biblio search for ISBN $isbn\n";
294 my $method = $self->method_lookup("open-ils.search.biblio.marc");
295 my ($records) = $method->run( $cat_search_hash->{isbn}, $isbn );
297 return { count => 0 } unless($records and @$records);
298 my $size = @$records;
299 return { count => $size, ids => $records };
304 # --------------------------------------------------------------------------------
306 __PACKAGE__->register_method(
307 method => "biblio_barcode_to_copy",
308 api_name => "open-ils.search.asset.copy.find_by_barcode",
311 # turns a barcode into a copy object
312 sub biblio_barcode_to_copy {
313 my( $self, $client, $barcode ) = @_;
315 throw OpenSRF::EX::InvalidArg
316 ("search.biblio.barcode needs a barcode to search")
317 unless defined $barcode;
319 warn "copy search for barcode $barcode\n";
320 my $record = OpenILS::Application::AppUtils->simple_scalar_request(
322 "open-ils.storage.direct.asset.copy.search.barcode.atomic",
325 return undef unless($record);
330 __PACKAGE__->register_method(
331 method => "biblio_id_to_copy",
332 api_name => "open-ils.search.asset.copy.batch.retrieve",
335 # turns a barcode into a copy object
336 sub biblio_id_to_copy {
337 my( $self, $client, $ids ) = @_;
339 throw OpenSRF::EX::InvalidArg
340 ("search.biblio.batch.retrieve needs a id to search")
343 warn "copy search for ids @$ids\n";
344 my $record = OpenILS::Application::AppUtils->simple_scalar_request(
346 "open-ils.storage.direct.asset.copy.batch.retrieve.atomic",
354 __PACKAGE__->register_method(
355 method => "fleshed_copy_retrieve_batch",
356 api_name => "open-ils.search.asset.copy.fleshed.batch.retrieve",
359 sub fleshed_copy_retrieve_batch {
360 my( $self, $client, $ids ) = @_;
362 throw OpenSRF::EX::InvalidArg
363 ("search.biblio.batch.retrieve needs a id to search")
366 warn "fleshed copy search for id @$ids\n";
367 my $copy = OpenILS::Application::AppUtils->simple_scalar_request(
369 "open-ils.storage.fleshed.asset.copy.batch.retrieve.atomic",
375 __PACKAGE__->register_method(
376 method => "fleshed_copy_retrieve",
377 api_name => "open-ils.search.asset.copy.fleshed.retrieve",
380 sub fleshed_copy_retrieve {
381 my( $self, $client, $id ) = @_;
383 return undef unless defined $id;
384 warn "copy retrieve for id $id\n";
385 return OpenILS::Application::AppUtils->simple_scalar_request(
387 "open-ils.storage.fleshed.asset.copy.retrieve.atomic",
393 __PACKAGE__->register_method(
394 method => "biblio_barcode_to_title",
395 api_name => "open-ils.search.biblio.find_by_barcode",
398 sub biblio_barcode_to_title {
399 my( $self, $client, $barcode ) = @_;
402 throw OpenSRF::EX::ERROR
403 ("Not enough args to find_by_barcode");
406 my $title = $apputils->simple_scalar_request(
408 "open-ils.storage.biblio.record_entry.retrieve_by_barcode",
412 return { ids => [ $title->id ], count => 1 };
414 return { count => 0 };
420 __PACKAGE__->register_method(
421 method => "biblio_copy_to_mods",
422 api_name => "open-ils.search.biblio.copy.mods.retrieve",
425 # takes a copy object and returns it fleshed mods object
426 sub biblio_copy_to_mods {
427 my( $self, $client, $copy ) = @_;
429 throw OpenSRF::EX::InvalidArgs
430 ("copy.mods.retrieve needs a copy") unless( $copy );
432 new Fieldmapper::asset::copy($copy);
434 my $volume = OpenILS::Application::AppUtils->simple_scalar_request(
436 "open-ils.storage.direct.asset.call_number.retrieve",
437 $copy->call_number() );
439 my $mods = _records_to_mods($volume->record());
440 $mods = shift @$mods;
441 $volume->copies([$copy]);
442 push @{$mods->call_numbers()}, $volume;
448 sub barcode_to_mods {
453 # --------------------------------------------------------------------------------
457 __PACKAGE__->register_method(
458 method => "cat_biblio_search_class",
459 api_name => "open-ils.search.cat.biblio.class",
463 sub cat_biblio_search_class {
465 my( $self, $client, $org_id, $class, $sort, $string ) = @_;
467 throw OpenSRF::EX::InvalidArg
468 ("Not enough args to open-ils.search.cat.biblio.class")
469 unless( defined($org_id) and $class and $sort and $string );
474 my $method = $self->method_lookup("open-ils.search.biblio.marc");
476 throw OpenSRF::EX::PANIC
477 ("Can't lookup method 'open-ils.search.biblio.marc'");
480 my ($records) = $method->run( $cat_search_hash->{$class}, $string );
483 for my $i (@$records) { push @ids, $i->[0]; }
485 my $mods_list = _records_to_mods( @ids );
486 return undef unless (ref($mods_list) eq "ARRAY");
488 # ---------------------------------------------------------------
489 # append copy count information to the mods objects
490 my $session = OpenSRF::AppSession->create("open-ils.storage");
492 my $request = $session->request(
493 "open-ils.storage.direct.biblio.record_copy_count.batch", $org_id, @ids );
497 warn "receiving copy counts for doc $id\n";
499 my $response = $request->recv();
500 next unless $response;
502 if( $response and UNIVERSAL::isa($response, "Error")) {
503 throw $response ($response->stringify);
506 my $count = $response->content;
507 my $mods_obj = undef;
508 for my $m (@$mods_list) {
509 $mods_obj = $m if ($m->doc_id() == $id)
512 $mods_obj->copy_count($count);
515 $client->respond( $mods_obj );
521 $session->disconnect();
523 # ---------------------------------------------------------------
531 __PACKAGE__->register_method(
532 method => "cat_biblio_search_class_id",
533 api_name => "open-ils.search.cat.biblio.class.id",
535 note => "Searches biblio information by search class and returns the IDs",
538 sub cat_biblio_search_class_id {
540 my( $self, $client, $org_id, $class, $string, $limit, $offset ) = @_;
547 my $bool = ($class eq "subject" || $class eq "keyword");
548 $string = OpenILS::Application::Search->filter_search($string, $bool);
551 return OpenILS::EX->new("SEARCH_TOO_LARGE")->ex();
554 warn "Searching cat.biblio.class.id string: $string offset: $offset limit: $limit\n";
556 throw OpenSRF::EX::InvalidArg
557 ("Not enough args to open-ils.search.cat.biblio.class")
558 unless( defined($org_id) and $class and $string );
563 my $cache_key = md5_hex( $org_id . $class . $string );
564 my $id_array = OpenILS::Application::SearchCache->get_cache($cache_key);
567 warn "Returning class search from cache\n";
568 my $size = @$id_array;
569 my @ids = @$id_array[ $offset..($offset+$limit) ];
570 return { count => $size, ids => \@ids };
573 my $method = $self->method_lookup("open-ils.search.biblio.marc");
575 throw OpenSRF::EX::PANIC
576 ("Can't lookup method 'open-ils.search.biblio.marc'");
579 my ($records) = $method->run( $cat_search_hash->{$class}, $string );
583 for my $i (@$records) {
584 if(defined($i->[0])) {
585 push @cache_ids, $i->[0];
589 my @ids = @cache_ids[ $offset..($offset+$limit) ];
590 my $size = @$records;
592 OpenILS::Application::SearchCache->put_cache(
593 $cache_key, \@cache_ids, $size );
595 return { count =>$size, ids => \@ids };
600 __PACKAGE__->register_method(
601 method => "biblio_search_class_count",
602 api_name => "open-ils.search.biblio.class.count",
605 __PACKAGE__->register_method(
606 method => "biblio_search_class_count",
607 api_name => "open-ils.search.biblio.class.count.staff",
610 sub biblio_search_class_count {
612 my( $self, $client, $class, $string, $org_id, $org_type ) = @_;
614 warn "org: $org_id : depth: $org_type\n";
616 $org_id = "1" unless defined($org_id); # xxx
617 $org_type = 0 unless defined($org_type);
619 warn "Searching biblio.class.id\n" .
621 "org_id: $org_id\n" .
622 "depth: $org_type\n" ;
624 my $bool = ($class eq "subject" || $class eq "keyword");
625 $string = OpenILS::Application::Search->filter_search($string, $bool);
628 return OpenILS::EX->new("SEARCH_TOO_LARGE")->ex;
632 if( !defined($org_id) or !$class or !$string ) {
633 warn "not enbough args to metarecord search\n";
634 throw OpenSRF::EX::InvalidArg
635 ("Not enough args to open-ils.search.cat.biblio.class")
640 if( ($class ne "title") and ($class ne "author") and
641 ($class ne "subject") and ($class ne "keyword")
642 and ($class ne "series" )) {
643 warn "Invalid search class: $class\n";
644 throw OpenSRF::EX::InvalidArg ("Not a valid search class: $class")
647 # grab the mr id's from storage
649 my $method = "open-ils.storage.cachable.metabib.$class.search_fts.metarecord_count";
650 if($self->api_name =~ /staff/) {
651 $method = "$method.staff";
652 $method =~ s/\.cachable//o;
654 warn "Performing count method $method\n";
655 warn "API name " . $self->api_name() . "\n";
657 my $session = OpenSRF::AppSession->create('open-ils.storage');
659 my $request = $session->request( $method,
662 cache_page_size => 1,
665 my $count = $request->gather(1);
666 warn "Received count $count\n";
672 __PACKAGE__->register_method(
673 method => "biblio_search_class",
674 api_name => "open-ils.search.biblio.class",
677 __PACKAGE__->register_method(
678 method => "biblio_search_class",
679 api_name => "open-ils.search.biblio.class.unordered",
682 __PACKAGE__->register_method(
683 method => "biblio_search_class",
684 api_name => "open-ils.search.biblio.class.staff",
687 __PACKAGE__->register_method(
688 method => "biblio_search_class",
689 api_name => "open-ils.search.biblio.class.unordered.staff",
692 sub biblio_search_class {
694 my( $self, $client, $class, $string,
695 $org_id, $org_type, $limit, $offset ) = @_;
697 warn "org: $org_id : depth: $org_type : limit: $limit : offset: $offset\n";
699 $offset = 0 unless (defined($offset) and $offset > 0);
700 $limit = 100 unless (defined($limit) and $limit > 0);
701 $org_id = "1" unless (defined($org_id)); # xxx
702 $org_type = 0 unless (defined($org_type));
704 warn "Searching biblio.class.id\n" .
706 "\noffset: $offset\n" .
708 "org_id: $org_id\n" .
709 "depth: $org_type\n" ;
711 warn "Search filtering string " . time() . "\n";
712 $string = OpenILS::Application::Search->filter_search($string);
713 if(!$string) { return undef; }
715 if( !defined($org_id) or !$class or !$string ) {
716 warn "not enbough args to metarecord search\n";
717 throw OpenSRF::EX::InvalidArg
718 ("Not enough args to open-ils.search.cat.biblio.class")
723 if( ($class ne "title") and ($class ne "author") and
724 ($class ne "subject") and ($class ne "keyword")
725 and ($class ne "series") ) {
726 warn "Invalid search class: $class\n";
727 throw OpenSRF::EX::InvalidArg ("Not a valid search class: $class")
730 #my $method = "open-ils.storage.metabib.$class.search_fts.metarecord.atomic";
731 my $method = "open-ils.storage.cachable.metabib.$class.search_fts.metarecord.atomic";
733 if($self->api_name =~ /order/) {
734 $method = "open-ils.storage.cachable.metabib.$class.search_fts.metarecord.unordered.atomic",
735 #$method = "open-ils.storage.metabib.$class.search_fts.metarecord.unordered.atomic";
738 if($self->api_name =~ /staff/) {
739 $method =~ s/atomic/staff\.atomic/og;
740 $method =~ s/\.cachable//o;
743 warn "Performing search method $method\n";
744 warn "MR search method is $method\n";
746 my $session = OpenSRF::AppSession->create('open-ils.storage');
748 warn "Search making request " . time() . "\n";
749 my $request = $session->request(
756 cache_page_size => 200,
759 my $records = $request->gather(1);
760 warn "Search request complete " . time() . "\n";
765 warn "Received " . scalar(@$records) . " id's from class search\n";
767 # if we just get one, it won't be wrapped in an array
768 if(!ref($records->[0])) {
769 $records = [$records]; }
770 for my $i (@$records) {
777 @ids = grep { defined($_->[0]) } @ids;
780 $session->disconnect();
782 return { ids => \@ids };
787 __PACKAGE__->register_method(
788 method => "biblio_mrid_to_modsbatch_batch",
789 api_name => "open-ils.search.biblio.metarecord.mods_slim.batch.retrieve");
791 sub biblio_mrid_to_modsbatch_batch {
792 my( $self, $client, $mrids) = @_;
793 warn "Performing mrid_to_modsbatch_batch...";
795 my $method = $self->method_lookup("open-ils.search.biblio.metarecord.mods_slim.retrieve");
797 warn "Grabbing mods for " . Dumper($mrids) . "\n";
799 for my $id (@$mrids) {
800 next unless defined $id;
801 #push @mods, biblio_mrid_to_modsbatch($self, $client, $id);
802 my ($m) = $method->run($id);
809 __PACKAGE__->register_method(
810 method => "biblio_mrid_to_modsbatch",
811 api_name => "open-ils.search.biblio.metarecord.mods_slim.retrieve");
813 sub biblio_mrid_to_modsbatch {
814 my( $self, $client, $mrid ) = @_;
816 throw OpenSRF::EX::InvalidArg
817 ("search.biblio.metarecord_to_mods requires mr id")
818 unless defined( $mrid );
821 my $metarecord = OpenILS::Application::AppUtils->simple_scalar_request( "open-ils.storage",
822 "open-ils.storage.direct.metabib.metarecord.retrieve", $mrid );
825 throw OpenSRF::EX::ERROR ("No metarecord exists with the given id: $mrid");
828 my $master_id = $metarecord->master_record();
831 # check for existing mods
832 if($metarecord->mods()){
833 warn "We already have mods for " . $metarecord->id . "\n";
834 my $perl = JSON->JSON2perl($metarecord->mods());
835 return Fieldmapper::metabib::virtual_record->new($perl);
840 warn "Creating mods batch for metarecord $mrid\n";
841 my $id_hash = biblio_mrid_to_record_ids( undef, undef, $mrid );
842 my @ids = @{$id_hash->{ids}};
844 if(@ids < 1) { return undef; }
846 warn "Master ID is $master_id\n";
847 # grab the master record to start the mods batch
849 my $record = OpenILS::Application::AppUtils->simple_scalar_request( "open-ils.storage",
850 "open-ils.storage.direct.biblio.record_entry.retrieve", $master_id );
853 throw OpenSRF::EX::ERROR
854 ("No record returned with id $master_id");
857 my $u = OpenILS::Utils::ModsParser->new();
859 $u->start_mods_batch( $record->marc );
860 my $main_doc_id = $record->id();
862 @ids = grep { $_ ne $master_id } @ids;
864 # now we have to collect all of the marc objects and push them into a mods batch
865 my $session = OpenSRF::AppSession->create("open-ils.storage");
866 my $request = $session->request(
867 "open-ils.storage.direct.biblio.record_entry.batch.retrieve", @ids );
869 while( my $response = $request->recv() ) {
871 next unless $response;
872 if(UNIVERSAL::isa( $response,"OpenSRF::EX")) {
873 throw $response ($response->stringify);
876 my $content = $response->content;
879 $u->push_mods_batch( $content->marc );
883 my $mods = $u->finish_mods_batch();
884 $mods->doc_id($mrid);
887 $client->respond_complete($mods);
889 my $mods_string = JSON->perl2JSON($mods->decast);
891 $metarecord->mods($mods_string);
893 my $req = $session->request(
894 "open-ils.storage.direct.metabib.metarecord.update",
901 $session->disconnect();
909 # converts a mr id into a list of record ids
911 __PACKAGE__->register_method(
912 method => "biblio_mrid_to_record_ids",
913 api_name => "open-ils.search.biblio.metarecord_to_records",
916 sub biblio_mrid_to_record_ids {
917 my( $self, $client, $mrid ) = @_;
919 throw OpenSRF::EX::InvalidArg
920 ("search.biblio.metarecord_to_record_ids requires mr id")
921 unless defined( $mrid );
923 warn "Searching for record for MR $mrid\n";
925 my $mrmaps = OpenILS::Application::AppUtils->simple_scalar_request(
927 #"open-ils.storage.direct.metabib.metarecord_source_map.search.metarecord", $mrid );
928 "open-ils.storage.ordered.metabib.metarecord.records.atomic",
933 #for my $map (@$mrmaps) { push @ids, $map->source(); }
934 #warn "Recovered id's [@ids] for mr $mrid\n";
939 return { count => $size, ids => $mrmaps };
945 __PACKAGE__->register_method(
946 method => "biblio_record_to_marc_html",
947 api_name => "open-ils.search.biblio.record.html" );
949 my $parser = XML::LibXML->new();
950 my $xslt = XML::LibXSLT->new();
953 my $settings_client = OpenSRF::Utils::SettingsClient->new();
954 sub biblio_record_to_marc_html {
955 my( $self, $client, $recordid ) = @_;
958 my $dir = $settings_client->config_value( "dirs", "xsl" );
959 my $xsl = $settings_client->config_value(
960 "apps", "open-ils.search", "app_settings", "marc_html_xsl" );
962 $xsl = $parser->parse_file("$dir/$xsl");
963 $marc_sheet = $xslt->parse_stylesheet( $xsl );
967 my $record = $apputils->simple_scalar_request(
969 "open-ils.storage.direct.biblio.record_entry.retrieve",
972 my $xmldoc = $parser->parse_string($record->marc);
973 my $html = $marc_sheet->transform($xmldoc);
974 $html = $html->toString();
981 __PACKAGE__->register_method(
982 method => "retrieve_all_copy_locations",
983 api_name => "open-ils.search.config.copy_location.retrieve.all" );
985 my $shelving_locations;
986 sub retrieve_all_copy_locations {
987 my( $self, $client ) = @_;
988 if(!$shelving_locations) {
989 $shelving_locations = $apputils->simple_scalar_request(
991 "open-ils.storage.direct.asset.copy_location.retrieve.all.atomic");
993 return $shelving_locations;
998 __PACKAGE__->register_method(
999 method => "retrieve_all_copy_statuses",
1000 api_name => "open-ils.search.config.copy_status.retrieve.all" );
1003 sub retrieve_all_copy_statuses {
1004 my( $self, $client ) = @_;
1005 if(!$copy_statuses) {
1006 $copy_statuses = $apputils->simple_scalar_request(
1008 "open-ils.storage.direct.config.copy_status.retrieve.all.atomic" );
1010 return $copy_statuses;
1014 __PACKAGE__->register_method(
1015 method => "copy_counts_per_org",
1016 api_name => "open-ils.search.biblio.copy_counts.retrieve");
1018 sub copy_counts_per_org {
1019 my( $self, $client, $record_id ) = @_;
1020 my $counts = $apputils->simple_scalar_request(
1022 "open-ils.storage.biblio.record_entry.global_copy_count.atomic",
1024 $counts = [ sort {$a->[0] <=> $b->[0]} @$counts ];