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;
25 use OpenILS::Const qw/:const/;
27 use OpenILS::Application::Actor::Container;
28 use OpenILS::Application::Actor::ClosedDates;
30 use OpenILS::Utils::CStoreEditor qw/:funcs/;
32 use OpenILS::Application::Actor::UserGroups;
34 OpenILS::Application::Actor::Container->initialize();
35 OpenILS::Application::Actor::UserGroups->initialize();
36 OpenILS::Application::Actor::ClosedDates->initialize();
39 my $apputils = "OpenILS::Application::AppUtils";
42 sub _d { warn "Patron:\n" . Dumper(shift()); }
47 my $set_user_settings;
50 __PACKAGE__->register_method(
51 method => "set_user_settings",
52 api_name => "open-ils.actor.patron.settings.update",
54 sub set_user_settings {
55 my( $self, $client, $user_session, $uid, $settings ) = @_;
57 $logger->debug("Setting user settings: $user_session, $uid, " . Dumper($settings));
59 my( $staff, $user, $evt ) =
60 $apputils->checkses_requestor( $user_session, $uid, 'UPDATE_USER' );
64 [{ usr => $user->id, name => $_}, {value => $$settings{$_}}] } keys %$settings;
66 $_->[1]->{value} = JSON->perl2JSON($_->[1]->{value}) for @params;
68 $logger->activity("User " . $staff->id . " updating user $uid settings with: " . Dumper(\@params));
70 my $ses = $U->start_db_session();
71 my $stat = $ses->request(
72 'open-ils.storage.direct.actor.user_setting.batch.merge', @params )->gather(1);
73 $U->commit_db_session($ses);
80 __PACKAGE__->register_method(
81 method => "set_ou_settings",
82 api_name => "open-ils.actor.org_unit.settings.update",
85 my( $self, $client, $user_session, $ouid, $settings ) = @_;
87 my( $staff, $evt ) = $apputils->checkses( $user_session );
89 $evt = $apputils->check_perms( $staff->id, $ouid, 'UPDATE_ORG_SETTING' );
93 for my $set (keys %$settings) {
95 my $json = JSON->perl2JSON($$settings{$set});
96 $logger->activity("updating org_unit.setting: $ouid : $set : $json");
99 { org_unit => $ouid, name => $set },
100 { value => $json } );
103 my $ses = $U->start_db_session();
104 my $stat = $ses->request(
105 'open-ils.storage.direct.actor.org_unit_setting.merge', @params )->gather(1);
106 $U->commit_db_session($ses);
112 my $fetch_user_settings;
113 my $fetch_ou_settings;
115 __PACKAGE__->register_method(
116 method => "user_settings",
117 api_name => "open-ils.actor.patron.settings.retrieve",
120 my( $self, $client, $user_session, $uid ) = @_;
122 my( $staff, $user, $evt ) =
123 $apputils->checkses_requestor( $user_session, $uid, 'VIEW_USER' );
126 $logger->debug("User " . $staff->id . " fetching user $uid\n");
127 my $s = $apputils->simplereq(
129 'open-ils.cstore.direct.actor.user_setting.search.atomic', { usr => $uid } );
131 return { map { ( $_->name => JSON->JSON2perl($_->value) ) } @$s };
136 __PACKAGE__->register_method(
137 method => "ou_settings",
138 api_name => "open-ils.actor.org_unit.settings.retrieve",
141 my( $self, $client, $ouid ) = @_;
143 $logger->info("Fetching org unit settings for org $ouid");
145 my $s = $apputils->simplereq(
147 'open-ils.cstore.direct.actor.org_unit_setting.search.atomic', {org_unit => $ouid});
149 return { map { ( $_->name => JSON->JSON2perl($_->value) ) } @$s };
152 __PACKAGE__->register_method (
153 method => "ou_setting_delete",
154 api_name => 'open-ils.actor.org_setting.delete',
156 Deletes a specific org unit setting for a specific location
157 @param authtoken The login session key
158 @param orgid The org unit whose setting we're changing
159 @param setting The name of the setting to delete
160 @return True value on success.
164 sub ou_setting_delete {
165 my( $self, $conn, $authtoken, $orgid, $setting ) = @_;
166 my( $reqr, $evt) = $U->checkses($authtoken);
168 $evt = $U->check_perms($reqr->id, $orgid, 'UPDATE_ORG_SETTING');
171 my $id = $U->cstorereq(
172 'open-ils.cstore.direct.actor.org_unit_setting.id_list',
173 { name => $setting, org_unit => $orgid } );
175 $logger->debug("Retrieved setting $id in org unit setting delete");
177 my $s = $U->cstorereq(
178 'open-ils.cstore.direct.actor.org_unit_setting.delete', $id );
180 $logger->activity("User ".$reqr->id." deleted org unit setting $id") if $s;
186 __PACKAGE__->register_method(
187 method => "update_patron",
188 api_name => "open-ils.actor.patron.update",);
191 my( $self, $client, $user_session, $patron ) = @_;
193 my $session = $apputils->start_db_session();
197 $logger->info("Creating new patron...") if $patron->isnew;
198 $logger->info("Updating Patron: " . $patron->id) unless $patron->isnew;
200 my( $user_obj, $evt ) = $U->checkses($user_session);
203 $evt = check_group_perm($session, $user_obj, $patron);
207 # XXX does this user have permission to add/create users. Granularity?
208 # $new_patron is the patron in progress. $patron is the original patron
209 # passed in with the method. new_patron will change as the components
210 # of patron are added/updated.
214 # unflesh the real items on the patron
215 $patron->card( $patron->card->id ) if(ref($patron->card));
216 $patron->billing_address( $patron->billing_address->id )
217 if(ref($patron->billing_address));
218 $patron->mailing_address( $patron->mailing_address->id )
219 if(ref($patron->mailing_address));
221 # create/update the patron first so we can use his id
222 if($patron->isnew()) {
223 ( $new_patron, $evt ) = _add_patron($session, _clone_patron($patron), $user_obj);
225 } else { $new_patron = $patron; }
227 ( $new_patron, $evt ) = _add_update_addresses($session, $patron, $new_patron, $user_obj);
230 ( $new_patron, $evt ) = _add_update_cards($session, $patron, $new_patron, $user_obj);
233 ( $new_patron, $evt ) = _add_survey_responses($session, $patron, $new_patron, $user_obj);
236 # re-update the patron if anything has happened to him during this process
237 if($new_patron->ischanged()) {
238 ( $new_patron, $evt ) = _update_patron($session, $new_patron, $user_obj);
242 ($new_patron, $evt) = _create_stat_maps($session, $user_session, $patron, $new_patron, $user_obj);
245 ($new_patron, $evt) = _create_perm_maps($session, $user_session, $patron, $new_patron, $user_obj);
248 ($new_patron, $evt) = _create_standing_penalties($session, $user_session, $patron, $new_patron, $user_obj);
251 $logger->activity("user ".$user_obj->id." updating/creating user ".$new_patron->id);
254 if(!$patron->isnew) {
255 $opatron = new_editor()->retrieve_actor_user($new_patron->id);
258 $apputils->commit_db_session($session);
259 my $fuser = flesh_user($new_patron->id());
262 # Log the new and old patron for investigation
263 $logger->info("$user_session updating patron object. orig patron object = ".
264 JSON->perl2JSON($opatron). " |||| new patron = ".JSON->perl2JSON($fuser));
274 return new_flesh_user($id, [
277 "standing_penalties",
281 "stat_cat_entries" ] );
289 # clone and clear stuff that would break the database
293 my $new_patron = $patron->clone;
295 $new_patron->clear_billing_address();
296 $new_patron->clear_mailing_address();
297 $new_patron->clear_addresses();
298 $new_patron->clear_card();
299 $new_patron->clear_cards();
300 $new_patron->clear_id();
301 $new_patron->clear_isnew();
302 $new_patron->clear_ischanged();
303 $new_patron->clear_isdeleted();
304 $new_patron->clear_stat_cat_entries();
305 $new_patron->clear_permissions();
306 $new_patron->clear_standing_penalties();
316 my $user_obj = shift;
318 my $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'CREATE_USER');
319 return (undef, $evt) if $evt;
321 my $ex = $session->request(
322 'open-ils.storage.direct.actor.user.search.usrname', $patron->usrname())->gather(1);
324 return (undef, OpenILS::Event->new('USERNAME_EXISTS'));
327 $logger->info("Creating new user in the DB with username: ".$patron->usrname());
329 my $id = $session->request(
330 "open-ils.storage.direct.actor.user.create", $patron)->gather(1);
331 return (undef, $U->DB_UPDATE_FAILED($patron)) unless $id;
333 $logger->info("Successfully created new user [$id] in DB");
335 return ( $session->request(
336 "open-ils.storage.direct.actor.user.retrieve", $id)->gather(1), undef );
340 sub check_group_perm {
341 my( $session, $requestor, $patron ) = @_;
344 # first let's see if the requestor has
345 # priveleges to update this user in any way
346 if( ! $patron->isnew ) {
347 my $p = $session->request(
348 'open-ils.storage.direct.actor.user.retrieve', $patron->id )->gather(1);
350 # If we are the requestor (trying to update our own account)
351 # and we are not trying to change our profile, we're good
352 if( $p->id == $requestor->id and
353 $p->profile == $patron->profile ) {
358 $evt = group_perm_failed($session, $requestor, $p);
362 # They are allowed to edit this patron.. can they put the
363 # patron into the group requested?
364 $evt = group_perm_failed($session, $requestor, $patron);
370 sub group_perm_failed {
371 my( $session, $requestor, $patron ) = @_;
375 my $grpid = $patron->profile;
379 $logger->debug("user update looking for group perm for group $grpid");
380 $grp = $session->request(
381 'open-ils.storage.direct.permission.grp_tree.retrieve', $grpid )->gather(1);
382 return OpenILS::Event->new('PERMISSION_GRP_TREE_NOT_FOUND') unless $grp;
384 } while( !($perm = $grp->application_perm) and ($grpid = $grp->parent) );
386 $logger->info("user update checking perm $perm on user ".
387 $requestor->id." for update/create on user username=".$patron->usrname);
389 my $evt = $U->check_perms($requestor->id, $patron->home_ou, $perm);
397 my( $session, $patron, $user_obj, $noperm) = @_;
399 $logger->info("Updating patron ".$patron->id." in DB");
404 $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'UPDATE_USER');
405 return (undef, $evt) if $evt;
408 # update the password by itself to avoid the password protection magic
409 if( $patron->passwd ) {
410 my $s = $session->request(
411 'open-ils.storage.direct.actor.user.remote_update',
412 {id => $patron->id}, {passwd => $patron->passwd})->gather(1);
413 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($s);
414 $patron->clear_passwd;
417 if(!$patron->ident_type) {
418 $patron->clear_ident_type;
419 $patron->clear_ident_value;
422 my $stat = $session->request(
423 "open-ils.storage.direct.actor.user.update",$patron )->gather(1);
424 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($stat);
429 sub _check_dup_ident {
430 my( $session, $patron ) = @_;
432 return undef unless $patron->ident_value;
435 ident_type => $patron->ident_type,
436 ident_value => $patron->ident_value,
439 $logger->debug("patron update searching for dup ident values: " .
440 $patron->ident_type . ':' . $patron->ident_value);
442 $search->{id} = {'!=' => $patron->id} if $patron->id and $patron->id > 0;
444 my $dups = $session->request(
445 'open-ils.storage.direct.actor.user.search_where.atomic', $search )->gather(1);
448 return OpenILS::Event->new('PATRON_DUP_IDENT1', payload => $patron )
455 sub _add_update_addresses {
459 my $new_patron = shift;
463 my $current_id; # id of the address before creation
465 for my $address (@{$patron->addresses()}) {
467 next unless ref $address;
468 $current_id = $address->id();
470 if( $patron->billing_address() and
471 $patron->billing_address() == $current_id ) {
472 $logger->info("setting billing addr to $current_id");
473 $new_patron->billing_address($address->id());
474 $new_patron->ischanged(1);
477 if( $patron->mailing_address() and
478 $patron->mailing_address() == $current_id ) {
479 $new_patron->mailing_address($address->id());
480 $logger->info("setting mailing addr to $current_id");
481 $new_patron->ischanged(1);
485 if($address->isnew()) {
487 $address->usr($new_patron->id());
489 ($address, $evt) = _add_address($session,$address);
490 return (undef, $evt) if $evt;
492 # we need to get the new id
493 if( $patron->billing_address() and
494 $patron->billing_address() == $current_id ) {
495 $new_patron->billing_address($address->id());
496 $logger->info("setting billing addr to $current_id");
497 $new_patron->ischanged(1);
500 if( $patron->mailing_address() and
501 $patron->mailing_address() == $current_id ) {
502 $new_patron->mailing_address($address->id());
503 $logger->info("setting mailing addr to $current_id");
504 $new_patron->ischanged(1);
507 } elsif($address->ischanged() ) {
509 ($address, $evt) = _update_address($session, $address);
510 return (undef, $evt) if $evt;
512 } elsif($address->isdeleted() ) {
514 if( $address->id() == $new_patron->mailing_address() ) {
515 $new_patron->clear_mailing_address();
516 ($new_patron, $evt) = _update_patron($session, $new_patron);
517 return (undef, $evt) if $evt;
520 if( $address->id() == $new_patron->billing_address() ) {
521 $new_patron->clear_billing_address();
522 ($new_patron, $evt) = _update_patron($session, $new_patron);
523 return (undef, $evt) if $evt;
526 $evt = _delete_address($session, $address);
527 return (undef, $evt) if $evt;
531 return ( $new_patron, undef );
535 # adds an address to the db and returns the address with new id
537 my($session, $address) = @_;
538 $address->clear_id();
540 $logger->info("Creating new address at street ".$address->street1);
542 # put the address into the database
543 my $id = $session->request(
544 "open-ils.storage.direct.actor.user_address.create", $address )->gather(1);
545 return (undef, $U->DB_UPDATE_FAILED($address)) unless $id;
548 return ($address, undef);
552 sub _update_address {
553 my( $session, $address ) = @_;
555 $logger->info("Updating address ".$address->id." in the DB");
557 my $stat = $session->request(
558 "open-ils.storage.direct.actor.user_address.update", $address )->gather(1);
560 return (undef, $U->DB_UPDATE_FAILED($address)) unless defined($stat);
561 return ($address, undef);
566 sub _add_update_cards {
570 my $new_patron = shift;
574 my $virtual_id; #id of the card before creation
575 for my $card (@{$patron->cards()}) {
577 $card->usr($new_patron->id());
579 if(ref($card) and $card->isnew()) {
581 $virtual_id = $card->id();
582 ( $card, $evt ) = _add_card($session,$card);
583 return (undef, $evt) if $evt;
585 #if(ref($patron->card)) { $patron->card($patron->card->id); }
586 if($patron->card() == $virtual_id) {
587 $new_patron->card($card->id());
588 $new_patron->ischanged(1);
591 } elsif( ref($card) and $card->ischanged() ) {
592 $evt = _update_card($session, $card);
593 return (undef, $evt) if $evt;
597 return ( $new_patron, undef );
601 # adds an card to the db and returns the card with new id
603 my( $session, $card ) = @_;
606 $logger->info("Adding new patron card ".$card->barcode);
608 my $id = $session->request(
609 "open-ils.storage.direct.actor.card.create", $card )->gather(1);
610 return (undef, $U->DB_UPDATE_FAILED($card)) unless $id;
611 $logger->info("Successfully created patron card $id");
614 return ( $card, undef );
618 # returns event on error. returns undef otherwise
620 my( $session, $card ) = @_;
621 $logger->info("Updating patron card ".$card->id);
623 my $stat = $session->request(
624 "open-ils.storage.direct.actor.card.update", $card )->gather(1);
625 return $U->DB_UPDATE_FAILED($card) unless defined($stat);
632 # returns event on error. returns undef otherwise
633 sub _delete_address {
634 my( $session, $address ) = @_;
636 $logger->info("Deleting address ".$address->id." from DB");
638 my $stat = $session->request(
639 "open-ils.storage.direct.actor.user_address.delete", $address )->gather(1);
641 return $U->DB_UPDATE_FAILED($address) unless defined($stat);
647 sub _add_survey_responses {
648 my ($session, $patron, $new_patron) = @_;
650 $logger->info( "Updating survey responses for patron ".$new_patron->id );
652 my $responses = $patron->survey_responses;
656 $_->usr($new_patron->id) for (@$responses);
658 my $evt = $U->simplereq( "open-ils.circ",
659 "open-ils.circ.survey.submit.user_id", $responses );
661 return (undef, $evt) if defined($U->event_code($evt));
665 return ( $new_patron, undef );
669 sub _create_stat_maps {
671 my($session, $user_session, $patron, $new_patron) = @_;
673 my $maps = $patron->stat_cat_entries();
675 for my $map (@$maps) {
677 my $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.update";
679 if ($map->isdeleted()) {
680 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.delete";
682 } elsif ($map->isnew()) {
683 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.create";
688 $map->target_usr($new_patron->id);
691 $logger->info("Updating stat entry with method $method and map $map");
693 my $stat = $session->request($method, $map)->gather(1);
694 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
698 return ($new_patron, undef);
701 sub _create_perm_maps {
703 my($session, $user_session, $patron, $new_patron) = @_;
705 my $maps = $patron->permissions;
707 for my $map (@$maps) {
709 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
710 if ($map->isdeleted()) {
711 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
712 } elsif ($map->isnew()) {
713 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
718 $map->usr($new_patron->id);
720 #warn( "Updating permissions with method $method and session $user_session and map $map" );
721 $logger->info( "Updating permissions with method $method and map $map" );
723 my $stat = $session->request($method, $map)->gather(1);
724 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
728 return ($new_patron, undef);
732 __PACKAGE__->register_method(
733 method => "set_user_perms",
734 api_name => "open-ils.actor.user.permissions.update",
743 my $session = $apputils->start_db_session();
745 my( $user_obj, $evt ) = $U->checkses($ses);
748 my $perms = $session->request('open-ils.storage.permission.user_perms.atomic', $user_obj->id)->gather(1);
751 $all = 1 if ($user_obj->super_user());
752 $all = 1 unless ($U->check_perms($user_obj->id, $user_obj->home_ou, 'EVERYTHING'));
754 for my $map (@$maps) {
756 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
757 if ($map->isdeleted()) {
758 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
759 } elsif ($map->isnew()) {
760 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
764 next if (!$all || !grep { $_->perm eq $map->perm and $_->grantable == 1 and $_->depth <= $map->depth } @$perms);
766 #warn( "Updating permissions with method $method and session $ses and map $map" );
767 $logger->info( "Updating permissions with method $method and map $map" );
769 my $stat = $session->request($method, $map)->gather(1);
770 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
774 $apputils->commit_db_session($session);
776 return scalar(@$maps);
780 sub _create_standing_penalties {
782 my($session, $user_session, $patron, $new_patron) = @_;
784 my $maps = $patron->standing_penalties;
787 for my $map (@$maps) {
789 if ($map->isdeleted()) {
790 $method = "open-ils.storage.direct.actor.user_standing_penalty.delete";
791 } elsif ($map->isnew()) {
792 $method = "open-ils.storage.direct.actor.user_standing_penalty.create";
798 $map->usr($new_patron->id);
800 $logger->debug( "Updating standing penalty with method $method and session $user_session and map $map" );
802 my $stat = $session->request($method, $map)->gather(1);
803 return (undef, $U->DB_UPDATE_FAILED($map)) unless $stat;
806 return ($new_patron, undef);
811 __PACKAGE__->register_method(
812 method => "search_username",
813 api_name => "open-ils.actor.user.search.username",
816 sub search_username {
817 my($self, $client, $username) = @_;
818 my $users = OpenILS::Application::AppUtils->simple_scalar_request(
820 "open-ils.cstore.direct.actor.user.search.atomic",
821 { usrname => $username }
829 __PACKAGE__->register_method(
830 method => "user_retrieve_by_barcode",
831 api_name => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
833 sub user_retrieve_by_barcode {
834 my($self, $client, $user_session, $barcode) = @_;
836 $logger->debug("Searching for user with barcode $barcode");
837 my ($user_obj, $evt) = $apputils->checkses($user_session);
840 my $card = OpenILS::Application::AppUtils->simple_scalar_request(
842 "open-ils.cstore.direct.actor.card.search.atomic",
843 { barcode => $barcode }
846 if(!$card || !$card->[0]) {
847 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' );
851 my $user = flesh_user($card->usr());
853 $evt = $U->check_perms($user_obj->id, $user->home_ou, 'VIEW_USER');
856 if(!$user) { return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ); }
863 __PACKAGE__->register_method(
864 method => "get_user_by_id",
865 api_name => "open-ils.actor.user.retrieve",);
868 my ($self, $client, $auth, $id) = @_;
869 my $e = new_editor(authtoken=>$auth);
870 return $e->event unless $e->checkauth;
871 my $user = $e->retrieve_actor_user($id)
873 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
879 __PACKAGE__->register_method(
880 method => "get_org_types",
881 api_name => "open-ils.actor.org_types.retrieve",);
885 my($self, $client) = @_;
886 return $org_types if $org_types;
887 return $org_types = new_editor()->retrieve_all_actor_org_unit_type();
892 __PACKAGE__->register_method(
893 method => "get_user_ident_types",
894 api_name => "open-ils.actor.user.ident_types.retrieve",
897 sub get_user_ident_types {
898 return $ident_types if $ident_types;
899 return $ident_types =
900 new_editor()->retrieve_all_config_identification_type();
906 __PACKAGE__->register_method(
907 method => "get_org_unit",
908 api_name => "open-ils.actor.org_unit.retrieve",
912 my( $self, $client, $user_session, $org_id ) = @_;
913 my $e = new_editor(authtoken => $user_session);
915 return $e->event unless $e->checkauth;
916 $org_id = $e->requestor->ws_ou;
918 my $o = $e->retrieve_actor_org_unit($org_id)
923 __PACKAGE__->register_method(
924 method => "search_org_unit",
925 api_name => "open-ils.actor.org_unit_list.search",
928 sub search_org_unit {
930 my( $self, $client, $field, $value ) = @_;
932 my $list = OpenILS::Application::AppUtils->simple_scalar_request(
934 "open-ils.cstore.direct.actor.org_unit.search.atomic",
935 { $field => $value } );
943 __PACKAGE__->register_method(
944 method => "get_org_tree",
945 api_name => "open-ils.actor.org_tree.retrieve",
947 note => "Returns the entire org tree structure",
951 my( $self, $client) = @_;
953 $cache = OpenSRF::Utils::Cache->new("global", 0) unless $cache;
954 my $tree = $cache->get_cache('orgtree');
955 return $tree if $tree;
957 $tree = new_editor()->search_actor_org_unit(
959 {"parent_ou" => undef },
962 flesh_fields => { aou => ['children'] },
963 order_by => { aou => 'name'}
968 $cache->put_cache('orgtree', $tree);
973 # turns an org list into an org tree
976 my( $self, $orglist) = @_;
978 return $orglist unless (
979 ref($orglist) and @$orglist > 1 );
982 $a->ou_type <=> $b->ou_type ||
983 $a->name cmp $b->name } @$orglist;
985 for my $org (@list) {
987 next unless ($org and defined($org->parent_ou));
988 my ($parent) = grep { $_->id == $org->parent_ou } @list;
991 $parent->children([]) unless defined($parent->children);
992 push( @{$parent->children}, $org );
1000 __PACKAGE__->register_method(
1001 method => "get_org_descendants",
1002 api_name => "open-ils.actor.org_tree.descendants.retrieve"
1005 # depth is optional. org_unit is the id
1006 sub get_org_descendants {
1007 my( $self, $client, $org_unit, $depth ) = @_;
1008 my $orglist = $apputils->simple_scalar_request(
1010 "open-ils.storage.actor.org_unit.descendants.atomic",
1011 $org_unit, $depth );
1012 return $self->build_org_tree($orglist);
1016 __PACKAGE__->register_method(
1017 method => "get_org_ancestors",
1018 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
1021 # depth is optional. org_unit is the id
1022 sub get_org_ancestors {
1023 my( $self, $client, $org_unit, $depth ) = @_;
1024 my $orglist = $apputils->simple_scalar_request(
1026 "open-ils.storage.actor.org_unit.ancestors.atomic",
1027 $org_unit, $depth );
1028 return $self->build_org_tree($orglist);
1032 __PACKAGE__->register_method(
1033 method => "get_standings",
1034 api_name => "open-ils.actor.standings.retrieve"
1039 return $user_standings if $user_standings;
1040 return $user_standings =
1041 $apputils->simple_scalar_request(
1043 "open-ils.cstore.direct.config.standing.search.atomic",
1044 { id => { "!=" => undef } }
1050 __PACKAGE__->register_method(
1051 method => "get_my_org_path",
1052 api_name => "open-ils.actor.org_unit.full_path.retrieve"
1055 sub get_my_org_path {
1056 my( $self, $client, $user_session, $org_id ) = @_;
1057 my $user_obj = $apputils->check_user_session($user_session);
1058 if(!defined($org_id)) { $org_id = $user_obj->home_ou; }
1060 return $apputils->simple_scalar_request(
1062 "open-ils.storage.actor.org_unit.full_path.atomic",
1067 __PACKAGE__->register_method(
1068 method => "patron_adv_search",
1069 api_name => "open-ils.actor.patron.search.advanced" );
1070 sub patron_adv_search {
1071 my( $self, $client, $auth, $search_hash, $search_limit, $search_sort, $include_inactive ) = @_;
1072 my $e = new_editor(authtoken=>$auth);
1073 return $e->event unless $e->checkauth;
1074 return $e->event unless $e->allowed('VIEW_USER');
1075 return $U->storagereq(
1076 "open-ils.storage.actor.user.crazy_search",
1077 $search_hash, $search_limit, $search_sort, $include_inactive);
1082 sub _verify_password {
1083 my($user_session, $password) = @_;
1084 my $user_obj = $apputils->check_user_session($user_session);
1086 #grab the user with password
1087 $user_obj = $apputils->simple_scalar_request(
1089 "open-ils.cstore.direct.actor.user.retrieve",
1092 if($user_obj->passwd eq $password) {
1100 __PACKAGE__->register_method(
1101 method => "update_password",
1102 api_name => "open-ils.actor.user.password.update");
1104 __PACKAGE__->register_method(
1105 method => "update_password",
1106 api_name => "open-ils.actor.user.username.update");
1108 __PACKAGE__->register_method(
1109 method => "update_password",
1110 api_name => "open-ils.actor.user.email.update");
1112 sub update_password {
1113 my( $self, $client, $user_session, $new_value, $current_password ) = @_;
1117 my $user_obj = $apputils->check_user_session($user_session);
1119 if($self->api_name =~ /password/o) {
1121 #make sure they know the current password
1122 if(!_verify_password($user_session, md5_hex($current_password))) {
1123 return OpenILS::Event->new('INCORRECT_PASSWORD');
1126 $logger->debug("update_password setting new password $new_value");
1127 $user_obj->passwd($new_value);
1129 } elsif($self->api_name =~ /username/o) {
1130 my $users = search_username(undef, undef, $new_value);
1131 if( $users and $users->[0] ) {
1132 return OpenILS::Event->new('USERNAME_EXISTS');
1134 $user_obj->usrname($new_value);
1136 } elsif($self->api_name =~ /email/o) {
1137 #warn "Updating email to $new_value\n";
1138 $user_obj->email($new_value);
1141 my $session = $apputils->start_db_session();
1143 ( $user_obj, $evt ) = _update_patron($session, $user_obj, $user_obj, 1);
1144 return $evt if $evt;
1146 $apputils->commit_db_session($session);
1148 if($user_obj) { return 1; }
1153 __PACKAGE__->register_method(
1154 method => "check_user_perms",
1155 api_name => "open-ils.actor.user.perm.check",
1156 notes => <<" NOTES");
1157 Takes a login session, user id, an org id, and an array of perm type strings. For each
1158 perm type, if the user does *not* have the given permission it is added
1159 to a list which is returned from the method. If all permissions
1160 are allowed, an empty list is returned
1161 if the logged in user does not match 'user_id', then the logged in user must
1162 have VIEW_PERMISSION priveleges.
1165 sub check_user_perms {
1166 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1168 my( $staff, $evt ) = $apputils->checkses($login_session);
1169 return $evt if $evt;
1171 if($staff->id ne $user_id) {
1172 if( $evt = $apputils->check_perms(
1173 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1179 for my $perm (@$perm_types) {
1180 if($apputils->check_perms($user_id, $org_id, $perm)) {
1181 push @not_allowed, $perm;
1185 return \@not_allowed
1188 __PACKAGE__->register_method(
1189 method => "check_user_perms2",
1190 api_name => "open-ils.actor.user.perm.check.multi_org",
1192 Checks the permissions on a list of perms and orgs for a user
1193 @param authtoken The login session key
1194 @param user_id The id of the user to check
1195 @param orgs The array of org ids
1196 @param perms The array of permission names
1197 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1198 if the logged in user does not match 'user_id', then the logged in user must
1199 have VIEW_PERMISSION priveleges.
1202 sub check_user_perms2 {
1203 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1205 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1206 $authtoken, $user_id, 'VIEW_PERMISSION' );
1207 return $evt if $evt;
1210 for my $org (@$orgs) {
1211 for my $perm (@$perms) {
1212 if($apputils->check_perms($user_id, $org, $perm)) {
1213 push @not_allowed, [ $org, $perm ];
1218 return \@not_allowed
1222 __PACKAGE__->register_method(
1223 method => 'check_user_perms3',
1224 api_name => 'open-ils.actor.user.perm.highest_org',
1226 Returns the highest org unit id at which a user has a given permission
1227 If the requestor does not match the target user, the requestor must have
1228 'VIEW_PERMISSION' rights at the home org unit of the target user
1229 @param authtoken The login session key
1230 @param userid The id of the user in question
1231 @param perm The permission to check
1232 @return The org unit highest in the org tree within which the user has
1233 the requested permission
1236 sub check_user_perms3 {
1237 my( $self, $client, $authtoken, $userid, $perm ) = @_;
1239 my( $staff, $target, $org, $evt );
1241 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1242 $authtoken, $userid, 'VIEW_PERMISSION' );
1243 return $evt if $evt;
1245 my $tree = $self->get_org_tree();
1246 return _find_highest_perm_org( $perm, $userid, $target->ws_ou, $tree );
1250 sub _find_highest_perm_org {
1251 my ( $perm, $userid, $start_org, $org_tree ) = @_;
1252 my $org = $apputils->find_org($org_tree, $start_org );
1256 last if ($apputils->check_perms( $userid, $org->id, $perm )); # perm failed
1258 $org = $apputils->find_org( $org_tree, $org->parent_ou() );
1264 __PACKAGE__->register_method(
1265 method => 'check_user_perms4',
1266 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1268 Returns the highest org unit id at which a user has a given permission
1269 If the requestor does not match the target user, the requestor must have
1270 'VIEW_PERMISSION' rights at the home org unit of the target user
1271 @param authtoken The login session key
1272 @param userid The id of the user in question
1273 @param perms An array of perm names to check
1274 @return An array of orgId's representing the org unit
1275 highest in the org tree within which the user has the requested permission
1276 The arrah of orgId's has matches the order of the perms array
1279 sub check_user_perms4 {
1280 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1282 my( $staff, $target, $org, $evt );
1284 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1285 $authtoken, $userid, 'VIEW_PERMISSION' );
1286 return $evt if $evt;
1289 return [] unless ref($perms);
1290 my $tree = $self->get_org_tree();
1292 for my $p (@$perms) {
1293 push( @arr, _find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1301 __PACKAGE__->register_method(
1302 method => "user_fines_summary",
1303 api_name => "open-ils.actor.user.fines.summary",
1304 notes => <<" NOTES");
1305 Returns a short summary of the users total open fines, excluding voided fines
1306 Params are login_session, user_id
1307 Returns a 'mous' object.
1310 sub user_fines_summary {
1311 my( $self, $client, $auth, $user_id ) = @_;
1312 my $e = new_editor(authtoken=>$auth);
1313 return $e->event unless $e->checkauth;
1314 my $user = $e->retrieve_actor_user($user_id)
1315 or return $e->event;
1317 if( $user_id ne $e->requestor->id ) {
1318 return $e->event unless
1319 $e->allowed('VIEW_USER_FINES_SUMMARY', $user->home_ou);
1322 # run this inside a transaction to prevent replication delay errors
1323 my $ses = $U->start_db_session();
1324 my $s = $ses->request(
1325 'open-ils.storage.money.open_user_summary.search', $user_id )->gather(1);
1326 $U->rollback_db_session($ses);
1333 __PACKAGE__->register_method(
1334 method => "user_transactions",
1335 api_name => "open-ils.actor.user.transactions",
1336 notes => <<" NOTES");
1337 Returns a list of open user transactions (mbts objects);
1338 Params are login_session, user_id
1339 Optional third parameter is the transactions type. defaults to all
1342 __PACKAGE__->register_method(
1343 method => "user_transactions",
1344 api_name => "open-ils.actor.user.transactions.have_charge",
1345 notes => <<" NOTES");
1346 Returns a list of all open user transactions (mbts objects) that have an initial charge
1347 Params are login_session, user_id
1348 Optional third parameter is the transactions type. defaults to all
1351 __PACKAGE__->register_method(
1352 method => "user_transactions",
1353 api_name => "open-ils.actor.user.transactions.have_balance",
1354 notes => <<" NOTES");
1355 Returns a list of all open user transactions (mbts objects) that have a balance
1356 Params are login_session, user_id
1357 Optional third parameter is the transactions type. defaults to all
1360 __PACKAGE__->register_method(
1361 method => "user_transactions",
1362 api_name => "open-ils.actor.user.transactions.fleshed",
1363 notes => <<" NOTES");
1364 Returns an object/hash of transaction, circ, title where transaction = an open
1365 user transactions (mbts objects), circ is the attached circluation, and title
1366 is the title the circ points to
1367 Params are login_session, user_id
1368 Optional third parameter is the transactions type. defaults to all
1371 __PACKAGE__->register_method(
1372 method => "user_transactions",
1373 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1374 notes => <<" NOTES");
1375 Returns an object/hash of transaction, circ, title where transaction = an open
1376 user transactions that has an initial charge (mbts objects), circ is the
1377 attached circluation, and title is the title the circ points to
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.fleshed",
1385 notes => <<" NOTES");
1386 Returns an object/hash of transaction, circ, title where transaction = an open
1387 user transaction that has a balance (mbts objects), circ is the attached
1388 circluation, and title is the title the circ points to
1389 Params are login_session, user_id
1390 Optional third parameter is the transaction type. defaults to all
1393 __PACKAGE__->register_method(
1394 method => "user_transactions",
1395 api_name => "open-ils.actor.user.transactions.count",
1396 notes => <<" NOTES");
1397 Returns an object/hash of transaction, circ, title where transaction = an open
1398 user transactions (mbts objects), circ is the attached circluation, and title
1399 is the title the circ points to
1400 Params are login_session, user_id
1401 Optional third parameter is the transactions type. defaults to all
1404 __PACKAGE__->register_method(
1405 method => "user_transactions",
1406 api_name => "open-ils.actor.user.transactions.have_charge.count",
1407 notes => <<" NOTES");
1408 Returns an object/hash of transaction, circ, title where transaction = an open
1409 user transactions that has an initial charge (mbts objects), circ is the
1410 attached circluation, and title is the title the circ points to
1411 Params are login_session, user_id
1412 Optional third parameter is the transactions type. defaults to all
1415 __PACKAGE__->register_method(
1416 method => "user_transactions",
1417 api_name => "open-ils.actor.user.transactions.have_balance.count",
1418 notes => <<" NOTES");
1419 Returns an object/hash of transaction, circ, title where transaction = an open
1420 user transaction that has a balance (mbts objects), circ is the attached
1421 circluation, and title is the title the circ points to
1422 Params are login_session, user_id
1423 Optional third parameter is the transaction type. defaults to all
1426 __PACKAGE__->register_method(
1427 method => "user_transactions",
1428 api_name => "open-ils.actor.user.transactions.have_balance.total",
1429 notes => <<" NOTES");
1430 Returns an object/hash of transaction, circ, title where transaction = an open
1431 user transaction that has a balance (mbts objects), circ is the attached
1432 circluation, and title is the title the circ points to
1433 Params are login_session, user_id
1434 Optional third parameter is the transaction type. defaults to all
1439 sub user_transactions {
1440 my( $self, $client, $login_session, $user_id, $type ) = @_;
1442 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1443 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1444 return $evt if $evt;
1446 my $api = $self->api_name();
1450 if(defined($type)) { @xact = (xact_type => $type);
1452 } else { @xact = (); }
1455 ->method_lookup('open-ils.actor.user.transactions.history.still_open')
1456 ->run($login_session => $user_id => $type);
1458 if($api =~ /have_charge/o) {
1460 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1462 } elsif($api =~ /have_balance/o) {
1464 $trans = [ grep { int($_->balance_owed * 100) != 0 } @$trans ];
1467 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1471 if($api =~ /total/o) {
1473 for my $t (@$trans) {
1474 $total += $t->balance_owed;
1477 $logger->debug("Total balance owed by user $user_id: $total");
1481 if($api =~ /count/o) { return scalar @$trans; }
1482 if($api !~ /fleshed/o) { return $trans; }
1485 for my $t (@$trans) {
1487 if( $t->xact_type ne 'circulation' ) {
1488 push @resp, {transaction => $t};
1492 my $circ = $apputils->simple_scalar_request(
1494 "open-ils.cstore.direct.action.circulation.retrieve",
1499 my $title = $apputils->simple_scalar_request(
1501 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1502 $circ->target_copy );
1506 my $u = OpenILS::Utils::ModsParser->new();
1507 $u->start_mods_batch($title->marc());
1508 my $mods = $u->finish_mods_batch();
1509 $mods->doc_id($title->id) if $mods;
1511 push @resp, {transaction => $t, circ => $circ, record => $mods };
1519 __PACKAGE__->register_method(
1520 method => "user_transaction_retrieve",
1521 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1523 notes => <<" NOTES");
1524 Returns a fleshedtransaction record
1526 __PACKAGE__->register_method(
1527 method => "user_transaction_retrieve",
1528 api_name => "open-ils.actor.user.transaction.retrieve",
1530 notes => <<" NOTES");
1531 Returns a transaction record
1533 sub user_transaction_retrieve {
1534 my( $self, $client, $login_session, $bill_id ) = @_;
1536 my $trans = $apputils->simple_scalar_request(
1538 "open-ils.cstore.direct.money.billable_transaction_summary.retrieve",
1542 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1543 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1544 return $evt if $evt;
1546 my $api = $self->api_name();
1547 if($api !~ /fleshed/o) { return $trans; }
1549 if( $trans->xact_type ne 'circulation' ) {
1550 $logger->debug("Returning non-circ transaction");
1551 return {transaction => $trans};
1554 my $circ = $apputils->simple_scalar_request(
1556 "open-ils..direct.action.circulation.retrieve",
1559 return {transaction => $trans} unless $circ;
1560 $logger->debug("Found the circ transaction");
1562 my $title = $apputils->simple_scalar_request(
1564 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1565 $circ->target_copy );
1567 return {transaction => $trans, circ => $circ } unless $title;
1568 $logger->debug("Found the circ title");
1572 my $u = OpenILS::Utils::ModsParser->new();
1573 $u->start_mods_batch($title->marc());
1574 $mods = $u->finish_mods_batch();
1576 if ($title->id == OILS_PRECAT_RECORD) {
1577 my $copy = $apputils->simple_scalar_request(
1579 "open-ils.cstore.direct.asset.copy.retrieve",
1580 $circ->target_copy );
1582 $mods = new Fieldmapper::metabib::virtual_record;
1583 $mods->doc_id(OILS_PRECAT_RECORD);
1584 $mods->title($copy->dummy_title);
1585 $mods->author($copy->dummy_author);
1589 $logger->debug("MODSized the circ title");
1591 return {transaction => $trans, circ => $circ, record => $mods };
1595 __PACKAGE__->register_method(
1596 method => "hold_request_count",
1597 api_name => "open-ils.actor.user.hold_requests.count",
1599 notes => <<" NOTES");
1600 Returns hold ready/total counts
1602 sub hold_request_count {
1603 my( $self, $client, $login_session, $userid ) = @_;
1605 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1606 $login_session, $userid, 'VIEW_HOLD' );
1607 return $evt if $evt;
1610 my $holds = $apputils->simple_scalar_request(
1612 "open-ils.cstore.direct.action.hold_request.search.atomic",
1615 fulfillment_time => {"=" => undef },
1616 cancel_time => undef,
1621 for my $h (@$holds) {
1622 next unless $h->capture_time and $h->current_copy;
1624 my $copy = $apputils->simple_scalar_request(
1626 "open-ils.cstore.direct.asset.copy.retrieve",
1630 if ($copy and $copy->status == 8) {
1635 return { total => scalar(@$holds), ready => scalar(@ready) };
1639 __PACKAGE__->register_method(
1640 method => "checkedout_count",
1641 api_name => "open-ils.actor.user.checked_out.count__",
1643 notes => <<" NOTES");
1644 Returns a transaction record
1648 sub checkedout_count {
1649 my( $self, $client, $login_session, $userid ) = @_;
1651 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1652 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1653 return $evt if $evt;
1655 my $circs = $apputils->simple_scalar_request(
1657 "open-ils.cstore.direct.action.circulation.search.atomic",
1658 { usr => $userid, stop_fines => undef }
1659 #{ usr => $userid, checkin_time => {"=" => undef } }
1662 my $parser = DateTime::Format::ISO8601->new;
1665 for my $c (@$circs) {
1666 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1667 my $due = $due_dt->epoch;
1669 if ($due < DateTime->today->epoch) {
1674 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1678 __PACKAGE__->register_method(
1679 method => "checked_out",
1680 api_name => "open-ils.actor.user.checked_out",
1683 Returns a structure of circulations objects sorted by
1684 out, overdue, lost, claims_returned, long_overdue.
1685 A list of IDs are returned of each type.
1686 lost, long_overdue, and claims_returned circ will not
1687 be "finished" (there is an outstanding balance or some
1688 other pending action on the circ).
1690 The .count method also includes a 'total' field which
1691 sums all "open" circs
1695 __PACKAGE__->register_method(
1696 method => "checked_out",
1697 api_name => "open-ils.actor.user.checked_out.count",
1699 signature => q/@see open-ils.actor.user.checked_out/
1703 my( $self, $conn, $auth, $userid ) = @_;
1705 my $e = new_editor(authtoken=>$auth);
1706 return $e->event unless $e->checkauth;
1708 if( $userid ne $e->requestor->id ) {
1709 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1712 my $count = $self->api_name =~ /count/;
1713 return _checked_out( $count, $e, $userid );
1717 my( $iscount, $e, $userid ) = @_;
1720 my $meth = 'open-ils.storage.actor.user.checked_out';
1721 $meth = "$meth.count" if $iscount;
1722 return $U->storagereq($meth, $userid);
1724 # XXX Old code - moved to storage
1725 #------------------------------------------------------------------------------
1726 #------------------------------------------------------------------------------
1727 my $circs = $e->search_action_circulation(
1728 { usr => $userid, checkin_time => undef });
1730 my $parser = DateTime::Format::ISO8601->new;
1732 # split the circs up into overdue and not-overdue circs
1734 for my $c (@$circs) {
1735 if( $c->due_date ) {
1736 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1737 my $due = $due_dt->epoch;
1738 if ($due < DateTime->today->epoch) {
1748 my( @open, @od, @lost, @cr, @lo );
1750 while (my $c = shift(@out)) {
1751 push( @open, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1752 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1753 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1754 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1757 while (my $c = shift(@overdue)) {
1758 push( @od, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1759 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1760 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1761 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1766 total => @open + @od + @lost + @cr + @lo,
1767 out => scalar(@open),
1768 overdue => scalar(@od),
1769 lost => scalar(@lost),
1770 claims_returned => scalar(@cr),
1771 long_overdue => scalar(@lo)
1779 claims_returned => \@cr,
1780 long_overdue => \@lo
1785 sub _checked_out_WHAT {
1786 my( $iscount, $e, $userid ) = @_;
1788 my $circs = $e->search_action_circulation(
1789 { usr => $userid, stop_fines => undef });
1791 my $mcircs = $e->search_action_circulation(
1794 checkin_time => undef,
1795 xact_finish => undef,
1799 push( @$circs, @$mcircs );
1801 my $parser = DateTime::Format::ISO8601->new;
1803 # split the circs up into overdue and not-overdue circs
1805 for my $c (@$circs) {
1806 if( $c->due_date ) {
1807 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1808 my $due = $due_dt->epoch;
1809 if ($due < DateTime->today->epoch) {
1810 push @overdue, $c->id;
1819 # grab all of the lost, claims-returned, and longoverdue circs
1820 #my $open = $e->search_action_circulation(
1821 # {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1824 # these items have stop_fines, but no xact_finish, so money
1825 # is owed on them and they have not been checked in
1826 my $open = $e->search_action_circulation(
1829 stop_fines => { in => [ qw/LOST CLAIMSRETURNED LONGOVERDUE/ ] },
1830 xact_finish => undef,
1831 checkin_time => undef,
1836 my( @lost, @cr, @lo );
1837 for my $c (@$open) {
1838 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1839 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1840 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1846 total => @$circs + @lost + @cr + @lo,
1847 out => scalar(@out),
1848 overdue => scalar(@overdue),
1849 lost => scalar(@lost),
1850 claims_returned => scalar(@cr),
1851 long_overdue => scalar(@lo)
1857 overdue => \@overdue,
1859 claims_returned => \@cr,
1860 long_overdue => \@lo
1866 __PACKAGE__->register_method(
1867 method => "checked_in_with_fines",
1868 api_name => "open-ils.actor.user.checked_in_with_fines",
1870 signature => q/@see open-ils.actor.user.checked_out/
1872 sub checked_in_with_fines {
1873 my( $self, $conn, $auth, $userid ) = @_;
1875 my $e = new_editor(authtoken=>$auth);
1876 return $e->event unless $e->checkauth;
1878 if( $userid ne $e->requestor->id ) {
1879 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1882 # money is owed on these items and they are checked in
1883 my $open = $e->search_action_circulation(
1886 xact_finish => undef,
1887 checkin_time => { "!=" => undef },
1892 my( @lost, @cr, @lo );
1893 for my $c (@$open) {
1894 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1895 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1896 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1901 claims_returned => \@cr,
1902 long_overdue => \@lo
1914 __PACKAGE__->register_method(
1915 method => "user_transaction_history",
1916 api_name => "open-ils.actor.user.transactions.history",
1918 notes => <<" NOTES");
1919 Returns a list of billable transaction ids for a user, optionally by type
1921 __PACKAGE__->register_method(
1922 method => "user_transaction_history",
1923 api_name => "open-ils.actor.user.transactions.history.have_charge",
1925 notes => <<" NOTES");
1926 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
1928 __PACKAGE__->register_method(
1929 method => "user_transaction_history",
1930 api_name => "open-ils.actor.user.transactions.history.have_balance",
1932 notes => <<" NOTES");
1933 Returns a list of billable transaction ids for a user that have a balance, optionally by type
1935 __PACKAGE__->register_method(
1936 method => "user_transaction_history",
1937 api_name => "open-ils.actor.user.transactions.history.still_open",
1939 notes => <<" NOTES");
1940 Returns a list of billable transaction ids for a user that are not finished
1942 __PACKAGE__->register_method(
1943 method => "user_transaction_history",
1944 api_name => "open-ils.actor.user.transactions.history.have_bill",
1946 notes => <<" NOTES");
1947 Returns a list of billable transaction ids for a user that has billings
1953 sub _user_transaction_history {
1954 my( $self, $client, $login_session, $user_id, $type ) = @_;
1956 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1957 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1958 return $evt if $evt;
1960 my $api = $self->api_name();
1965 @xact = (xact_type => $type) if(defined($type));
1966 @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
1967 @charge = (last_billing_ts => { "<>" => undef }) if $api =~ /have_charge/;
1969 $logger->debug("searching for transaction history: @xact : @balance, @charge");
1971 my $trans = $apputils->simple_scalar_request(
1973 "open-ils.cstore.direct.money.billable_transaction_summary.search.atomic",
1974 { usr => $user_id, @xact, @charge, @balance }, { order_by => { mbts => 'xact_start DESC' } });
1976 return [ map { $_->id } @$trans ];
1980 =head SEE APPUTILS.PM
1985 for my $x (@xacts) {
1986 my $s = new Fieldmapper::money::billable_transaction_summary;
1989 $s->xact_start( $x->xact_start );
1990 $s->xact_finish( $x->xact_finish );
1994 for my $b (@{ $x->billings }) {
1995 next if ($U->is_true($b->voided));
1996 $to += ($b->amount * 100);
1997 $lb ||= $b->billing_ts;
1998 if ($b->billing_ts ge $lb) {
1999 $lb = $b->billing_ts;
2000 $s->last_billing_note($b->note);
2001 $s->last_billing_ts($b->billing_ts);
2002 $s->last_billing_type($b->billing_type);
2006 $s->total_owed( sprintf('%0.2f', $to / 100 ) );
2010 for my $p (@{ $x->payments }) {
2011 next if ($U->is_true($p->voided));
2012 $tp += ($p->amount * 100);
2013 $lp ||= $p->payment_ts;
2014 if ($p->payment_ts ge $lp) {
2015 $lp = $p->payment_ts;
2016 $s->last_payment_note($p->note);
2017 $s->last_payment_ts($p->payment_ts);
2018 $s->last_payment_type($p->payment_type);
2021 $s->total_paid( sprintf('%0.2f', $tp / 100 ) );
2023 $s->balance_owed( sprintf('%0.2f', ($to - $tp) / 100) );
2025 $s->xact_type( 'grocery' ) if ($x->grocery);
2026 $s->xact_type( 'circulation' ) if ($x->circulation);
2035 sub user_transaction_history {
2036 my( $self, $conn, $auth, $userid, $type ) = @_;
2038 # run inside of a transaction to prevent replication delays
2039 my $e = new_editor(xact=>1, authtoken=>$auth);
2040 return $e->die_event unless $e->checkauth;
2042 if( $e->requestor->id ne $userid ) {
2043 return $e->die_event
2044 unless $e->allowed('VIEW_USER_TRANSACTIONS');
2047 my $api = $self->api_name;
2048 my @xact_finish = (xact_finish => undef ) if ($api =~ /history.still_open$/);
2050 my @xacts = @{ $e->search_money_billable_transaction(
2051 [ { usr => $userid, @xact_finish },
2053 flesh_fields => { mbt => [ qw/billings payments grocery circulation/ ] },
2054 order_by => { mbt => 'xact_start DESC' },
2061 #my @mbts = _make_mbts( @xacts );
2062 my @mbts = $U->make_mbts( @xacts );
2064 if(defined($type)) {
2065 @mbts = grep { $_->xact_type eq $type } @mbts;
2068 if($api =~ /have_balance/o) {
2069 @mbts = grep { int($_->balance_owed * 100) != 0 } @mbts;
2072 if($api =~ /have_charge/o) {
2073 @mbts = grep { defined($_->last_billing_ts) } @mbts;
2076 if($api =~ /have_bill/o) {
2077 @mbts = grep { int($_->total_owed * 100) != 0 } @mbts;
2085 __PACKAGE__->register_method(
2086 method => "user_perms",
2087 api_name => "open-ils.actor.permissions.user_perms.retrieve",
2089 notes => <<" NOTES");
2090 Returns a list of permissions
2093 my( $self, $client, $authtoken, $user ) = @_;
2095 my( $staff, $evt ) = $apputils->checkses($authtoken);
2096 return $evt if $evt;
2098 $user ||= $staff->id;
2100 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
2104 return $apputils->simple_scalar_request(
2106 "open-ils.storage.permission.user_perms.atomic",
2110 __PACKAGE__->register_method(
2111 method => "retrieve_perms",
2112 api_name => "open-ils.actor.permissions.retrieve",
2113 notes => <<" NOTES");
2114 Returns a list of permissions
2116 sub retrieve_perms {
2117 my( $self, $client ) = @_;
2118 return $apputils->simple_scalar_request(
2120 "open-ils.cstore.direct.permission.perm_list.search.atomic",
2121 { id => { '!=' => undef } }
2125 __PACKAGE__->register_method(
2126 method => "retrieve_groups",
2127 api_name => "open-ils.actor.groups.retrieve",
2128 notes => <<" NOTES");
2129 Returns a list of user groupss
2131 sub retrieve_groups {
2132 my( $self, $client ) = @_;
2133 return new_editor()->retrieve_all_permission_grp_tree();
2136 __PACKAGE__->register_method(
2137 method => "retrieve_org_address",
2138 api_name => "open-ils.actor.org_unit.address.retrieve",
2139 notes => <<' NOTES');
2140 Returns an org_unit address by ID
2141 @param An org_address ID
2143 sub retrieve_org_address {
2144 my( $self, $client, $id ) = @_;
2145 return $apputils->simple_scalar_request(
2147 "open-ils.cstore.direct.actor.org_address.retrieve",
2152 __PACKAGE__->register_method(
2153 method => "retrieve_groups_tree",
2154 api_name => "open-ils.actor.groups.tree.retrieve",
2155 notes => <<" NOTES");
2156 Returns a list of user groups
2158 sub retrieve_groups_tree {
2159 my( $self, $client ) = @_;
2160 return new_editor()->search_permission_grp_tree(
2165 flesh_fields => { pgt => ["children"] },
2166 order_by => { pgt => 'name'}
2173 # turns an org list into an org tree
2175 sub build_group_tree {
2177 my( $self, $grplist) = @_;
2179 return $grplist unless (
2180 ref($grplist) and @$grplist > 1 );
2182 my @list = sort { $a->name cmp $b->name } @$grplist;
2185 for my $grp (@list) {
2187 if ($grp and !defined($grp->parent)) {
2191 my ($parent) = grep { $_->id == $grp->parent} @list;
2193 $parent->children([]) unless defined($parent->children);
2194 push( @{$parent->children}, $grp );
2202 __PACKAGE__->register_method(
2203 method => "add_user_to_groups",
2204 api_name => "open-ils.actor.user.set_groups",
2205 notes => <<" NOTES");
2206 Adds a user to one or more permission groups
2209 sub add_user_to_groups {
2210 my( $self, $client, $authtoken, $userid, $groups ) = @_;
2212 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2213 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
2214 return $evt if $evt;
2216 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2217 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
2218 return $evt if $evt;
2220 $apputils->simplereq(
2222 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
2224 for my $group (@$groups) {
2225 my $link = Fieldmapper::permission::usr_grp_map->new;
2227 $link->usr($userid);
2229 my $id = $apputils->simplereq(
2231 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2237 __PACKAGE__->register_method(
2238 method => "get_user_perm_groups",
2239 api_name => "open-ils.actor.user.get_groups",
2240 notes => <<" NOTES");
2241 Retrieve a user's permission groups.
2245 sub get_user_perm_groups {
2246 my( $self, $client, $authtoken, $userid ) = @_;
2248 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2249 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2250 return $evt if $evt;
2252 return $apputils->simplereq(
2254 'open-ils.cstore.direct.permission.usr_grp_map.search.atomic', { usr => $userid } );
2259 __PACKAGE__->register_method (
2260 method => 'register_workstation',
2261 api_name => 'open-ils.actor.workstation.register.override',
2262 signature => q/@see open-ils.actor.workstation.register/);
2264 __PACKAGE__->register_method (
2265 method => 'register_workstation',
2266 api_name => 'open-ils.actor.workstation.register',
2268 Registers a new workstion in the system
2269 @param authtoken The login session key
2270 @param name The name of the workstation id
2271 @param owner The org unit that owns this workstation
2272 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2273 if the name is already in use.
2276 sub _register_workstation {
2277 my( $self, $connection, $authtoken, $name, $owner ) = @_;
2278 my( $requestor, $evt ) = $U->checkses($authtoken);
2279 return $evt if $evt;
2280 $evt = $U->check_perms($requestor->id, $owner, 'REGISTER_WORKSTATION');
2281 return $evt if $evt;
2283 my $ws = $U->cstorereq(
2284 'open-ils.cstore.direct.actor.workstation.search', { name => $name } );
2285 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS') if $ws;
2287 $ws = Fieldmapper::actor::workstation->new;
2288 $ws->owning_lib($owner);
2291 my $id = $U->storagereq(
2292 'open-ils.storage.direct.actor.workstation.create', $ws );
2293 return $U->DB_UPDATE_FAILED($ws) unless $id;
2299 sub register_workstation {
2300 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2302 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2303 return $e->event unless $e->checkauth;
2304 return $e->event unless $e->allowed('REGISTER_WORKSTATION'); # XXX rely on editor perms
2305 my $existing = $e->search_actor_workstation({name => $name});
2308 if( $self->api_name =~ /override/o ) {
2309 return $e->event unless $e->allowed('DELETE_WORKSTATION'); # XXX rely on editor perms
2310 return $e->event unless $e->delete_actor_workstation($$existing[0]);
2312 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2316 my $ws = Fieldmapper::actor::workstation->new;
2317 $ws->owning_lib($owner);
2319 $e->create_actor_workstation($ws) or return $e->event;
2321 return $ws->id; # note: editor sets the id on the new object for us
2325 __PACKAGE__->register_method (
2326 method => 'fetch_patron_note',
2327 api_name => 'open-ils.actor.note.retrieve.all',
2329 Returns a list of notes for a given user
2330 Requestor must have VIEW_USER permission if pub==false and
2331 @param authtoken The login session key
2332 @param args Hash of params including
2333 patronid : the patron's id
2334 pub : true if retrieving only public notes
2338 sub fetch_patron_note {
2339 my( $self, $conn, $authtoken, $args ) = @_;
2340 my $patronid = $$args{patronid};
2342 my($reqr, $evt) = $U->checkses($authtoken);
2343 return $evt if $evt;
2346 ($patron, $evt) = $U->fetch_user($patronid);
2347 return $evt if $evt;
2350 if( $patronid ne $reqr->id ) {
2351 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2352 return $evt if $evt;
2354 return $U->cstorereq(
2355 'open-ils.cstore.direct.actor.usr_note.search.atomic',
2356 { usr => $patronid, pub => 't' } );
2359 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2360 return $evt if $evt;
2362 return $U->cstorereq(
2363 'open-ils.cstore.direct.actor.usr_note.search.atomic', { usr => $patronid } );
2366 __PACKAGE__->register_method (
2367 method => 'create_user_note',
2368 api_name => 'open-ils.actor.note.create',
2370 Creates a new note for the given user
2371 @param authtoken The login session key
2372 @param note The note object
2375 sub create_user_note {
2376 my( $self, $conn, $authtoken, $note ) = @_;
2377 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2378 return $e->die_event unless $e->checkauth;
2380 my $user = $e->retrieve_actor_user($note->usr)
2381 or return $e->die_event;
2383 return $e->die_event unless
2384 $e->allowed('UPDATE_USER',$user->home_ou);
2386 $note->creator($e->requestor->id);
2387 $e->create_actor_usr_note($note) or return $e->die_event;
2393 __PACKAGE__->register_method (
2394 method => 'delete_user_note',
2395 api_name => 'open-ils.actor.note.delete',
2397 Deletes a note for the given user
2398 @param authtoken The login session key
2399 @param noteid The note id
2402 sub delete_user_note {
2403 my( $self, $conn, $authtoken, $noteid ) = @_;
2405 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2406 return $e->die_event unless $e->checkauth;
2407 my $note = $e->retrieve_actor_usr_note($noteid)
2408 or return $e->die_event;
2409 my $user = $e->retrieve_actor_user($note->usr)
2410 or return $e->die_event;
2411 return $e->die_event unless
2412 $e->allowed('UPDATE_USER', $user->home_ou);
2414 $e->delete_actor_usr_note($note) or return $e->die_event;
2420 __PACKAGE__->register_method (
2421 method => 'update_user_note',
2422 api_name => 'open-ils.actor.note.update',
2424 @param authtoken The login session key
2425 @param note The note
2429 sub update_user_note {
2430 my( $self, $conn, $auth, $note ) = @_;
2431 my $e = new_editor(authtoken=>$auth, xact=>1);
2432 return $e->event unless $e->checkauth;
2433 my $patron = $e->retrieve_actor_user($note->usr)
2434 or return $e->event;
2435 return $e->event unless
2436 $e->allowed('UPDATE_USER', $patron->home_ou);
2437 $e->update_actor_user_note($note)
2438 or return $e->event;
2446 __PACKAGE__->register_method (
2447 method => 'create_closed_date',
2448 api_name => 'open-ils.actor.org_unit.closed_date.create',
2450 Creates a new closing entry for the given org_unit
2451 @param authtoken The login session key
2452 @param note The closed_date object
2455 sub create_closed_date {
2456 my( $self, $conn, $authtoken, $cd ) = @_;
2458 my( $user, $evt ) = $U->checkses($authtoken);
2459 return $evt if $evt;
2461 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2462 return $evt if $evt;
2464 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2466 my $id = $U->storagereq(
2467 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2468 return $U->DB_UPDATE_FAILED($cd) unless $id;
2473 __PACKAGE__->register_method (
2474 method => 'delete_closed_date',
2475 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2477 Deletes a closing entry for the given org_unit
2478 @param authtoken The login session key
2479 @param noteid The close_date id
2482 sub delete_closed_date {
2483 my( $self, $conn, $authtoken, $cd ) = @_;
2485 my( $user, $evt ) = $U->checkses($authtoken);
2486 return $evt if $evt;
2489 ($cd_obj, $evt) = fetch_closed_date($cd);
2490 return $evt if $evt;
2492 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2493 return $evt if $evt;
2495 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2497 my $stat = $U->storagereq(
2498 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2499 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2504 __PACKAGE__->register_method(
2505 method => 'usrname_exists',
2506 api_name => 'open-ils.actor.username.exists',
2508 Returns 1 if the requested username exists, returns 0 otherwise
2512 sub usrname_exists {
2513 my( $self, $conn, $auth, $usrname ) = @_;
2514 my $e = new_editor(authtoken=>$auth);
2515 return $e->event unless $e->checkauth;
2516 my $a = $e->search_actor_user({usrname => $usrname, deleted=>'f'}, {idlist=>1});
2517 return $$a[0] if $a and @$a;
2521 __PACKAGE__->register_method(
2522 method => 'barcode_exists',
2523 api_name => 'open-ils.actor.barcode.exists',
2525 Returns 1 if the requested barcode exists, returns 0 otherwise
2529 sub barcode_exists {
2530 my( $self, $conn, $auth, $barcode ) = @_;
2531 my $e = new_editor(authtoken=>$auth);
2532 return $e->event unless $e->checkauth;
2533 my $a = $e->search_actor_card({barcode => $barcode}, {idlist=>1});
2534 return $$a[0] if $a and @$a;
2539 __PACKAGE__->register_method(
2540 method => 'retrieve_net_levels',
2541 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2544 sub retrieve_net_levels {
2545 my( $self, $conn, $auth ) = @_;
2546 my $e = new_editor(authtoken=>$auth);
2547 return $e->event unless $e->checkauth;
2548 return $e->retrieve_all_config_net_access_level();
2552 __PACKAGE__->register_method(
2553 method => 'fetch_org_by_shortname',
2554 api_name => 'open-ils.actor.org_unit.retrieve_by_shorname',
2556 sub fetch_org_by_shortname {
2557 my( $self, $conn, $sname ) = @_;
2558 my $e = new_editor();
2559 my $org = $e->search_actor_org_unit({ shortname => uc($sname)})->[0];
2560 return $e->event unless $org;
2565 __PACKAGE__->register_method(
2566 method => 'session_home_lib',
2567 api_name => 'open-ils.actor.session.home_lib',
2570 sub session_home_lib {
2571 my( $self, $conn, $auth ) = @_;
2572 my $e = new_editor(authtoken=>$auth);
2573 return undef unless $e->checkauth;
2574 my $org = $e->retrieve_actor_org_unit($e->requestor->home_ou);
2575 return $org->shortname;
2580 __PACKAGE__->register_method(
2581 method => 'slim_tree',
2582 api_name => "open-ils.actor.org_tree.slim_hash.retrieve",
2585 my $tree = new_editor()->search_actor_org_unit(
2587 {"parent_ou" => undef },
2590 flesh_fields => { aou => ['children'] },
2591 order_by => { aou => 'name'},
2592 select => { aou => ["id","shortname", "name"]},
2597 return trim_tree($tree);
2603 return undef unless $tree;
2605 code => $tree->shortname,
2606 name => $tree->name,
2608 if( $tree->children and @{$tree->children} ) {
2609 $htree->{children} = [];
2610 for my $c (@{$tree->children}) {
2611 push( @{$htree->{children}}, trim_tree($c) );
2619 __PACKAGE__->register_method(
2620 method => "update_penalties",
2621 api_name => "open-ils.actor.user.penalties.update");
2622 sub update_penalties {
2623 my( $self, $conn, $auth, $userid ) = @_;
2624 my $e = new_editor(authtoken=>$auth);
2625 return $e->event unless $e->checkauth;
2626 $U->update_patron_penalties(
2628 patronid => $userid,
2635 __PACKAGE__->register_method(
2636 method => "user_retrieve_fleshed_by_id",
2637 api_name => "open-ils.actor.user.fleshed.retrieve",);
2639 sub user_retrieve_fleshed_by_id {
2640 my( $self, $client, $auth, $user_id, $fields ) = @_;
2641 my $e = new_editor(authtoken => $auth);
2642 return $e->event unless $e->checkauth;
2644 if( $e->requestor->id != $user_id ) {
2645 return $e->event unless $e->allowed('VIEW_USER');
2651 "standing_penalties",
2655 "stat_cat_entries" ];
2656 return new_flesh_user($user_id, $fields, $e);
2660 sub new_flesh_user {
2663 my $fields = shift || [];
2664 my $e = shift || new_editor(xact=>1);
2666 my $user = $e->retrieve_actor_user(
2671 "flesh_fields" => { "au" => $fields }
2674 ) or return $e->event;
2677 if( grep { $_ eq 'addresses' } @$fields ) {
2679 $user->addresses([]) unless @{$user->addresses};
2681 if( ref $user->billing_address ) {
2682 unless( grep { $user->billing_address->id == $_->id } @{$user->addresses} ) {
2683 push( @{$user->addresses}, $user->billing_address );
2687 if( ref $user->mailing_address ) {
2688 unless( grep { $user->mailing_address->id == $_->id } @{$user->addresses} ) {
2689 push( @{$user->addresses}, $user->mailing_address );
2695 $user->clear_passwd();
2702 __PACKAGE__->register_method(
2703 method => "user_retrieve_parts",
2704 api_name => "open-ils.actor.user.retrieve.parts",);
2706 sub user_retrieve_parts {
2707 my( $self, $client, $auth, $user_id, $fields ) = @_;
2708 my $e = new_editor(authtoken => $auth);
2709 return $e->event unless $e->checkauth;
2710 if( $e->requestor->id != $user_id ) {
2711 return $e->event unless $e->allowed('VIEW_USER');
2714 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2715 push(@resp, $user->$_()) for(@$fields);