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, $setting ) = @_;
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 my $settings = { map { ( $_->name => JSON->JSON2perl($_->value) ) } @$s };
133 return $$settings{$setting} if $setting;
139 __PACKAGE__->register_method(
140 method => "ou_settings",
141 api_name => "open-ils.actor.org_unit.settings.retrieve",
144 my( $self, $client, $ouid ) = @_;
146 $logger->info("Fetching org unit settings for org $ouid");
148 my $s = $apputils->simplereq(
150 'open-ils.cstore.direct.actor.org_unit_setting.search.atomic', {org_unit => $ouid});
152 return { map { ( $_->name => JSON->JSON2perl($_->value) ) } @$s };
157 __PACKAGE__->register_method(
158 api_name => 'open-ils.actor.ou_setting.ancestor_default',
159 method => 'ou_ancestor_setting',
162 # ------------------------------------------------------------------
163 # Attempts to find the org setting value for a given org. if not
164 # found at the requested org, searches up the org tree until it
165 # finds a parent that has the requested setting.
166 # when found, returns { org => $id, value => $value }
167 # otherwise, returns NULL
168 # ------------------------------------------------------------------
169 sub ou_ancestor_setting {
170 my( $self, $client, $orgid, $name ) = @_;
171 return $U->ou_ancestor_setting($orgid, $name);
177 __PACKAGE__->register_method (
178 method => "ou_setting_delete",
179 api_name => 'open-ils.actor.org_setting.delete',
181 Deletes a specific org unit setting for a specific location
182 @param authtoken The login session key
183 @param orgid The org unit whose setting we're changing
184 @param setting The name of the setting to delete
185 @return True value on success.
189 sub ou_setting_delete {
190 my( $self, $conn, $authtoken, $orgid, $setting ) = @_;
191 my( $reqr, $evt) = $U->checkses($authtoken);
193 $evt = $U->check_perms($reqr->id, $orgid, 'UPDATE_ORG_SETTING');
196 my $id = $U->cstorereq(
197 'open-ils.cstore.direct.actor.org_unit_setting.id_list',
198 { name => $setting, org_unit => $orgid } );
200 $logger->debug("Retrieved setting $id in org unit setting delete");
202 my $s = $U->cstorereq(
203 'open-ils.cstore.direct.actor.org_unit_setting.delete', $id );
205 $logger->activity("User ".$reqr->id." deleted org unit setting $id") if $s;
211 __PACKAGE__->register_method(
212 method => "update_patron",
213 api_name => "open-ils.actor.patron.update",);
216 my( $self, $client, $user_session, $patron ) = @_;
218 my $session = $apputils->start_db_session();
222 $logger->info("Creating new patron...") if $patron->isnew;
223 $logger->info("Updating Patron: " . $patron->id) unless $patron->isnew;
225 my( $user_obj, $evt ) = $U->checkses($user_session);
228 $evt = check_group_perm($session, $user_obj, $patron);
232 # $new_patron is the patron in progress. $patron is the original patron
233 # passed in with the method. new_patron will change as the components
234 # of patron are added/updated.
238 # unflesh the real items on the patron
239 $patron->card( $patron->card->id ) if(ref($patron->card));
240 $patron->billing_address( $patron->billing_address->id )
241 if(ref($patron->billing_address));
242 $patron->mailing_address( $patron->mailing_address->id )
243 if(ref($patron->mailing_address));
245 # create/update the patron first so we can use his id
246 if($patron->isnew()) {
247 ( $new_patron, $evt ) = _add_patron($session, _clone_patron($patron), $user_obj);
249 } else { $new_patron = $patron; }
251 ( $new_patron, $evt ) = _add_update_addresses($session, $patron, $new_patron, $user_obj);
254 ( $new_patron, $evt ) = _add_update_cards($session, $patron, $new_patron, $user_obj);
257 ( $new_patron, $evt ) = _add_survey_responses($session, $patron, $new_patron, $user_obj);
260 # re-update the patron if anything has happened to him during this process
261 if($new_patron->ischanged()) {
262 ( $new_patron, $evt ) = _update_patron($session, $new_patron, $user_obj);
266 ($new_patron, $evt) = _create_stat_maps($session, $user_session, $patron, $new_patron, $user_obj);
269 ($new_patron, $evt) = _create_perm_maps($session, $user_session, $patron, $new_patron, $user_obj);
272 ($new_patron, $evt) = _create_standing_penalties($session, $user_session, $patron, $new_patron, $user_obj);
275 $logger->activity("user ".$user_obj->id." updating/creating user ".$new_patron->id);
278 if(!$patron->isnew) {
279 $opatron = new_editor()->retrieve_actor_user($new_patron->id);
282 $apputils->commit_db_session($session);
283 my $fuser = flesh_user($new_patron->id());
286 # Log the new and old patron for investigation
287 $logger->info("$user_session updating patron object. orig patron object = ".
288 JSON->perl2JSON($opatron). " |||| new patron = ".JSON->perl2JSON($fuser));
298 return new_flesh_user($id, [
301 "standing_penalties",
305 "stat_cat_entries" ] );
313 # clone and clear stuff that would break the database
317 my $new_patron = $patron->clone;
319 $new_patron->clear_billing_address();
320 $new_patron->clear_mailing_address();
321 $new_patron->clear_addresses();
322 $new_patron->clear_card();
323 $new_patron->clear_cards();
324 $new_patron->clear_id();
325 $new_patron->clear_isnew();
326 $new_patron->clear_ischanged();
327 $new_patron->clear_isdeleted();
328 $new_patron->clear_stat_cat_entries();
329 $new_patron->clear_permissions();
330 $new_patron->clear_standing_penalties();
340 my $user_obj = shift;
342 my $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'CREATE_USER');
343 return (undef, $evt) if $evt;
345 my $ex = $session->request(
346 'open-ils.storage.direct.actor.user.search.usrname', $patron->usrname())->gather(1);
348 return (undef, OpenILS::Event->new('USERNAME_EXISTS'));
351 $logger->info("Creating new user in the DB with username: ".$patron->usrname());
353 my $id = $session->request(
354 "open-ils.storage.direct.actor.user.create", $patron)->gather(1);
355 return (undef, $U->DB_UPDATE_FAILED($patron)) unless $id;
357 $logger->info("Successfully created new user [$id] in DB");
359 return ( $session->request(
360 "open-ils.storage.direct.actor.user.retrieve", $id)->gather(1), undef );
364 sub check_group_perm {
365 my( $session, $requestor, $patron ) = @_;
368 # first let's see if the requestor has
369 # priveleges to update this user in any way
370 if( ! $patron->isnew ) {
371 my $p = $session->request(
372 'open-ils.storage.direct.actor.user.retrieve', $patron->id )->gather(1);
374 # If we are the requestor (trying to update our own account)
375 # and we are not trying to change our profile, we're good
376 if( $p->id == $requestor->id and
377 $p->profile == $patron->profile ) {
382 $evt = group_perm_failed($session, $requestor, $p);
386 # They are allowed to edit this patron.. can they put the
387 # patron into the group requested?
388 $evt = group_perm_failed($session, $requestor, $patron);
394 sub group_perm_failed {
395 my( $session, $requestor, $patron ) = @_;
399 my $grpid = $patron->profile;
403 $logger->debug("user update looking for group perm for group $grpid");
404 $grp = $session->request(
405 'open-ils.storage.direct.permission.grp_tree.retrieve', $grpid )->gather(1);
406 return OpenILS::Event->new('PERMISSION_GRP_TREE_NOT_FOUND') unless $grp;
408 } while( !($perm = $grp->application_perm) and ($grpid = $grp->parent) );
410 $logger->info("user update checking perm $perm on user ".
411 $requestor->id." for update/create on user username=".$patron->usrname);
413 my $evt = $U->check_perms($requestor->id, $patron->home_ou, $perm);
421 my( $session, $patron, $user_obj, $noperm) = @_;
423 $logger->info("Updating patron ".$patron->id." in DB");
428 $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'UPDATE_USER');
429 return (undef, $evt) if $evt;
432 # update the password by itself to avoid the password protection magic
433 if( $patron->passwd ) {
434 my $s = $session->request(
435 'open-ils.storage.direct.actor.user.remote_update',
436 {id => $patron->id}, {passwd => $patron->passwd})->gather(1);
437 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($s);
438 $patron->clear_passwd;
441 if(!$patron->ident_type) {
442 $patron->clear_ident_type;
443 $patron->clear_ident_value;
446 $evt = verify_last_xact($session, $patron);
447 return (undef, $evt) if $evt;
449 my $stat = $session->request(
450 "open-ils.storage.direct.actor.user.update",$patron )->gather(1);
451 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($stat);
456 sub verify_last_xact {
457 my( $session, $patron ) = @_;
458 return undef unless $patron->id and $patron->id > 0;
459 my $p = $session->request(
460 'open-ils.storage.direct.actor.user.retrieve', $patron->id)->gather(1);
461 my $xact = $p->last_xact_id;
462 return undef unless $xact;
463 $logger->info("user xact = $xact, saving with xact " . $patron->last_xact_id);
464 return OpenILS::Event->new('XACT_COLLISION')
465 if $xact != $patron->last_xact_id;
470 sub _check_dup_ident {
471 my( $session, $patron ) = @_;
473 return undef unless $patron->ident_value;
476 ident_type => $patron->ident_type,
477 ident_value => $patron->ident_value,
480 $logger->debug("patron update searching for dup ident values: " .
481 $patron->ident_type . ':' . $patron->ident_value);
483 $search->{id} = {'!=' => $patron->id} if $patron->id and $patron->id > 0;
485 my $dups = $session->request(
486 'open-ils.storage.direct.actor.user.search_where.atomic', $search )->gather(1);
489 return OpenILS::Event->new('PATRON_DUP_IDENT1', payload => $patron )
496 sub _add_update_addresses {
500 my $new_patron = shift;
504 my $current_id; # id of the address before creation
506 for my $address (@{$patron->addresses()}) {
508 next unless ref $address;
509 $current_id = $address->id();
511 if( $patron->billing_address() and
512 $patron->billing_address() == $current_id ) {
513 $logger->info("setting billing addr to $current_id");
514 $new_patron->billing_address($address->id());
515 $new_patron->ischanged(1);
518 if( $patron->mailing_address() and
519 $patron->mailing_address() == $current_id ) {
520 $new_patron->mailing_address($address->id());
521 $logger->info("setting mailing addr to $current_id");
522 $new_patron->ischanged(1);
526 if($address->isnew()) {
528 $address->usr($new_patron->id());
530 ($address, $evt) = _add_address($session,$address);
531 return (undef, $evt) if $evt;
533 # we need to get the new id
534 if( $patron->billing_address() and
535 $patron->billing_address() == $current_id ) {
536 $new_patron->billing_address($address->id());
537 $logger->info("setting billing addr to $current_id");
538 $new_patron->ischanged(1);
541 if( $patron->mailing_address() and
542 $patron->mailing_address() == $current_id ) {
543 $new_patron->mailing_address($address->id());
544 $logger->info("setting mailing addr to $current_id");
545 $new_patron->ischanged(1);
548 } elsif($address->ischanged() ) {
550 ($address, $evt) = _update_address($session, $address);
551 return (undef, $evt) if $evt;
553 } elsif($address->isdeleted() ) {
555 if( $address->id() == $new_patron->mailing_address() ) {
556 $new_patron->clear_mailing_address();
557 ($new_patron, $evt) = _update_patron($session, $new_patron);
558 return (undef, $evt) if $evt;
561 if( $address->id() == $new_patron->billing_address() ) {
562 $new_patron->clear_billing_address();
563 ($new_patron, $evt) = _update_patron($session, $new_patron);
564 return (undef, $evt) if $evt;
567 $evt = _delete_address($session, $address);
568 return (undef, $evt) if $evt;
572 return ( $new_patron, undef );
576 # adds an address to the db and returns the address with new id
578 my($session, $address) = @_;
579 $address->clear_id();
581 $logger->info("Creating new address at street ".$address->street1);
583 # put the address into the database
584 my $id = $session->request(
585 "open-ils.storage.direct.actor.user_address.create", $address )->gather(1);
586 return (undef, $U->DB_UPDATE_FAILED($address)) unless $id;
589 return ($address, undef);
593 sub _update_address {
594 my( $session, $address ) = @_;
596 $logger->info("Updating address ".$address->id." in the DB");
598 my $stat = $session->request(
599 "open-ils.storage.direct.actor.user_address.update", $address )->gather(1);
601 return (undef, $U->DB_UPDATE_FAILED($address)) unless defined($stat);
602 return ($address, undef);
607 sub _add_update_cards {
611 my $new_patron = shift;
615 my $virtual_id; #id of the card before creation
616 for my $card (@{$patron->cards()}) {
618 $card->usr($new_patron->id());
620 if(ref($card) and $card->isnew()) {
622 $virtual_id = $card->id();
623 ( $card, $evt ) = _add_card($session,$card);
624 return (undef, $evt) if $evt;
626 #if(ref($patron->card)) { $patron->card($patron->card->id); }
627 if($patron->card() == $virtual_id) {
628 $new_patron->card($card->id());
629 $new_patron->ischanged(1);
632 } elsif( ref($card) and $card->ischanged() ) {
633 $evt = _update_card($session, $card);
634 return (undef, $evt) if $evt;
638 return ( $new_patron, undef );
642 # adds an card to the db and returns the card with new id
644 my( $session, $card ) = @_;
647 $logger->info("Adding new patron card ".$card->barcode);
649 my $id = $session->request(
650 "open-ils.storage.direct.actor.card.create", $card )->gather(1);
651 return (undef, $U->DB_UPDATE_FAILED($card)) unless $id;
652 $logger->info("Successfully created patron card $id");
655 return ( $card, undef );
659 # returns event on error. returns undef otherwise
661 my( $session, $card ) = @_;
662 $logger->info("Updating patron card ".$card->id);
664 my $stat = $session->request(
665 "open-ils.storage.direct.actor.card.update", $card )->gather(1);
666 return $U->DB_UPDATE_FAILED($card) unless defined($stat);
673 # returns event on error. returns undef otherwise
674 sub _delete_address {
675 my( $session, $address ) = @_;
677 $logger->info("Deleting address ".$address->id." from DB");
679 my $stat = $session->request(
680 "open-ils.storage.direct.actor.user_address.delete", $address )->gather(1);
682 return $U->DB_UPDATE_FAILED($address) unless defined($stat);
688 sub _add_survey_responses {
689 my ($session, $patron, $new_patron) = @_;
691 $logger->info( "Updating survey responses for patron ".$new_patron->id );
693 my $responses = $patron->survey_responses;
697 $_->usr($new_patron->id) for (@$responses);
699 my $evt = $U->simplereq( "open-ils.circ",
700 "open-ils.circ.survey.submit.user_id", $responses );
702 return (undef, $evt) if defined($U->event_code($evt));
706 return ( $new_patron, undef );
710 sub _create_stat_maps {
712 my($session, $user_session, $patron, $new_patron) = @_;
714 my $maps = $patron->stat_cat_entries();
716 for my $map (@$maps) {
718 my $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.update";
720 if ($map->isdeleted()) {
721 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.delete";
723 } elsif ($map->isnew()) {
724 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.create";
729 $map->target_usr($new_patron->id);
732 $logger->info("Updating stat entry with method $method and map $map");
734 my $stat = $session->request($method, $map)->gather(1);
735 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
739 return ($new_patron, undef);
742 sub _create_perm_maps {
744 my($session, $user_session, $patron, $new_patron) = @_;
746 my $maps = $patron->permissions;
748 for my $map (@$maps) {
750 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
751 if ($map->isdeleted()) {
752 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
753 } elsif ($map->isnew()) {
754 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
759 $map->usr($new_patron->id);
761 #warn( "Updating permissions with method $method and session $user_session and map $map" );
762 $logger->info( "Updating permissions with method $method and map $map" );
764 my $stat = $session->request($method, $map)->gather(1);
765 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
769 return ($new_patron, undef);
773 __PACKAGE__->register_method(
774 method => "set_user_perms",
775 api_name => "open-ils.actor.user.permissions.update",
784 my $session = $apputils->start_db_session();
786 my( $user_obj, $evt ) = $U->checkses($ses);
789 my $perms = $session->request('open-ils.storage.permission.user_perms.atomic', $user_obj->id)->gather(1);
792 $all = 1 if ($user_obj->super_user());
793 $all = 1 unless ($U->check_perms($user_obj->id, $user_obj->home_ou, 'EVERYTHING'));
795 for my $map (@$maps) {
797 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
798 if ($map->isdeleted()) {
799 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
800 } elsif ($map->isnew()) {
801 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
805 next if (!$all || !grep { $_->perm eq $map->perm and $_->grantable == 1 and $_->depth <= $map->depth } @$perms);
807 #warn( "Updating permissions with method $method and session $ses and map $map" );
808 $logger->info( "Updating permissions with method $method and map $map" );
810 my $stat = $session->request($method, $map)->gather(1);
811 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
815 $apputils->commit_db_session($session);
817 return scalar(@$maps);
821 sub _create_standing_penalties {
823 my($session, $user_session, $patron, $new_patron) = @_;
825 my $maps = $patron->standing_penalties;
828 for my $map (@$maps) {
830 if ($map->isdeleted()) {
831 $method = "open-ils.storage.direct.actor.user_standing_penalty.delete";
832 } elsif ($map->isnew()) {
833 $method = "open-ils.storage.direct.actor.user_standing_penalty.create";
839 $map->usr($new_patron->id);
841 $logger->debug( "Updating standing penalty with method $method and session $user_session and map $map" );
843 my $stat = $session->request($method, $map)->gather(1);
844 return (undef, $U->DB_UPDATE_FAILED($map)) unless $stat;
847 return ($new_patron, undef);
852 __PACKAGE__->register_method(
853 method => "search_username",
854 api_name => "open-ils.actor.user.search.username",
857 sub search_username {
858 my($self, $client, $username) = @_;
859 my $users = OpenILS::Application::AppUtils->simple_scalar_request(
861 "open-ils.cstore.direct.actor.user.search.atomic",
862 { usrname => $username }
870 __PACKAGE__->register_method(
871 method => "user_retrieve_by_barcode",
872 api_name => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
874 sub user_retrieve_by_barcode {
875 my($self, $client, $user_session, $barcode) = @_;
877 $logger->debug("Searching for user with barcode $barcode");
878 my ($user_obj, $evt) = $apputils->checkses($user_session);
881 my $card = OpenILS::Application::AppUtils->simple_scalar_request(
883 "open-ils.cstore.direct.actor.card.search.atomic",
884 { barcode => $barcode }
887 if(!$card || !$card->[0]) {
888 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' );
892 my $user = flesh_user($card->usr());
894 $evt = $U->check_perms($user_obj->id, $user->home_ou, 'VIEW_USER');
897 if(!$user) { return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ); }
904 __PACKAGE__->register_method(
905 method => "get_user_by_id",
906 api_name => "open-ils.actor.user.retrieve",);
909 my ($self, $client, $auth, $id) = @_;
910 my $e = new_editor(authtoken=>$auth);
911 return $e->event unless $e->checkauth;
912 my $user = $e->retrieve_actor_user($id)
914 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
920 __PACKAGE__->register_method(
921 method => "get_org_types",
922 api_name => "open-ils.actor.org_types.retrieve",);
926 my($self, $client) = @_;
927 return $org_types if $org_types;
928 return $org_types = new_editor()->retrieve_all_actor_org_unit_type();
933 __PACKAGE__->register_method(
934 method => "get_user_ident_types",
935 api_name => "open-ils.actor.user.ident_types.retrieve",
938 sub get_user_ident_types {
939 return $ident_types if $ident_types;
940 return $ident_types =
941 new_editor()->retrieve_all_config_identification_type();
947 __PACKAGE__->register_method(
948 method => "get_org_unit",
949 api_name => "open-ils.actor.org_unit.retrieve",
953 my( $self, $client, $user_session, $org_id ) = @_;
954 my $e = new_editor(authtoken => $user_session);
956 return $e->event unless $e->checkauth;
957 $org_id = $e->requestor->ws_ou;
959 my $o = $e->retrieve_actor_org_unit($org_id)
964 __PACKAGE__->register_method(
965 method => "search_org_unit",
966 api_name => "open-ils.actor.org_unit_list.search",
969 sub search_org_unit {
971 my( $self, $client, $field, $value ) = @_;
973 my $list = OpenILS::Application::AppUtils->simple_scalar_request(
975 "open-ils.cstore.direct.actor.org_unit.search.atomic",
976 { $field => $value } );
984 __PACKAGE__->register_method(
985 method => "get_org_tree",
986 api_name => "open-ils.actor.org_tree.retrieve",
988 note => "Returns the entire org tree structure",
992 my( $self, $client) = @_;
994 $cache = OpenSRF::Utils::Cache->new("global", 0) unless $cache;
995 my $tree = $cache->get_cache('orgtree');
996 return $tree if $tree;
998 $tree = new_editor()->search_actor_org_unit(
1000 {"parent_ou" => undef },
1003 flesh_fields => { aou => ['children'] },
1004 order_by => { aou => 'name'}
1009 $cache->put_cache('orgtree', $tree);
1014 # turns an org list into an org tree
1015 sub build_org_tree {
1017 my( $self, $orglist) = @_;
1019 return $orglist unless (
1020 ref($orglist) and @$orglist > 1 );
1023 $a->ou_type <=> $b->ou_type ||
1024 $a->name cmp $b->name } @$orglist;
1026 for my $org (@list) {
1028 next unless ($org and defined($org->parent_ou));
1029 my ($parent) = grep { $_->id == $org->parent_ou } @list;
1030 next unless $parent;
1032 $parent->children([]) unless defined($parent->children);
1033 push( @{$parent->children}, $org );
1041 __PACKAGE__->register_method(
1042 method => "get_org_descendants",
1043 api_name => "open-ils.actor.org_tree.descendants.retrieve"
1046 # depth is optional. org_unit is the id
1047 sub get_org_descendants {
1048 my( $self, $client, $org_unit, $depth ) = @_;
1049 my $orglist = $apputils->simple_scalar_request(
1051 "open-ils.storage.actor.org_unit.descendants.atomic",
1052 $org_unit, $depth );
1053 return $self->build_org_tree($orglist);
1057 __PACKAGE__->register_method(
1058 method => "get_org_ancestors",
1059 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
1062 # depth is optional. org_unit is the id
1063 sub get_org_ancestors {
1064 my( $self, $client, $org_unit, $depth ) = @_;
1065 my $orglist = $apputils->simple_scalar_request(
1067 "open-ils.storage.actor.org_unit.ancestors.atomic",
1068 $org_unit, $depth );
1069 return $self->build_org_tree($orglist);
1073 __PACKAGE__->register_method(
1074 method => "get_standings",
1075 api_name => "open-ils.actor.standings.retrieve"
1080 return $user_standings if $user_standings;
1081 return $user_standings =
1082 $apputils->simple_scalar_request(
1084 "open-ils.cstore.direct.config.standing.search.atomic",
1085 { id => { "!=" => undef } }
1091 __PACKAGE__->register_method(
1092 method => "get_my_org_path",
1093 api_name => "open-ils.actor.org_unit.full_path.retrieve"
1096 sub get_my_org_path {
1097 my( $self, $client, $auth, $org_id ) = @_;
1098 my $e = new_editor(authtoken=>$auth);
1099 return $e->event unless $e->checkauth;
1100 $org_id = $e->requestor->ws_ou unless defined $org_id;
1102 return $apputils->simple_scalar_request(
1104 "open-ils.storage.actor.org_unit.full_path.atomic",
1109 __PACKAGE__->register_method(
1110 method => "patron_adv_search",
1111 api_name => "open-ils.actor.patron.search.advanced" );
1112 sub patron_adv_search {
1113 my( $self, $client, $auth, $search_hash, $search_limit, $search_sort, $include_inactive ) = @_;
1114 my $e = new_editor(authtoken=>$auth);
1115 return $e->event unless $e->checkauth;
1116 return $e->event unless $e->allowed('VIEW_USER');
1117 return $U->storagereq(
1118 "open-ils.storage.actor.user.crazy_search",
1119 $search_hash, $search_limit, $search_sort, $include_inactive);
1124 sub _verify_password {
1125 my($user_session, $password) = @_;
1126 my $user_obj = $apputils->check_user_session($user_session);
1128 #grab the user with password
1129 $user_obj = $apputils->simple_scalar_request(
1131 "open-ils.cstore.direct.actor.user.retrieve",
1134 if($user_obj->passwd eq $password) {
1142 __PACKAGE__->register_method(
1143 method => "update_password",
1144 api_name => "open-ils.actor.user.password.update");
1146 __PACKAGE__->register_method(
1147 method => "update_password",
1148 api_name => "open-ils.actor.user.username.update");
1150 __PACKAGE__->register_method(
1151 method => "update_password",
1152 api_name => "open-ils.actor.user.email.update");
1154 sub update_password {
1155 my( $self, $client, $user_session, $new_value, $current_password ) = @_;
1159 my $user_obj = $apputils->check_user_session($user_session);
1161 if($self->api_name =~ /password/o) {
1163 #make sure they know the current password
1164 if(!_verify_password($user_session, md5_hex($current_password))) {
1165 return OpenILS::Event->new('INCORRECT_PASSWORD');
1168 $logger->debug("update_password setting new password $new_value");
1169 $user_obj->passwd($new_value);
1171 } elsif($self->api_name =~ /username/o) {
1172 my $users = search_username(undef, undef, $new_value);
1173 if( $users and $users->[0] ) {
1174 return OpenILS::Event->new('USERNAME_EXISTS');
1176 $user_obj->usrname($new_value);
1178 } elsif($self->api_name =~ /email/o) {
1179 #warn "Updating email to $new_value\n";
1180 $user_obj->email($new_value);
1183 my $session = $apputils->start_db_session();
1185 ( $user_obj, $evt ) = _update_patron($session, $user_obj, $user_obj, 1);
1186 return $evt if $evt;
1188 $apputils->commit_db_session($session);
1190 if($user_obj) { return 1; }
1195 __PACKAGE__->register_method(
1196 method => "check_user_perms",
1197 api_name => "open-ils.actor.user.perm.check",
1198 notes => <<" NOTES");
1199 Takes a login session, user id, an org id, and an array of perm type strings. For each
1200 perm type, if the user does *not* have the given permission it is added
1201 to a list which is returned from the method. If all permissions
1202 are allowed, an empty list is returned
1203 if the logged in user does not match 'user_id', then the logged in user must
1204 have VIEW_PERMISSION priveleges.
1207 sub check_user_perms {
1208 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1210 my( $staff, $evt ) = $apputils->checkses($login_session);
1211 return $evt if $evt;
1213 if($staff->id ne $user_id) {
1214 if( $evt = $apputils->check_perms(
1215 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1221 for my $perm (@$perm_types) {
1222 if($apputils->check_perms($user_id, $org_id, $perm)) {
1223 push @not_allowed, $perm;
1227 return \@not_allowed
1230 __PACKAGE__->register_method(
1231 method => "check_user_perms2",
1232 api_name => "open-ils.actor.user.perm.check.multi_org",
1234 Checks the permissions on a list of perms and orgs for a user
1235 @param authtoken The login session key
1236 @param user_id The id of the user to check
1237 @param orgs The array of org ids
1238 @param perms The array of permission names
1239 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1240 if the logged in user does not match 'user_id', then the logged in user must
1241 have VIEW_PERMISSION priveleges.
1244 sub check_user_perms2 {
1245 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1247 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1248 $authtoken, $user_id, 'VIEW_PERMISSION' );
1249 return $evt if $evt;
1252 for my $org (@$orgs) {
1253 for my $perm (@$perms) {
1254 if($apputils->check_perms($user_id, $org, $perm)) {
1255 push @not_allowed, [ $org, $perm ];
1260 return \@not_allowed
1264 __PACKAGE__->register_method(
1265 method => 'check_user_perms3',
1266 api_name => 'open-ils.actor.user.perm.highest_org',
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 perm The permission to check
1274 @return The org unit highest in the org tree within which the user has
1275 the requested permission
1278 sub check_user_perms3 {
1279 my( $self, $client, $authtoken, $userid, $perm ) = @_;
1281 my( $staff, $target, $org, $evt );
1283 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1284 $authtoken, $userid, 'VIEW_PERMISSION' );
1285 return $evt if $evt;
1287 my $tree = $self->get_org_tree();
1288 return _find_highest_perm_org( $perm, $userid, $target->ws_ou, $tree );
1292 sub _find_highest_perm_org {
1293 my ( $perm, $userid, $start_org, $org_tree ) = @_;
1294 my $org = $apputils->find_org($org_tree, $start_org );
1298 last if ($apputils->check_perms( $userid, $org->id, $perm )); # perm failed
1300 $org = $apputils->find_org( $org_tree, $org->parent_ou() );
1306 __PACKAGE__->register_method(
1307 method => 'check_user_perms4',
1308 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1310 Returns the highest org unit id at which a user has a given permission
1311 If the requestor does not match the target user, the requestor must have
1312 'VIEW_PERMISSION' rights at the home org unit of the target user
1313 @param authtoken The login session key
1314 @param userid The id of the user in question
1315 @param perms An array of perm names to check
1316 @return An array of orgId's representing the org unit
1317 highest in the org tree within which the user has the requested permission
1318 The arrah of orgId's has matches the order of the perms array
1321 sub check_user_perms4 {
1322 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1324 my( $staff, $target, $org, $evt );
1326 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1327 $authtoken, $userid, 'VIEW_PERMISSION' );
1328 return $evt if $evt;
1331 return [] unless ref($perms);
1332 my $tree = $self->get_org_tree();
1334 for my $p (@$perms) {
1335 push( @arr, _find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1343 __PACKAGE__->register_method(
1344 method => "user_fines_summary",
1345 api_name => "open-ils.actor.user.fines.summary",
1346 notes => <<" NOTES");
1347 Returns a short summary of the users total open fines, excluding voided fines
1348 Params are login_session, user_id
1349 Returns a 'mous' object.
1352 sub user_fines_summary {
1353 my( $self, $client, $auth, $user_id ) = @_;
1354 my $e = new_editor(authtoken=>$auth);
1355 return $e->event unless $e->checkauth;
1356 my $user = $e->retrieve_actor_user($user_id)
1357 or return $e->event;
1359 if( $user_id ne $e->requestor->id ) {
1360 return $e->event unless
1361 $e->allowed('VIEW_USER_FINES_SUMMARY', $user->home_ou);
1364 # run this inside a transaction to prevent replication delay errors
1365 my $ses = $U->start_db_session();
1366 my $s = $ses->request(
1367 'open-ils.storage.money.open_user_summary.search', $user_id )->gather(1);
1368 $U->rollback_db_session($ses);
1375 __PACKAGE__->register_method(
1376 method => "user_transactions",
1377 api_name => "open-ils.actor.user.transactions",
1378 notes => <<" NOTES");
1379 Returns a list of open user transactions (mbts objects);
1380 Params are login_session, user_id
1381 Optional third parameter is the transactions type. defaults to all
1384 __PACKAGE__->register_method(
1385 method => "user_transactions",
1386 api_name => "open-ils.actor.user.transactions.have_charge",
1387 notes => <<" NOTES");
1388 Returns a list of all open user transactions (mbts objects) that have an initial charge
1389 Params are login_session, user_id
1390 Optional third parameter is the transactions type. defaults to all
1393 __PACKAGE__->register_method(
1394 method => "user_transactions",
1395 api_name => "open-ils.actor.user.transactions.have_balance",
1396 notes => <<" NOTES");
1397 Returns a list of all open user transactions (mbts objects) that have a balance
1398 Params are login_session, user_id
1399 Optional third parameter is the transactions type. defaults to all
1402 __PACKAGE__->register_method(
1403 method => "user_transactions",
1404 api_name => "open-ils.actor.user.transactions.fleshed",
1405 notes => <<" NOTES");
1406 Returns an object/hash of transaction, circ, title where transaction = an open
1407 user transactions (mbts objects), circ is the attached circluation, and title
1408 is the title the circ points to
1409 Params are login_session, user_id
1410 Optional third parameter is the transactions type. defaults to all
1413 __PACKAGE__->register_method(
1414 method => "user_transactions",
1415 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1416 notes => <<" NOTES");
1417 Returns an object/hash of transaction, circ, title where transaction = an open
1418 user transactions that has an initial charge (mbts objects), circ is the
1419 attached circluation, and title is the title the circ points to
1420 Params are login_session, user_id
1421 Optional third parameter is the transactions type. defaults to all
1424 __PACKAGE__->register_method(
1425 method => "user_transactions",
1426 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1427 notes => <<" NOTES");
1428 Returns an object/hash of transaction, circ, title where transaction = an open
1429 user transaction that has a balance (mbts objects), circ is the attached
1430 circluation, and title is the title the circ points to
1431 Params are login_session, user_id
1432 Optional third parameter is the transaction type. defaults to all
1435 __PACKAGE__->register_method(
1436 method => "user_transactions",
1437 api_name => "open-ils.actor.user.transactions.count",
1438 notes => <<" NOTES");
1439 Returns an object/hash of transaction, circ, title where transaction = an open
1440 user transactions (mbts objects), circ is the attached circluation, and title
1441 is the title the circ points to
1442 Params are login_session, user_id
1443 Optional third parameter is the transactions type. defaults to all
1446 __PACKAGE__->register_method(
1447 method => "user_transactions",
1448 api_name => "open-ils.actor.user.transactions.have_charge.count",
1449 notes => <<" NOTES");
1450 Returns an object/hash of transaction, circ, title where transaction = an open
1451 user transactions that has an initial charge (mbts objects), circ is the
1452 attached circluation, and title is the title the circ points to
1453 Params are login_session, user_id
1454 Optional third parameter is the transactions type. defaults to all
1457 __PACKAGE__->register_method(
1458 method => "user_transactions",
1459 api_name => "open-ils.actor.user.transactions.have_balance.count",
1460 notes => <<" NOTES");
1461 Returns an object/hash of transaction, circ, title where transaction = an open
1462 user transaction that has a balance (mbts objects), circ is the attached
1463 circluation, and title is the title the circ points to
1464 Params are login_session, user_id
1465 Optional third parameter is the transaction type. defaults to all
1468 __PACKAGE__->register_method(
1469 method => "user_transactions",
1470 api_name => "open-ils.actor.user.transactions.have_balance.total",
1471 notes => <<" NOTES");
1472 Returns an object/hash of transaction, circ, title where transaction = an open
1473 user transaction that has a balance (mbts objects), circ is the attached
1474 circluation, and title is the title the circ points to
1475 Params are login_session, user_id
1476 Optional third parameter is the transaction type. defaults to all
1481 sub user_transactions {
1482 my( $self, $client, $login_session, $user_id, $type ) = @_;
1484 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1485 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1486 return $evt if $evt;
1488 my $api = $self->api_name();
1492 if(defined($type)) { @xact = (xact_type => $type);
1494 } else { @xact = (); }
1497 ->method_lookup('open-ils.actor.user.transactions.history.still_open')
1498 ->run($login_session => $user_id => $type);
1500 if($api =~ /have_charge/o) {
1502 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1504 } elsif($api =~ /have_balance/o) {
1506 $trans = [ grep { int($_->balance_owed * 100) != 0 } @$trans ];
1509 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1513 if($api =~ /total/o) {
1515 for my $t (@$trans) {
1516 $total += $t->balance_owed;
1519 $logger->debug("Total balance owed by user $user_id: $total");
1523 if($api =~ /count/o) { return scalar @$trans; }
1524 if($api !~ /fleshed/o) { return $trans; }
1527 for my $t (@$trans) {
1529 if( $t->xact_type ne 'circulation' ) {
1530 push @resp, {transaction => $t};
1534 my $circ = $apputils->simple_scalar_request(
1536 "open-ils.cstore.direct.action.circulation.retrieve",
1541 my $title = $apputils->simple_scalar_request(
1543 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1544 $circ->target_copy );
1548 my $u = OpenILS::Utils::ModsParser->new();
1549 $u->start_mods_batch($title->marc());
1550 my $mods = $u->finish_mods_batch();
1551 $mods->doc_id($title->id) if $mods;
1553 push @resp, {transaction => $t, circ => $circ, record => $mods };
1561 __PACKAGE__->register_method(
1562 method => "user_transaction_retrieve",
1563 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1565 notes => <<" NOTES");
1566 Returns a fleshedtransaction record
1568 __PACKAGE__->register_method(
1569 method => "user_transaction_retrieve",
1570 api_name => "open-ils.actor.user.transaction.retrieve",
1572 notes => <<" NOTES");
1573 Returns a transaction record
1575 sub user_transaction_retrieve {
1576 my( $self, $client, $login_session, $bill_id ) = @_;
1578 # XXX I think I'm deprecated... make sure
1580 my $trans = $apputils->simple_scalar_request(
1582 "open-ils.cstore.direct.money.billable_transaction_summary.retrieve",
1586 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1587 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1588 return $evt if $evt;
1590 my $api = $self->api_name();
1591 if($api !~ /fleshed/o) { return $trans; }
1593 if( $trans->xact_type ne 'circulation' ) {
1594 $logger->debug("Returning non-circ transaction");
1595 return {transaction => $trans};
1598 my $circ = $apputils->simple_scalar_request(
1600 "open-ils..direct.action.circulation.retrieve",
1603 return {transaction => $trans} unless $circ;
1604 $logger->debug("Found the circ transaction");
1606 my $title = $apputils->simple_scalar_request(
1608 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1609 $circ->target_copy );
1611 return {transaction => $trans, circ => $circ } unless $title;
1612 $logger->debug("Found the circ title");
1616 my $u = OpenILS::Utils::ModsParser->new();
1617 $u->start_mods_batch($title->marc());
1618 $mods = $u->finish_mods_batch();
1620 if ($title->id == OILS_PRECAT_RECORD) {
1621 my $copy = $apputils->simple_scalar_request(
1623 "open-ils.cstore.direct.asset.copy.retrieve",
1624 $circ->target_copy );
1626 $mods = new Fieldmapper::metabib::virtual_record;
1627 $mods->doc_id(OILS_PRECAT_RECORD);
1628 $mods->title($copy->dummy_title);
1629 $mods->author($copy->dummy_author);
1633 $logger->debug("MODSized the circ title");
1635 return {transaction => $trans, circ => $circ, record => $mods };
1639 __PACKAGE__->register_method(
1640 method => "hold_request_count",
1641 api_name => "open-ils.actor.user.hold_requests.count",
1643 notes => <<" NOTES");
1644 Returns hold ready/total counts
1646 sub hold_request_count {
1647 my( $self, $client, $login_session, $userid ) = @_;
1649 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1650 $login_session, $userid, 'VIEW_HOLD' );
1651 return $evt if $evt;
1654 my $holds = $apputils->simple_scalar_request(
1656 "open-ils.cstore.direct.action.hold_request.search.atomic",
1659 fulfillment_time => {"=" => undef },
1660 cancel_time => undef,
1665 for my $h (@$holds) {
1666 next unless $h->capture_time and $h->current_copy;
1668 my $copy = $apputils->simple_scalar_request(
1670 "open-ils.cstore.direct.asset.copy.retrieve",
1674 if ($copy and $copy->status == 8) {
1679 return { total => scalar(@$holds), ready => scalar(@ready) };
1683 __PACKAGE__->register_method(
1684 method => "checkedout_count",
1685 api_name => "open-ils.actor.user.checked_out.count__",
1687 notes => <<" NOTES");
1688 Returns a transaction record
1692 sub checkedout_count {
1693 my( $self, $client, $login_session, $userid ) = @_;
1695 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1696 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1697 return $evt if $evt;
1699 my $circs = $apputils->simple_scalar_request(
1701 "open-ils.cstore.direct.action.circulation.search.atomic",
1702 { usr => $userid, stop_fines => undef }
1703 #{ usr => $userid, checkin_time => {"=" => undef } }
1706 my $parser = DateTime::Format::ISO8601->new;
1709 for my $c (@$circs) {
1710 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1711 my $due = $due_dt->epoch;
1713 if ($due < DateTime->today->epoch) {
1718 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1722 __PACKAGE__->register_method(
1723 method => "checked_out",
1724 api_name => "open-ils.actor.user.checked_out",
1727 Returns a structure of circulations objects sorted by
1728 out, overdue, lost, claims_returned, long_overdue.
1729 A list of IDs are returned of each type.
1730 lost, long_overdue, and claims_returned circ will not
1731 be "finished" (there is an outstanding balance or some
1732 other pending action on the circ).
1734 The .count method also includes a 'total' field which
1735 sums all "open" circs
1739 __PACKAGE__->register_method(
1740 method => "checked_out",
1741 api_name => "open-ils.actor.user.checked_out.count",
1743 signature => q/@see open-ils.actor.user.checked_out/
1747 my( $self, $conn, $auth, $userid ) = @_;
1749 my $e = new_editor(authtoken=>$auth);
1750 return $e->event unless $e->checkauth;
1752 if( $userid ne $e->requestor->id ) {
1753 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1756 my $count = $self->api_name =~ /count/;
1757 return _checked_out( $count, $e, $userid );
1761 my( $iscount, $e, $userid ) = @_;
1764 my $meth = 'open-ils.storage.actor.user.checked_out';
1765 $meth = "$meth.count" if $iscount;
1766 return $U->storagereq($meth, $userid);
1768 # XXX Old code - moved to storage
1769 #------------------------------------------------------------------------------
1770 #------------------------------------------------------------------------------
1771 my $circs = $e->search_action_circulation(
1772 { usr => $userid, checkin_time => undef });
1774 my $parser = DateTime::Format::ISO8601->new;
1776 # split the circs up into overdue and not-overdue circs
1778 for my $c (@$circs) {
1779 if( $c->due_date ) {
1780 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1781 my $due = $due_dt->epoch;
1782 if ($due < DateTime->today->epoch) {
1792 my( @open, @od, @lost, @cr, @lo );
1794 while (my $c = shift(@out)) {
1795 push( @open, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1796 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1797 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1798 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1801 while (my $c = shift(@overdue)) {
1802 push( @od, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1803 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1804 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1805 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1810 total => @open + @od + @lost + @cr + @lo,
1811 out => scalar(@open),
1812 overdue => scalar(@od),
1813 lost => scalar(@lost),
1814 claims_returned => scalar(@cr),
1815 long_overdue => scalar(@lo)
1823 claims_returned => \@cr,
1824 long_overdue => \@lo
1829 sub _checked_out_WHAT {
1830 my( $iscount, $e, $userid ) = @_;
1832 my $circs = $e->search_action_circulation(
1833 { usr => $userid, stop_fines => undef });
1835 my $mcircs = $e->search_action_circulation(
1838 checkin_time => undef,
1839 xact_finish => undef,
1843 push( @$circs, @$mcircs );
1845 my $parser = DateTime::Format::ISO8601->new;
1847 # split the circs up into overdue and not-overdue circs
1849 for my $c (@$circs) {
1850 if( $c->due_date ) {
1851 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1852 my $due = $due_dt->epoch;
1853 if ($due < DateTime->today->epoch) {
1854 push @overdue, $c->id;
1863 # grab all of the lost, claims-returned, and longoverdue circs
1864 #my $open = $e->search_action_circulation(
1865 # {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1868 # these items have stop_fines, but no xact_finish, so money
1869 # is owed on them and they have not been checked in
1870 my $open = $e->search_action_circulation(
1873 stop_fines => { in => [ qw/LOST CLAIMSRETURNED LONGOVERDUE/ ] },
1874 xact_finish => undef,
1875 checkin_time => undef,
1880 my( @lost, @cr, @lo );
1881 for my $c (@$open) {
1882 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1883 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1884 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1890 total => @$circs + @lost + @cr + @lo,
1891 out => scalar(@out),
1892 overdue => scalar(@overdue),
1893 lost => scalar(@lost),
1894 claims_returned => scalar(@cr),
1895 long_overdue => scalar(@lo)
1901 overdue => \@overdue,
1903 claims_returned => \@cr,
1904 long_overdue => \@lo
1910 __PACKAGE__->register_method(
1911 method => "checked_in_with_fines",
1912 api_name => "open-ils.actor.user.checked_in_with_fines",
1914 signature => q/@see open-ils.actor.user.checked_out/
1916 sub checked_in_with_fines {
1917 my( $self, $conn, $auth, $userid ) = @_;
1919 my $e = new_editor(authtoken=>$auth);
1920 return $e->event unless $e->checkauth;
1922 if( $userid ne $e->requestor->id ) {
1923 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1926 # money is owed on these items and they are checked in
1927 my $open = $e->search_action_circulation(
1930 xact_finish => undef,
1931 checkin_time => { "!=" => undef },
1936 my( @lost, @cr, @lo );
1937 for my $c (@$open) {
1938 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1939 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1940 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1945 claims_returned => \@cr,
1946 long_overdue => \@lo
1958 __PACKAGE__->register_method(
1959 method => "user_transaction_history",
1960 api_name => "open-ils.actor.user.transactions.history",
1962 notes => <<" NOTES");
1963 Returns a list of billable transaction ids for a user, optionally by type
1965 __PACKAGE__->register_method(
1966 method => "user_transaction_history",
1967 api_name => "open-ils.actor.user.transactions.history.have_charge",
1969 notes => <<" NOTES");
1970 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
1972 __PACKAGE__->register_method(
1973 method => "user_transaction_history",
1974 api_name => "open-ils.actor.user.transactions.history.have_balance",
1976 notes => <<" NOTES");
1977 Returns a list of billable transaction ids for a user that have a balance, optionally by type
1979 __PACKAGE__->register_method(
1980 method => "user_transaction_history",
1981 api_name => "open-ils.actor.user.transactions.history.still_open",
1983 notes => <<" NOTES");
1984 Returns a list of billable transaction ids for a user that are not finished
1986 __PACKAGE__->register_method(
1987 method => "user_transaction_history",
1988 api_name => "open-ils.actor.user.transactions.history.have_bill",
1990 notes => <<" NOTES");
1991 Returns a list of billable transaction ids for a user that has billings
1997 sub _user_transaction_history {
1998 my( $self, $client, $login_session, $user_id, $type ) = @_;
2000 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
2001 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
2002 return $evt if $evt;
2004 my $api = $self->api_name();
2009 @xact = (xact_type => $type) if(defined($type));
2010 @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
2011 @charge = (last_billing_ts => { "<>" => undef }) if $api =~ /have_charge/;
2013 $logger->debug("searching for transaction history: @xact : @balance, @charge");
2015 my $trans = $apputils->simple_scalar_request(
2017 "open-ils.cstore.direct.money.billable_transaction_summary.search.atomic",
2018 { usr => $user_id, @xact, @charge, @balance }, { order_by => { mbts => 'xact_start DESC' } });
2020 return [ map { $_->id } @$trans ];
2024 =head SEE APPUTILS.PM
2029 for my $x (@xacts) {
2030 my $s = new Fieldmapper::money::billable_transaction_summary;
2033 $s->xact_start( $x->xact_start );
2034 $s->xact_finish( $x->xact_finish );
2038 for my $b (@{ $x->billings }) {
2039 next if ($U->is_true($b->voided));
2040 $to += ($b->amount * 100);
2041 $lb ||= $b->billing_ts;
2042 if ($b->billing_ts ge $lb) {
2043 $lb = $b->billing_ts;
2044 $s->last_billing_note($b->note);
2045 $s->last_billing_ts($b->billing_ts);
2046 $s->last_billing_type($b->billing_type);
2050 $s->total_owed( sprintf('%0.2f', $to / 100 ) );
2054 for my $p (@{ $x->payments }) {
2055 next if ($U->is_true($p->voided));
2056 $tp += ($p->amount * 100);
2057 $lp ||= $p->payment_ts;
2058 if ($p->payment_ts ge $lp) {
2059 $lp = $p->payment_ts;
2060 $s->last_payment_note($p->note);
2061 $s->last_payment_ts($p->payment_ts);
2062 $s->last_payment_type($p->payment_type);
2065 $s->total_paid( sprintf('%0.2f', $tp / 100 ) );
2067 $s->balance_owed( sprintf('%0.2f', ($to - $tp) / 100) );
2069 $s->xact_type( 'grocery' ) if ($x->grocery);
2070 $s->xact_type( 'circulation' ) if ($x->circulation);
2079 sub user_transaction_history {
2080 my( $self, $conn, $auth, $userid, $type ) = @_;
2082 # run inside of a transaction to prevent replication delays
2083 my $e = new_editor(xact=>1, authtoken=>$auth);
2084 return $e->die_event unless $e->checkauth;
2086 if( $e->requestor->id ne $userid ) {
2087 return $e->die_event
2088 unless $e->allowed('VIEW_USER_TRANSACTIONS');
2091 my $api = $self->api_name;
2092 my @xact_finish = (xact_finish => undef ) if ($api =~ /history.still_open$/);
2094 my @xacts = @{ $e->search_money_billable_transaction(
2095 [ { usr => $userid, @xact_finish },
2097 flesh_fields => { mbt => [ qw/billings payments grocery circulation/ ] },
2098 order_by => { mbt => 'xact_start DESC' },
2106 #my @mbts = _make_mbts( @xacts );
2107 my @mbts = $U->make_mbts( @xacts );
2109 if(defined($type)) {
2110 @mbts = grep { $_->xact_type eq $type } @mbts;
2113 if($api =~ /have_balance/o) {
2114 @mbts = grep { int($_->balance_owed * 100) != 0 } @mbts;
2117 if($api =~ /have_charge/o) {
2118 @mbts = grep { defined($_->last_billing_ts) } @mbts;
2121 if($api =~ /have_bill/o) {
2122 @mbts = grep { int($_->total_owed * 100) != 0 } @mbts;
2130 __PACKAGE__->register_method(
2131 method => "user_perms",
2132 api_name => "open-ils.actor.permissions.user_perms.retrieve",
2134 notes => <<" NOTES");
2135 Returns a list of permissions
2138 my( $self, $client, $authtoken, $user ) = @_;
2140 my( $staff, $evt ) = $apputils->checkses($authtoken);
2141 return $evt if $evt;
2143 $user ||= $staff->id;
2145 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
2149 return $apputils->simple_scalar_request(
2151 "open-ils.storage.permission.user_perms.atomic",
2155 __PACKAGE__->register_method(
2156 method => "retrieve_perms",
2157 api_name => "open-ils.actor.permissions.retrieve",
2158 notes => <<" NOTES");
2159 Returns a list of permissions
2161 sub retrieve_perms {
2162 my( $self, $client ) = @_;
2163 return $apputils->simple_scalar_request(
2165 "open-ils.cstore.direct.permission.perm_list.search.atomic",
2166 { id => { '!=' => undef } }
2170 __PACKAGE__->register_method(
2171 method => "retrieve_groups",
2172 api_name => "open-ils.actor.groups.retrieve",
2173 notes => <<" NOTES");
2174 Returns a list of user groupss
2176 sub retrieve_groups {
2177 my( $self, $client ) = @_;
2178 return new_editor()->retrieve_all_permission_grp_tree();
2181 __PACKAGE__->register_method(
2182 method => "retrieve_org_address",
2183 api_name => "open-ils.actor.org_unit.address.retrieve",
2184 notes => <<' NOTES');
2185 Returns an org_unit address by ID
2186 @param An org_address ID
2188 sub retrieve_org_address {
2189 my( $self, $client, $id ) = @_;
2190 return $apputils->simple_scalar_request(
2192 "open-ils.cstore.direct.actor.org_address.retrieve",
2197 __PACKAGE__->register_method(
2198 method => "retrieve_groups_tree",
2199 api_name => "open-ils.actor.groups.tree.retrieve",
2200 notes => <<" NOTES");
2201 Returns a list of user groups
2203 sub retrieve_groups_tree {
2204 my( $self, $client ) = @_;
2205 return new_editor()->search_permission_grp_tree(
2210 flesh_fields => { pgt => ["children"] },
2211 order_by => { pgt => 'name'}
2218 # turns an org list into an org tree
2220 sub build_group_tree {
2222 my( $self, $grplist) = @_;
2224 return $grplist unless (
2225 ref($grplist) and @$grplist > 1 );
2227 my @list = sort { $a->name cmp $b->name } @$grplist;
2230 for my $grp (@list) {
2232 if ($grp and !defined($grp->parent)) {
2236 my ($parent) = grep { $_->id == $grp->parent} @list;
2238 $parent->children([]) unless defined($parent->children);
2239 push( @{$parent->children}, $grp );
2247 __PACKAGE__->register_method(
2248 method => "add_user_to_groups",
2249 api_name => "open-ils.actor.user.set_groups",
2250 notes => <<" NOTES");
2251 Adds a user to one or more permission groups
2254 sub add_user_to_groups {
2255 my( $self, $client, $authtoken, $userid, $groups ) = @_;
2257 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2258 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
2259 return $evt if $evt;
2261 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2262 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
2263 return $evt if $evt;
2265 $apputils->simplereq(
2267 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
2269 for my $group (@$groups) {
2270 my $link = Fieldmapper::permission::usr_grp_map->new;
2272 $link->usr($userid);
2274 my $id = $apputils->simplereq(
2276 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2282 __PACKAGE__->register_method(
2283 method => "get_user_perm_groups",
2284 api_name => "open-ils.actor.user.get_groups",
2285 notes => <<" NOTES");
2286 Retrieve a user's permission groups.
2290 sub get_user_perm_groups {
2291 my( $self, $client, $authtoken, $userid ) = @_;
2293 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2294 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2295 return $evt if $evt;
2297 return $apputils->simplereq(
2299 'open-ils.cstore.direct.permission.usr_grp_map.search.atomic', { usr => $userid } );
2304 __PACKAGE__->register_method (
2305 method => 'register_workstation',
2306 api_name => 'open-ils.actor.workstation.register.override',
2307 signature => q/@see open-ils.actor.workstation.register/);
2309 __PACKAGE__->register_method (
2310 method => 'register_workstation',
2311 api_name => 'open-ils.actor.workstation.register',
2313 Registers a new workstion in the system
2314 @param authtoken The login session key
2315 @param name The name of the workstation id
2316 @param owner The org unit that owns this workstation
2317 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2318 if the name is already in use.
2321 sub _register_workstation {
2322 my( $self, $connection, $authtoken, $name, $owner ) = @_;
2323 my( $requestor, $evt ) = $U->checkses($authtoken);
2324 return $evt if $evt;
2325 $evt = $U->check_perms($requestor->id, $owner, 'REGISTER_WORKSTATION');
2326 return $evt if $evt;
2328 my $ws = $U->cstorereq(
2329 'open-ils.cstore.direct.actor.workstation.search', { name => $name } );
2330 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS') if $ws;
2332 $ws = Fieldmapper::actor::workstation->new;
2333 $ws->owning_lib($owner);
2336 my $id = $U->storagereq(
2337 'open-ils.storage.direct.actor.workstation.create', $ws );
2338 return $U->DB_UPDATE_FAILED($ws) unless $id;
2344 sub register_workstation {
2345 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2347 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2348 return $e->event unless $e->checkauth;
2349 return $e->event unless $e->allowed('REGISTER_WORKSTATION'); # XXX rely on editor perms
2350 my $existing = $e->search_actor_workstation({name => $name});
2353 if( $self->api_name =~ /override/o ) {
2354 return $e->event unless $e->allowed('DELETE_WORKSTATION'); # XXX rely on editor perms
2355 return $e->event unless $e->delete_actor_workstation($$existing[0]);
2357 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2361 my $ws = Fieldmapper::actor::workstation->new;
2362 $ws->owning_lib($owner);
2364 $e->create_actor_workstation($ws) or return $e->event;
2366 return $ws->id; # note: editor sets the id on the new object for us
2370 __PACKAGE__->register_method (
2371 method => 'fetch_patron_note',
2372 api_name => 'open-ils.actor.note.retrieve.all',
2374 Returns a list of notes for a given user
2375 Requestor must have VIEW_USER permission if pub==false and
2376 @param authtoken The login session key
2377 @param args Hash of params including
2378 patronid : the patron's id
2379 pub : true if retrieving only public notes
2383 sub fetch_patron_note {
2384 my( $self, $conn, $authtoken, $args ) = @_;
2385 my $patronid = $$args{patronid};
2387 my($reqr, $evt) = $U->checkses($authtoken);
2388 return $evt if $evt;
2391 ($patron, $evt) = $U->fetch_user($patronid);
2392 return $evt if $evt;
2395 if( $patronid ne $reqr->id ) {
2396 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2397 return $evt if $evt;
2399 return $U->cstorereq(
2400 'open-ils.cstore.direct.actor.usr_note.search.atomic',
2401 { usr => $patronid, pub => 't' } );
2404 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2405 return $evt if $evt;
2407 return $U->cstorereq(
2408 'open-ils.cstore.direct.actor.usr_note.search.atomic', { usr => $patronid } );
2411 __PACKAGE__->register_method (
2412 method => 'create_user_note',
2413 api_name => 'open-ils.actor.note.create',
2415 Creates a new note for the given user
2416 @param authtoken The login session key
2417 @param note The note object
2420 sub create_user_note {
2421 my( $self, $conn, $authtoken, $note ) = @_;
2422 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2423 return $e->die_event unless $e->checkauth;
2425 my $user = $e->retrieve_actor_user($note->usr)
2426 or return $e->die_event;
2428 return $e->die_event unless
2429 $e->allowed('UPDATE_USER',$user->home_ou);
2431 $note->creator($e->requestor->id);
2432 $e->create_actor_usr_note($note) or return $e->die_event;
2438 __PACKAGE__->register_method (
2439 method => 'delete_user_note',
2440 api_name => 'open-ils.actor.note.delete',
2442 Deletes a note for the given user
2443 @param authtoken The login session key
2444 @param noteid The note id
2447 sub delete_user_note {
2448 my( $self, $conn, $authtoken, $noteid ) = @_;
2450 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2451 return $e->die_event unless $e->checkauth;
2452 my $note = $e->retrieve_actor_usr_note($noteid)
2453 or return $e->die_event;
2454 my $user = $e->retrieve_actor_user($note->usr)
2455 or return $e->die_event;
2456 return $e->die_event unless
2457 $e->allowed('UPDATE_USER', $user->home_ou);
2459 $e->delete_actor_usr_note($note) or return $e->die_event;
2465 __PACKAGE__->register_method (
2466 method => 'update_user_note',
2467 api_name => 'open-ils.actor.note.update',
2469 @param authtoken The login session key
2470 @param note The note
2474 sub update_user_note {
2475 my( $self, $conn, $auth, $note ) = @_;
2476 my $e = new_editor(authtoken=>$auth, xact=>1);
2477 return $e->event unless $e->checkauth;
2478 my $patron = $e->retrieve_actor_user($note->usr)
2479 or return $e->event;
2480 return $e->event unless
2481 $e->allowed('UPDATE_USER', $patron->home_ou);
2482 $e->update_actor_user_note($note)
2483 or return $e->event;
2491 __PACKAGE__->register_method (
2492 method => 'create_closed_date',
2493 api_name => 'open-ils.actor.org_unit.closed_date.create',
2495 Creates a new closing entry for the given org_unit
2496 @param authtoken The login session key
2497 @param note The closed_date object
2500 sub create_closed_date {
2501 my( $self, $conn, $authtoken, $cd ) = @_;
2503 my( $user, $evt ) = $U->checkses($authtoken);
2504 return $evt if $evt;
2506 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2507 return $evt if $evt;
2509 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2511 my $id = $U->storagereq(
2512 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2513 return $U->DB_UPDATE_FAILED($cd) unless $id;
2518 __PACKAGE__->register_method (
2519 method => 'delete_closed_date',
2520 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2522 Deletes a closing entry for the given org_unit
2523 @param authtoken The login session key
2524 @param noteid The close_date id
2527 sub delete_closed_date {
2528 my( $self, $conn, $authtoken, $cd ) = @_;
2530 my( $user, $evt ) = $U->checkses($authtoken);
2531 return $evt if $evt;
2534 ($cd_obj, $evt) = fetch_closed_date($cd);
2535 return $evt if $evt;
2537 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2538 return $evt if $evt;
2540 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2542 my $stat = $U->storagereq(
2543 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2544 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2549 __PACKAGE__->register_method(
2550 method => 'usrname_exists',
2551 api_name => 'open-ils.actor.username.exists',
2553 Returns 1 if the requested username exists, returns 0 otherwise
2557 sub usrname_exists {
2558 my( $self, $conn, $auth, $usrname ) = @_;
2559 my $e = new_editor(authtoken=>$auth);
2560 return $e->event unless $e->checkauth;
2561 my $a = $e->search_actor_user({usrname => $usrname, deleted=>'f'}, {idlist=>1});
2562 return $$a[0] if $a and @$a;
2566 __PACKAGE__->register_method(
2567 method => 'barcode_exists',
2568 api_name => 'open-ils.actor.barcode.exists',
2570 Returns 1 if the requested barcode exists, returns 0 otherwise
2574 sub barcode_exists {
2575 my( $self, $conn, $auth, $barcode ) = @_;
2576 my $e = new_editor(authtoken=>$auth);
2577 return $e->event unless $e->checkauth;
2578 my $a = $e->search_actor_card({barcode => $barcode}, {idlist=>1});
2579 return $$a[0] if $a and @$a;
2584 __PACKAGE__->register_method(
2585 method => 'retrieve_net_levels',
2586 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2589 sub retrieve_net_levels {
2590 my( $self, $conn, $auth ) = @_;
2591 my $e = new_editor(authtoken=>$auth);
2592 return $e->event unless $e->checkauth;
2593 return $e->retrieve_all_config_net_access_level();
2597 __PACKAGE__->register_method(
2598 method => 'fetch_org_by_shortname',
2599 api_name => 'open-ils.actor.org_unit.retrieve_by_shorname',
2601 sub fetch_org_by_shortname {
2602 my( $self, $conn, $sname ) = @_;
2603 my $e = new_editor();
2604 my $org = $e->search_actor_org_unit({ shortname => uc($sname)})->[0];
2605 return $e->event unless $org;
2610 __PACKAGE__->register_method(
2611 method => 'session_home_lib',
2612 api_name => 'open-ils.actor.session.home_lib',
2615 sub session_home_lib {
2616 my( $self, $conn, $auth ) = @_;
2617 my $e = new_editor(authtoken=>$auth);
2618 return undef unless $e->checkauth;
2619 my $org = $e->retrieve_actor_org_unit($e->requestor->home_ou);
2620 return $org->shortname;
2623 __PACKAGE__->register_method(
2624 method => 'session_safe_token',
2625 api_name => 'open-ils.actor.session.safe_token',
2627 Returns a hashed session ID that is safe for export to the world.
2628 This safe token will expire after 1 hour of non-use.
2629 @param auth Active authentication token
2633 sub session_safe_token {
2634 my( $self, $conn, $auth ) = @_;
2635 my $e = new_editor(authtoken=>$auth);
2636 return undef unless $e->checkauth;
2638 my $safe_token = md5_hex($auth);
2640 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2642 # Add more like the following if needed...
2644 "safe-token-home_lib-shortname-$safe_token",
2645 $e->retrieve_actor_org_unit(
2646 $e->requestor->home_ou
2655 __PACKAGE__->register_method(
2656 method => 'safe_token_home_lib',
2657 api_name => 'open-ils.actor.safe_token.home_lib.shortname',
2659 Returns the home library shortname from the session
2660 asscociated with a safe token from generated by
2661 open-ils.actor.session.safe_token.
2662 @param safe_token Active safe token
2666 sub safe_token_home_lib {
2667 my( $self, $conn, $safe_token ) = @_;
2669 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2670 return $cache->get_cache( 'safe-token-home_lib-shortname-'. $safe_token );
2675 __PACKAGE__->register_method(
2676 method => 'slim_tree',
2677 api_name => "open-ils.actor.org_tree.slim_hash.retrieve",
2680 my $tree = new_editor()->search_actor_org_unit(
2682 {"parent_ou" => undef },
2685 flesh_fields => { aou => ['children'] },
2686 order_by => { aou => 'name'},
2687 select => { aou => ["id","shortname", "name"]},
2692 return trim_tree($tree);
2698 return undef unless $tree;
2700 code => $tree->shortname,
2701 name => $tree->name,
2703 if( $tree->children and @{$tree->children} ) {
2704 $htree->{children} = [];
2705 for my $c (@{$tree->children}) {
2706 push( @{$htree->{children}}, trim_tree($c) );
2714 __PACKAGE__->register_method(
2715 method => "update_penalties",
2716 api_name => "open-ils.actor.user.penalties.update");
2717 sub update_penalties {
2718 my( $self, $conn, $auth, $userid ) = @_;
2719 my $e = new_editor(authtoken=>$auth);
2720 return $e->event unless $e->checkauth;
2721 $U->update_patron_penalties(
2723 patronid => $userid,
2730 __PACKAGE__->register_method(
2731 method => "user_retrieve_fleshed_by_id",
2732 api_name => "open-ils.actor.user.fleshed.retrieve",);
2734 sub user_retrieve_fleshed_by_id {
2735 my( $self, $client, $auth, $user_id, $fields ) = @_;
2736 my $e = new_editor(authtoken => $auth);
2737 return $e->event unless $e->checkauth;
2739 if( $e->requestor->id != $user_id ) {
2740 return $e->event unless $e->allowed('VIEW_USER');
2746 "standing_penalties",
2750 "stat_cat_entries" ];
2751 return new_flesh_user($user_id, $fields, $e);
2755 sub new_flesh_user {
2758 my $fields = shift || [];
2759 my $e = shift || new_editor(xact=>1);
2761 my $user = $e->retrieve_actor_user(
2766 "flesh_fields" => { "au" => $fields }
2769 ) or return $e->event;
2772 if( grep { $_ eq 'addresses' } @$fields ) {
2774 $user->addresses([]) unless @{$user->addresses};
2776 if( ref $user->billing_address ) {
2777 unless( grep { $user->billing_address->id == $_->id } @{$user->addresses} ) {
2778 push( @{$user->addresses}, $user->billing_address );
2782 if( ref $user->mailing_address ) {
2783 unless( grep { $user->mailing_address->id == $_->id } @{$user->addresses} ) {
2784 push( @{$user->addresses}, $user->mailing_address );
2790 $user->clear_passwd();
2797 __PACKAGE__->register_method(
2798 method => "user_retrieve_parts",
2799 api_name => "open-ils.actor.user.retrieve.parts",);
2801 sub user_retrieve_parts {
2802 my( $self, $client, $auth, $user_id, $fields ) = @_;
2803 my $e = new_editor(authtoken => $auth);
2804 return $e->event unless $e->checkauth;
2805 if( $e->requestor->id != $user_id ) {
2806 return $e->event unless $e->allowed('VIEW_USER');
2809 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2810 push(@resp, $user->$_()) for(@$fields);