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) = @_;
893 return $org_types if $org_types;
894 return $org_types = new_editor()->retrieve_all_actor_org_unit_type();
899 __PACKAGE__->register_method(
900 method => "get_user_profiles",
901 api_name => "open-ils.actor.user.profiles.retrieve",
905 sub get_user_profiles {
906 return $user_profiles if $user_profiles;
908 return $user_profiles =
909 $apputils->simple_scalar_request(
911 "open-ils.storage.direct.actor.profile.retrieve.all.atomic");
916 __PACKAGE__->register_method(
917 method => "get_user_ident_types",
918 api_name => "open-ils.actor.user.ident_types.retrieve",
921 sub get_user_ident_types {
922 return $ident_types if $ident_types;
923 return $ident_types =
924 new_editor()->retrieve_all_config_identification_type();
930 __PACKAGE__->register_method(
931 method => "get_org_unit",
932 api_name => "open-ils.actor.org_unit.retrieve",
936 my( $self, $client, $user_session, $org_id ) = @_;
937 my $e = new_editor(authtoken => $user_session);
939 return $e->event unless $e->checkauth;
940 $org_id = $e->requestor->ws_ou;
942 my $o = $e->retrieve_actor_org_unit($org_id)
947 __PACKAGE__->register_method(
948 method => "search_org_unit",
949 api_name => "open-ils.actor.org_unit_list.search",
952 sub search_org_unit {
954 my( $self, $client, $field, $value ) = @_;
956 my $list = OpenILS::Application::AppUtils->simple_scalar_request(
958 "open-ils.storage.direct.actor.org_unit.search.$field.atomic",
967 __PACKAGE__->register_method(
968 method => "get_org_tree",
969 api_name => "open-ils.actor.org_tree.retrieve",
971 note => "Returns the entire org tree structure",
975 my( $self, $client) = @_;
977 $cache = OpenSRF::Utils::Cache->new("global", 0) unless $cache;
978 my $tree = $cache->get_cache('orgtree');
979 return $tree if $tree;
981 $tree = new_editor()->search_actor_org_unit(
983 {"parent_ou" => undef },
986 flesh_fields => { aou => ['children'] },
987 order_by => { aou => 'shortname'}
992 $cache->put_cache('orgtree', $tree);
997 # turns an org list into an org tree
1000 my( $self, $orglist) = @_;
1002 return $orglist unless (
1003 ref($orglist) and @$orglist > 1 );
1006 $a->ou_type <=> $b->ou_type ||
1007 $a->name cmp $b->name } @$orglist;
1009 for my $org (@list) {
1011 next unless ($org and defined($org->parent_ou));
1012 my ($parent) = grep { $_->id == $org->parent_ou } @list;
1013 next unless $parent;
1015 $parent->children([]) unless defined($parent->children);
1016 push( @{$parent->children}, $org );
1024 __PACKAGE__->register_method(
1025 method => "get_org_descendants",
1026 api_name => "open-ils.actor.org_tree.descendants.retrieve"
1029 # depth is optional. org_unit is the id
1030 sub get_org_descendants {
1031 my( $self, $client, $org_unit, $depth ) = @_;
1032 my $orglist = $apputils->simple_scalar_request(
1034 "open-ils.storage.actor.org_unit.descendants.atomic",
1035 $org_unit, $depth );
1036 return $self->build_org_tree($orglist);
1040 __PACKAGE__->register_method(
1041 method => "get_org_ancestors",
1042 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
1045 # depth is optional. org_unit is the id
1046 sub get_org_ancestors {
1047 my( $self, $client, $org_unit, $depth ) = @_;
1048 my $orglist = $apputils->simple_scalar_request(
1050 "open-ils.storage.actor.org_unit.ancestors.atomic",
1051 $org_unit, $depth );
1052 return $self->build_org_tree($orglist);
1056 __PACKAGE__->register_method(
1057 method => "get_standings",
1058 api_name => "open-ils.actor.standings.retrieve"
1063 return $user_standings if $user_standings;
1064 return $user_standings =
1065 $apputils->simple_scalar_request(
1067 "open-ils.storage.direct.config.standing.retrieve.all.atomic" );
1072 __PACKAGE__->register_method(
1073 method => "get_my_org_path",
1074 api_name => "open-ils.actor.org_unit.full_path.retrieve"
1077 sub get_my_org_path {
1078 my( $self, $client, $user_session, $org_id ) = @_;
1079 my $user_obj = $apputils->check_user_session($user_session);
1080 if(!defined($org_id)) { $org_id = $user_obj->home_ou; }
1082 return $apputils->simple_scalar_request(
1084 "open-ils.storage.actor.org_unit.full_path.atomic",
1089 __PACKAGE__->register_method(
1090 method => "patron_adv_search",
1091 api_name => "open-ils.actor.patron.search.advanced" );
1092 sub patron_adv_search {
1093 my( $self, $client, $auth, $search_hash, $search_limit, $search_sort ) = @_;
1094 my $e = new_editor(authtoken=>$auth);
1095 return $e->event unless $e->checkauth;
1096 return $e->event unless $e->allowed('VIEW_USER');
1097 return $U->storagereq(
1098 "open-ils.storage.actor.user.crazy_search",
1099 $search_hash, $search_limit, $search_sort);
1104 sub _verify_password {
1105 my($user_session, $password) = @_;
1106 my $user_obj = $apputils->check_user_session($user_session);
1108 #grab the user with password
1109 $user_obj = $apputils->simple_scalar_request(
1111 "open-ils.storage.direct.actor.user.retrieve",
1114 if($user_obj->passwd eq $password) {
1122 __PACKAGE__->register_method(
1123 method => "update_password",
1124 api_name => "open-ils.actor.user.password.update");
1126 __PACKAGE__->register_method(
1127 method => "update_password",
1128 api_name => "open-ils.actor.user.username.update");
1130 __PACKAGE__->register_method(
1131 method => "update_password",
1132 api_name => "open-ils.actor.user.email.update");
1134 sub update_password {
1135 my( $self, $client, $user_session, $new_value, $current_password ) = @_;
1139 my $user_obj = $apputils->check_user_session($user_session);
1141 if($self->api_name =~ /password/o) {
1143 #make sure they know the current password
1144 if(!_verify_password($user_session, md5_hex($current_password))) {
1145 return OpenILS::Event->new('INCORRECT_PASSWORD');
1148 $logger->debug("update_password setting new password $new_value");
1149 $user_obj->passwd($new_value);
1151 } elsif($self->api_name =~ /username/o) {
1152 my $users = search_username(undef, undef, $new_value);
1153 if( $users and $users->[0] ) {
1154 return OpenILS::Event->new('USERNAME_EXISTS');
1156 $user_obj->usrname($new_value);
1158 } elsif($self->api_name =~ /email/o) {
1159 #warn "Updating email to $new_value\n";
1160 $user_obj->email($new_value);
1163 my $session = $apputils->start_db_session();
1165 ( $user_obj, $evt ) = _update_patron($session, $user_obj, $user_obj, 1);
1166 return $evt if $evt;
1168 $apputils->commit_db_session($session);
1170 if($user_obj) { return 1; }
1175 __PACKAGE__->register_method(
1176 method => "check_user_perms",
1177 api_name => "open-ils.actor.user.perm.check",
1178 notes => <<" NOTES");
1179 Takes a login session, user id, an org id, and an array of perm type strings. For each
1180 perm type, if the user does *not* have the given permission it is added
1181 to a list which is returned from the method. If all permissions
1182 are allowed, an empty list is returned
1183 if the logged in user does not match 'user_id', then the logged in user must
1184 have VIEW_PERMISSION priveleges.
1187 sub check_user_perms {
1188 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1190 my( $staff, $evt ) = $apputils->checkses($login_session);
1191 return $evt if $evt;
1193 if($staff->id ne $user_id) {
1194 if( my $evt = $apputils->check_perms(
1195 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1201 for my $perm (@$perm_types) {
1202 if($apputils->check_perms($user_id, $org_id, $perm)) {
1203 push @not_allowed, $perm;
1207 return \@not_allowed
1210 __PACKAGE__->register_method(
1211 method => "check_user_perms2",
1212 api_name => "open-ils.actor.user.perm.check.multi_org",
1214 Checks the permissions on a list of perms and orgs for a user
1215 @param authtoken The login session key
1216 @param user_id The id of the user to check
1217 @param orgs The array of org ids
1218 @param perms The array of permission names
1219 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1220 if the logged in user does not match 'user_id', then the logged in user must
1221 have VIEW_PERMISSION priveleges.
1224 sub check_user_perms2 {
1225 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1227 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1228 $authtoken, $user_id, 'VIEW_PERMISSION' );
1229 return $evt if $evt;
1232 for my $org (@$orgs) {
1233 for my $perm (@$perms) {
1234 if($apputils->check_perms($user_id, $org, $perm)) {
1235 push @not_allowed, [ $org, $perm ];
1240 return \@not_allowed
1244 __PACKAGE__->register_method(
1245 method => 'check_user_perms3',
1246 api_name => 'open-ils.actor.user.perm.highest_org',
1248 Returns the highest org unit id at which a user has a given permission
1249 If the requestor does not match the target user, the requestor must have
1250 'VIEW_PERMISSION' rights at the home org unit of the target user
1251 @param authtoken The login session key
1252 @param userid The id of the user in question
1253 @param perm The permission to check
1254 @return The org unit highest in the org tree within which the user has
1255 the requested permission
1258 sub check_user_perms3 {
1259 my( $self, $client, $authtoken, $userid, $perm ) = @_;
1261 my( $staff, $target, $org, $evt );
1263 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1264 $authtoken, $userid, 'VIEW_PERMISSION' );
1265 return $evt if $evt;
1267 my $tree = $self->get_org_tree();
1268 return _find_highest_perm_org( $perm, $userid, $target->ws_ou, $tree );
1272 sub _find_highest_perm_org {
1273 my ( $perm, $userid, $start_org, $org_tree ) = @_;
1274 my $org = $apputils->find_org($org_tree, $start_org );
1278 last if ($apputils->check_perms( $userid, $org->id, $perm )); # perm failed
1280 $org = $apputils->find_org( $org_tree, $org->parent_ou() );
1286 __PACKAGE__->register_method(
1287 method => 'check_user_perms4',
1288 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1290 Returns the highest org unit id at which a user has a given permission
1291 If the requestor does not match the target user, the requestor must have
1292 'VIEW_PERMISSION' rights at the home org unit of the target user
1293 @param authtoken The login session key
1294 @param userid The id of the user in question
1295 @param perms An array of perm names to check
1296 @return An array of orgId's representing the org unit
1297 highest in the org tree within which the user has the requested permission
1298 The arrah of orgId's has matches the order of the perms array
1301 sub check_user_perms4 {
1302 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1304 my( $staff, $target, $org, $evt );
1306 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1307 $authtoken, $userid, 'VIEW_PERMISSION' );
1308 return $evt if $evt;
1311 return [] unless ref($perms);
1312 my $tree = $self->get_org_tree();
1314 for my $p (@$perms) {
1315 push( @arr, _find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1323 __PACKAGE__->register_method(
1324 method => "user_fines_summary",
1325 api_name => "open-ils.actor.user.fines.summary",
1326 notes => <<" NOTES");
1327 Returns a short summary of the users total open fines, excluding voided fines
1328 Params are login_session, user_id
1329 Returns a 'mous' object.
1332 sub user_fines_summary {
1333 my( $self, $client, $login_session, $user_id ) = @_;
1335 my $user_obj = $apputils->check_user_session($login_session);
1336 if($user_obj->id ne $user_id) {
1337 if($apputils->check_user_perms($user_obj->id, $user_obj->home_ou, "VIEW_USER_FINES_SUMMARY")) {
1338 return OpenILS::Perm->new("VIEW_USER_FINES_SUMMARY");
1342 return $apputils->simple_scalar_request(
1344 "open-ils.storage.direct.money.open_user_summary.search.usr",
1352 __PACKAGE__->register_method(
1353 method => "user_transactions",
1354 api_name => "open-ils.actor.user.transactions",
1355 notes => <<" NOTES");
1356 Returns a list of open user transactions (mbts objects);
1357 Params are login_session, user_id
1358 Optional third parameter is the transactions type. defaults to all
1361 __PACKAGE__->register_method(
1362 method => "user_transactions",
1363 api_name => "open-ils.actor.user.transactions.have_charge",
1364 notes => <<" NOTES");
1365 Returns a list of all open user transactions (mbts objects) that have an initial charge
1366 Params are login_session, user_id
1367 Optional third parameter is the transactions type. defaults to all
1370 __PACKAGE__->register_method(
1371 method => "user_transactions",
1372 api_name => "open-ils.actor.user.transactions.have_balance",
1373 notes => <<" NOTES");
1374 Returns a list of all open user transactions (mbts objects) that have a balance
1375 Params are login_session, user_id
1376 Optional third parameter is the transactions type. defaults to all
1379 __PACKAGE__->register_method(
1380 method => "user_transactions",
1381 api_name => "open-ils.actor.user.transactions.fleshed",
1382 notes => <<" NOTES");
1383 Returns an object/hash of transaction, circ, title where transaction = an open
1384 user transactions (mbts objects), circ is the attached circluation, and title
1385 is the title the circ points to
1386 Params are login_session, user_id
1387 Optional third parameter is the transactions type. defaults to all
1390 __PACKAGE__->register_method(
1391 method => "user_transactions",
1392 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1393 notes => <<" NOTES");
1394 Returns an object/hash of transaction, circ, title where transaction = an open
1395 user transactions that has an initial charge (mbts objects), circ is the
1396 attached circluation, and title is the title the circ points to
1397 Params are login_session, user_id
1398 Optional third parameter is the transactions type. defaults to all
1401 __PACKAGE__->register_method(
1402 method => "user_transactions",
1403 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1404 notes => <<" NOTES");
1405 Returns an object/hash of transaction, circ, title where transaction = an open
1406 user transaction that has a balance (mbts objects), circ is the attached
1407 circluation, and title is the title the circ points to
1408 Params are login_session, user_id
1409 Optional third parameter is the transaction type. defaults to all
1412 __PACKAGE__->register_method(
1413 method => "user_transactions",
1414 api_name => "open-ils.actor.user.transactions.count",
1415 notes => <<" NOTES");
1416 Returns an object/hash of transaction, circ, title where transaction = an open
1417 user transactions (mbts objects), circ is the attached circluation, and title
1418 is the title the circ points to
1419 Params are login_session, user_id
1420 Optional third parameter is the transactions type. defaults to all
1423 __PACKAGE__->register_method(
1424 method => "user_transactions",
1425 api_name => "open-ils.actor.user.transactions.have_charge.count",
1426 notes => <<" NOTES");
1427 Returns an object/hash of transaction, circ, title where transaction = an open
1428 user transactions that has an initial charge (mbts objects), circ is the
1429 attached circluation, and title is the title the circ points to
1430 Params are login_session, user_id
1431 Optional third parameter is the transactions type. defaults to all
1434 __PACKAGE__->register_method(
1435 method => "user_transactions",
1436 api_name => "open-ils.actor.user.transactions.have_balance.count",
1437 notes => <<" NOTES");
1438 Returns an object/hash of transaction, circ, title where transaction = an open
1439 user transaction that has a balance (mbts objects), circ is the attached
1440 circluation, and title is the title the circ points to
1441 Params are login_session, user_id
1442 Optional third parameter is the transaction type. defaults to all
1445 __PACKAGE__->register_method(
1446 method => "user_transactions",
1447 api_name => "open-ils.actor.user.transactions.have_balance.total",
1448 notes => <<" NOTES");
1449 Returns an object/hash of transaction, circ, title where transaction = an open
1450 user transaction that has a balance (mbts objects), circ is the attached
1451 circluation, and title is the title the circ points to
1452 Params are login_session, user_id
1453 Optional third parameter is the transaction type. defaults to all
1458 sub user_transactions {
1459 my( $self, $client, $login_session, $user_id, $type ) = @_;
1461 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1462 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1463 return $evt if $evt;
1465 my $api = $self->api_name();
1469 if(defined($type)) { @xact = (xact_type => $type);
1471 } else { @xact = (); }
1473 if($api =~ /have_charge/o) {
1475 $trans = $apputils->simple_scalar_request(
1477 "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1478 { usr => $user_id, total_owed => { ">" => 0 }, @xact });
1480 } elsif($api =~ /have_balance/o) {
1482 $trans = $apputils->simple_scalar_request(
1484 "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1485 { usr => $user_id, balance_owed => { "<>" => 0 }, @xact });
1489 $trans = $apputils->simple_scalar_request(
1491 "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1492 { usr => $user_id, @xact });
1495 if($api =~ /total/o) {
1497 for my $t (@$trans) {
1498 $total += $t->balance_owed;
1501 $logger->debug("Total balance owed by user $user_id: $total");
1505 if($api =~ /count/o) { return scalar @$trans; }
1506 if($api !~ /fleshed/o) { return $trans; }
1509 for my $t (@$trans) {
1511 if( $t->xact_type ne 'circulation' ) {
1512 push @resp, {transaction => $t};
1516 my $circ = $apputils->simple_scalar_request(
1518 "open-ils.storage.direct.action.circulation.retrieve",
1523 my $title = $apputils->simple_scalar_request(
1525 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1526 $circ->target_copy );
1530 my $u = OpenILS::Utils::ModsParser->new();
1531 $u->start_mods_batch($title->marc());
1532 my $mods = $u->finish_mods_batch();
1534 push @resp, {transaction => $t, circ => $circ, record => $mods };
1542 __PACKAGE__->register_method(
1543 method => "user_transaction_retrieve",
1544 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1546 notes => <<" NOTES");
1547 Returns a fleshedtransaction record
1549 __PACKAGE__->register_method(
1550 method => "user_transaction_retrieve",
1551 api_name => "open-ils.actor.user.transaction.retrieve",
1553 notes => <<" NOTES");
1554 Returns a transaction record
1556 sub user_transaction_retrieve {
1557 my( $self, $client, $login_session, $bill_id ) = @_;
1559 my $trans = $apputils->simple_scalar_request(
1561 "open-ils.storage.direct.money.billable_transaction_summary.retrieve",
1565 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1566 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1567 return $evt if $evt;
1569 my $api = $self->api_name();
1570 if($api !~ /fleshed/o) { return $trans; }
1572 if( $trans->xact_type ne 'circulation' ) {
1573 $logger->debug("Returning non-circ transaction");
1574 return {transaction => $trans};
1577 my $circ = $apputils->simple_scalar_request(
1579 "open-ils.storage.direct.action.circulation.retrieve",
1582 return {transaction => $trans} unless $circ;
1583 $logger->debug("Found the circ transaction");
1585 my $title = $apputils->simple_scalar_request(
1587 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1588 $circ->target_copy );
1590 return {transaction => $trans, circ => $circ } unless $title;
1591 $logger->debug("Found the circ title");
1595 my $u = OpenILS::Utils::ModsParser->new();
1596 $u->start_mods_batch($title->marc());
1597 $mods = $u->finish_mods_batch();
1599 if ($title->id == -1) {
1600 my $copy = $apputils->simple_scalar_request(
1602 "open-ils.storage.direct.asset.copy.retrieve",
1603 $circ->target_copy );
1605 $mods = new Fieldmapper::metabib::virtual_record;
1607 $mods->title($copy->dummy_title);
1608 $mods->author($copy->dummy_author);
1612 $logger->debug("MODSized the circ title");
1614 return {transaction => $trans, circ => $circ, record => $mods };
1618 __PACKAGE__->register_method(
1619 method => "hold_request_count",
1620 api_name => "open-ils.actor.user.hold_requests.count",
1622 notes => <<" NOTES");
1623 Returns hold ready/total counts
1625 sub hold_request_count {
1626 my( $self, $client, $login_session, $userid ) = @_;
1628 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1629 $login_session, $userid, 'VIEW_HOLD' );
1630 return $evt if $evt;
1633 my $holds = $apputils->simple_scalar_request(
1635 "open-ils.storage.direct.action.hold_request.search_where.atomic",
1637 fulfillment_time => {"=" => undef } }
1641 for my $h (@$holds) {
1642 next unless $h->capture_time;
1644 my $copy = $apputils->simple_scalar_request(
1646 "open-ils.storage.direct.asset.copy.retrieve",
1650 if ($copy->status == 8) {
1655 return { total => scalar(@$holds), ready => scalar(@ready) };
1659 __PACKAGE__->register_method(
1660 method => "checkedout_count",
1661 api_name => "open-ils.actor.user.checked_out.count__",
1663 notes => <<" NOTES");
1664 Returns a transaction record
1668 sub checkedout_count {
1669 my( $self, $client, $login_session, $userid ) = @_;
1671 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1672 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1673 return $evt if $evt;
1675 my $circs = $apputils->simple_scalar_request(
1677 "open-ils.storage.direct.action.circulation.search_where.atomic",
1678 { usr => $userid, stop_fines => undef }
1679 #{ usr => $userid, checkin_time => {"=" => undef } }
1682 my $parser = DateTime::Format::ISO8601->new;
1685 for my $c (@$circs) {
1686 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1687 my $due = $due_dt->epoch;
1689 if ($due < DateTime->today->epoch) {
1694 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1698 __PACKAGE__->register_method(
1699 method => "checked_out",
1700 api_name => "open-ils.actor.user.checked_out",
1703 Returns a structure of circulations objects sorted by
1704 out, overdue, lost, claims_returned, long_overdue.
1705 A list of IDs are returned of each type.
1706 lost, long_overdue, and claims_returned circ will not
1707 be "finished" (there is an outstanding balance or some
1708 other pending action on the circ).
1710 The .count method also includes a 'total' field which
1711 sums all "open" circs
1715 __PACKAGE__->register_method(
1716 method => "checked_out",
1717 api_name => "open-ils.actor.user.checked_out.count",
1719 signature => q/@see open-ils.actor.user.checked_out/
1723 my( $self, $conn, $auth, $userid ) = @_;
1725 my $e = new_editor(authtoken=>$auth);
1726 return $e->event unless $e->checkauth;
1728 if( $userid ne $e->requestor->id ) {
1729 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1732 my $count = $self->api_name =~ /count/;
1733 return _checked_out( $count, $e, $userid );
1737 my( $iscount, $e, $userid ) = @_;
1739 my $circs = $e->search_action_circulation(
1740 { usr => $userid, stop_fines => undef });
1742 my $parser = DateTime::Format::ISO8601->new;
1744 # split the circs up into overdue and not-overdue circs
1746 for my $c (@$circs) {
1747 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1748 my $due = $due_dt->epoch;
1749 if ($due < DateTime->today->epoch) {
1750 push @overdue, $c->id;
1756 # grab all of the lost, claims-returned, and longoverdue circs
1757 my $open = $e->search_action_circulation(
1758 {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1760 my( @lost, @cr, @lo );
1761 for my $c (@$open) {
1762 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1763 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1764 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1770 total => @$circs + @lost + @cr + @lo,
1771 out => scalar(@out),
1772 overdue => scalar(@overdue),
1773 lost => scalar(@lost),
1774 claims_returned => scalar(@cr),
1775 long_overdue => scalar(@lo)
1781 overdue => \@overdue,
1783 claims_returned => \@cr,
1784 long_overdue => \@lo
1792 __PACKAGE__->register_method(
1793 method => "user_transaction_history",
1794 api_name => "open-ils.actor.user.transactions.history",
1796 notes => <<" NOTES");
1797 Returns a list of billable transaction ids for a user, optionally by type
1799 __PACKAGE__->register_method(
1800 method => "user_transaction_history",
1801 api_name => "open-ils.actor.user.transactions.history.have_charge",
1803 notes => <<" NOTES");
1804 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
1806 __PACKAGE__->register_method(
1807 method => "user_transaction_history",
1808 api_name => "open-ils.actor.user.transactions.history.have_balance",
1810 notes => <<" NOTES");
1811 Returns a list of billable transaction ids for a user that have a balance, optionally by type
1815 sub _user_transaction_history {
1816 my( $self, $client, $login_session, $user_id, $type ) = @_;
1818 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1819 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1820 return $evt if $evt;
1822 my $api = $self->api_name();
1827 @xact = (xact_type => $type) if(defined($type));
1828 @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
1829 @charge = (last_billing_ts => { "<>" => undef }) if $api =~ /have_charge/;
1831 $logger->debug("searching for transaction history: @xact : @balance, @charge");
1833 my $trans = $apputils->simple_scalar_request(
1835 "open-ils.storage.direct.money.billable_transaction_summary.search_where.atomic",
1836 { usr => $user_id, @xact, @charge, @balance }, { order_by => 'xact_start DESC' });
1838 return [ map { $_->id } @$trans ];
1843 sub user_transaction_history {
1844 my( $self, $conn, $auth, $userid, $type ) = @_;
1845 my $e = new_editor(authtoken=>$auth);
1846 return $e->event unless $e->checkauth;
1847 return $e->event unless $e->allowed('VIEW_USER_TRANSACTIONS');
1849 my $api = $self->api_name;
1850 my @xact = (xact_type => $type) if(defined($type));
1851 my @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
1852 my @charge = (last_billing_ts => { "!=" => undef }) if $api =~ /have_charge/;
1854 return $e->search_money_billable_transaction_summary(
1856 { usr => $userid, @xact, @charge, @balance },
1857 { order_by => 'xact_start DESC' }
1863 __PACKAGE__->register_method(
1864 method => "user_perms",
1865 api_name => "open-ils.actor.permissions.user_perms.retrieve",
1867 notes => <<" NOTES");
1868 Returns a list of permissions
1871 my( $self, $client, $authtoken, $user ) = @_;
1873 my( $staff, $evt ) = $apputils->checkses($authtoken);
1874 return $evt if $evt;
1876 $user ||= $staff->id;
1878 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
1882 return $apputils->simple_scalar_request(
1884 "open-ils.storage.permission.user_perms.atomic",
1888 __PACKAGE__->register_method(
1889 method => "retrieve_perms",
1890 api_name => "open-ils.actor.permissions.retrieve",
1891 notes => <<" NOTES");
1892 Returns a list of permissions
1894 sub retrieve_perms {
1895 my( $self, $client ) = @_;
1896 return $apputils->simple_scalar_request(
1898 "open-ils.storage.direct.permission.perm_list.retrieve.all.atomic");
1901 __PACKAGE__->register_method(
1902 method => "retrieve_groups",
1903 api_name => "open-ils.actor.groups.retrieve",
1904 notes => <<" NOTES");
1905 Returns a list of user groupss
1907 sub retrieve_groups {
1908 my( $self, $client ) = @_;
1909 return new_editor()->retrieve_all_permission_grp_tree();
1912 __PACKAGE__->register_method(
1913 method => "retrieve_org_address",
1914 api_name => "open-ils.actor.org_unit.address.retrieve",
1915 notes => <<' NOTES');
1916 Returns an org_unit address by ID
1917 @param An org_address ID
1919 sub retrieve_org_address {
1920 my( $self, $client, $id ) = @_;
1921 return $apputils->simple_scalar_request(
1923 "open-ils.storage.direct.actor.org_address.retrieve",
1928 __PACKAGE__->register_method(
1929 method => "retrieve_groups_tree",
1930 api_name => "open-ils.actor.groups.tree.retrieve",
1931 notes => <<" NOTES");
1932 Returns a list of user groups
1934 sub retrieve_groups_tree {
1935 my( $self, $client ) = @_;
1936 my $groups = $apputils->simple_scalar_request(
1938 "open-ils.storage.direct.permission.grp_tree.retrieve.all.atomic");
1939 return $self->build_group_tree($groups);
1943 # turns an org list into an org tree
1944 sub build_group_tree {
1946 my( $self, $grplist) = @_;
1948 return $grplist unless (
1949 ref($grplist) and @$grplist > 1 );
1951 my @list = sort { $a->name cmp $b->name } @$grplist;
1954 for my $grp (@list) {
1956 if ($grp and !defined($grp->parent)) {
1960 my ($parent) = grep { $_->id == $grp->parent} @list;
1962 $parent->children([]) unless defined($parent->children);
1963 push( @{$parent->children}, $grp );
1971 __PACKAGE__->register_method(
1972 method => "add_user_to_groups",
1973 api_name => "open-ils.actor.user.set_groups",
1974 notes => <<" NOTES");
1975 Adds a user to one or more permission groups
1978 sub add_user_to_groups {
1979 my( $self, $client, $authtoken, $userid, $groups ) = @_;
1981 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1982 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
1983 return $evt if $evt;
1985 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1986 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
1987 return $evt if $evt;
1989 $apputils->simplereq(
1991 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
1993 for my $group (@$groups) {
1994 my $link = Fieldmapper::permission::usr_grp_map->new;
1996 $link->usr($userid);
1998 my $id = $apputils->simplereq(
2000 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2006 __PACKAGE__->register_method(
2007 method => "get_user_perm_groups",
2008 api_name => "open-ils.actor.user.get_groups",
2009 notes => <<" NOTES");
2010 Retrieve a user's permission groups.
2014 sub get_user_perm_groups {
2015 my( $self, $client, $authtoken, $userid ) = @_;
2017 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2018 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2019 return $evt if $evt;
2021 return $apputils->simplereq(
2023 'open-ils.storage.direct.permission.usr_grp_map.search.usr.atomic', $userid );
2028 __PACKAGE__->register_method (
2029 method => 'register_workstation',
2030 api_name => 'open-ils.actor.workstation.register.override',
2031 signature => q/@see open-ils.actor.workstation.register/);
2033 __PACKAGE__->register_method (
2034 method => 'register_workstation',
2035 api_name => 'open-ils.actor.workstation.register',
2037 Registers a new workstion in the system
2038 @param authtoken The login session key
2039 @param name The name of the workstation id
2040 @param owner The org unit that owns this workstation
2041 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2042 if the name is already in use.
2045 sub _register_workstation {
2046 my( $self, $connection, $authtoken, $name, $owner ) = @_;
2047 my( $requestor, $evt ) = $U->checkses($authtoken);
2048 return $evt if $evt;
2049 $evt = $U->check_perms($requestor->id, $owner, 'REGISTER_WORKSTATION');
2050 return $evt if $evt;
2052 my $ws = $U->storagereq(
2053 'open-ils.storage.direct.actor.workstation.search.name', $name );
2054 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS') if $ws;
2056 $ws = Fieldmapper::actor::workstation->new;
2057 $ws->owning_lib($owner);
2060 my $id = $U->storagereq(
2061 'open-ils.storage.direct.actor.workstation.create', $ws );
2062 return $U->DB_UPDATE_FAILED($ws) unless $id;
2068 sub register_workstation {
2069 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2071 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2072 return $e->event unless $e->checkauth;
2073 return $e->event unless $e->allowed('REGISTER_WORKSTATION'); # XXX rely on editor perms
2074 my $existing = $e->search_actor_workstation({name => $name});
2077 if( $self->api_name =~ /override/o ) {
2078 return $e->event unless $e->allowed('DELETE_WORKSTATION'); # XXX rely on editor perms
2079 return $e->event unless $e->delete_actor_workstation($$existing[0]);
2081 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2085 my $ws = Fieldmapper::actor::workstation->new;
2086 $ws->owning_lib($owner);
2088 $e->create_actor_workstation($ws) or return $e->event;
2090 return $ws->id; # note: editor sets the id on the new object for us
2094 __PACKAGE__->register_method (
2095 method => 'fetch_patron_note',
2096 api_name => 'open-ils.actor.note.retrieve.all',
2098 Returns a list of notes for a given user
2099 Requestor must have VIEW_USER permission if pub==false and
2100 @param authtoken The login session key
2101 @param args Hash of params including
2102 patronid : the patron's id
2103 pub : true if retrieving only public notes
2107 sub fetch_patron_note {
2108 my( $self, $conn, $authtoken, $args ) = @_;
2109 my $patronid = $$args{patronid};
2111 my($reqr, $evt) = $U->checkses($authtoken);
2114 ($patron, $evt) = $U->fetch_user($patronid);
2115 return $evt if $evt;
2118 if( $patronid ne $reqr->id ) {
2119 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2120 return $evt if $evt;
2122 return $U->storagereq(
2123 'open-ils.storage.direct.actor.usr_note.search_where.atomic',
2124 { usr => $patronid, pub => 't' } );
2127 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2128 return $evt if $evt;
2130 return $U->storagereq(
2131 'open-ils.storage.direct.actor.usr_note.search.usr.atomic', $patronid );
2134 __PACKAGE__->register_method (
2135 method => 'create_user_note',
2136 api_name => 'open-ils.actor.note.create',
2138 Creates a new note for the given user
2139 @param authtoken The login session key
2140 @param note The note object
2143 sub create_user_note {
2144 my( $self, $conn, $authtoken, $note ) = @_;
2145 my( $reqr, $patron, $evt ) =
2146 $U->checkses_requestor($authtoken, $note->usr, 'UPDATE_USER');
2147 return $evt if $evt;
2148 $logger->activity("user ".$reqr->id." creating note for user ".$note->usr);
2150 $note->pub('f') unless $note->pub;
2151 $note->creator($reqr->id);
2152 my $id = $U->storagereq(
2153 'open-ils.storage.direct.actor.usr_note.create', $note );
2154 return $U->DB_UPDATE_FAILED($note) unless $id;
2159 __PACKAGE__->register_method (
2160 method => 'delete_user_note',
2161 api_name => 'open-ils.actor.note.delete',
2163 Deletes a note for the given user
2164 @param authtoken The login session key
2165 @param noteid The note id
2168 sub delete_user_note {
2169 my( $self, $conn, $authtoken, $noteid ) = @_;
2171 my $note = $U->storagereq(
2172 'open-ils.storage.direct.actor.usr_note.retrieve', $noteid);
2173 return OpenILS::Event->new('ACTOR_USER_NOTE_NOT_FOUND') unless $note;
2175 my( $reqr, $patron, $evt ) =
2176 $U->checkses_requestor($authtoken, $note->usr, 'UPDATE_USER');
2177 return $evt if $evt;
2178 $logger->activity("user ".$reqr->id." deleting note [$noteid] for user ".$note->usr);
2180 my $stat = $U->storagereq(
2181 'open-ils.storage.direct.actor.usr_note.delete', $noteid );
2182 return $U->DB_UPDATE_FAILED($note) unless defined $stat;
2188 __PACKAGE__->register_method (
2189 method => 'create_closed_date',
2190 api_name => 'open-ils.actor.org_unit.closed_date.create',
2192 Creates a new closing entry for the given org_unit
2193 @param authtoken The login session key
2194 @param note The closed_date object
2197 sub create_closed_date {
2198 my( $self, $conn, $authtoken, $cd ) = @_;
2200 my( $user, $evt ) = $U->checkses($authtoken);
2201 return $evt if $evt;
2203 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2204 return $evt if $evt;
2206 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2208 my $id = $U->storagereq(
2209 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2210 return $U->DB_UPDATE_FAILED($cd) unless $id;
2215 __PACKAGE__->register_method (
2216 method => 'delete_closed_date',
2217 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2219 Deletes a closing entry for the given org_unit
2220 @param authtoken The login session key
2221 @param noteid The close_date id
2224 sub delete_closed_date {
2225 my( $self, $conn, $authtoken, $cd ) = @_;
2227 my( $user, $evt ) = $U->checkses($authtoken);
2228 return $evt if $evt;
2231 ($cd_obj, $evt) = fetch_closed_date($cd);
2232 return $evt if $evt;
2234 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2235 return $evt if $evt;
2237 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2239 my $stat = $U->storagereq(
2240 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2241 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2246 __PACKAGE__->register_method(
2247 method => 'usrname_exists',
2248 api_name => 'open-ils.actor.username.exists',
2250 Returns 1 if the requested username exists, returns 0 otherwise
2254 sub usrname_exists {
2255 my( $self, $conn, $auth, $usrname ) = @_;
2256 my $e = new_editor(authtoken=>$auth);
2257 return $e->event unless $e->checkauth;
2258 my $a = $e->search_actor_user({usrname => $usrname}, {idlist=>1});
2259 return $$a[0] if $a and @$a;
2263 __PACKAGE__->register_method(
2264 method => 'barcode_exists',
2265 api_name => 'open-ils.actor.barcode.exists',
2267 Returns 1 if the requested barcode exists, returns 0 otherwise
2271 sub barcode_exists {
2272 my( $self, $conn, $auth, $barcode ) = @_;
2273 my $e = new_editor(authtoken=>$auth);
2274 return $e->event unless $e->checkauth;
2275 my $a = $e->search_actor_card({barcode => $barcode}, {idlist=>1});
2276 return $$a[0] if $a and @$a;
2281 __PACKAGE__->register_method(
2282 method => 'retrieve_net_levels',
2283 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2286 sub retrieve_net_levels {
2287 my( $self, $conn, $auth ) = @_;
2288 my $e = new_editor(authtoken=>$auth);
2289 return $e->event unless $e->checkauth;
2290 return $e->retrieve_all_config_net_access_level();