]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/Application/Actor.pm
more work with containers.
[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 OpenILS::Event->new( 'USER_NOT_FOUND' );
706         }
707
708         $card = $card->[0];
709         my $user = flesh_user($card->usr(), $session);
710         $session->disconnect();
711         if(!$user) { return OpenILS::Event->new( 'USER_NOT_FOUND' ); }
712         return $user;
713
714 }
715
716
717
718 __PACKAGE__->register_method(
719         method  => "get_user_by_id",
720         api_name        => "open-ils.actor.user.retrieve",);
721
722 sub get_user_by_id {
723         my ($self, $client, $user_session, $id) = @_;
724
725         my $user_obj = $apputils->check_user_session( $user_session ); 
726
727         return $apputils->simple_scalar_request(
728                 "open-ils.storage",
729                 "open-ils.storage.direct.actor.user.retrieve",
730                 $id );
731 }
732
733
734
735 __PACKAGE__->register_method(
736         method  => "get_org_types",
737         api_name        => "open-ils.actor.org_types.retrieve",);
738
739 my $org_types;
740 sub get_org_types {
741         my($self, $client) = @_;
742
743         return $org_types if $org_types;
744          return $org_types = 
745                  $apputils->simple_scalar_request(
746                         "open-ils.storage",
747                         "open-ils.storage.direct.actor.org_unit_type.retrieve.all.atomic" );
748 }
749
750
751
752 __PACKAGE__->register_method(
753         method  => "get_user_profiles",
754         api_name        => "open-ils.actor.user.profiles.retrieve",
755 );
756
757 my $user_profiles;
758 sub get_user_profiles {
759         return $user_profiles if $user_profiles;
760
761         return $user_profiles = 
762                 $apputils->simple_scalar_request(
763                         "open-ils.storage",
764                         "open-ils.storage.direct.actor.profile.retrieve.all.atomic");
765 }
766
767
768
769 __PACKAGE__->register_method(
770         method  => "get_user_ident_types",
771         api_name        => "open-ils.actor.user.ident_types.retrieve",
772 );
773 my $ident_types;
774 sub get_user_ident_types {
775         return $ident_types if $ident_types;
776         return $ident_types = 
777                 $apputils->simple_scalar_request(
778                 "open-ils.storage",
779                 "open-ils.storage.direct.config.identification_type.retrieve.all.atomic" );
780 }
781
782
783
784
785 __PACKAGE__->register_method(
786         method  => "get_org_unit",
787         api_name        => "open-ils.actor.org_unit.retrieve",
788 );
789
790 sub get_org_unit {
791
792         my( $self, $client, $user_session, $org_id ) = @_;
793
794         if(defined($user_session) && !defined($org_id)) {
795                 my $user_obj = 
796                         OpenILS::Application::AppUtils->check_user_session( $user_session ); #throws EX on error
797                 if(!defined($org_id)) {
798                         $org_id = $user_obj->home_ou;
799                 }
800         }
801
802
803         my $home_ou = OpenILS::Application::AppUtils->simple_scalar_request(
804                 "open-ils.storage",
805                 "open-ils.storage.direct.actor.org_unit.retrieve", 
806                 $org_id );
807
808         return $home_ou;
809 }
810
811
812 # build the org tree
813
814 __PACKAGE__->register_method(
815         method  => "get_org_tree",
816         api_name        => "open-ils.actor.org_tree.retrieve",
817         argc            => 1, 
818         note            => "Returns the entire org tree structure",
819 );
820
821 sub get_org_tree {
822         my( $self, $client) = @_;
823
824         if(!$cache_client) {
825                 $cache_client = OpenSRF::Utils::Cache->new("global", 0);
826         }
827         # see if it's in the cache
828         warn "Getting ORG Tree\n";
829         my $tree = $cache_client->get_cache('orgtree');
830         if($tree) { 
831                 warn "Found orgtree in cache. returning...\n";
832                 return $tree; 
833         }
834
835         my $orglist = $apputils->simple_scalar_request( 
836                 "open-ils.storage", 
837                 "open-ils.storage.direct.actor.org_unit.retrieve.all.atomic" );
838
839         if($orglist) {
840                 warn "found org list\n";
841         }
842
843         $tree = $self->build_org_tree($orglist);
844         $cache_client->put_cache('orgtree', $tree);
845
846         return $tree;
847
848 }
849
850 # turns an org list into an org tree
851 sub build_org_tree {
852
853         my( $self, $orglist) = @_;
854
855         return $orglist unless ( 
856                         ref($orglist) and @$orglist > 1 );
857
858         my @list = sort { 
859                 $a->ou_type <=> $b->ou_type ||
860                 $a->name cmp $b->name } @$orglist;
861
862         for my $org (@list) {
863
864                 next unless ($org and defined($org->parent_ou));
865                 my ($parent) = grep { $_->id == $org->parent_ou } @list;
866                 next unless $parent;
867
868                 $parent->children([]) unless defined($parent->children); 
869                 push( @{$parent->children}, $org );
870         }
871
872         return $list[0];
873
874 }
875
876
877 __PACKAGE__->register_method(
878         method  => "get_org_descendants",
879         api_name        => "open-ils.actor.org_tree.descendants.retrieve"
880 );
881
882 # depth is optional.  org_unit is the id
883 sub get_org_descendants {
884         my( $self, $client, $org_unit, $depth ) = @_;
885         my $orglist = $apputils->simple_scalar_request(
886                         "open-ils.storage", 
887                         "open-ils.storage.actor.org_unit.descendants.atomic",
888                         $org_unit, $depth );
889         return $self->build_org_tree($orglist);
890 }
891
892
893 __PACKAGE__->register_method(
894         method  => "get_org_ancestors",
895         api_name        => "open-ils.actor.org_tree.ancestors.retrieve"
896 );
897
898 # depth is optional.  org_unit is the id
899 sub get_org_ancestors {
900         my( $self, $client, $org_unit, $depth ) = @_;
901         my $orglist = $apputils->simple_scalar_request(
902                         "open-ils.storage", 
903                         "open-ils.storage.actor.org_unit.ancestors.atomic",
904                         $org_unit, $depth );
905         return $self->build_org_tree($orglist);
906 }
907
908
909 __PACKAGE__->register_method(
910         method  => "get_standings",
911         api_name        => "open-ils.actor.standings.retrieve"
912 );
913
914 my $user_standings;
915 sub get_standings {
916         return $user_standings if $user_standings;
917         return $user_standings = 
918                 $apputils->simple_scalar_request(
919                         "open-ils.storage",
920                         "open-ils.storage.direct.config.standing.retrieve.all.atomic" );
921 }
922
923
924
925 __PACKAGE__->register_method(
926         method  => "get_my_org_path",
927         api_name        => "open-ils.actor.org_unit.full_path.retrieve"
928 );
929
930 sub get_my_org_path {
931         my( $self, $client, $user_session, $org_id ) = @_;
932         my $user_obj = $apputils->check_user_session($user_session); 
933         if(!defined($org_id)) { $org_id = $user_obj->home_ou; }
934
935         return $apputils->simple_scalar_request(
936                 "open-ils.storage",
937                 "open-ils.storage.actor.org_unit.full_path.atomic",
938                 $org_id );
939 }
940
941
942 __PACKAGE__->register_method(
943         method  => "patron_adv_search",
944         api_name        => "open-ils.actor.patron.search.advanced" );
945
946 sub patron_adv_search {
947         my( $self, $client, $staff_login, $search_hash ) = @_;
948
949         use Data::Dumper;
950         warn "patron adv with $staff_login and search " . 
951                 Dumper($search_hash) . "\n";
952
953         my $session = OpenSRF::AppSession->create("open-ils.storage");
954         my $req = $session->request(
955                 "open-ils.storage.actor.user.crazy_search", $search_hash);
956
957         my $ans = $req->gather(1);
958
959         my %hash = map { ($_ =>1) } @$ans;
960         $ans = [ keys %hash ];
961
962         warn "Returning @$ans\n";
963
964         $session->disconnect();
965         return $ans;
966
967 }
968
969
970
971 sub _verify_password {
972         my($user_session, $password) = @_;
973         my $user_obj = $apputils->check_user_session($user_session); 
974
975         #grab the user with password
976         $user_obj = $apputils->simple_scalar_request(
977                 "open-ils.storage", 
978                 "open-ils.storage.direct.actor.user.retrieve",
979                 $user_obj->id );
980
981         if($user_obj->passwd eq $password) {
982                 return 1;
983         }
984
985         return 0;
986 }
987
988
989 __PACKAGE__->register_method(
990         method  => "update_password",
991         api_name        => "open-ils.actor.user.password.update");
992
993 __PACKAGE__->register_method(
994         method  => "update_password",
995         api_name        => "open-ils.actor.user.username.update");
996
997 __PACKAGE__->register_method(
998         method  => "update_password",
999         api_name        => "open-ils.actor.user.email.update");
1000
1001 sub update_password {
1002         my( $self, $client, $user_session, $new_value, $current_password ) = @_;
1003
1004         warn "Updating user with method " .$self->api_name . "\n";
1005         my $user_obj = $apputils->check_user_session($user_session); 
1006
1007         if($self->api_name =~ /password/) {
1008
1009                 #make sure they know the current password
1010                 if(!_verify_password($user_session, md5_hex($current_password))) {
1011                         return OpenILS::EX->new("USER_WRONG_PASSWORD")->ex;
1012                 }
1013
1014                 $user_obj->passwd($new_value);
1015         } 
1016         elsif($self->api_name =~ /username/) {
1017                 $user_obj->usrname($new_value);
1018         }
1019
1020         elsif($self->api_name =~ /email/) {
1021                 warn "Updating email to $new_value\n";
1022                 $user_obj->email($new_value);
1023         }
1024
1025         my $session = $apputils->start_db_session();
1026         $user_obj = _update_patron($session, $user_obj, $user_obj);
1027         $apputils->commit_db_session($session);
1028
1029         if($user_obj) { return 1; }
1030         return undef;
1031 }
1032
1033
1034 __PACKAGE__->register_method(
1035         method  => "check_user_perms",
1036         api_name        => "open-ils.actor.user.perm.check",
1037         notes           => <<"  NOTES");
1038         Takes a login session, user id, an org id, and an array of perm type strings.  For each
1039         perm type, if the user does *not* have the given permission it is added
1040         to a list which is returned from the method.  If all permissions
1041         are allowed, an empty list is returned
1042         if the logged in user does not match 'user_id', then the logged in user must
1043         have VIEW_PERMISSION priveleges.
1044         NOTES
1045
1046 sub check_user_perms {
1047         my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1048
1049         my( $staff, $evt ) = $apputils->checkses($login_session);
1050         return $evt if $evt;
1051
1052         if($staff->id ne $user_id) {
1053                 if( my $evt = $apputils->check_perms(
1054                         $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1055                         return $evt;
1056                 }
1057         }
1058
1059         my @not_allowed;
1060         for my $perm (@$perm_types) {
1061                 if($apputils->check_user_perms($user_id, $org_id, $perm)) {
1062                         push @not_allowed, $perm;
1063                 }
1064         }
1065
1066         return \@not_allowed
1067 }
1068
1069
1070
1071 __PACKAGE__->register_method(
1072         method  => "user_fines_summary",
1073         api_name        => "open-ils.actor.user.fines.summary",
1074         notes           => <<"  NOTES");
1075         Returns a short summary of the users total open fines, excluding voided fines
1076         Params are login_session, user_id
1077         Returns a 'mous' object.
1078         NOTES
1079
1080 sub user_fines_summary {
1081         my( $self, $client, $login_session, $user_id ) = @_;
1082
1083         my $user_obj = $apputils->check_user_session($login_session); 
1084         if($user_obj->id ne $user_id) {
1085                 if($apputils->check_user_perms($user_obj->id, $user_obj->home_ou, "VIEW_USER_FINES_SUMMARY")) {
1086                         return OpenILS::Perm->new("VIEW_USER_FINES_SUMMARY"); 
1087                 }
1088         }
1089
1090         return $apputils->simple_scalar_request( 
1091                 "open-ils.storage",
1092                 "open-ils.storage.direct.money.open_user_summary.search.usr",
1093                 $user_id );
1094
1095 }
1096
1097
1098
1099
1100 __PACKAGE__->register_method(
1101         method  => "user_transactions",
1102         api_name        => "open-ils.actor.user.transactions",
1103         notes           => <<"  NOTES");
1104         Returns a list of open user transactions (mbts objects);
1105         Params are login_session, user_id
1106         Optional third parameter is the transactions type.  defaults to all
1107         NOTES
1108
1109 __PACKAGE__->register_method(
1110         method  => "user_transactions",
1111         api_name        => "open-ils.actor.user.transactions.have_charge",
1112         notes           => <<"  NOTES");
1113         Returns a list of all open user transactions (mbts objects) that have an initial charge
1114         Params are login_session, user_id
1115         Optional third parameter is the transactions type.  defaults to all
1116         NOTES
1117
1118 __PACKAGE__->register_method(
1119         method  => "user_transactions",
1120         api_name        => "open-ils.actor.user.transactions.have_balance",
1121         notes           => <<"  NOTES");
1122         Returns a list of all open user transactions (mbts objects) that have a balance
1123         Params are login_session, user_id
1124         Optional third parameter is the transactions type.  defaults to all
1125         NOTES
1126
1127 __PACKAGE__->register_method(
1128         method  => "user_transactions",
1129         api_name        => "open-ils.actor.user.transactions.fleshed",
1130         notes           => <<"  NOTES");
1131         Returns an object/hash of transaction, circ, title where transaction = an open 
1132         user transactions (mbts objects), circ is the attached circluation, and title
1133         is the title the circ points to
1134         Params are login_session, user_id
1135         Optional third parameter is the transactions type.  defaults to all
1136         NOTES
1137
1138 __PACKAGE__->register_method(
1139         method  => "user_transactions",
1140         api_name        => "open-ils.actor.user.transactions.have_charge.fleshed",
1141         notes           => <<"  NOTES");
1142         Returns an object/hash of transaction, circ, title where transaction = an open 
1143         user transactions that has an initial charge (mbts objects), circ is the 
1144         attached circluation, and title is the title the circ points to
1145         Params are login_session, user_id
1146         Optional third parameter is the transactions type.  defaults to all
1147         NOTES
1148
1149 __PACKAGE__->register_method(
1150         method  => "user_transactions",
1151         api_name        => "open-ils.actor.user.transactions.have_balance.fleshed",
1152         notes           => <<"  NOTES");
1153         Returns an object/hash of transaction, circ, title where transaction = an open 
1154         user transaction that has a balance (mbts objects), circ is the attached 
1155         circluation, and title is the title the circ points to
1156         Params are login_session, user_id
1157         Optional third parameter is the transaction type.  defaults to all
1158         NOTES
1159
1160
1161
1162 sub user_transactions {
1163         my( $self, $client, $login_session, $user_id, $type ) = @_;
1164
1165         my $user_obj = $apputils->check_user_session($login_session); 
1166         if($user_obj->id ne $user_id) {
1167                 if($apputils->check_user_perms($user_obj->id, $user_obj->home_ou, "VIEW_USER_TRANSACTIONS")) {
1168                         return OpenILS::Perm->new("VIEW_USER_TRANSACTIONS"); 
1169                 }
1170         }
1171
1172         my $api = $self->api_name();
1173         my $trans;
1174         my @xact;
1175         if(defined($type)) { @xact = (xact_type =>  $type); 
1176         } else { @xact = (); }
1177
1178         if($api =~ /have_charge/) {
1179
1180                 $trans = $apputils->simple_scalar_request( 
1181                         "open-ils.storage",
1182                         "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1183                         { usr => $user_id, total_owed => { ">" => 0 }, @xact });
1184
1185         } elsif($api =~ /have_balance/) {
1186
1187                 $trans =  $apputils->simple_scalar_request( 
1188                         "open-ils.storage",
1189                         "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1190                         { usr => $user_id, balance_owed => { ">" => 0 }, @xact });
1191
1192         } else {
1193
1194                 $trans =  $apputils->simple_scalar_request( 
1195                         "open-ils.storage",
1196                         "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1197                         { usr => $user_id, @xact });
1198         }
1199
1200         if($api !~ /fleshed/) { return $trans; }
1201
1202         warn "API: $api\n";
1203
1204         my @resp;
1205         for my $t (@$trans) {
1206                         
1207                 warn $t->id . "\n";
1208
1209                 my $circ = $apputils->simple_scalar_request(
1210                                 "open-ils.storage",
1211                                 "open-ils.storage.direct.action.circulation.retrieve",
1212                                 $t->id );
1213
1214                 next unless $circ;
1215
1216                 my $title = $apputils->simple_scalar_request(
1217                         "open-ils.storage", 
1218                         "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1219                         $circ->target_copy );
1220
1221                 next unless $title;
1222
1223                 my $u = OpenILS::Utils::ModsParser->new();
1224                 $u->start_mods_batch($title->marc());
1225                 my $mods = $u->finish_mods_batch();
1226
1227                 push @resp, {transaction => $t, circ => $circ, record => $mods };
1228
1229         }
1230
1231         return \@resp; 
1232
1233
1234
1235
1236
1237 __PACKAGE__->register_method(
1238         method  => "retrieve_groups",
1239         api_name        => "open-ils.actor.groups.retrieve",
1240         notes           => <<"  NOTES");
1241         Returns a list of user groups
1242         NOTES
1243 sub retrieve_groups {
1244         my( $self, $client ) = @_;
1245         return $apputils->simple_scalar_request(
1246                 "open-ils.storage",
1247                 "open-ils.storage.direct.permission.grp_tree.retrieve.all.atomic");
1248 }
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261 1;
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
1295
1296
1297
1298 __END__
1299
1300
1301 some old methods that may be good to keep around for now
1302
1303 sub _delete_card {
1304         my( $session, $card ) = @_;
1305
1306         warn "Deleting card with barcode " . $card->barcode() . "\n";
1307         my $req = $session->request(
1308                 "open-ils.storage.direct.actor.card.delete",
1309                 $card );
1310         my $status = $req->gather(1);
1311         if(!defined($status)) { 
1312                 throw OpenSRF::EX::ERROR 
1313                         ("Unknown error updating card"); 
1314         }
1315 }
1316
1317
1318
1319 # deletes the patron and any attached addresses and cards
1320 __PACKAGE__->register_method(
1321         method  => "delete_patron",
1322         api_name        => "open-ils.actor.patron.delete",
1323 );
1324
1325 sub delete_patron {
1326
1327         my( $self, $client, $patron ) = @_;
1328         my $session = $apputils->start_db_session();
1329         my $err = undef;
1330
1331         try {
1332
1333                 $patron->clear_mailing_address();
1334                 $patron->clear_billing_address();
1335                 $patron->ischanged(1);
1336
1337                 _update_patron($session, $patron);
1338                 _delete_address($session,$_) for (@{$patron->addresses()});
1339                 _delete_card($session,$_) for (@{$patron->cards()});
1340                 _delete_patron($session,$patron);
1341                 $apputils->commit_db_session($session);
1342
1343         } catch Error with {
1344                 my $e = shift;
1345                 $err =  "-*- Failure deleting user: $e";
1346                 $apputils->rollback_db_session($session);
1347                 warn $err;
1348         };
1349
1350         if($err) { throw OpenSRF::EX::ERROR ($err); }
1351         warn "Patron Delete complete\n";
1352         return 1;
1353 }
1354
1355 sub _delete_patron {
1356         my( $session, $patron ) = @_;
1357
1358         warn "Deleting patron " . $patron->usrname() . "\n";
1359
1360         my $req = $session->request(
1361                 "open-ils.storage.direct.actor.user.delete",
1362                 $patron );
1363         my $status = $req->gather(1);
1364         if(!defined($status)) { 
1365                 throw OpenSRF::EX::ERROR 
1366                         ("Unknown error updating patron"); 
1367         }
1368 }
1369
1370