movin on, adding exceptions, more more more
[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 Digest::MD5 qw(md5_hex);
7
8 use OpenSRF::EX qw(:try);
9 use OpenILS::EX;
10
11 use OpenILS::Application::AppUtils;
12 use OpenILS::Utils::Fieldmapper;
13 use OpenILS::Application::Search::Actor;
14 use OpenILS::Utils::ModsParser;
15
16 my $apputils = "OpenILS::Application::AppUtils";
17 sub _d { warn "Patron:\n" . Dumper(shift()); }
18 my $cache_client = OpenSRF::Utils::Cache->new("global", 0);
19
20
21 __PACKAGE__->register_method(
22         method  => "update_patron",
23         api_name        => "open-ils.actor.patron.update",);
24
25 sub update_patron {
26         my( $self, $client, $user_session, $patron ) = @_;
27
28         my $session = $apputils->start_db_session();
29         my $err = undef;
30
31         warn $user_session . " " . $patron . "\n";
32         _d($patron);
33
34         my $user_obj = 
35                 OpenILS::Application::AppUtils->check_user_session( 
36                                 $user_session ); #throws EX on error
37
38         # XXX does this user have permission to add/create users.  Granularity?
39
40         # $new_patron is the patron in progress.  $patron is the original patron
41         # passed in with the method.  new_patron will change as the components
42         # of patron are added/updated.
43
44         my $new_patron;
45
46         if(ref($patron->card)) { $patron->card( $patron->card->id ); }
47         if(ref($patron->billing_address)) { $patron->billing_address( $patron->billing_address->id ); }
48         if(ref($patron->mailing_address)) { $patron->mailing_address( $patron->mailing_address->id ); }
49
50         # create/update the patron first so we can use his id
51         if($patron->isnew()) {
52
53                 $new_patron = _add_patron($session, _clone_patron($patron), $user_obj);
54
55                 if(UNIVERSAL::isa($new_patron, "OpenILS::EX") || 
56                         UNIVERSAL::isa($new_patron, "OpenILS::Perm")) {
57                         $client->respond_complete($new_patron->ex);
58                         return undef;
59                 }
60
61         } else { $new_patron = $patron; }
62
63         $new_patron = _add_update_addresses($session, $patron, $new_patron, $user_obj);
64
65         if(UNIVERSAL::isa($new_patron, "OpenILS::EX") || 
66                 UNIVERSAL::isa($new_patron, "OpenILS::Perm")) {
67                 $client->respond_complete($new_patron->ex);
68                 return undef;
69         }
70
71         $new_patron = _add_update_cards($session, $patron, $new_patron, $user_obj);
72
73         if(UNIVERSAL::isa($new_patron, "OpenILS::EX") || 
74                 UNIVERSAL::isa($new_patron, "OpenILS::Perm")) {
75                 $client->respond_complete($new_patron->ex);
76                 return undef;
77         }
78
79         $new_patron = _add_survey_responses($session, $patron, $new_patron, $user_obj);
80         if(UNIVERSAL::isa($new_patron, "OpenILS::EX") || 
81                 UNIVERSAL::isa($new_patron, "OpenILS::Perm")) {
82                 $client->respond_complete($new_patron->ex);
83                 return undef;
84         }
85
86         $new_patron     = _create_stat_maps($session, $user_session, $patron, $new_patron, $user_obj);
87         if(UNIVERSAL::isa($new_patron, "OpenILS::EX") || 
88                 UNIVERSAL::isa($new_patron, "OpenILS::Perm")) {
89                 $client->respond_complete($new_patron->ex);
90                 return undef;
91         }
92
93
94         # re-update the patron if anything has happened to him during this process
95         if($new_patron->ischanged()) {
96                 $new_patron = _update_patron($session, $new_patron, $user_obj);
97
98                 if(UNIVERSAL::isa($new_patron, "OpenILS::EX") || 
99                         UNIVERSAL::isa($new_patron, "OpenILS::Perm")) {
100                         $client->respond_complete($new_patron->ex);
101                         return undef;
102                 }
103         }
104         $apputils->commit_db_session($session);
105
106         warn "Patron Update/Create complete\n";
107         return flesh_user($new_patron->id());
108 }
109
110
111
112
113 __PACKAGE__->register_method(
114         method  => "user_retrieve_fleshed_by_id",
115         api_name        => "open-ils.actor.user.fleshed.retrieve",);
116
117 sub user_retrieve_fleshed_by_id {
118         my( $self, $client, $user_session, $user_id ) = @_;
119         my $user_obj = $apputils->check_user_session( $user_session ); 
120
121         if($apputils->check_user_perms($user_obj->id, $user_obj->home_ou, "VIEW_USER")) {
122                 return OpenILS::Perm->new("VIEW_USER");
123         }
124
125         return flesh_user($user_id);
126 }
127
128
129 sub flesh_user {
130         my $id = shift;
131         my $session = shift;
132
133         my $kill = 0;
134
135         if(!$session) {
136                 $session = OpenSRF::AppSession->create("open-ils.storage");
137                 $kill = 1;
138         }
139
140         # grab the user with the given id 
141         my $ureq = $session->request(
142                         "open-ils.storage.direct.actor.user.retrieve", $id);
143         my $user = $ureq->gather(1);
144
145         if(!$user) { return undef; }
146
147         # grab the cards
148         my $cards_req = $session->request(
149                         "open-ils.storage.direct.actor.card.search.usr.atomic",
150                         $user->id() );
151         $user->cards( $cards_req->gather(1) );
152
153         for my $c(@{$user->cards}) {
154                 if($c->id == $user->card || $c->id eq $user->card ) {
155                         warn "Setting my card to " . $c->id . "\n";
156                         $user->card($c);
157                 }
158         }
159
160         my $add_req = $session->request(
161                         "open-ils.storage.direct.actor.user_address.search.usr.atomic",
162                         $user->id() );
163         $user->addresses( $add_req->gather(1) );
164
165         for my $c(@{$user->addresses}) {
166                 if($c->id == $user->billing_address || $c->id eq $user->billing_address ) {
167                         warn "Setting my address to " . $c->id . "\n";
168                         $user->billing_address($c);
169                 }
170         }
171
172         for my $c(@{$user->addresses}) {
173                 if($c->id == $user->mailing_address || $c->id eq $user->mailing_address ) {
174                         warn "Setting my address to " . $c->id . "\n";
175                         $user->mailing_address($c);
176                 }
177         }
178
179         my $stat_req = $session->request(
180                 "open-ils.storage.direct.actor.stat_cat_entry_user_map.search.target_usr.atomic",
181                 $user->id() );
182         $user->stat_cat_entries($stat_req->gather(1));
183
184         if($kill) { $session->disconnect(); }
185         $user->clear_passwd();
186         warn Dumper $user;
187
188         return $user;
189
190 }
191
192
193 # clone and clear stuff that would break the database
194 sub _clone_patron {
195         my $patron = shift;
196
197         my $new_patron = Fieldmapper::actor::user->new();
198
199         my $fmap = $Fieldmapper::fieldmap;
200         no strict; # shallow clone, may be useful in the fieldmapper
201         for my $field 
202                 (keys %{$fmap->{"Fieldmapper::actor::user"}->{'fields'}}) {
203                         $new_patron->$field( $patron->$field() );
204         }
205         use strict;
206
207         # clear these
208         $new_patron->clear_billing_address();
209         $new_patron->clear_mailing_address();
210         $new_patron->clear_addresses();
211         $new_patron->clear_card();
212         $new_patron->clear_cards();
213         $new_patron->clear_id();
214         $new_patron->clear_isnew();
215         $new_patron->clear_changed();
216         $new_patron->clear_deleted();
217         $new_patron->clear_stat_cat_entries();
218
219         return $new_patron;
220 }
221
222
223 sub _add_patron {
224         my $session             = shift;
225         my $patron              = shift;
226         my $user_obj    = shift;
227
228
229         if($apputils->check_user_perms(
230                                 $user_obj->id, $user_obj->home_ou, "CREATE_USER")) {
231                 return OpenILS::Perm->new("CREATE_USER");
232         }
233
234         warn "Creating new patron\n";
235         _d($patron);
236
237         my $req = $session->request(
238                 "open-ils.storage.direct.actor.user.create",$patron);
239         my $id = $req->gather(1);
240         if(!$id) { 
241                 return OpenILS::EX->new("DUPLICATE_USER_USERNAME");
242         }
243
244         # retrieve the patron from the db to collect defaults
245         my $ureq = $session->request(
246                         "open-ils.storage.direct.actor.user.retrieve",
247                         $id);
248
249         warn "Created new patron with id $id\n";
250
251         return $ureq->gather(1);
252 }
253
254
255 sub _update_patron {
256         my( $session, $patron, $user_obj) = @_;
257
258
259         if($apputils->check_user_perms(
260                                 $user_obj->id, $user_obj->home_ou, "UPDATE_USER")) {
261                 return OpenILS::Perm->new("UPDATE_USER");
262         }
263
264         warn "updating patron " . Dumper($patron) . "\n";
265
266         my $req = $session->request(
267                 "open-ils.storage.direct.actor.user.update",$patron );
268         my $status = $req->gather(1);
269         if(!defined($status)) { 
270                 throw OpenSRF::EX::ERROR 
271                         ("Unknown error updating patron"); 
272         }
273         return $patron;
274 }
275
276
277 sub _add_update_addresses {
278         my $session = shift;
279         my $patron = shift;
280         my $new_patron = shift;
281
282         my $current_id; # id of the address before creation
283
284         for my $address (@{$patron->addresses()}) {
285
286                 $address->usr($new_patron->id());
287
288                 if(ref($address) and $address->isnew()) {
289                         warn "Adding new address at street " . $address->street1() . "\n";
290
291                         $current_id = $address->id();
292                         $address = _add_address($session,$address);
293
294                         if( $patron->billing_address() and 
295                                         $patron->billing_address() == $current_id ) {
296                                 $new_patron->billing_address($address->id());
297                                 $new_patron->ischanged(1);
298                         }
299
300                         if( $patron->mailing_address() and
301                                         $patron->mailing_address() == $current_id ) {
302                                 $new_patron->mailing_address($address->id());
303                                 $new_patron->ischanged(1);
304                         }
305
306                 } elsif( ref($address) and $address->ischanged() ) {
307                         warn "Updating address at street " . $address->street1();
308                         $address->usr($new_patron->id());
309                         _update_address($session,$address);
310
311                 } elsif( ref($address) and $address->isdeleted() ) {
312                         warn "Deleting address at street " . $address->street1();
313
314                         if( $address->id() == $new_patron->mailing_address() ) {
315                                 $new_patron->clear_mailing_address();
316                                 _update_patron($session, $new_patron);
317                         }
318
319                         if( $address->id() == $new_patron->billing_address() ) {
320                                 $new_patron->clear_billing_address();
321                                 _update_patron($session, $new_patron);
322                         }
323
324                         _delete_address($session,$address);
325                 }
326         }
327
328         return $new_patron;
329 }
330
331
332 # adds an address to the db and returns the address with new id
333 sub _add_address {
334         my($session, $address) = @_;
335         $address->clear_id();
336
337         # put the address into the database
338         my $req = $session->request(
339                 "open-ils.storage.direct.actor.user_address.create",
340                 $address );
341
342         #update the id
343         my $id = $req->gather(1);
344         if(!$id) { 
345                 throw OpenSRF::EX::ERROR 
346                         ("Unable to create new user address"); 
347         }
348
349         warn "Created address with id $id\n";
350
351         # update all the necessary id's
352         $address->id( $id );
353         return $address;
354 }
355
356
357 sub _update_address {
358         my( $session, $address ) = @_;
359         my $req = $session->request(
360                 "open-ils.storage.direct.actor.user_address.update",
361                 $address );
362         my $status = $req->gather(1);
363         if(!defined($status)) { 
364                 throw OpenSRF::EX::ERROR 
365                         ("Unknown error updating address"); 
366         }
367         return $address;
368 }
369
370
371
372 sub _add_update_cards {
373
374         my $session = shift;
375         my $patron = shift;
376         my $new_patron = shift;
377
378         my $virtual_id; #id of the card before creation
379         for my $card (@{$patron->cards()}) {
380
381                 $card->usr($new_patron->id());
382
383                 if(ref($card) and $card->isnew()) {
384
385                         $virtual_id = $card->id();
386                         $card = _add_card($session,$card);
387                         if(UNIVERSAL::isa($card,"OpenILS::EX")) {
388                                 return $card;
389                         }
390
391                         #if(ref($patron->card)) { $patron->card($patron->card->id); }
392                         if($patron->card() == $virtual_id) {
393                                 $new_patron->card($card->id());
394                                 $new_patron->ischanged(1);
395                         }
396
397                 } elsif( ref($card) and $card->ischanged() ) {
398                         $card->usr($new_patron->id());
399                         _update_card($session, $card);
400                 }
401         }
402         return $new_patron;
403 }
404
405
406 # adds an card to the db and returns the card with new id
407 sub _add_card {
408         my( $session, $card ) = @_;
409         $card->clear_id();
410
411         warn "Adding card with barcode " . $card->barcode() . "\n";
412         my $req = $session->request(
413                 "open-ils.storage.direct.actor.card.create",
414                 $card );
415
416         my $id = $req->gather(1);
417         if(!$id) { 
418                 return OpenILS::EX->new("DUPLICATE_INVALID_USER_BARCODE");
419         }
420
421         $card->id($id);
422         warn "Created patron card with id $id\n";
423         return $card;
424 }
425
426
427 sub _update_card {
428         my( $session, $card ) = @_;
429         warn Dumper $card;
430
431         my $req = $session->request(
432                 "open-ils.storage.direct.actor.card.update",
433                 $card );
434         my $status = $req->gather(1);
435         if(!defined($status)) { 
436                 throw OpenSRF::EX::ERROR 
437                         ("Unknown error updating card"); 
438         }
439         return $card;
440 }
441
442
443
444
445 sub _delete_address {
446         my( $session, $address ) = @_;
447
448         warn "Deleting address " . $address->street1() . "\n";
449
450         my $req = $session->request(
451                 "open-ils.storage.direct.actor.user_address.delete",
452                 $address );
453         my $status = $req->gather(1);
454         if(!defined($status)) { 
455                 throw OpenSRF::EX::ERROR 
456                         ("Unknown error updating address"); 
457         }
458         warn "Delete address status is $status\n";
459 }
460
461
462
463 sub _add_survey_responses {
464         my ($session, $patron, $new_patron) = @_;
465
466         warn "updating responses for user " . $new_patron->id . "\n";
467
468         my $responses = $patron->survey_responses;
469
470         if($responses) {
471
472                 for my $resp( @$responses ) {
473                         $resp->usr($new_patron->id);
474                 }
475
476                 my $status = $apputils->simple_scalar_request(
477                         "open-ils.circ", 
478                         "open-ils.circ.survey.submit.user_id",
479                         $responses );
480
481         }
482
483         return $new_patron;
484 }
485
486
487 sub _create_stat_maps {
488
489         my($session, $user_session, $patron, $new_patron) = @_;
490
491         my $maps = $patron->stat_cat_entries();
492
493         for my $map (@$maps) {
494
495                 next unless($map->isnew() || $map->ischanged());
496
497                 my $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.update";
498                 if($map->isnew()) {
499                         $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.create";
500                 }
501
502                 $map->target_usr($new_patron->id);
503
504                 warn "Updating stat entry with method $method and session $user_session and map $map\n";
505
506                 my $req = $session->request($method, $map);
507                 my $status = $req->gather(1);
508
509                 warn "Updated\n";
510
511                 if(!$status) {
512                         throw OpenSRF::EX::ERROR 
513                                 ("Error updating stat map with method $method");        
514                 }
515         }
516
517         return $new_patron;
518 }
519
520
521
522 __PACKAGE__->register_method(
523         method  => "search_username",
524         api_name        => "open-ils.actor.user.search.username",
525 );
526
527 sub search_username {
528         my($self, $client, $username) = @_;
529         my $users = OpenILS::Application::AppUtils->simple_scalar_request(
530                         "open-ils.storage", 
531                         "open-ils.storage.direct.actor.user.search.usrname.atomic",
532                         $username );
533         return $users;
534 }
535
536
537
538
539 __PACKAGE__->register_method(
540         method  => "user_retrieve_by_barcode",
541         api_name        => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
542
543 sub user_retrieve_by_barcode {
544         my($self, $client, $user_session, $barcode) = @_;
545         warn "Searching for user with barcode $barcode\n";
546         my $user_obj = $apputils->check_user_session( $user_session ); 
547
548         my $session = OpenSRF::AppSession->create("open-ils.storage");
549
550         # find the card with the given barcode
551         my $creq        = $session->request(
552                         "open-ils.storage.direct.actor.card.search.barcode.atomic",
553                         $barcode );
554         my $card = $creq->gather(1);
555
556         if(!$card || !$card->[0]) {
557                 $session->disconnect();
558                 return undef;
559         }
560
561         $card = $card->[0];
562         my $user = flesh_user($card->usr(), $session);
563         $session->disconnect();
564         return $user;
565
566 }
567
568
569
570 __PACKAGE__->register_method(
571         method  => "get_user_by_id",
572         api_name        => "open-ils.actor.user.retrieve",);
573
574 sub get_user_by_id {
575         my ($self, $client, $user_session, $id) = @_;
576
577         my $user_obj = $apputils->check_user_session( $user_session ); 
578
579         return $apputils->simple_scalar_request(
580                 "open-ils.storage",
581                 "open-ils.storage.direct.actor.user.retrieve",
582                 $id );
583 }
584
585
586
587 __PACKAGE__->register_method(
588         method  => "get_org_types",
589         api_name        => "open-ils.actor.org_types.retrieve",);
590
591 my $org_types;
592 sub get_org_types {
593         my($self, $client) = @_;
594
595         return $org_types if $org_types;
596          return $org_types = 
597                  $apputils->simple_scalar_request(
598                         "open-ils.storage",
599                         "open-ils.storage.direct.actor.org_unit_type.retrieve.all.atomic" );
600 }
601
602
603
604 __PACKAGE__->register_method(
605         method  => "get_user_profiles",
606         api_name        => "open-ils.actor.user.profiles.retrieve",
607 );
608
609 my $user_profiles;
610 sub get_user_profiles {
611         return $user_profiles if $user_profiles;
612
613         return $user_profiles = 
614                 $apputils->simple_scalar_request(
615                         "open-ils.storage",
616                         "open-ils.storage.direct.actor.profile.retrieve.all.atomic");
617 }
618
619
620
621 __PACKAGE__->register_method(
622         method  => "get_user_ident_types",
623         api_name        => "open-ils.actor.user.ident_types.retrieve",
624 );
625 my $ident_types;
626 sub get_user_ident_types {
627         return $ident_types if $ident_types;
628         return $ident_types = 
629                 $apputils->simple_scalar_request(
630                 "open-ils.storage",
631                 "open-ils.storage.direct.config.identification_type.retrieve.all.atomic" );
632 }
633
634
635
636
637 __PACKAGE__->register_method(
638         method  => "get_org_unit",
639         api_name        => "open-ils.actor.org_unit.retrieve",
640 );
641
642 sub get_org_unit {
643
644         my( $self, $client, $user_session, $org_id ) = @_;
645
646         if(defined($user_session) && !defined($org_id)) {
647                 my $user_obj = 
648                         OpenILS::Application::AppUtils->check_user_session( $user_session ); #throws EX on error
649                 if(!defined($org_id)) {
650                         $org_id = $user_obj->home_ou;
651                 }
652         }
653
654
655         my $home_ou = OpenILS::Application::AppUtils->simple_scalar_request(
656                 "open-ils.storage",
657                 "open-ils.storage.direct.actor.org_unit.retrieve", 
658                 $org_id );
659
660         return $home_ou;
661 }
662
663
664 # build the org tree
665
666 __PACKAGE__->register_method(
667         method  => "get_org_tree",
668         api_name        => "open-ils.actor.org_tree.retrieve",
669         argc            => 1, 
670         note            => "Returns the entire org tree structure",
671 );
672
673 sub get_org_tree {
674         my( $self, $client) = @_;
675
676         # see if it's in the cache
677         warn "Getting ORG Tree\n";
678         my $tree = $cache_client->get_cache('orgtree');
679         if($tree) { 
680                 warn "Found orgtree in cache. returning...\n";
681                 return $tree; 
682         }
683
684         my $orglist = $apputils->simple_scalar_request( 
685                 "open-ils.storage", 
686                 "open-ils.storage.direct.actor.org_unit.retrieve.all.atomic" );
687
688         if($orglist) {
689                 warn "found org list\n";
690         }
691
692         $tree = $self->build_org_tree($orglist);
693         $cache_client->put_cache('orgtree', $tree);
694
695         return $tree;
696
697 }
698
699 # turns an org list into an org tree
700 sub build_org_tree {
701
702         my( $self, $orglist) = @_;
703
704         return $orglist unless ( 
705                         ref($orglist) and @$orglist > 1 );
706
707         my @list = sort { 
708                 $a->ou_type <=> $b->ou_type ||
709                 $a->name cmp $b->name } @$orglist;
710
711         for my $org (@list) {
712
713                 next unless ($org and defined($org->parent_ou));
714                 my ($parent) = grep { $_->id == $org->parent_ou } @list;
715                 next unless $parent;
716
717                 $parent->children([]) unless defined($parent->children); 
718                 push( @{$parent->children}, $org );
719         }
720
721         return $list[0];
722
723 }
724
725
726 __PACKAGE__->register_method(
727         method  => "get_org_descendants",
728         api_name        => "open-ils.actor.org_tree.descendants.retrieve"
729 );
730
731 # depth is optional.  org_unit is the id
732 sub get_org_descendants {
733         my( $self, $client, $org_unit, $depth ) = @_;
734         my $orglist = $apputils->simple_scalar_request(
735                         "open-ils.storage", 
736                         "open-ils.storage.actor.org_unit.descendants.atomic",
737                         $org_unit, $depth );
738         return $self->build_org_tree($orglist);
739 }
740
741
742 __PACKAGE__->register_method(
743         method  => "get_org_ancestors",
744         api_name        => "open-ils.actor.org_tree.ancestors.retrieve"
745 );
746
747 # depth is optional.  org_unit is the id
748 sub get_org_ancestors {
749         my( $self, $client, $org_unit, $depth ) = @_;
750         my $orglist = $apputils->simple_scalar_request(
751                         "open-ils.storage", 
752                         "open-ils.storage.actor.org_unit.ancestors.atomic",
753                         $org_unit, $depth );
754         return $self->build_org_tree($orglist);
755 }
756
757
758 __PACKAGE__->register_method(
759         method  => "get_standings",
760         api_name        => "open-ils.actor.standings.retrieve"
761 );
762
763 my $user_standings;
764 sub get_standings {
765         return $user_standings if $user_standings;
766         return $user_standings = 
767                 $apputils->simple_scalar_request(
768                         "open-ils.storage",
769                         "open-ils.storage.direct.config.standing.retrieve.all.atomic" );
770 }
771
772
773
774 __PACKAGE__->register_method(
775         method  => "get_my_org_path",
776         api_name        => "open-ils.actor.org_unit.full_path.retrieve"
777 );
778
779 sub get_my_org_path {
780         my( $self, $client, $user_session, $org_id ) = @_;
781         my $user_obj = $apputils->check_user_session($user_session); 
782         if(!defined($org_id)) { $org_id = $user_obj->home_ou; }
783
784         return $apputils->simple_scalar_request(
785                 "open-ils.storage",
786                 "open-ils.storage.actor.org_unit.full_path.atomic",
787                 $org_id );
788 }
789
790
791 __PACKAGE__->register_method(
792         method  => "patron_adv_search",
793         api_name        => "open-ils.actor.patron.search.advanced" );
794
795 sub patron_adv_search {
796         my( $self, $client, $staff_login, $search_hash ) = @_;
797
798         use Data::Dumper;
799         warn "patron adv with $staff_login and search " . 
800                 Dumper($search_hash) . "\n";
801
802         my $session = OpenSRF::AppSession->create("open-ils.storage");
803         my $req = $session->request(
804                 "open-ils.storage.actor.user.crazy_search", $search_hash);
805
806         my $ans = $req->gather(1);
807
808         my %hash = map { ($_ =>1) } @$ans;
809         $ans = [ keys %hash ];
810
811         warn "Returning @$ans\n";
812
813         $session->disconnect();
814         return $ans;
815
816 }
817
818
819
820 sub _verify_password {
821         my($user_session, $password) = @_;
822         my $user_obj = $apputils->check_user_session($user_session); 
823
824         #grab the user with password
825         $user_obj = $apputils->simple_scalar_request(
826                 "open-ils.storage", 
827                 "open-ils.storage.direct.actor.user.retrieve",
828                 $user_obj->id );
829
830         if($user_obj->passwd eq $password) {
831                 return 1;
832         }
833
834         return 0;
835 }
836
837
838 __PACKAGE__->register_method(
839         method  => "update_password",
840         api_name        => "open-ils.actor.user.password.update");
841
842 __PACKAGE__->register_method(
843         method  => "update_password",
844         api_name        => "open-ils.actor.user.username.update");
845
846 __PACKAGE__->register_method(
847         method  => "update_password",
848         api_name        => "open-ils.actor.user.email.update");
849
850 sub update_password {
851         my( $self, $client, $user_session, $new_value, $current_password ) = @_;
852
853         warn "Updating user with method " .$self->api_name . "\n";
854         my $user_obj = $apputils->check_user_session($user_session); 
855
856         if($self->api_name =~ /password/) {
857
858                 #make sure they know the current password
859                 if(!_verify_password($user_session, md5_hex($current_password))) {
860                         return OpenILS::EX->new("USER_WRONG_PASSWORD")->ex;
861                 }
862
863                 $user_obj->passwd($new_value);
864         } 
865         elsif($self->api_name =~ /username/) {
866                 $user_obj->usrname($new_value);
867         }
868
869         elsif($self->api_name =~ /email/) {
870                 warn "Updating email to $new_value\n";
871                 $user_obj->email($new_value);
872         }
873
874         my $session = $apputils->start_db_session();
875         $user_obj = _update_patron($session, $user_obj);
876         $apputils->commit_db_session($session);
877
878         if($user_obj) { return 1; }
879         return undef;
880 }
881
882
883 __PACKAGE__->register_method(
884         method  => "check_user_perms",
885         api_name        => "open-ils.actor.user.perm.check",
886         notes           => <<"  NOTES");
887         Takes a login session, user id, an org id, and an array of perm type strings.  For each
888         perm type, if the user does *not* have the given permission it is added
889         to a list which is returned from the method.  If all permissions
890         are allowed, an empty list is returned
891         if the logged in user does not match 'user_id', then the logged in user must
892         have VIEW_PERMISSION priveleges.
893         NOTES
894
895 sub check_user_perms {
896         my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
897         my $user_obj = $apputils->check_user_session($login_session); 
898
899         if($user_obj->id ne $user_id) {
900                 if($apputils->check_user_perms($user_obj->id, $org_id, "VIEW_PERMISSION")) {
901                         return OpenILS::Perm->new("VIEW_PERMISSION");
902                 }
903         }
904
905         my @not_allowed;
906         for my $perm (@$perm_types) {
907                 if($apputils->check_user_perms($user_id, $org_id, $perm)) {
908                         push @not_allowed, $perm;
909                 }
910         }
911
912         return \@not_allowed
913 }
914
915
916
917 __PACKAGE__->register_method(
918         method  => "user_fines_summary",
919         api_name        => "open-ils.actor.user.fines.summary",
920         notes           => <<"  NOTES");
921         Returns a short summary of the users total open fines, excluding voided fines
922         Params are login_session, user_id
923         Returns a 'mus' object.
924         NOTES
925
926 sub user_fines_summary {
927         my( $self, $client, $login_session, $user_id ) = @_;
928
929         my $user_obj = $apputils->check_user_session($login_session); 
930         if($user_obj->id ne $user_id) {
931                 if($apputils->check_user_perms($user_obj->id, $user_obj->home_ou, "VIEW_USER_FINES_SUMMARY")) {
932                         return OpenILS::Perm->new("VIEW_USER_FINES_SUMMARY"); 
933                 }
934         }
935
936         return $apputils->simple_scalar_request( 
937                 "open-ils.storage",
938                 "open-ils.storage.direct.money.user_summary.search.usr",
939                 $user_id );
940
941 }
942
943
944
945
946 __PACKAGE__->register_method(
947         method  => "user_transactions",
948         api_name        => "open-ils.actor.user.transactions",
949         notes           => <<"  NOTES");
950         Returns a list of open user transactions (mbts objects);
951         Params are login_session, user_id
952         Optional third parameter is the transactions type.  defaults to all
953         NOTES
954
955 __PACKAGE__->register_method(
956         method  => "user_transactions",
957         api_name        => "open-ils.actor.user.transactions.have_charge",
958         notes           => <<"  NOTES");
959         Returns a list of all open user transactions (mbts objects) that have an initial charge
960         Params are login_session, user_id
961         Optional third parameter is the transactions type.  defaults to all
962         NOTES
963
964 __PACKAGE__->register_method(
965         method  => "user_transactions",
966         api_name        => "open-ils.actor.user.transactions.have_balance",
967         notes           => <<"  NOTES");
968         Returns a list of all open user transactions (mbts objects) that have a balance
969         Params are login_session, user_id
970         Optional third parameter is the transactions type.  defaults to all
971         NOTES
972
973 __PACKAGE__->register_method(
974         method  => "user_transactions",
975         api_name        => "open-ils.actor.user.transactions.fleshed",
976         notes           => <<"  NOTES");
977         Returns an object/hash of transaction, circ, title where transaction = an open 
978         user transactions (mbts objects), circ is the attached circluation, and title
979         is the title the circ points to
980         Params are login_session, user_id
981         Optional third parameter is the transactions type.  defaults to all
982         NOTES
983
984 __PACKAGE__->register_method(
985         method  => "user_transactions",
986         api_name        => "open-ils.actor.user.transactions.have_charge.fleshed",
987         notes           => <<"  NOTES");
988         Returns an object/hash of transaction, circ, title where transaction = an open 
989         user transactions that has an initial charge (mbts objects), circ is the 
990         attached circluation, and title is the title the circ points to
991         Params are login_session, user_id
992         Optional third parameter is the transactions type.  defaults to all
993         NOTES
994
995 __PACKAGE__->register_method(
996         method  => "user_transactions",
997         api_name        => "open-ils.actor.user.transactions.have_balance.fleshed",
998         notes           => <<"  NOTES");
999         Returns an object/hash of transaction, circ, title where transaction = an open 
1000         user transaction that has a balance (mbts objects), circ is the attached 
1001         circluation, and title is the title the circ points to
1002         Params are login_session, user_id
1003         Optional third parameter is the transaction type.  defaults to all
1004         NOTES
1005
1006
1007
1008 sub user_transactions {
1009         my( $self, $client, $login_session, $user_id, $type ) = @_;
1010
1011         my $user_obj = $apputils->check_user_session($login_session); 
1012         if($user_obj->id ne $user_id) {
1013                 if($apputils->check_user_perms($user_obj->id, $user_obj->home_ou, "VIEW_USER_TRANSACTIONS")) {
1014                         return OpenILS::Perm->new("VIEW_USER_TRANSACTIONS"); 
1015                 }
1016         }
1017
1018         my $api = $self->api_name();
1019         my $trans;
1020         my @xact;
1021         if(defined($type)) { @xact = (xact_type =>  $type); 
1022         } else { @xact = (); }
1023
1024         if($api =~ /have_charge/) {
1025
1026                 $trans = $apputils->simple_scalar_request( 
1027                         "open-ils.storage",
1028                         "open-ils.storage.direct.money.billable_transaction_summary.search_where.atomic",
1029                         { usr => $user_id, total_owed => { ">" => 0 }, @xact });
1030
1031         } elsif($api =~ /have_balance/) {
1032
1033                 $trans =  $apputils->simple_scalar_request( 
1034                         "open-ils.storage",
1035                         "open-ils.storage.direct.money.billable_transaction_summary.search_where.atomic",
1036                         { usr => $user_id, balance_owed => { ">" => 0 }, @xact });
1037
1038         } else {
1039
1040                 $trans =  $apputils->simple_scalar_request( 
1041                         "open-ils.storage",
1042                         "open-ils.storage.direct.money.billable_transaction_summary.search_where.atomic",
1043                         { usr => $user_id, @xact });
1044         }
1045
1046         if($api !~ /fleshed/) { return $trans; }
1047
1048         warn "API: $api\n";
1049
1050         my @resp;
1051         for my $t (@$trans) {
1052                         
1053                 warn $t->id . "\n";
1054
1055                 my $circ = $apputils->simple_scalar_request(
1056                                 "open-ils.storage",
1057                                 "open-ils.storage.direct.action.circulation.retrieve",
1058                                 $t->id );
1059
1060                 my $title = $apputils->simple_scalar_request(
1061                         "open-ils.storage", 
1062                         "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1063                         $circ->target_copy );
1064
1065                 my $u = OpenILS::Utils::ModsParser->new();
1066                 $u->start_mods_batch($title->marc());
1067                 my $mods = $u->finish_mods_batch();
1068
1069                 push @resp, {transaction => $t, circ => $circ, record => $mods };
1070
1071         }
1072
1073         return \@resp; 
1074
1075
1076
1077
1078
1079 __PACKAGE__->register_method(
1080         method  => "retrieve_groups",
1081         api_name        => "open-ils.actor.groups.retrieve",
1082         notes           => <<"  NOTES");
1083         Returns a list of user groups
1084         NOTES
1085 sub retrieve_groups {
1086         my( $self, $client ) = @_;
1087         return $apputils->simple_scalar_request(
1088                 "open-ils.storage",
1089                 "open-ils.storage.direct.permission.grp_tree.retrieve.all.atomic");
1090 }
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103 1;
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140 __END__
1141
1142
1143 some old methods that may be good to keep around for now
1144
1145 sub _delete_card {
1146         my( $session, $card ) = @_;
1147
1148         warn "Deleting card with barcode " . $card->barcode() . "\n";
1149         my $req = $session->request(
1150                 "open-ils.storage.direct.actor.card.delete",
1151                 $card );
1152         my $status = $req->gather(1);
1153         if(!defined($status)) { 
1154                 throw OpenSRF::EX::ERROR 
1155                         ("Unknown error updating card"); 
1156         }
1157 }
1158
1159
1160
1161 # deletes the patron and any attached addresses and cards
1162 __PACKAGE__->register_method(
1163         method  => "delete_patron",
1164         api_name        => "open-ils.actor.patron.delete",
1165 );
1166
1167 sub delete_patron {
1168
1169         my( $self, $client, $patron ) = @_;
1170         my $session = $apputils->start_db_session();
1171         my $err = undef;
1172
1173         try {
1174
1175                 $patron->clear_mailing_address();
1176                 $patron->clear_billing_address();
1177                 $patron->ischanged(1);
1178
1179                 _update_patron($session, $patron);
1180                 _delete_address($session,$_) for (@{$patron->addresses()});
1181                 _delete_card($session,$_) for (@{$patron->cards()});
1182                 _delete_patron($session,$patron);
1183                 $apputils->commit_db_session($session);
1184
1185         } catch Error with {
1186                 my $e = shift;
1187                 $err =  "-*- Failure deleting user: $e";
1188                 $apputils->rollback_db_session($session);
1189                 warn $err;
1190         };
1191
1192         if($err) { throw OpenSRF::EX::ERROR ($err); }
1193         warn "Patron Delete complete\n";
1194         return 1;
1195 }
1196
1197 sub _delete_patron {
1198         my( $session, $patron ) = @_;
1199
1200         warn "Deleting patron " . $patron->usrname() . "\n";
1201
1202         my $req = $session->request(
1203                 "open-ils.storage.direct.actor.user.delete",
1204                 $patron );
1205         my $status = $req->gather(1);
1206         if(!defined($status)) { 
1207                 throw OpenSRF::EX::ERROR 
1208                         ("Unknown error updating patron"); 
1209         }
1210 }
1211
1212