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