]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/Application/Actor.pm
adding org address retrieval method
[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 $Data::Dumper::Indent = 0;
6 use OpenILS::Event;
7
8 use Digest::MD5 qw(md5_hex);
9
10 use OpenSRF::EX qw(:try);
11 use OpenILS::EX;
12 use OpenILS::Perm;
13
14 use OpenILS::Application::AppUtils;
15
16 use OpenILS::Utils::Fieldmapper;
17 use OpenILS::Application::Search::Actor;
18 use OpenILS::Utils::ModsParser;
19 use OpenSRF::Utils::Logger qw/$logger/;
20 use OpenSRF::Utils qw/:datetime/;
21
22 use OpenSRF::Utils::Cache;
23
24 use DateTime;
25 use DateTime::Format::ISO8601;
26
27 use OpenILS::Application::Actor::Container;
28
29 sub initialize {
30         OpenILS::Application::Actor::Container->initialize();
31 }
32
33 my $apputils = "OpenILS::Application::AppUtils";
34 my $U = $apputils;
35
36 sub _d { warn "Patron:\n" . Dumper(shift()); }
37
38 my $cache_client;
39
40
41 my $set_user_settings;
42 my $set_ou_settings;
43
44 __PACKAGE__->register_method(
45         method  => "set_user_settings",
46         api_name        => "open-ils.actor.patron.settings.update",
47 );
48 sub set_user_settings {
49         my( $self, $client, $user_session, $uid, $settings ) = @_;
50         
51         $logger->debug("Setting user settings: $user_session, $uid, " . Dumper($settings));
52
53         my( $staff, $user, $evt ) = 
54                 $apputils->checkses_requestor( $user_session, $uid, 'UPDATE_USER' );    
55         return $evt if $evt;
56         
57
58         #my ($params) = map { 
59         #       [{ usr => $user->id, name => $_}, {value => $$settings{$_}}] } keys %$settings;
60
61         my @params = map { 
62                 [{ usr => $user->id, name => $_}, {value => $$settings{$_}}] } keys %$settings;
63
64         $logger->activity("User " . $staff->id . " updating user $uid settings with: " . Dumper(\@params));
65
66         return $apputils->simplereq(
67                 'open-ils.storage',
68                 'open-ils.storage.direct.actor.user_setting.batch.merge', @params );
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         my( $staff, $evt ) = $apputils->checkses( $user_session );
82         return $evt if $evt;
83         $evt = $apputils->check_perms( $staff->id, $ouid, 'UPDATE_ORG_UNIT' );
84         return $evt if $evt;
85
86
87         my ($params) = 
88                 map { [{ org_unit => $ouid, name => $_}, {value => $$settings{$_}}] } keys %$settings;
89
90         $logger->activity("Updating org unit [$ouid] settings with: " . Dumper($params));
91
92         return $apputils->simplereq(
93                 'open-ils.storage',
94                 'open-ils.storage.direct.actor.org_unit_setting.merge', @$params );
95 }
96
97
98 my $fetch_user_settings;
99 my $fetch_ou_settings;
100
101 __PACKAGE__->register_method(
102         method  => "user_settings",
103         api_name        => "open-ils.actor.patron.settings.retrieve",
104 );
105 sub user_settings {
106         my( $self, $client, $user_session, $uid ) = @_;
107         
108         my( $staff, $user, $evt ) = 
109                 $apputils->checkses_requestor( $user_session, $uid, 'VIEW_USER' );
110         return $evt if $evt;
111
112         $logger->debug("User " . $staff->id . " fetching user $uid\n");
113         my $s = $apputils->simplereq(
114                 'open-ils.storage',
115                 'open-ils.storage.direct.actor.user_setting.search.usr.atomic',$uid );
116
117         return { map { ($_->name,$_->value) } @$s };
118 }
119
120
121
122 __PACKAGE__->register_method(
123         method  => "ou_settings",
124         api_name        => "open-ils.actor.org_unit.settings.retrieve",
125 );
126 sub ou_settings {
127         my( $self, $client, $ouid ) = @_;
128         
129         my $s = $apputils->simplereq(
130                 'open-ils.storage',
131                 'open-ils.storage.direct.actor.org_unit_setting.search.org_unit.atomic', $ouid);
132
133         return { map { ($_->name,$_->value) } @$s };
134 }
135
136 __PACKAGE__->register_method (
137         method          => "ou_setting_delete",
138         api_name                => 'open-ils.actor.org_setting.delete',
139         signature       => q/
140                 Deletes a specific org unit setting for a specific location
141                 @param authtoken The login session key
142                 @param orgid The org unit whose setting we're changing
143                 @param setting The name of the setting to delete
144                 @return True value on success.
145         /
146 );
147
148 sub ou_setting_delete {
149         my( $self, $conn, $authtoken, $orgid, $setting ) = @_;
150         my( $reqr, $evt) = $U->checkses($authtoken);
151         return $evt if $evt;
152         $evt = $U->check_perms($reqr->id, $orgid, 'UPDATE_ORG_SETTING');
153         return $evt if $evt;
154
155         my $id = $U->storagereq(
156                 'open-ils.storage.id_list.actor.org_unit_setting.search_where', 
157                 { name => $setting, org_unit => $orgid } );
158
159         $logger->debug("Retrieved setting $id in org unit setting delete");
160
161         my $s = $U->storagereq(
162                 'open-ils.storage.direct.actor.org_unit_setting.delete', $id );
163
164         $logger->activity("User ".$reqr->id." deleted org unit setting $id") if $s;
165         return $s;
166 }
167
168
169
170 __PACKAGE__->register_method(
171         method  => "update_patron",
172         api_name        => "open-ils.actor.patron.update",);
173
174 sub update_patron {
175         my( $self, $client, $user_session, $patron ) = @_;
176
177         my $session = $apputils->start_db_session();
178         my $err = undef;
179
180         $logger->info("Creating new patron...") if $patron->isnew; 
181         $logger->info("Updating Patron: " . $patron->id) unless $patron->isnew;
182
183         my( $user_obj, $evt ) = $U->checkses($user_session);
184         return $evt if $evt;
185
186         # XXX does this user have permission to add/create users.  Granularity?
187         # $new_patron is the patron in progress.  $patron is the original patron
188         # passed in with the method.  new_patron will change as the components
189         # of patron are added/updated.
190
191         my $new_patron;
192
193         # unflesh the real items on the patron
194         $patron->card( $patron->card->id ) if(ref($patron->card));
195         $patron->billing_address( $patron->billing_address->id ) 
196                 if(ref($patron->billing_address));
197         $patron->mailing_address( $patron->mailing_address->id ) 
198                 if(ref($patron->mailing_address));
199
200         # create/update the patron first so we can use his id
201         if($patron->isnew()) {
202                 ( $new_patron, $evt ) = _add_patron($session, _clone_patron($patron), $user_obj);
203                 return $evt if $evt;
204         } else { $new_patron = $patron; }
205
206         ( $new_patron, $evt ) = _add_update_addresses($session, $patron, $new_patron, $user_obj);
207         return $evt if $evt;
208
209         ( $new_patron, $evt ) = _add_update_cards($session, $patron, $new_patron, $user_obj);
210         return $evt if $evt;
211
212         ( $new_patron, $evt ) = _add_survey_responses($session, $patron, $new_patron, $user_obj);
213         return $evt if $evt;
214
215         # re-update the patron if anything has happened to him during this process
216         if($new_patron->ischanged()) {
217                 ( $new_patron, $evt ) = _update_patron($session, $new_patron, $user_obj);
218                 return $evt if $evt;
219         }
220
221         #$session = OpenSRF::AppSession->create("open-ils.storage");  # why did i put this here?
222
223         ($new_patron, $evt) = _create_stat_maps($session, $user_session, $patron, $new_patron, $user_obj);
224         return $evt if $evt;
225
226         ($new_patron, $evt) = _create_perm_maps($session, $user_session, $patron, $new_patron, $user_obj);
227         return $evt if $evt;
228
229         ($new_patron, $evt) = _create_standing_penalties($session, $user_session, $patron, $new_patron, $user_obj);
230         return $evt if $evt;
231
232         $logger->activity("user ".$user_obj->id." updating/creating  user ".$new_patron->id);
233         $apputils->commit_db_session($session);
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
249         my( $requestor, $target, $evt ) = $apputils->
250                 checkses_requestor( $user_session, $user_id, 'VIEW_USER' );
251         return $evt if $evt;
252
253         return flesh_user($user_id);
254 }
255
256
257 # fleshes: card, cards, address, addresses, stat_cat_entries, standing_penalties
258 sub flesh_user {
259         my $id = shift;
260         my $session = shift;
261
262         my $kill = 0;
263
264         if(!$session) {
265                 $session = OpenSRF::AppSession->create("open-ils.storage");
266                 $kill = 1;
267         }
268
269         # grab the user with the given id 
270         my $ureq = $session->request(
271                         "open-ils.storage.direct.actor.user.retrieve", $id);
272         my $user = $ureq->gather(1);
273
274         if(!$user) { return undef; }
275
276         # grab the cards
277         my $cards_req = $session->request(
278                         "open-ils.storage.direct.actor.card.search.usr.atomic",
279                         $user->id() );
280         $user->cards( $cards_req->gather(1) );
281
282         for my $c(@{$user->cards}) {
283                 if($c->id == $user->card || $c->id eq $user->card ) {
284                         #warn "Setting my card to " . $c->id . "\n";
285                         $user->card($c);
286                 }
287         }
288
289         my $add_req = $session->request(
290                         "open-ils.storage.direct.actor.user_address.search.usr.atomic",
291                         $user->id() );
292         $user->addresses( $add_req->gather(1) );
293
294         for my $c(@{$user->addresses}) {
295                 if($c->id eq $user->billing_address ) { $user->billing_address($c); }
296                 if($c->id eq $user->mailing_address ) { $user->mailing_address($c); }
297         }
298
299         my $stat_req = $session->request(
300                 "open-ils.storage.direct.actor.stat_cat_entry_user_map.search.target_usr.atomic",
301                 $user->id() );
302         $user->stat_cat_entries($stat_req->gather(1));
303
304         my $standing_penalties_req = $session->request(
305                 "open-ils.storage.direct.actor.user_standing_penalty.search.usr.atomic",
306                 $user->id() );
307         $user->standing_penalties($standing_penalties_req->gather(1));
308
309         if($kill) { $session->disconnect(); }
310         $user->clear_passwd();
311
312         return $user;
313 }
314
315
316 # clone and clear stuff that would break the database
317 sub _clone_patron {
318         my $patron = shift;
319
320         my $new_patron = $patron->clone;
321
322         # Using the Fieldmapper clone method
323         #my $new_patron = Fieldmapper::actor::user->new();
324
325         #my $fmap = $Fieldmapper::fieldmap;
326         #no strict; # shallow clone, may be useful in the fieldmapper
327         #for my $field 
328         #       (keys %{$fmap->{"Fieldmapper::actor::user"}->{'fields'}}) {
329         #               $new_patron->$field( $patron->$field() );
330         #}
331         #use strict;
332
333         # clear these
334         $new_patron->clear_billing_address();
335         $new_patron->clear_mailing_address();
336         $new_patron->clear_addresses();
337         $new_patron->clear_card();
338         $new_patron->clear_cards();
339         $new_patron->clear_id();
340         $new_patron->clear_isnew();
341         $new_patron->clear_ischanged();
342         $new_patron->clear_isdeleted();
343         $new_patron->clear_stat_cat_entries();
344         $new_patron->clear_permissions();
345         $new_patron->clear_standing_penalties();
346
347         return $new_patron;
348 }
349
350
351 sub _add_patron {
352
353         my $session             = shift;
354         my $patron              = shift;
355         my $user_obj    = shift;
356
357         my $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'CREATE_USER');
358         return (undef, $evt) if $evt;
359
360         $logger->info("Creating new user in the DB with username: ".$patron->usrname());
361
362         my $id = $session->request(
363                 "open-ils.storage.direct.actor.user.create", $patron)->gather(1);
364         return (undef, $U->DB_UPDATE_FAILED($patron)) unless $id;
365
366         $logger->info("Successfully created new user [$id] in DB");
367
368         return ( $session->request( 
369                 "open-ils.storage.direct.actor.user.retrieve", $id)->gather(1), undef );
370 }
371
372
373 sub _update_patron {
374         my( $session, $patron, $user_obj) = @_;
375
376         $logger->info("Updating patron ".$patron->id." in DB");
377         my $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'UPDATE_USER');
378         return (undef, $evt) if $evt;
379
380         $patron->clear_passwd unless $patron->passwd;
381
382         if(!$patron->ident_type) {
383                 $patron->clear_ident_type;
384                 $patron->clear_ident_value;
385         }
386
387         if(!$patron->ident_type2) {
388                 $patron->clear_ident_type2;
389                 $patron->clear_ident_value2;
390         }
391
392         my $stat = $session->request(
393                 "open-ils.storage.direct.actor.user.update",$patron )->gather(1);
394         return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($stat);
395
396         return ($patron);
397 }
398
399
400 sub _add_update_addresses {
401
402         my $session = shift;
403         my $patron = shift;
404         my $new_patron = shift;
405
406         my $evt;
407
408         my $current_id; # id of the address before creation
409
410         for my $address (@{$patron->addresses()}) {
411
412                 $address->usr($new_patron->id());
413
414                 if(ref($address) and $address->isnew()) {
415
416                         $current_id = $address->id();
417                         ($address, $evt) = _add_address($session,$address);
418                         return (undef, $evt) if $evt;
419
420                         if( $patron->billing_address() and 
421                                         $patron->billing_address() == $current_id ) {
422                                 $new_patron->billing_address($address->id());
423                                 $new_patron->ischanged(1);
424                         }
425
426                         if( $patron->mailing_address() and
427                                         $patron->mailing_address() == $current_id ) {
428                                 $new_patron->mailing_address($address->id());
429                                 $new_patron->ischanged(1);
430                         }
431
432                 } elsif( ref($address) and $address->ischanged() ) {
433
434                         $address->usr($new_patron->id());
435                         ($address, $evt) = _update_address($session, $address);
436                         return (undef, $evt) if $evt;
437
438                 } elsif( ref($address) and $address->isdeleted() ) {
439
440                         if( $address->id() == $new_patron->mailing_address() ) {
441                                 $new_patron->clear_mailing_address();
442                                 ($new_patron, $evt) = _update_patron($session, $new_patron);
443                                 return (undef, $evt) if $evt;
444                         }
445
446                         if( $address->id() == $new_patron->billing_address() ) {
447                                 $new_patron->clear_billing_address();
448                                 ($new_patron, $evt) = _update_patron($session, $new_patron);
449                                 return (undef, $evt) if $evt;
450                         }
451
452                         $evt = _delete_address($session, $address);
453                         return (undef, $evt) if $evt;
454                 }
455         }
456
457         return ( $new_patron, undef );
458 }
459
460
461 # adds an address to the db and returns the address with new id
462 sub _add_address {
463         my($session, $address) = @_;
464         $address->clear_id();
465
466         $logger->info("Creating new address at street ".$address->street1);
467
468         # put the address into the database
469         my $id = $session->request(
470                 "open-ils.storage.direct.actor.user_address.create", $address )->gather(1);
471         return (undef, $U->DB_UPDATE_FAILED($address)) unless $id;
472
473         $address->id( $id );
474         return ($address, undef);
475 }
476
477
478 sub _update_address {
479         my( $session, $address ) = @_;
480
481         $logger->info("Updating address ".$address->id." in the DB");
482
483         my $stat = $session->request(
484                 "open-ils.storage.direct.actor.user_address.update", $address )->gather(1);
485
486         return (undef, $U->DB_UPDATE_FAILED($address)) unless defined($stat);
487         return ($address, undef);
488 }
489
490
491
492 sub _add_update_cards {
493
494         my $session = shift;
495         my $patron = shift;
496         my $new_patron = shift;
497
498         my $evt;
499
500         my $virtual_id; #id of the card before creation
501         for my $card (@{$patron->cards()}) {
502
503                 $card->usr($new_patron->id());
504
505                 if(ref($card) and $card->isnew()) {
506
507                         $virtual_id = $card->id();
508                         ( $card, $evt ) = _add_card($session,$card);
509                         return (undef, $evt) if $evt;
510
511                         #if(ref($patron->card)) { $patron->card($patron->card->id); }
512                         if($patron->card() == $virtual_id) {
513                                 $new_patron->card($card->id());
514                                 $new_patron->ischanged(1);
515                         }
516
517                 } elsif( ref($card) and $card->ischanged() ) {
518                         $card->usr($new_patron->id());
519                         $evt = _update_card($session, $card);
520                         return (undef, $evt) if $evt;
521                 }
522         }
523
524         return ( $new_patron, undef );
525 }
526
527
528 # adds an card to the db and returns the card with new id
529 sub _add_card {
530         my( $session, $card ) = @_;
531         $card->clear_id();
532
533         $logger->info("Adding new patron card ".$card->barcode);
534
535         my $id = $session->request(
536                 "open-ils.storage.direct.actor.card.create", $card )->gather(1);
537         return (undef, $U->DB_UPDATE_FAILED($card)) unless $id;
538         $logger->info("Successfully created patron card $id");
539
540         $card->id($id);
541         return ( $card, undef );
542 }
543
544
545 # returns event on error.  returns undef otherwise
546 sub _update_card {
547         my( $session, $card ) = @_;
548         $logger->info("Updating patron card ".$card->id);
549
550         my $stat = $session->request(
551                 "open-ils.storage.direct.actor.card.update", $card )->gather(1);
552         return $U->DB_UPDATE_FAILED($card) unless defined($stat);
553         return undef;
554 }
555
556
557
558
559 # returns event on error.  returns undef otherwise
560 sub _delete_address {
561         my( $session, $address ) = @_;
562
563         $logger->info("Deleting address ".$address->id." from DB");
564
565         my $stat = $session->request(
566                 "open-ils.storage.direct.actor.user_address.delete", $address )->gather(1);
567
568         return $U->DB_UPDATE_FAILED($address) unless defined($stat);
569         return undef;
570 }
571
572
573
574 sub _add_survey_responses {
575         my ($session, $patron, $new_patron) = @_;
576
577         $logger->info( "Updating survey responses for patron ".$new_patron->id );
578
579         my $responses = $patron->survey_responses;
580
581         if($responses) {
582
583                 $_->usr($new_patron->id) for (@$responses);
584
585                 my $evt = $U->simplereq( "open-ils.circ", 
586                         "open-ils.circ.survey.submit.user_id", $responses );
587
588                 return (undef, $evt) if defined($U->event_code($evt));
589
590         }
591
592         return ( $new_patron, undef );
593 }
594
595
596 sub _create_stat_maps {
597
598         my($session, $user_session, $patron, $new_patron) = @_;
599
600         my $maps = $patron->stat_cat_entries();
601
602         for my $map (@$maps) {
603
604                 my $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.update";
605
606                 if ($map->isdeleted()) {
607                         $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.delete";
608
609                 } elsif ($map->isnew()) {
610                         $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.create";
611                         $map->clear_id;
612                 }
613
614
615                 $map->target_usr($new_patron->id);
616
617                 #warn "
618                 $logger->info("Updating stat entry with method $method and map $map");
619
620                 my $stat = $session->request($method, $map)->gather(1);
621                 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
622
623         }
624
625         return ($new_patron, undef);
626 }
627
628 sub _create_perm_maps {
629
630         my($session, $user_session, $patron, $new_patron) = @_;
631
632         my $maps = $patron->permissions;
633
634         for my $map (@$maps) {
635
636                 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
637                 if ($map->isdeleted()) {
638                         $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
639                 } elsif ($map->isnew()) {
640                         $method = "open-ils.storage.direct.permission.usr_perm_map.create";
641                         $map->clear_id;
642                 }
643
644
645                 $map->usr($new_patron->id);
646
647                 #warn( "Updating permissions with method $method and session $user_session and map $map" );
648                 $logger->info( "Updating permissions with method $method and map $map" );
649
650                 my $stat = $session->request($method, $map)->gather(1);
651                 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
652
653         }
654
655         return ($new_patron, undef);
656 }
657
658
659 sub _create_standing_penalties {
660
661         my($session, $user_session, $patron, $new_patron) = @_;
662
663         my $maps = $patron->standing_penalties;
664         my $method;
665
666         for my $map (@$maps) {
667
668                 if ($map->isdeleted()) {
669                         $method = "open-ils.storage.direct.actor.user_standing_penalty.delete";
670                 } elsif ($map->isnew()) {
671                         $method = "open-ils.storage.direct.actor.user_standing_penalty.create";
672                         $map->clear_id;
673                 } else {
674                         next;
675                 }
676
677                 $map->usr($new_patron->id);
678
679                 $logger->debug( "Updating standing penalty with method $method and session $user_session and map $map" );
680
681                 my $stat = $session->request($method, $map)->gather(1);
682                 return (undef, $U->DB_UPDATE_FAILED($map)) unless $stat;
683         }
684
685         return ($new_patron, undef);
686 }
687
688
689
690 __PACKAGE__->register_method(
691         method  => "search_username",
692         api_name        => "open-ils.actor.user.search.username",
693 );
694
695 sub search_username {
696         my($self, $client, $username) = @_;
697         my $users = OpenILS::Application::AppUtils->simple_scalar_request(
698                         "open-ils.storage", 
699                         "open-ils.storage.direct.actor.user.search.usrname.atomic",
700                         $username );
701         return $users;
702 }
703
704
705
706
707 __PACKAGE__->register_method(
708         method  => "user_retrieve_by_barcode",
709         api_name        => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
710
711 sub user_retrieve_by_barcode {
712         my($self, $client, $user_session, $barcode) = @_;
713
714         $logger->debug("Searching for user with barcode $barcode");
715         my ($user_obj, $evt) = $apputils->checkses($user_session);
716         return $evt if $evt;
717
718
719         my $session = OpenSRF::AppSession->create("open-ils.storage");
720
721         # find the card with the given barcode
722         my $creq        = $session->request(
723                         "open-ils.storage.direct.actor.card.search.barcode.atomic",
724                         $barcode );
725         my $card = $creq->gather(1);
726
727         if(!$card || !$card->[0]) {
728                 $session->disconnect();
729                 return OpenILS::Event->new( 'USER_NOT_FOUND' );
730         }
731
732         $card = $card->[0];
733         my $user = flesh_user($card->usr(), $session);
734
735         $evt = $U->check_perms($user_obj->id, $user->home_ou, 'VIEW_USER');
736         return $evt if $evt;
737
738         $session->disconnect();
739         if(!$user) { return OpenILS::Event->new( 'USER_NOT_FOUND' ); }
740         return $user;
741
742 }
743
744
745
746 __PACKAGE__->register_method(
747         method  => "get_user_by_id",
748         api_name        => "open-ils.actor.user.retrieve",);
749
750 sub get_user_by_id {
751         my ($self, $client, $user_session, $id) = @_;
752
753         my $user_obj = $apputils->check_user_session( $user_session ); 
754
755         return $apputils->simple_scalar_request(
756                 "open-ils.storage",
757                 "open-ils.storage.direct.actor.user.retrieve",
758                 $id );
759 }
760
761
762
763 __PACKAGE__->register_method(
764         method  => "get_org_types",
765         api_name        => "open-ils.actor.org_types.retrieve",);
766
767 my $org_types;
768 sub get_org_types {
769         my($self, $client) = @_;
770
771         return $org_types if $org_types;
772          return $org_types = 
773                  $apputils->simple_scalar_request(
774                         "open-ils.storage",
775                         "open-ils.storage.direct.actor.org_unit_type.retrieve.all.atomic" );
776 }
777
778
779
780 __PACKAGE__->register_method(
781         method  => "get_user_profiles",
782         api_name        => "open-ils.actor.user.profiles.retrieve",
783 );
784
785 my $user_profiles;
786 sub get_user_profiles {
787         return $user_profiles if $user_profiles;
788
789         return $user_profiles = 
790                 $apputils->simple_scalar_request(
791                         "open-ils.storage",
792                         "open-ils.storage.direct.actor.profile.retrieve.all.atomic");
793 }
794
795
796
797 __PACKAGE__->register_method(
798         method  => "get_user_ident_types",
799         api_name        => "open-ils.actor.user.ident_types.retrieve",
800 );
801 my $ident_types;
802 sub get_user_ident_types {
803         return $ident_types if $ident_types;
804         return $ident_types = 
805                 $apputils->simple_scalar_request(
806                 "open-ils.storage",
807                 "open-ils.storage.direct.config.identification_type.retrieve.all.atomic" );
808 }
809
810
811
812
813 __PACKAGE__->register_method(
814         method  => "get_org_unit",
815         api_name        => "open-ils.actor.org_unit.retrieve",
816 );
817
818 sub get_org_unit {
819
820         my( $self, $client, $user_session, $org_id ) = @_;
821
822         if(defined($user_session) && !defined($org_id)) {
823                 my $user_obj = 
824                         OpenILS::Application::AppUtils->check_user_session( $user_session ); #throws EX on error
825                 if(!defined($org_id)) {
826                         $org_id = $user_obj->home_ou;
827                 }
828         }
829
830
831         my $home_ou = OpenILS::Application::AppUtils->simple_scalar_request(
832                 "open-ils.storage",
833                 "open-ils.storage.direct.actor.org_unit.retrieve", 
834                 $org_id );
835
836         return $home_ou;
837 }
838
839 __PACKAGE__->register_method(
840         method  => "search_org_unit",
841         api_name        => "open-ils.actor.org_unit_list.search",
842 );
843
844 sub search_org_unit {
845
846         my( $self, $client, $field, $value ) = @_;
847
848         my $list = OpenILS::Application::AppUtils->simple_scalar_request(
849                 "open-ils.storage",
850                 "open-ils.storage.direct.actor.org_unit.search.$field.atomic", 
851                 $value );
852
853         return $list;
854 }
855
856
857 # build the org tree
858
859 __PACKAGE__->register_method(
860         method  => "get_org_tree",
861         api_name        => "open-ils.actor.org_tree.retrieve",
862         argc            => 0, 
863         note            => "Returns the entire org tree structure",
864 );
865
866 sub get_org_tree {
867         my( $self, $client) = @_;
868
869         if(!$cache_client) {
870                 $cache_client = OpenSRF::Utils::Cache->new("global", 0);
871         }
872         # see if it's in the cache
873         #warn "Getting ORG Tree\n";
874         my $tree = $cache_client->get_cache('orgtree');
875         if($tree) { 
876                 #warn "Found orgtree in cache. returning...\n";
877                 return $tree; 
878         }
879
880         my $orglist = $apputils->simple_scalar_request( 
881                 "open-ils.storage", 
882                 "open-ils.storage.direct.actor.org_unit.retrieve.all.atomic" );
883
884         #if($orglist) {
885                 #warn "found org list\n";
886         #}
887
888         $tree = $self->build_org_tree($orglist);
889         $cache_client->put_cache('orgtree', $tree);
890
891         return $tree;
892
893 }
894
895 # turns an org list into an org tree
896 sub build_org_tree {
897
898         my( $self, $orglist) = @_;
899
900         return $orglist unless ( 
901                         ref($orglist) and @$orglist > 1 );
902
903         my @list = sort { 
904                 $a->ou_type <=> $b->ou_type ||
905                 $a->name cmp $b->name } @$orglist;
906
907         for my $org (@list) {
908
909                 next unless ($org and defined($org->parent_ou));
910                 my ($parent) = grep { $_->id == $org->parent_ou } @list;
911                 next unless $parent;
912
913                 $parent->children([]) unless defined($parent->children); 
914                 push( @{$parent->children}, $org );
915         }
916
917         return $list[0];
918
919 }
920
921
922 __PACKAGE__->register_method(
923         method  => "get_org_descendants",
924         api_name        => "open-ils.actor.org_tree.descendants.retrieve"
925 );
926
927 # depth is optional.  org_unit is the id
928 sub get_org_descendants {
929         my( $self, $client, $org_unit, $depth ) = @_;
930         my $orglist = $apputils->simple_scalar_request(
931                         "open-ils.storage", 
932                         "open-ils.storage.actor.org_unit.descendants.atomic",
933                         $org_unit, $depth );
934         return $self->build_org_tree($orglist);
935 }
936
937
938 __PACKAGE__->register_method(
939         method  => "get_org_ancestors",
940         api_name        => "open-ils.actor.org_tree.ancestors.retrieve"
941 );
942
943 # depth is optional.  org_unit is the id
944 sub get_org_ancestors {
945         my( $self, $client, $org_unit, $depth ) = @_;
946         my $orglist = $apputils->simple_scalar_request(
947                         "open-ils.storage", 
948                         "open-ils.storage.actor.org_unit.ancestors.atomic",
949                         $org_unit, $depth );
950         return $self->build_org_tree($orglist);
951 }
952
953
954 __PACKAGE__->register_method(
955         method  => "get_standings",
956         api_name        => "open-ils.actor.standings.retrieve"
957 );
958
959 my $user_standings;
960 sub get_standings {
961         return $user_standings if $user_standings;
962         return $user_standings = 
963                 $apputils->simple_scalar_request(
964                         "open-ils.storage",
965                         "open-ils.storage.direct.config.standing.retrieve.all.atomic" );
966 }
967
968
969
970 __PACKAGE__->register_method(
971         method  => "get_my_org_path",
972         api_name        => "open-ils.actor.org_unit.full_path.retrieve"
973 );
974
975 sub get_my_org_path {
976         my( $self, $client, $user_session, $org_id ) = @_;
977         my $user_obj = $apputils->check_user_session($user_session); 
978         if(!defined($org_id)) { $org_id = $user_obj->home_ou; }
979
980         return $apputils->simple_scalar_request(
981                 "open-ils.storage",
982                 "open-ils.storage.actor.org_unit.full_path.atomic",
983                 $org_id );
984 }
985
986
987 __PACKAGE__->register_method(
988         method  => "patron_adv_search",
989         api_name        => "open-ils.actor.patron.search.advanced" );
990
991 sub patron_adv_search {
992         my( $self, $client, $staff_login, $search_hash ) = @_;
993
994         #warn "patron adv with $staff_login and search " . 
995                 #Dumper($search_hash) . "\n";
996
997         my $session = OpenSRF::AppSession->create("open-ils.storage");
998         my $req = $session->request(
999                 "open-ils.storage.actor.user.crazy_search", $search_hash);
1000
1001         my $ans = $req->gather(1);
1002
1003         my %hash = map { ($_ =>1) } @$ans;
1004         $ans = [ keys %hash ];
1005
1006         #warn "Returning @$ans\n";
1007
1008         $session->disconnect();
1009         return $ans;
1010
1011 }
1012
1013
1014
1015 sub _verify_password {
1016         my($user_session, $password) = @_;
1017         my $user_obj = $apputils->check_user_session($user_session); 
1018
1019         #grab the user with password
1020         $user_obj = $apputils->simple_scalar_request(
1021                 "open-ils.storage", 
1022                 "open-ils.storage.direct.actor.user.retrieve",
1023                 $user_obj->id );
1024
1025         if($user_obj->passwd eq $password) {
1026                 return 1;
1027         }
1028
1029         return 0;
1030 }
1031
1032
1033 __PACKAGE__->register_method(
1034         method  => "update_password",
1035         api_name        => "open-ils.actor.user.password.update");
1036
1037 __PACKAGE__->register_method(
1038         method  => "update_password",
1039         api_name        => "open-ils.actor.user.username.update");
1040
1041 __PACKAGE__->register_method(
1042         method  => "update_password",
1043         api_name        => "open-ils.actor.user.email.update");
1044
1045 sub update_password {
1046         my( $self, $client, $user_session, $new_value, $current_password ) = @_;
1047
1048         my $evt;
1049
1050         #warn "Updating user with method " .$self->api_name . "\n";
1051         my $user_obj = $apputils->check_user_session($user_session); 
1052
1053         if($self->api_name =~ /password/o) {
1054
1055                 #make sure they know the current password
1056                 if(!_verify_password($user_session, md5_hex($current_password))) {
1057                         return OpenILS::EX->new("USER_WRONG_PASSWORD")->ex;
1058                 }
1059
1060                 $user_obj->passwd($new_value);
1061         } 
1062         elsif($self->api_name =~ /username/o) {
1063                 my $users = search_username(undef, undef, $new_value); 
1064                 if( $users and $users->[0] ) {
1065                         return OpenILS::Event->new('USERNAME_EXISTS');
1066                 }
1067                 $user_obj->usrname($new_value);
1068         }
1069
1070         elsif($self->api_name =~ /email/o) {
1071                 #warn "Updating email to $new_value\n";
1072                 $user_obj->email($new_value);
1073         }
1074
1075         my $session = $apputils->start_db_session();
1076
1077         ( $user_obj, $evt ) = _update_patron($session, $user_obj, $user_obj);
1078         return $evt if $evt;
1079
1080         $apputils->commit_db_session($session);
1081
1082         if($user_obj) { return 1; }
1083         return undef;
1084 }
1085
1086
1087 __PACKAGE__->register_method(
1088         method  => "check_user_perms",
1089         api_name        => "open-ils.actor.user.perm.check",
1090         notes           => <<"  NOTES");
1091         Takes a login session, user id, an org id, and an array of perm type strings.  For each
1092         perm type, if the user does *not* have the given permission it is added
1093         to a list which is returned from the method.  If all permissions
1094         are allowed, an empty list is returned
1095         if the logged in user does not match 'user_id', then the logged in user must
1096         have VIEW_PERMISSION priveleges.
1097         NOTES
1098
1099 sub check_user_perms {
1100         my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1101
1102         my( $staff, $evt ) = $apputils->checkses($login_session);
1103         return $evt if $evt;
1104
1105         if($staff->id ne $user_id) {
1106                 if( my $evt = $apputils->check_perms(
1107                         $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1108                         return $evt;
1109                 }
1110         }
1111
1112         my @not_allowed;
1113         for my $perm (@$perm_types) {
1114                 if($apputils->check_perms($user_id, $org_id, $perm)) {
1115                         push @not_allowed, $perm;
1116                 }
1117         }
1118
1119         return \@not_allowed
1120 }
1121
1122 __PACKAGE__->register_method(
1123         method  => "check_user_perms2",
1124         api_name        => "open-ils.actor.user.perm.check.multi_org",
1125         notes           => q/
1126                 Checks the permissions on a list of perms and orgs for a user
1127                 @param authtoken The login session key
1128                 @param user_id The id of the user to check
1129                 @param orgs The array of org ids
1130                 @param perms The array of permission names
1131                 @return An array of  [ orgId, permissionName ] arrays that FAILED the check
1132                 if the logged in user does not match 'user_id', then the logged in user must
1133                 have VIEW_PERMISSION priveleges.
1134         /);
1135
1136 sub check_user_perms2 {
1137         my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1138
1139         my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1140                 $authtoken, $user_id, 'VIEW_PERMISSION' );
1141         return $evt if $evt;
1142
1143         my @not_allowed;
1144         for my $org (@$orgs) {
1145                 for my $perm (@$perms) {
1146                         if($apputils->check_perms($user_id, $org, $perm)) {
1147                                 push @not_allowed, [ $org, $perm ];
1148                         }
1149                 }
1150         }
1151
1152         return \@not_allowed
1153 }
1154
1155
1156 __PACKAGE__->register_method(
1157         method => 'check_user_perms3',
1158         api_name        => 'open-ils.actor.user.perm.highest_org',
1159         notes           => q/
1160                 Returns the highest org unit id at which a user has a given permission
1161                 If the requestor does not match the target user, the requestor must have
1162                 'VIEW_PERMISSION' rights at the home org unit of the target user
1163                 @param authtoken The login session key
1164                 @param userid The id of the user in question
1165                 @param perm The permission to check
1166                 @return The org unit highest in the org tree within which the user has
1167                 the requested permission
1168         /);
1169
1170 sub check_user_perms3 {
1171         my( $self, $client, $authtoken, $userid, $perm ) = @_;
1172
1173         my( $staff, $target, $org, $evt );
1174
1175         ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1176                 $authtoken, $userid, 'VIEW_PERMISSION' );
1177         return $evt if $evt;
1178
1179         my $tree = $self->get_org_tree();
1180         return _find_highest_perm_org( $perm, $userid, $target->home_ou, $tree );
1181 }
1182
1183
1184 sub _find_highest_perm_org {
1185         my ( $perm, $userid, $start_org, $org_tree ) = @_;
1186         my $org = $apputils->find_org($org_tree, $start_org );
1187
1188         my $lastid = undef;
1189         while( $org ) {
1190                 last if ($apputils->check_perms( $userid, $org->id, $perm )); # perm failed
1191                 $lastid = $org->id;
1192                 $org = $apputils->find_org( $org_tree, $org->parent_ou() );
1193         }
1194
1195         return $lastid;
1196 }
1197
1198 __PACKAGE__->register_method(
1199         method => 'check_user_perms4',
1200         api_name        => 'open-ils.actor.user.perm.highest_org.batch',
1201         notes           => q/
1202                 Returns the highest org unit id at which a user has a given permission
1203                 If the requestor does not match the target user, the requestor must have
1204                 'VIEW_PERMISSION' rights at the home org unit of the target user
1205                 @param authtoken The login session key
1206                 @param userid The id of the user in question
1207                 @param perms An array of perm names to check 
1208                 @return An array of orgId's  representing the org unit 
1209                 highest in the org tree within which the user has the requested permission
1210                 The arrah of orgId's has matches the order of the perms array
1211         /);
1212
1213 sub check_user_perms4 {
1214         my( $self, $client, $authtoken, $userid, $perms ) = @_;
1215         
1216         my( $staff, $target, $org, $evt );
1217
1218         ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1219                 $authtoken, $userid, 'VIEW_PERMISSION' );
1220         return $evt if $evt;
1221
1222         my @arr;
1223         return [] unless ref($perms);
1224         my $tree = $self->get_org_tree();
1225
1226         for my $p (@$perms) {
1227                 push( @arr, _find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1228         }
1229         return \@arr;
1230 }
1231
1232
1233
1234
1235 __PACKAGE__->register_method(
1236         method  => "user_fines_summary",
1237         api_name        => "open-ils.actor.user.fines.summary",
1238         notes           => <<"  NOTES");
1239         Returns a short summary of the users total open fines, excluding voided fines
1240         Params are login_session, user_id
1241         Returns a 'mous' object.
1242         NOTES
1243
1244 sub user_fines_summary {
1245         my( $self, $client, $login_session, $user_id ) = @_;
1246
1247         my $user_obj = $apputils->check_user_session($login_session); 
1248         if($user_obj->id ne $user_id) {
1249                 if($apputils->check_user_perms($user_obj->id, $user_obj->home_ou, "VIEW_USER_FINES_SUMMARY")) {
1250                         return OpenILS::Perm->new("VIEW_USER_FINES_SUMMARY"); 
1251                 }
1252         }
1253
1254         return $apputils->simple_scalar_request( 
1255                 "open-ils.storage",
1256                 "open-ils.storage.direct.money.open_user_summary.search.usr",
1257                 $user_id );
1258
1259 }
1260
1261
1262
1263
1264 __PACKAGE__->register_method(
1265         method  => "user_transactions",
1266         api_name        => "open-ils.actor.user.transactions",
1267         notes           => <<"  NOTES");
1268         Returns a list of open user transactions (mbts objects);
1269         Params are login_session, user_id
1270         Optional third parameter is the transactions type.  defaults to all
1271         NOTES
1272
1273 __PACKAGE__->register_method(
1274         method  => "user_transactions",
1275         api_name        => "open-ils.actor.user.transactions.have_charge",
1276         notes           => <<"  NOTES");
1277         Returns a list of all open user transactions (mbts objects) that have an initial charge
1278         Params are login_session, user_id
1279         Optional third parameter is the transactions type.  defaults to all
1280         NOTES
1281
1282 __PACKAGE__->register_method(
1283         method  => "user_transactions",
1284         api_name        => "open-ils.actor.user.transactions.have_balance",
1285         notes           => <<"  NOTES");
1286         Returns a list of all open user transactions (mbts objects) that have a balance
1287         Params are login_session, user_id
1288         Optional third parameter is the transactions type.  defaults to all
1289         NOTES
1290
1291 __PACKAGE__->register_method(
1292         method  => "user_transactions",
1293         api_name        => "open-ils.actor.user.transactions.fleshed",
1294         notes           => <<"  NOTES");
1295         Returns an object/hash of transaction, circ, title where transaction = an open 
1296         user transactions (mbts objects), circ is the attached circluation, and title
1297         is the title the circ points to
1298         Params are login_session, user_id
1299         Optional third parameter is the transactions type.  defaults to all
1300         NOTES
1301
1302 __PACKAGE__->register_method(
1303         method  => "user_transactions",
1304         api_name        => "open-ils.actor.user.transactions.have_charge.fleshed",
1305         notes           => <<"  NOTES");
1306         Returns an object/hash of transaction, circ, title where transaction = an open 
1307         user transactions that has an initial charge (mbts objects), circ is the 
1308         attached circluation, and title is the title the circ points to
1309         Params are login_session, user_id
1310         Optional third parameter is the transactions type.  defaults to all
1311         NOTES
1312
1313 __PACKAGE__->register_method(
1314         method  => "user_transactions",
1315         api_name        => "open-ils.actor.user.transactions.have_balance.fleshed",
1316         notes           => <<"  NOTES");
1317         Returns an object/hash of transaction, circ, title where transaction = an open 
1318         user transaction that has a balance (mbts objects), circ is the attached 
1319         circluation, and title is the title the circ points to
1320         Params are login_session, user_id
1321         Optional third parameter is the transaction type.  defaults to all
1322         NOTES
1323
1324 __PACKAGE__->register_method(
1325         method  => "user_transactions",
1326         api_name        => "open-ils.actor.user.transactions.count",
1327         notes           => <<"  NOTES");
1328         Returns an object/hash of transaction, circ, title where transaction = an open 
1329         user transactions (mbts objects), circ is the attached circluation, and title
1330         is the title the circ points to
1331         Params are login_session, user_id
1332         Optional third parameter is the transactions type.  defaults to all
1333         NOTES
1334
1335 __PACKAGE__->register_method(
1336         method  => "user_transactions",
1337         api_name        => "open-ils.actor.user.transactions.have_charge.count",
1338         notes           => <<"  NOTES");
1339         Returns an object/hash of transaction, circ, title where transaction = an open 
1340         user transactions that has an initial charge (mbts objects), circ is the 
1341         attached circluation, and title is the title the circ points to
1342         Params are login_session, user_id
1343         Optional third parameter is the transactions type.  defaults to all
1344         NOTES
1345
1346 __PACKAGE__->register_method(
1347         method  => "user_transactions",
1348         api_name        => "open-ils.actor.user.transactions.have_balance.count",
1349         notes           => <<"  NOTES");
1350         Returns an object/hash of transaction, circ, title where transaction = an open 
1351         user transaction that has a balance (mbts objects), circ is the attached 
1352         circluation, and title is the title the circ points to
1353         Params are login_session, user_id
1354         Optional third parameter is the transaction type.  defaults to all
1355         NOTES
1356
1357 __PACKAGE__->register_method(
1358         method  => "user_transactions",
1359         api_name        => "open-ils.actor.user.transactions.have_balance.total",
1360         notes           => <<"  NOTES");
1361         Returns an object/hash of transaction, circ, title where transaction = an open 
1362         user transaction that has a balance (mbts objects), circ is the attached 
1363         circluation, and title is the title the circ points to
1364         Params are login_session, user_id
1365         Optional third parameter is the transaction type.  defaults to all
1366         NOTES
1367
1368
1369
1370 sub user_transactions {
1371         my( $self, $client, $login_session, $user_id, $type ) = @_;
1372
1373         my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1374                 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1375         return $evt if $evt;
1376         
1377         my $api = $self->api_name();
1378         my $trans;
1379         my @xact;
1380
1381         if(defined($type)) { @xact = (xact_type =>  $type); 
1382
1383         } else { @xact = (); }
1384
1385         if($api =~ /have_charge/o) {
1386
1387                 $trans = $apputils->simple_scalar_request( 
1388                         "open-ils.storage",
1389                         "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1390                         { usr => $user_id, total_owed => { ">" => 0 }, @xact });
1391
1392         } elsif($api =~ /have_balance/o) {
1393
1394                 $trans =  $apputils->simple_scalar_request( 
1395                         "open-ils.storage",
1396                         "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1397                         { usr => $user_id, balance_owed => { ">" => 0 }, @xact });
1398
1399         } else {
1400
1401                 $trans =  $apputils->simple_scalar_request( 
1402                         "open-ils.storage",
1403                         "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1404                         { usr => $user_id, @xact });
1405         }
1406
1407         if($api =~ /total/o) { 
1408                 my $total = 0.0;
1409                 for my $t (@$trans) {
1410                         $total += $t->balance_owed;
1411                 }
1412
1413                 $logger->debug("Total balance owed by user $user_id: $total");
1414                 return $total;
1415         }
1416
1417         if($api =~ /count/o) { return scalar @$trans; }
1418         if($api !~ /fleshed/o) { return $trans; }
1419
1420         #warn "API: $api\n";
1421
1422         my @resp;
1423         for my $t (@$trans) {
1424                         
1425                 #warn $t->id . "\n";
1426
1427
1428                 if( $t->xact_type ne 'circulation' ) {
1429                         push @resp, {transaction => $t};
1430                         next;
1431                 }
1432
1433                 my $circ = $apputils->simple_scalar_request(
1434                                 "open-ils.storage",
1435                                 "open-ils.storage.direct.action.circulation.retrieve",
1436                                 $t->id );
1437
1438                 next unless $circ;
1439
1440                 my $title = $apputils->simple_scalar_request(
1441                         "open-ils.storage", 
1442                         "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1443                         $circ->target_copy );
1444
1445                 next unless $title;
1446
1447                 my $u = OpenILS::Utils::ModsParser->new();
1448                 $u->start_mods_batch($title->marc());
1449                 my $mods = $u->finish_mods_batch();
1450
1451                 push @resp, {transaction => $t, circ => $circ, record => $mods };
1452
1453         }
1454
1455         return \@resp; 
1456
1457
1458
1459 __PACKAGE__->register_method(
1460         method  => "user_transaction_retrieve",
1461         api_name        => "open-ils.actor.user.transaction.fleshed.retrieve",
1462         argc            => 1,
1463         notes           => <<"  NOTES");
1464         Returns a fleshedtransaction record
1465         NOTES
1466 __PACKAGE__->register_method(
1467         method  => "user_transaction_retrieve",
1468         api_name        => "open-ils.actor.user.transaction.retrieve",
1469         argc            => 1,
1470         notes           => <<"  NOTES");
1471         Returns a transaction record
1472         NOTES
1473 sub user_transaction_retrieve {
1474         my( $self, $client, $login_session, $bill_id ) = @_;
1475
1476         my $trans = $apputils->simple_scalar_request( 
1477                 "open-ils.storage",
1478                 "open-ils.storage.direct.money.billable_transaction_summary.retrieve",
1479                 $bill_id
1480         );
1481
1482         my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1483                 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1484         return $evt if $evt;
1485         
1486         my $api = $self->api_name();
1487         if($api !~ /fleshed/o) { return $trans; }
1488
1489         if( $trans->xact_type ne 'circulation' ) {
1490                 $logger->debug("Returning non-circ transaction");
1491                 return {transaction => $trans};
1492         }
1493
1494         my $circ = $apputils->simple_scalar_request(
1495                         "open-ils.storage",
1496                         "open-ils.storage.direct.action.circulation.retrieve",
1497                         $trans->id );
1498
1499         return {transaction => $trans} unless $circ;
1500         $logger->debug("Found the circ transaction");
1501
1502         my $title = $apputils->simple_scalar_request(
1503                 "open-ils.storage", 
1504                 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1505                 $circ->target_copy );
1506
1507         return {transaction => $trans, circ => $circ } unless $title;
1508         $logger->debug("Found the circ title");
1509
1510         my $mods;
1511         try {
1512                 my $u = OpenILS::Utils::ModsParser->new();
1513                 $u->start_mods_batch($title->marc());
1514                 $mods = $u->finish_mods_batch();
1515         } otherwise {
1516                 if ($title->id == -1) {
1517                         my $copy = $apputils->simple_scalar_request(
1518                                 "open-ils.storage",
1519                                 "open-ils.storage.direct.asset.copy.retrieve",
1520                                 $circ->target_copy );
1521
1522                         $mods = new Fieldmapper::metabib::virtual_record;
1523                         $mods->doc_id(-1);
1524                         $mods->title($copy->dummy_title);
1525                         $mods->author($copy->dummy_author);
1526                 }
1527         };
1528
1529         $logger->debug("MODSized the circ title");
1530
1531         return {transaction => $trans, circ => $circ, record => $mods };
1532 }
1533
1534
1535 __PACKAGE__->register_method(
1536         method  => "hold_request_count",
1537         api_name        => "open-ils.actor.user.hold_requests.count",
1538         argc            => 1,
1539         notes           => <<"  NOTES");
1540         Returns hold ready/total counts
1541         NOTES
1542 sub hold_request_count {
1543         my( $self, $client, $login_session, $userid ) = @_;
1544
1545         my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1546                 $login_session, $userid, 'VIEW_HOLD' );
1547         return $evt if $evt;
1548         
1549
1550         my $holds = $apputils->simple_scalar_request(
1551                         "open-ils.storage",
1552                         "open-ils.storage.direct.action.hold_request.search_where.atomic",
1553                         { usr => $userid,
1554                           fulfillment_time => {"=" => undef } }
1555         );
1556
1557         my @ready;
1558         for my $h (@$holds) {
1559                 next unless $h->capture_time;
1560
1561                 my $copy = $apputils->simple_scalar_request(
1562                         "open-ils.storage",
1563                         "open-ils.storage.direct.asset.copy.retrieve",
1564                         $h->current_copy
1565                 );
1566
1567                 if ($copy->status == 8) {
1568                         push @ready, $h;
1569                 }
1570         }
1571
1572         return { total => scalar(@$holds), ready => scalar(@ready) };
1573 }
1574
1575
1576 __PACKAGE__->register_method(
1577         method  => "checkedout_count",
1578         api_name        => "open-ils.actor.user.checked_out.count",
1579         argc            => 1,
1580         notes           => <<"  NOTES");
1581         Returns a transaction record
1582         NOTES
1583 sub checkedout_count {
1584         my( $self, $client, $login_session, $userid ) = @_;
1585
1586         my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1587                 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1588         return $evt if $evt;
1589         
1590
1591         my $circs = $apputils->simple_scalar_request(
1592                         "open-ils.storage",
1593                         "open-ils.storage.direct.action.circulation.search_where.atomic",
1594                         { usr => $userid,
1595                           checkin_time => {"=" => undef } }
1596         );
1597
1598         my $parser = DateTime::Format::ISO8601->new;
1599
1600         my (@out,@overdue);
1601         for my $c (@$circs) {
1602                 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1603                 my $due = $due_dt->epoch;
1604
1605                 if ($due < DateTime->today->epoch) {
1606                         push @overdue, $c;
1607                 }
1608         }
1609
1610         return { total => scalar(@$circs), overdue => scalar(@overdue) };
1611 }
1612
1613 __PACKAGE__->register_method(
1614         method  => "user_transaction_history",
1615         api_name        => "open-ils.actor.user.transactions.history",
1616         argc            => 1,
1617         notes           => <<"  NOTES");
1618         Returns a list of billable transaction ids for a user, optionally by type
1619         NOTES
1620 __PACKAGE__->register_method(
1621         method  => "user_transaction_history",
1622         api_name        => "open-ils.actor.user.transactions.history.have_charge",
1623         argc            => 1,
1624         notes           => <<"  NOTES");
1625         Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
1626         NOTES
1627 sub user_transaction_history {
1628         my( $self, $client, $login_session, $user_id, $type ) = @_;
1629
1630         my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1631                 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1632         return $evt if $evt;
1633         
1634         my $api = $self->api_name();
1635         my @xact;
1636         my @charge;
1637
1638         @xact = (xact_type =>  $type) if(defined($type));
1639         @charge = (total_owed => { ">" => 0}) if($api =~ /have_charge/);
1640
1641         my $trans = $apputils->simple_scalar_request( 
1642                 "open-ils.storage",
1643                 "open-ils.storage.direct.money.billable_transaction_summary.search_where.atomic",
1644                 { usr => $user_id, @xact, @charge }, { order_by => 'xact_start DESC' });
1645
1646         return [ map { $_->id } @$trans ];
1647 }
1648
1649
1650 __PACKAGE__->register_method(
1651         method  => "user_perms",
1652         api_name        => "open-ils.actor.permissions.user_perms.retrieve",
1653         argc            => 1,
1654         notes           => <<"  NOTES");
1655         Returns a list of permissions
1656         NOTES
1657 sub user_perms {
1658         my( $self, $client, $authtoken, $user ) = @_;
1659
1660         my( $staff, $evt ) = $apputils->checkses($authtoken);
1661         return $evt if $evt;
1662
1663         $user ||= $staff->id;
1664
1665         if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
1666                 return $evt;
1667         }
1668
1669         return $apputils->simple_scalar_request(
1670                 "open-ils.storage",
1671                 "open-ils.storage.permission.user_perms.atomic",
1672                 $user);
1673 }
1674
1675 __PACKAGE__->register_method(
1676         method  => "retrieve_perms",
1677         api_name        => "open-ils.actor.permissions.retrieve",
1678         notes           => <<"  NOTES");
1679         Returns a list of permissions
1680         NOTES
1681 sub retrieve_perms {
1682         my( $self, $client ) = @_;
1683         return $apputils->simple_scalar_request(
1684                 "open-ils.storage",
1685                 "open-ils.storage.direct.permission.perm_list.retrieve.all.atomic");
1686 }
1687
1688 __PACKAGE__->register_method(
1689         method  => "retrieve_groups",
1690         api_name        => "open-ils.actor.groups.retrieve",
1691         notes           => <<"  NOTES");
1692         Returns a list of user groupss
1693         NOTES
1694 sub retrieve_groups {
1695         my( $self, $client ) = @_;
1696         return $apputils->simple_scalar_request(
1697                 "open-ils.storage",
1698                 "open-ils.storage.direct.permission.grp_tree.retrieve.all.atomic");
1699 }
1700
1701 __PACKAGE__->register_method(
1702         method  => "retrieve_org_address",
1703         api_name        => "open-ils.actor.org_unit.address.retrieve",
1704         notes           => <<'  NOTES');
1705         Returns an org_unit address by ID
1706         @param An org_address ID
1707         NOTES
1708 sub retrieve_org_address {
1709         my( $self, $client, $id ) = @_;
1710         return $apputils->simple_scalar_request(
1711                 "open-ils.storage",
1712                 "open-ils.storage.direct.actor.org_address.retrieve",
1713                 $id
1714         );
1715 }
1716
1717 __PACKAGE__->register_method(
1718         method  => "retrieve_groups_tree",
1719         api_name        => "open-ils.actor.groups.tree.retrieve",
1720         notes           => <<"  NOTES");
1721         Returns a list of user groups
1722         NOTES
1723 sub retrieve_groups_tree {
1724         my( $self, $client ) = @_;
1725         my $groups = $apputils->simple_scalar_request(
1726                 "open-ils.storage",
1727                 "open-ils.storage.direct.permission.grp_tree.retrieve.all.atomic");
1728         return $self->build_group_tree($groups);        
1729 }
1730
1731
1732 # turns an org list into an org tree
1733 sub build_group_tree {
1734
1735         my( $self, $grplist) = @_;
1736
1737         return $grplist unless ( 
1738                         ref($grplist) and @$grplist > 1 );
1739
1740         my @list = sort { $a->name cmp $b->name } @$grplist;
1741
1742         my $root;
1743         for my $grp (@list) {
1744
1745                 if ($grp and !defined($grp->parent)) {
1746                         $root = $grp;
1747                         next;
1748                 }
1749                 my ($parent) = grep { $_->id == $grp->parent} @list;
1750
1751                 $parent->children([]) unless defined($parent->children); 
1752                 push( @{$parent->children}, $grp );
1753         }
1754
1755         return $root;
1756
1757 }
1758
1759
1760 __PACKAGE__->register_method(
1761         method  => "add_user_to_groups",
1762         api_name        => "open-ils.actor.user.set_groups",
1763         notes           => <<"  NOTES");
1764         Adds a user to one or more permission groups
1765         NOTES
1766
1767 sub add_user_to_groups {
1768         my( $self, $client, $authtoken, $userid, $groups ) = @_;
1769
1770         my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1771                 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
1772         return $evt if $evt;
1773
1774         ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1775                 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
1776         return $evt if $evt;
1777
1778         $apputils->simplereq(
1779                 'open-ils.storage',
1780                 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
1781                 
1782         for my $group (@$groups) {
1783                 my $link = Fieldmapper::permission::usr_grp_map->new;
1784                 $link->grp($group);
1785                 $link->usr($userid);
1786
1787                 my $id = $apputils->simplereq(
1788                         'open-ils.storage',
1789                         'open-ils.storage.direct.permission.usr_grp_map.create', $link );
1790         }
1791
1792         return 1;
1793 }
1794
1795 __PACKAGE__->register_method(
1796         method  => "get_user_perm_groups",
1797         api_name        => "open-ils.actor.user.get_groups",
1798         notes           => <<"  NOTES");
1799         Retrieve a user's permission groups.
1800         NOTES
1801
1802
1803 sub get_user_perm_groups {
1804         my( $self, $client, $authtoken, $userid ) = @_;
1805
1806         my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1807                 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
1808         return $evt if $evt;
1809
1810         return $apputils->simplereq(
1811                 'open-ils.storage',
1812                 'open-ils.storage.direct.permission.usr_grp_map.search.usr.atomic', $userid );
1813 }       
1814
1815
1816
1817 __PACKAGE__->register_method (
1818         method          => 'register_workstation',
1819         api_name                => 'open-ils.actor.workstation.register',
1820         signature       => q/
1821                 Registers a new workstion in the system
1822                 @param authtoken The login session key
1823                 @param name The name of the workstation id
1824                 @param owner The org unit that owns this workstation
1825                 @return The workstation id on success, WORKSTATION_NAME_EXISTS
1826                 if the name is already in use.
1827         /);
1828
1829 sub register_workstation {
1830         my( $self, $connection, $authtoken, $name, $owner ) = @_;
1831         my( $requestor, $evt ) = $U->checkses($authtoken);
1832         return $evt if $evt;
1833         $evt = $U->check_perms($requestor->id, $owner, 'REGISTER_WORKSTATION');
1834         return $evt if $evt;
1835
1836         my $ws = $U->storagereq(
1837                 'open-ils.storage.direct.actor.workstation.search.name', $name );
1838         return OpenILS::Event->new('WORKSTATION_NAME_EXISTS') if $ws;
1839
1840         $ws = Fieldmapper::actor::workstation->new;
1841         $ws->owning_lib($owner);
1842         $ws->name($name);
1843
1844         my $id = $U->storagereq(
1845                 'open-ils.storage.direct.actor.workstation.create', $ws );
1846         return $U->DB_UPDATE_FAILED($ws) unless $id;
1847
1848         $ws->id($id);
1849         return $ws->id();
1850 }
1851
1852
1853 __PACKAGE__->register_method (
1854         method          => 'fetch_patron_note',
1855         api_name                => 'open-ils.actor.note.retrieve.all',
1856         signature       => q/
1857                 Returns a list of notes for a given user
1858                 Requestor must have VIEW_USER permission if pub==false and
1859                 @param authtoken The login session key
1860                 @param args Hash of params including
1861                         patronid : the patron's id
1862                         pub : true if retrieving only public notes
1863         /
1864 );
1865
1866 sub fetch_patron_note {
1867         my( $self, $conn, $authtoken, $args ) = @_;
1868         my $patronid = $$args{patronid};
1869
1870         my($reqr, $evt) = $U->checkses($authtoken);
1871
1872         my $patron;
1873         ($patron, $evt) = $U->fetch_user($patronid);
1874         return $evt if $evt;
1875
1876         if($$args{pub}) {
1877                 if( $patronid ne $reqr->id ) {
1878                         $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
1879                         return $evt if $evt;
1880                 }
1881                 return $U->storagereq(
1882                         'open-ils.storage.direct.actor.usr_note.search_where.atomic', 
1883                         { usr => $patronid, pub => 't' } );
1884         }
1885
1886         $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
1887         return $evt if $evt;
1888
1889         return $U->storagereq(
1890                 'open-ils.storage.direct.actor.usr_note.search.usr.atomic', $patronid );
1891 }
1892
1893 __PACKAGE__->register_method (
1894         method          => 'create_user_note',
1895         api_name                => 'open-ils.actor.note.create',
1896         signature       => q/
1897                 Creates a new note for the given user
1898                 @param authtoken The login session key
1899                 @param note The note object
1900         /
1901 );
1902 sub create_user_note {
1903         my( $self, $conn, $authtoken, $note ) = @_;
1904         my( $reqr, $patron, $evt ) = 
1905                 $U->checkses_requestor($authtoken, $note->usr, 'UPDATE_USER');
1906         return $evt if $evt;
1907         $logger->activity("user ".$reqr->id." creating note for user ".$note->usr);
1908
1909         $note->pub('f') unless $note->pub;
1910         $note->creator($reqr->id);
1911         my $id = $U->storagereq(
1912                 'open-ils.storage.direct.actor.usr_note.create', $note );
1913         return $U->DB_UPDATE_FAILED($note) unless $id;
1914         return $id;
1915 }
1916
1917
1918 __PACKAGE__->register_method (
1919         method          => 'delete_user_note',
1920         api_name                => 'open-ils.actor.note.delete',
1921         signature       => q/
1922                 Deletes a note for the given user
1923                 @param authtoken The login session key
1924                 @param noteid The note id
1925         /
1926 );
1927 sub delete_user_note {
1928         my( $self, $conn, $authtoken, $noteid ) = @_;
1929
1930         my $note = $U->storagereq(
1931                 'open-ils.storage.direct.actor.usr_note.retrieve', $noteid);
1932         return OpenILS::Event->new('USER_NOTE_NOT_FOUND') unless $note;
1933
1934         my( $reqr, $patron, $evt ) = 
1935                 $U->checkses_requestor($authtoken, $note->usr, 'UPDATE_USER');
1936         return $evt if $evt;
1937         $logger->activity("user ".$reqr->id." deleting note [$noteid] for user ".$note->usr);
1938
1939         my $stat = $U->storagereq(
1940                 'open-ils.storage.direct.actor.usr_note.delete', $noteid );
1941         return $U->DB_UPDATE_FAILED($note) unless defined $stat;
1942         return $stat;
1943 }
1944
1945
1946 1;
1947