1 package OpenILS::Application::Actor;
2 use OpenILS::Application;
3 use base qw/OpenILS::Application/;
4 use strict; use warnings;
6 $Data::Dumper::Indent = 0;
9 use Digest::MD5 qw(md5_hex);
11 use OpenSRF::EX qw(:try);
14 use OpenILS::Application::AppUtils;
16 use OpenILS::Utils::Fieldmapper;
17 use OpenILS::Utils::ModsParser;
18 use OpenSRF::Utils::Logger qw/$logger/;
19 use OpenSRF::Utils qw/:datetime/;
20 use OpenSRF::Utils::SettingsClient;
22 use OpenSRF::Utils::Cache;
24 use OpenSRF::Utils::JSON;
26 use DateTime::Format::ISO8601;
27 use OpenILS::Const qw/:const/;
29 use OpenILS::Application::Actor::Container;
30 use OpenILS::Application::Actor::ClosedDates;
32 use OpenILS::Utils::CStoreEditor qw/:funcs/;
34 use OpenILS::Application::Actor::UserGroups;
36 OpenILS::Application::Actor::Container->initialize();
37 OpenILS::Application::Actor::UserGroups->initialize();
38 OpenILS::Application::Actor::ClosedDates->initialize();
41 my $apputils = "OpenILS::Application::AppUtils";
44 sub _d { warn "Patron:\n" . Dumper(shift()); }
49 my $set_user_settings;
52 __PACKAGE__->register_method(
53 method => "set_user_settings",
54 api_name => "open-ils.actor.patron.settings.update",
56 sub set_user_settings {
57 my( $self, $client, $user_session, $uid, $settings ) = @_;
59 $logger->debug("Setting user settings: $user_session, $uid, " . Dumper($settings));
61 my( $staff, $user, $evt ) =
62 $apputils->checkses_requestor( $user_session, $uid, 'UPDATE_USER' );
66 [{ usr => $user->id, name => $_}, {value => $$settings{$_}}] } keys %$settings;
68 $_->[1]->{value} = OpenSRF::Utils::JSON->perl2JSON($_->[1]->{value}) for @params;
70 $logger->activity("User " . $staff->id . " updating user $uid settings with: " . Dumper(\@params));
72 my $ses = $U->start_db_session();
73 my $stat = $ses->request(
74 'open-ils.storage.direct.actor.user_setting.batch.merge', @params )->gather(1);
75 $U->commit_db_session($ses);
82 __PACKAGE__->register_method(
83 method => "set_ou_settings",
84 api_name => "open-ils.actor.org_unit.settings.update",
87 my( $self, $client, $user_session, $ouid, $settings ) = @_;
89 my( $staff, $evt ) = $apputils->checkses( $user_session );
91 $evt = $apputils->check_perms( $staff->id, $ouid, 'UPDATE_ORG_SETTING' );
95 for my $set (keys %$settings) {
97 my $json = OpenSRF::Utils::JSON->perl2JSON($$settings{$set});
98 $logger->activity("updating org_unit.setting: $ouid : $set : $json");
101 { org_unit => $ouid, name => $set },
102 { value => $json } );
105 my $ses = $U->start_db_session();
106 my $stat = $ses->request(
107 'open-ils.storage.direct.actor.org_unit_setting.merge', @params )->gather(1);
108 $U->commit_db_session($ses);
114 my $fetch_user_settings;
115 my $fetch_ou_settings;
117 __PACKAGE__->register_method(
118 method => "user_settings",
119 api_name => "open-ils.actor.patron.settings.retrieve",
122 my( $self, $client, $user_session, $uid, $setting ) = @_;
124 my( $staff, $user, $evt ) =
125 $apputils->checkses_requestor( $user_session, $uid, 'VIEW_USER' );
128 $logger->debug("User " . $staff->id . " fetching user $uid\n");
129 my $s = $apputils->simplereq(
131 'open-ils.cstore.direct.actor.user_setting.search.atomic', { usr => $uid } );
133 my $settings = { map { ( $_->name => OpenSRF::Utils::JSON->JSON2perl($_->value) ) } @$s };
135 return $$settings{$setting} if $setting;
141 __PACKAGE__->register_method(
142 method => "ou_settings",
143 api_name => "open-ils.actor.org_unit.settings.retrieve",
146 my( $self, $client, $ouid ) = @_;
148 $logger->info("Fetching org unit settings for org $ouid");
150 my $s = $apputils->simplereq(
152 'open-ils.cstore.direct.actor.org_unit_setting.search.atomic', {org_unit => $ouid});
154 return { map { ( $_->name => OpenSRF::Utils::JSON->JSON2perl($_->value) ) } @$s };
159 __PACKAGE__->register_method(
160 api_name => 'open-ils.actor.ou_setting.ancestor_default',
161 method => 'ou_ancestor_setting',
164 # ------------------------------------------------------------------
165 # Attempts to find the org setting value for a given org. if not
166 # found at the requested org, searches up the org tree until it
167 # finds a parent that has the requested setting.
168 # when found, returns { org => $id, value => $value }
169 # otherwise, returns NULL
170 # ------------------------------------------------------------------
171 sub ou_ancestor_setting {
172 my( $self, $client, $orgid, $name ) = @_;
173 return $U->ou_ancestor_setting($orgid, $name);
179 __PACKAGE__->register_method (
180 method => "ou_setting_delete",
181 api_name => 'open-ils.actor.org_setting.delete',
183 Deletes a specific org unit setting for a specific location
184 @param authtoken The login session key
185 @param orgid The org unit whose setting we're changing
186 @param setting The name of the setting to delete
187 @return True value on success.
191 sub ou_setting_delete {
192 my( $self, $conn, $authtoken, $orgid, $setting ) = @_;
193 my( $reqr, $evt) = $U->checkses($authtoken);
195 $evt = $U->check_perms($reqr->id, $orgid, 'UPDATE_ORG_SETTING');
198 my $id = $U->cstorereq(
199 'open-ils.cstore.direct.actor.org_unit_setting.id_list',
200 { name => $setting, org_unit => $orgid } );
202 $logger->debug("Retrieved setting $id in org unit setting delete");
204 my $s = $U->cstorereq(
205 'open-ils.cstore.direct.actor.org_unit_setting.delete', $id );
207 $logger->activity("User ".$reqr->id." deleted org unit setting $id") if $s;
221 __PACKAGE__->register_method(
222 method => "update_patron",
223 api_name => "open-ils.actor.patron.update",);
226 my( $self, $client, $user_session, $patron ) = @_;
228 my $session = $apputils->start_db_session();
232 $logger->info("Creating new patron...") if $patron->isnew;
233 $logger->info("Updating Patron: " . $patron->id) unless $patron->isnew;
235 my( $user_obj, $evt ) = $U->checkses($user_session);
238 $evt = check_group_perm($session, $user_obj, $patron);
242 # $new_patron is the patron in progress. $patron is the original patron
243 # passed in with the method. new_patron will change as the components
244 # of patron are added/updated.
248 # unflesh the real items on the patron
249 $patron->card( $patron->card->id ) if(ref($patron->card));
250 $patron->billing_address( $patron->billing_address->id )
251 if(ref($patron->billing_address));
252 $patron->mailing_address( $patron->mailing_address->id )
253 if(ref($patron->mailing_address));
255 # create/update the patron first so we can use his id
256 if($patron->isnew()) {
257 ( $new_patron, $evt ) = _add_patron($session, _clone_patron($patron), $user_obj);
259 } else { $new_patron = $patron; }
261 ( $new_patron, $evt ) = _add_update_addresses($session, $patron, $new_patron, $user_obj);
264 ( $new_patron, $evt ) = _add_update_cards($session, $patron, $new_patron, $user_obj);
267 ( $new_patron, $evt ) = _add_survey_responses($session, $patron, $new_patron, $user_obj);
270 # re-update the patron if anything has happened to him during this process
271 if($new_patron->ischanged()) {
272 ( $new_patron, $evt ) = _update_patron($session, $new_patron, $user_obj);
276 ($new_patron, $evt) = _create_stat_maps($session, $user_session, $patron, $new_patron, $user_obj);
279 ($new_patron, $evt) = _create_perm_maps($session, $user_session, $patron, $new_patron, $user_obj);
282 ($new_patron, $evt) = _create_standing_penalties($session, $user_session, $patron, $new_patron, $user_obj);
285 $logger->activity("user ".$user_obj->id." updating/creating user ".$new_patron->id);
288 if(!$patron->isnew) {
289 $opatron = new_editor()->retrieve_actor_user($new_patron->id);
292 $apputils->commit_db_session($session);
293 my $fuser = flesh_user($new_patron->id());
296 # Log the new and old patron for investigation
297 $logger->info("$user_session updating patron object. orig patron object = ".
298 OpenSRF::Utils::JSON->perl2JSON($opatron). " |||| new patron = ".OpenSRF::Utils::JSON->perl2JSON($fuser));
308 return new_flesh_user($id, [
311 "standing_penalties",
315 "stat_cat_entries" ] );
323 # clone and clear stuff that would break the database
327 my $new_patron = $patron->clone;
329 $new_patron->clear_billing_address();
330 $new_patron->clear_mailing_address();
331 $new_patron->clear_addresses();
332 $new_patron->clear_card();
333 $new_patron->clear_cards();
334 $new_patron->clear_id();
335 $new_patron->clear_isnew();
336 $new_patron->clear_ischanged();
337 $new_patron->clear_isdeleted();
338 $new_patron->clear_stat_cat_entries();
339 $new_patron->clear_permissions();
340 $new_patron->clear_standing_penalties();
350 my $user_obj = shift;
352 my $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'CREATE_USER');
353 return (undef, $evt) if $evt;
355 my $ex = $session->request(
356 'open-ils.storage.direct.actor.user.search.usrname', $patron->usrname())->gather(1);
358 return (undef, OpenILS::Event->new('USERNAME_EXISTS'));
361 $logger->info("Creating new user in the DB with username: ".$patron->usrname());
363 my $id = $session->request(
364 "open-ils.storage.direct.actor.user.create", $patron)->gather(1);
365 return (undef, $U->DB_UPDATE_FAILED($patron)) unless $id;
367 $logger->info("Successfully created new user [$id] in DB");
369 return ( $session->request(
370 "open-ils.storage.direct.actor.user.retrieve", $id)->gather(1), undef );
374 sub check_group_perm {
375 my( $session, $requestor, $patron ) = @_;
378 # first let's see if the requestor has
379 # priveleges to update this user in any way
380 if( ! $patron->isnew ) {
381 my $p = $session->request(
382 'open-ils.storage.direct.actor.user.retrieve', $patron->id )->gather(1);
384 # If we are the requestor (trying to update our own account)
385 # and we are not trying to change our profile, we're good
386 if( $p->id == $requestor->id and
387 $p->profile == $patron->profile ) {
392 $evt = group_perm_failed($session, $requestor, $p);
396 # They are allowed to edit this patron.. can they put the
397 # patron into the group requested?
398 $evt = group_perm_failed($session, $requestor, $patron);
404 sub group_perm_failed {
405 my( $session, $requestor, $patron ) = @_;
409 my $grpid = $patron->profile;
413 $logger->debug("user update looking for group perm for group $grpid");
414 $grp = $session->request(
415 'open-ils.storage.direct.permission.grp_tree.retrieve', $grpid )->gather(1);
416 return OpenILS::Event->new('PERMISSION_GRP_TREE_NOT_FOUND') unless $grp;
418 } while( !($perm = $grp->application_perm) and ($grpid = $grp->parent) );
420 $logger->info("user update checking perm $perm on user ".
421 $requestor->id." for update/create on user username=".$patron->usrname);
423 my $evt = $U->check_perms($requestor->id, $patron->home_ou, $perm);
431 my( $session, $patron, $user_obj, $noperm) = @_;
433 $logger->info("Updating patron ".$patron->id." in DB");
438 $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'UPDATE_USER');
439 return (undef, $evt) if $evt;
442 # update the password by itself to avoid the password protection magic
443 if( $patron->passwd ) {
444 my $s = $session->request(
445 'open-ils.storage.direct.actor.user.remote_update',
446 {id => $patron->id}, {passwd => $patron->passwd})->gather(1);
447 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($s);
448 $patron->clear_passwd;
451 if(!$patron->ident_type) {
452 $patron->clear_ident_type;
453 $patron->clear_ident_value;
456 $evt = verify_last_xact($session, $patron);
457 return (undef, $evt) if $evt;
459 my $stat = $session->request(
460 "open-ils.storage.direct.actor.user.update",$patron )->gather(1);
461 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($stat);
466 sub verify_last_xact {
467 my( $session, $patron ) = @_;
468 return undef unless $patron->id and $patron->id > 0;
469 my $p = $session->request(
470 'open-ils.storage.direct.actor.user.retrieve', $patron->id)->gather(1);
471 my $xact = $p->last_xact_id;
472 return undef unless $xact;
473 $logger->info("user xact = $xact, saving with xact " . $patron->last_xact_id);
474 return OpenILS::Event->new('XACT_COLLISION')
475 if $xact != $patron->last_xact_id;
480 sub _check_dup_ident {
481 my( $session, $patron ) = @_;
483 return undef unless $patron->ident_value;
486 ident_type => $patron->ident_type,
487 ident_value => $patron->ident_value,
490 $logger->debug("patron update searching for dup ident values: " .
491 $patron->ident_type . ':' . $patron->ident_value);
493 $search->{id} = {'!=' => $patron->id} if $patron->id and $patron->id > 0;
495 my $dups = $session->request(
496 'open-ils.storage.direct.actor.user.search_where.atomic', $search )->gather(1);
499 return OpenILS::Event->new('PATRON_DUP_IDENT1', payload => $patron )
506 sub _add_update_addresses {
510 my $new_patron = shift;
514 my $current_id; # id of the address before creation
516 for my $address (@{$patron->addresses()}) {
518 next unless ref $address;
519 $current_id = $address->id();
521 if( $patron->billing_address() and
522 $patron->billing_address() == $current_id ) {
523 $logger->info("setting billing addr to $current_id");
524 $new_patron->billing_address($address->id());
525 $new_patron->ischanged(1);
528 if( $patron->mailing_address() and
529 $patron->mailing_address() == $current_id ) {
530 $new_patron->mailing_address($address->id());
531 $logger->info("setting mailing addr to $current_id");
532 $new_patron->ischanged(1);
536 if($address->isnew()) {
538 $address->usr($new_patron->id());
540 ($address, $evt) = _add_address($session,$address);
541 return (undef, $evt) if $evt;
543 # we need to get the new id
544 if( $patron->billing_address() and
545 $patron->billing_address() == $current_id ) {
546 $new_patron->billing_address($address->id());
547 $logger->info("setting billing addr to $current_id");
548 $new_patron->ischanged(1);
551 if( $patron->mailing_address() and
552 $patron->mailing_address() == $current_id ) {
553 $new_patron->mailing_address($address->id());
554 $logger->info("setting mailing addr to $current_id");
555 $new_patron->ischanged(1);
558 } elsif($address->ischanged() ) {
560 ($address, $evt) = _update_address($session, $address);
561 return (undef, $evt) if $evt;
563 } elsif($address->isdeleted() ) {
565 if( $address->id() == $new_patron->mailing_address() ) {
566 $new_patron->clear_mailing_address();
567 ($new_patron, $evt) = _update_patron($session, $new_patron);
568 return (undef, $evt) if $evt;
571 if( $address->id() == $new_patron->billing_address() ) {
572 $new_patron->clear_billing_address();
573 ($new_patron, $evt) = _update_patron($session, $new_patron);
574 return (undef, $evt) if $evt;
577 $evt = _delete_address($session, $address);
578 return (undef, $evt) if $evt;
582 return ( $new_patron, undef );
586 # adds an address to the db and returns the address with new id
588 my($session, $address) = @_;
589 $address->clear_id();
591 $logger->info("Creating new address at street ".$address->street1);
593 # put the address into the database
594 my $id = $session->request(
595 "open-ils.storage.direct.actor.user_address.create", $address )->gather(1);
596 return (undef, $U->DB_UPDATE_FAILED($address)) unless $id;
599 return ($address, undef);
603 sub _update_address {
604 my( $session, $address ) = @_;
606 $logger->info("Updating address ".$address->id." in the DB");
608 my $stat = $session->request(
609 "open-ils.storage.direct.actor.user_address.update", $address )->gather(1);
611 return (undef, $U->DB_UPDATE_FAILED($address)) unless defined($stat);
612 return ($address, undef);
617 sub _add_update_cards {
621 my $new_patron = shift;
625 my $virtual_id; #id of the card before creation
626 for my $card (@{$patron->cards()}) {
628 $card->usr($new_patron->id());
630 if(ref($card) and $card->isnew()) {
632 $virtual_id = $card->id();
633 ( $card, $evt ) = _add_card($session,$card);
634 return (undef, $evt) if $evt;
636 #if(ref($patron->card)) { $patron->card($patron->card->id); }
637 if($patron->card() == $virtual_id) {
638 $new_patron->card($card->id());
639 $new_patron->ischanged(1);
642 } elsif( ref($card) and $card->ischanged() ) {
643 $evt = _update_card($session, $card);
644 return (undef, $evt) if $evt;
648 return ( $new_patron, undef );
652 # adds an card to the db and returns the card with new id
654 my( $session, $card ) = @_;
657 $logger->info("Adding new patron card ".$card->barcode);
659 my $id = $session->request(
660 "open-ils.storage.direct.actor.card.create", $card )->gather(1);
661 return (undef, $U->DB_UPDATE_FAILED($card)) unless $id;
662 $logger->info("Successfully created patron card $id");
665 return ( $card, undef );
669 # returns event on error. returns undef otherwise
671 my( $session, $card ) = @_;
672 $logger->info("Updating patron card ".$card->id);
674 my $stat = $session->request(
675 "open-ils.storage.direct.actor.card.update", $card )->gather(1);
676 return $U->DB_UPDATE_FAILED($card) unless defined($stat);
683 # returns event on error. returns undef otherwise
684 sub _delete_address {
685 my( $session, $address ) = @_;
687 $logger->info("Deleting address ".$address->id." from DB");
689 my $stat = $session->request(
690 "open-ils.storage.direct.actor.user_address.delete", $address )->gather(1);
692 return $U->DB_UPDATE_FAILED($address) unless defined($stat);
698 sub _add_survey_responses {
699 my ($session, $patron, $new_patron) = @_;
701 $logger->info( "Updating survey responses for patron ".$new_patron->id );
703 my $responses = $patron->survey_responses;
707 $_->usr($new_patron->id) for (@$responses);
709 my $evt = $U->simplereq( "open-ils.circ",
710 "open-ils.circ.survey.submit.user_id", $responses );
712 return (undef, $evt) if defined($U->event_code($evt));
716 return ( $new_patron, undef );
720 sub _create_stat_maps {
722 my($session, $user_session, $patron, $new_patron) = @_;
724 my $maps = $patron->stat_cat_entries();
726 for my $map (@$maps) {
728 my $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.update";
730 if ($map->isdeleted()) {
731 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.delete";
733 } elsif ($map->isnew()) {
734 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.create";
739 $map->target_usr($new_patron->id);
742 $logger->info("Updating stat entry with method $method and map $map");
744 my $stat = $session->request($method, $map)->gather(1);
745 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
749 return ($new_patron, undef);
752 sub _create_perm_maps {
754 my($session, $user_session, $patron, $new_patron) = @_;
756 my $maps = $patron->permissions;
758 for my $map (@$maps) {
760 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
761 if ($map->isdeleted()) {
762 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
763 } elsif ($map->isnew()) {
764 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
769 $map->usr($new_patron->id);
771 #warn( "Updating permissions with method $method and session $user_session and map $map" );
772 $logger->info( "Updating permissions with method $method and map $map" );
774 my $stat = $session->request($method, $map)->gather(1);
775 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
779 return ($new_patron, undef);
783 __PACKAGE__->register_method(
784 method => "set_user_work_ous",
785 api_name => "open-ils.actor.user.work_ous.update",
788 sub set_user_work_ous {
794 my( $requestor, $evt ) = $apputils->checksesperm( $ses, 'ASSIGN_WORK_ORG_UNIT' );
797 my $session = $apputils->start_db_session();
799 for my $map (@$maps) {
801 my $method = "open-ils.storage.direct.permission.usr_work_ou_map.update";
802 if ($map->isdeleted()) {
803 $method = "open-ils.storage.direct.permission.usr_work_ou_map.delete";
804 } elsif ($map->isnew()) {
805 $method = "open-ils.storage.direct.permission.usr_work_ou_map.create";
809 #warn( "Updating permissions with method $method and session $ses and map $map" );
810 $logger->info( "Updating work_ou map with method $method and map $map" );
812 my $stat = $session->request($method, $map)->gather(1);
813 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
817 $apputils->commit_db_session($session);
819 return scalar(@$maps);
823 __PACKAGE__->register_method(
824 method => "set_user_perms",
825 api_name => "open-ils.actor.user.permissions.update",
834 my $session = $apputils->start_db_session();
836 my( $user_obj, $evt ) = $U->checkses($ses);
839 my $perms = $session->request('open-ils.storage.permission.user_perms.atomic', $user_obj->id)->gather(1);
842 $all = 1 if ($user_obj->super_user());
843 $all = 1 unless ($U->check_perms($user_obj->id, $user_obj->home_ou, 'EVERYTHING'));
845 for my $map (@$maps) {
847 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
848 if ($map->isdeleted()) {
849 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
850 } elsif ($map->isnew()) {
851 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
855 next if (!$all || !grep { $_->perm eq $map->perm and $_->grantable == 1 and $_->depth <= $map->depth } @$perms);
857 #warn( "Updating permissions with method $method and session $ses and map $map" );
858 $logger->info( "Updating permissions with method $method and map $map" );
860 my $stat = $session->request($method, $map)->gather(1);
861 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
865 $apputils->commit_db_session($session);
867 return scalar(@$maps);
871 sub _create_standing_penalties {
873 my($session, $user_session, $patron, $new_patron) = @_;
875 my $maps = $patron->standing_penalties;
878 for my $map (@$maps) {
880 if ($map->isdeleted()) {
881 $method = "open-ils.storage.direct.actor.user_standing_penalty.delete";
882 } elsif ($map->isnew()) {
883 $method = "open-ils.storage.direct.actor.user_standing_penalty.create";
889 $map->usr($new_patron->id);
891 $logger->debug( "Updating standing penalty with method $method and session $user_session and map $map" );
893 my $stat = $session->request($method, $map)->gather(1);
894 return (undef, $U->DB_UPDATE_FAILED($map)) unless $stat;
897 return ($new_patron, undef);
902 __PACKAGE__->register_method(
903 method => "search_username",
904 api_name => "open-ils.actor.user.search.username",
907 sub search_username {
908 my($self, $client, $username) = @_;
909 return new_editor()->search_actor_user({usrname=>$username});
915 __PACKAGE__->register_method(
916 method => "user_retrieve_by_barcode",
917 api_name => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
919 sub user_retrieve_by_barcode {
920 my($self, $client, $user_session, $barcode) = @_;
922 $logger->debug("Searching for user with barcode $barcode");
923 my ($user_obj, $evt) = $apputils->checkses($user_session);
926 my $card = OpenILS::Application::AppUtils->simple_scalar_request(
928 "open-ils.cstore.direct.actor.card.search.atomic",
929 { barcode => $barcode }
932 if(!$card || !$card->[0]) {
933 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' );
937 my $user = flesh_user($card->usr());
939 $evt = $U->check_perms($user_obj->id, $user->home_ou, 'VIEW_USER');
942 if(!$user) { return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ); }
949 __PACKAGE__->register_method(
950 method => "get_user_by_id",
951 api_name => "open-ils.actor.user.retrieve",);
954 my ($self, $client, $auth, $id) = @_;
955 my $e = new_editor(authtoken=>$auth);
956 return $e->event unless $e->checkauth;
957 my $user = $e->retrieve_actor_user($id)
959 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
965 __PACKAGE__->register_method(
966 method => "get_org_types",
967 api_name => "open-ils.actor.org_types.retrieve",);
970 return $U->get_org_types();
975 __PACKAGE__->register_method(
976 method => "get_user_ident_types",
977 api_name => "open-ils.actor.user.ident_types.retrieve",
980 sub get_user_ident_types {
981 return $ident_types if $ident_types;
982 return $ident_types =
983 new_editor()->retrieve_all_config_identification_type();
989 __PACKAGE__->register_method(
990 method => "get_org_unit",
991 api_name => "open-ils.actor.org_unit.retrieve",
995 my( $self, $client, $user_session, $org_id ) = @_;
996 my $e = new_editor(authtoken => $user_session);
998 return $e->event unless $e->checkauth;
999 $org_id = $e->requestor->ws_ou;
1001 my $o = $e->retrieve_actor_org_unit($org_id)
1002 or return $e->event;
1006 __PACKAGE__->register_method(
1007 method => "search_org_unit",
1008 api_name => "open-ils.actor.org_unit_list.search",
1011 sub search_org_unit {
1013 my( $self, $client, $field, $value ) = @_;
1015 my $list = OpenILS::Application::AppUtils->simple_scalar_request(
1017 "open-ils.cstore.direct.actor.org_unit.search.atomic",
1018 { $field => $value } );
1024 # build the org tree
1026 __PACKAGE__->register_method(
1027 method => "get_org_tree",
1028 api_name => "open-ils.actor.org_tree.retrieve",
1030 note => "Returns the entire org tree structure",
1034 my( $self, $client) = @_;
1035 return $U->get_org_tree();
1039 __PACKAGE__->register_method(
1040 method => "get_org_descendants",
1041 api_name => "open-ils.actor.org_tree.descendants.retrieve"
1044 # depth is optional. org_unit is the id
1045 sub get_org_descendants {
1046 my( $self, $client, $org_unit, $depth ) = @_;
1047 my $orglist = $apputils->simple_scalar_request(
1049 "open-ils.storage.actor.org_unit.descendants.atomic",
1050 $org_unit, $depth );
1051 return $U->build_org_tree($orglist);
1055 __PACKAGE__->register_method(
1056 method => "get_org_ancestors",
1057 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
1060 # depth is optional. org_unit is the id
1061 sub get_org_ancestors {
1062 my( $self, $client, $org_unit, $depth ) = @_;
1063 my $orglist = $apputils->simple_scalar_request(
1065 "open-ils.storage.actor.org_unit.ancestors.atomic",
1066 $org_unit, $depth );
1067 return $U->build_org_tree($orglist);
1071 __PACKAGE__->register_method(
1072 method => "get_standings",
1073 api_name => "open-ils.actor.standings.retrieve"
1078 return $user_standings if $user_standings;
1079 return $user_standings =
1080 $apputils->simple_scalar_request(
1082 "open-ils.cstore.direct.config.standing.search.atomic",
1083 { id => { "!=" => undef } }
1089 __PACKAGE__->register_method(
1090 method => "get_my_org_path",
1091 api_name => "open-ils.actor.org_unit.full_path.retrieve"
1094 sub get_my_org_path {
1095 my( $self, $client, $auth, $org_id ) = @_;
1096 my $e = new_editor(authtoken=>$auth);
1097 return $e->event unless $e->checkauth;
1098 $org_id = $e->requestor->ws_ou unless defined $org_id;
1100 return $apputils->simple_scalar_request(
1102 "open-ils.storage.actor.org_unit.full_path.atomic",
1107 __PACKAGE__->register_method(
1108 method => "patron_adv_search",
1109 api_name => "open-ils.actor.patron.search.advanced" );
1110 sub patron_adv_search {
1111 my( $self, $client, $auth, $search_hash,
1112 $search_limit, $search_sort, $include_inactive, $search_depth ) = @_;
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", $search_hash,
1119 $search_limit, $search_sort, $include_inactive, $e->requestor->ws_ou, $search_depth);
1123 __PACKAGE__->register_method(
1124 method => "update_passwd",
1126 api_name => "open-ils.actor.user.password.update");
1128 __PACKAGE__->register_method(
1129 method => "update_passwd",
1130 api_name => "open-ils.actor.user.username.update");
1132 __PACKAGE__->register_method(
1133 method => "update_passwd",
1134 api_name => "open-ils.actor.user.email.update");
1137 my( $self, $conn, $auth, $new_val, $orig_pw ) = @_;
1138 my $e = new_editor(xact=>1, authtoken=>$auth);
1139 return $e->die_event unless $e->checkauth;
1141 my $db_user = $e->retrieve_actor_user($e->requestor->id)
1142 or return $e->die_event;
1143 my $api = $self->api_name;
1145 if( $api =~ /password/o ) {
1147 # make sure the original password matches the in-database password
1148 return OpenILS::Event->new('INCORRECT_PASSWORD')
1149 if md5_hex($orig_pw) ne $db_user->passwd;
1150 $db_user->passwd($new_val);
1154 # if we don't clear the password, the user will be updated with
1155 # a hashed version of the hashed version of their password
1156 $db_user->clear_passwd;
1158 if( $api =~ /username/o ) {
1160 # make sure no one else has this username
1161 my $exist = $e->search_actor_user({usrname=>$new_val},{idlist=>1});
1162 return OpenILS::Event->new('USERNAME_EXISTS') if @$exist;
1163 $db_user->usrname($new_val);
1165 } elsif( $api =~ /email/o ) {
1166 $db_user->email($new_val);
1170 $e->update_actor_user($db_user) or return $e->die_event;
1178 __PACKAGE__->register_method(
1179 method => "check_user_perms",
1180 api_name => "open-ils.actor.user.perm.check",
1181 notes => <<" NOTES");
1182 Takes a login session, user id, an org id, and an array of perm type strings. For each
1183 perm type, if the user does *not* have the given permission it is added
1184 to a list which is returned from the method. If all permissions
1185 are allowed, an empty list is returned
1186 if the logged in user does not match 'user_id', then the logged in user must
1187 have VIEW_PERMISSION priveleges.
1190 sub check_user_perms {
1191 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1193 my( $staff, $evt ) = $apputils->checkses($login_session);
1194 return $evt if $evt;
1196 if($staff->id ne $user_id) {
1197 if( $evt = $apputils->check_perms(
1198 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1204 for my $perm (@$perm_types) {
1205 if($apputils->check_perms($user_id, $org_id, $perm)) {
1206 push @not_allowed, $perm;
1210 return \@not_allowed
1213 __PACKAGE__->register_method(
1214 method => "check_user_perms2",
1215 api_name => "open-ils.actor.user.perm.check.multi_org",
1217 Checks the permissions on a list of perms and orgs for a user
1218 @param authtoken The login session key
1219 @param user_id The id of the user to check
1220 @param orgs The array of org ids
1221 @param perms The array of permission names
1222 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1223 if the logged in user does not match 'user_id', then the logged in user must
1224 have VIEW_PERMISSION priveleges.
1227 sub check_user_perms2 {
1228 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1230 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1231 $authtoken, $user_id, 'VIEW_PERMISSION' );
1232 return $evt if $evt;
1235 for my $org (@$orgs) {
1236 for my $perm (@$perms) {
1237 if($apputils->check_perms($user_id, $org, $perm)) {
1238 push @not_allowed, [ $org, $perm ];
1243 return \@not_allowed
1247 __PACKAGE__->register_method(
1248 method => 'check_user_perms3',
1249 api_name => 'open-ils.actor.user.perm.highest_org',
1251 Returns the highest org unit id at which a user has a given permission
1252 If the requestor does not match the target user, the requestor must have
1253 'VIEW_PERMISSION' rights at the home org unit of the target user
1254 @param authtoken The login session key
1255 @param userid The id of the user in question
1256 @param perm The permission to check
1257 @return The org unit highest in the org tree within which the user has
1258 the requested permission
1261 sub check_user_perms3 {
1262 my( $self, $client, $authtoken, $userid, $perm ) = @_;
1264 my( $staff, $target, $org, $evt );
1266 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1267 $authtoken, $userid, 'VIEW_PERMISSION' );
1268 return $evt if $evt;
1270 my $tree = $U->get_org_tree();
1271 return $U->find_highest_perm_org( $perm, $userid, $target->ws_ou, $tree );
1275 __PACKAGE__->register_method(
1276 method => 'check_user_work_perms',
1277 api_name => 'open-ils.actor.user.work_perm.highest_org_set',
1281 Returns a set of org units which represent the highest orgs in
1282 the org tree where the user has the requested permission. The
1283 purpose of this method is to return the smallest set of org units
1284 which represent the full expanse of the user's ability to perform
1285 the requested action. The user whose perms this method should
1286 check is implied by the authtoken. /,
1288 {desc => 'authtoken', type => 'string'},
1289 {desc => 'permission name', type => 'string'},
1290 {desc => 'options hash, including "descendants", which will include all child orgs of the found perm orgs', type => 'hash'}
1292 return => {desc => 'An array of org IDs'}
1296 sub check_user_work_perms {
1297 my($self, $conn, $auth, $perm, $options) = @_;
1298 my $e = new_editor(authtoken=>$auth);
1299 return $e->event unless $e->checkauth;
1300 return $U->find_highest_work_orgs($e, $perm, $options);
1303 __PACKAGE__->register_method(
1304 method => 'check_user_perms4',
1305 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1307 Returns the highest org unit id at which a user has a given permission
1308 If the requestor does not match the target user, the requestor must have
1309 'VIEW_PERMISSION' rights at the home org unit of the target user
1310 @param authtoken The login session key
1311 @param userid The id of the user in question
1312 @param perms An array of perm names to check
1313 @return An array of orgId's representing the org unit
1314 highest in the org tree within which the user has the requested permission
1315 The arrah of orgId's has matches the order of the perms array
1318 sub check_user_perms4 {
1319 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1321 my( $staff, $target, $org, $evt );
1323 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1324 $authtoken, $userid, 'VIEW_PERMISSION' );
1325 return $evt if $evt;
1328 return [] unless ref($perms);
1329 my $tree = $U->get_org_tree();
1331 for my $p (@$perms) {
1332 push( @arr, $U->find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1340 __PACKAGE__->register_method(
1341 method => "user_fines_summary",
1342 api_name => "open-ils.actor.user.fines.summary",
1343 notes => <<" NOTES");
1344 Returns a short summary of the users total open fines, excluding voided fines
1345 Params are login_session, user_id
1346 Returns a 'mous' object.
1349 sub user_fines_summary {
1350 my( $self, $client, $auth, $user_id ) = @_;
1351 my $e = new_editor(authtoken=>$auth);
1352 return $e->event unless $e->checkauth;
1353 my $user = $e->retrieve_actor_user($user_id)
1354 or return $e->event;
1356 if( $user_id ne $e->requestor->id ) {
1357 return $e->event unless
1358 $e->allowed('VIEW_USER_FINES_SUMMARY', $user->home_ou);
1361 # run this inside a transaction to prevent replication delay errors
1362 my $ses = $U->start_db_session();
1363 my $s = $ses->request(
1364 'open-ils.storage.money.open_user_summary.search', $user_id )->gather(1);
1365 $U->rollback_db_session($ses);
1372 __PACKAGE__->register_method(
1373 method => "user_transactions",
1374 api_name => "open-ils.actor.user.transactions",
1375 notes => <<" NOTES");
1376 Returns a list of open user transactions (mbts objects);
1377 Params are login_session, user_id
1378 Optional third parameter is the transactions type. defaults to all
1381 __PACKAGE__->register_method(
1382 method => "user_transactions",
1383 api_name => "open-ils.actor.user.transactions.have_charge",
1384 notes => <<" NOTES");
1385 Returns a list of all open user transactions (mbts objects) that have an initial charge
1386 Params are login_session, user_id
1387 Optional third parameter is the transactions type. defaults to all
1390 __PACKAGE__->register_method(
1391 method => "user_transactions",
1392 api_name => "open-ils.actor.user.transactions.have_balance",
1393 notes => <<" NOTES");
1394 Returns a list of all open user transactions (mbts objects) that have a balance
1395 Params are login_session, user_id
1396 Optional third parameter is the transactions type. defaults to all
1399 __PACKAGE__->register_method(
1400 method => "user_transactions",
1401 api_name => "open-ils.actor.user.transactions.fleshed",
1402 notes => <<" NOTES");
1403 Returns an object/hash of transaction, circ, title where transaction = an open
1404 user transactions (mbts objects), circ is the attached circluation, and title
1405 is the title the circ points to
1406 Params are login_session, user_id
1407 Optional third parameter is the transactions type. defaults to all
1410 __PACKAGE__->register_method(
1411 method => "user_transactions",
1412 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1413 notes => <<" NOTES");
1414 Returns an object/hash of transaction, circ, title where transaction = an open
1415 user transactions that has an initial charge (mbts objects), circ is the
1416 attached circluation, and title is the title the circ points to
1417 Params are login_session, user_id
1418 Optional third parameter is the transactions type. defaults to all
1421 __PACKAGE__->register_method(
1422 method => "user_transactions",
1423 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1424 notes => <<" NOTES");
1425 Returns an object/hash of transaction, circ, title where transaction = an open
1426 user transaction that has a balance (mbts objects), circ is the attached
1427 circluation, and title is the title the circ points to
1428 Params are login_session, user_id
1429 Optional third parameter is the transaction type. defaults to all
1432 __PACKAGE__->register_method(
1433 method => "user_transactions",
1434 api_name => "open-ils.actor.user.transactions.count",
1435 notes => <<" NOTES");
1436 Returns an object/hash of transaction, circ, title where transaction = an open
1437 user transactions (mbts objects), circ is the attached circluation, and title
1438 is the title the circ points to
1439 Params are login_session, user_id
1440 Optional third parameter is the transactions type. defaults to all
1443 __PACKAGE__->register_method(
1444 method => "user_transactions",
1445 api_name => "open-ils.actor.user.transactions.have_charge.count",
1446 notes => <<" NOTES");
1447 Returns an object/hash of transaction, circ, title where transaction = an open
1448 user transactions that has an initial charge (mbts objects), circ is the
1449 attached circluation, and title is the title the circ points to
1450 Params are login_session, user_id
1451 Optional third parameter is the transactions type. defaults to all
1454 __PACKAGE__->register_method(
1455 method => "user_transactions",
1456 api_name => "open-ils.actor.user.transactions.have_balance.count",
1457 notes => <<" NOTES");
1458 Returns an object/hash of transaction, circ, title where transaction = an open
1459 user transaction that has a balance (mbts objects), circ is the attached
1460 circluation, and title is the title the circ points to
1461 Params are login_session, user_id
1462 Optional third parameter is the transaction type. defaults to all
1465 __PACKAGE__->register_method(
1466 method => "user_transactions",
1467 api_name => "open-ils.actor.user.transactions.have_balance.total",
1468 notes => <<" NOTES");
1469 Returns an object/hash of transaction, circ, title where transaction = an open
1470 user transaction that has a balance (mbts objects), circ is the attached
1471 circluation, and title is the title the circ points to
1472 Params are login_session, user_id
1473 Optional third parameter is the transaction type. defaults to all
1478 sub user_transactions {
1479 my( $self, $client, $login_session, $user_id, $type ) = @_;
1481 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1482 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1483 return $evt if $evt;
1485 my $api = $self->api_name();
1489 if(defined($type)) { @xact = (xact_type => $type);
1491 } else { @xact = (); }
1494 ->method_lookup('open-ils.actor.user.transactions.history.still_open')
1495 ->run($login_session => $user_id => $type);
1497 if($api =~ /have_charge/o) {
1499 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1501 } elsif($api =~ /have_balance/o) {
1503 $trans = [ grep { int($_->balance_owed * 100) != 0 } @$trans ];
1506 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1510 if($api =~ /total/o) {
1512 for my $t (@$trans) {
1513 $total += $t->balance_owed;
1516 $logger->debug("Total balance owed by user $user_id: $total");
1520 if($api =~ /count/o) { return scalar @$trans; }
1521 if($api !~ /fleshed/o) { return $trans; }
1524 for my $t (@$trans) {
1526 if( $t->xact_type ne 'circulation' ) {
1527 push @resp, {transaction => $t};
1531 my $circ = $apputils->simple_scalar_request(
1533 "open-ils.cstore.direct.action.circulation.retrieve",
1538 my $title = $apputils->simple_scalar_request(
1540 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1541 $circ->target_copy );
1545 my $u = OpenILS::Utils::ModsParser->new();
1546 $u->start_mods_batch($title->marc());
1547 my $mods = $u->finish_mods_batch();
1548 $mods->doc_id($title->id) if $mods;
1550 push @resp, {transaction => $t, circ => $circ, record => $mods };
1558 __PACKAGE__->register_method(
1559 method => "user_transaction_retrieve",
1560 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1562 notes => <<" NOTES");
1563 Returns a fleshedtransaction record
1565 __PACKAGE__->register_method(
1566 method => "user_transaction_retrieve",
1567 api_name => "open-ils.actor.user.transaction.retrieve",
1569 notes => <<" NOTES");
1570 Returns a transaction record
1572 sub user_transaction_retrieve {
1573 my( $self, $client, $login_session, $bill_id ) = @_;
1575 # XXX I think I'm deprecated... make sure
1577 my $trans = $apputils->simple_scalar_request(
1579 "open-ils.cstore.direct.money.billable_transaction_summary.retrieve",
1583 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1584 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1585 return $evt if $evt;
1587 my $api = $self->api_name();
1588 if($api !~ /fleshed/o) { return $trans; }
1590 if( $trans->xact_type ne 'circulation' ) {
1591 $logger->debug("Returning non-circ transaction");
1592 return {transaction => $trans};
1595 my $circ = $apputils->simple_scalar_request(
1597 "open-ils..direct.action.circulation.retrieve",
1600 return {transaction => $trans} unless $circ;
1601 $logger->debug("Found the circ transaction");
1603 my $title = $apputils->simple_scalar_request(
1605 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1606 $circ->target_copy );
1608 return {transaction => $trans, circ => $circ } unless $title;
1609 $logger->debug("Found the circ title");
1613 my $u = OpenILS::Utils::ModsParser->new();
1614 $u->start_mods_batch($title->marc());
1615 $mods = $u->finish_mods_batch();
1617 if ($title->id == OILS_PRECAT_RECORD) {
1618 my $copy = $apputils->simple_scalar_request(
1620 "open-ils.cstore.direct.asset.copy.retrieve",
1621 $circ->target_copy );
1623 $mods = new Fieldmapper::metabib::virtual_record;
1624 $mods->doc_id(OILS_PRECAT_RECORD);
1625 $mods->title($copy->dummy_title);
1626 $mods->author($copy->dummy_author);
1630 $logger->debug("MODSized the circ title");
1632 return {transaction => $trans, circ => $circ, record => $mods };
1636 __PACKAGE__->register_method(
1637 method => "hold_request_count",
1638 api_name => "open-ils.actor.user.hold_requests.count",
1640 notes => <<" NOTES");
1641 Returns hold ready/total counts
1643 sub hold_request_count {
1644 my( $self, $client, $login_session, $userid ) = @_;
1646 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1647 $login_session, $userid, 'VIEW_HOLD' );
1648 return $evt if $evt;
1651 my $holds = $apputils->simple_scalar_request(
1653 "open-ils.cstore.direct.action.hold_request.search.atomic",
1656 fulfillment_time => {"=" => undef },
1657 cancel_time => undef,
1662 for my $h (@$holds) {
1663 next unless $h->capture_time and $h->current_copy;
1665 my $copy = $apputils->simple_scalar_request(
1667 "open-ils.cstore.direct.asset.copy.retrieve",
1671 if ($copy and $copy->status == 8) {
1676 return { total => scalar(@$holds), ready => scalar(@ready) };
1680 __PACKAGE__->register_method(
1681 method => "checkedout_count",
1682 api_name => "open-ils.actor.user.checked_out.count__",
1684 notes => <<" NOTES");
1685 Returns a transaction record
1689 sub checkedout_count {
1690 my( $self, $client, $login_session, $userid ) = @_;
1692 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1693 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1694 return $evt if $evt;
1696 my $circs = $apputils->simple_scalar_request(
1698 "open-ils.cstore.direct.action.circulation.search.atomic",
1699 { usr => $userid, stop_fines => undef }
1700 #{ usr => $userid, checkin_time => {"=" => undef } }
1703 my $parser = DateTime::Format::ISO8601->new;
1706 for my $c (@$circs) {
1707 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1708 my $due = $due_dt->epoch;
1710 if ($due < DateTime->today->epoch) {
1715 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1719 __PACKAGE__->register_method(
1720 method => "checked_out",
1721 api_name => "open-ils.actor.user.checked_out",
1724 Returns a structure of circulations objects sorted by
1725 out, overdue, lost, claims_returned, long_overdue.
1726 A list of IDs are returned of each type.
1727 lost, long_overdue, and claims_returned circ will not
1728 be "finished" (there is an outstanding balance or some
1729 other pending action on the circ).
1731 The .count method also includes a 'total' field which
1732 sums all "open" circs
1736 __PACKAGE__->register_method(
1737 method => "checked_out",
1738 api_name => "open-ils.actor.user.checked_out.count",
1740 signature => q/@see open-ils.actor.user.checked_out/
1744 my( $self, $conn, $auth, $userid ) = @_;
1746 my $e = new_editor(authtoken=>$auth);
1747 return $e->event unless $e->checkauth;
1749 if( $userid ne $e->requestor->id ) {
1750 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1753 my $count = $self->api_name =~ /count/;
1754 return _checked_out( $count, $e, $userid );
1758 my( $iscount, $e, $userid ) = @_;
1761 my $meth = 'open-ils.storage.actor.user.checked_out';
1762 $meth = "$meth.count" if $iscount;
1763 return $U->storagereq($meth, $userid);
1765 # XXX Old code - moved to storage
1766 #------------------------------------------------------------------------------
1767 #------------------------------------------------------------------------------
1768 my $circs = $e->search_action_circulation(
1769 { usr => $userid, checkin_time => undef });
1771 my $parser = DateTime::Format::ISO8601->new;
1773 # split the circs up into overdue and not-overdue circs
1775 for my $c (@$circs) {
1776 if( $c->due_date ) {
1777 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1778 my $due = $due_dt->epoch;
1779 if ($due < DateTime->today->epoch) {
1789 my( @open, @od, @lost, @cr, @lo );
1791 while (my $c = shift(@out)) {
1792 push( @open, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1793 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1794 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1795 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1798 while (my $c = shift(@overdue)) {
1799 push( @od, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1800 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1801 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1802 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1807 total => @open + @od + @lost + @cr + @lo,
1808 out => scalar(@open),
1809 overdue => scalar(@od),
1810 lost => scalar(@lost),
1811 claims_returned => scalar(@cr),
1812 long_overdue => scalar(@lo)
1820 claims_returned => \@cr,
1821 long_overdue => \@lo
1826 sub _checked_out_WHAT {
1827 my( $iscount, $e, $userid ) = @_;
1829 my $circs = $e->search_action_circulation(
1830 { usr => $userid, stop_fines => undef });
1832 my $mcircs = $e->search_action_circulation(
1835 checkin_time => undef,
1836 xact_finish => undef,
1840 push( @$circs, @$mcircs );
1842 my $parser = DateTime::Format::ISO8601->new;
1844 # split the circs up into overdue and not-overdue circs
1846 for my $c (@$circs) {
1847 if( $c->due_date ) {
1848 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1849 my $due = $due_dt->epoch;
1850 if ($due < DateTime->today->epoch) {
1851 push @overdue, $c->id;
1860 # grab all of the lost, claims-returned, and longoverdue circs
1861 #my $open = $e->search_action_circulation(
1862 # {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1865 # these items have stop_fines, but no xact_finish, so money
1866 # is owed on them and they have not been checked in
1867 my $open = $e->search_action_circulation(
1870 stop_fines => { in => [ qw/LOST CLAIMSRETURNED LONGOVERDUE/ ] },
1871 xact_finish => undef,
1872 checkin_time => undef,
1877 my( @lost, @cr, @lo );
1878 for my $c (@$open) {
1879 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1880 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1881 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1887 total => @$circs + @lost + @cr + @lo,
1888 out => scalar(@out),
1889 overdue => scalar(@overdue),
1890 lost => scalar(@lost),
1891 claims_returned => scalar(@cr),
1892 long_overdue => scalar(@lo)
1898 overdue => \@overdue,
1900 claims_returned => \@cr,
1901 long_overdue => \@lo
1907 __PACKAGE__->register_method(
1908 method => "checked_in_with_fines",
1909 api_name => "open-ils.actor.user.checked_in_with_fines",
1911 signature => q/@see open-ils.actor.user.checked_out/
1913 sub checked_in_with_fines {
1914 my( $self, $conn, $auth, $userid ) = @_;
1916 my $e = new_editor(authtoken=>$auth);
1917 return $e->event unless $e->checkauth;
1919 if( $userid ne $e->requestor->id ) {
1920 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1923 # money is owed on these items and they are checked in
1924 my $open = $e->search_action_circulation(
1927 xact_finish => undef,
1928 checkin_time => { "!=" => undef },
1933 my( @lost, @cr, @lo );
1934 for my $c (@$open) {
1935 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1936 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1937 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1942 claims_returned => \@cr,
1943 long_overdue => \@lo
1955 __PACKAGE__->register_method(
1956 method => "user_transaction_history",
1957 api_name => "open-ils.actor.user.transactions.history",
1959 notes => <<" NOTES");
1960 Returns a list of billable transaction ids for a user, optionally by type
1962 __PACKAGE__->register_method(
1963 method => "user_transaction_history",
1964 api_name => "open-ils.actor.user.transactions.history.have_charge",
1966 notes => <<" NOTES");
1967 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
1969 __PACKAGE__->register_method(
1970 method => "user_transaction_history",
1971 api_name => "open-ils.actor.user.transactions.history.have_balance",
1973 notes => <<" NOTES");
1974 Returns a list of billable transaction ids for a user that have a balance, optionally by type
1976 __PACKAGE__->register_method(
1977 method => "user_transaction_history",
1978 api_name => "open-ils.actor.user.transactions.history.still_open",
1980 notes => <<" NOTES");
1981 Returns a list of billable transaction ids for a user that are not finished
1983 __PACKAGE__->register_method(
1984 method => "user_transaction_history",
1985 api_name => "open-ils.actor.user.transactions.history.have_bill",
1987 notes => <<" NOTES");
1988 Returns a list of billable transaction ids for a user that has billings
1994 sub _user_transaction_history {
1995 my( $self, $client, $login_session, $user_id, $type ) = @_;
1997 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1998 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1999 return $evt if $evt;
2001 my $api = $self->api_name();
2006 @xact = (xact_type => $type) if(defined($type));
2007 @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
2008 @charge = (last_billing_ts => { "<>" => undef }) if $api =~ /have_charge/;
2010 $logger->debug("searching for transaction history: @xact : @balance, @charge");
2012 my $trans = $apputils->simple_scalar_request(
2014 "open-ils.cstore.direct.money.billable_transaction_summary.search.atomic",
2015 { usr => $user_id, @xact, @charge, @balance }, { order_by => { mbts => 'xact_start DESC' } });
2017 return [ map { $_->id } @$trans ];
2021 =head SEE APPUTILS.PM
2026 for my $x (@xacts) {
2027 my $s = new Fieldmapper::money::billable_transaction_summary;
2030 $s->xact_start( $x->xact_start );
2031 $s->xact_finish( $x->xact_finish );
2035 for my $b (@{ $x->billings }) {
2036 next if ($U->is_true($b->voided));
2037 $to += ($b->amount * 100);
2038 $lb ||= $b->billing_ts;
2039 if ($b->billing_ts ge $lb) {
2040 $lb = $b->billing_ts;
2041 $s->last_billing_note($b->note);
2042 $s->last_billing_ts($b->billing_ts);
2043 $s->last_billing_type($b->billing_type);
2047 $s->total_owed( sprintf('%0.2f', $to / 100 ) );
2051 for my $p (@{ $x->payments }) {
2052 next if ($U->is_true($p->voided));
2053 $tp += ($p->amount * 100);
2054 $lp ||= $p->payment_ts;
2055 if ($p->payment_ts ge $lp) {
2056 $lp = $p->payment_ts;
2057 $s->last_payment_note($p->note);
2058 $s->last_payment_ts($p->payment_ts);
2059 $s->last_payment_type($p->payment_type);
2062 $s->total_paid( sprintf('%0.2f', $tp / 100 ) );
2064 $s->balance_owed( sprintf('%0.2f', ($to - $tp) / 100) );
2066 $s->xact_type( 'grocery' ) if ($x->grocery);
2067 $s->xact_type( 'circulation' ) if ($x->circulation);
2076 sub user_transaction_history {
2077 my( $self, $conn, $auth, $userid, $type ) = @_;
2079 # run inside of a transaction to prevent replication delays
2080 my $e = new_editor(xact=>1, authtoken=>$auth);
2081 return $e->die_event unless $e->checkauth;
2083 if( $e->requestor->id ne $userid ) {
2084 return $e->die_event
2085 unless $e->allowed('VIEW_USER_TRANSACTIONS');
2088 my $api = $self->api_name;
2089 my @xact_finish = (xact_finish => undef ) if ($api =~ /history.still_open$/);
2091 my @xacts = @{ $e->search_money_billable_transaction(
2092 [ { usr => $userid, @xact_finish },
2094 flesh_fields => { mbt => [ qw/billings payments grocery circulation/ ] },
2095 order_by => { mbt => 'xact_start DESC' },
2103 #my @mbts = _make_mbts( @xacts );
2104 my @mbts = $U->make_mbts( @xacts );
2106 if(defined($type)) {
2107 @mbts = grep { $_->xact_type eq $type } @mbts;
2110 if($api =~ /have_balance/o) {
2111 @mbts = grep { int($_->balance_owed * 100) != 0 } @mbts;
2114 if($api =~ /have_charge/o) {
2115 @mbts = grep { defined($_->last_billing_ts) } @mbts;
2118 if($api =~ /have_bill/o) {
2119 @mbts = grep { int($_->total_owed * 100) != 0 } @mbts;
2127 __PACKAGE__->register_method(
2128 method => "user_perms",
2129 api_name => "open-ils.actor.permissions.user_perms.retrieve",
2131 notes => <<" NOTES");
2132 Returns a list of permissions
2135 my( $self, $client, $authtoken, $user ) = @_;
2137 my( $staff, $evt ) = $apputils->checkses($authtoken);
2138 return $evt if $evt;
2140 $user ||= $staff->id;
2142 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
2146 return $apputils->simple_scalar_request(
2148 "open-ils.storage.permission.user_perms.atomic",
2152 __PACKAGE__->register_method(
2153 method => "retrieve_perms",
2154 api_name => "open-ils.actor.permissions.retrieve",
2155 notes => <<" NOTES");
2156 Returns a list of permissions
2158 sub retrieve_perms {
2159 my( $self, $client ) = @_;
2160 return $apputils->simple_scalar_request(
2162 "open-ils.cstore.direct.permission.perm_list.search.atomic",
2163 { id => { '!=' => undef } }
2167 __PACKAGE__->register_method(
2168 method => "retrieve_groups",
2169 api_name => "open-ils.actor.groups.retrieve",
2170 notes => <<" NOTES");
2171 Returns a list of user groupss
2173 sub retrieve_groups {
2174 my( $self, $client ) = @_;
2175 return new_editor()->retrieve_all_permission_grp_tree();
2178 __PACKAGE__->register_method(
2179 method => "retrieve_org_address",
2180 api_name => "open-ils.actor.org_unit.address.retrieve",
2181 notes => <<' NOTES');
2182 Returns an org_unit address by ID
2183 @param An org_address ID
2185 sub retrieve_org_address {
2186 my( $self, $client, $id ) = @_;
2187 return $apputils->simple_scalar_request(
2189 "open-ils.cstore.direct.actor.org_address.retrieve",
2194 __PACKAGE__->register_method(
2195 method => "retrieve_groups_tree",
2196 api_name => "open-ils.actor.groups.tree.retrieve",
2197 notes => <<" NOTES");
2198 Returns a list of user groups
2200 sub retrieve_groups_tree {
2201 my( $self, $client ) = @_;
2202 return new_editor()->search_permission_grp_tree(
2207 flesh_fields => { pgt => ["children"] },
2208 order_by => { pgt => 'name'}
2215 # turns an org list into an org tree
2217 sub build_group_tree {
2219 my( $self, $grplist) = @_;
2221 return $grplist unless (
2222 ref($grplist) and @$grplist > 1 );
2224 my @list = sort { $a->name cmp $b->name } @$grplist;
2227 for my $grp (@list) {
2229 if ($grp and !defined($grp->parent)) {
2233 my ($parent) = grep { $_->id == $grp->parent} @list;
2235 $parent->children([]) unless defined($parent->children);
2236 push( @{$parent->children}, $grp );
2244 __PACKAGE__->register_method(
2245 method => "add_user_to_groups",
2246 api_name => "open-ils.actor.user.set_groups",
2247 notes => <<" NOTES");
2248 Adds a user to one or more permission groups
2251 sub add_user_to_groups {
2252 my( $self, $client, $authtoken, $userid, $groups ) = @_;
2254 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2255 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
2256 return $evt if $evt;
2258 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2259 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
2260 return $evt if $evt;
2262 $apputils->simplereq(
2264 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
2266 for my $group (@$groups) {
2267 my $link = Fieldmapper::permission::usr_grp_map->new;
2269 $link->usr($userid);
2271 my $id = $apputils->simplereq(
2273 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2279 __PACKAGE__->register_method(
2280 method => "get_user_perm_groups",
2281 api_name => "open-ils.actor.user.get_groups",
2282 notes => <<" NOTES");
2283 Retrieve a user's permission groups.
2287 sub get_user_perm_groups {
2288 my( $self, $client, $authtoken, $userid ) = @_;
2290 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2291 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2292 return $evt if $evt;
2294 return $apputils->simplereq(
2296 'open-ils.cstore.direct.permission.usr_grp_map.search.atomic', { usr => $userid } );
2300 __PACKAGE__->register_method(
2301 method => "get_user_work_ous",
2302 api_name => "open-ils.actor.user.get_work_ous",
2303 notes => <<" NOTES");
2304 Retrieve a user's work org units.
2306 __PACKAGE__->register_method(
2307 method => "get_user_work_ous",
2308 api_name => "open-ils.actor.user.get_work_ous.ids",
2309 notes => <<" NOTES");
2310 Retrieve a user's work org units.
2314 sub get_user_work_ous {
2315 my( $self, $client, $auth, $userid ) = @_;
2316 my $e = new_editor(authtoken=>$auth);
2317 return $e->event unless $e->checkauth;
2318 $userid ||= $e->requestor->id;
2320 if($e->requestor->id != $userid) {
2321 my $user = $e->retrieve_actor_user($userid)
2322 or return $e->event;
2323 return $e->event unless $e->allowed('ASSIGN_WORK_ORG_UNIT', $user->home_ou);
2326 return $e->search_permission_usr_work_ou_map({usr => $userid})
2327 unless $self->api_name =~ /.ids$/;
2329 # client just wants a list of org IDs
2330 return $U->get_user_work_ou_ids($e, $userid);
2336 __PACKAGE__->register_method (
2337 method => 'register_workstation',
2338 api_name => 'open-ils.actor.workstation.register.override',
2339 signature => q/@see open-ils.actor.workstation.register/);
2341 __PACKAGE__->register_method (
2342 method => 'register_workstation',
2343 api_name => 'open-ils.actor.workstation.register',
2345 Registers a new workstion in the system
2346 @param authtoken The login session key
2347 @param name The name of the workstation id
2348 @param owner The org unit that owns this workstation
2349 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2350 if the name is already in use.
2353 sub register_workstation {
2354 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2356 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2357 return $e->die_event unless $e->checkauth;
2358 return $e->die_event unless $e->allowed('REGISTER_WORKSTATION', $owner);
2359 my $existing = $e->search_actor_workstation({name => $name})->[0];
2363 if( $self->api_name =~ /override/o ) {
2364 # workstation with the given name exists.
2366 if($owner ne $existing->owning_lib) {
2367 # if necessary, update the owning_lib of the workstation
2369 $logger->info("changing owning lib of workstation ".$existing->id.
2370 " from ".$existing->owning_lib." to $owner");
2371 return $e->die_event unless
2372 $e->allowed('UPDATE_WORKSTATION', $existing->owning_lib);
2374 return $e->die_event unless $e->allowed('UPDATE_WORKSTATION', $owner);
2376 $existing->owning_lib($owner);
2377 return $e->die_event unless $e->update_actor_workstation($existing);
2383 "attempt to register an existing workstation. returning existing ID");
2386 return $existing->id;
2389 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2393 my $ws = Fieldmapper::actor::workstation->new;
2394 $ws->owning_lib($owner);
2396 $e->create_actor_workstation($ws) or return $e->die_event;
2398 return $ws->id; # note: editor sets the id on the new object for us
2401 __PACKAGE__->register_method (
2402 method => 'workstation_list',
2403 api_name => 'open-ils.actor.workstation.list',
2405 Returns a list of workstations registered at the given location
2406 @param authtoken The login session key
2407 @param ids A list of org_unit.id's for the workstation owners
2410 sub workstation_list {
2411 my( $self, $conn, $authtoken, @orgs ) = @_;
2413 my $e = new_editor(authtoken=>$authtoken);
2414 return $e->event unless $e->checkauth;
2419 unless $e->allowed('REGISTER_WORKSTATION', $o);
2420 $results{$o} = $e->search_actor_workstation({owning_lib=>$o});
2431 __PACKAGE__->register_method (
2432 method => 'fetch_patron_note',
2433 api_name => 'open-ils.actor.note.retrieve.all',
2435 Returns a list of notes for a given user
2436 Requestor must have VIEW_USER permission if pub==false and
2437 @param authtoken The login session key
2438 @param args Hash of params including
2439 patronid : the patron's id
2440 pub : true if retrieving only public notes
2444 sub fetch_patron_note {
2445 my( $self, $conn, $authtoken, $args ) = @_;
2446 my $patronid = $$args{patronid};
2448 my($reqr, $evt) = $U->checkses($authtoken);
2449 return $evt if $evt;
2452 ($patron, $evt) = $U->fetch_user($patronid);
2453 return $evt if $evt;
2456 if( $patronid ne $reqr->id ) {
2457 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2458 return $evt if $evt;
2460 return $U->cstorereq(
2461 'open-ils.cstore.direct.actor.usr_note.search.atomic',
2462 { usr => $patronid, pub => 't' } );
2465 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2466 return $evt if $evt;
2468 return $U->cstorereq(
2469 'open-ils.cstore.direct.actor.usr_note.search.atomic', { usr => $patronid } );
2472 __PACKAGE__->register_method (
2473 method => 'create_user_note',
2474 api_name => 'open-ils.actor.note.create',
2476 Creates a new note for the given user
2477 @param authtoken The login session key
2478 @param note The note object
2481 sub create_user_note {
2482 my( $self, $conn, $authtoken, $note ) = @_;
2483 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2484 return $e->die_event unless $e->checkauth;
2486 my $user = $e->retrieve_actor_user($note->usr)
2487 or return $e->die_event;
2489 return $e->die_event unless
2490 $e->allowed('UPDATE_USER',$user->home_ou);
2492 $note->creator($e->requestor->id);
2493 $e->create_actor_usr_note($note) or return $e->die_event;
2499 __PACKAGE__->register_method (
2500 method => 'delete_user_note',
2501 api_name => 'open-ils.actor.note.delete',
2503 Deletes a note for the given user
2504 @param authtoken The login session key
2505 @param noteid The note id
2508 sub delete_user_note {
2509 my( $self, $conn, $authtoken, $noteid ) = @_;
2511 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2512 return $e->die_event unless $e->checkauth;
2513 my $note = $e->retrieve_actor_usr_note($noteid)
2514 or return $e->die_event;
2515 my $user = $e->retrieve_actor_user($note->usr)
2516 or return $e->die_event;
2517 return $e->die_event unless
2518 $e->allowed('UPDATE_USER', $user->home_ou);
2520 $e->delete_actor_usr_note($note) or return $e->die_event;
2526 __PACKAGE__->register_method (
2527 method => 'update_user_note',
2528 api_name => 'open-ils.actor.note.update',
2530 @param authtoken The login session key
2531 @param note The note
2535 sub update_user_note {
2536 my( $self, $conn, $auth, $note ) = @_;
2537 my $e = new_editor(authtoken=>$auth, xact=>1);
2538 return $e->event unless $e->checkauth;
2539 my $patron = $e->retrieve_actor_user($note->usr)
2540 or return $e->event;
2541 return $e->event unless
2542 $e->allowed('UPDATE_USER', $patron->home_ou);
2543 $e->update_actor_user_note($note)
2544 or return $e->event;
2552 __PACKAGE__->register_method (
2553 method => 'create_closed_date',
2554 api_name => 'open-ils.actor.org_unit.closed_date.create',
2556 Creates a new closing entry for the given org_unit
2557 @param authtoken The login session key
2558 @param note The closed_date object
2561 sub create_closed_date {
2562 my( $self, $conn, $authtoken, $cd ) = @_;
2564 my( $user, $evt ) = $U->checkses($authtoken);
2565 return $evt if $evt;
2567 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2568 return $evt if $evt;
2570 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2572 my $id = $U->storagereq(
2573 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2574 return $U->DB_UPDATE_FAILED($cd) unless $id;
2579 __PACKAGE__->register_method (
2580 method => 'delete_closed_date',
2581 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2583 Deletes a closing entry for the given org_unit
2584 @param authtoken The login session key
2585 @param noteid The close_date id
2588 sub delete_closed_date {
2589 my( $self, $conn, $authtoken, $cd ) = @_;
2591 my( $user, $evt ) = $U->checkses($authtoken);
2592 return $evt if $evt;
2595 ($cd_obj, $evt) = fetch_closed_date($cd);
2596 return $evt if $evt;
2598 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2599 return $evt if $evt;
2601 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2603 my $stat = $U->storagereq(
2604 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2605 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2610 __PACKAGE__->register_method(
2611 method => 'usrname_exists',
2612 api_name => 'open-ils.actor.username.exists',
2614 Returns 1 if the requested username exists, returns 0 otherwise
2618 sub usrname_exists {
2619 my( $self, $conn, $auth, $usrname ) = @_;
2620 my $e = new_editor(authtoken=>$auth);
2621 return $e->event unless $e->checkauth;
2622 my $a = $e->search_actor_user({usrname => $usrname, deleted=>'f'}, {idlist=>1});
2623 return $$a[0] if $a and @$a;
2627 __PACKAGE__->register_method(
2628 method => 'barcode_exists',
2629 api_name => 'open-ils.actor.barcode.exists',
2631 Returns 1 if the requested barcode exists, returns 0 otherwise
2635 sub barcode_exists {
2636 my( $self, $conn, $auth, $barcode ) = @_;
2637 my $e = new_editor(authtoken=>$auth);
2638 return $e->event unless $e->checkauth;
2639 my $card = $e->search_actor_card({barcode => $barcode});
2640 return undef unless @$card;
2641 return $card->[0]->usr;
2645 __PACKAGE__->register_method(
2646 method => 'retrieve_net_levels',
2647 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2650 sub retrieve_net_levels {
2651 my( $self, $conn, $auth ) = @_;
2652 my $e = new_editor(authtoken=>$auth);
2653 return $e->event unless $e->checkauth;
2654 return $e->retrieve_all_config_net_access_level();
2658 __PACKAGE__->register_method(
2659 method => 'fetch_org_by_shortname',
2660 api_name => 'open-ils.actor.org_unit.retrieve_by_shorname',
2662 sub fetch_org_by_shortname {
2663 my( $self, $conn, $sname ) = @_;
2664 my $e = new_editor();
2665 my $org = $e->search_actor_org_unit({ shortname => uc($sname)})->[0];
2666 return $e->event unless $org;
2671 __PACKAGE__->register_method(
2672 method => 'session_home_lib',
2673 api_name => 'open-ils.actor.session.home_lib',
2676 sub session_home_lib {
2677 my( $self, $conn, $auth ) = @_;
2678 my $e = new_editor(authtoken=>$auth);
2679 return undef unless $e->checkauth;
2680 my $org = $e->retrieve_actor_org_unit($e->requestor->home_ou);
2681 return $org->shortname;
2684 __PACKAGE__->register_method(
2685 method => 'session_safe_token',
2686 api_name => 'open-ils.actor.session.safe_token',
2688 Returns a hashed session ID that is safe for export to the world.
2689 This safe token will expire after 1 hour of non-use.
2690 @param auth Active authentication token
2694 sub session_safe_token {
2695 my( $self, $conn, $auth ) = @_;
2696 my $e = new_editor(authtoken=>$auth);
2697 return undef unless $e->checkauth;
2699 my $safe_token = md5_hex($auth);
2701 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2703 # Add more like the following if needed...
2705 "safe-token-home_lib-shortname-$safe_token",
2706 $e->retrieve_actor_org_unit(
2707 $e->requestor->home_ou
2716 __PACKAGE__->register_method(
2717 method => 'safe_token_home_lib',
2718 api_name => 'open-ils.actor.safe_token.home_lib.shortname',
2720 Returns the home library shortname from the session
2721 asscociated with a safe token from generated by
2722 open-ils.actor.session.safe_token.
2723 @param safe_token Active safe token
2727 sub safe_token_home_lib {
2728 my( $self, $conn, $safe_token ) = @_;
2730 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2731 return $cache->get_cache( 'safe-token-home_lib-shortname-'. $safe_token );
2736 __PACKAGE__->register_method(
2737 method => 'slim_tree',
2738 api_name => "open-ils.actor.org_tree.slim_hash.retrieve",
2741 my $tree = new_editor()->search_actor_org_unit(
2743 {"parent_ou" => undef },
2746 flesh_fields => { aou => ['children'] },
2747 order_by => { aou => 'name'},
2748 select => { aou => ["id","shortname", "name"]},
2753 return trim_tree($tree);
2759 return undef unless $tree;
2761 code => $tree->shortname,
2762 name => $tree->name,
2764 if( $tree->children and @{$tree->children} ) {
2765 $htree->{children} = [];
2766 for my $c (@{$tree->children}) {
2767 push( @{$htree->{children}}, trim_tree($c) );
2775 __PACKAGE__->register_method(
2776 method => "update_penalties",
2777 api_name => "open-ils.actor.user.penalties.update");
2778 sub update_penalties {
2779 my( $self, $conn, $auth, $userid ) = @_;
2780 my $e = new_editor(authtoken=>$auth);
2781 return $e->event unless $e->checkauth;
2782 $U->update_patron_penalties(
2784 patronid => $userid,
2791 __PACKAGE__->register_method(
2792 method => "user_retrieve_fleshed_by_id",
2793 api_name => "open-ils.actor.user.fleshed.retrieve",);
2795 sub user_retrieve_fleshed_by_id {
2796 my( $self, $client, $auth, $user_id, $fields ) = @_;
2797 my $e = new_editor(authtoken => $auth);
2798 return $e->event unless $e->checkauth;
2800 if( $e->requestor->id != $user_id ) {
2801 return $e->event unless $e->allowed('VIEW_USER');
2807 "standing_penalties",
2811 "stat_cat_entries" ];
2812 return new_flesh_user($user_id, $fields, $e);
2816 sub new_flesh_user {
2819 my $fields = shift || [];
2820 my $e = shift || new_editor(xact=>1);
2822 my $user = $e->retrieve_actor_user(
2827 "flesh_fields" => { "au" => $fields }
2830 ) or return $e->event;
2833 if( grep { $_ eq 'addresses' } @$fields ) {
2835 $user->addresses([]) unless @{$user->addresses};
2837 if( ref $user->billing_address ) {
2838 unless( grep { $user->billing_address->id == $_->id } @{$user->addresses} ) {
2839 push( @{$user->addresses}, $user->billing_address );
2843 if( ref $user->mailing_address ) {
2844 unless( grep { $user->mailing_address->id == $_->id } @{$user->addresses} ) {
2845 push( @{$user->addresses}, $user->mailing_address );
2851 $user->clear_passwd();
2858 __PACKAGE__->register_method(
2859 method => "user_retrieve_parts",
2860 api_name => "open-ils.actor.user.retrieve.parts",);
2862 sub user_retrieve_parts {
2863 my( $self, $client, $auth, $user_id, $fields ) = @_;
2864 my $e = new_editor(authtoken => $auth);
2865 return $e->event unless $e->checkauth;
2866 if( $e->requestor->id != $user_id ) {
2867 return $e->event unless $e->allowed('VIEW_USER');
2870 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2871 push(@resp, $user->$_()) for(@$fields);
2877 __PACKAGE__->register_method(
2878 method => 'user_opt_in_enabled',
2879 api_name => 'open-ils.actor.user.org_unit_opt_in.enabled',
2881 @return 1 if user opt-in is globally enabled, 0 otherwise.
2884 sub user_opt_in_enabled {
2885 my($self, $conn) = @_;
2886 my $sc = OpenSRF::Utils::SettingsClient->new;
2887 return 1 if lc($sc->config_value(share => user => 'opt_in')) eq 'true';
2892 __PACKAGE__->register_method(
2893 method => 'user_opt_in_at_org',
2894 api_name => 'open-ils.actor.user.org_unit_opt_in.check',
2896 @param $auth The auth token
2897 @param user_id The ID of the user to test
2898 @return 1 if the user has opted in at the specified org,
2899 event on error, and 0 otherwise. /);
2900 sub user_opt_in_at_org {
2901 my($self, $conn, $auth, $user_id) = @_;
2903 # see if we even need to enforce the opt-in value
2904 return 1 unless user_opt_in_enabled($self);
2906 my $e = new_editor(authtoken => $auth);
2907 return $e->event unless $e->checkauth;
2908 my $org_id = $e->requestor->ws_ou;
2910 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2911 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
2913 # user is automatically opted-in at the home org
2914 return 1 if $user->home_ou eq $org_id;
2916 my $vals = $e->search_actor_usr_org_unit_opt_in(
2917 {org_unit=>$org_id, usr=>$user_id},{idlist=>1});
2923 __PACKAGE__->register_method(
2924 method => 'create_user_opt_in_at_org',
2925 api_name => 'open-ils.actor.user.org_unit_opt_in.create',
2927 @param $auth The auth token
2928 @param user_id The ID of the user to test
2929 @return The ID of the newly created object, event on error./);
2931 sub create_user_opt_in_at_org {
2932 my($self, $conn, $auth, $user_id) = @_;
2934 my $e = new_editor(authtoken => $auth, xact=>1);
2935 return $e->die_event unless $e->checkauth;
2936 my $org_id = $e->requestor->ws_ou;
2938 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
2939 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2941 my $opt_in = Fieldmapper::actor::usr_org_unit_opt_in->new;
2943 $opt_in->org_unit($org_id);
2944 $opt_in->usr($user_id);
2945 $opt_in->staff($e->requestor->id);
2946 $opt_in->opt_in_ts('now');
2947 $opt_in->opt_in_ws($e->requestor->wsid);
2949 $opt_in = $e->create_actor_usr_org_unit_opt_in($opt_in)
2950 or return $e->die_event;