1 use strict; use warnings;
2 package OpenILS::Application::Cat;
3 use OpenILS::Application::AppUtils;
4 use OpenSRF::Application;
5 use OpenILS::Application::Cat::Utils;
6 use base qw/OpenSRF::Application/;
7 use Time::HiRes qw(time);
8 use OpenSRF::EX qw(:try);
10 use OpenILS::Utils::Fieldmapper;
12 my $apputils = "OpenILS::Application::AppUtils";
14 my $utils = "OpenILS::Application::Cat::Utils";
19 __PACKAGE__->register_method(
20 method => "biblio_record_tree_retrieve",
21 api_name => "open-ils.cat.biblio.record.tree.retrieve",
23 note => "Returns the tree associated with the nodeset of the given doc id"
26 sub biblio_record_tree_retrieve {
28 my( $self, $client, $recordid ) = @_;
30 my $name = "open-ils.storage.direct.biblio.record_entry.retrieve";
31 my $session = OpenSRF::AppSession->create( "open-ils.storage" );
32 my $request = $session->request( $name, $recordid );
33 my $marcxml = $request->gather(1);
36 throw OpenSRF::EX::ERROR
37 ("No record in database with id $recordid");
40 $session->disconnect();
43 warn "turning into nodeset\n";
44 my $nodes = OpenILS::Utils::FlatXML->new()->xml_to_nodeset( $marcxml->marc );
45 warn "turning nodeset into tree\n";
46 my $tree = $utils->nodeset2tree( $nodes->nodeset );
48 $tree->owner_doc( $marcxml->id() );
50 warn "returning tree\n";
55 __PACKAGE__->register_method(
56 method => "biblio_record_tree_commit",
57 api_name => "open-ils.cat.biblio.record.tree.commit",
58 argc => 3, #(session_id, biblio_tree )
59 note => "Walks the tree and commits any changed nodes " .
60 "adds any new nodes, and deletes any deleted nodes",
63 sub biblio_record_tree_commit {
65 my( $self, $client, $user_session, $tree ) = @_;
66 new Fieldmapper::biblio::record_node ($tree);
70 throw OpenSRF::EX::InvalidArg
71 ("Not enough args to to open-ils.cat.biblio.record.tree.commit")
72 unless ( $user_session and $tree );
75 OpenILS::Application::AppUtils->check_user_session( $user_session ); #throws EX on error
78 my $docid = $tree->owner_doc();
79 my $session = OpenILS::Application::AppUtils->start_db_session();
81 warn "Retrieving biblio record from storage for update\n";
83 my $req1 = $session->request(
84 "open-ils.storage.direct.biblio.record_entry.batch.retrieve",
86 my $biblio = $req1->gather(1);
88 warn "retrieved doc $docid\n";
91 # turn the tree into a nodeset
92 my $nodeset = $utils->tree2nodeset($tree);
93 $nodeset = $utils->clean_nodeset( $nodeset );
95 if(!defined($docid)) { # be sure
96 for my $node (@$nodeset) {
97 $docid = $node->owner_doc();
98 last if defined($docid);
102 # turn the nodeset into a doc
103 my $marcxml = OpenILS::Utils::FlatXML->new()->nodeset_to_xml( $nodeset );
105 $biblio->marc( $marcxml->toString() );
107 warn "Starting db session\n";
109 my $x = _update_record_metadata( $session, { user => $user_obj, docid => $docid } );
110 OpenILS::Application::AppUtils->rollback_db_session($session) unless $x;
112 warn "Sending updated doc $docid to db\n";
113 my $req = $session->request( "open-ils.storage.direct.biblio.record_entry.update", $biblio );
116 my $status = $req->recv();
117 if( !$status || $status->isa("Error") || ! $status->content) {
118 OpenILS::Application::AppUtils->rollback_db_session($session);
119 if($status->isa("Error")) { throw $status ($status); }
120 throw OpenSRF::EX::ERROR ("Error updating biblio record");
124 # Send the doc to the wormer for wormizing
125 warn "Starting worm session\n";
130 my $wreq = $session->request( "open-ils.worm.wormize", $docid );
137 warn "wormizing failed, rolling back\n";
138 OpenILS::Application::AppUtils->rollback_db_session($session);
140 if($e) { throw $e ($e); }
141 throw OpenSRF::EX::ERROR ("Wormizing Failed for $docid" );
144 OpenILS::Application::AppUtils->commit_db_session( $session );
146 $nodeset = OpenILS::Utils::FlatXML->new()->xmldoc_to_nodeset($marcxml);
147 $tree = $utils->nodeset2tree($nodeset->nodeset);
148 $tree->owner_doc($docid);
150 $client->respond_complete($tree);
152 warn "Done wormizing\n";
158 __PACKAGE__->register_method(
159 method => "biblio_record_record_metadata",
160 api_name => "open-ils.cat.biblio.record.metadata.retrieve",
161 argc => 1, #(session_id, biblio_tree )
162 note => "Walks the tree and commits any changed nodes " .
163 "adds any new nodes, and deletes any deleted nodes",
166 sub biblio_record_record_metadata {
167 my( $self, $client, @ids ) = @_;
169 if(!@ids){return undef;}
171 my $session = OpenSRF::AppSession->create("open-ils.storage");
172 my $request = $session->request(
173 "open-ils.storage.direct.biblio.record_entry.batch.retrieve", @ids );
177 while( my $response = $request->recv() ) {
180 throw OpenSRF::EX::ERROR ("No Response from Storage");
182 if($response->isa("Error")) {
183 throw $response ($response->stringify);
186 my $record_entry = $response->content;
188 my $creator = $record_entry->creator;
189 my $editor = $record_entry->editor;
191 ($creator, $editor) = _get_userid_by_id($creator, $editor);
193 $record_entry->creator( $creator );
194 $record_entry->editor( $editor );
196 push @$results, $record_entry;
201 $session->disconnect();
209 sub _get_userid_by_id {
214 my $session = OpenSRF::AppSession->create( "open-ils.storage" );
215 my $request = $session->request(
216 "open-ils.storage.direct.actor.user.batch.retrieve.atomic", @ids );
218 $request->wait_complete;
219 my $response = $request->recv();
220 if(!$request->complete) { return undef; }
222 if($response->isa("Error")){
223 throw $response ($response);
226 for my $u (@{$response->content}) {
228 push @users, $u->usrname;
232 $session->disconnect;
238 sub _get_id_by_userid {
243 my $session = OpenSRF::AppSession->create( "open-ils.storage" );
244 my $request = $session->request(
245 "open-ils.storage.direct.actor.user.search.usrname", @users );
247 $request->wait_complete;
248 my $response = $request->recv();
249 if(!$request->complete) {
250 throw OpenSRF::EX::ERROR ("no response from storage on user retrieve");
253 if(UNIVERSAL::isa( $response, "Error")){
254 throw $response ($response);
257 for my $u (@{$response->content}) {
263 $session->disconnect;
270 # commits metadata objects to the db
271 sub _update_record_metadata {
273 my ($session, @docs ) = @_;
275 for my $doc (@docs) {
277 my $user_obj = $doc->{user};
278 my $docid = $doc->{docid};
280 warn "Updating metata for doc $docid\n";
282 my $request = $session->request(
283 "open-ils.storage.direct.biblio.record_entry.retrieve", $docid );
284 my $record = $request->gather(1);
286 warn "retrieved record\n";
287 my ($id) = _get_id_by_userid($user_obj->usrname);
289 warn "got $id from _get_id_by_userid\n";
290 $record->editor($id);
292 warn "Grabbed the record, updating and moving on\n";
294 $request = $session->request(
295 "open-ils.storage.direct.biblio.record_entry.update", $record );
299 warn "committing metarecord update\n";
306 __PACKAGE__->register_method(
307 method => "orgs_for_title",
308 api_name => "open-ils.cat.actor.org_unit.retrieve_by_title"
312 my( $self, $client, $record_id ) = @_;
314 my $vols = $apputils->simple_scalar_request(
316 "open-ils.storage.direct.asset.call_number.search.record",
319 my $orgs = { map {$_->owning_lib => 1 } @$vols };
320 return [ keys %$orgs ];
325 __PACKAGE__->register_method(
326 method => "retrieve_copies",
327 api_name => "open-ils.cat.asset.copy_tree.retrieve",
330 __PACKAGE__->register_method(
331 method => "retrieve_copies",
332 api_name => "open-ils.cat.asset.copy_tree.global.retrieve",
335 sub retrieve_copies {
337 my( $self, $client, $user_session, $docid, @org_ids ) = @_;
339 if(ref($org_ids[0])) { @org_ids = @{$org_ids[0]}; }
343 warn " $$ retrieving copy tree for doc $docid at " . time() . "\n";
347 OpenILS::Application::AppUtils->check_user_session( $user_session ); #throws EX on error
348 @org_ids = ($user_obj->home_ou);
351 if( $self->api_name =~ /global/ ) {
352 warn "performing global copy_tree search for $docid\n";
353 return _build_volume_list( { record => $docid } );
358 for my $orgid (@org_ids) {
359 my $vols = _build_volume_list(
360 { record => $docid, owning_lib => $orgid } );
361 warn "Volumes built for org $orgid\n";
362 push( @all_vols, @$vols );
365 warn " $$ Finished copy_tree at " . time() . "\n";
373 sub _build_volume_list {
374 my $search_hash = shift;
376 my $session = OpenSRF::AppSession->create( "open-ils.storage" );
379 my $request = $session->request(
380 "open-ils.storage.direct.asset.call_number.search.atomic", $search_hash );
382 my $vols = $request->gather(1);
385 for my $volume (@$vols) {
387 warn "Grabbing copies for volume: " . $volume->id . "\n";
388 my $creq = $session->request(
389 "open-ils.storage.direct.asset.copy.search.call_number",
391 my $copies = $creq->gather(1);
393 $volume->copies($copies);
395 push( @volumes, $volume );
399 $session->disconnect();
408 __PACKAGE__->register_method(
409 method => "generic_edit_copies_volumes",
410 api_name => "open-ils.cat.asset.volume.batch.update",
413 __PACKAGE__->register_method(
414 method => "generic_edit_copies_volumes",
415 api_name => "open-ils.cat.asset.volume.batch.delete",
418 __PACKAGE__->register_method(
419 method => "generic_edit_copies_volumes",
420 api_name => "open-ils.cat.asset.copy.batch.update",
423 __PACKAGE__->register_method(
424 method => "generic_edit_copies_volumes",
425 api_name => "open-ils.cat.asset.copy.batch.delete",
429 sub generic_edit_copies_volumes {
431 my( $self, $client, $user_session, $items ) = @_;
433 my $method = $self->api_name;
434 $method =~ s/open-ils\.cat/open-ils\.storage\.direct/og;
435 warn "our method is $method\n";
438 OpenILS::Application::AppUtils->check_user_session( $user_session ); #throws EX on error
440 warn "updating editor info\n";
442 for my $item (@$items) {
443 $item->editor( $user_obj->id );
446 my $session = OpenILS::Application::AppUtils->start_db_session;
447 my $request = $session->request( $method, @$items );
448 my $result = $request->gather(1);
450 OpenILS::Application::AppUtils->commit_db_session($session);
452 warn "looks like we succeeded\n";
460 # -----------------------------------------------------------------
461 # Fleshed volume tree batch add/update. This does everything a
462 # volume tree could want, add, update, delete
463 # -----------------------------------------------------------------
464 __PACKAGE__->register_method(
465 method => "volume_tree_fleshed_update",
466 api_name => "open-ils.cat.asset.volume_tree.fleshed.batch.update",
468 sub volume_tree_fleshed_update {
470 my( $self, $client, $user_session, $volumes ) = @_;
471 return undef unless $volumes;
472 my $user_obj = $apputils->check_user_session($user_session);
474 my $session = $apputils->start_db_session();
475 warn "Looping on volumes in fleshed volume tree update\n";
477 # cycle through the volumes provided and update/create/delete where necessary
478 for my $volume (@$volumes) {
480 warn "updating volume " . $volume->id . "\n";
482 my $update_copy_list = $volume->copies;
484 if( $volume->isnew ) {
487 $volume->editor($user_obj->id);
488 $volume->creator($user_obj->id);
489 $volume = _add_volume($session, $volume);
491 } elsif( $volume->ischanged ) {
492 $volume->editor($user_obj->id);
493 _update_volume($session, $volume);
495 } elsif( $volume->isdeleted) {
496 return _delete_volume($session, $volume);
499 for my $copy (@{$update_copy_list}) {
501 $copy->editor($user_obj->id);
502 warn "updating copy for volume " . $volume->id . "\n";
506 $copy->call_number($volume->id);
507 $copy->creator($user_obj->id);
508 $copy = _fleshed_copy_update($session,$copy,$user_obj->id);
510 } elsif( $copy->ischanged ) {
511 $copy->call_number($volume->id);
512 $copy = _fleshed_copy_update($session, $copy, $user_obj->id);
514 } elsif( $copy->isdeleted ) {
515 _fleshed_copy_update($session, $copy, $user_obj->id);
519 $apputils->commit_db_session($session);
520 return scalar(@$volumes);
526 my( $session, $volume ) = @_;
528 $volume = _find_volume($session, $volume);
530 # my $copies = $session->request(
531 # "open-ils.storage.direct.asset.copy.search.call_number",
532 # $volume-id )->gather(1);
534 # throw OpenSRF::EX::ERROR
535 # ("Cannot remove volume with copies attached");
542 my( $session, $volume ) = @_;
543 my $cn_req = $session->request(
544 'open-ils.storage.direct.asset.call_number.search' =>
545 { owning_lib => $volume->owning_lib,
546 label => $volume->label,
547 record => $volume->record,
550 return $cn_req->gather(1);
555 my($session, $volume) = @_;
556 my $req = $session->request(
557 "open-ils.storage.direct.asset.call_number.update",
559 my $status = $req->gather(1);
564 my($session, $volume) = @_;
566 my $request = $session->request(
567 "open-ils.storage.direct.asset.call_number.create", $volume );
569 my $id = $request->gather(1);
572 OpenILS::Application::AppUtils->rollback_db_session($session);
573 throw OpenSRF::EX::ERROR (" * -> Error creating new volume");
577 warn "received new volume id: $id\n";
586 __PACKAGE__->register_method(
587 method => "volume_tree_add",
588 api_name => "open-ils.cat.asset.volume.tree.batch.add",
591 sub volume_tree_add {
593 my( $self, $client, $user_session, $volumes ) = @_;
594 return undef unless $volumes;
598 warn Dumper $volumes;
601 OpenILS::Application::AppUtils->check_user_session( $user_session ); #throws EX on error
603 warn "volume_tree_add creating new db session\n";
605 my $session = OpenILS::Application::AppUtils->start_db_session;
607 for my $volume (@$volumes) {
609 warn "Looping on volumes\n";
611 my $new_copy_list = $volume->copies;
613 warn "Searching for volume with ".$volume->owning_lib . " " .
614 $volume->label . " " . $volume->record . "\n";
616 my $cn = _find_volume($session, $volume);
622 $volume->editor( $user_obj->id );
626 $volume->creator( $user_obj->id );
627 $volume->editor( $user_obj->id );
628 $volume = _add_volume($volume);
632 for my $copy (@{$new_copy_list}) {
634 warn "adding a copy for volume $id\n";
636 $copy->call_number($id);
637 $copy->creator($user_obj->id);
638 $copy->editor($user_obj->id);
642 if( $copy->isnew() ) {
644 my $req = $session->request(
645 "open-ils.storage.direct.asset.copy.create", $copy );
646 my $cid = $req->gather(1);
649 OpenILS::Application::AppUtils->rollback_db_session($session);
650 throw OpenSRF::EX::ERROR ("Error adding copy to volume $id" );
653 warn "got new copy id $cid\n";
655 } elsif( $copy->ischanged() ) {
661 warn "completed adding copies for $id\n";
666 warn "committing volume tree add db session\n";
667 OpenILS::Application::AppUtils->commit_db_session($session);
669 return scalar(@$volumes);
673 __PACKAGE__->register_method(
674 method => "copy_update",
675 api_name => "open-ils.cat.asset.copy.batch.update",
679 my($self, $client, $user_session, $copies) = @_;
681 my $user_obj = $apputils->check_user_session( $user_session ); #throws EX on error
683 my $session = $apputils->start_db_session();
684 for my $copy (@$copies) {
685 $copy->editor($user_obj->id);
686 my $req = $session->request(
687 "open-ils.storage.direct.asset.copy.update",
689 my $status = $req->gather(1);
692 $apputils->commit_db_session($session);
699 __PACKAGE__->register_method(
700 method => "fleshed_copy_update",
701 api_name => "open-ils.cat.asset.copy.fleshed.batch.update",
704 sub fleshed_copy_update {
705 my($self, $client, $user_session, $copies) = @_;
707 my $user_obj = $apputils->check_user_session($user_session);
708 my $session = $apputils->start_db_session();
710 for my $copy (@$copies) {
711 _fleshed_copy_update($session, $copies, $user_obj->id);
714 $apputils->commit_db_session($session);
720 my($session, $copy) = @_;
721 warn "Deleting copy " . $copy->id . "\n";
722 my $request = $session->request(
723 "open-ils.storage.direct.asset.copy.delete",
725 return $request->gather(1);
729 my($session, $copy) = @_;
731 my $request = $session->request(
732 "open-ils.storage.direct.asset.copy.create",
734 my $id = $request->gather(1);
737 throw OpenSRF::EX::ERROR
738 ("Unable to create new copy " . Dumper($copy));
741 warn "Created copy " . $copy->id . "\n";
748 my($session, $copy) = @_;
749 my $request = $session->request(
750 "open-ils.storage.asset.copy.update",
752 warn "Updated copy " . $copy->id . "\n";
753 return $request->gather(1);
757 # -----------------------------------------------------------------
758 # Creates/Updates/Deletes a fleshed asset.copy.
759 # adds/deletes copy stat_cat maps where necessary
760 # -----------------------------------------------------------------
761 sub _fleshed_copy_update {
762 my($session, $copy, $editor) = @_;
764 my $stat_cat_entries = $copy->stat_cat_entries;
765 $copy->editor($editor);
767 # in case we're fleshed
768 if(ref($copy->status)) {$copy->status( $copy->status->id ); }
769 if(ref($copy->location)) {$copy->location( $copy->location->id ); }
770 if(ref($copy->circ_lib)) {$copy->circ_lib( $copy->circ_lib->id ); }
773 if( $copy->isdeleted ) {
774 return _delete_copy($session, $copy);
775 } elsif( $copy->isnew ) {
776 $copy = _create_copy($session, $copy);
777 } elsif( $copy->ischanged ) {
778 _update_copy($session, $copy);
781 warn "Updating copy " . Dumper($copy) . "\n";
783 if(!@$stat_cat_entries) { return 1; }
785 my $stat_maps = $session->request(
786 "open-ils.storage.direct.asset.stat_cat_entry_copy_map.search.owning_copy",
787 $copy->id )->gather(1);
789 if( ! $copy->isnew ) { _delete_stale_maps($session, $copy); }
791 # go through the stat cat update/create process
792 for my $stat_entry (@{$stat_cat_entries}){
793 _copy_update_stat_cats( $session, $copy, $stat_maps, $stat_entry );
800 # -----------------------------------------------------------------
801 # Deletes stat maps attached to this copy in the database that
802 # are no longer attached to the current copy
803 # -----------------------------------------------------------------
804 sub _delete_stale_maps {
805 my( $session, $stat_maps, $copy) = @_;
807 warn "Deleting stale stat maps for copy " . $copy->id . "\n";
808 for my $map (@$stat_maps) {
809 # if there is no stat cat entry on the copy who's id matches the
810 # current map's id, remove the map from the database
811 if(! grep { $_->id == $map->stat_cat_entry } @{$copy->stat_cat_entries} ) {
812 my $req = $session->request(
813 "open-ils.storage.direct.asset.stat_cat_entry_copy_map.delete", $map );
822 # -----------------------------------------------------------------
823 # Searches the stat maps to see if '$entry' already exists on
824 # the given copy. If it does not, a new stat map is created
825 # for the given entry and copy
826 # -----------------------------------------------------------------
827 sub _copy_update_stat_cats {
828 my ( $session, $copy, $stat_maps, $entry ) = @_;
830 warn "Updating stat maps for copy " . $copy->id . "\n";
832 # see if this map already exists
833 for my $map (@$stat_maps) {
834 if( $map->stat_cat_entry == $entry->id ) {return;}
837 warn "Creating new stat map for stat " .
838 $entry->stat_cat . " and copy " . $copy->id . "\n";
841 my $new_map = Fieldmapper::asset::stat_cat_entry_copy_map->new();
843 $new_map->stat_cat( $entry->stat_cat );
844 $new_map->stat_cat_entry( $entry->id );
845 $new_map->owning_copy( $copy->id );
847 warn "New map is " . Dumper($new_map) . "\n";
849 my $request = $session->request(
850 "open-ils.storage.direct.asset.stat_cat_entry_copy_map.create",
852 my $status = $request->gather(1);
853 warn "created new map with id $status\n";
860 __PACKAGE__->register_method(
861 method => "volume_tree_delete",
862 api_name => "open-ils.cat.asset.volume.tree.batch.delete",
865 sub volume_tree_delete {
867 my( $self, $client, $user_session, $volumes ) = @_;
868 return undef unless $volumes;
871 OpenILS::Application::AppUtils->check_user_session( $user_session ); #throws EX on error
873 my $session = OpenILS::Application::AppUtils->start_db_session;
875 for my $volume (@$volumes) {
877 $volume->editor($user_obj->id);
879 new Fieldmapper::asset::call_number($volume);
881 for my $copy (@{$volume->copies}) {
883 new Fieldmapper::asset::copy($copy);
885 $copy->editor( $user_obj->id );
887 warn "Deleting copy " . $copy->id . " from db\n";
889 my $req = $session->request(
890 "open-ils.storage.direct.asset.copy.delete", $copy );
892 my $resp = $req->recv();
894 if( !$req->complete ) {
895 OpenILS::Application::AppUtils->rollback_db_session($session);
896 throw OpenSRF::EX::ERROR (
897 "No response from storage on copy delete");
900 if(UNIVERSAL::isa($resp, "Error")) {
901 OpenILS::Application::AppUtils->rollback_db_session($session);
902 throw $resp ($resp->stringify);
908 warn "Deleting volume " . $volume->id . " from database\n";
910 my $vol_req = $session->request(
911 "open-ils.storage.direct.asset.call_number.delete", $volume );
912 my $vol_resp = $vol_req;
914 if(!$vol_req->complete) {
915 OpenILS::Application::AppUtils->rollback_db_session($session);
916 throw OpenSRF::EX::ERROR
917 ("No response from storage on volume delete");
920 if( $vol_resp and UNIVERSAL::isa($vol_resp, "Error")) {
921 OpenILS::Application::AppUtils->rollback_db_session($session);
922 throw $vol_resp ($vol_resp->stringify);
929 warn "committing delete volume tree add db session\n";
931 OpenILS::Application::AppUtils->commit_db_session($session);
933 return scalar(@$volumes);