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