]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/Application/Actor.pm
sanity checking the hold request
[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
1532                 push @resp, {transaction => $t, circ => $circ, record => $mods };
1533
1534         }
1535
1536         return \@resp; 
1537
1538
1539
1540 __PACKAGE__->register_method(
1541         method  => "user_transaction_retrieve",
1542         api_name        => "open-ils.actor.user.transaction.fleshed.retrieve",
1543         argc            => 1,
1544         notes           => <<"  NOTES");
1545         Returns a fleshedtransaction record
1546         NOTES
1547 __PACKAGE__->register_method(
1548         method  => "user_transaction_retrieve",
1549         api_name        => "open-ils.actor.user.transaction.retrieve",
1550         argc            => 1,
1551         notes           => <<"  NOTES");
1552         Returns a transaction record
1553         NOTES
1554 sub user_transaction_retrieve {
1555         my( $self, $client, $login_session, $bill_id ) = @_;
1556
1557         my $trans = $apputils->simple_scalar_request( 
1558                 "open-ils.cstore",
1559                 "open-ils.cstore.direct.money.billable_transaction_summary.retrieve",
1560                 $bill_id
1561         );
1562
1563         my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1564                 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1565         return $evt if $evt;
1566         
1567         my $api = $self->api_name();
1568         if($api !~ /fleshed/o) { return $trans; }
1569
1570         if( $trans->xact_type ne 'circulation' ) {
1571                 $logger->debug("Returning non-circ transaction");
1572                 return {transaction => $trans};
1573         }
1574
1575         my $circ = $apputils->simple_scalar_request(
1576                         "open-ils.cstore",
1577                         "open-ils..direct.action.circulation.retrieve",
1578                         $trans->id );
1579
1580         return {transaction => $trans} unless $circ;
1581         $logger->debug("Found the circ transaction");
1582
1583         my $title = $apputils->simple_scalar_request(
1584                 "open-ils.storage", 
1585                 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1586                 $circ->target_copy );
1587
1588         return {transaction => $trans, circ => $circ } unless $title;
1589         $logger->debug("Found the circ title");
1590
1591         my $mods;
1592         try {
1593                 my $u = OpenILS::Utils::ModsParser->new();
1594                 $u->start_mods_batch($title->marc());
1595                 $mods = $u->finish_mods_batch();
1596         } otherwise {
1597                 if ($title->id == -1) {
1598                         my $copy = $apputils->simple_scalar_request(
1599                                 "open-ils.cstore",
1600                                 "open-ils.cstore.direct.asset.copy.retrieve",
1601                                 $circ->target_copy );
1602
1603                         $mods = new Fieldmapper::metabib::virtual_record;
1604                         $mods->doc_id(-1);
1605                         $mods->title($copy->dummy_title);
1606                         $mods->author($copy->dummy_author);
1607                 }
1608         };
1609
1610         $logger->debug("MODSized the circ title");
1611
1612         return {transaction => $trans, circ => $circ, record => $mods };
1613 }
1614
1615
1616 __PACKAGE__->register_method(
1617         method  => "hold_request_count",
1618         api_name        => "open-ils.actor.user.hold_requests.count",
1619         argc            => 1,
1620         notes           => <<"  NOTES");
1621         Returns hold ready/total counts
1622         NOTES
1623 sub hold_request_count {
1624         my( $self, $client, $login_session, $userid ) = @_;
1625
1626         my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1627                 $login_session, $userid, 'VIEW_HOLD' );
1628         return $evt if $evt;
1629         
1630
1631         my $holds = $apputils->simple_scalar_request(
1632                         "open-ils.cstore",
1633                         "open-ils.cstore.direct.action.hold_request.search.atomic",
1634                         { usr => $userid,
1635                           fulfillment_time => {"=" => undef } }
1636         );
1637
1638         my @ready;
1639         for my $h (@$holds) {
1640                 next unless $h->capture_time and $h->current_copy;
1641
1642                 my $copy = $apputils->simple_scalar_request(
1643                         "open-ils.cstore",
1644                         "open-ils.cstore.direct.asset.copy.retrieve",
1645                         $h->current_copy
1646                 );
1647
1648                 if ($copy and $copy->status == 8) {
1649                         push @ready, $h;
1650                 }
1651         }
1652
1653         return { total => scalar(@$holds), ready => scalar(@ready) };
1654 }
1655
1656
1657 __PACKAGE__->register_method(
1658         method  => "checkedout_count",
1659         api_name        => "open-ils.actor.user.checked_out.count__",
1660         argc            => 1,
1661         notes           => <<"  NOTES");
1662         Returns a transaction record
1663         NOTES
1664
1665 # XXX Deprecate Me
1666 sub checkedout_count {
1667         my( $self, $client, $login_session, $userid ) = @_;
1668
1669         my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1670                 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1671         return $evt if $evt;
1672         
1673         my $circs = $apputils->simple_scalar_request(
1674                         "open-ils.cstore",
1675                         "open-ils.cstore.direct.action.circulation.search.atomic",
1676                         { usr => $userid, stop_fines => undef }
1677                         #{ usr => $userid, checkin_time => {"=" => undef } }
1678         );
1679
1680         my $parser = DateTime::Format::ISO8601->new;
1681
1682         my (@out,@overdue);
1683         for my $c (@$circs) {
1684                 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1685                 my $due = $due_dt->epoch;
1686
1687                 if ($due < DateTime->today->epoch) {
1688                         push @overdue, $c;
1689                 }
1690         }
1691
1692         return { total => scalar(@$circs), overdue => scalar(@overdue) };
1693 }
1694
1695
1696 __PACKAGE__->register_method(
1697         method          => "checked_out",
1698         api_name                => "open-ils.actor.user.checked_out",
1699         argc                    => 2,
1700         signature       => q/
1701                 Returns a structure of circulations objects sorted by
1702                 out, overdue, lost, claims_returned, long_overdue.
1703                 A list of IDs are returned of each type.
1704                 lost, long_overdue, and claims_returned circ will not
1705                 be "finished" (there is an outstanding balance or some 
1706                 other pending action on the circ). 
1707
1708                 The .count method also includes a 'total' field which 
1709                 sums all "open" circs
1710         /
1711 );
1712
1713 __PACKAGE__->register_method(
1714         method          => "checked_out",
1715         api_name                => "open-ils.actor.user.checked_out.count",
1716         argc                    => 2,
1717         signature       => q/@see open-ils.actor.user.checked_out/
1718 );
1719
1720 sub checked_out {
1721         my( $self, $conn, $auth, $userid ) = @_;
1722
1723         my $e = new_editor(authtoken=>$auth);
1724         return $e->event unless $e->checkauth;
1725
1726         if( $userid ne $e->requestor->id ) {
1727                 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1728         }
1729
1730         my $count = $self->api_name =~ /count/;
1731         return _checked_out( $count, $e, $userid );
1732 }
1733
1734 sub _checked_out {
1735         my( $iscount, $e, $userid ) = @_;
1736
1737         my $circs = $e->search_action_circulation( 
1738                 { usr => $userid, stop_fines => undef });
1739
1740         my $parser = DateTime::Format::ISO8601->new;
1741
1742         # split the circs up into overdue and not-overdue circs
1743         my (@out,@overdue);
1744         for my $c (@$circs) {
1745                 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1746                 my $due = $due_dt->epoch;
1747                 if ($due < DateTime->today->epoch) {
1748                         push @overdue, $c->id;
1749                 } else {
1750                         push @out, $c->id;
1751                 }
1752         }
1753
1754         # grab all of the lost, claims-returned, and longoverdue circs
1755         my $open = $e->search_action_circulation(
1756                 {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1757
1758         my( @lost, @cr, @lo );
1759         for my $c (@$open) {
1760                 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1761                 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1762                 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1763         }
1764
1765
1766         if( $iscount ) {
1767                 return {
1768                         total           => @$circs + @lost + @cr + @lo,
1769                         out             => scalar(@out),
1770                         overdue => scalar(@overdue),
1771                         lost            => scalar(@lost),
1772                         claims_returned => scalar(@cr),
1773                         long_overdue            => scalar(@lo)
1774                 };
1775         }
1776
1777         return {
1778                 out             => \@out,
1779                 overdue => \@overdue,
1780                 lost            => \@lost,
1781                 claims_returned => \@cr,
1782                 long_overdue            => \@lo
1783         };
1784 }
1785
1786
1787
1788
1789
1790 __PACKAGE__->register_method(
1791         method  => "user_transaction_history",
1792         api_name        => "open-ils.actor.user.transactions.history",
1793         argc            => 1,
1794         notes           => <<"  NOTES");
1795         Returns a list of billable transaction ids for a user, optionally by type
1796         NOTES
1797 __PACKAGE__->register_method(
1798         method  => "user_transaction_history",
1799         api_name        => "open-ils.actor.user.transactions.history.have_charge",
1800         argc            => 1,
1801         notes           => <<"  NOTES");
1802         Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
1803         NOTES
1804 __PACKAGE__->register_method(
1805         method  => "user_transaction_history",
1806         api_name        => "open-ils.actor.user.transactions.history.have_balance",
1807         argc            => 1,
1808         notes           => <<"  NOTES");
1809         Returns a list of billable transaction ids for a user that have a balance, optionally by type
1810         NOTES
1811
1812 =head old
1813 sub _user_transaction_history {
1814         my( $self, $client, $login_session, $user_id, $type ) = @_;
1815
1816         my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1817                 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1818         return $evt if $evt;
1819
1820         my $api = $self->api_name();
1821         my @xact;
1822         my @charge;
1823         my @balance;
1824
1825         @xact = (xact_type =>  $type) if(defined($type));
1826         @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
1827         @charge  = (last_billing_ts => { "<>" => undef }) if $api =~ /have_charge/;
1828
1829         $logger->debug("searching for transaction history: @xact : @balance, @charge");
1830
1831         my $trans = $apputils->simple_scalar_request( 
1832                 "open-ils.cstore",
1833                 "open-ils.cstore.direct.money.billable_transaction_summary.search.atomic",
1834                 { usr => $user_id, @xact, @charge, @balance }, { order_by => { mbts => 'xact_start DESC' } });
1835
1836         return [ map { $_->id } @$trans ];
1837 }
1838 =cut
1839
1840
1841 sub user_transaction_history {
1842         my( $self, $conn, $auth, $userid, $type ) = @_;
1843         my $e = new_editor(authtoken=>$auth);
1844         return $e->event unless $e->checkauth;
1845         return $e->event unless $e->allowed('VIEW_USER_TRANSACTIONS');
1846
1847         my $api = $self->api_name;
1848         my @xact = (xact_type =>  $type) if(defined($type));
1849         my @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
1850         my @charge  = (last_billing_ts => { "!=" => undef }) if $api =~ /have_charge/;
1851
1852         return $e->search_money_billable_transaction_summary(
1853                 [
1854                         { usr => $userid, @xact, @charge, @balance }, 
1855                         { order_by => 'xact_start DESC' }
1856                 ], {idlist => 1});
1857 }
1858
1859
1860
1861 __PACKAGE__->register_method(
1862         method  => "user_perms",
1863         api_name        => "open-ils.actor.permissions.user_perms.retrieve",
1864         argc            => 1,
1865         notes           => <<"  NOTES");
1866         Returns a list of permissions
1867         NOTES
1868 sub user_perms {
1869         my( $self, $client, $authtoken, $user ) = @_;
1870
1871         my( $staff, $evt ) = $apputils->checkses($authtoken);
1872         return $evt if $evt;
1873
1874         $user ||= $staff->id;
1875
1876         if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
1877                 return $evt;
1878         }
1879
1880         return $apputils->simple_scalar_request(
1881                 "open-ils.storage",
1882                 "open-ils.storage.permission.user_perms.atomic",
1883                 $user);
1884 }
1885
1886 __PACKAGE__->register_method(
1887         method  => "retrieve_perms",
1888         api_name        => "open-ils.actor.permissions.retrieve",
1889         notes           => <<"  NOTES");
1890         Returns a list of permissions
1891         NOTES
1892 sub retrieve_perms {
1893         my( $self, $client ) = @_;
1894         return $apputils->simple_scalar_request(
1895                 "open-ils.cstore",
1896                 "open-ils.cstore.direct.permission.perm_list.search.atomic",
1897                 { id => { '!=' => undef } }
1898         );
1899 }
1900
1901 __PACKAGE__->register_method(
1902         method  => "retrieve_groups",
1903         api_name        => "open-ils.actor.groups.retrieve",
1904         notes           => <<"  NOTES");
1905         Returns a list of user groupss
1906         NOTES
1907 sub retrieve_groups {
1908         my( $self, $client ) = @_;
1909         return new_editor()->retrieve_all_permission_grp_tree();
1910 }
1911
1912 __PACKAGE__->register_method(
1913         method  => "retrieve_org_address",
1914         api_name        => "open-ils.actor.org_unit.address.retrieve",
1915         notes           => <<'  NOTES');
1916         Returns an org_unit address by ID
1917         @param An org_address ID
1918         NOTES
1919 sub retrieve_org_address {
1920         my( $self, $client, $id ) = @_;
1921         return $apputils->simple_scalar_request(
1922                 "open-ils.cstore",
1923                 "open-ils.cstore.direct.actor.org_address.retrieve",
1924                 $id
1925         );
1926 }
1927
1928 __PACKAGE__->register_method(
1929         method  => "retrieve_groups_tree",
1930         api_name        => "open-ils.actor.groups.tree.retrieve",
1931         notes           => <<"  NOTES");
1932         Returns a list of user groups
1933         NOTES
1934 sub retrieve_groups_tree {
1935         my( $self, $client ) = @_;
1936         return new_editor()->search_permission_grp_tree(
1937                 [
1938                         { parent => undef},
1939                         {       
1940                                 flesh                           => 10, 
1941                                 flesh_fields    => { pgt => ["children"] }, 
1942                                 order_by                        => { pgt => 'name'}
1943                         }
1944                 ]
1945         )->[0];
1946 }
1947
1948
1949 # turns an org list into an org tree
1950 =head old code
1951 sub build_group_tree {
1952
1953         my( $self, $grplist) = @_;
1954
1955         return $grplist unless ( 
1956                         ref($grplist) and @$grplist > 1 );
1957
1958         my @list = sort { $a->name cmp $b->name } @$grplist;
1959
1960         my $root;
1961         for my $grp (@list) {
1962
1963                 if ($grp and !defined($grp->parent)) {
1964                         $root = $grp;
1965                         next;
1966                 }
1967                 my ($parent) = grep { $_->id == $grp->parent} @list;
1968
1969                 $parent->children([]) unless defined($parent->children); 
1970                 push( @{$parent->children}, $grp );
1971         }
1972
1973         return $root;
1974 }
1975 =cut
1976
1977
1978 __PACKAGE__->register_method(
1979         method  => "add_user_to_groups",
1980         api_name        => "open-ils.actor.user.set_groups",
1981         notes           => <<"  NOTES");
1982         Adds a user to one or more permission groups
1983         NOTES
1984
1985 sub add_user_to_groups {
1986         my( $self, $client, $authtoken, $userid, $groups ) = @_;
1987
1988         my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1989                 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
1990         return $evt if $evt;
1991
1992         ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1993                 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
1994         return $evt if $evt;
1995
1996         $apputils->simplereq(
1997                 'open-ils.storage',
1998                 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
1999                 
2000         for my $group (@$groups) {
2001                 my $link = Fieldmapper::permission::usr_grp_map->new;
2002                 $link->grp($group);
2003                 $link->usr($userid);
2004
2005                 my $id = $apputils->simplereq(
2006                         'open-ils.storage',
2007                         'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2008         }
2009
2010         return 1;
2011 }
2012
2013 __PACKAGE__->register_method(
2014         method  => "get_user_perm_groups",
2015         api_name        => "open-ils.actor.user.get_groups",
2016         notes           => <<"  NOTES");
2017         Retrieve a user's permission groups.
2018         NOTES
2019
2020
2021 sub get_user_perm_groups {
2022         my( $self, $client, $authtoken, $userid ) = @_;
2023
2024         my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2025                 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2026         return $evt if $evt;
2027
2028         return $apputils->simplereq(
2029                 'open-ils.cstore',
2030                 'open-ils.cstore.direct.permission.usr_grp_map.search.atomic', { usr => $userid } );
2031 }       
2032
2033
2034
2035 __PACKAGE__->register_method (
2036         method          => 'register_workstation',
2037         api_name                => 'open-ils.actor.workstation.register.override',
2038         signature       => q/@see open-ils.actor.workstation.register/);
2039
2040 __PACKAGE__->register_method (
2041         method          => 'register_workstation',
2042         api_name                => 'open-ils.actor.workstation.register',
2043         signature       => q/
2044                 Registers a new workstion in the system
2045                 @param authtoken The login session key
2046                 @param name The name of the workstation id
2047                 @param owner The org unit that owns this workstation
2048                 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2049                 if the name is already in use.
2050         /);
2051
2052 sub _register_workstation {
2053         my( $self, $connection, $authtoken, $name, $owner ) = @_;
2054         my( $requestor, $evt ) = $U->checkses($authtoken);
2055         return $evt if $evt;
2056         $evt = $U->check_perms($requestor->id, $owner, 'REGISTER_WORKSTATION');
2057         return $evt if $evt;
2058
2059         my $ws = $U->cstorereq(
2060                 'open-ils.cstore.direct.actor.workstation.search', { name => $name } );
2061         return OpenILS::Event->new('WORKSTATION_NAME_EXISTS') if $ws;
2062
2063         $ws = Fieldmapper::actor::workstation->new;
2064         $ws->owning_lib($owner);
2065         $ws->name($name);
2066
2067         my $id = $U->storagereq(
2068                 'open-ils.storage.direct.actor.workstation.create', $ws );
2069         return $U->DB_UPDATE_FAILED($ws) unless $id;
2070
2071         $ws->id($id);
2072         return $ws->id();
2073 }
2074
2075 sub register_workstation {
2076         my( $self, $conn, $authtoken, $name, $owner ) = @_;
2077
2078         my $e = new_editor(authtoken=>$authtoken, xact=>1);
2079         return $e->event unless $e->checkauth;
2080         return $e->event unless $e->allowed('REGISTER_WORKSTATION'); # XXX rely on editor perms
2081         my $existing = $e->search_actor_workstation({name => $name});
2082
2083         if( @$existing ) {
2084                 if( $self->api_name =~ /override/o ) {
2085                         return $e->event unless $e->allowed('DELETE_WORKSTATION'); # XXX rely on editor perms
2086                         return $e->event unless $e->delete_actor_workstation($$existing[0]);
2087                 } else {
2088                         return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2089                 }
2090         }
2091
2092         my $ws = Fieldmapper::actor::workstation->new;
2093         $ws->owning_lib($owner);
2094         $ws->name($name);
2095         $e->create_actor_workstation($ws) or return $e->event;
2096         $e->commit;
2097         return $ws->id; # note: editor sets the id on the new object for us
2098 }
2099
2100
2101 __PACKAGE__->register_method (
2102         method          => 'fetch_patron_note',
2103         api_name                => 'open-ils.actor.note.retrieve.all',
2104         signature       => q/
2105                 Returns a list of notes for a given user
2106                 Requestor must have VIEW_USER permission if pub==false and
2107                 @param authtoken The login session key
2108                 @param args Hash of params including
2109                         patronid : the patron's id
2110                         pub : true if retrieving only public notes
2111         /
2112 );
2113
2114 sub fetch_patron_note {
2115         my( $self, $conn, $authtoken, $args ) = @_;
2116         my $patronid = $$args{patronid};
2117
2118         my($reqr, $evt) = $U->checkses($authtoken);
2119
2120         my $patron;
2121         ($patron, $evt) = $U->fetch_user($patronid);
2122         return $evt if $evt;
2123
2124         if($$args{pub}) {
2125                 if( $patronid ne $reqr->id ) {
2126                         $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2127                         return $evt if $evt;
2128                 }
2129                 return $U->cstorereq(
2130                         'open-ils.cstore.direct.actor.usr_note.search.atomic', 
2131                         { usr => $patronid, pub => 't' } );
2132         }
2133
2134         $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2135         return $evt if $evt;
2136
2137         return $U->cstorereq(
2138                 'open-ils.cstore.direct.actor.usr_note.search.atomic', { usr => $patronid } );
2139 }
2140
2141 __PACKAGE__->register_method (
2142         method          => 'create_user_note',
2143         api_name                => 'open-ils.actor.note.create',
2144         signature       => q/
2145                 Creates a new note for the given user
2146                 @param authtoken The login session key
2147                 @param note The note object
2148         /
2149 );
2150 sub create_user_note {
2151         my( $self, $conn, $authtoken, $note ) = @_;
2152         my( $reqr, $patron, $evt ) = 
2153                 $U->checkses_requestor($authtoken, $note->usr, 'UPDATE_USER');
2154         return $evt if $evt;
2155         $logger->activity("user ".$reqr->id." creating note for user ".$note->usr);
2156
2157         $note->pub('f') unless $note->pub;
2158         $note->creator($reqr->id);
2159         my $id = $U->storagereq(
2160                 'open-ils.storage.direct.actor.usr_note.create', $note );
2161         return $U->DB_UPDATE_FAILED($note) unless $id;
2162         return $id;
2163 }
2164
2165
2166 __PACKAGE__->register_method (
2167         method          => 'delete_user_note',
2168         api_name                => 'open-ils.actor.note.delete',
2169         signature       => q/
2170                 Deletes a note for the given user
2171                 @param authtoken The login session key
2172                 @param noteid The note id
2173         /
2174 );
2175 sub delete_user_note {
2176         my( $self, $conn, $authtoken, $noteid ) = @_;
2177
2178         my $note = $U->cstorereq(
2179                 'open-ils.cstore.direct.actor.usr_note.retrieve', $noteid);
2180         return OpenILS::Event->new('ACTOR_USER_NOTE_NOT_FOUND') unless $note;
2181
2182         my( $reqr, $patron, $evt ) = 
2183                 $U->checkses_requestor($authtoken, $note->usr, 'UPDATE_USER');
2184         return $evt if $evt;
2185         $logger->activity("user ".$reqr->id." deleting note [$noteid] for user ".$note->usr);
2186
2187         my $stat = $U->storagereq(
2188                 'open-ils.storage.direct.actor.usr_note.delete', $noteid );
2189         return $U->DB_UPDATE_FAILED($note) unless defined $stat;
2190         return $stat;
2191 }
2192
2193
2194
2195 __PACKAGE__->register_method (
2196         method          => 'create_closed_date',
2197         api_name        => 'open-ils.actor.org_unit.closed_date.create',
2198         signature       => q/
2199                 Creates a new closing entry for the given org_unit
2200                 @param authtoken The login session key
2201                 @param note The closed_date object
2202         /
2203 );
2204 sub create_closed_date {
2205         my( $self, $conn, $authtoken, $cd ) = @_;
2206
2207         my( $user, $evt ) = $U->checkses($authtoken);
2208         return $evt if $evt;
2209
2210         $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2211         return $evt if $evt;
2212
2213         $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2214
2215         my $id = $U->storagereq(
2216                 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2217         return $U->DB_UPDATE_FAILED($cd) unless $id;
2218         return $id;
2219 }
2220
2221
2222 __PACKAGE__->register_method (
2223         method          => 'delete_closed_date',
2224         api_name        => 'open-ils.actor.org_unit.closed_date.delete',
2225         signature       => q/
2226                 Deletes a closing entry for the given org_unit
2227                 @param authtoken The login session key
2228                 @param noteid The close_date id
2229         /
2230 );
2231 sub delete_closed_date {
2232         my( $self, $conn, $authtoken, $cd ) = @_;
2233
2234         my( $user, $evt ) = $U->checkses($authtoken);
2235         return $evt if $evt;
2236
2237         my $cd_obj;
2238         ($cd_obj, $evt) = fetch_closed_date($cd);
2239         return $evt if $evt;
2240
2241         $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2242         return $evt if $evt;
2243
2244         $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2245
2246         my $stat = $U->storagereq(
2247                 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2248         return $U->DB_UPDATE_FAILED($cd) unless $stat;
2249         return $stat;
2250 }
2251
2252
2253 __PACKAGE__->register_method(
2254         method => 'usrname_exists',
2255         api_name        => 'open-ils.actor.username.exists',
2256         signature => q/
2257                 Returns 1 if the requested username exists, returns 0 otherwise
2258         /
2259 );
2260
2261 sub usrname_exists {
2262         my( $self, $conn, $auth, $usrname ) = @_;
2263         my $e = new_editor(authtoken=>$auth);
2264         return $e->event unless $e->checkauth;
2265         my $a = $e->search_actor_user({usrname => $usrname}, {idlist=>1});
2266         return $$a[0] if $a and @$a;
2267         return 0;
2268 }
2269
2270 __PACKAGE__->register_method(
2271         method => 'barcode_exists',
2272         api_name        => 'open-ils.actor.barcode.exists',
2273         signature => q/
2274                 Returns 1 if the requested barcode exists, returns 0 otherwise
2275         /
2276 );
2277
2278 sub barcode_exists {
2279         my( $self, $conn, $auth, $barcode ) = @_;
2280         my $e = new_editor(authtoken=>$auth);
2281         return $e->event unless $e->checkauth;
2282         my $a = $e->search_actor_card({barcode => $barcode}, {idlist=>1});
2283         return $$a[0] if $a and @$a;
2284         return 0;
2285 }
2286
2287
2288 __PACKAGE__->register_method(
2289         method => 'retrieve_net_levels',
2290         api_name        => 'open-ils.actor.net_access_level.retrieve.all',
2291 );
2292
2293 sub retrieve_net_levels {
2294         my( $self, $conn, $auth ) = @_;
2295         my $e = new_editor(authtoken=>$auth);
2296         return $e->event unless $e->checkauth;
2297         return $e->retrieve_all_config_net_access_level();
2298 }
2299
2300
2301
2302 1;
2303