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, $auth, $org_id ) = @_;
1057 my $e = new_editor(authtoken=>$auth);
1058 return $e->event unless $e->checkauth;
1059 $org_id = $e->requestor->ws_ou unless defined $org_id;
1061 return $apputils->simple_scalar_request(
1063 "open-ils.storage.actor.org_unit.full_path.atomic",
1068 __PACKAGE__->register_method(
1069 method => "patron_adv_search",
1070 api_name => "open-ils.actor.patron.search.advanced" );
1071 sub patron_adv_search {
1072 my( $self, $client, $auth, $search_hash, $search_limit, $search_sort, $include_inactive ) = @_;
1073 my $e = new_editor(authtoken=>$auth);
1074 return $e->event unless $e->checkauth;
1075 return $e->event unless $e->allowed('VIEW_USER');
1076 return $U->storagereq(
1077 "open-ils.storage.actor.user.crazy_search",
1078 $search_hash, $search_limit, $search_sort, $include_inactive);
1083 sub _verify_password {
1084 my($user_session, $password) = @_;
1085 my $user_obj = $apputils->check_user_session($user_session);
1087 #grab the user with password
1088 $user_obj = $apputils->simple_scalar_request(
1090 "open-ils.cstore.direct.actor.user.retrieve",
1093 if($user_obj->passwd eq $password) {
1101 __PACKAGE__->register_method(
1102 method => "update_password",
1103 api_name => "open-ils.actor.user.password.update");
1105 __PACKAGE__->register_method(
1106 method => "update_password",
1107 api_name => "open-ils.actor.user.username.update");
1109 __PACKAGE__->register_method(
1110 method => "update_password",
1111 api_name => "open-ils.actor.user.email.update");
1113 sub update_password {
1114 my( $self, $client, $user_session, $new_value, $current_password ) = @_;
1118 my $user_obj = $apputils->check_user_session($user_session);
1120 if($self->api_name =~ /password/o) {
1122 #make sure they know the current password
1123 if(!_verify_password($user_session, md5_hex($current_password))) {
1124 return OpenILS::Event->new('INCORRECT_PASSWORD');
1127 $logger->debug("update_password setting new password $new_value");
1128 $user_obj->passwd($new_value);
1130 } elsif($self->api_name =~ /username/o) {
1131 my $users = search_username(undef, undef, $new_value);
1132 if( $users and $users->[0] ) {
1133 return OpenILS::Event->new('USERNAME_EXISTS');
1135 $user_obj->usrname($new_value);
1137 } elsif($self->api_name =~ /email/o) {
1138 #warn "Updating email to $new_value\n";
1139 $user_obj->email($new_value);
1142 my $session = $apputils->start_db_session();
1144 ( $user_obj, $evt ) = _update_patron($session, $user_obj, $user_obj, 1);
1145 return $evt if $evt;
1147 $apputils->commit_db_session($session);
1149 if($user_obj) { return 1; }
1154 __PACKAGE__->register_method(
1155 method => "check_user_perms",
1156 api_name => "open-ils.actor.user.perm.check",
1157 notes => <<" NOTES");
1158 Takes a login session, user id, an org id, and an array of perm type strings. For each
1159 perm type, if the user does *not* have the given permission it is added
1160 to a list which is returned from the method. If all permissions
1161 are allowed, an empty list is returned
1162 if the logged in user does not match 'user_id', then the logged in user must
1163 have VIEW_PERMISSION priveleges.
1166 sub check_user_perms {
1167 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1169 my( $staff, $evt ) = $apputils->checkses($login_session);
1170 return $evt if $evt;
1172 if($staff->id ne $user_id) {
1173 if( $evt = $apputils->check_perms(
1174 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1180 for my $perm (@$perm_types) {
1181 if($apputils->check_perms($user_id, $org_id, $perm)) {
1182 push @not_allowed, $perm;
1186 return \@not_allowed
1189 __PACKAGE__->register_method(
1190 method => "check_user_perms2",
1191 api_name => "open-ils.actor.user.perm.check.multi_org",
1193 Checks the permissions on a list of perms and orgs for a user
1194 @param authtoken The login session key
1195 @param user_id The id of the user to check
1196 @param orgs The array of org ids
1197 @param perms The array of permission names
1198 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1199 if the logged in user does not match 'user_id', then the logged in user must
1200 have VIEW_PERMISSION priveleges.
1203 sub check_user_perms2 {
1204 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1206 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1207 $authtoken, $user_id, 'VIEW_PERMISSION' );
1208 return $evt if $evt;
1211 for my $org (@$orgs) {
1212 for my $perm (@$perms) {
1213 if($apputils->check_perms($user_id, $org, $perm)) {
1214 push @not_allowed, [ $org, $perm ];
1219 return \@not_allowed
1223 __PACKAGE__->register_method(
1224 method => 'check_user_perms3',
1225 api_name => 'open-ils.actor.user.perm.highest_org',
1227 Returns the highest org unit id at which a user has a given permission
1228 If the requestor does not match the target user, the requestor must have
1229 'VIEW_PERMISSION' rights at the home org unit of the target user
1230 @param authtoken The login session key
1231 @param userid The id of the user in question
1232 @param perm The permission to check
1233 @return The org unit highest in the org tree within which the user has
1234 the requested permission
1237 sub check_user_perms3 {
1238 my( $self, $client, $authtoken, $userid, $perm ) = @_;
1240 my( $staff, $target, $org, $evt );
1242 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1243 $authtoken, $userid, 'VIEW_PERMISSION' );
1244 return $evt if $evt;
1246 my $tree = $self->get_org_tree();
1247 return _find_highest_perm_org( $perm, $userid, $target->ws_ou, $tree );
1251 sub _find_highest_perm_org {
1252 my ( $perm, $userid, $start_org, $org_tree ) = @_;
1253 my $org = $apputils->find_org($org_tree, $start_org );
1257 last if ($apputils->check_perms( $userid, $org->id, $perm )); # perm failed
1259 $org = $apputils->find_org( $org_tree, $org->parent_ou() );
1265 __PACKAGE__->register_method(
1266 method => 'check_user_perms4',
1267 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1269 Returns the highest org unit id at which a user has a given permission
1270 If the requestor does not match the target user, the requestor must have
1271 'VIEW_PERMISSION' rights at the home org unit of the target user
1272 @param authtoken The login session key
1273 @param userid The id of the user in question
1274 @param perms An array of perm names to check
1275 @return An array of orgId's representing the org unit
1276 highest in the org tree within which the user has the requested permission
1277 The arrah of orgId's has matches the order of the perms array
1280 sub check_user_perms4 {
1281 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1283 my( $staff, $target, $org, $evt );
1285 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1286 $authtoken, $userid, 'VIEW_PERMISSION' );
1287 return $evt if $evt;
1290 return [] unless ref($perms);
1291 my $tree = $self->get_org_tree();
1293 for my $p (@$perms) {
1294 push( @arr, _find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1302 __PACKAGE__->register_method(
1303 method => "user_fines_summary",
1304 api_name => "open-ils.actor.user.fines.summary",
1305 notes => <<" NOTES");
1306 Returns a short summary of the users total open fines, excluding voided fines
1307 Params are login_session, user_id
1308 Returns a 'mous' object.
1311 sub user_fines_summary {
1312 my( $self, $client, $auth, $user_id ) = @_;
1313 my $e = new_editor(authtoken=>$auth);
1314 return $e->event unless $e->checkauth;
1315 my $user = $e->retrieve_actor_user($user_id)
1316 or return $e->event;
1318 if( $user_id ne $e->requestor->id ) {
1319 return $e->event unless
1320 $e->allowed('VIEW_USER_FINES_SUMMARY', $user->home_ou);
1323 # run this inside a transaction to prevent replication delay errors
1324 my $ses = $U->start_db_session();
1325 my $s = $ses->request(
1326 'open-ils.storage.money.open_user_summary.search', $user_id )->gather(1);
1327 $U->rollback_db_session($ses);
1334 __PACKAGE__->register_method(
1335 method => "user_transactions",
1336 api_name => "open-ils.actor.user.transactions",
1337 notes => <<" NOTES");
1338 Returns a list of open user transactions (mbts objects);
1339 Params are login_session, user_id
1340 Optional third parameter is the transactions type. defaults to all
1343 __PACKAGE__->register_method(
1344 method => "user_transactions",
1345 api_name => "open-ils.actor.user.transactions.have_charge",
1346 notes => <<" NOTES");
1347 Returns a list of all open user transactions (mbts objects) that have an initial charge
1348 Params are login_session, user_id
1349 Optional third parameter is the transactions type. defaults to all
1352 __PACKAGE__->register_method(
1353 method => "user_transactions",
1354 api_name => "open-ils.actor.user.transactions.have_balance",
1355 notes => <<" NOTES");
1356 Returns a list of all open user transactions (mbts objects) that have a balance
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.fleshed",
1364 notes => <<" NOTES");
1365 Returns an object/hash of transaction, circ, title where transaction = an open
1366 user transactions (mbts objects), circ is the attached circluation, and title
1367 is the title the circ points to
1368 Params are login_session, user_id
1369 Optional third parameter is the transactions type. defaults to all
1372 __PACKAGE__->register_method(
1373 method => "user_transactions",
1374 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1375 notes => <<" NOTES");
1376 Returns an object/hash of transaction, circ, title where transaction = an open
1377 user transactions that has an initial charge (mbts objects), circ is the
1378 attached circluation, and title is the title the circ points to
1379 Params are login_session, user_id
1380 Optional third parameter is the transactions type. defaults to all
1383 __PACKAGE__->register_method(
1384 method => "user_transactions",
1385 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1386 notes => <<" NOTES");
1387 Returns an object/hash of transaction, circ, title where transaction = an open
1388 user transaction that has a balance (mbts objects), circ is the attached
1389 circluation, and title is the title the circ points to
1390 Params are login_session, user_id
1391 Optional third parameter is the transaction type. defaults to all
1394 __PACKAGE__->register_method(
1395 method => "user_transactions",
1396 api_name => "open-ils.actor.user.transactions.count",
1397 notes => <<" NOTES");
1398 Returns an object/hash of transaction, circ, title where transaction = an open
1399 user transactions (mbts objects), circ is the attached circluation, and title
1400 is the title the circ points to
1401 Params are login_session, user_id
1402 Optional third parameter is the transactions type. defaults to all
1405 __PACKAGE__->register_method(
1406 method => "user_transactions",
1407 api_name => "open-ils.actor.user.transactions.have_charge.count",
1408 notes => <<" NOTES");
1409 Returns an object/hash of transaction, circ, title where transaction = an open
1410 user transactions that has an initial charge (mbts objects), circ is the
1411 attached circluation, and title is the title the circ points to
1412 Params are login_session, user_id
1413 Optional third parameter is the transactions type. defaults to all
1416 __PACKAGE__->register_method(
1417 method => "user_transactions",
1418 api_name => "open-ils.actor.user.transactions.have_balance.count",
1419 notes => <<" NOTES");
1420 Returns an object/hash of transaction, circ, title where transaction = an open
1421 user transaction that has a balance (mbts objects), circ is the attached
1422 circluation, and title is the title the circ points to
1423 Params are login_session, user_id
1424 Optional third parameter is the transaction type. defaults to all
1427 __PACKAGE__->register_method(
1428 method => "user_transactions",
1429 api_name => "open-ils.actor.user.transactions.have_balance.total",
1430 notes => <<" NOTES");
1431 Returns an object/hash of transaction, circ, title where transaction = an open
1432 user transaction that has a balance (mbts objects), circ is the attached
1433 circluation, and title is the title the circ points to
1434 Params are login_session, user_id
1435 Optional third parameter is the transaction type. defaults to all
1440 sub user_transactions {
1441 my( $self, $client, $login_session, $user_id, $type ) = @_;
1443 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1444 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1445 return $evt if $evt;
1447 my $api = $self->api_name();
1451 if(defined($type)) { @xact = (xact_type => $type);
1453 } else { @xact = (); }
1456 ->method_lookup('open-ils.actor.user.transactions.history.still_open')
1457 ->run($login_session => $user_id => $type);
1459 if($api =~ /have_charge/o) {
1461 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1463 } elsif($api =~ /have_balance/o) {
1465 $trans = [ grep { int($_->balance_owed * 100) != 0 } @$trans ];
1468 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1472 if($api =~ /total/o) {
1474 for my $t (@$trans) {
1475 $total += $t->balance_owed;
1478 $logger->debug("Total balance owed by user $user_id: $total");
1482 if($api =~ /count/o) { return scalar @$trans; }
1483 if($api !~ /fleshed/o) { return $trans; }
1486 for my $t (@$trans) {
1488 if( $t->xact_type ne 'circulation' ) {
1489 push @resp, {transaction => $t};
1493 my $circ = $apputils->simple_scalar_request(
1495 "open-ils.cstore.direct.action.circulation.retrieve",
1500 my $title = $apputils->simple_scalar_request(
1502 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1503 $circ->target_copy );
1507 my $u = OpenILS::Utils::ModsParser->new();
1508 $u->start_mods_batch($title->marc());
1509 my $mods = $u->finish_mods_batch();
1510 $mods->doc_id($title->id) if $mods;
1512 push @resp, {transaction => $t, circ => $circ, record => $mods };
1520 __PACKAGE__->register_method(
1521 method => "user_transaction_retrieve",
1522 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1524 notes => <<" NOTES");
1525 Returns a fleshedtransaction record
1527 __PACKAGE__->register_method(
1528 method => "user_transaction_retrieve",
1529 api_name => "open-ils.actor.user.transaction.retrieve",
1531 notes => <<" NOTES");
1532 Returns a transaction record
1534 sub user_transaction_retrieve {
1535 my( $self, $client, $login_session, $bill_id ) = @_;
1537 # XXX I think I'm deprecated... make sure
1539 my $trans = $apputils->simple_scalar_request(
1541 "open-ils.cstore.direct.money.billable_transaction_summary.retrieve",
1545 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1546 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1547 return $evt if $evt;
1549 my $api = $self->api_name();
1550 if($api !~ /fleshed/o) { return $trans; }
1552 if( $trans->xact_type ne 'circulation' ) {
1553 $logger->debug("Returning non-circ transaction");
1554 return {transaction => $trans};
1557 my $circ = $apputils->simple_scalar_request(
1559 "open-ils..direct.action.circulation.retrieve",
1562 return {transaction => $trans} unless $circ;
1563 $logger->debug("Found the circ transaction");
1565 my $title = $apputils->simple_scalar_request(
1567 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1568 $circ->target_copy );
1570 return {transaction => $trans, circ => $circ } unless $title;
1571 $logger->debug("Found the circ title");
1575 my $u = OpenILS::Utils::ModsParser->new();
1576 $u->start_mods_batch($title->marc());
1577 $mods = $u->finish_mods_batch();
1579 if ($title->id == OILS_PRECAT_RECORD) {
1580 my $copy = $apputils->simple_scalar_request(
1582 "open-ils.cstore.direct.asset.copy.retrieve",
1583 $circ->target_copy );
1585 $mods = new Fieldmapper::metabib::virtual_record;
1586 $mods->doc_id(OILS_PRECAT_RECORD);
1587 $mods->title($copy->dummy_title);
1588 $mods->author($copy->dummy_author);
1592 $logger->debug("MODSized the circ title");
1594 return {transaction => $trans, circ => $circ, record => $mods };
1598 __PACKAGE__->register_method(
1599 method => "hold_request_count",
1600 api_name => "open-ils.actor.user.hold_requests.count",
1602 notes => <<" NOTES");
1603 Returns hold ready/total counts
1605 sub hold_request_count {
1606 my( $self, $client, $login_session, $userid ) = @_;
1608 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1609 $login_session, $userid, 'VIEW_HOLD' );
1610 return $evt if $evt;
1613 my $holds = $apputils->simple_scalar_request(
1615 "open-ils.cstore.direct.action.hold_request.search.atomic",
1618 fulfillment_time => {"=" => undef },
1619 cancel_time => undef,
1624 for my $h (@$holds) {
1625 next unless $h->capture_time and $h->current_copy;
1627 my $copy = $apputils->simple_scalar_request(
1629 "open-ils.cstore.direct.asset.copy.retrieve",
1633 if ($copy and $copy->status == 8) {
1638 return { total => scalar(@$holds), ready => scalar(@ready) };
1642 __PACKAGE__->register_method(
1643 method => "checkedout_count",
1644 api_name => "open-ils.actor.user.checked_out.count__",
1646 notes => <<" NOTES");
1647 Returns a transaction record
1651 sub checkedout_count {
1652 my( $self, $client, $login_session, $userid ) = @_;
1654 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1655 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1656 return $evt if $evt;
1658 my $circs = $apputils->simple_scalar_request(
1660 "open-ils.cstore.direct.action.circulation.search.atomic",
1661 { usr => $userid, stop_fines => undef }
1662 #{ usr => $userid, checkin_time => {"=" => undef } }
1665 my $parser = DateTime::Format::ISO8601->new;
1668 for my $c (@$circs) {
1669 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1670 my $due = $due_dt->epoch;
1672 if ($due < DateTime->today->epoch) {
1677 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1681 __PACKAGE__->register_method(
1682 method => "checked_out",
1683 api_name => "open-ils.actor.user.checked_out",
1686 Returns a structure of circulations objects sorted by
1687 out, overdue, lost, claims_returned, long_overdue.
1688 A list of IDs are returned of each type.
1689 lost, long_overdue, and claims_returned circ will not
1690 be "finished" (there is an outstanding balance or some
1691 other pending action on the circ).
1693 The .count method also includes a 'total' field which
1694 sums all "open" circs
1698 __PACKAGE__->register_method(
1699 method => "checked_out",
1700 api_name => "open-ils.actor.user.checked_out.count",
1702 signature => q/@see open-ils.actor.user.checked_out/
1706 my( $self, $conn, $auth, $userid ) = @_;
1708 my $e = new_editor(authtoken=>$auth);
1709 return $e->event unless $e->checkauth;
1711 if( $userid ne $e->requestor->id ) {
1712 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1715 my $count = $self->api_name =~ /count/;
1716 return _checked_out( $count, $e, $userid );
1720 my( $iscount, $e, $userid ) = @_;
1723 my $meth = 'open-ils.storage.actor.user.checked_out';
1724 $meth = "$meth.count" if $iscount;
1725 return $U->storagereq($meth, $userid);
1727 # XXX Old code - moved to storage
1728 #------------------------------------------------------------------------------
1729 #------------------------------------------------------------------------------
1730 my $circs = $e->search_action_circulation(
1731 { usr => $userid, checkin_time => undef });
1733 my $parser = DateTime::Format::ISO8601->new;
1735 # split the circs up into overdue and not-overdue circs
1737 for my $c (@$circs) {
1738 if( $c->due_date ) {
1739 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1740 my $due = $due_dt->epoch;
1741 if ($due < DateTime->today->epoch) {
1751 my( @open, @od, @lost, @cr, @lo );
1753 while (my $c = shift(@out)) {
1754 push( @open, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1755 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1756 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1757 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1760 while (my $c = shift(@overdue)) {
1761 push( @od, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
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';
1769 total => @open + @od + @lost + @cr + @lo,
1770 out => scalar(@open),
1771 overdue => scalar(@od),
1772 lost => scalar(@lost),
1773 claims_returned => scalar(@cr),
1774 long_overdue => scalar(@lo)
1782 claims_returned => \@cr,
1783 long_overdue => \@lo
1788 sub _checked_out_WHAT {
1789 my( $iscount, $e, $userid ) = @_;
1791 my $circs = $e->search_action_circulation(
1792 { usr => $userid, stop_fines => undef });
1794 my $mcircs = $e->search_action_circulation(
1797 checkin_time => undef,
1798 xact_finish => undef,
1802 push( @$circs, @$mcircs );
1804 my $parser = DateTime::Format::ISO8601->new;
1806 # split the circs up into overdue and not-overdue circs
1808 for my $c (@$circs) {
1809 if( $c->due_date ) {
1810 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1811 my $due = $due_dt->epoch;
1812 if ($due < DateTime->today->epoch) {
1813 push @overdue, $c->id;
1822 # grab all of the lost, claims-returned, and longoverdue circs
1823 #my $open = $e->search_action_circulation(
1824 # {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1827 # these items have stop_fines, but no xact_finish, so money
1828 # is owed on them and they have not been checked in
1829 my $open = $e->search_action_circulation(
1832 stop_fines => { in => [ qw/LOST CLAIMSRETURNED LONGOVERDUE/ ] },
1833 xact_finish => undef,
1834 checkin_time => undef,
1839 my( @lost, @cr, @lo );
1840 for my $c (@$open) {
1841 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1842 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1843 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1849 total => @$circs + @lost + @cr + @lo,
1850 out => scalar(@out),
1851 overdue => scalar(@overdue),
1852 lost => scalar(@lost),
1853 claims_returned => scalar(@cr),
1854 long_overdue => scalar(@lo)
1860 overdue => \@overdue,
1862 claims_returned => \@cr,
1863 long_overdue => \@lo
1869 __PACKAGE__->register_method(
1870 method => "checked_in_with_fines",
1871 api_name => "open-ils.actor.user.checked_in_with_fines",
1873 signature => q/@see open-ils.actor.user.checked_out/
1875 sub checked_in_with_fines {
1876 my( $self, $conn, $auth, $userid ) = @_;
1878 my $e = new_editor(authtoken=>$auth);
1879 return $e->event unless $e->checkauth;
1881 if( $userid ne $e->requestor->id ) {
1882 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1885 # money is owed on these items and they are checked in
1886 my $open = $e->search_action_circulation(
1889 xact_finish => undef,
1890 checkin_time => { "!=" => undef },
1895 my( @lost, @cr, @lo );
1896 for my $c (@$open) {
1897 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1898 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1899 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1904 claims_returned => \@cr,
1905 long_overdue => \@lo
1917 __PACKAGE__->register_method(
1918 method => "user_transaction_history",
1919 api_name => "open-ils.actor.user.transactions.history",
1921 notes => <<" NOTES");
1922 Returns a list of billable transaction ids for a user, optionally by type
1924 __PACKAGE__->register_method(
1925 method => "user_transaction_history",
1926 api_name => "open-ils.actor.user.transactions.history.have_charge",
1928 notes => <<" NOTES");
1929 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
1931 __PACKAGE__->register_method(
1932 method => "user_transaction_history",
1933 api_name => "open-ils.actor.user.transactions.history.have_balance",
1935 notes => <<" NOTES");
1936 Returns a list of billable transaction ids for a user that have a balance, optionally by type
1938 __PACKAGE__->register_method(
1939 method => "user_transaction_history",
1940 api_name => "open-ils.actor.user.transactions.history.still_open",
1942 notes => <<" NOTES");
1943 Returns a list of billable transaction ids for a user that are not finished
1945 __PACKAGE__->register_method(
1946 method => "user_transaction_history",
1947 api_name => "open-ils.actor.user.transactions.history.have_bill",
1949 notes => <<" NOTES");
1950 Returns a list of billable transaction ids for a user that has billings
1956 sub _user_transaction_history {
1957 my( $self, $client, $login_session, $user_id, $type ) = @_;
1959 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1960 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1961 return $evt if $evt;
1963 my $api = $self->api_name();
1968 @xact = (xact_type => $type) if(defined($type));
1969 @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
1970 @charge = (last_billing_ts => { "<>" => undef }) if $api =~ /have_charge/;
1972 $logger->debug("searching for transaction history: @xact : @balance, @charge");
1974 my $trans = $apputils->simple_scalar_request(
1976 "open-ils.cstore.direct.money.billable_transaction_summary.search.atomic",
1977 { usr => $user_id, @xact, @charge, @balance }, { order_by => { mbts => 'xact_start DESC' } });
1979 return [ map { $_->id } @$trans ];
1983 =head SEE APPUTILS.PM
1988 for my $x (@xacts) {
1989 my $s = new Fieldmapper::money::billable_transaction_summary;
1992 $s->xact_start( $x->xact_start );
1993 $s->xact_finish( $x->xact_finish );
1997 for my $b (@{ $x->billings }) {
1998 next if ($U->is_true($b->voided));
1999 $to += ($b->amount * 100);
2000 $lb ||= $b->billing_ts;
2001 if ($b->billing_ts ge $lb) {
2002 $lb = $b->billing_ts;
2003 $s->last_billing_note($b->note);
2004 $s->last_billing_ts($b->billing_ts);
2005 $s->last_billing_type($b->billing_type);
2009 $s->total_owed( sprintf('%0.2f', $to / 100 ) );
2013 for my $p (@{ $x->payments }) {
2014 next if ($U->is_true($p->voided));
2015 $tp += ($p->amount * 100);
2016 $lp ||= $p->payment_ts;
2017 if ($p->payment_ts ge $lp) {
2018 $lp = $p->payment_ts;
2019 $s->last_payment_note($p->note);
2020 $s->last_payment_ts($p->payment_ts);
2021 $s->last_payment_type($p->payment_type);
2024 $s->total_paid( sprintf('%0.2f', $tp / 100 ) );
2026 $s->balance_owed( sprintf('%0.2f', ($to - $tp) / 100) );
2028 $s->xact_type( 'grocery' ) if ($x->grocery);
2029 $s->xact_type( 'circulation' ) if ($x->circulation);
2038 sub user_transaction_history {
2039 my( $self, $conn, $auth, $userid, $type ) = @_;
2041 # run inside of a transaction to prevent replication delays
2042 my $e = new_editor(xact=>1, authtoken=>$auth);
2043 return $e->die_event unless $e->checkauth;
2045 if( $e->requestor->id ne $userid ) {
2046 return $e->die_event
2047 unless $e->allowed('VIEW_USER_TRANSACTIONS');
2050 my $api = $self->api_name;
2051 my @xact_finish = (xact_finish => undef ) if ($api =~ /history.still_open$/);
2053 my @xacts = @{ $e->search_money_billable_transaction(
2054 [ { usr => $userid, @xact_finish },
2056 flesh_fields => { mbt => [ qw/billings payments grocery circulation/ ] },
2057 order_by => { mbt => 'xact_start DESC' },
2064 #my @mbts = _make_mbts( @xacts );
2065 my @mbts = $U->make_mbts( @xacts );
2067 if(defined($type)) {
2068 @mbts = grep { $_->xact_type eq $type } @mbts;
2071 if($api =~ /have_balance/o) {
2072 @mbts = grep { int($_->balance_owed * 100) != 0 } @mbts;
2075 if($api =~ /have_charge/o) {
2076 @mbts = grep { defined($_->last_billing_ts) } @mbts;
2079 if($api =~ /have_bill/o) {
2080 @mbts = grep { int($_->total_owed * 100) != 0 } @mbts;
2088 __PACKAGE__->register_method(
2089 method => "user_perms",
2090 api_name => "open-ils.actor.permissions.user_perms.retrieve",
2092 notes => <<" NOTES");
2093 Returns a list of permissions
2096 my( $self, $client, $authtoken, $user ) = @_;
2098 my( $staff, $evt ) = $apputils->checkses($authtoken);
2099 return $evt if $evt;
2101 $user ||= $staff->id;
2103 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
2107 return $apputils->simple_scalar_request(
2109 "open-ils.storage.permission.user_perms.atomic",
2113 __PACKAGE__->register_method(
2114 method => "retrieve_perms",
2115 api_name => "open-ils.actor.permissions.retrieve",
2116 notes => <<" NOTES");
2117 Returns a list of permissions
2119 sub retrieve_perms {
2120 my( $self, $client ) = @_;
2121 return $apputils->simple_scalar_request(
2123 "open-ils.cstore.direct.permission.perm_list.search.atomic",
2124 { id => { '!=' => undef } }
2128 __PACKAGE__->register_method(
2129 method => "retrieve_groups",
2130 api_name => "open-ils.actor.groups.retrieve",
2131 notes => <<" NOTES");
2132 Returns a list of user groupss
2134 sub retrieve_groups {
2135 my( $self, $client ) = @_;
2136 return new_editor()->retrieve_all_permission_grp_tree();
2139 __PACKAGE__->register_method(
2140 method => "retrieve_org_address",
2141 api_name => "open-ils.actor.org_unit.address.retrieve",
2142 notes => <<' NOTES');
2143 Returns an org_unit address by ID
2144 @param An org_address ID
2146 sub retrieve_org_address {
2147 my( $self, $client, $id ) = @_;
2148 return $apputils->simple_scalar_request(
2150 "open-ils.cstore.direct.actor.org_address.retrieve",
2155 __PACKAGE__->register_method(
2156 method => "retrieve_groups_tree",
2157 api_name => "open-ils.actor.groups.tree.retrieve",
2158 notes => <<" NOTES");
2159 Returns a list of user groups
2161 sub retrieve_groups_tree {
2162 my( $self, $client ) = @_;
2163 return new_editor()->search_permission_grp_tree(
2168 flesh_fields => { pgt => ["children"] },
2169 order_by => { pgt => 'name'}
2176 # turns an org list into an org tree
2178 sub build_group_tree {
2180 my( $self, $grplist) = @_;
2182 return $grplist unless (
2183 ref($grplist) and @$grplist > 1 );
2185 my @list = sort { $a->name cmp $b->name } @$grplist;
2188 for my $grp (@list) {
2190 if ($grp and !defined($grp->parent)) {
2194 my ($parent) = grep { $_->id == $grp->parent} @list;
2196 $parent->children([]) unless defined($parent->children);
2197 push( @{$parent->children}, $grp );
2205 __PACKAGE__->register_method(
2206 method => "add_user_to_groups",
2207 api_name => "open-ils.actor.user.set_groups",
2208 notes => <<" NOTES");
2209 Adds a user to one or more permission groups
2212 sub add_user_to_groups {
2213 my( $self, $client, $authtoken, $userid, $groups ) = @_;
2215 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2216 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
2217 return $evt if $evt;
2219 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2220 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
2221 return $evt if $evt;
2223 $apputils->simplereq(
2225 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
2227 for my $group (@$groups) {
2228 my $link = Fieldmapper::permission::usr_grp_map->new;
2230 $link->usr($userid);
2232 my $id = $apputils->simplereq(
2234 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2240 __PACKAGE__->register_method(
2241 method => "get_user_perm_groups",
2242 api_name => "open-ils.actor.user.get_groups",
2243 notes => <<" NOTES");
2244 Retrieve a user's permission groups.
2248 sub get_user_perm_groups {
2249 my( $self, $client, $authtoken, $userid ) = @_;
2251 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2252 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2253 return $evt if $evt;
2255 return $apputils->simplereq(
2257 'open-ils.cstore.direct.permission.usr_grp_map.search.atomic', { usr => $userid } );
2262 __PACKAGE__->register_method (
2263 method => 'register_workstation',
2264 api_name => 'open-ils.actor.workstation.register.override',
2265 signature => q/@see open-ils.actor.workstation.register/);
2267 __PACKAGE__->register_method (
2268 method => 'register_workstation',
2269 api_name => 'open-ils.actor.workstation.register',
2271 Registers a new workstion in the system
2272 @param authtoken The login session key
2273 @param name The name of the workstation id
2274 @param owner The org unit that owns this workstation
2275 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2276 if the name is already in use.
2279 sub _register_workstation {
2280 my( $self, $connection, $authtoken, $name, $owner ) = @_;
2281 my( $requestor, $evt ) = $U->checkses($authtoken);
2282 return $evt if $evt;
2283 $evt = $U->check_perms($requestor->id, $owner, 'REGISTER_WORKSTATION');
2284 return $evt if $evt;
2286 my $ws = $U->cstorereq(
2287 'open-ils.cstore.direct.actor.workstation.search', { name => $name } );
2288 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS') if $ws;
2290 $ws = Fieldmapper::actor::workstation->new;
2291 $ws->owning_lib($owner);
2294 my $id = $U->storagereq(
2295 'open-ils.storage.direct.actor.workstation.create', $ws );
2296 return $U->DB_UPDATE_FAILED($ws) unless $id;
2302 sub register_workstation {
2303 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2305 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2306 return $e->event unless $e->checkauth;
2307 return $e->event unless $e->allowed('REGISTER_WORKSTATION'); # XXX rely on editor perms
2308 my $existing = $e->search_actor_workstation({name => $name});
2311 if( $self->api_name =~ /override/o ) {
2312 return $e->event unless $e->allowed('DELETE_WORKSTATION'); # XXX rely on editor perms
2313 return $e->event unless $e->delete_actor_workstation($$existing[0]);
2315 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2319 my $ws = Fieldmapper::actor::workstation->new;
2320 $ws->owning_lib($owner);
2322 $e->create_actor_workstation($ws) or return $e->event;
2324 return $ws->id; # note: editor sets the id on the new object for us
2328 __PACKAGE__->register_method (
2329 method => 'fetch_patron_note',
2330 api_name => 'open-ils.actor.note.retrieve.all',
2332 Returns a list of notes for a given user
2333 Requestor must have VIEW_USER permission if pub==false and
2334 @param authtoken The login session key
2335 @param args Hash of params including
2336 patronid : the patron's id
2337 pub : true if retrieving only public notes
2341 sub fetch_patron_note {
2342 my( $self, $conn, $authtoken, $args ) = @_;
2343 my $patronid = $$args{patronid};
2345 my($reqr, $evt) = $U->checkses($authtoken);
2346 return $evt if $evt;
2349 ($patron, $evt) = $U->fetch_user($patronid);
2350 return $evt if $evt;
2353 if( $patronid ne $reqr->id ) {
2354 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2355 return $evt if $evt;
2357 return $U->cstorereq(
2358 'open-ils.cstore.direct.actor.usr_note.search.atomic',
2359 { usr => $patronid, pub => 't' } );
2362 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2363 return $evt if $evt;
2365 return $U->cstorereq(
2366 'open-ils.cstore.direct.actor.usr_note.search.atomic', { usr => $patronid } );
2369 __PACKAGE__->register_method (
2370 method => 'create_user_note',
2371 api_name => 'open-ils.actor.note.create',
2373 Creates a new note for the given user
2374 @param authtoken The login session key
2375 @param note The note object
2378 sub create_user_note {
2379 my( $self, $conn, $authtoken, $note ) = @_;
2380 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2381 return $e->die_event unless $e->checkauth;
2383 my $user = $e->retrieve_actor_user($note->usr)
2384 or return $e->die_event;
2386 return $e->die_event unless
2387 $e->allowed('UPDATE_USER',$user->home_ou);
2389 $note->creator($e->requestor->id);
2390 $e->create_actor_usr_note($note) or return $e->die_event;
2396 __PACKAGE__->register_method (
2397 method => 'delete_user_note',
2398 api_name => 'open-ils.actor.note.delete',
2400 Deletes a note for the given user
2401 @param authtoken The login session key
2402 @param noteid The note id
2405 sub delete_user_note {
2406 my( $self, $conn, $authtoken, $noteid ) = @_;
2408 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2409 return $e->die_event unless $e->checkauth;
2410 my $note = $e->retrieve_actor_usr_note($noteid)
2411 or return $e->die_event;
2412 my $user = $e->retrieve_actor_user($note->usr)
2413 or return $e->die_event;
2414 return $e->die_event unless
2415 $e->allowed('UPDATE_USER', $user->home_ou);
2417 $e->delete_actor_usr_note($note) or return $e->die_event;
2423 __PACKAGE__->register_method (
2424 method => 'update_user_note',
2425 api_name => 'open-ils.actor.note.update',
2427 @param authtoken The login session key
2428 @param note The note
2432 sub update_user_note {
2433 my( $self, $conn, $auth, $note ) = @_;
2434 my $e = new_editor(authtoken=>$auth, xact=>1);
2435 return $e->event unless $e->checkauth;
2436 my $patron = $e->retrieve_actor_user($note->usr)
2437 or return $e->event;
2438 return $e->event unless
2439 $e->allowed('UPDATE_USER', $patron->home_ou);
2440 $e->update_actor_user_note($note)
2441 or return $e->event;
2449 __PACKAGE__->register_method (
2450 method => 'create_closed_date',
2451 api_name => 'open-ils.actor.org_unit.closed_date.create',
2453 Creates a new closing entry for the given org_unit
2454 @param authtoken The login session key
2455 @param note The closed_date object
2458 sub create_closed_date {
2459 my( $self, $conn, $authtoken, $cd ) = @_;
2461 my( $user, $evt ) = $U->checkses($authtoken);
2462 return $evt if $evt;
2464 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2465 return $evt if $evt;
2467 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2469 my $id = $U->storagereq(
2470 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2471 return $U->DB_UPDATE_FAILED($cd) unless $id;
2476 __PACKAGE__->register_method (
2477 method => 'delete_closed_date',
2478 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2480 Deletes a closing entry for the given org_unit
2481 @param authtoken The login session key
2482 @param noteid The close_date id
2485 sub delete_closed_date {
2486 my( $self, $conn, $authtoken, $cd ) = @_;
2488 my( $user, $evt ) = $U->checkses($authtoken);
2489 return $evt if $evt;
2492 ($cd_obj, $evt) = fetch_closed_date($cd);
2493 return $evt if $evt;
2495 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2496 return $evt if $evt;
2498 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2500 my $stat = $U->storagereq(
2501 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2502 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2507 __PACKAGE__->register_method(
2508 method => 'usrname_exists',
2509 api_name => 'open-ils.actor.username.exists',
2511 Returns 1 if the requested username exists, returns 0 otherwise
2515 sub usrname_exists {
2516 my( $self, $conn, $auth, $usrname ) = @_;
2517 my $e = new_editor(authtoken=>$auth);
2518 return $e->event unless $e->checkauth;
2519 my $a = $e->search_actor_user({usrname => $usrname, deleted=>'f'}, {idlist=>1});
2520 return $$a[0] if $a and @$a;
2524 __PACKAGE__->register_method(
2525 method => 'barcode_exists',
2526 api_name => 'open-ils.actor.barcode.exists',
2528 Returns 1 if the requested barcode exists, returns 0 otherwise
2532 sub barcode_exists {
2533 my( $self, $conn, $auth, $barcode ) = @_;
2534 my $e = new_editor(authtoken=>$auth);
2535 return $e->event unless $e->checkauth;
2536 my $a = $e->search_actor_card({barcode => $barcode}, {idlist=>1});
2537 return $$a[0] if $a and @$a;
2542 __PACKAGE__->register_method(
2543 method => 'retrieve_net_levels',
2544 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2547 sub retrieve_net_levels {
2548 my( $self, $conn, $auth ) = @_;
2549 my $e = new_editor(authtoken=>$auth);
2550 return $e->event unless $e->checkauth;
2551 return $e->retrieve_all_config_net_access_level();
2555 __PACKAGE__->register_method(
2556 method => 'fetch_org_by_shortname',
2557 api_name => 'open-ils.actor.org_unit.retrieve_by_shorname',
2559 sub fetch_org_by_shortname {
2560 my( $self, $conn, $sname ) = @_;
2561 my $e = new_editor();
2562 my $org = $e->search_actor_org_unit({ shortname => uc($sname)})->[0];
2563 return $e->event unless $org;
2568 __PACKAGE__->register_method(
2569 method => 'session_home_lib',
2570 api_name => 'open-ils.actor.session.home_lib',
2573 sub session_home_lib {
2574 my( $self, $conn, $auth ) = @_;
2575 my $e = new_editor(authtoken=>$auth);
2576 return undef unless $e->checkauth;
2577 my $org = $e->retrieve_actor_org_unit($e->requestor->home_ou);
2578 return $org->shortname;
2583 __PACKAGE__->register_method(
2584 method => 'slim_tree',
2585 api_name => "open-ils.actor.org_tree.slim_hash.retrieve",
2588 my $tree = new_editor()->search_actor_org_unit(
2590 {"parent_ou" => undef },
2593 flesh_fields => { aou => ['children'] },
2594 order_by => { aou => 'name'},
2595 select => { aou => ["id","shortname", "name"]},
2600 return trim_tree($tree);
2606 return undef unless $tree;
2608 code => $tree->shortname,
2609 name => $tree->name,
2611 if( $tree->children and @{$tree->children} ) {
2612 $htree->{children} = [];
2613 for my $c (@{$tree->children}) {
2614 push( @{$htree->{children}}, trim_tree($c) );
2622 __PACKAGE__->register_method(
2623 method => "update_penalties",
2624 api_name => "open-ils.actor.user.penalties.update");
2625 sub update_penalties {
2626 my( $self, $conn, $auth, $userid ) = @_;
2627 my $e = new_editor(authtoken=>$auth);
2628 return $e->event unless $e->checkauth;
2629 $U->update_patron_penalties(
2631 patronid => $userid,
2638 __PACKAGE__->register_method(
2639 method => "user_retrieve_fleshed_by_id",
2640 api_name => "open-ils.actor.user.fleshed.retrieve",);
2642 sub user_retrieve_fleshed_by_id {
2643 my( $self, $client, $auth, $user_id, $fields ) = @_;
2644 my $e = new_editor(authtoken => $auth);
2645 return $e->event unless $e->checkauth;
2647 if( $e->requestor->id != $user_id ) {
2648 return $e->event unless $e->allowed('VIEW_USER');
2654 "standing_penalties",
2658 "stat_cat_entries" ];
2659 return new_flesh_user($user_id, $fields, $e);
2663 sub new_flesh_user {
2666 my $fields = shift || [];
2667 my $e = shift || new_editor(xact=>1);
2669 my $user = $e->retrieve_actor_user(
2674 "flesh_fields" => { "au" => $fields }
2677 ) or return $e->event;
2680 if( grep { $_ eq 'addresses' } @$fields ) {
2682 $user->addresses([]) unless @{$user->addresses};
2684 if( ref $user->billing_address ) {
2685 unless( grep { $user->billing_address->id == $_->id } @{$user->addresses} ) {
2686 push( @{$user->addresses}, $user->billing_address );
2690 if( ref $user->mailing_address ) {
2691 unless( grep { $user->mailing_address->id == $_->id } @{$user->addresses} ) {
2692 push( @{$user->addresses}, $user->mailing_address );
2698 $user->clear_passwd();
2705 __PACKAGE__->register_method(
2706 method => "user_retrieve_parts",
2707 api_name => "open-ils.actor.user.retrieve.parts",);
2709 sub user_retrieve_parts {
2710 my( $self, $client, $auth, $user_id, $fields ) = @_;
2711 my $e = new_editor(authtoken => $auth);
2712 return $e->event unless $e->checkauth;
2713 if( $e->requestor->id != $user_id ) {
2714 return $e->event unless $e->allowed('VIEW_USER');
2717 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2718 push(@resp, $user->$_()) for(@$fields);