]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/Application/Actor.pm
moved some select methods to editor
[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;
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         return $org_types if $org_types;
894         return $org_types = new_editor()->retrieve_all_actor_org_unit_type();
895 }
896
897
898
899 __PACKAGE__->register_method(
900         method  => "get_user_profiles",
901         api_name        => "open-ils.actor.user.profiles.retrieve",
902 );
903
904 my $user_profiles;
905 sub get_user_profiles {
906         return $user_profiles if $user_profiles;
907
908         return $user_profiles = 
909                 $apputils->simple_scalar_request(
910                         "open-ils.storage",
911                         "open-ils.storage.direct.actor.profile.retrieve.all.atomic");
912 }
913
914
915
916 __PACKAGE__->register_method(
917         method  => "get_user_ident_types",
918         api_name        => "open-ils.actor.user.ident_types.retrieve",
919 );
920 my $ident_types;
921 sub get_user_ident_types {
922         return $ident_types if $ident_types;
923         return $ident_types = 
924                 new_editor()->retrieve_all_config_identification_type();
925 }
926
927
928
929
930 __PACKAGE__->register_method(
931         method  => "get_org_unit",
932         api_name        => "open-ils.actor.org_unit.retrieve",
933 );
934
935 sub get_org_unit {
936         my( $self, $client, $user_session, $org_id ) = @_;
937         my $e = new_editor(authtoken => $user_session);
938         if(!$org_id) {
939                 return $e->event unless $e->checkauth;
940                 $org_id = $e->requestor->ws_ou;
941         }
942         my $o = $e->retrieve_actor_org_unit($org_id)
943                 or return $e->event;
944         return $o;
945 }
946
947 __PACKAGE__->register_method(
948         method  => "search_org_unit",
949         api_name        => "open-ils.actor.org_unit_list.search",
950 );
951
952 sub search_org_unit {
953
954         my( $self, $client, $field, $value ) = @_;
955
956         my $list = OpenILS::Application::AppUtils->simple_scalar_request(
957                 "open-ils.storage",
958                 "open-ils.storage.direct.actor.org_unit.search.$field.atomic", 
959                 $value );
960
961         return $list;
962 }
963
964
965 # build the org tree
966
967 __PACKAGE__->register_method(
968         method  => "get_org_tree",
969         api_name        => "open-ils.actor.org_tree.retrieve",
970         argc            => 0, 
971         note            => "Returns the entire org tree structure",
972 );
973
974 sub get_org_tree {
975         my( $self, $client) = @_;
976
977         $cache  = OpenSRF::Utils::Cache->new("global", 0) unless $cache;
978         my $tree = $cache->get_cache('orgtree');
979         return $tree if $tree;
980
981         $tree = new_editor()->search_actor_org_unit( 
982                 [
983                         {"parent_ou" => undef },
984                         {
985                                 flesh                           => 2,
986                                 flesh_fields    => { aou =>  ['children'] },
987                                 order_by                        => { aou => 'shortname'}
988                         }
989                 ]
990         )->[0];
991
992         $cache->put_cache('orgtree', $tree);
993         return $tree;
994 }
995
996
997 # turns an org list into an org tree
998 sub build_org_tree {
999
1000         my( $self, $orglist) = @_;
1001
1002         return $orglist unless ( 
1003                         ref($orglist) and @$orglist > 1 );
1004
1005         my @list = sort { 
1006                 $a->ou_type <=> $b->ou_type ||
1007                 $a->name cmp $b->name } @$orglist;
1008
1009         for my $org (@list) {
1010
1011                 next unless ($org and defined($org->parent_ou));
1012                 my ($parent) = grep { $_->id == $org->parent_ou } @list;
1013                 next unless $parent;
1014
1015                 $parent->children([]) unless defined($parent->children); 
1016                 push( @{$parent->children}, $org );
1017         }
1018
1019         return $list[0];
1020
1021 }
1022
1023
1024 __PACKAGE__->register_method(
1025         method  => "get_org_descendants",
1026         api_name        => "open-ils.actor.org_tree.descendants.retrieve"
1027 );
1028
1029 # depth is optional.  org_unit is the id
1030 sub get_org_descendants {
1031         my( $self, $client, $org_unit, $depth ) = @_;
1032         my $orglist = $apputils->simple_scalar_request(
1033                         "open-ils.storage", 
1034                         "open-ils.storage.actor.org_unit.descendants.atomic",
1035                         $org_unit, $depth );
1036         return $self->build_org_tree($orglist);
1037 }
1038
1039
1040 __PACKAGE__->register_method(
1041         method  => "get_org_ancestors",
1042         api_name        => "open-ils.actor.org_tree.ancestors.retrieve"
1043 );
1044
1045 # depth is optional.  org_unit is the id
1046 sub get_org_ancestors {
1047         my( $self, $client, $org_unit, $depth ) = @_;
1048         my $orglist = $apputils->simple_scalar_request(
1049                         "open-ils.storage", 
1050                         "open-ils.storage.actor.org_unit.ancestors.atomic",
1051                         $org_unit, $depth );
1052         return $self->build_org_tree($orglist);
1053 }
1054
1055
1056 __PACKAGE__->register_method(
1057         method  => "get_standings",
1058         api_name        => "open-ils.actor.standings.retrieve"
1059 );
1060
1061 my $user_standings;
1062 sub get_standings {
1063         return $user_standings if $user_standings;
1064         return $user_standings = 
1065                 $apputils->simple_scalar_request(
1066                         "open-ils.storage",
1067                         "open-ils.storage.direct.config.standing.retrieve.all.atomic" );
1068 }
1069
1070
1071
1072 __PACKAGE__->register_method(
1073         method  => "get_my_org_path",
1074         api_name        => "open-ils.actor.org_unit.full_path.retrieve"
1075 );
1076
1077 sub get_my_org_path {
1078         my( $self, $client, $user_session, $org_id ) = @_;
1079         my $user_obj = $apputils->check_user_session($user_session); 
1080         if(!defined($org_id)) { $org_id = $user_obj->home_ou; }
1081
1082         return $apputils->simple_scalar_request(
1083                 "open-ils.storage",
1084                 "open-ils.storage.actor.org_unit.full_path.atomic",
1085                 $org_id );
1086 }
1087
1088
1089 __PACKAGE__->register_method(
1090         method  => "patron_adv_search",
1091         api_name        => "open-ils.actor.patron.search.advanced" );
1092 sub patron_adv_search {
1093         my( $self, $client, $auth, $search_hash, $search_limit, $search_sort ) = @_;
1094         my $e = new_editor(authtoken=>$auth);
1095         return $e->event unless $e->checkauth;
1096         return $e->event unless $e->allowed('VIEW_USER');
1097         return $U->storagereq(
1098                 "open-ils.storage.actor.user.crazy_search", 
1099                 $search_hash, $search_limit, $search_sort);
1100 }
1101
1102
1103
1104 sub _verify_password {
1105         my($user_session, $password) = @_;
1106         my $user_obj = $apputils->check_user_session($user_session); 
1107
1108         #grab the user with password
1109         $user_obj = $apputils->simple_scalar_request(
1110                 "open-ils.storage", 
1111                 "open-ils.storage.direct.actor.user.retrieve",
1112                 $user_obj->id );
1113
1114         if($user_obj->passwd eq $password) {
1115                 return 1;
1116         }
1117
1118         return 0;
1119 }
1120
1121
1122 __PACKAGE__->register_method(
1123         method  => "update_password",
1124         api_name        => "open-ils.actor.user.password.update");
1125
1126 __PACKAGE__->register_method(
1127         method  => "update_password",
1128         api_name        => "open-ils.actor.user.username.update");
1129
1130 __PACKAGE__->register_method(
1131         method  => "update_password",
1132         api_name        => "open-ils.actor.user.email.update");
1133
1134 sub update_password {
1135         my( $self, $client, $user_session, $new_value, $current_password ) = @_;
1136
1137         my $evt;
1138
1139         my $user_obj = $apputils->check_user_session($user_session); 
1140
1141         if($self->api_name =~ /password/o) {
1142
1143                 #make sure they know the current password
1144                 if(!_verify_password($user_session, md5_hex($current_password))) {
1145                         return OpenILS::Event->new('INCORRECT_PASSWORD');
1146                 }
1147
1148                 $logger->debug("update_password setting new password $new_value");
1149                 $user_obj->passwd($new_value);
1150
1151         } elsif($self->api_name =~ /username/o) {
1152                 my $users = search_username(undef, undef, $new_value); 
1153                 if( $users and $users->[0] ) {
1154                         return OpenILS::Event->new('USERNAME_EXISTS');
1155                 }
1156                 $user_obj->usrname($new_value);
1157
1158         } elsif($self->api_name =~ /email/o) {
1159                 #warn "Updating email to $new_value\n";
1160                 $user_obj->email($new_value);
1161         }
1162
1163         my $session = $apputils->start_db_session();
1164
1165         ( $user_obj, $evt ) = _update_patron($session, $user_obj, $user_obj, 1);
1166         return $evt if $evt;
1167
1168         $apputils->commit_db_session($session);
1169
1170         if($user_obj) { return 1; }
1171         return undef;
1172 }
1173
1174
1175 __PACKAGE__->register_method(
1176         method  => "check_user_perms",
1177         api_name        => "open-ils.actor.user.perm.check",
1178         notes           => <<"  NOTES");
1179         Takes a login session, user id, an org id, and an array of perm type strings.  For each
1180         perm type, if the user does *not* have the given permission it is added
1181         to a list which is returned from the method.  If all permissions
1182         are allowed, an empty list is returned
1183         if the logged in user does not match 'user_id', then the logged in user must
1184         have VIEW_PERMISSION priveleges.
1185         NOTES
1186
1187 sub check_user_perms {
1188         my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1189
1190         my( $staff, $evt ) = $apputils->checkses($login_session);
1191         return $evt if $evt;
1192
1193         if($staff->id ne $user_id) {
1194                 if( my $evt = $apputils->check_perms(
1195                         $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1196                         return $evt;
1197                 }
1198         }
1199
1200         my @not_allowed;
1201         for my $perm (@$perm_types) {
1202                 if($apputils->check_perms($user_id, $org_id, $perm)) {
1203                         push @not_allowed, $perm;
1204                 }
1205         }
1206
1207         return \@not_allowed
1208 }
1209
1210 __PACKAGE__->register_method(
1211         method  => "check_user_perms2",
1212         api_name        => "open-ils.actor.user.perm.check.multi_org",
1213         notes           => q/
1214                 Checks the permissions on a list of perms and orgs for a user
1215                 @param authtoken The login session key
1216                 @param user_id The id of the user to check
1217                 @param orgs The array of org ids
1218                 @param perms The array of permission names
1219                 @return An array of  [ orgId, permissionName ] arrays that FAILED the check
1220                 if the logged in user does not match 'user_id', then the logged in user must
1221                 have VIEW_PERMISSION priveleges.
1222         /);
1223
1224 sub check_user_perms2 {
1225         my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1226
1227         my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1228                 $authtoken, $user_id, 'VIEW_PERMISSION' );
1229         return $evt if $evt;
1230
1231         my @not_allowed;
1232         for my $org (@$orgs) {
1233                 for my $perm (@$perms) {
1234                         if($apputils->check_perms($user_id, $org, $perm)) {
1235                                 push @not_allowed, [ $org, $perm ];
1236                         }
1237                 }
1238         }
1239
1240         return \@not_allowed
1241 }
1242
1243
1244 __PACKAGE__->register_method(
1245         method => 'check_user_perms3',
1246         api_name        => 'open-ils.actor.user.perm.highest_org',
1247         notes           => q/
1248                 Returns the highest org unit id at which a user has a given permission
1249                 If the requestor does not match the target user, the requestor must have
1250                 'VIEW_PERMISSION' rights at the home org unit of the target user
1251                 @param authtoken The login session key
1252                 @param userid The id of the user in question
1253                 @param perm The permission to check
1254                 @return The org unit highest in the org tree within which the user has
1255                 the requested permission
1256         /);
1257
1258 sub check_user_perms3 {
1259         my( $self, $client, $authtoken, $userid, $perm ) = @_;
1260
1261         my( $staff, $target, $org, $evt );
1262
1263         ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1264                 $authtoken, $userid, 'VIEW_PERMISSION' );
1265         return $evt if $evt;
1266
1267         my $tree = $self->get_org_tree();
1268         return _find_highest_perm_org( $perm, $userid, $target->ws_ou, $tree );
1269 }
1270
1271
1272 sub _find_highest_perm_org {
1273         my ( $perm, $userid, $start_org, $org_tree ) = @_;
1274         my $org = $apputils->find_org($org_tree, $start_org );
1275
1276         my $lastid = undef;
1277         while( $org ) {
1278                 last if ($apputils->check_perms( $userid, $org->id, $perm )); # perm failed
1279                 $lastid = $org->id;
1280                 $org = $apputils->find_org( $org_tree, $org->parent_ou() );
1281         }
1282
1283         return $lastid;
1284 }
1285
1286 __PACKAGE__->register_method(
1287         method => 'check_user_perms4',
1288         api_name        => 'open-ils.actor.user.perm.highest_org.batch',
1289         notes           => q/
1290                 Returns the highest org unit id at which a user has a given permission
1291                 If the requestor does not match the target user, the requestor must have
1292                 'VIEW_PERMISSION' rights at the home org unit of the target user
1293                 @param authtoken The login session key
1294                 @param userid The id of the user in question
1295                 @param perms An array of perm names to check 
1296                 @return An array of orgId's  representing the org unit 
1297                 highest in the org tree within which the user has the requested permission
1298                 The arrah of orgId's has matches the order of the perms array
1299         /);
1300
1301 sub check_user_perms4 {
1302         my( $self, $client, $authtoken, $userid, $perms ) = @_;
1303         
1304         my( $staff, $target, $org, $evt );
1305
1306         ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1307                 $authtoken, $userid, 'VIEW_PERMISSION' );
1308         return $evt if $evt;
1309
1310         my @arr;
1311         return [] unless ref($perms);
1312         my $tree = $self->get_org_tree();
1313
1314         for my $p (@$perms) {
1315                 push( @arr, _find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1316         }
1317         return \@arr;
1318 }
1319
1320
1321
1322
1323 __PACKAGE__->register_method(
1324         method  => "user_fines_summary",
1325         api_name        => "open-ils.actor.user.fines.summary",
1326         notes           => <<"  NOTES");
1327         Returns a short summary of the users total open fines, excluding voided fines
1328         Params are login_session, user_id
1329         Returns a 'mous' object.
1330         NOTES
1331
1332 sub user_fines_summary {
1333         my( $self, $client, $login_session, $user_id ) = @_;
1334
1335         my $user_obj = $apputils->check_user_session($login_session); 
1336         if($user_obj->id ne $user_id) {
1337                 if($apputils->check_user_perms($user_obj->id, $user_obj->home_ou, "VIEW_USER_FINES_SUMMARY")) {
1338                         return OpenILS::Perm->new("VIEW_USER_FINES_SUMMARY"); 
1339                 }
1340         }
1341
1342         return $apputils->simple_scalar_request( 
1343                 "open-ils.storage",
1344                 "open-ils.storage.direct.money.open_user_summary.search.usr",
1345                 $user_id );
1346
1347 }
1348
1349
1350
1351
1352 __PACKAGE__->register_method(
1353         method  => "user_transactions",
1354         api_name        => "open-ils.actor.user.transactions",
1355         notes           => <<"  NOTES");
1356         Returns a list of open user transactions (mbts objects);
1357         Params are login_session, user_id
1358         Optional third parameter is the transactions type.  defaults to all
1359         NOTES
1360
1361 __PACKAGE__->register_method(
1362         method  => "user_transactions",
1363         api_name        => "open-ils.actor.user.transactions.have_charge",
1364         notes           => <<"  NOTES");
1365         Returns a list of all open user transactions (mbts objects) that have an initial charge
1366         Params are login_session, user_id
1367         Optional third parameter is the transactions type.  defaults to all
1368         NOTES
1369
1370 __PACKAGE__->register_method(
1371         method  => "user_transactions",
1372         api_name        => "open-ils.actor.user.transactions.have_balance",
1373         notes           => <<"  NOTES");
1374         Returns a list of all open user transactions (mbts objects) that have a balance
1375         Params are login_session, user_id
1376         Optional third parameter is the transactions type.  defaults to all
1377         NOTES
1378
1379 __PACKAGE__->register_method(
1380         method  => "user_transactions",
1381         api_name        => "open-ils.actor.user.transactions.fleshed",
1382         notes           => <<"  NOTES");
1383         Returns an object/hash of transaction, circ, title where transaction = an open 
1384         user transactions (mbts objects), circ is the attached circluation, and title
1385         is the title the circ points to
1386         Params are login_session, user_id
1387         Optional third parameter is the transactions type.  defaults to all
1388         NOTES
1389
1390 __PACKAGE__->register_method(
1391         method  => "user_transactions",
1392         api_name        => "open-ils.actor.user.transactions.have_charge.fleshed",
1393         notes           => <<"  NOTES");
1394         Returns an object/hash of transaction, circ, title where transaction = an open 
1395         user transactions that has an initial charge (mbts objects), circ is the 
1396         attached circluation, and title is the title the circ points to
1397         Params are login_session, user_id
1398         Optional third parameter is the transactions type.  defaults to all
1399         NOTES
1400
1401 __PACKAGE__->register_method(
1402         method  => "user_transactions",
1403         api_name        => "open-ils.actor.user.transactions.have_balance.fleshed",
1404         notes           => <<"  NOTES");
1405         Returns an object/hash of transaction, circ, title where transaction = an open 
1406         user transaction that has a balance (mbts objects), circ is the attached 
1407         circluation, and title is the title the circ points to
1408         Params are login_session, user_id
1409         Optional third parameter is the transaction type.  defaults to all
1410         NOTES
1411
1412 __PACKAGE__->register_method(
1413         method  => "user_transactions",
1414         api_name        => "open-ils.actor.user.transactions.count",
1415         notes           => <<"  NOTES");
1416         Returns an object/hash of transaction, circ, title where transaction = an open 
1417         user transactions (mbts objects), circ is the attached circluation, and title
1418         is the title the circ points to
1419         Params are login_session, user_id
1420         Optional third parameter is the transactions type.  defaults to all
1421         NOTES
1422
1423 __PACKAGE__->register_method(
1424         method  => "user_transactions",
1425         api_name        => "open-ils.actor.user.transactions.have_charge.count",
1426         notes           => <<"  NOTES");
1427         Returns an object/hash of transaction, circ, title where transaction = an open 
1428         user transactions that has an initial charge (mbts objects), circ is the 
1429         attached circluation, and title is the title the circ points to
1430         Params are login_session, user_id
1431         Optional third parameter is the transactions type.  defaults to all
1432         NOTES
1433
1434 __PACKAGE__->register_method(
1435         method  => "user_transactions",
1436         api_name        => "open-ils.actor.user.transactions.have_balance.count",
1437         notes           => <<"  NOTES");
1438         Returns an object/hash of transaction, circ, title where transaction = an open 
1439         user transaction that has a balance (mbts objects), circ is the attached 
1440         circluation, and title is the title the circ points to
1441         Params are login_session, user_id
1442         Optional third parameter is the transaction type.  defaults to all
1443         NOTES
1444
1445 __PACKAGE__->register_method(
1446         method  => "user_transactions",
1447         api_name        => "open-ils.actor.user.transactions.have_balance.total",
1448         notes           => <<"  NOTES");
1449         Returns an object/hash of transaction, circ, title where transaction = an open 
1450         user transaction that has a balance (mbts objects), circ is the attached 
1451         circluation, and title is the title the circ points to
1452         Params are login_session, user_id
1453         Optional third parameter is the transaction type.  defaults to all
1454         NOTES
1455
1456
1457
1458 sub user_transactions {
1459         my( $self, $client, $login_session, $user_id, $type ) = @_;
1460
1461         my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1462                 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1463         return $evt if $evt;
1464         
1465         my $api = $self->api_name();
1466         my $trans;
1467         my @xact;
1468
1469         if(defined($type)) { @xact = (xact_type =>  $type); 
1470
1471         } else { @xact = (); }
1472
1473         if($api =~ /have_charge/o) {
1474
1475                 $trans = $apputils->simple_scalar_request( 
1476                         "open-ils.storage",
1477                         "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1478                         { usr => $user_id, total_owed => { ">" => 0 }, @xact });
1479
1480         } elsif($api =~ /have_balance/o) {
1481
1482                 $trans =  $apputils->simple_scalar_request( 
1483                         "open-ils.storage",
1484                         "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1485                         { usr => $user_id, balance_owed => { "<>" => 0 }, @xact });
1486
1487         } else {
1488
1489                 $trans =  $apputils->simple_scalar_request( 
1490                         "open-ils.storage",
1491                         "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1492                         { usr => $user_id, @xact });
1493         }
1494
1495         if($api =~ /total/o) { 
1496                 my $total = 0.0;
1497                 for my $t (@$trans) {
1498                         $total += $t->balance_owed;
1499                 }
1500
1501                 $logger->debug("Total balance owed by user $user_id: $total");
1502                 return $total;
1503         }
1504
1505         if($api =~ /count/o) { return scalar @$trans; }
1506         if($api !~ /fleshed/o) { return $trans; }
1507
1508         my @resp;
1509         for my $t (@$trans) {
1510                         
1511                 if( $t->xact_type ne 'circulation' ) {
1512                         push @resp, {transaction => $t};
1513                         next;
1514                 }
1515
1516                 my $circ = $apputils->simple_scalar_request(
1517                                 "open-ils.storage",
1518                                 "open-ils.storage.direct.action.circulation.retrieve",
1519                                 $t->id );
1520
1521                 next unless $circ;
1522
1523                 my $title = $apputils->simple_scalar_request(
1524                         "open-ils.storage", 
1525                         "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1526                         $circ->target_copy );
1527
1528                 next unless $title;
1529
1530                 my $u = OpenILS::Utils::ModsParser->new();
1531                 $u->start_mods_batch($title->marc());
1532                 my $mods = $u->finish_mods_batch();
1533
1534                 push @resp, {transaction => $t, circ => $circ, record => $mods };
1535
1536         }
1537
1538         return \@resp; 
1539
1540
1541
1542 __PACKAGE__->register_method(
1543         method  => "user_transaction_retrieve",
1544         api_name        => "open-ils.actor.user.transaction.fleshed.retrieve",
1545         argc            => 1,
1546         notes           => <<"  NOTES");
1547         Returns a fleshedtransaction record
1548         NOTES
1549 __PACKAGE__->register_method(
1550         method  => "user_transaction_retrieve",
1551         api_name        => "open-ils.actor.user.transaction.retrieve",
1552         argc            => 1,
1553         notes           => <<"  NOTES");
1554         Returns a transaction record
1555         NOTES
1556 sub user_transaction_retrieve {
1557         my( $self, $client, $login_session, $bill_id ) = @_;
1558
1559         my $trans = $apputils->simple_scalar_request( 
1560                 "open-ils.storage",
1561                 "open-ils.storage.direct.money.billable_transaction_summary.retrieve",
1562                 $bill_id
1563         );
1564
1565         my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1566                 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1567         return $evt if $evt;
1568         
1569         my $api = $self->api_name();
1570         if($api !~ /fleshed/o) { return $trans; }
1571
1572         if( $trans->xact_type ne 'circulation' ) {
1573                 $logger->debug("Returning non-circ transaction");
1574                 return {transaction => $trans};
1575         }
1576
1577         my $circ = $apputils->simple_scalar_request(
1578                         "open-ils.storage",
1579                         "open-ils.storage.direct.action.circulation.retrieve",
1580                         $trans->id );
1581
1582         return {transaction => $trans} unless $circ;
1583         $logger->debug("Found the circ transaction");
1584
1585         my $title = $apputils->simple_scalar_request(
1586                 "open-ils.storage", 
1587                 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1588                 $circ->target_copy );
1589
1590         return {transaction => $trans, circ => $circ } unless $title;
1591         $logger->debug("Found the circ title");
1592
1593         my $mods;
1594         try {
1595                 my $u = OpenILS::Utils::ModsParser->new();
1596                 $u->start_mods_batch($title->marc());
1597                 $mods = $u->finish_mods_batch();
1598         } otherwise {
1599                 if ($title->id == -1) {
1600                         my $copy = $apputils->simple_scalar_request(
1601                                 "open-ils.storage",
1602                                 "open-ils.storage.direct.asset.copy.retrieve",
1603                                 $circ->target_copy );
1604
1605                         $mods = new Fieldmapper::metabib::virtual_record;
1606                         $mods->doc_id(-1);
1607                         $mods->title($copy->dummy_title);
1608                         $mods->author($copy->dummy_author);
1609                 }
1610         };
1611
1612         $logger->debug("MODSized the circ title");
1613
1614         return {transaction => $trans, circ => $circ, record => $mods };
1615 }
1616
1617
1618 __PACKAGE__->register_method(
1619         method  => "hold_request_count",
1620         api_name        => "open-ils.actor.user.hold_requests.count",
1621         argc            => 1,
1622         notes           => <<"  NOTES");
1623         Returns hold ready/total counts
1624         NOTES
1625 sub hold_request_count {
1626         my( $self, $client, $login_session, $userid ) = @_;
1627
1628         my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1629                 $login_session, $userid, 'VIEW_HOLD' );
1630         return $evt if $evt;
1631         
1632
1633         my $holds = $apputils->simple_scalar_request(
1634                         "open-ils.storage",
1635                         "open-ils.storage.direct.action.hold_request.search_where.atomic",
1636                         { usr => $userid,
1637                           fulfillment_time => {"=" => undef } }
1638         );
1639
1640         my @ready;
1641         for my $h (@$holds) {
1642                 next unless $h->capture_time;
1643
1644                 my $copy = $apputils->simple_scalar_request(
1645                         "open-ils.storage",
1646                         "open-ils.storage.direct.asset.copy.retrieve",
1647                         $h->current_copy
1648                 );
1649
1650                 if ($copy->status == 8) {
1651                         push @ready, $h;
1652                 }
1653         }
1654
1655         return { total => scalar(@$holds), ready => scalar(@ready) };
1656 }
1657
1658
1659 __PACKAGE__->register_method(
1660         method  => "checkedout_count",
1661         api_name        => "open-ils.actor.user.checked_out.count__",
1662         argc            => 1,
1663         notes           => <<"  NOTES");
1664         Returns a transaction record
1665         NOTES
1666
1667 # XXX Deprecate Me
1668 sub checkedout_count {
1669         my( $self, $client, $login_session, $userid ) = @_;
1670
1671         my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1672                 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1673         return $evt if $evt;
1674         
1675         my $circs = $apputils->simple_scalar_request(
1676                         "open-ils.storage",
1677                         "open-ils.storage.direct.action.circulation.search_where.atomic",
1678                         { usr => $userid, stop_fines => undef }
1679                         #{ usr => $userid, checkin_time => {"=" => undef } }
1680         );
1681
1682         my $parser = DateTime::Format::ISO8601->new;
1683
1684         my (@out,@overdue);
1685         for my $c (@$circs) {
1686                 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1687                 my $due = $due_dt->epoch;
1688
1689                 if ($due < DateTime->today->epoch) {
1690                         push @overdue, $c;
1691                 }
1692         }
1693
1694         return { total => scalar(@$circs), overdue => scalar(@overdue) };
1695 }
1696
1697
1698 __PACKAGE__->register_method(
1699         method          => "checked_out",
1700         api_name                => "open-ils.actor.user.checked_out",
1701         argc                    => 2,
1702         signature       => q/
1703                 Returns a structure of circulations objects sorted by
1704                 out, overdue, lost, claims_returned, long_overdue.
1705                 A list of IDs are returned of each type.
1706                 lost, long_overdue, and claims_returned circ will not
1707                 be "finished" (there is an outstanding balance or some 
1708                 other pending action on the circ). 
1709
1710                 The .count method also includes a 'total' field which 
1711                 sums all "open" circs
1712         /
1713 );
1714
1715 __PACKAGE__->register_method(
1716         method          => "checked_out",
1717         api_name                => "open-ils.actor.user.checked_out.count",
1718         argc                    => 2,
1719         signature       => q/@see open-ils.actor.user.checked_out/
1720 );
1721
1722 sub checked_out {
1723         my( $self, $conn, $auth, $userid ) = @_;
1724
1725         my $e = new_editor(authtoken=>$auth);
1726         return $e->event unless $e->checkauth;
1727
1728         if( $userid ne $e->requestor->id ) {
1729                 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1730         }
1731
1732         my $count = $self->api_name =~ /count/;
1733         return _checked_out( $count, $e, $userid );
1734 }
1735
1736 sub _checked_out {
1737         my( $iscount, $e, $userid ) = @_;
1738
1739         my $circs = $e->search_action_circulation( 
1740                 { usr => $userid, stop_fines => undef });
1741
1742         my $parser = DateTime::Format::ISO8601->new;
1743
1744         # split the circs up into overdue and not-overdue circs
1745         my (@out,@overdue);
1746         for my $c (@$circs) {
1747                 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1748                 my $due = $due_dt->epoch;
1749                 if ($due < DateTime->today->epoch) {
1750                         push @overdue, $c->id;
1751                 } else {
1752                         push @out, $c->id;
1753                 }
1754         }
1755
1756         # grab all of the lost, claims-returned, and longoverdue circs
1757         my $open = $e->search_action_circulation(
1758                 {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1759
1760         my( @lost, @cr, @lo );
1761         for my $c (@$open) {
1762                 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1763                 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1764                 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1765         }
1766
1767
1768         if( $iscount ) {
1769                 return {
1770                         total           => @$circs + @lost + @cr + @lo,
1771                         out             => scalar(@out),
1772                         overdue => scalar(@overdue),
1773                         lost            => scalar(@lost),
1774                         claims_returned => scalar(@cr),
1775                         long_overdue            => scalar(@lo)
1776                 };
1777         }
1778
1779         return {
1780                 out             => \@out,
1781                 overdue => \@overdue,
1782                 lost            => \@lost,
1783                 claims_returned => \@cr,
1784                 long_overdue            => \@lo
1785         };
1786 }
1787
1788
1789
1790
1791
1792 __PACKAGE__->register_method(
1793         method  => "user_transaction_history",
1794         api_name        => "open-ils.actor.user.transactions.history",
1795         argc            => 1,
1796         notes           => <<"  NOTES");
1797         Returns a list of billable transaction ids for a user, optionally by type
1798         NOTES
1799 __PACKAGE__->register_method(
1800         method  => "user_transaction_history",
1801         api_name        => "open-ils.actor.user.transactions.history.have_charge",
1802         argc            => 1,
1803         notes           => <<"  NOTES");
1804         Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
1805         NOTES
1806 __PACKAGE__->register_method(
1807         method  => "user_transaction_history",
1808         api_name        => "open-ils.actor.user.transactions.history.have_balance",
1809         argc            => 1,
1810         notes           => <<"  NOTES");
1811         Returns a list of billable transaction ids for a user that have a balance, optionally by type
1812         NOTES
1813
1814 =head old
1815 sub _user_transaction_history {
1816         my( $self, $client, $login_session, $user_id, $type ) = @_;
1817
1818         my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1819                 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1820         return $evt if $evt;
1821
1822         my $api = $self->api_name();
1823         my @xact;
1824         my @charge;
1825         my @balance;
1826
1827         @xact = (xact_type =>  $type) if(defined($type));
1828         @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
1829         @charge  = (last_billing_ts => { "<>" => undef }) if $api =~ /have_charge/;
1830
1831         $logger->debug("searching for transaction history: @xact : @balance, @charge");
1832
1833         my $trans = $apputils->simple_scalar_request( 
1834                 "open-ils.storage",
1835                 "open-ils.storage.direct.money.billable_transaction_summary.search_where.atomic",
1836                 { usr => $user_id, @xact, @charge, @balance }, { order_by => 'xact_start DESC' });
1837
1838         return [ map { $_->id } @$trans ];
1839 }
1840 =cut
1841
1842
1843 sub user_transaction_history {
1844         my( $self, $conn, $auth, $userid, $type ) = @_;
1845         my $e = new_editor(authtoken=>$auth);
1846         return $e->event unless $e->checkauth;
1847         return $e->event unless $e->allowed('VIEW_USER_TRANSACTIONS');
1848
1849         my $api = $self->api_name;
1850         my @xact = (xact_type =>  $type) if(defined($type));
1851         my @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
1852         my @charge  = (last_billing_ts => { "!=" => undef }) if $api =~ /have_charge/;
1853
1854         return $e->search_money_billable_transaction_summary(
1855                 [
1856                         { usr => $userid, @xact, @charge, @balance }, 
1857                         { order_by => 'xact_start DESC' }
1858                 ], {idlist => 1});
1859 }
1860
1861
1862
1863 __PACKAGE__->register_method(
1864         method  => "user_perms",
1865         api_name        => "open-ils.actor.permissions.user_perms.retrieve",
1866         argc            => 1,
1867         notes           => <<"  NOTES");
1868         Returns a list of permissions
1869         NOTES
1870 sub user_perms {
1871         my( $self, $client, $authtoken, $user ) = @_;
1872
1873         my( $staff, $evt ) = $apputils->checkses($authtoken);
1874         return $evt if $evt;
1875
1876         $user ||= $staff->id;
1877
1878         if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
1879                 return $evt;
1880         }
1881
1882         return $apputils->simple_scalar_request(
1883                 "open-ils.storage",
1884                 "open-ils.storage.permission.user_perms.atomic",
1885                 $user);
1886 }
1887
1888 __PACKAGE__->register_method(
1889         method  => "retrieve_perms",
1890         api_name        => "open-ils.actor.permissions.retrieve",
1891         notes           => <<"  NOTES");
1892         Returns a list of permissions
1893         NOTES
1894 sub retrieve_perms {
1895         my( $self, $client ) = @_;
1896         return $apputils->simple_scalar_request(
1897                 "open-ils.storage",
1898                 "open-ils.storage.direct.permission.perm_list.retrieve.all.atomic");
1899 }
1900
1901 __PACKAGE__->register_method(
1902         method  => "retrieve_groups",
1903         api_name        => "open-ils.actor.groups.retrieve",
1904         notes           => <<"  NOTES");
1905         Returns a list of user groupss
1906         NOTES
1907 sub retrieve_groups {
1908         my( $self, $client ) = @_;
1909         return new_editor()->retrieve_all_permission_grp_tree();
1910 }
1911
1912 __PACKAGE__->register_method(
1913         method  => "retrieve_org_address",
1914         api_name        => "open-ils.actor.org_unit.address.retrieve",
1915         notes           => <<'  NOTES');
1916         Returns an org_unit address by ID
1917         @param An org_address ID
1918         NOTES
1919 sub retrieve_org_address {
1920         my( $self, $client, $id ) = @_;
1921         return $apputils->simple_scalar_request(
1922                 "open-ils.storage",
1923                 "open-ils.storage.direct.actor.org_address.retrieve",
1924                 $id
1925         );
1926 }
1927
1928 __PACKAGE__->register_method(
1929         method  => "retrieve_groups_tree",
1930         api_name        => "open-ils.actor.groups.tree.retrieve",
1931         notes           => <<"  NOTES");
1932         Returns a list of user groups
1933         NOTES
1934 sub retrieve_groups_tree {
1935         my( $self, $client ) = @_;
1936         my $groups = $apputils->simple_scalar_request(
1937                 "open-ils.storage",
1938                 "open-ils.storage.direct.permission.grp_tree.retrieve.all.atomic");
1939         return $self->build_group_tree($groups);        
1940 }
1941
1942
1943 # turns an org list into an org tree
1944 sub build_group_tree {
1945
1946         my( $self, $grplist) = @_;
1947
1948         return $grplist unless ( 
1949                         ref($grplist) and @$grplist > 1 );
1950
1951         my @list = sort { $a->name cmp $b->name } @$grplist;
1952
1953         my $root;
1954         for my $grp (@list) {
1955
1956                 if ($grp and !defined($grp->parent)) {
1957                         $root = $grp;
1958                         next;
1959                 }
1960                 my ($parent) = grep { $_->id == $grp->parent} @list;
1961
1962                 $parent->children([]) unless defined($parent->children); 
1963                 push( @{$parent->children}, $grp );
1964         }
1965
1966         return $root;
1967
1968 }
1969
1970
1971 __PACKAGE__->register_method(
1972         method  => "add_user_to_groups",
1973         api_name        => "open-ils.actor.user.set_groups",
1974         notes           => <<"  NOTES");
1975         Adds a user to one or more permission groups
1976         NOTES
1977
1978 sub add_user_to_groups {
1979         my( $self, $client, $authtoken, $userid, $groups ) = @_;
1980
1981         my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1982                 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
1983         return $evt if $evt;
1984
1985         ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1986                 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
1987         return $evt if $evt;
1988
1989         $apputils->simplereq(
1990                 'open-ils.storage',
1991                 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
1992                 
1993         for my $group (@$groups) {
1994                 my $link = Fieldmapper::permission::usr_grp_map->new;
1995                 $link->grp($group);
1996                 $link->usr($userid);
1997
1998                 my $id = $apputils->simplereq(
1999                         'open-ils.storage',
2000                         'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2001         }
2002
2003         return 1;
2004 }
2005
2006 __PACKAGE__->register_method(
2007         method  => "get_user_perm_groups",
2008         api_name        => "open-ils.actor.user.get_groups",
2009         notes           => <<"  NOTES");
2010         Retrieve a user's permission groups.
2011         NOTES
2012
2013
2014 sub get_user_perm_groups {
2015         my( $self, $client, $authtoken, $userid ) = @_;
2016
2017         my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2018                 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2019         return $evt if $evt;
2020
2021         return $apputils->simplereq(
2022                 'open-ils.storage',
2023                 'open-ils.storage.direct.permission.usr_grp_map.search.usr.atomic', $userid );
2024 }       
2025
2026
2027
2028 __PACKAGE__->register_method (
2029         method          => 'register_workstation',
2030         api_name                => 'open-ils.actor.workstation.register.override',
2031         signature       => q/@see open-ils.actor.workstation.register/);
2032
2033 __PACKAGE__->register_method (
2034         method          => 'register_workstation',
2035         api_name                => 'open-ils.actor.workstation.register',
2036         signature       => q/
2037                 Registers a new workstion in the system
2038                 @param authtoken The login session key
2039                 @param name The name of the workstation id
2040                 @param owner The org unit that owns this workstation
2041                 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2042                 if the name is already in use.
2043         /);
2044
2045 sub _register_workstation {
2046         my( $self, $connection, $authtoken, $name, $owner ) = @_;
2047         my( $requestor, $evt ) = $U->checkses($authtoken);
2048         return $evt if $evt;
2049         $evt = $U->check_perms($requestor->id, $owner, 'REGISTER_WORKSTATION');
2050         return $evt if $evt;
2051
2052         my $ws = $U->storagereq(
2053                 'open-ils.storage.direct.actor.workstation.search.name', $name );
2054         return OpenILS::Event->new('WORKSTATION_NAME_EXISTS') if $ws;
2055
2056         $ws = Fieldmapper::actor::workstation->new;
2057         $ws->owning_lib($owner);
2058         $ws->name($name);
2059
2060         my $id = $U->storagereq(
2061                 'open-ils.storage.direct.actor.workstation.create', $ws );
2062         return $U->DB_UPDATE_FAILED($ws) unless $id;
2063
2064         $ws->id($id);
2065         return $ws->id();
2066 }
2067
2068 sub register_workstation {
2069         my( $self, $conn, $authtoken, $name, $owner ) = @_;
2070
2071         my $e = new_editor(authtoken=>$authtoken, xact=>1);
2072         return $e->event unless $e->checkauth;
2073         return $e->event unless $e->allowed('REGISTER_WORKSTATION'); # XXX rely on editor perms
2074         my $existing = $e->search_actor_workstation({name => $name});
2075
2076         if( @$existing ) {
2077                 if( $self->api_name =~ /override/o ) {
2078                         return $e->event unless $e->allowed('DELETE_WORKSTATION'); # XXX rely on editor perms
2079                         return $e->event unless $e->delete_actor_workstation($$existing[0]);
2080                 } else {
2081                         return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2082                 }
2083         }
2084
2085         my $ws = Fieldmapper::actor::workstation->new;
2086         $ws->owning_lib($owner);
2087         $ws->name($name);
2088         $e->create_actor_workstation($ws) or return $e->event;
2089         $e->commit;
2090         return $ws->id; # note: editor sets the id on the new object for us
2091 }
2092
2093
2094 __PACKAGE__->register_method (
2095         method          => 'fetch_patron_note',
2096         api_name                => 'open-ils.actor.note.retrieve.all',
2097         signature       => q/
2098                 Returns a list of notes for a given user
2099                 Requestor must have VIEW_USER permission if pub==false and
2100                 @param authtoken The login session key
2101                 @param args Hash of params including
2102                         patronid : the patron's id
2103                         pub : true if retrieving only public notes
2104         /
2105 );
2106
2107 sub fetch_patron_note {
2108         my( $self, $conn, $authtoken, $args ) = @_;
2109         my $patronid = $$args{patronid};
2110
2111         my($reqr, $evt) = $U->checkses($authtoken);
2112
2113         my $patron;
2114         ($patron, $evt) = $U->fetch_user($patronid);
2115         return $evt if $evt;
2116
2117         if($$args{pub}) {
2118                 if( $patronid ne $reqr->id ) {
2119                         $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2120                         return $evt if $evt;
2121                 }
2122                 return $U->storagereq(
2123                         'open-ils.storage.direct.actor.usr_note.search_where.atomic', 
2124                         { usr => $patronid, pub => 't' } );
2125         }
2126
2127         $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2128         return $evt if $evt;
2129
2130         return $U->storagereq(
2131                 'open-ils.storage.direct.actor.usr_note.search.usr.atomic', $patronid );
2132 }
2133
2134 __PACKAGE__->register_method (
2135         method          => 'create_user_note',
2136         api_name                => 'open-ils.actor.note.create',
2137         signature       => q/
2138                 Creates a new note for the given user
2139                 @param authtoken The login session key
2140                 @param note The note object
2141         /
2142 );
2143 sub create_user_note {
2144         my( $self, $conn, $authtoken, $note ) = @_;
2145         my( $reqr, $patron, $evt ) = 
2146                 $U->checkses_requestor($authtoken, $note->usr, 'UPDATE_USER');
2147         return $evt if $evt;
2148         $logger->activity("user ".$reqr->id." creating note for user ".$note->usr);
2149
2150         $note->pub('f') unless $note->pub;
2151         $note->creator($reqr->id);
2152         my $id = $U->storagereq(
2153                 'open-ils.storage.direct.actor.usr_note.create', $note );
2154         return $U->DB_UPDATE_FAILED($note) unless $id;
2155         return $id;
2156 }
2157
2158
2159 __PACKAGE__->register_method (
2160         method          => 'delete_user_note',
2161         api_name                => 'open-ils.actor.note.delete',
2162         signature       => q/
2163                 Deletes a note for the given user
2164                 @param authtoken The login session key
2165                 @param noteid The note id
2166         /
2167 );
2168 sub delete_user_note {
2169         my( $self, $conn, $authtoken, $noteid ) = @_;
2170
2171         my $note = $U->storagereq(
2172                 'open-ils.storage.direct.actor.usr_note.retrieve', $noteid);
2173         return OpenILS::Event->new('ACTOR_USER_NOTE_NOT_FOUND') unless $note;
2174
2175         my( $reqr, $patron, $evt ) = 
2176                 $U->checkses_requestor($authtoken, $note->usr, 'UPDATE_USER');
2177         return $evt if $evt;
2178         $logger->activity("user ".$reqr->id." deleting note [$noteid] for user ".$note->usr);
2179
2180         my $stat = $U->storagereq(
2181                 'open-ils.storage.direct.actor.usr_note.delete', $noteid );
2182         return $U->DB_UPDATE_FAILED($note) unless defined $stat;
2183         return $stat;
2184 }
2185
2186
2187
2188 __PACKAGE__->register_method (
2189         method          => 'create_closed_date',
2190         api_name        => 'open-ils.actor.org_unit.closed_date.create',
2191         signature       => q/
2192                 Creates a new closing entry for the given org_unit
2193                 @param authtoken The login session key
2194                 @param note The closed_date object
2195         /
2196 );
2197 sub create_closed_date {
2198         my( $self, $conn, $authtoken, $cd ) = @_;
2199
2200         my( $user, $evt ) = $U->checkses($authtoken);
2201         return $evt if $evt;
2202
2203         $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2204         return $evt if $evt;
2205
2206         $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2207
2208         my $id = $U->storagereq(
2209                 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2210         return $U->DB_UPDATE_FAILED($cd) unless $id;
2211         return $id;
2212 }
2213
2214
2215 __PACKAGE__->register_method (
2216         method          => 'delete_closed_date',
2217         api_name        => 'open-ils.actor.org_unit.closed_date.delete',
2218         signature       => q/
2219                 Deletes a closing entry for the given org_unit
2220                 @param authtoken The login session key
2221                 @param noteid The close_date id
2222         /
2223 );
2224 sub delete_closed_date {
2225         my( $self, $conn, $authtoken, $cd ) = @_;
2226
2227         my( $user, $evt ) = $U->checkses($authtoken);
2228         return $evt if $evt;
2229
2230         my $cd_obj;
2231         ($cd_obj, $evt) = fetch_closed_date($cd);
2232         return $evt if $evt;
2233
2234         $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2235         return $evt if $evt;
2236
2237         $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2238
2239         my $stat = $U->storagereq(
2240                 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2241         return $U->DB_UPDATE_FAILED($cd) unless $stat;
2242         return $stat;
2243 }
2244
2245
2246 __PACKAGE__->register_method(
2247         method => 'usrname_exists',
2248         api_name        => 'open-ils.actor.username.exists',
2249         signature => q/
2250                 Returns 1 if the requested username exists, returns 0 otherwise
2251         /
2252 );
2253
2254 sub usrname_exists {
2255         my( $self, $conn, $auth, $usrname ) = @_;
2256         my $e = new_editor(authtoken=>$auth);
2257         return $e->event unless $e->checkauth;
2258         my $a = $e->search_actor_user({usrname => $usrname}, {idlist=>1});
2259         return $$a[0] if $a and @$a;
2260         return 0;
2261 }
2262
2263 __PACKAGE__->register_method(
2264         method => 'barcode_exists',
2265         api_name        => 'open-ils.actor.barcode.exists',
2266         signature => q/
2267                 Returns 1 if the requested barcode exists, returns 0 otherwise
2268         /
2269 );
2270
2271 sub barcode_exists {
2272         my( $self, $conn, $auth, $barcode ) = @_;
2273         my $e = new_editor(authtoken=>$auth);
2274         return $e->event unless $e->checkauth;
2275         my $a = $e->search_actor_card({barcode => $barcode}, {idlist=>1});
2276         return $$a[0] if $a and @$a;
2277         return 0;
2278 }
2279
2280
2281 __PACKAGE__->register_method(
2282         method => 'retrieve_net_levels',
2283         api_name        => 'open-ils.actor.net_access_level.retrieve.all',
2284 );
2285
2286 sub retrieve_net_levels {
2287         my( $self, $conn, $auth ) = @_;
2288         my $e = new_editor(authtoken=>$auth);
2289         return $e->event unless $e->checkauth;
2290         return $e->retrieve_all_config_net_access_level();
2291 }
2292
2293
2294
2295 1;
2296