squashing bugs
[Evergreen.git] / Open-ILS / src / perlmods / OpenILS / Application / Actor.pm
1 package OpenILS::Application::Actor;
2 use base qw/OpenSRF::Application/;
3 use strict; use warnings;
4 use Data::Dumper;
5
6 use OpenSRF::EX qw(:try);
7 use OpenILS::EX;
8
9 use OpenILS::Application::AppUtils;
10 use OpenILS::Utils::Fieldmapper;
11 use OpenILS::Application::Search::Actor;
12
13 my $apputils = "OpenILS::Application::AppUtils";
14 sub _d { warn "Patron:\n" . Dumper(shift()); }
15 my $cache_client = OpenSRF::Utils::Cache->new("global", 0);
16
17
18 __PACKAGE__->register_method(
19         method  => "update_patron",
20         api_name        => "open-ils.actor.patron.update",
21 );
22
23
24 sub update_patron {
25         my( $self, $client, $user_session, $patron ) = @_;
26
27         my $session = $apputils->start_db_session();
28         my $err = undef;
29
30         warn $user_session . " " . $patron . "\n";
31         _d($patron);
32
33         my $user_obj = 
34                 OpenILS::Application::AppUtils->check_user_session( 
35                                 $user_session ); #throws EX on error
36
37         # XXX does this user have permission to add/create users.  Granularity?
38
39         # $new_patron is the patron in progress.  $patron is the original patron
40         # passed in with the method.  new_patron will change as the components
41         # of patron are added/updated.
42
43         my $new_patron;
44
45         #try {
46                 # create/update the patron first so we can use his id
47                 if($patron->isnew()) {
48                         $new_patron = _add_patron(
49                                         $session, _clone_patron($patron));
50                         if(UNIVERSAL::isa($new_patron, "OpenILS::EX")) {
51                                 $client->respond_complete($new_patron->ex);
52                                 return undef;
53                         }
54
55                 } else { 
56                         $new_patron = $patron; 
57                 }
58
59                 $new_patron = _add_update_addresses($session, $patron, $new_patron);
60                 $new_patron = _add_update_cards($session, $patron, $new_patron);
61
62                 if(UNIVERSAL::isa($new_patron,"OpenILS::EX")) {
63                         $client->respond_complete($new_patron->ex);
64                         return undef;
65                 }
66
67                 $new_patron = _add_survey_responses($session, $patron, $new_patron);
68                 $new_patron     = _create_stat_maps($session, $user_session, $patron, $new_patron);
69
70                 # re-update the patron if anything has happened to him during this process
71                 if($new_patron->ischanged()) {
72                         $new_patron = _update_patron($session, $new_patron);
73                 }
74                 $apputils->commit_db_session($session);
75
76 =head
77         } catch Error with { 
78                 my $e = shift;
79                 $err =  "-*- Failure adding user: $e";
80                 $apputils->rollback_db_session($session);
81                 warn $err;
82         };
83
84         if($err) { throw OpenSRF::EX::ERROR ($err); }
85 =cut
86
87         warn "Patron Update/Create complete\n";
88         return flesh_user($new_patron->id());
89 }
90
91
92 __PACKAGE__->register_method(
93         method  => "user_retrieve_fleshed_by_id",
94         api_name        => "open-ils.actor.user.fleshed.retrieve",);
95
96 sub user_retrieve_fleshed_by_id {
97         my( $self, $client, $user_session, $user_id ) = @_;
98         my $user_obj = $apputils->check_user_session( $user_session ); 
99         return flesh_user($user_id);
100 }
101
102
103 sub flesh_user {
104         my $id = shift;
105         my $session = shift;
106
107         my $kill = 0;
108
109         if(!$session) {
110                 $session = OpenSRF::AppSession->create("open-ils.storage");
111                 $kill = 1;
112         }
113
114         # grab the user with the given card
115         my $ureq = $session->request(
116                         "open-ils.storage.direct.actor.user.retrieve",
117                         $id);
118         my $user = $ureq->gather(1);
119
120         # grab the cards
121         my $cards_req = $session->request(
122                         "open-ils.storage.direct.actor.card.search.usr",
123                         $user->id() );
124         $user->cards( $cards_req->gather(1) );
125
126         my $add_req = $session->request(
127                         "open-ils.storage.direct.actor.user_address.search.usr",
128                         $user->id() );
129         $user->addresses( $add_req->gather(1) );
130
131         my $stat_req = $session->request(
132                 "open-ils.storage.direct.actor.stat_cat_entry_user_map.search.target_usr",
133                 $user->id() );
134         $user->stat_cat_entries($stat_req->gather(1));
135
136         if($kill) { $session->disconnect(); }
137         $user->clear_passwd();
138         warn Dumper $user;
139
140         return $user;
141
142 }
143
144
145 # clone and clear stuff that would break the database
146 sub _clone_patron {
147         my $patron = shift;
148
149         my $new_patron = Fieldmapper::actor::user->new();
150
151         my $fmap = $Fieldmapper::fieldmap;
152         no strict; # shallow clone, may be useful in the fieldmapper
153         for my $field 
154                 (keys %{$fmap->{"Fieldmapper::actor::user"}->{'fields'}}) {
155                         $new_patron->$field( $patron->$field() );
156         }
157         use strict;
158
159         # clear these
160         $new_patron->clear_billing_address();
161         $new_patron->clear_mailing_address();
162         $new_patron->clear_addresses();
163         $new_patron->clear_card();
164         $new_patron->clear_cards();
165         $new_patron->clear_id();
166         $new_patron->clear_isnew();
167         $new_patron->clear_changed();
168         $new_patron->clear_deleted();
169         $new_patron->clear_stat_cat_entries();
170
171         return $new_patron;
172 }
173
174
175 sub _add_patron {
176         my $session             = shift;
177         my $patron              = shift;
178
179         warn "Creating new patron\n";
180         _d($patron);
181
182         my $req = $session->request(
183                 "open-ils.storage.direct.actor.user.create",$patron);
184         my $id = $req->gather(1);
185         if(!$id) { 
186                 return OpenILS::EX->new("DUPLICATE_USER_USERNAME");
187         }
188         warn "Created new patron with id $id\n";
189
190         # retrieve the patron from the db to collect defaults
191         my $ureq = $session->request(
192                         "open-ils.storage.direct.actor.user.retrieve",
193                         $id);
194         return $ureq->gather(1);
195 }
196
197
198 sub _update_patron {
199         my( $session, $patron) = @_;
200
201         warn "updating patron " . Dumper($patron) . "\n";
202
203         my $req = $session->request(
204                 "open-ils.storage.direct.actor.user.update",$patron );
205         my $status = $req->gather(1);
206         if(!defined($status)) { 
207                 throw OpenSRF::EX::ERROR 
208                         ("Unknown error updating patron"); 
209         }
210         return $patron;
211 }
212
213
214 sub _add_update_addresses {
215         my $session = shift;
216         my $patron = shift;
217         my $new_patron = shift;
218
219         my $current_id; # id of the address before creation
220
221         for my $address (@{$patron->addresses()}) {
222
223                 $address->usr($new_patron->id());
224
225                 if(ref($address) and $address->isnew()) {
226                         warn "Adding new address at street " . $address->street1() . "\n";
227
228                         $current_id = $address->id();
229                         $address = _add_address($session,$address);
230
231                         if( $patron->billing_address() and 
232                                         $patron->billing_address() == $current_id ) {
233                                 $new_patron->billing_address($address->id());
234                                 $new_patron->ischanged(1);
235                         }
236
237                         if( $patron->mailing_address() and
238                                         $patron->mailing_address() == $current_id ) {
239                                 $new_patron->mailing_address($address->id());
240                                 $new_patron->ischanged(1);
241                         }
242
243                 } elsif( ref($address) and $address->ischanged() ) {
244                         warn "Updating address at street " . $address->street1();
245                         $address->usr($new_patron->id());
246                         _update_address($session,$address);
247
248                 } elsif( ref($address) and $address->isdeleted() ) {
249                         warn "Deleting address at street " . $address->street1();
250
251                         if( $address->id() == $new_patron->mailing_address() ) {
252                                 $new_patron->clear_mailing_address();
253                                 _update_patron($session, $new_patron);
254                         }
255
256                         if( $address->id() == $new_patron->billing_address() ) {
257                                 $new_patron->clear_billing_address();
258                                 _update_patron($session, $new_patron);
259                         }
260
261                         _delete_address($session,$address);
262                 }
263         }
264
265         return $new_patron;
266 }
267
268
269 # adds an address to the db and returns the address with new id
270 sub _add_address {
271         my($session, $address) = @_;
272         $address->clear_id();
273
274         # put the address into the database
275         my $req = $session->request(
276                 "open-ils.storage.direct.actor.user_address.create",
277                 $address );
278
279         #update the id
280         my $id = $req->gather(1);
281         if(!$id) { 
282                 throw OpenSRF::EX::ERROR 
283                         ("Unable to create new user address"); 
284         }
285
286         warn "Created address with id $id\n";
287
288         # update all the necessary id's
289         $address->id( $id );
290         return $address;
291 }
292
293
294 sub _update_address {
295         my( $session, $address ) = @_;
296         my $req = $session->request(
297                 "open-ils.storage.direct.actor.user_address.update",
298                 $address );
299         my $status = $req->gather(1);
300         if(!defined($status)) { 
301                 throw OpenSRF::EX::ERROR 
302                         ("Unknown error updating address"); 
303         }
304         return $address;
305 }
306
307
308
309 sub _add_update_cards {
310
311         my $session = shift;
312         my $patron = shift;
313         my $new_patron = shift;
314
315         my $virtual_id; #id of the card before creation
316         for my $card (@{$patron->cards()}) {
317
318                 $card->usr($new_patron->id());
319
320                 if(ref($card) and $card->isnew()) {
321
322                         $virtual_id = $card->id();
323                         $card = _add_card($session,$card);
324                         if(UNIVERSAL::isa($card,"OpenILS::EX")) {
325                                 return $card;
326                         }
327
328                         if($patron->card() == $virtual_id) {
329                                 $new_patron->card($card->id());
330                                 $new_patron->ischanged(1);
331                         }
332
333                 } elsif( ref($card) and $card->ischanged() ) {
334                         $card->usr($new_patron->id());
335                         _update_card($session, $card);
336                 }
337         }
338         return $new_patron;
339 }
340
341
342 # adds an card to the db and returns the card with new id
343 sub _add_card {
344         my( $session, $card ) = @_;
345         $card->clear_id();
346
347         warn "Adding card with barcode " . $card->barcode() . "\n";
348         my $req = $session->request(
349                 "open-ils.storage.direct.actor.card.create",
350                 $card );
351
352         my $id = $req->gather(1);
353         if(!$id) { 
354                 return OpenILS::EX->new("DUPLICATE_INVALID_USER_BARCODE");
355         }
356
357         $card->id($id);
358         warn "Created patron card with id $id\n";
359         return $card;
360 }
361
362
363 sub _update_card {
364         my( $session, $card ) = @_;
365         warn Dumper $card;
366
367         my $req = $session->request(
368                 "open-ils.storage.direct.actor.card.update",
369                 $card );
370         my $status = $req->gather(1);
371         if(!defined($status)) { 
372                 throw OpenSRF::EX::ERROR 
373                         ("Unknown error updating card"); 
374         }
375         return $card;
376 }
377
378
379
380
381 sub _delete_address {
382         my( $session, $address ) = @_;
383
384         warn "Deleting address " . $address->street1() . "\n";
385
386         my $req = $session->request(
387                 "open-ils.storage.direct.actor.user_address.delete",
388                 $address );
389         my $status = $req->gather(1);
390         if(!defined($status)) { 
391                 throw OpenSRF::EX::ERROR 
392                         ("Unknown error updating address"); 
393         }
394         warn "Delete address status is $status\n";
395 }
396
397
398
399 sub _add_survey_responses {
400         my ($session, $patron, $new_patron) = @_;
401
402         warn "updating responses for user " . $new_patron->id . "\n";
403
404         my $responses = $patron->survey_responses;
405         for my $resp( @$responses ) {
406                 $resp->usr($new_patron->id);
407         }
408
409         my $status = $apputils->simple_scalar_request(
410                 "open-ils.circ", 
411                 "open-ils.circ.survey.submit.user_id",
412                 $responses );
413
414         return $new_patron;
415 }
416
417
418 sub _create_stat_maps {
419
420         my($session, $user_session, $patron, $new_patron) = @_;
421
422         my $maps = $patron->stat_cat_entries();
423
424         for my $map (@$maps) {
425
426                 next unless($map->isnew() || $map->ischanged());
427
428                 my $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.update";
429                 if($map->isnew()) {
430                         $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.create";
431                 }
432
433                 $map->target_usr($new_patron->id);
434
435                 warn "Updating stat entry with method $method and session $user_session and map $map\n";
436
437                 my $req = $session->request($method, $map);
438                 my $status = $req->gather(1);
439
440                 warn "Updated\n";
441
442                 if(!$status) {
443                         throw OpenSRF::EX::ERROR 
444                                 ("Error updating stat map with method $method");        
445                 }
446         }
447
448         return $new_patron;
449 }
450
451
452
453 __PACKAGE__->register_method(
454         method  => "search_username",
455         api_name        => "open-ils.actor.user.search.username",
456 );
457
458 sub search_username {
459         my($self, $client, $username) = @_;
460         my $users = OpenILS::Application::AppUtils->simple_scalar_request(
461                         "open-ils.storage", 
462                         "open-ils.storage.direct.actor.user.search.usrname",
463                         $username );
464         return $users;
465 }
466
467
468
469
470 __PACKAGE__->register_method(
471         method  => "user_retrieve_by_barcode",
472         api_name        => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
473
474 sub user_retrieve_by_barcode {
475         my($self, $client, $user_session, $barcode) = @_;
476         warn "Searching for user with barcode $barcode\n";
477         my $user_obj = $apputils->check_user_session( $user_session ); 
478
479         my $session = OpenSRF::AppSession->create("open-ils.storage");
480
481         # find the card with the given barcode
482         my $creq        = $session->request(
483                         "open-ils.storage.direct.actor.card.search.barcode",
484                         $barcode );
485         my $card = $creq->gather(1);
486         $card = $card->[0];
487         my $user = flesh_user($card->usr(), $session);
488         $session->disconnect();
489         return $user;
490
491 }
492
493
494
495 __PACKAGE__->register_method(
496         method  => "get_user_by_id",
497         api_name        => "open-ils.actor.user.retrieve",);
498
499 sub get_user_by_id {
500         my ($self, $client, $user_session, $id) = @_;
501
502         my $user_obj = $apputils->check_user_session( $user_session ); 
503
504         return $apputils->simple_scalar_request(
505                 "open-ils.storage",
506                 "open-ils.storage.direct.actor.user.retrieve",
507                 $id );
508 }
509
510
511
512 __PACKAGE__->register_method(
513         method  => "get_org_types",
514         api_name        => "open-ils.actor.org_types.retrieve",);
515
516 my $org_types;
517 sub get_org_types {
518         my($self, $client) = @_;
519
520         return $org_types if $org_types;
521          return $org_types = 
522                  $apputils->simple_scalar_request(
523                         "open-ils.storage",
524                         "open-ils.storage.direct.actor.org_unit_type.retrieve.all.atomic" );
525 }
526
527
528
529 __PACKAGE__->register_method(
530         method  => "get_user_profiles",
531         api_name        => "open-ils.actor.user.profiles.retrieve",
532 );
533
534 my $user_profiles;
535 sub get_user_profiles {
536         return $user_profiles if $user_profiles;
537
538         return $user_profiles = 
539                 $apputils->simple_scalar_request(
540                         "open-ils.storage",
541                         "open-ils.storage.direct.actor.profile.retrieve.all.atomic");
542 }
543
544
545
546 __PACKAGE__->register_method(
547         method  => "get_user_ident_types",
548         api_name        => "open-ils.actor.user.ident_types.retrieve",
549 );
550 my $ident_types;
551 sub get_user_ident_types {
552         return $ident_types if $ident_types;
553         return $ident_types = 
554                 $apputils->simple_scalar_request(
555                 "open-ils.storage",
556                 "open-ils.storage.direct.config.identification_type.retrieve.all.atomic" );
557 }
558
559
560
561
562 __PACKAGE__->register_method(
563         method  => "get_org_unit",
564         api_name        => "open-ils.actor.org_unit.retrieve",
565 );
566
567 sub get_org_unit {
568
569         my( $self, $client, $user_session ) = @_;
570
571         my $user_obj = 
572                 OpenILS::Application::AppUtils->check_user_session( $user_session ); #throws EX on error
573
574         my $home_ou = OpenILS::Application::AppUtils->simple_scalar_request(
575                 "open-ils.storage",
576                 "open-ils.storage.direct.actor.org_unit.retrieve", 
577                 $user_obj->home_ou );
578
579         return $home_ou;
580 }
581
582
583 # build the org tree
584
585 __PACKAGE__->register_method(
586         method  => "get_org_tree",
587         api_name        => "open-ils.actor.org_tree.retrieve",
588         argc            => 1, 
589         note            => "Returns the entire org tree structure",
590 );
591
592 sub get_org_tree {
593         my( $self, $client) = @_;
594
595         # see if it's in the cache
596         warn "Getting ORG Tree\n";
597         my $tree = $cache_client->get_cache('orgtree');
598         if($tree) { 
599                 warn "Found orgtree in cache. returning...\n";
600                 return $tree; 
601         }
602
603         my $orglist = $apputils->simple_scalar_request( 
604                 "open-ils.storage", 
605                 "open-ils.storage.direct.actor.org_unit.retrieve.all.atomic" );
606
607         $tree = $self->build_org_tree($orglist);
608         $cache_client->put_cache('orgtree', $tree);
609
610         return $tree;
611
612 }
613
614 # turns an org list into an org tree
615 sub build_org_tree {
616
617         my( $self, $orglist) = @_;
618
619         return $orglist unless ( 
620                         ref($orglist) and @$orglist > 1 );
621
622         my @list = sort { 
623                 $a->ou_type <=> $b->ou_type ||
624                 $a->name cmp $b->name } @$orglist;
625
626         for my $org (@list) {
627
628                 next unless ($org and defined($org->parent_ou));
629                 my ($parent) = grep { $_->id == $org->parent_ou } @list;
630                 next unless $parent;
631
632                 $parent->children([]) unless defined($parent->children); 
633                 push( @{$parent->children}, $org );
634         }
635
636         return $list[0];
637
638 }
639
640
641 __PACKAGE__->register_method(
642         method  => "get_org_descendants",
643         api_name        => "open-ils.actor.org_tree.descendants.retrieve"
644 );
645
646 # depth is optional.  org_unit is the id
647 sub get_org_descendants {
648         my( $self, $client, $org_unit, $depth ) = @_;
649         my $orglist = $apputils->simple_scalar_request(
650                         "open-ils.storage", 
651                         "open-ils.storage.actor.org_unit.descendants.atomic",
652                         $org_unit, $depth );
653         return $self->build_org_tree($orglist);
654 }
655
656
657 __PACKAGE__->register_method(
658         method  => "get_org_ancestors",
659         api_name        => "open-ils.actor.org_tree.ancestors.retrieve"
660 );
661
662 # depth is optional.  org_unit is the id
663 sub get_org_ancestors {
664         my( $self, $client, $org_unit, $depth ) = @_;
665         my $orglist = $apputils->simple_scalar_request(
666                         "open-ils.storage", 
667                         "open-ils.storage.actor.org_unit.ancestors.atomic",
668                         $org_unit, $depth );
669         return $self->build_org_tree($orglist);
670 }
671
672
673 __PACKAGE__->register_method(
674         method  => "get_standings",
675         api_name        => "open-ils.actor.standings.retrieve"
676 );
677
678 my $user_standings;
679 sub get_standings {
680         return $user_standings if $user_standings;
681         return $user_standings = 
682                 $apputils->simple_scalar_request(
683                         "open-ils.storage",
684                         "open-ils.storage.direct.config.standing.retrieve.all.atomic" );
685 }
686
687
688
689 __PACKAGE__->register_method(
690         method  => "get_my_org_path",
691         api_name        => "open-ils.actor.org_unit.full_path.retrieve"
692 );
693
694 sub get_my_org_path {
695         my( $self, $client, $user_session, $org_id ) = @_;
696         my $user_obj = $apputils->check_user_session($user_session); 
697         if(!defined($org_id)) { $org_id = $user_obj->home_ou; }
698
699         return $apputils->simple_scalar_request(
700                 "open-ils.storage",
701                 "open-ils.storage.actor.org_unit.full_path.atomic",
702                 $org_id );
703 }
704
705
706 __PACKAGE__->register_method(
707         method  => "patron_adv_search",
708         api_name        => "open-ils.actor.patron.search.advanced" );
709
710 sub patron_adv_search {
711         my( $self, $client, $staff_login, $search_hash ) = @_;
712
713         use Data::Dumper;
714         warn "patron adv with $staff_login and search " . 
715                 Dumper($search_hash) . "\n";
716
717         my $session = OpenSRF::AppSession->create("open-ils.storage");
718         my $req = $session->request(
719                 "open-ils.storage.actor.user.crazy_search", $search_hash);
720
721         my $ans = $req->gather(1);
722         $session->disconnect();
723         return $ans;
724
725 }
726
727
728
729
730
731
732
733
734 1;
735
736
737
738
739 __END__
740
741
742 some old methods that may be good to keep around for now
743
744 sub _delete_card {
745         my( $session, $card ) = @_;
746
747         warn "Deleting card with barcode " . $card->barcode() . "\n";
748         my $req = $session->request(
749                 "open-ils.storage.direct.actor.card.delete",
750                 $card );
751         my $status = $req->gather(1);
752         if(!defined($status)) { 
753                 throw OpenSRF::EX::ERROR 
754                         ("Unknown error updating card"); 
755         }
756 }
757
758
759
760 # deletes the patron and any attached addresses and cards
761 __PACKAGE__->register_method(
762         method  => "delete_patron",
763         api_name        => "open-ils.actor.patron.delete",
764 );
765
766 sub delete_patron {
767
768         my( $self, $client, $patron ) = @_;
769         my $session = $apputils->start_db_session();
770         my $err = undef;
771
772         try {
773
774                 $patron->clear_mailing_address();
775                 $patron->clear_billing_address();
776                 $patron->ischanged(1);
777
778                 _update_patron($session, $patron);
779                 _delete_address($session,$_) for (@{$patron->addresses()});
780                 _delete_card($session,$_) for (@{$patron->cards()});
781                 _delete_patron($session,$patron);
782                 $apputils->commit_db_session($session);
783
784         } catch Error with {
785                 my $e = shift;
786                 $err =  "-*- Failure deleting user: $e";
787                 $apputils->rollback_db_session($session);
788                 warn $err;
789         };
790
791         if($err) { throw OpenSRF::EX::ERROR ($err); }
792         warn "Patron Delete complete\n";
793         return 1;
794 }
795
796 sub _delete_patron {
797         my( $session, $patron ) = @_;
798
799         warn "Deleting patron " . $patron->usrname() . "\n";
800
801         my $req = $session->request(
802                 "open-ils.storage.direct.actor.user.delete",
803                 $patron );
804         my $status = $req->gather(1);
805         if(!defined($status)) { 
806                 throw OpenSRF::EX::ERROR 
807                         ("Unknown error updating patron"); 
808         }
809 }
810