dcc90862292cce80b5f429bfea32f569a6e424f3
[Evergreen.git] / Open-ILS / src / perlmods / OpenILS / Application / Cat.pm
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);
9 use JSON;
10 use OpenILS::Utils::Fieldmapper;
11
12 my $apputils = "OpenILS::Application::AppUtils";
13
14 my $utils = "OpenILS::Application::Cat::Utils";
15
16
17
18
19 __PACKAGE__->register_method(
20         method  => "biblio_record_tree_retrieve",
21         api_name        => "open-ils.cat.biblio.record.tree.retrieve",
22         argc            => 1, 
23         note            => "Returns the tree associated with the nodeset of the given doc id"
24 );
25
26 sub biblio_record_tree_retrieve {
27
28         my( $self, $client, $recordid ) = @_;
29
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);
34
35         if(!$marcxml) {
36                 throw OpenSRF::EX::ERROR 
37                         ("No record in database with id $recordid");
38         }
39
40         $session->disconnect();
41         $session->kill_me();
42
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 );
47
48         $tree->owner_doc( $marcxml->id() );
49
50         warn "returning tree\n";
51
52         return $tree;
53 }
54
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",
61 );
62
63 sub biblio_record_tree_commit {
64
65         my( $self, $client, $user_session,  $tree ) = @_;
66         new Fieldmapper::biblio::record_node ($tree);
67
68         use Data::Dumper;
69
70         throw OpenSRF::EX::InvalidArg 
71                 ("Not enough args to to open-ils.cat.biblio.record.tree.commit")
72                 unless ( $user_session and $tree );
73
74         my $user_obj = 
75                 OpenILS::Application::AppUtils->check_user_session( $user_session ); #throws EX on error
76
77         # capture the doc id
78         my $docid = $tree->owner_doc();
79         my $session = OpenILS::Application::AppUtils->start_db_session();
80
81         warn "Retrieving biblio record from storage for update\n";
82
83         my $req1 = $session->request(
84                         "open-ils.storage.direct.biblio.record_entry.batch.retrieve", 
85                         $docid );
86         my $biblio = $req1->gather(1);
87
88         warn "retrieved doc $docid\n";
89
90
91         # turn the tree into a nodeset
92         my $nodeset = $utils->tree2nodeset($tree);
93         $nodeset = $utils->clean_nodeset( $nodeset );
94
95         if(!defined($docid)) { # be sure
96                 for my $node (@$nodeset) {
97                         $docid = $node->owner_doc();
98                         last if defined($docid);
99                 }
100         }
101
102         # turn the nodeset into a doc
103         my $marcxml = OpenILS::Utils::FlatXML->new()->nodeset_to_xml( $nodeset );
104
105         $biblio->marc( $marcxml->toString() );
106
107         warn "Starting db session\n";
108
109         my $x = _update_record_metadata( $session, { user => $user_obj, docid => $docid } );
110         OpenILS::Application::AppUtils->rollback_db_session($session) unless $x;
111
112         warn "Sending updated doc $docid to db\n";
113         my $req = $session->request( "open-ils.storage.direct.biblio.record_entry.update", $biblio );
114
115         $req->wait_complete;
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");
121         }
122         $req->finish();
123
124         # Send the doc to the wormer for wormizing
125         warn "Starting worm session\n";
126
127         my $success = 0;
128         my $wresp;
129
130         my $wreq = $session->request( "open-ils.worm.wormize", $docid );
131
132         try {
133                 $wreq->gather(1);
134
135         } catch Error with {
136                 my $e = shift;
137                 warn "wormizing failed, rolling back\n";
138                 OpenILS::Application::AppUtils->rollback_db_session($session);
139
140                 if($e) { throw $e ($e); }
141                 throw OpenSRF::EX::ERROR ("Wormizing Failed for $docid" );
142         };
143
144         OpenILS::Application::AppUtils->commit_db_session( $session );
145
146         $nodeset = OpenILS::Utils::FlatXML->new()->xmldoc_to_nodeset($marcxml);
147         $tree = $utils->nodeset2tree($nodeset->nodeset);
148         $tree->owner_doc($docid);
149
150         $client->respond_complete($tree);
151
152         warn "Done wormizing\n";
153
154 }
155
156
157
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",
164 );
165
166 sub biblio_record_record_metadata {
167         my( $self, $client, @ids ) = @_;
168
169         if(!@ids){return undef;}
170
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 );
174
175         my $results = [];
176
177         while( my $response = $request->recv() ) {
178
179                 if(!$response) {
180                         throw OpenSRF::EX::ERROR ("No Response from Storage");
181                 }
182                 if($response->isa("Error")) {
183                         throw $response ($response->stringify);
184                 }
185
186                 my $record_entry = $response->content;
187
188                 my $creator = $record_entry->creator;
189                 my $editor      = $record_entry->editor;
190
191                 ($creator, $editor) = _get_userid_by_id($creator, $editor);
192
193                 $record_entry->creator( $creator );
194                 $record_entry->editor( $editor );
195
196                 push @$results, $record_entry;
197
198         }
199
200         $request->finish;
201         $session->disconnect();
202         $session->finish();
203
204         return $results;
205
206 }
207
208 # gets the username
209 sub _get_userid_by_id {
210
211         my @ids = @_;
212         my @users;
213
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 );
217
218         $request->wait_complete;
219         my $response = $request->recv();
220         if(!$request->complete) { return undef; }
221
222         if($response->isa("Error")){
223                 throw $response ($response);
224         }
225
226         for my $u (@{$response->content}) {
227                 next unless ref($u);
228                 push @users, $u->usrname;
229         }
230
231         $request->finish;
232         $session->disconnect;
233         $session->kill_me();
234
235         return @users;
236 }
237
238 # open-ils.storage.direct.actor.user.search.usrid
239
240 sub _get_id_by_userid {
241
242         my @users = @_;
243         my @ids;
244
245         my $session = OpenSRF::AppSession->create( "open-ils.storage" );
246         my $request = $session->request( 
247                 "open-ils.storage.direct.actor.user.search.usrname", @users );
248
249         $request->wait_complete;
250         my $response = $request->recv();
251         if(!$request->complete) { 
252                 throw OpenSRF::EX::ERROR ("no response from storage on user retrieve");
253         }
254
255         if(UNIVERSAL::isa( $response, "Error")){
256                 throw $response ($response);
257         }
258
259         for my $u (@{$response->content}) {
260                 next unless ref($u);
261                 push @ids, $u->id();
262         }
263
264         $request->finish;
265         $session->disconnect;
266         $session->kill_me();
267
268         return @ids;
269 }
270
271
272 # commits metadata objects to the db
273 sub _update_record_metadata {
274
275         my ($session, @docs ) = @_;
276
277         for my $doc (@docs) {
278
279                 my $user_obj = $doc->{user};
280                 my $docid = $doc->{docid};
281
282                 warn "Updating metata for doc $docid\n";
283
284                 my $request = $session->request( 
285                         "open-ils.storage.direct.biblio.record_entry.retrieve", $docid );
286                 my $record = $request->gather(1);
287
288                 warn "retrieved record\n";
289                 my ($id) = _get_id_by_userid($user_obj->usrname);
290
291                 warn "got $id from _get_id_by_userid\n";
292                 $record->editor($id);
293                 
294                 warn "Grabbed the record, updating and moving on\n";
295
296                 $request = $session->request( 
297                         "open-ils.storage.direct.biblio.record_entry.update", $record );
298                 $request->gather(1);
299         }
300
301         warn "committing metarecord update\n";
302
303         return 1;
304 }
305
306
307
308 __PACKAGE__->register_method(
309         method  => "orgs_for_title",
310         api_name        => "open-ils.cat.actor.org_unit.retrieve_by_title"
311 );
312
313 sub orgs_for_title {
314         my( $self, $client, $record_id ) = @_;
315
316         my $vols = $apputils->simple_scalar_request(
317                 "open-ils.storage",
318                 "open-ils.storage.direct.asset.call_number.search.record",
319                 $record_id );
320
321         my $orgs = { map {$_->owning_lib => 1 } @$vols };
322         return [ keys %$orgs ];
323 }
324
325
326
327 __PACKAGE__->register_method(
328         method  => "retrieve_copies",
329         api_name        => "open-ils.cat.asset.copy_tree.retrieve",
330 );
331
332 __PACKAGE__->register_method(
333         method  => "retrieve_copies",
334         api_name        => "open-ils.cat.asset.copy_tree.global.retrieve",
335 );
336
337 sub retrieve_copies {
338
339         my( $self, $client, $user_session, $docid, @org_ids ) = @_;
340
341         if(ref($org_ids[0])) { @org_ids = @{$org_ids[0]}; }
342
343         $docid = "$docid";
344
345         warn " $$ retrieving copy tree for doc $docid at " . time() . "\n";
346
347         if(!@org_ids) {
348                 my $user_obj = 
349                         OpenILS::Application::AppUtils->check_user_session( $user_session ); #throws EX on error
350                         @org_ids = ($user_obj->home_ou);
351         }
352
353         if( $self->api_name =~ /global/ ) {
354                 warn "performing global copy_tree search for $docid\n";
355                 return _build_volume_list( { record => $docid } );
356
357         } else {
358
359                 my @all_vols;
360                 for my $orgid (@org_ids) {
361                         my $vols = _build_volume_list( 
362                                         { record => $docid, owning_lib => $orgid } );
363                         warn "Volumes built for org $orgid\n";
364                         push( @all_vols, @$vols );
365                 }
366                 
367                 warn " $$ Finished copy_tree at " . time() . "\n";
368                 return \@all_vols;
369         }
370
371         return undef;
372 }
373
374
375 sub _build_volume_list {
376         my $search_hash = shift;
377
378         my      $session = OpenSRF::AppSession->create( "open-ils.storage" );
379         
380
381         my $request = $session->request( 
382                         "open-ils.storage.direct.asset.call_number.search.atomic", $search_hash );
383
384         my $vols = $request->gather(1);
385         my @volumes;
386
387         for my $volume (@$vols) {
388
389                 warn "Grabbing copies for volume: " . $volume->id . "\n";
390                 my $creq = $session->request(
391                         "open-ils.storage.direct.asset.copy.search.call_number", 
392                         $volume->id );
393                 my $copies = $creq->gather(1);
394
395                 $volume->copies($copies);
396
397                 push( @volumes, $volume );
398         }
399
400
401         $session->disconnect();
402         return \@volumes;
403
404 }
405
406
407
408
409 __PACKAGE__->register_method(
410         method  => "generic_edit_copies_volumes",
411         api_name        => "open-ils.cat.asset.volume.batch.update",
412 );
413
414 __PACKAGE__->register_method(
415         method  => "generic_edit_copies_volumes",
416         api_name        => "open-ils.cat.asset.volume.batch.delete",
417 );
418
419 __PACKAGE__->register_method(
420         method  => "generic_edit_copies_volumes",
421         api_name        => "open-ils.cat.asset.copy.batch.update",
422 );
423
424 __PACKAGE__->register_method(
425         method  => "generic_edit_copies_volumes",
426         api_name        => "open-ils.cat.asset.copy.batch.delete",
427 );
428
429
430 sub generic_edit_copies_volumes {
431
432         my( $self, $client, $user_session, $items ) = @_;
433
434         my $method = $self->api_name;
435         $method =~ s/open-ils\.cat/open-ils\.storage\.direct/og;
436         warn "our method is $method\n";
437
438         my $user_obj = 
439                 OpenILS::Application::AppUtils->check_user_session( $user_session ); #throws EX on error
440         
441         warn "updating editor info\n";
442
443         for my $item (@$items) {
444                 $item->editor( $user_obj->id );
445         }
446
447         my $session = OpenILS::Application::AppUtils->start_db_session;
448         my $request = $session->request( $method, @$items );
449         my $result = $request->gather(1);
450
451         OpenILS::Application::AppUtils->commit_db_session($session);
452
453         warn "looks like we succeeded\n";
454         return $result;
455 }
456
457
458 __PACKAGE__->register_method(
459         method  => "volume_tree_add",
460         api_name        => "open-ils.cat.asset.volume.tree.batch.add",
461 );
462
463 sub volume_tree_add {
464
465         my( $self, $client, $user_session, $volumes ) = @_;
466         return undef unless $volumes;
467
468         use Data::Dumper;
469         warn "Volumes:\n";
470         warn Dumper $volumes;
471
472         my $user_obj = 
473                 OpenILS::Application::AppUtils->check_user_session( $user_session ); #throws EX on error
474
475         warn "volume_tree_add creating new db session\n";
476
477         my $session = OpenILS::Application::AppUtils->start_db_session;
478
479         for my $volume (@$volumes) {
480
481                 new Fieldmapper::asset::call_number($volume);
482
483                 warn "Looping on volumes\n";
484
485
486
487                 my $new_copy_list = $volume->copies;
488                 my $id;
489
490                 warn "Searching for volume with ".$volume->owning_lib . " " .
491                         $volume->label . " " . $volume->record . "\n";
492
493                 my $cn_req = $session->request( 
494                                 'open-ils.storage.direct.asset.call_number.search' =>
495                       {       owning_lib      => $volume->owning_lib,
496                               label           => $volume->label,
497                               record          => $volume->record,
498                                 }); 
499
500                 $cn_req->wait_complete;
501                 my $cn = $cn_req->recv();
502                 
503                 if(!$cn_req->complete) {
504                         throw OpenSRF::EX::ERROR ("Error searching volumes on storage");
505                 }
506
507                 $cn_req->finish();
508
509                 if($cn) {
510
511                         if(UNIVERSAL::isa($cn,"Error")) {
512                                 throw $cn ($cn->stringify);
513                         }
514
515                         $volume = $cn->content;
516                         $id = $volume->id;
517                         $volume->editor( $user_obj->id );
518
519                 } else {
520
521                         $volume->creator( $user_obj->id );
522                         $volume->editor( $user_obj->id );
523
524                         warn "Attempting to create a new volume:\n";
525
526                         warn Dumper $volume;
527
528                         my $request = $session->request( 
529                                 "open-ils.storage.direct.asset.call_number.create", $volume );
530
531                         my $response = $request->recv();
532
533                         if(!$request->complete) { 
534                                 OpenILS::Application::AppUtils->rollback_db_session($session);
535                                 throw OpenSRF::EX::ERROR 
536                                         ("No response from storage on call_number.create");
537                         }
538                 
539                         if(UNIVERSAL::isa($response, "Error")) {
540                                 OpenILS::Application::AppUtils->rollback_db_session($session);
541                                 throw $response ($response->stringify);
542                         }
543
544                         $id = $response->content;
545
546                         if( $id == 0 ) {
547                                 OpenILS::Application::AppUtils->rollback_db_session($session);
548                                 throw OpenSRF::EX::ERROR (" * -> Error creating new volume");
549                         }
550
551                         $request->finish();
552         
553                         warn "received new volume id: $id\n";
554
555                 }
556
557
558                 for my $copy (@{$new_copy_list}) {
559
560                         new Fieldmapper::asset::copy($copy);
561
562                         warn "adding a copy for volume $id\n";
563
564                         $copy->call_number($id);
565                         $copy->creator( $user_obj->id );
566                         $copy->editor( $user_obj->id );
567
568                         warn Dumper $copy;
569
570                         my $req = $session->request(
571                                         "open-ils.storage.direct.asset.copy.create", $copy );
572                         my $resp = $req->recv();
573
574                         if(!$resp || ! ref($resp) ) { 
575                                 OpenILS::Application::AppUtils->rollback_db_session($session);
576                                 throw OpenSRF::EX::ERROR 
577                                         ("No response from storage on call_number.create");
578                         }
579         
580                         if(UNIVERSAL::isa($resp, "Error")) {
581                                 OpenILS::Application::AppUtils->rollback_db_session($session);
582                                 throw $resp ($resp->stringify);
583                         }
584                         
585                         my $cid = $resp->content;
586
587                         if(!$cid) {
588                                 OpenILS::Application::AppUtils->rollback_db_session($session);
589                                 throw OpenSRF::EX::ERROR ("Error adding copy to volume $id" );
590                         }
591
592                         warn "got new copy id $cid\n";
593
594                         $req->finish();
595                 }
596
597                 warn "completed adding copies for $id\n";
598
599
600         }
601
602         warn "committing volume tree add db session\n";
603         OpenILS::Application::AppUtils->commit_db_session($session);
604
605         return scalar(@$volumes);
606
607 }
608
609 __PACKAGE__->register_method(
610         method  => "copy_update",
611         api_name        => "open-ils.cat.asset.copy.batch.update",
612 );
613
614 sub copy_update {
615         my($self, $client, $user_session, $copies) = @_;
616
617         my $user_obj = $apputils->check_user_session( $user_session ); #throws EX on error
618
619         my $session = $apputils->start_db_session();
620         for my $copy (@$copies) {
621                 $copy->editor($user_obj->id);
622                 my $req = $session->request(
623                         "open-ils.storage.direct.asset.copy.update",
624                         $copy );
625                 my $status = $req->gather(1);
626         }
627
628         $apputils->commit_db_session($session);
629         return 1;
630 }
631
632
633
634 __PACKAGE__->register_method(
635         method  => "fleshed_copy_update",
636         api_name        => "open-ils.cat.asset.copy.fleshed.batch.update",
637 );
638
639 sub fleshed_copy_update {
640         my($self, $client, $user_session, $copies) = @_;
641
642         my $user_obj = $apputils->check_user_session( $user_session ); #throws EX on error
643
644         my $session = $apputils->start_db_session();
645
646         warn "Updating copies " . Dumper($copies) . "\n";
647         
648         for my $copy (@$copies) {
649
650                 warn "Gathering stat maps for copy " . $copy->id . "\n";
651                 my $stat_maps = $session->request(
652                         "open-ils.storage.direct.asset.stat_cat_entry_copy_map.search.owning_copy",
653                         $copy->id )->gather(1);
654
655                 $copy->editor($user_obj->id);
656
657                 for my $stat_entry (@{$copy->stat_cat_entries}){ 
658                         _copy_update_stat_cats( 
659                                         $session, $copy, $stat_maps, $stat_entry );
660                 }
661
662
663                 # clean up stale stat maps for the copy
664                 for my $map (@$stat_maps) {
665                         # if there is no stat cat entry on the copy who's id matches the
666                         # current map's id, remove the map from the database
667                         if(! grep { $_->id == $map->stat_cat_entry } 
668                                                                         @{$copy->stat_cat_entries} ) {
669
670                                 warn "Deleting copy stat map " . Dumper($map) . "\n";
671                                 my $req = $session->request(
672                                         "open-ils.storage.direct.asset.stat_cat_entry_copy_map.delete",
673                                         $map );
674                                 $req->gather(1);
675                         }
676                 }
677
678
679                 # if we're fleshed, change back to id's
680                 if(ref($copy->status)) {
681                         $copy->status( $copy->status->id ); }
682
683                 if(ref($copy->location)) {
684                         $copy->location( $copy->location->id ); }
685
686
687                 my $req = $session->request(
688                         "open-ils.storage.direct.asset.copy.update",
689                         $copy );
690                 my $status = $req->gather(1);
691         }
692
693
694         $apputils->commit_db_session($session);
695         return 1;
696 }
697
698 sub _copy_update_stat_cats {
699         my ( $session, $copy, $stat_maps, $entry ) = @_;
700
701         # see if this map already exists
702         for my $map (@$stat_maps) {
703                 if( $map->stat_cat_entry == $entry->id ) {
704                         return;
705                 }
706         }
707
708         warn "Creating new stat map for stat  " . 
709                 $entry->stat_cat . " and copy " . $copy->id . "\n";
710
711         # if not, create it
712         $entry->clear_id;
713         my $request = $session->request(
714                 "open-ils.storage.direct.asset.stat_cat_entry_copy_map.create",
715                 $entry );
716         my $status = $request->gather(1);
717
718 }
719
720
721
722 __PACKAGE__->register_method(
723         method  => "volume_tree_delete",
724         api_name        => "open-ils.cat.asset.volume.tree.batch.delete",
725 );
726
727 sub volume_tree_delete {
728
729
730         my( $self, $client, $user_session, $volumes ) = @_;
731         return undef unless $volumes;
732
733         my $user_obj = 
734                 OpenILS::Application::AppUtils->check_user_session( $user_session ); #throws EX on error
735
736         my $session = OpenILS::Application::AppUtils->start_db_session;
737
738         for my $volume (@$volumes) {
739
740                 $volume->editor($user_obj->id);
741
742                 new Fieldmapper::asset::call_number($volume);
743
744                 for my $copy (@{$volume->copies}) {
745
746                         new Fieldmapper::asset::copy($copy);
747
748                         $copy->editor( $user_obj->id );
749
750                         warn "Deleting copy " . $copy->id . " from db\n";
751
752                         my $req = $session->request(
753                                         "open-ils.storage.direct.asset.copy.delete", $copy );
754
755                         my $resp = $req->recv();
756
757                         if( !$req->complete ) {
758                                 OpenILS::Application::AppUtils->rollback_db_session($session);
759                                 throw OpenSRF::EX::ERROR (
760                                                 "No response from storage on copy delete");
761                         }
762         
763                         if(UNIVERSAL::isa($resp, "Error")) {
764                                 OpenILS::Application::AppUtils->rollback_db_session($session);
765                                 throw $resp ($resp->stringify);
766                         }
767                         
768                         $req->finish();
769                 }
770
771                 warn "Deleting volume " . $volume->id . " from database\n";
772
773                 my $vol_req = $session->request(
774                                 "open-ils.storage.direct.asset.call_number.delete", $volume );
775                 my $vol_resp = $vol_req;
776
777                 if(!$vol_req->complete) {
778                         OpenILS::Application::AppUtils->rollback_db_session($session);
779                                 throw OpenSRF::EX::ERROR 
780                                         ("No response from storage on volume delete");
781                 }
782
783                 if( $vol_resp and UNIVERSAL::isa($vol_resp, "Error")) {
784                         OpenILS::Application::AppUtils->rollback_db_session($session);
785                         throw $vol_resp ($vol_resp->stringify);
786                 }
787
788                 $vol_req->finish();
789
790         }
791
792         warn "committing delete volume tree add db session\n";
793
794         OpenILS::Application::AppUtils->commit_db_session($session);
795
796         return scalar(@$volumes);
797
798 }
799
800
801
802
803
804 1;