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