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