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