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