]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/Application/Actor.pm
XUL based holds work. Need to test from within the staff client.
[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         my $user_obj = $apputils->check_user_session($login_session); 
1049
1050         if($user_obj->id ne $user_id) {
1051                 if($apputils->check_user_perms($user_obj->id, $org_id, "VIEW_PERMISSION")) {
1052                         return OpenILS::Perm->new("VIEW_PERMISSION");
1053                 }
1054         }
1055
1056         my @not_allowed;
1057         for my $perm (@$perm_types) {
1058                 if($apputils->check_user_perms($user_id, $org_id, $perm)) {
1059                         push @not_allowed, $perm;
1060                 }
1061         }
1062
1063         return \@not_allowed
1064 }
1065
1066
1067
1068 __PACKAGE__->register_method(
1069         method  => "user_fines_summary",
1070         api_name        => "open-ils.actor.user.fines.summary",
1071         notes           => <<"  NOTES");
1072         Returns a short summary of the users total open fines, excluding voided fines
1073         Params are login_session, user_id
1074         Returns a 'mous' object.
1075         NOTES
1076
1077 sub user_fines_summary {
1078         my( $self, $client, $login_session, $user_id ) = @_;
1079
1080         my $user_obj = $apputils->check_user_session($login_session); 
1081         if($user_obj->id ne $user_id) {
1082                 if($apputils->check_user_perms($user_obj->id, $user_obj->home_ou, "VIEW_USER_FINES_SUMMARY")) {
1083                         return OpenILS::Perm->new("VIEW_USER_FINES_SUMMARY"); 
1084                 }
1085         }
1086
1087         return $apputils->simple_scalar_request( 
1088                 "open-ils.storage",
1089                 "open-ils.storage.direct.money.open_user_summary.search.usr",
1090                 $user_id );
1091
1092 }
1093
1094
1095
1096
1097 __PACKAGE__->register_method(
1098         method  => "user_transactions",
1099         api_name        => "open-ils.actor.user.transactions",
1100         notes           => <<"  NOTES");
1101         Returns a list of open user transactions (mbts objects);
1102         Params are login_session, user_id
1103         Optional third parameter is the transactions type.  defaults to all
1104         NOTES
1105
1106 __PACKAGE__->register_method(
1107         method  => "user_transactions",
1108         api_name        => "open-ils.actor.user.transactions.have_charge",
1109         notes           => <<"  NOTES");
1110         Returns a list of all open user transactions (mbts objects) that have an initial charge
1111         Params are login_session, user_id
1112         Optional third parameter is the transactions type.  defaults to all
1113         NOTES
1114
1115 __PACKAGE__->register_method(
1116         method  => "user_transactions",
1117         api_name        => "open-ils.actor.user.transactions.have_balance",
1118         notes           => <<"  NOTES");
1119         Returns a list of all open user transactions (mbts objects) that have a balance
1120         Params are login_session, user_id
1121         Optional third parameter is the transactions type.  defaults to all
1122         NOTES
1123
1124 __PACKAGE__->register_method(
1125         method  => "user_transactions",
1126         api_name        => "open-ils.actor.user.transactions.fleshed",
1127         notes           => <<"  NOTES");
1128         Returns an object/hash of transaction, circ, title where transaction = an open 
1129         user transactions (mbts objects), circ is the attached circluation, and title
1130         is the title the circ points to
1131         Params are login_session, user_id
1132         Optional third parameter is the transactions type.  defaults to all
1133         NOTES
1134
1135 __PACKAGE__->register_method(
1136         method  => "user_transactions",
1137         api_name        => "open-ils.actor.user.transactions.have_charge.fleshed",
1138         notes           => <<"  NOTES");
1139         Returns an object/hash of transaction, circ, title where transaction = an open 
1140         user transactions that has an initial charge (mbts objects), circ is the 
1141         attached circluation, and title is the title the circ points to
1142         Params are login_session, user_id
1143         Optional third parameter is the transactions type.  defaults to all
1144         NOTES
1145
1146 __PACKAGE__->register_method(
1147         method  => "user_transactions",
1148         api_name        => "open-ils.actor.user.transactions.have_balance.fleshed",
1149         notes           => <<"  NOTES");
1150         Returns an object/hash of transaction, circ, title where transaction = an open 
1151         user transaction that has a balance (mbts objects), circ is the attached 
1152         circluation, and title is the title the circ points to
1153         Params are login_session, user_id
1154         Optional third parameter is the transaction type.  defaults to all
1155         NOTES
1156
1157
1158
1159 sub user_transactions {
1160         my( $self, $client, $login_session, $user_id, $type ) = @_;
1161
1162         my $user_obj = $apputils->check_user_session($login_session); 
1163         if($user_obj->id ne $user_id) {
1164                 if($apputils->check_user_perms($user_obj->id, $user_obj->home_ou, "VIEW_USER_TRANSACTIONS")) {
1165                         return OpenILS::Perm->new("VIEW_USER_TRANSACTIONS"); 
1166                 }
1167         }
1168
1169         my $api = $self->api_name();
1170         my $trans;
1171         my @xact;
1172         if(defined($type)) { @xact = (xact_type =>  $type); 
1173         } else { @xact = (); }
1174
1175         if($api =~ /have_charge/) {
1176
1177                 $trans = $apputils->simple_scalar_request( 
1178                         "open-ils.storage",
1179                         "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1180                         { usr => $user_id, total_owed => { ">" => 0 }, @xact });
1181
1182         } elsif($api =~ /have_balance/) {
1183
1184                 $trans =  $apputils->simple_scalar_request( 
1185                         "open-ils.storage",
1186                         "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1187                         { usr => $user_id, balance_owed => { ">" => 0 }, @xact });
1188
1189         } else {
1190
1191                 $trans =  $apputils->simple_scalar_request( 
1192                         "open-ils.storage",
1193                         "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1194                         { usr => $user_id, @xact });
1195         }
1196
1197         if($api !~ /fleshed/) { return $trans; }
1198
1199         warn "API: $api\n";
1200
1201         my @resp;
1202         for my $t (@$trans) {
1203                         
1204                 warn $t->id . "\n";
1205
1206                 my $circ = $apputils->simple_scalar_request(
1207                                 "open-ils.storage",
1208                                 "open-ils.storage.direct.action.circulation.retrieve",
1209                                 $t->id );
1210
1211                 next unless $circ;
1212
1213                 my $title = $apputils->simple_scalar_request(
1214                         "open-ils.storage", 
1215                         "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1216                         $circ->target_copy );
1217
1218                 next unless $title;
1219
1220                 my $u = OpenILS::Utils::ModsParser->new();
1221                 $u->start_mods_batch($title->marc());
1222                 my $mods = $u->finish_mods_batch();
1223
1224                 push @resp, {transaction => $t, circ => $circ, record => $mods };
1225
1226         }
1227
1228         return \@resp; 
1229
1230
1231
1232
1233
1234 __PACKAGE__->register_method(
1235         method  => "retrieve_groups",
1236         api_name        => "open-ils.actor.groups.retrieve",
1237         notes           => <<"  NOTES");
1238         Returns a list of user groups
1239         NOTES
1240 sub retrieve_groups {
1241         my( $self, $client ) = @_;
1242         return $apputils->simple_scalar_request(
1243                 "open-ils.storage",
1244                 "open-ils.storage.direct.permission.grp_tree.retrieve.all.atomic");
1245 }
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258 1;
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
1295 __END__
1296
1297
1298 some old methods that may be good to keep around for now
1299
1300 sub _delete_card {
1301         my( $session, $card ) = @_;
1302
1303         warn "Deleting card with barcode " . $card->barcode() . "\n";
1304         my $req = $session->request(
1305                 "open-ils.storage.direct.actor.card.delete",
1306                 $card );
1307         my $status = $req->gather(1);
1308         if(!defined($status)) { 
1309                 throw OpenSRF::EX::ERROR 
1310                         ("Unknown error updating card"); 
1311         }
1312 }
1313
1314
1315
1316 # deletes the patron and any attached addresses and cards
1317 __PACKAGE__->register_method(
1318         method  => "delete_patron",
1319         api_name        => "open-ils.actor.patron.delete",
1320 );
1321
1322 sub delete_patron {
1323
1324         my( $self, $client, $patron ) = @_;
1325         my $session = $apputils->start_db_session();
1326         my $err = undef;
1327
1328         try {
1329
1330                 $patron->clear_mailing_address();
1331                 $patron->clear_billing_address();
1332                 $patron->ischanged(1);
1333
1334                 _update_patron($session, $patron);
1335                 _delete_address($session,$_) for (@{$patron->addresses()});
1336                 _delete_card($session,$_) for (@{$patron->cards()});
1337                 _delete_patron($session,$patron);
1338                 $apputils->commit_db_session($session);
1339
1340         } catch Error with {
1341                 my $e = shift;
1342                 $err =  "-*- Failure deleting user: $e";
1343                 $apputils->rollback_db_session($session);
1344                 warn $err;
1345         };
1346
1347         if($err) { throw OpenSRF::EX::ERROR ($err); }
1348         warn "Patron Delete complete\n";
1349         return 1;
1350 }
1351
1352 sub _delete_patron {
1353         my( $session, $patron ) = @_;
1354
1355         warn "Deleting patron " . $patron->usrname() . "\n";
1356
1357         my $req = $session->request(
1358                 "open-ils.storage.direct.actor.user.delete",
1359                 $patron );
1360         my $status = $req->gather(1);
1361         if(!defined($status)) { 
1362                 throw OpenSRF::EX::ERROR 
1363                         ("Unknown error updating patron"); 
1364         }
1365 }
1366
1367