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