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