1 package OpenILS::Application::Actor;
2 use base qw/OpenSRF::Application/;
3 use strict; use warnings;
5 $Data::Dumper::Indent = 0;
8 use Digest::MD5 qw(md5_hex);
10 use OpenSRF::EX qw(:try);
13 use OpenILS::Application::AppUtils;
15 use OpenILS::Utils::Fieldmapper;
16 use OpenILS::Utils::ModsParser;
17 use OpenSRF::Utils::Logger qw/$logger/;
18 use OpenSRF::Utils qw/:datetime/;
20 use OpenSRF::Utils::Cache;
24 use DateTime::Format::ISO8601;
26 use OpenILS::Application::Actor::Container;
27 use OpenILS::Application::Actor::ClosedDates;
29 use OpenILS::Utils::CStoreEditor qw/:funcs/;
31 use OpenILS::Application::Actor::UserGroups;
33 OpenILS::Application::Actor::Container->initialize();
34 OpenILS::Application::Actor::UserGroups->initialize();
35 OpenILS::Application::Actor::ClosedDates->initialize();
38 my $apputils = "OpenILS::Application::AppUtils";
41 sub _d { warn "Patron:\n" . Dumper(shift()); }
46 my $set_user_settings;
49 __PACKAGE__->register_method(
50 method => "set_user_settings",
51 api_name => "open-ils.actor.patron.settings.update",
53 sub set_user_settings {
54 my( $self, $client, $user_session, $uid, $settings ) = @_;
56 $logger->debug("Setting user settings: $user_session, $uid, " . Dumper($settings));
58 my( $staff, $user, $evt ) =
59 $apputils->checkses_requestor( $user_session, $uid, 'UPDATE_USER' );
63 [{ usr => $user->id, name => $_}, {value => $$settings{$_}}] } keys %$settings;
65 $_->[1]->{value} = JSON->perl2JSON($_->[1]->{value}) for @params;
67 $logger->activity("User " . $staff->id . " updating user $uid settings with: " . Dumper(\@params));
69 return $apputils->simplereq(
71 'open-ils.storage.direct.actor.user_setting.batch.merge', @params );
77 __PACKAGE__->register_method(
78 method => "set_ou_settings",
79 api_name => "open-ils.actor.org_unit.settings.update",
82 my( $self, $client, $user_session, $ouid, $settings ) = @_;
84 my( $staff, $evt ) = $apputils->checkses( $user_session );
86 $evt = $apputils->check_perms( $staff->id, $ouid, 'UPDATE_ORG_UNIT' );
91 map { [{ org_unit => $ouid, name => $_}, {value => $$settings{$_}}] } keys %$settings;
93 $_->[1]->{value} = JSON->perl2JSON($_->[1]->{value}) for @params;
95 $logger->activity("Updating org unit [$ouid] settings with: " . Dumper(\@params));
97 return $apputils->simplereq(
99 'open-ils.storage.direct.actor.org_unit_setting.merge', @params );
103 my $fetch_user_settings;
104 my $fetch_ou_settings;
106 __PACKAGE__->register_method(
107 method => "user_settings",
108 api_name => "open-ils.actor.patron.settings.retrieve",
111 my( $self, $client, $user_session, $uid ) = @_;
113 my( $staff, $user, $evt ) =
114 $apputils->checkses_requestor( $user_session, $uid, 'VIEW_USER' );
117 $logger->debug("User " . $staff->id . " fetching user $uid\n");
118 my $s = $apputils->simplereq(
120 'open-ils.storage.direct.actor.user_setting.search.usr.atomic',$uid );
122 return { map { ( $_->name => JSON->JSON2perl($_->value) ) } @$s };
127 __PACKAGE__->register_method(
128 method => "ou_settings",
129 api_name => "open-ils.actor.org_unit.settings.retrieve",
132 my( $self, $client, $ouid ) = @_;
134 $logger->info("Fetching org unit settings for org $ouid");
136 my $s = $apputils->simplereq(
138 'open-ils.storage.direct.actor.org_unit_setting.search.org_unit.atomic', $ouid);
140 return { map { ( $_->name => JSON->JSON2perl($_->value) ) } @$s };
143 __PACKAGE__->register_method (
144 method => "ou_setting_delete",
145 api_name => 'open-ils.actor.org_setting.delete',
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.
155 sub ou_setting_delete {
156 my( $self, $conn, $authtoken, $orgid, $setting ) = @_;
157 my( $reqr, $evt) = $U->checkses($authtoken);
159 $evt = $U->check_perms($reqr->id, $orgid, 'UPDATE_ORG_SETTING');
162 my $id = $U->storagereq(
163 'open-ils.storage.id_list.actor.org_unit_setting.search_where',
164 { name => $setting, org_unit => $orgid } );
166 $logger->debug("Retrieved setting $id in org unit setting delete");
168 my $s = $U->storagereq(
169 'open-ils.storage.direct.actor.org_unit_setting.delete', $id );
171 $logger->activity("User ".$reqr->id." deleted org unit setting $id") if $s;
177 __PACKAGE__->register_method(
178 method => "update_patron",
179 api_name => "open-ils.actor.patron.update",);
182 my( $self, $client, $user_session, $patron ) = @_;
184 my $session = $apputils->start_db_session();
187 $logger->info("Creating new patron...") if $patron->isnew;
188 $logger->info("Updating Patron: " . $patron->id) unless $patron->isnew;
190 my( $user_obj, $evt ) = $U->checkses($user_session);
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.
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));
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);
211 } else { $new_patron = $patron; }
213 ( $new_patron, $evt ) = _add_update_addresses($session, $patron, $new_patron, $user_obj);
216 ( $new_patron, $evt ) = _add_update_cards($session, $patron, $new_patron, $user_obj);
219 ( $new_patron, $evt ) = _add_survey_responses($session, $patron, $new_patron, $user_obj);
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);
228 #$session = OpenSRF::AppSession->create("open-ils.storage"); # why did i put this here?
230 ($new_patron, $evt) = _create_stat_maps($session, $user_session, $patron, $new_patron, $user_obj);
233 ($new_patron, $evt) = _create_perm_maps($session, $user_session, $patron, $new_patron, $user_obj);
236 ($new_patron, $evt) = _create_standing_penalties($session, $user_session, $patron, $new_patron, $user_obj);
239 $logger->activity("user ".$user_obj->id." updating/creating user ".$new_patron->id);
240 $apputils->commit_db_session($session);
242 #warn "Patron Update/Create complete\n";
243 return flesh_user($new_patron->id());
249 __PACKAGE__->register_method(
250 method => "user_retrieve_fleshed_by_id",
251 api_name => "open-ils.actor.user.fleshed.retrieve",);
253 sub user_retrieve_fleshed_by_id {
254 my( $self, $client, $user_session, $user_id ) = @_;
256 my( $requestor, $target, $evt ) = $apputils->
257 checkses_requestor( $user_session, $user_id, 'VIEW_USER' );
260 return flesh_user($user_id);
264 # fleshes: card, cards, address, addresses, stat_cat_entries, standing_penalties
273 $session = OpenSRF::AppSession->create("open-ils.storage");
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);
282 if(!$user) { return undef; }
285 my $cards_req = $session->request(
286 "open-ils.storage.direct.actor.card.search.usr.atomic",
288 $user->cards( $cards_req->gather(1) );
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";
297 my $add_req = $session->request(
298 "open-ils.storage.direct.actor.user_address.search.usr.atomic",
300 $user->addresses( $add_req->gather(1) );
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 );
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 );
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); }
324 my $stat_req = $session->request(
325 "open-ils.storage.direct.actor.stat_cat_entry_user_map.search.target_usr.atomic",
327 $user->stat_cat_entries($stat_req->gather(1));
329 my $standing_penalties_req = $session->request(
330 "open-ils.storage.direct.actor.user_standing_penalty.search.usr.atomic",
332 $user->standing_penalties($standing_penalties_req->gather(1));
334 if($kill) { $session->disconnect(); }
335 $user->clear_passwd();
342 my $e = new_editor();
343 my $user = $e->retrieve_actor_user(
352 "standing_penalties",
361 ) or return $e->event;
363 $user->clear_passwd();
372 # clone and clear stuff that would break the database
376 my $new_patron = $patron->clone;
378 # Using the Fieldmapper clone method
379 #my $new_patron = Fieldmapper::actor::user->new();
381 #my $fmap = $Fieldmapper::fieldmap;
382 #no strict; # shallow clone, may be useful in the fieldmapper
384 # (keys %{$fmap->{"Fieldmapper::actor::user"}->{'fields'}}) {
385 # $new_patron->$field( $patron->$field() );
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();
411 my $user_obj = shift;
413 my $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'CREATE_USER');
414 return (undef, $evt) if $evt;
416 my $ex = $session->request(
417 'open-ils.storage.direct.actor.user.search.usrname', $patron->usrname())->gather(1);
419 return (undef, OpenILS::Event->new('USERNAME_EXISTS'));
422 $evt = _check_dup_ident($session, $patron);
423 return (undef, $evt) if $evt;
425 $logger->info("Creating new user in the DB with username: ".$patron->usrname());
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;
431 $logger->info("Successfully created new user [$id] in DB");
433 return ( $session->request(
434 "open-ils.storage.direct.actor.user.retrieve", $id)->gather(1), undef );
439 my( $session, $patron, $user_obj, $noperm) = @_;
441 $logger->info("Updating patron ".$patron->id." in DB");
446 $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'UPDATE_USER');
447 return (undef, $evt) if $evt;
450 $evt = _check_dup_ident($session, $patron);
451 return (undef, $evt) if $evt;
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;
463 if(!$patron->ident_type) {
464 $patron->clear_ident_type;
465 $patron->clear_ident_value;
468 if(!$patron->ident_type2) {
469 $patron->clear_ident_type2;
470 $patron->clear_ident_value2;
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);
480 sub _check_dup_ident {
481 my( $session, $patron ) = @_;
483 return undef unless $patron->ident_value;
486 ident_type => $patron->ident_type,
487 ident_value => $patron->ident_value,
490 $logger->debug("patron update searching for dup ident values: " .
491 $patron->ident_type . ':' . $patron->ident_value);
493 $search->{id} = {'!=' => $patron->id} if $patron->id and $patron->id > 0;
495 my $dups = $session->request(
496 'open-ils.storage.direct.actor.user.search_where.atomic', $search )->gather(1);
499 return OpenILS::Event->new('PATRON_DUP_IDENT1', payload => $patron )
506 sub _add_update_addresses {
510 my $new_patron = shift;
514 my $current_id; # id of the address before creation
516 for my $address (@{$patron->addresses()}) {
518 next unless ref $address;
519 $current_id = $address->id();
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);
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);
536 if($address->isnew()) {
538 $address->usr($new_patron->id());
540 ($address, $evt) = _add_address($session,$address);
541 return (undef, $evt) if $evt;
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);
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);
558 } elsif($address->ischanged() ) {
560 ($address, $evt) = _update_address($session, $address);
561 return (undef, $evt) if $evt;
563 } elsif($address->isdeleted() ) {
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;
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;
577 $evt = _delete_address($session, $address);
578 return (undef, $evt) if $evt;
582 return ( $new_patron, undef );
586 # adds an address to the db and returns the address with new id
588 my($session, $address) = @_;
589 $address->clear_id();
591 $logger->info("Creating new address at street ".$address->street1);
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;
599 return ($address, undef);
603 sub _update_address {
604 my( $session, $address ) = @_;
606 $logger->info("Updating address ".$address->id." in the DB");
608 my $stat = $session->request(
609 "open-ils.storage.direct.actor.user_address.update", $address )->gather(1);
611 return (undef, $U->DB_UPDATE_FAILED($address)) unless defined($stat);
612 return ($address, undef);
617 sub _add_update_cards {
621 my $new_patron = shift;
625 my $virtual_id; #id of the card before creation
626 for my $card (@{$patron->cards()}) {
628 $card->usr($new_patron->id());
630 if(ref($card) and $card->isnew()) {
632 $virtual_id = $card->id();
633 ( $card, $evt ) = _add_card($session,$card);
634 return (undef, $evt) if $evt;
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);
642 } elsif( ref($card) and $card->ischanged() ) {
643 $evt = _update_card($session, $card);
644 return (undef, $evt) if $evt;
648 return ( $new_patron, undef );
652 # adds an card to the db and returns the card with new id
654 my( $session, $card ) = @_;
657 $logger->info("Adding new patron card ".$card->barcode);
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");
665 return ( $card, undef );
669 # returns event on error. returns undef otherwise
671 my( $session, $card ) = @_;
672 $logger->info("Updating patron card ".$card->id);
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);
683 # returns event on error. returns undef otherwise
684 sub _delete_address {
685 my( $session, $address ) = @_;
687 $logger->info("Deleting address ".$address->id." from DB");
689 my $stat = $session->request(
690 "open-ils.storage.direct.actor.user_address.delete", $address )->gather(1);
692 return $U->DB_UPDATE_FAILED($address) unless defined($stat);
698 sub _add_survey_responses {
699 my ($session, $patron, $new_patron) = @_;
701 $logger->info( "Updating survey responses for patron ".$new_patron->id );
703 my $responses = $patron->survey_responses;
707 $_->usr($new_patron->id) for (@$responses);
709 my $evt = $U->simplereq( "open-ils.circ",
710 "open-ils.circ.survey.submit.user_id", $responses );
712 return (undef, $evt) if defined($U->event_code($evt));
716 return ( $new_patron, undef );
720 sub _create_stat_maps {
722 my($session, $user_session, $patron, $new_patron) = @_;
724 my $maps = $patron->stat_cat_entries();
726 for my $map (@$maps) {
728 my $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.update";
730 if ($map->isdeleted()) {
731 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.delete";
733 } elsif ($map->isnew()) {
734 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.create";
739 $map->target_usr($new_patron->id);
742 $logger->info("Updating stat entry with method $method and map $map");
744 my $stat = $session->request($method, $map)->gather(1);
745 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
749 return ($new_patron, undef);
752 sub _create_perm_maps {
754 my($session, $user_session, $patron, $new_patron) = @_;
756 my $maps = $patron->permissions;
758 for my $map (@$maps) {
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";
769 $map->usr($new_patron->id);
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" );
774 my $stat = $session->request($method, $map)->gather(1);
775 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
779 return ($new_patron, undef);
783 sub _create_standing_penalties {
785 my($session, $user_session, $patron, $new_patron) = @_;
787 my $maps = $patron->standing_penalties;
790 for my $map (@$maps) {
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";
801 $map->usr($new_patron->id);
803 $logger->debug( "Updating standing penalty with method $method and session $user_session and map $map" );
805 my $stat = $session->request($method, $map)->gather(1);
806 return (undef, $U->DB_UPDATE_FAILED($map)) unless $stat;
809 return ($new_patron, undef);
814 __PACKAGE__->register_method(
815 method => "search_username",
816 api_name => "open-ils.actor.user.search.username",
819 sub search_username {
820 my($self, $client, $username) = @_;
821 my $users = OpenILS::Application::AppUtils->simple_scalar_request(
823 "open-ils.storage.direct.actor.user.search.usrname.atomic",
831 __PACKAGE__->register_method(
832 method => "user_retrieve_by_barcode",
833 api_name => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
835 sub user_retrieve_by_barcode {
836 my($self, $client, $user_session, $barcode) = @_;
838 $logger->debug("Searching for user with barcode $barcode");
839 my ($user_obj, $evt) = $apputils->checkses($user_session);
843 my $session = OpenSRF::AppSession->create("open-ils.storage");
845 # find the card with the given barcode
846 my $creq = $session->request(
847 "open-ils.storage.direct.actor.card.search.barcode.atomic",
849 my $card = $creq->gather(1);
851 if(!$card || !$card->[0]) {
852 $session->disconnect();
853 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' );
857 my $user = flesh_user($card->usr(), $session);
859 $evt = $U->check_perms($user_obj->id, $user->home_ou, 'VIEW_USER');
862 $session->disconnect();
863 if(!$user) { return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ); }
870 __PACKAGE__->register_method(
871 method => "get_user_by_id",
872 api_name => "open-ils.actor.user.retrieve",);
875 my ($self, $client, $auth, $id) = @_;
876 my $e = new_editor(authtoken=>$auth);
877 return $e->event unless $e->checkauth;
878 my $user = $e->retrieve_actor_user($id)
880 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
886 __PACKAGE__->register_method(
887 method => "get_org_types",
888 api_name => "open-ils.actor.org_types.retrieve",);
892 my($self, $client) = @_;
894 return $org_types if $org_types;
896 $apputils->simple_scalar_request(
898 "open-ils.storage.direct.actor.org_unit_type.retrieve.all.atomic" );
903 __PACKAGE__->register_method(
904 method => "get_user_profiles",
905 api_name => "open-ils.actor.user.profiles.retrieve",
909 sub get_user_profiles {
910 return $user_profiles if $user_profiles;
912 return $user_profiles =
913 $apputils->simple_scalar_request(
915 "open-ils.storage.direct.actor.profile.retrieve.all.atomic");
920 __PACKAGE__->register_method(
921 method => "get_user_ident_types",
922 api_name => "open-ils.actor.user.ident_types.retrieve",
925 sub get_user_ident_types {
926 return $ident_types if $ident_types;
927 return $ident_types =
928 $apputils->simple_scalar_request(
930 "open-ils.storage.direct.config.identification_type.retrieve.all.atomic" );
936 __PACKAGE__->register_method(
937 method => "get_org_unit",
938 api_name => "open-ils.actor.org_unit.retrieve",
942 my( $self, $client, $user_session, $org_id ) = @_;
943 my $e = new_editor(authtoken => $user_session);
945 return $e->event unless $e->checkauth;
946 $org_id = $e->requestor->ws_ou;
948 my $o = $e->retrieve_actor_org_unit($org_id)
953 __PACKAGE__->register_method(
954 method => "search_org_unit",
955 api_name => "open-ils.actor.org_unit_list.search",
958 sub search_org_unit {
960 my( $self, $client, $field, $value ) = @_;
962 my $list = OpenILS::Application::AppUtils->simple_scalar_request(
964 "open-ils.storage.direct.actor.org_unit.search.$field.atomic",
973 __PACKAGE__->register_method(
974 method => "get_org_tree",
975 api_name => "open-ils.actor.org_tree.retrieve",
977 note => "Returns the entire org tree structure",
981 my( $self, $client) = @_;
984 $cache_client = OpenSRF::Utils::Cache->new("global", 0);
986 # see if it's in the cache
987 #warn "Getting ORG Tree\n";
988 my $tree = $cache_client->get_cache('orgtree');
990 #warn "Found orgtree in cache. returning...\n";
994 my $orglist = $apputils->simple_scalar_request(
996 "open-ils.storage.direct.actor.org_unit.retrieve.all.atomic" );
999 #warn "found org list\n";
1002 $tree = $self->build_org_tree($orglist);
1003 $cache_client->put_cache('orgtree', $tree);
1009 # turns an org list into an org tree
1010 sub build_org_tree {
1012 my( $self, $orglist) = @_;
1014 return $orglist unless (
1015 ref($orglist) and @$orglist > 1 );
1018 $a->ou_type <=> $b->ou_type ||
1019 $a->name cmp $b->name } @$orglist;
1021 for my $org (@list) {
1023 next unless ($org and defined($org->parent_ou));
1024 my ($parent) = grep { $_->id == $org->parent_ou } @list;
1025 next unless $parent;
1027 $parent->children([]) unless defined($parent->children);
1028 push( @{$parent->children}, $org );
1036 __PACKAGE__->register_method(
1037 method => "get_org_descendants",
1038 api_name => "open-ils.actor.org_tree.descendants.retrieve"
1041 # depth is optional. org_unit is the id
1042 sub get_org_descendants {
1043 my( $self, $client, $org_unit, $depth ) = @_;
1044 my $orglist = $apputils->simple_scalar_request(
1046 "open-ils.storage.actor.org_unit.descendants.atomic",
1047 $org_unit, $depth );
1048 return $self->build_org_tree($orglist);
1052 __PACKAGE__->register_method(
1053 method => "get_org_ancestors",
1054 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
1057 # depth is optional. org_unit is the id
1058 sub get_org_ancestors {
1059 my( $self, $client, $org_unit, $depth ) = @_;
1060 my $orglist = $apputils->simple_scalar_request(
1062 "open-ils.storage.actor.org_unit.ancestors.atomic",
1063 $org_unit, $depth );
1064 return $self->build_org_tree($orglist);
1068 __PACKAGE__->register_method(
1069 method => "get_standings",
1070 api_name => "open-ils.actor.standings.retrieve"
1075 return $user_standings if $user_standings;
1076 return $user_standings =
1077 $apputils->simple_scalar_request(
1079 "open-ils.storage.direct.config.standing.retrieve.all.atomic" );
1084 __PACKAGE__->register_method(
1085 method => "get_my_org_path",
1086 api_name => "open-ils.actor.org_unit.full_path.retrieve"
1089 sub get_my_org_path {
1090 my( $self, $client, $user_session, $org_id ) = @_;
1091 my $user_obj = $apputils->check_user_session($user_session);
1092 if(!defined($org_id)) { $org_id = $user_obj->home_ou; }
1094 return $apputils->simple_scalar_request(
1096 "open-ils.storage.actor.org_unit.full_path.atomic",
1101 __PACKAGE__->register_method(
1102 method => "patron_adv_search",
1103 api_name => "open-ils.actor.patron.search.advanced" );
1104 sub patron_adv_search {
1105 my( $self, $client, $auth, $search_hash, $search_limit, $search_sort ) = @_;
1106 my $e = new_editor(authtoken=>$auth);
1107 return $e->event unless $e->checkauth;
1108 return $e->event unless $e->allowed('VIEW_USER');
1109 return $U->storagereq(
1110 "open-ils.storage.actor.user.crazy_search",
1111 $search_hash, $search_limit, $search_sort);
1116 sub _verify_password {
1117 my($user_session, $password) = @_;
1118 my $user_obj = $apputils->check_user_session($user_session);
1120 #grab the user with password
1121 $user_obj = $apputils->simple_scalar_request(
1123 "open-ils.storage.direct.actor.user.retrieve",
1126 if($user_obj->passwd eq $password) {
1134 __PACKAGE__->register_method(
1135 method => "update_password",
1136 api_name => "open-ils.actor.user.password.update");
1138 __PACKAGE__->register_method(
1139 method => "update_password",
1140 api_name => "open-ils.actor.user.username.update");
1142 __PACKAGE__->register_method(
1143 method => "update_password",
1144 api_name => "open-ils.actor.user.email.update");
1146 sub update_password {
1147 my( $self, $client, $user_session, $new_value, $current_password ) = @_;
1151 my $user_obj = $apputils->check_user_session($user_session);
1153 if($self->api_name =~ /password/o) {
1155 #make sure they know the current password
1156 if(!_verify_password($user_session, md5_hex($current_password))) {
1157 return OpenILS::Event->new('INCORRECT_PASSWORD');
1160 $logger->debug("update_password setting new password $new_value");
1161 $user_obj->passwd($new_value);
1163 } elsif($self->api_name =~ /username/o) {
1164 my $users = search_username(undef, undef, $new_value);
1165 if( $users and $users->[0] ) {
1166 return OpenILS::Event->new('USERNAME_EXISTS');
1168 $user_obj->usrname($new_value);
1170 } elsif($self->api_name =~ /email/o) {
1171 #warn "Updating email to $new_value\n";
1172 $user_obj->email($new_value);
1175 my $session = $apputils->start_db_session();
1177 ( $user_obj, $evt ) = _update_patron($session, $user_obj, $user_obj, 1);
1178 return $evt if $evt;
1180 $apputils->commit_db_session($session);
1182 if($user_obj) { return 1; }
1187 __PACKAGE__->register_method(
1188 method => "check_user_perms",
1189 api_name => "open-ils.actor.user.perm.check",
1190 notes => <<" NOTES");
1191 Takes a login session, user id, an org id, and an array of perm type strings. For each
1192 perm type, if the user does *not* have the given permission it is added
1193 to a list which is returned from the method. If all permissions
1194 are allowed, an empty list is returned
1195 if the logged in user does not match 'user_id', then the logged in user must
1196 have VIEW_PERMISSION priveleges.
1199 sub check_user_perms {
1200 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1202 my( $staff, $evt ) = $apputils->checkses($login_session);
1203 return $evt if $evt;
1205 if($staff->id ne $user_id) {
1206 if( my $evt = $apputils->check_perms(
1207 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1213 for my $perm (@$perm_types) {
1214 if($apputils->check_perms($user_id, $org_id, $perm)) {
1215 push @not_allowed, $perm;
1219 return \@not_allowed
1222 __PACKAGE__->register_method(
1223 method => "check_user_perms2",
1224 api_name => "open-ils.actor.user.perm.check.multi_org",
1226 Checks the permissions on a list of perms and orgs for a user
1227 @param authtoken The login session key
1228 @param user_id The id of the user to check
1229 @param orgs The array of org ids
1230 @param perms The array of permission names
1231 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1232 if the logged in user does not match 'user_id', then the logged in user must
1233 have VIEW_PERMISSION priveleges.
1236 sub check_user_perms2 {
1237 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1239 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1240 $authtoken, $user_id, 'VIEW_PERMISSION' );
1241 return $evt if $evt;
1244 for my $org (@$orgs) {
1245 for my $perm (@$perms) {
1246 if($apputils->check_perms($user_id, $org, $perm)) {
1247 push @not_allowed, [ $org, $perm ];
1252 return \@not_allowed
1256 __PACKAGE__->register_method(
1257 method => 'check_user_perms3',
1258 api_name => 'open-ils.actor.user.perm.highest_org',
1260 Returns the highest org unit id at which a user has a given permission
1261 If the requestor does not match the target user, the requestor must have
1262 'VIEW_PERMISSION' rights at the home org unit of the target user
1263 @param authtoken The login session key
1264 @param userid The id of the user in question
1265 @param perm The permission to check
1266 @return The org unit highest in the org tree within which the user has
1267 the requested permission
1270 sub check_user_perms3 {
1271 my( $self, $client, $authtoken, $userid, $perm ) = @_;
1273 my( $staff, $target, $org, $evt );
1275 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1276 $authtoken, $userid, 'VIEW_PERMISSION' );
1277 return $evt if $evt;
1279 my $tree = $self->get_org_tree();
1280 return _find_highest_perm_org( $perm, $userid, $target->ws_ou, $tree );
1284 sub _find_highest_perm_org {
1285 my ( $perm, $userid, $start_org, $org_tree ) = @_;
1286 my $org = $apputils->find_org($org_tree, $start_org );
1290 last if ($apputils->check_perms( $userid, $org->id, $perm )); # perm failed
1292 $org = $apputils->find_org( $org_tree, $org->parent_ou() );
1298 __PACKAGE__->register_method(
1299 method => 'check_user_perms4',
1300 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1302 Returns the highest org unit id at which a user has a given permission
1303 If the requestor does not match the target user, the requestor must have
1304 'VIEW_PERMISSION' rights at the home org unit of the target user
1305 @param authtoken The login session key
1306 @param userid The id of the user in question
1307 @param perms An array of perm names to check
1308 @return An array of orgId's representing the org unit
1309 highest in the org tree within which the user has the requested permission
1310 The arrah of orgId's has matches the order of the perms array
1313 sub check_user_perms4 {
1314 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1316 my( $staff, $target, $org, $evt );
1318 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1319 $authtoken, $userid, 'VIEW_PERMISSION' );
1320 return $evt if $evt;
1323 return [] unless ref($perms);
1324 my $tree = $self->get_org_tree();
1326 for my $p (@$perms) {
1327 push( @arr, _find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1335 __PACKAGE__->register_method(
1336 method => "user_fines_summary",
1337 api_name => "open-ils.actor.user.fines.summary",
1338 notes => <<" NOTES");
1339 Returns a short summary of the users total open fines, excluding voided fines
1340 Params are login_session, user_id
1341 Returns a 'mous' object.
1344 sub user_fines_summary {
1345 my( $self, $client, $login_session, $user_id ) = @_;
1347 my $user_obj = $apputils->check_user_session($login_session);
1348 if($user_obj->id ne $user_id) {
1349 if($apputils->check_user_perms($user_obj->id, $user_obj->home_ou, "VIEW_USER_FINES_SUMMARY")) {
1350 return OpenILS::Perm->new("VIEW_USER_FINES_SUMMARY");
1354 return $apputils->simple_scalar_request(
1356 "open-ils.storage.direct.money.open_user_summary.search.usr",
1364 __PACKAGE__->register_method(
1365 method => "user_transactions",
1366 api_name => "open-ils.actor.user.transactions",
1367 notes => <<" NOTES");
1368 Returns a list of open user transactions (mbts objects);
1369 Params are login_session, user_id
1370 Optional third parameter is the transactions type. defaults to all
1373 __PACKAGE__->register_method(
1374 method => "user_transactions",
1375 api_name => "open-ils.actor.user.transactions.have_charge",
1376 notes => <<" NOTES");
1377 Returns a list of all open user transactions (mbts objects) that have an initial charge
1378 Params are login_session, user_id
1379 Optional third parameter is the transactions type. defaults to all
1382 __PACKAGE__->register_method(
1383 method => "user_transactions",
1384 api_name => "open-ils.actor.user.transactions.have_balance",
1385 notes => <<" NOTES");
1386 Returns a list of all open user transactions (mbts objects) that have a balance
1387 Params are login_session, user_id
1388 Optional third parameter is the transactions type. defaults to all
1391 __PACKAGE__->register_method(
1392 method => "user_transactions",
1393 api_name => "open-ils.actor.user.transactions.fleshed",
1394 notes => <<" NOTES");
1395 Returns an object/hash of transaction, circ, title where transaction = an open
1396 user transactions (mbts objects), circ is the attached circluation, and title
1397 is the title the circ points to
1398 Params are login_session, user_id
1399 Optional third parameter is the transactions type. defaults to all
1402 __PACKAGE__->register_method(
1403 method => "user_transactions",
1404 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1405 notes => <<" NOTES");
1406 Returns an object/hash of transaction, circ, title where transaction = an open
1407 user transactions that has an initial charge (mbts objects), circ is the
1408 attached circluation, and title is the title the circ points to
1409 Params are login_session, user_id
1410 Optional third parameter is the transactions type. defaults to all
1413 __PACKAGE__->register_method(
1414 method => "user_transactions",
1415 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1416 notes => <<" NOTES");
1417 Returns an object/hash of transaction, circ, title where transaction = an open
1418 user transaction that has a balance (mbts objects), circ is the attached
1419 circluation, and title is the title the circ points to
1420 Params are login_session, user_id
1421 Optional third parameter is the transaction type. defaults to all
1424 __PACKAGE__->register_method(
1425 method => "user_transactions",
1426 api_name => "open-ils.actor.user.transactions.count",
1427 notes => <<" NOTES");
1428 Returns an object/hash of transaction, circ, title where transaction = an open
1429 user transactions (mbts objects), circ is the attached circluation, and title
1430 is the title the circ points to
1431 Params are login_session, user_id
1432 Optional third parameter is the transactions type. defaults to all
1435 __PACKAGE__->register_method(
1436 method => "user_transactions",
1437 api_name => "open-ils.actor.user.transactions.have_charge.count",
1438 notes => <<" NOTES");
1439 Returns an object/hash of transaction, circ, title where transaction = an open
1440 user transactions that has an initial charge (mbts objects), circ is the
1441 attached circluation, and title is the title the circ points to
1442 Params are login_session, user_id
1443 Optional third parameter is the transactions type. defaults to all
1446 __PACKAGE__->register_method(
1447 method => "user_transactions",
1448 api_name => "open-ils.actor.user.transactions.have_balance.count",
1449 notes => <<" NOTES");
1450 Returns an object/hash of transaction, circ, title where transaction = an open
1451 user transaction that has a balance (mbts objects), circ is the attached
1452 circluation, and title is the title the circ points to
1453 Params are login_session, user_id
1454 Optional third parameter is the transaction type. defaults to all
1457 __PACKAGE__->register_method(
1458 method => "user_transactions",
1459 api_name => "open-ils.actor.user.transactions.have_balance.total",
1460 notes => <<" NOTES");
1461 Returns an object/hash of transaction, circ, title where transaction = an open
1462 user transaction that has a balance (mbts objects), circ is the attached
1463 circluation, and title is the title the circ points to
1464 Params are login_session, user_id
1465 Optional third parameter is the transaction type. defaults to all
1470 sub user_transactions {
1471 my( $self, $client, $login_session, $user_id, $type ) = @_;
1473 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1474 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1475 return $evt if $evt;
1477 my $api = $self->api_name();
1481 if(defined($type)) { @xact = (xact_type => $type);
1483 } else { @xact = (); }
1485 if($api =~ /have_charge/o) {
1487 $trans = $apputils->simple_scalar_request(
1489 "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1490 { usr => $user_id, total_owed => { ">" => 0 }, @xact });
1492 } elsif($api =~ /have_balance/o) {
1494 $trans = $apputils->simple_scalar_request(
1496 "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1497 { usr => $user_id, balance_owed => { "<>" => 0 }, @xact });
1501 $trans = $apputils->simple_scalar_request(
1503 "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1504 { usr => $user_id, @xact });
1507 if($api =~ /total/o) {
1509 for my $t (@$trans) {
1510 $total += $t->balance_owed;
1513 $logger->debug("Total balance owed by user $user_id: $total");
1517 if($api =~ /count/o) { return scalar @$trans; }
1518 if($api !~ /fleshed/o) { return $trans; }
1521 for my $t (@$trans) {
1523 if( $t->xact_type ne 'circulation' ) {
1524 push @resp, {transaction => $t};
1528 my $circ = $apputils->simple_scalar_request(
1530 "open-ils.storage.direct.action.circulation.retrieve",
1535 my $title = $apputils->simple_scalar_request(
1537 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1538 $circ->target_copy );
1542 my $u = OpenILS::Utils::ModsParser->new();
1543 $u->start_mods_batch($title->marc());
1544 my $mods = $u->finish_mods_batch();
1546 push @resp, {transaction => $t, circ => $circ, record => $mods };
1554 __PACKAGE__->register_method(
1555 method => "user_transaction_retrieve",
1556 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1558 notes => <<" NOTES");
1559 Returns a fleshedtransaction record
1561 __PACKAGE__->register_method(
1562 method => "user_transaction_retrieve",
1563 api_name => "open-ils.actor.user.transaction.retrieve",
1565 notes => <<" NOTES");
1566 Returns a transaction record
1568 sub user_transaction_retrieve {
1569 my( $self, $client, $login_session, $bill_id ) = @_;
1571 my $trans = $apputils->simple_scalar_request(
1573 "open-ils.storage.direct.money.billable_transaction_summary.retrieve",
1577 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1578 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1579 return $evt if $evt;
1581 my $api = $self->api_name();
1582 if($api !~ /fleshed/o) { return $trans; }
1584 if( $trans->xact_type ne 'circulation' ) {
1585 $logger->debug("Returning non-circ transaction");
1586 return {transaction => $trans};
1589 my $circ = $apputils->simple_scalar_request(
1591 "open-ils.storage.direct.action.circulation.retrieve",
1594 return {transaction => $trans} unless $circ;
1595 $logger->debug("Found the circ transaction");
1597 my $title = $apputils->simple_scalar_request(
1599 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1600 $circ->target_copy );
1602 return {transaction => $trans, circ => $circ } unless $title;
1603 $logger->debug("Found the circ title");
1607 my $u = OpenILS::Utils::ModsParser->new();
1608 $u->start_mods_batch($title->marc());
1609 $mods = $u->finish_mods_batch();
1611 if ($title->id == -1) {
1612 my $copy = $apputils->simple_scalar_request(
1614 "open-ils.storage.direct.asset.copy.retrieve",
1615 $circ->target_copy );
1617 $mods = new Fieldmapper::metabib::virtual_record;
1619 $mods->title($copy->dummy_title);
1620 $mods->author($copy->dummy_author);
1624 $logger->debug("MODSized the circ title");
1626 return {transaction => $trans, circ => $circ, record => $mods };
1630 __PACKAGE__->register_method(
1631 method => "hold_request_count",
1632 api_name => "open-ils.actor.user.hold_requests.count",
1634 notes => <<" NOTES");
1635 Returns hold ready/total counts
1637 sub hold_request_count {
1638 my( $self, $client, $login_session, $userid ) = @_;
1640 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1641 $login_session, $userid, 'VIEW_HOLD' );
1642 return $evt if $evt;
1645 my $holds = $apputils->simple_scalar_request(
1647 "open-ils.storage.direct.action.hold_request.search_where.atomic",
1649 fulfillment_time => {"=" => undef } }
1653 for my $h (@$holds) {
1654 next unless $h->capture_time;
1656 my $copy = $apputils->simple_scalar_request(
1658 "open-ils.storage.direct.asset.copy.retrieve",
1662 if ($copy->status == 8) {
1667 return { total => scalar(@$holds), ready => scalar(@ready) };
1671 __PACKAGE__->register_method(
1672 method => "checkedout_count",
1673 api_name => "open-ils.actor.user.checked_out.count__",
1675 notes => <<" NOTES");
1676 Returns a transaction record
1680 sub checkedout_count {
1681 my( $self, $client, $login_session, $userid ) = @_;
1683 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1684 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1685 return $evt if $evt;
1687 my $circs = $apputils->simple_scalar_request(
1689 "open-ils.storage.direct.action.circulation.search_where.atomic",
1690 { usr => $userid, stop_fines => undef }
1691 #{ usr => $userid, checkin_time => {"=" => undef } }
1694 my $parser = DateTime::Format::ISO8601->new;
1697 for my $c (@$circs) {
1698 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1699 my $due = $due_dt->epoch;
1701 if ($due < DateTime->today->epoch) {
1706 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1710 __PACKAGE__->register_method(
1711 method => "checked_out",
1712 api_name => "open-ils.actor.user.checked_out",
1715 Returns a structure of circulations objects sorted by
1716 out, overdue, lost, claims_returned, long_overdue.
1717 A list of IDs are returned of each type.
1718 lost, long_overdue, and claims_returned circ will not
1719 be "finished" (there is an outstanding balance or some
1720 other pending action on the circ).
1722 The .count method also includes a 'total' field which
1723 sums all "open" circs
1727 __PACKAGE__->register_method(
1728 method => "checked_out",
1729 api_name => "open-ils.actor.user.checked_out.count",
1731 signature => q/@see open-ils.actor.user.checked_out/
1735 my( $self, $conn, $auth, $userid ) = @_;
1737 my $e = new_editor(authtoken=>$auth);
1738 return $e->event unless $e->checkauth;
1740 if( $userid ne $e->requestor->id ) {
1741 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1744 my $count = $self->api_name =~ /count/;
1745 return _checked_out( $count, $e, $userid );
1749 my( $iscount, $e, $userid ) = @_;
1751 my $circs = $e->search_action_circulation(
1752 { usr => $userid, stop_fines => undef });
1754 my $parser = DateTime::Format::ISO8601->new;
1756 # split the circs up into overdue and not-overdue circs
1758 for my $c (@$circs) {
1759 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1760 my $due = $due_dt->epoch;
1761 if ($due < DateTime->today->epoch) {
1762 push @overdue, $c->id;
1768 # grab all of the lost, claims-returned, and longoverdue circs
1769 my $open = $e->search_action_circulation(
1770 {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1772 my( @lost, @cr, @lo );
1773 for my $c (@$open) {
1774 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1775 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1776 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1782 total => @$circs + @lost + @cr + @lo,
1783 out => scalar(@out),
1784 overdue => scalar(@overdue),
1785 lost => scalar(@lost),
1786 claims_returned => scalar(@cr),
1787 long_overdue => scalar(@lo)
1793 overdue => \@overdue,
1795 claims_returned => \@cr,
1796 long_overdue => \@lo
1804 __PACKAGE__->register_method(
1805 method => "user_transaction_history",
1806 api_name => "open-ils.actor.user.transactions.history",
1808 notes => <<" NOTES");
1809 Returns a list of billable transaction ids for a user, optionally by type
1811 __PACKAGE__->register_method(
1812 method => "user_transaction_history",
1813 api_name => "open-ils.actor.user.transactions.history.have_charge",
1815 notes => <<" NOTES");
1816 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
1818 __PACKAGE__->register_method(
1819 method => "user_transaction_history",
1820 api_name => "open-ils.actor.user.transactions.history.have_balance",
1822 notes => <<" NOTES");
1823 Returns a list of billable transaction ids for a user that have a balance, optionally by type
1827 sub _user_transaction_history {
1828 my( $self, $client, $login_session, $user_id, $type ) = @_;
1830 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1831 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1832 return $evt if $evt;
1834 my $api = $self->api_name();
1839 @xact = (xact_type => $type) if(defined($type));
1840 @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
1841 @charge = (last_billing_ts => { "<>" => undef }) if $api =~ /have_charge/;
1843 $logger->debug("searching for transaction history: @xact : @balance, @charge");
1845 my $trans = $apputils->simple_scalar_request(
1847 "open-ils.storage.direct.money.billable_transaction_summary.search_where.atomic",
1848 { usr => $user_id, @xact, @charge, @balance }, { order_by => 'xact_start DESC' });
1850 return [ map { $_->id } @$trans ];
1855 sub user_transaction_history {
1856 my( $self, $conn, $auth, $userid, $type ) = @_;
1857 my $e = new_editor(authtoken=>$auth);
1858 return $e->event unless $e->checkauth;
1859 return $e->event unless $e->allowed('VIEW_USER_TRANSACTIONS');
1861 my $api = $self->api_name;
1862 my @xact = (xact_type => $type) if(defined($type));
1863 my @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
1864 my @charge = (last_billing_ts => { "!=" => undef }) if $api =~ /have_charge/;
1866 return $e->search_money_billable_transaction_summary(
1868 { usr => $userid, @xact, @charge, @balance },
1869 { order_by => 'xact_start DESC' }
1875 __PACKAGE__->register_method(
1876 method => "user_perms",
1877 api_name => "open-ils.actor.permissions.user_perms.retrieve",
1879 notes => <<" NOTES");
1880 Returns a list of permissions
1883 my( $self, $client, $authtoken, $user ) = @_;
1885 my( $staff, $evt ) = $apputils->checkses($authtoken);
1886 return $evt if $evt;
1888 $user ||= $staff->id;
1890 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
1894 return $apputils->simple_scalar_request(
1896 "open-ils.storage.permission.user_perms.atomic",
1900 __PACKAGE__->register_method(
1901 method => "retrieve_perms",
1902 api_name => "open-ils.actor.permissions.retrieve",
1903 notes => <<" NOTES");
1904 Returns a list of permissions
1906 sub retrieve_perms {
1907 my( $self, $client ) = @_;
1908 return $apputils->simple_scalar_request(
1910 "open-ils.storage.direct.permission.perm_list.retrieve.all.atomic");
1913 __PACKAGE__->register_method(
1914 method => "retrieve_groups",
1915 api_name => "open-ils.actor.groups.retrieve",
1916 notes => <<" NOTES");
1917 Returns a list of user groupss
1919 sub retrieve_groups {
1920 my( $self, $client ) = @_;
1921 return $apputils->simple_scalar_request(
1923 "open-ils.storage.direct.permission.grp_tree.retrieve.all.atomic");
1926 __PACKAGE__->register_method(
1927 method => "retrieve_org_address",
1928 api_name => "open-ils.actor.org_unit.address.retrieve",
1929 notes => <<' NOTES');
1930 Returns an org_unit address by ID
1931 @param An org_address ID
1933 sub retrieve_org_address {
1934 my( $self, $client, $id ) = @_;
1935 return $apputils->simple_scalar_request(
1937 "open-ils.storage.direct.actor.org_address.retrieve",
1942 __PACKAGE__->register_method(
1943 method => "retrieve_groups_tree",
1944 api_name => "open-ils.actor.groups.tree.retrieve",
1945 notes => <<" NOTES");
1946 Returns a list of user groups
1948 sub retrieve_groups_tree {
1949 my( $self, $client ) = @_;
1950 my $groups = $apputils->simple_scalar_request(
1952 "open-ils.storage.direct.permission.grp_tree.retrieve.all.atomic");
1953 return $self->build_group_tree($groups);
1957 # turns an org list into an org tree
1958 sub build_group_tree {
1960 my( $self, $grplist) = @_;
1962 return $grplist unless (
1963 ref($grplist) and @$grplist > 1 );
1965 my @list = sort { $a->name cmp $b->name } @$grplist;
1968 for my $grp (@list) {
1970 if ($grp and !defined($grp->parent)) {
1974 my ($parent) = grep { $_->id == $grp->parent} @list;
1976 $parent->children([]) unless defined($parent->children);
1977 push( @{$parent->children}, $grp );
1985 __PACKAGE__->register_method(
1986 method => "add_user_to_groups",
1987 api_name => "open-ils.actor.user.set_groups",
1988 notes => <<" NOTES");
1989 Adds a user to one or more permission groups
1992 sub add_user_to_groups {
1993 my( $self, $client, $authtoken, $userid, $groups ) = @_;
1995 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1996 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
1997 return $evt if $evt;
1999 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2000 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
2001 return $evt if $evt;
2003 $apputils->simplereq(
2005 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
2007 for my $group (@$groups) {
2008 my $link = Fieldmapper::permission::usr_grp_map->new;
2010 $link->usr($userid);
2012 my $id = $apputils->simplereq(
2014 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2020 __PACKAGE__->register_method(
2021 method => "get_user_perm_groups",
2022 api_name => "open-ils.actor.user.get_groups",
2023 notes => <<" NOTES");
2024 Retrieve a user's permission groups.
2028 sub get_user_perm_groups {
2029 my( $self, $client, $authtoken, $userid ) = @_;
2031 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2032 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2033 return $evt if $evt;
2035 return $apputils->simplereq(
2037 'open-ils.storage.direct.permission.usr_grp_map.search.usr.atomic', $userid );
2042 __PACKAGE__->register_method (
2043 method => 'register_workstation',
2044 api_name => 'open-ils.actor.workstation.register.override',
2045 signature => q/@see open-ils.actor.workstation.register/);
2047 __PACKAGE__->register_method (
2048 method => 'register_workstation',
2049 api_name => 'open-ils.actor.workstation.register',
2051 Registers a new workstion in the system
2052 @param authtoken The login session key
2053 @param name The name of the workstation id
2054 @param owner The org unit that owns this workstation
2055 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2056 if the name is already in use.
2059 sub _register_workstation {
2060 my( $self, $connection, $authtoken, $name, $owner ) = @_;
2061 my( $requestor, $evt ) = $U->checkses($authtoken);
2062 return $evt if $evt;
2063 $evt = $U->check_perms($requestor->id, $owner, 'REGISTER_WORKSTATION');
2064 return $evt if $evt;
2066 my $ws = $U->storagereq(
2067 'open-ils.storage.direct.actor.workstation.search.name', $name );
2068 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS') if $ws;
2070 $ws = Fieldmapper::actor::workstation->new;
2071 $ws->owning_lib($owner);
2074 my $id = $U->storagereq(
2075 'open-ils.storage.direct.actor.workstation.create', $ws );
2076 return $U->DB_UPDATE_FAILED($ws) unless $id;
2082 sub register_workstation {
2083 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2085 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2086 return $e->event unless $e->checkauth;
2087 return $e->event unless $e->allowed('REGISTER_WORKSTATION'); # XXX rely on editor perms
2088 my $existing = $e->search_actor_workstation({name => $name});
2091 if( $self->api_name =~ /override/o ) {
2092 return $e->event unless $e->allowed('DELETE_WORKSTATION'); # XXX rely on editor perms
2093 return $e->event unless $e->delete_actor_workstation($$existing[0]);
2095 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2099 my $ws = Fieldmapper::actor::workstation->new;
2100 $ws->owning_lib($owner);
2102 $e->create_actor_workstation($ws) or return $e->event;
2104 return $ws->id; # note: editor sets the id on the new object for us
2108 __PACKAGE__->register_method (
2109 method => 'fetch_patron_note',
2110 api_name => 'open-ils.actor.note.retrieve.all',
2112 Returns a list of notes for a given user
2113 Requestor must have VIEW_USER permission if pub==false and
2114 @param authtoken The login session key
2115 @param args Hash of params including
2116 patronid : the patron's id
2117 pub : true if retrieving only public notes
2121 sub fetch_patron_note {
2122 my( $self, $conn, $authtoken, $args ) = @_;
2123 my $patronid = $$args{patronid};
2125 my($reqr, $evt) = $U->checkses($authtoken);
2128 ($patron, $evt) = $U->fetch_user($patronid);
2129 return $evt if $evt;
2132 if( $patronid ne $reqr->id ) {
2133 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2134 return $evt if $evt;
2136 return $U->storagereq(
2137 'open-ils.storage.direct.actor.usr_note.search_where.atomic',
2138 { usr => $patronid, pub => 't' } );
2141 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2142 return $evt if $evt;
2144 return $U->storagereq(
2145 'open-ils.storage.direct.actor.usr_note.search.usr.atomic', $patronid );
2148 __PACKAGE__->register_method (
2149 method => 'create_user_note',
2150 api_name => 'open-ils.actor.note.create',
2152 Creates a new note for the given user
2153 @param authtoken The login session key
2154 @param note The note object
2157 sub create_user_note {
2158 my( $self, $conn, $authtoken, $note ) = @_;
2159 my( $reqr, $patron, $evt ) =
2160 $U->checkses_requestor($authtoken, $note->usr, 'UPDATE_USER');
2161 return $evt if $evt;
2162 $logger->activity("user ".$reqr->id." creating note for user ".$note->usr);
2164 $note->pub('f') unless $note->pub;
2165 $note->creator($reqr->id);
2166 my $id = $U->storagereq(
2167 'open-ils.storage.direct.actor.usr_note.create', $note );
2168 return $U->DB_UPDATE_FAILED($note) unless $id;
2173 __PACKAGE__->register_method (
2174 method => 'delete_user_note',
2175 api_name => 'open-ils.actor.note.delete',
2177 Deletes a note for the given user
2178 @param authtoken The login session key
2179 @param noteid The note id
2182 sub delete_user_note {
2183 my( $self, $conn, $authtoken, $noteid ) = @_;
2185 my $note = $U->storagereq(
2186 'open-ils.storage.direct.actor.usr_note.retrieve', $noteid);
2187 return OpenILS::Event->new('ACTOR_USER_NOTE_NOT_FOUND') unless $note;
2189 my( $reqr, $patron, $evt ) =
2190 $U->checkses_requestor($authtoken, $note->usr, 'UPDATE_USER');
2191 return $evt if $evt;
2192 $logger->activity("user ".$reqr->id." deleting note [$noteid] for user ".$note->usr);
2194 my $stat = $U->storagereq(
2195 'open-ils.storage.direct.actor.usr_note.delete', $noteid );
2196 return $U->DB_UPDATE_FAILED($note) unless defined $stat;
2202 __PACKAGE__->register_method (
2203 method => 'create_closed_date',
2204 api_name => 'open-ils.actor.org_unit.closed_date.create',
2206 Creates a new closing entry for the given org_unit
2207 @param authtoken The login session key
2208 @param note The closed_date object
2211 sub create_closed_date {
2212 my( $self, $conn, $authtoken, $cd ) = @_;
2214 my( $user, $evt ) = $U->checkses($authtoken);
2215 return $evt if $evt;
2217 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2218 return $evt if $evt;
2220 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2222 my $id = $U->storagereq(
2223 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2224 return $U->DB_UPDATE_FAILED($cd) unless $id;
2229 __PACKAGE__->register_method (
2230 method => 'delete_closed_date',
2231 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2233 Deletes a closing entry for the given org_unit
2234 @param authtoken The login session key
2235 @param noteid The close_date id
2238 sub delete_closed_date {
2239 my( $self, $conn, $authtoken, $cd ) = @_;
2241 my( $user, $evt ) = $U->checkses($authtoken);
2242 return $evt if $evt;
2245 ($cd_obj, $evt) = fetch_closed_date($cd);
2246 return $evt if $evt;
2248 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2249 return $evt if $evt;
2251 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2253 my $stat = $U->storagereq(
2254 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2255 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2260 __PACKAGE__->register_method(
2261 method => 'usrname_exists',
2262 api_name => 'open-ils.actor.username.exists',
2264 Returns 1 if the requested username exists, returns 0 otherwise
2268 sub usrname_exists {
2269 my( $self, $conn, $auth, $usrname ) = @_;
2270 my $e = new_editor(authtoken=>$auth);
2271 return $e->event unless $e->checkauth;
2272 my $a = $e->search_actor_user({usrname => $usrname}, {idlist=>1});
2273 return $$a[0] if $a and @$a;
2277 __PACKAGE__->register_method(
2278 method => 'barcode_exists',
2279 api_name => 'open-ils.actor.barcode.exists',
2281 Returns 1 if the requested barcode exists, returns 0 otherwise
2285 sub barcode_exists {
2286 my( $self, $conn, $auth, $barcode ) = @_;
2287 my $e = new_editor(authtoken=>$auth);
2288 return $e->event unless $e->checkauth;
2289 my $a = $e->search_actor_card({barcode => $barcode}, {idlist=>1});
2290 return $$a[0] if $a and @$a;
2295 __PACKAGE__->register_method(
2296 method => 'retrieve_net_levels',
2297 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2300 sub retrieve_net_levels {
2301 my( $self, $conn, $auth ) = @_;
2302 my $e = new_editor(authtoken=>$auth);
2303 return $e->event unless $e->checkauth;
2304 return $e->retrieve_all_config_net_access_level();