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