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