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",
918 api_name => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
920 sub user_retrieve_by_barcode {
921 my($self, $client, $user_session, $barcode) = @_;
923 $logger->debug("Searching for user with barcode $barcode");
924 my ($user_obj, $evt) = $apputils->checkses($user_session);
927 my $card = OpenILS::Application::AppUtils->simple_scalar_request(
929 "open-ils.cstore.direct.actor.card.search.atomic",
930 { barcode => $barcode }
933 if(!$card || !$card->[0]) {
934 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' );
938 my $user = flesh_user($card->usr());
940 $evt = $U->check_perms($user_obj->id, $user->home_ou, 'VIEW_USER');
943 if(!$user) { return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ); }
950 __PACKAGE__->register_method(
951 method => "get_user_by_id",
952 api_name => "open-ils.actor.user.retrieve",);
955 my ($self, $client, $auth, $id) = @_;
956 my $e = new_editor(authtoken=>$auth);
957 return $e->event unless $e->checkauth;
958 my $user = $e->retrieve_actor_user($id)
960 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
966 __PACKAGE__->register_method(
967 method => "get_org_types",
968 api_name => "open-ils.actor.org_types.retrieve",);
971 return $U->get_org_types();
976 __PACKAGE__->register_method(
977 method => "get_user_ident_types",
978 api_name => "open-ils.actor.user.ident_types.retrieve",
981 sub get_user_ident_types {
982 return $ident_types if $ident_types;
983 return $ident_types =
984 new_editor()->retrieve_all_config_identification_type();
990 __PACKAGE__->register_method(
991 method => "get_org_unit",
992 api_name => "open-ils.actor.org_unit.retrieve",
996 my( $self, $client, $user_session, $org_id ) = @_;
997 my $e = new_editor(authtoken => $user_session);
999 return $e->event unless $e->checkauth;
1000 $org_id = $e->requestor->ws_ou;
1002 my $o = $e->retrieve_actor_org_unit($org_id)
1003 or return $e->event;
1007 __PACKAGE__->register_method(
1008 method => "search_org_unit",
1009 api_name => "open-ils.actor.org_unit_list.search",
1012 sub search_org_unit {
1014 my( $self, $client, $field, $value ) = @_;
1016 my $list = OpenILS::Application::AppUtils->simple_scalar_request(
1018 "open-ils.cstore.direct.actor.org_unit.search.atomic",
1019 { $field => $value } );
1025 # build the org tree
1027 __PACKAGE__->register_method(
1028 method => "get_org_tree",
1029 api_name => "open-ils.actor.org_tree.retrieve",
1031 note => "Returns the entire org tree structure",
1035 my( $self, $client) = @_;
1036 return $U->get_org_tree();
1040 __PACKAGE__->register_method(
1041 method => "get_org_descendants",
1042 api_name => "open-ils.actor.org_tree.descendants.retrieve"
1045 # depth is optional. org_unit is the id
1046 sub get_org_descendants {
1047 my( $self, $client, $org_unit, $depth ) = @_;
1048 my $orglist = $apputils->simple_scalar_request(
1050 "open-ils.storage.actor.org_unit.descendants.atomic",
1051 $org_unit, $depth );
1052 return $U->build_org_tree($orglist);
1056 __PACKAGE__->register_method(
1057 method => "get_org_ancestors",
1058 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
1061 # depth is optional. org_unit is the id
1062 sub get_org_ancestors {
1063 my( $self, $client, $org_unit, $depth ) = @_;
1064 my $orglist = $apputils->simple_scalar_request(
1066 "open-ils.storage.actor.org_unit.ancestors.atomic",
1067 $org_unit, $depth );
1068 return $U->build_org_tree($orglist);
1072 __PACKAGE__->register_method(
1073 method => "get_standings",
1074 api_name => "open-ils.actor.standings.retrieve"
1079 return $user_standings if $user_standings;
1080 return $user_standings =
1081 $apputils->simple_scalar_request(
1083 "open-ils.cstore.direct.config.standing.search.atomic",
1084 { id => { "!=" => undef } }
1090 __PACKAGE__->register_method(
1091 method => "get_my_org_path",
1092 api_name => "open-ils.actor.org_unit.full_path.retrieve"
1095 sub get_my_org_path {
1096 my( $self, $client, $auth, $org_id ) = @_;
1097 my $e = new_editor(authtoken=>$auth);
1098 return $e->event unless $e->checkauth;
1099 $org_id = $e->requestor->ws_ou unless defined $org_id;
1101 return $apputils->simple_scalar_request(
1103 "open-ils.storage.actor.org_unit.full_path.atomic",
1108 __PACKAGE__->register_method(
1109 method => "patron_adv_search",
1110 api_name => "open-ils.actor.patron.search.advanced" );
1111 sub patron_adv_search {
1112 my( $self, $client, $auth, $search_hash,
1113 $search_limit, $search_sort, $include_inactive, $search_depth ) = @_;
1115 my $e = new_editor(authtoken=>$auth);
1116 return $e->event unless $e->checkauth;
1117 return $e->event unless $e->allowed('VIEW_USER');
1118 return $U->storagereq(
1119 "open-ils.storage.actor.user.crazy_search", $search_hash,
1120 $search_limit, $search_sort, $include_inactive, $e->requestor->ws_ou, $search_depth);
1124 __PACKAGE__->register_method(
1125 method => "update_passwd",
1127 api_name => "open-ils.actor.user.password.update");
1129 __PACKAGE__->register_method(
1130 method => "update_passwd",
1131 api_name => "open-ils.actor.user.username.update");
1133 __PACKAGE__->register_method(
1134 method => "update_passwd",
1135 api_name => "open-ils.actor.user.email.update");
1138 my( $self, $conn, $auth, $new_val, $orig_pw ) = @_;
1139 my $e = new_editor(xact=>1, authtoken=>$auth);
1140 return $e->die_event unless $e->checkauth;
1142 my $db_user = $e->retrieve_actor_user($e->requestor->id)
1143 or return $e->die_event;
1144 my $api = $self->api_name;
1146 if( $api =~ /password/o ) {
1148 # make sure the original password matches the in-database password
1149 return OpenILS::Event->new('INCORRECT_PASSWORD')
1150 if md5_hex($orig_pw) ne $db_user->passwd;
1151 $db_user->passwd($new_val);
1155 # if we don't clear the password, the user will be updated with
1156 # a hashed version of the hashed version of their password
1157 $db_user->clear_passwd;
1159 if( $api =~ /username/o ) {
1161 # make sure no one else has this username
1162 my $exist = $e->search_actor_user({usrname=>$new_val},{idlist=>1});
1163 return OpenILS::Event->new('USERNAME_EXISTS') if @$exist;
1164 $db_user->usrname($new_val);
1166 } elsif( $api =~ /email/o ) {
1167 $db_user->email($new_val);
1171 $e->update_actor_user($db_user) or return $e->die_event;
1179 __PACKAGE__->register_method(
1180 method => "check_user_perms",
1181 api_name => "open-ils.actor.user.perm.check",
1182 notes => <<" NOTES");
1183 Takes a login session, user id, an org id, and an array of perm type strings. For each
1184 perm type, if the user does *not* have the given permission it is added
1185 to a list which is returned from the method. If all permissions
1186 are allowed, an empty list is returned
1187 if the logged in user does not match 'user_id', then the logged in user must
1188 have VIEW_PERMISSION priveleges.
1191 sub check_user_perms {
1192 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1194 my( $staff, $evt ) = $apputils->checkses($login_session);
1195 return $evt if $evt;
1197 if($staff->id ne $user_id) {
1198 if( $evt = $apputils->check_perms(
1199 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1205 for my $perm (@$perm_types) {
1206 if($apputils->check_perms($user_id, $org_id, $perm)) {
1207 push @not_allowed, $perm;
1211 return \@not_allowed
1214 __PACKAGE__->register_method(
1215 method => "check_user_perms2",
1216 api_name => "open-ils.actor.user.perm.check.multi_org",
1218 Checks the permissions on a list of perms and orgs for a user
1219 @param authtoken The login session key
1220 @param user_id The id of the user to check
1221 @param orgs The array of org ids
1222 @param perms The array of permission names
1223 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1224 if the logged in user does not match 'user_id', then the logged in user must
1225 have VIEW_PERMISSION priveleges.
1228 sub check_user_perms2 {
1229 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1231 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1232 $authtoken, $user_id, 'VIEW_PERMISSION' );
1233 return $evt if $evt;
1236 for my $org (@$orgs) {
1237 for my $perm (@$perms) {
1238 if($apputils->check_perms($user_id, $org, $perm)) {
1239 push @not_allowed, [ $org, $perm ];
1244 return \@not_allowed
1248 __PACKAGE__->register_method(
1249 method => 'check_user_perms3',
1250 api_name => 'open-ils.actor.user.perm.highest_org',
1252 Returns the highest org unit id at which a user has a given permission
1253 If the requestor does not match the target user, the requestor must have
1254 'VIEW_PERMISSION' rights at the home org unit of the target user
1255 @param authtoken The login session key
1256 @param userid The id of the user in question
1257 @param perm The permission to check
1258 @return The org unit highest in the org tree within which the user has
1259 the requested permission
1262 sub check_user_perms3 {
1263 my( $self, $client, $authtoken, $userid, $perm ) = @_;
1265 my( $staff, $target, $org, $evt );
1267 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1268 $authtoken, $userid, 'VIEW_PERMISSION' );
1269 return $evt if $evt;
1271 my $tree = $U->get_org_tree();
1272 return $U->find_highest_perm_org( $perm, $userid, $target->ws_ou, $tree );
1276 __PACKAGE__->register_method(
1277 method => 'check_user_work_perms',
1278 api_name => 'open-ils.actor.user.work_perm.highest_org_set',
1282 Returns a set of org units which represent the highest orgs in
1283 the org tree where the user has the requested permission. The
1284 purpose of this method is to return the smallest set of org units
1285 which represent the full expanse of the user's ability to perform
1286 the requested action. The user whose perms this method should
1287 check is implied by the authtoken. /,
1289 {desc => 'authtoken', type => 'string'},
1290 {desc => 'permission name', type => 'string'},
1291 {desc => 'options hash, including "descendants", which will include all child orgs of the found perm orgs', type => 'hash'}
1293 return => {desc => 'An array of org IDs'}
1297 sub check_user_work_perms {
1298 my($self, $conn, $auth, $perm, $options) = @_;
1299 my $e = new_editor(authtoken=>$auth);
1300 return $e->event unless $e->checkauth;
1301 return $U->find_highest_work_orgs($e, $perm, $options);
1304 __PACKAGE__->register_method(
1305 method => 'check_user_perms4',
1306 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1308 Returns the highest org unit id at which a user has a given permission
1309 If the requestor does not match the target user, the requestor must have
1310 'VIEW_PERMISSION' rights at the home org unit of the target user
1311 @param authtoken The login session key
1312 @param userid The id of the user in question
1313 @param perms An array of perm names to check
1314 @return An array of orgId's representing the org unit
1315 highest in the org tree within which the user has the requested permission
1316 The arrah of orgId's has matches the order of the perms array
1319 sub check_user_perms4 {
1320 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1322 my( $staff, $target, $org, $evt );
1324 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1325 $authtoken, $userid, 'VIEW_PERMISSION' );
1326 return $evt if $evt;
1329 return [] unless ref($perms);
1330 my $tree = $U->get_org_tree();
1332 for my $p (@$perms) {
1333 push( @arr, $U->find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1341 __PACKAGE__->register_method(
1342 method => "user_fines_summary",
1343 api_name => "open-ils.actor.user.fines.summary",
1345 notes => <<" NOTES");
1346 Returns a short summary of the users total open fines, excluding voided fines
1347 Params are login_session, user_id
1348 Returns a 'mous' object.
1351 sub user_fines_summary {
1352 my( $self, $client, $auth, $user_id ) = @_;
1353 my $e = new_editor(authtoken=>$auth);
1354 return $e->event unless $e->checkauth;
1355 my $user = $e->retrieve_actor_user($user_id)
1356 or return $e->event;
1358 if( $user_id ne $e->requestor->id ) {
1359 return $e->event unless
1360 $e->allowed('VIEW_USER_FINES_SUMMARY', $user->home_ou);
1363 # run this inside a transaction to prevent replication delay errors
1364 my $ses = $U->start_db_session();
1365 my $s = $ses->request(
1366 'open-ils.storage.money.open_user_summary.search', $user_id )->gather(1);
1367 $U->rollback_db_session($ses);
1374 __PACKAGE__->register_method(
1375 method => "user_transactions",
1376 api_name => "open-ils.actor.user.transactions",
1377 notes => <<" NOTES");
1378 Returns a list of open user transactions (mbts objects);
1379 Params are login_session, user_id
1380 Optional third parameter is the transactions type. defaults to all
1383 __PACKAGE__->register_method(
1384 method => "user_transactions",
1385 api_name => "open-ils.actor.user.transactions.have_charge",
1386 notes => <<" NOTES");
1387 Returns a list of all open user transactions (mbts objects) that have an initial charge
1388 Params are login_session, user_id
1389 Optional third parameter is the transactions type. defaults to all
1392 __PACKAGE__->register_method(
1393 method => "user_transactions",
1394 api_name => "open-ils.actor.user.transactions.have_balance",
1395 notes => <<" NOTES");
1396 Returns a list of all open user transactions (mbts objects) that have a balance
1397 Params are login_session, user_id
1398 Optional third parameter is the transactions type. defaults to all
1401 __PACKAGE__->register_method(
1402 method => "user_transactions",
1403 api_name => "open-ils.actor.user.transactions.fleshed",
1404 notes => <<" NOTES");
1405 Returns an object/hash of transaction, circ, title where transaction = an open
1406 user transactions (mbts objects), circ is the attached circluation, and title
1407 is the title the circ points to
1408 Params are login_session, user_id
1409 Optional third parameter is the transactions type. defaults to all
1412 __PACKAGE__->register_method(
1413 method => "user_transactions",
1414 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1415 notes => <<" NOTES");
1416 Returns an object/hash of transaction, circ, title where transaction = an open
1417 user transactions that has an initial charge (mbts objects), circ is the
1418 attached circluation, and title is the title the circ points to
1419 Params are login_session, user_id
1420 Optional third parameter is the transactions type. defaults to all
1423 __PACKAGE__->register_method(
1424 method => "user_transactions",
1425 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1426 notes => <<" NOTES");
1427 Returns an object/hash of transaction, circ, title where transaction = an open
1428 user transaction that has a balance (mbts objects), circ is the attached
1429 circluation, and title is the title the circ points to
1430 Params are login_session, user_id
1431 Optional third parameter is the transaction type. defaults to all
1434 __PACKAGE__->register_method(
1435 method => "user_transactions",
1436 api_name => "open-ils.actor.user.transactions.count",
1437 notes => <<" NOTES");
1438 Returns an object/hash of transaction, circ, title where transaction = an open
1439 user transactions (mbts objects), circ is the attached circluation, and title
1440 is the title the circ points to
1441 Params are login_session, user_id
1442 Optional third parameter is the transactions type. defaults to all
1445 __PACKAGE__->register_method(
1446 method => "user_transactions",
1447 api_name => "open-ils.actor.user.transactions.have_charge.count",
1448 notes => <<" NOTES");
1449 Returns an object/hash of transaction, circ, title where transaction = an open
1450 user transactions that has an initial charge (mbts objects), circ is the
1451 attached circluation, and title is the title the circ points to
1452 Params are login_session, user_id
1453 Optional third parameter is the transactions type. defaults to all
1456 __PACKAGE__->register_method(
1457 method => "user_transactions",
1458 api_name => "open-ils.actor.user.transactions.have_balance.count",
1459 notes => <<" NOTES");
1460 Returns an object/hash of transaction, circ, title where transaction = an open
1461 user transaction that has a balance (mbts objects), circ is the attached
1462 circluation, and title is the title the circ points to
1463 Params are login_session, user_id
1464 Optional third parameter is the transaction type. defaults to all
1467 __PACKAGE__->register_method(
1468 method => "user_transactions",
1469 api_name => "open-ils.actor.user.transactions.have_balance.total",
1470 notes => <<" NOTES");
1471 Returns an object/hash of transaction, circ, title where transaction = an open
1472 user transaction that has a balance (mbts objects), circ is the attached
1473 circluation, and title is the title the circ points to
1474 Params are login_session, user_id
1475 Optional third parameter is the transaction type. defaults to all
1480 sub user_transactions {
1481 my( $self, $client, $login_session, $user_id, $type ) = @_;
1483 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1484 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1485 return $evt if $evt;
1487 my $api = $self->api_name();
1491 if(defined($type)) { @xact = (xact_type => $type);
1493 } else { @xact = (); }
1496 ->method_lookup('open-ils.actor.user.transactions.history.still_open')
1497 ->run($login_session => $user_id => $type);
1499 if($api =~ /have_charge/o) {
1501 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1503 } elsif($api =~ /have_balance/o) {
1505 $trans = [ grep { int($_->balance_owed * 100) != 0 } @$trans ];
1508 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1512 if($api =~ /total/o) {
1514 for my $t (@$trans) {
1515 $total += $t->balance_owed;
1518 $logger->debug("Total balance owed by user $user_id: $total");
1522 if($api =~ /count/o) { return scalar @$trans; }
1523 if($api !~ /fleshed/o) { return $trans; }
1526 for my $t (@$trans) {
1528 if( $t->xact_type ne 'circulation' ) {
1529 push @resp, {transaction => $t};
1533 my $circ = $apputils->simple_scalar_request(
1535 "open-ils.cstore.direct.action.circulation.retrieve",
1540 my $title = $apputils->simple_scalar_request(
1542 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1543 $circ->target_copy );
1547 my $u = OpenILS::Utils::ModsParser->new();
1548 $u->start_mods_batch($title->marc());
1549 my $mods = $u->finish_mods_batch();
1550 $mods->doc_id($title->id) if $mods;
1552 push @resp, {transaction => $t, circ => $circ, record => $mods };
1560 __PACKAGE__->register_method(
1561 method => "user_transaction_retrieve",
1562 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1564 notes => <<" NOTES");
1565 Returns a fleshedtransaction record
1567 __PACKAGE__->register_method(
1568 method => "user_transaction_retrieve",
1569 api_name => "open-ils.actor.user.transaction.retrieve",
1571 notes => <<" NOTES");
1572 Returns a transaction record
1574 sub user_transaction_retrieve {
1575 my( $self, $client, $login_session, $bill_id ) = @_;
1577 # XXX I think I'm deprecated... make sure
1579 my $trans = $apputils->simple_scalar_request(
1581 "open-ils.cstore.direct.money.billable_transaction_summary.retrieve",
1585 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1586 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1587 return $evt if $evt;
1589 my $api = $self->api_name();
1590 if($api !~ /fleshed/o) { return $trans; }
1592 if( $trans->xact_type ne 'circulation' ) {
1593 $logger->debug("Returning non-circ transaction");
1594 return {transaction => $trans};
1597 my $circ = $apputils->simple_scalar_request(
1599 "open-ils..direct.action.circulation.retrieve",
1602 return {transaction => $trans} unless $circ;
1603 $logger->debug("Found the circ transaction");
1605 my $title = $apputils->simple_scalar_request(
1607 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1608 $circ->target_copy );
1610 return {transaction => $trans, circ => $circ } unless $title;
1611 $logger->debug("Found the circ title");
1615 my $u = OpenILS::Utils::ModsParser->new();
1616 $u->start_mods_batch($title->marc());
1617 $mods = $u->finish_mods_batch();
1619 if ($title->id == OILS_PRECAT_RECORD) {
1620 my $copy = $apputils->simple_scalar_request(
1622 "open-ils.cstore.direct.asset.copy.retrieve",
1623 $circ->target_copy );
1625 $mods = new Fieldmapper::metabib::virtual_record;
1626 $mods->doc_id(OILS_PRECAT_RECORD);
1627 $mods->title($copy->dummy_title);
1628 $mods->author($copy->dummy_author);
1632 $logger->debug("MODSized the circ title");
1634 return {transaction => $trans, circ => $circ, record => $mods };
1638 __PACKAGE__->register_method(
1639 method => "hold_request_count",
1640 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",
1728 Returns a structure of circulations objects sorted by
1729 out, overdue, lost, claims_returned, long_overdue.
1730 A list of IDs are returned of each type.
1731 lost, long_overdue, and claims_returned circ will not
1732 be "finished" (there is an outstanding balance or some
1733 other pending action on the circ).
1735 The .count method also includes a 'total' field which
1736 sums all "open" circs
1740 __PACKAGE__->register_method(
1741 method => "checked_out",
1742 api_name => "open-ils.actor.user.checked_out.count",
1745 signature => q/@see open-ils.actor.user.checked_out/
1749 my( $self, $conn, $auth, $userid ) = @_;
1751 my $e = new_editor(authtoken=>$auth);
1752 return $e->event unless $e->checkauth;
1754 if( $userid ne $e->requestor->id ) {
1755 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1758 my $count = $self->api_name =~ /count/;
1759 return _checked_out( $count, $e, $userid );
1763 my( $iscount, $e, $userid ) = @_;
1766 my $meth = 'open-ils.storage.actor.user.checked_out';
1767 $meth = "$meth.count" if $iscount;
1768 return $U->storagereq($meth, $userid);
1770 # XXX Old code - moved to storage
1771 #------------------------------------------------------------------------------
1772 #------------------------------------------------------------------------------
1773 my $circs = $e->search_action_circulation(
1774 { usr => $userid, checkin_time => undef });
1776 my $parser = DateTime::Format::ISO8601->new;
1778 # split the circs up into overdue and not-overdue circs
1780 for my $c (@$circs) {
1781 if( $c->due_date ) {
1782 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1783 my $due = $due_dt->epoch;
1784 if ($due < DateTime->today->epoch) {
1794 my( @open, @od, @lost, @cr, @lo );
1796 while (my $c = shift(@out)) {
1797 push( @open, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1798 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1799 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1800 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1803 while (my $c = shift(@overdue)) {
1804 push( @od, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1805 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1806 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1807 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1812 total => @open + @od + @lost + @cr + @lo,
1813 out => scalar(@open),
1814 overdue => scalar(@od),
1815 lost => scalar(@lost),
1816 claims_returned => scalar(@cr),
1817 long_overdue => scalar(@lo)
1825 claims_returned => \@cr,
1826 long_overdue => \@lo
1831 sub _checked_out_WHAT {
1832 my( $iscount, $e, $userid ) = @_;
1834 my $circs = $e->search_action_circulation(
1835 { usr => $userid, stop_fines => undef });
1837 my $mcircs = $e->search_action_circulation(
1840 checkin_time => undef,
1841 xact_finish => undef,
1845 push( @$circs, @$mcircs );
1847 my $parser = DateTime::Format::ISO8601->new;
1849 # split the circs up into overdue and not-overdue circs
1851 for my $c (@$circs) {
1852 if( $c->due_date ) {
1853 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1854 my $due = $due_dt->epoch;
1855 if ($due < DateTime->today->epoch) {
1856 push @overdue, $c->id;
1865 # grab all of the lost, claims-returned, and longoverdue circs
1866 #my $open = $e->search_action_circulation(
1867 # {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1870 # these items have stop_fines, but no xact_finish, so money
1871 # is owed on them and they have not been checked in
1872 my $open = $e->search_action_circulation(
1875 stop_fines => { in => [ qw/LOST CLAIMSRETURNED LONGOVERDUE/ ] },
1876 xact_finish => undef,
1877 checkin_time => undef,
1882 my( @lost, @cr, @lo );
1883 for my $c (@$open) {
1884 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1885 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1886 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1892 total => @$circs + @lost + @cr + @lo,
1893 out => scalar(@out),
1894 overdue => scalar(@overdue),
1895 lost => scalar(@lost),
1896 claims_returned => scalar(@cr),
1897 long_overdue => scalar(@lo)
1903 overdue => \@overdue,
1905 claims_returned => \@cr,
1906 long_overdue => \@lo
1912 __PACKAGE__->register_method(
1913 method => "checked_in_with_fines",
1914 api_name => "open-ils.actor.user.checked_in_with_fines",
1917 signature => q/@see open-ils.actor.user.checked_out/
1919 sub checked_in_with_fines {
1920 my( $self, $conn, $auth, $userid ) = @_;
1922 my $e = new_editor(authtoken=>$auth);
1923 return $e->event unless $e->checkauth;
1925 if( $userid ne $e->requestor->id ) {
1926 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1929 # money is owed on these items and they are checked in
1930 my $open = $e->search_action_circulation(
1933 xact_finish => undef,
1934 checkin_time => { "!=" => undef },
1939 my( @lost, @cr, @lo );
1940 for my $c (@$open) {
1941 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1942 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1943 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1948 claims_returned => \@cr,
1949 long_overdue => \@lo
1961 __PACKAGE__->register_method(
1962 method => "user_transaction_history",
1963 api_name => "open-ils.actor.user.transactions.history",
1965 notes => <<" NOTES");
1966 Returns a list of billable transaction ids for a user, optionally by type
1968 __PACKAGE__->register_method(
1969 method => "user_transaction_history",
1970 api_name => "open-ils.actor.user.transactions.history.have_charge",
1972 notes => <<" NOTES");
1973 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
1975 __PACKAGE__->register_method(
1976 method => "user_transaction_history",
1977 api_name => "open-ils.actor.user.transactions.history.have_balance",
1980 notes => <<" NOTES");
1981 Returns a list of billable transaction ids for a user that have a balance, optionally by type
1983 __PACKAGE__->register_method(
1984 method => "user_transaction_history",
1985 api_name => "open-ils.actor.user.transactions.history.still_open",
1987 notes => <<" NOTES");
1988 Returns a list of billable transaction ids for a user that are not finished
1990 __PACKAGE__->register_method(
1991 method => "user_transaction_history",
1992 api_name => "open-ils.actor.user.transactions.history.have_bill",
1995 notes => <<" NOTES");
1996 Returns a list of billable transaction ids for a user that has billings
2002 sub _user_transaction_history {
2003 my( $self, $client, $login_session, $user_id, $type ) = @_;
2005 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
2006 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
2007 return $evt if $evt;
2009 my $api = $self->api_name();
2014 @xact = (xact_type => $type) if(defined($type));
2015 @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
2016 @charge = (last_billing_ts => { "<>" => undef }) if $api =~ /have_charge/;
2018 $logger->debug("searching for transaction history: @xact : @balance, @charge");
2020 my $trans = $apputils->simple_scalar_request(
2022 "open-ils.cstore.direct.money.billable_transaction_summary.search.atomic",
2023 { usr => $user_id, @xact, @charge, @balance }, { order_by => { mbts => 'xact_start DESC' } });
2025 return [ map { $_->id } @$trans ];
2029 =head SEE APPUTILS.PM
2034 for my $x (@xacts) {
2035 my $s = new Fieldmapper::money::billable_transaction_summary;
2038 $s->xact_start( $x->xact_start );
2039 $s->xact_finish( $x->xact_finish );
2043 for my $b (@{ $x->billings }) {
2044 next if ($U->is_true($b->voided));
2045 $to += ($b->amount * 100);
2046 $lb ||= $b->billing_ts;
2047 if ($b->billing_ts ge $lb) {
2048 $lb = $b->billing_ts;
2049 $s->last_billing_note($b->note);
2050 $s->last_billing_ts($b->billing_ts);
2051 $s->last_billing_type($b->billing_type);
2055 $s->total_owed( sprintf('%0.2f', $to / 100 ) );
2059 for my $p (@{ $x->payments }) {
2060 next if ($U->is_true($p->voided));
2061 $tp += ($p->amount * 100);
2062 $lp ||= $p->payment_ts;
2063 if ($p->payment_ts ge $lp) {
2064 $lp = $p->payment_ts;
2065 $s->last_payment_note($p->note);
2066 $s->last_payment_ts($p->payment_ts);
2067 $s->last_payment_type($p->payment_type);
2070 $s->total_paid( sprintf('%0.2f', $tp / 100 ) );
2072 $s->balance_owed( sprintf('%0.2f', ($to - $tp) / 100) );
2074 $s->xact_type( 'grocery' ) if ($x->grocery);
2075 $s->xact_type( 'circulation' ) if ($x->circulation);
2084 sub user_transaction_history {
2085 my( $self, $conn, $auth, $userid, $type ) = @_;
2087 # run inside of a transaction to prevent replication delays
2088 my $e = new_editor(xact=>1, authtoken=>$auth);
2089 return $e->die_event unless $e->checkauth;
2091 if( $e->requestor->id ne $userid ) {
2092 return $e->die_event
2093 unless $e->allowed('VIEW_USER_TRANSACTIONS');
2096 my $api = $self->api_name;
2097 my @xact_finish = (xact_finish => undef ) if ($api =~ /history.still_open$/);
2099 my @xacts = @{ $e->search_money_billable_transaction(
2100 [ { usr => $userid, @xact_finish },
2102 flesh_fields => { mbt => [ qw/billings payments grocery circulation/ ] },
2103 order_by => { mbt => 'xact_start DESC' },
2111 #my @mbts = _make_mbts( @xacts );
2112 my @mbts = $U->make_mbts( @xacts );
2114 if(defined($type)) {
2115 @mbts = grep { $_->xact_type eq $type } @mbts;
2118 if($api =~ /have_balance/o) {
2119 @mbts = grep { int($_->balance_owed * 100) != 0 } @mbts;
2122 if($api =~ /have_charge/o) {
2123 @mbts = grep { defined($_->last_billing_ts) } @mbts;
2126 if($api =~ /have_bill/o) {
2127 @mbts = grep { int($_->total_owed * 100) != 0 } @mbts;
2135 __PACKAGE__->register_method(
2136 method => "user_perms",
2137 api_name => "open-ils.actor.permissions.user_perms.retrieve",
2139 notes => <<" NOTES");
2140 Returns a list of permissions
2143 my( $self, $client, $authtoken, $user ) = @_;
2145 my( $staff, $evt ) = $apputils->checkses($authtoken);
2146 return $evt if $evt;
2148 $user ||= $staff->id;
2150 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
2154 return $apputils->simple_scalar_request(
2156 "open-ils.storage.permission.user_perms.atomic",
2160 __PACKAGE__->register_method(
2161 method => "retrieve_perms",
2162 api_name => "open-ils.actor.permissions.retrieve",
2163 notes => <<" NOTES");
2164 Returns a list of permissions
2166 sub retrieve_perms {
2167 my( $self, $client ) = @_;
2168 return $apputils->simple_scalar_request(
2170 "open-ils.cstore.direct.permission.perm_list.search.atomic",
2171 { id => { '!=' => undef } }
2175 __PACKAGE__->register_method(
2176 method => "retrieve_groups",
2177 api_name => "open-ils.actor.groups.retrieve",
2178 notes => <<" NOTES");
2179 Returns a list of user groupss
2181 sub retrieve_groups {
2182 my( $self, $client ) = @_;
2183 return new_editor()->retrieve_all_permission_grp_tree();
2186 __PACKAGE__->register_method(
2187 method => "retrieve_org_address",
2188 api_name => "open-ils.actor.org_unit.address.retrieve",
2189 notes => <<' NOTES');
2190 Returns an org_unit address by ID
2191 @param An org_address ID
2193 sub retrieve_org_address {
2194 my( $self, $client, $id ) = @_;
2195 return $apputils->simple_scalar_request(
2197 "open-ils.cstore.direct.actor.org_address.retrieve",
2202 __PACKAGE__->register_method(
2203 method => "retrieve_groups_tree",
2204 api_name => "open-ils.actor.groups.tree.retrieve",
2205 notes => <<" NOTES");
2206 Returns a list of user groups
2208 sub retrieve_groups_tree {
2209 my( $self, $client ) = @_;
2210 return new_editor()->search_permission_grp_tree(
2215 flesh_fields => { pgt => ["children"] },
2216 order_by => { pgt => 'name'}
2223 # turns an org list into an org tree
2225 sub build_group_tree {
2227 my( $self, $grplist) = @_;
2229 return $grplist unless (
2230 ref($grplist) and @$grplist > 1 );
2232 my @list = sort { $a->name cmp $b->name } @$grplist;
2235 for my $grp (@list) {
2237 if ($grp and !defined($grp->parent)) {
2241 my ($parent) = grep { $_->id == $grp->parent} @list;
2243 $parent->children([]) unless defined($parent->children);
2244 push( @{$parent->children}, $grp );
2252 __PACKAGE__->register_method(
2253 method => "add_user_to_groups",
2254 api_name => "open-ils.actor.user.set_groups",
2255 notes => <<" NOTES");
2256 Adds a user to one or more permission groups
2259 sub add_user_to_groups {
2260 my( $self, $client, $authtoken, $userid, $groups ) = @_;
2262 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2263 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
2264 return $evt if $evt;
2266 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2267 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
2268 return $evt if $evt;
2270 $apputils->simplereq(
2272 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
2274 for my $group (@$groups) {
2275 my $link = Fieldmapper::permission::usr_grp_map->new;
2277 $link->usr($userid);
2279 my $id = $apputils->simplereq(
2281 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2287 __PACKAGE__->register_method(
2288 method => "get_user_perm_groups",
2289 api_name => "open-ils.actor.user.get_groups",
2290 notes => <<" NOTES");
2291 Retrieve a user's permission groups.
2295 sub get_user_perm_groups {
2296 my( $self, $client, $authtoken, $userid ) = @_;
2298 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2299 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2300 return $evt if $evt;
2302 return $apputils->simplereq(
2304 'open-ils.cstore.direct.permission.usr_grp_map.search.atomic', { usr => $userid } );
2308 __PACKAGE__->register_method(
2309 method => "get_user_work_ous",
2310 api_name => "open-ils.actor.user.get_work_ous",
2311 notes => <<" NOTES");
2312 Retrieve a user's work org units.
2314 __PACKAGE__->register_method(
2315 method => "get_user_work_ous",
2316 api_name => "open-ils.actor.user.get_work_ous.ids",
2317 notes => <<" NOTES");
2318 Retrieve a user's work org units.
2322 sub get_user_work_ous {
2323 my( $self, $client, $auth, $userid ) = @_;
2324 my $e = new_editor(authtoken=>$auth);
2325 return $e->event unless $e->checkauth;
2326 $userid ||= $e->requestor->id;
2328 if($e->requestor->id != $userid) {
2329 my $user = $e->retrieve_actor_user($userid)
2330 or return $e->event;
2331 return $e->event unless $e->allowed('ASSIGN_WORK_ORG_UNIT', $user->home_ou);
2334 return $e->search_permission_usr_work_ou_map({usr => $userid})
2335 unless $self->api_name =~ /.ids$/;
2337 # client just wants a list of org IDs
2338 return $U->get_user_work_ou_ids($e, $userid);
2344 __PACKAGE__->register_method (
2345 method => 'register_workstation',
2346 api_name => 'open-ils.actor.workstation.register.override',
2347 signature => q/@see open-ils.actor.workstation.register/);
2349 __PACKAGE__->register_method (
2350 method => 'register_workstation',
2351 api_name => 'open-ils.actor.workstation.register',
2353 Registers a new workstion in the system
2354 @param authtoken The login session key
2355 @param name The name of the workstation id
2356 @param owner The org unit that owns this workstation
2357 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2358 if the name is already in use.
2361 sub register_workstation {
2362 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2364 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2365 return $e->die_event unless $e->checkauth;
2366 return $e->die_event unless $e->allowed('REGISTER_WORKSTATION', $owner);
2367 my $existing = $e->search_actor_workstation({name => $name})->[0];
2371 if( $self->api_name =~ /override/o ) {
2372 # workstation with the given name exists.
2374 if($owner ne $existing->owning_lib) {
2375 # if necessary, update the owning_lib of the workstation
2377 $logger->info("changing owning lib of workstation ".$existing->id.
2378 " from ".$existing->owning_lib." to $owner");
2379 return $e->die_event unless
2380 $e->allowed('UPDATE_WORKSTATION', $existing->owning_lib);
2382 return $e->die_event unless $e->allowed('UPDATE_WORKSTATION', $owner);
2384 $existing->owning_lib($owner);
2385 return $e->die_event unless $e->update_actor_workstation($existing);
2391 "attempt to register an existing workstation. returning existing ID");
2394 return $existing->id;
2397 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2401 my $ws = Fieldmapper::actor::workstation->new;
2402 $ws->owning_lib($owner);
2404 $e->create_actor_workstation($ws) or return $e->die_event;
2406 return $ws->id; # note: editor sets the id on the new object for us
2409 __PACKAGE__->register_method (
2410 method => 'workstation_list',
2411 api_name => 'open-ils.actor.workstation.list',
2413 Returns a list of workstations registered at the given location
2414 @param authtoken The login session key
2415 @param ids A list of org_unit.id's for the workstation owners
2418 sub workstation_list {
2419 my( $self, $conn, $authtoken, @orgs ) = @_;
2421 my $e = new_editor(authtoken=>$authtoken);
2422 return $e->event unless $e->checkauth;
2427 unless $e->allowed('REGISTER_WORKSTATION', $o);
2428 $results{$o} = $e->search_actor_workstation({owning_lib=>$o});
2439 __PACKAGE__->register_method (
2440 method => 'fetch_patron_note',
2441 api_name => 'open-ils.actor.note.retrieve.all',
2444 Returns a list of notes for a given user
2445 Requestor must have VIEW_USER permission if pub==false and
2446 @param authtoken The login session key
2447 @param args Hash of params including
2448 patronid : the patron's id
2449 pub : true if retrieving only public notes
2453 sub fetch_patron_note {
2454 my( $self, $conn, $authtoken, $args ) = @_;
2455 my $patronid = $$args{patronid};
2457 my($reqr, $evt) = $U->checkses($authtoken);
2458 return $evt if $evt;
2461 ($patron, $evt) = $U->fetch_user($patronid);
2462 return $evt if $evt;
2465 if( $patronid ne $reqr->id ) {
2466 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2467 return $evt if $evt;
2469 return $U->cstorereq(
2470 'open-ils.cstore.direct.actor.usr_note.search.atomic',
2471 { usr => $patronid, pub => 't' } );
2474 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2475 return $evt if $evt;
2477 return $U->cstorereq(
2478 'open-ils.cstore.direct.actor.usr_note.search.atomic', { usr => $patronid } );
2481 __PACKAGE__->register_method (
2482 method => 'create_user_note',
2483 api_name => 'open-ils.actor.note.create',
2485 Creates a new note for the given user
2486 @param authtoken The login session key
2487 @param note The note object
2490 sub create_user_note {
2491 my( $self, $conn, $authtoken, $note ) = @_;
2492 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2493 return $e->die_event unless $e->checkauth;
2495 my $user = $e->retrieve_actor_user($note->usr)
2496 or return $e->die_event;
2498 return $e->die_event unless
2499 $e->allowed('UPDATE_USER',$user->home_ou);
2501 $note->creator($e->requestor->id);
2502 $e->create_actor_usr_note($note) or return $e->die_event;
2508 __PACKAGE__->register_method (
2509 method => 'delete_user_note',
2510 api_name => 'open-ils.actor.note.delete',
2512 Deletes a note for the given user
2513 @param authtoken The login session key
2514 @param noteid The note id
2517 sub delete_user_note {
2518 my( $self, $conn, $authtoken, $noteid ) = @_;
2520 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2521 return $e->die_event unless $e->checkauth;
2522 my $note = $e->retrieve_actor_usr_note($noteid)
2523 or return $e->die_event;
2524 my $user = $e->retrieve_actor_user($note->usr)
2525 or return $e->die_event;
2526 return $e->die_event unless
2527 $e->allowed('UPDATE_USER', $user->home_ou);
2529 $e->delete_actor_usr_note($note) or return $e->die_event;
2535 __PACKAGE__->register_method (
2536 method => 'update_user_note',
2537 api_name => 'open-ils.actor.note.update',
2539 @param authtoken The login session key
2540 @param note The note
2544 sub update_user_note {
2545 my( $self, $conn, $auth, $note ) = @_;
2546 my $e = new_editor(authtoken=>$auth, xact=>1);
2547 return $e->event unless $e->checkauth;
2548 my $patron = $e->retrieve_actor_user($note->usr)
2549 or return $e->event;
2550 return $e->event unless
2551 $e->allowed('UPDATE_USER', $patron->home_ou);
2552 $e->update_actor_user_note($note)
2553 or return $e->event;
2561 __PACKAGE__->register_method (
2562 method => 'create_closed_date',
2563 api_name => 'open-ils.actor.org_unit.closed_date.create',
2565 Creates a new closing entry for the given org_unit
2566 @param authtoken The login session key
2567 @param note The closed_date object
2570 sub create_closed_date {
2571 my( $self, $conn, $authtoken, $cd ) = @_;
2573 my( $user, $evt ) = $U->checkses($authtoken);
2574 return $evt if $evt;
2576 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2577 return $evt if $evt;
2579 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2581 my $id = $U->storagereq(
2582 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2583 return $U->DB_UPDATE_FAILED($cd) unless $id;
2588 __PACKAGE__->register_method (
2589 method => 'delete_closed_date',
2590 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2592 Deletes a closing entry for the given org_unit
2593 @param authtoken The login session key
2594 @param noteid The close_date id
2597 sub delete_closed_date {
2598 my( $self, $conn, $authtoken, $cd ) = @_;
2600 my( $user, $evt ) = $U->checkses($authtoken);
2601 return $evt if $evt;
2604 ($cd_obj, $evt) = fetch_closed_date($cd);
2605 return $evt if $evt;
2607 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2608 return $evt if $evt;
2610 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2612 my $stat = $U->storagereq(
2613 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2614 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2619 __PACKAGE__->register_method(
2620 method => 'usrname_exists',
2621 api_name => 'open-ils.actor.username.exists',
2623 Returns 1 if the requested username exists, returns 0 otherwise
2627 sub usrname_exists {
2628 my( $self, $conn, $auth, $usrname ) = @_;
2629 my $e = new_editor(authtoken=>$auth);
2630 return $e->event unless $e->checkauth;
2631 my $a = $e->search_actor_user({usrname => $usrname, deleted=>'f'}, {idlist=>1});
2632 return $$a[0] if $a and @$a;
2636 __PACKAGE__->register_method(
2637 method => 'barcode_exists',
2638 api_name => 'open-ils.actor.barcode.exists',
2641 Returns 1 if the requested barcode exists, returns 0 otherwise
2645 sub barcode_exists {
2646 my( $self, $conn, $auth, $barcode ) = @_;
2647 my $e = new_editor(authtoken=>$auth);
2648 return $e->event unless $e->checkauth;
2649 my $card = $e->search_actor_card({barcode => $barcode});
2650 return undef unless @$card;
2651 return $card->[0]->usr;
2655 __PACKAGE__->register_method(
2656 method => 'retrieve_net_levels',
2657 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2660 sub retrieve_net_levels {
2661 my( $self, $conn, $auth ) = @_;
2662 my $e = new_editor(authtoken=>$auth);
2663 return $e->event unless $e->checkauth;
2664 return $e->retrieve_all_config_net_access_level();
2668 __PACKAGE__->register_method(
2669 method => 'fetch_org_by_shortname',
2670 api_name => 'open-ils.actor.org_unit.retrieve_by_shorname',
2672 sub fetch_org_by_shortname {
2673 my( $self, $conn, $sname ) = @_;
2674 my $e = new_editor();
2675 my $org = $e->search_actor_org_unit({ shortname => uc($sname)})->[0];
2676 return $e->event unless $org;
2681 __PACKAGE__->register_method(
2682 method => 'session_home_lib',
2683 api_name => 'open-ils.actor.session.home_lib',
2686 sub session_home_lib {
2687 my( $self, $conn, $auth ) = @_;
2688 my $e = new_editor(authtoken=>$auth);
2689 return undef unless $e->checkauth;
2690 my $org = $e->retrieve_actor_org_unit($e->requestor->home_ou);
2691 return $org->shortname;
2694 __PACKAGE__->register_method(
2695 method => 'session_safe_token',
2696 api_name => 'open-ils.actor.session.safe_token',
2698 Returns a hashed session ID that is safe for export to the world.
2699 This safe token will expire after 1 hour of non-use.
2700 @param auth Active authentication token
2704 sub session_safe_token {
2705 my( $self, $conn, $auth ) = @_;
2706 my $e = new_editor(authtoken=>$auth);
2707 return undef unless $e->checkauth;
2709 my $safe_token = md5_hex($auth);
2711 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2713 # Add more like the following if needed...
2715 "safe-token-home_lib-shortname-$safe_token",
2716 $e->retrieve_actor_org_unit(
2717 $e->requestor->home_ou
2726 __PACKAGE__->register_method(
2727 method => 'safe_token_home_lib',
2728 api_name => 'open-ils.actor.safe_token.home_lib.shortname',
2730 Returns the home library shortname from the session
2731 asscociated with a safe token from generated by
2732 open-ils.actor.session.safe_token.
2733 @param safe_token Active safe token
2737 sub safe_token_home_lib {
2738 my( $self, $conn, $safe_token ) = @_;
2740 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2741 return $cache->get_cache( 'safe-token-home_lib-shortname-'. $safe_token );
2746 __PACKAGE__->register_method(
2747 method => 'slim_tree',
2748 api_name => "open-ils.actor.org_tree.slim_hash.retrieve",
2751 my $tree = new_editor()->search_actor_org_unit(
2753 {"parent_ou" => undef },
2756 flesh_fields => { aou => ['children'] },
2757 order_by => { aou => 'name'},
2758 select => { aou => ["id","shortname", "name"]},
2763 return trim_tree($tree);
2769 return undef unless $tree;
2771 code => $tree->shortname,
2772 name => $tree->name,
2774 if( $tree->children and @{$tree->children} ) {
2775 $htree->{children} = [];
2776 for my $c (@{$tree->children}) {
2777 push( @{$htree->{children}}, trim_tree($c) );
2785 __PACKAGE__->register_method(
2786 method => "update_penalties",
2787 api_name => "open-ils.actor.user.penalties.update");
2788 sub update_penalties {
2789 my( $self, $conn, $auth, $userid ) = @_;
2790 my $e = new_editor(authtoken=>$auth);
2791 return $e->event unless $e->checkauth;
2792 $U->update_patron_penalties(
2794 patronid => $userid,
2801 __PACKAGE__->register_method(
2802 method => "user_retrieve_fleshed_by_id",
2803 api_name => "open-ils.actor.user.fleshed.retrieve",);
2805 sub user_retrieve_fleshed_by_id {
2806 my( $self, $client, $auth, $user_id, $fields ) = @_;
2807 my $e = new_editor(authtoken => $auth);
2808 return $e->event unless $e->checkauth;
2810 if( $e->requestor->id != $user_id ) {
2811 return $e->event unless $e->allowed('VIEW_USER');
2817 "standing_penalties",
2821 "stat_cat_entries" ];
2822 return new_flesh_user($user_id, $fields, $e);
2826 sub new_flesh_user {
2829 my $fields = shift || [];
2830 my $e = shift || new_editor(xact=>1);
2832 my $user = $e->retrieve_actor_user(
2837 "flesh_fields" => { "au" => $fields }
2840 ) or return $e->event;
2843 if( grep { $_ eq 'addresses' } @$fields ) {
2845 $user->addresses([]) unless @{$user->addresses};
2847 if( ref $user->billing_address ) {
2848 unless( grep { $user->billing_address->id == $_->id } @{$user->addresses} ) {
2849 push( @{$user->addresses}, $user->billing_address );
2853 if( ref $user->mailing_address ) {
2854 unless( grep { $user->mailing_address->id == $_->id } @{$user->addresses} ) {
2855 push( @{$user->addresses}, $user->mailing_address );
2861 $user->clear_passwd();
2868 __PACKAGE__->register_method(
2869 method => "user_retrieve_parts",
2870 api_name => "open-ils.actor.user.retrieve.parts",);
2872 sub user_retrieve_parts {
2873 my( $self, $client, $auth, $user_id, $fields ) = @_;
2874 my $e = new_editor(authtoken => $auth);
2875 return $e->event unless $e->checkauth;
2876 if( $e->requestor->id != $user_id ) {
2877 return $e->event unless $e->allowed('VIEW_USER');
2880 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2881 push(@resp, $user->$_()) for(@$fields);
2887 __PACKAGE__->register_method(
2888 method => 'user_opt_in_enabled',
2889 api_name => 'open-ils.actor.user.org_unit_opt_in.enabled',
2891 @return 1 if user opt-in is globally enabled, 0 otherwise.
2894 sub user_opt_in_enabled {
2895 my($self, $conn) = @_;
2896 my $sc = OpenSRF::Utils::SettingsClient->new;
2897 return 1 if lc($sc->config_value(share => user => 'opt_in')) eq 'true';
2902 __PACKAGE__->register_method(
2903 method => 'user_opt_in_at_org',
2904 api_name => 'open-ils.actor.user.org_unit_opt_in.check',
2906 @param $auth The auth token
2907 @param user_id The ID of the user to test
2908 @return 1 if the user has opted in at the specified org,
2909 event on error, and 0 otherwise. /);
2910 sub user_opt_in_at_org {
2911 my($self, $conn, $auth, $user_id) = @_;
2913 # see if we even need to enforce the opt-in value
2914 return 1 unless user_opt_in_enabled($self);
2916 my $e = new_editor(authtoken => $auth);
2917 return $e->event unless $e->checkauth;
2918 my $org_id = $e->requestor->ws_ou;
2920 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2921 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
2923 # user is automatically opted-in at the home org
2924 return 1 if $user->home_ou eq $org_id;
2926 my $vals = $e->search_actor_usr_org_unit_opt_in(
2927 {org_unit=>$org_id, usr=>$user_id},{idlist=>1});
2933 __PACKAGE__->register_method(
2934 method => 'create_user_opt_in_at_org',
2935 api_name => 'open-ils.actor.user.org_unit_opt_in.create',
2937 @param $auth The auth token
2938 @param user_id The ID of the user to test
2939 @return The ID of the newly created object, event on error./);
2941 sub create_user_opt_in_at_org {
2942 my($self, $conn, $auth, $user_id) = @_;
2944 my $e = new_editor(authtoken => $auth, xact=>1);
2945 return $e->die_event unless $e->checkauth;
2946 my $org_id = $e->requestor->ws_ou;
2948 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
2949 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2951 my $opt_in = Fieldmapper::actor::usr_org_unit_opt_in->new;
2953 $opt_in->org_unit($org_id);
2954 $opt_in->usr($user_id);
2955 $opt_in->staff($e->requestor->id);
2956 $opt_in->opt_in_ts('now');
2957 $opt_in->opt_in_ws($e->requestor->wsid);
2959 $opt_in = $e->create_actor_usr_org_unit_opt_in($opt_in)
2960 or return $e->die_event;