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